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.
25 Description: Computer Boards PC-CARD DAS16/16
26 Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
28 Updated: Mon, 04 Nov 2002 20:04:21 -0800
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_types.h>
41 #include <pcmcia/cs.h>
42 #include <pcmcia/cistpl.h>
43 #include <pcmcia/ds.h>
47 #define DAS16CS_SIZE 18
49 #define DAS16CS_ADC_DATA 0
50 #define DAS16CS_DIO_MUX 2
51 #define DAS16CS_MISC1 4
52 #define DAS16CS_MISC2 6
53 #define DAS16CS_CTR0 8
54 #define DAS16CS_CTR1 10
55 #define DAS16CS_CTR2 12
56 #define DAS16CS_CTR_CONTROL 14
57 #define DAS16CS_DIO 16
59 struct das16cs_board {
64 static const struct das16cs_board das16cs_boards[] = {
66 .device_id = 0x0000, /* unknown */
67 .name = "PC-CARD DAS16/16",
72 .name = "PC-CARD DAS16/16-AO",
77 .name = "PCM-DAS16s/16",
82 #define n_boards ARRAY_SIZE(das16cs_boards)
83 #define thisboard ((const struct das16cs_board *)dev->board_ptr)
85 struct das16cs_private {
86 struct pcmcia_device *link;
88 unsigned int ao_readback[2];
89 unsigned short status1;
90 unsigned short status2;
92 #define devpriv ((struct das16cs_private *)dev->private)
94 static int das16cs_attach(struct comedi_device *dev,
95 struct comedi_devconfig *it);
96 static int das16cs_detach(struct comedi_device *dev);
97 static struct comedi_driver driver_das16cs = {
98 .driver_name = "cb_das16_cs",
99 .module = THIS_MODULE,
100 .attach = das16cs_attach,
101 .detach = das16cs_detach,
104 static struct pcmcia_device *cur_dev = NULL;
106 static const struct comedi_lrange das16cs_ai_range = { 4, {
114 static irqreturn_t das16cs_interrupt(int irq, void *d);
115 static int das16cs_ai_rinsn(struct comedi_device *dev,
116 struct comedi_subdevice *s,
117 struct comedi_insn *insn, unsigned int *data);
118 static int das16cs_ai_cmd(struct comedi_device *dev,
119 struct comedi_subdevice *s);
120 static int das16cs_ai_cmdtest(struct comedi_device *dev,
121 struct comedi_subdevice *s,
122 struct comedi_cmd *cmd);
123 static int das16cs_ao_winsn(struct comedi_device *dev,
124 struct comedi_subdevice *s,
125 struct comedi_insn *insn, unsigned int *data);
126 static int das16cs_ao_rinsn(struct comedi_device *dev,
127 struct comedi_subdevice *s,
128 struct comedi_insn *insn, unsigned int *data);
129 static int das16cs_dio_insn_bits(struct comedi_device *dev,
130 struct comedi_subdevice *s,
131 struct comedi_insn *insn, unsigned int *data);
132 static int das16cs_dio_insn_config(struct comedi_device *dev,
133 struct comedi_subdevice *s,
134 struct comedi_insn *insn,
136 static int das16cs_timer_insn_read(struct comedi_device *dev,
137 struct comedi_subdevice *s,
138 struct comedi_insn *insn,
140 static int das16cs_timer_insn_config(struct comedi_device *dev,
141 struct comedi_subdevice *s,
142 struct comedi_insn *insn,
145 static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
146 struct pcmcia_device *link)
150 for (i = 0; i < n_boards; i++) {
151 if (das16cs_boards[i].device_id == link->card_id)
152 return das16cs_boards + i;
155 printk("unknown board!\n");
160 static int das16cs_attach(struct comedi_device *dev,
161 struct comedi_devconfig *it)
163 struct pcmcia_device *link;
164 struct comedi_subdevice *s;
168 printk("comedi%d: cb_das16_cs: ", dev->minor);
170 link = cur_dev; /* XXX hack */
174 dev->iobase = link->io.BasePort1;
175 printk("I/O base=0x%04lx ", dev->iobase);
177 printk("fingerprint:\n");
178 for (i = 0; i < 48; i += 2)
179 printk("%04x ", inw(dev->iobase + i));
183 ret = request_irq(link->irq.AssignedIRQ, das16cs_interrupt,
184 IRQF_SHARED, "cb_das16_cs", dev);
188 dev->irq = link->irq.AssignedIRQ;
189 printk("irq=%u ", dev->irq);
191 dev->board_ptr = das16cs_probe(dev, link);
195 dev->board_name = thisboard->name;
197 if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
200 if (alloc_subdevices(dev, 4) < 0)
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;
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;
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 */
231 s->type = COMEDI_SUBD_DIO;
232 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
235 s->range_table = &range_digital;
236 s->insn_bits = das16cs_dio_insn_bits;
237 s->insn_config = das16cs_dio_insn_config;
239 s->type = COMEDI_SUBD_UNUSED;
242 s = dev->subdevices + 3;
243 /* timer subdevice */
245 s->type = COMEDI_SUBD_TIMER;
246 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
249 s->range_table = &range_unknown;
250 s->insn_read = das16cs_timer_insn_read;
251 s->insn_config = das16cs_timer_insn_config;
253 s->type = COMEDI_SUBD_UNUSED;
256 printk("attached\n");
261 static int das16cs_detach(struct comedi_device *dev)
263 printk("comedi%d: das16cs: remove\n", dev->minor);
266 free_irq(dev->irq, dev);
272 static irqreturn_t das16cs_interrupt(int irq, void *d)
274 /* struct comedi_device *dev = d; */
279 * "instructions" read/write data in "one-shot" or "software-triggered"
282 static int das16cs_ai_rinsn(struct comedi_device *dev,
283 struct comedi_subdevice *s,
284 struct comedi_insn *insn, unsigned int *data)
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);
311 for (to = 0; to < TIMEOUT; to++) {
312 if (inw(dev->iobase + 4) & 0x0080)
316 printk("cb_das16_cs: ai timeout\n");
319 data[i] = (unsigned short)inw(dev->iobase + 0);
325 static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
330 static int das16cs_ai_cmdtest(struct comedi_device *dev,
331 struct comedi_subdevice *s,
332 struct comedi_cmd *cmd)
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)
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)
356 tmp = cmd->convert_src;
357 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
358 if (!cmd->convert_src || tmp != cmd->convert_src)
361 tmp = cmd->scan_end_src;
362 cmd->scan_end_src &= TRIG_COUNT;
363 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
367 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
368 if (!cmd->stop_src || tmp != cmd->stop_src)
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)
380 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
382 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
388 /* step 3: make sure arguments are trivially compatible */
390 if (cmd->start_arg != 0) {
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;
402 if (cmd->scan_begin_arg > MIN_SPEED) {
403 cmd->scan_begin_arg = MIN_SPEED;
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;
415 if (cmd->convert_src == TRIG_TIMER) {
416 if (cmd->convert_arg < MAX_SPEED) {
417 cmd->convert_arg = MAX_SPEED;
420 if (cmd->convert_arg > MIN_SPEED) {
421 cmd->convert_arg = MIN_SPEED;
425 /* external trigger */
427 if (cmd->convert_arg > 9) {
428 cmd->convert_arg = 9;
433 if (cmd->scan_end_arg != cmd->chanlist_len) {
434 cmd->scan_end_arg = cmd->chanlist_len;
437 if (cmd->stop_src == TRIG_COUNT) {
438 if (cmd->stop_arg > 0x00ffffff) {
439 cmd->stop_arg = 0x00ffffff;
444 if (cmd->stop_arg != 0) {
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)
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)
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;
489 static int das16cs_ao_winsn(struct comedi_device *dev,
490 struct comedi_subdevice *s,
491 struct comedi_insn *insn, unsigned int *data)
494 int chan = CR_CHAN(insn->chanspec);
495 unsigned short status1;
499 for (i = 0; i < insn->n; i++) {
500 devpriv->ao_readback[chan] = data[i];
503 outw(devpriv->status1, dev->iobase + 4);
506 status1 = devpriv->status1 & ~0xf;
512 /* printk("0x%04x\n",status1);*/
513 outw(status1, dev->iobase + 4);
516 for (bit = 15; bit >= 0; bit--) {
517 int b = (d >> bit) & 0x1;
519 /* printk("0x%04x\n",status1 | b | 0x0000);*/
520 outw(status1 | b | 0x0000, dev->iobase + 4);
522 /* printk("0x%04x\n",status1 | b | 0x0004);*/
523 outw(status1 | b | 0x0004, dev->iobase + 4);
526 /* make high both DAC0CS and DAC1CS to load
527 new data and update analog output*/
528 outw(status1 | 0x9, dev->iobase + 4);
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)
541 int chan = CR_CHAN(insn->chanspec);
543 for (i = 0; i < insn->n; i++)
544 data[i] = devpriv->ao_readback[chan];
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)
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);
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);
588 case INSN_CONFIG_DIO_OUTPUT:
591 case INSN_CONFIG_DIO_INPUT:
594 case INSN_CONFIG_DIO_QUERY:
596 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
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);
613 static int das16cs_timer_insn_read(struct comedi_device *dev,
614 struct comedi_subdevice *s,
615 struct comedi_insn *insn, unsigned int *data)
620 static int das16cs_timer_insn_config(struct comedi_device *dev,
621 struct comedi_subdevice *s,
622 struct comedi_insn *insn,
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.
665 The dev_info variable is the "key" that is used to match up this
666 device driver with appropriate cards, through the card configuration
670 static dev_info_t dev_info = "cb_das16_cs";
672 struct local_info_t {
673 struct pcmcia_device *link;
676 struct bus_operations *bus;
679 /*======================================================================
681 das16cs_pcmcia_attach() creates an "instance" of the driver, allocating
682 local data structures for one device. The device is registered
685 The dev_link structure is initialized, but we don't actually
686 configure the card at this point -- we wait until we receive a
687 card insertion event.
689 ======================================================================*/
691 static int das16cs_pcmcia_attach(struct pcmcia_device *link)
693 struct local_info_t *local;
695 dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n");
697 /* Allocate space for private device-specific data */
698 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
704 /* Initialize the pcmcia_device structure */
705 /* Interrupt setup */
706 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
707 link->irq.Handler = NULL;
709 link->conf.Attributes = 0;
710 link->conf.IntType = INT_MEMORY_AND_IO;
714 das16cs_pcmcia_config(link);
717 } /* das16cs_pcmcia_attach */
719 static void das16cs_pcmcia_detach(struct pcmcia_device *link)
721 dev_dbg(&link->dev, "das16cs_pcmcia_detach\n");
723 if (link->dev_node) {
724 ((struct local_info_t *)link->priv)->stop = 1;
725 das16cs_pcmcia_release(link);
727 /* This points to the parent struct local_info_t struct */
730 } /* das16cs_pcmcia_detach */
733 static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
734 cistpl_cftable_entry_t *cfg,
735 cistpl_cftable_entry_t *dflt,
742 /* Do we need to allocate an interrupt? */
743 if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1)
744 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
746 /* IO window settings */
747 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
748 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
749 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
750 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
751 if (!(io->flags & CISTPL_IO_8BIT))
752 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
753 if (!(io->flags & CISTPL_IO_16BIT))
754 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
755 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
756 p_dev->io.BasePort1 = io->win[0].base;
757 p_dev->io.NumPorts1 = io->win[0].len;
759 p_dev->io.Attributes2 = p_dev->io.Attributes1;
760 p_dev->io.BasePort2 = io->win[1].base;
761 p_dev->io.NumPorts2 = io->win[1].len;
763 /* This reserves IO space but doesn't actually enable it */
764 return pcmcia_request_io(p_dev, &p_dev->io);
770 static void das16cs_pcmcia_config(struct pcmcia_device *link)
772 struct local_info_t *dev = link->priv;
775 dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
777 ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
779 dev_warn(&link->dev, "no configuration found\n");
784 Allocate an interrupt line. Note that this does not assign a
785 handler to the interrupt, unless the 'Handler' member of the
786 irq structure is initialized.
788 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
789 ret = pcmcia_request_irq(link, &link->irq);
794 This actually configures the PCMCIA socket -- setting up
795 the I/O windows and the interrupt mapping, and putting the
796 card and host interface into "Memory and IO" mode.
798 ret = pcmcia_request_configuration(link, &link->conf);
803 At this point, the dev_node_t structure(s) need to be
804 initialized and arranged in a linked list at link->dev.
806 sprintf(dev->node.dev_name, "cb_das16_cs");
807 dev->node.major = dev->node.minor = 0;
808 link->dev_node = &dev->node;
810 /* Finally, report what we've done */
811 printk(KERN_INFO "%s: index 0x%02x",
812 dev->node.dev_name, link->conf.ConfigIndex);
813 if (link->conf.Attributes & CONF_ENABLE_IRQ)
814 printk(", irq %u", link->irq.AssignedIRQ);
815 if (link->io.NumPorts1)
816 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
817 link->io.BasePort1 + link->io.NumPorts1 - 1);
818 if (link->io.NumPorts2)
819 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
820 link->io.BasePort2 + link->io.NumPorts2 - 1);
826 das16cs_pcmcia_release(link);
827 } /* das16cs_pcmcia_config */
829 static void das16cs_pcmcia_release(struct pcmcia_device *link)
831 dev_dbg(&link->dev, "das16cs_pcmcia_release\n");
832 pcmcia_disable_device(link);
833 } /* das16cs_pcmcia_release */
835 static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
837 struct local_info_t *local = link->priv;
839 /* Mark the device as stopped, to block IO until later */
843 } /* das16cs_pcmcia_suspend */
845 static int das16cs_pcmcia_resume(struct pcmcia_device *link)
847 struct local_info_t *local = link->priv;
851 } /* das16cs_pcmcia_resume */
853 /*====================================================================*/
855 static struct pcmcia_device_id das16cs_id_table[] = {
856 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
857 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
861 MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
862 MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
863 MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
864 MODULE_LICENSE("GPL");
866 struct pcmcia_driver das16cs_driver = {
867 .probe = das16cs_pcmcia_attach,
868 .remove = das16cs_pcmcia_detach,
869 .suspend = das16cs_pcmcia_suspend,
870 .resume = das16cs_pcmcia_resume,
871 .id_table = das16cs_id_table,
872 .owner = THIS_MODULE,
878 static int __init init_das16cs_pcmcia_cs(void)
880 pcmcia_register_driver(&das16cs_driver);
884 static void __exit exit_das16cs_pcmcia_cs(void)
886 pr_debug("das16cs_pcmcia_cs: unloading\n");
887 pcmcia_unregister_driver(&das16cs_driver);
890 int __init init_module(void)
894 ret = init_das16cs_pcmcia_cs();
898 return comedi_driver_register(&driver_das16cs);
901 void __exit cleanup_module(void)
903 exit_das16cs_pcmcia_cs();
904 comedi_driver_unregister(&driver_das16cs);
908 COMEDI_INITCLEANUP(driver_das16cs);
909 #endif /* CONFIG_PCMCIA */