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