Cleanups suggested by check_driver. Mostly leaky symbols, incorrect
[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)
27
28 This driver is indended to support very simple ISA-based devices,
29 including:
30   dac02 - Keithley DAC-02 analog output board
31
32 Configuration options:
33   [0] - I/O port base
34 */
35 /*
36     dac02 - Keithley DAC-02 analog output board driver
37
38 */
39
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <linux/sched.h>
43 #include <linux/mm.h>
44 #include <linux/slab.h>
45 #include <linux/errno.h>
46 #include <linux/ioport.h>
47 #include <linux/delay.h>
48 #include <linux/interrupt.h>
49 #include <linux/timex.h>
50 #include <linux/timer.h>
51 #include <asm/io.h>
52 #include <linux/comedidev.h>
53
54 /* DAC-02 registers */
55 #define DAC02_LSB(a)    (2 * a)
56 #define DAC02_MSB(a)    (2 * a + 1)
57
58 static int poc_attach(comedi_device *dev,comedi_devconfig *it);
59 static int poc_detach(comedi_device *dev);
60 static int dac02_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
61 static int readback_insn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
62
63 struct boarddef_struct{
64         char *name;
65         int iosize;
66         int (*setup)(comedi_device *);
67         int type;
68         int n_chan;
69         int n_bits;
70         int (*winsn)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *);
71         int (*rinsn)(comedi_device *,comedi_subdevice *,comedi_insn *,lsampl_t *);
72         comedi_lrange* range;
73 };
74 static struct boarddef_struct boards[]={
75         {
76         name:           "dac02",
77         iosize:         8,
78         //setup:                dac02_setup,
79         type:           COMEDI_SUBD_AO,
80         n_chan:         2,
81         n_bits:         12,
82         winsn:          dac02_ao_winsn,
83         rinsn:          readback_insn,
84         range:          &range_unknown,
85         }
86 };
87 #define n_boards (sizeof(boards)/sizeof(boards[0]))
88 #define this_board ((struct boarddef_struct *)dev->board_ptr)
89
90 static comedi_driver driver_poc=
91 {
92         driver_name:    "poc",
93         module:         THIS_MODULE,
94         attach:         poc_attach,
95         detach:         poc_detach,
96         board_name:     boards,
97         num_names:      n_boards,
98         offset:         sizeof(boards[0]),
99 };
100
101 static int poc_attach(comedi_device *dev, comedi_devconfig *it)
102 {
103         comedi_subdevice *s;
104         int iosize, iobase;
105
106         iobase = it->options[0];
107         printk("comedi%d: poc: using %s iobase 0x%x\n", dev->minor,
108                 this_board->name, iobase);
109
110         dev->board_name = this_board->name;
111
112         if(iobase == 0)
113         {
114                 printk("io base address required\n");
115                 return -EINVAL;
116         }
117
118         iosize = this_board->iosize;
119         /* check if io addresses are available */
120         if(check_region(iobase, iosize) < 0)
121         {
122                 printk("I/O port conflict: failed to allocate ports 0x%x to 0x%x\n",
123                         iobase, iobase + iosize - 1);
124                 return -EIO;
125         }
126         request_region(iobase, iosize, "dac02");
127         dev->iobase = iobase;
128
129         dev->n_subdevices = 1;
130         if(alloc_subdevices(dev) < 0)
131                 return -ENOMEM;
132         if(alloc_private(dev,sizeof(lsampl_t)*this_board->n_chan) < 0)
133                 return -ENOMEM;
134
135         /* analog output subdevice */
136         s=dev->subdevices + 0;
137         s->type = this_board->type;
138         s->n_chan = this_board->n_chan;
139         s->maxdata = (1<<this_board->n_bits)-1;
140         s->range_table = this_board->range;
141         s->insn_write = this_board->winsn;
142         s->insn_read = this_board->rinsn;
143         if(s->type==COMEDI_SUBD_AO || s->type==COMEDI_SUBD_DO){
144                 s->subdev_flags = SDF_WRITEABLE;
145         }
146
147         return 0;
148 }
149
150 static int poc_detach(comedi_device *dev)
151 {
152         /* only free stuff if it has been allocated by _attach */
153         if(dev->iobase)
154                 release_region(dev->iobase, this_board->iosize);
155
156         printk("comedi%d: dac02: remove\n", dev->minor);
157
158         return 0;
159 }
160
161 static int readback_insn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
162 {
163         int chan;
164
165         chan = CR_CHAN(insn->chanspec);
166         data[0]=((lsampl_t *)dev->private)[chan];
167
168         return 1;
169 }
170
171 static int dac02_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
172 {
173         int temp;
174         int chan;
175         int output;
176
177         chan = CR_CHAN(insn->chanspec);
178         ((lsampl_t *)dev->private)[chan] = data[0];
179         output = data[0];
180 #if wrong
181         // convert to complementary binary if range is bipolar
182         if((CR_RANGE(insn->chanspec) & 0x2) == 0)
183                 output = ~output;
184 #endif
185         temp = (output << 4) & 0xf0;
186         outb(temp, dev->iobase + DAC02_LSB(chan));
187         temp = (output >> 4) & 0xff;
188         outb(temp, dev->iobase + DAC02_MSB(chan));
189
190         return 1;
191 }
192
193 COMEDI_INITCLEANUP(driver_poc);
194