dt282x.c revision 18e7e78e945527d9cb570a17f0835815f1794c2f
1/* 2 comedi/drivers/dt282x.c 3 Hardware driver for Data Translation DT2821 series 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 1997-8 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: dt282x 25Description: Data Translation DT2821 series (including DT-EZ) 26Author: ds 27Devices: [Data Translation] DT2821 (dt2821), 28 DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f), 29 DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g), 30 DT2823 (dt2823), 31 DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825), 32 DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez), 33 DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl) 34Status: complete 35Updated: Wed, 22 Aug 2001 17:11:34 -0700 36 37Configuration options: 38 [0] - I/O port base address 39 [1] - IRQ 40 [2] - DMA 1 41 [3] - DMA 2 42 [4] - AI jumpered for 0=single ended, 1=differential 43 [5] - AI jumpered for 0=straight binary, 1=2's complement 44 [6] - AO 0 jumpered for 0=straight binary, 1=2's complement 45 [7] - AO 1 jumpered for 0=straight binary, 1=2's complement 46 [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5] 47 [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5], 48 4=[-2.5,2.5] 49 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5], 50 4=[-2.5,2.5] 51 52Notes: 53 - AO commands might be broken. 54 - If you try to run a command on both the AI and AO subdevices 55 simultaneously, bad things will happen. The driver needs to 56 be fixed to check for this situation and return an error. 57*/ 58 59#include "../comedidev.h" 60 61#include <linux/gfp.h> 62#include <linux/ioport.h> 63#include <linux/interrupt.h> 64#include <asm/dma.h> 65#include "comedi_fc.h" 66 67#define DEBUG 68 69#define DT2821_TIMEOUT 100 /* 500 us */ 70#define DT2821_SIZE 0x10 71 72/* 73 * Registers in the DT282x 74 */ 75 76#define DT2821_ADCSR 0x00 /* A/D Control/Status */ 77#define DT2821_CHANCSR 0x02 /* Channel Control/Status */ 78#define DT2821_ADDAT 0x04 /* A/D data */ 79#define DT2821_DACSR 0x06 /* D/A Control/Status */ 80#define DT2821_DADAT 0x08 /* D/A data */ 81#define DT2821_DIODAT 0x0a /* digital data */ 82#define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */ 83#define DT2821_TMRCTR 0x0e /* Timer/Counter */ 84 85/* 86 * At power up, some registers are in a well-known state. The 87 * masks and values are as follows: 88 */ 89 90#define DT2821_ADCSR_MASK 0xfff0 91#define DT2821_ADCSR_VAL 0x7c00 92 93#define DT2821_CHANCSR_MASK 0xf0f0 94#define DT2821_CHANCSR_VAL 0x70f0 95 96#define DT2821_DACSR_MASK 0x7c93 97#define DT2821_DACSR_VAL 0x7c90 98 99#define DT2821_SUPCSR_MASK 0xf8ff 100#define DT2821_SUPCSR_VAL 0x0000 101 102#define DT2821_TMRCTR_MASK 0xff00 103#define DT2821_TMRCTR_VAL 0xf000 104 105/* 106 * Bit fields of each register 107 */ 108 109/* ADCSR */ 110 111#define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */ 112#define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */ 113 /* 0x7c00 read as 1's */ 114#define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */ 115#define DT2821_ADDONE 0x0080 /* (R) A/D done */ 116#define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */ 117 /* 0x0030 gain select */ 118 /* 0x000f channel select */ 119 120/* CHANCSR */ 121 122#define DT2821_LLE 0x8000 /* (R/W) Load List Enable */ 123 /* 0x7000 read as 1's */ 124 /* 0x0f00 (R) present address */ 125 /* 0x00f0 read as 1's */ 126 /* 0x000f (R) number of entries - 1 */ 127 128/* DACSR */ 129 130#define DT2821_DAERR 0x8000 /* (R) D/A error */ 131#define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */ 132#define DT2821_SSEL 0x0100 /* (R/W) single channel select */ 133#define DT2821_DACRDY 0x0080 /* (R) DAC ready */ 134#define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */ 135#define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */ 136#define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */ 137#define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */ 138 139/* SUPCSR */ 140 141#define DT2821_DMAD 0x8000 /* (R) DMA done */ 142#define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */ 143#define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */ 144#define DT2821_DDMA 0x1000 /* (R/W) dual DMA */ 145#define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */ 146#define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */ 147#define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */ 148#define DT2821_SCDN 0x0100 /* (R) scan done */ 149#define DT2821_DACON 0x0080 /* (W) DAC single conversion */ 150#define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */ 151#define DT2821_DACINIT 0x0020 /* (W) D/A initialize */ 152#define DT2821_PRLD 0x0010 /* (W) preload multiplexer */ 153#define DT2821_STRIG 0x0008 /* (W) software trigger */ 154#define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */ 155#define DT2821_XCLK 0x0002 /* (R/W) external clock enable */ 156#define DT2821_BDINIT 0x0001 /* (W) initialize board */ 157 158static const struct comedi_lrange range_dt282x_ai_lo_bipolar = { 159 4, { 160 RANGE(-10, 10), 161 RANGE(-5, 5), 162 RANGE(-2.5, 2.5), 163 RANGE(-1.25, 1.25) 164 } 165}; 166 167static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 168 4, { 169 RANGE(0, 10), 170 RANGE(0, 5), 171 RANGE(0, 2.5), 172 RANGE(0, 1.25) 173 } 174}; 175 176static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 177 4, { 178 RANGE(-5, 5), 179 RANGE(-2.5, 2.5), 180 RANGE(-1.25, 1.25), 181 RANGE(-0.625, 0.625) 182 } 183}; 184 185static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 186 4, { 187 RANGE(0, 5), 188 RANGE(0, 2.5), 189 RANGE(0, 1.25), 190 RANGE(0, 0.625), 191 } 192}; 193 194static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 195 4, { 196 RANGE(-10, 10), 197 RANGE(-1, 1), 198 RANGE(-0.1, 0.1), 199 RANGE(-0.02, 0.02) 200 } 201}; 202 203static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 204 4, { 205 RANGE(0, 10), 206 RANGE(0, 1), 207 RANGE(0, 0.1), 208 RANGE(0, 0.02) 209 } 210}; 211 212struct dt282x_board { 213 const char *name; 214 int adbits; 215 int adchan_se; 216 int adchan_di; 217 int ai_speed; 218 int ispgl; 219 int dachan; 220 int dabits; 221}; 222 223static const struct dt282x_board boardtypes[] = { 224 {.name = "dt2821", 225 .adbits = 12, 226 .adchan_se = 16, 227 .adchan_di = 8, 228 .ai_speed = 20000, 229 .ispgl = 0, 230 .dachan = 2, 231 .dabits = 12, 232 }, 233 {.name = "dt2821-f", 234 .adbits = 12, 235 .adchan_se = 16, 236 .adchan_di = 8, 237 .ai_speed = 6500, 238 .ispgl = 0, 239 .dachan = 2, 240 .dabits = 12, 241 }, 242 {.name = "dt2821-g", 243 .adbits = 12, 244 .adchan_se = 16, 245 .adchan_di = 8, 246 .ai_speed = 4000, 247 .ispgl = 0, 248 .dachan = 2, 249 .dabits = 12, 250 }, 251 {.name = "dt2823", 252 .adbits = 16, 253 .adchan_se = 0, 254 .adchan_di = 4, 255 .ai_speed = 10000, 256 .ispgl = 0, 257 .dachan = 2, 258 .dabits = 16, 259 }, 260 {.name = "dt2824-pgh", 261 .adbits = 12, 262 .adchan_se = 16, 263 .adchan_di = 8, 264 .ai_speed = 20000, 265 .ispgl = 0, 266 .dachan = 0, 267 .dabits = 0, 268 }, 269 {.name = "dt2824-pgl", 270 .adbits = 12, 271 .adchan_se = 16, 272 .adchan_di = 8, 273 .ai_speed = 20000, 274 .ispgl = 1, 275 .dachan = 0, 276 .dabits = 0, 277 }, 278 {.name = "dt2825", 279 .adbits = 12, 280 .adchan_se = 16, 281 .adchan_di = 8, 282 .ai_speed = 20000, 283 .ispgl = 1, 284 .dachan = 2, 285 .dabits = 12, 286 }, 287 {.name = "dt2827", 288 .adbits = 16, 289 .adchan_se = 0, 290 .adchan_di = 4, 291 .ai_speed = 10000, 292 .ispgl = 0, 293 .dachan = 2, 294 .dabits = 12, 295 }, 296 {.name = "dt2828", 297 .adbits = 12, 298 .adchan_se = 4, 299 .adchan_di = 0, 300 .ai_speed = 10000, 301 .ispgl = 0, 302 .dachan = 2, 303 .dabits = 12, 304 }, 305 {.name = "dt2829", 306 .adbits = 16, 307 .adchan_se = 8, 308 .adchan_di = 0, 309 .ai_speed = 33250, 310 .ispgl = 0, 311 .dachan = 2, 312 .dabits = 16, 313 }, 314 {.name = "dt21-ez", 315 .adbits = 12, 316 .adchan_se = 16, 317 .adchan_di = 8, 318 .ai_speed = 10000, 319 .ispgl = 0, 320 .dachan = 2, 321 .dabits = 12, 322 }, 323 {.name = "dt23-ez", 324 .adbits = 16, 325 .adchan_se = 16, 326 .adchan_di = 8, 327 .ai_speed = 10000, 328 .ispgl = 0, 329 .dachan = 0, 330 .dabits = 0, 331 }, 332 {.name = "dt24-ez", 333 .adbits = 12, 334 .adchan_se = 16, 335 .adchan_di = 8, 336 .ai_speed = 10000, 337 .ispgl = 0, 338 .dachan = 0, 339 .dabits = 0, 340 }, 341 {.name = "dt24-ez-pgl", 342 .adbits = 12, 343 .adchan_se = 16, 344 .adchan_di = 8, 345 .ai_speed = 10000, 346 .ispgl = 1, 347 .dachan = 0, 348 .dabits = 0, 349 }, 350}; 351 352#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board)) 353#define this_board ((const struct dt282x_board *)dev->board_ptr) 354 355struct dt282x_private { 356 int ad_2scomp; /* we have 2's comp jumper set */ 357 int da0_2scomp; /* same, for DAC0 */ 358 int da1_2scomp; /* same, for DAC1 */ 359 360 const struct comedi_lrange *darangelist[2]; 361 362 short ao[2]; 363 364 volatile int dacsr; /* software copies of registers */ 365 volatile int adcsr; 366 volatile int supcsr; 367 368 volatile int ntrig; 369 volatile int nread; 370 371 struct { 372 int chan; 373 short *buf; /* DMA buffer */ 374 volatile int size; /* size of current transfer */ 375 } dma[2]; 376 int dma_maxsize; /* max size of DMA transfer (in bytes) */ 377 int usedma; /* driver uses DMA */ 378 volatile int current_dma_index; 379 int dma_dir; 380}; 381 382#define devpriv ((struct dt282x_private *)dev->private) 383#define boardtype (*(const struct dt282x_board *)dev->board_ptr) 384 385/* 386 * Some useless abstractions 387 */ 388#define chan_to_DAC(a) ((a)&1) 389#define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR) 390#define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR) 391#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) 392#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) 393#define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR) 394 395/* 396 * danger! macro abuse... a is the expression to wait on, and b is 397 * the statement(s) to execute if it doesn't happen. 398 */ 399#define wait_for(a, b) \ 400 do { \ 401 int _i; \ 402 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \ 403 if (a) { \ 404 _i = 0; \ 405 break; \ 406 } \ 407 udelay(5); \ 408 } \ 409 if (_i) \ 410 b \ 411 } while (0) 412 413static int dt282x_attach(struct comedi_device *dev, 414 struct comedi_devconfig *it); 415static int dt282x_detach(struct comedi_device *dev); 416static struct comedi_driver driver_dt282x = { 417 .driver_name = "dt282x", 418 .module = THIS_MODULE, 419 .attach = dt282x_attach, 420 .detach = dt282x_detach, 421 .board_name = &boardtypes[0].name, 422 .num_names = n_boardtypes, 423 .offset = sizeof(struct dt282x_board), 424}; 425 426COMEDI_INITCLEANUP(driver_dt282x); 427 428static void free_resources(struct comedi_device *dev); 429static int prep_ai_dma(struct comedi_device *dev, int chan, int size); 430static int prep_ao_dma(struct comedi_device *dev, int chan, int size); 431static int dt282x_ai_cancel(struct comedi_device *dev, 432 struct comedi_subdevice *s); 433static int dt282x_ao_cancel(struct comedi_device *dev, 434 struct comedi_subdevice *s); 435static int dt282x_ns_to_timer(int *nanosec, int round_mode); 436static void dt282x_disable_dma(struct comedi_device *dev); 437 438static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2); 439 440static void dt282x_munge(struct comedi_device *dev, short *buf, 441 unsigned int nbytes) 442{ 443 unsigned int i; 444 unsigned short mask = (1 << boardtype.adbits) - 1; 445 unsigned short sign = 1 << (boardtype.adbits - 1); 446 int n; 447 448 if (devpriv->ad_2scomp) 449 sign = 1 << (boardtype.adbits - 1); 450 else 451 sign = 0; 452 453 if (nbytes % 2) 454 comedi_error(dev, "bug! odd number of bytes from dma xfer"); 455 n = nbytes / 2; 456 for (i = 0; i < n; i++) 457 buf[i] = (buf[i] & mask) ^ sign; 458} 459 460static void dt282x_ao_dma_interrupt(struct comedi_device *dev) 461{ 462 void *ptr; 463 int size; 464 int i; 465 struct comedi_subdevice *s = dev->subdevices + 1; 466 467 update_supcsr(DT2821_CLRDMADNE); 468 469 if (!s->async->prealloc_buf) { 470 printk(KERN_ERR "async->data disappeared. dang!\n"); 471 return; 472 } 473 474 i = devpriv->current_dma_index; 475 ptr = devpriv->dma[i].buf; 476 477 disable_dma(devpriv->dma[i].chan); 478 479 devpriv->current_dma_index = 1 - i; 480 481 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); 482 if (size == 0) { 483 printk(KERN_ERR "dt282x: AO underrun\n"); 484 dt282x_ao_cancel(dev, s); 485 s->async->events |= COMEDI_CB_OVERFLOW; 486 return; 487 } 488 prep_ao_dma(dev, i, size); 489 return; 490} 491 492static void dt282x_ai_dma_interrupt(struct comedi_device *dev) 493{ 494 void *ptr; 495 int size; 496 int i; 497 int ret; 498 struct comedi_subdevice *s = dev->subdevices; 499 500 update_supcsr(DT2821_CLRDMADNE); 501 502 if (!s->async->prealloc_buf) { 503 printk(KERN_ERR "async->data disappeared. dang!\n"); 504 return; 505 } 506 507 i = devpriv->current_dma_index; 508 ptr = devpriv->dma[i].buf; 509 size = devpriv->dma[i].size; 510 511 disable_dma(devpriv->dma[i].chan); 512 513 devpriv->current_dma_index = 1 - i; 514 515 dt282x_munge(dev, ptr, size); 516 ret = cfc_write_array_to_buffer(s, ptr, size); 517 if (ret != size) { 518 dt282x_ai_cancel(dev, s); 519 return; 520 } 521 devpriv->nread -= size / 2; 522 523 if (devpriv->nread < 0) { 524 printk(KERN_INFO "dt282x: off by one\n"); 525 devpriv->nread = 0; 526 } 527 if (!devpriv->nread) { 528 dt282x_ai_cancel(dev, s); 529 s->async->events |= COMEDI_CB_EOA; 530 return; 531 } 532#if 0 533 /* clear the dual dma flag, making this the last dma segment */ 534 /* XXX probably wrong */ 535 if (!devpriv->ntrig) { 536 devpriv->supcsr &= ~(DT2821_DDMA); 537 update_supcsr(0); 538 } 539#endif 540 /* restart the channel */ 541 prep_ai_dma(dev, i, 0); 542} 543 544static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n) 545{ 546 int dma_chan; 547 unsigned long dma_ptr; 548 unsigned long flags; 549 550 if (!devpriv->ntrig) 551 return 0; 552 553 if (n == 0) 554 n = devpriv->dma_maxsize; 555 if (n > devpriv->ntrig * 2) 556 n = devpriv->ntrig * 2; 557 devpriv->ntrig -= n / 2; 558 559 devpriv->dma[dma_index].size = n; 560 dma_chan = devpriv->dma[dma_index].chan; 561 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf); 562 563 set_dma_mode(dma_chan, DMA_MODE_READ); 564 flags = claim_dma_lock(); 565 clear_dma_ff(dma_chan); 566 set_dma_addr(dma_chan, dma_ptr); 567 set_dma_count(dma_chan, n); 568 release_dma_lock(flags); 569 570 enable_dma(dma_chan); 571 572 return n; 573} 574 575static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n) 576{ 577 int dma_chan; 578 unsigned long dma_ptr; 579 unsigned long flags; 580 581 devpriv->dma[dma_index].size = n; 582 dma_chan = devpriv->dma[dma_index].chan; 583 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf); 584 585 set_dma_mode(dma_chan, DMA_MODE_WRITE); 586 flags = claim_dma_lock(); 587 clear_dma_ff(dma_chan); 588 set_dma_addr(dma_chan, dma_ptr); 589 set_dma_count(dma_chan, n); 590 release_dma_lock(flags); 591 592 enable_dma(dma_chan); 593 594 return n; 595} 596 597static irqreturn_t dt282x_interrupt(int irq, void *d) 598{ 599 struct comedi_device *dev = d; 600 struct comedi_subdevice *s; 601 struct comedi_subdevice *s_ao; 602 unsigned int supcsr, adcsr, dacsr; 603 int handled = 0; 604 605 if (!dev->attached) { 606 comedi_error(dev, "spurious interrupt"); 607 return IRQ_HANDLED; 608 } 609 610 s = dev->subdevices + 0; 611 s_ao = dev->subdevices + 1; 612 adcsr = inw(dev->iobase + DT2821_ADCSR); 613 dacsr = inw(dev->iobase + DT2821_DACSR); 614 supcsr = inw(dev->iobase + DT2821_SUPCSR); 615 if (supcsr & DT2821_DMAD) { 616 if (devpriv->dma_dir == DMA_MODE_READ) 617 dt282x_ai_dma_interrupt(dev); 618 else 619 dt282x_ao_dma_interrupt(dev); 620 handled = 1; 621 } 622 if (adcsr & DT2821_ADERR) { 623 if (devpriv->nread != 0) { 624 comedi_error(dev, "A/D error"); 625 dt282x_ai_cancel(dev, s); 626 s->async->events |= COMEDI_CB_ERROR; 627 } 628 handled = 1; 629 } 630 if (dacsr & DT2821_DAERR) { 631#if 0 632 static int warn = 5; 633 if (--warn <= 0) { 634 disable_irq(dev->irq); 635 printk(KERN_INFO "disabling irq\n"); 636 } 637#endif 638 comedi_error(dev, "D/A error"); 639 dt282x_ao_cancel(dev, s_ao); 640 s->async->events |= COMEDI_CB_ERROR; 641 handled = 1; 642 } 643#if 0 644 if (adcsr & DT2821_ADDONE) { 645 int ret; 646 short data; 647 648 data = (short)inw(dev->iobase + DT2821_ADDAT); 649 data &= (1 << boardtype.adbits) - 1; 650 651 if (devpriv->ad_2scomp) 652 data ^= 1 << (boardtype.adbits - 1); 653 ret = comedi_buf_put(s->async, data); 654 655 if (ret == 0) 656 s->async->events |= COMEDI_CB_OVERFLOW; 657 658 devpriv->nread--; 659 if (!devpriv->nread) { 660 s->async->events |= COMEDI_CB_EOA; 661 } else { 662 if (supcsr & DT2821_SCDN) 663 update_supcsr(DT2821_STRIG); 664 } 665 handled = 1; 666 } 667#endif 668 comedi_event(dev, s); 669 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", 670 adcsr, dacsr, supcsr); */ 671 return IRQ_RETVAL(handled); 672} 673 674static void dt282x_load_changain(struct comedi_device *dev, int n, 675 unsigned int *chanlist) 676{ 677 unsigned int i; 678 unsigned int chan, range; 679 680 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR); 681 for (i = 0; i < n; i++) { 682 chan = CR_CHAN(chanlist[i]); 683 range = CR_RANGE(chanlist[i]); 684 update_adcsr((range << 4) | (chan)); 685 } 686 outw(n - 1, dev->iobase + DT2821_CHANCSR); 687} 688 689/* 690 * Performs a single A/D conversion. 691 * - Put channel/gain into channel-gain list 692 * - preload multiplexer 693 * - trigger conversion and wait for it to finish 694 */ 695static int dt282x_ai_insn_read(struct comedi_device *dev, 696 struct comedi_subdevice *s, 697 struct comedi_insn *insn, unsigned int *data) 698{ 699 int i; 700 701 /* XXX should we really be enabling the ad clock here? */ 702 devpriv->adcsr = DT2821_ADCLK; 703 update_adcsr(0); 704 705 dt282x_load_changain(dev, 1, &insn->chanspec); 706 707 update_supcsr(DT2821_PRLD); 708 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); 709 710 for (i = 0; i < insn->n; i++) { 711 update_supcsr(DT2821_STRIG); 712 wait_for(ad_done(), comedi_error(dev, "timeout\n"); 713 return -ETIME;); 714 715 data[i] = 716 inw(dev->iobase + 717 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1); 718 if (devpriv->ad_2scomp) 719 data[i] ^= (1 << (boardtype.adbits - 1)); 720 } 721 722 return i; 723} 724 725static int dt282x_ai_cmdtest(struct comedi_device *dev, 726 struct comedi_subdevice *s, struct comedi_cmd *cmd) 727{ 728 int err = 0; 729 int tmp; 730 731 /* step 1: make sure trigger sources are trivially valid */ 732 733 tmp = cmd->start_src; 734 cmd->start_src &= TRIG_NOW; 735 if (!cmd->start_src || tmp != cmd->start_src) 736 err++; 737 738 tmp = cmd->scan_begin_src; 739 cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT; 740 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 741 err++; 742 743 tmp = cmd->convert_src; 744 cmd->convert_src &= TRIG_TIMER; 745 if (!cmd->convert_src || tmp != cmd->convert_src) 746 err++; 747 748 tmp = cmd->scan_end_src; 749 cmd->scan_end_src &= TRIG_COUNT; 750 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 751 err++; 752 753 tmp = cmd->stop_src; 754 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 755 if (!cmd->stop_src || tmp != cmd->stop_src) 756 err++; 757 758 if (err) 759 return 1; 760 761 /* 762 * step 2: make sure trigger sources are unique 763 * and mutually compatible 764 */ 765 766 /* note that mutual compatibility is not an issue here */ 767 if (cmd->scan_begin_src != TRIG_FOLLOW && 768 cmd->scan_begin_src != TRIG_EXT) 769 err++; 770 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 771 err++; 772 773 if (err) 774 return 2; 775 776 /* step 3: make sure arguments are trivially compatible */ 777 778 if (cmd->start_arg != 0) { 779 cmd->start_arg = 0; 780 err++; 781 } 782 if (cmd->scan_begin_src == TRIG_FOLLOW) { 783 /* internal trigger */ 784 if (cmd->scan_begin_arg != 0) { 785 cmd->scan_begin_arg = 0; 786 err++; 787 } 788 } else { 789 /* external trigger */ 790 /* should be level/edge, hi/lo specification here */ 791 if (cmd->scan_begin_arg != 0) { 792 cmd->scan_begin_arg = 0; 793 err++; 794 } 795 } 796 if (cmd->convert_arg < 4000) { 797 /* XXX board dependent */ 798 cmd->convert_arg = 4000; 799 err++; 800 } 801#define SLOWEST_TIMER (250*(1<<15)*255) 802 if (cmd->convert_arg > SLOWEST_TIMER) { 803 cmd->convert_arg = SLOWEST_TIMER; 804 err++; 805 } 806 if (cmd->convert_arg < this_board->ai_speed) { 807 cmd->convert_arg = this_board->ai_speed; 808 err++; 809 } 810 if (cmd->scan_end_arg != cmd->chanlist_len) { 811 cmd->scan_end_arg = cmd->chanlist_len; 812 err++; 813 } 814 if (cmd->stop_src == TRIG_COUNT) { 815 /* any count is allowed */ 816 } else { 817 /* TRIG_NONE */ 818 if (cmd->stop_arg != 0) { 819 cmd->stop_arg = 0; 820 err++; 821 } 822 } 823 824 if (err) 825 return 3; 826 827 /* step 4: fix up any arguments */ 828 829 tmp = cmd->convert_arg; 830 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); 831 if (tmp != cmd->convert_arg) 832 err++; 833 834 if (err) 835 return 4; 836 837 return 0; 838} 839 840static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 841{ 842 struct comedi_cmd *cmd = &s->async->cmd; 843 int timer; 844 845 if (devpriv->usedma == 0) { 846 comedi_error(dev, 847 "driver requires 2 dma channels" 848 " to execute command"); 849 return -EIO; 850 } 851 852 dt282x_disable_dma(dev); 853 854 if (cmd->convert_arg < this_board->ai_speed) 855 cmd->convert_arg = this_board->ai_speed; 856 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST); 857 outw(timer, dev->iobase + DT2821_TMRCTR); 858 859 if (cmd->scan_begin_src == TRIG_FOLLOW) { 860 /* internal trigger */ 861 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0; 862 } else { 863 /* external trigger */ 864 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1; 865 } 866 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT); 867 868 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg; 869 devpriv->nread = devpriv->ntrig; 870 871 devpriv->dma_dir = DMA_MODE_READ; 872 devpriv->current_dma_index = 0; 873 prep_ai_dma(dev, 0, 0); 874 if (devpriv->ntrig) { 875 prep_ai_dma(dev, 1, 0); 876 devpriv->supcsr |= DT2821_DDMA; 877 update_supcsr(0); 878 } 879 880 devpriv->adcsr = 0; 881 882 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist); 883 884 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE; 885 update_adcsr(0); 886 887 update_supcsr(DT2821_PRLD); 888 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); 889 890 if (cmd->scan_begin_src == TRIG_FOLLOW) { 891 update_supcsr(DT2821_STRIG); 892 } else { 893 devpriv->supcsr |= DT2821_XTRIG; 894 update_supcsr(0); 895 } 896 897 return 0; 898} 899 900static void dt282x_disable_dma(struct comedi_device *dev) 901{ 902 if (devpriv->usedma) { 903 disable_dma(devpriv->dma[0].chan); 904 disable_dma(devpriv->dma[1].chan); 905 } 906} 907 908static int dt282x_ai_cancel(struct comedi_device *dev, 909 struct comedi_subdevice *s) 910{ 911 dt282x_disable_dma(dev); 912 913 devpriv->adcsr = 0; 914 update_adcsr(0); 915 916 devpriv->supcsr = 0; 917 update_supcsr(DT2821_ADCINIT); 918 919 return 0; 920} 921 922static int dt282x_ns_to_timer(int *nanosec, int round_mode) 923{ 924 int prescale, base, divider; 925 926 for (prescale = 0; prescale < 16; prescale++) { 927 if (prescale == 1) 928 continue; 929 base = 250 * (1 << prescale); 930 switch (round_mode) { 931 case TRIG_ROUND_NEAREST: 932 default: 933 divider = (*nanosec + base / 2) / base; 934 break; 935 case TRIG_ROUND_DOWN: 936 divider = (*nanosec) / base; 937 break; 938 case TRIG_ROUND_UP: 939 divider = (*nanosec + base - 1) / base; 940 break; 941 } 942 if (divider < 256) { 943 *nanosec = divider * base; 944 return (prescale << 8) | (255 - divider); 945 } 946 } 947 base = 250 * (1 << 15); 948 divider = 255; 949 *nanosec = divider * base; 950 return (15 << 8) | (255 - divider); 951} 952 953/* 954 * Analog output routine. Selects single channel conversion, 955 * selects correct channel, converts from 2's compliment to 956 * offset binary if necessary, loads the data into the DAC 957 * data register, and performs the conversion. 958 */ 959static int dt282x_ao_insn_read(struct comedi_device *dev, 960 struct comedi_subdevice *s, 961 struct comedi_insn *insn, unsigned int *data) 962{ 963 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)]; 964 965 return 1; 966} 967 968static int dt282x_ao_insn_write(struct comedi_device *dev, 969 struct comedi_subdevice *s, 970 struct comedi_insn *insn, unsigned int *data) 971{ 972 short d; 973 unsigned int chan; 974 975 chan = CR_CHAN(insn->chanspec); 976 d = data[0]; 977 d &= (1 << boardtype.dabits) - 1; 978 devpriv->ao[chan] = d; 979 980 devpriv->dacsr |= DT2821_SSEL; 981 982 if (chan) { 983 /* select channel */ 984 devpriv->dacsr |= DT2821_YSEL; 985 if (devpriv->da0_2scomp) 986 d ^= (1 << (boardtype.dabits - 1)); 987 } else { 988 devpriv->dacsr &= ~DT2821_YSEL; 989 if (devpriv->da1_2scomp) 990 d ^= (1 << (boardtype.dabits - 1)); 991 } 992 993 update_dacsr(0); 994 995 outw(d, dev->iobase + DT2821_DADAT); 996 997 update_supcsr(DT2821_DACON); 998 999 return 1; 1000} 1001 1002static int dt282x_ao_cmdtest(struct comedi_device *dev, 1003 struct comedi_subdevice *s, struct comedi_cmd *cmd) 1004{ 1005 int err = 0; 1006 int tmp; 1007 1008 /* step 1: make sure trigger sources are trivially valid */ 1009 1010 tmp = cmd->start_src; 1011 cmd->start_src &= TRIG_INT; 1012 if (!cmd->start_src || tmp != cmd->start_src) 1013 err++; 1014 1015 tmp = cmd->scan_begin_src; 1016 cmd->scan_begin_src &= TRIG_TIMER; 1017 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 1018 err++; 1019 1020 tmp = cmd->convert_src; 1021 cmd->convert_src &= TRIG_NOW; 1022 if (!cmd->convert_src || tmp != cmd->convert_src) 1023 err++; 1024 1025 tmp = cmd->scan_end_src; 1026 cmd->scan_end_src &= TRIG_COUNT; 1027 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 1028 err++; 1029 1030 tmp = cmd->stop_src; 1031 cmd->stop_src &= TRIG_NONE; 1032 if (!cmd->stop_src || tmp != cmd->stop_src) 1033 err++; 1034 1035 if (err) 1036 return 1; 1037 1038 /* 1039 * step 2: make sure trigger sources are unique 1040 * and mutually compatible 1041 */ 1042 1043 /* note that mutual compatibility is not an issue here */ 1044 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) 1045 err++; 1046 1047 if (err) 1048 return 2; 1049 1050 /* step 3: make sure arguments are trivially compatible */ 1051 1052 if (cmd->start_arg != 0) { 1053 cmd->start_arg = 0; 1054 err++; 1055 } 1056 if (cmd->scan_begin_arg < 5000 /* XXX unknown */) { 1057 cmd->scan_begin_arg = 5000; 1058 err++; 1059 } 1060 if (cmd->convert_arg != 0) { 1061 cmd->convert_arg = 0; 1062 err++; 1063 } 1064 if (cmd->scan_end_arg > 2) { 1065 /* XXX chanlist stuff? */ 1066 cmd->scan_end_arg = 2; 1067 err++; 1068 } 1069 if (cmd->stop_src == TRIG_COUNT) { 1070 /* any count is allowed */ 1071 } else { 1072 /* TRIG_NONE */ 1073 if (cmd->stop_arg != 0) { 1074 cmd->stop_arg = 0; 1075 err++; 1076 } 1077 } 1078 1079 if (err) 1080 return 3; 1081 1082 /* step 4: fix up any arguments */ 1083 1084 tmp = cmd->scan_begin_arg; 1085 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); 1086 if (tmp != cmd->scan_begin_arg) 1087 err++; 1088 1089 if (err) 1090 return 4; 1091 1092 return 0; 1093 1094} 1095 1096static int dt282x_ao_inttrig(struct comedi_device *dev, 1097 struct comedi_subdevice *s, unsigned int x) 1098{ 1099 int size; 1100 1101 if (x != 0) 1102 return -EINVAL; 1103 1104 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, 1105 devpriv->dma_maxsize); 1106 if (size == 0) { 1107 printk(KERN_ERR "dt282x: AO underrun\n"); 1108 return -EPIPE; 1109 } 1110 prep_ao_dma(dev, 0, size); 1111 1112 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, 1113 devpriv->dma_maxsize); 1114 if (size == 0) { 1115 printk(KERN_ERR "dt282x: AO underrun\n"); 1116 return -EPIPE; 1117 } 1118 prep_ao_dma(dev, 1, size); 1119 1120 update_supcsr(DT2821_STRIG); 1121 s->async->inttrig = NULL; 1122 1123 return 1; 1124} 1125 1126static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 1127{ 1128 int timer; 1129 struct comedi_cmd *cmd = &s->async->cmd; 1130 1131 if (devpriv->usedma == 0) { 1132 comedi_error(dev, 1133 "driver requires 2 dma channels" 1134 " to execute command"); 1135 return -EIO; 1136 } 1137 1138 dt282x_disable_dma(dev); 1139 1140 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA; 1141 update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT); 1142 1143 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len; 1144 devpriv->nread = devpriv->ntrig; 1145 1146 devpriv->dma_dir = DMA_MODE_WRITE; 1147 devpriv->current_dma_index = 0; 1148 1149 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST); 1150 outw(timer, dev->iobase + DT2821_TMRCTR); 1151 1152 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY; 1153 update_dacsr(0); 1154 1155 s->async->inttrig = dt282x_ao_inttrig; 1156 1157 return 0; 1158} 1159 1160static int dt282x_ao_cancel(struct comedi_device *dev, 1161 struct comedi_subdevice *s) 1162{ 1163 dt282x_disable_dma(dev); 1164 1165 devpriv->dacsr = 0; 1166 update_dacsr(0); 1167 1168 devpriv->supcsr = 0; 1169 update_supcsr(DT2821_DACINIT); 1170 1171 return 0; 1172} 1173 1174static int dt282x_dio_insn_bits(struct comedi_device *dev, 1175 struct comedi_subdevice *s, 1176 struct comedi_insn *insn, unsigned int *data) 1177{ 1178 if (data[0]) { 1179 s->state &= ~data[0]; 1180 s->state |= (data[0] & data[1]); 1181 1182 outw(s->state, dev->iobase + DT2821_DIODAT); 1183 } 1184 data[1] = inw(dev->iobase + DT2821_DIODAT); 1185 1186 return 2; 1187} 1188 1189static int dt282x_dio_insn_config(struct comedi_device *dev, 1190 struct comedi_subdevice *s, 1191 struct comedi_insn *insn, unsigned int *data) 1192{ 1193 int mask; 1194 1195 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00; 1196 if (data[0]) 1197 s->io_bits |= mask; 1198 else 1199 s->io_bits &= ~mask; 1200 1201 if (s->io_bits & 0x00ff) 1202 devpriv->dacsr |= DT2821_LBOE; 1203 else 1204 devpriv->dacsr &= ~DT2821_LBOE; 1205 if (s->io_bits & 0xff00) 1206 devpriv->dacsr |= DT2821_HBOE; 1207 else 1208 devpriv->dacsr &= ~DT2821_HBOE; 1209 1210 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); 1211 1212 return 1; 1213} 1214 1215static const struct comedi_lrange *const ai_range_table[] = { 1216 &range_dt282x_ai_lo_bipolar, 1217 &range_dt282x_ai_lo_unipolar, 1218 &range_dt282x_ai_5_bipolar, 1219 &range_dt282x_ai_5_unipolar 1220}; 1221 1222static const struct comedi_lrange *const ai_range_pgl_table[] = { 1223 &range_dt282x_ai_hi_bipolar, 1224 &range_dt282x_ai_hi_unipolar 1225}; 1226 1227static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x) 1228{ 1229 if (ispgl) { 1230 if (x < 0 || x >= 2) 1231 x = 0; 1232 return ai_range_pgl_table[x]; 1233 } else { 1234 if (x < 0 || x >= 4) 1235 x = 0; 1236 return ai_range_table[x]; 1237 } 1238} 1239 1240static const struct comedi_lrange *const ao_range_table[] = { 1241 &range_bipolar10, 1242 &range_unipolar10, 1243 &range_bipolar5, 1244 &range_unipolar5, 1245 &range_bipolar2_5 1246}; 1247 1248static const struct comedi_lrange *opt_ao_range_lkup(int x) 1249{ 1250 if (x < 0 || x >= 5) 1251 x = 0; 1252 return ao_range_table[x]; 1253} 1254 1255enum { /* i/o base, irq, dma channels */ 1256 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2, 1257 opt_diff, /* differential */ 1258 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */ 1259 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */ 1260}; 1261 1262/* 1263 options: 1264 0 i/o base 1265 1 irq 1266 2 dma1 1267 3 dma2 1268 4 0=single ended, 1=differential 1269 5 ai 0=straight binary, 1=2's comp 1270 6 ao0 0=straight binary, 1=2's comp 1271 7 ao1 0=straight binary, 1=2's comp 1272 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V 1273 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V 1274 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V 1275 */ 1276static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) 1277{ 1278 int i, irq; 1279 int ret; 1280 struct comedi_subdevice *s; 1281 unsigned long iobase; 1282 1283 dev->board_name = this_board->name; 1284 1285 iobase = it->options[opt_iobase]; 1286 if (!iobase) 1287 iobase = 0x240; 1288 1289 printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase); 1290 if (!request_region(iobase, DT2821_SIZE, "dt282x")) { 1291 printk(KERN_INFO " I/O port conflict\n"); 1292 return -EBUSY; 1293 } 1294 dev->iobase = iobase; 1295 1296 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR); 1297 i = inw(dev->iobase + DT2821_ADCSR); 1298#ifdef DEBUG 1299 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x", 1300 inw(dev->iobase + DT2821_ADCSR), 1301 inw(dev->iobase + DT2821_CHANCSR), 1302 inw(dev->iobase + DT2821_DACSR), 1303 inw(dev->iobase + DT2821_SUPCSR), 1304 inw(dev->iobase + DT2821_TMRCTR)); 1305#endif 1306 1307 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK) 1308 != DT2821_ADCSR_VAL) || 1309 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK) 1310 != DT2821_CHANCSR_VAL) || 1311 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK) 1312 != DT2821_DACSR_VAL) || 1313 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK) 1314 != DT2821_SUPCSR_VAL) || 1315 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK) 1316 != DT2821_TMRCTR_VAL)) { 1317 printk(KERN_ERR " board not found"); 1318 return -EIO; 1319 } 1320 /* should do board test */ 1321 1322 irq = it->options[opt_irq]; 1323#if 0 1324 if (irq < 0) { 1325 unsigned long flags; 1326 int irqs; 1327 1328 save_flags(flags); 1329 sti(); 1330 irqs = probe_irq_on(); 1331 1332 /* trigger interrupt */ 1333 1334 udelay(100); 1335 1336 irq = probe_irq_off(irqs); 1337 restore_flags(flags); 1338 if (0 /* error */) 1339 printk(KERN_ERR " error probing irq (bad)"); 1340 } 1341#endif 1342 if (irq > 0) { 1343 printk(KERN_INFO " ( irq = %d )", irq); 1344 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev); 1345 if (ret < 0) { 1346 printk(KERN_ERR " failed to get irq\n"); 1347 return -EIO; 1348 } 1349 dev->irq = irq; 1350 } else if (irq == 0) { 1351 printk(KERN_INFO " (no irq)"); 1352 } else { 1353#if 0 1354 printk(KERN_INFO " (probe returned multiple irqs--bad)"); 1355#else 1356 printk(KERN_INFO " (irq probe not implemented)"); 1357#endif 1358 } 1359 1360 ret = alloc_private(dev, sizeof(struct dt282x_private)); 1361 if (ret < 0) 1362 return ret; 1363 1364 ret = dt282x_grab_dma(dev, it->options[opt_dma1], 1365 it->options[opt_dma2]); 1366 if (ret < 0) 1367 return ret; 1368 1369 ret = alloc_subdevices(dev, 3); 1370 if (ret < 0) 1371 return ret; 1372 1373 s = dev->subdevices + 0; 1374 1375 dev->read_subdev = s; 1376 /* ai subdevice */ 1377 s->type = COMEDI_SUBD_AI; 1378 s->subdev_flags = SDF_READABLE | SDF_CMD_READ | 1379 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON); 1380 s->n_chan = 1381 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se; 1382 s->insn_read = dt282x_ai_insn_read; 1383 s->do_cmdtest = dt282x_ai_cmdtest; 1384 s->do_cmd = dt282x_ai_cmd; 1385 s->cancel = dt282x_ai_cancel; 1386 s->maxdata = (1 << boardtype.adbits) - 1; 1387 s->len_chanlist = 16; 1388 s->range_table = 1389 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]); 1390 devpriv->ad_2scomp = it->options[opt_ai_twos]; 1391 1392 s++; 1393 1394 s->n_chan = boardtype.dachan; 1395 if (s->n_chan) { 1396 /* ao subsystem */ 1397 s->type = COMEDI_SUBD_AO; 1398 dev->write_subdev = s; 1399 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE; 1400 s->insn_read = dt282x_ao_insn_read; 1401 s->insn_write = dt282x_ao_insn_write; 1402 s->do_cmdtest = dt282x_ao_cmdtest; 1403 s->do_cmd = dt282x_ao_cmd; 1404 s->cancel = dt282x_ao_cancel; 1405 s->maxdata = (1 << boardtype.dabits) - 1; 1406 s->len_chanlist = 2; 1407 s->range_table_list = devpriv->darangelist; 1408 devpriv->darangelist[0] = 1409 opt_ao_range_lkup(it->options[opt_ao0_range]); 1410 devpriv->darangelist[1] = 1411 opt_ao_range_lkup(it->options[opt_ao1_range]); 1412 devpriv->da0_2scomp = it->options[opt_ao0_twos]; 1413 devpriv->da1_2scomp = it->options[opt_ao1_twos]; 1414 } else { 1415 s->type = COMEDI_SUBD_UNUSED; 1416 } 1417 1418 s++; 1419 /* dio subsystem */ 1420 s->type = COMEDI_SUBD_DIO; 1421 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 1422 s->n_chan = 16; 1423 s->insn_bits = dt282x_dio_insn_bits; 1424 s->insn_config = dt282x_dio_insn_config; 1425 s->maxdata = 1; 1426 s->range_table = &range_digital; 1427 1428 printk(KERN_INFO "\n"); 1429 1430 return 0; 1431} 1432 1433static void free_resources(struct comedi_device *dev) 1434{ 1435 if (dev->irq) 1436 free_irq(dev->irq, dev); 1437 if (dev->iobase) 1438 release_region(dev->iobase, DT2821_SIZE); 1439 if (dev->private) { 1440 if (devpriv->dma[0].chan) 1441 free_dma(devpriv->dma[0].chan); 1442 if (devpriv->dma[1].chan) 1443 free_dma(devpriv->dma[1].chan); 1444 if (devpriv->dma[0].buf) 1445 free_page((unsigned long)devpriv->dma[0].buf); 1446 if (devpriv->dma[1].buf) 1447 free_page((unsigned long)devpriv->dma[1].buf); 1448 } 1449} 1450 1451static int dt282x_detach(struct comedi_device *dev) 1452{ 1453 printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor); 1454 1455 free_resources(dev); 1456 1457 return 0; 1458} 1459 1460static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) 1461{ 1462 int ret; 1463 1464 devpriv->usedma = 0; 1465 1466 if (!dma1 && !dma2) { 1467 printk(KERN_ERR " (no dma)"); 1468 return 0; 1469 } 1470 1471 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7) 1472 return -EINVAL; 1473 1474 if (dma2 < dma1) { 1475 int i; 1476 i = dma1; 1477 dma1 = dma2; 1478 dma2 = i; 1479 } 1480 1481 ret = request_dma(dma1, "dt282x A"); 1482 if (ret) 1483 return -EBUSY; 1484 devpriv->dma[0].chan = dma1; 1485 1486 ret = request_dma(dma2, "dt282x B"); 1487 if (ret) 1488 return -EBUSY; 1489 devpriv->dma[1].chan = dma2; 1490 1491 devpriv->dma_maxsize = PAGE_SIZE; 1492 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); 1493 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); 1494 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) { 1495 printk(KERN_ERR " can't get DMA memory"); 1496 return -ENOMEM; 1497 } 1498 1499 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2); 1500 1501 devpriv->usedma = 1; 1502 1503 return 0; 1504} 1505