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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67#include <linux/interrupt.h>
68#include <linux/slab.h>
69#include "../comedidev.h"
70
71#include <linux/ioport.h>
72#include <linux/io.h>
73#include <asm/dma.h>
74
75#include "8253.h"
76#include "comedi_fc.h"
77
78#define A2150_SIZE 28
79#define A2150_DMA_BUFFER_SIZE 0xff00
80
81
82#undef A2150_DEBUG
83
84
85#define CONFIG_REG 0x0
86#define CHANNEL_BITS(x) ((x) & 0x7)
87#define CHANNEL_MASK 0x7
88#define CLOCK_SELECT_BITS(x) (((x) & 0x3) << 3)
89#define CLOCK_DIVISOR_BITS(x) (((x) & 0x3) << 5)
90#define CLOCK_MASK (0xf << 3)
91#define ENABLE0_BIT 0x80
92#define ENABLE1_BIT 0x100
93#define AC0_BIT 0x200
94#define AC1_BIT 0x400
95#define APD_BIT 0x800
96#define DPD_BIT 0x1000
97#define TRIGGER_REG 0x2
98#define POST_TRIGGER_BITS 0x2
99#define DELAY_TRIGGER_BITS 0x3
100#define HW_TRIG_EN 0x10
101#define FIFO_START_REG 0x6
102#define FIFO_RESET_REG 0x8
103#define FIFO_DATA_REG 0xa
104#define DMA_TC_CLEAR_REG 0xe
105#define STATUS_REG 0x12
106#define FNE_BIT 0x1
107#define OVFL_BIT 0x8
108#define EDAQ_BIT 0x10
109#define DCAL_BIT 0x20
110#define INTR_BIT 0x40
111#define DMA_TC_BIT 0x80
112#define ID_BITS(x) (((x) >> 8) & 0x3)
113#define IRQ_DMA_CNTRL_REG 0x12
114#define DMA_CHAN_BITS(x) ((x) & 0x7)
115#define DMA_EN_BIT 0x8
116#define IRQ_LVL_BITS(x) (((x) & 0xf) << 4)
117#define FIFO_INTR_EN_BIT 0x100
118#define FIFO_INTR_FHF_BIT 0x200
119#define DMA_INTR_EN_BIT 0x800
120#define DMA_DEM_EN_BIT 0x1000
121#define I8253_BASE_REG 0x14
122#define I8253_MODE_REG 0x17
123#define HW_COUNT_DISABLE 0x30
124
125struct a2150_board {
126 const char *name;
127 int clock[4];
128 int num_clocks;
129 int ai_speed;
130};
131
132
133static const struct comedi_lrange range_a2150 = {
134 1,
135 {
136 RANGE(-2.828, 2.828),
137 }
138};
139
140
141enum { a2150_c, a2150_s };
142static const struct a2150_board a2150_boards[] = {
143 {
144 .name = "at-a2150c",
145 .clock = {31250, 22676, 20833, 19531},
146 .num_clocks = 4,
147 .ai_speed = 19531,
148 },
149 {
150 .name = "at-a2150s",
151 .clock = {62500, 50000, 41667, 0},
152 .num_clocks = 3,
153 .ai_speed = 41667,
154 },
155};
156
157
158
159
160#define thisboard ((const struct a2150_board *)dev->board_ptr)
161
162struct a2150_private {
163
164 volatile unsigned int count;
165 unsigned int dma;
166 s16 *dma_buffer;
167 unsigned int dma_transfer_size;
168 int irq_dma_bits;
169 int config_bits;
170};
171
172#define devpriv ((struct a2150_private *)dev->private)
173
174static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
175
176static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
177 int flags);
178static int a2150_set_chanlist(struct comedi_device *dev,
179 unsigned int start_channel,
180 unsigned int num_channels);
181#ifdef A2150_DEBUG
182
183static void ni_dump_regs(struct comedi_device *dev)
184{
185 printk("config bits 0x%x\n", devpriv->config_bits);
186 printk("irq dma bits 0x%x\n", devpriv->irq_dma_bits);
187 printk("status bits 0x%x\n", inw(dev->iobase + STATUS_REG));
188}
189
190#endif
191
192
193static irqreturn_t a2150_interrupt(int irq, void *d)
194{
195 int i;
196 int status;
197 unsigned long flags;
198 struct comedi_device *dev = d;
199 struct comedi_subdevice *s = dev->read_subdev;
200 struct comedi_async *async;
201 struct comedi_cmd *cmd;
202 unsigned int max_points, num_points, residue, leftover;
203 short dpnt;
204 static const int sample_size = sizeof(devpriv->dma_buffer[0]);
205
206 if (dev->attached == 0) {
207 comedi_error(dev, "premature interrupt");
208 return IRQ_HANDLED;
209 }
210
211 async = s->async;
212 async->events = 0;
213 cmd = &async->cmd;
214
215 status = inw(dev->iobase + STATUS_REG);
216
217 if ((status & INTR_BIT) == 0) {
218 comedi_error(dev, "spurious interrupt");
219 return IRQ_NONE;
220 }
221
222 if (status & OVFL_BIT) {
223 comedi_error(dev, "fifo overflow");
224 a2150_cancel(dev, s);
225 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
226 }
227
228 if ((status & DMA_TC_BIT) == 0) {
229 comedi_error(dev, "caught non-dma interrupt? Aborting.");
230 a2150_cancel(dev, s);
231 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
232 comedi_event(dev, s);
233 return IRQ_HANDLED;
234 }
235
236 flags = claim_dma_lock();
237 disable_dma(devpriv->dma);
238
239
240 clear_dma_ff(devpriv->dma);
241
242
243 max_points = devpriv->dma_transfer_size / sample_size;
244
245
246
247
248 residue = get_dma_residue(devpriv->dma) / sample_size;
249 num_points = max_points - residue;
250 if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT)
251 num_points = devpriv->count;
252
253
254 leftover = 0;
255 if (cmd->stop_src == TRIG_NONE) {
256 leftover = devpriv->dma_transfer_size / sample_size;
257 } else if (devpriv->count > max_points) {
258 leftover = devpriv->count - max_points;
259 if (leftover > max_points)
260 leftover = max_points;
261 }
262
263
264
265
266 if (residue)
267 leftover = 0;
268
269 for (i = 0; i < num_points; i++) {
270
271 dpnt = devpriv->dma_buffer[i];
272
273 dpnt ^= 0x8000;
274 cfc_write_to_buffer(s, dpnt);
275 if (cmd->stop_src == TRIG_COUNT) {
276 if (--devpriv->count == 0) {
277 a2150_cancel(dev, s);
278 async->events |= COMEDI_CB_EOA;
279 break;
280 }
281 }
282 }
283
284 if (leftover) {
285 set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer));
286 set_dma_count(devpriv->dma, leftover * sample_size);
287 enable_dma(devpriv->dma);
288 }
289 release_dma_lock(flags);
290
291 async->events |= COMEDI_CB_BLOCK;
292
293 comedi_event(dev, s);
294
295
296 outw(0x00, dev->iobase + DMA_TC_CLEAR_REG);
297
298 return IRQ_HANDLED;
299}
300
301static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
302{
303
304 devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT;
305 outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
306
307
308 disable_dma(devpriv->dma);
309
310
311 outw(0, dev->iobase + FIFO_RESET_REG);
312
313 return 0;
314}
315
316static int a2150_ai_cmdtest(struct comedi_device *dev,
317 struct comedi_subdevice *s, struct comedi_cmd *cmd)
318{
319 int err = 0;
320 int tmp;
321 int startChan;
322 int i;
323
324
325
326 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
327 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
328 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
329 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
330 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
331
332 if (err)
333 return 1;
334
335
336
337 err |= cfc_check_trigger_is_unique(cmd->start_src);
338 err |= cfc_check_trigger_is_unique(cmd->stop_src);
339
340
341
342 if (err)
343 return 2;
344
345
346
347 if (cmd->start_arg != 0) {
348 cmd->start_arg = 0;
349 err++;
350 }
351 if (cmd->convert_src == TRIG_TIMER) {
352 if (cmd->convert_arg < thisboard->ai_speed) {
353 cmd->convert_arg = thisboard->ai_speed;
354 err++;
355 }
356 }
357 if (!cmd->chanlist_len) {
358 cmd->chanlist_len = 1;
359 err++;
360 }
361 if (cmd->scan_end_arg != cmd->chanlist_len) {
362 cmd->scan_end_arg = cmd->chanlist_len;
363 err++;
364 }
365 if (cmd->stop_src == TRIG_COUNT) {
366 if (!cmd->stop_arg) {
367 cmd->stop_arg = 1;
368 err++;
369 }
370 } else {
371 if (cmd->stop_arg != 0) {
372 cmd->stop_arg = 0;
373 err++;
374 }
375 }
376
377 if (err)
378 return 3;
379
380
381
382 if (cmd->scan_begin_src == TRIG_TIMER) {
383 tmp = cmd->scan_begin_arg;
384 a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags);
385 if (tmp != cmd->scan_begin_arg)
386 err++;
387 }
388
389 if (err)
390 return 4;
391
392
393 if (cmd->chanlist) {
394 startChan = CR_CHAN(cmd->chanlist[0]);
395 for (i = 1; i < cmd->chanlist_len; i++) {
396 if (CR_CHAN(cmd->chanlist[i]) != (startChan + i)) {
397 comedi_error(dev,
398 "entries in chanlist must be consecutive channels, counting upwards\n");
399 err++;
400 }
401 }
402 if (cmd->chanlist_len == 2 && CR_CHAN(cmd->chanlist[0]) == 1) {
403 comedi_error(dev,
404 "length 2 chanlist must be channels 0,1 or channels 2,3");
405 err++;
406 }
407 if (cmd->chanlist_len == 3) {
408 comedi_error(dev,
409 "chanlist must have 1,2 or 4 channels");
410 err++;
411 }
412 if (CR_AREF(cmd->chanlist[0]) != CR_AREF(cmd->chanlist[1]) ||
413 CR_AREF(cmd->chanlist[2]) != CR_AREF(cmd->chanlist[3])) {
414 comedi_error(dev,
415 "channels 0/1 and 2/3 must have the same analog reference");
416 err++;
417 }
418 }
419
420 if (err)
421 return 5;
422
423 return 0;
424}
425
426static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
427{
428 struct comedi_async *async = s->async;
429 struct comedi_cmd *cmd = &async->cmd;
430 unsigned long lock_flags;
431 unsigned int old_config_bits = devpriv->config_bits;
432 unsigned int trigger_bits;
433
434 if (!dev->irq || !devpriv->dma) {
435 comedi_error(dev,
436 " irq and dma required, cannot do hardware conversions");
437 return -1;
438 }
439 if (cmd->flags & TRIG_RT) {
440 comedi_error(dev,
441 " dma incompatible with hard real-time interrupt (TRIG_RT), aborting");
442 return -1;
443 }
444
445 outw(0, dev->iobase + FIFO_RESET_REG);
446
447
448 if (a2150_set_chanlist(dev, CR_CHAN(cmd->chanlist[0]),
449 cmd->chanlist_len) < 0)
450 return -1;
451
452
453 if (CR_AREF(cmd->chanlist[0]) == AREF_OTHER)
454 devpriv->config_bits |= AC0_BIT;
455 else
456 devpriv->config_bits &= ~AC0_BIT;
457 if (CR_AREF(cmd->chanlist[2]) == AREF_OTHER)
458 devpriv->config_bits |= AC1_BIT;
459 else
460 devpriv->config_bits &= ~AC1_BIT;
461
462
463 a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags);
464
465
466 outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
467
468
469 devpriv->count = cmd->stop_arg * cmd->chanlist_len;
470
471
472 lock_flags = claim_dma_lock();
473 disable_dma(devpriv->dma);
474
475
476 clear_dma_ff(devpriv->dma);
477 set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer));
478
479#define ONE_THIRD_SECOND 333333333
480 devpriv->dma_transfer_size =
481 sizeof(devpriv->dma_buffer[0]) * cmd->chanlist_len *
482 ONE_THIRD_SECOND / cmd->scan_begin_arg;
483 if (devpriv->dma_transfer_size > A2150_DMA_BUFFER_SIZE)
484 devpriv->dma_transfer_size = A2150_DMA_BUFFER_SIZE;
485 if (devpriv->dma_transfer_size < sizeof(devpriv->dma_buffer[0]))
486 devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]);
487 devpriv->dma_transfer_size -=
488 devpriv->dma_transfer_size % sizeof(devpriv->dma_buffer[0]);
489 set_dma_count(devpriv->dma, devpriv->dma_transfer_size);
490 enable_dma(devpriv->dma);
491 release_dma_lock(lock_flags);
492
493
494
495 outw(0x00, dev->iobase + DMA_TC_CLEAR_REG);
496
497
498 devpriv->irq_dma_bits |= DMA_INTR_EN_BIT | DMA_EN_BIT;
499 outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
500
501
502 i8254_load(dev->iobase + I8253_BASE_REG, 0, 2, 72, 0);
503
504
505 trigger_bits = 0;
506
507 if (cmd->start_src == TRIG_NOW &&
508 (old_config_bits & CLOCK_MASK) !=
509 (devpriv->config_bits & CLOCK_MASK)) {
510
511 trigger_bits |= DELAY_TRIGGER_BITS;
512 } else {
513
514 trigger_bits |= POST_TRIGGER_BITS;
515 }
516
517 if (cmd->start_src == TRIG_EXT) {
518 trigger_bits |= HW_TRIG_EN;
519 } else if (cmd->start_src == TRIG_OTHER) {
520
521 comedi_error(dev, "you shouldn't see this?");
522 }
523
524 outw(trigger_bits, dev->iobase + TRIGGER_REG);
525
526
527 if (cmd->start_src == TRIG_NOW)
528 outw(0, dev->iobase + FIFO_START_REG);
529#ifdef A2150_DEBUG
530 ni_dump_regs(dev);
531#endif
532
533 return 0;
534}
535
536static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
537 struct comedi_insn *insn, unsigned int *data)
538{
539 unsigned int i, n;
540 static const int timeout = 100000;
541 static const int filter_delay = 36;
542
543
544 outw(0, dev->iobase + FIFO_RESET_REG);
545
546
547 if (a2150_set_chanlist(dev, CR_CHAN(insn->chanspec), 1) < 0)
548 return -1;
549
550
551 devpriv->config_bits &= ~AC0_BIT;
552 devpriv->config_bits &= ~AC1_BIT;
553
554
555 outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
556
557
558 devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT;
559 outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
560
561
562 outw(0, dev->iobase + TRIGGER_REG);
563
564
565 outw(0, dev->iobase + FIFO_START_REG);
566
567
568
569
570
571 for (n = 0; n < filter_delay; n++) {
572 for (i = 0; i < timeout; i++) {
573 if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
574 break;
575 udelay(1);
576 }
577 if (i == timeout) {
578 comedi_error(dev, "timeout");
579 return -ETIME;
580 }
581 inw(dev->iobase + FIFO_DATA_REG);
582 }
583
584
585 for (n = 0; n < insn->n; n++) {
586 for (i = 0; i < timeout; i++) {
587 if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
588 break;
589 udelay(1);
590 }
591 if (i == timeout) {
592 comedi_error(dev, "timeout");
593 return -ETIME;
594 }
595#ifdef A2150_DEBUG
596 ni_dump_regs(dev);
597#endif
598 data[n] = inw(dev->iobase + FIFO_DATA_REG);
599#ifdef A2150_DEBUG
600 printk(" data is %i\n", data[n]);
601#endif
602 data[n] ^= 0x8000;
603 }
604
605
606 outw(0, dev->iobase + FIFO_RESET_REG);
607
608 return n;
609}
610
611
612
613
614
615static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
616 int flags)
617{
618 int lub, glb, temp;
619 int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index;
620 int i, j;
621
622
623 lub_divisor_shift = 3;
624 lub_index = 0;
625 lub = thisboard->clock[lub_index] * (1 << lub_divisor_shift);
626 glb_divisor_shift = 0;
627 glb_index = thisboard->num_clocks - 1;
628 glb = thisboard->clock[glb_index] * (1 << glb_divisor_shift);
629
630
631 if (*period < glb)
632 *period = glb;
633 if (*period > lub)
634 *period = lub;
635
636
637 for (i = 0; i < 4; i++) {
638
639 for (j = 0; j < thisboard->num_clocks; j++) {
640
641 temp = thisboard->clock[j] * (1 << i);
642
643 if (temp < lub && temp >= *period) {
644 lub_divisor_shift = i;
645 lub_index = j;
646 lub = temp;
647 }
648 if (temp > glb && temp <= *period) {
649 glb_divisor_shift = i;
650 glb_index = j;
651 glb = temp;
652 }
653 }
654 }
655 flags &= TRIG_ROUND_MASK;
656 switch (flags) {
657 case TRIG_ROUND_NEAREST:
658 default:
659
660 if (lub - *period < *period - glb)
661 *period = lub;
662 else
663 *period = glb;
664 break;
665 case TRIG_ROUND_UP:
666 *period = lub;
667 break;
668 case TRIG_ROUND_DOWN:
669 *period = glb;
670 break;
671 }
672
673
674 devpriv->config_bits &= ~CLOCK_MASK;
675 if (*period == lub) {
676 devpriv->config_bits |=
677 CLOCK_SELECT_BITS(lub_index) |
678 CLOCK_DIVISOR_BITS(lub_divisor_shift);
679 } else {
680 devpriv->config_bits |=
681 CLOCK_SELECT_BITS(glb_index) |
682 CLOCK_DIVISOR_BITS(glb_divisor_shift);
683 }
684
685 return 0;
686}
687
688static int a2150_set_chanlist(struct comedi_device *dev,
689 unsigned int start_channel,
690 unsigned int num_channels)
691{
692 if (start_channel + num_channels > 4)
693 return -1;
694
695 devpriv->config_bits &= ~CHANNEL_MASK;
696
697 switch (num_channels) {
698 case 1:
699 devpriv->config_bits |= CHANNEL_BITS(0x4 | start_channel);
700 break;
701 case 2:
702 if (start_channel == 0) {
703 devpriv->config_bits |= CHANNEL_BITS(0x2);
704 } else if (start_channel == 2) {
705 devpriv->config_bits |= CHANNEL_BITS(0x3);
706 } else {
707 return -1;
708 }
709 break;
710 case 4:
711 devpriv->config_bits |= CHANNEL_BITS(0x1);
712 break;
713 default:
714 return -1;
715 break;
716 }
717
718 return 0;
719}
720
721
722static int a2150_probe(struct comedi_device *dev)
723{
724 int status = inw(dev->iobase + STATUS_REG);
725 return ID_BITS(status);
726}
727
728static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
729{
730 struct comedi_subdevice *s;
731 unsigned long iobase = it->options[0];
732 unsigned int irq = it->options[1];
733 unsigned int dma = it->options[2];
734 static const int timeout = 2000;
735 int i;
736 int ret;
737
738 printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name,
739 iobase);
740 if (irq) {
741 printk(", irq %u", irq);
742 } else {
743 printk(", no irq");
744 }
745 if (dma) {
746 printk(", dma %u", dma);
747 } else {
748 printk(", no dma");
749 }
750 printk("\n");
751
752
753 if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
754 return -ENOMEM;
755
756 if (iobase == 0) {
757 printk(" io base address required\n");
758 return -EINVAL;
759 }
760
761
762 if (!request_region(iobase, A2150_SIZE, dev->driver->driver_name)) {
763 printk(" I/O port conflict\n");
764 return -EIO;
765 }
766 dev->iobase = iobase;
767
768
769 if (irq) {
770
771 if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
772 printk(" invalid irq line %u\n", irq);
773 return -EINVAL;
774 }
775 if (request_irq(irq, a2150_interrupt, 0,
776 dev->driver->driver_name, dev)) {
777 printk("unable to allocate irq %u\n", irq);
778 return -EINVAL;
779 }
780 devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
781 dev->irq = irq;
782 }
783
784 if (dma) {
785 if (dma == 4 || dma > 7) {
786 printk(" invalid dma channel %u\n", dma);
787 return -EINVAL;
788 }
789 if (request_dma(dma, dev->driver->driver_name)) {
790 printk(" failed to allocate dma channel %u\n", dma);
791 return -EINVAL;
792 }
793 devpriv->dma = dma;
794 devpriv->dma_buffer =
795 kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
796 if (devpriv->dma_buffer == NULL)
797 return -ENOMEM;
798
799 disable_dma(dma);
800 set_dma_mode(dma, DMA_MODE_READ);
801
802 devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
803 }
804
805 dev->board_ptr = a2150_boards + a2150_probe(dev);
806 dev->board_name = thisboard->name;
807
808 ret = comedi_alloc_subdevices(dev, 1);
809 if (ret)
810 return ret;
811
812
813 s = &dev->subdevices[0];
814 dev->read_subdev = s;
815 s->type = COMEDI_SUBD_AI;
816 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
817 s->n_chan = 4;
818 s->len_chanlist = 4;
819 s->maxdata = 0xffff;
820 s->range_table = &range_a2150;
821 s->do_cmd = a2150_ai_cmd;
822 s->do_cmdtest = a2150_ai_cmdtest;
823 s->insn_read = a2150_ai_rinsn;
824 s->cancel = a2150_cancel;
825
826
827
828 outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
829
830
831 outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
832
833
834 outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
835 outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
836
837 devpriv->config_bits = 0;
838 outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
839
840 for (i = 0; i < timeout; i++) {
841 if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
842 break;
843 udelay(1000);
844 }
845 if (i == timeout) {
846 printk
847 (" timed out waiting for offset calibration to complete\n");
848 return -ETIME;
849 }
850 devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
851 outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
852
853 return 0;
854};
855
856static void a2150_detach(struct comedi_device *dev)
857{
858 if (dev->iobase) {
859 outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
860 release_region(dev->iobase, A2150_SIZE);
861 }
862 if (dev->irq)
863 free_irq(dev->irq, dev);
864 if (devpriv) {
865 if (devpriv->dma)
866 free_dma(devpriv->dma);
867 kfree(devpriv->dma_buffer);
868 }
869};
870
871static struct comedi_driver ni_at_a2150_driver = {
872 .driver_name = "ni_at_a2150",
873 .module = THIS_MODULE,
874 .attach = a2150_attach,
875 .detach = a2150_detach,
876};
877module_comedi_driver(ni_at_a2150_driver);
878
879MODULE_AUTHOR("Comedi http://www.comedi.org");
880MODULE_DESCRIPTION("Comedi low-level driver");
881MODULE_LICENSE("GPL");
882