GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / cb_das16_cs.c
blobc02ad4566fd31b742e6f414f4fd58e8d070c4c31
1 /*
2 comedi/drivers/das16cs.c
3 Driver for Computer Boards PC-CARD DAS16/16.
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.org>
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.
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.
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.
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
34 #include <linux/interrupt.h>
35 #include <linux/slab.h>
36 #include "../comedidev.h"
37 #include <linux/delay.h>
38 #include <linux/pci.h>
40 #include <pcmcia/cs.h>
41 #include <pcmcia/cistpl.h>
42 #include <pcmcia/ds.h>
44 #include "8253.h"
46 #define DAS16CS_SIZE 18
48 #define DAS16CS_ADC_DATA 0
49 #define DAS16CS_DIO_MUX 2
50 #define DAS16CS_MISC1 4
51 #define DAS16CS_MISC2 6
52 #define DAS16CS_CTR0 8
53 #define DAS16CS_CTR1 10
54 #define DAS16CS_CTR2 12
55 #define DAS16CS_CTR_CONTROL 14
56 #define DAS16CS_DIO 16
58 struct das16cs_board {
59 const char *name;
60 int device_id;
61 int n_ao_chans;
63 static const struct das16cs_board das16cs_boards[] = {
65 .device_id = 0x0000, /* unknown */
66 .name = "PC-CARD DAS16/16",
67 .n_ao_chans = 0,
70 .device_id = 0x0039,
71 .name = "PC-CARD DAS16/16-AO",
72 .n_ao_chans = 2,
75 .device_id = 0x4009,
76 .name = "PCM-DAS16s/16",
77 .n_ao_chans = 0,
81 #define n_boards ARRAY_SIZE(das16cs_boards)
82 #define thisboard ((const struct das16cs_board *)dev->board_ptr)
84 struct das16cs_private {
85 struct pcmcia_device *link;
87 unsigned int ao_readback[2];
88 unsigned short status1;
89 unsigned short status2;
91 #define devpriv ((struct das16cs_private *)dev->private)
93 static int das16cs_attach(struct comedi_device *dev,
94 struct comedi_devconfig *it);
95 static int das16cs_detach(struct comedi_device *dev);
96 static struct comedi_driver driver_das16cs = {
97 .driver_name = "cb_das16_cs",
98 .module = THIS_MODULE,
99 .attach = das16cs_attach,
100 .detach = das16cs_detach,
103 static struct pcmcia_device *cur_dev = NULL;
105 static const struct comedi_lrange das16cs_ai_range = { 4, {
106 RANGE(-10, 10),
107 RANGE(-5, 5),
108 RANGE(-2.5, 2.5),
109 RANGE(-1.25, 1.25),
113 static irqreturn_t das16cs_interrupt(int irq, void *d);
114 static int das16cs_ai_rinsn(struct comedi_device *dev,
115 struct comedi_subdevice *s,
116 struct comedi_insn *insn, unsigned int *data);
117 static int das16cs_ai_cmd(struct comedi_device *dev,
118 struct comedi_subdevice *s);
119 static int das16cs_ai_cmdtest(struct comedi_device *dev,
120 struct comedi_subdevice *s,
121 struct comedi_cmd *cmd);
122 static int das16cs_ao_winsn(struct comedi_device *dev,
123 struct comedi_subdevice *s,
124 struct comedi_insn *insn, unsigned int *data);
125 static int das16cs_ao_rinsn(struct comedi_device *dev,
126 struct comedi_subdevice *s,
127 struct comedi_insn *insn, unsigned int *data);
128 static int das16cs_dio_insn_bits(struct comedi_device *dev,
129 struct comedi_subdevice *s,
130 struct comedi_insn *insn, unsigned int *data);
131 static int das16cs_dio_insn_config(struct comedi_device *dev,
132 struct comedi_subdevice *s,
133 struct comedi_insn *insn,
134 unsigned int *data);
135 static int das16cs_timer_insn_read(struct comedi_device *dev,
136 struct comedi_subdevice *s,
137 struct comedi_insn *insn,
138 unsigned int *data);
139 static int das16cs_timer_insn_config(struct comedi_device *dev,
140 struct comedi_subdevice *s,
141 struct comedi_insn *insn,
142 unsigned int *data);
144 static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
145 struct pcmcia_device *link)
147 int i;
149 for (i = 0; i < n_boards; i++) {
150 if (das16cs_boards[i].device_id == link->card_id)
151 return das16cs_boards + i;
154 printk("unknown board!\n");
156 return NULL;
159 static int das16cs_attach(struct comedi_device *dev,
160 struct comedi_devconfig *it)
162 struct pcmcia_device *link;
163 struct comedi_subdevice *s;
164 int ret;
165 int i;
167 printk("comedi%d: cb_das16_cs: ", dev->minor);
169 link = cur_dev;
170 if (!link)
171 return -EIO;
173 dev->iobase = link->resource[0]->start;;
174 printk("I/O base=0x%04lx ", dev->iobase);
176 printk("fingerprint:\n");
177 for (i = 0; i < 48; i += 2)
178 printk("%04x ", inw(dev->iobase + i));
180 printk("\n");
182 ret = request_irq(link->irq, das16cs_interrupt,
183 IRQF_SHARED, "cb_das16_cs", dev);
184 if (ret < 0)
185 return ret;
187 dev->irq = link->irq;
189 printk("irq=%u ", dev->irq);
191 dev->board_ptr = das16cs_probe(dev, link);
192 if (!dev->board_ptr)
193 return -EIO;
195 dev->board_name = thisboard->name;
197 if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
198 return -ENOMEM;
200 if (alloc_subdevices(dev, 4) < 0)
201 return -ENOMEM;
203 s = dev->subdevices + 0;
204 dev->read_subdev = s;
205 /* analog input subdevice */
206 s->type = COMEDI_SUBD_AI;
207 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
208 s->n_chan = 16;
209 s->maxdata = 0xffff;
210 s->range_table = &das16cs_ai_range;
211 s->len_chanlist = 16;
212 s->insn_read = das16cs_ai_rinsn;
213 s->do_cmd = das16cs_ai_cmd;
214 s->do_cmdtest = das16cs_ai_cmdtest;
216 s = dev->subdevices + 1;
217 /* analog output subdevice */
218 if (thisboard->n_ao_chans) {
219 s->type = COMEDI_SUBD_AO;
220 s->subdev_flags = SDF_WRITABLE;
221 s->n_chan = thisboard->n_ao_chans;
222 s->maxdata = 0xffff;
223 s->range_table = &range_bipolar10;
224 s->insn_write = &das16cs_ao_winsn;
225 s->insn_read = &das16cs_ao_rinsn;
228 s = dev->subdevices + 2;
229 /* digital i/o subdevice */
230 if (1) {
231 s->type = COMEDI_SUBD_DIO;
232 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
233 s->n_chan = 8;
234 s->maxdata = 1;
235 s->range_table = &range_digital;
236 s->insn_bits = das16cs_dio_insn_bits;
237 s->insn_config = das16cs_dio_insn_config;
238 } else {
239 s->type = COMEDI_SUBD_UNUSED;
242 s = dev->subdevices + 3;
243 /* timer subdevice */
244 if (0) {
245 s->type = COMEDI_SUBD_TIMER;
246 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
247 s->n_chan = 1;
248 s->maxdata = 0xff;
249 s->range_table = &range_unknown;
250 s->insn_read = das16cs_timer_insn_read;
251 s->insn_config = das16cs_timer_insn_config;
252 } else {
253 s->type = COMEDI_SUBD_UNUSED;
256 printk("attached\n");
258 return 1;
261 static int das16cs_detach(struct comedi_device *dev)
263 printk("comedi%d: das16cs: remove\n", dev->minor);
265 if (dev->irq)
266 free_irq(dev->irq, dev);
269 return 0;
272 static irqreturn_t das16cs_interrupt(int irq, void *d)
274 /* struct comedi_device *dev = d; */
275 return IRQ_HANDLED;
279 * "instructions" read/write data in "one-shot" or "software-triggered"
280 * mode.
282 static int das16cs_ai_rinsn(struct comedi_device *dev,
283 struct comedi_subdevice *s,
284 struct comedi_insn *insn, unsigned int *data)
286 int i;
287 int to;
288 int aref;
289 int range;
290 int chan;
291 static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
293 chan = CR_CHAN(insn->chanspec);
294 aref = CR_AREF(insn->chanspec);
295 range = CR_RANGE(insn->chanspec);
297 outw(chan, dev->iobase + 2);
299 devpriv->status1 &= ~0xf320;
300 devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
301 outw(devpriv->status1, dev->iobase + 4);
303 devpriv->status2 &= ~0xff00;
304 devpriv->status2 |= range_bits[range];
305 outw(devpriv->status2, dev->iobase + 6);
307 for (i = 0; i < insn->n; i++) {
308 outw(0, dev->iobase);
310 #define TIMEOUT 1000
311 for (to = 0; to < TIMEOUT; to++) {
312 if (inw(dev->iobase + 4) & 0x0080)
313 break;
315 if (to == TIMEOUT) {
316 printk("cb_das16_cs: ai timeout\n");
317 return -ETIME;
319 data[i] = (unsigned short)inw(dev->iobase + 0);
322 return i;
325 static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
327 return -EINVAL;
330 static int das16cs_ai_cmdtest(struct comedi_device *dev,
331 struct comedi_subdevice *s,
332 struct comedi_cmd *cmd)
334 int err = 0;
335 int tmp;
337 /* cmdtest tests a particular command to see if it is valid.
338 * Using the cmdtest ioctl, a user can create a valid cmd
339 * and then have it executes by the cmd ioctl.
341 * cmdtest returns 1,2,3,4 or 0, depending on which tests
342 * the command passes. */
344 /* step 1: make sure trigger sources are trivially valid */
346 tmp = cmd->start_src;
347 cmd->start_src &= TRIG_NOW;
348 if (!cmd->start_src || tmp != cmd->start_src)
349 err++;
351 tmp = cmd->scan_begin_src;
352 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
353 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
354 err++;
356 tmp = cmd->convert_src;
357 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
358 if (!cmd->convert_src || tmp != cmd->convert_src)
359 err++;
361 tmp = cmd->scan_end_src;
362 cmd->scan_end_src &= TRIG_COUNT;
363 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
364 err++;
366 tmp = cmd->stop_src;
367 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
368 if (!cmd->stop_src || tmp != cmd->stop_src)
369 err++;
371 if (err)
372 return 1;
374 /* step 2: make sure trigger sources are unique and mutually compatible */
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++;
385 if (err)
386 return 2;
388 /* step 3: make sure arguments are trivially compatible */
390 if (cmd->start_arg != 0) {
391 cmd->start_arg = 0;
392 err++;
394 #define MAX_SPEED 10000 /* in nanoseconds */
395 #define MIN_SPEED 1000000000 /* in nanoseconds */
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++;
402 if (cmd->scan_begin_arg > MIN_SPEED) {
403 cmd->scan_begin_arg = MIN_SPEED;
404 err++;
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++;
415 if (cmd->convert_src == TRIG_TIMER) {
416 if (cmd->convert_arg < MAX_SPEED) {
417 cmd->convert_arg = MAX_SPEED;
418 err++;
420 if (cmd->convert_arg > MIN_SPEED) {
421 cmd->convert_arg = MIN_SPEED;
422 err++;
424 } else {
425 /* external trigger */
426 /* see above */
427 if (cmd->convert_arg > 9) {
428 cmd->convert_arg = 9;
429 err++;
433 if (cmd->scan_end_arg != cmd->chanlist_len) {
434 cmd->scan_end_arg = cmd->chanlist_len;
435 err++;
437 if (cmd->stop_src == TRIG_COUNT) {
438 if (cmd->stop_arg > 0x00ffffff) {
439 cmd->stop_arg = 0x00ffffff;
440 err++;
442 } else {
443 /* TRIG_NONE */
444 if (cmd->stop_arg != 0) {
445 cmd->stop_arg = 0;
446 err++;
450 if (err)
451 return 3;
453 /* step 4: fix up any arguments */
455 if (cmd->scan_begin_src == TRIG_TIMER) {
456 unsigned int div1 = 0, div2 = 0;
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++;
465 if (cmd->convert_src == TRIG_TIMER) {
466 unsigned int div1 = 0, div2 = 0;
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++;
483 if (err)
484 return 4;
486 return 0;
489 static int das16cs_ao_winsn(struct comedi_device *dev,
490 struct comedi_subdevice *s,
491 struct comedi_insn *insn, unsigned int *data)
493 int i;
494 int chan = CR_CHAN(insn->chanspec);
495 unsigned short status1;
496 unsigned short d;
497 int bit;
499 for (i = 0; i < insn->n; i++) {
500 devpriv->ao_readback[chan] = data[i];
501 d = data[i];
503 outw(devpriv->status1, dev->iobase + 4);
504 udelay(1);
506 status1 = devpriv->status1 & ~0xf;
507 if (chan)
508 status1 |= 0x0001;
509 else
510 status1 |= 0x0008;
512 /* printk("0x%04x\n",status1);*/
513 outw(status1, dev->iobase + 4);
514 udelay(1);
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);
526 /* make high both DAC0CS and DAC1CS to load
527 new data and update analog output*/
528 outw(status1 | 0x9, dev->iobase + 4);
531 return i;
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)
540 int i;
541 int chan = CR_CHAN(insn->chanspec);
543 for (i = 0; i < insn->n; i++)
544 data[i] = devpriv->ao_readback[chan];
546 return i;
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)
558 if (insn->n != 2)
559 return -EINVAL;
561 if (data[0]) {
562 s->state &= ~data[0];
563 s->state |= data[0] & data[1];
565 outw(s->state, dev->iobase + 16);
568 /* on return, data[1] contains the value of the digital
569 * input and output lines. */
570 data[1] = inw(dev->iobase + 16);
572 return 2;
575 static int das16cs_dio_insn_config(struct comedi_device *dev,
576 struct comedi_subdevice *s,
577 struct comedi_insn *insn, unsigned int *data)
579 int chan = CR_CHAN(insn->chanspec);
580 int bits;
582 if (chan < 4)
583 bits = 0x0f;
584 else
585 bits = 0xf0;
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;
604 devpriv->status2 &= ~0x00c0;
605 devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
606 devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
608 outw(devpriv->status2, dev->iobase + 6);
610 return insn->n;
613 static int das16cs_timer_insn_read(struct comedi_device *dev,
614 struct comedi_subdevice *s,
615 struct comedi_insn *insn, unsigned int *data)
617 return -EINVAL;
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)
625 return -EINVAL;
628 /* PCMCIA stuff */
630 /*======================================================================
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.
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.
639 ======================================================================*/
641 #if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
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);
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.
654 static int das16cs_pcmcia_attach(struct pcmcia_device *);
655 static void das16cs_pcmcia_detach(struct pcmcia_device *);
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.
664 struct local_info_t {
665 struct pcmcia_device *link;
666 int stop;
667 struct bus_operations *bus;
670 /*======================================================================
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.
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.
680 ======================================================================*/
682 static int das16cs_pcmcia_attach(struct pcmcia_device *link)
684 struct local_info_t *local;
686 dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
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;
695 /* Initialize the pcmcia_device structure */
696 link->conf.Attributes = 0;
697 link->conf.IntType = INT_MEMORY_AND_IO;
699 cur_dev = link;
701 das16cs_pcmcia_config(link);
703 return 0;
704 } /* das16cs_pcmcia_attach */
706 static void das16cs_pcmcia_detach(struct pcmcia_device *link)
708 dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
710 ((struct local_info_t *)link->priv)->stop = 1;
711 das16cs_pcmcia_release(link);
712 /* This points to the parent struct local_info_t struct */
713 kfree(link->priv);
714 } /* das16cs_pcmcia_detach */
717 static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
718 cistpl_cftable_entry_t *cfg,
719 cistpl_cftable_entry_t *dflt,
720 unsigned int vcc,
721 void *priv_data)
723 if (cfg->index == 0)
724 return -EINVAL;
726 /* Do we need to allocate an interrupt? */
727 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
729 /* IO window settings */
730 p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
731 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
732 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
733 p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
734 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
735 p_dev->resource[0]->flags |=
736 pcmcia_io_cfg_data_width(io->flags);
737 p_dev->resource[0]->start = io->win[0].base;
738 p_dev->resource[0]->end = io->win[0].len;
739 if (io->nwin > 1) {
740 p_dev->resource[1]->flags = p_dev->resource[0]->flags;
741 p_dev->resource[1]->start = io->win[1].base;
742 p_dev->resource[1]->end = io->win[1].len;
744 /* This reserves IO space but doesn't actually enable it */
745 return pcmcia_request_io(p_dev);
748 return 0;
751 static void das16cs_pcmcia_config(struct pcmcia_device *link)
753 int ret;
755 dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
757 ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
758 if (ret) {
759 dev_warn(&link->dev, "no configuration found\n");
760 goto failed;
763 if (!link->irq)
764 goto failed;
767 This actually configures the PCMCIA socket -- setting up
768 the I/O windows and the interrupt mapping, and putting the
769 card and host interface into "Memory and IO" mode.
771 ret = pcmcia_request_configuration(link, &link->conf);
772 if (ret)
773 goto failed;
775 /* Finally, report what we've done */
776 dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
777 if (link->conf.Attributes & CONF_ENABLE_IRQ)
778 printk(", irq %u", link->irq);
779 if (link->resource[0])
780 printk(", io %pR", link->resource[0]);
781 if (link->resource[1])
782 printk(", io %pR", link->resource[1]);
783 printk("\n");
785 return;
787 failed:
788 das16cs_pcmcia_release(link);
789 } /* das16cs_pcmcia_config */
791 static void das16cs_pcmcia_release(struct pcmcia_device *link)
793 dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
794 pcmcia_disable_device(link);
795 } /* das16cs_pcmcia_release */
797 static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
799 struct local_info_t *local = link->priv;
801 /* Mark the device as stopped, to block IO until later */
802 local->stop = 1;
804 return 0;
805 } /* das16cs_pcmcia_suspend */
807 static int das16cs_pcmcia_resume(struct pcmcia_device *link)
809 struct local_info_t *local = link->priv;
811 local->stop = 0;
812 return 0;
813 } /* das16cs_pcmcia_resume */
815 /*====================================================================*/
817 static struct pcmcia_device_id das16cs_id_table[] = {
818 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
819 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
820 PCMCIA_DEVICE_NULL
823 MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
824 MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
825 MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
826 MODULE_LICENSE("GPL");
828 struct pcmcia_driver das16cs_driver = {
829 .probe = das16cs_pcmcia_attach,
830 .remove = das16cs_pcmcia_detach,
831 .suspend = das16cs_pcmcia_suspend,
832 .resume = das16cs_pcmcia_resume,
833 .id_table = das16cs_id_table,
834 .owner = THIS_MODULE,
835 .drv = {
836 .name = "cb_das16_cs",
840 static int __init init_das16cs_pcmcia_cs(void)
842 pcmcia_register_driver(&das16cs_driver);
843 return 0;
846 static void __exit exit_das16cs_pcmcia_cs(void)
848 pr_debug("das16cs_pcmcia_cs: unloading\n");
849 pcmcia_unregister_driver(&das16cs_driver);
852 int __init init_module(void)
854 int ret;
856 ret = init_das16cs_pcmcia_cs();
857 if (ret < 0)
858 return ret;
860 return comedi_driver_register(&driver_das16cs);
863 void __exit cleanup_module(void)
865 exit_das16cs_pcmcia_cs();
866 comedi_driver_unregister(&driver_das16cs);
869 #else
870 static int __init driver_das16cs_init_module(void)
872 return comedi_driver_register(&driver_das16cs);
875 static void __exit driver_das16cs_cleanup_module(void)
877 comedi_driver_unregister(&driver_das16cs);
880 module_init(driver_das16cs_init_module);
881 module_exit(driver_das16cs_cleanup_module);
882 #endif /* CONFIG_PCMCIA */