Version:  2.0.40 2.2.26 2.4.37 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4

Linux/drivers/staging/comedi/drivers/dt3000.c

  1 /*
  2  * dt3000.c
  3  * Data Translation DT3000 series driver
  4  *
  5  * COMEDI - Linux Control and Measurement Device Interface
  6  * Copyright (C) 1999 David A. Schleef <ds@schleef.org>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2 of the License, or
 11  * (at your option) any later version.
 12  *
 13  * This program is distributed in the hope that it will be useful,
 14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  * GNU General Public License for more details.
 17  */
 18 
 19 /*
 20  * Driver: dt3000
 21  * Description: Data Translation DT3000 series
 22  * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
 23  *   DT3003-PGL, DT3004, DT3005, DT3004-200
 24  * Author: ds
 25  * Updated: Mon, 14 Apr 2008 15:41:24 +0100
 26  * Status: works
 27  *
 28  * Configuration Options: not applicable, uses PCI auto config
 29  *
 30  * There is code to support AI commands, but it may not work.
 31  *
 32  * AO commands are not supported.
 33  */
 34 
 35 /*
 36  * The DT3000 series is Data Translation's attempt to make a PCI
 37  * data acquisition board.  The design of this series is very nice,
 38  * since each board has an on-board DSP (Texas Instruments TMS320C52).
 39  * However, a few details are a little annoying.  The boards lack
 40  * bus-mastering DMA, which eliminates them from serious work.
 41  * They also are not capable of autocalibration, which is a common
 42  * feature in modern hardware.  The default firmware is pretty bad,
 43  * making it nearly impossible to write an RT compatible driver.
 44  * It would make an interesting project to write a decent firmware
 45  * for these boards.
 46  *
 47  * Data Translation originally wanted an NDA for the documentation
 48  * for the 3k series.  However, if you ask nicely, they might send
 49  * you the docs without one, also.
 50  */
 51 
 52 #include <linux/module.h>
 53 #include <linux/delay.h>
 54 #include <linux/interrupt.h>
 55 
 56 #include "../comedi_pci.h"
 57 
 58 /*
 59  * PCI BAR0 - dual-ported RAM location definitions (dev->mmio)
 60  */
 61 #define DPR_DAC_BUFFER          (4 * 0x000)
 62 #define DPR_ADC_BUFFER          (4 * 0x800)
 63 #define DPR_COMMAND             (4 * 0xfd3)
 64 #define DPR_SUBSYS              (4 * 0xfd3)
 65 #define DPR_SUBSYS_AI           0
 66 #define DPR_SUBSYS_AO           1
 67 #define DPR_SUBSYS_DIN          2
 68 #define DPR_SUBSYS_DOUT         3
 69 #define DPR_SUBSYS_MEM          4
 70 #define DPR_SUBSYS_CT           5
 71 #define DPR_ENCODE              (4 * 0xfd4)
 72 #define DPR_PARAMS(x)           (4 * (0xfd5 + (x)))
 73 #define DPR_TICK_REG_LO         (4 * 0xff5)
 74 #define DPR_TICK_REG_HI         (4 * 0xff6)
 75 #define DPR_DA_BUF_FRONT        (4 * 0xff7)
 76 #define DPR_DA_BUF_REAR         (4 * 0xff8)
 77 #define DPR_AD_BUF_FRONT        (4 * 0xff9)
 78 #define DPR_AD_BUF_REAR         (4 * 0xffa)
 79 #define DPR_INT_MASK            (4 * 0xffb)
 80 #define DPR_INTR_FLAG           (4 * 0xffc)
 81 #define DPR_INTR_CMDONE         BIT(7)
 82 #define DPR_INTR_CTDONE         BIT(6)
 83 #define DPR_INTR_DAHWERR        BIT(5)
 84 #define DPR_INTR_DASWERR        BIT(4)
 85 #define DPR_INTR_DAEMPTY        BIT(3)
 86 #define DPR_INTR_ADHWERR        BIT(2)
 87 #define DPR_INTR_ADSWERR        BIT(1)
 88 #define DPR_INTR_ADFULL         BIT(0)
 89 #define DPR_RESPONSE_MBX        (4 * 0xffe)
 90 #define DPR_CMD_MBX             (4 * 0xfff)
 91 #define DPR_CMD_COMPLETION(x)   ((x) << 8)
 92 #define DPR_CMD_NOTPROCESSED    DPR_CMD_COMPLETION(0x00)
 93 #define DPR_CMD_NOERROR         DPR_CMD_COMPLETION(0x55)
 94 #define DPR_CMD_ERROR           DPR_CMD_COMPLETION(0xaa)
 95 #define DPR_CMD_NOTSUPPORTED    DPR_CMD_COMPLETION(0xff)
 96 #define DPR_CMD_COMPLETION_MASK DPR_CMD_COMPLETION(0xff)
 97 #define DPR_CMD(x)              ((x) << 0)
 98 #define DPR_CMD_GETBRDINFO      DPR_CMD(0)
 99 #define DPR_CMD_CONFIG          DPR_CMD(1)
100 #define DPR_CMD_GETCONFIG       DPR_CMD(2)
101 #define DPR_CMD_START           DPR_CMD(3)
102 #define DPR_CMD_STOP            DPR_CMD(4)
103 #define DPR_CMD_READSINGLE      DPR_CMD(5)
104 #define DPR_CMD_WRITESINGLE     DPR_CMD(6)
105 #define DPR_CMD_CALCCLOCK       DPR_CMD(7)
106 #define DPR_CMD_READEVENTS      DPR_CMD(8)
107 #define DPR_CMD_WRITECTCTRL     DPR_CMD(16)
108 #define DPR_CMD_READCTCTRL      DPR_CMD(17)
109 #define DPR_CMD_WRITECT         DPR_CMD(18)
110 #define DPR_CMD_READCT          DPR_CMD(19)
111 #define DPR_CMD_WRITEDATA       DPR_CMD(32)
112 #define DPR_CMD_READDATA        DPR_CMD(33)
113 #define DPR_CMD_WRITEIO         DPR_CMD(34)
114 #define DPR_CMD_READIO          DPR_CMD(35)
115 #define DPR_CMD_WRITECODE       DPR_CMD(36)
116 #define DPR_CMD_READCODE        DPR_CMD(37)
117 #define DPR_CMD_EXECUTE         DPR_CMD(38)
118 #define DPR_CMD_HALT            DPR_CMD(48)
119 #define DPR_CMD_MASK            DPR_CMD(0xff)
120 
121 #define DPR_PARAM5_AD_TRIG(x)           (((x) & 0x7) << 2)
122 #define DPR_PARAM5_AD_TRIG_INT          DPR_PARAM5_AD_TRIG(0)
123 #define DPR_PARAM5_AD_TRIG_EXT          DPR_PARAM5_AD_TRIG(1)
124 #define DPR_PARAM5_AD_TRIG_INT_RETRIG   DPR_PARAM5_AD_TRIG(2)
125 #define DPR_PARAM5_AD_TRIG_EXT_RETRIG   DPR_PARAM5_AD_TRIG(3)
126 #define DPR_PARAM5_AD_TRIG_INT_RETRIG2  DPR_PARAM5_AD_TRIG(4)
127 
128 #define DPR_PARAM6_AD_DIFF              BIT(0)
129 
130 #define DPR_AI_FIFO_DEPTH               2003
131 #define DPR_AO_FIFO_DEPTH               2048
132 
133 #define DPR_EXTERNAL_CLOCK              1
134 #define DPR_RISING_EDGE                 2
135 
136 #define DPR_TMODE_MASK                  0x1c
137 
138 #define DPR_CMD_TIMEOUT                 100
139 
140 static const struct comedi_lrange range_dt3000_ai = {
141         4, {
142                 BIP_RANGE(10),
143                 BIP_RANGE(5),
144                 BIP_RANGE(2.5),
145                 BIP_RANGE(1.25)
146         }
147 };
148 
149 static const struct comedi_lrange range_dt3000_ai_pgl = {
150         4, {
151                 BIP_RANGE(10),
152                 BIP_RANGE(1),
153                 BIP_RANGE(0.1),
154                 BIP_RANGE(0.02)
155         }
156 };
157 
158 enum dt3k_boardid {
159         BOARD_DT3001,
160         BOARD_DT3001_PGL,
161         BOARD_DT3002,
162         BOARD_DT3003,
163         BOARD_DT3003_PGL,
164         BOARD_DT3004,
165         BOARD_DT3005,
166 };
167 
168 struct dt3k_boardtype {
169         const char *name;
170         int adchan;
171         int ai_speed;
172         const struct comedi_lrange *adrange;
173         unsigned int ai_is_16bit:1;
174         unsigned int has_ao:1;
175 };
176 
177 static const struct dt3k_boardtype dt3k_boardtypes[] = {
178         [BOARD_DT3001] = {
179                 .name           = "dt3001",
180                 .adchan         = 16,
181                 .adrange        = &range_dt3000_ai,
182                 .ai_speed       = 3000,
183                 .has_ao         = 1,
184         },
185         [BOARD_DT3001_PGL] = {
186                 .name           = "dt3001-pgl",
187                 .adchan         = 16,
188                 .adrange        = &range_dt3000_ai_pgl,
189                 .ai_speed       = 3000,
190                 .has_ao         = 1,
191         },
192         [BOARD_DT3002] = {
193                 .name           = "dt3002",
194                 .adchan         = 32,
195                 .adrange        = &range_dt3000_ai,
196                 .ai_speed       = 3000,
197         },
198         [BOARD_DT3003] = {
199                 .name           = "dt3003",
200                 .adchan         = 64,
201                 .adrange        = &range_dt3000_ai,
202                 .ai_speed       = 3000,
203                 .has_ao         = 1,
204         },
205         [BOARD_DT3003_PGL] = {
206                 .name           = "dt3003-pgl",
207                 .adchan         = 64,
208                 .adrange        = &range_dt3000_ai_pgl,
209                 .ai_speed       = 3000,
210                 .has_ao         = 1,
211         },
212         [BOARD_DT3004] = {
213                 .name           = "dt3004",
214                 .adchan         = 16,
215                 .adrange        = &range_dt3000_ai,
216                 .ai_speed       = 10000,
217                 .ai_is_16bit    = 1,
218                 .has_ao         = 1,
219         },
220         [BOARD_DT3005] = {
221                 .name           = "dt3005",     /* a.k.a. 3004-200 */
222                 .adchan         = 16,
223                 .adrange        = &range_dt3000_ai,
224                 .ai_speed       = 5000,
225                 .ai_is_16bit    = 1,
226                 .has_ao         = 1,
227         },
228 };
229 
230 struct dt3k_private {
231         unsigned int lock;
232         unsigned int ai_front;
233         unsigned int ai_rear;
234 };
235 
236 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
237 {
238         int i;
239         unsigned int status = 0;
240 
241         writew(cmd, dev->mmio + DPR_CMD_MBX);
242 
243         for (i = 0; i < DPR_CMD_TIMEOUT; i++) {
244                 status = readw(dev->mmio + DPR_CMD_MBX);
245                 status &= DPR_CMD_COMPLETION_MASK;
246                 if (status != DPR_CMD_NOTPROCESSED)
247                         break;
248                 udelay(1);
249         }
250 
251         if (status != DPR_CMD_NOERROR)
252                 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
253                         __func__, status);
254 }
255 
256 static unsigned int dt3k_readsingle(struct comedi_device *dev,
257                                     unsigned int subsys, unsigned int chan,
258                                     unsigned int gain)
259 {
260         writew(subsys, dev->mmio + DPR_SUBSYS);
261 
262         writew(chan, dev->mmio + DPR_PARAMS(0));
263         writew(gain, dev->mmio + DPR_PARAMS(1));
264 
265         dt3k_send_cmd(dev, DPR_CMD_READSINGLE);
266 
267         return readw(dev->mmio + DPR_PARAMS(2));
268 }
269 
270 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
271                              unsigned int chan, unsigned int data)
272 {
273         writew(subsys, dev->mmio + DPR_SUBSYS);
274 
275         writew(chan, dev->mmio + DPR_PARAMS(0));
276         writew(0, dev->mmio + DPR_PARAMS(1));
277         writew(data, dev->mmio + DPR_PARAMS(2));
278 
279         dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE);
280 }
281 
282 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
283                                struct comedi_subdevice *s)
284 {
285         struct dt3k_private *devpriv = dev->private;
286         int front;
287         int rear;
288         int count;
289         int i;
290         unsigned short data;
291 
292         front = readw(dev->mmio + DPR_AD_BUF_FRONT);
293         count = front - devpriv->ai_front;
294         if (count < 0)
295                 count += DPR_AI_FIFO_DEPTH;
296 
297         rear = devpriv->ai_rear;
298 
299         for (i = 0; i < count; i++) {
300                 data = readw(dev->mmio + DPR_ADC_BUFFER + rear);
301                 comedi_buf_write_samples(s, &data, 1);
302                 rear++;
303                 if (rear >= DPR_AI_FIFO_DEPTH)
304                         rear = 0;
305         }
306 
307         devpriv->ai_rear = rear;
308         writew(rear, dev->mmio + DPR_AD_BUF_REAR);
309 }
310 
311 static int dt3k_ai_cancel(struct comedi_device *dev,
312                           struct comedi_subdevice *s)
313 {
314         writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
315         dt3k_send_cmd(dev, DPR_CMD_STOP);
316 
317         writew(0, dev->mmio + DPR_INT_MASK);
318 
319         return 0;
320 }
321 
322 static int debug_n_ints;
323 
324 /* FIXME! Assumes shared interrupt is for this card. */
325 /* What's this debug_n_ints stuff? Obviously needs some work... */
326 static irqreturn_t dt3k_interrupt(int irq, void *d)
327 {
328         struct comedi_device *dev = d;
329         struct comedi_subdevice *s = dev->read_subdev;
330         unsigned int status;
331 
332         if (!dev->attached)
333                 return IRQ_NONE;
334 
335         status = readw(dev->mmio + DPR_INTR_FLAG);
336 
337         if (status & DPR_INTR_ADFULL)
338                 dt3k_ai_empty_fifo(dev, s);
339 
340         if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR))
341                 s->async->events |= COMEDI_CB_ERROR;
342 
343         debug_n_ints++;
344         if (debug_n_ints >= 10)
345                 s->async->events |= COMEDI_CB_EOA;
346 
347         comedi_handle_events(dev, s);
348         return IRQ_HANDLED;
349 }
350 
351 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
352                             unsigned int flags)
353 {
354         int divider, base, prescale;
355 
356         /* This function needs improvment */
357         /* Don't know if divider==0 works. */
358 
359         for (prescale = 0; prescale < 16; prescale++) {
360                 base = timer_base * (prescale + 1);
361                 switch (flags & CMDF_ROUND_MASK) {
362                 case CMDF_ROUND_NEAREST:
363                 default:
364                         divider = (*nanosec + base / 2) / base;
365                         break;
366                 case CMDF_ROUND_DOWN:
367                         divider = (*nanosec) / base;
368                         break;
369                 case CMDF_ROUND_UP:
370                         divider = (*nanosec) / base;
371                         break;
372                 }
373                 if (divider < 65536) {
374                         *nanosec = divider * base;
375                         return (prescale << 16) | (divider);
376                 }
377         }
378 
379         prescale = 15;
380         base = timer_base * (1 << prescale);
381         divider = 65535;
382         *nanosec = divider * base;
383         return (prescale << 16) | (divider);
384 }
385 
386 static int dt3k_ai_cmdtest(struct comedi_device *dev,
387                            struct comedi_subdevice *s, struct comedi_cmd *cmd)
388 {
389         const struct dt3k_boardtype *board = dev->board_ptr;
390         int err = 0;
391         unsigned int arg;
392 
393         /* Step 1 : check if triggers are trivially valid */
394 
395         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
396         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
397         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
398         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
399         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
400 
401         if (err)
402                 return 1;
403 
404         /* Step 2a : make sure trigger sources are unique */
405         /* Step 2b : and mutually compatible */
406 
407         /* Step 3: check if arguments are trivially valid */
408 
409         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
410 
411         if (cmd->scan_begin_src == TRIG_TIMER) {
412                 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
413                                                     board->ai_speed);
414                 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
415                                                     100 * 16 * 65535);
416         }
417 
418         if (cmd->convert_src == TRIG_TIMER) {
419                 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
420                                                     board->ai_speed);
421                 err |= comedi_check_trigger_arg_max(&cmd->convert_arg,
422                                                     50 * 16 * 65535);
423         }
424 
425         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
426                                            cmd->chanlist_len);
427 
428         if (cmd->stop_src == TRIG_COUNT)
429                 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
430         else    /* TRIG_NONE */
431                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
432 
433         if (err)
434                 return 3;
435 
436         /* step 4: fix up any arguments */
437 
438         if (cmd->scan_begin_src == TRIG_TIMER) {
439                 arg = cmd->scan_begin_arg;
440                 dt3k_ns_to_timer(100, &arg, cmd->flags);
441                 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
442         }
443 
444         if (cmd->convert_src == TRIG_TIMER) {
445                 arg = cmd->convert_arg;
446                 dt3k_ns_to_timer(50, &arg, cmd->flags);
447                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
448 
449                 if (cmd->scan_begin_src == TRIG_TIMER) {
450                         arg = cmd->convert_arg * cmd->scan_end_arg;
451                         err |= comedi_check_trigger_arg_min(&cmd->
452                                                             scan_begin_arg,
453                                                             arg);
454                 }
455         }
456 
457         if (err)
458                 return 4;
459 
460         return 0;
461 }
462 
463 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
464 {
465         struct comedi_cmd *cmd = &s->async->cmd;
466         int i;
467         unsigned int chan, range, aref;
468         unsigned int divider;
469         unsigned int tscandiv;
470 
471         for (i = 0; i < cmd->chanlist_len; i++) {
472                 chan = CR_CHAN(cmd->chanlist[i]);
473                 range = CR_RANGE(cmd->chanlist[i]);
474 
475                 writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i);
476         }
477         aref = CR_AREF(cmd->chanlist[0]);
478 
479         writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0));
480 
481         if (cmd->convert_src == TRIG_TIMER) {
482                 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
483                 writew((divider >> 16), dev->mmio + DPR_PARAMS(1));
484                 writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2));
485         }
486 
487         if (cmd->scan_begin_src == TRIG_TIMER) {
488                 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
489                                             cmd->flags);
490                 writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3));
491                 writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4));
492         }
493 
494         writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5));
495         writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0,
496                dev->mmio + DPR_PARAMS(6));
497 
498         writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7));
499 
500         writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
501         dt3k_send_cmd(dev, DPR_CMD_CONFIG);
502 
503         writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR,
504                dev->mmio + DPR_INT_MASK);
505 
506         debug_n_ints = 0;
507 
508         writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
509         dt3k_send_cmd(dev, DPR_CMD_START);
510 
511         return 0;
512 }
513 
514 static int dt3k_ai_insn_read(struct comedi_device *dev,
515                              struct comedi_subdevice *s,
516                              struct comedi_insn *insn,
517                              unsigned int *data)
518 {
519         int i;
520         unsigned int chan, gain, aref;
521 
522         chan = CR_CHAN(insn->chanspec);
523         gain = CR_RANGE(insn->chanspec);
524         /* XXX docs don't explain how to select aref */
525         aref = CR_AREF(insn->chanspec);
526 
527         for (i = 0; i < insn->n; i++)
528                 data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain);
529 
530         return i;
531 }
532 
533 static int dt3k_ao_insn_write(struct comedi_device *dev,
534                               struct comedi_subdevice *s,
535                               struct comedi_insn *insn,
536                               unsigned int *data)
537 {
538         unsigned int chan = CR_CHAN(insn->chanspec);
539         unsigned int val = s->readback[chan];
540         int i;
541 
542         for (i = 0; i < insn->n; i++) {
543                 val = data[i];
544                 dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val);
545         }
546         s->readback[chan] = val;
547 
548         return insn->n;
549 }
550 
551 static void dt3k_dio_config(struct comedi_device *dev, int bits)
552 {
553         /* XXX */
554         writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS);
555 
556         writew(bits, dev->mmio + DPR_PARAMS(0));
557 
558         /* XXX write 0 to DPR_PARAMS(1) and DPR_PARAMS(2) ? */
559 
560         dt3k_send_cmd(dev, DPR_CMD_CONFIG);
561 }
562 
563 static int dt3k_dio_insn_config(struct comedi_device *dev,
564                                 struct comedi_subdevice *s,
565                                 struct comedi_insn *insn,
566                                 unsigned int *data)
567 {
568         unsigned int chan = CR_CHAN(insn->chanspec);
569         unsigned int mask;
570         int ret;
571 
572         if (chan < 4)
573                 mask = 0x0f;
574         else
575                 mask = 0xf0;
576 
577         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
578         if (ret)
579                 return ret;
580 
581         dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
582 
583         return insn->n;
584 }
585 
586 static int dt3k_dio_insn_bits(struct comedi_device *dev,
587                               struct comedi_subdevice *s,
588                               struct comedi_insn *insn,
589                               unsigned int *data)
590 {
591         if (comedi_dio_update_state(s, data))
592                 dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state);
593 
594         data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0);
595 
596         return insn->n;
597 }
598 
599 static int dt3k_mem_insn_read(struct comedi_device *dev,
600                               struct comedi_subdevice *s,
601                               struct comedi_insn *insn,
602                               unsigned int *data)
603 {
604         unsigned int addr = CR_CHAN(insn->chanspec);
605         int i;
606 
607         for (i = 0; i < insn->n; i++) {
608                 writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS);
609                 writew(addr, dev->mmio + DPR_PARAMS(0));
610                 writew(1, dev->mmio + DPR_PARAMS(1));
611 
612                 dt3k_send_cmd(dev, DPR_CMD_READCODE);
613 
614                 data[i] = readw(dev->mmio + DPR_PARAMS(2));
615         }
616 
617         return i;
618 }
619 
620 static int dt3000_auto_attach(struct comedi_device *dev,
621                               unsigned long context)
622 {
623         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
624         const struct dt3k_boardtype *board = NULL;
625         struct dt3k_private *devpriv;
626         struct comedi_subdevice *s;
627         int ret = 0;
628 
629         if (context < ARRAY_SIZE(dt3k_boardtypes))
630                 board = &dt3k_boardtypes[context];
631         if (!board)
632                 return -ENODEV;
633         dev->board_ptr = board;
634         dev->board_name = board->name;
635 
636         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
637         if (!devpriv)
638                 return -ENOMEM;
639 
640         ret = comedi_pci_enable(dev);
641         if (ret < 0)
642                 return ret;
643 
644         dev->mmio = pci_ioremap_bar(pcidev, 0);
645         if (!dev->mmio)
646                 return -ENOMEM;
647 
648         if (pcidev->irq) {
649                 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
650                                   dev->board_name, dev);
651                 if (ret == 0)
652                         dev->irq = pcidev->irq;
653         }
654 
655         ret = comedi_alloc_subdevices(dev, 4);
656         if (ret)
657                 return ret;
658 
659         /* Analog Input subdevice */
660         s = &dev->subdevices[0];
661         s->type         = COMEDI_SUBD_AI;
662         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
663         s->n_chan       = board->adchan;
664         s->maxdata      = board->ai_is_16bit ? 0xffff : 0x0fff;
665         s->range_table  = &range_dt3000_ai;     /* XXX */
666         s->insn_read    = dt3k_ai_insn_read;
667         if (dev->irq) {
668                 dev->read_subdev = s;
669                 s->subdev_flags |= SDF_CMD_READ;
670                 s->len_chanlist = 512;
671                 s->do_cmd       = dt3k_ai_cmd;
672                 s->do_cmdtest   = dt3k_ai_cmdtest;
673                 s->cancel       = dt3k_ai_cancel;
674         }
675 
676         /* Analog Output subdevice */
677         s = &dev->subdevices[1];
678         if (board->has_ao) {
679                 s->type         = COMEDI_SUBD_AO;
680                 s->subdev_flags = SDF_WRITABLE;
681                 s->n_chan       = 2;
682                 s->maxdata      = 0x0fff;
683                 s->range_table  = &range_bipolar10;
684                 s->insn_write   = dt3k_ao_insn_write;
685 
686                 ret = comedi_alloc_subdev_readback(s);
687                 if (ret)
688                         return ret;
689 
690         } else {
691                 s->type         = COMEDI_SUBD_UNUSED;
692         }
693 
694         /* Digital I/O subdevice */
695         s = &dev->subdevices[2];
696         s->type         = COMEDI_SUBD_DIO;
697         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
698         s->n_chan       = 8;
699         s->maxdata      = 1;
700         s->range_table  = &range_digital;
701         s->insn_config  = dt3k_dio_insn_config;
702         s->insn_bits    = dt3k_dio_insn_bits;
703 
704         /* Memory subdevice */
705         s = &dev->subdevices[3];
706         s->type         = COMEDI_SUBD_MEMORY;
707         s->subdev_flags = SDF_READABLE;
708         s->n_chan       = 0x1000;
709         s->maxdata      = 0xff;
710         s->range_table  = &range_unknown;
711         s->insn_read    = dt3k_mem_insn_read;
712 
713         return 0;
714 }
715 
716 static struct comedi_driver dt3000_driver = {
717         .driver_name    = "dt3000",
718         .module         = THIS_MODULE,
719         .auto_attach    = dt3000_auto_attach,
720         .detach         = comedi_pci_detach,
721 };
722 
723 static int dt3000_pci_probe(struct pci_dev *dev,
724                             const struct pci_device_id *id)
725 {
726         return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
727 }
728 
729 static const struct pci_device_id dt3000_pci_table[] = {
730         { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
731         { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
732         { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
733         { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
734         { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
735         { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
736         { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
737         { 0 }
738 };
739 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
740 
741 static struct pci_driver dt3000_pci_driver = {
742         .name           = "dt3000",
743         .id_table       = dt3000_pci_table,
744         .probe          = dt3000_pci_probe,
745         .remove         = comedi_pci_auto_unconfig,
746 };
747 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
748 
749 MODULE_AUTHOR("Comedi http://www.comedi.org");
750 MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards");
751 MODULE_LICENSE("GPL");
752 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us