dmm32at.c revision 0707bb04be89b18ee83b5a997e36cc585f0b988d
1/* 2 comedi/drivers/dmm32at.c 3 Diamond Systems mm32at code for a Comedi driver 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: dmm32at 25Description: Diamond Systems mm32at driver. 26Devices: 27Author: Perry J. Piplani <perry.j.piplani@nasa.gov> 28Updated: Fri Jun 4 09:13:24 CDT 2004 29Status: experimental 30 31This driver is for the Diamond Systems MM-32-AT board 32http://www.diamondsystems.com/products/diamondmm32at It is being used 33on serveral projects inside NASA, without problems so far. For analog 34input commands, TRIG_EXT is not yet supported at all.. 35 36Configuration Options: 37 comedi_config /dev/comedi0 dmm32at baseaddr,irq 38*/ 39 40/* 41 * The previous block comment is used to automatically generate 42 * documentation in Comedi and Comedilib. The fields: 43 * 44 * Driver: the name of the driver 45 * Description: a short phrase describing the driver. Don't list boards. 46 * Devices: a full list of the boards that attempt to be supported by 47 * the driver. Format is "(manufacturer) board name [comedi name]", 48 * where comedi_name is the name that is used to configure the board. 49 * See the comment near board_name: in the struct comedi_driver structure 50 * below. If (manufacturer) or [comedi name] is missing, the previous 51 * value is used. 52 * Author: you 53 * Updated: date when the _documentation_ was last updated. Use 'date -R' 54 * to get a value for this. 55 * Status: a one-word description of the status. Valid values are: 56 * works - driver works correctly on most boards supported, and 57 * passes comedi_test. 58 * unknown - unknown. Usually put there by ds. 59 * experimental - may not work in any particular release. Author 60 * probably wants assistance testing it. 61 * bitrotten - driver has not been update in a long time, probably 62 * doesn't work, and probably is missing support for significant 63 * Comedi interface features. 64 * untested - author probably wrote it "blind", and is believed to 65 * work, but no confirmation. 66 * 67 * These headers should be followed by a blank line, and any comments 68 * you wish to say about the driver. The comment area is the place 69 * to put any known bugs, limitations, unsupported features, supported 70 * command triggers, whether or not commands are supported on particular 71 * subdevices, etc. 72 * 73 * Somewhere in the comment should be information about configuration 74 * options that are used with comedi_config. 75 */ 76 77#include "../comedidev.h" 78#include <linux/ioport.h> 79 80/* Board register addresses */ 81 82#define DMM32AT_MEMSIZE 0x10 83 84#define DMM32AT_CONV 0x00 85#define DMM32AT_AILSB 0x00 86#define DMM32AT_AUXDOUT 0x01 87#define DMM32AT_AIMSB 0x01 88#define DMM32AT_AILOW 0x02 89#define DMM32AT_AIHIGH 0x03 90 91#define DMM32AT_DACLSB 0x04 92#define DMM32AT_DACSTAT 0x04 93#define DMM32AT_DACMSB 0x05 94 95#define DMM32AT_FIFOCNTRL 0x07 96#define DMM32AT_FIFOSTAT 0x07 97 98#define DMM32AT_CNTRL 0x08 99#define DMM32AT_AISTAT 0x08 100 101#define DMM32AT_INTCLOCK 0x09 102 103#define DMM32AT_CNTRDIO 0x0a 104 105#define DMM32AT_AICONF 0x0b 106#define DMM32AT_AIRBACK 0x0b 107 108#define DMM32AT_CLK1 0x0d 109#define DMM32AT_CLK2 0x0e 110#define DMM32AT_CLKCT 0x0f 111 112#define DMM32AT_DIOA 0x0c 113#define DMM32AT_DIOB 0x0d 114#define DMM32AT_DIOC 0x0e 115#define DMM32AT_DIOCONF 0x0f 116 117#define dmm_inb(cdev,reg) inb((cdev->iobase)+reg) 118#define dmm_outb(cdev,reg,valu) outb(valu,(cdev->iobase)+reg) 119 120/* Board register values. */ 121 122/* DMM32AT_DACSTAT 0x04 */ 123#define DMM32AT_DACBUSY 0x80 124 125/* DMM32AT_FIFOCNTRL 0x07 */ 126#define DMM32AT_FIFORESET 0x02 127#define DMM32AT_SCANENABLE 0x04 128 129/* DMM32AT_CNTRL 0x08 */ 130#define DMM32AT_RESET 0x20 131#define DMM32AT_INTRESET 0x08 132#define DMM32AT_CLKACC 0x00 133#define DMM32AT_DIOACC 0x01 134 135/* DMM32AT_AISTAT 0x08 */ 136#define DMM32AT_STATUS 0x80 137 138/* DMM32AT_INTCLOCK 0x09 */ 139#define DMM32AT_ADINT 0x80 140#define DMM32AT_CLKSEL 0x03 141 142/* DMM32AT_CNTRDIO 0x0a */ 143#define DMM32AT_FREQ12 0x80 144 145/* DMM32AT_AICONF 0x0b */ 146#define DMM32AT_RANGE_U10 0x0c 147#define DMM32AT_RANGE_U5 0x0d 148#define DMM32AT_RANGE_B10 0x08 149#define DMM32AT_RANGE_B5 0x00 150#define DMM32AT_SCINT_20 0x00 151#define DMM32AT_SCINT_15 0x10 152#define DMM32AT_SCINT_10 0x20 153#define DMM32AT_SCINT_5 0x30 154 155/* DMM32AT_CLKCT 0x0f */ 156#define DMM32AT_CLKCT1 0x56 /* mode3 counter 1 - write low byte only */ 157#define DMM32AT_CLKCT2 0xb6 /* mode3 counter 2 - write high and low byte */ 158 159/* DMM32AT_DIOCONF 0x0f */ 160#define DMM32AT_DIENABLE 0x80 161#define DMM32AT_DIRA 0x10 162#define DMM32AT_DIRB 0x02 163#define DMM32AT_DIRCL 0x01 164#define DMM32AT_DIRCH 0x08 165 166/* board AI ranges in comedi structure */ 167static const struct comedi_lrange dmm32at_airanges = { 168 4, 169 { 170 UNI_RANGE(10), 171 UNI_RANGE(5), 172 BIP_RANGE(10), 173 BIP_RANGE(5), 174 } 175}; 176 177/* register values for above ranges */ 178static const unsigned char dmm32at_rangebits[] = { 179 DMM32AT_RANGE_U10, 180 DMM32AT_RANGE_U5, 181 DMM32AT_RANGE_B10, 182 DMM32AT_RANGE_B5, 183}; 184 185/* only one of these ranges is valid, as set by a jumper on the 186 * board. The application should only use the range set by the jumper 187 */ 188static const struct comedi_lrange dmm32at_aoranges = { 189 4, 190 { 191 UNI_RANGE(10), 192 UNI_RANGE(5), 193 BIP_RANGE(10), 194 BIP_RANGE(5), 195 } 196}; 197 198/* 199 * Board descriptions for two imaginary boards. Describing the 200 * boards in this way is optional, and completely driver-dependent. 201 * Some drivers use arrays such as this, other do not. 202 */ 203typedef struct dmm32at_board_struct { 204 const char *name; 205 int ai_chans; 206 int ai_bits; 207 const struct comedi_lrange *ai_ranges; 208 int ao_chans; 209 int ao_bits; 210 const struct comedi_lrange *ao_ranges; 211 int have_dio; 212 int dio_chans; 213} dmm32at_board; 214static const dmm32at_board dmm32at_boards[] = { 215 { 216 name: "dmm32at", 217 ai_chans:32, 218 ai_bits: 16, 219 ai_ranges:&dmm32at_airanges, 220 ao_chans:4, 221 ao_bits: 12, 222 ao_ranges:&dmm32at_aoranges, 223 have_dio:1, 224 dio_chans:24, 225 }, 226}; 227 228/* 229 * Useful for shorthand access to the particular board structure 230 */ 231#define thisboard ((const dmm32at_board *)dev->board_ptr) 232 233/* this structure is for data unique to this hardware driver. If 234 * several hardware drivers keep similar information in this structure, 235 * feel free to suggest moving the variable to the struct comedi_device struct. 236 */ 237typedef struct { 238 239 int data; 240 int ai_inuse; 241 unsigned int ai_scans_left; 242 243 /* Used for AO readback */ 244 unsigned int ao_readback[4]; 245 unsigned char dio_config; 246 247} dmm32at_private; 248 249/* 250 * most drivers define the following macro to make it easy to 251 * access the private structure. 252 */ 253#define devpriv ((dmm32at_private *)dev->private) 254 255/* 256 * The struct comedi_driver structure tells the Comedi core module 257 * which functions to call to configure/deconfigure (attach/detach) 258 * the board, and also about the kernel module that contains 259 * the device code. 260 */ 261static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * it); 262static int dmm32at_detach(struct comedi_device * dev); 263static struct comedi_driver driver_dmm32at = { 264 driver_name:"dmm32at", 265 module:THIS_MODULE, 266 attach:dmm32at_attach, 267 detach:dmm32at_detach, 268/* It is not necessary to implement the following members if you are 269 * writing a driver for a ISA PnP or PCI card */ 270/* Most drivers will support multiple types of boards by 271 * having an array of board structures. These were defined 272 * in dmm32at_boards[] above. Note that the element 'name' 273 * was first in the structure -- Comedi uses this fact to 274 * extract the name of the board without knowing any details 275 * about the structure except for its length. 276 * When a device is attached (by comedi_config), the name 277 * of the device is given to Comedi, and Comedi tries to 278 * match it by going through the list of board names. If 279 * there is a match, the address of the pointer is put 280 * into dev->board_ptr and driver->attach() is called. 281 * 282 * Note that these are not necessary if you can determine 283 * the type of board in software. ISA PnP, PCI, and PCMCIA 284 * devices are such boards. 285 */ 286 board_name:&dmm32at_boards[0].name, 287 offset:sizeof(dmm32at_board), 288 num_names:sizeof(dmm32at_boards) / sizeof(dmm32at_board), 289}; 290 291/* prototypes for driver functions below */ 292static int dmm32at_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 293 struct comedi_insn * insn, unsigned int * data); 294static int dmm32at_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, 295 struct comedi_insn * insn, unsigned int * data); 296static int dmm32at_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 297 struct comedi_insn * insn, unsigned int * data); 298static int dmm32at_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 299 struct comedi_insn * insn, unsigned int * data); 300static int dmm32at_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 301 struct comedi_insn * insn, unsigned int * data); 302static int dmm32at_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, 303 struct comedi_cmd * cmd); 304static int dmm32at_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); 305static int dmm32at_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); 306static int dmm32at_ns_to_timer(unsigned int *ns, int round); 307static irqreturn_t dmm32at_isr(int irq, void *d PT_REGS_ARG); 308void dmm32at_setaitimer(struct comedi_device * dev, unsigned int nansec); 309 310/* 311 * Attach is called by the Comedi core to configure the driver 312 * for a particular board. If you specified a board_name array 313 * in the driver structure, dev->board_ptr contains that 314 * address. 315 */ 316static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * it) 317{ 318 int ret; 319 struct comedi_subdevice *s; 320 unsigned char aihi, ailo, fifostat, aistat, intstat, airback; 321 unsigned long iobase; 322 unsigned int irq; 323 324 iobase = it->options[0]; 325 irq = it->options[1]; 326 327 printk("comedi%d: dmm32at: attaching\n", dev->minor); 328 printk("dmm32at: probing at address 0x%04lx, irq %u\n", iobase, irq); 329 330 /* register address space */ 331 if (!request_region(iobase, DMM32AT_MEMSIZE, thisboard->name)) { 332 printk("I/O port conflict\n"); 333 return -EIO; 334 } 335 dev->iobase = iobase; 336 337 /* the following just makes sure the board is there and gets 338 it to a known state */ 339 340 /* reset the board */ 341 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_RESET); 342 343 /* allow a millisecond to reset */ 344 udelay(1000); 345 346 /* zero scan and fifo control */ 347 dmm_outb(dev, DMM32AT_FIFOCNTRL, 0x0); 348 349 /* zero interrupt and clock control */ 350 dmm_outb(dev, DMM32AT_INTCLOCK, 0x0); 351 352 /* write a test channel range, the high 3 bits should drop */ 353 dmm_outb(dev, DMM32AT_AILOW, 0x80); 354 dmm_outb(dev, DMM32AT_AIHIGH, 0xff); 355 356 /* set the range at 10v unipolar */ 357 dmm_outb(dev, DMM32AT_AICONF, DMM32AT_RANGE_U10); 358 359 /* should take 10 us to settle, here's a hundred */ 360 udelay(100); 361 362 /* read back the values */ 363 ailo = dmm_inb(dev, DMM32AT_AILOW); 364 aihi = dmm_inb(dev, DMM32AT_AIHIGH); 365 fifostat = dmm_inb(dev, DMM32AT_FIFOSTAT); 366 aistat = dmm_inb(dev, DMM32AT_AISTAT); 367 intstat = dmm_inb(dev, DMM32AT_INTCLOCK); 368 airback = dmm_inb(dev, DMM32AT_AIRBACK); 369 370 printk("dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n", 371 ailo, aihi, fifostat); 372 printk("dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n", 373 aistat, intstat, airback); 374 375 if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) || 376 (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) { 377 printk("dmmat32: board detection failed\n"); 378 return -EIO; 379 } 380 381 /* board is there, register interrupt */ 382 if (irq) { 383 ret = comedi_request_irq(irq, dmm32at_isr, 0, thisboard->name, 384 dev); 385 if (ret < 0) { 386 printk("irq conflict\n"); 387 return ret; 388 } 389 dev->irq = irq; 390 } 391 392/* 393 * If you can probe the device to determine what device in a series 394 * it is, this is the place to do it. Otherwise, dev->board_ptr 395 * should already be initialized. 396 */ 397 //dev->board_ptr = dmm32at_probe(dev); 398 399/* 400 * Initialize dev->board_name. Note that we can use the "thisboard" 401 * macro now, since we just initialized it in the last line. 402 */ 403 dev->board_name = thisboard->name; 404 405/* 406 * Allocate the private structure area. alloc_private() is a 407 * convenient macro defined in comedidev.h. 408 */ 409 if (alloc_private(dev, sizeof(dmm32at_private)) < 0) 410 return -ENOMEM; 411 412/* 413 * Allocate the subdevice structures. alloc_subdevice() is a 414 * convenient macro defined in comedidev.h. 415 */ 416 if (alloc_subdevices(dev, 3) < 0) 417 return -ENOMEM; 418 419 s = dev->subdevices + 0; 420 dev->read_subdev = s; 421 /* analog input subdevice */ 422 s->type = COMEDI_SUBD_AI; 423 /* we support single-ended (ground) and differential */ 424 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; 425 s->n_chan = thisboard->ai_chans; 426 s->maxdata = (1 << thisboard->ai_bits) - 1; 427 s->range_table = thisboard->ai_ranges; 428 s->len_chanlist = 32; /* This is the maximum chanlist length that 429 the board can handle */ 430 s->insn_read = dmm32at_ai_rinsn; 431 s->do_cmd = dmm32at_ai_cmd; 432 s->do_cmdtest = dmm32at_ai_cmdtest; 433 s->cancel = dmm32at_ai_cancel; 434 435 s = dev->subdevices + 1; 436 /* analog output subdevice */ 437 s->type = COMEDI_SUBD_AO; 438 s->subdev_flags = SDF_WRITABLE; 439 s->n_chan = thisboard->ao_chans; 440 s->maxdata = (1 << thisboard->ao_bits) - 1; 441 s->range_table = thisboard->ao_ranges; 442 s->insn_write = dmm32at_ao_winsn; 443 s->insn_read = dmm32at_ao_rinsn; 444 445 s = dev->subdevices + 2; 446 /* digital i/o subdevice */ 447 if (thisboard->have_dio) { 448 449 /* get access to the DIO regs */ 450 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC); 451 /* set the DIO's to the defualt input setting */ 452 devpriv->dio_config = DMM32AT_DIRA | DMM32AT_DIRB | 453 DMM32AT_DIRCL | DMM32AT_DIRCH | DMM32AT_DIENABLE; 454 dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config); 455 456 /* set up the subdevice */ 457 s->type = COMEDI_SUBD_DIO; 458 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 459 s->n_chan = thisboard->dio_chans; 460 s->maxdata = 1; 461 s->state = 0; 462 s->range_table = &range_digital; 463 s->insn_bits = dmm32at_dio_insn_bits; 464 s->insn_config = dmm32at_dio_insn_config; 465 } else { 466 s->type = COMEDI_SUBD_UNUSED; 467 } 468 469 /* success */ 470 printk("comedi%d: dmm32at: attached\n", dev->minor); 471 472 return 1; 473 474} 475 476/* 477 * _detach is called to deconfigure a device. It should deallocate 478 * resources. 479 * This function is also called when _attach() fails, so it should be 480 * careful not to release resources that were not necessarily 481 * allocated by _attach(). dev->private and dev->subdevices are 482 * deallocated automatically by the core. 483 */ 484static int dmm32at_detach(struct comedi_device * dev) 485{ 486 printk("comedi%d: dmm32at: remove\n", dev->minor); 487 if (dev->irq) 488 comedi_free_irq(dev->irq, dev); 489 if (dev->iobase) 490 release_region(dev->iobase, DMM32AT_MEMSIZE); 491 492 return 0; 493} 494 495/* 496 * "instructions" read/write data in "one-shot" or "software-triggered" 497 * mode. 498 */ 499 500static int dmm32at_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 501 struct comedi_insn * insn, unsigned int * data) 502{ 503 int n, i; 504 unsigned int d; 505 unsigned char status; 506 unsigned short msb, lsb; 507 unsigned char chan; 508 int range; 509 510 /* get the channel and range number */ 511 512 chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1); 513 range = CR_RANGE(insn->chanspec); 514 515 //printk("channel=0x%02x, range=%d\n",chan,range); 516 517 /* zero scan and fifo control and reset fifo */ 518 dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET); 519 520 /* write the ai channel range regs */ 521 dmm_outb(dev, DMM32AT_AILOW, chan); 522 dmm_outb(dev, DMM32AT_AIHIGH, chan); 523 /* set the range bits */ 524 dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]); 525 526 /* wait for circuit to settle */ 527 for (i = 0; i < 40000; i++) { 528 status = dmm_inb(dev, DMM32AT_AIRBACK); 529 if ((status & DMM32AT_STATUS) == 0) 530 break; 531 } 532 if (i == 40000) { 533 printk("timeout\n"); 534 return -ETIMEDOUT; 535 } 536 537 /* convert n samples */ 538 for (n = 0; n < insn->n; n++) { 539 /* trigger conversion */ 540 dmm_outb(dev, DMM32AT_CONV, 0xff); 541 /* wait for conversion to end */ 542 for (i = 0; i < 40000; i++) { 543 status = dmm_inb(dev, DMM32AT_AISTAT); 544 if ((status & DMM32AT_STATUS) == 0) 545 break; 546 } 547 if (i == 40000) { 548 printk("timeout\n"); 549 return -ETIMEDOUT; 550 } 551 552 /* read data */ 553 lsb = dmm_inb(dev, DMM32AT_AILSB); 554 msb = dmm_inb(dev, DMM32AT_AIMSB); 555 556 /* invert sign bit to make range unsigned, this is an 557 idiosyncracy of the diamond board, it return 558 conversions as a signed value, i.e. -32768 to 559 32767, flipping the bit and interpreting it as 560 signed gives you a range of 0 to 65535 which is 561 used by comedi */ 562 d = ((msb ^ 0x0080) << 8) + lsb; 563 564 data[n] = d; 565 } 566 567 /* return the number of samples read/written */ 568 return n; 569} 570 571static int dmm32at_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, 572 struct comedi_cmd * cmd) 573{ 574 int err = 0; 575 int tmp; 576 int start_chan, gain, i; 577 578 //printk("dmmat32 in command test\n"); 579 580 /* cmdtest tests a particular command to see if it is valid. 581 * Using the cmdtest ioctl, a user can create a valid cmd 582 * and then have it executes by the cmd ioctl. 583 * 584 * cmdtest returns 1,2,3,4 or 0, depending on which tests 585 * the command passes. */ 586 587 /* step 1: make sure trigger sources are trivially valid */ 588 589 tmp = cmd->start_src; 590 cmd->start_src &= TRIG_NOW; 591 if (!cmd->start_src || tmp != cmd->start_src) 592 err++; 593 594 tmp = cmd->scan_begin_src; 595 cmd->scan_begin_src &= TRIG_TIMER /*| TRIG_EXT */ ; 596 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 597 err++; 598 599 tmp = cmd->convert_src; 600 cmd->convert_src &= TRIG_TIMER /*| TRIG_EXT */ ; 601 if (!cmd->convert_src || tmp != cmd->convert_src) 602 err++; 603 604 tmp = cmd->scan_end_src; 605 cmd->scan_end_src &= TRIG_COUNT; 606 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 607 err++; 608 609 tmp = cmd->stop_src; 610 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 611 if (!cmd->stop_src || tmp != cmd->stop_src) 612 err++; 613 614 if (err) 615 return 1; 616 617 /* step 2: make sure trigger sources are unique and mutually compatible */ 618 619 /* note that mutual compatiblity is not an issue here */ 620 if (cmd->scan_begin_src != TRIG_TIMER && 621 cmd->scan_begin_src != TRIG_EXT) 622 err++; 623 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) 624 err++; 625 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 626 err++; 627 628 if (err) 629 return 2; 630 631 /* step 3: make sure arguments are trivially compatible */ 632 633 if (cmd->start_arg != 0) { 634 cmd->start_arg = 0; 635 err++; 636 } 637#define MAX_SCAN_SPEED 1000000 /* in nanoseconds */ 638#define MIN_SCAN_SPEED 1000000000 /* in nanoseconds */ 639 640 if (cmd->scan_begin_src == TRIG_TIMER) { 641 if (cmd->scan_begin_arg < MAX_SCAN_SPEED) { 642 cmd->scan_begin_arg = MAX_SCAN_SPEED; 643 err++; 644 } 645 if (cmd->scan_begin_arg > MIN_SCAN_SPEED) { 646 cmd->scan_begin_arg = MIN_SCAN_SPEED; 647 err++; 648 } 649 } else { 650 /* external trigger */ 651 /* should be level/edge, hi/lo specification here */ 652 /* should specify multiple external triggers */ 653 if (cmd->scan_begin_arg > 9) { 654 cmd->scan_begin_arg = 9; 655 err++; 656 } 657 } 658 if (cmd->convert_src == TRIG_TIMER) { 659 if (cmd->convert_arg >= 17500) 660 cmd->convert_arg = 20000; 661 else if (cmd->convert_arg >= 12500) 662 cmd->convert_arg = 15000; 663 else if (cmd->convert_arg >= 7500) 664 cmd->convert_arg = 10000; 665 else 666 cmd->convert_arg = 5000; 667 668 } else { 669 /* external trigger */ 670 /* see above */ 671 if (cmd->convert_arg > 9) { 672 cmd->convert_arg = 9; 673 err++; 674 } 675 } 676 677 if (cmd->scan_end_arg != cmd->chanlist_len) { 678 cmd->scan_end_arg = cmd->chanlist_len; 679 err++; 680 } 681 if (cmd->stop_src == TRIG_COUNT) { 682 if (cmd->stop_arg > 0xfffffff0) { 683 cmd->stop_arg = 0xfffffff0; 684 err++; 685 } 686 if (cmd->stop_arg == 0) { 687 cmd->stop_arg = 1; 688 err++; 689 } 690 } else { 691 /* TRIG_NONE */ 692 if (cmd->stop_arg != 0) { 693 cmd->stop_arg = 0; 694 err++; 695 } 696 } 697 698 if (err) 699 return 3; 700 701 /* step 4: fix up any arguments */ 702 703 if (cmd->scan_begin_src == TRIG_TIMER) { 704 tmp = cmd->scan_begin_arg; 705 dmm32at_ns_to_timer(&cmd->scan_begin_arg, 706 cmd->flags & TRIG_ROUND_MASK); 707 if (tmp != cmd->scan_begin_arg) 708 err++; 709 } 710 if (cmd->convert_src == TRIG_TIMER) { 711 tmp = cmd->convert_arg; 712 dmm32at_ns_to_timer(&cmd->convert_arg, 713 cmd->flags & TRIG_ROUND_MASK); 714 if (tmp != cmd->convert_arg) 715 err++; 716 if (cmd->scan_begin_src == TRIG_TIMER && 717 cmd->scan_begin_arg < 718 cmd->convert_arg * cmd->scan_end_arg) { 719 cmd->scan_begin_arg = 720 cmd->convert_arg * cmd->scan_end_arg; 721 err++; 722 } 723 } 724 725 if (err) 726 return 4; 727 728 /* step 5 check the channel list, the channel list for this 729 board must be consecutive and gains must be the same */ 730 731 if (cmd->chanlist) { 732 gain = CR_RANGE(cmd->chanlist[0]); 733 start_chan = CR_CHAN(cmd->chanlist[0]); 734 for (i = 1; i < cmd->chanlist_len; i++) { 735 if (CR_CHAN(cmd->chanlist[i]) != 736 (start_chan + i) % s->n_chan) { 737 comedi_error(dev, 738 "entries in chanlist must be consecutive channels, counting upwards\n"); 739 err++; 740 } 741 if (CR_RANGE(cmd->chanlist[i]) != gain) { 742 comedi_error(dev, 743 "entries in chanlist must all have the same gain\n"); 744 err++; 745 } 746 } 747 } 748 749 if (err) 750 return 5; 751 752 return 0; 753} 754 755static int dmm32at_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) 756{ 757 struct comedi_cmd *cmd = &s->async->cmd; 758 int i, range; 759 unsigned char chanlo, chanhi, status; 760 761 if (!cmd->chanlist) 762 return -EINVAL; 763 764 /* get the channel list and range */ 765 chanlo = CR_CHAN(cmd->chanlist[0]) & (s->n_chan - 1); 766 chanhi = chanlo + cmd->chanlist_len - 1; 767 if (chanhi >= s->n_chan) 768 return -EINVAL; 769 range = CR_RANGE(cmd->chanlist[0]); 770 771 /* reset fifo */ 772 dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET); 773 774 /* set scan enable */ 775 dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_SCANENABLE); 776 777 /* write the ai channel range regs */ 778 dmm_outb(dev, DMM32AT_AILOW, chanlo); 779 dmm_outb(dev, DMM32AT_AIHIGH, chanhi); 780 781 /* set the range bits */ 782 dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]); 783 784 /* reset the interrupt just in case */ 785 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET); 786 787 if (cmd->stop_src == TRIG_COUNT) 788 devpriv->ai_scans_left = cmd->stop_arg; 789 else { /* TRIG_NONE */ 790 devpriv->ai_scans_left = 0xffffffff; /* indicates TRIG_NONE to isr */ 791 } 792 793 /* wait for circuit to settle */ 794 for (i = 0; i < 40000; i++) { 795 status = dmm_inb(dev, DMM32AT_AIRBACK); 796 if ((status & DMM32AT_STATUS) == 0) 797 break; 798 } 799 if (i == 40000) { 800 printk("timeout\n"); 801 return -ETIMEDOUT; 802 } 803 804 if (devpriv->ai_scans_left > 1) { 805 /* start the clock and enable the interrupts */ 806 dmm32at_setaitimer(dev, cmd->scan_begin_arg); 807 } else { 808 /* start the interrups and initiate a single scan */ 809 dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT); 810 dmm_outb(dev, DMM32AT_CONV, 0xff); 811 } 812 813/* printk("dmmat32 in command\n"); */ 814 815/* for(i=0;i<cmd->chanlist_len;i++) */ 816/* comedi_buf_put(s->async,i*100); */ 817 818/* s->async->events |= COMEDI_CB_EOA; */ 819/* comedi_event(dev, s); */ 820 821 return 0; 822 823} 824 825static int dmm32at_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) 826{ 827 devpriv->ai_scans_left = 1; 828 return 0; 829} 830 831static irqreturn_t dmm32at_isr(int irq, void *d PT_REGS_ARG) 832{ 833 unsigned char intstat; 834 unsigned int samp; 835 unsigned short msb, lsb; 836 int i; 837 struct comedi_device *dev = d; 838 839 if (!dev->attached) { 840 comedi_error(dev, "spurious interrupt"); 841 return IRQ_HANDLED; 842 } 843 844 intstat = dmm_inb(dev, DMM32AT_INTCLOCK); 845 846 if (intstat & DMM32AT_ADINT) { 847 struct comedi_subdevice *s = dev->read_subdev; 848 struct comedi_cmd *cmd = &s->async->cmd; 849 850 for (i = 0; i < cmd->chanlist_len; i++) { 851 /* read data */ 852 lsb = dmm_inb(dev, DMM32AT_AILSB); 853 msb = dmm_inb(dev, DMM32AT_AIMSB); 854 855 /* invert sign bit to make range unsigned */ 856 samp = ((msb ^ 0x0080) << 8) + lsb; 857 comedi_buf_put(s->async, samp); 858 } 859 860 if (devpriv->ai_scans_left != 0xffffffff) { /* TRIG_COUNT */ 861 devpriv->ai_scans_left--; 862 if (devpriv->ai_scans_left == 0) { 863 /* disable further interrupts and clocks */ 864 dmm_outb(dev, DMM32AT_INTCLOCK, 0x0); 865 /* set the buffer to be flushed with an EOF */ 866 s->async->events |= COMEDI_CB_EOA; 867 } 868 869 } 870 /* flush the buffer */ 871 comedi_event(dev, s); 872 } 873 874 /* reset the interrupt */ 875 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET); 876 return IRQ_HANDLED; 877} 878 879/* This function doesn't require a particular form, this is just 880 * what happens to be used in some of the drivers. It should 881 * convert ns nanoseconds to a counter value suitable for programming 882 * the device. Also, it should adjust ns so that it cooresponds to 883 * the actual time that the device will use. */ 884static int dmm32at_ns_to_timer(unsigned int *ns, int round) 885{ 886 /* trivial timer */ 887 /* if your timing is done through two cascaded timers, the 888 * i8253_cascade_ns_to_timer() function in 8253.h can be 889 * very helpful. There are also i8254_load() and i8254_mm_load() 890 * which can be used to load values into the ubiquitous 8254 counters 891 */ 892 893 return *ns; 894} 895 896static int dmm32at_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, 897 struct comedi_insn * insn, unsigned int * data) 898{ 899 int i; 900 int chan = CR_CHAN(insn->chanspec); 901 unsigned char hi, lo, status; 902 903 /* Writing a list of values to an AO channel is probably not 904 * very useful, but that's how the interface is defined. */ 905 for (i = 0; i < insn->n; i++) { 906 907 devpriv->ao_readback[chan] = data[i]; 908 909 /* get the low byte */ 910 lo = data[i] & 0x00ff; 911 /* high byte also contains channel number */ 912 hi = (data[i] >> 8) + chan * (1 << 6); 913 //printk("writing 0x%02x 0x%02x\n",hi,lo); 914 /* write the low and high values to the board */ 915 dmm_outb(dev, DMM32AT_DACLSB, lo); 916 dmm_outb(dev, DMM32AT_DACMSB, hi); 917 918 /* wait for circuit to settle */ 919 for (i = 0; i < 40000; i++) { 920 status = dmm_inb(dev, DMM32AT_DACSTAT); 921 if ((status & DMM32AT_DACBUSY) == 0) 922 break; 923 } 924 if (i == 40000) { 925 printk("timeout\n"); 926 return -ETIMEDOUT; 927 } 928 /* dummy read to update trigger the output */ 929 status = dmm_inb(dev, DMM32AT_DACMSB); 930 931 } 932 933 /* return the number of samples read/written */ 934 return i; 935} 936 937/* AO subdevices should have a read insn as well as a write insn. 938 * Usually this means copying a value stored in devpriv. */ 939static int dmm32at_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 940 struct comedi_insn * insn, unsigned int * data) 941{ 942 int i; 943 int chan = CR_CHAN(insn->chanspec); 944 945 for (i = 0; i < insn->n; i++) 946 data[i] = devpriv->ao_readback[chan]; 947 948 return i; 949} 950 951/* DIO devices are slightly special. Although it is possible to 952 * implement the insn_read/insn_write interface, it is much more 953 * useful to applications if you implement the insn_bits interface. 954 * This allows packed reading/writing of the DIO channels. The 955 * comedi core can convert between insn_bits and insn_read/write */ 956static int dmm32at_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 957 struct comedi_insn * insn, unsigned int * data) 958{ 959 unsigned char diobits; 960 961 if (insn->n != 2) 962 return -EINVAL; 963 964 /* The insn data is a mask in data[0] and the new data 965 * in data[1], each channel cooresponding to a bit. */ 966 if (data[0]) { 967 s->state &= ~data[0]; 968 s->state |= data[0] & data[1]; 969 /* Write out the new digital output lines */ 970 //outw(s->state,dev->iobase + DMM32AT_DIO); 971 } 972 973 /* get access to the DIO regs */ 974 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC); 975 976 /* if either part of dio is set for output */ 977 if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || 978 ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { 979 diobits = (s->state & 0x00ff0000) >> 16; 980 dmm_outb(dev, DMM32AT_DIOC, diobits); 981 } 982 if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { 983 diobits = (s->state & 0x0000ff00) >> 8; 984 dmm_outb(dev, DMM32AT_DIOB, diobits); 985 } 986 if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { 987 diobits = (s->state & 0x000000ff); 988 dmm_outb(dev, DMM32AT_DIOA, diobits); 989 } 990 991 /* now read the state back in */ 992 s->state = dmm_inb(dev, DMM32AT_DIOC); 993 s->state <<= 8; 994 s->state |= dmm_inb(dev, DMM32AT_DIOB); 995 s->state <<= 8; 996 s->state |= dmm_inb(dev, DMM32AT_DIOA); 997 data[1] = s->state; 998 999 /* on return, data[1] contains the value of the digital 1000 * input and output lines. */ 1001 //data[1]=inw(dev->iobase + DMM32AT_DIO); 1002 /* or we could just return the software copy of the output values if 1003 * it was a purely digital output subdevice */ 1004 //data[1]=s->state; 1005 1006 return 2; 1007} 1008 1009static int dmm32at_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 1010 struct comedi_insn * insn, unsigned int * data) 1011{ 1012 unsigned char chanbit; 1013 int chan = CR_CHAN(insn->chanspec); 1014 1015 if (insn->n != 1) 1016 return -EINVAL; 1017 1018 if (chan < 8) 1019 chanbit = DMM32AT_DIRA; 1020 else if (chan < 16) 1021 chanbit = DMM32AT_DIRB; 1022 else if (chan < 20) 1023 chanbit = DMM32AT_DIRCL; 1024 else 1025 chanbit = DMM32AT_DIRCH; 1026 1027 /* The input or output configuration of each digital line is 1028 * configured by a special insn_config instruction. chanspec 1029 * contains the channel to be changed, and data[0] contains the 1030 * value COMEDI_INPUT or COMEDI_OUTPUT. */ 1031 1032 /* if output clear the bit, otherwise set it */ 1033 if (data[0] == COMEDI_OUTPUT) { 1034 devpriv->dio_config &= ~chanbit; 1035 } else { 1036 devpriv->dio_config |= chanbit; 1037 } 1038 /* get access to the DIO regs */ 1039 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC); 1040 /* set the DIO's to the new configuration setting */ 1041 dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config); 1042 1043 return 1; 1044} 1045 1046void dmm32at_setaitimer(struct comedi_device * dev, unsigned int nansec) 1047{ 1048 unsigned char lo1, lo2, hi2; 1049 unsigned short both2; 1050 1051 /* based on 10mhz clock */ 1052 lo1 = 200; 1053 both2 = nansec / 20000; 1054 hi2 = (both2 & 0xff00) >> 8; 1055 lo2 = both2 & 0x00ff; 1056 1057 /* set the counter frequency to 10mhz */ 1058 dmm_outb(dev, DMM32AT_CNTRDIO, 0); 1059 1060 /* get access to the clock regs */ 1061 dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_CLKACC); 1062 1063 /* write the counter 1 control word and low byte to counter */ 1064 dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT1); 1065 dmm_outb(dev, DMM32AT_CLK1, lo1); 1066 1067 /* write the counter 2 control word and low byte then to counter */ 1068 dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT2); 1069 dmm_outb(dev, DMM32AT_CLK2, lo2); 1070 dmm_outb(dev, DMM32AT_CLK2, hi2); 1071 1072 /* enable the ai conversion interrupt and the clock to start scans */ 1073 dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT | DMM32AT_CLKSEL); 1074 1075} 1076 1077/* 1078 * A convenient macro that defines init_module() and cleanup_module(), 1079 * as necessary. 1080 */ 1081COMEDI_INITCLEANUP(driver_dmm32at); 1082