1 /*
2  * V4L2 asynchronous subdevice registration API
3  *
4  * Copyright (C) 2012-2013, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/i2c.h>
14 #include <linux/list.h>
15 #include <linux/module.h>
16 #include <linux/mutex.h>
17 #include <linux/platform_device.h>
18 #include <linux/slab.h>
19 #include <linux/types.h>
20 
21 #include <media/v4l2-async.h>
22 #include <media/v4l2-device.h>
23 #include <media/v4l2-subdev.h>
24 
25 static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
26 {
27 #if IS_ENABLED(CONFIG_I2C)
28 	struct i2c_client *client = i2c_verify_client(dev);
29 	return client &&
30 		asd->bus_type == V4L2_ASYNC_BUS_I2C &&
31 		asd->match.i2c.adapter_id == client->adapter->nr &&
32 		asd->match.i2c.address == client->addr;
33 #else
34 	return false;
35 #endif
36 }
37 
38 static bool match_platform(struct device *dev, struct v4l2_async_subdev *asd)
39 {
40 	return asd->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
41 		!strcmp(asd->match.platform.name, dev_name(dev));
42 }
43 
44 static LIST_HEAD(subdev_list);
45 static LIST_HEAD(notifier_list);
46 static DEFINE_MUTEX(list_lock);
47 
48 static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
49 						    struct v4l2_async_subdev_list *asdl)
50 {
51 	struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
52 	struct v4l2_async_subdev *asd;
53 	bool (*match)(struct device *,
54 		      struct v4l2_async_subdev *);
55 
56 	list_for_each_entry(asd, &notifier->waiting, list) {
57 		/* bus_type has been verified valid before */
58 		switch (asd->bus_type) {
59 		case V4L2_ASYNC_BUS_CUSTOM:
60 			match = asd->match.custom.match;
61 			if (!match)
62 				/* Match always */
63 				return asd;
64 			break;
65 		case V4L2_ASYNC_BUS_PLATFORM:
66 			match = match_platform;
67 			break;
68 		case V4L2_ASYNC_BUS_I2C:
69 			match = match_i2c;
70 			break;
71 		default:
72 			/* Cannot happen, unless someone breaks us */
73 			WARN_ON(true);
74 			return NULL;
75 		}
76 
77 		/* match cannot be NULL here */
78 		if (match(sd->dev, asd))
79 			return asd;
80 	}
81 
82 	return NULL;
83 }
84 
85 static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
86 				  struct v4l2_async_subdev_list *asdl,
87 				  struct v4l2_async_subdev *asd)
88 {
89 	struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
90 	int ret;
91 
92 	/* Remove from the waiting list */
93 	list_del(&asd->list);
94 	asdl->asd = asd;
95 	asdl->notifier = notifier;
96 
97 	if (notifier->bound) {
98 		ret = notifier->bound(notifier, sd, asd);
99 		if (ret < 0)
100 			return ret;
101 	}
102 	/* Move from the global subdevice list to notifier's done */
103 	list_move(&asdl->list, &notifier->done);
104 
105 	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
106 	if (ret < 0) {
107 		if (notifier->unbind)
108 			notifier->unbind(notifier, sd, asd);
109 		return ret;
110 	}
111 
112 	if (list_empty(&notifier->waiting) && notifier->complete)
113 		return notifier->complete(notifier);
114 
115 	return 0;
116 }
117 
118 static void v4l2_async_cleanup(struct v4l2_async_subdev_list *asdl)
119 {
120 	struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
121 
122 	v4l2_device_unregister_subdev(sd);
123 	/* Subdevice driver will reprobe and put asdl back onto the list */
124 	list_del_init(&asdl->list);
125 	asdl->asd = NULL;
126 	sd->dev = NULL;
127 }
128 
129 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
130 				 struct v4l2_async_notifier *notifier)
131 {
132 	struct v4l2_async_subdev_list *asdl, *tmp;
133 	struct v4l2_async_subdev *asd;
134 	int i;
135 
136 	if (!notifier->num_subdevs || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
137 		return -EINVAL;
138 
139 	notifier->v4l2_dev = v4l2_dev;
140 	INIT_LIST_HEAD(&notifier->waiting);
141 	INIT_LIST_HEAD(&notifier->done);
142 
143 	for (i = 0; i < notifier->num_subdevs; i++) {
144 		asd = notifier->subdev[i];
145 
146 		switch (asd->bus_type) {
147 		case V4L2_ASYNC_BUS_CUSTOM:
148 		case V4L2_ASYNC_BUS_PLATFORM:
149 		case V4L2_ASYNC_BUS_I2C:
150 			break;
151 		default:
152 			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
153 				"Invalid bus-type %u on %p\n",
154 				asd->bus_type, asd);
155 			return -EINVAL;
156 		}
157 		list_add_tail(&asd->list, &notifier->waiting);
158 	}
159 
160 	mutex_lock(&list_lock);
161 
162 	/* Keep also completed notifiers on the list */
163 	list_add(&notifier->list, &notifier_list);
164 
165 	list_for_each_entry_safe(asdl, tmp, &subdev_list, list) {
166 		int ret;
167 
168 		asd = v4l2_async_belongs(notifier, asdl);
169 		if (!asd)
170 			continue;
171 
172 		ret = v4l2_async_test_notify(notifier, asdl, asd);
173 		if (ret < 0) {
174 			mutex_unlock(&list_lock);
175 			return ret;
176 		}
177 	}
178 
179 	mutex_unlock(&list_lock);
180 
181 	return 0;
182 }
183 EXPORT_SYMBOL(v4l2_async_notifier_register);
184 
185 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
186 {
187 	struct v4l2_async_subdev_list *asdl, *tmp;
188 	unsigned int notif_n_subdev = notifier->num_subdevs;
189 	unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
190 	struct device *dev[n_subdev];
191 	int i = 0;
192 
193 	mutex_lock(&list_lock);
194 
195 	list_del(&notifier->list);
196 
197 	list_for_each_entry_safe(asdl, tmp, &notifier->done, list) {
198 		struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
199 
200 		dev[i] = get_device(sd->dev);
201 
202 		v4l2_async_cleanup(asdl);
203 
204 		/* If we handled USB devices, we'd have to lock the parent too */
205 		device_release_driver(dev[i++]);
206 
207 		if (notifier->unbind)
208 			notifier->unbind(notifier, sd, sd->asdl.asd);
209 	}
210 
211 	mutex_unlock(&list_lock);
212 
213 	while (i--) {
214 		struct device *d = dev[i];
215 
216 		if (d && device_attach(d) < 0) {
217 			const char *name = "(none)";
218 			int lock = device_trylock(d);
219 
220 			if (lock && d->driver)
221 				name = d->driver->name;
222 			dev_err(d, "Failed to re-probe to %s\n", name);
223 			if (lock)
224 				device_unlock(d);
225 		}
226 		put_device(d);
227 	}
228 	/*
229 	 * Don't care about the waiting list, it is initialised and populated
230 	 * upon notifier registration.
231 	 */
232 }
233 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
234 
235 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
236 {
237 	struct v4l2_async_subdev_list *asdl = &sd->asdl;
238 	struct v4l2_async_notifier *notifier;
239 
240 	mutex_lock(&list_lock);
241 
242 	INIT_LIST_HEAD(&asdl->list);
243 
244 	list_for_each_entry(notifier, &notifier_list, list) {
245 		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, asdl);
246 		if (asd) {
247 			int ret = v4l2_async_test_notify(notifier, asdl, asd);
248 			mutex_unlock(&list_lock);
249 			return ret;
250 		}
251 	}
252 
253 	/* None matched, wait for hot-plugging */
254 	list_add(&asdl->list, &subdev_list);
255 
256 	mutex_unlock(&list_lock);
257 
258 	return 0;
259 }
260 EXPORT_SYMBOL(v4l2_async_register_subdev);
261 
262 void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
263 {
264 	struct v4l2_async_subdev_list *asdl = &sd->asdl;
265 	struct v4l2_async_notifier *notifier = asdl->notifier;
266 
267 	if (!asdl->asd) {
268 		if (!list_empty(&asdl->list))
269 			v4l2_async_cleanup(asdl);
270 		return;
271 	}
272 
273 	mutex_lock(&list_lock);
274 
275 	list_add(&asdl->asd->list, &notifier->waiting);
276 
277 	v4l2_async_cleanup(asdl);
278 
279 	if (notifier->unbind)
280 		notifier->unbind(notifier, sd, sd->asdl.asd);
281 
282 	mutex_unlock(&list_lock);
283 }
284 EXPORT_SYMBOL(v4l2_async_unregister_subdev);
285