Version:  2.0.40 2.2.26 2.4.37 3.2 3.3 3.4 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

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

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