Staging: comedi: fix "foo * bar" should be "foo *bar"
[pandora-kernel.git] / drivers / staging / comedi / drivers / amplc_pc236.c
1 /*
2     comedi/drivers/amplc_pc236.c
3     Driver for Amplicon PC36AT and PCI236 DIO boards.
4
5     Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/>
6
7     COMEDI - Linux Control and Measurement Device Interface
8     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25 /*
26 Driver: amplc_pc236
27 Description: Amplicon PC36AT, PCI236
28 Author: Ian Abbott <abbotti@mev.co.uk>
29 Devices: [Amplicon] PC36AT (pc36at), PCI236 (pci236 or amplc_pc236)
30 Updated: Wed, 01 Apr 2009 15:41:25 +0100
31 Status: works
32
33 Configuration options - PC36AT:
34   [0] - I/O port base address
35   [1] - IRQ (optional)
36
37 Configuration options - PCI236:
38   [0] - PCI bus of device (optional)
39   [1] - PCI slot of device (optional)
40   If bus/slot is not specified, the first available PCI device will be
41   used.
42
43 The PC36AT ISA board and PCI236 PCI board have a single 8255 appearing
44 as subdevice 0.
45
46 Subdevice 1 pretends to be a digital input device, but it always returns
47 0 when read. However, if you run a command with scan_begin_src=TRIG_EXT,
48 a rising edge on port C bit 3 acts as an external trigger, which can be
49 used to wake up tasks.  This is like the comedi_parport device, but the
50 only way to physically disable the interrupt on the PC36AT is to remove
51 the IRQ jumper.  If no interrupt is connected, then subdevice 1 is
52 unused.
53 */
54
55 #include <linux/interrupt.h>
56
57 #include "../comedidev.h"
58
59 #include "comedi_pci.h"
60
61 #include "8255.h"
62 #include "plx9052.h"
63
64 #define PC236_DRIVER_NAME       "amplc_pc236"
65
66 /* PCI236 PCI configuration register information */
67 #define PCI_VENDOR_ID_AMPLICON 0x14dc
68 #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
69 #define PCI_DEVICE_ID_INVALID 0xffff
70
71 /* PC36AT / PCI236 registers */
72
73 #define PC236_IO_SIZE           4
74 #define PC236_LCR_IO_SIZE       128
75
76 /*
77  * INTCSR values for PCI236.
78  */
79 /* Disable interrupt, also clear any interrupt there */
80 #define PCI236_INTR_DISABLE ( PLX9052_INTCSR_LI1ENAB_DISABLED \
81         | PLX9052_INTCSR_LI1POL_HIGH \
82         | PLX9052_INTCSR_LI2POL_HIGH \
83         | PLX9052_INTCSR_PCIENAB_DISABLED \
84         | PLX9052_INTCSR_LI1SEL_EDGE \
85         | PLX9052_INTCSR_LI1CLRINT_ASSERTED )
86 /* Enable interrupt, also clear any interrupt there. */
87 #define PCI236_INTR_ENABLE ( PLX9052_INTCSR_LI1ENAB_ENABLED \
88         | PLX9052_INTCSR_LI1POL_HIGH \
89         | PLX9052_INTCSR_LI2POL_HIGH \
90         | PLX9052_INTCSR_PCIENAB_ENABLED \
91         | PLX9052_INTCSR_LI1SEL_EDGE \
92         | PLX9052_INTCSR_LI1CLRINT_ASSERTED )
93
94 /*
95  * Board descriptions for Amplicon PC36AT and PCI236.
96  */
97
98 enum pc236_bustype { isa_bustype, pci_bustype };
99 enum pc236_model { pc36at_model, pci236_model, anypci_model };
100
101 struct pc236_board {
102         const char *name;
103         const char *fancy_name;
104         unsigned short devid;
105         enum pc236_bustype bustype;
106         enum pc236_model model;
107 };
108 static const struct pc236_board pc236_boards[] = {
109         {
110               name:     "pc36at",
111               fancy_name:"PC36AT",
112               bustype:  isa_bustype,
113               model:    pc36at_model,
114                 },
115 #ifdef CONFIG_COMEDI_PCI
116         {
117               name:     "pci236",
118               fancy_name:"PCI236",
119               devid:    PCI_DEVICE_ID_AMPLICON_PCI236,
120               bustype:  pci_bustype,
121               model:    pci236_model,
122                 },
123 #endif
124 #ifdef CONFIG_COMEDI_PCI
125         {
126               name:     PC236_DRIVER_NAME,
127               fancy_name:PC236_DRIVER_NAME,
128               devid:    PCI_DEVICE_ID_INVALID,
129               bustype:  pci_bustype,
130               model:    anypci_model,   /* wildcard */
131                 },
132 #endif
133 };
134
135 #ifdef CONFIG_COMEDI_PCI
136 static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
137         {PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236, PCI_ANY_ID,
138                 PCI_ANY_ID, 0, 0, 0},
139         {0}
140 };
141
142 MODULE_DEVICE_TABLE(pci, pc236_pci_table);
143 #endif /* CONFIG_COMEDI_PCI */
144
145 /*
146  * Useful for shorthand access to the particular board structure
147  */
148 #define thisboard ((const struct pc236_board *)dev->board_ptr)
149
150 /* this structure is for data unique to this hardware driver.  If
151    several hardware drivers keep similar information in this structure,
152    feel free to suggest moving the variable to the struct comedi_device struct.  */
153 struct pc236_private {
154 #ifdef CONFIG_COMEDI_PCI
155         /* PCI device */
156         struct pci_dev *pci_dev;
157         unsigned long lcr_iobase;       /* PLX PCI9052 config registers in PCIBAR1 */
158 #endif
159         int enable_irq;
160 };
161
162 #define devpriv ((struct pc236_private *)dev->private)
163
164 /*
165  * The struct comedi_driver structure tells the Comedi core module
166  * which functions to call to configure/deconfigure (attach/detach)
167  * the board, and also about the kernel module that contains
168  * the device code.
169  */
170 static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it);
171 static int pc236_detach(struct comedi_device *dev);
172 static struct comedi_driver driver_amplc_pc236 = {
173       driver_name:PC236_DRIVER_NAME,
174       module:THIS_MODULE,
175       attach:pc236_attach,
176       detach:pc236_detach,
177       board_name:&pc236_boards[0].name,
178       offset:sizeof(struct pc236_board),
179       num_names:sizeof(pc236_boards) / sizeof(struct pc236_board),
180 };
181
182 #ifdef CONFIG_COMEDI_PCI
183 COMEDI_PCI_INITCLEANUP(driver_amplc_pc236, pc236_pci_table);
184 #else
185 COMEDI_INITCLEANUP(driver_amplc_pc236);
186 #endif
187
188 static int pc236_request_region(unsigned minor, unsigned long from,
189         unsigned long extent);
190 static void pc236_intr_disable(struct comedi_device * dev);
191 static void pc236_intr_enable(struct comedi_device * dev);
192 static int pc236_intr_check(struct comedi_device * dev);
193 static int pc236_intr_insn(struct comedi_device * dev, struct comedi_subdevice * s,
194         struct comedi_insn * insn, unsigned int * data);
195 static int pc236_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
196         struct comedi_cmd * cmd);
197 static int pc236_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s);
198 static int pc236_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
199 static irqreturn_t pc236_interrupt(int irq, void *d);
200
201 /*
202  * This function looks for a PCI device matching the requested board name,
203  * bus and slot.
204  */
205 #ifdef CONFIG_COMEDI_PCI
206 static int
207 pc236_find_pci(struct comedi_device *dev, int bus, int slot,
208         struct pci_dev **pci_dev_p)
209 {
210         struct pci_dev *pci_dev = NULL;
211
212         *pci_dev_p = NULL;
213
214         /* Look for matching PCI device. */
215         for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
216                 pci_dev != NULL;
217                 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
218                         PCI_ANY_ID, pci_dev)) {
219                 /* If bus/slot specified, check them. */
220                 if (bus || slot) {
221                         if (bus != pci_dev->bus->number
222                                 || slot != PCI_SLOT(pci_dev->devfn))
223                                 continue;
224                 }
225                 if (thisboard->model == anypci_model) {
226                         /* Match any supported model. */
227                         int i;
228
229                         for (i = 0; i < ARRAY_SIZE(pc236_boards); i++) {
230                                 if (pc236_boards[i].bustype != pci_bustype)
231                                         continue;
232                                 if (pci_dev->device == pc236_boards[i].devid) {
233                                         /* Change board_ptr to matched board. */
234                                         dev->board_ptr = &pc236_boards[i];
235                                         break;
236                                 }
237                         }
238                         if (i == ARRAY_SIZE(pc236_boards))
239                                 continue;
240                 } else {
241                         /* Match specific model name. */
242                         if (pci_dev->device != thisboard->devid)
243                                 continue;
244                 }
245
246                 /* Found a match. */
247                 *pci_dev_p = pci_dev;
248                 return 0;
249         }
250         /* No match found. */
251         if (bus || slot) {
252                 printk(KERN_ERR
253                         "comedi%d: error! no %s found at pci %02x:%02x!\n",
254                         dev->minor, thisboard->name, bus, slot);
255         } else {
256                 printk(KERN_ERR "comedi%d: error! no %s found!\n",
257                         dev->minor, thisboard->name);
258         }
259         return -EIO;
260 }
261 #endif
262
263 /*
264  * Attach is called by the Comedi core to configure the driver
265  * for a particular board.  If you specified a board_name array
266  * in the driver structure, dev->board_ptr contains that
267  * address.
268  */
269 static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
270 {
271         struct comedi_subdevice *s;
272         unsigned long iobase = 0;
273         unsigned int irq = 0;
274 #ifdef CONFIG_COMEDI_PCI
275         struct pci_dev *pci_dev = NULL;
276         int bus = 0, slot = 0;
277 #endif
278         int share_irq = 0;
279         int ret;
280
281         printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor,
282                 PC236_DRIVER_NAME);
283 /*
284  * Allocate the private structure area.  alloc_private() is a
285  * convenient macro defined in comedidev.h.
286  */
287         if ((ret = alloc_private(dev, sizeof(struct pc236_private))) < 0) {
288                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
289                         dev->minor);
290                 return ret;
291         }
292         /* Process options. */
293         switch (thisboard->bustype) {
294         case isa_bustype:
295                 iobase = it->options[0];
296                 irq = it->options[1];
297                 share_irq = 0;
298                 break;
299 #ifdef CONFIG_COMEDI_PCI
300         case pci_bustype:
301                 bus = it->options[0];
302                 slot = it->options[1];
303                 share_irq = 1;
304
305                 if ((ret = pc236_find_pci(dev, bus, slot, &pci_dev)) < 0)
306                         return ret;
307                 devpriv->pci_dev = pci_dev;
308                 break;
309 #endif /* CONFIG_COMEDI_PCI */
310         default:
311                 printk(KERN_ERR
312                         "comedi%d: %s: BUG! cannot determine board type!\n",
313                         dev->minor, PC236_DRIVER_NAME);
314                 return -EINVAL;
315                 break;
316         }
317
318 /*
319  * Initialize dev->board_name.
320  */
321         dev->board_name = thisboard->name;
322
323         /* Enable device and reserve I/O spaces. */
324 #ifdef CONFIG_COMEDI_PCI
325         if (pci_dev) {
326                 if ((ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME)) < 0) {
327                         printk(KERN_ERR
328                                 "comedi%d: error! cannot enable PCI device and request regions!\n",
329                                 dev->minor);
330                         return ret;
331                 }
332                 devpriv->lcr_iobase = pci_resource_start(pci_dev, 1);
333                 iobase = pci_resource_start(pci_dev, 2);
334                 irq = pci_dev->irq;
335         } else
336 #endif
337         {
338                 ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE);
339                 if (ret < 0) {
340                         return ret;
341                 }
342         }
343         dev->iobase = iobase;
344
345 /*
346  * Allocate the subdevice structures.  alloc_subdevice() is a
347  * convenient macro defined in comedidev.h.
348  */
349         if ((ret = alloc_subdevices(dev, 2)) < 0) {
350                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
351                         dev->minor);
352                 return ret;
353         }
354
355         s = dev->subdevices + 0;
356         /* digital i/o subdevice (8255) */
357         if ((ret = subdev_8255_init(dev, s, NULL, iobase)) < 0) {
358                 printk(KERN_ERR "comedi%d: error! out of memory!\n",
359                         dev->minor);
360                 return ret;
361         }
362         s = dev->subdevices + 1;
363         dev->read_subdev = s;
364         s->type = COMEDI_SUBD_UNUSED;
365         pc236_intr_disable(dev);
366         if (irq) {
367                 unsigned long flags = share_irq ? IRQF_SHARED : 0;
368
369                 if (comedi_request_irq(irq, pc236_interrupt, flags,
370                                 PC236_DRIVER_NAME, dev) >= 0) {
371                         dev->irq = irq;
372                         s->type = COMEDI_SUBD_DI;
373                         s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
374                         s->n_chan = 1;
375                         s->maxdata = 1;
376                         s->range_table = &range_digital;
377                         s->insn_bits = pc236_intr_insn;
378                         s->do_cmdtest = pc236_intr_cmdtest;
379                         s->do_cmd = pc236_intr_cmd;
380                         s->cancel = pc236_intr_cancel;
381                 }
382         }
383         printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
384         if (thisboard->bustype == isa_bustype) {
385                 printk("(base %#lx) ", iobase);
386         } else {
387 #ifdef CONFIG_COMEDI_PCI
388                 printk("(pci %s) ", pci_name(pci_dev));
389 #endif
390         }
391         if (irq) {
392                 printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
393         } else {
394                 printk("(no irq) ");
395         }
396
397         printk("attached\n");
398
399         return 1;
400 }
401
402 /*
403  * _detach is called to deconfigure a device.  It should deallocate
404  * resources.
405  * This function is also called when _attach() fails, so it should be
406  * careful not to release resources that were not necessarily
407  * allocated by _attach().  dev->private and dev->subdevices are
408  * deallocated automatically by the core.
409  */
410 static int pc236_detach(struct comedi_device *dev)
411 {
412         printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
413                 PC236_DRIVER_NAME);
414         if (devpriv) {
415                 pc236_intr_disable(dev);
416         }
417         if (dev->irq)
418                 comedi_free_irq(dev->irq, dev);
419         if (dev->subdevices) {
420                 subdev_8255_cleanup(dev, dev->subdevices + 0);
421         }
422         if (devpriv) {
423 #ifdef CONFIG_COMEDI_PCI
424                 if (devpriv->pci_dev) {
425                         if (dev->iobase) {
426                                 comedi_pci_disable(devpriv->pci_dev);
427                         }
428                         pci_dev_put(devpriv->pci_dev);
429                 } else
430 #endif
431                 {
432                         if (dev->iobase) {
433                                 release_region(dev->iobase, PC236_IO_SIZE);
434                         }
435                 }
436         }
437         if (dev->board_name) {
438                 printk(KERN_INFO "comedi%d: %s removed\n",
439                         dev->minor, dev->board_name);
440         }
441         return 0;
442 }
443
444 /*
445  * This function checks and requests an I/O region, reporting an error
446  * if there is a conflict.
447  */
448 static int pc236_request_region(unsigned minor, unsigned long from,
449         unsigned long extent)
450 {
451         if (!from || !request_region(from, extent, PC236_DRIVER_NAME)) {
452                 printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n",
453                         minor, from, extent);
454                 return -EIO;
455         }
456         return 0;
457 }
458
459 /*
460  * This function is called to mark the interrupt as disabled (no command
461  * configured on subdevice 1) and to physically disable the interrupt
462  * (not possible on the PC36AT, except by removing the IRQ jumper!).
463  */
464 static void pc236_intr_disable(struct comedi_device *dev)
465 {
466         unsigned long flags;
467
468         comedi_spin_lock_irqsave(&dev->spinlock, flags);
469         devpriv->enable_irq = 0;
470 #ifdef CONFIG_COMEDI_PCI
471         if (devpriv->lcr_iobase)
472                 outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
473 #endif
474         comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
475 }
476
477 /*
478  * This function is called to mark the interrupt as enabled (a command
479  * configured on subdevice 1) and to physically enable the interrupt
480  * (not possible on the PC36AT, except by (re)connecting the IRQ jumper!).
481  */
482 static void pc236_intr_enable(struct comedi_device *dev)
483 {
484         unsigned long flags;
485
486         comedi_spin_lock_irqsave(&dev->spinlock, flags);
487         devpriv->enable_irq = 1;
488 #ifdef CONFIG_COMEDI_PCI
489         if (devpriv->lcr_iobase)
490                 outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
491 #endif
492         comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
493 }
494
495 /*
496  * This function is called when an interrupt occurs to check whether
497  * the interrupt has been marked as enabled and was generated by the
498  * board.  If so, the function prepares the hardware for the next
499  * interrupt.
500  * Returns 0 if the interrupt should be ignored.
501  */
502 static int pc236_intr_check(struct comedi_device *dev)
503 {
504         int retval = 0;
505         unsigned long flags;
506
507         comedi_spin_lock_irqsave(&dev->spinlock, flags);
508         if (devpriv->enable_irq) {
509                 retval = 1;
510 #ifdef CONFIG_COMEDI_PCI
511                 if (devpriv->lcr_iobase) {
512                         if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
513                                         & PLX9052_INTCSR_LI1STAT_MASK)
514                                 == PLX9052_INTCSR_LI1STAT_INACTIVE) {
515                                 retval = 0;
516                         } else {
517                                 /* Clear interrupt and keep it enabled. */
518                                 outl(PCI236_INTR_ENABLE,
519                                         devpriv->lcr_iobase + PLX9052_INTCSR);
520                         }
521                 }
522 #endif
523         }
524         comedi_spin_unlock_irqrestore(&dev->spinlock, flags);
525
526         return retval;
527 }
528
529 /*
530  * Input from subdevice 1.
531  * Copied from the comedi_parport driver.
532  */
533 static int pc236_intr_insn(struct comedi_device *dev, struct comedi_subdevice *s,
534         struct comedi_insn *insn, unsigned int *data)
535 {
536         data[1] = 0;
537         return 2;
538 }
539
540 /*
541  * Subdevice 1 command test.
542  * Copied from the comedi_parport driver.
543  */
544 static int pc236_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
545         struct comedi_cmd *cmd)
546 {
547         int err = 0;
548         int tmp;
549
550         /* step 1 */
551
552         tmp = cmd->start_src;
553         cmd->start_src &= TRIG_NOW;
554         if (!cmd->start_src || tmp != cmd->start_src)
555                 err++;
556
557         tmp = cmd->scan_begin_src;
558         cmd->scan_begin_src &= TRIG_EXT;
559         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
560                 err++;
561
562         tmp = cmd->convert_src;
563         cmd->convert_src &= TRIG_FOLLOW;
564         if (!cmd->convert_src || tmp != cmd->convert_src)
565                 err++;
566
567         tmp = cmd->scan_end_src;
568         cmd->scan_end_src &= TRIG_COUNT;
569         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
570                 err++;
571
572         tmp = cmd->stop_src;
573         cmd->stop_src &= TRIG_NONE;
574         if (!cmd->stop_src || tmp != cmd->stop_src)
575                 err++;
576
577         if (err)
578                 return 1;
579
580         /* step 2: ignored */
581
582         if (err)
583                 return 2;
584
585         /* step 3: */
586
587         if (cmd->start_arg != 0) {
588                 cmd->start_arg = 0;
589                 err++;
590         }
591         if (cmd->scan_begin_arg != 0) {
592                 cmd->scan_begin_arg = 0;
593                 err++;
594         }
595         if (cmd->convert_arg != 0) {
596                 cmd->convert_arg = 0;
597                 err++;
598         }
599         if (cmd->scan_end_arg != 1) {
600                 cmd->scan_end_arg = 1;
601                 err++;
602         }
603         if (cmd->stop_arg != 0) {
604                 cmd->stop_arg = 0;
605                 err++;
606         }
607
608         if (err)
609                 return 3;
610
611         /* step 4: ignored */
612
613         if (err)
614                 return 4;
615
616         return 0;
617 }
618
619 /*
620  * Subdevice 1 command.
621  */
622 static int pc236_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
623 {
624         pc236_intr_enable(dev);
625
626         return 0;
627 }
628
629 /*
630  * Subdevice 1 cancel command.
631  */
632 static int pc236_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
633 {
634         pc236_intr_disable(dev);
635
636         return 0;
637 }
638
639 /*
640  * Interrupt service routine.
641  * Based on the comedi_parport driver.
642  */
643 static irqreturn_t pc236_interrupt(int irq, void *d)
644 {
645         struct comedi_device *dev = d;
646         struct comedi_subdevice *s = dev->subdevices + 1;
647         int handled;
648
649         handled = pc236_intr_check(dev);
650         if (dev->attached && handled) {
651                 comedi_buf_put(s->async, 0);
652                 s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
653                 comedi_event(dev, s);
654         }
655         return IRQ_RETVAL(handled);
656 }