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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50#include "../comedidev.h"
51#include <linux/semaphore.h>
52
53#include <pcmcia/cistpl.h>
54#include <pcmcia/cisreg.h>
55#include <pcmcia/ds.h>
56
57#include <linux/completion.h>
58
59
60#define MAX_DEV 4
61
62struct local_info_t {
63 struct pcmcia_device *link;
64 int stop;
65 int table_index;
66 char board_name[32];
67
68 enum { semaphore, buffer } interrupt_mode;
69
70 struct completion eos;
71
72 struct comedi_device *dev;
73 struct comedi_subdevice *s;
74 int count;
75};
76
77
78
79static struct local_info_t *dev_table[MAX_DEV] = { NULL, };
80
81
82
83#define DAQP_FIFO_SIZE 4096
84
85#define DAQP_FIFO 0
86#define DAQP_SCANLIST 1
87#define DAQP_CONTROL 2
88#define DAQP_STATUS 2
89#define DAQP_DIGITAL_IO 3
90#define DAQP_PACER_LOW 4
91#define DAQP_PACER_MID 5
92#define DAQP_PACER_HIGH 6
93#define DAQP_COMMAND 7
94#define DAQP_DA 8
95#define DAQP_TIMER 10
96#define DAQP_AUX 15
97
98#define DAQP_SCANLIST_DIFFERENTIAL 0x4000
99#define DAQP_SCANLIST_GAIN(x) ((x)<<12)
100#define DAQP_SCANLIST_CHANNEL(x) ((x)<<8)
101#define DAQP_SCANLIST_START 0x0080
102#define DAQP_SCANLIST_EXT_GAIN(x) ((x)<<4)
103#define DAQP_SCANLIST_EXT_CHANNEL(x) (x)
104
105#define DAQP_CONTROL_PACER_100kHz 0xc0
106#define DAQP_CONTROL_PACER_1MHz 0x80
107#define DAQP_CONTROL_PACER_5MHz 0x40
108#define DAQP_CONTROL_PACER_EXTERNAL 0x00
109#define DAQP_CONTORL_EXPANSION 0x20
110#define DAQP_CONTROL_EOS_INT_ENABLE 0x10
111#define DAQP_CONTROL_FIFO_INT_ENABLE 0x08
112#define DAQP_CONTROL_TRIGGER_ONESHOT 0x00
113#define DAQP_CONTROL_TRIGGER_CONTINUOUS 0x04
114#define DAQP_CONTROL_TRIGGER_INTERNAL 0x00
115#define DAQP_CONTROL_TRIGGER_EXTERNAL 0x02
116#define DAQP_CONTROL_TRIGGER_RISING 0x00
117#define DAQP_CONTROL_TRIGGER_FALLING 0x01
118
119#define DAQP_STATUS_IDLE 0x80
120#define DAQP_STATUS_RUNNING 0x40
121#define DAQP_STATUS_EVENTS 0x38
122#define DAQP_STATUS_DATA_LOST 0x20
123#define DAQP_STATUS_END_OF_SCAN 0x10
124#define DAQP_STATUS_FIFO_THRESHOLD 0x08
125#define DAQP_STATUS_FIFO_FULL 0x04
126#define DAQP_STATUS_FIFO_NEARFULL 0x02
127#define DAQP_STATUS_FIFO_EMPTY 0x01
128
129#define DAQP_COMMAND_ARM 0x80
130#define DAQP_COMMAND_RSTF 0x40
131#define DAQP_COMMAND_RSTQ 0x20
132#define DAQP_COMMAND_STOP 0x10
133#define DAQP_COMMAND_LATCH 0x08
134#define DAQP_COMMAND_100kHz 0x00
135#define DAQP_COMMAND_50kHz 0x02
136#define DAQP_COMMAND_25kHz 0x04
137#define DAQP_COMMAND_FIFO_DATA 0x01
138#define DAQP_COMMAND_FIFO_PROGRAM 0x00
139
140#define DAQP_AUX_TRIGGER_TTL 0x00
141#define DAQP_AUX_TRIGGER_ANALOG 0x80
142#define DAQP_AUX_TRIGGER_PRETRIGGER 0x40
143#define DAQP_AUX_TIMER_INT_ENABLE 0x20
144#define DAQP_AUX_TIMER_RELOAD 0x00
145#define DAQP_AUX_TIMER_PAUSE 0x08
146#define DAQP_AUX_TIMER_GO 0x10
147#define DAQP_AUX_TIMER_GO_EXTERNAL 0x18
148#define DAQP_AUX_TIMER_EXTERNAL_SRC 0x04
149#define DAQP_AUX_TIMER_INTERNAL_SRC 0x00
150#define DAQP_AUX_DA_DIRECT 0x00
151#define DAQP_AUX_DA_OVERFLOW 0x01
152#define DAQP_AUX_DA_EXTERNAL 0x02
153#define DAQP_AUX_DA_PACER 0x03
154
155#define DAQP_AUX_RUNNING 0x80
156#define DAQP_AUX_TRIGGERED 0x40
157#define DAQP_AUX_DA_BUFFER 0x20
158#define DAQP_AUX_TIMER_OVERFLOW 0x10
159#define DAQP_AUX_CONVERSION 0x08
160#define DAQP_AUX_DATA_LOST 0x04
161#define DAQP_AUX_FIFO_NEARFULL 0x02
162#define DAQP_AUX_FIFO_EMPTY 0x01
163
164
165
166
167
168
169static const struct comedi_lrange range_daqp_ai = { 4, {
170 BIP_RANGE(10),
171 BIP_RANGE(5),
172 BIP_RANGE(2.5),
173 BIP_RANGE(1.25)
174 }
175};
176
177static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} };
178
179
180
181
182
183static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
184static int daqp_detach(struct comedi_device *dev);
185static struct comedi_driver driver_daqp = {
186 .driver_name = "quatech_daqp_cs",
187 .module = THIS_MODULE,
188 .attach = daqp_attach,
189 .detach = daqp_detach,
190};
191
192#ifdef DAQP_DEBUG
193
194static void daqp_dump(struct comedi_device *dev)
195{
196 printk(KERN_INFO "DAQP: status %02x; aux status %02x\n",
197 inb(dev->iobase + DAQP_STATUS), inb(dev->iobase + DAQP_AUX));
198}
199
200static void hex_dump(char *str, void *ptr, int len)
201{
202 unsigned char *cptr = ptr;
203 int i;
204
205 printk(str);
206
207 for (i = 0; i < len; i++) {
208 if (i % 16 == 0)
209 printk("\n%p:", cptr);
210
211 printk(" %02x", *(cptr++));
212 }
213 printk("\n");
214}
215
216#endif
217
218
219
220static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
221{
222 struct local_info_t *local = (struct local_info_t *)s->private;
223
224 if (local->stop)
225 return -EIO;
226
227
228 outb(DAQP_COMMAND_STOP, dev->iobase + DAQP_COMMAND);
229
230
231
232
233 local->interrupt_mode = semaphore;
234
235 return 0;
236}
237
238
239
240
241
242
243
244
245
246
247static enum irqreturn daqp_interrupt(int irq, void *dev_id)
248{
249 struct local_info_t *local = (struct local_info_t *)dev_id;
250 struct comedi_device *dev;
251 struct comedi_subdevice *s;
252 int loop_limit = 10000;
253 int status;
254
255 if (local == NULL) {
256 printk(KERN_WARNING
257 "daqp_interrupt(): irq %d for unknown device.\n", irq);
258 return IRQ_NONE;
259 }
260
261 dev = local->dev;
262 if (dev == NULL) {
263 printk(KERN_WARNING "daqp_interrupt(): NULL comedi_device.\n");
264 return IRQ_NONE;
265 }
266
267 if (!dev->attached) {
268 printk(KERN_WARNING
269 "daqp_interrupt(): struct comedi_device not yet attached.\n");
270 return IRQ_NONE;
271 }
272
273 s = local->s;
274 if (s == NULL) {
275 printk(KERN_WARNING
276 "daqp_interrupt(): NULL comedi_subdevice.\n");
277 return IRQ_NONE;
278 }
279
280 if ((struct local_info_t *)s->private != local) {
281 printk(KERN_WARNING
282 "daqp_interrupt(): invalid comedi_subdevice.\n");
283 return IRQ_NONE;
284 }
285
286 switch (local->interrupt_mode) {
287
288 case semaphore:
289
290 complete(&local->eos);
291 break;
292
293 case buffer:
294
295 while (!((status = inb(dev->iobase + DAQP_STATUS))
296 & DAQP_STATUS_FIFO_EMPTY)) {
297
298 short data;
299
300 if (status & DAQP_STATUS_DATA_LOST) {
301 s->async->events |=
302 COMEDI_CB_EOA | COMEDI_CB_OVERFLOW;
303 printk("daqp: data lost\n");
304 daqp_ai_cancel(dev, s);
305 break;
306 }
307
308 data = inb(dev->iobase + DAQP_FIFO);
309 data |= inb(dev->iobase + DAQP_FIFO) << 8;
310 data ^= 0x8000;
311
312 comedi_buf_put(s->async, data);
313
314
315
316
317
318 if (local->count > 0) {
319 local->count--;
320 if (local->count == 0) {
321 daqp_ai_cancel(dev, s);
322 s->async->events |= COMEDI_CB_EOA;
323 break;
324 }
325 }
326
327 if ((loop_limit--) <= 0)
328 break;
329 }
330
331 if (loop_limit <= 0) {
332 printk(KERN_WARNING
333 "loop_limit reached in daqp_interrupt()\n");
334 daqp_ai_cancel(dev, s);
335 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
336 }
337
338 s->async->events |= COMEDI_CB_BLOCK;
339
340 comedi_event(dev, s);
341 }
342 return IRQ_HANDLED;
343}
344
345
346
347static int daqp_ai_insn_read(struct comedi_device *dev,
348 struct comedi_subdevice *s,
349 struct comedi_insn *insn, unsigned int *data)
350{
351 struct local_info_t *local = (struct local_info_t *)s->private;
352 int i;
353 int v;
354 int counter = 10000;
355
356 if (local->stop)
357 return -EIO;
358
359
360
361 daqp_ai_cancel(dev, s);
362
363 outb(0, dev->iobase + DAQP_AUX);
364
365
366 outb(DAQP_COMMAND_RSTQ, dev->iobase + DAQP_COMMAND);
367
368
369
370 v = DAQP_SCANLIST_CHANNEL(CR_CHAN(insn->chanspec))
371 | DAQP_SCANLIST_GAIN(CR_RANGE(insn->chanspec));
372
373 if (CR_AREF(insn->chanspec) == AREF_DIFF)
374 v |= DAQP_SCANLIST_DIFFERENTIAL;
375
376
377 v |= DAQP_SCANLIST_START;
378
379 outb(v & 0xff, dev->iobase + DAQP_SCANLIST);
380 outb(v >> 8, dev->iobase + DAQP_SCANLIST);
381
382
383
384 outb(DAQP_COMMAND_RSTF, dev->iobase + DAQP_COMMAND);
385
386
387
388 v = DAQP_CONTROL_TRIGGER_ONESHOT | DAQP_CONTROL_TRIGGER_INTERNAL
389 | DAQP_CONTROL_PACER_100kHz | DAQP_CONTROL_EOS_INT_ENABLE;
390
391 outb(v, dev->iobase + DAQP_CONTROL);
392
393
394
395
396
397 while (--counter
398 && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) ;
399 if (!counter) {
400 printk("daqp: couldn't clear interrupts in status register\n");
401 return -1;
402 }
403
404 init_completion(&local->eos);
405 local->interrupt_mode = semaphore;
406 local->dev = dev;
407 local->s = s;
408
409 for (i = 0; i < insn->n; i++) {
410
411
412 outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA,
413 dev->iobase + DAQP_COMMAND);
414
415
416
417 if (wait_for_completion_interruptible(&local->eos))
418 return -EINTR;
419
420 data[i] = inb(dev->iobase + DAQP_FIFO);
421 data[i] |= inb(dev->iobase + DAQP_FIFO) << 8;
422 data[i] ^= 0x8000;
423 }
424
425 return insn->n;
426}
427
428
429
430
431
432
433
434
435static int daqp_ns_to_timer(unsigned int *ns, int round)
436{
437 int timer;
438
439 timer = *ns / 200;
440 *ns = timer * 200;
441
442 return timer;
443}
444
445
446
447
448
449
450
451
452
453static int daqp_ai_cmdtest(struct comedi_device *dev,
454 struct comedi_subdevice *s, struct comedi_cmd *cmd)
455{
456 int err = 0;
457 int tmp;
458
459
460
461 tmp = cmd->start_src;
462 cmd->start_src &= TRIG_NOW;
463 if (!cmd->start_src || tmp != cmd->start_src)
464 err++;
465
466 tmp = cmd->scan_begin_src;
467 cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
468 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
469 err++;
470
471 tmp = cmd->convert_src;
472 cmd->convert_src &= TRIG_TIMER | TRIG_NOW;
473 if (!cmd->convert_src || tmp != cmd->convert_src)
474 err++;
475
476 tmp = cmd->scan_end_src;
477 cmd->scan_end_src &= TRIG_COUNT;
478 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
479 err++;
480
481 tmp = cmd->stop_src;
482 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
483 if (!cmd->stop_src || tmp != cmd->stop_src)
484 err++;
485
486 if (err)
487 return 1;
488
489
490
491
492
493
494
495 if (cmd->scan_begin_src != TRIG_TIMER &&
496 cmd->scan_begin_src != TRIG_FOLLOW)
497 err++;
498 if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER)
499 err++;
500 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
501 err++;
502 if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
503 err++;
504
505 if (err)
506 return 2;
507
508
509
510 if (cmd->start_arg != 0) {
511 cmd->start_arg = 0;
512 err++;
513 }
514#define MAX_SPEED 10000
515
516 if (cmd->scan_begin_src == TRIG_TIMER
517 && cmd->scan_begin_arg < MAX_SPEED) {
518 cmd->scan_begin_arg = MAX_SPEED;
519 err++;
520 }
521
522
523
524
525
526
527 if (cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER
528 && cmd->scan_begin_arg != cmd->convert_arg * cmd->scan_end_arg) {
529 err++;
530 }
531
532 if (cmd->convert_src == TRIG_TIMER && cmd->convert_arg < MAX_SPEED) {
533 cmd->convert_arg = MAX_SPEED;
534 err++;
535 }
536
537 if (cmd->scan_end_arg != cmd->chanlist_len) {
538 cmd->scan_end_arg = cmd->chanlist_len;
539 err++;
540 }
541 if (cmd->stop_src == TRIG_COUNT) {
542 if (cmd->stop_arg > 0x00ffffff) {
543 cmd->stop_arg = 0x00ffffff;
544 err++;
545 }
546 } else {
547
548 if (cmd->stop_arg != 0) {
549 cmd->stop_arg = 0;
550 err++;
551 }
552 }
553
554 if (err)
555 return 3;
556
557
558
559 if (cmd->scan_begin_src == TRIG_TIMER) {
560 tmp = cmd->scan_begin_arg;
561 daqp_ns_to_timer(&cmd->scan_begin_arg,
562 cmd->flags & TRIG_ROUND_MASK);
563 if (tmp != cmd->scan_begin_arg)
564 err++;
565 }
566
567 if (cmd->convert_src == TRIG_TIMER) {
568 tmp = cmd->convert_arg;
569 daqp_ns_to_timer(&cmd->convert_arg,
570 cmd->flags & TRIG_ROUND_MASK);
571 if (tmp != cmd->convert_arg)
572 err++;
573 }
574
575 if (err)
576 return 4;
577
578 return 0;
579}
580
581static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
582{
583 struct local_info_t *local = (struct local_info_t *)s->private;
584 struct comedi_cmd *cmd = &s->async->cmd;
585 int counter;
586 int scanlist_start_on_every_entry;
587 int threshold;
588
589 int i;
590 int v;
591
592 if (local->stop)
593 return -EIO;
594
595
596
597 daqp_ai_cancel(dev, s);
598
599 outb(0, dev->iobase + DAQP_AUX);
600
601
602 outb(DAQP_COMMAND_RSTQ, dev->iobase + DAQP_COMMAND);
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617 if (cmd->convert_src == TRIG_TIMER) {
618 counter = daqp_ns_to_timer(&cmd->convert_arg,
619 cmd->flags & TRIG_ROUND_MASK);
620 outb(counter & 0xff, dev->iobase + DAQP_PACER_LOW);
621 outb((counter >> 8) & 0xff, dev->iobase + DAQP_PACER_MID);
622 outb((counter >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH);
623 scanlist_start_on_every_entry = 1;
624 } else {
625 counter = daqp_ns_to_timer(&cmd->scan_begin_arg,
626 cmd->flags & TRIG_ROUND_MASK);
627 outb(counter & 0xff, dev->iobase + DAQP_PACER_LOW);
628 outb((counter >> 8) & 0xff, dev->iobase + DAQP_PACER_MID);
629 outb((counter >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH);
630 scanlist_start_on_every_entry = 0;
631 }
632
633
634
635 for (i = 0; i < cmd->chanlist_len; i++) {
636
637 int chanspec = cmd->chanlist[i];
638
639
640
641 v = DAQP_SCANLIST_CHANNEL(CR_CHAN(chanspec))
642 | DAQP_SCANLIST_GAIN(CR_RANGE(chanspec));
643
644 if (CR_AREF(chanspec) == AREF_DIFF)
645 v |= DAQP_SCANLIST_DIFFERENTIAL;
646
647 if (i == 0 || scanlist_start_on_every_entry)
648 v |= DAQP_SCANLIST_START;
649
650 outb(v & 0xff, dev->iobase + DAQP_SCANLIST);
651 outb(v >> 8, dev->iobase + DAQP_SCANLIST);
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720 if (cmd->stop_src == TRIG_COUNT) {
721 local->count = cmd->stop_arg * cmd->scan_end_arg;
722 threshold = 2 * local->count;
723 while (threshold > DAQP_FIFO_SIZE * 3 / 4)
724 threshold /= 2;
725 } else {
726 local->count = -1;
727 threshold = DAQP_FIFO_SIZE / 2;
728 }
729
730
731
732 outb(DAQP_COMMAND_RSTF, dev->iobase + DAQP_COMMAND);
733
734
735
736
737
738
739
740
741
742 outb(0x00, dev->iobase + DAQP_FIFO);
743 outb(0x00, dev->iobase + DAQP_FIFO);
744
745 outb((DAQP_FIFO_SIZE - threshold) & 0xff, dev->iobase + DAQP_FIFO);
746 outb((DAQP_FIFO_SIZE - threshold) >> 8, dev->iobase + DAQP_FIFO);
747
748
749
750 v = DAQP_CONTROL_TRIGGER_CONTINUOUS | DAQP_CONTROL_TRIGGER_INTERNAL
751 | DAQP_CONTROL_PACER_5MHz | DAQP_CONTROL_FIFO_INT_ENABLE;
752
753 outb(v, dev->iobase + DAQP_CONTROL);
754
755
756
757
758 counter = 100;
759 while (--counter
760 && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) ;
761 if (!counter) {
762 printk(KERN_ERR
763 "daqp: couldn't clear interrupts in status register\n");
764 return -1;
765 }
766
767 local->interrupt_mode = buffer;
768 local->dev = dev;
769 local->s = s;
770
771
772 outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA,
773 dev->iobase + DAQP_COMMAND);
774
775 return 0;
776}
777
778
779
780static int daqp_ao_insn_write(struct comedi_device *dev,
781 struct comedi_subdevice *s,
782 struct comedi_insn *insn, unsigned int *data)
783{
784 struct local_info_t *local = (struct local_info_t *)s->private;
785 int d;
786 unsigned int chan;
787
788 if (local->stop)
789 return -EIO;
790
791 chan = CR_CHAN(insn->chanspec);
792 d = data[0];
793 d &= 0x0fff;
794 d ^= 0x0800;
795 d |= chan << 12;
796
797
798 outb(0, dev->iobase + DAQP_AUX);
799
800 outw(d, dev->iobase + DAQP_DA);
801
802 return 1;
803}
804
805
806
807static int daqp_di_insn_read(struct comedi_device *dev,
808 struct comedi_subdevice *s,
809 struct comedi_insn *insn, unsigned int *data)
810{
811 struct local_info_t *local = (struct local_info_t *)s->private;
812
813 if (local->stop)
814 return -EIO;
815
816 data[0] = inb(dev->iobase + DAQP_DIGITAL_IO);
817
818 return 1;
819}
820
821
822
823static int daqp_do_insn_write(struct comedi_device *dev,
824 struct comedi_subdevice *s,
825 struct comedi_insn *insn, unsigned int *data)
826{
827 struct local_info_t *local = (struct local_info_t *)s->private;
828
829 if (local->stop)
830 return -EIO;
831
832 outw(data[0] & 0xf, dev->iobase + DAQP_DIGITAL_IO);
833
834 return 1;
835}
836
837
838
839
840
841
842
843static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
844{
845 int ret;
846 struct local_info_t *local = dev_table[it->options[0]];
847 struct comedi_subdevice *s;
848
849 if (it->options[0] < 0 || it->options[0] >= MAX_DEV || !local) {
850 printk("comedi%d: No such daqp device %d\n",
851 dev->minor, it->options[0]);
852 return -EIO;
853 }
854
855
856
857
858
859
860
861
862
863 strcpy(local->board_name, "DAQP");
864 dev->board_name = local->board_name;
865 if (local->link->prod_id[2]) {
866 if (strncmp(local->link->prod_id[2], "DAQP", 4) == 0) {
867 strncpy(local->board_name, local->link->prod_id[2],
868 sizeof(local->board_name));
869 }
870 }
871
872 dev->iobase = local->link->resource[0]->start;
873
874 ret = alloc_subdevices(dev, 4);
875 if (ret < 0)
876 return ret;
877
878 printk(KERN_INFO "comedi%d: attaching daqp%d (io 0x%04lx)\n",
879 dev->minor, it->options[0], dev->iobase);
880
881 s = dev->subdevices + 0;
882 dev->read_subdev = s;
883 s->private = local;
884 s->type = COMEDI_SUBD_AI;
885 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
886 s->n_chan = 8;
887 s->len_chanlist = 2048;
888 s->maxdata = 0xffff;
889 s->range_table = &range_daqp_ai;
890 s->insn_read = daqp_ai_insn_read;
891 s->do_cmdtest = daqp_ai_cmdtest;
892 s->do_cmd = daqp_ai_cmd;
893 s->cancel = daqp_ai_cancel;
894
895 s = dev->subdevices + 1;
896 dev->write_subdev = s;
897 s->private = local;
898 s->type = COMEDI_SUBD_AO;
899 s->subdev_flags = SDF_WRITEABLE;
900 s->n_chan = 2;
901 s->len_chanlist = 1;
902 s->maxdata = 0x0fff;
903 s->range_table = &range_daqp_ao;
904 s->insn_write = daqp_ao_insn_write;
905
906 s = dev->subdevices + 2;
907 s->private = local;
908 s->type = COMEDI_SUBD_DI;
909 s->subdev_flags = SDF_READABLE;
910 s->n_chan = 1;
911 s->len_chanlist = 1;
912 s->insn_read = daqp_di_insn_read;
913
914 s = dev->subdevices + 3;
915 s->private = local;
916 s->type = COMEDI_SUBD_DO;
917 s->subdev_flags = SDF_WRITEABLE;
918 s->n_chan = 1;
919 s->len_chanlist = 1;
920 s->insn_write = daqp_do_insn_write;
921
922 return 1;
923}
924
925
926
927
928
929static int daqp_detach(struct comedi_device *dev)
930{
931 printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor);
932
933 return 0;
934}
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971static void daqp_cs_config(struct pcmcia_device *link);
972static void daqp_cs_release(struct pcmcia_device *link);
973static int daqp_cs_suspend(struct pcmcia_device *p_dev);
974static int daqp_cs_resume(struct pcmcia_device *p_dev);
975
976static int daqp_cs_attach(struct pcmcia_device *);
977static void daqp_cs_detach(struct pcmcia_device *);
978
979static int daqp_cs_attach(struct pcmcia_device *link)
980{
981 struct local_info_t *local;
982 int i;
983
984 dev_dbg(&link->dev, "daqp_cs_attach()\n");
985
986 for (i = 0; i < MAX_DEV; i++)
987 if (dev_table[i] == NULL)
988 break;
989 if (i == MAX_DEV) {
990 printk(KERN_NOTICE "daqp_cs: no devices available\n");
991 return -ENODEV;
992 }
993
994
995 local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL);
996 if (!local)
997 return -ENOMEM;
998
999 local->table_index = i;
1000 dev_table[i] = local;
1001 local->link = link;
1002 link->priv = local;
1003
1004 daqp_cs_config(link);
1005
1006 return 0;
1007}
1008
1009static void daqp_cs_detach(struct pcmcia_device *link)
1010{
1011 struct local_info_t *dev = link->priv;
1012
1013 dev_dbg(&link->dev, "daqp_cs_detach\n");
1014
1015 dev->stop = 1;
1016 daqp_cs_release(link);
1017
1018
1019 dev_table[dev->table_index] = NULL;
1020 kfree(dev);
1021
1022}
1023
1024static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
1025{
1026 if (p_dev->config_index == 0)
1027 return -EINVAL;
1028
1029 return pcmcia_request_io(p_dev);
1030}
1031
1032static void daqp_cs_config(struct pcmcia_device *link)
1033{
1034 int ret;
1035
1036 dev_dbg(&link->dev, "daqp_cs_config\n");
1037
1038 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
1039
1040 ret = pcmcia_loop_config(link, daqp_pcmcia_config_loop, NULL);
1041 if (ret) {
1042 dev_warn(&link->dev, "no configuration found\n");
1043 goto failed;
1044 }
1045
1046 ret = pcmcia_request_irq(link, daqp_interrupt);
1047 if (ret)
1048 goto failed;
1049
1050 ret = pcmcia_enable_device(link);
1051 if (ret)
1052 goto failed;
1053
1054 return;
1055
1056failed:
1057 daqp_cs_release(link);
1058
1059}
1060
1061static void daqp_cs_release(struct pcmcia_device *link)
1062{
1063 dev_dbg(&link->dev, "daqp_cs_release\n");
1064
1065 pcmcia_disable_device(link);
1066}
1067
1068static int daqp_cs_suspend(struct pcmcia_device *link)
1069{
1070 struct local_info_t *local = link->priv;
1071
1072
1073 local->stop = 1;
1074 return 0;
1075}
1076
1077static int daqp_cs_resume(struct pcmcia_device *link)
1078{
1079 struct local_info_t *local = link->priv;
1080
1081 local->stop = 0;
1082
1083 return 0;
1084}
1085
1086
1087
1088#ifdef MODULE
1089
1090static struct pcmcia_device_id daqp_cs_id_table[] = {
1091 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0027),
1092 PCMCIA_DEVICE_NULL
1093};
1094
1095MODULE_DEVICE_TABLE(pcmcia, daqp_cs_id_table);
1096MODULE_AUTHOR("Brent Baccala <baccala@freesoft.org>");
1097MODULE_DESCRIPTION("Comedi driver for Quatech DAQP PCMCIA data capture cards");
1098MODULE_LICENSE("GPL");
1099
1100static struct pcmcia_driver daqp_cs_driver = {
1101 .probe = daqp_cs_attach,
1102 .remove = daqp_cs_detach,
1103 .suspend = daqp_cs_suspend,
1104 .resume = daqp_cs_resume,
1105 .id_table = daqp_cs_id_table,
1106 .owner = THIS_MODULE,
1107 .name = "quatech_daqp_cs",
1108};
1109
1110int __init init_module(void)
1111{
1112 pcmcia_register_driver(&daqp_cs_driver);
1113 comedi_driver_register(&driver_daqp);
1114 return 0;
1115}
1116
1117void __exit cleanup_module(void)
1118{
1119 comedi_driver_unregister(&driver_daqp);
1120 pcmcia_unregister_driver(&daqp_cs_driver);
1121}
1122
1123#endif
1124