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");