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