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