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