Version:  2.0.40 2.2.26 2.4.37 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7

Linux/drivers/staging/comedi/drivers/adv_pci_dio.c

  1 /*
  2  * comedi/drivers/adv_pci_dio.c
  3  *
  4  * Author: Michal Dobes <dobes@tesnet.cz>
  5  *
  6  *  Hardware driver for Advantech PCI DIO cards.
  7  */
  8 
  9 /*
 10  * Driver: adv_pci_dio
 11  * Description: Advantech Digital I/O Cards
 12  * Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
 13  *   PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
 14  *   PCI-1751, PCI-1752, PCI-1753, PCI-1753+PCI-1753E,
 15  *   PCI-1754, PCI-1756, PCI-1762
 16  * Author: Michal Dobes <dobes@tesnet.cz>
 17  * Updated: Mon, 09 Jan 2012 12:40:46 +0000
 18  * Status: untested
 19  *
 20  * Configuration Options: not applicable, uses PCI auto config
 21  */
 22 
 23 #include <linux/module.h>
 24 #include <linux/delay.h>
 25 
 26 #include "../comedi_pci.h"
 27 
 28 #include "8255.h"
 29 #include "comedi_8254.h"
 30 
 31 /*
 32  * Register offset definitions
 33  */
 34 
 35 /* PCI-1730, PCI-1733, PCI-1736 interrupt control registers */
 36 #define PCI173X_INT_EN_REG      0x08    /* R/W: enable/disable */
 37 #define PCI173X_INT_RF_REG      0x0c    /* R/W: falling/rising edge */
 38 #define PCI173X_INT_CLR_REG     0x10    /* R/W: clear */
 39 
 40 /* PCI-1739U, PCI-1750, PCI1751 interrupt control registers */
 41 #define PCI1750_INT_REG         0x20    /* R/W: status/control */
 42 
 43 /* PCI-1753, PCI-1753E interrupt control registers */
 44 #define PCI1753_INT_REG(x)      (0x10 + (x)) /* R/W: control group 0 to 3 */
 45 #define PCI1753E_INT_REG(x)     (0x30 + (x)) /* R/W: control group 0 to 3 */
 46 
 47 /* PCI-1754, PCI-1756 interrupt control registers */
 48 #define PCI1754_INT_REG(x)      (0x08 + (x) * 2) /* R/W: control group 0 to 3 */
 49 
 50 /* PCI-1752, PCI-1756 special registers */
 51 #define PCI1752_CFC_REG         0x12    /* R/W: channel freeze function */
 52 
 53 /* PCI-1762 interrupt control registers */
 54 #define PCI1762_INT_REG         0x06    /* R/W: status/control */
 55 
 56 /* maximum number of subdevice descriptions in the boardinfo */
 57 #define PCI_DIO_MAX_DI_SUBDEVS  2       /* 2 x 8/16/32 input channels max */
 58 #define PCI_DIO_MAX_DO_SUBDEVS  2       /* 2 x 8/16/32 output channels max */
 59 #define PCI_DIO_MAX_DIO_SUBDEVG 2       /* 2 x any number of 8255 devices max */
 60 
 61 enum pci_dio_boardid {
 62         TYPE_PCI1730,
 63         TYPE_PCI1733,
 64         TYPE_PCI1734,
 65         TYPE_PCI1735,
 66         TYPE_PCI1736,
 67         TYPE_PCI1739,
 68         TYPE_PCI1750,
 69         TYPE_PCI1751,
 70         TYPE_PCI1752,
 71         TYPE_PCI1753,
 72         TYPE_PCI1753E,
 73         TYPE_PCI1754,
 74         TYPE_PCI1756,
 75         TYPE_PCI1762
 76 };
 77 
 78 struct diosubd_data {
 79         int chans;              /*  num of chans or 8255 devices */
 80         unsigned long addr;     /*  PCI address ofset */
 81 };
 82 
 83 struct dio_boardtype {
 84         const char *name;       /*  board name */
 85         int nsubdevs;
 86         struct diosubd_data sdi[PCI_DIO_MAX_DI_SUBDEVS];
 87         struct diosubd_data sdo[PCI_DIO_MAX_DO_SUBDEVS];
 88         struct diosubd_data sdio[PCI_DIO_MAX_DIO_SUBDEVG];
 89         unsigned long id_reg;
 90         unsigned long timer_regbase;
 91         unsigned int is_16bit:1;
 92 };
 93 
 94 static const struct dio_boardtype boardtypes[] = {
 95         [TYPE_PCI1730] = {
 96                 .name           = "pci1730",
 97                 .nsubdevs       = 5,
 98                 .sdi[0]         = { 16, 0x02, },        /* DI 0-15 */
 99                 .sdi[1]         = { 16, 0x00, },        /* ISO DI 0-15 */
100                 .sdo[0]         = { 16, 0x02, },        /* DO 0-15 */
101                 .sdo[1]         = { 16, 0x00, },        /* ISO DO 0-15 */
102                 .id_reg         = 0x04,
103         },
104         [TYPE_PCI1733] = {
105                 .name           = "pci1733",
106                 .nsubdevs       = 2,
107                 .sdi[1]         = { 32, 0x00, },        /* ISO DI 0-31 */
108                 .id_reg         = 0x04,
109         },
110         [TYPE_PCI1734] = {
111                 .name           = "pci1734",
112                 .nsubdevs       = 2,
113                 .sdo[1]         = { 32, 0x00, },        /* ISO DO 0-31 */
114                 .id_reg         = 0x04,
115         },
116         [TYPE_PCI1735] = {
117                 .name           = "pci1735",
118                 .nsubdevs       = 4,
119                 .sdi[0]         = { 32, 0x00, },        /* DI 0-31 */
120                 .sdo[0]         = { 32, 0x00, },        /* DO 0-31 */
121                 .id_reg         = 0x08,
122                 .timer_regbase  = 0x04,
123         },
124         [TYPE_PCI1736] = {
125                 .name           = "pci1736",
126                 .nsubdevs       = 3,
127                 .sdi[1]         = { 16, 0x00, },        /* ISO DI 0-15 */
128                 .sdo[1]         = { 16, 0x00, },        /* ISO DO 0-15 */
129                 .id_reg         = 0x04,
130         },
131         [TYPE_PCI1739] = {
132                 .name           = "pci1739",
133                 .nsubdevs       = 3,
134                 .sdio[0]        = { 2, 0x00, },         /* 8255 DIO */
135                 .id_reg         = 0x08,
136         },
137         [TYPE_PCI1750] = {
138                 .name           = "pci1750",
139                 .nsubdevs       = 2,
140                 .sdi[1]         = { 16, 0x00, },        /* ISO DI 0-15 */
141                 .sdo[1]         = { 16, 0x00, },        /* ISO DO 0-15 */
142         },
143         [TYPE_PCI1751] = {
144                 .name           = "pci1751",
145                 .nsubdevs       = 3,
146                 .sdio[0]        = { 2, 0x00, },         /* 8255 DIO */
147                 .timer_regbase  = 0x18,
148         },
149         [TYPE_PCI1752] = {
150                 .name           = "pci1752",
151                 .nsubdevs       = 3,
152                 .sdo[0]         = { 32, 0x00, },        /* DO 0-31 */
153                 .sdo[1]         = { 32, 0x04, },        /* DO 32-63 */
154                 .id_reg         = 0x10,
155                 .is_16bit       = 1,
156         },
157         [TYPE_PCI1753] = {
158                 .name           = "pci1753",
159                 .nsubdevs       = 4,
160                 .sdio[0]        = { 4, 0x00, },         /* 8255 DIO */
161         },
162         [TYPE_PCI1753E] = {
163                 .name           = "pci1753e",
164                 .nsubdevs       = 8,
165                 .sdio[0]        = { 4, 0x00, },         /* 8255 DIO */
166                 .sdio[1]        = { 4, 0x20, },         /* 8255 DIO */
167         },
168         [TYPE_PCI1754] = {
169                 .name           = "pci1754",
170                 .nsubdevs       = 3,
171                 .sdi[0]         = { 32, 0x00, },        /* DI 0-31 */
172                 .sdi[1]         = { 32, 0x04, },        /* DI 32-63 */
173                 .id_reg         = 0x10,
174                 .is_16bit       = 1,
175         },
176         [TYPE_PCI1756] = {
177                 .name           = "pci1756",
178                 .nsubdevs       = 3,
179                 .sdi[1]         = { 32, 0x00, },        /* DI 0-31 */
180                 .sdo[1]         = { 32, 0x04, },        /* DO 0-31 */
181                 .id_reg         = 0x10,
182                 .is_16bit       = 1,
183         },
184         [TYPE_PCI1762] = {
185                 .name           = "pci1762",
186                 .nsubdevs       = 3,
187                 .sdi[1]         = { 16, 0x02, },        /* ISO DI 0-15 */
188                 .sdo[1]         = { 16, 0x00, },        /* ISO DO 0-15 */
189                 .id_reg         = 0x04,
190                 .is_16bit       = 1,
191         },
192 };
193 
194 static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
195                                   struct comedi_subdevice *s,
196                                   struct comedi_insn *insn,
197                                   unsigned int *data)
198 {
199         unsigned long reg = (unsigned long)s->private;
200         unsigned long iobase = dev->iobase + reg;
201 
202         data[1] = inb(iobase);
203         if (s->n_chan > 8)
204                 data[1] |= (inb(iobase + 1) << 8);
205         if (s->n_chan > 16)
206                 data[1] |= (inb(iobase + 2) << 16);
207         if (s->n_chan > 24)
208                 data[1] |= (inb(iobase + 3) << 24);
209 
210         return insn->n;
211 }
212 
213 static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
214                                   struct comedi_subdevice *s,
215                                   struct comedi_insn *insn,
216                                   unsigned int *data)
217 {
218         unsigned long reg = (unsigned long)s->private;
219         unsigned long iobase = dev->iobase + reg;
220 
221         data[1] = inw(iobase);
222         if (s->n_chan > 16)
223                 data[1] |= (inw(iobase + 2) << 16);
224 
225         return insn->n;
226 }
227 
228 static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
229                                   struct comedi_subdevice *s,
230                                   struct comedi_insn *insn,
231                                   unsigned int *data)
232 {
233         unsigned long reg = (unsigned long)s->private;
234         unsigned long iobase = dev->iobase + reg;
235 
236         if (comedi_dio_update_state(s, data)) {
237                 outb(s->state & 0xff, iobase);
238                 if (s->n_chan > 8)
239                         outb((s->state >> 8) & 0xff, iobase + 1);
240                 if (s->n_chan > 16)
241                         outb((s->state >> 16) & 0xff, iobase + 2);
242                 if (s->n_chan > 24)
243                         outb((s->state >> 24) & 0xff, iobase + 3);
244         }
245 
246         data[1] = s->state;
247 
248         return insn->n;
249 }
250 
251 static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
252                                   struct comedi_subdevice *s,
253                                   struct comedi_insn *insn,
254                                   unsigned int *data)
255 {
256         unsigned long reg = (unsigned long)s->private;
257         unsigned long iobase = dev->iobase + reg;
258 
259         if (comedi_dio_update_state(s, data)) {
260                 outw(s->state & 0xffff, iobase);
261                 if (s->n_chan > 16)
262                         outw((s->state >> 16) & 0xffff, iobase + 2);
263         }
264 
265         data[1] = s->state;
266 
267         return insn->n;
268 }
269 
270 static int pci_dio_reset(struct comedi_device *dev, unsigned long cardtype)
271 {
272         /* disable channel freeze function on the PCI-1752/1756 boards */
273         if (cardtype == TYPE_PCI1752 || cardtype == TYPE_PCI1756)
274                 outw(0, dev->iobase + PCI1752_CFC_REG);
275 
276         /* disable and clear interrupts */
277         switch (cardtype) {
278         case TYPE_PCI1730:
279         case TYPE_PCI1733:
280         case TYPE_PCI1736:
281                 outb(0, dev->iobase + PCI173X_INT_EN_REG);
282                 outb(0x0f, dev->iobase + PCI173X_INT_CLR_REG);
283                 outb(0, dev->iobase + PCI173X_INT_RF_REG);
284                 break;
285         case TYPE_PCI1739:
286         case TYPE_PCI1750:
287         case TYPE_PCI1751:
288                 outb(0x88, dev->iobase + PCI1750_INT_REG);
289                 break;
290         case TYPE_PCI1753:
291         case TYPE_PCI1753E:
292                 outb(0x88, dev->iobase + PCI1753_INT_REG(0));
293                 outb(0x80, dev->iobase + PCI1753_INT_REG(1));
294                 outb(0x80, dev->iobase + PCI1753_INT_REG(2));
295                 outb(0x80, dev->iobase + PCI1753_INT_REG(3));
296                 if (cardtype == TYPE_PCI1753E) {
297                         outb(0x88, dev->iobase + PCI1753E_INT_REG(0));
298                         outb(0x80, dev->iobase + PCI1753E_INT_REG(1));
299                         outb(0x80, dev->iobase + PCI1753E_INT_REG(2));
300                         outb(0x80, dev->iobase + PCI1753E_INT_REG(3));
301                 }
302                 break;
303         case TYPE_PCI1754:
304         case TYPE_PCI1756:
305                 outw(0x08, dev->iobase + PCI1754_INT_REG(0));
306                 outw(0x08, dev->iobase + PCI1754_INT_REG(1));
307                 if (cardtype == TYPE_PCI1754) {
308                         outw(0x08, dev->iobase + PCI1754_INT_REG(2));
309                         outw(0x08, dev->iobase + PCI1754_INT_REG(3));
310                 }
311                 break;
312         case TYPE_PCI1762:
313                 outw(0x0101, dev->iobase + PCI1762_INT_REG);
314                 break;
315         default:
316                 break;
317         }
318 
319         return 0;
320 }
321 
322 static int pci_dio_auto_attach(struct comedi_device *dev,
323                                unsigned long context)
324 {
325         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
326         const struct dio_boardtype *board = NULL;
327         const struct diosubd_data *d;
328         struct comedi_subdevice *s;
329         int ret, subdev, i, j;
330 
331         if (context < ARRAY_SIZE(boardtypes))
332                 board = &boardtypes[context];
333         if (!board)
334                 return -ENODEV;
335         dev->board_ptr = board;
336         dev->board_name = board->name;
337 
338         ret = comedi_pci_enable(dev);
339         if (ret)
340                 return ret;
341         if (context == TYPE_PCI1736)
342                 dev->iobase = pci_resource_start(pcidev, 0);
343         else
344                 dev->iobase = pci_resource_start(pcidev, 2);
345 
346         pci_dio_reset(dev, context);
347 
348         ret = comedi_alloc_subdevices(dev, board->nsubdevs);
349         if (ret)
350                 return ret;
351 
352         subdev = 0;
353         for (i = 0; i < PCI_DIO_MAX_DI_SUBDEVS; i++) {
354                 d = &board->sdi[i];
355                 if (d->chans) {
356                         s = &dev->subdevices[subdev++];
357                         s->type         = COMEDI_SUBD_DI;
358                         s->subdev_flags = SDF_READABLE;
359                         s->n_chan       = d->chans;
360                         s->maxdata      = 1;
361                         s->range_table  = &range_digital;
362                         s->insn_bits    = board->is_16bit
363                                                 ? pci_dio_insn_bits_di_w
364                                                 : pci_dio_insn_bits_di_b;
365                         s->private      = (void *)d->addr;
366                 }
367         }
368 
369         for (i = 0; i < PCI_DIO_MAX_DO_SUBDEVS; i++) {
370                 d = &board->sdo[i];
371                 if (d->chans) {
372                         s = &dev->subdevices[subdev++];
373                         s->type         = COMEDI_SUBD_DO;
374                         s->subdev_flags = SDF_WRITABLE;
375                         s->n_chan       = d->chans;
376                         s->maxdata      = 1;
377                         s->range_table  = &range_digital;
378                         s->insn_bits    = board->is_16bit
379                                                 ? pci_dio_insn_bits_do_w
380                                                 : pci_dio_insn_bits_do_b;
381                         s->private      = (void *)d->addr;
382 
383                         /* reset all outputs to 0 */
384                         if (board->is_16bit) {
385                                 outw(0, dev->iobase + d->addr);
386                                 if (s->n_chan > 16)
387                                         outw(0, dev->iobase + d->addr + 2);
388                         } else {
389                                 outb(0, dev->iobase + d->addr);
390                                 if (s->n_chan > 8)
391                                         outb(0, dev->iobase + d->addr + 1);
392                                 if (s->n_chan > 16)
393                                         outb(0, dev->iobase + d->addr + 2);
394                                 if (s->n_chan > 24)
395                                         outb(0, dev->iobase + d->addr + 3);
396                         }
397                 }
398         }
399 
400         for (i = 0; i < PCI_DIO_MAX_DIO_SUBDEVG; i++) {
401                 d = &board->sdio[i];
402                 for (j = 0; j < d->chans; j++) {
403                         s = &dev->subdevices[subdev++];
404                         ret = subdev_8255_init(dev, s, NULL,
405                                                d->addr + j * I8255_SIZE);
406                         if (ret)
407                                 return ret;
408                 }
409         }
410 
411         if (board->id_reg) {
412                 s = &dev->subdevices[subdev++];
413                 s->type         = COMEDI_SUBD_DI;
414                 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
415                 s->n_chan       = 4;
416                 s->maxdata      = 1;
417                 s->range_table  = &range_digital;
418                 s->insn_bits    = board->is_16bit ? pci_dio_insn_bits_di_w
419                                                   : pci_dio_insn_bits_di_b;
420                 s->private      = (void *)board->id_reg;
421         }
422 
423         if (board->timer_regbase) {
424                 s = &dev->subdevices[subdev++];
425 
426                 dev->pacer = comedi_8254_init(dev->iobase +
427                                               board->timer_regbase,
428                                               0, I8254_IO8, 0);
429                 if (!dev->pacer)
430                         return -ENOMEM;
431 
432                 comedi_8254_subdevice_init(s, dev->pacer);
433         }
434 
435         return 0;
436 }
437 
438 static struct comedi_driver adv_pci_dio_driver = {
439         .driver_name    = "adv_pci_dio",
440         .module         = THIS_MODULE,
441         .auto_attach    = pci_dio_auto_attach,
442         .detach         = comedi_pci_detach,
443 };
444 
445 static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
446                                                unsigned long cardtype)
447 {
448         /*
449          * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
450          * board available.  Need to enable PCI device and request the main
451          * registers PCI BAR temporarily to perform the test.
452          */
453         if (cardtype != TYPE_PCI1753)
454                 return cardtype;
455         if (pci_enable_device(pcidev) < 0)
456                 return cardtype;
457         if (pci_request_region(pcidev, 2, "adv_pci_dio") == 0) {
458                 /*
459                  * This test is based on Advantech's "advdaq" driver source
460                  * (which declares its module licence as "GPL" although the
461                  * driver source does not include a "COPYING" file).
462                  */
463                 unsigned long reg = pci_resource_start(pcidev, 2) + 53;
464 
465                 outb(0x05, reg);
466                 if ((inb(reg) & 0x07) == 0x02) {
467                         outb(0x02, reg);
468                         if ((inb(reg) & 0x07) == 0x05)
469                                 cardtype = TYPE_PCI1753E;
470                 }
471                 pci_release_region(pcidev, 2);
472         }
473         pci_disable_device(pcidev);
474         return cardtype;
475 }
476 
477 static int adv_pci_dio_pci_probe(struct pci_dev *dev,
478                                  const struct pci_device_id *id)
479 {
480         unsigned long cardtype;
481 
482         cardtype = pci_dio_override_cardtype(dev, id->driver_data);
483         return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype);
484 }
485 
486 static const struct pci_device_id adv_pci_dio_pci_table[] = {
487         { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 },
488         { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 },
489         { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 },
490         { PCI_VDEVICE(ADVANTECH, 0x1735), TYPE_PCI1735 },
491         { PCI_VDEVICE(ADVANTECH, 0x1736), TYPE_PCI1736 },
492         { PCI_VDEVICE(ADVANTECH, 0x1739), TYPE_PCI1739 },
493         { PCI_VDEVICE(ADVANTECH, 0x1750), TYPE_PCI1750 },
494         { PCI_VDEVICE(ADVANTECH, 0x1751), TYPE_PCI1751 },
495         { PCI_VDEVICE(ADVANTECH, 0x1752), TYPE_PCI1752 },
496         { PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 },
497         { PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 },
498         { PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 },
499         { PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 },
500         { 0 }
501 };
502 MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
503 
504 static struct pci_driver adv_pci_dio_pci_driver = {
505         .name           = "adv_pci_dio",
506         .id_table       = adv_pci_dio_pci_table,
507         .probe          = adv_pci_dio_pci_probe,
508         .remove         = comedi_pci_auto_unconfig,
509 };
510 module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
511 
512 MODULE_AUTHOR("Comedi http://www.comedi.org");
513 MODULE_DESCRIPTION("Comedi driver for Advantech Digital I/O Cards");
514 MODULE_LICENSE("GPL");
515 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us