~ubuntu-branches/ubuntu/lucid/linux-rt/lucid

« back to all changes in this revision

Viewing changes to drivers/staging/comedi/drivers/dt3000.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-08-05 23:00:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090805230052-7xedvqcyk9dnnxb2
Tags: 2.6.31-1.1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
    You should have received a copy of the GNU General Public License
 
19
    along with this program; if not, write to the Free Software
 
20
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 
 
22
*/
 
23
/*
 
24
Driver: dt3000
 
25
Description: Data Translation DT3000 series
 
26
Author: ds
 
27
Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
 
28
  DT3003-PGL, DT3004, DT3005, DT3004-200
 
29
Updated: Mon, 14 Apr 2008 15:41:24 +0100
 
30
Status: works
 
31
 
 
32
Configuration Options:
 
33
  [0] - PCI bus of device (optional)
 
34
  [1] - PCI slot of device (optional)
 
35
  If bus/slot is not specified, the first supported
 
36
  PCI device found will be used.
 
37
 
 
38
There is code to support AI commands, but it may not work.
 
39
 
 
40
AO commands are not supported.
 
41
*/
 
42
 
 
43
/*
 
44
   The DT3000 series is Data Translation's attempt to make a PCI
 
45
   data acquisition board.  The design of this series is very nice,
 
46
   since each board has an on-board DSP (Texas Instruments TMS320C52).
 
47
   However, a few details are a little annoying.  The boards lack
 
48
   bus-mastering DMA, which eliminates them from serious work.
 
49
   They also are not capable of autocalibration, which is a common
 
50
   feature in modern hardware.  The default firmware is pretty bad,
 
51
   making it nearly impossible to write an RT compatible driver.
 
52
   It would make an interesting project to write a decent firmware
 
53
   for these boards.
 
54
 
 
55
   Data Translation originally wanted an NDA for the documentation
 
56
   for the 3k series.  However, if you ask nicely, they might send
 
57
   you the docs without one, also.
 
58
*/
 
59
 
 
60
#define DEBUG 1
 
61
 
 
62
#include <linux/interrupt.h>
 
63
#include "../comedidev.h"
 
64
#include <linux/delay.h>
 
65
 
 
66
#include "comedi_pci.h"
 
67
 
 
68
#define PCI_VENDOR_ID_DT        0x1116
 
69
 
 
70
static const struct comedi_lrange range_dt3000_ai = { 4, {
 
71
                        RANGE(-10, 10),
 
72
                        RANGE(-5, 5),
 
73
                        RANGE(-2.5, 2.5),
 
74
                        RANGE(-1.25, 1.25)
 
75
        }
 
76
};
 
77
static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
 
78
                        RANGE(-10, 10),
 
79
                        RANGE(-1, 1),
 
80
                        RANGE(-0.1, 0.1),
 
81
                        RANGE(-0.02, 0.02)
 
82
        }
 
83
};
 
84
 
 
85
struct dt3k_boardtype {
 
86
 
 
87
        const char *name;
 
88
        unsigned int device_id;
 
89
        int adchan;
 
90
        int adbits;
 
91
        int ai_speed;
 
92
        const struct comedi_lrange *adrange;
 
93
        int dachan;
 
94
        int dabits;
 
95
};
 
96
 
 
97
 
 
98
static const struct dt3k_boardtype dt3k_boardtypes[] = {
 
99
        {.name = "dt3001",
 
100
         .device_id = 0x22,
 
101
         .adchan = 16,
 
102
         .adbits = 12,
 
103
         .adrange = &range_dt3000_ai,
 
104
         .ai_speed = 3000,
 
105
         .dachan = 2,
 
106
         .dabits = 12,
 
107
        },
 
108
        {.name = "dt3001-pgl",
 
109
         .device_id = 0x27,
 
110
         .adchan = 16,
 
111
         .adbits = 12,
 
112
         .adrange = &range_dt3000_ai_pgl,
 
113
         .ai_speed = 3000,
 
114
         .dachan = 2,
 
115
         .dabits = 12,
 
116
        },
 
117
        {.name = "dt3002",
 
118
         .device_id = 0x23,
 
119
         .adchan = 32,
 
120
         .adbits = 12,
 
121
         .adrange = &range_dt3000_ai,
 
122
         .ai_speed = 3000,
 
123
         .dachan = 0,
 
124
         .dabits = 0,
 
125
        },
 
126
        {.name = "dt3003",
 
127
         .device_id = 0x24,
 
128
         .adchan = 64,
 
129
         .adbits = 12,
 
130
         .adrange = &range_dt3000_ai,
 
131
         .ai_speed = 3000,
 
132
         .dachan = 2,
 
133
         .dabits = 12,
 
134
        },
 
135
        {.name = "dt3003-pgl",
 
136
         .device_id = 0x28,
 
137
         .adchan = 64,
 
138
         .adbits = 12,
 
139
         .adrange = &range_dt3000_ai_pgl,
 
140
         .ai_speed = 3000,
 
141
         .dachan = 2,
 
142
         .dabits = 12,
 
143
        },
 
144
        {.name = "dt3004",
 
145
         .device_id = 0x25,
 
146
         .adchan = 16,
 
147
         .adbits = 16,
 
148
         .adrange = &range_dt3000_ai,
 
149
         .ai_speed = 10000,
 
150
         .dachan = 2,
 
151
         .dabits = 12,
 
152
        },
 
153
        {.name = "dt3005",              /* a.k.a. 3004-200 */
 
154
         .device_id = 0x26,
 
155
         .adchan = 16,
 
156
         .adbits = 16,
 
157
         .adrange = &range_dt3000_ai,
 
158
         .ai_speed = 5000,
 
159
         .dachan = 2,
 
160
         .dabits = 12,
 
161
        },
 
162
};
 
163
 
 
164
#define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
 
165
#define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
 
166
 
 
167
static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
 
168
        {PCI_VENDOR_ID_DT, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
169
        {PCI_VENDOR_ID_DT, 0x0027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
170
        {PCI_VENDOR_ID_DT, 0x0023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
171
        {PCI_VENDOR_ID_DT, 0x0024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
172
        {PCI_VENDOR_ID_DT, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
173
        {PCI_VENDOR_ID_DT, 0x0025, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
174
        {PCI_VENDOR_ID_DT, 0x0026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 
175
        {0}
 
176
};
 
177
 
 
178
MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
 
179
 
 
180
#define DT3000_SIZE             (4*0x1000)
 
181
 
 
182
/* dual-ported RAM location definitions */
 
183
 
 
184
#define DPR_DAC_buffer          (4*0x000)
 
185
#define DPR_ADC_buffer          (4*0x800)
 
186
#define DPR_Command             (4*0xfd3)
 
187
#define DPR_SubSys              (4*0xfd3)
 
188
#define DPR_Encode              (4*0xfd4)
 
189
#define DPR_Params(a)           (4*(0xfd5+(a)))
 
190
#define DPR_Tick_Reg_Lo         (4*0xff5)
 
191
#define DPR_Tick_Reg_Hi         (4*0xff6)
 
192
#define DPR_DA_Buf_Front        (4*0xff7)
 
193
#define DPR_DA_Buf_Rear         (4*0xff8)
 
194
#define DPR_AD_Buf_Front        (4*0xff9)
 
195
#define DPR_AD_Buf_Rear         (4*0xffa)
 
196
#define DPR_Int_Mask            (4*0xffb)
 
197
#define DPR_Intr_Flag           (4*0xffc)
 
198
#define DPR_Response_Mbx        (4*0xffe)
 
199
#define DPR_Command_Mbx         (4*0xfff)
 
200
 
 
201
#define AI_FIFO_DEPTH   2003
 
202
#define AO_FIFO_DEPTH   2048
 
203
 
 
204
/* command list */
 
205
 
 
206
#define CMD_GETBRDINFO          0
 
207
#define CMD_CONFIG              1
 
208
#define CMD_GETCONFIG           2
 
209
#define CMD_START               3
 
210
#define CMD_STOP                4
 
211
#define CMD_READSINGLE          5
 
212
#define CMD_WRITESINGLE         6
 
213
#define CMD_CALCCLOCK           7
 
214
#define CMD_READEVENTS          8
 
215
#define CMD_WRITECTCTRL         16
 
216
#define CMD_READCTCTRL          17
 
217
#define CMD_WRITECT             18
 
218
#define CMD_READCT              19
 
219
#define CMD_WRITEDATA           32
 
220
#define CMD_READDATA            33
 
221
#define CMD_WRITEIO             34
 
222
#define CMD_READIO              35
 
223
#define CMD_WRITECODE           36
 
224
#define CMD_READCODE            37
 
225
#define CMD_EXECUTE             38
 
226
#define CMD_HALT                48
 
227
 
 
228
#define SUBS_AI         0
 
229
#define SUBS_AO         1
 
230
#define SUBS_DIN        2
 
231
#define SUBS_DOUT       3
 
232
#define SUBS_MEM        4
 
233
#define SUBS_CT         5
 
234
 
 
235
/* interrupt flags */
 
236
#define DT3000_CMDONE           0x80
 
237
#define DT3000_CTDONE           0x40
 
238
#define DT3000_DAHWERR          0x20
 
239
#define DT3000_DASWERR          0x10
 
240
#define DT3000_DAEMPTY          0x08
 
241
#define DT3000_ADHWERR          0x04
 
242
#define DT3000_ADSWERR          0x02
 
243
#define DT3000_ADFULL           0x01
 
244
 
 
245
#define DT3000_COMPLETION_MASK  0xff00
 
246
#define DT3000_COMMAND_MASK     0x00ff
 
247
#define DT3000_NOTPROCESSED     0x0000
 
248
#define DT3000_NOERROR          0x5500
 
249
#define DT3000_ERROR            0xaa00
 
250
#define DT3000_NOTSUPPORTED     0xff00
 
251
 
 
252
#define DT3000_EXTERNAL_CLOCK   1
 
253
#define DT3000_RISING_EDGE      2
 
254
 
 
255
#define TMODE_MASK              0x1c
 
256
 
 
257
#define DT3000_AD_TRIG_INTERNAL         (0<<2)
 
258
#define DT3000_AD_TRIG_EXTERNAL         (1<<2)
 
259
#define DT3000_AD_RETRIG_INTERNAL       (2<<2)
 
260
#define DT3000_AD_RETRIG_EXTERNAL       (3<<2)
 
261
#define DT3000_AD_EXTRETRIG             (4<<2)
 
262
 
 
263
#define DT3000_CHANNEL_MODE_SE          0
 
264
#define DT3000_CHANNEL_MODE_DI          1
 
265
 
 
266
struct dt3k_private {
 
267
 
 
268
        struct pci_dev *pci_dev;
 
269
        resource_size_t phys_addr;
 
270
        void *io_addr;
 
271
        unsigned int lock;
 
272
        unsigned int ao_readback[2];
 
273
        unsigned int ai_front;
 
274
        unsigned int ai_rear;
 
275
};
 
276
 
 
277
#define devpriv ((struct dt3k_private *)dev->private)
 
278
 
 
279
static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it);
 
280
static int dt3000_detach(struct comedi_device *dev);
 
281
static struct comedi_driver driver_dt3000 = {
 
282
        .driver_name = "dt3000",
 
283
        .module = THIS_MODULE,
 
284
        .attach = dt3000_attach,
 
285
        .detach = dt3000_detach,
 
286
};
 
287
 
 
288
COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table);
 
289
 
 
290
static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s);
 
291
static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
 
292
        unsigned int round_mode);
 
293
static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 
294
#ifdef DEBUG
 
295
static void debug_intr_flags(unsigned int flags);
 
296
#endif
 
297
 
 
298
#define TIMEOUT 100
 
299
 
 
300
static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
 
301
{
 
302
        int i;
 
303
        unsigned int status = 0;
 
304
 
 
305
        writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
 
306
 
 
307
        for (i = 0; i < TIMEOUT; i++) {
 
308
                status = readw(devpriv->io_addr + DPR_Command_Mbx);
 
309
                if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
 
310
                        break;
 
311
                udelay(1);
 
312
        }
 
313
        if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) {
 
314
                return 0;
 
315
        }
 
316
 
 
317
        printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status);
 
318
 
 
319
        return -ETIME;
 
320
}
 
321
 
 
322
static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys,
 
323
        unsigned int chan, unsigned int gain)
 
324
{
 
325
        writew(subsys, devpriv->io_addr + DPR_SubSys);
 
326
 
 
327
        writew(chan, devpriv->io_addr + DPR_Params(0));
 
328
        writew(gain, devpriv->io_addr + DPR_Params(1));
 
329
 
 
330
        dt3k_send_cmd(dev, CMD_READSINGLE);
 
331
 
 
332
        return readw(devpriv->io_addr + DPR_Params(2));
 
333
}
 
334
 
 
335
static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
 
336
        unsigned int chan, unsigned int data)
 
337
{
 
338
        writew(subsys, devpriv->io_addr + DPR_SubSys);
 
339
 
 
340
        writew(chan, devpriv->io_addr + DPR_Params(0));
 
341
        writew(0, devpriv->io_addr + DPR_Params(1));
 
342
        writew(data, devpriv->io_addr + DPR_Params(2));
 
343
 
 
344
        dt3k_send_cmd(dev, CMD_WRITESINGLE);
 
345
}
 
346
 
 
347
static int debug_n_ints = 0;
 
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 comedi_subdevice *s;
 
355
        unsigned int status;
 
356
 
 
357
        if (!dev->attached) {
 
358
                return IRQ_NONE;
 
359
        }
 
360
 
 
361
        s = dev->subdevices + 0;
 
362
        status = readw(devpriv->io_addr + DPR_Intr_Flag);
 
363
#ifdef DEBUG
 
364
        debug_intr_flags(status);
 
365
#endif
 
366
 
 
367
        if (status & DT3000_ADFULL) {
 
368
                dt3k_ai_empty_fifo(dev, s);
 
369
                s->async->events |= COMEDI_CB_BLOCK;
 
370
        }
 
371
 
 
372
        if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) {
 
373
                s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
 
374
        }
 
375
 
 
376
        debug_n_ints++;
 
377
        if (debug_n_ints >= 10) {
 
378
                dt3k_ai_cancel(dev, s);
 
379
                s->async->events |= COMEDI_CB_EOA;
 
380
        }
 
381
 
 
382
        comedi_event(dev, s);
 
383
        return IRQ_HANDLED;
 
384
}
 
385
 
 
386
#ifdef DEBUG
 
387
static char *intr_flags[] = {
 
388
        "AdFull", "AdSwError", "AdHwError", "DaEmpty",
 
389
        "DaSwError", "DaHwError", "CtDone", "CmDone",
 
390
};
 
391
static void debug_intr_flags(unsigned int flags)
 
392
{
 
393
        int i;
 
394
        printk("dt3k: intr_flags:");
 
395
        for (i = 0; i < 8; i++) {
 
396
                if (flags & (1 << i)) {
 
397
                        printk(" %s", intr_flags[i]);
 
398
                }
 
399
        }
 
400
        printk("\n");
 
401
}
 
402
#endif
 
403
 
 
404
static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s)
 
405
{
 
406
        int front;
 
407
        int rear;
 
408
        int count;
 
409
        int i;
 
410
        short data;
 
411
 
 
412
        front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
 
413
        count = front - devpriv->ai_front;
 
414
        if (count < 0)
 
415
                count += AI_FIFO_DEPTH;
 
416
 
 
417
        printk("reading %d samples\n", count);
 
418
 
 
419
        rear = devpriv->ai_rear;
 
420
 
 
421
        for (i = 0; i < count; i++) {
 
422
                data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
 
423
                comedi_buf_put(s->async, data);
 
424
                rear++;
 
425
                if (rear >= AI_FIFO_DEPTH)
 
426
                        rear = 0;
 
427
        }
 
428
 
 
429
        devpriv->ai_rear = rear;
 
430
        writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
 
431
}
 
432
 
 
433
static int dt3k_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 
434
        struct comedi_cmd *cmd)
 
435
{
 
436
        int err = 0;
 
437
        int tmp;
 
438
 
 
439
        /* step 1: make sure trigger sources are trivially valid */
 
440
 
 
441
        tmp = cmd->start_src;
 
442
        cmd->start_src &= TRIG_NOW;
 
443
        if (!cmd->start_src || tmp != cmd->start_src)
 
444
                err++;
 
445
 
 
446
        tmp = cmd->scan_begin_src;
 
447
        cmd->scan_begin_src &= TRIG_TIMER;
 
448
        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 
449
                err++;
 
450
 
 
451
        tmp = cmd->convert_src;
 
452
        cmd->convert_src &= TRIG_TIMER;
 
453
        if (!cmd->convert_src || tmp != cmd->convert_src)
 
454
                err++;
 
455
 
 
456
        tmp = cmd->scan_end_src;
 
457
        cmd->scan_end_src &= TRIG_COUNT;
 
458
        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 
459
                err++;
 
460
 
 
461
        tmp = cmd->stop_src;
 
462
        cmd->stop_src &= TRIG_COUNT;
 
463
        if (!cmd->stop_src || tmp != cmd->stop_src)
 
464
                err++;
 
465
 
 
466
        if (err)
 
467
                return 1;
 
468
 
 
469
        /* step 2: make sure trigger sources are unique and mutually compatible */
 
470
 
 
471
        if (err)
 
472
                return 2;
 
473
 
 
474
        /* step 3: make sure arguments are trivially compatible */
 
475
 
 
476
        if (cmd->start_arg != 0) {
 
477
                cmd->start_arg = 0;
 
478
                err++;
 
479
        }
 
480
 
 
481
        if (cmd->scan_begin_src == TRIG_TIMER) {
 
482
                if (cmd->scan_begin_arg < this_board->ai_speed) {
 
483
                        cmd->scan_begin_arg = this_board->ai_speed;
 
484
                        err++;
 
485
                }
 
486
                if (cmd->scan_begin_arg > 100 * 16 * 65535) {
 
487
                        cmd->scan_begin_arg = 100 * 16 * 65535;
 
488
                        err++;
 
489
                }
 
490
        } else {
 
491
                /* not supported */
 
492
        }
 
493
        if (cmd->convert_src == TRIG_TIMER) {
 
494
                if (cmd->convert_arg < this_board->ai_speed) {
 
495
                        cmd->convert_arg = this_board->ai_speed;
 
496
                        err++;
 
497
                }
 
498
                if (cmd->convert_arg > 50 * 16 * 65535) {
 
499
                        cmd->convert_arg = 50 * 16 * 65535;
 
500
                        err++;
 
501
                }
 
502
        } else {
 
503
                /* not supported */
 
504
        }
 
505
 
 
506
        if (cmd->scan_end_arg != cmd->chanlist_len) {
 
507
                cmd->scan_end_arg = cmd->chanlist_len;
 
508
                err++;
 
509
        }
 
510
        if (cmd->stop_src == TRIG_COUNT) {
 
511
                if (cmd->stop_arg > 0x00ffffff) {
 
512
                        cmd->stop_arg = 0x00ffffff;
 
513
                        err++;
 
514
                }
 
515
        } else {
 
516
                /* TRIG_NONE */
 
517
                if (cmd->stop_arg != 0) {
 
518
                        cmd->stop_arg = 0;
 
519
                        err++;
 
520
                }
 
521
        }
 
522
 
 
523
        if (err)
 
524
                return 3;
 
525
 
 
526
        /* step 4: fix up any arguments */
 
527
 
 
528
        if (cmd->scan_begin_src == TRIG_TIMER) {
 
529
                tmp = cmd->scan_begin_arg;
 
530
                dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
 
531
                        cmd->flags & TRIG_ROUND_MASK);
 
532
                if (tmp != cmd->scan_begin_arg)
 
533
                        err++;
 
534
        } else {
 
535
                /* not supported */
 
536
        }
 
537
        if (cmd->convert_src == TRIG_TIMER) {
 
538
                tmp = cmd->convert_arg;
 
539
                dt3k_ns_to_timer(50, &cmd->convert_arg,
 
540
                        cmd->flags & TRIG_ROUND_MASK);
 
541
                if (tmp != cmd->convert_arg)
 
542
                        err++;
 
543
                if (cmd->scan_begin_src == TRIG_TIMER &&
 
544
                        cmd->scan_begin_arg <
 
545
                        cmd->convert_arg * cmd->scan_end_arg) {
 
546
                        cmd->scan_begin_arg =
 
547
                                cmd->convert_arg * cmd->scan_end_arg;
 
548
                        err++;
 
549
                }
 
550
        } else {
 
551
                /* not supported */
 
552
        }
 
553
 
 
554
        if (err)
 
555
                return 4;
 
556
 
 
557
        return 0;
 
558
}
 
559
 
 
560
static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
 
561
        unsigned int round_mode)
 
562
{
 
563
        int divider, base, prescale;
 
564
 
 
565
        /* This function needs improvment */
 
566
        /* Don't know if divider==0 works. */
 
567
 
 
568
        for (prescale = 0; prescale < 16; prescale++) {
 
569
                base = timer_base * (prescale + 1);
 
570
                switch (round_mode) {
 
571
                case TRIG_ROUND_NEAREST:
 
572
                default:
 
573
                        divider = (*nanosec + base / 2) / base;
 
574
                        break;
 
575
                case TRIG_ROUND_DOWN:
 
576
                        divider = (*nanosec) / base;
 
577
                        break;
 
578
                case TRIG_ROUND_UP:
 
579
                        divider = (*nanosec) / base;
 
580
                        break;
 
581
                }
 
582
                if (divider < 65536) {
 
583
                        *nanosec = divider * base;
 
584
                        return (prescale << 16) | (divider);
 
585
                }
 
586
        }
 
587
 
 
588
        prescale = 15;
 
589
        base = timer_base * (1 << prescale);
 
590
        divider = 65535;
 
591
        *nanosec = divider * base;
 
592
        return (prescale << 16) | (divider);
 
593
}
 
594
 
 
595
static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 
596
{
 
597
        struct comedi_cmd *cmd = &s->async->cmd;
 
598
        int i;
 
599
        unsigned int chan, range, aref;
 
600
        unsigned int divider;
 
601
        unsigned int tscandiv;
 
602
        int ret;
 
603
        unsigned int mode;
 
604
 
 
605
        printk("dt3k_ai_cmd:\n");
 
606
        for (i = 0; i < cmd->chanlist_len; i++) {
 
607
                chan = CR_CHAN(cmd->chanlist[i]);
 
608
                range = CR_RANGE(cmd->chanlist[i]);
 
609
 
 
610
                writew((range << 6) | chan,
 
611
                        devpriv->io_addr + DPR_ADC_buffer + i);
 
612
        }
 
613
        aref = CR_AREF(cmd->chanlist[0]);
 
614
 
 
615
        writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
 
616
        printk("param[0]=0x%04x\n", cmd->scan_end_arg);
 
617
 
 
618
        if (cmd->convert_src == TRIG_TIMER) {
 
619
                divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
 
620
                        cmd->flags & TRIG_ROUND_MASK);
 
621
                writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
 
622
                printk("param[1]=0x%04x\n", divider >> 16);
 
623
                writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
 
624
                printk("param[2]=0x%04x\n", divider & 0xffff);
 
625
        } else {
 
626
                /* not supported */
 
627
        }
 
628
 
 
629
        if (cmd->scan_begin_src == TRIG_TIMER) {
 
630
                tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
 
631
                        cmd->flags & TRIG_ROUND_MASK);
 
632
                writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
 
633
                printk("param[3]=0x%04x\n", tscandiv >> 16);
 
634
                writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
 
635
                printk("param[4]=0x%04x\n", tscandiv & 0xffff);
 
636
        } else {
 
637
                /* not supported */
 
638
        }
 
639
 
 
640
        mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
 
641
        writew(mode, devpriv->io_addr + DPR_Params(5));
 
642
        printk("param[5]=0x%04x\n", mode);
 
643
        writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
 
644
        printk("param[6]=0x%04x\n", aref == AREF_DIFF);
 
645
 
 
646
        writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
 
647
        printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
 
648
 
 
649
        writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 
650
        ret = dt3k_send_cmd(dev, CMD_CONFIG);
 
651
 
 
652
        writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
 
653
                devpriv->io_addr + DPR_Int_Mask);
 
654
 
 
655
        debug_n_ints = 0;
 
656
 
 
657
        writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 
658
        ret = dt3k_send_cmd(dev, CMD_START);
 
659
 
 
660
        return 0;
 
661
}
 
662
 
 
663
static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 
664
{
 
665
        int ret;
 
666
 
 
667
        writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
 
668
        ret = dt3k_send_cmd(dev, CMD_STOP);
 
669
 
 
670
        writew(0, devpriv->io_addr + DPR_Int_Mask);
 
671
 
 
672
        return 0;
 
673
}
 
674
 
 
675
static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 
676
        struct comedi_insn *insn, unsigned int *data)
 
677
{
 
678
        int i;
 
679
        unsigned int chan, gain, aref;
 
680
 
 
681
        chan = CR_CHAN(insn->chanspec);
 
682
        gain = CR_RANGE(insn->chanspec);
 
683
        /* XXX docs don't explain how to select aref */
 
684
        aref = CR_AREF(insn->chanspec);
 
685
 
 
686
        for (i = 0; i < insn->n; i++) {
 
687
                data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
 
688
        }
 
689
 
 
690
        return i;
 
691
}
 
692
 
 
693
static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 
694
        struct comedi_insn *insn, unsigned int *data)
 
695
{
 
696
        int i;
 
697
        unsigned int chan;
 
698
 
 
699
        chan = CR_CHAN(insn->chanspec);
 
700
        for (i = 0; i < insn->n; i++) {
 
701
                dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
 
702
                devpriv->ao_readback[chan] = data[i];
 
703
        }
 
704
 
 
705
        return i;
 
706
}
 
707
 
 
708
static int dt3k_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
 
709
        struct comedi_insn *insn, unsigned int *data)
 
710
{
 
711
        int i;
 
712
        unsigned int chan;
 
713
 
 
714
        chan = CR_CHAN(insn->chanspec);
 
715
        for (i = 0; i < insn->n; i++) {
 
716
                data[i] = devpriv->ao_readback[chan];
 
717
        }
 
718
 
 
719
        return i;
 
720
}
 
721
 
 
722
static void dt3k_dio_config(struct comedi_device *dev, int bits)
 
723
{
 
724
        /* XXX */
 
725
        writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
 
726
 
 
727
        writew(bits, devpriv->io_addr + DPR_Params(0));
 
728
#if 0
 
729
        /* don't know */
 
730
        writew(0, devpriv->io_addr + DPR_Params(1));
 
731
        writew(0, devpriv->io_addr + DPR_Params(2));
 
732
#endif
 
733
 
 
734
        dt3k_send_cmd(dev, CMD_CONFIG);
 
735
}
 
736
 
 
737
static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
 
738
        struct comedi_insn *insn, unsigned int *data)
 
739
{
 
740
        int mask;
 
741
 
 
742
        mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
 
743
 
 
744
        switch (data[0]) {
 
745
        case INSN_CONFIG_DIO_OUTPUT:
 
746
                s->io_bits |= mask;
 
747
                break;
 
748
        case INSN_CONFIG_DIO_INPUT:
 
749
                s->io_bits &= ~mask;
 
750
                break;
 
751
        case INSN_CONFIG_DIO_QUERY:
 
752
                data[1] =
 
753
                        (s->io_bits & (1 << CR_CHAN(insn->
 
754
                                        chanspec))) ? COMEDI_OUTPUT :
 
755
                        COMEDI_INPUT;
 
756
                return insn->n;
 
757
                break;
 
758
        default:
 
759
                return -EINVAL;
 
760
                break;
 
761
        }
 
762
        mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
 
763
        dt3k_dio_config(dev, mask);
 
764
 
 
765
        return insn->n;
 
766
}
 
767
 
 
768
static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
 
769
        struct comedi_insn *insn, unsigned int *data)
 
770
{
 
771
        if (insn->n != 2)
 
772
                return -EINVAL;
 
773
 
 
774
        if (data[0]) {
 
775
                s->state &= ~data[0];
 
776
                s->state |= data[1] & data[0];
 
777
                dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
 
778
        }
 
779
        data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
 
780
 
 
781
        return 2;
 
782
}
 
783
 
 
784
static int dt3k_mem_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
 
785
        struct comedi_insn *insn, unsigned int *data)
 
786
{
 
787
        unsigned int addr = CR_CHAN(insn->chanspec);
 
788
        int i;
 
789
 
 
790
        for (i = 0; i < insn->n; i++) {
 
791
                writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
 
792
                writew(addr, devpriv->io_addr + DPR_Params(0));
 
793
                writew(1, devpriv->io_addr + DPR_Params(1));
 
794
 
 
795
                dt3k_send_cmd(dev, CMD_READCODE);
 
796
 
 
797
                data[i] = readw(devpriv->io_addr + DPR_Params(2));
 
798
        }
 
799
 
 
800
        return i;
 
801
}
 
802
 
 
803
static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
 
804
 
 
805
static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
806
{
 
807
        struct comedi_subdevice *s;
 
808
        int bus, slot;
 
809
        int ret = 0;
 
810
 
 
811
        printk("dt3000:");
 
812
        bus = it->options[0];
 
813
        slot = it->options[1];
 
814
 
 
815
        ret = alloc_private(dev, sizeof(struct dt3k_private));
 
816
        if (ret < 0)
 
817
                return ret;
 
818
 
 
819
        ret = dt_pci_probe(dev, bus, slot);
 
820
        if (ret < 0)
 
821
                return ret;
 
822
        if (ret == 0) {
 
823
                printk(" no DT board found\n");
 
824
                return -ENODEV;
 
825
        }
 
826
 
 
827
        dev->board_name = this_board->name;
 
828
 
 
829
        if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED,
 
830
                        "dt3000", dev)) {
 
831
                printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq);
 
832
                return -EINVAL;
 
833
        }
 
834
        dev->irq = devpriv->pci_dev->irq;
 
835
 
 
836
        ret = alloc_subdevices(dev, 4);
 
837
        if (ret < 0)
 
838
                return ret;
 
839
 
 
840
        s = dev->subdevices;
 
841
        dev->read_subdev = s;
 
842
 
 
843
        /* ai subdevice */
 
844
        s->type = COMEDI_SUBD_AI;
 
845
        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
 
846
        s->n_chan = this_board->adchan;
 
847
        s->insn_read = dt3k_ai_insn;
 
848
        s->maxdata = (1 << this_board->adbits) - 1;
 
849
        s->len_chanlist = 512;
 
850
        s->range_table = &range_dt3000_ai;      /* XXX */
 
851
        s->do_cmd = dt3k_ai_cmd;
 
852
        s->do_cmdtest = dt3k_ai_cmdtest;
 
853
        s->cancel = dt3k_ai_cancel;
 
854
 
 
855
        s++;
 
856
        /* ao subsystem */
 
857
        s->type = COMEDI_SUBD_AO;
 
858
        s->subdev_flags = SDF_WRITABLE;
 
859
        s->n_chan = 2;
 
860
        s->insn_read = dt3k_ao_insn_read;
 
861
        s->insn_write = dt3k_ao_insn;
 
862
        s->maxdata = (1 << this_board->dabits) - 1;
 
863
        s->len_chanlist = 1;
 
864
        s->range_table = &range_bipolar10;
 
865
 
 
866
        s++;
 
867
        /* dio subsystem */
 
868
        s->type = COMEDI_SUBD_DIO;
 
869
        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 
870
        s->n_chan = 8;
 
871
        s->insn_config = dt3k_dio_insn_config;
 
872
        s->insn_bits = dt3k_dio_insn_bits;
 
873
        s->maxdata = 1;
 
874
        s->len_chanlist = 8;
 
875
        s->range_table = &range_digital;
 
876
 
 
877
        s++;
 
878
        /* mem subsystem */
 
879
        s->type = COMEDI_SUBD_MEMORY;
 
880
        s->subdev_flags = SDF_READABLE;
 
881
        s->n_chan = 0x1000;
 
882
        s->insn_read = dt3k_mem_insn_read;
 
883
        s->maxdata = 0xff;
 
884
        s->len_chanlist = 1;
 
885
        s->range_table = &range_unknown;
 
886
 
 
887
#if 0
 
888
        s++;
 
889
        /* proc subsystem */
 
890
        s->type = COMEDI_SUBD_PROC;
 
891
#endif
 
892
 
 
893
        return 0;
 
894
}
 
895
 
 
896
static int dt3000_detach(struct comedi_device *dev)
 
897
{
 
898
        if (dev->irq)
 
899
                free_irq(dev->irq, dev);
 
900
 
 
901
        if (devpriv) {
 
902
                if (devpriv->pci_dev) {
 
903
                        if (devpriv->phys_addr) {
 
904
                                comedi_pci_disable(devpriv->pci_dev);
 
905
                        }
 
906
                        pci_dev_put(devpriv->pci_dev);
 
907
                }
 
908
                if (devpriv->io_addr)
 
909
                        iounmap(devpriv->io_addr);
 
910
        }
 
911
        /* XXX */
 
912
 
 
913
        return 0;
 
914
}
 
915
 
 
916
static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
 
917
static int setup_pci(struct comedi_device *dev);
 
918
 
 
919
static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
 
920
{
 
921
        int board;
 
922
        int ret;
 
923
        struct pci_dev *pcidev;
 
924
 
 
925
        pcidev = NULL;
 
926
        while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
 
927
                if ((bus == 0 && slot == 0) ||
 
928
                        (pcidev->bus->number == bus &&
 
929
                         PCI_SLOT(pcidev->devfn) == slot)) {
 
930
                        break;
 
931
                }
 
932
        }
 
933
        devpriv->pci_dev = pcidev;
 
934
 
 
935
        if (board >= 0)
 
936
                dev->board_ptr = dt3k_boardtypes + board;
 
937
 
 
938
        if (!devpriv->pci_dev)
 
939
                return 0;
 
940
 
 
941
        ret = setup_pci(dev);
 
942
        if (ret < 0)
 
943
                return ret;
 
944
 
 
945
        return 1;
 
946
}
 
947
 
 
948
static int setup_pci(struct comedi_device *dev)
 
949
{
 
950
        resource_size_t addr;
 
951
        int ret;
 
952
 
 
953
        ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
 
954
        if (ret < 0)
 
955
                return ret;
 
956
 
 
957
        addr = pci_resource_start(devpriv->pci_dev, 0);
 
958
        devpriv->phys_addr = addr;
 
959
        devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
 
960
        if (!devpriv->io_addr)
 
961
                return -ENOMEM;
 
962
#if DEBUG
 
963
        printk("0x%08llx mapped to %p, ",
 
964
                (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
 
965
#endif
 
966
 
 
967
        return 0;
 
968
}
 
969
 
 
970
static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
 
971
{
 
972
        int i;
 
973
 
 
974
        for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
 
975
                from != NULL;
 
976
                from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
 
977
                for (i = 0; i < n_dt3k_boards; i++) {
 
978
                        if (from->device == dt3k_boardtypes[i].device_id) {
 
979
                                *board = i;
 
980
                                return from;
 
981
                        }
 
982
                }
 
983
                printk("unknown Data Translation PCI device found with device_id=0x%04x\n", from->device);
 
984
        }
 
985
        *board = -1;
 
986
        return from;
 
987
}