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