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