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