1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
39MODULE_AUTHOR("David Schleef <ds@schleef.org>");
40MODULE_DESCRIPTION("Comedi kernel library");
41MODULE_LICENSE("GPL");
42
43struct 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}
66EXPORT_SYMBOL_GPL(comedi_open);
67
68int 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}
76EXPORT_SYMBOL_GPL(comedi_close);
77
78static 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
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
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
120 ret = s->insn_config(dev, s, insn, data);
121 break;
122 default:
123 ret = -EINVAL;
124 break;
125 }
126
127 s->busy = NULL;
128error:
129
130 return ret;
131}
132
133int 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}
146EXPORT_SYMBOL_GPL(comedi_dio_config);
147
148int 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}
169EXPORT_SYMBOL_GPL(comedi_dio_bitfield);
170
171int 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}
186EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
187
188int 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}
194EXPORT_SYMBOL_GPL(comedi_get_n_channels);
195