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