~ubuntu-branches/ubuntu/karmic/linux-ports/karmic

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich, Luke Yelavich, Michael Casadevall, Tim Gardner, Upstream Kernel Changes
  • Date: 2009-05-06 18:18:55 UTC
  • Revision ID: james.westby@ubuntu.com-20090506181855-t00baeevpnvd9o7a
Tags: 2.6.30-1.1
[ Luke Yelavich ]
* initial release for karmic
* SAUCE: rebase-ports - adjust for the karmic ports kernel
* SAUCE: rebase-ports - also remove abi dirs/files on rebase
* Update configs after rebase against mainline Jaunty tree
* [Config] Disable CONFIG_BLK_DEV_UB and CONFIG_USB_LIBUSUAL as per
  mainline jaunty
* forward-port patch to drbd for powerpc compilation
* [Config] disable CONFIG_LENOVO_SL_LAPTOP for i386 due to FTBFS
* add .o files found in arch/powerpc/lib to all powerpc kernel header
  packages
* [Config] enable CONFIG_DRM_I915_KMS for i386 as per karmic mainline

[ Michael Casadevall ]

* Disable kgdb on sparc64
* [sparc] [Config] Disable GPIO LEDS
* [ia64] Rename -ia64-generic to -ia64 in line with other architectures
* Correct kernel image path for sparc builds
* [hppa] Fix HPPA config files to build modules for all udebian

Rebase on top of karmic mainline 2.6.30-1.1

[ Tim Gardner ]

* [Config] armel: disable staging drivers, fixes FTBS
* [Config] armel imx51: Disable CONFIG_MTD_NAND_MXC, fixes FTBS

[ Upstream Kernel Changes ]

* mpt2sas: Change reset_type enum to avoid namespace collision.
  Submitted upstream.

* Initial release after rebasing against v2.6.30-rc3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      comedi/drivers/ii_pci20kc.c
 
3
 *      Driver for Intelligent Instruments PCI-20001C carrier board
 
4
 *      and modules.
 
5
 *
 
6
 *      Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de>
 
7
 *      with suggestions from David Schleef
 
8
 *                      16.06.2000
 
9
 *
 
10
 *      Linux device driver for COMEDI
 
11
 *      Intelligent Instrumentation
 
12
 *      PCI-20001 C-2A Carrier Board
 
13
 *      PCI-20341 M-1A 16-Bit analog input module
 
14
 *                              - differential
 
15
 *                              - range (-5V - +5V)
 
16
 *                              - 16 bit
 
17
 *      PCI-20006 M-2 16-Bit analog output module
 
18
 *                              - ranges (-10V - +10V) (0V - +10V) (-5V - +5V)
 
19
 *                              - 16 bit
 
20
 *
 
21
 *      only ONE PCI-20341 module possible
 
22
 *      only ONE PCI-20006 module possible
 
23
 *      no extern trigger implemented
 
24
 *
 
25
 *      NOT WORKING (but soon) only 4 on-board differential channels supported
 
26
 *      NOT WORKING (but soon) only ONE di-port and ONE do-port supported instead of 4 digital ports
 
27
 *      di-port == Port 0
 
28
 *      do-port == Port 1
 
29
 *
 
30
 *      The state of this driver is only a starting point for a complete
 
31
 *      COMEDI-driver. The final driver should support all features of the
 
32
 *      carrier board and modules.
 
33
 *
 
34
 *      The test configuration:
 
35
 *
 
36
 *      kernel 2.2.14 with RTAI v1.2  and patch-2.2.14rthal2
 
37
 *      COMEDI 0.7.45
 
38
 *      COMEDILIB 0.7.9
 
39
 *
 
40
 */
 
41
/*
 
42
Driver: ii_pci20kc
 
43
Description: Intelligent Instruments PCI-20001C carrier board
 
44
Author: Markus Kempf <kempf@matsci.uni-sb.de>
 
45
Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc)
 
46
Status: works
 
47
 
 
48
Supports the PCI-20001 C-2a Carrier board, and could probably support
 
49
the other carrier boards with small modifications.  Modules supported
 
50
are:
 
51
        PCI-20006 M-2 16-bit analog output module
 
52
        PCI-20341 M-1A 16-bit analog input module
 
53
 
 
54
Options:
 
55
  0   Board base address
 
56
  1   IRQ
 
57
  2   first option for module 1
 
58
  3   second option for module 1
 
59
  4   first option for module 2
 
60
  5   second option for module 2
 
61
  6   first option for module 3
 
62
  7   second option for module 3
 
63
 
 
64
options for PCI-20006M:
 
65
  first:   Analog output channel 0 range configuration
 
66
             0  bipolar 10  (-10V -- +10V)
 
67
             1  unipolar 10  (0V -- +10V)
 
68
             2  bipolar 5  (-5V -- 5V)
 
69
  second:  Analog output channel 1 range configuration
 
70
 
 
71
options for PCI-20341M:
 
72
  first:   Analog input gain configuration
 
73
             0  1
 
74
             1  10
 
75
             2  100
 
76
             3  200
 
77
*/
 
78
 
 
79
/* XXX needs to use ioremap() for compatibility with 2.4 kernels.  Should also
 
80
 * check_mem_region() etc. - fmhess */
 
81
 
 
82
#include "../comedidev.h"
 
83
 
 
84
#define PCI20000_ID                     0x1d
 
85
#define PCI20341_ID                     0x77
 
86
#define PCI20006_ID                     0xe3
 
87
#define PCI20xxx_EMPTY_ID               0xff
 
88
 
 
89
#define PCI20000_OFFSET                 0x100
 
90
#define PCI20000_MODULES                3
 
91
 
 
92
#define PCI20000_DIO_0                  0x80
 
93
#define PCI20000_DIO_1                  0x81
 
94
#define PCI20000_DIO_2                  0xc0
 
95
#define PCI20000_DIO_3                  0xc1
 
96
#define PCI20000_DIO_CONTROL_01         0x83    /* port 0, 1 control */
 
97
#define PCI20000_DIO_CONTROL_23         0xc3    /* port 2, 3 control */
 
98
#define PCI20000_DIO_BUFFER             0x82    /* buffer direction and enable */
 
99
#define PCI20000_DIO_EOC                0xef    /* even port, control output */
 
100
#define PCI20000_DIO_OOC                0xfd    /* odd port, control output */
 
101
#define PCI20000_DIO_EIC                0x90    /* even port, control input */
 
102
#define PCI20000_DIO_OIC                0x82    /* odd port, control input */
 
103
#define DIO_CAND                        0x12    /* and bit 1, bit 4 of control */
 
104
#define DIO_BE                          0x01    /* buffer: port enable */
 
105
#define DIO_BO                          0x04    /* buffer: output */
 
106
#define DIO_BI                          0x05    /* buffer: input */
 
107
#define DIO_PS_0                        0x00    /* buffer: port shift 0 */
 
108
#define DIO_PS_1                        0x01    /* buffer: port shift 1 */
 
109
#define DIO_PS_2                        0x04    /* buffer: port shift 2 */
 
110
#define DIO_PS_3                        0x05    /* buffer: port shift 3 */
 
111
 
 
112
#define PCI20006_LCHAN0                 0x0d
 
113
#define PCI20006_STROBE0                0x0b
 
114
#define PCI20006_LCHAN1                 0x15
 
115
#define PCI20006_STROBE1                0x13
 
116
 
 
117
#define PCI20341_INIT                   0x04
 
118
#define PCI20341_REPMODE                0x00    /* single shot mode */
 
119
#define PCI20341_PACER                  0x00    /* Hardware Pacer disabled */
 
120
#define PCI20341_CHAN_NR                0x04    /* number of input channels */
 
121
#define PCI20341_CONFIG_REG             0x10
 
122
#define PCI20341_MOD_STATUS             0x01
 
123
#define PCI20341_OPT_REG                0x11
 
124
#define PCI20341_SET_TIME_REG           0x15
 
125
#define PCI20341_LCHAN_ADDR_REG         0x13
 
126
#define PCI20341_CHAN_LIST              0x80
 
127
#define PCI20341_CC_RESET               0x1b
 
128
#define PCI20341_CHAN_RESET             0x19
 
129
#define PCI20341_SOFT_PACER             0x04
 
130
#define PCI20341_STATUS_REG             0x12
 
131
#define PCI20341_LDATA                  0x02
 
132
#define PCI20341_DAISY_CHAIN            0x20    /* On-board inputs only */
 
133
#define PCI20341_MUX                    0x04    /* Enable on-board MUX */
 
134
#define PCI20341_SCANLIST               0x80    /* Channel/Gain Scan List */
 
135
 
 
136
union pci20xxx_subdev_private {
 
137
        void *iobase;
 
138
        struct {
 
139
                void *iobase;
 
140
                const struct comedi_lrange *ao_range_list[2];   /* range of channels of ao module */
 
141
                unsigned int last_data[2];
 
142
        } pci20006;
 
143
        struct {
 
144
                void *iobase;
 
145
                int timebase;
 
146
                int settling_time;
 
147
                int ai_gain;
 
148
        } pci20341;
 
149
};
 
150
 
 
151
struct pci20xxx_private {
 
152
 
 
153
        void *ioaddr;
 
154
        union pci20xxx_subdev_private subdev_private[PCI20000_MODULES];
 
155
};
 
156
 
 
157
 
 
158
#define devpriv ((struct pci20xxx_private *)dev->private)
 
159
#define CHAN (CR_CHAN(it->chanlist[0]))
 
160
 
 
161
static int pci20xxx_attach(struct comedi_device * dev, struct comedi_devconfig * it);
 
162
static int pci20xxx_detach(struct comedi_device * dev);
 
163
 
 
164
static struct comedi_driver driver_pci20xxx = {
 
165
      driver_name:"ii_pci20kc",
 
166
      module:THIS_MODULE,
 
167
      attach:pci20xxx_attach,
 
168
      detach:pci20xxx_detach,
 
169
};
 
170
 
 
171
static int pci20006_init(struct comedi_device * dev, struct comedi_subdevice * s,
 
172
        int opt0, int opt1);
 
173
static int pci20341_init(struct comedi_device * dev, struct comedi_subdevice * s,
 
174
        int opt0, int opt1);
 
175
static int pci20xxx_dio_init(struct comedi_device * dev, struct comedi_subdevice * s);
 
176
 
 
177
/*
 
178
  options[0]    Board base address
 
179
  options[1]    IRQ
 
180
  options[2]    first option for module 1
 
181
  options[3]    second option for module 1
 
182
  options[4]    first option for module 2
 
183
  options[5]    second option for module 2
 
184
  options[6]    first option for module 3
 
185
  options[7]    second option for module 3
 
186
 
 
187
  options for PCI-20341M:
 
188
  first         Analog input gain configuration
 
189
                0 == 1
 
190
                1 == 10
 
191
                2 == 100
 
192
                3 == 200
 
193
 
 
194
  options for PCI-20006M:
 
195
  first         Analog output channel 0 range configuration
 
196
                0 == bipolar 10  (-10V -- +10V)
 
197
                1 == unipolar 10V  (0V -- +10V)
 
198
                2 == bipolar 5V  (-5V -- +5V)
 
199
  second        Analog output channel 1 range configuration
 
200
                0 == bipolar 10  (-10V -- +10V)
 
201
                1 == unipolar 10V  (0V -- +10V)
 
202
                2 == bipolar 5V  (-5V -- +5V)
 
203
*/
 
204
static int pci20xxx_attach(struct comedi_device * dev, struct comedi_devconfig * it)
 
205
{
 
206
        unsigned char i;
 
207
        int ret;
 
208
        int id;
 
209
        struct comedi_subdevice *s;
 
210
        union pci20xxx_subdev_private *sdp;
 
211
 
 
212
        if ((ret = alloc_subdevices(dev, 1 + PCI20000_MODULES)) < 0)
 
213
                return ret;
 
214
        if ((ret = alloc_private(dev, sizeof(struct pci20xxx_private))) < 0)
 
215
                return ret;
 
216
 
 
217
        devpriv->ioaddr = (void *)(unsigned long)it->options[0];
 
218
        dev->board_name = "pci20kc";
 
219
 
 
220
        /* Check PCI-20001 C-2A Carrier Board ID */
 
221
        if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) {
 
222
                printk("comedi%d: ii_pci20kc", dev->minor);
 
223
                printk(" PCI-20001 C-2A Carrier Board at base=0x%p not found !\n", devpriv->ioaddr);
 
224
                return -EINVAL;
 
225
        }
 
226
        printk("comedi%d:\n", dev->minor);
 
227
        printk("ii_pci20kc: PCI-20001 C-2A at base=0x%p\n", devpriv->ioaddr);
 
228
 
 
229
        for (i = 0; i < PCI20000_MODULES; i++) {
 
230
                s = dev->subdevices + i;
 
231
                id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET);
 
232
                s->private = devpriv->subdev_private + i;
 
233
                sdp = s->private;
 
234
                switch (id) {
 
235
                case PCI20006_ID:
 
236
                        sdp->pci20006.iobase =
 
237
                                devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
 
238
                        pci20006_init(dev, s, it->options[2 * i + 2],
 
239
                                it->options[2 * i + 3]);
 
240
                        printk("comedi%d: ii_pci20kc", dev->minor);
 
241
                        printk(" PCI-20006 module in slot %d \n", i + 1);
 
242
                        break;
 
243
                case PCI20341_ID:
 
244
                        sdp->pci20341.iobase =
 
245
                                devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
 
246
                        pci20341_init(dev, s, it->options[2 * i + 2],
 
247
                                it->options[2 * i + 3]);
 
248
                        printk("comedi%d: ii_pci20kc", dev->minor);
 
249
                        printk(" PCI-20341 module in slot %d \n", i + 1);
 
250
                        break;
 
251
                default:
 
252
                        printk("ii_pci20kc: unknown module code 0x%02x in slot %d: module disabled\n", id, i);
 
253
                        /* fall through */
 
254
                case PCI20xxx_EMPTY_ID:
 
255
                        s->type = COMEDI_SUBD_UNUSED;
 
256
                        break;
 
257
                }
 
258
        }
 
259
 
 
260
        /* initialize struct pci20xxx_private */
 
261
        pci20xxx_dio_init(dev, dev->subdevices + PCI20000_MODULES);
 
262
 
 
263
        return 1;
 
264
}
 
265
 
 
266
static int pci20xxx_detach(struct comedi_device * dev)
 
267
{
 
268
        printk("comedi%d: pci20xxx: remove\n", dev->minor);
 
269
 
 
270
        return 0;
 
271
}
 
272
 
 
273
/* pci20006m */
 
274
 
 
275
static int pci20006_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
 
276
        struct comedi_insn * insn, unsigned int * data);
 
277
static int pci20006_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
 
278
        struct comedi_insn * insn, unsigned int * data);
 
279
 
 
280
static const struct comedi_lrange *pci20006_range_list[] = {
 
281
        &range_bipolar10,
 
282
        &range_unipolar10,
 
283
        &range_bipolar5,
 
284
};
 
285
 
 
286
static int pci20006_init(struct comedi_device * dev, struct comedi_subdevice * s,
 
287
        int opt0, int opt1)
 
288
{
 
289
        union pci20xxx_subdev_private *sdp = s->private;
 
290
 
 
291
        if (opt0 < 0 || opt0 > 2)
 
292
                opt0 = 0;
 
293
        if (opt1 < 0 || opt1 > 2)
 
294
                opt1 = 0;
 
295
 
 
296
        sdp->pci20006.ao_range_list[0] = pci20006_range_list[opt0];
 
297
        sdp->pci20006.ao_range_list[1] = pci20006_range_list[opt1];
 
298
 
 
299
        /* ao subdevice */
 
300
        s->type = COMEDI_SUBD_AO;
 
301
        s->subdev_flags = SDF_WRITABLE;
 
302
        s->n_chan = 2;
 
303
        s->len_chanlist = 2;
 
304
        s->insn_read = pci20006_insn_read;
 
305
        s->insn_write = pci20006_insn_write;
 
306
        s->maxdata = 0xffff;
 
307
        s->range_table_list = sdp->pci20006.ao_range_list;
 
308
        return 0;
 
309
}
 
310
 
 
311
static int pci20006_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
 
312
        struct comedi_insn * insn, unsigned int * data)
 
313
{
 
314
        union pci20xxx_subdev_private *sdp = s->private;
 
315
 
 
316
        data[0] = sdp->pci20006.last_data[CR_CHAN(insn->chanspec)];
 
317
 
 
318
        return 1;
 
319
}
 
320
 
 
321
static int pci20006_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
 
322
        struct comedi_insn * insn, unsigned int * data)
 
323
{
 
324
        union pci20xxx_subdev_private *sdp = s->private;
 
325
        int hi, lo;
 
326
        unsigned int boarddata;
 
327
 
 
328
        sdp->pci20006.last_data[CR_CHAN(insn->chanspec)] = data[0];
 
329
        boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff);        /* comedi-data -> board-data */
 
330
        lo = (boarddata & 0xff);
 
331
        hi = ((boarddata >> 8) & 0xff);
 
332
 
 
333
        switch (CR_CHAN(insn->chanspec)) {
 
334
        case 0:
 
335
                writeb(lo, sdp->iobase + PCI20006_LCHAN0);
 
336
                writeb(hi, sdp->iobase + PCI20006_LCHAN0 + 1);
 
337
                writeb(0x00, sdp->iobase + PCI20006_STROBE0);
 
338
                break;
 
339
        case 1:
 
340
                writeb(lo, sdp->iobase + PCI20006_LCHAN1);
 
341
                writeb(hi, sdp->iobase + PCI20006_LCHAN1 + 1);
 
342
                writeb(0x00, sdp->iobase + PCI20006_STROBE1);
 
343
                break;
 
344
        default:
 
345
                printk(" comedi%d: pci20xxx: ao channel Error!\n", dev->minor);
 
346
                return -EINVAL;
 
347
        }
 
348
 
 
349
        return 1;
 
350
}
 
351
 
 
352
/* PCI20341M */
 
353
 
 
354
static int pci20341_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
 
355
        struct comedi_insn * insn, unsigned int * data);
 
356
 
 
357
static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 };
 
358
static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 };
 
359
 
 
360
static const struct comedi_lrange range_bipolar0_5 = { 1, {BIP_RANGE(0.5)} };
 
361
static const struct comedi_lrange range_bipolar0_05 = { 1, {BIP_RANGE(0.05)} };
 
362
static const struct comedi_lrange range_bipolar0_025 = { 1, {BIP_RANGE(0.025)} };
 
363
 
 
364
static const struct comedi_lrange *const pci20341_ranges[] = {
 
365
        &range_bipolar5,
 
366
        &range_bipolar0_5,
 
367
        &range_bipolar0_05,
 
368
        &range_bipolar0_025,
 
369
};
 
370
 
 
371
static int pci20341_init(struct comedi_device * dev, struct comedi_subdevice * s,
 
372
        int opt0, int opt1)
 
373
{
 
374
        union pci20xxx_subdev_private *sdp = s->private;
 
375
        int option;
 
376
 
 
377
        /* options handling */
 
378
        if (opt0 < 0 || opt0 > 3)
 
379
                opt0 = 0;
 
380
        sdp->pci20341.timebase = pci20341_timebase[opt0];
 
381
        sdp->pci20341.settling_time = pci20341_settling_time[opt0];
 
382
 
 
383
        /* ai subdevice */
 
384
        s->type = COMEDI_SUBD_AI;
 
385
        s->subdev_flags = SDF_READABLE;
 
386
        s->n_chan = PCI20341_CHAN_NR;
 
387
        s->len_chanlist = PCI20341_SCANLIST;
 
388
        s->insn_read = pci20341_insn_read;
 
389
        s->maxdata = 0xffff;
 
390
        s->range_table = pci20341_ranges[opt0];
 
391
 
 
392
        option = sdp->pci20341.timebase | PCI20341_REPMODE;     /* depends on gain, trigger, repetition mode */
 
393
 
 
394
        writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG);       /* initialize Module */
 
395
        writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS);      /* set Pacer */
 
396
        writeb(option, sdp->iobase + PCI20341_OPT_REG); /* option register */
 
397
        writeb(sdp->pci20341.settling_time, sdp->iobase + PCI20341_SET_TIME_REG);       /* settling time counter */
 
398
        /* trigger not implemented */
 
399
        return 0;
 
400
}
 
401
 
 
402
static int pci20341_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
 
403
        struct comedi_insn * insn, unsigned int * data)
 
404
{
 
405
        union pci20xxx_subdev_private *sdp = s->private;
 
406
        unsigned int i = 0, j = 0;
 
407
        int lo, hi;
 
408
        unsigned char eoc;      /* end of conversion */
 
409
        unsigned int clb;       /* channel list byte */
 
410
        unsigned int boarddata;
 
411
 
 
412
        writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG);       /* write number of input channels */
 
413
        clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3)
 
414
                | CR_CHAN(insn->chanspec);
 
415
        writeb(clb, sdp->iobase + PCI20341_CHAN_LIST);
 
416
        writeb(0x00, sdp->iobase + PCI20341_CC_RESET);  /* reset settling time counter and trigger delay counter */
 
417
        writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET);
 
418
 
 
419
        /* generate Pacer */
 
420
 
 
421
        for (i = 0; i < insn->n; i++) {
 
422
                /* data polling isn't the niciest way to get the data, I know,
 
423
                 * but there are only 6 cycles (mean) and it is easier than
 
424
                 * the whole interrupt stuff
 
425
                 */
 
426
                j = 0;
 
427
                readb(sdp->iobase + PCI20341_SOFT_PACER);       /* generate Pacer */
 
428
                eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
 
429
                while ((eoc < 0x80) && j < 100) {       /* poll Interrupt Flag */
 
430
                        j++;
 
431
                        eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
 
432
                }
 
433
                if (j >= 100) {
 
434
                        printk("comedi%d:  pci20xxx: AI interrupt channel %i polling exit !\n", dev->minor, i);
 
435
                        return -EINVAL;
 
436
                }
 
437
                lo = readb(sdp->iobase + PCI20341_LDATA);
 
438
                hi = readb(sdp->iobase + PCI20341_LDATA + 1);
 
439
                boarddata = lo + 0x100 * hi;
 
440
                data[i] = (short) ((boarddata + 0x8000) & 0xffff);      /* board-data -> comedi-data */
 
441
        }
 
442
 
 
443
        return i;
 
444
}
 
445
 
 
446
/* native DIO */
 
447
 
 
448
static void pci20xxx_dio_config(struct comedi_device * dev, struct comedi_subdevice * s);
 
449
static int pci20xxx_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
 
450
        struct comedi_insn * insn, unsigned int * data);
 
451
static int pci20xxx_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
 
452
        struct comedi_insn * insn, unsigned int * data);
 
453
 
 
454
/* initialize struct pci20xxx_private */
 
455
static int pci20xxx_dio_init(struct comedi_device * dev, struct comedi_subdevice * s)
 
456
{
 
457
 
 
458
        s->type = COMEDI_SUBD_DIO;
 
459
        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 
460
        s->n_chan = 32;
 
461
        s->insn_bits = pci20xxx_dio_insn_bits;
 
462
        s->insn_config = pci20xxx_dio_insn_config;
 
463
        s->maxdata = 1;
 
464
        s->len_chanlist = 32;
 
465
        s->range_table = &range_digital;
 
466
        s->io_bits = 0;
 
467
 
 
468
        /* digital I/O lines default to input on board reset. */
 
469
        pci20xxx_dio_config(dev, s);
 
470
 
 
471
        return 0;
 
472
}
 
473
 
 
474
static int pci20xxx_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
 
475
        struct comedi_insn * insn, unsigned int * data)
 
476
{
 
477
        int mask, bits;
 
478
 
 
479
        mask = 1 << CR_CHAN(insn->chanspec);
 
480
        if (mask & 0x000000ff) {
 
481
                bits = 0x000000ff;
 
482
        } else if (mask & 0x0000ff00) {
 
483
                bits = 0x0000ff00;
 
484
        } else if (mask & 0x00ff0000) {
 
485
                bits = 0x00ff0000;
 
486
        } else {
 
487
                bits = 0xff000000;
 
488
        }
 
489
        if (data[0]) {
 
490
                s->io_bits |= bits;
 
491
        } else {
 
492
                s->io_bits &= ~bits;
 
493
        }
 
494
        pci20xxx_dio_config(dev, s);
 
495
 
 
496
        return 1;
 
497
}
 
498
 
 
499
static int pci20xxx_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
 
500
        struct comedi_insn * insn, unsigned int * data)
 
501
{
 
502
        unsigned int mask = data[0];
 
503
 
 
504
        s->state &= ~mask;
 
505
        s->state |= (mask & data[1]);
 
506
 
 
507
        mask &= s->io_bits;
 
508
        if (mask & 0x000000ff)
 
509
                writeb((s->state >> 0) & 0xff,
 
510
                        devpriv->ioaddr + PCI20000_DIO_0);
 
511
        if (mask & 0x0000ff00)
 
512
                writeb((s->state >> 8) & 0xff,
 
513
                        devpriv->ioaddr + PCI20000_DIO_1);
 
514
        if (mask & 0x00ff0000)
 
515
                writeb((s->state >> 16) & 0xff,
 
516
                        devpriv->ioaddr + PCI20000_DIO_2);
 
517
        if (mask & 0xff000000)
 
518
                writeb((s->state >> 24) & 0xff,
 
519
                        devpriv->ioaddr + PCI20000_DIO_3);
 
520
 
 
521
        data[1] = readb(devpriv->ioaddr + PCI20000_DIO_0);
 
522
        data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
 
523
        data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
 
524
        data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
 
525
 
 
526
        return 2;
 
527
}
 
528
 
 
529
static void pci20xxx_dio_config(struct comedi_device * dev, struct comedi_subdevice * s)
 
530
{
 
531
        unsigned char control_01;
 
532
        unsigned char control_23;
 
533
        unsigned char buffer;
 
534
 
 
535
        control_01 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
 
536
        control_23 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
 
537
        buffer = readb(devpriv->ioaddr + PCI20000_DIO_BUFFER);
 
538
 
 
539
        if (s->io_bits & 0x000000ff) {
 
540
                /* output port 0 */
 
541
                control_01 &= PCI20000_DIO_EOC;
 
542
                buffer = (buffer & (~(DIO_BE << DIO_PS_0))) | (DIO_BO <<
 
543
                        DIO_PS_0);
 
544
        } else {
 
545
                /* input port 0 */
 
546
                control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_EIC;
 
547
                buffer = (buffer & (~(DIO_BI << DIO_PS_0)));
 
548
        }
 
549
        if (s->io_bits & 0x0000ff00) {
 
550
                /* output port 1 */
 
551
                control_01 &= PCI20000_DIO_OOC;
 
552
                buffer = (buffer & (~(DIO_BE << DIO_PS_1))) | (DIO_BO <<
 
553
                        DIO_PS_1);
 
554
        } else {
 
555
                /* input port 1 */
 
556
                control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_OIC;
 
557
                buffer = (buffer & (~(DIO_BI << DIO_PS_1)));
 
558
        }
 
559
        if (s->io_bits & 0x00ff0000) {
 
560
                /* output port 2 */
 
561
                control_23 &= PCI20000_DIO_EOC;
 
562
                buffer = (buffer & (~(DIO_BE << DIO_PS_2))) | (DIO_BO <<
 
563
                        DIO_PS_2);
 
564
        } else {
 
565
                /* input port 2 */
 
566
                control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_EIC;
 
567
                buffer = (buffer & (~(DIO_BI << DIO_PS_2)));
 
568
        }
 
569
        if (s->io_bits & 0xff000000) {
 
570
                /* output port 3 */
 
571
                control_23 &= PCI20000_DIO_OOC;
 
572
                buffer = (buffer & (~(DIO_BE << DIO_PS_3))) | (DIO_BO <<
 
573
                        DIO_PS_3);
 
574
        } else {
 
575
                /* input port 3 */
 
576
                control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_OIC;
 
577
                buffer = (buffer & (~(DIO_BI << DIO_PS_3)));
 
578
        }
 
579
        writeb(control_01, devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
 
580
        writeb(control_23, devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
 
581
        writeb(buffer, devpriv->ioaddr + PCI20000_DIO_BUFFER);
 
582
}
 
583
 
 
584
#if 0
 
585
static void pci20xxx_do(struct comedi_device * dev, struct comedi_subdevice * s)
 
586
{
 
587
        /* XXX if the channel is configured for input, does this
 
588
           do bad things? */
 
589
        /* XXX it would be a good idea to only update the registers
 
590
           that _need_ to be updated.  This requires changes to
 
591
           comedi, however. */
 
592
        writeb((s->state >> 0) & 0xff, devpriv->ioaddr + PCI20000_DIO_0);
 
593
        writeb((s->state >> 8) & 0xff, devpriv->ioaddr + PCI20000_DIO_1);
 
594
        writeb((s->state >> 16) & 0xff, devpriv->ioaddr + PCI20000_DIO_2);
 
595
        writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3);
 
596
}
 
597
 
 
598
static unsigned int pci20xxx_di(struct comedi_device * dev, struct comedi_subdevice * s)
 
599
{
 
600
        /* XXX same note as above */
 
601
        unsigned int bits;
 
602
 
 
603
        bits = readb(devpriv->ioaddr + PCI20000_DIO_0);
 
604
        bits |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
 
605
        bits |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
 
606
        bits |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
 
607
 
 
608
        return bits;
 
609
}
 
610
#endif
 
611
 
 
612
COMEDI_INITCLEANUP(driver_pci20xxx);