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