Linux 3.9-rc5
[deliverable/linux.git] / 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");
This page took 0.094667 seconds and 5 git commands to generate.