1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/module.h>
25#include <linux/interrupt.h>
26
27#include "../comedi_pci.h"
28#include "amcc_s5933.h"
29#include "z8536.h"
30
31
32
33
34
35
36
37
38
39
40#define APCI1500_Z8536_PORTC_REG 0x00
41#define APCI1500_Z8536_PORTB_REG 0x01
42#define APCI1500_Z8536_PORTA_REG 0x02
43#define APCI1500_Z8536_CTRL_REG 0x03
44
45
46
47
48#define APCI1500_CLK_SEL_REG 0x00
49#define APCI1500_DI_REG 0x00
50#define APCI1500_DO_REG 0x02
51
52struct apci1500_private {
53 unsigned long amcc;
54 unsigned long addon;
55
56 unsigned int clk_src;
57
58
59 unsigned int pm[2];
60 unsigned int pt[2];
61 unsigned int pp[2];
62};
63
64static unsigned int z8536_read(struct comedi_device *dev, unsigned int reg)
65{
66 unsigned long flags;
67 unsigned int val;
68
69 spin_lock_irqsave(&dev->spinlock, flags);
70 outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
71 val = inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
72 spin_unlock_irqrestore(&dev->spinlock, flags);
73
74 return val;
75}
76
77static void z8536_write(struct comedi_device *dev,
78 unsigned int val, unsigned int reg)
79{
80 unsigned long flags;
81
82 spin_lock_irqsave(&dev->spinlock, flags);
83 outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
84 outb(val, dev->iobase + APCI1500_Z8536_CTRL_REG);
85 spin_unlock_irqrestore(&dev->spinlock, flags);
86}
87
88static void z8536_reset(struct comedi_device *dev)
89{
90 unsigned long flags;
91
92
93
94
95
96 spin_lock_irqsave(&dev->spinlock, flags);
97 inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
98 outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
99 inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
100 outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
101 outb(1, dev->iobase + APCI1500_Z8536_CTRL_REG);
102 outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
103 spin_unlock_irqrestore(&dev->spinlock, flags);
104
105
106 z8536_write(dev, 0x00, Z8536_CFG_CTRL_REG);
107
108
109
110
111
112 z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
113 Z8536_PAB_MODE_SB |
114 Z8536_PAB_MODE_PMS_DISABLE,
115 Z8536_PA_MODE_REG);
116 z8536_write(dev, 0xff, Z8536_PB_DPP_REG);
117 z8536_write(dev, 0xff, Z8536_PA_DD_REG);
118
119
120
121
122
123
124
125
126 z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
127 Z8536_PAB_MODE_SB |
128 Z8536_PAB_MODE_PMS_DISABLE,
129 Z8536_PB_MODE_REG);
130 z8536_write(dev, 0x7f, Z8536_PB_DPP_REG);
131 z8536_write(dev, 0xff, Z8536_PB_DD_REG);
132
133
134
135
136 z8536_write(dev, 0x09, Z8536_PC_DPP_REG);
137 z8536_write(dev, 0x0e, Z8536_PC_DD_REG);
138
139
140
141
142
143
144
145 z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PA_CMDSTAT_REG);
146 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
147
148 z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PB_CMDSTAT_REG);
149 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
150
151 z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(0));
152 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(0));
153
154 z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(1));
155 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(1));
156
157 z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(2));
158 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(2));
159
160
161 z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
162}
163
164static void apci1500_port_enable(struct comedi_device *dev, bool enable)
165{
166 unsigned int cfg;
167
168 cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
169 if (enable)
170 cfg |= (Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
171 else
172 cfg &= ~(Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
173 z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
174}
175
176static void apci1500_timer_enable(struct comedi_device *dev,
177 unsigned int chan, bool enable)
178{
179 unsigned int bit;
180 unsigned int cfg;
181
182 if (chan == 0)
183 bit = Z8536_CFG_CTRL_CT1E;
184 else if (chan == 1)
185 bit = Z8536_CFG_CTRL_CT2E;
186 else
187 bit = Z8536_CFG_CTRL_PCE_CT3E;
188
189 cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
190 if (enable) {
191 cfg |= bit;
192 } else {
193 cfg &= ~bit;
194 z8536_write(dev, 0x00, Z8536_CT_CMDSTAT_REG(chan));
195 }
196 z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
197}
198
199static bool apci1500_ack_irq(struct comedi_device *dev,
200 unsigned int reg)
201{
202 unsigned int val;
203
204 val = z8536_read(dev, reg);
205 if ((val & Z8536_STAT_IE_IP) == Z8536_STAT_IE_IP) {
206 val &= 0x0f;
207 val |= Z8536_CMD_CLR_IP_IUS;
208 z8536_write(dev, val, reg);
209
210 return true;
211 }
212 return false;
213}
214
215static irqreturn_t apci1500_interrupt(int irq, void *d)
216{
217 struct comedi_device *dev = d;
218 struct apci1500_private *devpriv = dev->private;
219 struct comedi_subdevice *s = dev->read_subdev;
220 unsigned int status = 0;
221 unsigned int val;
222
223 val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
224 if (!(val & INTCSR_INTR_ASSERTED))
225 return IRQ_NONE;
226
227 if (apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG))
228 status |= 0x01;
229
230 if (apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG)) {
231
232 val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG);
233 val &= 0xc0;
234 if (val) {
235 if (val & 0x80)
236 status |= 0x40;
237 if (val & 0x40)
238 status |= 0x80;
239 } else {
240 status |= 0x02;
241 }
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259 comedi_buf_write_samples(s, &status, 1);
260 comedi_handle_events(dev, s);
261
262 return IRQ_HANDLED;
263}
264
265static int apci1500_di_cancel(struct comedi_device *dev,
266 struct comedi_subdevice *s)
267{
268
269 z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
270
271
272 apci1500_port_enable(dev, false);
273
274
275 apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG);
276 apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG);
277
278
279 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
280 z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
281
282
283 apci1500_port_enable(dev, true);
284
285 return 0;
286}
287
288static int apci1500_di_inttrig_start(struct comedi_device *dev,
289 struct comedi_subdevice *s,
290 unsigned int trig_num)
291{
292 struct apci1500_private *devpriv = dev->private;
293 struct comedi_cmd *cmd = &s->async->cmd;
294 unsigned int pa_mode = Z8536_PAB_MODE_PMS_DISABLE;
295 unsigned int pb_mode = Z8536_PAB_MODE_PMS_DISABLE;
296 unsigned int pa_trig = trig_num & 0x01;
297 unsigned int pb_trig = (trig_num >> 1) & 0x01;
298 bool valid_trig = false;
299 unsigned int val;
300
301 if (trig_num != cmd->start_arg)
302 return -EINVAL;
303
304
305 apci1500_port_enable(dev, false);
306
307
308 z8536_write(dev, devpriv->pm[pa_trig] & 0xff, Z8536_PA_PM_REG);
309 z8536_write(dev, devpriv->pt[pa_trig] & 0xff, Z8536_PA_PT_REG);
310 z8536_write(dev, devpriv->pp[pa_trig] & 0xff, Z8536_PA_PP_REG);
311
312
313 z8536_write(dev, (devpriv->pm[pb_trig] >> 8) & 0xff, Z8536_PB_PM_REG);
314 z8536_write(dev, (devpriv->pt[pb_trig] >> 8) & 0xff, Z8536_PB_PT_REG);
315 z8536_write(dev, (devpriv->pp[pb_trig] >> 8) & 0xff, Z8536_PB_PP_REG);
316
317
318 if (devpriv->pm[pa_trig] & 0xff) {
319 pa_mode = pa_trig ? Z8536_PAB_MODE_PMS_AND
320 : Z8536_PAB_MODE_PMS_OR;
321
322 val = z8536_read(dev, Z8536_PA_MODE_REG);
323 val &= ~Z8536_PAB_MODE_PMS_MASK;
324 val |= (pa_mode | Z8536_PAB_MODE_IMO);
325 z8536_write(dev, val, Z8536_PA_MODE_REG);
326
327 z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PA_CMDSTAT_REG);
328
329 valid_trig = true;
330
331 dev_dbg(dev->class_dev,
332 "Port A configured for %s mode pattern detection\n",
333 pa_trig ? "AND" : "OR");
334 }
335
336
337 if (devpriv->pm[pb_trig] & 0xff00) {
338 pb_mode = pb_trig ? Z8536_PAB_MODE_PMS_AND
339 : Z8536_PAB_MODE_PMS_OR;
340
341 val = z8536_read(dev, Z8536_PB_MODE_REG);
342 val &= ~Z8536_PAB_MODE_PMS_MASK;
343 val |= (pb_mode | Z8536_PAB_MODE_IMO);
344 z8536_write(dev, val, Z8536_PB_MODE_REG);
345
346 z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PB_CMDSTAT_REG);
347
348 valid_trig = true;
349
350 dev_dbg(dev->class_dev,
351 "Port B configured for %s mode pattern detection\n",
352 pb_trig ? "AND" : "OR");
353 }
354
355
356 apci1500_port_enable(dev, true);
357
358 if (!valid_trig) {
359 dev_dbg(dev->class_dev,
360 "digital trigger %d is not configured\n", trig_num);
361 return -EINVAL;
362 }
363
364
365 z8536_write(dev, Z8536_INT_CTRL_MIE | Z8536_INT_CTRL_DLC,
366 Z8536_INT_CTRL_REG);
367
368 return 0;
369}
370
371static int apci1500_di_cmd(struct comedi_device *dev,
372 struct comedi_subdevice *s)
373{
374 s->async->inttrig = apci1500_di_inttrig_start;
375
376 return 0;
377}
378
379static int apci1500_di_cmdtest(struct comedi_device *dev,
380 struct comedi_subdevice *s,
381 struct comedi_cmd *cmd)
382{
383 int err = 0;
384
385
386
387 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
388 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
389 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
390 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
391 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
392
393 if (err)
394 return 1;
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416 err |= comedi_check_trigger_arg_max(&cmd->start_arg, 3);
417
418 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
419 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
420 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
421 cmd->chanlist_len);
422 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
423
424 if (err)
425 return 3;
426
427
428
429
430
431 return 0;
432}
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456static int apci1500_di_cfg_trig(struct comedi_device *dev,
457 struct comedi_subdevice *s,
458 struct comedi_insn *insn,
459 unsigned int *data)
460{
461 struct apci1500_private *devpriv = dev->private;
462 unsigned int trig = data[1];
463 unsigned int shift = data[3];
464 unsigned int hi_mask = data[4] << shift;
465 unsigned int lo_mask = data[5] << shift;
466 unsigned int chan_mask = hi_mask | lo_mask;
467 unsigned int old_mask = (1 << shift) - 1;
468 unsigned int pm = devpriv->pm[trig] & old_mask;
469 unsigned int pt = devpriv->pt[trig] & old_mask;
470 unsigned int pp = devpriv->pp[trig] & old_mask;
471
472 if (trig > 1) {
473 dev_dbg(dev->class_dev,
474 "invalid digital trigger number (0=AND, 1=OR)\n");
475 return -EINVAL;
476 }
477
478 if (chan_mask > 0xffff) {
479 dev_dbg(dev->class_dev, "invalid digital trigger channel\n");
480 return -EINVAL;
481 }
482
483 switch (data[2]) {
484 case COMEDI_DIGITAL_TRIG_DISABLE:
485
486 pm = 0;
487 pt = 0;
488 pp = 0;
489 break;
490 case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
491 pm |= chan_mask;
492 pt |= chan_mask;
493 pp |= hi_mask;
494 pp &= ~lo_mask;
495 break;
496 case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
497 pm |= chan_mask;
498 pt &= ~chan_mask;
499 pp |= hi_mask;
500 pp &= ~lo_mask;
501 break;
502 default:
503 return -EINVAL;
504 }
505
506
507
508
509
510 if (trig == 0) {
511 int ret = 0;
512 unsigned int src;
513
514 src = pt & 0xff;
515 if (src)
516 ret |= comedi_check_trigger_is_unique(src);
517
518 src = (pt >> 8) & 0xff;
519 if (src)
520 ret |= comedi_check_trigger_is_unique(src);
521
522 if (ret) {
523 dev_dbg(dev->class_dev,
524 "invalid AND trigger configuration\n");
525 return ret;
526 }
527 }
528
529
530 devpriv->pm[trig] = pm;
531 devpriv->pt[trig] = pt;
532 devpriv->pp[trig] = pp;
533
534 return insn->n;
535}
536
537static int apci1500_di_insn_config(struct comedi_device *dev,
538 struct comedi_subdevice *s,
539 struct comedi_insn *insn,
540 unsigned int *data)
541{
542 switch (data[0]) {
543 case INSN_CONFIG_DIGITAL_TRIG:
544 return apci1500_di_cfg_trig(dev, s, insn, data);
545 default:
546 return -EINVAL;
547 }
548}
549
550static int apci1500_di_insn_bits(struct comedi_device *dev,
551 struct comedi_subdevice *s,
552 struct comedi_insn *insn,
553 unsigned int *data)
554{
555 struct apci1500_private *devpriv = dev->private;
556
557 data[1] = inw(devpriv->addon + APCI1500_DI_REG);
558
559 return insn->n;
560}
561
562static int apci1500_do_insn_bits(struct comedi_device *dev,
563 struct comedi_subdevice *s,
564 struct comedi_insn *insn,
565 unsigned int *data)
566{
567 struct apci1500_private *devpriv = dev->private;
568
569 if (comedi_dio_update_state(s, data))
570 outw(s->state, devpriv->addon + APCI1500_DO_REG);
571
572 data[1] = s->state;
573
574 return insn->n;
575}
576
577static int apci1500_timer_insn_config(struct comedi_device *dev,
578 struct comedi_subdevice *s,
579 struct comedi_insn *insn,
580 unsigned int *data)
581{
582 struct apci1500_private *devpriv = dev->private;
583 unsigned int chan = CR_CHAN(insn->chanspec);
584 unsigned int val;
585
586 switch (data[0]) {
587 case INSN_CONFIG_ARM:
588 val = data[1] & s->maxdata;
589 z8536_write(dev, val & 0xff, Z8536_CT_RELOAD_LSB_REG(chan));
590 z8536_write(dev, (val >> 8) & 0xff,
591 Z8536_CT_RELOAD_MSB_REG(chan));
592
593 apci1500_timer_enable(dev, chan, true);
594 z8536_write(dev, Z8536_CT_CMDSTAT_GCB,
595 Z8536_CT_CMDSTAT_REG(chan));
596 break;
597 case INSN_CONFIG_DISARM:
598 apci1500_timer_enable(dev, chan, false);
599 break;
600
601 case INSN_CONFIG_GET_COUNTER_STATUS:
602 data[1] = 0;
603 val = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
604 if (val & Z8536_CT_STAT_CIP)
605 data[1] |= COMEDI_COUNTER_COUNTING;
606 if (val & Z8536_CT_CMDSTAT_GCB)
607 data[1] |= COMEDI_COUNTER_ARMED;
608 if (val & Z8536_STAT_IP) {
609 data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
610 apci1500_ack_irq(dev, Z8536_CT_CMDSTAT_REG(chan));
611 }
612 data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
613 COMEDI_COUNTER_TERMINAL_COUNT;
614 break;
615
616 case INSN_CONFIG_SET_COUNTER_MODE:
617
618 switch (data[1]) {
619 case I8254_MODE0:
620
621 val = Z8536_CT_MODE_ECE |
622 Z8536_CT_MODE_DCS_ONESHOT;
623 break;
624 case I8254_MODE1:
625
626 val = Z8536_CT_MODE_ETE |
627 Z8536_CT_MODE_DCS_ONESHOT;
628 break;
629 case I8254_MODE2:
630
631 val = Z8536_CT_MODE_CSC |
632 Z8536_CT_MODE_DCS_PULSE;
633 break;
634 case I8254_MODE3:
635
636 val = Z8536_CT_MODE_CSC |
637 Z8536_CT_MODE_DCS_SQRWAVE;
638 break;
639 case I8254_MODE4:
640
641 val = Z8536_CT_MODE_REB |
642 Z8536_CT_MODE_DCS_PULSE;
643 break;
644 case I8254_MODE5:
645
646 val = Z8536_CT_MODE_EOE |
647 Z8536_CT_MODE_ETE |
648 Z8536_CT_MODE_REB |
649 Z8536_CT_MODE_DCS_PULSE;
650 break;
651 default:
652 return -EINVAL;
653 }
654 apci1500_timer_enable(dev, chan, false);
655 z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
656 break;
657
658 case INSN_CONFIG_SET_CLOCK_SRC:
659 if (data[1] > 2)
660 return -EINVAL;
661 devpriv->clk_src = data[1];
662 if (devpriv->clk_src == 2)
663 devpriv->clk_src = 3;
664 outw(devpriv->clk_src, devpriv->addon + APCI1500_CLK_SEL_REG);
665 break;
666 case INSN_CONFIG_GET_CLOCK_SRC:
667 switch (devpriv->clk_src) {
668 case 0:
669 data[1] = 0;
670 data[2] = 17879;
671 break;
672 case 1:
673 data[1] = 1;
674 data[2] = 573066;
675 break;
676 case 3:
677 data[1] = 2;
678 data[2] = 1164822;
679 break;
680 default:
681 return -EINVAL;
682 }
683 break;
684
685 case INSN_CONFIG_SET_GATE_SRC:
686 if (chan == 0)
687 return -EINVAL;
688
689 val = z8536_read(dev, Z8536_CT_MODE_REG(chan));
690 val &= Z8536_CT_MODE_EGE;
691 if (data[1] == 1)
692 val |= Z8536_CT_MODE_EGE;
693 else if (data[1] > 1)
694 return -EINVAL;
695 z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
696 break;
697 case INSN_CONFIG_GET_GATE_SRC:
698 if (chan == 0)
699 return -EINVAL;
700 break;
701
702 default:
703 return -EINVAL;
704 }
705 return insn->n;
706}
707
708static int apci1500_timer_insn_write(struct comedi_device *dev,
709 struct comedi_subdevice *s,
710 struct comedi_insn *insn,
711 unsigned int *data)
712{
713 unsigned int chan = CR_CHAN(insn->chanspec);
714 unsigned int cmd;
715
716 cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
717 cmd &= Z8536_CT_CMDSTAT_GCB;
718 cmd |= Z8536_CT_CMD_TCB;
719
720
721 if (insn->n)
722 z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
723
724 return insn->n;
725}
726
727static int apci1500_timer_insn_read(struct comedi_device *dev,
728 struct comedi_subdevice *s,
729 struct comedi_insn *insn,
730 unsigned int *data)
731{
732 unsigned int chan = CR_CHAN(insn->chanspec);
733 unsigned int cmd;
734 unsigned int val;
735 int i;
736
737 cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
738 cmd &= Z8536_CT_CMDSTAT_GCB;
739 cmd |= Z8536_CT_CMD_RCC;
740
741 for (i = 0; i < insn->n; i++) {
742 z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
743
744 val = z8536_read(dev, Z8536_CT_VAL_MSB_REG(chan)) << 8;
745 val |= z8536_read(dev, Z8536_CT_VAL_LSB_REG(chan));
746
747 data[i] = val;
748 }
749
750 return insn->n;
751}
752
753static int apci1500_auto_attach(struct comedi_device *dev,
754 unsigned long context)
755{
756 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
757 struct apci1500_private *devpriv;
758 struct comedi_subdevice *s;
759 int ret;
760
761 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
762 if (!devpriv)
763 return -ENOMEM;
764
765 ret = comedi_pci_enable(dev);
766 if (ret)
767 return ret;
768
769 dev->iobase = pci_resource_start(pcidev, 1);
770 devpriv->amcc = pci_resource_start(pcidev, 0);
771 devpriv->addon = pci_resource_start(pcidev, 2);
772
773 z8536_reset(dev);
774
775 if (pcidev->irq > 0) {
776 ret = request_irq(pcidev->irq, apci1500_interrupt, IRQF_SHARED,
777 dev->board_name, dev);
778 if (ret == 0)
779 dev->irq = pcidev->irq;
780 }
781
782 ret = comedi_alloc_subdevices(dev, 3);
783 if (ret)
784 return ret;
785
786
787 s = &dev->subdevices[0];
788 s->type = COMEDI_SUBD_DI;
789 s->subdev_flags = SDF_READABLE;
790 s->n_chan = 16;
791 s->maxdata = 1;
792 s->range_table = &range_digital;
793 s->insn_bits = apci1500_di_insn_bits;
794 if (dev->irq) {
795 dev->read_subdev = s;
796 s->subdev_flags |= SDF_CMD_READ;
797 s->len_chanlist = 1;
798 s->insn_config = apci1500_di_insn_config;
799 s->do_cmdtest = apci1500_di_cmdtest;
800 s->do_cmd = apci1500_di_cmd;
801 s->cancel = apci1500_di_cancel;
802 }
803
804
805 s = &dev->subdevices[1];
806 s->type = COMEDI_SUBD_DO;
807 s->subdev_flags = SDF_WRITABLE;
808 s->n_chan = 16;
809 s->maxdata = 1;
810 s->range_table = &range_digital;
811 s->insn_bits = apci1500_do_insn_bits;
812
813
814 outw(0x0, devpriv->addon + APCI1500_DO_REG);
815
816
817 s = &dev->subdevices[2];
818 s->type = COMEDI_SUBD_TIMER;
819 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
820 s->n_chan = 3;
821 s->maxdata = 0xffff;
822 s->range_table = &range_unknown;
823 s->insn_config = apci1500_timer_insn_config;
824 s->insn_write = apci1500_timer_insn_write;
825 s->insn_read = apci1500_timer_insn_read;
826
827
828 if (dev->irq) {
829 outl(0x2000 | INTCSR_INBOX_FULL_INT,
830 devpriv->amcc + AMCC_OP_REG_INTCSR);
831 inl(devpriv->amcc + AMCC_OP_REG_IMB1);
832 inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
833 outl(INTCSR_INBOX_INTR_STATUS | 0x2000 | INTCSR_INBOX_FULL_INT,
834 devpriv->amcc + AMCC_OP_REG_INTCSR);
835 }
836
837 return 0;
838}
839
840static void apci1500_detach(struct comedi_device *dev)
841{
842 struct apci1500_private *devpriv = dev->private;
843
844 if (devpriv->amcc)
845 outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
846 comedi_pci_detach(dev);
847}
848
849static struct comedi_driver apci1500_driver = {
850 .driver_name = "addi_apci_1500",
851 .module = THIS_MODULE,
852 .auto_attach = apci1500_auto_attach,
853 .detach = apci1500_detach,
854};
855
856static int apci1500_pci_probe(struct pci_dev *dev,
857 const struct pci_device_id *id)
858{
859 return comedi_pci_auto_config(dev, &apci1500_driver, id->driver_data);
860}
861
862static const struct pci_device_id apci1500_pci_table[] = {
863 { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80fc) },
864 { 0 }
865};
866MODULE_DEVICE_TABLE(pci, apci1500_pci_table);
867
868static struct pci_driver apci1500_pci_driver = {
869 .name = "addi_apci_1500",
870 .id_table = apci1500_pci_table,
871 .probe = apci1500_pci_probe,
872 .remove = comedi_pci_auto_unconfig,
873};
874module_comedi_pci_driver(apci1500_driver, apci1500_pci_driver);
875
876MODULE_AUTHOR("Comedi http://www.comedi.org");
877MODULE_DESCRIPTION("ADDI-DATA APCI-1500, 16 channel DI / 16 channel DO boards");
878MODULE_LICENSE("GPL");
879