linux/drivers/staging/comedi/drivers/pcl816.c
<<
>>
Prefs
   1/*
   2   comedi/drivers/pcl816.c
   3
   4   Author:  Juan Grigera <juan@grigera.com.ar>
   5            based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
   6
   7   hardware driver for Advantech cards:
   8    card:   PCL-816, PCL814B
   9    driver: pcl816
  10*/
  11/*
  12Driver: pcl816
  13Description: Advantech PCL-816 cards, PCL-814
  14Author: Juan Grigera <juan@grigera.com.ar>
  15Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b)
  16Status: works
  17Updated: Tue,  2 Apr 2002 23:15:21 -0800
  18
  19PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO.
  20Differences are at resolution (16 vs 12 bits).
  21
  22The driver support AI command mode, other subdevices not written.
  23
  24Analog output and digital input and output are not supported.
  25
  26Configuration Options:
  27  [0] - IO Base
  28  [1] - IRQ     (0=disable, 2, 3, 4, 5, 6, 7)
  29  [2] - DMA     (0=disable, 1, 3)
  30  [3] - 0, 10=10MHz clock for 8254
  31            1= 1MHz clock for 8254
  32
  33*/
  34
  35#include "../comedidev.h"
  36
  37#include <linux/ioport.h>
  38#include <linux/mc146818rtc.h>
  39#include <linux/gfp.h>
  40#include <linux/delay.h>
  41#include <asm/dma.h>
  42
  43#include "8253.h"
  44
  45#define DEBUG(x) x
  46
  47/* boards constants */
  48/* IO space len */
  49#define PCLx1x_RANGE 16
  50
  51/* #define outb(x,y)  printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
  52
  53/* INTEL 8254 counters */
  54#define PCL816_CTR0 4
  55#define PCL816_CTR1 5
  56#define PCL816_CTR2 6
  57/* R: counter read-back register W: counter control */
  58#define PCL816_CTRCTL 7
  59
  60/* R: A/D high byte W: A/D range control */
  61#define PCL816_RANGE 9
  62/* W: clear INT request */
  63#define PCL816_CLRINT 10
  64/* R: next mux scan channel W: mux scan channel & range control pointer */
  65#define PCL816_MUX 11
  66/* R/W: operation control register */
  67#define PCL816_CONTROL 12
  68
  69/* R: return status byte  W: set DMA/IRQ */
  70#define PCL816_STATUS 13
  71#define PCL816_STATUS_DRDY_MASK 0x80
  72
  73/* R: low byte of A/D W: soft A/D trigger */
  74#define PCL816_AD_LO 8
  75/* R: high byte of A/D W: A/D range control */
  76#define PCL816_AD_HI 9
  77
  78/* type of interrupt handler */
  79#define INT_TYPE_AI1_INT 1
  80#define INT_TYPE_AI1_DMA 2
  81#define INT_TYPE_AI3_INT 4
  82#define INT_TYPE_AI3_DMA 5
  83#ifdef unused
  84#define INT_TYPE_AI1_DMA_RTC 9
  85#define INT_TYPE_AI3_DMA_RTC 10
  86
  87/* RTC stuff... */
  88#define RTC_IRQ         8
  89#define RTC_IO_EXTENT   0x10
  90#endif
  91
  92#define MAGIC_DMA_WORD 0x5a5a
  93
  94static const struct comedi_lrange range_pcl816 = { 8, {
  95                                                       BIP_RANGE(10),
  96                                                       BIP_RANGE(5),
  97                                                       BIP_RANGE(2.5),
  98                                                       BIP_RANGE(1.25),
  99                                                       UNI_RANGE(10),
 100                                                       UNI_RANGE(5),
 101                                                       UNI_RANGE(2.5),
 102                                                       UNI_RANGE(1.25),
 103                                                       }
 104};
 105
 106struct pcl816_board {
 107
 108        const char *name;       /*  board name */
 109        int n_ranges;           /*  len of range list */
 110        int n_aichan;           /*  num of A/D chans in diferencial mode */
 111        unsigned int ai_ns_min; /*  minimal allowed delay between samples (in ns) */
 112        int n_aochan;           /*  num of D/A chans */
 113        int n_dichan;           /*  num of DI chans */
 114        int n_dochan;           /*  num of DO chans */
 115        const struct comedi_lrange *ai_range_type;      /*  default A/D rangelist */
 116        const struct comedi_lrange *ao_range_type;      /*  default D/A rangelist */
 117        unsigned int io_range;  /*  len of IO space */
 118        unsigned int IRQbits;   /*  allowed interrupts */
 119        unsigned int DMAbits;   /*  allowed DMA chans */
 120        int ai_maxdata;         /*  maxdata for A/D */
 121        int ao_maxdata;         /*  maxdata for D/A */
 122        int ai_chanlist;        /*  allowed len of channel list A/D */
 123        int ao_chanlist;        /*  allowed len of channel list D/A */
 124        int i8254_osc_base;     /*  1/frequency of on board oscilator in ns */
 125};
 126
 127static const struct pcl816_board boardtypes[] = {
 128        {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
 129         &range_pcl816, PCLx1x_RANGE,
 130         0x00fc,                /*  IRQ mask */
 131         0x0a,                  /*  DMA mask */
 132         0xffff,                /*  16-bit card */
 133         0xffff,                /*  D/A maxdata */
 134         1024,
 135         1,                     /*  ao chan list */
 136         100},
 137        {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
 138         &range_pcl816, PCLx1x_RANGE,
 139         0x00fc,
 140         0x0a,
 141         0x3fff,                /* 14 bit card */
 142         0x3fff,
 143         1024,
 144         1,
 145         100},
 146};
 147
 148#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
 149#define devpriv ((struct pcl816_private *)dev->private)
 150#define this_board ((const struct pcl816_board *)dev->board_ptr)
 151
 152static int pcl816_attach(struct comedi_device *dev,
 153                         struct comedi_devconfig *it);
 154static int pcl816_detach(struct comedi_device *dev);
 155
 156#ifdef unused
 157static int RTC_lock = 0;        /* RTC lock */
 158static int RTC_timer_lock = 0;  /* RTC int lock */
 159#endif
 160
 161static struct comedi_driver driver_pcl816 = {
 162        .driver_name = "pcl816",
 163        .module = THIS_MODULE,
 164        .attach = pcl816_attach,
 165        .detach = pcl816_detach,
 166        .board_name = &boardtypes[0].name,
 167        .num_names = n_boardtypes,
 168        .offset = sizeof(struct pcl816_board),
 169};
 170
 171static int __init driver_pcl816_init_module(void)
 172{
 173        return comedi_driver_register(&driver_pcl816);
 174}
 175
 176static void __exit driver_pcl816_cleanup_module(void)
 177{
 178        comedi_driver_unregister(&driver_pcl816);
 179}
 180
 181module_init(driver_pcl816_init_module);
 182module_exit(driver_pcl816_cleanup_module);
 183
 184struct pcl816_private {
 185
 186        unsigned int dma;       /*  used DMA, 0=don't use DMA */
 187        int dma_rtc;            /*  1=RTC used with DMA, 0=no RTC alloc */
 188#ifdef unused
 189        unsigned long rtc_iobase;       /*  RTC port region */
 190        unsigned int rtc_iosize;
 191        unsigned int rtc_irq;
 192#endif
 193        unsigned long dmabuf[2];        /*  pointers to begin of DMA buffers */
 194        unsigned int dmapages[2];       /*  len of DMA buffers in PAGE_SIZEs */
 195        unsigned int hwdmaptr[2];       /*  hardware address of DMA buffers */
 196        unsigned int hwdmasize[2];      /*  len of DMA buffers in Bytes */
 197        unsigned int dmasamplsize;      /*  size in samples hwdmasize[0]/2 */
 198        unsigned int last_top_dma;      /*  DMA pointer in last RTC int */
 199        int next_dma_buf;       /*  which DMA buffer will be used next round */
 200        long dma_runs_to_end;   /*  how many we must permorm DMA transfer to end of record */
 201        unsigned long last_dma_run;     /*  how many bytes we must transfer on last DMA page */
 202
 203        unsigned int ai_scans;  /*  len of scanlist */
 204        unsigned char ai_neverending;   /*  if=1, then we do neverending record (you must use cancel()) */
 205        int irq_free;           /*  1=have allocated IRQ */
 206        int irq_blocked;        /*  1=IRQ now uses any subdev */
 207#ifdef unused
 208        int rtc_irq_blocked;    /*  1=we now do AI with DMA&RTC */
 209#endif
 210        int irq_was_now_closed; /*  when IRQ finish, there's stored int816_mode for last interrupt */
 211        int int816_mode;        /*  who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
 212        struct comedi_subdevice *last_int_sub;  /*  ptr to subdevice which now finish */
 213        int ai_act_scan;        /*  how many scans we finished */
 214        unsigned int ai_act_chanlist[16];       /*  MUX setting for actual AI operations */
 215        unsigned int ai_act_chanlist_len;       /*  how long is actual MUX list */
 216        unsigned int ai_act_chanlist_pos;       /*  actual position in MUX list */
 217        unsigned int ai_n_chan;         /*  how many channels per scan */
 218        unsigned int ai_poll_ptr;       /*  how many sampes transfer poll */
 219        struct comedi_subdevice *sub_ai;        /*  ptr to AI subdevice */
 220#ifdef unused
 221        struct timer_list rtc_irq_timer;        /*  timer for RTC sanity check */
 222        unsigned long rtc_freq; /*  RTC int freq */
 223#endif
 224};
 225
 226/*
 227==============================================================================
 228*/
 229static int check_channel_list(struct comedi_device *dev,
 230                              struct comedi_subdevice *s,
 231                              unsigned int *chanlist, unsigned int chanlen);
 232static void setup_channel_list(struct comedi_device *dev,
 233                               struct comedi_subdevice *s,
 234                               unsigned int *chanlist, unsigned int seglen);
 235static int pcl816_ai_cancel(struct comedi_device *dev,
 236                            struct comedi_subdevice *s);
 237static void start_pacer(struct comedi_device *dev, int mode,
 238                        unsigned int divisor1, unsigned int divisor2);
 239#ifdef unused
 240static int set_rtc_irq_bit(unsigned char bit);
 241#endif
 242
 243static int pcl816_ai_cmdtest(struct comedi_device *dev,
 244                             struct comedi_subdevice *s,
 245                             struct comedi_cmd *cmd);
 246static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
 247
 248/*
 249==============================================================================
 250   ANALOG INPUT MODE0, 816 cards, slow version
 251*/
 252static int pcl816_ai_insn_read(struct comedi_device *dev,
 253                               struct comedi_subdevice *s,
 254                               struct comedi_insn *insn, unsigned int *data)
 255{
 256        int n;
 257        int timeout;
 258
 259        DPRINTK("mode 0 analog input\n");
 260        /*  software trigger, DMA and INT off */
 261        outb(0, dev->iobase + PCL816_CONTROL);
 262        /*  clear INT (conversion end) flag */
 263        outb(0, dev->iobase + PCL816_CLRINT);
 264
 265        /*  Set the input channel */
 266        outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
 267        /* select gain */
 268        outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
 269
 270        for (n = 0; n < insn->n; n++) {
 271
 272                outb(0, dev->iobase + PCL816_AD_LO);    /* start conversion */
 273
 274                timeout = 100;
 275                while (timeout--) {
 276                        if (!(inb(dev->iobase + PCL816_STATUS) &
 277                              PCL816_STATUS_DRDY_MASK)) {
 278                                /*  return read value */
 279                                data[n] =
 280                                    ((inb(dev->iobase +
 281                                          PCL816_AD_HI) << 8) |
 282                                     (inb(dev->iobase + PCL816_AD_LO)));
 283                                /* clear INT (conversion end) flag */
 284                                outb(0, dev->iobase + PCL816_CLRINT);
 285                                break;
 286                        }
 287                        udelay(1);
 288                }
 289                /*  Return timeout error */
 290                if (!timeout) {
 291                        comedi_error(dev, "A/D insn timeout\n");
 292                        data[0] = 0;
 293                        /* clear INT (conversion end) flag */
 294                        outb(0, dev->iobase + PCL816_CLRINT);
 295                        return -EIO;
 296                }
 297
 298        }
 299        return n;
 300}
 301
 302/*
 303==============================================================================
 304   analog input interrupt mode 1 & 3, 818 cards
 305   one sample per interrupt version
 306*/
 307static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
 308{
 309        struct comedi_device *dev = d;
 310        struct comedi_subdevice *s = dev->subdevices + 0;
 311        int low, hi;
 312        int timeout = 50;       /* wait max 50us */
 313
 314        while (timeout--) {
 315                if (!(inb(dev->iobase + PCL816_STATUS) &
 316                      PCL816_STATUS_DRDY_MASK))
 317                        break;
 318                udelay(1);
 319        }
 320        if (!timeout) {         /*  timeout, bail error */
 321                outb(0, dev->iobase + PCL816_CLRINT);   /* clear INT request */
 322                comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
 323                pcl816_ai_cancel(dev, s);
 324                s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
 325                comedi_event(dev, s);
 326                return IRQ_HANDLED;
 327
 328        }
 329
 330        /*  get the sample */
 331        low = inb(dev->iobase + PCL816_AD_LO);
 332        hi = inb(dev->iobase + PCL816_AD_HI);
 333
 334        comedi_buf_put(s->async, (hi << 8) | low);
 335
 336        outb(0, dev->iobase + PCL816_CLRINT);   /* clear INT request */
 337
 338        if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
 339                devpriv->ai_act_chanlist_pos = 0;
 340
 341        s->async->cur_chan++;
 342        if (s->async->cur_chan >= devpriv->ai_n_chan) {
 343                s->async->cur_chan = 0;
 344                devpriv->ai_act_scan++;
 345        }
 346
 347        if (!devpriv->ai_neverending)
 348                                        /* all data sampled */
 349                if (devpriv->ai_act_scan >= devpriv->ai_scans) {
 350                        /* all data sampled */
 351                        pcl816_ai_cancel(dev, s);
 352                        s->async->events |= COMEDI_CB_EOA;
 353                }
 354        comedi_event(dev, s);
 355        return IRQ_HANDLED;
 356}
 357
 358/*
 359==============================================================================
 360   analog input dma mode 1 & 3, 816 cards
 361*/
 362static void transfer_from_dma_buf(struct comedi_device *dev,
 363                                  struct comedi_subdevice *s, short *ptr,
 364                                  unsigned int bufptr, unsigned int len)
 365{
 366        int i;
 367
 368        s->async->events = 0;
 369
 370        for (i = 0; i < len; i++) {
 371
 372                comedi_buf_put(s->async, ptr[bufptr++]);
 373
 374                if (++devpriv->ai_act_chanlist_pos >=
 375                    devpriv->ai_act_chanlist_len) {
 376                        devpriv->ai_act_chanlist_pos = 0;
 377                }
 378
 379                s->async->cur_chan++;
 380                if (s->async->cur_chan >= devpriv->ai_n_chan) {
 381                        s->async->cur_chan = 0;
 382                        devpriv->ai_act_scan++;
 383                }
 384
 385                if (!devpriv->ai_neverending)
 386                                                /*  all data sampled */
 387                        if (devpriv->ai_act_scan >= devpriv->ai_scans) {
 388                                pcl816_ai_cancel(dev, s);
 389                                s->async->events |= COMEDI_CB_EOA;
 390                                s->async->events |= COMEDI_CB_BLOCK;
 391                                break;
 392                        }
 393        }
 394
 395        comedi_event(dev, s);
 396}
 397
 398static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
 399{
 400        struct comedi_device *dev = d;
 401        struct comedi_subdevice *s = dev->subdevices + 0;
 402        int len, bufptr, this_dma_buf;
 403        unsigned long dma_flags;
 404        short *ptr;
 405
 406        disable_dma(devpriv->dma);
 407        this_dma_buf = devpriv->next_dma_buf;
 408
 409        /*  switch dma bufs */
 410        if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
 411
 412                devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
 413                set_dma_mode(devpriv->dma, DMA_MODE_READ);
 414                dma_flags = claim_dma_lock();
 415/* clear_dma_ff (devpriv->dma); */
 416                set_dma_addr(devpriv->dma,
 417                             devpriv->hwdmaptr[devpriv->next_dma_buf]);
 418                if (devpriv->dma_runs_to_end) {
 419                        set_dma_count(devpriv->dma,
 420                                      devpriv->hwdmasize[devpriv->
 421                                                         next_dma_buf]);
 422                } else {
 423                        set_dma_count(devpriv->dma, devpriv->last_dma_run);
 424                }
 425                release_dma_lock(dma_flags);
 426                enable_dma(devpriv->dma);
 427        }
 428
 429        devpriv->dma_runs_to_end--;
 430        outb(0, dev->iobase + PCL816_CLRINT);   /* clear INT request */
 431
 432        ptr = (short *)devpriv->dmabuf[this_dma_buf];
 433
 434        len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
 435        bufptr = devpriv->ai_poll_ptr;
 436        devpriv->ai_poll_ptr = 0;
 437
 438        transfer_from_dma_buf(dev, s, ptr, bufptr, len);
 439        return IRQ_HANDLED;
 440}
 441
 442/*
 443==============================================================================
 444    INT procedure
 445*/
 446static irqreturn_t interrupt_pcl816(int irq, void *d)
 447{
 448        struct comedi_device *dev = d;
 449        DPRINTK("<I>");
 450
 451        if (!dev->attached) {
 452                comedi_error(dev, "premature interrupt");
 453                return IRQ_HANDLED;
 454        }
 455
 456        switch (devpriv->int816_mode) {
 457        case INT_TYPE_AI1_DMA:
 458        case INT_TYPE_AI3_DMA:
 459                return interrupt_pcl816_ai_mode13_dma(irq, d);
 460        case INT_TYPE_AI1_INT:
 461        case INT_TYPE_AI3_INT:
 462                return interrupt_pcl816_ai_mode13_int(irq, d);
 463        }
 464
 465        outb(0, dev->iobase + PCL816_CLRINT);   /* clear INT request */
 466        if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) |
 467            (!devpriv->int816_mode)) {
 468                if (devpriv->irq_was_now_closed) {
 469                        devpriv->irq_was_now_closed = 0;
 470                        /*  comedi_error(dev,"last IRQ.."); */
 471                        return IRQ_HANDLED;
 472                }
 473                comedi_error(dev, "bad IRQ!");
 474                return IRQ_NONE;
 475        }
 476        comedi_error(dev, "IRQ from unknown source!");
 477        return IRQ_NONE;
 478}
 479
 480/*
 481==============================================================================
 482   COMMAND MODE
 483*/
 484static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
 485{
 486        printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
 487               cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
 488        printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
 489               cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
 490        printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
 491               cmd->stop_src, cmd->scan_end_src);
 492        printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
 493               e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
 494}
 495
 496/*
 497==============================================================================
 498*/
 499static int pcl816_ai_cmdtest(struct comedi_device *dev,
 500                             struct comedi_subdevice *s, struct comedi_cmd *cmd)
 501{
 502        int err = 0;
 503        int tmp, divisor1 = 0, divisor2 = 0;
 504
 505        DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
 506              pcl816_cmdtest_out(-1, cmd);
 507             );
 508
 509        /* step 1: make sure trigger sources are trivially valid */
 510        tmp = cmd->start_src;
 511        cmd->start_src &= TRIG_NOW;
 512        if (!cmd->start_src || tmp != cmd->start_src)
 513                err++;
 514
 515        tmp = cmd->scan_begin_src;
 516        cmd->scan_begin_src &= TRIG_FOLLOW;
 517        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 518                err++;
 519
 520        tmp = cmd->convert_src;
 521        cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
 522        if (!cmd->convert_src || tmp != cmd->convert_src)
 523                err++;
 524
 525        tmp = cmd->scan_end_src;
 526        cmd->scan_end_src &= TRIG_COUNT;
 527        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 528                err++;
 529
 530        tmp = cmd->stop_src;
 531        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 532        if (!cmd->stop_src || tmp != cmd->stop_src)
 533                err++;
 534
 535        if (err)
 536                return 1;
 537
 538
 539        /*
 540         * step 2: make sure trigger sources
 541         * are unique and mutually compatible
 542         */
 543
 544        if (cmd->start_src != TRIG_NOW) {
 545                cmd->start_src = TRIG_NOW;
 546                err++;
 547        }
 548
 549        if (cmd->scan_begin_src != TRIG_FOLLOW) {
 550                cmd->scan_begin_src = TRIG_FOLLOW;
 551                err++;
 552        }
 553
 554        if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
 555                cmd->convert_src = TRIG_TIMER;
 556                err++;
 557        }
 558
 559        if (cmd->scan_end_src != TRIG_COUNT) {
 560                cmd->scan_end_src = TRIG_COUNT;
 561                err++;
 562        }
 563
 564        if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
 565                err++;
 566
 567        if (err)
 568                return 2;
 569
 570
 571        /* step 3: make sure arguments are trivially compatible */
 572        if (cmd->start_arg != 0) {
 573                cmd->start_arg = 0;
 574                err++;
 575        }
 576
 577        if (cmd->scan_begin_arg != 0) {
 578                cmd->scan_begin_arg = 0;
 579                err++;
 580        }
 581        if (cmd->convert_src == TRIG_TIMER) {
 582                if (cmd->convert_arg < this_board->ai_ns_min) {
 583                        cmd->convert_arg = this_board->ai_ns_min;
 584                        err++;
 585                }
 586        } else {                /* TRIG_EXT */
 587                if (cmd->convert_arg != 0) {
 588                        cmd->convert_arg = 0;
 589                        err++;
 590                }
 591        }
 592
 593        if (cmd->scan_end_arg != cmd->chanlist_len) {
 594                cmd->scan_end_arg = cmd->chanlist_len;
 595                err++;
 596        }
 597        if (cmd->stop_src == TRIG_COUNT) {
 598                if (!cmd->stop_arg) {
 599                        cmd->stop_arg = 1;
 600                        err++;
 601                }
 602        } else {                /* TRIG_NONE */
 603                if (cmd->stop_arg != 0) {
 604                        cmd->stop_arg = 0;
 605                        err++;
 606                }
 607        }
 608
 609        if (err)
 610                return 3;
 611
 612
 613        /* step 4: fix up any arguments */
 614        if (cmd->convert_src == TRIG_TIMER) {
 615                tmp = cmd->convert_arg;
 616                i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
 617                                          &divisor1, &divisor2,
 618                                          &cmd->convert_arg,
 619                                          cmd->flags & TRIG_ROUND_MASK);
 620                if (cmd->convert_arg < this_board->ai_ns_min)
 621                        cmd->convert_arg = this_board->ai_ns_min;
 622                if (tmp != cmd->convert_arg)
 623                        err++;
 624        }
 625
 626        if (err)
 627                return 4;
 628
 629
 630        /* step 5: complain about special chanlist considerations */
 631
 632        if (cmd->chanlist) {
 633                if (!check_channel_list(dev, s, cmd->chanlist,
 634                                        cmd->chanlist_len))
 635                        return 5;       /*  incorrect channels list */
 636        }
 637
 638        return 0;
 639}
 640
 641static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 642{
 643        unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
 644        struct comedi_cmd *cmd = &s->async->cmd;
 645        unsigned int seglen;
 646
 647        if (cmd->start_src != TRIG_NOW)
 648                return -EINVAL;
 649        if (cmd->scan_begin_src != TRIG_FOLLOW)
 650                return -EINVAL;
 651        if (cmd->scan_end_src != TRIG_COUNT)
 652                return -EINVAL;
 653        if (cmd->scan_end_arg != cmd->chanlist_len)
 654                return -EINVAL;
 655/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
 656        if (devpriv->irq_blocked)
 657                return -EBUSY;
 658
 659        if (cmd->convert_src == TRIG_TIMER) {
 660                if (cmd->convert_arg < this_board->ai_ns_min)
 661                        cmd->convert_arg = this_board->ai_ns_min;
 662
 663                i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
 664                                          &divisor2, &cmd->convert_arg,
 665                                          cmd->flags & TRIG_ROUND_MASK);
 666
 667                /*  PCL816 crash if any divisor is set to 1 */
 668                if (divisor1 == 1) {
 669                        divisor1 = 2;
 670                        divisor2 /= 2;
 671                }
 672                if (divisor2 == 1) {
 673                        divisor2 = 2;
 674                        divisor1 /= 2;
 675                }
 676        }
 677
 678        start_pacer(dev, -1, 0, 0);     /*  stop pacer */
 679
 680        seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
 681        if (seglen < 1)
 682                return -EINVAL;
 683        setup_channel_list(dev, s, cmd->chanlist, seglen);
 684        udelay(1);
 685
 686        devpriv->ai_n_chan = cmd->chanlist_len;
 687        devpriv->ai_act_scan = 0;
 688        s->async->cur_chan = 0;
 689        devpriv->irq_blocked = 1;
 690        devpriv->ai_poll_ptr = 0;
 691        devpriv->irq_was_now_closed = 0;
 692
 693        if (cmd->stop_src == TRIG_COUNT) {
 694                devpriv->ai_scans = cmd->stop_arg;
 695                devpriv->ai_neverending = 0;
 696        } else {
 697                devpriv->ai_scans = 0;
 698                devpriv->ai_neverending = 1;
 699        }
 700
 701        /*  don't we want wake up every scan? */
 702        if ((cmd->flags & TRIG_WAKE_EOS)) {
 703                printk(KERN_INFO
 704                       "pl816: You wankt WAKE_EOS but I dont want handle it");
 705                /*               devpriv->ai_eos=1; */
 706                /* if (devpriv->ai_n_chan==1) */
 707                /*       devpriv->dma=0; // DMA is useless for this situation */
 708        }
 709
 710        if (devpriv->dma) {
 711                bytes = devpriv->hwdmasize[0];
 712                if (!devpriv->ai_neverending) {
 713                        /*  how many */
 714                        bytes = s->async->cmd.chanlist_len *
 715                        s->async->cmd.chanlist_len *
 716                        sizeof(short);
 717
 718                        /*  how many DMA pages we must fill */
 719                        devpriv->dma_runs_to_end = bytes /
 720                        devpriv->hwdmasize[0];
 721
 722                        /* on last dma transfer must be moved */
 723                        devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
 724                        devpriv->dma_runs_to_end--;
 725                        if (devpriv->dma_runs_to_end >= 0)
 726                                bytes = devpriv->hwdmasize[0];
 727                } else
 728                        devpriv->dma_runs_to_end = -1;
 729
 730                devpriv->next_dma_buf = 0;
 731                set_dma_mode(devpriv->dma, DMA_MODE_READ);
 732                dma_flags = claim_dma_lock();
 733                clear_dma_ff(devpriv->dma);
 734                set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
 735                set_dma_count(devpriv->dma, bytes);
 736                release_dma_lock(dma_flags);
 737                enable_dma(devpriv->dma);
 738        }
 739
 740        start_pacer(dev, 1, divisor1, divisor2);
 741        dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
 742
 743        switch (cmd->convert_src) {
 744        case TRIG_TIMER:
 745                devpriv->int816_mode = INT_TYPE_AI1_DMA;
 746
 747                /*  Pacer+IRQ+DMA */
 748                outb(0x32, dev->iobase + PCL816_CONTROL);
 749
 750                /*  write irq and DMA to card */
 751                outb(dmairq, dev->iobase + PCL816_STATUS);
 752                break;
 753
 754        default:
 755                devpriv->int816_mode = INT_TYPE_AI3_DMA;
 756
 757                /*  Ext trig+IRQ+DMA */
 758                outb(0x34, dev->iobase + PCL816_CONTROL);
 759
 760                /*  write irq to card */
 761                outb(dmairq, dev->iobase + PCL816_STATUS);
 762                break;
 763        }
 764
 765        DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
 766        return 0;
 767}
 768
 769static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
 770{
 771        unsigned long flags;
 772        unsigned int top1, top2, i;
 773
 774        if (!devpriv->dma)
 775                return 0;       /*  poll is valid only for DMA transfer */
 776
 777        spin_lock_irqsave(&dev->spinlock, flags);
 778
 779        for (i = 0; i < 20; i++) {
 780                top1 = get_dma_residue(devpriv->dma);   /*  where is now DMA */
 781                top2 = get_dma_residue(devpriv->dma);
 782                if (top1 == top2)
 783                        break;
 784        }
 785        if (top1 != top2) {
 786                spin_unlock_irqrestore(&dev->spinlock, flags);
 787                return 0;
 788        }
 789
 790        /*  where is now DMA in buffer */
 791        top1 = devpriv->hwdmasize[0] - top1;
 792        top1 >>= 1;             /*  sample position */
 793        top2 = top1 - devpriv->ai_poll_ptr;
 794        if (top2 < 1) {         /*  no new samples */
 795                spin_unlock_irqrestore(&dev->spinlock, flags);
 796                return 0;
 797        }
 798
 799        transfer_from_dma_buf(dev, s,
 800                              (short *)devpriv->dmabuf[devpriv->next_dma_buf],
 801                              devpriv->ai_poll_ptr, top2);
 802
 803        devpriv->ai_poll_ptr = top1;    /*  new buffer position */
 804        spin_unlock_irqrestore(&dev->spinlock, flags);
 805
 806        return s->async->buf_write_count - s->async->buf_read_count;
 807}
 808
 809/*
 810==============================================================================
 811 cancel any mode 1-4 AI
 812*/
 813static int pcl816_ai_cancel(struct comedi_device *dev,
 814                            struct comedi_subdevice *s)
 815{
 816/* DEBUG(printk("pcl816_ai_cancel()\n");) */
 817
 818        if (devpriv->irq_blocked > 0) {
 819                switch (devpriv->int816_mode) {
 820#ifdef unused
 821                case INT_TYPE_AI1_DMA_RTC:
 822                case INT_TYPE_AI3_DMA_RTC:
 823                        set_rtc_irq_bit(0);     /*  stop RTC */
 824                        del_timer(&devpriv->rtc_irq_timer);
 825#endif
 826                case INT_TYPE_AI1_DMA:
 827                case INT_TYPE_AI3_DMA:
 828                        disable_dma(devpriv->dma);
 829                case INT_TYPE_AI1_INT:
 830                case INT_TYPE_AI3_INT:
 831                        outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
 832                             dev->iobase + PCL816_CONTROL);     /* Stop A/D */
 833                        udelay(1);
 834                        outb(0, dev->iobase + PCL816_CONTROL);  /* Stop A/D */
 835
 836                        /* Stop pacer */
 837                        outb(0xb0, dev->iobase + PCL816_CTRCTL);
 838                        outb(0x70, dev->iobase + PCL816_CTRCTL);
 839                        outb(0, dev->iobase + PCL816_AD_LO);
 840                        inb(dev->iobase + PCL816_AD_LO);
 841                        inb(dev->iobase + PCL816_AD_HI);
 842
 843                        /* clear INT request */
 844                        outb(0, dev->iobase + PCL816_CLRINT);
 845
 846                        /* Stop A/D */
 847                        outb(0, dev->iobase + PCL816_CONTROL);
 848                        devpriv->irq_blocked = 0;
 849                        devpriv->irq_was_now_closed = devpriv->int816_mode;
 850                        devpriv->int816_mode = 0;
 851                        devpriv->last_int_sub = s;
 852/* s->busy = 0; */
 853                        break;
 854                }
 855        }
 856
 857        DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
 858            return 0;
 859}
 860
 861/*
 862==============================================================================
 863 chech for PCL816
 864*/
 865static int pcl816_check(unsigned long iobase)
 866{
 867        outb(0x00, iobase + PCL816_MUX);
 868        udelay(1);
 869        if (inb(iobase + PCL816_MUX) != 0x00)
 870                return 1;       /* there isn't card */
 871        outb(0x55, iobase + PCL816_MUX);
 872        udelay(1);
 873        if (inb(iobase + PCL816_MUX) != 0x55)
 874                return 1;       /* there isn't card */
 875        outb(0x00, iobase + PCL816_MUX);
 876        udelay(1);
 877        outb(0x18, iobase + PCL816_CONTROL);
 878        udelay(1);
 879        if (inb(iobase + PCL816_CONTROL) != 0x18)
 880                return 1;       /* there isn't card */
 881        return 0;               /*  ok, card exist */
 882}
 883
 884/*
 885==============================================================================
 886 reset whole PCL-816 cards
 887*/
 888static void pcl816_reset(struct comedi_device *dev)
 889{
 890/* outb (0, dev->iobase + PCL818_DA_LO);         DAC=0V */
 891/* outb (0, dev->iobase + PCL818_DA_HI); */
 892/* udelay (1); */
 893/* outb (0, dev->iobase + PCL818_DO_HI);        DO=$0000 */
 894/* outb (0, dev->iobase + PCL818_DO_LO); */
 895/* udelay (1); */
 896        outb(0, dev->iobase + PCL816_CONTROL);
 897        outb(0, dev->iobase + PCL816_MUX);
 898        outb(0, dev->iobase + PCL816_CLRINT);
 899        outb(0xb0, dev->iobase + PCL816_CTRCTL);        /* Stop pacer */
 900        outb(0x70, dev->iobase + PCL816_CTRCTL);
 901        outb(0x30, dev->iobase + PCL816_CTRCTL);
 902        outb(0, dev->iobase + PCL816_RANGE);
 903}
 904
 905/*
 906==============================================================================
 907 Start/stop pacer onboard pacer
 908*/
 909static void
 910start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
 911            unsigned int divisor2)
 912{
 913        outb(0x32, dev->iobase + PCL816_CTRCTL);
 914        outb(0xff, dev->iobase + PCL816_CTR0);
 915        outb(0x00, dev->iobase + PCL816_CTR0);
 916        udelay(1);
 917
 918        /*  set counter 2 as mode 3 */
 919        outb(0xb4, dev->iobase + PCL816_CTRCTL);
 920        /*  set counter 1 as mode 3 */
 921        outb(0x74, dev->iobase + PCL816_CTRCTL);
 922        udelay(1);
 923
 924        if (mode == 1) {
 925                DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
 926                        divisor2);
 927                outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
 928                outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
 929                outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
 930                outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
 931        }
 932
 933        /* clear pending interrupts (just in case) */
 934/* outb(0, dev->iobase + PCL816_CLRINT); */
 935}
 936
 937/*
 938==============================================================================
 939 Check if channel list from user is builded correctly
 940 If it's ok, then return non-zero length of repeated segment of channel list
 941*/
 942static int
 943check_channel_list(struct comedi_device *dev,
 944                   struct comedi_subdevice *s, unsigned int *chanlist,
 945                   unsigned int chanlen)
 946{
 947        unsigned int chansegment[16];
 948        unsigned int i, nowmustbechan, seglen, segpos;
 949
 950        /*  correct channel and range number check itself comedi/range.c */
 951        if (chanlen < 1) {
 952                comedi_error(dev, "range/channel list is empty!");
 953                return 0;
 954        }
 955
 956        if (chanlen > 1) {
 957                /*  first channel is every time ok */
 958                chansegment[0] = chanlist[0];
 959                for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
 960                        /*  build part of chanlist */
 961                        DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
 962                                     CR_CHAN(chanlist[i]),
 963                                     CR_RANGE(chanlist[i]));)
 964
 965                        /*  we detect loop, this must by finish */
 966                            if (chanlist[0] == chanlist[i])
 967                                break;
 968                        nowmustbechan =
 969                            (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
 970                        if (nowmustbechan != CR_CHAN(chanlist[i])) {
 971                                /*  channel list isn't continuous :-( */
 972                                printk(KERN_WARNING
 973                                       "comedi%d: pcl816: channel list must "
 974                                       "be continuous! chanlist[%i]=%d but "
 975                                       "must be %d or %d!\n", dev->minor,
 976                                       i, CR_CHAN(chanlist[i]), nowmustbechan,
 977                                       CR_CHAN(chanlist[0]));
 978                                return 0;
 979                        }
 980                        /*  well, this is next correct channel in list */
 981                        chansegment[i] = chanlist[i];
 982                }
 983
 984                /*  check whole chanlist */
 985                for (i = 0, segpos = 0; i < chanlen; i++) {
 986                        DEBUG(printk("%d %d=%d %d\n",
 987                                     CR_CHAN(chansegment[i % seglen]),
 988                                     CR_RANGE(chansegment[i % seglen]),
 989                                     CR_CHAN(chanlist[i]),
 990                                     CR_RANGE(chanlist[i]));)
 991                            if (chanlist[i] != chansegment[i % seglen]) {
 992                                printk(KERN_WARNING
 993                                       "comedi%d: pcl816: bad channel or range"
 994                                       " number! chanlist[%i]=%d,%d,%d and not"
 995                                       " %d,%d,%d!\n", dev->minor, i,
 996                                       CR_CHAN(chansegment[i]),
 997                                       CR_RANGE(chansegment[i]),
 998                                       CR_AREF(chansegment[i]),
 999                                       CR_CHAN(chanlist[i % seglen]),
1000                                       CR_RANGE(chanlist[i % seglen]),
1001                                       CR_AREF(chansegment[i % seglen]));
1002                                return 0;       /*  chan/gain list is strange */
1003                        }
1004                }
1005        } else {
1006                seglen = 1;
1007        }
1008
1009        return seglen;  /*  we can serve this with MUX logic */
1010}
1011
1012/*
1013==============================================================================
1014 Program scan/gain logic with channel list.
1015*/
1016static void
1017setup_channel_list(struct comedi_device *dev,
1018                   struct comedi_subdevice *s, unsigned int *chanlist,
1019                   unsigned int seglen)
1020{
1021        unsigned int i;
1022
1023        devpriv->ai_act_chanlist_len = seglen;
1024        devpriv->ai_act_chanlist_pos = 0;
1025
1026        for (i = 0; i < seglen; i++) {  /*  store range list to card */
1027                devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
1028                outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
1029                /* select gain */
1030                outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
1031        }
1032
1033        udelay(1);
1034        /* select channel interval to scan */
1035        outb(devpriv->ai_act_chanlist[0] |
1036             (devpriv->ai_act_chanlist[seglen - 1] << 4),
1037             dev->iobase + PCL816_MUX);
1038}
1039
1040#ifdef unused
1041/*
1042==============================================================================
1043  Enable(1)/disable(0) periodic interrupts from RTC
1044*/
1045static int set_rtc_irq_bit(unsigned char bit)
1046{
1047        unsigned char val;
1048        unsigned long flags;
1049
1050        if (bit == 1) {
1051                RTC_timer_lock++;
1052                if (RTC_timer_lock > 1)
1053                        return 0;
1054        } else {
1055                RTC_timer_lock--;
1056                if (RTC_timer_lock < 0)
1057                        RTC_timer_lock = 0;
1058                if (RTC_timer_lock > 0)
1059                        return 0;
1060        }
1061
1062        save_flags(flags);
1063        cli();
1064        val = CMOS_READ(RTC_CONTROL);
1065        if (bit)
1066                val |= RTC_PIE;
1067        else
1068                val &= ~RTC_PIE;
1069
1070        CMOS_WRITE(val, RTC_CONTROL);
1071        CMOS_READ(RTC_INTR_FLAGS);
1072        restore_flags(flags);
1073        return 0;
1074}
1075#endif
1076
1077/*
1078==============================================================================
1079  Free any resources that we have claimed
1080*/
1081static void free_resources(struct comedi_device *dev)
1082{
1083        /* printk("free_resource()\n"); */
1084        if (dev->private) {
1085                pcl816_ai_cancel(dev, devpriv->sub_ai);
1086                pcl816_reset(dev);
1087                if (devpriv->dma)
1088                        free_dma(devpriv->dma);
1089                if (devpriv->dmabuf[0])
1090                        free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1091                if (devpriv->dmabuf[1])
1092                        free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1093#ifdef unused
1094                if (devpriv->rtc_irq)
1095                        free_irq(devpriv->rtc_irq, dev);
1096                if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1097                        if (devpriv->rtc_iobase)
1098                                release_region(devpriv->rtc_iobase,
1099                                               devpriv->rtc_iosize);
1100                }
1101#endif
1102        }
1103
1104        if (dev->irq)
1105                free_irq(dev->irq, dev);
1106        if (dev->iobase)
1107                release_region(dev->iobase, this_board->io_range);
1108        /* printk("free_resource() end\n"); */
1109}
1110
1111/*
1112==============================================================================
1113
1114   Initialization
1115
1116*/
1117static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1118{
1119        int ret;
1120        unsigned long iobase;
1121        unsigned int irq, dma;
1122        unsigned long pages;
1123        /* int i; */
1124        struct comedi_subdevice *s;
1125
1126        /* claim our I/O space */
1127        iobase = it->options[0];
1128        printk("comedi%d: pcl816:  board=%s, ioport=0x%03lx", dev->minor,
1129               this_board->name, iobase);
1130
1131        if (!request_region(iobase, this_board->io_range, "pcl816")) {
1132                printk("I/O port conflict\n");
1133                return -EIO;
1134        }
1135
1136        dev->iobase = iobase;
1137
1138        if (pcl816_check(iobase)) {
1139                printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1140                return -EIO;
1141        }
1142
1143        ret = alloc_private(dev, sizeof(struct pcl816_private));
1144        if (ret < 0)
1145                return ret;     /* Can't alloc mem */
1146
1147        /* set up some name stuff */
1148        dev->board_name = this_board->name;
1149
1150        /* grab our IRQ */
1151        irq = 0;
1152        if (this_board->IRQbits != 0) { /* board support IRQ */
1153                irq = it->options[1];
1154                if (irq) {      /* we want to use IRQ */
1155                        if (((1 << irq) & this_board->IRQbits) == 0) {
1156                                printk
1157                                    (", IRQ %u is out of allowed range, "
1158                                     "DISABLING IT", irq);
1159                                irq = 0;        /* Bad IRQ */
1160                        } else {
1161                                if (request_irq
1162                                    (irq, interrupt_pcl816, 0, "pcl816", dev)) {
1163                                        printk
1164                                            (", unable to allocate IRQ %u, "
1165                                             "DISABLING IT", irq);
1166                                        irq = 0;        /* Can't use IRQ */
1167                                } else {
1168                                        printk(KERN_INFO ", irq=%u", irq);
1169                                }
1170                        }
1171                }
1172        }
1173
1174        dev->irq = irq;
1175        if (irq)        /* 1=we have allocated irq */
1176                devpriv->irq_free = 1;
1177        else
1178                devpriv->irq_free = 0;
1179
1180        devpriv->irq_blocked = 0;       /* number of subdevice which use IRQ */
1181        devpriv->int816_mode = 0;       /* mode of irq */
1182
1183#ifdef unused
1184        /* grab RTC for DMA operations */
1185        devpriv->dma_rtc = 0;
1186        if (it->options[2] > 0) {       /*  we want to use DMA */
1187                if (RTC_lock == 0) {
1188                        if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1189                                            "pcl816 (RTC)"))
1190                                goto no_rtc;
1191                }
1192                devpriv->rtc_iobase = RTC_PORT(0);
1193                devpriv->rtc_iosize = RTC_IO_EXTENT;
1194                RTC_lock++;
1195#ifdef UNTESTED_CODE
1196                if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1197                                 "pcl816 DMA (RTC)", dev)) {
1198                        devpriv->dma_rtc = 1;
1199                        devpriv->rtc_irq = RTC_IRQ;
1200                        printk(", dma_irq=%u", devpriv->rtc_irq);
1201                } else {
1202                        RTC_lock--;
1203                        if (RTC_lock == 0) {
1204                                if (devpriv->rtc_iobase)
1205                                        release_region(devpriv->rtc_iobase,
1206                                                       devpriv->rtc_iosize);
1207                        }
1208                        devpriv->rtc_iobase = 0;
1209                        devpriv->rtc_iosize = 0;
1210                }
1211#else
1212                printk("pcl816: RTC code missing");
1213#endif
1214
1215        }
1216
1217no_rtc:
1218#endif
1219        /* grab our DMA */
1220        dma = 0;
1221        devpriv->dma = dma;
1222        if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1223                goto no_dma;    /* if we haven't IRQ, we can't use DMA */
1224
1225        if (this_board->DMAbits != 0) { /* board support DMA */
1226                dma = it->options[2];
1227                if (dma < 1)
1228                        goto no_dma;    /* DMA disabled */
1229
1230                if (((1 << dma) & this_board->DMAbits) == 0) {
1231                        printk(", DMA is out of allowed range, FAIL!\n");
1232                        return -EINVAL; /* Bad DMA */
1233                }
1234                ret = request_dma(dma, "pcl816");
1235                if (ret) {
1236                        printk(KERN_ERR
1237                               ", unable to allocate DMA %u, FAIL!\n", dma);
1238                        return -EBUSY;  /* DMA isn't free */
1239                }
1240
1241                devpriv->dma = dma;
1242                printk(KERN_INFO ", dma=%u", dma);
1243                pages = 2;      /* we need 16KB */
1244                devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1245
1246                if (!devpriv->dmabuf[0]) {
1247                        printk(", unable to allocate DMA buffer, FAIL!\n");
1248                        /*
1249                         * maybe experiment with try_to_free_pages()
1250                         * will help ....
1251                         */
1252                        return -EBUSY;  /* no buffer :-( */
1253                }
1254                devpriv->dmapages[0] = pages;
1255                devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1256                devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1257                /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1258
1259                if (devpriv->dma_rtc == 0) {    /*  we must do duble buff :-( */
1260                        devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1261                        if (!devpriv->dmabuf[1]) {
1262                                printk(KERN_ERR
1263                                       ", unable to allocate DMA buffer, "
1264                                       "FAIL!\n");
1265                                return -EBUSY;
1266                        }
1267                        devpriv->dmapages[1] = pages;
1268                        devpriv->hwdmaptr[1] =
1269                            virt_to_bus((void *)devpriv->dmabuf[1]);
1270                        devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1271                }
1272        }
1273
1274no_dma:
1275
1276/*  if (this_board->n_aochan > 0)
1277    subdevs[1] = COMEDI_SUBD_AO;
1278  if (this_board->n_dichan > 0)
1279    subdevs[2] = COMEDI_SUBD_DI;
1280  if (this_board->n_dochan > 0)
1281    subdevs[3] = COMEDI_SUBD_DO;
1282*/
1283
1284        ret = alloc_subdevices(dev, 1);
1285        if (ret < 0)
1286                return ret;
1287
1288        s = dev->subdevices + 0;
1289        if (this_board->n_aichan > 0) {
1290                s->type = COMEDI_SUBD_AI;
1291                devpriv->sub_ai = s;
1292                dev->read_subdev = s;
1293                s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1294                s->n_chan = this_board->n_aichan;
1295                s->subdev_flags |= SDF_DIFF;
1296                /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
1297                s->maxdata = this_board->ai_maxdata;
1298                s->len_chanlist = this_board->ai_chanlist;
1299                s->range_table = this_board->ai_range_type;
1300                s->cancel = pcl816_ai_cancel;
1301                s->do_cmdtest = pcl816_ai_cmdtest;
1302                s->do_cmd = pcl816_ai_cmd;
1303                s->poll = pcl816_ai_poll;
1304                s->insn_read = pcl816_ai_insn_read;
1305        } else {
1306                s->type = COMEDI_SUBD_UNUSED;
1307        }
1308
1309#if 0
1310case COMEDI_SUBD_AO:
1311        s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1312        s->n_chan = this_board->n_aochan;
1313        s->maxdata = this_board->ao_maxdata;
1314        s->len_chanlist = this_board->ao_chanlist;
1315        s->range_table = this_board->ao_range_type;
1316        break;
1317
1318case COMEDI_SUBD_DI:
1319        s->subdev_flags = SDF_READABLE;
1320        s->n_chan = this_board->n_dichan;
1321        s->maxdata = 1;
1322        s->len_chanlist = this_board->n_dichan;
1323        s->range_table = &range_digital;
1324        break;
1325
1326case COMEDI_SUBD_DO:
1327        s->subdev_flags = SDF_WRITABLE;
1328        s->n_chan = this_board->n_dochan;
1329        s->maxdata = 1;
1330        s->len_chanlist = this_board->n_dochan;
1331        s->range_table = &range_digital;
1332        break;
1333#endif
1334
1335        pcl816_reset(dev);
1336
1337        printk("\n");
1338
1339        return 0;
1340}
1341
1342/*
1343==============================================================================
1344  Removes device
1345 */
1346static int pcl816_detach(struct comedi_device *dev)
1347{
1348        DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
1349            free_resources(dev);
1350#ifdef unused
1351        if (devpriv->dma_rtc)
1352                RTC_lock--;
1353#endif
1354        return 0;
1355}
1356
1357MODULE_AUTHOR("Comedi http://www.comedi.org");
1358MODULE_DESCRIPTION("Comedi low-level driver");
1359MODULE_LICENSE("GPL");
1360