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