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