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