pcl812.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
1/* 2 * comedi/drivers/pcl812.c 3 * 4 * Author: Michal Dobes <dobes@tesnet.cz> 5 * 6 * hardware driver for Advantech cards 7 * card: PCL-812, PCL-812PG, PCL-813, PCL-813B 8 * driver: pcl812, pcl812pg, pcl813, pcl813b 9 * and for ADlink cards 10 * card: ACL-8112DG, ACL-8112HG, ACL-8112PG, ACL-8113, ACL-8216 11 * driver: acl8112dg, acl8112hg, acl8112pg, acl8113, acl8216 12 * and for ICP DAS cards 13 * card: ISO-813, A-821PGH, A-821PGL, A-821PGL-NDA, A-822PGH, A-822PGL, 14 * driver: iso813, a821pgh, a-821pgl, a-821pglnda, a822pgh, a822pgl, 15 * card: A-823PGH, A-823PGL, A-826PG 16 * driver: a823pgh, a823pgl, a826pg 17 */ 18/* 19Driver: pcl812 20Description: Advantech PCL-812/PG, PCL-813/B, 21 ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, 22 ICP DAS A-821PGH/PGL/PGL-NDA, A-822PGH/PGL, A-823PGH/PGL, A-826PG, 23 ICP DAS ISO-813 24Author: Michal Dobes <dobes@tesnet.cz> 25Devices: [Advantech] PCL-812 (pcl812), PCL-812PG (pcl812pg), 26 PCL-813 (pcl813), PCL-813B (pcl813b), [ADLink] ACL-8112DG (acl8112dg), 27 ACL-8112HG (acl8112hg), ACL-8113 (acl-8113), ACL-8216 (acl8216), 28 [ICP] ISO-813 (iso813), A-821PGH (a821pgh), A-821PGL (a821pgl), 29 A-821PGL-NDA (a821pclnda), A-822PGH (a822pgh), A-822PGL (a822pgl), 30 A-823PGH (a823pgh), A-823PGL (a823pgl), A-826PG (a826pg) 31Updated: Mon, 06 Aug 2007 12:03:15 +0100 32Status: works (I hope. My board fire up under my hands 33 and I cann't test all features.) 34 35This driver supports insn and cmd interfaces. Some boards support only insn 36becouse their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813). 37Data transfer over DMA is supported only when you measure only one 38channel, this is too hardware limitation of these boards. 39 40Options for PCL-812: 41 [0] - IO Base 42 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15) 43 [2] - DMA (0=disable, 1, 3) 44 [3] - 0=trigger source is internal 8253 with 2MHz clock 45 1=trigger source is external 46 [4] - 0=A/D input range is +/-10V 47 1=A/D input range is +/-5V 48 2=A/D input range is +/-2.5V 49 3=A/D input range is +/-1.25V 50 4=A/D input range is +/-0.625V 51 5=A/D input range is +/-0.3125V 52 [5] - 0=D/A outputs 0-5V (internal reference -5V) 53 1=D/A outputs 0-10V (internal reference -10V) 54 2=D/A outputs unknow (external reference) 55 56Options for PCL-812PG, ACL-8112PG: 57 [0] - IO Base 58 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15) 59 [2] - DMA (0=disable, 1, 3) 60 [3] - 0=trigger source is internal 8253 with 2MHz clock 61 1=trigger source is external 62 [4] - 0=A/D have max +/-5V input 63 1=A/D have max +/-10V input 64 [5] - 0=D/A outputs 0-5V (internal reference -5V) 65 1=D/A outputs 0-10V (internal reference -10V) 66 2=D/A outputs unknow (external reference) 67 68Options for ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH, ACL-8216, A-826PG: 69 [0] - IO Base 70 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7; 10, 11, 12, 14, 15) 71 [2] - DMA (0=disable, 1, 3) 72 [3] - 0=trigger source is internal 8253 with 2MHz clock 73 1=trigger source is external 74 [4] - 0=A/D channels are S.E. 75 1=A/D channels are DIFF 76 [5] - 0=D/A outputs 0-5V (internal reference -5V) 77 1=D/A outputs 0-10V (internal reference -10V) 78 2=D/A outputs unknow (external reference) 79 80Options for A-821PGL/PGH: 81 [0] - IO Base 82 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 83 [2] - 0=A/D channels are S.E. 84 1=A/D channels are DIFF 85 [3] - 0=D/A output 0-5V (internal reference -5V) 86 1=D/A output 0-10V (internal reference -10V) 87 88Options for A-821PGL-NDA: 89 [0] - IO Base 90 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7) 91 [2] - 0=A/D channels are S.E. 92 1=A/D channels are DIFF 93 94Options for PCL-813: 95 [0] - IO Base 96 97Options for PCL-813B: 98 [0] - IO Base 99 [1] - 0= bipolar inputs 100 1= unipolar inputs 101 102Options for ACL-8113, ISO-813: 103 [0] - IO Base 104 [1] - 0= 10V bipolar inputs 105 1= 10V unipolar inputs 106 2= 20V bipolar inputs 107 3= 20V unipolar inputs 108*/ 109 110#include <linux/interrupt.h> 111#include "../comedidev.h" 112 113#include <linux/delay.h> 114#include <linux/ioport.h> 115#include <asm/dma.h> 116 117#include "8253.h" 118 119#undef PCL812_EXTDEBUG /* if this is defined then a lot of messages is printed */ 120 121/* hardware types of the cards */ 122#define boardPCL812PG 0 /* and ACL-8112PG */ 123#define boardPCL813B 1 124#define boardPCL812 2 125#define boardPCL813 3 126#define boardISO813 5 127#define boardACL8113 6 128#define boardACL8112 7 /* ACL-8112DG/HG, A-822PGL/PGH, A-823PGL/PGH */ 129#define boardACL8216 8 /* and ICP DAS A-826PG */ 130#define boardA821 9 /* PGH, PGL, PGL/NDA versions */ 131 132#define PCLx1x_IORANGE 16 133 134#define PCL812_CTR0 0 135#define PCL812_CTR1 1 136#define PCL812_CTR2 2 137#define PCL812_CTRCTL 3 138#define PCL812_AD_LO 4 139#define PCL812_DA1_LO 4 140#define PCL812_AD_HI 5 141#define PCL812_DA1_HI 5 142#define PCL812_DA2_LO 6 143#define PCL812_DI_LO 6 144#define PCL812_DA2_HI 7 145#define PCL812_DI_HI 7 146#define PCL812_CLRINT 8 147#define PCL812_GAIN 9 148#define PCL812_MUX 10 149#define PCL812_MODE 11 150#define PCL812_CNTENABLE 10 151#define PCL812_SOFTTRIG 12 152#define PCL812_DO_LO 13 153#define PCL812_DO_HI 14 154 155#define PCL812_DRDY 0x10 /* =0 data ready */ 156 157#define ACL8216_STATUS 8 /* 5. bit signalize data ready */ 158 159#define ACL8216_DRDY 0x20 /* =0 data ready */ 160 161#define MAX_CHANLIST_LEN 256 /* length of scan list */ 162 163static const struct comedi_lrange range_pcl812pg_ai = { 5, { 164 BIP_RANGE(5), 165 BIP_RANGE(2.5), 166 BIP_RANGE(1.25), 167 BIP_RANGE(0.625), 168 BIP_RANGE(0.3125), 169 } 170}; 171static const struct comedi_lrange range_pcl812pg2_ai = { 5, { 172 BIP_RANGE(10), 173 BIP_RANGE(5), 174 BIP_RANGE(2.5), 175 BIP_RANGE(1.25), 176 BIP_RANGE(0.625), 177 } 178}; 179static const struct comedi_lrange range812_bipolar1_25 = { 1, { 180 BIP_RANGE(1.25), 181 } 182}; 183static const struct comedi_lrange range812_bipolar0_625 = { 1, { 184 BIP_RANGE(0.625), 185 } 186}; 187static const struct comedi_lrange range812_bipolar0_3125 = { 1, { 188 BIP_RANGE(0.3125), 189 } 190}; 191static const struct comedi_lrange range_pcl813b_ai = { 4, { 192 BIP_RANGE(5), 193 BIP_RANGE(2.5), 194 BIP_RANGE(1.25), 195 BIP_RANGE(0.625), 196 } 197}; 198static const struct comedi_lrange range_pcl813b2_ai = { 4, { 199 UNI_RANGE(10), 200 UNI_RANGE(5), 201 UNI_RANGE(2.5), 202 UNI_RANGE(1.25), 203 } 204}; 205static const struct comedi_lrange range_iso813_1_ai = { 5, { 206 BIP_RANGE(5), 207 BIP_RANGE(2.5), 208 BIP_RANGE(1.25), 209 BIP_RANGE(0.625), 210 BIP_RANGE(0.3125), 211 } 212}; 213static const struct comedi_lrange range_iso813_1_2_ai = { 5, { 214 UNI_RANGE(10), 215 UNI_RANGE(5), 216 UNI_RANGE(2.5), 217 UNI_RANGE(1.25), 218 UNI_RANGE(0.625), 219 } 220}; 221static const struct comedi_lrange range_iso813_2_ai = { 4, { 222 BIP_RANGE(5), 223 BIP_RANGE(2.5), 224 BIP_RANGE(1.25), 225 BIP_RANGE(0.625), 226 } 227}; 228static const struct comedi_lrange range_iso813_2_2_ai = { 4, { 229 UNI_RANGE(10), 230 UNI_RANGE(5), 231 UNI_RANGE(2.5), 232 UNI_RANGE(1.25), 233 } 234}; 235static const struct comedi_lrange range_acl8113_1_ai = { 4, { 236 BIP_RANGE(5), 237 BIP_RANGE(2.5), 238 BIP_RANGE(1.25), 239 BIP_RANGE(0.625), 240 } 241}; 242static const struct comedi_lrange range_acl8113_1_2_ai = { 4, { 243 UNI_RANGE(10), 244 UNI_RANGE(5), 245 UNI_RANGE(2.5), 246 UNI_RANGE(1.25), 247 } 248}; 249static const struct comedi_lrange range_acl8113_2_ai = { 3, { 250 BIP_RANGE(5), 251 BIP_RANGE(2.5), 252 BIP_RANGE(1.25), 253 } 254}; 255static const struct comedi_lrange range_acl8113_2_2_ai = { 3, { 256 UNI_RANGE(10), 257 UNI_RANGE(5), 258 UNI_RANGE(2.5), 259 } 260}; 261static const struct comedi_lrange range_acl8112dg_ai = { 9, { 262 BIP_RANGE(5), 263 BIP_RANGE(2.5), 264 BIP_RANGE(1.25), 265 BIP_RANGE(0.625), 266 UNI_RANGE(10), 267 UNI_RANGE(5), 268 UNI_RANGE(2.5), 269 UNI_RANGE(1.25), 270 BIP_RANGE(10), 271 } 272}; 273static const struct comedi_lrange range_acl8112hg_ai = { 12, { 274 BIP_RANGE(5), 275 BIP_RANGE(0.5), 276 BIP_RANGE(0.05), 277 BIP_RANGE(0.005), 278 UNI_RANGE(10), 279 UNI_RANGE(1), 280 UNI_RANGE(0.1), 281 UNI_RANGE(0.01), 282 BIP_RANGE(10), 283 BIP_RANGE(1), 284 BIP_RANGE(0.1), 285 BIP_RANGE(0.01), 286 } 287}; 288static const struct comedi_lrange range_a821pgh_ai = { 4, { 289 BIP_RANGE(5), 290 BIP_RANGE(0.5), 291 BIP_RANGE(0.05), 292 BIP_RANGE(0.005), 293 } 294}; 295 296static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it); 297static int pcl812_detach(struct comedi_device *dev); 298 299struct pcl812_board { 300 301 const char *name; /* board name */ 302 int board_type; /* type of this board */ 303 int n_aichan; /* num of AI chans in S.E. */ 304 int n_aichan_diff; /* DIFF num of chans */ 305 int n_aochan; /* num of DA chans */ 306 int n_dichan; /* DI and DO chans */ 307 int n_dochan; 308 int ai_maxdata; /* AI resolution */ 309 unsigned int ai_ns_min; /* max sample speed of card v ns */ 310 unsigned int i8254_osc_base; /* clock base */ 311 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ 312 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ 313 unsigned int IRQbits; /* allowed IRQ */ 314 unsigned char DMAbits; /* allowed DMA chans */ 315 unsigned char io_range; /* iorange for this board */ 316 unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ 317}; 318 319 320static const struct pcl812_board boardtypes[] = { 321 {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, 322 33000, 500, &range_bipolar10, &range_unipolar5, 323 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 324 {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, 325 33000, 500, &range_pcl812pg_ai, &range_unipolar5, 326 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 327 {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, 328 10000, 500, &range_pcl812pg_ai, &range_unipolar5, 329 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 330 {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, 331 10000, 500, &range_acl8112dg_ai, &range_unipolar5, 332 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, 333 {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, 334 10000, 500, &range_acl8112hg_ai, &range_unipolar5, 335 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, 336 {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, 337 10000, 500, &range_pcl813b_ai, &range_unipolar5, 338 0x000c, 0x00, PCLx1x_IORANGE, 0}, 339 {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, 340 10000, 500, &range_pcl813b_ai, NULL, 341 0x000c, 0x00, PCLx1x_IORANGE, 0}, 342 {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, 343 10000, 500, &range_a821pgh_ai, &range_unipolar5, 344 0x000c, 0x00, PCLx1x_IORANGE, 0}, 345 {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, 346 10000, 500, &range_acl8112dg_ai, &range_unipolar5, 347 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 348 {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, 349 10000, 500, &range_acl8112hg_ai, &range_unipolar5, 350 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 351 {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, 352 8000, 500, &range_acl8112dg_ai, &range_unipolar5, 353 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 354 {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, 355 8000, 500, &range_acl8112hg_ai, &range_unipolar5, 356 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 357 {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, 358 0, 0, &range_pcl813b_ai, NULL, 359 0x0000, 0x00, PCLx1x_IORANGE, 0}, 360 {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, 361 0, 0, &range_pcl813b_ai, NULL, 362 0x0000, 0x00, PCLx1x_IORANGE, 0}, 363 {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, 364 0, 0, &range_acl8113_1_ai, NULL, 365 0x0000, 0x00, PCLx1x_IORANGE, 0}, 366 {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, 367 0, 0, &range_iso813_1_ai, NULL, 368 0x0000, 0x00, PCLx1x_IORANGE, 0}, 369 {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, 370 10000, 500, &range_pcl813b2_ai, &range_unipolar5, 371 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, 372 {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, 373 10000, 500, &range_pcl813b2_ai, &range_unipolar5, 374 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, 375}; 376 377#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl812_board)) 378#define this_board ((const struct pcl812_board *)dev->board_ptr) 379 380static struct comedi_driver driver_pcl812 = { 381 .driver_name = "pcl812", 382 .module = THIS_MODULE, 383 .attach = pcl812_attach, 384 .detach = pcl812_detach, 385 .board_name = &boardtypes[0].name, 386 .num_names = n_boardtypes, 387 .offset = sizeof(struct pcl812_board), 388}; 389 390COMEDI_INITCLEANUP(driver_pcl812); 391 392struct pcl812_private { 393 394 unsigned char valid; /* =1 device is OK */ 395 unsigned char dma; /* >0 use dma ( usedDMA channel) */ 396 unsigned char use_diff; /* =1 diff inputs */ 397 unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ 398 unsigned char use_ext_trg; /* 1=board uses external trigger */ 399 unsigned char range_correction; /* =1 we must add 1 to range number */ 400 unsigned char old_chan_reg; /* lastly used chan/gain pair */ 401 unsigned char old_gain_reg; 402 unsigned char mode_reg_int; /* there is stored INT number for some card */ 403 unsigned char ai_neverending; /* =1 we do unlimited AI */ 404 unsigned char ai_eos; /* 1=EOS wake up */ 405 unsigned char ai_dma; /* =1 we use DMA */ 406 unsigned int ai_poll_ptr; /* how many sampes transfer poll */ 407 unsigned int ai_scans; /* len of scanlist */ 408 unsigned int ai_act_scan; /* how many scans we finished */ 409 unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ 410 unsigned int ai_n_chan; /* how many channels is measured */ 411 unsigned int ai_flags; /* flaglist */ 412 unsigned int ai_data_len; /* len of data buffer */ 413 short *ai_data; /* data buffer */ 414 unsigned int ai_is16b; /* =1 we have 16 bit card */ 415 unsigned long dmabuf[2]; /* PTR to DMA buf */ 416 unsigned int dmapages[2]; /* how many pages we have allocated */ 417 unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ 418 unsigned int hwdmasize[2]; /* DMA buf size in bytes */ 419 unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ 420 int next_dma_buf; /* which buffer is next to use */ 421 unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ 422 unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ 423 unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ 424 unsigned int ao_readback[2]; /* data for AO readback */ 425}; 426 427 428#define devpriv ((struct pcl812_private *)dev->private) 429 430/* 431============================================================================== 432*/ 433static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, 434 unsigned int divisor2); 435static void setup_range_channel(struct comedi_device *dev, struct comedi_subdevice *s, 436 unsigned int rangechan, char wait); 437static int pcl812_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 438/* 439============================================================================== 440*/ 441static int pcl812_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 442 struct comedi_insn *insn, unsigned int *data) 443{ 444 int n; 445 int timeout, hi; 446 447 outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); /* select software trigger */ 448 setup_range_channel(dev, s, insn->chanspec, 1); /* select channel and renge */ 449 for (n = 0; n < insn->n; n++) { 450 outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */ 451 udelay(5); 452 timeout = 50; /* wait max 50us, it must finish under 33us */ 453 while (timeout--) { 454 hi = inb(dev->iobase + PCL812_AD_HI); 455 if (!(hi & PCL812_DRDY)) 456 goto conv_finish; 457 udelay(1); 458 } 459 printk 460 ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", 461 dev->minor, dev->board_name, dev->iobase); 462 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); 463 return -ETIME; 464 465 conv_finish: 466 data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); 467 } 468 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); 469 return n; 470} 471 472/* 473============================================================================== 474*/ 475static int acl8216_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 476 struct comedi_insn *insn, unsigned int *data) 477{ 478 int n; 479 int timeout; 480 481 outb(1, dev->iobase + PCL812_MODE); /* select software trigger */ 482 setup_range_channel(dev, s, insn->chanspec, 1); /* select channel and renge */ 483 for (n = 0; n < insn->n; n++) { 484 outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */ 485 udelay(5); 486 timeout = 50; /* wait max 50us, it must finish under 33us */ 487 while (timeout--) { 488 if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) 489 goto conv_finish; 490 udelay(1); 491 } 492 printk 493 ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", 494 dev->minor, dev->board_name, dev->iobase); 495 outb(0, dev->iobase + PCL812_MODE); 496 return -ETIME; 497 498 conv_finish: 499 data[n] = 500 (inb(dev->iobase + 501 PCL812_AD_HI) << 8) | inb(dev->iobase + 502 PCL812_AD_LO); 503 } 504 outb(0, dev->iobase + PCL812_MODE); 505 return n; 506} 507 508/* 509============================================================================== 510*/ 511static int pcl812_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, 512 struct comedi_insn *insn, unsigned int *data) 513{ 514 int chan = CR_CHAN(insn->chanspec); 515 int i; 516 517 for (i = 0; i < insn->n; i++) { 518 outb((data[i] & 0xff), 519 dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO)); 520 outb((data[i] >> 8) & 0x0f, 521 dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI)); 522 devpriv->ao_readback[chan] = data[i]; 523 } 524 525 return i; 526} 527 528/* 529============================================================================== 530*/ 531static int pcl812_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 532 struct comedi_insn *insn, unsigned int *data) 533{ 534 int chan = CR_CHAN(insn->chanspec); 535 int i; 536 537 for (i = 0; i < insn->n; i++) { 538 data[i] = devpriv->ao_readback[chan]; 539 } 540 541 return i; 542} 543 544/* 545============================================================================== 546*/ 547static int pcl812_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 548 struct comedi_insn *insn, unsigned int *data) 549{ 550 if (insn->n != 2) 551 return -EINVAL; 552 553 data[1] = inb(dev->iobase + PCL812_DI_LO); 554 data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; 555 556 return 2; 557} 558 559/* 560============================================================================== 561*/ 562static int pcl812_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 563 struct comedi_insn *insn, unsigned int *data) 564{ 565 if (insn->n != 2) 566 return -EINVAL; 567 568 if (data[0]) { 569 s->state &= ~data[0]; 570 s->state |= data[0] & data[1]; 571 outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); 572 outb((s->state >> 8), dev->iobase + PCL812_DO_HI); 573 } 574 data[1] = s->state; 575 576 return 2; 577} 578 579#ifdef PCL812_EXTDEBUG 580/* 581============================================================================== 582*/ 583static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd) 584{ 585 printk("pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, 586 cmd->start_src, cmd->scan_begin_src, cmd->convert_src); 587 printk("pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e, 588 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); 589 printk("pcl812 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, 590 cmd->scan_end_src); 591 printk("pcl812 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, 592 cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); 593} 594#endif 595 596/* 597============================================================================== 598*/ 599static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, 600 struct comedi_cmd *cmd) 601{ 602 int err = 0; 603 int tmp, divisor1, divisor2; 604 605#ifdef PCL812_EXTDEBUG 606 printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n"); 607 pcl812_cmdtest_out(-1, cmd); 608#endif 609 /* step 1: make sure trigger sources are trivially valid */ 610 611 tmp = cmd->start_src; 612 cmd->start_src &= TRIG_NOW; 613 if (!cmd->start_src || tmp != cmd->start_src) 614 err++; 615 616 tmp = cmd->scan_begin_src; 617 cmd->scan_begin_src &= TRIG_FOLLOW; 618 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) 619 err++; 620 621 tmp = cmd->convert_src; 622 if (devpriv->use_ext_trg) { 623 cmd->convert_src &= TRIG_EXT; 624 } else { 625 cmd->convert_src &= TRIG_TIMER; 626 } 627 if (!cmd->convert_src || tmp != cmd->convert_src) 628 err++; 629 630 tmp = cmd->scan_end_src; 631 cmd->scan_end_src &= TRIG_COUNT; 632 if (!cmd->scan_end_src || tmp != cmd->scan_end_src) 633 err++; 634 635 tmp = cmd->stop_src; 636 cmd->stop_src &= TRIG_COUNT | TRIG_NONE; 637 if (!cmd->stop_src || tmp != cmd->stop_src) 638 err++; 639 640 if (err) { 641#ifdef PCL812_EXTDEBUG 642 pcl812_cmdtest_out(1, cmd); 643 printk 644 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n", 645 err); 646#endif 647 return 1; 648 } 649 650 /* step 2: make sure trigger sources are unique and mutually compatible */ 651 652 if (cmd->start_src != TRIG_NOW) { 653 cmd->start_src = TRIG_NOW; 654 err++; 655 } 656 657 if (cmd->scan_begin_src != TRIG_FOLLOW) { 658 cmd->scan_begin_src = TRIG_FOLLOW; 659 err++; 660 } 661 662 if (devpriv->use_ext_trg) { 663 if (cmd->convert_src != TRIG_EXT) { 664 cmd->convert_src = TRIG_EXT; 665 err++; 666 } 667 } else { 668 if (cmd->convert_src != TRIG_TIMER) { 669 cmd->convert_src = TRIG_TIMER; 670 err++; 671 } 672 } 673 674 if (cmd->scan_end_src != TRIG_COUNT) { 675 cmd->scan_end_src = TRIG_COUNT; 676 err++; 677 } 678 679 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) 680 err++; 681 682 if (err) { 683#ifdef PCL812_EXTDEBUG 684 pcl812_cmdtest_out(2, cmd); 685 printk 686 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n", 687 err); 688#endif 689 return 2; 690 } 691 692 /* step 3: make sure arguments are trivially compatible */ 693 694 if (cmd->start_arg != 0) { 695 cmd->start_arg = 0; 696 err++; 697 } 698 699 if (cmd->scan_begin_arg != 0) { 700 cmd->scan_begin_arg = 0; 701 err++; 702 } 703 704 if (cmd->convert_src == TRIG_TIMER) { 705 if (cmd->convert_arg < this_board->ai_ns_min) { 706 cmd->convert_arg = this_board->ai_ns_min; 707 err++; 708 } 709 } else { /* TRIG_EXT */ 710 if (cmd->convert_arg != 0) { 711 cmd->convert_arg = 0; 712 err++; 713 } 714 } 715 716 if (!cmd->chanlist_len) { 717 cmd->chanlist_len = 1; 718 err++; 719 } 720 if (cmd->chanlist_len > MAX_CHANLIST_LEN) { 721 cmd->chanlist_len = this_board->n_aichan; 722 err++; 723 } 724 if (cmd->scan_end_arg != cmd->chanlist_len) { 725 cmd->scan_end_arg = cmd->chanlist_len; 726 err++; 727 } 728 if (cmd->stop_src == TRIG_COUNT) { 729 if (!cmd->stop_arg) { 730 cmd->stop_arg = 1; 731 err++; 732 } 733 } else { /* TRIG_NONE */ 734 if (cmd->stop_arg != 0) { 735 cmd->stop_arg = 0; 736 err++; 737 } 738 } 739 740 if (err) { 741#ifdef PCL812_EXTDEBUG 742 pcl812_cmdtest_out(3, cmd); 743 printk 744 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n", 745 err); 746#endif 747 return 3; 748 } 749 750 /* step 4: fix up any arguments */ 751 752 if (cmd->convert_src == TRIG_TIMER) { 753 tmp = cmd->convert_arg; 754 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1, 755 &divisor2, &cmd->convert_arg, 756 cmd->flags & TRIG_ROUND_MASK); 757 if (cmd->convert_arg < this_board->ai_ns_min) 758 cmd->convert_arg = this_board->ai_ns_min; 759 if (tmp != cmd->convert_arg) 760 err++; 761 } 762 763 if (err) { 764#ifdef PCL812_EXTDEBUG 765 printk 766 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n", 767 err); 768#endif 769 return 4; 770 } 771 772 return 0; 773} 774 775/* 776============================================================================== 777*/ 778static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 779{ 780 unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes; 781 struct comedi_cmd *cmd = &s->async->cmd; 782 783#ifdef PCL812_EXTDEBUG 784 printk("pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n"); 785#endif 786 787 if (cmd->start_src != TRIG_NOW) 788 return -EINVAL; 789 if (cmd->scan_begin_src != TRIG_FOLLOW) 790 return -EINVAL; 791 if (devpriv->use_ext_trg) { 792 if (cmd->convert_src != TRIG_EXT) 793 return -EINVAL; 794 } else { 795 if (cmd->convert_src != TRIG_TIMER) 796 return -EINVAL; 797 } 798 if (cmd->scan_end_src != TRIG_COUNT) 799 return -EINVAL; 800 if (cmd->scan_end_arg != cmd->chanlist_len) 801 return -EINVAL; 802 if (cmd->chanlist_len > MAX_CHANLIST_LEN) 803 return -EINVAL; 804 805 if (cmd->convert_src == TRIG_TIMER) { 806 if (cmd->convert_arg < this_board->ai_ns_min) 807 cmd->convert_arg = this_board->ai_ns_min; 808 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, 809 &divisor1, &divisor2, &cmd->convert_arg, 810 cmd->flags & TRIG_ROUND_MASK); 811 } 812 813 start_pacer(dev, -1, 0, 0); /* stop pacer */ 814 815 devpriv->ai_n_chan = cmd->chanlist_len; 816 memcpy(devpriv->ai_chanlist, cmd->chanlist, 817 sizeof(unsigned int) * cmd->scan_end_arg); 818 setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); /* select first channel and range */ 819 820 if (devpriv->dma) { /* check if we can use DMA transfer */ 821 devpriv->ai_dma = 1; 822 for (i = 1; i < devpriv->ai_n_chan; i++) 823 if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) { 824 devpriv->ai_dma = 0; /* we cann't use DMA :-( */ 825 break; 826 } 827 } else 828 devpriv->ai_dma = 0; 829 830 devpriv->ai_flags = cmd->flags; 831 devpriv->ai_data_len = s->async->prealloc_bufsz; 832 devpriv->ai_data = s->async->prealloc_buf; 833 if (cmd->stop_src == TRIG_COUNT) { 834 devpriv->ai_scans = cmd->stop_arg; 835 devpriv->ai_neverending = 0; 836 } else { 837 devpriv->ai_scans = 0; 838 devpriv->ai_neverending = 1; 839 } 840 841 devpriv->ai_act_scan = 0; 842 devpriv->ai_poll_ptr = 0; 843 s->async->cur_chan = 0; 844 845 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? */ 846 devpriv->ai_eos = 1; 847 if (devpriv->ai_n_chan == 1) 848 devpriv->ai_dma = 0; /* DMA is useless for this situation */ 849 } 850 851 if (devpriv->ai_dma) { 852 if (devpriv->ai_eos) { /* we use EOS, so adapt DMA buffer to one scan */ 853 devpriv->dmabytestomove[0] = 854 devpriv->ai_n_chan * sizeof(short); 855 devpriv->dmabytestomove[1] = 856 devpriv->ai_n_chan * sizeof(short); 857 devpriv->dma_runs_to_end = 1; 858 } else { 859 devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; 860 devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; 861 if (devpriv->ai_data_len < devpriv->hwdmasize[0]) 862 devpriv->dmabytestomove[0] = 863 devpriv->ai_data_len; 864 if (devpriv->ai_data_len < devpriv->hwdmasize[1]) 865 devpriv->dmabytestomove[1] = 866 devpriv->ai_data_len; 867 if (devpriv->ai_neverending) { 868 devpriv->dma_runs_to_end = 1; 869 } else { 870 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many samples we must transfer? */ 871 devpriv->dma_runs_to_end = bytes / devpriv->dmabytestomove[0]; /* how many DMA pages we must fill */ 872 devpriv->last_dma_run = bytes % devpriv->dmabytestomove[0]; /* on last dma transfer must be moved */ 873 if (devpriv->dma_runs_to_end == 0) 874 devpriv->dmabytestomove[0] = 875 devpriv->last_dma_run; 876 devpriv->dma_runs_to_end--; 877 } 878 } 879 if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) { 880 devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; 881 devpriv->ai_eos = 0; 882 } 883 if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) { 884 devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; 885 devpriv->ai_eos = 0; 886 } 887 devpriv->next_dma_buf = 0; 888 set_dma_mode(devpriv->dma, DMA_MODE_READ); 889 dma_flags = claim_dma_lock(); 890 clear_dma_ff(devpriv->dma); 891 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); 892 set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); 893 release_dma_lock(dma_flags); 894 enable_dma(devpriv->dma); 895#ifdef PCL812_EXTDEBUG 896 printk 897 ("pcl812 EDBG: DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n", 898 devpriv->dma, devpriv->hwdmaptr[0], 899 devpriv->hwdmaptr[1], devpriv->dmabytestomove[0], 900 devpriv->dmabytestomove[1], devpriv->ai_eos); 901#endif 902 } 903 904 switch (cmd->convert_src) { 905 case TRIG_TIMER: 906 start_pacer(dev, 1, divisor1, divisor2); 907 break; 908 } 909 910 if (devpriv->ai_dma) { 911 outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); /* let's go! */ 912 } else { 913 outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); /* let's go! */ 914 } 915 916#ifdef PCL812_EXTDEBUG 917 printk("pcl812 EDBG: END: pcl812_ai_cmd(...)\n"); 918#endif 919 920 return 0; 921} 922 923/* 924============================================================================== 925*/ 926static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) 927{ 928 char err = 1; 929 unsigned int mask, timeout; 930 struct comedi_device *dev = d; 931 struct comedi_subdevice *s = dev->subdevices + 0; 932 933 s->async->events = 0; 934 935 timeout = 50; /* wait max 50us, it must finish under 33us */ 936 if (devpriv->ai_is16b) { 937 mask = 0xffff; 938 while (timeout--) { 939 if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { 940 err = 0; 941 break; 942 } 943 udelay(1); 944 } 945 } else { 946 mask = 0x0fff; 947 while (timeout--) { 948 if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { 949 err = 0; 950 break; 951 } 952 udelay(1); 953 } 954 } 955 956 if (err) { 957 printk 958 ("comedi%d: pcl812: (%s at 0x%lx) A/D cmd IRQ without DRDY!\n", 959 dev->minor, dev->board_name, dev->iobase); 960 pcl812_ai_cancel(dev, s); 961 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 962 comedi_event(dev, s); 963 return IRQ_HANDLED; 964 } 965 966 comedi_buf_put(s->async, 967 ((inb(dev->iobase + PCL812_AD_HI) << 8) | inb(dev->iobase + 968 PCL812_AD_LO)) & mask); 969 970 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 971 972 if (s->async->cur_chan == 0) { /* one scan done */ 973 devpriv->ai_act_scan++; 974 if (!(devpriv->ai_neverending)) 975 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 976 pcl812_ai_cancel(dev, s); 977 s->async->events |= COMEDI_CB_EOA; 978 } 979 } 980 981 comedi_event(dev, s); 982 return IRQ_HANDLED; 983} 984 985/* 986============================================================================== 987*/ 988static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, 989 short *ptr, unsigned int bufptr, unsigned int len) 990{ 991 unsigned int i; 992 993 s->async->events = 0; 994 for (i = len; i; i--) { 995 comedi_buf_put(s->async, ptr[bufptr++]); /* get one sample */ 996 997 if (s->async->cur_chan == 0) { 998 devpriv->ai_act_scan++; 999 if (!devpriv->ai_neverending) 1000 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 1001 pcl812_ai_cancel(dev, s); 1002 s->async->events |= COMEDI_CB_EOA; 1003 break; 1004 } 1005 } 1006 } 1007 1008 comedi_event(dev, s); 1009} 1010 1011/* 1012============================================================================== 1013*/ 1014static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) 1015{ 1016 struct comedi_device *dev = d; 1017 struct comedi_subdevice *s = dev->subdevices + 0; 1018 unsigned long dma_flags; 1019 int len, bufptr; 1020 short *ptr; 1021 1022#ifdef PCL812_EXTDEBUG 1023 printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n"); 1024#endif 1025 ptr = (short *) devpriv->dmabuf[devpriv->next_dma_buf]; 1026 len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - 1027 devpriv->ai_poll_ptr; 1028 1029 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; 1030 disable_dma(devpriv->dma); 1031 set_dma_mode(devpriv->dma, DMA_MODE_READ); 1032 dma_flags = claim_dma_lock(); 1033 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); 1034 if (devpriv->ai_eos) { 1035 set_dma_count(devpriv->dma, 1036 devpriv->dmabytestomove[devpriv->next_dma_buf]); 1037 } else { 1038 if (devpriv->dma_runs_to_end) { 1039 set_dma_count(devpriv->dma, 1040 devpriv->dmabytestomove[devpriv->next_dma_buf]); 1041 } else { 1042 set_dma_count(devpriv->dma, devpriv->last_dma_run); 1043 } 1044 devpriv->dma_runs_to_end--; 1045 } 1046 release_dma_lock(dma_flags); 1047 enable_dma(devpriv->dma); 1048 1049 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1050 1051 bufptr = devpriv->ai_poll_ptr; 1052 devpriv->ai_poll_ptr = 0; 1053 1054 transfer_from_dma_buf(dev, s, ptr, bufptr, len); 1055 1056#ifdef PCL812_EXTDEBUG 1057 printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n"); 1058#endif 1059 return IRQ_HANDLED; 1060} 1061 1062/* 1063============================================================================== 1064*/ 1065static irqreturn_t interrupt_pcl812(int irq, void *d) 1066{ 1067 struct comedi_device *dev = d; 1068 1069 if (!dev->attached) { 1070 comedi_error(dev, "spurious interrupt"); 1071 return IRQ_HANDLED; 1072 } 1073 if (devpriv->ai_dma) { 1074 return interrupt_pcl812_ai_dma(irq, d); 1075 } else { 1076 return interrupt_pcl812_ai_int(irq, d); 1077 }; 1078} 1079 1080/* 1081============================================================================== 1082*/ 1083static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) 1084{ 1085 unsigned long flags; 1086 unsigned int top1, top2, i; 1087 1088 if (!devpriv->ai_dma) 1089 return 0; /* poll is valid only for DMA transfer */ 1090 1091 spin_lock_irqsave(&dev->spinlock, flags); 1092 1093 for (i = 0; i < 10; i++) { 1094 top1 = get_dma_residue(devpriv->ai_dma); /* where is now DMA */ 1095 top2 = get_dma_residue(devpriv->ai_dma); 1096 if (top1 == top2) 1097 break; 1098 } 1099 1100 if (top1 != top2) { 1101 spin_unlock_irqrestore(&dev->spinlock, flags); 1102 return 0; 1103 } 1104 1105 top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1; /* where is now DMA in buffer */ 1106 top1 >>= 1; /* sample position */ 1107 top2 = top1 - devpriv->ai_poll_ptr; 1108 if (top2 < 1) { /* no new samples */ 1109 spin_unlock_irqrestore(&dev->spinlock, flags); 1110 return 0; 1111 } 1112 1113 transfer_from_dma_buf(dev, s, 1114 (void *)devpriv->dmabuf[1 - devpriv->next_dma_buf], 1115 devpriv->ai_poll_ptr, top2); 1116 1117 devpriv->ai_poll_ptr = top1; /* new buffer position */ 1118 1119 spin_unlock_irqrestore(&dev->spinlock, flags); 1120 1121 return s->async->buf_write_count - s->async->buf_read_count; 1122} 1123 1124/* 1125============================================================================== 1126*/ 1127static void setup_range_channel(struct comedi_device *dev, struct comedi_subdevice *s, 1128 unsigned int rangechan, char wait) 1129{ 1130 unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ 1131 unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction; /* gain index */ 1132 1133 if ((chan_reg == devpriv->old_chan_reg) 1134 && (gain_reg == devpriv->old_gain_reg)) 1135 return; /* we can return, no change */ 1136 1137 devpriv->old_chan_reg = chan_reg; 1138 devpriv->old_gain_reg = gain_reg; 1139 1140 if (devpriv->use_MPC) { 1141 if (devpriv->use_diff) { 1142 chan_reg = chan_reg | 0x30; /* DIFF inputs */ 1143 } else { 1144 if (chan_reg & 0x80) { 1145 chan_reg = chan_reg | 0x20; /* SE inputs 8-15 */ 1146 } else { 1147 chan_reg = chan_reg | 0x10; /* SE inputs 0-7 */ 1148 } 1149 } 1150 } 1151 1152 outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ 1153 outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ 1154 1155 if (wait) { 1156 udelay(devpriv->max_812_ai_mode0_rangewait); /* XXX this depends on selected range and can be very long for some high gain ranges! */ 1157 } 1158} 1159 1160/* 1161============================================================================== 1162*/ 1163static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, 1164 unsigned int divisor2) 1165{ 1166#ifdef PCL812_EXTDEBUG 1167 printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1, 1168 divisor2); 1169#endif 1170 outb(0xb4, dev->iobase + PCL812_CTRCTL); 1171 outb(0x74, dev->iobase + PCL812_CTRCTL); 1172 udelay(1); 1173 1174 if (mode == 1) { 1175 outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); 1176 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); 1177 outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); 1178 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); 1179 } 1180#ifdef PCL812_EXTDEBUG 1181 printk("pcl812 EDBG: END: start_pacer(...)\n"); 1182#endif 1183} 1184 1185/* 1186============================================================================== 1187*/ 1188static void free_resources(struct comedi_device *dev) 1189{ 1190 1191 if (dev->private) { 1192 if (devpriv->dmabuf[0]) 1193 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); 1194 if (devpriv->dmabuf[1]) 1195 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); 1196 if (devpriv->dma) 1197 free_dma(devpriv->dma); 1198 } 1199 if (dev->irq) 1200 free_irq(dev->irq, dev); 1201 if (dev->iobase) 1202 release_region(dev->iobase, this_board->io_range); 1203} 1204 1205/* 1206============================================================================== 1207*/ 1208static int pcl812_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 1209{ 1210#ifdef PCL812_EXTDEBUG 1211 printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n"); 1212#endif 1213 if (devpriv->ai_dma) 1214 disable_dma(devpriv->dma); 1215 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1216 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); /* Stop A/D */ 1217 start_pacer(dev, -1, 0, 0); /* stop 8254 */ 1218 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1219#ifdef PCL812_EXTDEBUG 1220 printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n"); 1221#endif 1222 return 0; 1223} 1224 1225/* 1226============================================================================== 1227*/ 1228static void pcl812_reset(struct comedi_device *dev) 1229{ 1230#ifdef PCL812_EXTDEBUG 1231 printk("pcl812 EDBG: BGN: pcl812_reset(...)\n"); 1232#endif 1233 outb(0, dev->iobase + PCL812_MUX); 1234 outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); 1235 devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ 1236 devpriv->old_gain_reg = -1; 1237 1238 switch (this_board->board_type) { 1239 case boardPCL812PG: 1240 case boardPCL812: 1241 case boardACL8112: 1242 case boardACL8216: 1243 outb(0, dev->iobase + PCL812_DA2_LO); 1244 outb(0, dev->iobase + PCL812_DA2_HI); 1245 case boardA821: 1246 outb(0, dev->iobase + PCL812_DA1_LO); 1247 outb(0, dev->iobase + PCL812_DA1_HI); 1248 start_pacer(dev, -1, 0, 0); /* stop 8254 */ 1249 outb(0, dev->iobase + PCL812_DO_HI); 1250 outb(0, dev->iobase + PCL812_DO_LO); 1251 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); 1252 outb(0, dev->iobase + PCL812_CLRINT); 1253 break; 1254 case boardPCL813B: 1255 case boardPCL813: 1256 case boardISO813: 1257 case boardACL8113: 1258 udelay(5); 1259 break; 1260 } 1261 udelay(5); 1262#ifdef PCL812_EXTDEBUG 1263 printk("pcl812 EDBG: END: pcl812_reset(...)\n"); 1264#endif 1265} 1266 1267/* 1268============================================================================== 1269*/ 1270static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) 1271{ 1272 int ret, subdev; 1273 unsigned long iobase; 1274 unsigned int irq; 1275 unsigned int dma; 1276 unsigned long pages; 1277 struct comedi_subdevice *s; 1278 int n_subdevices; 1279 1280 iobase = it->options[0]; 1281 printk("comedi%d: pcl812: board=%s, ioport=0x%03lx", dev->minor, 1282 this_board->name, iobase); 1283 1284 if (!request_region(iobase, this_board->io_range, "pcl812")) { 1285 printk("I/O port conflict\n"); 1286 return -EIO; 1287 } 1288 dev->iobase = iobase; 1289 1290 ret = alloc_private(dev, sizeof(struct pcl812_private)); 1291 if (ret < 0) { 1292 free_resources(dev); 1293 return ret; /* Can't alloc mem */ 1294 } 1295 1296 dev->board_name = this_board->name; 1297 1298 irq = 0; 1299 if (this_board->IRQbits != 0) { /* board support IRQ */ 1300 irq = it->options[1]; 1301 if (irq) { /* we want to use IRQ */ 1302 if (((1 << irq) & this_board->IRQbits) == 0) { 1303 printk(", IRQ %u is out of allowed range, DISABLING IT", irq); 1304 irq = 0; /* Bad IRQ */ 1305 } else { 1306 if (request_irq(irq, interrupt_pcl812, 0, "pcl812", dev)) { 1307 printk(", unable to allocate IRQ %u, DISABLING IT", irq); 1308 irq = 0; /* Can't use IRQ */ 1309 } else { 1310 printk(", irq=%u", irq); 1311 } 1312 } 1313 } 1314 } 1315 1316 dev->irq = irq; 1317 1318 dma = 0; 1319 devpriv->dma = dma; 1320 if (!dev->irq) 1321 goto no_dma; /* if we haven't IRQ, we can't use DMA */ 1322 if (this_board->DMAbits != 0) { /* board support DMA */ 1323 dma = it->options[2]; 1324 if (((1 << dma) & this_board->DMAbits) == 0) { 1325 printk(", DMA is out of allowed range, FAIL!\n"); 1326 return -EINVAL; /* Bad DMA */ 1327 } 1328 ret = request_dma(dma, "pcl812"); 1329 if (ret) { 1330 printk(", unable to allocate DMA %u, FAIL!\n", dma); 1331 return -EBUSY; /* DMA isn't free */ 1332 } 1333 devpriv->dma = dma; 1334 printk(", dma=%u", dma); 1335 pages = 1; /* we want 8KB */ 1336 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); 1337 if (!devpriv->dmabuf[0]) { 1338 printk(", unable to allocate DMA buffer, FAIL!\n"); 1339 /* maybe experiment with try_to_free_pages() will help .... */ 1340 free_resources(dev); 1341 return -EBUSY; /* no buffer :-( */ 1342 } 1343 devpriv->dmapages[0] = pages; 1344 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); 1345 devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); 1346 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); 1347 if (!devpriv->dmabuf[1]) { 1348 printk(", unable to allocate DMA buffer, FAIL!\n"); 1349 free_resources(dev); 1350 return -EBUSY; 1351 } 1352 devpriv->dmapages[1] = pages; 1353 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); 1354 devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); 1355 } 1356 no_dma: 1357 1358 n_subdevices = 0; 1359 if (this_board->n_aichan > 0) 1360 n_subdevices++; 1361 if (this_board->n_aochan > 0) 1362 n_subdevices++; 1363 if (this_board->n_dichan > 0) 1364 n_subdevices++; 1365 if (this_board->n_dochan > 0) 1366 n_subdevices++; 1367 1368 ret = alloc_subdevices(dev, n_subdevices); 1369 if (ret < 0) { 1370 free_resources(dev); 1371 return ret; 1372 } 1373 1374 subdev = 0; 1375 1376 /* analog input */ 1377 if (this_board->n_aichan > 0) { 1378 s = dev->subdevices + subdev; 1379 s->type = COMEDI_SUBD_AI; 1380 s->subdev_flags = SDF_READABLE; 1381 switch (this_board->board_type) { 1382 case boardA821: 1383 if (it->options[2] == 1) { 1384 s->n_chan = this_board->n_aichan_diff; 1385 s->subdev_flags |= SDF_DIFF; 1386 devpriv->use_diff = 1; 1387 } else { 1388 s->n_chan = this_board->n_aichan; 1389 s->subdev_flags |= SDF_GROUND; 1390 } 1391 break; 1392 case boardACL8112: 1393 case boardACL8216: 1394 if (it->options[4] == 1) { 1395 s->n_chan = this_board->n_aichan_diff; 1396 s->subdev_flags |= SDF_DIFF; 1397 devpriv->use_diff = 1; 1398 } else { 1399 s->n_chan = this_board->n_aichan; 1400 s->subdev_flags |= SDF_GROUND; 1401 } 1402 break; 1403 default: 1404 s->n_chan = this_board->n_aichan; 1405 s->subdev_flags |= SDF_GROUND; 1406 break; 1407 } 1408 s->maxdata = this_board->ai_maxdata; 1409 s->len_chanlist = MAX_CHANLIST_LEN; 1410 s->range_table = this_board->rangelist_ai; 1411 if (this_board->board_type == boardACL8216) { 1412 s->insn_read = acl8216_ai_insn_read; 1413 } else { 1414 s->insn_read = pcl812_ai_insn_read; 1415 } 1416 devpriv->use_MPC = this_board->haveMPC508; 1417 s->cancel = pcl812_ai_cancel; 1418 if (dev->irq) { 1419 dev->read_subdev = s; 1420 s->subdev_flags |= SDF_CMD_READ; 1421 s->do_cmdtest = pcl812_ai_cmdtest; 1422 s->do_cmd = pcl812_ai_cmd; 1423 s->poll = pcl812_ai_poll; 1424 } 1425 switch (this_board->board_type) { 1426 case boardPCL812PG: 1427 if (it->options[4] == 1) 1428 s->range_table = &range_pcl812pg2_ai; 1429 break; 1430 case boardPCL812: 1431 switch (it->options[4]) { 1432 case 0: 1433 s->range_table = &range_bipolar10; 1434 break; 1435 case 1: 1436 s->range_table = &range_bipolar5; 1437 break; 1438 case 2: 1439 s->range_table = &range_bipolar2_5; 1440 break; 1441 case 3: 1442 s->range_table = &range812_bipolar1_25; 1443 break; 1444 case 4: 1445 s->range_table = &range812_bipolar0_625; 1446 break; 1447 case 5: 1448 s->range_table = &range812_bipolar0_3125; 1449 break; 1450 default: 1451 s->range_table = &range_bipolar10; 1452 break; 1453 printk(", incorrect range number %d, changing to 0 (+/-10V)", it->options[4]); 1454 break; 1455 } 1456 break; 1457 break; 1458 case boardPCL813B: 1459 if (it->options[1] == 1) 1460 s->range_table = &range_pcl813b2_ai; 1461 break; 1462 case boardISO813: 1463 switch (it->options[1]) { 1464 case 0: 1465 s->range_table = &range_iso813_1_ai; 1466 break; 1467 case 1: 1468 s->range_table = &range_iso813_1_2_ai; 1469 break; 1470 case 2: 1471 s->range_table = &range_iso813_2_ai; 1472 devpriv->range_correction = 1; 1473 break; 1474 case 3: 1475 s->range_table = &range_iso813_2_2_ai; 1476 devpriv->range_correction = 1; 1477 break; 1478 default: 1479 s->range_table = &range_iso813_1_ai; 1480 break; 1481 printk(", incorrect range number %d, changing to 0 ", it->options[1]); 1482 break; 1483 } 1484 break; 1485 case boardACL8113: 1486 switch (it->options[1]) { 1487 case 0: 1488 s->range_table = &range_acl8113_1_ai; 1489 break; 1490 case 1: 1491 s->range_table = &range_acl8113_1_2_ai; 1492 break; 1493 case 2: 1494 s->range_table = &range_acl8113_2_ai; 1495 devpriv->range_correction = 1; 1496 break; 1497 case 3: 1498 s->range_table = &range_acl8113_2_2_ai; 1499 devpriv->range_correction = 1; 1500 break; 1501 default: 1502 s->range_table = &range_acl8113_1_ai; 1503 break; 1504 printk(", incorrect range number %d, changing to 0 ", it->options[1]); 1505 break; 1506 } 1507 break; 1508 } 1509 subdev++; 1510 } 1511 1512 /* analog output */ 1513 if (this_board->n_aochan > 0) { 1514 s = dev->subdevices + subdev; 1515 s->type = COMEDI_SUBD_AO; 1516 s->subdev_flags = SDF_WRITABLE | SDF_GROUND; 1517 s->n_chan = this_board->n_aochan; 1518 s->maxdata = 0xfff; 1519 s->len_chanlist = 1; 1520 s->range_table = this_board->rangelist_ao; 1521 s->insn_read = pcl812_ao_insn_read; 1522 s->insn_write = pcl812_ao_insn_write; 1523 switch (this_board->board_type) { 1524 case boardA821: 1525 if (it->options[3] == 1) 1526 s->range_table = &range_unipolar10; 1527 break; 1528 case boardPCL812: 1529 case boardACL8112: 1530 case boardPCL812PG: 1531 case boardACL8216: 1532 if (it->options[5] == 1) 1533 s->range_table = &range_unipolar10; 1534 if (it->options[5] == 2) 1535 s->range_table = &range_unknown; 1536 break; 1537 } 1538 subdev++; 1539 } 1540 1541 /* digital input */ 1542 if (this_board->n_dichan > 0) { 1543 s = dev->subdevices + subdev; 1544 s->type = COMEDI_SUBD_DI; 1545 s->subdev_flags = SDF_READABLE; 1546 s->n_chan = this_board->n_dichan; 1547 s->maxdata = 1; 1548 s->len_chanlist = this_board->n_dichan; 1549 s->range_table = &range_digital; 1550 s->insn_bits = pcl812_di_insn_bits; 1551 subdev++; 1552 } 1553 1554 /* digital output */ 1555 if (this_board->n_dochan > 0) { 1556 s = dev->subdevices + subdev; 1557 s->type = COMEDI_SUBD_DO; 1558 s->subdev_flags = SDF_WRITABLE; 1559 s->n_chan = this_board->n_dochan; 1560 s->maxdata = 1; 1561 s->len_chanlist = this_board->n_dochan; 1562 s->range_table = &range_digital; 1563 s->insn_bits = pcl812_do_insn_bits; 1564 subdev++; 1565 } 1566 1567 switch (this_board->board_type) { 1568 case boardACL8216: 1569 devpriv->ai_is16b = 1; 1570 case boardPCL812PG: 1571 case boardPCL812: 1572 case boardACL8112: 1573 devpriv->max_812_ai_mode0_rangewait = 1; 1574 if (it->options[3] > 0) 1575 devpriv->use_ext_trg = 1; /* we use external trigger */ 1576 case boardA821: 1577 devpriv->max_812_ai_mode0_rangewait = 1; 1578 devpriv->mode_reg_int = (irq << 4) & 0xf0; 1579 break; 1580 case boardPCL813B: 1581 case boardPCL813: 1582 case boardISO813: 1583 case boardACL8113: 1584 devpriv->max_812_ai_mode0_rangewait = 5; /* maybe there must by greatest timeout */ 1585 break; 1586 } 1587 1588 printk("\n"); 1589 devpriv->valid = 1; 1590 1591 pcl812_reset(dev); 1592 1593 return 0; 1594} 1595 1596/* 1597============================================================================== 1598 */ 1599static int pcl812_detach(struct comedi_device *dev) 1600{ 1601 1602#ifdef PCL812_EXTDEBUG 1603 printk("comedi%d: pcl812: remove\n", dev->minor); 1604#endif 1605 free_resources(dev); 1606 return 0; 1607} 1608