dyna_pci10xx.c revision c34fa261b0ac3a862ccd3f71ee55a16b920dfc83
1/* 2 * comedi/drivers/dyna_pci10xx.c 3 * Copyright (C) 2011 Prashant Shah, pshah.mumbai@gmail.com 4 * 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. 9 * 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. 14 * 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. 18 */ 19 20/* 21 Driver: dyna_pci10xx 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> 26 http://www.iitb.ac.in 27 Status: Stable 28 Version: 1.0 29 Device Supported : 30 - Dynalog PCI 1050 31 32 Notes : 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 35 in the card. 36 - Dynalog India Pvt. Ltd. has provided the internal register specification for 37 their cards in their manuals. 38*/ 39 40#include "../comedidev.h" 41#include <linux/mutex.h> 42 43#define PCI_VENDOR_ID_DYNALOG 0x10b5 44 45#define READ_TIMEOUT 50 46 47static const struct comedi_lrange range_pci1050_ai = { 3, { 48 BIP_RANGE(10), 49 BIP_RANGE(5), 50 UNI_RANGE(10) 51 } 52}; 53 54static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 }; 55 56struct dyna_pci10xx_private { 57 struct mutex mutex; 58 unsigned long BADR3; 59}; 60 61/******************************************************************************/ 62/************************** READ WRITE FUNCTIONS ******************************/ 63/******************************************************************************/ 64 65/* analog input callback */ 66static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, 67 struct comedi_subdevice *s, 68 struct comedi_insn *insn, unsigned int *data) 69{ 70 struct dyna_pci10xx_private *devpriv = dev->private; 71 int n, counter; 72 u16 d = 0; 73 unsigned int chan, range; 74 75 /* get the channel number and range */ 76 chan = CR_CHAN(insn->chanspec); 77 range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; 78 79 mutex_lock(&devpriv->mutex); 80 /* convert n samples */ 81 for (n = 0; n < insn->n; n++) { 82 /* trigger conversion */ 83 smp_mb(); 84 outw_p(0x0000 + range + chan, dev->iobase + 2); 85 udelay(10); 86 /* read data */ 87 for (counter = 0; counter < READ_TIMEOUT; counter++) { 88 d = inw_p(dev->iobase); 89 90 /* check if read is successful if the EOC bit is set */ 91 if (d & (1 << 15)) 92 goto conv_finish; 93 } 94 data[n] = 0; 95 printk(KERN_DEBUG "comedi: dyna_pci10xx: " 96 "timeout reading analog input\n"); 97 continue; 98conv_finish: 99 /* mask the first 4 bits - EOC bits */ 100 d &= 0x0FFF; 101 data[n] = d; 102 } 103 mutex_unlock(&devpriv->mutex); 104 105 /* return the number of samples read/written */ 106 return n; 107} 108 109/* analog output callback */ 110static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev, 111 struct comedi_subdevice *s, 112 struct comedi_insn *insn, unsigned int *data) 113{ 114 struct dyna_pci10xx_private *devpriv = dev->private; 115 int n; 116 unsigned int chan, range; 117 118 chan = CR_CHAN(insn->chanspec); 119 range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; 120 121 mutex_lock(&devpriv->mutex); 122 for (n = 0; n < insn->n; n++) { 123 smp_mb(); 124 /* trigger conversion and write data */ 125 outw_p(data[n], dev->iobase); 126 udelay(10); 127 } 128 mutex_unlock(&devpriv->mutex); 129 return n; 130} 131 132/* digital input bit interface */ 133static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev, 134 struct comedi_subdevice *s, 135 struct comedi_insn *insn, unsigned int *data) 136{ 137 struct dyna_pci10xx_private *devpriv = dev->private; 138 u16 d = 0; 139 140 mutex_lock(&devpriv->mutex); 141 smp_mb(); 142 d = inw_p(devpriv->BADR3); 143 udelay(10); 144 145 /* on return the data[0] contains output and data[1] contains input */ 146 data[1] = d; 147 data[0] = s->state; 148 mutex_unlock(&devpriv->mutex); 149 return insn->n; 150} 151 152/* digital output bit interface */ 153static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev, 154 struct comedi_subdevice *s, 155 struct comedi_insn *insn, unsigned int *data) 156{ 157 struct dyna_pci10xx_private *devpriv = dev->private; 158 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 162 */ 163 mutex_lock(&devpriv->mutex); 164 if (data[0]) { 165 s->state &= ~data[0]; 166 s->state |= (data[0] & data[1]); 167 smp_mb(); 168 outw_p(s->state, devpriv->BADR3); 169 udelay(10); 170 } 171 172 /* 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. 176 */ 177 data[1] = s->state; 178 mutex_unlock(&devpriv->mutex); 179 return insn->n; 180} 181 182static int dyna_pci10xx_attach_pci(struct comedi_device *dev, 183 struct pci_dev *pcidev) 184{ 185 struct dyna_pci10xx_private *devpriv; 186 struct comedi_subdevice *s; 187 int ret; 188 189 comedi_set_hw_dev(dev, &pcidev->dev); 190 191 dev->board_name = dev->driver->driver_name; 192 193 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL); 194 if (!devpriv) 195 return -ENOMEM; 196 dev->private = devpriv; 197 198 ret = comedi_pci_enable(pcidev, dev->board_name); 199 if (ret) 200 return ret; 201 dev->iobase = pci_resource_start(pcidev, 2); 202 devpriv->BADR3 = pci_resource_start(pcidev, 3); 203 204 mutex_init(&devpriv->mutex); 205 206 ret = comedi_alloc_subdevices(dev, 4); 207 if (ret) 208 return ret; 209 210 /* analog input */ 211 s = &dev->subdevices[0]; 212 s->type = COMEDI_SUBD_AI; 213 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; 214 s->n_chan = 16; 215 s->maxdata = 0x0FFF; 216 s->range_table = &range_pci1050_ai; 217 s->len_chanlist = 16; 218 s->insn_read = dyna_pci10xx_insn_read_ai; 219 220 /* analog output */ 221 s = &dev->subdevices[1]; 222 s->type = COMEDI_SUBD_AO; 223 s->subdev_flags = SDF_WRITABLE; 224 s->n_chan = 16; 225 s->maxdata = 0x0FFF; 226 s->range_table = &range_unipolar10; 227 s->len_chanlist = 16; 228 s->insn_write = dyna_pci10xx_insn_write_ao; 229 230 /* digital input */ 231 s = &dev->subdevices[2]; 232 s->type = COMEDI_SUBD_DI; 233 s->subdev_flags = SDF_READABLE | SDF_GROUND; 234 s->n_chan = 16; 235 s->maxdata = 1; 236 s->range_table = &range_digital; 237 s->len_chanlist = 16; 238 s->insn_bits = dyna_pci10xx_di_insn_bits; 239 240 /* digital output */ 241 s = &dev->subdevices[3]; 242 s->type = COMEDI_SUBD_DO; 243 s->subdev_flags = SDF_WRITABLE | SDF_GROUND; 244 s->n_chan = 16; 245 s->maxdata = 1; 246 s->range_table = &range_digital; 247 s->len_chanlist = 16; 248 s->state = 0; 249 s->insn_bits = dyna_pci10xx_do_insn_bits; 250 251 dev_info(dev->class_dev, "%s attached\n", dev->board_name); 252 253 return 0; 254} 255 256static void dyna_pci10xx_detach(struct comedi_device *dev) 257{ 258 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 259 struct dyna_pci10xx_private *devpriv = dev->private; 260 261 if (devpriv) 262 mutex_destroy(&devpriv->mutex); 263 if (pcidev) { 264 if (dev->iobase) 265 comedi_pci_disable(pcidev); 266 } 267} 268 269static 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, 274}; 275 276static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev, 277 const struct pci_device_id *ent) 278{ 279 return comedi_pci_auto_config(dev, &dyna_pci10xx_driver); 280} 281 282static void __devexit dyna_pci10xx_pci_remove(struct pci_dev *dev) 283{ 284 comedi_pci_auto_unconfig(dev); 285} 286 287static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = { 288 { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) }, 289 { 0 } 290}; 291MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table); 292 293static 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), 298}; 299module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver); 300 301MODULE_LICENSE("GPL"); 302MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>"); 303MODULE_DESCRIPTION("Comedi based drivers for Dynalog PCI DAQ cards"); 304