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