cb_pcimdas.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
1/*
2    comedi/drivers/cb_pcimdas.c
3    Comedi driver for Computer Boards PCIM-DAS1602/16
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/*
24Driver: cb_pcimdas
25Description: Measurement Computing PCI Migration series boards
26Devices: [ComputerBoards] PCIM-DAS1602/16 (cb_pcimdas)
27Author: Richard Bytheway
28Updated: Wed, 13 Nov 2002 12:34:56 +0000
29Status: experimental
30
31Written to support the PCIM-DAS1602/16 on a 2.4 series kernel.
32
33Configuration Options:
34    [0] - PCI bus number
35    [1] - PCI slot number
36
37Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org).
38Only supports DIO, AO and simple AI in it's present form.
39No interrupts, multi channel or FIFO AI, although the card looks like it could support this.
40See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more details.
41*/
42
43#include "../comedidev.h"
44
45#include <linux/delay.h>
46#include <linux/interrupt.h>
47
48#include "comedi_pci.h"
49#include "plx9052.h"
50#include "8255.h"
51
52/* #define CBPCIMDAS_DEBUG */
53#undef CBPCIMDAS_DEBUG
54
55/* Registers for the PCIM-DAS1602/16 */
56
57/* sizes of io regions (bytes) */
58#define BADR0_SIZE 2		/* ?? */
59#define BADR1_SIZE 4
60#define BADR2_SIZE 6
61#define BADR3_SIZE 16
62#define BADR4_SIZE 4
63
64/* DAC Offsets */
65#define ADC_TRIG 0
66#define DAC0_OFFSET 2
67#define DAC1_OFFSET 4
68
69/* AI and Counter Constants */
70#define MUX_LIMITS 0
71#define MAIN_CONN_DIO 1
72#define ADC_STAT 2
73#define ADC_CONV_STAT 3
74#define ADC_INT 4
75#define ADC_PACER 5
76#define BURST_MODE 6
77#define PROG_GAIN 7
78#define CLK8254_1_DATA 8
79#define CLK8254_2_DATA 9
80#define CLK8254_3_DATA 10
81#define CLK8254_CONTROL 11
82#define USER_COUNTER 12
83#define RESID_COUNT_H 13
84#define RESID_COUNT_L 14
85
86/* Board description */
87struct cb_pcimdas_board {
88	const char *name;
89	unsigned short device_id;
90	int ai_se_chans;	/*  Inputs in single-ended mode */
91	int ai_diff_chans;	/*  Inputs in differential mode */
92	int ai_bits;		/*  analog input resolution */
93	int ai_speed;		/*  fastest conversion period in ns */
94	int ao_nchan;		/*  number of analog out channels */
95	int ao_bits;		/*  analogue output resolution */
96	int has_ao_fifo;	/*  analog output has fifo */
97	int ao_scan_speed;	/*  analog output speed for 1602 series (for a scan, not conversion) */
98	int fifo_size;		/*  number of samples fifo can hold */
99	int dio_bits;		/*  number of dio bits */
100	int has_dio;		/*  has DIO */
101	const struct comedi_lrange *ranges;
102};
103
104static const struct cb_pcimdas_board cb_pcimdas_boards[] = {
105	{
106	.name = "PCIM-DAS1602/16",
107	.device_id = 0x56,
108	.ai_se_chans = 16,
109	.ai_diff_chans = 8,
110	.ai_bits = 16,
111	.ai_speed = 10000,	/* ?? */
112	.ao_nchan = 2,
113	.ao_bits = 12,
114	.has_ao_fifo = 0,	/* ?? */
115	.ao_scan_speed = 10000,
116			/* ?? */
117	.fifo_size = 1024,
118	.dio_bits = 24,
119	.has_dio = 1,
120/*	.ranges = &cb_pcimdas_ranges, */
121		},
122};
123
124/* This is used by modprobe to translate PCI IDs to drivers.  Should
125 * only be used for PCI and ISA-PnP devices */
126static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
127	{PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
128	{0}
129};
130
131MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
132
133#define N_BOARDS 1		/*  Max number of boards supported */
134
135/*
136 * Useful for shorthand access to the particular board structure
137 */
138#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
139
140/* this structure is for data unique to this hardware driver.  If
141   several hardware drivers keep similar information in this structure,
142   feel free to suggest moving the variable to the struct comedi_device struct.  */
143struct cb_pcimdas_private {
144	int data;
145
146	/*  would be useful for a PCI device */
147	struct pci_dev *pci_dev;
148
149	/* base addresses */
150	unsigned long BADR0;
151	unsigned long BADR1;
152	unsigned long BADR2;
153	unsigned long BADR3;
154	unsigned long BADR4;
155
156	/* Used for AO readback */
157	unsigned int ao_readback[2];
158
159	/*  Used for DIO */
160	unsigned short int port_a;	/*  copy of BADR4+0 */
161	unsigned short int port_b;	/*  copy of BADR4+1 */
162	unsigned short int port_c;	/*  copy of BADR4+2 */
163	unsigned short int dio_mode;	/*  copy of BADR4+3 */
164
165};
166
167/*
168 * most drivers define the following macro to make it easy to
169 * access the private structure.
170 */
171#define devpriv ((struct cb_pcimdas_private *)dev->private)
172
173/*
174 * The struct comedi_driver structure tells the Comedi core module
175 * which functions to call to configure/deconfigure (attach/detach)
176 * the board, and also about the kernel module that contains
177 * the device code.
178 */
179static int cb_pcimdas_attach(struct comedi_device *dev, struct comedi_devconfig *it);
180static int cb_pcimdas_detach(struct comedi_device *dev);
181static struct comedi_driver driver_cb_pcimdas = {
182	.driver_name = "cb_pcimdas",
183	.module = THIS_MODULE,
184	.attach = cb_pcimdas_attach,
185	.detach = cb_pcimdas_detach,
186};
187
188static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
189	struct comedi_insn *insn, unsigned int *data);
190static int cb_pcimdas_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
191	struct comedi_insn *insn, unsigned int *data);
192static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
193	struct comedi_insn *insn, unsigned int *data);
194
195/*
196 * Attach is called by the Comedi core to configure the driver
197 * for a particular board.  If you specified a board_name array
198 * in the driver structure, dev->board_ptr contains that
199 * address.
200 */
201static int cb_pcimdas_attach(struct comedi_device *dev, struct comedi_devconfig *it)
202{
203	struct comedi_subdevice *s;
204	struct pci_dev *pcidev;
205	int index;
206	/* int i; */
207
208	printk("comedi%d: cb_pcimdas: ", dev->minor);
209
210/*
211 * Allocate the private structure area.
212 */
213	if (alloc_private(dev, sizeof(struct cb_pcimdas_private)) < 0)
214		return -ENOMEM;
215
216/*
217 * Probe the device to determine what device in the series it is.
218 */
219	printk("\n");
220
221	for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
222		pcidev != NULL;
223		pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
224		/*  is it not a computer boards card? */
225		if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
226			continue;
227		/*  loop through cards supported by this driver */
228		for (index = 0; index < N_BOARDS; index++) {
229			if (cb_pcimdas_boards[index].device_id !=
230				pcidev->device)
231				continue;
232			/*  was a particular bus/slot requested? */
233			if (it->options[0] || it->options[1]) {
234				/*  are we on the wrong bus/slot? */
235				if (pcidev->bus->number != it->options[0] ||
236					PCI_SLOT(pcidev->devfn) !=
237					it->options[1]) {
238					continue;
239				}
240			}
241			devpriv->pci_dev = pcidev;
242			dev->board_ptr = cb_pcimdas_boards + index;
243			goto found;
244		}
245	}
246
247	printk("No supported ComputerBoards/MeasurementComputing card found on "
248		"requested position\n");
249	return -EIO;
250
251      found:
252
253	printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name,
254		pcidev->bus->number, PCI_SLOT(pcidev->devfn));
255
256	/*  Warn about non-tested features */
257	switch (thisboard->device_id) {
258	case 0x56:
259		break;
260	default:
261		printk("THIS CARD IS UNSUPPORTED.\n"
262			"PLEASE REPORT USAGE TO <mocelet@sucs.org>\n");
263	};
264
265	if (comedi_pci_enable(pcidev, "cb_pcimdas")) {
266		printk(" Failed to enable PCI device and request regions\n");
267		return -EIO;
268	}
269
270	devpriv->BADR0 = pci_resource_start(devpriv->pci_dev, 0);
271	devpriv->BADR1 = pci_resource_start(devpriv->pci_dev, 1);
272	devpriv->BADR2 = pci_resource_start(devpriv->pci_dev, 2);
273	devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3);
274	devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4);
275
276#ifdef CBPCIMDAS_DEBUG
277	printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
278	printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
279	printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
280	printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
281	printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
282#endif
283
284/* Dont support IRQ yet */
285/*  get irq */
286/* if(request_irq(devpriv->pci_dev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */
287/* { */
288/* printk(" unable to allocate irq %u\n", devpriv->pci_dev->irq); */
289/* return -EINVAL; */
290/* } */
291/* dev->irq = devpriv->pci_dev->irq; */
292
293	/* Initialize dev->board_name */
294	dev->board_name = thisboard->name;
295
296/*
297 * Allocate the subdevice structures.  alloc_subdevice() is a
298 * convenient macro defined in comedidev.h.
299 */
300	if (alloc_subdevices(dev, 3) < 0)
301		return -ENOMEM;
302
303	s = dev->subdevices + 0;
304	/* dev->read_subdev=s; */
305	/*  analog input subdevice */
306	s->type = COMEDI_SUBD_AI;
307	s->subdev_flags = SDF_READABLE | SDF_GROUND;
308	s->n_chan = thisboard->ai_se_chans;
309	s->maxdata = (1 << thisboard->ai_bits) - 1;
310	s->range_table = &range_unknown;
311	s->len_chanlist = 1;	/*  This is the maximum chanlist length that */
312	/*  the board can handle */
313	s->insn_read = cb_pcimdas_ai_rinsn;
314
315	s = dev->subdevices + 1;
316	/*  analog output subdevice */
317	s->type = COMEDI_SUBD_AO;
318	s->subdev_flags = SDF_WRITABLE;
319	s->n_chan = thisboard->ao_nchan;
320	s->maxdata = 1 << thisboard->ao_bits;
321	s->range_table = &range_unknown;	/* ranges are hardware settable, but not software readable. */
322	s->insn_write = &cb_pcimdas_ao_winsn;
323	s->insn_read = &cb_pcimdas_ao_rinsn;
324
325	s = dev->subdevices + 2;
326	/* digital i/o subdevice */
327	if (thisboard->has_dio) {
328		subdev_8255_init(dev, s, NULL, devpriv->BADR4);
329	} else {
330		s->type = COMEDI_SUBD_UNUSED;
331	}
332
333	printk("attached\n");
334
335	return 1;
336}
337
338/*
339 * _detach is called to deconfigure a device.  It should deallocate
340 * resources.
341 * This function is also called when _attach() fails, so it should be
342 * careful not to release resources that were not necessarily
343 * allocated by _attach().  dev->private and dev->subdevices are
344 * deallocated automatically by the core.
345 */
346static int cb_pcimdas_detach(struct comedi_device *dev)
347{
348#ifdef CBPCIMDAS_DEBUG
349	if (devpriv) {
350		printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0);
351		printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1);
352		printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2);
353		printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3);
354		printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4);
355	}
356#endif
357	printk("comedi%d: cb_pcimdas: remove\n", dev->minor);
358	if (dev->irq)
359		free_irq(dev->irq, dev);
360	if (devpriv) {
361		if (devpriv->pci_dev) {
362			if (devpriv->BADR0) {
363				comedi_pci_disable(devpriv->pci_dev);
364			}
365			pci_dev_put(devpriv->pci_dev);
366		}
367	}
368
369	return 0;
370}
371
372/*
373 * "instructions" read/write data in "one-shot" or "software-triggered"
374 * mode.
375 */
376static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
377	struct comedi_insn *insn, unsigned int *data)
378{
379	int n, i;
380	unsigned int d;
381	unsigned int busy;
382	int chan = CR_CHAN(insn->chanspec);
383	unsigned short chanlims;
384	int maxchans;
385
386	/*  only support sw initiated reads from a single channel */
387
388	/* check channel number */
389	if ((inb(devpriv->BADR3 + 2) & 0x20) == 0)	/* differential mode */
390		maxchans = thisboard->ai_diff_chans;
391	else
392		maxchans = thisboard->ai_se_chans;
393
394	if (chan > (maxchans - 1))
395		return -ETIMEDOUT;	/* *** Wrong error code. Fixme. */
396
397	/* configure for sw initiated read */
398	d = inb(devpriv->BADR3 + 5);
399	if ((d & 0x03) > 0) {	/* only reset if needed. */
400		d = d & 0xfd;
401		outb(d, devpriv->BADR3 + 5);
402	}
403	outb(0x01, devpriv->BADR3 + 6);	/* set bursting off, conversions on */
404	outb(0x00, devpriv->BADR3 + 7);	/* set range to 10V. UP/BP is controlled by a switch on the board */
405
406	/*  write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */
407	chanlims = chan | (chan << 4);
408	outb(chanlims, devpriv->BADR3 + 0);
409
410	/* convert n samples */
411	for (n = 0; n < insn->n; n++) {
412		/* trigger conversion */
413		outw(0, devpriv->BADR2 + 0);
414
415#define TIMEOUT 1000		/* typically takes 5 loops on a lightly loaded Pentium 100MHz, */
416		/* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */
417
418		/* wait for conversion to end */
419		for (i = 0; i < TIMEOUT; i++) {
420			busy = inb(devpriv->BADR3 + 2) & 0x80;
421			if (!busy)
422				break;
423		}
424		if (i == TIMEOUT) {
425			printk("timeout\n");
426			return -ETIMEDOUT;
427		}
428		/* read data */
429		d = inw(devpriv->BADR2 + 0);
430
431		/* mangle the data as necessary */
432		/* d ^= 1<<(thisboard->ai_bits-1); // 16 bit data from ADC, so no mangle needed. */
433
434		data[n] = d;
435	}
436
437	/* return the number of samples read/written */
438	return n;
439}
440
441static int cb_pcimdas_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
442	struct comedi_insn *insn, unsigned int *data)
443{
444	int i;
445	int chan = CR_CHAN(insn->chanspec);
446
447	/* Writing a list of values to an AO channel is probably not
448	 * very useful, but that's how the interface is defined. */
449	for (i = 0; i < insn->n; i++) {
450		switch (chan) {
451		case 0:
452			outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC0_OFFSET);
453			break;
454		case 1:
455			outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC1_OFFSET);
456			break;
457		default:
458			return -1;
459		}
460		devpriv->ao_readback[chan] = data[i];
461	}
462
463	/* return the number of samples read/written */
464	return i;
465}
466
467/* AO subdevices should have a read insn as well as a write insn.
468 * Usually this means copying a value stored in devpriv. */
469static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
470	struct comedi_insn *insn, unsigned int *data)
471{
472	int i;
473	int chan = CR_CHAN(insn->chanspec);
474
475	for (i = 0; i < insn->n; i++)
476		data[i] = devpriv->ao_readback[chan];
477
478	return i;
479}
480
481/*
482 * A convenient macro that defines init_module() and cleanup_module(),
483 * as necessary.
484 */
485COMEDI_PCI_INITCLEANUP(driver_cb_pcimdas, cb_pcimdas_pci_table);
486