Version:  2.0.40 2.2.26 2.4.37 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 3.19

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_write_samples(s, &data, 1);
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 
357         if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
358                 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
359 
360         debug_n_ints++;
361         if (debug_n_ints >= 10)
362                 s->async->events |= COMEDI_CB_EOA;
363 
364         comedi_handle_events(dev, s);
365         return IRQ_HANDLED;
366 }
367 
368 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
369                             unsigned int flags)
370 {
371         int divider, base, prescale;
372 
373         /* This function needs improvment */
374         /* Don't know if divider==0 works. */
375 
376         for (prescale = 0; prescale < 16; prescale++) {
377                 base = timer_base * (prescale + 1);
378                 switch (flags & CMDF_ROUND_MASK) {
379                 case CMDF_ROUND_NEAREST:
380                 default:
381                         divider = (*nanosec + base / 2) / base;
382                         break;
383                 case CMDF_ROUND_DOWN:
384                         divider = (*nanosec) / base;
385                         break;
386                 case CMDF_ROUND_UP:
387                         divider = (*nanosec) / base;
388                         break;
389                 }
390                 if (divider < 65536) {
391                         *nanosec = divider * base;
392                         return (prescale << 16) | (divider);
393                 }
394         }
395 
396         prescale = 15;
397         base = timer_base * (1 << prescale);
398         divider = 65535;
399         *nanosec = divider * base;
400         return (prescale << 16) | (divider);
401 }
402 
403 static int dt3k_ai_cmdtest(struct comedi_device *dev,
404                            struct comedi_subdevice *s, struct comedi_cmd *cmd)
405 {
406         const struct dt3k_boardtype *this_board = dev->board_ptr;
407         int err = 0;
408         unsigned int arg;
409 
410         /* Step 1 : check if triggers are trivially valid */
411 
412         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
413         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
414         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
415         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
416         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
417 
418         if (err)
419                 return 1;
420 
421         /* Step 2a : make sure trigger sources are unique */
422         /* Step 2b : and mutually compatible */
423 
424         /* Step 3: check if arguments are trivially valid */
425 
426         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
427 
428         if (cmd->scan_begin_src == TRIG_TIMER) {
429                 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
430                                                  this_board->ai_speed);
431                 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
432                                                  100 * 16 * 65535);
433         }
434 
435         if (cmd->convert_src == TRIG_TIMER) {
436                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
437                                                  this_board->ai_speed);
438                 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
439                                                  50 * 16 * 65535);
440         }
441 
442         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
443 
444         if (cmd->stop_src == TRIG_COUNT)
445                 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
446         else    /* TRIG_NONE */
447                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
448 
449         if (err)
450                 return 3;
451 
452         /* step 4: fix up any arguments */
453 
454         if (cmd->scan_begin_src == TRIG_TIMER) {
455                 arg = cmd->scan_begin_arg;
456                 dt3k_ns_to_timer(100, &arg, cmd->flags);
457                 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
458         }
459 
460         if (cmd->convert_src == TRIG_TIMER) {
461                 arg = cmd->convert_arg;
462                 dt3k_ns_to_timer(50, &arg, cmd->flags);
463                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
464 
465                 if (cmd->scan_begin_src == TRIG_TIMER) {
466                         arg = cmd->convert_arg * cmd->scan_end_arg;
467                         err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
468                                                          arg);
469                 }
470         }
471 
472         if (err)
473                 return 4;
474 
475         return 0;
476 }
477 
478 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
479 {
480         struct comedi_cmd *cmd = &s->async->cmd;
481         int i;
482         unsigned int chan, range, aref;
483         unsigned int divider;
484         unsigned int tscandiv;
485 
486         for (i = 0; i < cmd->chanlist_len; i++) {
487                 chan = CR_CHAN(cmd->chanlist[i]);
488                 range = CR_RANGE(cmd->chanlist[i]);
489 
490                 writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i);
491         }
492         aref = CR_AREF(cmd->chanlist[0]);
493 
494         writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0));
495 
496         if (cmd->convert_src == TRIG_TIMER) {
497                 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
498                 writew((divider >> 16), dev->mmio + DPR_Params(1));
499                 writew((divider & 0xffff), dev->mmio + DPR_Params(2));
500         }
501 
502         if (cmd->scan_begin_src == TRIG_TIMER) {
503                 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
504                                             cmd->flags);
505                 writew((tscandiv >> 16), dev->mmio + DPR_Params(3));
506                 writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4));
507         }
508 
509         writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5));
510         writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6));
511 
512         writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7));
513 
514         writew(SUBS_AI, dev->mmio + DPR_SubSys);
515         dt3k_send_cmd(dev, CMD_CONFIG);
516 
517         writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
518                dev->mmio + DPR_Int_Mask);
519 
520         debug_n_ints = 0;
521 
522         writew(SUBS_AI, dev->mmio + DPR_SubSys);
523         dt3k_send_cmd(dev, CMD_START);
524 
525         return 0;
526 }
527 
528 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
529                         struct comedi_insn *insn, unsigned int *data)
530 {
531         int i;
532         unsigned int chan, gain, aref;
533 
534         chan = CR_CHAN(insn->chanspec);
535         gain = CR_RANGE(insn->chanspec);
536         /* XXX docs don't explain how to select aref */
537         aref = CR_AREF(insn->chanspec);
538 
539         for (i = 0; i < insn->n; i++)
540                 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
541 
542         return i;
543 }
544 
545 static int dt3k_ao_insn_write(struct comedi_device *dev,
546                               struct comedi_subdevice *s,
547                               struct comedi_insn *insn,
548                               unsigned int *data)
549 {
550         unsigned int chan = CR_CHAN(insn->chanspec);
551         unsigned int val = s->readback[chan];
552         int i;
553 
554         for (i = 0; i < insn->n; i++) {
555                 val = data[i];
556                 dt3k_writesingle(dev, SUBS_AO, chan, val);
557         }
558         s->readback[chan] = val;
559 
560         return insn->n;
561 }
562 
563 static void dt3k_dio_config(struct comedi_device *dev, int bits)
564 {
565         /* XXX */
566         writew(SUBS_DOUT, dev->mmio + DPR_SubSys);
567 
568         writew(bits, dev->mmio + DPR_Params(0));
569 #if 0
570         /* don't know */
571         writew(0, dev->mmio + DPR_Params(1));
572         writew(0, dev->mmio + DPR_Params(2));
573 #endif
574 
575         dt3k_send_cmd(dev, CMD_CONFIG);
576 }
577 
578 static int dt3k_dio_insn_config(struct comedi_device *dev,
579                                 struct comedi_subdevice *s,
580                                 struct comedi_insn *insn,
581                                 unsigned int *data)
582 {
583         unsigned int chan = CR_CHAN(insn->chanspec);
584         unsigned int mask;
585         int ret;
586 
587         if (chan < 4)
588                 mask = 0x0f;
589         else
590                 mask = 0xf0;
591 
592         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
593         if (ret)
594                 return ret;
595 
596         dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
597 
598         return insn->n;
599 }
600 
601 static int dt3k_dio_insn_bits(struct comedi_device *dev,
602                               struct comedi_subdevice *s,
603                               struct comedi_insn *insn,
604                               unsigned int *data)
605 {
606         if (comedi_dio_update_state(s, data))
607                 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
608 
609         data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
610 
611         return insn->n;
612 }
613 
614 static int dt3k_mem_insn_read(struct comedi_device *dev,
615                               struct comedi_subdevice *s,
616                               struct comedi_insn *insn,
617                               unsigned int *data)
618 {
619         unsigned int addr = CR_CHAN(insn->chanspec);
620         int i;
621 
622         for (i = 0; i < insn->n; i++) {
623                 writew(SUBS_MEM, dev->mmio + DPR_SubSys);
624                 writew(addr, dev->mmio + DPR_Params(0));
625                 writew(1, dev->mmio + DPR_Params(1));
626 
627                 dt3k_send_cmd(dev, CMD_READCODE);
628 
629                 data[i] = readw(dev->mmio + DPR_Params(2));
630         }
631 
632         return i;
633 }
634 
635 static int dt3000_auto_attach(struct comedi_device *dev,
636                               unsigned long context)
637 {
638         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
639         const struct dt3k_boardtype *this_board = NULL;
640         struct dt3k_private *devpriv;
641         struct comedi_subdevice *s;
642         int ret = 0;
643 
644         if (context < ARRAY_SIZE(dt3k_boardtypes))
645                 this_board = &dt3k_boardtypes[context];
646         if (!this_board)
647                 return -ENODEV;
648         dev->board_ptr = this_board;
649         dev->board_name = this_board->name;
650 
651         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
652         if (!devpriv)
653                 return -ENOMEM;
654 
655         ret = comedi_pci_enable(dev);
656         if (ret < 0)
657                 return ret;
658 
659         dev->mmio = pci_ioremap_bar(pcidev, 0);
660         if (!dev->mmio)
661                 return -ENOMEM;
662 
663         if (pcidev->irq) {
664                 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
665                                   dev->board_name, dev);
666                 if (ret == 0)
667                         dev->irq = pcidev->irq;
668         }
669 
670         ret = comedi_alloc_subdevices(dev, 4);
671         if (ret)
672                 return ret;
673 
674         s = &dev->subdevices[0];
675         /* ai subdevice */
676         s->type         = COMEDI_SUBD_AI;
677         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
678         s->n_chan       = this_board->adchan;
679         s->insn_read    = dt3k_ai_insn;
680         s->maxdata      = (1 << this_board->adbits) - 1;
681         s->range_table  = &range_dt3000_ai;     /* XXX */
682         if (dev->irq) {
683                 dev->read_subdev = s;
684                 s->subdev_flags |= SDF_CMD_READ;
685                 s->len_chanlist = 512;
686                 s->do_cmd       = dt3k_ai_cmd;
687                 s->do_cmdtest   = dt3k_ai_cmdtest;
688                 s->cancel       = dt3k_ai_cancel;
689         }
690 
691         s = &dev->subdevices[1];
692         /* ao subsystem */
693         s->type         = COMEDI_SUBD_AO;
694         s->subdev_flags = SDF_WRITABLE;
695         s->n_chan       = 2;
696         s->maxdata      = (1 << this_board->dabits) - 1;
697         s->len_chanlist = 1;
698         s->range_table  = &range_bipolar10;
699         s->insn_write   = dt3k_ao_insn_write;
700 
701         ret = comedi_alloc_subdev_readback(s);
702         if (ret)
703                 return ret;
704 
705         s = &dev->subdevices[2];
706         /* dio subsystem */
707         s->type         = COMEDI_SUBD_DIO;
708         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
709         s->n_chan       = 8;
710         s->insn_config  = dt3k_dio_insn_config;
711         s->insn_bits    = dt3k_dio_insn_bits;
712         s->maxdata      = 1;
713         s->len_chanlist = 8;
714         s->range_table  = &range_digital;
715 
716         s = &dev->subdevices[3];
717         /* mem subsystem */
718         s->type         = COMEDI_SUBD_MEMORY;
719         s->subdev_flags = SDF_READABLE;
720         s->n_chan       = 0x1000;
721         s->insn_read    = dt3k_mem_insn_read;
722         s->maxdata      = 0xff;
723         s->len_chanlist = 1;
724         s->range_table  = &range_unknown;
725 
726 #if 0
727         s = &dev->subdevices[4];
728         /* proc subsystem */
729         s->type = COMEDI_SUBD_PROC;
730 #endif
731 
732         return 0;
733 }
734 
735 static struct comedi_driver dt3000_driver = {
736         .driver_name    = "dt3000",
737         .module         = THIS_MODULE,
738         .auto_attach    = dt3000_auto_attach,
739         .detach         = comedi_pci_detach,
740 };
741 
742 static int dt3000_pci_probe(struct pci_dev *dev,
743                             const struct pci_device_id *id)
744 {
745         return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
746 }
747 
748 static const struct pci_device_id dt3000_pci_table[] = {
749         { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
750         { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
751         { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
752         { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
753         { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
754         { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
755         { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
756         { 0 }
757 };
758 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
759 
760 static struct pci_driver dt3000_pci_driver = {
761         .name           = "dt3000",
762         .id_table       = dt3000_pci_table,
763         .probe          = dt3000_pci_probe,
764         .remove         = comedi_pci_auto_unconfig,
765 };
766 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
767 
768 MODULE_AUTHOR("Comedi http://www.comedi.org");
769 MODULE_DESCRIPTION("Comedi low-level driver");
770 MODULE_LICENSE("GPL");
771 

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