Staging: comedi: Give the addi_apci_* drivers different driver names
[pandora-kernel.git] / drivers / staging / comedi / drivers / ke_counter.c
1 /*
2     comedi/drivers/ke_counter.c
3     Comedi driver for Kolter-Electronic PCI Counter 1 Card
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: ke_counter
25 Description: Driver for Kolter Electronic Counter Card
26 Devices: [Kolter Electronic] PCI Counter Card (ke_counter)
27 Author: Michael Hillmann
28 Updated: Mon, 14 Apr 2008 15:42:42 +0100
29 Status: tested
30
31 Configuration Options:
32   [0] - PCI bus of device (optional)
33   [1] - PCI slot of device (optional)
34   If bus/slot is not specified, the first supported
35   PCI device found will be used.
36
37 This driver is a simple driver to read the counter values from
38 Kolter Electronic PCI Counter Card.
39 */
40
41 #include "../comedidev.h"
42
43 #include "comedi_pci.h"
44
45 #define CNT_DRIVER_NAME         "ke_counter"
46 #define PCI_VENDOR_ID_KOLTER    0x1001
47 #define CNT_CARD_DEVICE_ID      0x0014
48
49 /*-- function prototypes ----------------------------------------------------*/
50
51 static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it);
52 static int cnt_detach(struct comedi_device *dev);
53
54 static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = {
55         {
56         PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID, PCI_ANY_ID,
57                     PCI_ANY_ID, 0, 0, 0}, {
58         0}
59 };
60
61 MODULE_DEVICE_TABLE(pci, cnt_pci_table);
62
63 /*-- board specification structure ------------------------------------------*/
64
65 struct cnt_board_struct {
66
67         const char *name;
68         int device_id;
69         int cnt_channel_nbr;
70         int cnt_bits;
71 };
72
73 static const struct cnt_board_struct cnt_boards[] = {
74         {
75          .name = CNT_DRIVER_NAME,
76          .device_id = CNT_CARD_DEVICE_ID,
77          .cnt_channel_nbr = 3,
78          .cnt_bits = 24}
79 };
80
81 #define cnt_board_nbr (sizeof(cnt_boards)/sizeof(struct cnt_board_struct))
82
83 /*-- device private structure -----------------------------------------------*/
84
85 struct cnt_device_private {
86
87         struct pci_dev *pcidev;
88 };
89
90 #define devpriv ((struct cnt_device_private *)dev->private)
91
92 static struct comedi_driver cnt_driver = {
93         .driver_name = CNT_DRIVER_NAME,
94         .module = THIS_MODULE,
95         .attach = cnt_attach,
96         .detach = cnt_detach,
97 };
98
99 COMEDI_PCI_INITCLEANUP(cnt_driver, cnt_pci_table);
100
101 /*-- counter write ----------------------------------------------------------*/
102
103 /* This should be used only for resetting the counters; maybe it is better
104    to make a special command 'reset'. */
105 static int cnt_winsn(struct comedi_device *dev,
106                      struct comedi_subdevice *s, struct comedi_insn *insn,
107                      unsigned int *data)
108 {
109         int chan = CR_CHAN(insn->chanspec);
110
111         outb((unsigned char)((data[0] >> 24) & 0xff),
112              dev->iobase + chan * 0x20 + 0x10);
113         outb((unsigned char)((data[0] >> 16) & 0xff),
114              dev->iobase + chan * 0x20 + 0x0c);
115         outb((unsigned char)((data[0] >> 8) & 0xff),
116              dev->iobase + chan * 0x20 + 0x08);
117         outb((unsigned char)((data[0] >> 0) & 0xff),
118              dev->iobase + chan * 0x20 + 0x04);
119
120         /* return the number of samples written */
121         return 1;
122 }
123
124 /*-- counter read -----------------------------------------------------------*/
125
126 static int cnt_rinsn(struct comedi_device *dev,
127                      struct comedi_subdevice *s, struct comedi_insn *insn,
128                      unsigned int *data)
129 {
130         unsigned char a0, a1, a2, a3, a4;
131         int chan = CR_CHAN(insn->chanspec);
132         int result;
133
134         a0 = inb(dev->iobase + chan * 0x20);
135         a1 = inb(dev->iobase + chan * 0x20 + 0x04);
136         a2 = inb(dev->iobase + chan * 0x20 + 0x08);
137         a3 = inb(dev->iobase + chan * 0x20 + 0x0c);
138         a4 = inb(dev->iobase + chan * 0x20 + 0x10);
139
140         result = (a1 + (a2 * 256) + (a3 * 65536));
141         if (a4 > 0)
142                 result = result - s->maxdata;
143
144         *data = (unsigned int)result;
145
146         /* return the number of samples read */
147         return 1;
148 }
149
150 /*-- attach -----------------------------------------------------------------*/
151
152 static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
153 {
154         struct comedi_subdevice *subdevice;
155         struct pci_dev *pci_device;
156         struct cnt_board_struct *board;
157         unsigned long io_base;
158         int error, i;
159
160         /* allocate device private structure */
161         error = alloc_private(dev, sizeof(struct cnt_device_private));
162         if (error < 0)
163                 return error;
164
165         /* Probe the device to determine what device in the series it is. */
166         for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
167              pci_device != NULL;
168              pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_device)) {
169                 if (pci_device->vendor == PCI_VENDOR_ID_KOLTER) {
170                         for (i = 0; i < cnt_board_nbr; i++) {
171                                 if (cnt_boards[i].device_id ==
172                                     pci_device->device) {
173                                         /* was a particular bus/slot requested? */
174                                         if ((it->options[0] != 0)
175                                             || (it->options[1] != 0)) {
176                                                 /* are we on the wrong bus/slot? */
177                                                 if (pci_device->bus->number !=
178                                                     it->options[0]
179                                                     ||
180                                                     PCI_SLOT(pci_device->devfn)
181                                                     != it->options[1]) {
182                                                         continue;
183                                                 }
184                                         }
185
186                                         dev->board_ptr = cnt_boards + i;
187                                         board =
188                                             (struct cnt_board_struct *)
189                                             dev->board_ptr;
190                                         goto found;
191                                 }
192                         }
193                 }
194         }
195         printk(KERN_WARNING
196                "comedi%d: no supported board found! (req. bus/slot: %d/%d)\n",
197                dev->minor, it->options[0], it->options[1]);
198         return -EIO;
199
200 found:
201         printk(KERN_INFO
202                "comedi%d: found %s at PCI bus %d, slot %d\n", dev->minor,
203                board->name, pci_device->bus->number,
204                PCI_SLOT(pci_device->devfn));
205         devpriv->pcidev = pci_device;
206         dev->board_name = board->name;
207
208         /* enable PCI device and request regions */
209         error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME);
210         if (error < 0) {
211                 printk(KERN_WARNING "comedi%d: "
212                        "failed to enable PCI device and request regions!\n",
213                        dev->minor);
214                 return error;
215         }
216
217         /* read register base address [PCI_BASE_ADDRESS #0] */
218         io_base = pci_resource_start(pci_device, 0);
219         dev->iobase = io_base;
220
221         /* allocate the subdevice structures */
222         error = alloc_subdevices(dev, 1);
223         if (error < 0)
224                 return error;
225
226         subdevice = dev->subdevices + 0;
227         dev->read_subdev = subdevice;
228
229         subdevice->type = COMEDI_SUBD_COUNTER;
230         subdevice->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
231         subdevice->n_chan = board->cnt_channel_nbr;
232         subdevice->maxdata = (1 << board->cnt_bits) - 1;
233         subdevice->insn_read = cnt_rinsn;
234         subdevice->insn_write = cnt_winsn;
235
236         /*  select 20MHz clock */
237         outb(3, dev->iobase + 248);
238
239         /*  reset all counters */
240         outb(0, dev->iobase);
241         outb(0, dev->iobase + 0x20);
242         outb(0, dev->iobase + 0x40);
243
244         printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " attached.\n",
245                dev->minor);
246         return 0;
247 }
248
249 /*-- detach -----------------------------------------------------------------*/
250
251 static int cnt_detach(struct comedi_device *dev)
252 {
253         if (devpriv && devpriv->pcidev) {
254                 if (dev->iobase)
255                         comedi_pci_disable(devpriv->pcidev);
256                 pci_dev_put(devpriv->pcidev);
257         }
258         printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n",
259                dev->minor);
260         return 0;
261 }