Added some ack'ing of b interrupts, and do acks before handling
[comedi.git] / comedi / drivers / acl7225b.c
1 /*
2  * Driver for Adlink NuDAQ ACL-7225b and clones
3  * José Luis Sánchez
4  */
5 /*
6 Driver: acl7225b.o
7 Description: Adlink NuDAQ ACL-7225b & compatibles
8 Author: José Luis Sánchez (jsanchezv@teleline.es)
9 Status: testing
10 Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio)
11 */
12
13 #include <linux/comedidev.h>
14
15 #include <linux/ioport.h>
16
17 #define ACL7225_SIZE   8  /* Requires 8 ioports, but only 4 are used */
18 #define P16R16DIO_SIZE 4
19 #define ACL7225_RIO_LO 0  /* Relays input/output low byte (R0-R7) */
20 #define ACL7225_RIO_HI 1  /* Relays input/output high byte (R8-R15) */
21 #define ACL7225_DI_LO  2  /* Digital input low byte (DI0-DI7) */
22 #define ACL7225_DI_HI  3  /* Digital input high byte (DI8-DI15) */
23
24 static int acl7225b_attach(comedi_device *dev,comedi_devconfig *it);
25 static int acl7225b_detach(comedi_device *dev);
26
27 typedef struct {
28         char    *name;          // driver name
29         int             io_range;       // len of I/O space
30 } boardtype;
31
32 static boardtype boardtypes[] =
33 {
34         { "acl7225b",  ACL7225_SIZE, },
35         { "p16r16dio", P16R16DIO_SIZE, },
36 };
37 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
38 #define this_board ((boardtype *)dev->board_ptr)
39
40 static comedi_driver driver_acl7225b = {
41         driver_name:    "acl7225b",
42         module:         THIS_MODULE,
43         attach:         acl7225b_attach,
44         detach:         acl7225b_detach,
45         board_name: (const char**)boardtypes,
46         num_names:      n_boardtypes,
47         offset:         sizeof(boardtype),
48 };
49 COMEDI_INITCLEANUP(driver_acl7225b);
50
51 static int acl7225b_do_insn(comedi_device *dev,comedi_subdevice *s,
52         comedi_insn *insn,lsampl_t *data)
53 {
54         if( insn->n != 2 )
55         return -EINVAL;
56
57         if(data[0])
58     {
59                 s->state &= ~data[0];
60                 s->state |= (data[0] & data[1]);
61         }
62     if( data[0] & 0x00ff )
63         outb(s->state & 0xff, dev->iobase+(unsigned long)s->private);
64     if( data[0] & 0xff00 )
65         outb((s->state >> 8), dev->iobase+(unsigned long)s->private+1);
66
67         data[1]=s->state;
68
69         return 2;
70 }
71
72 static int acl7225b_di_insn(comedi_device *dev,comedi_subdevice *s,
73         comedi_insn *insn,lsampl_t *data)
74 {
75         if( insn->n != 2 )
76         return -EINVAL;
77
78         data[1]=inb(dev->iobase + (unsigned long)s->private) |
79         (inb(dev->iobase + (unsigned long)s->private+1) << 8);
80
81         return 2;
82 }
83
84 static int acl7225b_attach(comedi_device *dev,comedi_devconfig *it)
85 {
86         comedi_subdevice *s;
87         int iobase, iorange;
88
89         iobase=it->options[0];
90         iorange=this_board->io_range;
91         printk("comedi%d: acl7225b: board=%s 0x%04x ", dev->minor,
92            this_board->name, iobase);
93         if( !request_region(iobase, iorange, "acl7225b") ) {
94                 printk("I/O port conflict\n");
95                 return -EIO;
96         }
97         dev->board_name=this_board->name;
98         dev->iobase=iobase;
99         dev->irq=0;
100
101         if( alloc_subdevices(dev, 3) < 0 )
102                 return -ENOMEM;
103
104         s=dev->subdevices+0;
105         /* Relays outputs */
106         s->type=COMEDI_SUBD_DO;
107         s->subdev_flags=SDF_WRITABLE;
108         s->maxdata=1;
109         s->n_chan=16;
110         s->insn_bits = acl7225b_do_insn;
111         s->range_table=&range_digital;
112     s->private=(void *)ACL7225_RIO_LO;
113
114         s=dev->subdevices+1;
115         /* Relays status */
116         s->type=COMEDI_SUBD_DI;
117         s->subdev_flags=SDF_READABLE;
118         s->maxdata=1;
119         s->n_chan=16;
120         s->insn_bits = acl7225b_di_insn;
121         s->range_table=&range_digital;
122     s->private=(void *)ACL7225_RIO_LO;
123
124         s=dev->subdevices+2;
125         /* Isolated digital inputs */
126         s->type=COMEDI_SUBD_DI;
127         s->subdev_flags=SDF_READABLE;
128         s->maxdata=1;
129         s->n_chan=16;
130         s->insn_bits = acl7225b_di_insn;
131         s->range_table=&range_digital;
132     s->private=(void *)ACL7225_DI_LO;
133
134         printk("\n");
135
136         return 0;
137 }
138
139 static int acl7225b_detach(comedi_device *dev)
140 {
141         printk("comedi%d: acl7225b: remove\n",dev->minor);
142
143         if(dev->iobase)
144         release_region(dev->iobase, this_board->io_range);
145
146         return 0;
147 }