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 <linux/pci.h>
41 #include <linux/mutex.h>
43 #include "../comedidev.h"
45 #define READ_TIMEOUT 50
47 static const struct comedi_lrange range_pci1050_ai
= { 3, {
54 static const char range_codes_pci1050_ai
[] = { 0x00, 0x10, 0x30 };
56 struct dyna_pci10xx_private
{
61 /******************************************************************************/
62 /************************** READ WRITE FUNCTIONS ******************************/
63 /******************************************************************************/
65 /* analog input callback */
66 static int dyna_pci10xx_insn_read_ai(struct comedi_device
*dev
,
67 struct comedi_subdevice
*s
,
68 struct comedi_insn
*insn
, unsigned int *data
)
70 struct dyna_pci10xx_private
*devpriv
= dev
->private;
73 unsigned int chan
, range
;
75 /* get the channel number and range */
76 chan
= CR_CHAN(insn
->chanspec
);
77 range
= range_codes_pci1050_ai
[CR_RANGE((insn
->chanspec
))];
79 mutex_lock(&devpriv
->mutex
);
80 /* convert n samples */
81 for (n
= 0; n
< insn
->n
; n
++) {
82 /* trigger conversion */
84 outw_p(0x0000 + range
+ chan
, dev
->iobase
+ 2);
87 for (counter
= 0; counter
< READ_TIMEOUT
; counter
++) {
88 d
= inw_p(dev
->iobase
);
90 /* check if read is successful if the EOC bit is set */
95 printk(KERN_DEBUG
"comedi: dyna_pci10xx: "
96 "timeout reading analog input\n");
99 /* mask the first 4 bits - EOC bits */
103 mutex_unlock(&devpriv
->mutex
);
105 /* return the number of samples read/written */
109 /* analog output callback */
110 static int dyna_pci10xx_insn_write_ao(struct comedi_device
*dev
,
111 struct comedi_subdevice
*s
,
112 struct comedi_insn
*insn
, unsigned int *data
)
114 struct dyna_pci10xx_private
*devpriv
= dev
->private;
116 unsigned int chan
, range
;
118 chan
= CR_CHAN(insn
->chanspec
);
119 range
= range_codes_pci1050_ai
[CR_RANGE((insn
->chanspec
))];
121 mutex_lock(&devpriv
->mutex
);
122 for (n
= 0; n
< insn
->n
; n
++) {
124 /* trigger conversion and write data */
125 outw_p(data
[n
], dev
->iobase
);
128 mutex_unlock(&devpriv
->mutex
);
132 /* digital input bit interface */
133 static int dyna_pci10xx_di_insn_bits(struct comedi_device
*dev
,
134 struct comedi_subdevice
*s
,
135 struct comedi_insn
*insn
, unsigned int *data
)
137 struct dyna_pci10xx_private
*devpriv
= dev
->private;
140 mutex_lock(&devpriv
->mutex
);
142 d
= inw_p(devpriv
->BADR3
);
145 /* on return the data[0] contains output and data[1] contains input */
148 mutex_unlock(&devpriv
->mutex
);
152 /* digital output bit interface */
153 static int dyna_pci10xx_do_insn_bits(struct comedi_device
*dev
,
154 struct comedi_subdevice
*s
,
155 struct comedi_insn
*insn
, unsigned int *data
)
157 struct dyna_pci10xx_private
*devpriv
= dev
->private;
159 /* The insn data is a mask in data[0] and the new data
160 * in data[1], each channel cooresponding to a bit.
161 * s->state contains the previous write data
163 mutex_lock(&devpriv
->mutex
);
165 s
->state
&= ~data
[0];
166 s
->state
|= (data
[0] & data
[1]);
168 outw_p(s
->state
, devpriv
->BADR3
);
173 * On return, data[1] contains the value of the digital
174 * input and output lines. We just return the software copy of the
175 * output values if it was a purely digital output subdevice.
178 mutex_unlock(&devpriv
->mutex
);
182 static int dyna_pci10xx_auto_attach(struct comedi_device
*dev
,
183 unsigned long context_unused
)
185 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
186 struct dyna_pci10xx_private
*devpriv
;
187 struct comedi_subdevice
*s
;
190 devpriv
= kzalloc(sizeof(*devpriv
), GFP_KERNEL
);
193 dev
->private = devpriv
;
195 ret
= comedi_pci_enable(dev
);
198 dev
->iobase
= pci_resource_start(pcidev
, 2);
199 devpriv
->BADR3
= pci_resource_start(pcidev
, 3);
201 mutex_init(&devpriv
->mutex
);
203 ret
= comedi_alloc_subdevices(dev
, 4);
208 s
= &dev
->subdevices
[0];
209 s
->type
= COMEDI_SUBD_AI
;
210 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_DIFF
;
213 s
->range_table
= &range_pci1050_ai
;
214 s
->len_chanlist
= 16;
215 s
->insn_read
= dyna_pci10xx_insn_read_ai
;
218 s
= &dev
->subdevices
[1];
219 s
->type
= COMEDI_SUBD_AO
;
220 s
->subdev_flags
= SDF_WRITABLE
;
223 s
->range_table
= &range_unipolar10
;
224 s
->len_chanlist
= 16;
225 s
->insn_write
= dyna_pci10xx_insn_write_ao
;
228 s
= &dev
->subdevices
[2];
229 s
->type
= COMEDI_SUBD_DI
;
230 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
;
233 s
->range_table
= &range_digital
;
234 s
->len_chanlist
= 16;
235 s
->insn_bits
= dyna_pci10xx_di_insn_bits
;
238 s
= &dev
->subdevices
[3];
239 s
->type
= COMEDI_SUBD_DO
;
240 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
243 s
->range_table
= &range_digital
;
244 s
->len_chanlist
= 16;
246 s
->insn_bits
= dyna_pci10xx_do_insn_bits
;
248 dev_info(dev
->class_dev
, "%s attached\n", dev
->board_name
);
253 static void dyna_pci10xx_detach(struct comedi_device
*dev
)
255 struct dyna_pci10xx_private
*devpriv
= dev
->private;
258 mutex_destroy(&devpriv
->mutex
);
259 comedi_pci_disable(dev
);
262 static struct comedi_driver dyna_pci10xx_driver
= {
263 .driver_name
= "dyna_pci10xx",
264 .module
= THIS_MODULE
,
265 .auto_attach
= dyna_pci10xx_auto_attach
,
266 .detach
= dyna_pci10xx_detach
,
269 static int dyna_pci10xx_pci_probe(struct pci_dev
*dev
,
270 const struct pci_device_id
*id
)
272 return comedi_pci_auto_config(dev
, &dyna_pci10xx_driver
,
276 static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table
) = {
277 { PCI_DEVICE(PCI_VENDOR_ID_PLX
, 0x1050) },
280 MODULE_DEVICE_TABLE(pci
, dyna_pci10xx_pci_table
);
282 static struct pci_driver dyna_pci10xx_pci_driver
= {
283 .name
= "dyna_pci10xx",
284 .id_table
= dyna_pci10xx_pci_table
,
285 .probe
= dyna_pci10xx_pci_probe
,
286 .remove
= comedi_pci_auto_unconfig
,
288 module_comedi_pci_driver(dyna_pci10xx_driver
, dyna_pci10xx_pci_driver
);
290 MODULE_LICENSE("GPL");
291 MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>");
292 MODULE_DESCRIPTION("Comedi based drivers for Dynalog PCI DAQ cards");