Commit | Line | Data |
---|---|---|
b79a7a20 DS |
1 | /* |
2 | kcomedilib/kcomedilib.c | |
3 | a comedlib interface for kernel modules | |
4 | ||
5 | COMEDI - Linux Control and Measurement Device Interface | |
6 | Copyright (C) 1997-2000 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 | ||
b79a7a20 DS |
24 | #include <linux/module.h> |
25 | ||
26 | #include <linux/errno.h> | |
27 | #include <linux/kernel.h> | |
28 | #include <linux/sched.h> | |
29 | #include <linux/fcntl.h> | |
30 | #include <linux/delay.h> | |
31 | #include <linux/ioport.h> | |
32 | #include <linux/mm.h> | |
7382e571 | 33 | #include <linux/io.h> |
b79a7a20 DS |
34 | |
35 | #include "../comedi.h" | |
36 | #include "../comedilib.h" | |
37 | #include "../comedidev.h" | |
38 | ||
39 | MODULE_AUTHOR("David Schleef <ds@schleef.org>"); | |
40 | MODULE_DESCRIPTION("Comedi kernel library"); | |
41 | MODULE_LICENSE("GPL"); | |
42 | ||
472dfe77 | 43 | struct comedi_device *comedi_open(const char *filename) |
b79a7a20 | 44 | { |
71b5f4f1 | 45 | struct comedi_device *dev; |
b79a7a20 DS |
46 | unsigned int minor; |
47 | ||
48 | if (strncmp(filename, "/dev/comedi", 11) != 0) | |
49 | return NULL; | |
50 | ||
51 | minor = simple_strtoul(filename + 11, NULL, 0); | |
52 | ||
53 | if (minor >= COMEDI_NUM_BOARD_MINORS) | |
54 | return NULL; | |
55 | ||
4da5fa9a | 56 | dev = comedi_dev_from_minor(minor); |
b79a7a20 | 57 | |
4da5fa9a | 58 | if (!dev || !dev->attached) |
b79a7a20 DS |
59 | return NULL; |
60 | ||
61 | if (!try_module_get(dev->driver->module)) | |
62 | return NULL; | |
63 | ||
472dfe77 | 64 | return dev; |
b79a7a20 | 65 | } |
5660e742 | 66 | EXPORT_SYMBOL_GPL(comedi_open); |
b79a7a20 | 67 | |
472dfe77 | 68 | int comedi_close(struct comedi_device *d) |
b79a7a20 | 69 | { |
0a85b6f0 | 70 | struct comedi_device *dev = (struct comedi_device *)d; |
b79a7a20 DS |
71 | |
72 | module_put(dev->driver->module); | |
73 | ||
74 | return 0; | |
75 | } | |
5660e742 | 76 | EXPORT_SYMBOL_GPL(comedi_close); |
b79a7a20 | 77 | |
1f5cc359 HS |
78 | static int comedi_do_insn(struct comedi_device *dev, |
79 | struct comedi_insn *insn, | |
80 | unsigned int *data) | |
b79a7a20 | 81 | { |
34c43922 | 82 | struct comedi_subdevice *s; |
b79a7a20 DS |
83 | int ret = 0; |
84 | ||
3781bc54 GKH |
85 | /* a subdevice instruction */ |
86 | if (insn->subdev >= dev->n_subdevices) { | |
87 | ret = -EINVAL; | |
88 | goto error; | |
b79a7a20 | 89 | } |
5818e709 | 90 | s = &dev->subdevices[insn->subdev]; |
3781bc54 GKH |
91 | |
92 | if (s->type == COMEDI_SUBD_UNUSED) { | |
49e8e44b YT |
93 | dev_err(dev->class_dev, |
94 | "%d not useable subdevice\n", insn->subdev); | |
3781bc54 | 95 | ret = -EIO; |
b79a7a20 | 96 | goto error; |
3781bc54 GKH |
97 | } |
98 | ||
99 | /* XXX check lock */ | |
100 | ||
101 | ret = comedi_check_chanlist(s, 1, &insn->chanspec); | |
102 | if (ret < 0) { | |
49e8e44b | 103 | dev_err(dev->class_dev, "bad chanspec\n"); |
b79a7a20 DS |
104 | ret = -EINVAL; |
105 | goto error; | |
106 | } | |
3781bc54 GKH |
107 | |
108 | if (s->busy) { | |
109 | ret = -EBUSY; | |
110 | goto error; | |
111 | } | |
112 | s->busy = dev; | |
113 | ||
114 | switch (insn->insn) { | |
115 | case INSN_BITS: | |
1f5cc359 | 116 | ret = s->insn_bits(dev, s, insn, data); |
3781bc54 GKH |
117 | break; |
118 | case INSN_CONFIG: | |
119 | /* XXX should check instruction length */ | |
1f5cc359 | 120 | ret = s->insn_config(dev, s, insn, data); |
3781bc54 GKH |
121 | break; |
122 | default: | |
123 | ret = -EINVAL; | |
124 | break; | |
125 | } | |
126 | ||
127 | s->busy = NULL; | |
0a85b6f0 | 128 | error: |
b79a7a20 DS |
129 | |
130 | return ret; | |
131 | } | |
132 | ||
472dfe77 GKH |
133 | int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, |
134 | unsigned int chan, unsigned int io) | |
a1525758 GKH |
135 | { |
136 | struct comedi_insn insn; | |
137 | ||
138 | memset(&insn, 0, sizeof(insn)); | |
139 | insn.insn = INSN_CONFIG; | |
140 | insn.n = 1; | |
a1525758 GKH |
141 | insn.subdev = subdev; |
142 | insn.chanspec = CR_PACK(chan, 0, 0); | |
143 | ||
1f5cc359 | 144 | return comedi_do_insn(dev, &insn, &io); |
a1525758 | 145 | } |
5660e742 | 146 | EXPORT_SYMBOL_GPL(comedi_dio_config); |
a1525758 | 147 | |
472dfe77 GKH |
148 | int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, |
149 | unsigned int mask, unsigned int *bits) | |
a1525758 GKH |
150 | { |
151 | struct comedi_insn insn; | |
152 | unsigned int data[2]; | |
153 | int ret; | |
154 | ||
155 | memset(&insn, 0, sizeof(insn)); | |
156 | insn.insn = INSN_BITS; | |
157 | insn.n = 2; | |
a1525758 GKH |
158 | insn.subdev = subdev; |
159 | ||
160 | data[0] = mask; | |
161 | data[1] = *bits; | |
162 | ||
1f5cc359 | 163 | ret = comedi_do_insn(dev, &insn, data); |
a1525758 GKH |
164 | |
165 | *bits = data[1]; | |
166 | ||
167 | return ret; | |
168 | } | |
5660e742 | 169 | EXPORT_SYMBOL_GPL(comedi_dio_bitfield); |
a1525758 | 170 | |
472dfe77 GKH |
171 | int comedi_find_subdevice_by_type(struct comedi_device *dev, int type, |
172 | unsigned int subd) | |
a1525758 | 173 | { |
5818e709 HS |
174 | struct comedi_subdevice *s; |
175 | ||
a1525758 GKH |
176 | if (subd > dev->n_subdevices) |
177 | return -ENODEV; | |
178 | ||
179 | for (; subd < dev->n_subdevices; subd++) { | |
5818e709 HS |
180 | s = &dev->subdevices[subd]; |
181 | if (s->type == type) | |
a1525758 GKH |
182 | return subd; |
183 | } | |
184 | return -1; | |
185 | } | |
5660e742 | 186 | EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type); |
a1525758 | 187 | |
472dfe77 | 188 | int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice) |
a1525758 | 189 | { |
5818e709 | 190 | struct comedi_subdevice *s = &dev->subdevices[subdevice]; |
a1525758 GKH |
191 | |
192 | return s->n_chan; | |
193 | } | |
5660e742 | 194 | EXPORT_SYMBOL_GPL(comedi_get_n_channels); |