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