]> Pileus Git - ~andy/linux/blob - drivers/staging/comedi/drivers/adl_pci8164.c
staging: comedi: conditionally build in PCI driver support
[~andy/linux] / 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: not applicable, uses PCI auto config
31 */
32
33 #include <linux/kernel.h>
34 #include <linux/pci.h>
35 #include <linux/delay.h>
36
37 #include "../comedidev.h"
38 #include "comedi_fc.h"
39 #include "8253.h"
40
41 #define PCI8164_AXIS_X  0x00
42 #define PCI8164_AXIS_Y  0x08
43 #define PCI8164_AXIS_Z  0x10
44 #define PCI8164_AXIS_U  0x18
45
46 #define PCI8164_MSTS    0x00
47 #define PCI8164_SSTS    0x02
48 #define PCI8164_BUF0    0x04
49 #define PCI8164_BUF1    0x06
50
51 #define PCI8164_CMD     0x00
52 #define PCI8164_OTP     0x02
53
54 #define PCI_DEVICE_ID_PCI8164 0x8164
55
56 /*
57  all the read commands are the same except for the addition a constant
58  * const to the data for inw()
59  */
60 static void adl_pci8164_insn_read(struct comedi_device *dev,
61                                   struct comedi_subdevice *s,
62                                   struct comedi_insn *insn,
63                                   unsigned int *data,
64                                   char *action, unsigned short offset)
65 {
66         int axis, axis_reg;
67         char axisname;
68
69         axis = CR_CHAN(insn->chanspec);
70
71         switch (axis) {
72         case 0:
73                 axis_reg = PCI8164_AXIS_X;
74                 axisname = 'X';
75                 break;
76         case 1:
77                 axis_reg = PCI8164_AXIS_Y;
78                 axisname = 'Y';
79                 break;
80         case 2:
81                 axis_reg = PCI8164_AXIS_Z;
82                 axisname = 'Z';
83                 break;
84         case 3:
85                 axis_reg = PCI8164_AXIS_U;
86                 axisname = 'U';
87                 break;
88         default:
89                 axis_reg = PCI8164_AXIS_X;
90                 axisname = 'X';
91         }
92
93         data[0] = inw(dev->iobase + axis_reg + offset);
94         dev_dbg(dev->class_dev,
95                 "pci8164 %s read -> %04X:%04X on axis %c\n",
96                 action, data[0], data[1], axisname);
97 }
98
99 static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
100                                       struct comedi_subdevice *s,
101                                       struct comedi_insn *insn,
102                                       unsigned int *data)
103 {
104         adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS);
105         return 2;
106 }
107
108 static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
109                                       struct comedi_subdevice *s,
110                                       struct comedi_insn *insn,
111                                       unsigned int *data)
112 {
113         adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS);
114         return 2;
115 }
116
117 static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
118                                       struct comedi_subdevice *s,
119                                       struct comedi_insn *insn,
120                                       unsigned int *data)
121 {
122         adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0);
123         return 2;
124 }
125
126 static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
127                                       struct comedi_subdevice *s,
128                                       struct comedi_insn *insn,
129                                       unsigned int *data)
130 {
131         adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1);
132         return 2;
133 }
134
135 /*
136  all the write commands are the same except for the addition a constant
137  * const to the data for outw()
138  */
139 static void adl_pci8164_insn_out(struct comedi_device *dev,
140                                  struct comedi_subdevice *s,
141                                  struct comedi_insn *insn,
142                                  unsigned int *data,
143                                  char *action, unsigned short offset)
144 {
145         unsigned int axis, axis_reg;
146
147         char axisname;
148
149         axis = CR_CHAN(insn->chanspec);
150
151         switch (axis) {
152         case 0:
153                 axis_reg = PCI8164_AXIS_X;
154                 axisname = 'X';
155                 break;
156         case 1:
157                 axis_reg = PCI8164_AXIS_Y;
158                 axisname = 'Y';
159                 break;
160         case 2:
161                 axis_reg = PCI8164_AXIS_Z;
162                 axisname = 'Z';
163                 break;
164         case 3:
165                 axis_reg = PCI8164_AXIS_U;
166                 axisname = 'U';
167                 break;
168         default:
169                 axis_reg = PCI8164_AXIS_X;
170                 axisname = 'X';
171         }
172
173         outw(data[0], dev->iobase + axis_reg + offset);
174
175         dev_dbg(dev->class_dev,
176                 "pci8164 %s write -> %04X:%04X on axis %c\n",
177                 action, data[0], data[1], axisname);
178
179 }
180
181 static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
182                                       struct comedi_subdevice *s,
183                                       struct comedi_insn *insn,
184                                       unsigned int *data)
185 {
186         adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD);
187         return 2;
188 }
189
190 static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
191                                       struct comedi_subdevice *s,
192                                       struct comedi_insn *insn,
193                                       unsigned int *data)
194 {
195         adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP);
196         return 2;
197 }
198
199 static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
200                                        struct comedi_subdevice *s,
201                                        struct comedi_insn *insn,
202                                        unsigned int *data)
203 {
204         adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0);
205         return 2;
206 }
207
208 static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
209                                        struct comedi_subdevice *s,
210                                        struct comedi_insn *insn,
211                                        unsigned int *data)
212 {
213         adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1);
214         return 2;
215 }
216
217 static int adl_pci8164_auto_attach(struct comedi_device *dev,
218                                              unsigned long context_unused)
219 {
220         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
221         struct comedi_subdevice *s;
222         int ret;
223
224         dev->board_name = dev->driver->driver_name;
225
226         ret = comedi_pci_enable(pcidev, dev->board_name);
227         if (ret)
228                 return ret;
229         dev->iobase = pci_resource_start(pcidev, 2);
230
231         ret = comedi_alloc_subdevices(dev, 4);
232         if (ret)
233                 return ret;
234
235         s = &dev->subdevices[0];
236         s->type = COMEDI_SUBD_PROC;
237         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
238         s->n_chan = 4;
239         s->maxdata = 0xffff;
240         s->len_chanlist = 4;
241         /* s->range_table = &range_axis; */
242         s->insn_read = adl_pci8164_insn_read_msts;
243         s->insn_write = adl_pci8164_insn_write_cmd;
244
245         s = &dev->subdevices[1];
246         s->type = COMEDI_SUBD_PROC;
247         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
248         s->n_chan = 4;
249         s->maxdata = 0xffff;
250         s->len_chanlist = 4;
251         /* s->range_table = &range_axis; */
252         s->insn_read = adl_pci8164_insn_read_ssts;
253         s->insn_write = adl_pci8164_insn_write_otp;
254
255         s = &dev->subdevices[2];
256         s->type = COMEDI_SUBD_PROC;
257         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
258         s->n_chan = 4;
259         s->maxdata = 0xffff;
260         s->len_chanlist = 4;
261         /* s->range_table = &range_axis; */
262         s->insn_read = adl_pci8164_insn_read_buf0;
263         s->insn_write = adl_pci8164_insn_write_buf0;
264
265         s = &dev->subdevices[3];
266         s->type = COMEDI_SUBD_PROC;
267         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
268         s->n_chan = 4;
269         s->maxdata = 0xffff;
270         s->len_chanlist = 4;
271         /* s->range_table = &range_axis; */
272         s->insn_read = adl_pci8164_insn_read_buf1;
273         s->insn_write = adl_pci8164_insn_write_buf1;
274
275         dev_info(dev->class_dev, "%s attached\n", dev->board_name);
276
277         return 0;
278 }
279
280 static void adl_pci8164_detach(struct comedi_device *dev)
281 {
282         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
283
284         if (pcidev) {
285                 if (dev->iobase)
286                         comedi_pci_disable(pcidev);
287         }
288 }
289
290 static struct comedi_driver adl_pci8164_driver = {
291         .driver_name    = "adl_pci8164",
292         .module         = THIS_MODULE,
293         .auto_attach    = adl_pci8164_auto_attach,
294         .detach         = adl_pci8164_detach,
295 };
296
297 static int adl_pci8164_pci_probe(struct pci_dev *dev,
298                                            const struct pci_device_id *ent)
299 {
300         return comedi_pci_auto_config(dev, &adl_pci8164_driver);
301 }
302
303 static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
304         { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
305         {0}
306 };
307 MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
308
309 static struct pci_driver adl_pci8164_pci_driver = {
310         .name           = "adl_pci8164",
311         .id_table       = adl_pci8164_pci_table,
312         .probe          = adl_pci8164_pci_probe,
313         .remove         = comedi_pci_auto_unconfig,
314 };
315 module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
316
317 MODULE_AUTHOR("Comedi http://www.comedi.org");
318 MODULE_DESCRIPTION("Comedi low-level driver");
319 MODULE_LICENSE("GPL");