2 * comedi/drivers/dyna_pci10xx.c
3 * Copyright (C) 2011 Prashant Shah, pshah.mumbai@gmail.com
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 Devices: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/
23 Author: Prashant Shah <pshah.mumbai@gmail.com>
24 Developed at Automation Labs, Chemical Dept., IIT Bombay, India.
25 Prof. Kannan Moudgalya <kannan@iitb.ac.in>
33 - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and
34 they are using the PLX Technlogies Vendor ID since that is the PCI Chip used
36 - Dynalog India Pvt. Ltd. has provided the internal register specification for
37 their cards in their manuals.
40 #include "../comedidev.h"
41 #include "comedi_pci.h"
42 #include <linux/mutex.h>
44 #define PCI_VENDOR_ID_DYNALOG 0x10b5
45 #define DRV_NAME "dyna_pci10xx"
47 #define READ_TIMEOUT 50
49 static DEFINE_MUTEX(start_stop_sem);
51 static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
52 { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
56 MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
58 static int dyna_pci10xx_attach(struct comedi_device *dev,
59 struct comedi_devconfig *it);
60 static int dyna_pci10xx_detach(struct comedi_device *dev);
62 static const struct comedi_lrange range_pci1050_ai = { 3, {
69 static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 };
71 static const struct comedi_lrange range_pci1050_ao = { 1, {
76 static const char range_codes_pci1050_ao[] = { 0x00 };
89 const struct comedi_lrange *range_ai;
90 const char *range_codes_ai;
91 const struct comedi_lrange *range_ao;
92 const char *range_codes_ao;
95 static const struct boardtype boardtypes[] = {
97 .name = "dyna_pci1050",
107 .range_ai = &range_pci1050_ai,
108 .range_codes_ai = range_codes_pci1050_ai,
109 .range_ao = &range_pci1050_ao,
110 .range_codes_ao = range_codes_pci1050_ao,
112 /* dummy entry corresponding to driver name */
116 static struct comedi_driver driver_dyna_pci10xx = {
117 .driver_name = DRV_NAME,
118 .module = THIS_MODULE,
119 .attach = dyna_pci10xx_attach,
120 .detach = dyna_pci10xx_detach,
121 .board_name = &boardtypes[0].name,
122 .offset = sizeof(struct boardtype),
123 .num_names = ARRAY_SIZE(boardtypes),
126 struct dyna_pci10xx_private {
127 struct pci_dev *pci_dev; /* ptr to PCI device */
128 char valid; /* card is usable */
131 /* device base address registers */
132 unsigned long BADR0, BADR1, BADR2, BADR3, BADR4, BADR5;
135 #define thisboard ((const struct boardtype *)dev->board_ptr)
136 #define devpriv ((struct dyna_pci10xx_private *)dev->private)
138 /******************************************************************************/
139 /************************** READ WRITE FUNCTIONS ******************************/
140 /******************************************************************************/
142 /* analog input callback */
143 static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
144 struct comedi_subdevice *s,
145 struct comedi_insn *insn, unsigned int *data)
149 unsigned int chan, range;
151 /* get the channel number and range */
152 chan = CR_CHAN(insn->chanspec);
153 range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))];
155 mutex_lock(&devpriv->mutex);
156 /* convert n samples */
157 for (n = 0; n < insn->n; n++) {
158 /* trigger conversion */
160 outw_p(0x0000 + range + chan, devpriv->BADR2 + 2);
163 for (counter = 0; counter < READ_TIMEOUT; counter++) {
164 d = inw_p(devpriv->BADR2);
166 /* check if read is successfull if the EOC bit is set */
171 printk(KERN_DEBUG "comedi: dyna_pci10xx: "
172 "timeout reading analog input\n");
175 /* mask the first 4 bits - EOC bits */
179 mutex_unlock(&devpriv->mutex);
181 /* return the number of samples read/written */
185 /* analog output callback */
186 static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev,
187 struct comedi_subdevice *s,
188 struct comedi_insn *insn, unsigned int *data)
191 unsigned int chan, range;
193 chan = CR_CHAN(insn->chanspec);
194 range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))];
196 mutex_lock(&devpriv->mutex);
197 for (n = 0; n < insn->n; n++) {
199 /* trigger conversion and write data */
200 outw_p(data[n], devpriv->BADR2);
203 mutex_unlock(&devpriv->mutex);
207 /* digital input bit interface */
208 static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev,
209 struct comedi_subdevice *s,
210 struct comedi_insn *insn, unsigned int *data)
217 mutex_lock(&devpriv->mutex);
219 d = inw_p(devpriv->BADR3);
222 /* on return the data[0] contains output and data[1] contains input */
225 mutex_unlock(&devpriv->mutex);
229 /* digital output bit interface */
230 static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev,
231 struct comedi_subdevice *s,
232 struct comedi_insn *insn, unsigned int *data)
237 /* The insn data is a mask in data[0] and the new data
238 * in data[1], each channel cooresponding to a bit.
239 * s->state contains the previous write data
241 mutex_lock(&devpriv->mutex);
243 s->state &= ~data[0];
244 s->state |= (data[0] & data[1]);
246 outw_p(s->state, devpriv->BADR3);
251 * On return, data[1] contains the value of the digital
252 * input and output lines. We just return the software copy of the
253 * output values if it was a purely digital output subdevice.
256 mutex_unlock(&devpriv->mutex);
260 /******************************************************************************/
261 /*********************** INITIALIZATION FUNCTIONS *****************************/
262 /******************************************************************************/
264 static int dyna_pci10xx_attach(struct comedi_device *dev,
265 struct comedi_devconfig *it)
267 struct comedi_subdevice *s;
268 struct pci_dev *pcidev;
269 unsigned int opt_bus, opt_slot;
272 mutex_lock(&start_stop_sem);
274 if (alloc_private(dev, sizeof(struct dyna_pci10xx_private)) < 0) {
275 printk(KERN_ERR "comedi: dyna_pci10xx: "
276 "failed to allocate memory!\n");
277 mutex_unlock(&start_stop_sem);
281 opt_bus = it->options[0];
282 opt_slot = it->options[1];
283 dev->board_name = thisboard->name;
287 * Probe the PCI bus and located the matching device
289 for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
291 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
294 for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
295 if ((pcidev->vendor == PCI_VENDOR_ID_DYNALOG) &&
296 (pcidev->device == boardtypes[i].device_id)) {
304 /* Found matching vendor/device. */
305 if (opt_bus || opt_slot) {
306 /* Check bus/slot. */
307 if (opt_bus != pcidev->bus->number
308 || opt_slot != PCI_SLOT(pcidev->devfn))
309 continue; /* no match */
314 printk(KERN_ERR "comedi: dyna_pci10xx: no supported device found!\n");
315 mutex_unlock(&start_stop_sem);
321 if (opt_bus || opt_slot) {
322 printk(KERN_ERR "comedi: dyna_pci10xx: "
323 "invalid PCI device at b:s %d:%d\n",
326 printk(KERN_ERR "comedi: dyna_pci10xx: "
327 "invalid PCI device\n");
329 mutex_unlock(&start_stop_sem);
333 if (comedi_pci_enable(pcidev, DRV_NAME)) {
334 printk(KERN_ERR "comedi: dyna_pci10xx: "
335 "failed to enable PCI device and request regions!");
336 mutex_unlock(&start_stop_sem);
340 mutex_init(&devpriv->mutex);
341 dev->board_ptr = &boardtypes[board_index];
342 devpriv->pci_dev = pcidev;
344 printk(KERN_INFO "comedi: dyna_pci10xx: device found!\n");
346 /* initialize device base address registers */
347 devpriv->BADR0 = pci_resource_start(pcidev, 0);
348 devpriv->BADR1 = pci_resource_start(pcidev, 1);
349 devpriv->BADR2 = pci_resource_start(pcidev, 2);
350 devpriv->BADR3 = pci_resource_start(pcidev, 3);
351 devpriv->BADR4 = pci_resource_start(pcidev, 4);
352 devpriv->BADR5 = pci_resource_start(pcidev, 5);
354 if (alloc_subdevices(dev, 4) < 0) {
355 printk(KERN_ERR "comedi: dyna_pci10xx: "
356 "failed allocating subdevices\n");
357 mutex_unlock(&start_stop_sem);
362 s = dev->subdevices + 0;
363 s->type = COMEDI_SUBD_AI;
364 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
365 s->n_chan = thisboard->ai_chans;
367 s->range_table = thisboard->range_ai;
368 s->len_chanlist = 16;
369 s->insn_read = dyna_pci10xx_insn_read_ai;
372 s = dev->subdevices + 1;
373 s->type = COMEDI_SUBD_AO;
374 s->subdev_flags = SDF_WRITABLE;
375 s->n_chan = thisboard->ao_chans;
377 s->range_table = thisboard->range_ao;
378 s->len_chanlist = 16;
379 s->insn_write = dyna_pci10xx_insn_write_ao;
382 s = dev->subdevices + 2;
383 s->type = COMEDI_SUBD_DI;
384 s->subdev_flags = SDF_READABLE | SDF_GROUND;
385 s->n_chan = thisboard->di_chans;
387 s->range_table = &range_digital;
388 s->len_chanlist = thisboard->di_chans;
389 s->insn_bits = dyna_pci10xx_di_insn_bits;
392 s = dev->subdevices + 3;
393 s->type = COMEDI_SUBD_DO;
394 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
395 s->n_chan = thisboard->do_chans;
397 s->range_table = &range_digital;
398 s->len_chanlist = thisboard->do_chans;
400 s->insn_bits = dyna_pci10xx_do_insn_bits;
403 mutex_unlock(&start_stop_sem);
405 printk(KERN_INFO "comedi: dyna_pci10xx: %s - device setup completed!\n",
406 boardtypes[board_index].name);
411 static int dyna_pci10xx_detach(struct comedi_device *dev)
413 if (devpriv && devpriv->pci_dev) {
414 comedi_pci_disable(devpriv->pci_dev);
415 mutex_destroy(&devpriv->mutex);
421 static int __devinit driver_dyna_pci10xx_pci_probe(struct pci_dev *dev,
422 const struct pci_device_id *ent)
424 return comedi_pci_auto_config(dev, driver_dyna_pci10xx.driver_name);
427 static void __devexit driver_dyna_pci10xx_pci_remove(struct pci_dev *dev)
429 comedi_pci_auto_unconfig(dev);
432 static struct pci_driver driver_dyna_pci10xx_pci_driver = {
433 .id_table = dyna_pci10xx_pci_table,
434 .probe = &driver_dyna_pci10xx_pci_probe,
435 .remove = __devexit_p(&driver_dyna_pci10xx_pci_remove)
438 static int __init driver_dyna_pci10xx_init_module(void)
442 retval = comedi_driver_register(&driver_dyna_pci10xx);
446 driver_dyna_pci10xx_pci_driver.name =
447 (char *)driver_dyna_pci10xx.driver_name;
448 return pci_register_driver(&driver_dyna_pci10xx_pci_driver);
451 static void __exit driver_dyna_pci10xx_cleanup_module(void)
453 pci_unregister_driver(&driver_dyna_pci10xx_pci_driver);
454 comedi_driver_unregister(&driver_dyna_pci10xx);
457 module_init(driver_dyna_pci10xx_init_module);
458 module_exit(driver_dyna_pci10xx_cleanup_module);
460 MODULE_LICENSE("GPL");
461 MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>");
462 MODULE_DESCRIPTION("Comedi based drivers for Dynalog PCI DAQ cards");