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 <linux/mutex.h>
43 #define PCI_VENDOR_ID_DYNALOG 0x10b5
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_attach_pci(struct comedi_device
*dev
,
183 struct pci_dev
*pcidev
)
185 struct dyna_pci10xx_private
*devpriv
;
186 struct comedi_subdevice
*s
;
189 comedi_set_hw_dev(dev
, &pcidev
->dev
);
191 dev
->board_name
= dev
->driver
->driver_name
;
193 ret
= alloc_private(dev
, sizeof(*devpriv
));
196 devpriv
= dev
->private;
198 ret
= comedi_pci_enable(pcidev
, dev
->board_name
);
201 dev
->iobase
= pci_resource_start(pcidev
, 2);
202 devpriv
->BADR3
= pci_resource_start(pcidev
, 3);
204 mutex_init(&devpriv
->mutex
);
206 ret
= comedi_alloc_subdevices(dev
, 4);
211 s
= &dev
->subdevices
[0];
212 s
->type
= COMEDI_SUBD_AI
;
213 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_DIFF
;
216 s
->range_table
= &range_pci1050_ai
;
217 s
->len_chanlist
= 16;
218 s
->insn_read
= dyna_pci10xx_insn_read_ai
;
221 s
= &dev
->subdevices
[1];
222 s
->type
= COMEDI_SUBD_AO
;
223 s
->subdev_flags
= SDF_WRITABLE
;
226 s
->range_table
= &range_unipolar10
;
227 s
->len_chanlist
= 16;
228 s
->insn_write
= dyna_pci10xx_insn_write_ao
;
231 s
= &dev
->subdevices
[2];
232 s
->type
= COMEDI_SUBD_DI
;
233 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
;
236 s
->range_table
= &range_digital
;
237 s
->len_chanlist
= 16;
238 s
->insn_bits
= dyna_pci10xx_di_insn_bits
;
241 s
= &dev
->subdevices
[3];
242 s
->type
= COMEDI_SUBD_DO
;
243 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
;
246 s
->range_table
= &range_digital
;
247 s
->len_chanlist
= 16;
249 s
->insn_bits
= dyna_pci10xx_do_insn_bits
;
251 dev_info(dev
->class_dev
, "%s attached\n", dev
->board_name
);
256 static void dyna_pci10xx_detach(struct comedi_device
*dev
)
258 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
259 struct dyna_pci10xx_private
*devpriv
= dev
->private;
262 mutex_destroy(&devpriv
->mutex
);
265 comedi_pci_disable(pcidev
);
269 static struct comedi_driver dyna_pci10xx_driver
= {
270 .driver_name
= "dyna_pci10xx",
271 .module
= THIS_MODULE
,
272 .attach_pci
= dyna_pci10xx_attach_pci
,
273 .detach
= dyna_pci10xx_detach
,
276 static int __devinit
dyna_pci10xx_pci_probe(struct pci_dev
*dev
,
277 const struct pci_device_id
*ent
)
279 return comedi_pci_auto_config(dev
, &dyna_pci10xx_driver
);
282 static void __devexit
dyna_pci10xx_pci_remove(struct pci_dev
*dev
)
284 comedi_pci_auto_unconfig(dev
);
287 static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table
) = {
288 { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG
, 0x1050) },
291 MODULE_DEVICE_TABLE(pci
, dyna_pci10xx_pci_table
);
293 static struct pci_driver dyna_pci10xx_pci_driver
= {
294 .name
= "dyna_pci10xx",
295 .id_table
= dyna_pci10xx_pci_table
,
296 .probe
= dyna_pci10xx_pci_probe
,
297 .remove
= __devexit_p(dyna_pci10xx_pci_remove
),
299 module_comedi_pci_driver(dyna_pci10xx_driver
, dyna_pci10xx_pci_driver
);
301 MODULE_LICENSE("GPL");
302 MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>");
303 MODULE_DESCRIPTION("Comedi based drivers for Dynalog PCI DAQ cards");