Fix bugs noticed by check_driver
[comedi.git] / comedi / drivers / poc.c
1 /*
2     comedi/drivers/poc.c
3     Mini-drivers for POC (Piece of Crap) boards
4     Copyright (C) 2000 Frank Mori Hess <fmhess@uiuc.edu>
5     Copyright (C) 2001 David A. Schleef <ds@schleef.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22 Driver: poc.o
23 Description: Generic driver for very simple devices
24 Device names: dac02
25 Author: ds
26 Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733),
27   PCL-734 (pcl734)
28 Updated: Sat, 16 Mar 2002 17:34:48 -0800
29 Status: unknown
30
31 This driver is indended to support very simple ISA-based devices,
32 including:
33   dac02 - Keithley DAC-02 analog output board
34   pcl733 - Advantech PCL-733
35   pcl734 - Advantech PCL-734
36
37 Configuration options:
38   [0] - I/O port base
39 */
40
41 #include <linux/kernel.h>
42 #include <linux/module.h>
43 #include <linux/sched.h>
44 #include <linux/mm.h>
45 #include <linux/slab.h>
46 #include <linux/errno.h>
47 #include <linux/ioport.h>
48 #include <linux/delay.h>
49 #include <linux/interrupt.h>
50 #include <linux/timex.h>
51 #include <linux/timer.h>
52 #include <asm/io.h>
53 #include <linux/comedidev.h>
54
55 static int poc_attach(comedi_device *dev,comedi_devconfig *it);
56 static int poc_detach(comedi_device *dev);
57 static int readback_insn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
58
59 static int dac02_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
60 static int pcl733_insn_bits(comedi_device *dev,comedi_subdevice *s,
61         comedi_insn *insn,lsampl_t *data);
62 static int pcl734_insn_bits(comedi_device *dev,comedi_subdevice *s,
63         comedi_insn *insn,lsampl_t *data);
64
65 struct boarddef_struct{
66         char *name;
67         int iosize;
68         int (*setup)(comedi_device *);
69         int type;
70         int n_chan;
71         int n_bits;
72         int (*winsn)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *);
73         int (*rinsn)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *);
74         int (*insnbits)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *);
75         comedi_lrange* range;
76 };
77 static struct boarddef_struct boards[]={
78         {
79         name:           "dac02",
80         iosize:         8,
81         //setup:                dac02_setup,
82         type:           COMEDI_SUBD_AO,
83         n_chan:         2,
84         n_bits:         12,
85         winsn:          dac02_ao_winsn,
86         rinsn:          readback_insn,
87         range:          &range_unknown,
88         },
89         {
90         name:           "pcl733",
91         iosize:         4,
92         type:           COMEDI_SUBD_DI,
93         n_chan:         32,
94         n_bits:         1,
95         insnbits:       pcl733_insn_bits,
96         range:          &range_digital,
97         },
98         {
99         name:           "pcl734",
100         iosize:         4,
101         type:           COMEDI_SUBD_DO,
102         n_chan:         32,
103         n_bits:         1,
104         insnbits:       pcl734_insn_bits,
105         range:          &range_digital,
106         },
107 };
108 #define n_boards (sizeof(boards)/sizeof(boards[0]))
109 #define this_board ((struct boarddef_struct *)dev->board_ptr)
110
111 static comedi_driver driver_poc=
112 {
113         driver_name:    "poc",
114         module:         THIS_MODULE,
115         attach:         poc_attach,
116         detach:         poc_detach,
117         board_name:     boards,
118         num_names:      n_boards,
119         offset:         sizeof(boards[0]),
120 };
121
122 static int poc_attach(comedi_device *dev, comedi_devconfig *it)
123 {
124         comedi_subdevice *s;
125         int iosize, iobase;
126
127         iobase = it->options[0];
128         printk("comedi%d: poc: using %s iobase 0x%x\n", dev->minor,
129                 this_board->name, iobase);
130
131         dev->board_name = this_board->name;
132
133         if(iobase == 0)
134         {
135                 printk("io base address required\n");
136                 return -EINVAL;
137         }
138
139         iosize = this_board->iosize;
140         /* check if io addresses are available */
141         if(check_region(iobase, iosize) < 0)
142         {
143                 printk("I/O port conflict: failed to allocate ports 0x%x to 0x%x\n",
144                         iobase, iobase + iosize - 1);
145                 return -EIO;
146         }
147         request_region(iobase, iosize, "dac02");
148         dev->iobase = iobase;
149
150         dev->n_subdevices = 1;
151         if(alloc_subdevices(dev) < 0)
152                 return -ENOMEM;
153         if(alloc_private(dev,sizeof(lsampl_t)*this_board->n_chan) < 0)
154                 return -ENOMEM;
155
156         /* analog output subdevice */
157         s=dev->subdevices + 0;
158         s->type = this_board->type;
159         s->n_chan = this_board->n_chan;
160         s->maxdata = (1<<this_board->n_bits)-1;
161         s->range_table = this_board->range;
162         s->insn_write = this_board->winsn;
163         s->insn_read = this_board->rinsn;
164         s->insn_bits = this_board->insnbits;
165         if(s->type==COMEDI_SUBD_AO || s->type==COMEDI_SUBD_DO){
166                 s->subdev_flags = SDF_WRITABLE;
167         }
168
169         return 0;
170 }
171
172 static int poc_detach(comedi_device *dev)
173 {
174         /* only free stuff if it has been allocated by _attach */
175         if(dev->iobase)
176                 release_region(dev->iobase, this_board->iosize);
177
178         printk("comedi%d: dac02: remove\n", dev->minor);
179
180         return 0;
181 }
182
183 static int readback_insn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
184 {
185         int chan;
186
187         chan = CR_CHAN(insn->chanspec);
188         data[0]=((lsampl_t *)dev->private)[chan];
189
190         return 1;
191 }
192
193 /* DAC-02 registers */
194 #define DAC02_LSB(a)    (2 * a)
195 #define DAC02_MSB(a)    (2 * a + 1)
196
197 static int dac02_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
198 {
199         int temp;
200         int chan;
201         int output;
202
203         chan = CR_CHAN(insn->chanspec);
204         ((lsampl_t *)dev->private)[chan] = data[0];
205         output = data[0];
206 #if wrong
207         // convert to complementary binary if range is bipolar
208         if((CR_RANGE(insn->chanspec) & 0x2) == 0)
209                 output = ~output;
210 #endif
211         temp = (output << 4) & 0xf0;
212         outb(temp, dev->iobase + DAC02_LSB(chan));
213         temp = (output >> 4) & 0xff;
214         outb(temp, dev->iobase + DAC02_MSB(chan));
215
216         return 1;
217 }
218
219 static int pcl733_insn_bits(comedi_device *dev,comedi_subdevice *s,
220         comedi_insn *insn,lsampl_t *data)
221 {
222         if(insn->n!=2)return -EINVAL;
223         
224         data[1] = inb(dev->iobase + 0);
225         data[1] |= (inb(dev->iobase + 1) << 8);
226         data[1] |= (inb(dev->iobase + 2) << 16);
227         data[1] |= (inb(dev->iobase + 3) << 24);
228
229         return 2;
230 }
231
232 static int pcl734_insn_bits(comedi_device *dev,comedi_subdevice *s,
233         comedi_insn *insn,lsampl_t *data)
234 {
235         if(insn->n!=2)return -EINVAL;
236         if(data[0]){
237                 s->state &= ~data[0];
238                 s->state |= (data[0]&data[1]);
239                 if((data[0]>>0)&0xff)
240                         outb((s->state>>0)&0xff, dev->iobase + 0);
241                 if((data[0]>>8)&0xff)
242                         outb((s->state>>8)&0xff, dev->iobase + 1);
243                 if((data[0]>>16)&0xff)
244                         outb((s->state>>16)&0xff, dev->iobase + 2);
245                 if((data[0]>>24)&0xff)
246                         outb((s->state>>24)&0xff, dev->iobase + 3);
247         }
248         data[1] = s->state;
249
250         return 2;
251 }
252
253 COMEDI_INITCLEANUP(driver_poc);
254