pcl812.c revision c203b521e64e062d94f1ced1510206c0a55d5b55
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 unknown (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 unknown (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 unknown (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 unsigned int next_chan; 959 960 s->async->events = 0; 961 962 timeout = 50; /* wait max 50us, it must finish under 33us */ 963 if (devpriv->ai_is16b) { 964 mask = 0xffff; 965 while (timeout--) { 966 if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { 967 err = 0; 968 break; 969 } 970 udelay(1); 971 } 972 } else { 973 mask = 0x0fff; 974 while (timeout--) { 975 if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { 976 err = 0; 977 break; 978 } 979 udelay(1); 980 } 981 } 982 983 if (err) { 984 printk 985 ("comedi%d: pcl812: (%s at 0x%lx) A/D cmd IRQ without DRDY!\n", 986 dev->minor, dev->board_name, dev->iobase); 987 pcl812_ai_cancel(dev, s); 988 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; 989 comedi_event(dev, s); 990 return IRQ_HANDLED; 991 } 992 993 comedi_buf_put(s->async, 994 ((inb(dev->iobase + PCL812_AD_HI) << 8) | 995 inb(dev->iobase + PCL812_AD_LO)) & mask); 996 997 /* Set up next channel. Added by abbotti 2010-01-20, but untested. */ 998 next_chan = s->async->cur_chan + 1; 999 if (next_chan >= devpriv->ai_n_chan) 1000 next_chan = 0; 1001 if (devpriv->ai_chanlist[s->async->cur_chan] != 1002 devpriv->ai_chanlist[next_chan]) 1003 setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0); 1004 1005 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1006 1007 s->async->cur_chan = next_chan; 1008 if (next_chan == 0) { /* one scan done */ 1009 devpriv->ai_act_scan++; 1010 if (!(devpriv->ai_neverending)) 1011 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 1012 pcl812_ai_cancel(dev, s); 1013 s->async->events |= COMEDI_CB_EOA; 1014 } 1015 } 1016 1017 comedi_event(dev, s); 1018 return IRQ_HANDLED; 1019} 1020 1021/* 1022============================================================================== 1023*/ 1024static void transfer_from_dma_buf(struct comedi_device *dev, 1025 struct comedi_subdevice *s, short *ptr, 1026 unsigned int bufptr, unsigned int len) 1027{ 1028 unsigned int i; 1029 1030 s->async->events = 0; 1031 for (i = len; i; i--) { 1032 comedi_buf_put(s->async, ptr[bufptr++]); /* get one sample */ 1033 1034 s->async->cur_chan++; 1035 if (s->async->cur_chan >= devpriv->ai_n_chan) { 1036 s->async->cur_chan = 0; 1037 devpriv->ai_act_scan++; 1038 if (!devpriv->ai_neverending) 1039 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ 1040 pcl812_ai_cancel(dev, s); 1041 s->async->events |= COMEDI_CB_EOA; 1042 break; 1043 } 1044 } 1045 } 1046 1047 comedi_event(dev, s); 1048} 1049 1050/* 1051============================================================================== 1052*/ 1053static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) 1054{ 1055 struct comedi_device *dev = d; 1056 struct comedi_subdevice *s = dev->subdevices + 0; 1057 unsigned long dma_flags; 1058 int len, bufptr; 1059 short *ptr; 1060 1061#ifdef PCL812_EXTDEBUG 1062 printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n"); 1063#endif 1064 ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf]; 1065 len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - 1066 devpriv->ai_poll_ptr; 1067 1068 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; 1069 disable_dma(devpriv->dma); 1070 set_dma_mode(devpriv->dma, DMA_MODE_READ); 1071 dma_flags = claim_dma_lock(); 1072 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); 1073 if (devpriv->ai_eos) { 1074 set_dma_count(devpriv->dma, 1075 devpriv->dmabytestomove[devpriv->next_dma_buf]); 1076 } else { 1077 if (devpriv->dma_runs_to_end) { 1078 set_dma_count(devpriv->dma, 1079 devpriv->dmabytestomove[devpriv-> 1080 next_dma_buf]); 1081 } else { 1082 set_dma_count(devpriv->dma, devpriv->last_dma_run); 1083 } 1084 devpriv->dma_runs_to_end--; 1085 } 1086 release_dma_lock(dma_flags); 1087 enable_dma(devpriv->dma); 1088 1089 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1090 1091 bufptr = devpriv->ai_poll_ptr; 1092 devpriv->ai_poll_ptr = 0; 1093 1094 transfer_from_dma_buf(dev, s, ptr, bufptr, len); 1095 1096#ifdef PCL812_EXTDEBUG 1097 printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n"); 1098#endif 1099 return IRQ_HANDLED; 1100} 1101 1102/* 1103============================================================================== 1104*/ 1105static irqreturn_t interrupt_pcl812(int irq, void *d) 1106{ 1107 struct comedi_device *dev = d; 1108 1109 if (!dev->attached) { 1110 comedi_error(dev, "spurious interrupt"); 1111 return IRQ_HANDLED; 1112 } 1113 if (devpriv->ai_dma) { 1114 return interrupt_pcl812_ai_dma(irq, d); 1115 } else { 1116 return interrupt_pcl812_ai_int(irq, d); 1117 }; 1118} 1119 1120/* 1121============================================================================== 1122*/ 1123static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) 1124{ 1125 unsigned long flags; 1126 unsigned int top1, top2, i; 1127 1128 if (!devpriv->ai_dma) 1129 return 0; /* poll is valid only for DMA transfer */ 1130 1131 spin_lock_irqsave(&dev->spinlock, flags); 1132 1133 for (i = 0; i < 10; i++) { 1134 top1 = get_dma_residue(devpriv->ai_dma); /* where is now DMA */ 1135 top2 = get_dma_residue(devpriv->ai_dma); 1136 if (top1 == top2) 1137 break; 1138 } 1139 1140 if (top1 != top2) { 1141 spin_unlock_irqrestore(&dev->spinlock, flags); 1142 return 0; 1143 } 1144 1145 top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1; /* where is now DMA in buffer */ 1146 top1 >>= 1; /* sample position */ 1147 top2 = top1 - devpriv->ai_poll_ptr; 1148 if (top2 < 1) { /* no new samples */ 1149 spin_unlock_irqrestore(&dev->spinlock, flags); 1150 return 0; 1151 } 1152 1153 transfer_from_dma_buf(dev, s, 1154 (void *)devpriv->dmabuf[1 - 1155 devpriv->next_dma_buf], 1156 devpriv->ai_poll_ptr, top2); 1157 1158 devpriv->ai_poll_ptr = top1; /* new buffer position */ 1159 1160 spin_unlock_irqrestore(&dev->spinlock, flags); 1161 1162 return s->async->buf_write_count - s->async->buf_read_count; 1163} 1164 1165/* 1166============================================================================== 1167*/ 1168static void setup_range_channel(struct comedi_device *dev, 1169 struct comedi_subdevice *s, 1170 unsigned int rangechan, char wait) 1171{ 1172 unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ 1173 unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction; /* gain index */ 1174 1175 if ((chan_reg == devpriv->old_chan_reg) 1176 && (gain_reg == devpriv->old_gain_reg)) 1177 return; /* we can return, no change */ 1178 1179 devpriv->old_chan_reg = chan_reg; 1180 devpriv->old_gain_reg = gain_reg; 1181 1182 if (devpriv->use_MPC) { 1183 if (devpriv->use_diff) { 1184 chan_reg = chan_reg | 0x30; /* DIFF inputs */ 1185 } else { 1186 if (chan_reg & 0x80) { 1187 chan_reg = chan_reg | 0x20; /* SE inputs 8-15 */ 1188 } else { 1189 chan_reg = chan_reg | 0x10; /* SE inputs 0-7 */ 1190 } 1191 } 1192 } 1193 1194 outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ 1195 outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ 1196 1197 if (wait) { 1198 udelay(devpriv->max_812_ai_mode0_rangewait); /* XXX this depends on selected range and can be very long for some high gain ranges! */ 1199 } 1200} 1201 1202/* 1203============================================================================== 1204*/ 1205static void start_pacer(struct comedi_device *dev, int mode, 1206 unsigned int divisor1, unsigned int divisor2) 1207{ 1208#ifdef PCL812_EXTDEBUG 1209 printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1, 1210 divisor2); 1211#endif 1212 outb(0xb4, dev->iobase + PCL812_CTRCTL); 1213 outb(0x74, dev->iobase + PCL812_CTRCTL); 1214 udelay(1); 1215 1216 if (mode == 1) { 1217 outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); 1218 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); 1219 outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); 1220 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); 1221 } 1222#ifdef PCL812_EXTDEBUG 1223 printk("pcl812 EDBG: END: start_pacer(...)\n"); 1224#endif 1225} 1226 1227/* 1228============================================================================== 1229*/ 1230static void free_resources(struct comedi_device *dev) 1231{ 1232 1233 if (dev->private) { 1234 if (devpriv->dmabuf[0]) 1235 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); 1236 if (devpriv->dmabuf[1]) 1237 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); 1238 if (devpriv->dma) 1239 free_dma(devpriv->dma); 1240 } 1241 if (dev->irq) 1242 free_irq(dev->irq, dev); 1243 if (dev->iobase) 1244 release_region(dev->iobase, this_board->io_range); 1245} 1246 1247/* 1248============================================================================== 1249*/ 1250static int pcl812_ai_cancel(struct comedi_device *dev, 1251 struct comedi_subdevice *s) 1252{ 1253#ifdef PCL812_EXTDEBUG 1254 printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n"); 1255#endif 1256 if (devpriv->ai_dma) 1257 disable_dma(devpriv->dma); 1258 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1259 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); /* Stop A/D */ 1260 start_pacer(dev, -1, 0, 0); /* stop 8254 */ 1261 outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ 1262#ifdef PCL812_EXTDEBUG 1263 printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n"); 1264#endif 1265 return 0; 1266} 1267 1268/* 1269============================================================================== 1270*/ 1271static void pcl812_reset(struct comedi_device *dev) 1272{ 1273#ifdef PCL812_EXTDEBUG 1274 printk("pcl812 EDBG: BGN: pcl812_reset(...)\n"); 1275#endif 1276 outb(0, dev->iobase + PCL812_MUX); 1277 outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); 1278 devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ 1279 devpriv->old_gain_reg = -1; 1280 1281 switch (this_board->board_type) { 1282 case boardPCL812PG: 1283 case boardPCL812: 1284 case boardACL8112: 1285 case boardACL8216: 1286 outb(0, dev->iobase + PCL812_DA2_LO); 1287 outb(0, dev->iobase + PCL812_DA2_HI); 1288 case boardA821: 1289 outb(0, dev->iobase + PCL812_DA1_LO); 1290 outb(0, dev->iobase + PCL812_DA1_HI); 1291 start_pacer(dev, -1, 0, 0); /* stop 8254 */ 1292 outb(0, dev->iobase + PCL812_DO_HI); 1293 outb(0, dev->iobase + PCL812_DO_LO); 1294 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); 1295 outb(0, dev->iobase + PCL812_CLRINT); 1296 break; 1297 case boardPCL813B: 1298 case boardPCL813: 1299 case boardISO813: 1300 case boardACL8113: 1301 udelay(5); 1302 break; 1303 } 1304 udelay(5); 1305#ifdef PCL812_EXTDEBUG 1306 printk("pcl812 EDBG: END: pcl812_reset(...)\n"); 1307#endif 1308} 1309 1310/* 1311============================================================================== 1312*/ 1313static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) 1314{ 1315 int ret, subdev; 1316 unsigned long iobase; 1317 unsigned int irq; 1318 unsigned int dma; 1319 unsigned long pages; 1320 struct comedi_subdevice *s; 1321 int n_subdevices; 1322 1323 iobase = it->options[0]; 1324 printk("comedi%d: pcl812: board=%s, ioport=0x%03lx", dev->minor, 1325 this_board->name, iobase); 1326 1327 if (!request_region(iobase, this_board->io_range, "pcl812")) { 1328 printk("I/O port conflict\n"); 1329 return -EIO; 1330 } 1331 dev->iobase = iobase; 1332 1333 ret = alloc_private(dev, sizeof(struct pcl812_private)); 1334 if (ret < 0) { 1335 free_resources(dev); 1336 return ret; /* Can't alloc mem */ 1337 } 1338 1339 dev->board_name = this_board->name; 1340 1341 irq = 0; 1342 if (this_board->IRQbits != 0) { /* board support IRQ */ 1343 irq = it->options[1]; 1344 if (irq) { /* we want to use IRQ */ 1345 if (((1 << irq) & this_board->IRQbits) == 0) { 1346 printk 1347 (", IRQ %u is out of allowed range, DISABLING IT", 1348 irq); 1349 irq = 0; /* Bad IRQ */ 1350 } else { 1351 if (request_irq 1352 (irq, interrupt_pcl812, 0, "pcl812", dev)) { 1353 printk 1354 (", unable to allocate IRQ %u, DISABLING IT", 1355 irq); 1356 irq = 0; /* Can't use IRQ */ 1357 } else { 1358 printk(", irq=%u", irq); 1359 } 1360 } 1361 } 1362 } 1363 1364 dev->irq = irq; 1365 1366 dma = 0; 1367 devpriv->dma = dma; 1368 if (!dev->irq) 1369 goto no_dma; /* if we haven't IRQ, we can't use DMA */ 1370 if (this_board->DMAbits != 0) { /* board support DMA */ 1371 dma = it->options[2]; 1372 if (((1 << dma) & this_board->DMAbits) == 0) { 1373 printk(", DMA is out of allowed range, FAIL!\n"); 1374 return -EINVAL; /* Bad DMA */ 1375 } 1376 ret = request_dma(dma, "pcl812"); 1377 if (ret) { 1378 printk(", unable to allocate DMA %u, FAIL!\n", dma); 1379 return -EBUSY; /* DMA isn't free */ 1380 } 1381 devpriv->dma = dma; 1382 printk(", dma=%u", dma); 1383 pages = 1; /* we want 8KB */ 1384 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); 1385 if (!devpriv->dmabuf[0]) { 1386 printk(", unable to allocate DMA buffer, FAIL!\n"); 1387 /* maybe experiment with try_to_free_pages() will help .... */ 1388 free_resources(dev); 1389 return -EBUSY; /* no buffer :-( */ 1390 } 1391 devpriv->dmapages[0] = pages; 1392 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); 1393 devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); 1394 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); 1395 if (!devpriv->dmabuf[1]) { 1396 printk(", unable to allocate DMA buffer, FAIL!\n"); 1397 free_resources(dev); 1398 return -EBUSY; 1399 } 1400 devpriv->dmapages[1] = pages; 1401 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); 1402 devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); 1403 } 1404no_dma: 1405 1406 n_subdevices = 0; 1407 if (this_board->n_aichan > 0) 1408 n_subdevices++; 1409 if (this_board->n_aochan > 0) 1410 n_subdevices++; 1411 if (this_board->n_dichan > 0) 1412 n_subdevices++; 1413 if (this_board->n_dochan > 0) 1414 n_subdevices++; 1415 1416 ret = alloc_subdevices(dev, n_subdevices); 1417 if (ret < 0) { 1418 free_resources(dev); 1419 return ret; 1420 } 1421 1422 subdev = 0; 1423 1424 /* analog input */ 1425 if (this_board->n_aichan > 0) { 1426 s = dev->subdevices + subdev; 1427 s->type = COMEDI_SUBD_AI; 1428 s->subdev_flags = SDF_READABLE; 1429 switch (this_board->board_type) { 1430 case boardA821: 1431 if (it->options[2] == 1) { 1432 s->n_chan = this_board->n_aichan_diff; 1433 s->subdev_flags |= SDF_DIFF; 1434 devpriv->use_diff = 1; 1435 } else { 1436 s->n_chan = this_board->n_aichan; 1437 s->subdev_flags |= SDF_GROUND; 1438 } 1439 break; 1440 case boardACL8112: 1441 case boardACL8216: 1442 if (it->options[4] == 1) { 1443 s->n_chan = this_board->n_aichan_diff; 1444 s->subdev_flags |= SDF_DIFF; 1445 devpriv->use_diff = 1; 1446 } else { 1447 s->n_chan = this_board->n_aichan; 1448 s->subdev_flags |= SDF_GROUND; 1449 } 1450 break; 1451 default: 1452 s->n_chan = this_board->n_aichan; 1453 s->subdev_flags |= SDF_GROUND; 1454 break; 1455 } 1456 s->maxdata = this_board->ai_maxdata; 1457 s->len_chanlist = MAX_CHANLIST_LEN; 1458 s->range_table = this_board->rangelist_ai; 1459 if (this_board->board_type == boardACL8216) { 1460 s->insn_read = acl8216_ai_insn_read; 1461 } else { 1462 s->insn_read = pcl812_ai_insn_read; 1463 } 1464 devpriv->use_MPC = this_board->haveMPC508; 1465 s->cancel = pcl812_ai_cancel; 1466 if (dev->irq) { 1467 dev->read_subdev = s; 1468 s->subdev_flags |= SDF_CMD_READ; 1469 s->do_cmdtest = pcl812_ai_cmdtest; 1470 s->do_cmd = pcl812_ai_cmd; 1471 s->poll = pcl812_ai_poll; 1472 } 1473 switch (this_board->board_type) { 1474 case boardPCL812PG: 1475 if (it->options[4] == 1) 1476 s->range_table = &range_pcl812pg2_ai; 1477 break; 1478 case boardPCL812: 1479 switch (it->options[4]) { 1480 case 0: 1481 s->range_table = &range_bipolar10; 1482 break; 1483 case 1: 1484 s->range_table = &range_bipolar5; 1485 break; 1486 case 2: 1487 s->range_table = &range_bipolar2_5; 1488 break; 1489 case 3: 1490 s->range_table = &range812_bipolar1_25; 1491 break; 1492 case 4: 1493 s->range_table = &range812_bipolar0_625; 1494 break; 1495 case 5: 1496 s->range_table = &range812_bipolar0_3125; 1497 break; 1498 default: 1499 s->range_table = &range_bipolar10; 1500 break; 1501 printk 1502 (", incorrect range number %d, changing to 0 (+/-10V)", 1503 it->options[4]); 1504 break; 1505 } 1506 break; 1507 break; 1508 case boardPCL813B: 1509 if (it->options[1] == 1) 1510 s->range_table = &range_pcl813b2_ai; 1511 break; 1512 case boardISO813: 1513 switch (it->options[1]) { 1514 case 0: 1515 s->range_table = &range_iso813_1_ai; 1516 break; 1517 case 1: 1518 s->range_table = &range_iso813_1_2_ai; 1519 break; 1520 case 2: 1521 s->range_table = &range_iso813_2_ai; 1522 devpriv->range_correction = 1; 1523 break; 1524 case 3: 1525 s->range_table = &range_iso813_2_2_ai; 1526 devpriv->range_correction = 1; 1527 break; 1528 default: 1529 s->range_table = &range_iso813_1_ai; 1530 break; 1531 printk 1532 (", incorrect range number %d, changing to 0 ", 1533 it->options[1]); 1534 break; 1535 } 1536 break; 1537 case boardACL8113: 1538 switch (it->options[1]) { 1539 case 0: 1540 s->range_table = &range_acl8113_1_ai; 1541 break; 1542 case 1: 1543 s->range_table = &range_acl8113_1_2_ai; 1544 break; 1545 case 2: 1546 s->range_table = &range_acl8113_2_ai; 1547 devpriv->range_correction = 1; 1548 break; 1549 case 3: 1550 s->range_table = &range_acl8113_2_2_ai; 1551 devpriv->range_correction = 1; 1552 break; 1553 default: 1554 s->range_table = &range_acl8113_1_ai; 1555 break; 1556 printk 1557 (", incorrect range number %d, changing to 0 ", 1558 it->options[1]); 1559 break; 1560 } 1561 break; 1562 } 1563 subdev++; 1564 } 1565 1566 /* analog output */ 1567 if (this_board->n_aochan > 0) { 1568 s = dev->subdevices + subdev; 1569 s->type = COMEDI_SUBD_AO; 1570 s->subdev_flags = SDF_WRITABLE | SDF_GROUND; 1571 s->n_chan = this_board->n_aochan; 1572 s->maxdata = 0xfff; 1573 s->len_chanlist = 1; 1574 s->range_table = this_board->rangelist_ao; 1575 s->insn_read = pcl812_ao_insn_read; 1576 s->insn_write = pcl812_ao_insn_write; 1577 switch (this_board->board_type) { 1578 case boardA821: 1579 if (it->options[3] == 1) 1580 s->range_table = &range_unipolar10; 1581 break; 1582 case boardPCL812: 1583 case boardACL8112: 1584 case boardPCL812PG: 1585 case boardACL8216: 1586 if (it->options[5] == 1) 1587 s->range_table = &range_unipolar10; 1588 if (it->options[5] == 2) 1589 s->range_table = &range_unknown; 1590 break; 1591 } 1592 subdev++; 1593 } 1594 1595 /* digital input */ 1596 if (this_board->n_dichan > 0) { 1597 s = dev->subdevices + subdev; 1598 s->type = COMEDI_SUBD_DI; 1599 s->subdev_flags = SDF_READABLE; 1600 s->n_chan = this_board->n_dichan; 1601 s->maxdata = 1; 1602 s->len_chanlist = this_board->n_dichan; 1603 s->range_table = &range_digital; 1604 s->insn_bits = pcl812_di_insn_bits; 1605 subdev++; 1606 } 1607 1608 /* digital output */ 1609 if (this_board->n_dochan > 0) { 1610 s = dev->subdevices + subdev; 1611 s->type = COMEDI_SUBD_DO; 1612 s->subdev_flags = SDF_WRITABLE; 1613 s->n_chan = this_board->n_dochan; 1614 s->maxdata = 1; 1615 s->len_chanlist = this_board->n_dochan; 1616 s->range_table = &range_digital; 1617 s->insn_bits = pcl812_do_insn_bits; 1618 subdev++; 1619 } 1620 1621 switch (this_board->board_type) { 1622 case boardACL8216: 1623 devpriv->ai_is16b = 1; 1624 case boardPCL812PG: 1625 case boardPCL812: 1626 case boardACL8112: 1627 devpriv->max_812_ai_mode0_rangewait = 1; 1628 if (it->options[3] > 0) 1629 devpriv->use_ext_trg = 1; /* we use external trigger */ 1630 case boardA821: 1631 devpriv->max_812_ai_mode0_rangewait = 1; 1632 devpriv->mode_reg_int = (irq << 4) & 0xf0; 1633 break; 1634 case boardPCL813B: 1635 case boardPCL813: 1636 case boardISO813: 1637 case boardACL8113: 1638 devpriv->max_812_ai_mode0_rangewait = 5; /* maybe there must by greatest timeout */ 1639 break; 1640 } 1641 1642 printk("\n"); 1643 devpriv->valid = 1; 1644 1645 pcl812_reset(dev); 1646 1647 return 0; 1648} 1649 1650/* 1651============================================================================== 1652 */ 1653static int pcl812_detach(struct comedi_device *dev) 1654{ 1655 1656#ifdef PCL812_EXTDEBUG 1657 printk("comedi%d: pcl812: remove\n", dev->minor); 1658#endif 1659 free_resources(dev); 1660 return 0; 1661} 1662