~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    comedi/drivers/das16cs.c
 
3
    Driver for Computer Boards PC-CARD DAS16/16.
 
4
 
 
5
    COMEDI - Linux Control and Measurement Device Interface
 
6
    Copyright (C) 2000, 2001, 2002 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: cb_das16_cs
 
25
Description: Computer Boards PC-CARD DAS16/16
 
26
Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
 
27
Author: ds
 
28
Updated: Mon, 04 Nov 2002 20:04:21 -0800
 
29
Status: experimental
 
30
 
 
31
 
 
32
*/
 
33
 
 
34
#include <linux/interrupt.h>
 
35
#include <linux/slab.h>
 
36
#include "../comedidev.h"
 
37
#include <linux/delay.h>
 
38
#include <linux/pci.h>
 
39
 
 
40
#include <pcmcia/cistpl.h>
 
41
#include <pcmcia/ds.h>
 
42
 
 
43
#include "8253.h"
 
44
 
 
45
#define DAS16CS_SIZE                    18
 
46
 
 
47
#define DAS16CS_ADC_DATA                0
 
48
#define DAS16CS_DIO_MUX                 2
 
49
#define DAS16CS_MISC1                   4
 
50
#define DAS16CS_MISC2                   6
 
51
#define DAS16CS_CTR0                    8
 
52
#define DAS16CS_CTR1                    10
 
53
#define DAS16CS_CTR2                    12
 
54
#define DAS16CS_CTR_CONTROL             14
 
55
#define DAS16CS_DIO                     16
 
56
 
 
57
struct das16cs_board {
 
58
        const char *name;
 
59
        int device_id;
 
60
        int n_ao_chans;
 
61
};
 
62
static const struct das16cs_board das16cs_boards[] = {
 
63
        {
 
64
         .device_id = 0x0000,   /* unknown */
 
65
         .name = "PC-CARD DAS16/16",
 
66
         .n_ao_chans = 0,
 
67
         },
 
68
        {
 
69
         .device_id = 0x0039,
 
70
         .name = "PC-CARD DAS16/16-AO",
 
71
         .n_ao_chans = 2,
 
72
         },
 
73
        {
 
74
         .device_id = 0x4009,
 
75
         .name = "PCM-DAS16s/16",
 
76
         .n_ao_chans = 0,
 
77
         },
 
78
};
 
79
 
 
80
#define n_boards ARRAY_SIZE(das16cs_boards)
 
81
#define thisboard ((const struct das16cs_board *)dev->board_ptr)
 
82
 
 
83
struct das16cs_private {
 
84
        struct pcmcia_device *link;
 
85
 
 
86
        unsigned int ao_readback[2];
 
87
        unsigned short status1;
 
88
        unsigned short status2;
 
89
};
 
90
#define devpriv ((struct das16cs_private *)dev->private)
 
91
 
 
92
static int das16cs_attach(struct comedi_device *dev,
 
93
                          struct comedi_devconfig *it);
 
94
static int das16cs_detach(struct comedi_device *dev);
 
95
static struct comedi_driver driver_das16cs = {
 
96
        .driver_name = "cb_das16_cs",
 
97
        .module = THIS_MODULE,
 
98
        .attach = das16cs_attach,
 
99
        .detach = das16cs_detach,
 
100
};
 
101
 
 
102
static struct pcmcia_device *cur_dev = NULL;
 
103
 
 
104
static const struct comedi_lrange das16cs_ai_range = { 4, {
 
105
                                                           RANGE(-10, 10),
 
106
                                                           RANGE(-5, 5),
 
107
                                                           RANGE(-2.5, 2.5),
 
108
                                                           RANGE(-1.25, 1.25),
 
109
                                                           }
 
110
};
 
111
 
 
112
static irqreturn_t das16cs_interrupt(int irq, void *d);
 
113
static int das16cs_ai_rinsn(struct comedi_device *dev,
 
114
                            struct comedi_subdevice *s,
 
115
                            struct comedi_insn *insn, unsigned int *data);
 
116
static int das16cs_ai_cmd(struct comedi_device *dev,
 
117
                          struct comedi_subdevice *s);
 
118
static int das16cs_ai_cmdtest(struct comedi_device *dev,
 
119
                              struct comedi_subdevice *s,
 
120
                              struct comedi_cmd *cmd);
 
121
static int das16cs_ao_winsn(struct comedi_device *dev,
 
122
                            struct comedi_subdevice *s,
 
123
                            struct comedi_insn *insn, unsigned int *data);
 
124
static int das16cs_ao_rinsn(struct comedi_device *dev,
 
125
                            struct comedi_subdevice *s,
 
126
                            struct comedi_insn *insn, unsigned int *data);
 
127
static int das16cs_dio_insn_bits(struct comedi_device *dev,
 
128
                                 struct comedi_subdevice *s,
 
129
                                 struct comedi_insn *insn, unsigned int *data);
 
130
static int das16cs_dio_insn_config(struct comedi_device *dev,
 
131
                                   struct comedi_subdevice *s,
 
132
                                   struct comedi_insn *insn,
 
133
                                   unsigned int *data);
 
134
static int das16cs_timer_insn_read(struct comedi_device *dev,
 
135
                                   struct comedi_subdevice *s,
 
136
                                   struct comedi_insn *insn,
 
137
                                   unsigned int *data);
 
138
static int das16cs_timer_insn_config(struct comedi_device *dev,
 
139
                                     struct comedi_subdevice *s,
 
140
                                     struct comedi_insn *insn,
 
141
                                     unsigned int *data);
 
142
 
 
143
static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
 
144
                                                 struct pcmcia_device *link)
 
145
{
 
146
        int i;
 
147
 
 
148
        for (i = 0; i < n_boards; i++) {
 
149
                if (das16cs_boards[i].device_id == link->card_id)
 
150
                        return das16cs_boards + i;
 
151
        }
 
152
 
 
153
        printk("unknown board!\n");
 
154
 
 
155
        return NULL;
 
156
}
 
157
 
 
158
static int das16cs_attach(struct comedi_device *dev,
 
159
                          struct comedi_devconfig *it)
 
160
{
 
161
        struct pcmcia_device *link;
 
162
        struct comedi_subdevice *s;
 
163
        int ret;
 
164
        int i;
 
165
 
 
166
        printk("comedi%d: cb_das16_cs: ", dev->minor);
 
167
 
 
168
        link = cur_dev;         /* XXX hack */
 
169
        if (!link)
 
170
                return -EIO;
 
171
 
 
172
        dev->iobase = link->resource[0]->start;
 
173
        printk("I/O base=0x%04lx ", dev->iobase);
 
174
 
 
175
        printk("fingerprint:\n");
 
176
        for (i = 0; i < 48; i += 2)
 
177
                printk("%04x ", inw(dev->iobase + i));
 
178
 
 
179
        printk("\n");
 
180
 
 
181
        ret = request_irq(link->irq, das16cs_interrupt,
 
182
                          IRQF_SHARED, "cb_das16_cs", dev);
 
183
        if (ret < 0)
 
184
                return ret;
 
185
 
 
186
        dev->irq = link->irq;
 
187
 
 
188
        printk("irq=%u ", dev->irq);
 
189
 
 
190
        dev->board_ptr = das16cs_probe(dev, link);
 
191
        if (!dev->board_ptr)
 
192
                return -EIO;
 
193
 
 
194
        dev->board_name = thisboard->name;
 
195
 
 
196
        if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
 
197
                return -ENOMEM;
 
198
 
 
199
        if (alloc_subdevices(dev, 4) < 0)
 
200
                return -ENOMEM;
 
201
 
 
202
        s = dev->subdevices + 0;
 
203
        dev->read_subdev = s;
 
204
        /* analog input subdevice */
 
205
        s->type = COMEDI_SUBD_AI;
 
206
        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
 
207
        s->n_chan = 16;
 
208
        s->maxdata = 0xffff;
 
209
        s->range_table = &das16cs_ai_range;
 
210
        s->len_chanlist = 16;
 
211
        s->insn_read = das16cs_ai_rinsn;
 
212
        s->do_cmd = das16cs_ai_cmd;
 
213
        s->do_cmdtest = das16cs_ai_cmdtest;
 
214
 
 
215
        s = dev->subdevices + 1;
 
216
        /* analog output subdevice */
 
217
        if (thisboard->n_ao_chans) {
 
218
                s->type = COMEDI_SUBD_AO;
 
219
                s->subdev_flags = SDF_WRITABLE;
 
220
                s->n_chan = thisboard->n_ao_chans;
 
221
                s->maxdata = 0xffff;
 
222
                s->range_table = &range_bipolar10;
 
223
                s->insn_write = &das16cs_ao_winsn;
 
224
                s->insn_read = &das16cs_ao_rinsn;
 
225
        }
 
226
 
 
227
        s = dev->subdevices + 2;
 
228
        /* digital i/o subdevice */
 
229
        if (1) {
 
230
                s->type = COMEDI_SUBD_DIO;
 
231
                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 
232
                s->n_chan = 8;
 
233
                s->maxdata = 1;
 
234
                s->range_table = &range_digital;
 
235
                s->insn_bits = das16cs_dio_insn_bits;
 
236
                s->insn_config = das16cs_dio_insn_config;
 
237
        } else {
 
238
                s->type = COMEDI_SUBD_UNUSED;
 
239
        }
 
240
 
 
241
        s = dev->subdevices + 3;
 
242
        /* timer subdevice */
 
243
        if (0) {
 
244
                s->type = COMEDI_SUBD_TIMER;
 
245
                s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 
246
                s->n_chan = 1;
 
247
                s->maxdata = 0xff;
 
248
                s->range_table = &range_unknown;
 
249
                s->insn_read = das16cs_timer_insn_read;
 
250
                s->insn_config = das16cs_timer_insn_config;
 
251
        } else {
 
252
                s->type = COMEDI_SUBD_UNUSED;
 
253
        }
 
254
 
 
255
        printk("attached\n");
 
256
 
 
257
        return 1;
 
258
}
 
259
 
 
260
static int das16cs_detach(struct comedi_device *dev)
 
261
{
 
262
        printk("comedi%d: das16cs: remove\n", dev->minor);
 
263
 
 
264
        if (dev->irq)
 
265
                free_irq(dev->irq, dev);
 
266
 
 
267
 
 
268
        return 0;
 
269
}
 
270
 
 
271
static irqreturn_t das16cs_interrupt(int irq, void *d)
 
272
{
 
273
        /* struct comedi_device *dev = d; */
 
274
        return IRQ_HANDLED;
 
275
}
 
276
 
 
277
/*
 
278
 * "instructions" read/write data in "one-shot" or "software-triggered"
 
279
 * mode.
 
280
 */
 
281
static int das16cs_ai_rinsn(struct comedi_device *dev,
 
282
                            struct comedi_subdevice *s,
 
283
                            struct comedi_insn *insn, unsigned int *data)
 
284
{
 
285
        int i;
 
286
        int to;
 
287
        int aref;
 
288
        int range;
 
289
        int chan;
 
290
        static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
 
291
 
 
292
        chan = CR_CHAN(insn->chanspec);
 
293
        aref = CR_AREF(insn->chanspec);
 
294
        range = CR_RANGE(insn->chanspec);
 
295
 
 
296
        outw(chan, dev->iobase + 2);
 
297
 
 
298
        devpriv->status1 &= ~0xf320;
 
299
        devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
 
300
        outw(devpriv->status1, dev->iobase + 4);
 
301
 
 
302
        devpriv->status2 &= ~0xff00;
 
303
        devpriv->status2 |= range_bits[range];
 
304
        outw(devpriv->status2, dev->iobase + 6);
 
305
 
 
306
        for (i = 0; i < insn->n; i++) {
 
307
                outw(0, dev->iobase);
 
308
 
 
309
#define TIMEOUT 1000
 
310
                for (to = 0; to < TIMEOUT; to++) {
 
311
                        if (inw(dev->iobase + 4) & 0x0080)
 
312
                                break;
 
313
                }
 
314
                if (to == TIMEOUT) {
 
315
                        printk("cb_das16_cs: ai timeout\n");
 
316
                        return -ETIME;
 
317
                }
 
318
                data[i] = (unsigned short)inw(dev->iobase + 0);
 
319
        }
 
320
 
 
321
        return i;
 
322
}
 
323
 
 
324
static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 
325
{
 
326
        return -EINVAL;
 
327
}
 
328
 
 
329
static int das16cs_ai_cmdtest(struct comedi_device *dev,
 
330
                              struct comedi_subdevice *s,
 
331
                              struct comedi_cmd *cmd)
 
332
{
 
333
        int err = 0;
 
334
        int tmp;
 
335
 
 
336
        /* cmdtest tests a particular command to see if it is valid.
 
337
         * Using the cmdtest ioctl, a user can create a valid cmd
 
338
         * and then have it executes by the cmd ioctl.
 
339
         *
 
340
         * cmdtest returns 1,2,3,4 or 0, depending on which tests
 
341
         * the command passes. */
 
342
 
 
343
        /* step 1: make sure trigger sources are trivially valid */
 
344
 
 
345
        tmp = cmd->start_src;
 
346
        cmd->start_src &= TRIG_NOW;
 
347
        if (!cmd->start_src || tmp != cmd->start_src)
 
348
                err++;
 
349
 
 
350
        tmp = cmd->scan_begin_src;
 
351
        cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
 
352
        if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
 
353
                err++;
 
354
 
 
355
        tmp = cmd->convert_src;
 
356
        cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
 
357
        if (!cmd->convert_src || tmp != cmd->convert_src)
 
358
                err++;
 
359
 
 
360
        tmp = cmd->scan_end_src;
 
361
        cmd->scan_end_src &= TRIG_COUNT;
 
362
        if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
 
363
                err++;
 
364
 
 
365
        tmp = cmd->stop_src;
 
366
        cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
 
367
        if (!cmd->stop_src || tmp != cmd->stop_src)
 
368
                err++;
 
369
 
 
370
        if (err)
 
371
                return 1;
 
372
 
 
373
        /* step 2: make sure trigger sources are unique and
 
374
         * mutually compatible */
 
375
 
 
376
        /* note that mutual compatibility is not an issue here */
 
377
        if (cmd->scan_begin_src != TRIG_TIMER &&
 
378
            cmd->scan_begin_src != TRIG_EXT)
 
379
                err++;
 
380
        if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
 
381
                err++;
 
382
        if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
 
383
                err++;
 
384
 
 
385
        if (err)
 
386
                return 2;
 
387
 
 
388
        /* step 3: make sure arguments are trivially compatible */
 
389
 
 
390
        if (cmd->start_arg != 0) {
 
391
                cmd->start_arg = 0;
 
392
                err++;
 
393
        }
 
394
#define MAX_SPEED       10000   /* in nanoseconds */
 
395
#define MIN_SPEED       1000000000      /* in nanoseconds */
 
396
 
 
397
        if (cmd->scan_begin_src == TRIG_TIMER) {
 
398
                if (cmd->scan_begin_arg < MAX_SPEED) {
 
399
                        cmd->scan_begin_arg = MAX_SPEED;
 
400
                        err++;
 
401
                }
 
402
                if (cmd->scan_begin_arg > MIN_SPEED) {
 
403
                        cmd->scan_begin_arg = MIN_SPEED;
 
404
                        err++;
 
405
                }
 
406
        } else {
 
407
                /* external trigger */
 
408
                /* should be level/edge, hi/lo specification here */
 
409
                /* should specify multiple external triggers */
 
410
                if (cmd->scan_begin_arg > 9) {
 
411
                        cmd->scan_begin_arg = 9;
 
412
                        err++;
 
413
                }
 
414
        }
 
415
        if (cmd->convert_src == TRIG_TIMER) {
 
416
                if (cmd->convert_arg < MAX_SPEED) {
 
417
                        cmd->convert_arg = MAX_SPEED;
 
418
                        err++;
 
419
                }
 
420
                if (cmd->convert_arg > MIN_SPEED) {
 
421
                        cmd->convert_arg = MIN_SPEED;
 
422
                        err++;
 
423
                }
 
424
        } else {
 
425
                /* external trigger */
 
426
                /* see above */
 
427
                if (cmd->convert_arg > 9) {
 
428
                        cmd->convert_arg = 9;
 
429
                        err++;
 
430
                }
 
431
        }
 
432
 
 
433
        if (cmd->scan_end_arg != cmd->chanlist_len) {
 
434
                cmd->scan_end_arg = cmd->chanlist_len;
 
435
                err++;
 
436
        }
 
437
        if (cmd->stop_src == TRIG_COUNT) {
 
438
                if (cmd->stop_arg > 0x00ffffff) {
 
439
                        cmd->stop_arg = 0x00ffffff;
 
440
                        err++;
 
441
                }
 
442
        } else {
 
443
                /* TRIG_NONE */
 
444
                if (cmd->stop_arg != 0) {
 
445
                        cmd->stop_arg = 0;
 
446
                        err++;
 
447
                }
 
448
        }
 
449
 
 
450
        if (err)
 
451
                return 3;
 
452
 
 
453
        /* step 4: fix up any arguments */
 
454
 
 
455
        if (cmd->scan_begin_src == TRIG_TIMER) {
 
456
                unsigned int div1 = 0, div2 = 0;
 
457
 
 
458
                tmp = cmd->scan_begin_arg;
 
459
                i8253_cascade_ns_to_timer(100, &div1, &div2,
 
460
                                          &cmd->scan_begin_arg,
 
461
                                          cmd->flags & TRIG_ROUND_MASK);
 
462
                if (tmp != cmd->scan_begin_arg)
 
463
                        err++;
 
464
        }
 
465
        if (cmd->convert_src == TRIG_TIMER) {
 
466
                unsigned int div1 = 0, div2 = 0;
 
467
 
 
468
                tmp = cmd->convert_arg;
 
469
                i8253_cascade_ns_to_timer(100, &div1, &div2,
 
470
                                          &cmd->scan_begin_arg,
 
471
                                          cmd->flags & TRIG_ROUND_MASK);
 
472
                if (tmp != cmd->convert_arg)
 
473
                        err++;
 
474
                if (cmd->scan_begin_src == TRIG_TIMER &&
 
475
                    cmd->scan_begin_arg <
 
476
                    cmd->convert_arg * cmd->scan_end_arg) {
 
477
                        cmd->scan_begin_arg =
 
478
                            cmd->convert_arg * cmd->scan_end_arg;
 
479
                        err++;
 
480
                }
 
481
        }
 
482
 
 
483
        if (err)
 
484
                return 4;
 
485
 
 
486
        return 0;
 
487
}
 
488
 
 
489
static int das16cs_ao_winsn(struct comedi_device *dev,
 
490
                            struct comedi_subdevice *s,
 
491
                            struct comedi_insn *insn, unsigned int *data)
 
492
{
 
493
        int i;
 
494
        int chan = CR_CHAN(insn->chanspec);
 
495
        unsigned short status1;
 
496
        unsigned short d;
 
497
        int bit;
 
498
 
 
499
        for (i = 0; i < insn->n; i++) {
 
500
                devpriv->ao_readback[chan] = data[i];
 
501
                d = data[i];
 
502
 
 
503
                outw(devpriv->status1, dev->iobase + 4);
 
504
                udelay(1);
 
505
 
 
506
                status1 = devpriv->status1 & ~0xf;
 
507
                if (chan)
 
508
                        status1 |= 0x0001;
 
509
                else
 
510
                        status1 |= 0x0008;
 
511
 
 
512
/*              printk("0x%04x\n",status1);*/
 
513
                outw(status1, dev->iobase + 4);
 
514
                udelay(1);
 
515
 
 
516
                for (bit = 15; bit >= 0; bit--) {
 
517
                        int b = (d >> bit) & 0x1;
 
518
                        b <<= 1;
 
519
/*                      printk("0x%04x\n",status1 | b | 0x0000);*/
 
520
                        outw(status1 | b | 0x0000, dev->iobase + 4);
 
521
                        udelay(1);
 
522
/*                      printk("0x%04x\n",status1 | b | 0x0004);*/
 
523
                        outw(status1 | b | 0x0004, dev->iobase + 4);
 
524
                        udelay(1);
 
525
                }
 
526
/*              make high both DAC0CS and DAC1CS to load
 
527
                new data and update analog output*/
 
528
                outw(status1 | 0x9, dev->iobase + 4);
 
529
        }
 
530
 
 
531
        return i;
 
532
}
 
533
 
 
534
/* AO subdevices should have a read insn as well as a write insn.
 
535
 * Usually this means copying a value stored in devpriv. */
 
536
static int das16cs_ao_rinsn(struct comedi_device *dev,
 
537
                            struct comedi_subdevice *s,
 
538
                            struct comedi_insn *insn, unsigned int *data)
 
539
{
 
540
        int i;
 
541
        int chan = CR_CHAN(insn->chanspec);
 
542
 
 
543
        for (i = 0; i < insn->n; i++)
 
544
                data[i] = devpriv->ao_readback[chan];
 
545
 
 
546
        return i;
 
547
}
 
548
 
 
549
/* DIO devices are slightly special.  Although it is possible to
 
550
 * implement the insn_read/insn_write interface, it is much more
 
551
 * useful to applications if you implement the insn_bits interface.
 
552
 * This allows packed reading/writing of the DIO channels.  The
 
553
 * comedi core can convert between insn_bits and insn_read/write */
 
554
static int das16cs_dio_insn_bits(struct comedi_device *dev,
 
555
                                 struct comedi_subdevice *s,
 
556
                                 struct comedi_insn *insn, unsigned int *data)
 
557
{
 
558
        if (insn->n != 2)
 
559
                return -EINVAL;
 
560
 
 
561
        if (data[0]) {
 
562
                s->state &= ~data[0];
 
563
                s->state |= data[0] & data[1];
 
564
 
 
565
                outw(s->state, dev->iobase + 16);
 
566
        }
 
567
 
 
568
        /* on return, data[1] contains the value of the digital
 
569
         * input and output lines. */
 
570
        data[1] = inw(dev->iobase + 16);
 
571
 
 
572
        return 2;
 
573
}
 
574
 
 
575
static int das16cs_dio_insn_config(struct comedi_device *dev,
 
576
                                   struct comedi_subdevice *s,
 
577
                                   struct comedi_insn *insn, unsigned int *data)
 
578
{
 
579
        int chan = CR_CHAN(insn->chanspec);
 
580
        int bits;
 
581
 
 
582
        if (chan < 4)
 
583
                bits = 0x0f;
 
584
        else
 
585
                bits = 0xf0;
 
586
 
 
587
        switch (data[0]) {
 
588
        case INSN_CONFIG_DIO_OUTPUT:
 
589
                s->io_bits |= bits;
 
590
                break;
 
591
        case INSN_CONFIG_DIO_INPUT:
 
592
                s->io_bits &= bits;
 
593
                break;
 
594
        case INSN_CONFIG_DIO_QUERY:
 
595
                data[1] =
 
596
                    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
 
597
                return insn->n;
 
598
                break;
 
599
        default:
 
600
                return -EINVAL;
 
601
                break;
 
602
        }
 
603
 
 
604
        devpriv->status2 &= ~0x00c0;
 
605
        devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
 
606
        devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
 
607
 
 
608
        outw(devpriv->status2, dev->iobase + 6);
 
609
 
 
610
        return insn->n;
 
611
}
 
612
 
 
613
static int das16cs_timer_insn_read(struct comedi_device *dev,
 
614
                                   struct comedi_subdevice *s,
 
615
                                   struct comedi_insn *insn, unsigned int *data)
 
616
{
 
617
        return -EINVAL;
 
618
}
 
619
 
 
620
static int das16cs_timer_insn_config(struct comedi_device *dev,
 
621
                                     struct comedi_subdevice *s,
 
622
                                     struct comedi_insn *insn,
 
623
                                     unsigned int *data)
 
624
{
 
625
        return -EINVAL;
 
626
}
 
627
 
 
628
/* PCMCIA stuff */
 
629
 
 
630
/*======================================================================
 
631
 
 
632
    The following pcmcia code for the pcm-das08 is adapted from the
 
633
    dummy_cs.c driver of the Linux PCMCIA Card Services package.
 
634
 
 
635
    The initial developer of the original code is David A. Hinds
 
636
    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 
637
    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
638
 
 
639
======================================================================*/
 
640
 
 
641
#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
 
642
 
 
643
static void das16cs_pcmcia_config(struct pcmcia_device *link);
 
644
static void das16cs_pcmcia_release(struct pcmcia_device *link);
 
645
static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
 
646
static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev);
 
647
 
 
648
/*
 
649
   The attach() and detach() entry points are used to create and destroy
 
650
   "instances" of the driver, where each instance represents everything
 
651
   needed to manage one actual PCMCIA card.
 
652
*/
 
653
 
 
654
static int das16cs_pcmcia_attach(struct pcmcia_device *);
 
655
static void das16cs_pcmcia_detach(struct pcmcia_device *);
 
656
 
 
657
/*
 
658
   You'll also need to prototype all the functions that will actually
 
659
   be used to talk to your device.  See 'memory_cs' for a good example
 
660
   of a fully self-sufficient driver; the other drivers rely more or
 
661
   less on other parts of the kernel.
 
662
*/
 
663
 
 
664
struct local_info_t {
 
665
        struct pcmcia_device *link;
 
666
        int stop;
 
667
        struct bus_operations *bus;
 
668
};
 
669
 
 
670
/*======================================================================
 
671
 
 
672
    das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
 
673
    local data structures for one device.  The device is registered
 
674
    with Card Services.
 
675
 
 
676
    The dev_link structure is initialized, but we don't actually
 
677
    configure the card at this point -- we wait until we receive a
 
678
    card insertion event.
 
679
 
 
680
======================================================================*/
 
681
 
 
682
static int das16cs_pcmcia_attach(struct pcmcia_device *link)
 
683
{
 
684
        struct local_info_t *local;
 
685
 
 
686
        dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
 
687
 
 
688
        /* Allocate space for private device-specific data */
 
689
        local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
 
690
        if (!local)
 
691
                return -ENOMEM;
 
692
        local->link = link;
 
693
        link->priv = local;
 
694
 
 
695
        cur_dev = link;
 
696
 
 
697
        das16cs_pcmcia_config(link);
 
698
 
 
699
        return 0;
 
700
}                               /* das16cs_pcmcia_attach */
 
701
 
 
702
static void das16cs_pcmcia_detach(struct pcmcia_device *link)
 
703
{
 
704
        dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
 
705
 
 
706
        ((struct local_info_t *)link->priv)->stop = 1;
 
707
        das16cs_pcmcia_release(link);
 
708
        /* This points to the parent struct local_info_t struct */
 
709
        kfree(link->priv);
 
710
}                               /* das16cs_pcmcia_detach */
 
711
 
 
712
 
 
713
static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
 
714
                                void *priv_data)
 
715
{
 
716
        if (p_dev->config_index == 0)
 
717
                return -EINVAL;
 
718
 
 
719
        return pcmcia_request_io(p_dev);
 
720
}
 
721
 
 
722
static void das16cs_pcmcia_config(struct pcmcia_device *link)
 
723
{
 
724
        int ret;
 
725
 
 
726
        dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
 
727
 
 
728
        /* Do we need to allocate an interrupt? */
 
729
        link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
730
 
 
731
        ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
 
732
        if (ret) {
 
733
                dev_warn(&link->dev, "no configuration found\n");
 
734
                goto failed;
 
735
        }
 
736
 
 
737
        if (!link->irq)
 
738
                goto failed;
 
739
 
 
740
        ret = pcmcia_enable_device(link);
 
741
        if (ret)
 
742
                goto failed;
 
743
 
 
744
        return;
 
745
 
 
746
failed:
 
747
        das16cs_pcmcia_release(link);
 
748
}                               /* das16cs_pcmcia_config */
 
749
 
 
750
static void das16cs_pcmcia_release(struct pcmcia_device *link)
 
751
{
 
752
        dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
 
753
        pcmcia_disable_device(link);
 
754
}                               /* das16cs_pcmcia_release */
 
755
 
 
756
static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
 
757
{
 
758
        struct local_info_t *local = link->priv;
 
759
 
 
760
        /* Mark the device as stopped, to block IO until later */
 
761
        local->stop = 1;
 
762
 
 
763
        return 0;
 
764
}                               /* das16cs_pcmcia_suspend */
 
765
 
 
766
static int das16cs_pcmcia_resume(struct pcmcia_device *link)
 
767
{
 
768
        struct local_info_t *local = link->priv;
 
769
 
 
770
        local->stop = 0;
 
771
        return 0;
 
772
}                               /* das16cs_pcmcia_resume */
 
773
 
 
774
/*====================================================================*/
 
775
 
 
776
static const struct pcmcia_device_id das16cs_id_table[] = {
 
777
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
 
778
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
 
779
        PCMCIA_DEVICE_NULL
 
780
};
 
781
 
 
782
MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
 
783
MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
 
784
MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
 
785
MODULE_LICENSE("GPL");
 
786
 
 
787
struct pcmcia_driver das16cs_driver = {
 
788
        .probe = das16cs_pcmcia_attach,
 
789
        .remove = das16cs_pcmcia_detach,
 
790
        .suspend = das16cs_pcmcia_suspend,
 
791
        .resume = das16cs_pcmcia_resume,
 
792
        .id_table = das16cs_id_table,
 
793
        .owner = THIS_MODULE,
 
794
        .name = "cb_das16_cs",
 
795
};
 
796
 
 
797
static int __init init_das16cs_pcmcia_cs(void)
 
798
{
 
799
        pcmcia_register_driver(&das16cs_driver);
 
800
        return 0;
 
801
}
 
802
 
 
803
static void __exit exit_das16cs_pcmcia_cs(void)
 
804
{
 
805
        pr_debug("das16cs_pcmcia_cs: unloading\n");
 
806
        pcmcia_unregister_driver(&das16cs_driver);
 
807
}
 
808
 
 
809
int __init init_module(void)
 
810
{
 
811
        int ret;
 
812
 
 
813
        ret = init_das16cs_pcmcia_cs();
 
814
        if (ret < 0)
 
815
                return ret;
 
816
 
 
817
        return comedi_driver_register(&driver_das16cs);
 
818
}
 
819
 
 
820
void __exit cleanup_module(void)
 
821
{
 
822
        exit_das16cs_pcmcia_cs();
 
823
        comedi_driver_unregister(&driver_das16cs);
 
824
}
 
825
 
 
826
#else
 
827
static int __init driver_das16cs_init_module(void)
 
828
{
 
829
        return comedi_driver_register(&driver_das16cs);
 
830
}
 
831
 
 
832
static void __exit driver_das16cs_cleanup_module(void)
 
833
{
 
834
        comedi_driver_unregister(&driver_das16cs);
 
835
}
 
836
 
 
837
module_init(driver_das16cs_init_module);
 
838
module_exit(driver_das16cs_cleanup_module);
 
839
#endif /* CONFIG_PCMCIA */