adq12b.c revision 47c6e95869228a8b464174ee0e85904a92b7baf4
1/* 2 comedi/drivers/adq12b.c 3 driver for MicroAxial ADQ12-B data acquisition and control card 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22*/ 23/* 24Driver: adq12b 25Description: driver for MicroAxial ADQ12-B data acquisition and control card 26Devices: [MicroAxial] ADQ12-B (adq12b) 27Author: jeremy theler <thelerg@ib.cnea.gov.ar> 28Updated: Thu, 21 Feb 2008 02:56:27 -0300 29Status: works 30 31Driver for the acquisition card ADQ12-B (without any add-on). 32 33 - Analog input is subdevice 0 (16 channels single-ended or 8 differential) 34 - Digital input is subdevice 1 (5 channels) 35 - Digital output is subdevice 1 (8 channels) 36 - The PACER is not supported in this version 37 38If you do not specify any options, they will default to 39 40 # comedi_config /dev/comedi0 adq12b 0x300,0,0 41 42 option 1: I/O base address. The following table is provided as a help 43 of the hardware jumpers. 44 45 address jumper JADR 46 0x300 1 (factory default) 47 0x320 2 48 0x340 3 49 0x360 4 50 0x380 5 51 0x3A0 6 52 53 option 2: unipolar/bipolar ADC selection: 0 -> bipolar, 1 -> unipolar 54 55 selection comedi_config option JUB 56 bipolar 0 2-3 (factory default) 57 unipolar 1 1-2 58 59 option 3: single-ended/differential AI selection: 0 -> SE, 1 -> differential 60 61 selection comedi_config option JCHA JCHB 62 single-ended 0 1-2 1-2 (factory default) 63 differential 1 2-3 2-3 64 65 66 written by jeremy theler <thelerg@ib.cnea.gov.ar> 67 68 instituto balseiro 69 comision nacional de energia atomica 70 universidad nacional de cuyo 71 argentina 72 73 21-feb-2008 74 + changed supported devices string (missused the [] and ()) 75 76 13-oct-2007 77 + first try 78 79 80*/ 81 82#include "../comedidev.h" 83 84// address scheme (page 2.17 of the manual) 85#define ADQ12B_SIZE 16 86 87#define ADQ12B_CTREG 0x00 88#define ADQ12B_STINR 0x00 89#define ADQ12B_OUTBR 0x04 90#define ADQ12B_ADLOW 0x08 91#define ADQ12B_ADHIG 0x09 92#define ADQ12B_CONT0 0x0c 93#define ADQ12B_CONT1 0x0d 94#define ADQ12B_CONT2 0x0e 95#define ADQ12B_COWORD 0x0f 96 97// mask of the bit at STINR to check end of conversion 98#define ADQ12B_EOC 0x20 99 100#define TIMEOUT 20 101 102// available ranges through the PGA gains 103static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { 104 BIP_RANGE( 5 ), 105 BIP_RANGE( 2 ), 106 BIP_RANGE( 1 ), 107 BIP_RANGE( 0.5 ) 108}}; 109 110static const struct comedi_lrange range_adq12b_ai_unipolar = { 4, { 111 UNI_RANGE( 5 ), 112 UNI_RANGE( 2 ), 113 UNI_RANGE( 1 ), 114 UNI_RANGE( 0.5 ) 115}}; 116 117 118 119struct adq12b_board { 120 const char *name; 121 int ai_se_chans; 122 int ai_diff_chans; 123 int ai_bits; 124 int di_chans; 125 int do_chans; 126}; 127 128static const struct adq12b_board adq12b_boards[] = { 129 { 130 name: "adq12b", 131 ai_se_chans: 16, 132 ai_diff_chans: 8, 133 ai_bits: 12, 134 di_chans: 5, 135 do_chans: 8 136 } 137// potentially, more adq-based deviced will be added 138/*, 139 name: "adq12b", 140 ai_chans: 16, // this is just for reference, hardcoded again later 141 ai_bits: 12, 142 di_chans: 8, 143 do_chans: 5 144 }*/ 145}; 146 147#define thisboard ((const struct adq12b_board *)dev->board_ptr) 148 149typedef struct{ 150 int unipolar; /* option 2 of comedi_config (1 is iobase) */ 151 int differential; /* option 3 of comedi_config */ 152 int last_channel; 153 int last_range; 154 unsigned int digital_state; 155 }adq12b_private; 156 157#define devpriv ((adq12b_private *)dev->private) 158 159/* 160 * The struct comedi_driver structure tells the Comedi core module 161 * which functions to call to configure/deconfigure (attach/detach) 162 * the board, and also about the kernel module that contains 163 * the device code. 164 */ 165static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it); 166static int adq12b_detach(struct comedi_device *dev); 167static struct comedi_driver driver_adq12b={ 168 driver_name: "adq12b", 169 module: THIS_MODULE, 170 attach: adq12b_attach, 171 detach: adq12b_detach, 172 board_name: &adq12b_boards[0].name, 173 offset: sizeof(struct adq12b_board), 174 num_names: sizeof(adq12b_boards) / sizeof(struct adq12b_board), 175}; 176 177static int adq12b_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); 178static int adq12b_di_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data); 179static int adq12b_do_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data); 180 181/* 182 * Attach is called by the Comedi core to configure the driver 183 * for a particular board. If you specified a board_name array 184 * in the driver structure, dev->board_ptr contains that 185 * address. 186 */ 187static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it) 188{ 189 struct comedi_subdevice *s; 190 unsigned long iobase; 191 int unipolar, differential; 192 193 iobase = it->options[0]; 194 unipolar = it->options[1]; 195 differential = it->options[2]; 196 197 printk("comedi%d: adq12b called with options base=0x%03lx, %s and %s\n",dev->minor, iobase, (unipolar==1)?"unipolar":"bipolar", (differential==1)?"differential":"single-ended"); 198 199 /* if no address was specified, try the default 0x300 */ 200 if (iobase == 0) { 201 printk("comedi%d: adq12b warning: I/O base address not specified. Trying the default 0x300.\n", dev->minor); 202 iobase = 0x300; 203 } 204 205 printk("comedi%d: adq12b: 0x%04lx ", dev->minor, iobase); 206 if (!request_region(iobase, ADQ12B_SIZE, "adq12b")) { 207 printk("I/O port conflict\n"); 208 return -EIO; 209 } 210 dev->iobase = iobase; 211 212/* 213 * Initialize dev->board_name. Note that we can use the "thisboard" 214 * macro now, since we just initialized it in the last line. 215 */ 216 dev->board_name = thisboard->name; 217 218/* 219 * Allocate the private structure area. alloc_private() is a 220 * convenient macro defined in comedidev.h. 221 */ 222 if(alloc_private(dev, sizeof(adq12b_private)) < 0) 223 return -ENOMEM; 224 225/* fill in devpriv structure */ 226 devpriv->unipolar = unipolar; 227 devpriv->differential = differential; 228 devpriv->digital_state = 0; 229/* initialize channel and range to -1 so we make sure we always write 230 at least once to the CTREG in the instruction */ 231 devpriv->last_channel = -1; 232 devpriv->last_range = -1; 233 234 235/* 236 * Allocate the subdevice structures. alloc_subdevice() is a 237 * convenient macro defined in comedidev.h. 238 */ 239 if(alloc_subdevices(dev, 3)<0) 240 return -ENOMEM; 241 242 s = dev->subdevices+0; 243 /* analog input subdevice */ 244 s->type = COMEDI_SUBD_AI; 245 if (differential) { 246 s->subdev_flags = SDF_READABLE|SDF_GROUND|SDF_DIFF; 247 s->n_chan = thisboard->ai_diff_chans; 248 } else { 249 s->subdev_flags = SDF_READABLE|SDF_GROUND; 250 s->n_chan = thisboard->ai_se_chans; 251 } 252 253 if (unipolar) { 254 s->range_table = &range_adq12b_ai_unipolar; 255 } else { 256 s->range_table = &range_adq12b_ai_bipolar; 257 } 258 259 s->maxdata = (1 << thisboard->ai_bits)-1; 260 261 262 s->len_chanlist = 4; /* This is the maximum chanlist length that 263 the board can handle */ 264 s->insn_read = adq12b_ai_rinsn; 265 266 267 s = dev->subdevices+1; 268 /* digital input subdevice */ 269 s->type = COMEDI_SUBD_DI; 270 s->subdev_flags = SDF_READABLE; 271 s->n_chan=thisboard->di_chans; 272 s->maxdata = 1; 273 s->range_table = &range_digital; 274 s->insn_bits = adq12b_di_insn_bits; 275 276 s = dev->subdevices+2; 277 /* digital output subdevice */ 278 s->type = COMEDI_SUBD_DO; 279 s->subdev_flags = SDF_WRITABLE; 280 s->n_chan = thisboard->do_chans; 281 s->maxdata = 1; 282 s->range_table = &range_digital; 283 s->insn_bits = adq12b_do_insn_bits; 284 285 286 printk("attached\n"); 287 288 return 0; 289} 290 291 292/* 293 * _detach is called to deconfigure a device. It should deallocate 294 * resources. 295 * This function is also called when _attach() fails, so it should be 296 * careful not to release resources that were not necessarily 297 * allocated by _attach(). dev->private and dev->subdevices are 298 * deallocated automatically by the core. 299 */ 300static int adq12b_detach(struct comedi_device *dev) 301{ 302 if (dev->iobase) 303 release_region(dev->iobase, ADQ12B_SIZE); 304 305 kfree(devpriv); 306 307 printk("comedi%d: adq12b: removed\n",dev->minor); 308 309 return 0; 310} 311 312/* 313 * "instructions" read/write data in "one-shot" or "software-triggered" 314 * mode. 315 */ 316 317static int adq12b_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) 318{ 319 int n, i; 320 int range, channel; 321 unsigned char hi, lo, status; 322 323 /* change channel and range only if it is different from the previous */ 324 range = CR_RANGE(insn->chanspec); 325 channel = CR_CHAN(insn->chanspec); 326 if (channel != devpriv->last_channel || range != devpriv->last_range) { 327 outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG); 328 comedi_udelay(50); /* wait for the mux to settle */ 329 } 330 331 /* trigger conversion */ 332 status = inb(dev->iobase + ADQ12B_ADLOW); 333 334 /* convert n samples */ 335 for(n=0; n < insn->n; n++){ 336 337 /* wait for end of convertion */ 338 i = 0; 339 do { 340// comedi_udelay(1); 341 status = inb(dev->iobase + ADQ12B_STINR); 342 status = status & ADQ12B_EOC; 343 } while (status == 0 && ++i < TIMEOUT); 344// } while (++i < 10); 345 346 /* read data */ 347 hi = inb(dev->iobase + ADQ12B_ADHIG); 348 lo = inb(dev->iobase + ADQ12B_ADLOW); 349 350 //rt_printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", channel, range, status, hi, lo); 351 data[n] = (hi << 8) | lo; 352 353 } 354 355 /* return the number of samples read/written */ 356 return n; 357} 358 359 360static int adq12b_di_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) 361{ 362 363 /* only bits 0-4 have information about digital inputs */ 364 data[1] = (inb(dev->iobase+ADQ12B_STINR) & (0x1f)); 365 366 return 2; 367} 368 369 370static int adq12b_do_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) 371{ 372 int channel; 373 374 for (channel = 0; channel < 8; channel++) 375 if (((data[0]>>channel) & 0x01) != 0) 376 outb((((data[1]>>channel)&0x01)<<3) | channel, dev->iobase + ADQ12B_OUTBR); 377 378 /* store information to retrieve when asked for reading */ 379 if (data[0]) { 380 devpriv->digital_state &= ~data[0]; 381 devpriv->digital_state |= (data[0]&data[1]); 382 } 383 384 data[1] = devpriv->digital_state; 385 386 return 2; 387} 388 389 390/* 391 * A convenient macro that defines init_module() and cleanup_module(), 392 * as necessary. 393 */ 394COMEDI_INITCLEANUP(driver_adq12b); 395