drivers.c revision 316f97f169084c9a984d989d88ddce4eff60d749
1/*
2    module/drivers.c
3    functions for manipulating drivers
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/device.h>
25#include <linux/module.h>
26#include <linux/errno.h>
27#include <linux/kconfig.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/slab.h>
35#include <linux/highmem.h>	/* for SuSE brokenness */
36#include <linux/vmalloc.h>
37#include <linux/cdev.h>
38#include <linux/dma-mapping.h>
39#include <linux/io.h>
40
41#include "comedidev.h"
42#include "comedi_internal.h"
43
44struct comedi_driver *comedi_drivers;
45
46int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
47{
48	if (hw_dev == dev->hw_dev)
49		return 0;
50	if (dev->hw_dev != NULL)
51		return -EEXIST;
52	dev->hw_dev = get_device(hw_dev);
53	return 0;
54}
55EXPORT_SYMBOL_GPL(comedi_set_hw_dev);
56
57static void comedi_clear_hw_dev(struct comedi_device *dev)
58{
59	put_device(dev->hw_dev);
60	dev->hw_dev = NULL;
61}
62
63int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
64{
65	struct comedi_subdevice *s;
66	int i;
67
68	if (num_subdevices < 1)
69		return -EINVAL;
70
71	s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL);
72	if (!s)
73		return -ENOMEM;
74	dev->subdevices = s;
75	dev->n_subdevices = num_subdevices;
76
77	for (i = 0; i < num_subdevices; ++i) {
78		s = &dev->subdevices[i];
79		s->device = dev;
80		s->index = i;
81		s->async_dma_dir = DMA_NONE;
82		spin_lock_init(&s->spin_lock);
83		s->minor = -1;
84	}
85	return 0;
86}
87EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
88
89void comedi_spriv_free(struct comedi_device *dev, int subdev_num)
90{
91	struct comedi_subdevice *s;
92
93	if (dev->subdevices && subdev_num < dev->n_subdevices) {
94		s = &dev->subdevices[subdev_num];
95		kfree(s->private);
96		s->private = NULL;
97	}
98}
99EXPORT_SYMBOL_GPL(comedi_spriv_free);
100
101static void cleanup_device(struct comedi_device *dev)
102{
103	int i;
104	struct comedi_subdevice *s;
105
106	if (dev->subdevices) {
107		for (i = 0; i < dev->n_subdevices; i++) {
108			s = &dev->subdevices[i];
109			comedi_free_subdevice_minor(s);
110			if (s->async) {
111				comedi_buf_alloc(dev, s, 0);
112				kfree(s->async);
113			}
114		}
115		kfree(dev->subdevices);
116		dev->subdevices = NULL;
117		dev->n_subdevices = 0;
118	}
119	kfree(dev->private);
120	dev->private = NULL;
121	dev->driver = NULL;
122	dev->board_name = NULL;
123	dev->board_ptr = NULL;
124	dev->iobase = 0;
125	dev->iolen = 0;
126	dev->ioenabled = false;
127	dev->irq = 0;
128	dev->read_subdev = NULL;
129	dev->write_subdev = NULL;
130	dev->open = NULL;
131	dev->close = NULL;
132	comedi_clear_hw_dev(dev);
133}
134
135void comedi_device_detach(struct comedi_device *dev)
136{
137	dev->attached = false;
138	if (dev->driver)
139		dev->driver->detach(dev);
140	cleanup_device(dev);
141}
142
143static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
144{
145	return -EINVAL;
146}
147
148int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
149	       struct comedi_insn *insn, unsigned int *data)
150{
151	return -EINVAL;
152}
153
154static int insn_rw_emulate_bits(struct comedi_device *dev,
155				struct comedi_subdevice *s,
156				struct comedi_insn *insn, unsigned int *data)
157{
158	struct comedi_insn new_insn;
159	int ret;
160	static const unsigned channels_per_bitfield = 32;
161
162	unsigned chan = CR_CHAN(insn->chanspec);
163	const unsigned base_bitfield_channel =
164	    (chan < channels_per_bitfield) ? 0 : chan;
165	unsigned int new_data[2];
166	memset(new_data, 0, sizeof(new_data));
167	memset(&new_insn, 0, sizeof(new_insn));
168	new_insn.insn = INSN_BITS;
169	new_insn.chanspec = base_bitfield_channel;
170	new_insn.n = 2;
171	new_insn.subdev = insn->subdev;
172
173	if (insn->insn == INSN_WRITE) {
174		if (!(s->subdev_flags & SDF_WRITABLE))
175			return -EINVAL;
176		new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */
177		new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel))
178			      : 0; /* bits */
179	}
180
181	ret = s->insn_bits(dev, s, &new_insn, new_data);
182	if (ret < 0)
183		return ret;
184
185	if (insn->insn == INSN_READ)
186		data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1;
187
188	return 1;
189}
190
191static int __comedi_device_postconfig_async(struct comedi_device *dev,
192					    struct comedi_subdevice *s)
193{
194	struct comedi_async *async;
195	unsigned int buf_size;
196	int ret;
197
198	if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) {
199		dev_warn(dev->class_dev,
200			 "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n");
201		return -EINVAL;
202	}
203	if (!s->do_cmdtest) {
204		dev_warn(dev->class_dev,
205			 "async subdevices must have a do_cmdtest() function\n");
206		return -EINVAL;
207	}
208
209	async = kzalloc(sizeof(*async), GFP_KERNEL);
210	if (!async)
211		return -ENOMEM;
212
213	init_waitqueue_head(&async->wait_head);
214	async->subdevice = s;
215	s->async = async;
216
217	async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;
218	buf_size = comedi_default_buf_size_kb * 1024;
219	if (buf_size > async->max_bufsize)
220		buf_size = async->max_bufsize;
221
222	if (comedi_buf_alloc(dev, s, buf_size) < 0) {
223		dev_warn(dev->class_dev, "Buffer allocation failed\n");
224		return -ENOMEM;
225	}
226	if (s->buf_change) {
227		ret = s->buf_change(dev, s, buf_size);
228		if (ret < 0)
229			return ret;
230	}
231
232	comedi_alloc_subdevice_minor(s);
233
234	return 0;
235}
236
237static int __comedi_device_postconfig(struct comedi_device *dev)
238{
239	struct comedi_subdevice *s;
240	int ret;
241	int i;
242
243	for (i = 0; i < dev->n_subdevices; i++) {
244		s = &dev->subdevices[i];
245
246		if (s->type == COMEDI_SUBD_UNUSED)
247			continue;
248
249		if (s->len_chanlist == 0)
250			s->len_chanlist = 1;
251
252		if (s->do_cmd) {
253			ret = __comedi_device_postconfig_async(dev, s);
254			if (ret)
255				return ret;
256		}
257
258		if (!s->range_table && !s->range_table_list)
259			s->range_table = &range_unknown;
260
261		if (!s->insn_read && s->insn_bits)
262			s->insn_read = insn_rw_emulate_bits;
263		if (!s->insn_write && s->insn_bits)
264			s->insn_write = insn_rw_emulate_bits;
265
266		if (!s->insn_read)
267			s->insn_read = insn_inval;
268		if (!s->insn_write)
269			s->insn_write = insn_inval;
270		if (!s->insn_bits)
271			s->insn_bits = insn_inval;
272		if (!s->insn_config)
273			s->insn_config = insn_inval;
274
275		if (!s->poll)
276			s->poll = poll_invalid;
277	}
278
279	return 0;
280}
281
282/* do a little post-config cleanup */
283static int comedi_device_postconfig(struct comedi_device *dev)
284{
285	int ret;
286
287	ret = __comedi_device_postconfig(dev);
288	if (ret < 0)
289		return ret;
290	smp_wmb();
291	dev->attached = true;
292	return 0;
293}
294
295/*
296 * Generic recognize function for drivers that register their supported
297 * board names.
298 *
299 * 'driv->board_name' points to a 'const char *' member within the
300 * zeroth element of an array of some private board information
301 * structure, say 'struct foo_board' containing a member 'const char
302 * *board_name' that is initialized to point to a board name string that
303 * is one of the candidates matched against this function's 'name'
304 * parameter.
305 *
306 * 'driv->offset' is the size of the private board information
307 * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is
308 * the length of the array of private board information structures.
309 *
310 * If one of the board names in the array of private board information
311 * structures matches the name supplied to this function, the function
312 * returns a pointer to the pointer to the board name, otherwise it
313 * returns NULL.  The return value ends up in the 'board_ptr' member of
314 * a 'struct comedi_device' that the low-level comedi driver's
315 * 'attach()' hook can convert to a point to a particular element of its
316 * array of private board information structures by subtracting the
317 * offset of the member that points to the board name.  (No subtraction
318 * is required if the board name pointer is the first member of the
319 * private board information structure, which is generally the case.)
320 */
321static void *comedi_recognize(struct comedi_driver *driv, const char *name)
322{
323	char **name_ptr = (char **)driv->board_name;
324	int i;
325
326	for (i = 0; i < driv->num_names; i++) {
327		if (strcmp(*name_ptr, name) == 0)
328			return name_ptr;
329		name_ptr = (void *)name_ptr + driv->offset;
330	}
331
332	return NULL;
333}
334
335static void comedi_report_boards(struct comedi_driver *driv)
336{
337	unsigned int i;
338	const char *const *name_ptr;
339
340	pr_info("comedi: valid board names for %s driver are:\n",
341		driv->driver_name);
342
343	name_ptr = driv->board_name;
344	for (i = 0; i < driv->num_names; i++) {
345		pr_info(" %s\n", *name_ptr);
346		name_ptr = (const char **)((char *)name_ptr + driv->offset);
347	}
348
349	if (driv->num_names == 0)
350		pr_info(" %s\n", driv->driver_name);
351}
352
353/**
354 * __comedi_request_region() - Request an I/O reqion for a legacy driver.
355 * @dev: comedi_device struct
356 * @start: base address of the I/O reqion
357 * @len: length of the I/O region
358 */
359int __comedi_request_region(struct comedi_device *dev,
360			    unsigned long start, unsigned long len)
361{
362	if (!start) {
363		dev_warn(dev->class_dev,
364			 "%s: a I/O base address must be specified\n",
365			 dev->board_name);
366		return -EINVAL;
367	}
368
369	if (!request_region(start, len, dev->board_name)) {
370		dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n",
371			 dev->board_name, start, len);
372		return -EIO;
373	}
374
375	return 0;
376}
377EXPORT_SYMBOL_GPL(__comedi_request_region);
378
379/**
380 * comedi_request_region() - Request an I/O reqion for a legacy driver.
381 * @dev: comedi_device struct
382 * @start: base address of the I/O reqion
383 * @len: length of the I/O region
384 */
385int comedi_request_region(struct comedi_device *dev,
386			  unsigned long start, unsigned long len)
387{
388	int ret;
389
390	ret = __comedi_request_region(dev, start, len);
391	if (ret == 0) {
392		dev->iobase = start;
393		dev->iolen = len;
394	}
395
396	return ret;
397}
398EXPORT_SYMBOL_GPL(comedi_request_region);
399
400/**
401 * comedi_legacy_detach() - A generic (*detach) function for legacy drivers.
402 * @dev: comedi_device struct
403 */
404void comedi_legacy_detach(struct comedi_device *dev)
405{
406	if (dev->iobase && dev->iolen) {
407		release_region(dev->iobase, dev->iolen);
408		dev->iobase = 0;
409		dev->iolen = 0;
410	}
411}
412EXPORT_SYMBOL_GPL(comedi_legacy_detach);
413
414int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
415{
416	struct comedi_driver *driv;
417	int ret;
418
419	if (dev->attached)
420		return -EBUSY;
421
422	for (driv = comedi_drivers; driv; driv = driv->next) {
423		if (!try_module_get(driv->module))
424			continue;
425		if (driv->num_names) {
426			dev->board_ptr = comedi_recognize(driv, it->board_name);
427			if (dev->board_ptr)
428				break;
429		} else if (strcmp(driv->driver_name, it->board_name) == 0)
430			break;
431		module_put(driv->module);
432	}
433	if (driv == NULL) {
434		/*  recognize has failed if we get here */
435		/*  report valid board names before returning error */
436		for (driv = comedi_drivers; driv; driv = driv->next) {
437			if (!try_module_get(driv->module))
438				continue;
439			comedi_report_boards(driv);
440			module_put(driv->module);
441		}
442		return -EIO;
443	}
444	if (driv->attach == NULL) {
445		/* driver does not support manual configuration */
446		dev_warn(dev->class_dev,
447			 "driver '%s' does not support attach using comedi_config\n",
448			 driv->driver_name);
449		module_put(driv->module);
450		return -ENOSYS;
451	}
452	/* initialize dev->driver here so
453	 * comedi_error() can be called from attach */
454	dev->driver = driv;
455	dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
456					 : dev->driver->driver_name;
457	ret = driv->attach(dev, it);
458	if (ret >= 0)
459		ret = comedi_device_postconfig(dev);
460	if (ret < 0) {
461		comedi_device_detach(dev);
462		module_put(dev->driver->module);
463	}
464	/* On success, the driver module count has been incremented. */
465	return ret;
466}
467
468int comedi_auto_config(struct device *hardware_device,
469		       struct comedi_driver *driver, unsigned long context)
470{
471	struct comedi_device *dev;
472	int ret;
473
474	if (!hardware_device) {
475		pr_warn("BUG! comedi_auto_config called with NULL hardware_device\n");
476		return -EINVAL;
477	}
478	if (!driver) {
479		dev_warn(hardware_device,
480			 "BUG! comedi_auto_config called with NULL comedi driver\n");
481		return -EINVAL;
482	}
483
484	if (!driver->auto_attach) {
485		dev_warn(hardware_device,
486			 "BUG! comedi driver '%s' has no auto_attach handler\n",
487			 driver->driver_name);
488		return -EINVAL;
489	}
490
491	dev = comedi_alloc_board_minor(hardware_device);
492	if (IS_ERR(dev))
493		return PTR_ERR(dev);
494	/* Note: comedi_alloc_board_minor() locked dev->mutex. */
495
496	dev->driver = driver;
497	dev->board_name = dev->driver->driver_name;
498	ret = driver->auto_attach(dev, context);
499	if (ret >= 0)
500		ret = comedi_device_postconfig(dev);
501	if (ret < 0)
502		comedi_device_detach(dev);
503	mutex_unlock(&dev->mutex);
504
505	if (ret < 0)
506		comedi_release_hardware_device(hardware_device);
507	return ret;
508}
509EXPORT_SYMBOL_GPL(comedi_auto_config);
510
511void comedi_auto_unconfig(struct device *hardware_device)
512{
513	if (hardware_device == NULL)
514		return;
515	comedi_release_hardware_device(hardware_device);
516}
517EXPORT_SYMBOL_GPL(comedi_auto_unconfig);
518
519int comedi_driver_register(struct comedi_driver *driver)
520{
521	driver->next = comedi_drivers;
522	comedi_drivers = driver;
523
524	return 0;
525}
526EXPORT_SYMBOL_GPL(comedi_driver_register);
527
528int comedi_driver_unregister(struct comedi_driver *driver)
529{
530	struct comedi_driver *prev;
531	int i;
532
533	/* check for devices using this driver */
534	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
535		struct comedi_device *dev = comedi_dev_from_minor(i);
536
537		if (!dev)
538			continue;
539
540		mutex_lock(&dev->mutex);
541		if (dev->attached && dev->driver == driver) {
542			if (dev->use_count)
543				dev_warn(dev->class_dev,
544					 "BUG! detaching device with use_count=%d\n",
545					 dev->use_count);
546			comedi_device_detach(dev);
547		}
548		mutex_unlock(&dev->mutex);
549	}
550
551	if (comedi_drivers == driver) {
552		comedi_drivers = driver->next;
553		return 0;
554	}
555
556	for (prev = comedi_drivers; prev->next; prev = prev->next) {
557		if (prev->next == driver) {
558			prev->next = driver->next;
559			return 0;
560		}
561	}
562	return -EINVAL;
563}
564EXPORT_SYMBOL_GPL(comedi_driver_unregister);
565