1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/interrupt.h>
35#include "../comedidev.h"
36#include <linux/delay.h>
37#include <linux/pci.h>
38
39#include <pcmcia/cs_types.h>
40#include <pcmcia/cs.h>
41#include <pcmcia/cistpl.h>
42#include <pcmcia/ds.h>
43
44#include "8253.h"
45
46#define DAS16CS_SIZE 18
47
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
57
58struct das16cs_board {
59 const char *name;
60 int device_id;
61 int n_ao_chans;
62};
63static const struct das16cs_board das16cs_boards[] = {
64 {
65 .device_id = 0x0000,
66 .name = "PC-CARD DAS16/16",
67 .n_ao_chans = 0,
68 },
69 {
70 .device_id = 0x0039,
71 .name = "PC-CARD DAS16/16-AO",
72 .n_ao_chans = 2,
73 },
74 {
75 .device_id = 0x4009,
76 .name = "PCM-DAS16s/16",
77 .n_ao_chans = 0,
78 },
79};
80
81#define n_boards ARRAY_SIZE(das16cs_boards)
82#define thisboard ((const struct das16cs_board *)dev->board_ptr)
83
84struct das16cs_private {
85 struct pcmcia_device *link;
86
87 unsigned int ao_readback[2];
88 unsigned short status1;
89 unsigned short status2;
90};
91#define devpriv ((struct das16cs_private *)dev->private)
92
93static int das16cs_attach(struct comedi_device *dev,
94 struct comedi_devconfig *it);
95static int das16cs_detach(struct comedi_device *dev);
96static struct comedi_driver driver_das16cs = {
97 .driver_name = "cb_das16_cs",
98 .module = THIS_MODULE,
99 .attach = das16cs_attach,
100 .detach = das16cs_detach,
101};
102
103static struct pcmcia_device *cur_dev = NULL;
104
105static 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),
110 }
111};
112
113static irqreturn_t das16cs_interrupt(int irq, void *d);
114static int das16cs_ai_rinsn(struct comedi_device *dev,
115 struct comedi_subdevice *s,
116 struct comedi_insn *insn, unsigned int *data);
117static int das16cs_ai_cmd(struct comedi_device *dev,
118 struct comedi_subdevice *s);
119static int das16cs_ai_cmdtest(struct comedi_device *dev,
120 struct comedi_subdevice *s,
121 struct comedi_cmd *cmd);
122static int das16cs_ao_winsn(struct comedi_device *dev,
123 struct comedi_subdevice *s,
124 struct comedi_insn *insn, unsigned int *data);
125static int das16cs_ao_rinsn(struct comedi_device *dev,
126 struct comedi_subdevice *s,
127 struct comedi_insn *insn, unsigned int *data);
128static int das16cs_dio_insn_bits(struct comedi_device *dev,
129 struct comedi_subdevice *s,
130 struct comedi_insn *insn, unsigned int *data);
131static int das16cs_dio_insn_config(struct comedi_device *dev,
132 struct comedi_subdevice *s,
133 struct comedi_insn *insn,
134 unsigned int *data);
135static int das16cs_timer_insn_read(struct comedi_device *dev,
136 struct comedi_subdevice *s,
137 struct comedi_insn *insn,
138 unsigned int *data);
139static int das16cs_timer_insn_config(struct comedi_device *dev,
140 struct comedi_subdevice *s,
141 struct comedi_insn *insn,
142 unsigned int *data);
143
144static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link)
145{
146 tuple_t tuple;
147 u_short buf[128];
148 int prodid = 0;
149
150 tuple.TupleData = (cisdata_t *) buf;
151 tuple.TupleOffset = 0;
152 tuple.TupleDataMax = 255;
153 tuple.DesiredTuple = CISTPL_MANFID;
154 tuple.Attributes = TUPLE_RETURN_COMMON;
155 if ((pcmcia_get_first_tuple(link, &tuple) == 0) &&
156 (pcmcia_get_tuple_data(link, &tuple) == 0)) {
157 prodid = le16_to_cpu(buf[1]);
158 }
159
160 return prodid;
161}
162
163static const struct das16cs_board *das16cs_probe(struct comedi_device *dev,
164 struct pcmcia_device *link)
165{
166 int id;
167 int i;
168
169 id = get_prodid(dev, link);
170
171 for (i = 0; i < n_boards; i++) {
172 if (das16cs_boards[i].device_id == id) {
173 return das16cs_boards + i;
174 }
175 }
176
177 printk("unknown board!\n");
178
179 return NULL;
180}
181
182static int das16cs_attach(struct comedi_device *dev,
183 struct comedi_devconfig *it)
184{
185 struct pcmcia_device *link;
186 struct comedi_subdevice *s;
187 int ret;
188 int i;
189
190 printk("comedi%d: cb_das16_cs: ", dev->minor);
191
192 link = cur_dev;
193 if (!link)
194 return -EIO;
195
196 dev->iobase = link->io.BasePort1;
197 printk("I/O base=0x%04lx ", dev->iobase);
198
199 printk("fingerprint:\n");
200 for (i = 0; i < 48; i += 2) {
201 printk("%04x ", inw(dev->iobase + i));
202 }
203 printk("\n");
204
205 ret = request_irq(link->irq.AssignedIRQ, das16cs_interrupt,
206 IRQF_SHARED, "cb_das16_cs", dev);
207 if (ret < 0) {
208 return ret;
209 }
210 dev->irq = link->irq.AssignedIRQ;
211 printk("irq=%u ", dev->irq);
212
213 dev->board_ptr = das16cs_probe(dev, link);
214 if (!dev->board_ptr)
215 return -EIO;
216
217 dev->board_name = thisboard->name;
218
219 if (alloc_private(dev, sizeof(struct das16cs_private)) < 0)
220 return -ENOMEM;
221
222 if (alloc_subdevices(dev, 4) < 0)
223 return -ENOMEM;
224
225 s = dev->subdevices + 0;
226 dev->read_subdev = s;
227
228 s->type = COMEDI_SUBD_AI;
229 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
230 s->n_chan = 16;
231 s->maxdata = 0xffff;
232 s->range_table = &das16cs_ai_range;
233 s->len_chanlist = 16;
234 s->insn_read = das16cs_ai_rinsn;
235 s->do_cmd = das16cs_ai_cmd;
236 s->do_cmdtest = das16cs_ai_cmdtest;
237
238 s = dev->subdevices + 1;
239
240 if (thisboard->n_ao_chans) {
241 s->type = COMEDI_SUBD_AO;
242 s->subdev_flags = SDF_WRITABLE;
243 s->n_chan = thisboard->n_ao_chans;
244 s->maxdata = 0xffff;
245 s->range_table = &range_bipolar10;
246 s->insn_write = &das16cs_ao_winsn;
247 s->insn_read = &das16cs_ao_rinsn;
248 }
249
250 s = dev->subdevices + 2;
251
252 if (1) {
253 s->type = COMEDI_SUBD_DIO;
254 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
255 s->n_chan = 8;
256 s->maxdata = 1;
257 s->range_table = &range_digital;
258 s->insn_bits = das16cs_dio_insn_bits;
259 s->insn_config = das16cs_dio_insn_config;
260 } else {
261 s->type = COMEDI_SUBD_UNUSED;
262 }
263
264 s = dev->subdevices + 3;
265
266 if (0) {
267 s->type = COMEDI_SUBD_TIMER;
268 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
269 s->n_chan = 1;
270 s->maxdata = 0xff;
271 s->range_table = &range_unknown;
272 s->insn_read = das16cs_timer_insn_read;
273 s->insn_config = das16cs_timer_insn_config;
274 } else {
275 s->type = COMEDI_SUBD_UNUSED;
276 }
277
278 printk("attached\n");
279
280 return 1;
281}
282
283static int das16cs_detach(struct comedi_device *dev)
284{
285 printk("comedi%d: das16cs: remove\n", dev->minor);
286
287 if (dev->irq) {
288 free_irq(dev->irq, dev);
289 }
290
291 return 0;
292}
293
294static irqreturn_t das16cs_interrupt(int irq, void *d)
295{
296
297 return IRQ_HANDLED;
298}
299
300
301
302
303
304static int das16cs_ai_rinsn(struct comedi_device *dev,
305 struct comedi_subdevice *s,
306 struct comedi_insn *insn, unsigned int *data)
307{
308 int i;
309 int to;
310 int aref;
311 int range;
312 int chan;
313 static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 };
314
315 chan = CR_CHAN(insn->chanspec);
316 aref = CR_AREF(insn->chanspec);
317 range = CR_RANGE(insn->chanspec);
318
319 outw(chan, dev->iobase + 2);
320
321 devpriv->status1 &= ~0xf320;
322 devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
323 outw(devpriv->status1, dev->iobase + 4);
324
325 devpriv->status2 &= ~0xff00;
326 devpriv->status2 |= range_bits[range];
327 outw(devpriv->status2, dev->iobase + 6);
328
329 for (i = 0; i < insn->n; i++) {
330 outw(0, dev->iobase);
331
332#define TIMEOUT 1000
333 for (to = 0; to < TIMEOUT; to++) {
334 if (inw(dev->iobase + 4) & 0x0080)
335 break;
336 }
337 if (to == TIMEOUT) {
338 printk("cb_das16_cs: ai timeout\n");
339 return -ETIME;
340 }
341 data[i] = (unsigned short)inw(dev->iobase + 0);
342 }
343
344 return i;
345}
346
347static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
348{
349 return -EINVAL;
350}
351
352static int das16cs_ai_cmdtest(struct comedi_device *dev,
353 struct comedi_subdevice *s,
354 struct comedi_cmd *cmd)
355{
356 int err = 0;
357 int tmp;
358
359
360
361
362
363
364
365
366
367
368 tmp = cmd->start_src;
369 cmd->start_src &= TRIG_NOW;
370 if (!cmd->start_src || tmp != cmd->start_src)
371 err++;
372
373 tmp = cmd->scan_begin_src;
374 cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
375 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
376 err++;
377
378 tmp = cmd->convert_src;
379 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
380 if (!cmd->convert_src || tmp != cmd->convert_src)
381 err++;
382
383 tmp = cmd->scan_end_src;
384 cmd->scan_end_src &= TRIG_COUNT;
385 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
386 err++;
387
388 tmp = cmd->stop_src;
389 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
390 if (!cmd->stop_src || tmp != cmd->stop_src)
391 err++;
392
393 if (err)
394 return 1;
395
396
397
398
399 if (cmd->scan_begin_src != TRIG_TIMER &&
400 cmd->scan_begin_src != TRIG_EXT)
401 err++;
402 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
403 err++;
404 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
405 err++;
406
407 if (err)
408 return 2;
409
410
411
412 if (cmd->start_arg != 0) {
413 cmd->start_arg = 0;
414 err++;
415 }
416#define MAX_SPEED 10000
417#define MIN_SPEED 1000000000
418
419 if (cmd->scan_begin_src == TRIG_TIMER) {
420 if (cmd->scan_begin_arg < MAX_SPEED) {
421 cmd->scan_begin_arg = MAX_SPEED;
422 err++;
423 }
424 if (cmd->scan_begin_arg > MIN_SPEED) {
425 cmd->scan_begin_arg = MIN_SPEED;
426 err++;
427 }
428 } else {
429
430
431
432 if (cmd->scan_begin_arg > 9) {
433 cmd->scan_begin_arg = 9;
434 err++;
435 }
436 }
437 if (cmd->convert_src == TRIG_TIMER) {
438 if (cmd->convert_arg < MAX_SPEED) {
439 cmd->convert_arg = MAX_SPEED;
440 err++;
441 }
442 if (cmd->convert_arg > MIN_SPEED) {
443 cmd->convert_arg = MIN_SPEED;
444 err++;
445 }
446 } else {
447
448
449 if (cmd->convert_arg > 9) {
450 cmd->convert_arg = 9;
451 err++;
452 }
453 }
454
455 if (cmd->scan_end_arg != cmd->chanlist_len) {
456 cmd->scan_end_arg = cmd->chanlist_len;
457 err++;
458 }
459 if (cmd->stop_src == TRIG_COUNT) {
460 if (cmd->stop_arg > 0x00ffffff) {
461 cmd->stop_arg = 0x00ffffff;
462 err++;
463 }
464 } else {
465
466 if (cmd->stop_arg != 0) {
467 cmd->stop_arg = 0;
468 err++;
469 }
470 }
471
472 if (err)
473 return 3;
474
475
476
477 if (cmd->scan_begin_src == TRIG_TIMER) {
478 unsigned int div1, div2;
479
480 tmp = cmd->scan_begin_arg;
481 i8253_cascade_ns_to_timer(100, &div1, &div2,
482 &cmd->scan_begin_arg,
483 cmd->flags & TRIG_ROUND_MASK);
484 if (tmp != cmd->scan_begin_arg)
485 err++;
486 }
487 if (cmd->convert_src == TRIG_TIMER) {
488 unsigned int div1, div2;
489
490 tmp = cmd->convert_arg;
491 i8253_cascade_ns_to_timer(100, &div1, &div2,
492 &cmd->scan_begin_arg,
493 cmd->flags & TRIG_ROUND_MASK);
494 if (tmp != cmd->convert_arg)
495 err++;
496 if (cmd->scan_begin_src == TRIG_TIMER &&
497 cmd->scan_begin_arg <
498 cmd->convert_arg * cmd->scan_end_arg) {
499 cmd->scan_begin_arg =
500 cmd->convert_arg * cmd->scan_end_arg;
501 err++;
502 }
503 }
504
505 if (err)
506 return 4;
507
508 return 0;
509}
510
511static int das16cs_ao_winsn(struct comedi_device *dev,
512 struct comedi_subdevice *s,
513 struct comedi_insn *insn, unsigned int *data)
514{
515 int i;
516 int chan = CR_CHAN(insn->chanspec);
517 unsigned short status1;
518 unsigned short d;
519 int bit;
520
521 for (i = 0; i < insn->n; i++) {
522 devpriv->ao_readback[chan] = data[i];
523 d = data[i];
524
525 outw(devpriv->status1, dev->iobase + 4);
526 udelay(1);
527
528 status1 = devpriv->status1 & ~0xf;
529 if (chan)
530 status1 |= 0x0001;
531 else
532 status1 |= 0x0008;
533
534
535 outw(status1, dev->iobase + 4);
536 udelay(1);
537
538 for (bit = 15; bit >= 0; bit--) {
539 int b = (d >> bit) & 0x1;
540 b <<= 1;
541
542 outw(status1 | b | 0x0000, dev->iobase + 4);
543 udelay(1);
544
545 outw(status1 | b | 0x0004, dev->iobase + 4);
546 udelay(1);
547 }
548
549
550 outw(status1 | 0x9, dev->iobase + 4);
551 }
552
553 return i;
554}
555
556
557
558static int das16cs_ao_rinsn(struct comedi_device *dev,
559 struct comedi_subdevice *s,
560 struct comedi_insn *insn, unsigned int *data)
561{
562 int i;
563 int chan = CR_CHAN(insn->chanspec);
564
565 for (i = 0; i < insn->n; i++)
566 data[i] = devpriv->ao_readback[chan];
567
568 return i;
569}
570
571
572
573
574
575
576static int das16cs_dio_insn_bits(struct comedi_device *dev,
577 struct comedi_subdevice *s,
578 struct comedi_insn *insn, unsigned int *data)
579{
580 if (insn->n != 2)
581 return -EINVAL;
582
583 if (data[0]) {
584 s->state &= ~data[0];
585 s->state |= data[0] & data[1];
586
587 outw(s->state, dev->iobase + 16);
588 }
589
590
591
592 data[1] = inw(dev->iobase + 16);
593
594 return 2;
595}
596
597static int das16cs_dio_insn_config(struct comedi_device *dev,
598 struct comedi_subdevice *s,
599 struct comedi_insn *insn, unsigned int *data)
600{
601 int chan = CR_CHAN(insn->chanspec);
602 int bits;
603
604 if (chan < 4)
605 bits = 0x0f;
606 else
607 bits = 0xf0;
608
609 switch (data[0]) {
610 case INSN_CONFIG_DIO_OUTPUT:
611 s->io_bits |= bits;
612 break;
613 case INSN_CONFIG_DIO_INPUT:
614 s->io_bits &= bits;
615 break;
616 case INSN_CONFIG_DIO_QUERY:
617 data[1] =
618 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
619 return insn->n;
620 break;
621 default:
622 return -EINVAL;
623 break;
624 }
625
626 devpriv->status2 &= ~0x00c0;
627 devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
628 devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
629
630 outw(devpriv->status2, dev->iobase + 6);
631
632 return insn->n;
633}
634
635static int das16cs_timer_insn_read(struct comedi_device *dev,
636 struct comedi_subdevice *s,
637 struct comedi_insn *insn, unsigned int *data)
638{
639 return -EINVAL;
640}
641
642static int das16cs_timer_insn_config(struct comedi_device *dev,
643 struct comedi_subdevice *s,
644 struct comedi_insn *insn,
645 unsigned int *data)
646{
647 return -EINVAL;
648}
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
671
672#ifdef PCMCIA_DEBUG
673static int pc_debug = PCMCIA_DEBUG;
674module_param(pc_debug, int, 0644);
675#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
676static char *version =
677 "cb_das16_cs.c pcmcia code (David Schleef), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)";
678#else
679#define DEBUG(n, args...)
680#endif
681
682
683
684static void das16cs_pcmcia_config(struct pcmcia_device *link);
685static void das16cs_pcmcia_release(struct pcmcia_device *link);
686static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev);
687static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev);
688
689
690
691
692
693
694
695static int das16cs_pcmcia_attach(struct pcmcia_device *);
696static void das16cs_pcmcia_detach(struct pcmcia_device *);
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711static dev_info_t dev_info = "cb_das16_cs";
712
713struct local_info_t {
714 struct pcmcia_device *link;
715 dev_node_t node;
716 int stop;
717 struct bus_operations *bus;
718};
719
720
721
722
723
724
725
726
727
728
729
730
731
732static int das16cs_pcmcia_attach(struct pcmcia_device *link)
733{
734 struct local_info_t *local;
735
736 DEBUG(0, "das16cs_pcmcia_attach()\n");
737
738
739 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
740 if (!local)
741 return -ENOMEM;
742 local->link = link;
743 link->priv = local;
744
745
746
747 link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
748 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
749 link->irq.Handler = NULL;
750
751 link->conf.Attributes = 0;
752 link->conf.IntType = INT_MEMORY_AND_IO;
753
754 cur_dev = link;
755
756 das16cs_pcmcia_config(link);
757
758 return 0;
759}
760
761static void das16cs_pcmcia_detach(struct pcmcia_device *link)
762{
763 DEBUG(0, "das16cs_pcmcia_detach(0x%p)\n", link);
764
765 if (link->dev_node) {
766 ((struct local_info_t *)link->priv)->stop = 1;
767 das16cs_pcmcia_release(link);
768 }
769
770 if (link->priv)
771 kfree(link->priv);
772}
773
774static void das16cs_pcmcia_config(struct pcmcia_device *link)
775{
776 struct local_info_t *dev = link->priv;
777 tuple_t tuple;
778 cisparse_t parse;
779 int last_fn, last_ret;
780 u_char buf[64];
781 cistpl_cftable_entry_t dflt = { 0 };
782
783 DEBUG(0, "das16cs_pcmcia_config(0x%p)\n", link);
784
785
786
787
788
789 tuple.DesiredTuple = CISTPL_CONFIG;
790 tuple.Attributes = 0;
791 tuple.TupleData = buf;
792 tuple.TupleDataMax = sizeof(buf);
793 tuple.TupleOffset = 0;
794
795 last_fn = GetFirstTuple;
796 last_ret = pcmcia_get_first_tuple(link, &tuple);
797 if (last_ret != 0)
798 goto cs_failed;
799
800 last_fn = GetTupleData;
801 last_ret = pcmcia_get_tuple_data(link, &tuple);
802 if (last_ret != 0)
803 goto cs_failed;
804
805 last_fn = ParseTuple;
806 last_ret = pcmcia_parse_tuple(&tuple, &parse);
807 if (last_ret != 0)
808 goto cs_failed;
809
810 link->conf.ConfigBase = parse.config.base;
811 link->conf.Present = parse.config.rmask[0];
812
813
814
815
816
817
818
819
820
821
822
823
824
825 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
826 last_fn = GetFirstTuple;
827
828 last_ret = pcmcia_get_first_tuple(link, &tuple);
829 if (last_ret)
830 goto cs_failed;
831
832 while (1) {
833 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
834 if (pcmcia_get_tuple_data(link, &tuple))
835 goto next_entry;
836 if (pcmcia_parse_tuple(&tuple, &parse))
837 goto next_entry;
838
839 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
840 dflt = *cfg;
841 if (cfg->index == 0)
842 goto next_entry;
843 link->conf.ConfigIndex = cfg->index;
844
845
846
847
848
849
850
851
852 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
853 link->conf.Attributes |= CONF_ENABLE_IRQ;
854
855
856 link->io.NumPorts1 = link->io.NumPorts2 = 0;
857 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
858 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
859 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
860 if (!(io->flags & CISTPL_IO_8BIT))
861 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
862 if (!(io->flags & CISTPL_IO_16BIT))
863 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
864 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
865 link->io.BasePort1 = io->win[0].base;
866 link->io.NumPorts1 = io->win[0].len;
867 if (io->nwin > 1) {
868 link->io.Attributes2 = link->io.Attributes1;
869 link->io.BasePort2 = io->win[1].base;
870 link->io.NumPorts2 = io->win[1].len;
871 }
872
873 if (pcmcia_request_io(link, &link->io))
874 goto next_entry;
875 }
876
877
878 break;
879
880next_entry:
881 last_fn = GetNextTuple;
882
883 last_ret = pcmcia_get_next_tuple(link, &tuple);
884 if (last_ret)
885 goto cs_failed;
886 }
887
888
889
890
891
892
893 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
894 last_fn = RequestIRQ;
895
896 last_ret = pcmcia_request_irq(link, &link->irq);
897 if (last_ret)
898 goto cs_failed;
899 }
900
901
902
903
904
905 last_fn = RequestConfiguration;
906 last_ret = pcmcia_request_configuration(link, &link->conf);
907 if (last_ret)
908 goto cs_failed;
909
910
911
912
913
914 sprintf(dev->node.dev_name, "cb_das16_cs");
915 dev->node.major = dev->node.minor = 0;
916 link->dev_node = &dev->node;
917
918
919 printk(KERN_INFO "%s: index 0x%02x",
920 dev->node.dev_name, link->conf.ConfigIndex);
921 if (link->conf.Attributes & CONF_ENABLE_IRQ)
922 printk(", irq %u", link->irq.AssignedIRQ);
923 if (link->io.NumPorts1)
924 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
925 link->io.BasePort1 + link->io.NumPorts1 - 1);
926 if (link->io.NumPorts2)
927 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
928 link->io.BasePort2 + link->io.NumPorts2 - 1);
929 printk("\n");
930
931 return;
932
933cs_failed:
934 cs_error(link, last_fn, last_ret);
935 das16cs_pcmcia_release(link);
936}
937
938static void das16cs_pcmcia_release(struct pcmcia_device *link)
939{
940 DEBUG(0, "das16cs_pcmcia_release(0x%p)\n", link);
941 pcmcia_disable_device(link);
942}
943
944static int das16cs_pcmcia_suspend(struct pcmcia_device *link)
945{
946 struct local_info_t *local = link->priv;
947
948
949 local->stop = 1;
950
951 return 0;
952}
953
954static int das16cs_pcmcia_resume(struct pcmcia_device *link)
955{
956 struct local_info_t *local = link->priv;
957
958 local->stop = 0;
959 return 0;
960}
961
962
963
964static struct pcmcia_device_id das16cs_id_table[] = {
965 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
966 PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
967 PCMCIA_DEVICE_NULL
968};
969
970MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
971
972struct pcmcia_driver das16cs_driver = {
973 .probe = das16cs_pcmcia_attach,
974 .remove = das16cs_pcmcia_detach,
975 .suspend = das16cs_pcmcia_suspend,
976 .resume = das16cs_pcmcia_resume,
977 .id_table = das16cs_id_table,
978 .owner = THIS_MODULE,
979 .drv = {
980 .name = dev_info,
981 },
982};
983
984static int __init init_das16cs_pcmcia_cs(void)
985{
986 DEBUG(0, "%s\n", version);
987 pcmcia_register_driver(&das16cs_driver);
988 return 0;
989}
990
991static void __exit exit_das16cs_pcmcia_cs(void)
992{
993 DEBUG(0, "das16cs_pcmcia_cs: unloading\n");
994 pcmcia_unregister_driver(&das16cs_driver);
995}
996
997int __init init_module(void)
998{
999 int ret;
1000
1001 ret = init_das16cs_pcmcia_cs();
1002 if (ret < 0)
1003 return ret;
1004
1005 return comedi_driver_register(&driver_das16cs);
1006}
1007
1008void __exit cleanup_module(void)
1009{
1010 exit_das16cs_pcmcia_cs();
1011 comedi_driver_unregister(&driver_das16cs);
1012}
1013
1014#else
1015COMEDI_INITCLEANUP(driver_das16cs);
1016#endif
1017