Staging: comedi: Give the addi_apci_* drivers different driver names
[safe/jmp/linux-2.6] / drivers / staging / comedi / drivers / adl_pci8164.c
1 /*
2     comedi/drivers/adl_pci8164.c
3
4     Hardware comedi driver fot PCI-8164 Adlink card
5     Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22 /*
23 Driver: adl_pci8164
24 Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
25 Devices: [ADLink] PCI-8164 (adl_pci8164)
26 Author: Michel Lachaine <mike@mikelachaine.ca>
27 Status: experimental
28 Updated: Mon, 14 Apr 2008 15:10:32 +0100
29
30 Configuration Options:
31   [0] - PCI bus of device (optional)
32   [1] - PCI slot of device (optional)
33   If bus/slot is not specified, the first supported
34   PCI device found will be used.
35 */
36
37 #include "../comedidev.h"
38 #include <linux/kernel.h>
39 #include <linux/delay.h>
40 #include "comedi_fc.h"
41 #include "comedi_pci.h"
42 #include "8253.h"
43
44 #define PCI8164_AXIS_X  0x00
45 #define PCI8164_AXIS_Y  0x08
46 #define PCI8164_AXIS_Z  0x10
47 #define PCI8164_AXIS_U  0x18
48
49 #define PCI8164_MSTS    0x00
50 #define PCI8164_SSTS    0x02
51 #define PCI8164_BUF0    0x04
52 #define PCI8164_BUF1    0x06
53
54 #define PCI8164_CMD     0x00
55 #define PCI8164_OTP     0x02
56
57 #define PCI_DEVICE_ID_PCI8164 0x8164
58
59 static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
60         {
61         PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164, PCI_ANY_ID,
62                     PCI_ANY_ID, 0, 0, 0}, {
63         0}
64 };
65
66 MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
67
68 struct adl_pci8164_private {
69         int data;
70         struct pci_dev *pci_dev;
71 };
72
73 #define devpriv ((struct adl_pci8164_private *)dev->private)
74
75 static int adl_pci8164_attach(struct comedi_device *dev,
76                               struct comedi_devconfig *it);
77 static int adl_pci8164_detach(struct comedi_device *dev);
78 static struct comedi_driver driver_adl_pci8164 = {
79         .driver_name = "adl_pci8164",
80         .module = THIS_MODULE,
81         .attach = adl_pci8164_attach,
82         .detach = adl_pci8164_detach,
83 };
84
85 static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
86                                       struct comedi_subdevice *s,
87                                       struct comedi_insn *insn,
88                                       unsigned int *data);
89
90 static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
91                                       struct comedi_subdevice *s,
92                                       struct comedi_insn *insn,
93                                       unsigned int *data);
94
95 static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
96                                       struct comedi_subdevice *s,
97                                       struct comedi_insn *insn,
98                                       unsigned int *data);
99
100 static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
101                                       struct comedi_subdevice *s,
102                                       struct comedi_insn *insn,
103                                       unsigned int *data);
104
105 static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
106                                       struct comedi_subdevice *s,
107                                       struct comedi_insn *insn,
108                                       unsigned int *data);
109
110 static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
111                                       struct comedi_subdevice *s,
112                                       struct comedi_insn *insn,
113                                       unsigned int *data);
114
115 static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
116                                        struct comedi_subdevice *s,
117                                        struct comedi_insn *insn,
118                                        unsigned int *data);
119
120 static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
121                                        struct comedi_subdevice *s,
122                                        struct comedi_insn *insn,
123                                        unsigned int *data);
124
125 static int adl_pci8164_attach(struct comedi_device *dev,
126                               struct comedi_devconfig *it)
127 {
128         struct pci_dev *pcidev;
129         struct comedi_subdevice *s;
130         int bus, slot;
131
132         printk(KERN_INFO "comedi: attempt to attach...\n");
133         printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
134
135         dev->board_name = "pci8164";
136         bus = it->options[0];
137         slot = it->options[1];
138
139         if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
140                 return -ENOMEM;
141
142         if (alloc_subdevices(dev, 4) < 0)
143                 return -ENOMEM;
144
145         for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
146              pcidev != NULL;
147              pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
148
149                 if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
150                     pcidev->device == PCI_DEVICE_ID_PCI8164) {
151                         if (bus || slot) {
152                                 /* requested particular bus/slot */
153                                 if (pcidev->bus->number != bus
154                                         || PCI_SLOT(pcidev->devfn) != slot)
155                                         continue;
156                         }
157                         devpriv->pci_dev = pcidev;
158                         if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
159                                 printk(KERN_ERR "comedi%d: Failed to enable "
160                                 "PCI device and request regions\n", dev->minor);
161                                 return -EIO;
162                         }
163                         dev->iobase = pci_resource_start(pcidev, 2);
164                         printk(KERN_DEBUG "comedi: base addr %4lx\n",
165                                    dev->iobase);
166
167                         s = dev->subdevices + 0;
168                         s->type = COMEDI_SUBD_PROC;
169                         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
170                         s->n_chan = 4;
171                         s->maxdata = 0xffff;
172                         s->len_chanlist = 4;
173                         /* s->range_table = &range_axis; */
174                         s->insn_read = adl_pci8164_insn_read_msts;
175                         s->insn_write = adl_pci8164_insn_write_cmd;
176
177                         s = dev->subdevices + 1;
178                         s->type = COMEDI_SUBD_PROC;
179                         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
180                         s->n_chan = 4;
181                         s->maxdata = 0xffff;
182                         s->len_chanlist = 4;
183                         /* s->range_table = &range_axis; */
184                         s->insn_read = adl_pci8164_insn_read_ssts;
185                         s->insn_write = adl_pci8164_insn_write_otp;
186
187                         s = dev->subdevices + 2;
188                         s->type = COMEDI_SUBD_PROC;
189                         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
190                         s->n_chan = 4;
191                         s->maxdata = 0xffff;
192                         s->len_chanlist = 4;
193                         /* s->range_table = &range_axis; */
194                         s->insn_read = adl_pci8164_insn_read_buf0;
195                         s->insn_write = adl_pci8164_insn_write_buf0;
196
197                         s = dev->subdevices + 3;
198                         s->type = COMEDI_SUBD_PROC;
199                         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
200                         s->n_chan = 4;
201                         s->maxdata = 0xffff;
202                         s->len_chanlist = 4;
203                         /* s->range_table = &range_axis; */
204                         s->insn_read = adl_pci8164_insn_read_buf1;
205                         s->insn_write = adl_pci8164_insn_write_buf1;
206
207                         printk(KERN_INFO "comedi: attached\n");
208
209                         return 1;
210                 }
211         }
212
213         printk(KERN_ERR "comedi%d: no supported board found!"
214                    "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
215         return -EIO;
216 }
217
218 static int adl_pci8164_detach(struct comedi_device *dev)
219 {
220         printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor);
221
222         if (devpriv && devpriv->pci_dev) {
223                 if (dev->iobase)
224                         comedi_pci_disable(devpriv->pci_dev);
225                 pci_dev_put(devpriv->pci_dev);
226         }
227
228         return 0;
229 }
230
231 /*
232  all the read commands are the same except for the addition a constant
233  * const to the data for inw()
234  */
235 static void adl_pci8164_insn_read(struct comedi_device *dev,
236                                   struct comedi_subdevice *s,
237                                   struct comedi_insn *insn,
238                                   unsigned int *data,
239                                   char *action, unsigned short offset)
240 {
241         int axis, axis_reg;
242         char *axisname;
243
244         axis = CR_CHAN(insn->chanspec);
245
246         switch (axis) {
247         case 0:
248                 axis_reg = PCI8164_AXIS_X;
249                 axisname = "X";
250                 break;
251         case 1:
252                 axis_reg = PCI8164_AXIS_Y;
253                 axisname = "Y";
254                 break;
255         case 2:
256                 axis_reg = PCI8164_AXIS_Z;
257                 axisname = "Z";
258                 break;
259         case 3:
260                 axis_reg = PCI8164_AXIS_U;
261                 axisname = "U";
262                 break;
263         default:
264                 axis_reg = PCI8164_AXIS_X;
265                 axisname = "X";
266         }
267
268         data[0] = inw(dev->iobase + axis_reg + offset);
269         printk(KERN_DEBUG "comedi: pci8164 %s read -> "
270                                                   "%04X:%04X on axis %s\n",
271                                 action, data[0], data[1], axisname);
272 }
273
274 static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
275                                       struct comedi_subdevice *s,
276                                       struct comedi_insn *insn,
277                                       unsigned int *data)
278 {
279         adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS);
280         return 2;
281 }
282
283 static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
284                                       struct comedi_subdevice *s,
285                                       struct comedi_insn *insn,
286                                       unsigned int *data)
287 {
288         adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS);
289         return 2;
290 }
291
292 static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
293                                       struct comedi_subdevice *s,
294                                       struct comedi_insn *insn,
295                                       unsigned int *data)
296 {
297         adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0);
298         return 2;
299 }
300
301 static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
302                                       struct comedi_subdevice *s,
303                                       struct comedi_insn *insn,
304                                       unsigned int *data)
305 {
306         adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1);
307         return 2;
308 }
309
310 /*
311  all the write commands are the same except for the addition a constant
312  * const to the data for outw()
313  */
314 static void adl_pci8164_insn_out(struct comedi_device *dev,
315                                  struct comedi_subdevice *s,
316                                  struct comedi_insn *insn,
317                                  unsigned int *data,
318                                  char *action, unsigned short offset)
319 {
320         unsigned int axis, axis_reg;
321
322         char *axisname;
323
324         axis = CR_CHAN(insn->chanspec);
325
326         switch (axis) {
327         case 0:
328                 axis_reg = PCI8164_AXIS_X;
329                 axisname = "X";
330                 break;
331         case 1:
332                 axis_reg = PCI8164_AXIS_Y;
333                 axisname = "Y";
334                 break;
335         case 2:
336                 axis_reg = PCI8164_AXIS_Z;
337                 axisname = "Z";
338                 break;
339         case 3:
340                 axis_reg = PCI8164_AXIS_U;
341                 axisname = "U";
342                 break;
343         default:
344                 axis_reg = PCI8164_AXIS_X;
345                 axisname = "X";
346         }
347
348         outw(data[0], dev->iobase + axis_reg + offset);
349
350         printk(KERN_DEBUG "comedi: pci8164 %s write -> "
351                                                 "%04X:%04X on axis %s\n",
352                                 action, data[0], data[1], axisname);
353
354 }
355
356 static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
357                                       struct comedi_subdevice *s,
358                                       struct comedi_insn *insn,
359                                       unsigned int *data)
360 {
361         adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD);
362         return 2;
363 }
364
365 static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
366                                       struct comedi_subdevice *s,
367                                       struct comedi_insn *insn,
368                                       unsigned int *data)
369 {
370         adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP);
371         return 2;
372 }
373
374 static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
375                                        struct comedi_subdevice *s,
376                                        struct comedi_insn *insn,
377                                        unsigned int *data)
378 {
379         adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0);
380         return 2;
381 }
382
383 static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
384                                        struct comedi_subdevice *s,
385                                        struct comedi_insn *insn,
386                                        unsigned int *data)
387 {
388         adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1);
389         return 2;
390 }
391
392 COMEDI_PCI_INITCLEANUP(driver_adl_pci8164, adl_pci8164_pci_table);