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