1 // SPDX-License-Identifier: GPL-2.0+
3 * kcomedilib/kcomedilib.c
4 * a comedlib interface for kernel modules
6 * COMEDI - Linux Control and Measurement Device Interface
7 * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
10 #include <linux/module.h>
12 #include <linux/errno.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/fcntl.h>
19 #include <linux/comedi.h>
20 #include <linux/comedi/comedidev.h>
21 #include <linux/comedi/comedilib.h>
23 MODULE_AUTHOR("David Schleef <ds@schleef.org>");
24 MODULE_DESCRIPTION("Comedi kernel library");
25 MODULE_LICENSE("GPL");
27 struct comedi_device
*comedi_open(const char *filename
)
29 struct comedi_device
*dev
, *retval
= NULL
;
32 if (strncmp(filename
, "/dev/comedi", 11) != 0)
35 if (kstrtouint(filename
+ 11, 0, &minor
))
38 if (minor
>= COMEDI_NUM_BOARD_MINORS
)
41 dev
= comedi_dev_get_from_minor(minor
);
45 down_read(&dev
->attach_lock
);
50 up_read(&dev
->attach_lock
);
57 EXPORT_SYMBOL_GPL(comedi_open
);
59 int comedi_close(struct comedi_device
*dev
)
64 EXPORT_SYMBOL_GPL(comedi_close
);
66 static int comedi_do_insn(struct comedi_device
*dev
,
67 struct comedi_insn
*insn
,
70 struct comedi_subdevice
*s
;
73 mutex_lock(&dev
->mutex
);
80 /* a subdevice instruction */
81 if (insn
->subdev
>= dev
->n_subdevices
) {
85 s
= &dev
->subdevices
[insn
->subdev
];
87 if (s
->type
== COMEDI_SUBD_UNUSED
) {
88 dev_err(dev
->class_dev
,
89 "%d not usable subdevice\n", insn
->subdev
);
96 ret
= comedi_check_chanlist(s
, 1, &insn
->chanspec
);
98 dev_err(dev
->class_dev
, "bad chanspec\n");
109 switch (insn
->insn
) {
111 ret
= s
->insn_bits(dev
, s
, insn
, data
);
114 /* XXX should check instruction length */
115 ret
= s
->insn_config(dev
, s
, insn
, data
);
125 mutex_unlock(&dev
->mutex
);
129 int comedi_dio_get_config(struct comedi_device
*dev
, unsigned int subdev
,
130 unsigned int chan
, unsigned int *io
)
132 struct comedi_insn insn
;
133 unsigned int data
[2];
136 memset(&insn
, 0, sizeof(insn
));
137 insn
.insn
= INSN_CONFIG
;
139 insn
.subdev
= subdev
;
140 insn
.chanspec
= CR_PACK(chan
, 0, 0);
141 data
[0] = INSN_CONFIG_DIO_QUERY
;
143 ret
= comedi_do_insn(dev
, &insn
, data
);
148 EXPORT_SYMBOL_GPL(comedi_dio_get_config
);
150 int comedi_dio_config(struct comedi_device
*dev
, unsigned int subdev
,
151 unsigned int chan
, unsigned int io
)
153 struct comedi_insn insn
;
155 memset(&insn
, 0, sizeof(insn
));
156 insn
.insn
= INSN_CONFIG
;
158 insn
.subdev
= subdev
;
159 insn
.chanspec
= CR_PACK(chan
, 0, 0);
161 return comedi_do_insn(dev
, &insn
, &io
);
163 EXPORT_SYMBOL_GPL(comedi_dio_config
);
165 int comedi_dio_bitfield2(struct comedi_device
*dev
, unsigned int subdev
,
166 unsigned int mask
, unsigned int *bits
,
167 unsigned int base_channel
)
169 struct comedi_insn insn
;
170 unsigned int data
[2];
175 base_channel
= CR_CHAN(base_channel
);
176 n_chan
= comedi_get_n_channels(dev
, subdev
);
177 if (base_channel
>= n_chan
)
180 memset(&insn
, 0, sizeof(insn
));
181 insn
.insn
= INSN_BITS
;
182 insn
.chanspec
= base_channel
;
184 insn
.subdev
= subdev
;
190 * Most drivers ignore the base channel in insn->chanspec.
191 * Fix this here if the subdevice has <= 32 channels.
194 shift
= base_channel
;
204 ret
= comedi_do_insn(dev
, &insn
, data
);
205 *bits
= data
[1] >> shift
;
208 EXPORT_SYMBOL_GPL(comedi_dio_bitfield2
);
210 int comedi_find_subdevice_by_type(struct comedi_device
*dev
, int type
,
213 struct comedi_subdevice
*s
;
216 down_read(&dev
->attach_lock
);
218 for (; subd
< dev
->n_subdevices
; subd
++) {
219 s
= &dev
->subdevices
[subd
];
220 if (s
->type
== type
) {
225 up_read(&dev
->attach_lock
);
228 EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type
);
230 int comedi_get_n_channels(struct comedi_device
*dev
, unsigned int subdevice
)
234 down_read(&dev
->attach_lock
);
235 if (!dev
->attached
|| subdevice
>= dev
->n_subdevices
)
238 n
= dev
->subdevices
[subdevice
].n_chan
;
239 up_read(&dev
->attach_lock
);
243 EXPORT_SYMBOL_GPL(comedi_get_n_channels
);
245 static int __init
kcomedilib_module_init(void)
250 static void __exit
kcomedilib_module_exit(void)
254 module_init(kcomedilib_module_init
);
255 module_exit(kcomedilib_module_exit
);