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