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
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>
33 #include <linux/io.h>
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
comedi_open(const char * filename)43 struct comedi_device *comedi_open(const char *filename)
44 {
45 struct comedi_device *dev;
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
56 dev = comedi_dev_from_minor(minor);
57
58 if (!dev || !dev->attached)
59 return NULL;
60
61 if (!try_module_get(dev->driver->module))
62 return NULL;
63
64 return dev;
65 }
66 EXPORT_SYMBOL_GPL(comedi_open);
67
comedi_close(struct comedi_device * d)68 int comedi_close(struct comedi_device *d)
69 {
70 struct comedi_device *dev = (struct comedi_device *)d;
71
72 module_put(dev->driver->module);
73
74 return 0;
75 }
76 EXPORT_SYMBOL_GPL(comedi_close);
77
comedi_do_insn(struct comedi_device * dev,struct comedi_insn * insn,unsigned int * data)78 static int comedi_do_insn(struct comedi_device *dev,
79 struct comedi_insn *insn,
80 unsigned int *data)
81 {
82 struct comedi_subdevice *s;
83 int ret = 0;
84
85 /* a subdevice instruction */
86 if (insn->subdev >= dev->n_subdevices) {
87 ret = -EINVAL;
88 goto error;
89 }
90 s = &dev->subdevices[insn->subdev];
91
92 if (s->type == COMEDI_SUBD_UNUSED) {
93 dev_err(dev->class_dev,
94 "%d not useable subdevice\n", insn->subdev);
95 ret = -EIO;
96 goto error;
97 }
98
99 /* XXX check lock */
100
101 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
102 if (ret < 0) {
103 dev_err(dev->class_dev, "bad chanspec\n");
104 ret = -EINVAL;
105 goto error;
106 }
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:
116 ret = s->insn_bits(dev, s, insn, data);
117 break;
118 case INSN_CONFIG:
119 /* XXX should check instruction length */
120 ret = s->insn_config(dev, s, insn, data);
121 break;
122 default:
123 ret = -EINVAL;
124 break;
125 }
126
127 s->busy = NULL;
128 error:
129
130 return ret;
131 }
132
comedi_dio_config(struct comedi_device * dev,unsigned int subdev,unsigned int chan,unsigned int io)133 int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
134 unsigned int chan, unsigned int io)
135 {
136 struct comedi_insn insn;
137
138 memset(&insn, 0, sizeof(insn));
139 insn.insn = INSN_CONFIG;
140 insn.n = 1;
141 insn.subdev = subdev;
142 insn.chanspec = CR_PACK(chan, 0, 0);
143
144 return comedi_do_insn(dev, &insn, &io);
145 }
146 EXPORT_SYMBOL_GPL(comedi_dio_config);
147
comedi_dio_bitfield(struct comedi_device * dev,unsigned int subdev,unsigned int mask,unsigned int * bits)148 int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
149 unsigned int mask, unsigned int *bits)
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;
158 insn.subdev = subdev;
159
160 data[0] = mask;
161 data[1] = *bits;
162
163 ret = comedi_do_insn(dev, &insn, data);
164
165 *bits = data[1];
166
167 return ret;
168 }
169 EXPORT_SYMBOL_GPL(comedi_dio_bitfield);
170
comedi_find_subdevice_by_type(struct comedi_device * dev,int type,unsigned int subd)171 int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
172 unsigned int subd)
173 {
174 struct comedi_subdevice *s;
175
176 if (subd > dev->n_subdevices)
177 return -ENODEV;
178
179 for (; subd < dev->n_subdevices; subd++) {
180 s = &dev->subdevices[subd];
181 if (s->type == type)
182 return subd;
183 }
184 return -1;
185 }
186 EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
187
comedi_get_n_channels(struct comedi_device * dev,unsigned int subdevice)188 int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
189 {
190 struct comedi_subdevice *s = &dev->subdevices[subdevice];
191
192 return s->n_chan;
193 }
194 EXPORT_SYMBOL_GPL(comedi_get_n_channels);
195