Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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