Added some ack'ing of b interrupts, and do acks before handling
[comedi.git] / comedi / drivers / fl512.c
1 /*
2     comedi/drivers/fl512.c
3     Anders Gnistrup <ex18@kalman.iau.dtu.dk>
4 */
5
6 /*
7 Driver: fl512.o
8 Description: unknown
9 Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
10 Devices: [unknown] FL512 (fl512)
11 Status: unknown
12
13 Digital I/O is not supported.
14
15 Configuration options:
16   [0] - I/O port base address
17 */
18
19 #define DEBUG 0
20
21 #include <linux/comedidev.h>
22
23 #include <linux/delay.h>
24 #include <linux/ioport.h>
25
26 #define FL512_SIZE 16               /* the size of the used memory */
27 typedef struct {
28   sampl_t ao_readback[2];
29 } fl512_private;
30 #define devpriv ((fl512_private *) dev->private)
31
32 static comedi_lrange range_fl512 =
33 { 4, {
34   BIP_RANGE(0.5),
35   BIP_RANGE(1),
36   BIP_RANGE(5),
37   BIP_RANGE(10),
38   UNI_RANGE(1),
39   UNI_RANGE(5),
40   UNI_RANGE(10),
41 }};
42
43 static int fl512_attach(comedi_device *dev,comedi_devconfig *it);
44 static int fl512_detach(comedi_device *dev);
45
46 static comedi_driver driver_fl512 = {
47  driver_name: "fl512",
48  module:  THIS_MODULE,
49  attach:  fl512_attach,
50  detach:  fl512_detach,
51 };
52 COMEDI_INITCLEANUP(driver_fl512);
53
54 static int fl512_ai_insn(comedi_device *dev,
55       comedi_subdevice *s,
56       comedi_insn *insn,
57       lsampl_t *data);
58 static int fl512_ao_insn(comedi_device *dev,
59       comedi_subdevice *s,
60       comedi_insn *insn,
61       lsampl_t *data);
62 static int fl512_ao_insn_readback(comedi_device *dev,
63       comedi_subdevice *s,
64       comedi_insn *insn,
65       lsampl_t *data);
66
67 /*
68  * fl512_ai_insn : this is the analog input function
69  */
70 static int fl512_ai_insn(comedi_device *dev,
71       comedi_subdevice *s,
72       comedi_insn *insn,
73       lsampl_t *data)
74 {
75   int n;
76   unsigned int lo_byte, hi_byte;
77   char chan = CR_CHAN(insn->chanspec);
78   unsigned long iobase = dev->iobase;
79
80   for(n=0; n<insn->n; n++) {          /* sample n times on selected channel */
81     /* XXX probably can move next step out of for() loop -- will make
82      * AI a little bit faster. */
83     outb(chan,iobase+2);              /* select chan */
84     outb(0,iobase+3);                 /* start conversion */
85     /* XXX should test "done" flag instead of delay */
86     comedi_udelay(30);                       /* sleep 30 usec */
87     lo_byte = inb(iobase+2);          /* low 8 byte */
88     hi_byte = inb(iobase+3) & 0xf;    /* high 4 bit and mask */
89     data[n] = lo_byte + (hi_byte << 8);
90   }
91   return n;
92 }
93
94 /*
95  * fl512_ao_insn : used to write to a DA port n times
96  */
97 static int fl512_ao_insn(comedi_device *dev,
98       comedi_subdevice *s,
99       comedi_insn *insn,
100       lsampl_t *data)
101 {
102   int n;
103   int chan = CR_CHAN(insn->chanspec);                  /* get chan to write */
104   unsigned long iobase = dev->iobase;                  /* get base address  */
105
106   for (n=0; n<insn->n; n++) {                            /* write n data set */
107     outb(data[n] & 0x0ff, iobase+4+2*chan);            /* write low byte   */
108     outb((data[n] & 0xf00) >> 8, iobase+4+2*chan);     /* write high byte  */
109     inb(iobase+4+2*chan);                              /* trig */
110
111     devpriv->ao_readback[chan]=data[n];
112   }
113   return n;
114 }
115
116 /*
117  * fl512_ao_insn_readback : used to read previous values written to
118  * DA port
119  */
120 static int fl512_ao_insn_readback(comedi_device *dev,
121       comedi_subdevice *s,
122       comedi_insn *insn,
123       lsampl_t *data)
124 {
125   int n;
126   int chan = CR_CHAN(insn->chanspec);
127
128   for (n=0; n<insn->n; n++) {
129     data[n] = devpriv->ao_readback[chan];
130   }
131
132   return n;
133 }
134
135 /*
136  * start attach
137  */
138 static int fl512_attach(comedi_device *dev,comedi_devconfig *it)
139 {
140   unsigned long iobase;
141   comedi_subdevice *s;      /* pointer to the subdevice:
142           Analog in, Analog out, ( not made ->and Digital IO) */
143
144   iobase = it->options[0];
145   printk("comedi:%d fl512: 0x%04lx",dev->minor,iobase);
146   if (!request_region(iobase, FL512_SIZE, "fl512")) {
147     printk(" I/O port conflict\n");
148     return -EIO;
149   }
150   dev->iobase = iobase;
151   dev->board_name = "fl512";
152   if(alloc_private(dev,sizeof(fl512_private)) < 0)
153     return -ENOMEM;
154
155 #if DEBUG
156   printk("malloc ok\n");
157 #endif
158
159   if(alloc_subdevices(dev, 2)<0)
160     return -ENOMEM;
161
162   /*
163    * this if the definitions of the supdevices, 2 have been defined
164    */
165   /* Analog indput */
166   s                = dev->subdevices+0;
167   s->type          = COMEDI_SUBD_AI;         /* define subdevice as Analog In   */
168   s->subdev_flags  = SDF_READABLE|SDF_GROUND;/* you can read it from userspace  */
169   s->n_chan        = 16;                     /* Number of Analog input channels */
170   s->maxdata       = 0x0fff;                 /* accept only 12 bits of data     */
171   s->range_table   = &range_fl512;           /* device use one of the ranges    */
172   s->insn_read     = fl512_ai_insn;          /* function to call when read AD   */
173   printk("comedi: fl512: subdevice 0 initialized\n");
174
175   /* Analog output */
176   s                = dev->subdevices+1;
177   s->type          = COMEDI_SUBD_AO;         /* define subdevice as Analog OUT   */
178   s->subdev_flags  = SDF_WRITABLE;          /* you can write it from userspace  */
179   s->n_chan        = 2;                      /* Number of Analog output channels */
180   s->maxdata       = 0x0fff;                 /* accept only 12 bits of data      */
181   s->range_table   = &range_fl512;           /* device use one of the ranges     */
182   s->insn_write    = fl512_ao_insn;          /* function to call when write DA   */
183   s->insn_read     = fl512_ao_insn_readback; /* function to call when reading DA   */
184   printk("comedi: fl512: subdevice 1 initialized\n");
185
186   return 1;
187 }
188
189 static int fl512_detach(comedi_device *dev)
190 {
191   if (dev->iobase) release_region(dev->iobase,FL512_SIZE);
192   printk("comedi%d: fl512: dummy i detach\n",dev->minor);
193   return 0;
194 }
195
196