Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 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

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

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

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