Added some ack'ing of b interrupts, and do acks before handling
[comedi.git] / comedi / drivers / dt2817.c
1 /*
2     module/dt2817.c
3     hardware driver for Data Translation DT2817
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1998 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: dt2817.o
25 Description: Data Translation DT2817
26 Author: ds
27 Status: complete
28 Devices: [Data Translation] DT2817 (dt2817)
29
30 A very simple digital I/O card.  Four banks of 8 lines, each bank
31 is configurable for input or output.  One wonders why it takes a
32 50 page manual to describe this thing.
33
34 The driver (which, btw, is much less than 50 pages) has 1 subdevice
35 with 32 channels, configurable in groups of 8.
36
37 Configuration options:
38   [0] - I/O port base base address
39 */
40
41 #include <linux/comedidev.h>
42
43 #include <linux/ioport.h>
44
45
46
47 #define DT2817_SIZE 5
48
49 #define DT2817_CR 0
50 #define DT2817_DATA 1
51
52
53 static int dt2817_attach(comedi_device *dev,comedi_devconfig *it);
54 static int dt2817_detach(comedi_device *dev);
55 static comedi_driver driver_dt2817={
56         driver_name:    "dt2817",
57         module:         THIS_MODULE,
58         attach:         dt2817_attach,
59         detach:         dt2817_detach,
60 };
61 COMEDI_INITCLEANUP(driver_dt2817);
62
63
64 static int dt2817_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
65         comedi_insn *insn,lsampl_t *data)
66 {
67         int mask;
68         int chan;
69         int oe=0;
70
71         if(insn->n!=1)return -EINVAL;
72
73         chan=CR_CHAN(insn->chanspec);
74         if(chan<8){
75                 mask=0xff;
76         }else if(chan<16){
77                 mask=0xff00;
78         }else if(chan<24){
79                 mask=0xff0000;
80         }else mask=0xff000000;
81         if(data[0])s->io_bits|=mask;
82         else s->io_bits&=~mask;
83
84         if(s->io_bits&0x000000ff)oe|=0x1;
85         if(s->io_bits&0x0000ff00)oe|=0x2;
86         if(s->io_bits&0x00ff0000)oe|=0x4;
87         if(s->io_bits&0xff000000)oe|=0x8;
88
89         outb(oe,dev->iobase + DT2817_CR);
90
91         return 1;
92 }
93
94 static int dt2817_dio_insn_bits(comedi_device *dev,comedi_subdevice *s,
95         comedi_insn *insn,lsampl_t *data)
96 {
97         unsigned int changed;
98
99         /* It's questionable whether it is more important in
100          * a driver like this to be deterministic or fast. 
101          * We choose fast. */
102
103         if(data[0]){
104                 changed = s->state;
105                 s->state &= ~data[0];
106                 s->state |= (data[0]&data[1]);
107                 changed ^= s->state;
108                 changed &= s->io_bits;
109                 if(changed&0x000000ff)
110                         outb(s->state&0xff, dev->iobase + DT2817_DATA+0);
111                 if(changed&0x0000ff00)
112                         outb((s->state>>8)&0xff, dev->iobase + DT2817_DATA+1);
113                 if(changed&0x00ff0000)
114                         outb((s->state>>16)&0xff, dev->iobase + DT2817_DATA+2);
115                 if(changed&0xff000000)
116                         outb((s->state>>24)&0xff, dev->iobase + DT2817_DATA+3);
117         }
118         data[1] = inb(dev->iobase + DT2817_DATA + 0);
119         data[1] |= (inb(dev->iobase + DT2817_DATA + 1)<<8);
120         data[1] |= (inb(dev->iobase + DT2817_DATA + 2)<<16);
121         data[1] |= (inb(dev->iobase + DT2817_DATA + 3)<<24);
122
123         return 2;
124 }
125
126 static int dt2817_attach(comedi_device *dev,comedi_devconfig *it)
127 {
128         int ret;
129         comedi_subdevice *s;
130         unsigned long iobase;
131
132         iobase=it->options[0];
133         printk("comedi%d: dt2817: 0x%04lx ",dev->minor,iobase);
134         if(!request_region(iobase,DT2817_SIZE,"dt2817")){
135                 printk("I/O port conflict\n");
136                 return -EIO;
137         }
138         dev->iobase = iobase;
139         dev->board_name="dt2817";
140
141         if((ret=alloc_subdevices(dev, 1))<0)
142                 return ret;
143
144         s=dev->subdevices+0;
145
146         s->n_chan=32;
147         s->type=COMEDI_SUBD_DIO;
148         s->subdev_flags=SDF_READABLE|SDF_WRITABLE;
149         s->range_table=&range_digital;
150         s->maxdata=1;
151         s->insn_bits=dt2817_dio_insn_bits;
152         s->insn_config=dt2817_dio_insn_config;
153
154         s->state=0;
155         outb(0,dev->iobase+DT2817_CR);
156
157         printk("\n");
158
159         return 0;
160 }
161
162
163 static int dt2817_detach(comedi_device *dev)
164 {
165         printk("comedi%d: dt2817: remove\n",dev->minor);
166         
167         if(dev->iobase)
168                 release_region(dev->iobase,DT2817_SIZE);
169
170         return 0;
171 }
172