| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 1 | /* | 
 | 2 |  * drivers/media/video/v4l2-int-device.c | 
 | 3 |  * | 
 | 4 |  * V4L2 internal ioctl interface. | 
 | 5 |  * | 
 | 6 |  * Copyright (C) 2007 Nokia Corporation. | 
 | 7 |  * | 
 | 8 |  * Contact: Sakari Ailus <sakari.ailus@nokia.com> | 
 | 9 |  * | 
 | 10 |  * This program is free software; you can redistribute it and/or | 
 | 11 |  * modify it under the terms of the GNU General Public License | 
 | 12 |  * version 2 as published by the Free Software Foundation. | 
 | 13 |  * | 
 | 14 |  * This program is distributed in the hope that it will be useful, but | 
 | 15 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 16 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 17 |  * General Public License for more details. | 
 | 18 |  * | 
 | 19 |  * You should have received a copy of the GNU General Public License | 
 | 20 |  * along with this program; if not, write to the Free Software | 
 | 21 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
 | 22 |  * 02110-1301 USA | 
 | 23 |  */ | 
 | 24 |  | 
 | 25 | #include <linux/kernel.h> | 
 | 26 | #include <linux/list.h> | 
 | 27 | #include <linux/sort.h> | 
 | 28 | #include <linux/string.h> | 
 | 29 |  | 
 | 30 | #include <media/v4l2-int-device.h> | 
 | 31 |  | 
 | 32 | static DEFINE_MUTEX(mutex); | 
 | 33 | static LIST_HEAD(int_list); | 
 | 34 |  | 
| Sakari Ailus | 36499e5 | 2008-10-18 12:28:36 -0300 | [diff] [blame] | 35 | void v4l2_int_device_try_attach_all(void) | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 36 | { | 
| Trent Piepho | a991f44 | 2007-10-10 05:37:43 -0300 | [diff] [blame] | 37 | 	struct v4l2_int_device *m, *s; | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 38 |  | 
| Trent Piepho | a991f44 | 2007-10-10 05:37:43 -0300 | [diff] [blame] | 39 | 	list_for_each_entry(m, &int_list, head) { | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 40 | 		if (m->type != v4l2_int_type_master) | 
 | 41 | 			continue; | 
 | 42 |  | 
| Trent Piepho | a991f44 | 2007-10-10 05:37:43 -0300 | [diff] [blame] | 43 | 		list_for_each_entry(s, &int_list, head) { | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 44 | 			if (s->type != v4l2_int_type_slave) | 
 | 45 | 				continue; | 
 | 46 |  | 
 | 47 | 			/* Slave is connected? */ | 
 | 48 | 			if (s->u.slave->master) | 
 | 49 | 				continue; | 
 | 50 |  | 
 | 51 | 			/* Slave wants to attach to master? */ | 
 | 52 | 			if (s->u.slave->attach_to[0] != 0 | 
 | 53 | 			    && strncmp(m->name, s->u.slave->attach_to, | 
 | 54 | 				       V4L2NAMESIZE)) | 
 | 55 | 				continue; | 
 | 56 |  | 
 | 57 | 			if (!try_module_get(m->module)) | 
 | 58 | 				continue; | 
 | 59 |  | 
| Sakari Ailus | 2c94a67 | 2007-10-30 05:52:52 -0300 | [diff] [blame] | 60 | 			s->u.slave->master = m; | 
 | 61 | 			if (m->u.master->attach(s)) { | 
 | 62 | 				s->u.slave->master = NULL; | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 63 | 				module_put(m->module); | 
 | 64 | 				continue; | 
 | 65 | 			} | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 66 | 		} | 
 | 67 | 	} | 
 | 68 | } | 
| Sakari Ailus | 36499e5 | 2008-10-18 12:28:36 -0300 | [diff] [blame] | 69 | EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all); | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 70 |  | 
 | 71 | static int ioctl_sort_cmp(const void *a, const void *b) | 
 | 72 | { | 
 | 73 | 	const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; | 
 | 74 |  | 
 | 75 | 	if (d1->num > d2->num) | 
 | 76 | 		return 1; | 
 | 77 |  | 
 | 78 | 	if (d1->num < d2->num) | 
 | 79 | 		return -1; | 
 | 80 |  | 
 | 81 | 	return 0; | 
 | 82 | } | 
 | 83 |  | 
 | 84 | int v4l2_int_device_register(struct v4l2_int_device *d) | 
 | 85 | { | 
 | 86 | 	if (d->type == v4l2_int_type_slave) | 
 | 87 | 		sort(d->u.slave->ioctls, d->u.slave->num_ioctls, | 
 | 88 | 		     sizeof(struct v4l2_int_ioctl_desc), | 
 | 89 | 		     &ioctl_sort_cmp, NULL); | 
 | 90 | 	mutex_lock(&mutex); | 
 | 91 | 	list_add(&d->head, &int_list); | 
 | 92 | 	v4l2_int_device_try_attach_all(); | 
 | 93 | 	mutex_unlock(&mutex); | 
 | 94 |  | 
 | 95 | 	return 0; | 
 | 96 | } | 
| Adrian Bunk | 261efd1 | 2007-07-30 11:43:55 -0300 | [diff] [blame] | 97 | EXPORT_SYMBOL_GPL(v4l2_int_device_register); | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 98 |  | 
 | 99 | void v4l2_int_device_unregister(struct v4l2_int_device *d) | 
 | 100 | { | 
 | 101 | 	mutex_lock(&mutex); | 
 | 102 | 	list_del(&d->head); | 
 | 103 | 	if (d->type == v4l2_int_type_slave | 
 | 104 | 	    && d->u.slave->master != NULL) { | 
 | 105 | 		d->u.slave->master->u.master->detach(d); | 
 | 106 | 		module_put(d->u.slave->master->module); | 
 | 107 | 		d->u.slave->master = NULL; | 
 | 108 | 	} | 
 | 109 | 	mutex_unlock(&mutex); | 
 | 110 | } | 
| Adrian Bunk | 261efd1 | 2007-07-30 11:43:55 -0300 | [diff] [blame] | 111 | EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 112 |  | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 113 | /* Adapted from search_extable in extable.c. */ | 
| Sakari Ailus | 63116fe | 2007-07-20 13:12:51 -0300 | [diff] [blame] | 114 | static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, | 
 | 115 | 				       v4l2_int_ioctl_func *no_such_ioctl) | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 116 | { | 
 | 117 | 	const struct v4l2_int_ioctl_desc *first = slave->ioctls; | 
 | 118 | 	const struct v4l2_int_ioctl_desc *last = | 
 | 119 | 		first + slave->num_ioctls - 1; | 
 | 120 |  | 
 | 121 | 	while (first <= last) { | 
 | 122 | 		const struct v4l2_int_ioctl_desc *mid; | 
 | 123 |  | 
 | 124 | 		mid = (last - first) / 2 + first; | 
 | 125 |  | 
 | 126 | 		if (mid->num < cmd) | 
 | 127 | 			first = mid + 1; | 
 | 128 | 		else if (mid->num > cmd) | 
 | 129 | 			last = mid - 1; | 
 | 130 | 		else | 
 | 131 | 			return mid->func; | 
 | 132 | 	} | 
 | 133 |  | 
| Sakari Ailus | 63116fe | 2007-07-20 13:12:51 -0300 | [diff] [blame] | 134 | 	return no_such_ioctl; | 
 | 135 | } | 
 | 136 |  | 
 | 137 | static int no_such_ioctl_0(struct v4l2_int_device *d) | 
 | 138 | { | 
| Sakari Ailus | 61c310d | 2007-08-30 09:20:40 -0300 | [diff] [blame] | 139 | 	return -ENOIOCTLCMD; | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 140 | } | 
 | 141 |  | 
 | 142 | int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) | 
 | 143 | { | 
| Sakari Ailus | 63116fe | 2007-07-20 13:12:51 -0300 | [diff] [blame] | 144 | 	return ((v4l2_int_ioctl_func_0 *) | 
 | 145 | 		find_ioctl(d->u.slave, cmd, | 
| Sakari Ailus | 098c645 | 2007-08-30 09:20:38 -0300 | [diff] [blame] | 146 | 			   (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); | 
| Sakari Ailus | 63116fe | 2007-07-20 13:12:51 -0300 | [diff] [blame] | 147 | } | 
| Sakari Ailus | 36499e5 | 2008-10-18 12:28:36 -0300 | [diff] [blame] | 148 | EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0); | 
| Sakari Ailus | 63116fe | 2007-07-20 13:12:51 -0300 | [diff] [blame] | 149 |  | 
 | 150 | static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) | 
 | 151 | { | 
| Sakari Ailus | 61c310d | 2007-08-30 09:20:40 -0300 | [diff] [blame] | 152 | 	return -ENOIOCTLCMD; | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 153 | } | 
 | 154 |  | 
 | 155 | int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) | 
 | 156 | { | 
| Sakari Ailus | 63116fe | 2007-07-20 13:12:51 -0300 | [diff] [blame] | 157 | 	return ((v4l2_int_ioctl_func_1 *) | 
 | 158 | 		find_ioctl(d->u.slave, cmd, | 
| Sakari Ailus | 098c645 | 2007-08-30 09:20:38 -0300 | [diff] [blame] | 159 | 			   (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); | 
| Sakari Ailus | 9b5d0f1 | 2007-07-18 17:59:15 -0300 | [diff] [blame] | 160 | } | 
| Sakari Ailus | 36499e5 | 2008-10-18 12:28:36 -0300 | [diff] [blame] | 161 | EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1); | 
| Adrian Bunk | 19ac111 | 2008-03-31 09:08:08 -0300 | [diff] [blame] | 162 |  | 
 | 163 | MODULE_LICENSE("GPL"); |