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

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 ao_readback[2];
249         unsigned int ai_front;
250         unsigned int ai_rear;
251 };
252 
253 #define TIMEOUT 100
254 
255 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
256 {
257         int i;
258         unsigned int status = 0;
259 
260         writew(cmd, dev->mmio + DPR_Command_Mbx);
261 
262         for (i = 0; i < TIMEOUT; i++) {
263                 status = readw(dev->mmio + DPR_Command_Mbx);
264                 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
265                         break;
266                 udelay(1);
267         }
268 
269         if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
270                 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
271                         __func__, status);
272 }
273 
274 static unsigned int dt3k_readsingle(struct comedi_device *dev,
275                                     unsigned int subsys, unsigned int chan,
276                                     unsigned int gain)
277 {
278         writew(subsys, dev->mmio + DPR_SubSys);
279 
280         writew(chan, dev->mmio + DPR_Params(0));
281         writew(gain, dev->mmio + DPR_Params(1));
282 
283         dt3k_send_cmd(dev, CMD_READSINGLE);
284 
285         return readw(dev->mmio + DPR_Params(2));
286 }
287 
288 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
289                              unsigned int chan, unsigned int data)
290 {
291         writew(subsys, dev->mmio + DPR_SubSys);
292 
293         writew(chan, dev->mmio + DPR_Params(0));
294         writew(0, dev->mmio + DPR_Params(1));
295         writew(data, dev->mmio + DPR_Params(2));
296 
297         dt3k_send_cmd(dev, CMD_WRITESINGLE);
298 }
299 
300 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
301                                struct comedi_subdevice *s)
302 {
303         struct dt3k_private *devpriv = dev->private;
304         int front;
305         int rear;
306         int count;
307         int i;
308         unsigned short data;
309 
310         front = readw(dev->mmio + DPR_AD_Buf_Front);
311         count = front - devpriv->ai_front;
312         if (count < 0)
313                 count += AI_FIFO_DEPTH;
314 
315         rear = devpriv->ai_rear;
316 
317         for (i = 0; i < count; i++) {
318                 data = readw(dev->mmio + DPR_ADC_buffer + rear);
319                 comedi_buf_put(s, data);
320                 rear++;
321                 if (rear >= AI_FIFO_DEPTH)
322                         rear = 0;
323         }
324 
325         devpriv->ai_rear = rear;
326         writew(rear, dev->mmio + DPR_AD_Buf_Rear);
327 }
328 
329 static int dt3k_ai_cancel(struct comedi_device *dev,
330                           struct comedi_subdevice *s)
331 {
332         writew(SUBS_AI, dev->mmio + DPR_SubSys);
333         dt3k_send_cmd(dev, CMD_STOP);
334 
335         writew(0, dev->mmio + DPR_Int_Mask);
336 
337         return 0;
338 }
339 
340 static int debug_n_ints;
341 
342 /* FIXME! Assumes shared interrupt is for this card. */
343 /* What's this debug_n_ints stuff? Obviously needs some work... */
344 static irqreturn_t dt3k_interrupt(int irq, void *d)
345 {
346         struct comedi_device *dev = d;
347         struct comedi_subdevice *s = dev->read_subdev;
348         unsigned int status;
349 
350         if (!dev->attached)
351                 return IRQ_NONE;
352 
353         status = readw(dev->mmio + DPR_Intr_Flag);
354 
355         if (status & DT3000_ADFULL) {
356                 dt3k_ai_empty_fifo(dev, s);
357                 s->async->events |= COMEDI_CB_BLOCK;
358         }
359 
360         if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
361                 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
362 
363         debug_n_ints++;
364         if (debug_n_ints >= 10)
365                 s->async->events |= COMEDI_CB_EOA;
366 
367         cfc_handle_events(dev, s);
368         return IRQ_HANDLED;
369 }
370 
371 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
372                             unsigned int flags)
373 {
374         int divider, base, prescale;
375 
376         /* This function needs improvment */
377         /* Don't know if divider==0 works. */
378 
379         for (prescale = 0; prescale < 16; prescale++) {
380                 base = timer_base * (prescale + 1);
381                 switch (flags & TRIG_ROUND_MASK) {
382                 case TRIG_ROUND_NEAREST:
383                 default:
384                         divider = (*nanosec + base / 2) / base;
385                         break;
386                 case TRIG_ROUND_DOWN:
387                         divider = (*nanosec) / base;
388                         break;
389                 case TRIG_ROUND_UP:
390                         divider = (*nanosec) / base;
391                         break;
392                 }
393                 if (divider < 65536) {
394                         *nanosec = divider * base;
395                         return (prescale << 16) | (divider);
396                 }
397         }
398 
399         prescale = 15;
400         base = timer_base * (1 << prescale);
401         divider = 65535;
402         *nanosec = divider * base;
403         return (prescale << 16) | (divider);
404 }
405 
406 static int dt3k_ai_cmdtest(struct comedi_device *dev,
407                            struct comedi_subdevice *s, struct comedi_cmd *cmd)
408 {
409         const struct dt3k_boardtype *this_board = comedi_board(dev);
410         int err = 0;
411         unsigned int arg;
412 
413         /* Step 1 : check if triggers are trivially valid */
414 
415         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
416         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
417         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
418         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
419         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
420 
421         if (err)
422                 return 1;
423 
424         /* Step 2a : make sure trigger sources are unique */
425         /* Step 2b : and mutually compatible */
426 
427         if (err)
428                 return 2;
429 
430         /* Step 3: check if arguments are trivially valid */
431 
432         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
433 
434         if (cmd->scan_begin_src == TRIG_TIMER) {
435                 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
436                                                  this_board->ai_speed);
437                 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
438                                                  100 * 16 * 65535);
439         }
440 
441         if (cmd->convert_src == TRIG_TIMER) {
442                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
443                                                  this_board->ai_speed);
444                 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
445                                                  50 * 16 * 65535);
446         }
447 
448         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
449 
450         if (cmd->stop_src == TRIG_COUNT)
451                 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
452         else    /* TRIG_NONE */
453                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
454 
455         if (err)
456                 return 3;
457 
458         /* step 4: fix up any arguments */
459 
460         if (cmd->scan_begin_src == TRIG_TIMER) {
461                 arg = cmd->scan_begin_arg;
462                 dt3k_ns_to_timer(100, &arg, cmd->flags);
463                 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
464         }
465 
466         if (cmd->convert_src == TRIG_TIMER) {
467                 arg = cmd->convert_arg;
468                 dt3k_ns_to_timer(50, &arg, cmd->flags);
469                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
470 
471                 if (cmd->scan_begin_src == TRIG_TIMER) {
472                         arg = cmd->convert_arg * cmd->scan_end_arg;
473                         err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
474                                                          arg);
475                 }
476         }
477 
478         if (err)
479                 return 4;
480 
481         return 0;
482 }
483 
484 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
485 {
486         struct comedi_cmd *cmd = &s->async->cmd;
487         int i;
488         unsigned int chan, range, aref;
489         unsigned int divider;
490         unsigned int tscandiv;
491         unsigned int mode;
492 
493         for (i = 0; i < cmd->chanlist_len; i++) {
494                 chan = CR_CHAN(cmd->chanlist[i]);
495                 range = CR_RANGE(cmd->chanlist[i]);
496 
497                 writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i);
498         }
499         aref = CR_AREF(cmd->chanlist[0]);
500 
501         writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0));
502 
503         if (cmd->convert_src == TRIG_TIMER) {
504                 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
505                 writew((divider >> 16), dev->mmio + DPR_Params(1));
506                 writew((divider & 0xffff), dev->mmio + DPR_Params(2));
507         }
508 
509         if (cmd->scan_begin_src == TRIG_TIMER) {
510                 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
511                                             cmd->flags);
512                 writew((tscandiv >> 16), dev->mmio + DPR_Params(3));
513                 writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4));
514         }
515 
516         mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
517         writew(mode, dev->mmio + DPR_Params(5));
518         writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6));
519 
520         writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7));
521 
522         writew(SUBS_AI, dev->mmio + DPR_SubSys);
523         dt3k_send_cmd(dev, CMD_CONFIG);
524 
525         writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
526                dev->mmio + DPR_Int_Mask);
527 
528         debug_n_ints = 0;
529 
530         writew(SUBS_AI, dev->mmio + DPR_SubSys);
531         dt3k_send_cmd(dev, CMD_START);
532 
533         return 0;
534 }
535 
536 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
537                         struct comedi_insn *insn, unsigned int *data)
538 {
539         int i;
540         unsigned int chan, gain, aref;
541 
542         chan = CR_CHAN(insn->chanspec);
543         gain = CR_RANGE(insn->chanspec);
544         /* XXX docs don't explain how to select aref */
545         aref = CR_AREF(insn->chanspec);
546 
547         for (i = 0; i < insn->n; i++)
548                 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
549 
550         return i;
551 }
552 
553 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
554                         struct comedi_insn *insn, unsigned int *data)
555 {
556         struct dt3k_private *devpriv = dev->private;
557         int i;
558         unsigned int chan;
559 
560         chan = CR_CHAN(insn->chanspec);
561         for (i = 0; i < insn->n; i++) {
562                 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
563                 devpriv->ao_readback[chan] = data[i];
564         }
565 
566         return i;
567 }
568 
569 static int dt3k_ao_insn_read(struct comedi_device *dev,
570                              struct comedi_subdevice *s,
571                              struct comedi_insn *insn, unsigned int *data)
572 {
573         struct dt3k_private *devpriv = dev->private;
574         int i;
575         unsigned int chan;
576 
577         chan = CR_CHAN(insn->chanspec);
578         for (i = 0; i < insn->n; i++)
579                 data[i] = devpriv->ao_readback[chan];
580 
581         return i;
582 }
583 
584 static void dt3k_dio_config(struct comedi_device *dev, int bits)
585 {
586         /* XXX */
587         writew(SUBS_DOUT, dev->mmio + DPR_SubSys);
588 
589         writew(bits, dev->mmio + DPR_Params(0));
590 #if 0
591         /* don't know */
592         writew(0, dev->mmio + DPR_Params(1));
593         writew(0, dev->mmio + DPR_Params(2));
594 #endif
595 
596         dt3k_send_cmd(dev, CMD_CONFIG);
597 }
598 
599 static int dt3k_dio_insn_config(struct comedi_device *dev,
600                                 struct comedi_subdevice *s,
601                                 struct comedi_insn *insn,
602                                 unsigned int *data)
603 {
604         unsigned int chan = CR_CHAN(insn->chanspec);
605         unsigned int mask;
606         int ret;
607 
608         if (chan < 4)
609                 mask = 0x0f;
610         else
611                 mask = 0xf0;
612 
613         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
614         if (ret)
615                 return ret;
616 
617         dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
618 
619         return insn->n;
620 }
621 
622 static int dt3k_dio_insn_bits(struct comedi_device *dev,
623                               struct comedi_subdevice *s,
624                               struct comedi_insn *insn,
625                               unsigned int *data)
626 {
627         if (comedi_dio_update_state(s, data))
628                 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
629 
630         data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
631 
632         return insn->n;
633 }
634 
635 static int dt3k_mem_insn_read(struct comedi_device *dev,
636                               struct comedi_subdevice *s,
637                               struct comedi_insn *insn,
638                               unsigned int *data)
639 {
640         unsigned int addr = CR_CHAN(insn->chanspec);
641         int i;
642 
643         for (i = 0; i < insn->n; i++) {
644                 writew(SUBS_MEM, dev->mmio + DPR_SubSys);
645                 writew(addr, dev->mmio + DPR_Params(0));
646                 writew(1, dev->mmio + DPR_Params(1));
647 
648                 dt3k_send_cmd(dev, CMD_READCODE);
649 
650                 data[i] = readw(dev->mmio + DPR_Params(2));
651         }
652 
653         return i;
654 }
655 
656 static int dt3000_auto_attach(struct comedi_device *dev,
657                               unsigned long context)
658 {
659         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
660         const struct dt3k_boardtype *this_board = NULL;
661         struct dt3k_private *devpriv;
662         struct comedi_subdevice *s;
663         int ret = 0;
664 
665         if (context < ARRAY_SIZE(dt3k_boardtypes))
666                 this_board = &dt3k_boardtypes[context];
667         if (!this_board)
668                 return -ENODEV;
669         dev->board_ptr = this_board;
670         dev->board_name = this_board->name;
671 
672         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
673         if (!devpriv)
674                 return -ENOMEM;
675 
676         ret = comedi_pci_enable(dev);
677         if (ret < 0)
678                 return ret;
679 
680         dev->mmio = pci_ioremap_bar(pcidev, 0);
681         if (!dev->mmio)
682                 return -ENOMEM;
683 
684         if (pcidev->irq) {
685                 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
686                                   dev->board_name, dev);
687                 if (ret == 0)
688                         dev->irq = pcidev->irq;
689         }
690 
691         ret = comedi_alloc_subdevices(dev, 4);
692         if (ret)
693                 return ret;
694 
695         s = &dev->subdevices[0];
696         /* ai subdevice */
697         s->type         = COMEDI_SUBD_AI;
698         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
699         s->n_chan       = this_board->adchan;
700         s->insn_read    = dt3k_ai_insn;
701         s->maxdata      = (1 << this_board->adbits) - 1;
702         s->range_table  = &range_dt3000_ai;     /* XXX */
703         if (dev->irq) {
704                 dev->read_subdev = s;
705                 s->subdev_flags |= SDF_CMD_READ;
706                 s->len_chanlist = 512;
707                 s->do_cmd       = dt3k_ai_cmd;
708                 s->do_cmdtest   = dt3k_ai_cmdtest;
709                 s->cancel       = dt3k_ai_cancel;
710         }
711 
712         s = &dev->subdevices[1];
713         /* ao subsystem */
714         s->type         = COMEDI_SUBD_AO;
715         s->subdev_flags = SDF_WRITABLE;
716         s->n_chan       = 2;
717         s->insn_read    = dt3k_ao_insn_read;
718         s->insn_write   = dt3k_ao_insn;
719         s->maxdata      = (1 << this_board->dabits) - 1;
720         s->len_chanlist = 1;
721         s->range_table  = &range_bipolar10;
722 
723         s = &dev->subdevices[2];
724         /* dio subsystem */
725         s->type         = COMEDI_SUBD_DIO;
726         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
727         s->n_chan       = 8;
728         s->insn_config  = dt3k_dio_insn_config;
729         s->insn_bits    = dt3k_dio_insn_bits;
730         s->maxdata      = 1;
731         s->len_chanlist = 8;
732         s->range_table  = &range_digital;
733 
734         s = &dev->subdevices[3];
735         /* mem subsystem */
736         s->type         = COMEDI_SUBD_MEMORY;
737         s->subdev_flags = SDF_READABLE;
738         s->n_chan       = 0x1000;
739         s->insn_read    = dt3k_mem_insn_read;
740         s->maxdata      = 0xff;
741         s->len_chanlist = 1;
742         s->range_table  = &range_unknown;
743 
744 #if 0
745         s = &dev->subdevices[4];
746         /* proc subsystem */
747         s->type = COMEDI_SUBD_PROC;
748 #endif
749 
750         return 0;
751 }
752 
753 static void dt3000_detach(struct comedi_device *dev)
754 {
755         if (dev->irq)
756                 free_irq(dev->irq, dev);
757         if (dev->mmio)
758                 iounmap(dev->mmio);
759         comedi_pci_disable(dev);
760 }
761 
762 static struct comedi_driver dt3000_driver = {
763         .driver_name    = "dt3000",
764         .module         = THIS_MODULE,
765         .auto_attach    = dt3000_auto_attach,
766         .detach         = dt3000_detach,
767 };
768 
769 static int dt3000_pci_probe(struct pci_dev *dev,
770                             const struct pci_device_id *id)
771 {
772         return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
773 }
774 
775 static const struct pci_device_id dt3000_pci_table[] = {
776         { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
777         { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
778         { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
779         { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
780         { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
781         { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
782         { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
783         { 0 }
784 };
785 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
786 
787 static struct pci_driver dt3000_pci_driver = {
788         .name           = "dt3000",
789         .id_table       = dt3000_pci_table,
790         .probe          = dt3000_pci_probe,
791         .remove         = comedi_pci_auto_unconfig,
792 };
793 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
794 
795 MODULE_AUTHOR("Comedi http://www.comedi.org");
796 MODULE_DESCRIPTION("Comedi low-level driver");
797 MODULE_LICENSE("GPL");
798 

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