drivers.c revision 6b362f5bea0dfbb648656041a92f6a00b298f558
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
19#include <linux/device.h>
20#include <linux/module.h>
21#include <linux/errno.h>
22#include <linux/kconfig.h>
23#include <linux/kernel.h>
24#include <linux/sched.h>
25#include <linux/fcntl.h>
26#include <linux/ioport.h>
27#include <linux/mm.h>
28#include <linux/slab.h>
29#include <linux/highmem.h>	/* for SuSE brokenness */
30#include <linux/vmalloc.h>
31#include <linux/cdev.h>
32#include <linux/dma-mapping.h>
33#include <linux/io.h>
34#include <linux/interrupt.h>
35#include <linux/firmware.h>
36
37#include "comedidev.h"
38#include "comedi_internal.h"
39
40struct comedi_driver *comedi_drivers;
41DEFINE_MUTEX(comedi_drivers_list_lock);
42
43int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
44{
45	if (hw_dev == dev->hw_dev)
46		return 0;
47	if (dev->hw_dev != NULL)
48		return -EEXIST;
49	dev->hw_dev = get_device(hw_dev);
50	return 0;
51}
52EXPORT_SYMBOL_GPL(comedi_set_hw_dev);
53
54static void comedi_clear_hw_dev(struct comedi_device *dev)
55{
56	put_device(dev->hw_dev);
57	dev->hw_dev = NULL;
58}
59
60/**
61 * comedi_alloc_devpriv() - Allocate memory for the device private data.
62 * @dev: comedi_device struct
63 * @size: size of the memory to allocate
64 */
65void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size)
66{
67	dev->private = kzalloc(size, GFP_KERNEL);
68	return dev->private;
69}
70EXPORT_SYMBOL_GPL(comedi_alloc_devpriv);
71
72int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
73{
74	struct comedi_subdevice *s;
75	int i;
76
77	if (num_subdevices < 1)
78		return -EINVAL;
79
80	s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL);
81	if (!s)
82		return -ENOMEM;
83	dev->subdevices = s;
84	dev->n_subdevices = num_subdevices;
85
86	for (i = 0; i < num_subdevices; ++i) {
87		s = &dev->subdevices[i];
88		s->device = dev;
89		s->index = i;
90		s->async_dma_dir = DMA_NONE;
91		spin_lock_init(&s->spin_lock);
92		s->minor = -1;
93	}
94	return 0;
95}
96EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
97
98static void comedi_device_detach_cleanup(struct comedi_device *dev)
99{
100	int i;
101	struct comedi_subdevice *s;
102
103	if (dev->subdevices) {
104		for (i = 0; i < dev->n_subdevices; i++) {
105			s = &dev->subdevices[i];
106			if (s->runflags & SRF_FREE_SPRIV)
107				kfree(s->private);
108			comedi_free_subdevice_minor(s);
109			if (s->async) {
110				comedi_buf_alloc(dev, s, 0);
111				kfree(s->async);
112			}
113		}
114		kfree(dev->subdevices);
115		dev->subdevices = NULL;
116		dev->n_subdevices = 0;
117	}
118	kfree(dev->private);
119	dev->private = NULL;
120	dev->driver = NULL;
121	dev->board_name = NULL;
122	dev->board_ptr = NULL;
123	dev->iobase = 0;
124	dev->iolen = 0;
125	dev->ioenabled = false;
126	dev->irq = 0;
127	dev->read_subdev = NULL;
128	dev->write_subdev = NULL;
129	dev->open = NULL;
130	dev->close = NULL;
131	comedi_clear_hw_dev(dev);
132}
133
134void comedi_device_detach(struct comedi_device *dev)
135{
136	comedi_device_cancel_all(dev);
137	down_write(&dev->attach_lock);
138	dev->attached = false;
139	dev->detach_count++;
140	if (dev->driver)
141		dev->driver->detach(dev);
142	comedi_device_detach_cleanup(dev);
143	up_write(&dev->attach_lock);
144}
145
146static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
147{
148	return -EINVAL;
149}
150
151int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
152	       struct comedi_insn *insn, unsigned int *data)
153{
154	return -EINVAL;
155}
156
157/**
158 * comedi_timeout() - busy-wait for a driver condition to occur.
159 * @dev: comedi_device struct
160 * @s: comedi_subdevice struct
161 * @insn: comedi_insn struct
162 * @cb: callback to check for the condition
163 * @context: private context from the driver
164 */
165int comedi_timeout(struct comedi_device *dev,
166		   struct comedi_subdevice *s,
167		   struct comedi_insn *insn,
168		   int (*cb)(struct comedi_device *dev,
169			     struct comedi_subdevice *s,
170			     struct comedi_insn *insn,
171			     unsigned long context),
172		   unsigned long context)
173{
174	unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS);
175	int ret;
176
177	while (time_before(jiffies, timeout)) {
178		ret = cb(dev, s, insn, context);
179		if (ret != -EBUSY)
180			return ret;	/* success (0) or non EBUSY errno */
181		cpu_relax();
182	}
183	return -ETIMEDOUT;
184}
185EXPORT_SYMBOL_GPL(comedi_timeout);
186
187/**
188 * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices.
189 * @dev: comedi_device struct
190 * @s: comedi_subdevice struct
191 * @insn: comedi_insn struct
192 * @data: parameters for the @insn
193 * @mask: io_bits mask for grouped channels
194 */
195int comedi_dio_insn_config(struct comedi_device *dev,
196			   struct comedi_subdevice *s,
197			   struct comedi_insn *insn,
198			   unsigned int *data,
199			   unsigned int mask)
200{
201	unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
202
203	if (!mask)
204		mask = chan_mask;
205
206	switch (data[0]) {
207	case INSN_CONFIG_DIO_INPUT:
208		s->io_bits &= ~mask;
209		break;
210
211	case INSN_CONFIG_DIO_OUTPUT:
212		s->io_bits |= mask;
213		break;
214
215	case INSN_CONFIG_DIO_QUERY:
216		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
217		return insn->n;
218
219	default:
220		return -EINVAL;
221	}
222
223	return 0;
224}
225EXPORT_SYMBOL_GPL(comedi_dio_insn_config);
226
227/**
228 * comedi_dio_update_state() - update the internal state of DIO subdevices.
229 * @s: comedi_subdevice struct
230 * @data: the channel mask and bits to update
231 */
232unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
233				     unsigned int *data)
234{
235	unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1)
236						 : 0xffffffff;
237	unsigned int mask = data[0] & chanmask;
238	unsigned int bits = data[1];
239
240	if (mask) {
241		s->state &= ~mask;
242		s->state |= (bits & mask);
243	}
244
245	return mask;
246}
247EXPORT_SYMBOL_GPL(comedi_dio_update_state);
248
249static int insn_rw_emulate_bits(struct comedi_device *dev,
250				struct comedi_subdevice *s,
251				struct comedi_insn *insn, unsigned int *data)
252{
253	struct comedi_insn new_insn;
254	int ret;
255	static const unsigned channels_per_bitfield = 32;
256
257	unsigned chan = CR_CHAN(insn->chanspec);
258	const unsigned base_bitfield_channel =
259	    (chan < channels_per_bitfield) ? 0 : chan;
260	unsigned int new_data[2];
261
262	memset(new_data, 0, sizeof(new_data));
263	memset(&new_insn, 0, sizeof(new_insn));
264	new_insn.insn = INSN_BITS;
265	new_insn.chanspec = base_bitfield_channel;
266	new_insn.n = 2;
267	new_insn.subdev = insn->subdev;
268
269	if (insn->insn == INSN_WRITE) {
270		if (!(s->subdev_flags & SDF_WRITABLE))
271			return -EINVAL;
272		new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */
273		new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel))
274			      : 0; /* bits */
275	}
276
277	ret = s->insn_bits(dev, s, &new_insn, new_data);
278	if (ret < 0)
279		return ret;
280
281	if (insn->insn == INSN_READ)
282		data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1;
283
284	return 1;
285}
286
287static int __comedi_device_postconfig_async(struct comedi_device *dev,
288					    struct comedi_subdevice *s)
289{
290	struct comedi_async *async;
291	unsigned int buf_size;
292	int ret;
293
294	if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) {
295		dev_warn(dev->class_dev,
296			 "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n");
297		return -EINVAL;
298	}
299	if (!s->do_cmdtest) {
300		dev_warn(dev->class_dev,
301			 "async subdevices must have a do_cmdtest() function\n");
302		return -EINVAL;
303	}
304
305	async = kzalloc(sizeof(*async), GFP_KERNEL);
306	if (!async)
307		return -ENOMEM;
308
309	init_waitqueue_head(&async->wait_head);
310	s->async = async;
311
312	async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;
313	buf_size = comedi_default_buf_size_kb * 1024;
314	if (buf_size > async->max_bufsize)
315		buf_size = async->max_bufsize;
316
317	if (comedi_buf_alloc(dev, s, buf_size) < 0) {
318		dev_warn(dev->class_dev, "Buffer allocation failed\n");
319		return -ENOMEM;
320	}
321	if (s->buf_change) {
322		ret = s->buf_change(dev, s, buf_size);
323		if (ret < 0)
324			return ret;
325	}
326
327	comedi_alloc_subdevice_minor(s);
328
329	return 0;
330}
331
332static int __comedi_device_postconfig(struct comedi_device *dev)
333{
334	struct comedi_subdevice *s;
335	int ret;
336	int i;
337
338	for (i = 0; i < dev->n_subdevices; i++) {
339		s = &dev->subdevices[i];
340
341		if (s->type == COMEDI_SUBD_UNUSED)
342			continue;
343
344		if (s->type == COMEDI_SUBD_DO) {
345			if (s->n_chan < 32)
346				s->io_bits = (1 << s->n_chan) - 1;
347			else
348				s->io_bits = 0xffffffff;
349		}
350
351		if (s->len_chanlist == 0)
352			s->len_chanlist = 1;
353
354		if (s->do_cmd) {
355			ret = __comedi_device_postconfig_async(dev, s);
356			if (ret)
357				return ret;
358		}
359
360		if (!s->range_table && !s->range_table_list)
361			s->range_table = &range_unknown;
362
363		if (!s->insn_read && s->insn_bits)
364			s->insn_read = insn_rw_emulate_bits;
365		if (!s->insn_write && s->insn_bits)
366			s->insn_write = insn_rw_emulate_bits;
367
368		if (!s->insn_read)
369			s->insn_read = insn_inval;
370		if (!s->insn_write)
371			s->insn_write = insn_inval;
372		if (!s->insn_bits)
373			s->insn_bits = insn_inval;
374		if (!s->insn_config)
375			s->insn_config = insn_inval;
376
377		if (!s->poll)
378			s->poll = poll_invalid;
379	}
380
381	return 0;
382}
383
384/* do a little post-config cleanup */
385static int comedi_device_postconfig(struct comedi_device *dev)
386{
387	int ret;
388
389	ret = __comedi_device_postconfig(dev);
390	if (ret < 0)
391		return ret;
392	down_write(&dev->attach_lock);
393	dev->attached = true;
394	up_write(&dev->attach_lock);
395	return 0;
396}
397
398/*
399 * Generic recognize function for drivers that register their supported
400 * board names.
401 *
402 * 'driv->board_name' points to a 'const char *' member within the
403 * zeroth element of an array of some private board information
404 * structure, say 'struct foo_board' containing a member 'const char
405 * *board_name' that is initialized to point to a board name string that
406 * is one of the candidates matched against this function's 'name'
407 * parameter.
408 *
409 * 'driv->offset' is the size of the private board information
410 * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is
411 * the length of the array of private board information structures.
412 *
413 * If one of the board names in the array of private board information
414 * structures matches the name supplied to this function, the function
415 * returns a pointer to the pointer to the board name, otherwise it
416 * returns NULL.  The return value ends up in the 'board_ptr' member of
417 * a 'struct comedi_device' that the low-level comedi driver's
418 * 'attach()' hook can convert to a point to a particular element of its
419 * array of private board information structures by subtracting the
420 * offset of the member that points to the board name.  (No subtraction
421 * is required if the board name pointer is the first member of the
422 * private board information structure, which is generally the case.)
423 */
424static void *comedi_recognize(struct comedi_driver *driv, const char *name)
425{
426	char **name_ptr = (char **)driv->board_name;
427	int i;
428
429	for (i = 0; i < driv->num_names; i++) {
430		if (strcmp(*name_ptr, name) == 0)
431			return name_ptr;
432		name_ptr = (void *)name_ptr + driv->offset;
433	}
434
435	return NULL;
436}
437
438static void comedi_report_boards(struct comedi_driver *driv)
439{
440	unsigned int i;
441	const char *const *name_ptr;
442
443	pr_info("comedi: valid board names for %s driver are:\n",
444		driv->driver_name);
445
446	name_ptr = driv->board_name;
447	for (i = 0; i < driv->num_names; i++) {
448		pr_info(" %s\n", *name_ptr);
449		name_ptr = (const char **)((char *)name_ptr + driv->offset);
450	}
451
452	if (driv->num_names == 0)
453		pr_info(" %s\n", driv->driver_name);
454}
455
456/**
457 * comedi_load_firmware() - Request and load firmware for a device.
458 * @dev: comedi_device struct
459 * @hw_device: device struct for the comedi_device
460 * @name: the name of the firmware image
461 * @cb: callback to the upload the firmware image
462 * @context: private context from the driver
463 */
464int comedi_load_firmware(struct comedi_device *dev,
465			 struct device *device,
466			 const char *name,
467			 int (*cb)(struct comedi_device *dev,
468				   const u8 *data, size_t size,
469				   unsigned long context),
470			 unsigned long context)
471{
472	const struct firmware *fw;
473	int ret;
474
475	if (!cb)
476		return -EINVAL;
477
478	ret = request_firmware(&fw, name, device);
479	if (ret == 0) {
480		ret = cb(dev, fw->data, fw->size, context);
481		release_firmware(fw);
482	}
483
484	return ret < 0 ? ret : 0;
485}
486EXPORT_SYMBOL_GPL(comedi_load_firmware);
487
488/**
489 * __comedi_request_region() - Request an I/O reqion for a legacy driver.
490 * @dev: comedi_device struct
491 * @start: base address of the I/O reqion
492 * @len: length of the I/O region
493 */
494int __comedi_request_region(struct comedi_device *dev,
495			    unsigned long start, unsigned long len)
496{
497	if (!start) {
498		dev_warn(dev->class_dev,
499			 "%s: a I/O base address must be specified\n",
500			 dev->board_name);
501		return -EINVAL;
502	}
503
504	if (!request_region(start, len, dev->board_name)) {
505		dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n",
506			 dev->board_name, start, len);
507		return -EIO;
508	}
509
510	return 0;
511}
512EXPORT_SYMBOL_GPL(__comedi_request_region);
513
514/**
515 * comedi_request_region() - Request an I/O reqion for a legacy driver.
516 * @dev: comedi_device struct
517 * @start: base address of the I/O reqion
518 * @len: length of the I/O region
519 */
520int comedi_request_region(struct comedi_device *dev,
521			  unsigned long start, unsigned long len)
522{
523	int ret;
524
525	ret = __comedi_request_region(dev, start, len);
526	if (ret == 0) {
527		dev->iobase = start;
528		dev->iolen = len;
529	}
530
531	return ret;
532}
533EXPORT_SYMBOL_GPL(comedi_request_region);
534
535/**
536 * comedi_legacy_detach() - A generic (*detach) function for legacy drivers.
537 * @dev: comedi_device struct
538 */
539void comedi_legacy_detach(struct comedi_device *dev)
540{
541	if (dev->irq) {
542		free_irq(dev->irq, dev);
543		dev->irq = 0;
544	}
545	if (dev->iobase && dev->iolen) {
546		release_region(dev->iobase, dev->iolen);
547		dev->iobase = 0;
548		dev->iolen = 0;
549	}
550}
551EXPORT_SYMBOL_GPL(comedi_legacy_detach);
552
553int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
554{
555	struct comedi_driver *driv;
556	int ret;
557
558	if (dev->attached)
559		return -EBUSY;
560
561	mutex_lock(&comedi_drivers_list_lock);
562	for (driv = comedi_drivers; driv; driv = driv->next) {
563		if (!try_module_get(driv->module))
564			continue;
565		if (driv->num_names) {
566			dev->board_ptr = comedi_recognize(driv, it->board_name);
567			if (dev->board_ptr)
568				break;
569		} else if (strcmp(driv->driver_name, it->board_name) == 0)
570			break;
571		module_put(driv->module);
572	}
573	if (driv == NULL) {
574		/*  recognize has failed if we get here */
575		/*  report valid board names before returning error */
576		for (driv = comedi_drivers; driv; driv = driv->next) {
577			if (!try_module_get(driv->module))
578				continue;
579			comedi_report_boards(driv);
580			module_put(driv->module);
581		}
582		ret = -EIO;
583		goto out;
584	}
585	if (driv->attach == NULL) {
586		/* driver does not support manual configuration */
587		dev_warn(dev->class_dev,
588			 "driver '%s' does not support attach using comedi_config\n",
589			 driv->driver_name);
590		module_put(driv->module);
591		ret = -ENOSYS;
592		goto out;
593	}
594	dev->driver = driv;
595	dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
596					 : dev->driver->driver_name;
597	ret = driv->attach(dev, it);
598	if (ret >= 0)
599		ret = comedi_device_postconfig(dev);
600	if (ret < 0) {
601		comedi_device_detach(dev);
602		module_put(driv->module);
603	}
604	/* On success, the driver module count has been incremented. */
605out:
606	mutex_unlock(&comedi_drivers_list_lock);
607	return ret;
608}
609
610int comedi_auto_config(struct device *hardware_device,
611		       struct comedi_driver *driver, unsigned long context)
612{
613	struct comedi_device *dev;
614	int ret;
615
616	if (!hardware_device) {
617		pr_warn("BUG! comedi_auto_config called with NULL hardware_device\n");
618		return -EINVAL;
619	}
620	if (!driver) {
621		dev_warn(hardware_device,
622			 "BUG! comedi_auto_config called with NULL comedi driver\n");
623		return -EINVAL;
624	}
625
626	if (!driver->auto_attach) {
627		dev_warn(hardware_device,
628			 "BUG! comedi driver '%s' has no auto_attach handler\n",
629			 driver->driver_name);
630		return -EINVAL;
631	}
632
633	dev = comedi_alloc_board_minor(hardware_device);
634	if (IS_ERR(dev)) {
635		dev_warn(hardware_device,
636			 "driver '%s' could not create device.\n",
637			 driver->driver_name);
638		return PTR_ERR(dev);
639	}
640	/* Note: comedi_alloc_board_minor() locked dev->mutex. */
641
642	dev->driver = driver;
643	dev->board_name = dev->driver->driver_name;
644	ret = driver->auto_attach(dev, context);
645	if (ret >= 0)
646		ret = comedi_device_postconfig(dev);
647	mutex_unlock(&dev->mutex);
648
649	if (ret < 0) {
650		dev_warn(hardware_device,
651			 "driver '%s' failed to auto-configure device.\n",
652			 driver->driver_name);
653		comedi_release_hardware_device(hardware_device);
654	} else {
655		/*
656		 * class_dev should be set properly here
657		 *  after a successful auto config
658		 */
659		dev_info(dev->class_dev,
660			 "driver '%s' has successfully auto-configured '%s'.\n",
661			 driver->driver_name, dev->board_name);
662	}
663	return ret;
664}
665EXPORT_SYMBOL_GPL(comedi_auto_config);
666
667void comedi_auto_unconfig(struct device *hardware_device)
668{
669	if (hardware_device == NULL)
670		return;
671	comedi_release_hardware_device(hardware_device);
672}
673EXPORT_SYMBOL_GPL(comedi_auto_unconfig);
674
675int comedi_driver_register(struct comedi_driver *driver)
676{
677	mutex_lock(&comedi_drivers_list_lock);
678	driver->next = comedi_drivers;
679	comedi_drivers = driver;
680	mutex_unlock(&comedi_drivers_list_lock);
681
682	return 0;
683}
684EXPORT_SYMBOL_GPL(comedi_driver_register);
685
686void comedi_driver_unregister(struct comedi_driver *driver)
687{
688	struct comedi_driver *prev;
689	int i;
690
691	/* unlink the driver */
692	mutex_lock(&comedi_drivers_list_lock);
693	if (comedi_drivers == driver) {
694		comedi_drivers = driver->next;
695	} else {
696		for (prev = comedi_drivers; prev->next; prev = prev->next) {
697			if (prev->next == driver) {
698				prev->next = driver->next;
699				break;
700			}
701		}
702	}
703	mutex_unlock(&comedi_drivers_list_lock);
704
705	/* check for devices using this driver */
706	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
707		struct comedi_device *dev = comedi_dev_get_from_minor(i);
708
709		if (!dev)
710			continue;
711
712		mutex_lock(&dev->mutex);
713		if (dev->attached && dev->driver == driver) {
714			if (dev->use_count)
715				dev_warn(dev->class_dev,
716					 "BUG! detaching device with use_count=%d\n",
717					 dev->use_count);
718			comedi_device_detach(dev);
719		}
720		mutex_unlock(&dev->mutex);
721		comedi_dev_put(dev);
722	}
723}
724EXPORT_SYMBOL_GPL(comedi_driver_unregister);
725