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#include <linux/module.h>
43
44#include "../comedi_pcmcia.h"
45
46
47
48
49
50
51
52
53
54
55#define DAQP_AI_FIFO_REG 0x00
56
57#define DAQP_SCANLIST_REG 0x01
58#define DAQP_SCANLIST_DIFFERENTIAL BIT(14)
59#define DAQP_SCANLIST_GAIN(x) (((x) & 0x3) << 12)
60#define DAQP_SCANLIST_CHANNEL(x) (((x) & 0xf) << 8)
61#define DAQP_SCANLIST_START BIT(7)
62#define DAQP_SCANLIST_EXT_GAIN(x) (((x) & 0x3) << 4)
63#define DAQP_SCANLIST_EXT_CHANNEL(x) (((x) & 0xf) << 0)
64
65#define DAQP_CTRL_REG 0x02
66#define DAQP_CTRL_PACER_CLK(x) (((x) & 0x3) << 6)
67#define DAQP_CTRL_PACER_CLK_EXT DAQP_CTRL_PACER_CLK(0)
68#define DAQP_CTRL_PACER_CLK_5MHZ DAQP_CTRL_PACER_CLK(1)
69#define DAQP_CTRL_PACER_CLK_1MHZ DAQP_CTRL_PACER_CLK(2)
70#define DAQP_CTRL_PACER_CLK_100KHZ DAQP_CTRL_PACER_CLK(3)
71#define DAQP_CTRL_EXPANSION BIT(5)
72#define DAQP_CTRL_EOS_INT_ENA BIT(4)
73#define DAQP_CTRL_FIFO_INT_ENA BIT(3)
74#define DAQP_CTRL_TRIG_MODE BIT(2)
75#define DAQP_CTRL_TRIG_SRC BIT(1)
76#define DAQP_CTRL_TRIG_EDGE BIT(0)
77
78#define DAQP_STATUS_REG 0x02
79#define DAQP_STATUS_IDLE BIT(7)
80#define DAQP_STATUS_RUNNING BIT(6)
81#define DAQP_STATUS_DATA_LOST BIT(5)
82#define DAQP_STATUS_END_OF_SCAN BIT(4)
83#define DAQP_STATUS_FIFO_THRESHOLD BIT(3)
84#define DAQP_STATUS_FIFO_FULL BIT(2)
85#define DAQP_STATUS_FIFO_NEARFULL BIT(1)
86#define DAQP_STATUS_FIFO_EMPTY BIT(0)
87
88#define DAQP_STATUS_EVENTS (DAQP_STATUS_DATA_LOST | \
89 DAQP_STATUS_END_OF_SCAN | \
90 DAQP_STATUS_FIFO_THRESHOLD)
91
92#define DAQP_DI_REG 0x03
93#define DAQP_DO_REG 0x03
94
95#define DAQP_PACER_LOW_REG 0x04
96#define DAQP_PACER_MID_REG 0x05
97#define DAQP_PACER_HIGH_REG 0x06
98
99#define DAQP_CMD_REG 0x07
100
101#define DAQP_CMD_ARM BIT(7)
102#define DAQP_CMD_RSTF BIT(6)
103#define DAQP_CMD_RSTQ BIT(5)
104#define DAQP_CMD_STOP BIT(4)
105#define DAQP_CMD_LATCH BIT(3)
106#define DAQP_CMD_SCANRATE(x) (((x) & 0x3) << 1)
107#define DAQP_CMD_SCANRATE_100KHZ DAQP_CMD_SCANRATE(0)
108#define DAQP_CMD_SCANRATE_50KHZ DAQP_CMD_SCANRATE(1)
109#define DAQP_CMD_SCANRATE_25KHZ DAQP_CMD_SCANRATE(2)
110#define DAQP_CMD_FIFO_DATA BIT(0)
111
112#define DAQP_AO_REG 0x08
113
114#define DAQP_TIMER_REG 0x0a
115
116#define DAQP_AUX_REG 0x0f
117
118#define DAQP_AUX_EXT_ANALOG_TRIG BIT(7)
119#define DAQP_AUX_PRETRIG BIT(6)
120#define DAQP_AUX_TIMER_INT_ENA BIT(5)
121#define DAQP_AUX_TIMER_MODE(x) (((x) & 0x3) << 3)
122#define DAQP_AUX_TIMER_MODE_RELOAD DAQP_AUX_TIMER_MODE(0)
123#define DAQP_AUX_TIMER_MODE_PAUSE DAQP_AUX_TIMER_MODE(1)
124#define DAQP_AUX_TIMER_MODE_GO DAQP_AUX_TIMER_MODE(2)
125#define DAQP_AUX_TIMER_MODE_EXT DAQP_AUX_TIMER_MODE(3)
126#define DAQP_AUX_TIMER_CLK_SRC_EXT BIT(2)
127#define DAQP_AUX_DA_UPDATE(x) (((x) & 0x3) << 0)
128#define DAQP_AUX_DA_UPDATE_DIRECT DAQP_AUX_DA_UPDATE(0)
129#define DAQP_AUX_DA_UPDATE_OVERFLOW DAQP_AUX_DA_UPDATE(1)
130#define DAQP_AUX_DA_UPDATE_EXTERNAL DAQP_AUX_DA_UPDATE(2)
131#define DAQP_AUX_DA_UPDATE_PACER DAQP_AUX_DA_UPDATE(3)
132
133#define DAQP_AUX_RUNNING BIT(7)
134#define DAQP_AUX_TRIGGERED BIT(6)
135#define DAQP_AUX_DA_BUFFER BIT(5)
136#define DAQP_AUX_TIMER_OVERFLOW BIT(4)
137#define DAQP_AUX_CONVERSION BIT(3)
138#define DAQP_AUX_DATA_LOST BIT(2)
139#define DAQP_AUX_FIFO_NEARFULL BIT(1)
140#define DAQP_AUX_FIFO_EMPTY BIT(0)
141
142#define DAQP_FIFO_SIZE 4096
143
144#define DAQP_MAX_TIMER_SPEED 10000
145
146struct daqp_private {
147 unsigned int pacer_div;
148 int stop;
149};
150
151static const struct comedi_lrange range_daqp_ai = {
152 4, {
153 BIP_RANGE(10),
154 BIP_RANGE(5),
155 BIP_RANGE(2.5),
156 BIP_RANGE(1.25)
157 }
158};
159
160static int daqp_clear_events(struct comedi_device *dev, int loops)
161{
162 unsigned int status;
163
164
165
166
167
168 while (--loops) {
169 status = inb(dev->iobase + DAQP_STATUS_REG);
170 if ((status & DAQP_STATUS_EVENTS) == 0)
171 return 0;
172 }
173 dev_err(dev->class_dev, "couldn't clear events in status register\n");
174 return -EBUSY;
175}
176
177static int daqp_ai_cancel(struct comedi_device *dev,
178 struct comedi_subdevice *s)
179{
180 struct daqp_private *devpriv = dev->private;
181
182 if (devpriv->stop)
183 return -EIO;
184
185
186
187
188
189 outb(DAQP_CMD_STOP, dev->iobase + DAQP_CMD_REG);
190 outb(0, dev->iobase + DAQP_CTRL_REG);
191 inb(dev->iobase + DAQP_STATUS_REG);
192
193 return 0;
194}
195
196static unsigned int daqp_ai_get_sample(struct comedi_device *dev,
197 struct comedi_subdevice *s)
198{
199 unsigned int val;
200
201
202
203
204
205 val = inb(dev->iobase + DAQP_AI_FIFO_REG);
206 val |= inb(dev->iobase + DAQP_AI_FIFO_REG) << 8;
207 return comedi_offset_munge(s, val);
208}
209
210static irqreturn_t daqp_interrupt(int irq, void *dev_id)
211{
212 struct comedi_device *dev = dev_id;
213 struct comedi_subdevice *s = dev->read_subdev;
214 struct comedi_cmd *cmd = &s->async->cmd;
215 int loop_limit = 10000;
216 int status;
217
218 if (!dev->attached)
219 return IRQ_NONE;
220
221 status = inb(dev->iobase + DAQP_STATUS_REG);
222 if (!(status & DAQP_STATUS_EVENTS))
223 return IRQ_NONE;
224
225 while (!(status & DAQP_STATUS_FIFO_EMPTY)) {
226 unsigned short data;
227
228 if (status & DAQP_STATUS_DATA_LOST) {
229 s->async->events |= COMEDI_CB_OVERFLOW;
230 dev_warn(dev->class_dev, "data lost\n");
231 break;
232 }
233
234 data = daqp_ai_get_sample(dev, s);
235 comedi_buf_write_samples(s, &data, 1);
236
237 if (cmd->stop_src == TRIG_COUNT &&
238 s->async->scans_done >= cmd->stop_arg) {
239 s->async->events |= COMEDI_CB_EOA;
240 break;
241 }
242
243 if ((loop_limit--) <= 0)
244 break;
245
246 status = inb(dev->iobase + DAQP_STATUS_REG);
247 }
248
249 if (loop_limit <= 0) {
250 dev_warn(dev->class_dev,
251 "loop_limit reached in %s()\n", __func__);
252 s->async->events |= COMEDI_CB_ERROR;
253 }
254
255 comedi_handle_events(dev, s);
256
257 return IRQ_HANDLED;
258}
259
260static void daqp_ai_set_one_scanlist_entry(struct comedi_device *dev,
261 unsigned int chanspec,
262 int start)
263{
264 unsigned int chan = CR_CHAN(chanspec);
265 unsigned int range = CR_RANGE(chanspec);
266 unsigned int aref = CR_AREF(chanspec);
267 unsigned int val;
268
269 val = DAQP_SCANLIST_CHANNEL(chan) | DAQP_SCANLIST_GAIN(range);
270
271 if (aref == AREF_DIFF)
272 val |= DAQP_SCANLIST_DIFFERENTIAL;
273
274 if (start)
275 val |= DAQP_SCANLIST_START;
276
277 outb(val & 0xff, dev->iobase + DAQP_SCANLIST_REG);
278 outb((val >> 8) & 0xff, dev->iobase + DAQP_SCANLIST_REG);
279}
280
281static int daqp_ai_eos(struct comedi_device *dev,
282 struct comedi_subdevice *s,
283 struct comedi_insn *insn,
284 unsigned long context)
285{
286 unsigned int status;
287
288 status = inb(dev->iobase + DAQP_AUX_REG);
289 if (status & DAQP_AUX_CONVERSION)
290 return 0;
291 return -EBUSY;
292}
293
294static int daqp_ai_insn_read(struct comedi_device *dev,
295 struct comedi_subdevice *s,
296 struct comedi_insn *insn,
297 unsigned int *data)
298{
299 struct daqp_private *devpriv = dev->private;
300 int ret = 0;
301 int i;
302
303 if (devpriv->stop)
304 return -EIO;
305
306 outb(0, dev->iobase + DAQP_AUX_REG);
307
308
309 outb(DAQP_CMD_RSTQ, dev->iobase + DAQP_CMD_REG);
310
311
312 daqp_ai_set_one_scanlist_entry(dev, insn->chanspec, 1);
313
314
315 outb(DAQP_CMD_RSTF, dev->iobase + DAQP_CMD_REG);
316
317
318 outb(DAQP_CTRL_PACER_CLK_100KHZ, dev->iobase + DAQP_CTRL_REG);
319
320 ret = daqp_clear_events(dev, 10000);
321 if (ret)
322 return ret;
323
324 for (i = 0; i < insn->n; i++) {
325
326 outb(DAQP_CMD_ARM | DAQP_CMD_FIFO_DATA,
327 dev->iobase + DAQP_CMD_REG);
328
329 ret = comedi_timeout(dev, s, insn, daqp_ai_eos, 0);
330 if (ret)
331 break;
332
333
334 inb(dev->iobase + DAQP_STATUS_REG);
335
336 data[i] = daqp_ai_get_sample(dev, s);
337 }
338
339
340 outb(DAQP_CMD_STOP, dev->iobase + DAQP_CMD_REG);
341 inb(dev->iobase + DAQP_STATUS_REG);
342
343 return ret ? ret : insn->n;
344}
345
346
347
348
349
350
351
352
353static int daqp_ns_to_timer(unsigned int *ns, unsigned int flags)
354{
355 int timer;
356
357 timer = *ns / 200;
358 *ns = timer * 200;
359
360 return timer;
361}
362
363static void daqp_set_pacer(struct comedi_device *dev, unsigned int val)
364{
365 outb(val & 0xff, dev->iobase + DAQP_PACER_LOW_REG);
366 outb((val >> 8) & 0xff, dev->iobase + DAQP_PACER_MID_REG);
367 outb((val >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH_REG);
368}
369
370static int daqp_ai_cmdtest(struct comedi_device *dev,
371 struct comedi_subdevice *s,
372 struct comedi_cmd *cmd)
373{
374 struct daqp_private *devpriv = dev->private;
375 int err = 0;
376 unsigned int arg;
377
378
379
380 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
381 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
382 TRIG_TIMER | TRIG_FOLLOW);
383 err |= comedi_check_trigger_src(&cmd->convert_src,
384 TRIG_TIMER | TRIG_NOW);
385 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
386 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
387
388 if (err)
389 return 1;
390
391
392
393 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
394 err |= comedi_check_trigger_is_unique(cmd->convert_src);
395 err |= comedi_check_trigger_is_unique(cmd->stop_src);
396
397
398
399
400 if (cmd->scan_begin_src != TRIG_TIMER && cmd->convert_src != TRIG_TIMER)
401 err |= -EINVAL;
402
403 if (err)
404 return 2;
405
406
407
408 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
409
410 err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
411 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
412 cmd->chanlist_len);
413
414 if (cmd->scan_begin_src == TRIG_TIMER)
415 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
416 DAQP_MAX_TIMER_SPEED);
417
418 if (cmd->convert_src == TRIG_TIMER) {
419 err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
420 DAQP_MAX_TIMER_SPEED);
421
422 if (cmd->scan_begin_src == TRIG_TIMER) {
423
424
425
426
427
428
429 arg = cmd->convert_arg * cmd->scan_end_arg;
430 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg,
431 arg);
432 }
433 }
434
435 if (cmd->stop_src == TRIG_COUNT)
436 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
437 else
438 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
439
440 if (err)
441 return 3;
442
443
444
445 if (cmd->convert_src == TRIG_TIMER) {
446 arg = cmd->convert_arg;
447 devpriv->pacer_div = daqp_ns_to_timer(&arg, cmd->flags);
448 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
449 } else if (cmd->scan_begin_src == TRIG_TIMER) {
450 arg = cmd->scan_begin_arg;
451 devpriv->pacer_div = daqp_ns_to_timer(&arg, cmd->flags);
452 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
453 }
454
455 if (err)
456 return 4;
457
458 return 0;
459}
460
461static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
462{
463 struct daqp_private *devpriv = dev->private;
464 struct comedi_cmd *cmd = &s->async->cmd;
465 int scanlist_start_on_every_entry;
466 int threshold;
467 int ret;
468 int i;
469
470 if (devpriv->stop)
471 return -EIO;
472
473 outb(0, dev->iobase + DAQP_AUX_REG);
474
475
476 outb(DAQP_CMD_RSTQ, dev->iobase + DAQP_CMD_REG);
477
478
479
480
481
482
483
484
485
486
487
488
489
490 daqp_set_pacer(dev, devpriv->pacer_div);
491
492 if (cmd->convert_src == TRIG_TIMER)
493 scanlist_start_on_every_entry = 1;
494 else
495 scanlist_start_on_every_entry = 0;
496
497
498 for (i = 0; i < cmd->chanlist_len; i++) {
499 int start = (i == 0 || scanlist_start_on_every_entry);
500
501 daqp_ai_set_one_scanlist_entry(dev, cmd->chanlist[i], start);
502 }
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570 if (cmd->stop_src == TRIG_COUNT) {
571 unsigned long long nsamples;
572 unsigned long long nbytes;
573
574 nsamples = (unsigned long long)cmd->stop_arg *
575 cmd->scan_end_arg;
576 nbytes = nsamples * comedi_bytes_per_sample(s);
577 while (nbytes > DAQP_FIFO_SIZE * 3 / 4)
578 nbytes /= 2;
579 threshold = nbytes;
580 } else {
581 threshold = DAQP_FIFO_SIZE / 2;
582 }
583
584
585
586 outb(DAQP_CMD_RSTF, dev->iobase + DAQP_CMD_REG);
587
588
589
590
591
592
593
594
595
596 outb(0x00, dev->iobase + DAQP_AI_FIFO_REG);
597 outb(0x00, dev->iobase + DAQP_AI_FIFO_REG);
598
599 outb((DAQP_FIFO_SIZE - threshold) & 0xff,
600 dev->iobase + DAQP_AI_FIFO_REG);
601 outb((DAQP_FIFO_SIZE - threshold) >> 8, dev->iobase + DAQP_AI_FIFO_REG);
602
603
604 outb(DAQP_CTRL_TRIG_MODE | DAQP_CTRL_PACER_CLK_5MHZ |
605 DAQP_CTRL_FIFO_INT_ENA, dev->iobase + DAQP_CTRL_REG);
606
607 ret = daqp_clear_events(dev, 100);
608 if (ret)
609 return ret;
610
611
612 outb(DAQP_CMD_ARM | DAQP_CMD_FIFO_DATA, dev->iobase + DAQP_CMD_REG);
613
614 return 0;
615}
616
617static int daqp_ao_empty(struct comedi_device *dev,
618 struct comedi_subdevice *s,
619 struct comedi_insn *insn,
620 unsigned long context)
621{
622 unsigned int status;
623
624 status = inb(dev->iobase + DAQP_AUX_REG);
625 if ((status & DAQP_AUX_DA_BUFFER) == 0)
626 return 0;
627 return -EBUSY;
628}
629
630static int daqp_ao_insn_write(struct comedi_device *dev,
631 struct comedi_subdevice *s,
632 struct comedi_insn *insn,
633 unsigned int *data)
634{
635 struct daqp_private *devpriv = dev->private;
636 unsigned int chan = CR_CHAN(insn->chanspec);
637 int i;
638
639 if (devpriv->stop)
640 return -EIO;
641
642
643 outb(0, dev->iobase + DAQP_AUX_REG);
644
645 for (i = 0; i < insn->n; i++) {
646 unsigned int val = data[i];
647 int ret;
648
649
650 ret = comedi_timeout(dev, s, insn, daqp_ao_empty, 0);
651 if (ret)
652 return ret;
653
654
655 outw((chan << 12) | comedi_offset_munge(s, val),
656 dev->iobase + DAQP_AO_REG);
657
658 s->readback[chan] = val;
659 }
660
661 return insn->n;
662}
663
664static int daqp_di_insn_bits(struct comedi_device *dev,
665 struct comedi_subdevice *s,
666 struct comedi_insn *insn,
667 unsigned int *data)
668{
669 struct daqp_private *devpriv = dev->private;
670
671 if (devpriv->stop)
672 return -EIO;
673
674 data[0] = inb(dev->iobase + DAQP_DI_REG);
675
676 return insn->n;
677}
678
679static int daqp_do_insn_bits(struct comedi_device *dev,
680 struct comedi_subdevice *s,
681 struct comedi_insn *insn,
682 unsigned int *data)
683{
684 struct daqp_private *devpriv = dev->private;
685
686 if (devpriv->stop)
687 return -EIO;
688
689 if (comedi_dio_update_state(s, data))
690 outb(s->state, dev->iobase + DAQP_DO_REG);
691
692 data[1] = s->state;
693
694 return insn->n;
695}
696
697static int daqp_auto_attach(struct comedi_device *dev,
698 unsigned long context)
699{
700 struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
701 struct daqp_private *devpriv;
702 struct comedi_subdevice *s;
703 int ret;
704
705 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
706 if (!devpriv)
707 return -ENOMEM;
708
709 link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
710 ret = comedi_pcmcia_enable(dev, NULL);
711 if (ret)
712 return ret;
713 dev->iobase = link->resource[0]->start;
714
715 link->priv = dev;
716 ret = pcmcia_request_irq(link, daqp_interrupt);
717 if (ret == 0)
718 dev->irq = link->irq;
719
720 ret = comedi_alloc_subdevices(dev, 4);
721 if (ret)
722 return ret;
723
724 s = &dev->subdevices[0];
725 s->type = COMEDI_SUBD_AI;
726 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
727 s->n_chan = 8;
728 s->maxdata = 0xffff;
729 s->range_table = &range_daqp_ai;
730 s->insn_read = daqp_ai_insn_read;
731 if (dev->irq) {
732 dev->read_subdev = s;
733 s->subdev_flags |= SDF_CMD_READ;
734 s->len_chanlist = 2048;
735 s->do_cmdtest = daqp_ai_cmdtest;
736 s->do_cmd = daqp_ai_cmd;
737 s->cancel = daqp_ai_cancel;
738 }
739
740 s = &dev->subdevices[1];
741 s->type = COMEDI_SUBD_AO;
742 s->subdev_flags = SDF_WRITABLE;
743 s->n_chan = 2;
744 s->maxdata = 0x0fff;
745 s->range_table = &range_bipolar5;
746 s->insn_write = daqp_ao_insn_write;
747
748 ret = comedi_alloc_subdev_readback(s);
749 if (ret)
750 return ret;
751
752
753
754
755
756
757
758
759
760
761
762
763 s = &dev->subdevices[2];
764 s->type = COMEDI_SUBD_DI;
765 s->subdev_flags = SDF_READABLE;
766 s->n_chan = 4;
767 s->maxdata = 1;
768 s->insn_bits = daqp_di_insn_bits;
769
770
771
772
773
774
775
776
777 s = &dev->subdevices[3];
778 s->type = COMEDI_SUBD_DO;
779 s->subdev_flags = SDF_WRITABLE;
780 s->n_chan = 4;
781 s->maxdata = 1;
782 s->insn_bits = daqp_do_insn_bits;
783
784 return 0;
785}
786
787static struct comedi_driver driver_daqp = {
788 .driver_name = "quatech_daqp_cs",
789 .module = THIS_MODULE,
790 .auto_attach = daqp_auto_attach,
791 .detach = comedi_pcmcia_disable,
792};
793
794static int daqp_cs_suspend(struct pcmcia_device *link)
795{
796 struct comedi_device *dev = link->priv;
797 struct daqp_private *devpriv = dev ? dev->private : NULL;
798
799
800 if (devpriv)
801 devpriv->stop = 1;
802
803 return 0;
804}
805
806static int daqp_cs_resume(struct pcmcia_device *link)
807{
808 struct comedi_device *dev = link->priv;
809 struct daqp_private *devpriv = dev ? dev->private : NULL;
810
811 if (devpriv)
812 devpriv->stop = 0;
813
814 return 0;
815}
816
817static int daqp_cs_attach(struct pcmcia_device *link)
818{
819 return comedi_pcmcia_auto_config(link, &driver_daqp);
820}
821
822static const struct pcmcia_device_id daqp_cs_id_table[] = {
823 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0027),
824 PCMCIA_DEVICE_NULL
825};
826MODULE_DEVICE_TABLE(pcmcia, daqp_cs_id_table);
827
828static struct pcmcia_driver daqp_cs_driver = {
829 .name = "quatech_daqp_cs",
830 .owner = THIS_MODULE,
831 .id_table = daqp_cs_id_table,
832 .probe = daqp_cs_attach,
833 .remove = comedi_pcmcia_auto_unconfig,
834 .suspend = daqp_cs_suspend,
835 .resume = daqp_cs_resume,
836};
837module_comedi_pcmcia_driver(driver_daqp, daqp_cs_driver);
838
839MODULE_DESCRIPTION("Comedi driver for Quatech DAQP PCMCIA data capture cards");
840MODULE_AUTHOR("Brent Baccala <baccala@freesoft.org>");
841MODULE_LICENSE("GPL");
842