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