adl_pci8164.c revision 790c55415aa31f4c732729f94d2c3a54f7d3bfc2
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/*
23Driver: adl_pci8164
24Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
25Devices: [ADLink] PCI-8164 (adl_pci8164)
26Author: Michel Lachaine <mike@mikelachaine.ca>
27Status: experimental
28Updated: Mon, 14 Apr 2008 15:10:32 +0100
29
30Configuration 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/delay.h>
39#include "comedi_fc.h"
40#include "comedi_pci.h"
41#include "8253.h"
42
43#define PCI8164_AXIS_X  0x00
44#define PCI8164_AXIS_Y  0x08
45#define PCI8164_AXIS_Z  0x10
46#define PCI8164_AXIS_U  0x18
47
48#define PCI8164_MSTS	0x00
49#define PCI8164_SSTS    0x02
50#define PCI8164_BUF0    0x04
51#define PCI8164_BUF1    0x06
52
53#define PCI8164_CMD     0x00
54#define PCI8164_OTP     0x02
55
56#define PCI_DEVICE_ID_PCI8164 0x8164
57
58static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
59	{PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164, PCI_ANY_ID, PCI_ANY_ID, 0,
60		0, 0},
61	{0}
62};
63
64MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
65
66typedef struct {
67	int data;
68	struct pci_dev *pci_dev;
69} adl_pci8164_private;
70
71#define devpriv ((adl_pci8164_private *)dev->private)
72
73static int adl_pci8164_attach(comedi_device * dev, comedi_devconfig * it);
74static int adl_pci8164_detach(comedi_device * dev);
75static comedi_driver driver_adl_pci8164 = {
76      driver_name:"adl_pci8164",
77      module:THIS_MODULE,
78      attach:adl_pci8164_attach,
79      detach:adl_pci8164_detach,
80};
81
82static int adl_pci8164_insn_read_msts(comedi_device * dev, comedi_subdevice * s,
83	comedi_insn * insn, unsigned int * data);
84
85static int adl_pci8164_insn_read_ssts(comedi_device * dev, comedi_subdevice * s,
86	comedi_insn * insn, unsigned int * data);
87
88static int adl_pci8164_insn_read_buf0(comedi_device * dev, comedi_subdevice * s,
89	comedi_insn * insn, unsigned int * data);
90
91static int adl_pci8164_insn_read_buf1(comedi_device * dev, comedi_subdevice * s,
92	comedi_insn * insn, unsigned int * data);
93
94static int adl_pci8164_insn_write_cmd(comedi_device * dev, comedi_subdevice * s,
95	comedi_insn * insn, unsigned int * data);
96
97static int adl_pci8164_insn_write_otp(comedi_device * dev, comedi_subdevice * s,
98	comedi_insn * insn, unsigned int * data);
99
100static int adl_pci8164_insn_write_buf0(comedi_device * dev,
101	comedi_subdevice * s, comedi_insn * insn, unsigned int * data);
102
103static int adl_pci8164_insn_write_buf1(comedi_device * dev,
104	comedi_subdevice * s, comedi_insn * insn, unsigned int * data);
105
106static int adl_pci8164_attach(comedi_device * dev, comedi_devconfig * it)
107{
108	struct pci_dev *pcidev;
109	comedi_subdevice *s;
110	int bus, slot;
111
112	printk("comedi: attempt to attach...\n");
113	printk("comedi%d: adl_pci8164\n", dev->minor);
114
115	dev->board_name = "pci8164";
116	bus = it->options[0];
117	slot = it->options[1];
118
119	if (alloc_private(dev, sizeof(adl_pci8164_private)) < 0)
120		return -ENOMEM;
121
122	if (alloc_subdevices(dev, 4) < 0)
123		return -ENOMEM;
124
125	for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
126		pcidev != NULL;
127		pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
128
129		if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
130			pcidev->device == PCI_DEVICE_ID_PCI8164) {
131			if (bus || slot) {
132				/* requested particular bus/slot */
133				if (pcidev->bus->number != bus
134					|| PCI_SLOT(pcidev->devfn) != slot) {
135					continue;
136				}
137			}
138			devpriv->pci_dev = pcidev;
139			if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
140				printk("comedi%d: Failed to enable PCI device and request regions\n", dev->minor);
141				return -EIO;
142			}
143			dev->iobase = pci_resource_start(pcidev, 2);
144			printk("comedi: base addr %4lx\n", dev->iobase);
145
146			s = dev->subdevices + 0;
147			s->type = COMEDI_SUBD_PROC;
148			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
149			s->n_chan = 4;
150			s->maxdata = 0xffff;
151			s->len_chanlist = 4;
152			//s->range_table = &range_axis;
153			s->insn_read = adl_pci8164_insn_read_msts;
154			s->insn_write = adl_pci8164_insn_write_cmd;
155
156			s = dev->subdevices + 1;
157			s->type = COMEDI_SUBD_PROC;
158			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
159			s->n_chan = 4;
160			s->maxdata = 0xffff;
161			s->len_chanlist = 4;
162			//s->range_table = &range_axis;
163			s->insn_read = adl_pci8164_insn_read_ssts;
164			s->insn_write = adl_pci8164_insn_write_otp;
165
166			s = dev->subdevices + 2;
167			s->type = COMEDI_SUBD_PROC;
168			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
169			s->n_chan = 4;
170			s->maxdata = 0xffff;
171			s->len_chanlist = 4;
172			//s->range_table = &range_axis;
173			s->insn_read = adl_pci8164_insn_read_buf0;
174			s->insn_write = adl_pci8164_insn_write_buf0;
175
176			s = dev->subdevices + 3;
177			s->type = COMEDI_SUBD_PROC;
178			s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
179			s->n_chan = 4;
180			s->maxdata = 0xffff;
181			s->len_chanlist = 4;
182			//s->range_table = &range_axis;
183			s->insn_read = adl_pci8164_insn_read_buf1;
184			s->insn_write = adl_pci8164_insn_write_buf1;
185
186			printk("comedi: attached\n");
187
188			return 1;
189		}
190	}
191
192	printk("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
193		dev->minor, bus, slot);
194	return -EIO;
195}
196
197static int adl_pci8164_detach(comedi_device * dev)
198{
199	printk("comedi%d: pci8164: remove\n", dev->minor);
200
201	if (devpriv && devpriv->pci_dev) {
202		if (dev->iobase) {
203			comedi_pci_disable(devpriv->pci_dev);
204		}
205		pci_dev_put(devpriv->pci_dev);
206	}
207
208	return 0;
209}
210
211static int adl_pci8164_insn_read_msts(comedi_device * dev, comedi_subdevice * s,
212	comedi_insn * insn, unsigned int * data)
213{
214	int axis, axis_reg;
215	char *axisname;
216
217	axis = CR_CHAN(insn->chanspec);
218
219	switch (axis) {
220	case 0:
221		axis_reg = PCI8164_AXIS_X;
222		axisname = "X";
223		break;
224	case 1:
225		axis_reg = PCI8164_AXIS_Y;
226		axisname = "Y";
227		break;
228	case 2:
229		axis_reg = PCI8164_AXIS_Z;
230		axisname = "Z";
231		break;
232	case 3:
233		axis_reg = PCI8164_AXIS_U;
234		axisname = "U";
235		break;
236	default:
237		axis_reg = PCI8164_AXIS_X;
238		axisname = "X";
239	}
240
241	data[0] = inw(dev->iobase + axis_reg + PCI8164_MSTS);
242	printk("comedi: pci8164 MSTS read -> %04X:%04X on axis %s\n", data[0],
243		data[1], axisname);
244
245	return 2;
246}
247
248static int adl_pci8164_insn_read_ssts(comedi_device * dev, comedi_subdevice * s,
249	comedi_insn * insn, unsigned int * data)
250{
251	int axis, axis_reg;
252	char *axisname;
253
254	axis = CR_CHAN(insn->chanspec);
255
256	switch (axis) {
257	case 0:
258		axis_reg = PCI8164_AXIS_X;
259		axisname = "X";
260		break;
261	case 1:
262		axis_reg = PCI8164_AXIS_Y;
263		axisname = "Y";
264		break;
265	case 2:
266		axis_reg = PCI8164_AXIS_Z;
267		axisname = "Z";
268		break;
269	case 3:
270		axis_reg = PCI8164_AXIS_U;
271		axisname = "U";
272		break;
273	default:
274		axis_reg = PCI8164_AXIS_X;
275		axisname = "X";
276	}
277
278	data[0] = inw(dev->iobase + axis_reg + PCI8164_SSTS);
279	printk("comedi: pci8164 SSTS read -> %04X:%04X on axis %s\n", data[0],
280		data[1], axisname);
281
282	return 2;
283}
284
285static int adl_pci8164_insn_read_buf0(comedi_device * dev, comedi_subdevice * s,
286	comedi_insn * insn, unsigned int * data)
287{
288	int axis, axis_reg;
289	char *axisname;
290
291	axis = CR_CHAN(insn->chanspec);
292
293	switch (axis) {
294	case 0:
295		axis_reg = PCI8164_AXIS_X;
296		axisname = "X";
297		break;
298	case 1:
299		axis_reg = PCI8164_AXIS_Y;
300		axisname = "Y";
301		break;
302	case 2:
303		axis_reg = PCI8164_AXIS_Z;
304		axisname = "Z";
305		break;
306	case 3:
307		axis_reg = PCI8164_AXIS_U;
308		axisname = "U";
309		break;
310	default:
311		axis_reg = PCI8164_AXIS_X;
312		axisname = "X";
313	}
314
315	data[0] = inw(dev->iobase + axis_reg + PCI8164_BUF0);
316	printk("comedi: pci8164 BUF0 read -> %04X:%04X on axis %s\n", data[0],
317		data[1], axisname);
318
319	return 2;
320}
321
322static int adl_pci8164_insn_read_buf1(comedi_device * dev, comedi_subdevice * s,
323	comedi_insn * insn, unsigned int * data)
324{
325	int axis, axis_reg;
326
327	char *axisname;
328
329	axis = CR_CHAN(insn->chanspec);
330
331	switch (axis) {
332	case 0:
333		axis_reg = PCI8164_AXIS_X;
334		axisname = "X";
335		break;
336	case 1:
337		axis_reg = PCI8164_AXIS_Y;
338		axisname = "Y";
339		break;
340	case 2:
341		axis_reg = PCI8164_AXIS_Z;
342		axisname = "Z";
343		break;
344	case 3:
345		axis_reg = PCI8164_AXIS_U;
346		axisname = "U";
347		break;
348	default:
349		axis_reg = PCI8164_AXIS_X;
350		axisname = "X";
351	}
352
353	data[0] = inw(dev->iobase + axis_reg + PCI8164_BUF1);
354	printk("comedi: pci8164 BUF1 read -> %04X:%04X on axis %s\n", data[0],
355		data[1], axisname);
356
357	return 2;
358}
359
360static int adl_pci8164_insn_write_cmd(comedi_device * dev, comedi_subdevice * s,
361	comedi_insn * insn, unsigned int * data)
362{
363	unsigned int axis, axis_reg;
364
365	char *axisname;
366
367	axis = CR_CHAN(insn->chanspec);
368
369	switch (axis) {
370	case 0:
371		axis_reg = PCI8164_AXIS_X;
372		axisname = "X";
373		break;
374	case 1:
375		axis_reg = PCI8164_AXIS_Y;
376		axisname = "Y";
377		break;
378	case 2:
379		axis_reg = PCI8164_AXIS_Z;
380		axisname = "Z";
381		break;
382	case 3:
383		axis_reg = PCI8164_AXIS_U;
384		axisname = "U";
385		break;
386	default:
387		axis_reg = PCI8164_AXIS_X;
388		axisname = "X";
389	}
390
391	outw(data[0], dev->iobase + axis_reg + PCI8164_CMD);
392	printk("comedi: pci8164 CMD write -> %04X:%04X on axis %s\n", data[0],
393		data[1], axisname);
394
395	return 2;
396}
397
398static int adl_pci8164_insn_write_otp(comedi_device * dev, comedi_subdevice * s,
399	comedi_insn * insn, unsigned int * data)
400{
401	int axis, axis_reg;
402
403	char *axisname;
404
405	axis = CR_CHAN(insn->chanspec);
406
407	switch (axis) {
408	case 0:
409		axis_reg = PCI8164_AXIS_X;
410		axisname = "X";
411		break;
412	case 1:
413		axis_reg = PCI8164_AXIS_Y;
414		axisname = "Y";
415		break;
416	case 2:
417		axis_reg = PCI8164_AXIS_Z;
418		axisname = "Z";
419		break;
420	case 3:
421		axis_reg = PCI8164_AXIS_U;
422		axisname = "U";
423		break;
424	default:
425		axis_reg = PCI8164_AXIS_X;
426		axisname = "X";
427	}
428
429	outw(data[0], dev->iobase + axis_reg + PCI8164_OTP);
430	printk("comedi: pci8164 OTP write -> %04X:%04X on axis %s\n", data[0],
431		data[1], axisname);
432
433	return 2;
434}
435
436static int adl_pci8164_insn_write_buf0(comedi_device * dev,
437	comedi_subdevice * s, comedi_insn * insn, unsigned int * data)
438{
439	int axis, axis_reg;
440
441	char *axisname;
442
443	axis = CR_CHAN(insn->chanspec);
444
445	switch (axis) {
446	case 0:
447		axis_reg = PCI8164_AXIS_X;
448		axisname = "X";
449		break;
450	case 1:
451		axis_reg = PCI8164_AXIS_Y;
452		axisname = "Y";
453		break;
454	case 2:
455		axis_reg = PCI8164_AXIS_Z;
456		axisname = "Z";
457		break;
458	case 3:
459		axis_reg = PCI8164_AXIS_U;
460		axisname = "U";
461		break;
462	default:
463		axis_reg = PCI8164_AXIS_X;
464		axisname = "X";
465	}
466
467	outw(data[0], dev->iobase + axis_reg + PCI8164_BUF0);
468	printk("comedi: pci8164 BUF0 write -> %04X:%04X on axis %s\n", data[0],
469		data[1], axisname);
470
471	return 2;
472}
473
474static int adl_pci8164_insn_write_buf1(comedi_device * dev,
475	comedi_subdevice * s, comedi_insn * insn, unsigned int * data)
476{
477	int axis, axis_reg;
478
479	char *axisname;
480
481	axis = CR_CHAN(insn->chanspec);
482
483	switch (axis) {
484	case 0:
485		axis_reg = PCI8164_AXIS_X;
486		axisname = "X";
487		break;
488	case 1:
489		axis_reg = PCI8164_AXIS_Y;
490		axisname = "Y";
491		break;
492	case 2:
493		axis_reg = PCI8164_AXIS_Z;
494		axisname = "Z";
495		break;
496	case 3:
497		axis_reg = PCI8164_AXIS_U;
498		axisname = "U";
499		break;
500	default:
501		axis_reg = PCI8164_AXIS_X;
502		axisname = "X";
503	}
504
505	outw(data[0], dev->iobase + axis_reg + PCI8164_BUF1);
506	printk("comedi: pci8164 BUF1 write -> %04X:%04X on axis %s\n", data[0],
507		data[1], axisname);
508
509	return 2;
510}
511
512COMEDI_PCI_INITCLEANUP(driver_adl_pci8164, adl_pci8164_pci_table);
513