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

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

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