diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch')
-rw-r--r-- | extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch b/extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch new file mode 100644 index 00000000..8fe2a9d6 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch | |||
@@ -0,0 +1,615 @@ | |||
1 | From e5b8af4e36ca5e922dd2b881d6c215e9d4d30a6f Mon Sep 17 00:00:00 2001 | ||
2 | From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
3 | Date: Wed, 9 Dec 2009 12:38:49 +0100 | ||
4 | Subject: [PATCH 04/43] v4l: subdev: Add device node support | ||
5 | |||
6 | Create a device node named subdevX for every registered subdev. | ||
7 | |||
8 | As the device node is registered before the subdev core::s_config | ||
9 | function is called, return -EGAIN on open until initialization | ||
10 | completes. | ||
11 | |||
12 | Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
13 | Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com> | ||
14 | --- | ||
15 | Documentation/video4linux/v4l2-framework.txt | 18 +++++++ | ||
16 | drivers/media/radio/radio-si4713.c | 2 +- | ||
17 | drivers/media/video/Makefile | 2 +- | ||
18 | drivers/media/video/cafe_ccic.c | 2 +- | ||
19 | drivers/media/video/davinci/vpfe_capture.c | 2 +- | ||
20 | drivers/media/video/davinci/vpif_capture.c | 2 +- | ||
21 | drivers/media/video/davinci/vpif_display.c | 2 +- | ||
22 | drivers/media/video/ivtv/ivtv-i2c.c | 2 +- | ||
23 | drivers/media/video/s5p-fimc/fimc-capture.c | 2 +- | ||
24 | drivers/media/video/sh_vou.c | 2 +- | ||
25 | drivers/media/video/soc_camera.c | 2 +- | ||
26 | drivers/media/video/v4l2-common.c | 15 +++++- | ||
27 | drivers/media/video/v4l2-dev.c | 27 ++++------ | ||
28 | drivers/media/video/v4l2-device.c | 24 +++++++++- | ||
29 | drivers/media/video/v4l2-ioctl.c | 2 +- | ||
30 | drivers/media/video/v4l2-subdev.c | 66 ++++++++++++++++++++++++++ | ||
31 | include/media/v4l2-common.h | 5 +- | ||
32 | include/media/v4l2-dev.h | 18 ++++++- | ||
33 | include/media/v4l2-ioctl.h | 3 + | ||
34 | include/media/v4l2-subdev.h | 16 ++++++- | ||
35 | 20 files changed, 176 insertions(+), 38 deletions(-) | ||
36 | create mode 100644 drivers/media/video/v4l2-subdev.c | ||
37 | |||
38 | diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt | ||
39 | index f22f35c..4c9185a 100644 | ||
40 | --- a/Documentation/video4linux/v4l2-framework.txt | ||
41 | +++ b/Documentation/video4linux/v4l2-framework.txt | ||
42 | @@ -319,6 +319,24 @@ controlled through GPIO pins. This distinction is only relevant when setting | ||
43 | up the device, but once the subdev is registered it is completely transparent. | ||
44 | |||
45 | |||
46 | +V4L2 sub-device userspace API | ||
47 | +----------------------------- | ||
48 | + | ||
49 | +Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2 | ||
50 | +sub-devices can also be controlled directly by userspace applications. | ||
51 | + | ||
52 | +When a sub-device is registered, a device node named v4l-subdevX can be created | ||
53 | +in /dev. If the sub-device supports direct userspace configuration it must set | ||
54 | +the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered. | ||
55 | + | ||
56 | +For I2C and SPI sub-devices, the v4l2_device driver can disable registration of | ||
57 | +the device node if it wants to control the sub-device on its own. In that case | ||
58 | +it must set the v4l2_i2c_new_subdev_board or v4l2_spi_new_subdev enable_devnode | ||
59 | +argument to 0. Setting the argument to 1 will only enable device node | ||
60 | +registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE | ||
61 | +flag. | ||
62 | + | ||
63 | + | ||
64 | I2C sub-device drivers | ||
65 | ---------------------- | ||
66 | |||
67 | diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c | ||
68 | index 726d367..f7c942f 100644 | ||
69 | --- a/drivers/media/radio/radio-si4713.c | ||
70 | +++ b/drivers/media/radio/radio-si4713.c | ||
71 | @@ -293,7 +293,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) | ||
72 | } | ||
73 | |||
74 | sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, | ||
75 | - pdata->subdev_board_info, NULL); | ||
76 | + pdata->subdev_board_info, NULL, 0); | ||
77 | if (!sd) { | ||
78 | dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n"); | ||
79 | rval = -ENODEV; | ||
80 | diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile | ||
81 | index af79d47..adc1bd5 100644 | ||
82 | --- a/drivers/media/video/Makefile | ||
83 | +++ b/drivers/media/video/Makefile | ||
84 | @@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o | ||
85 | omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o | ||
86 | |||
87 | videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ | ||
88 | - v4l2-event.o v4l2-ctrls.o | ||
89 | + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o | ||
90 | |||
91 | # V4L2 core modules | ||
92 | |||
93 | diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c | ||
94 | index 6e23add..f932da1 100644 | ||
95 | --- a/drivers/media/video/cafe_ccic.c | ||
96 | +++ b/drivers/media/video/cafe_ccic.c | ||
97 | @@ -2073,7 +2073,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, | ||
98 | info.platform_data = &sensor_cfg; | ||
99 | |||
100 | cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, | ||
101 | - &cam->i2c_adapter, &info, NULL); | ||
102 | + &cam->i2c_adapter, &info, NULL, 0); | ||
103 | if (cam->sensor == NULL) { | ||
104 | ret = -ENODEV; | ||
105 | goto out_smbus; | ||
106 | diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c | ||
107 | index 7333a9b..bfc2a47 100644 | ||
108 | --- a/drivers/media/video/davinci/vpfe_capture.c | ||
109 | +++ b/drivers/media/video/davinci/vpfe_capture.c | ||
110 | @@ -1987,7 +1987,7 @@ static __init int vpfe_probe(struct platform_device *pdev) | ||
111 | v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, | ||
112 | i2c_adap, | ||
113 | &sdinfo->board_info, | ||
114 | - NULL); | ||
115 | + NULL, 0); | ||
116 | if (vpfe_dev->sd[i]) { | ||
117 | v4l2_info(&vpfe_dev->v4l2_dev, | ||
118 | "v4l2 sub device %s registered\n", | ||
119 | diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c | ||
120 | index 193abab..d2228e0 100644 | ||
121 | --- a/drivers/media/video/davinci/vpif_capture.c | ||
122 | +++ b/drivers/media/video/davinci/vpif_capture.c | ||
123 | @@ -2014,7 +2014,7 @@ static __init int vpif_probe(struct platform_device *pdev) | ||
124 | v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | ||
125 | i2c_adap, | ||
126 | &subdevdata->board_info, | ||
127 | - NULL); | ||
128 | + NULL, 0); | ||
129 | |||
130 | if (!vpif_obj.sd[i]) { | ||
131 | vpif_err("Error registering v4l2 subdevice\n"); | ||
132 | diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c | ||
133 | index 412c65d..060c049 100644 | ||
134 | --- a/drivers/media/video/davinci/vpif_display.c | ||
135 | +++ b/drivers/media/video/davinci/vpif_display.c | ||
136 | @@ -1555,7 +1555,7 @@ static __init int vpif_probe(struct platform_device *pdev) | ||
137 | vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | ||
138 | i2c_adap, | ||
139 | &subdevdata[i].board_info, | ||
140 | - NULL); | ||
141 | + NULL, 0); | ||
142 | if (!vpif_obj.sd[i]) { | ||
143 | vpif_err("Error registering v4l2 subdevice\n"); | ||
144 | goto probe_subdev_out; | ||
145 | diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c | ||
146 | index 6651a6c..3d3b62d 100644 | ||
147 | --- a/drivers/media/video/ivtv/ivtv-i2c.c | ||
148 | +++ b/drivers/media/video/ivtv/ivtv-i2c.c | ||
149 | @@ -277,7 +277,7 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) | ||
150 | info.platform_data = &pdata; | ||
151 | |||
152 | sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, &info, | ||
153 | - NULL); | ||
154 | + NULL, 0); | ||
155 | } else { | ||
156 | sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, | ||
157 | adap, type, hw_addrs[idx], NULL); | ||
158 | diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c | ||
159 | index 2f50080..b237daa 100644 | ||
160 | --- a/drivers/media/video/s5p-fimc/fimc-capture.c | ||
161 | +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | ||
162 | @@ -44,7 +44,7 @@ static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc, | ||
163 | return ERR_PTR(-ENOMEM); | ||
164 | |||
165 | sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap, | ||
166 | - isp_info->board_info, NULL); | ||
167 | + isp_info->board_info, NULL, 0); | ||
168 | if (!sd) { | ||
169 | v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n"); | ||
170 | return NULL; | ||
171 | diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c | ||
172 | index 07cf0c6..c50f0f5 100644 | ||
173 | --- a/drivers/media/video/sh_vou.c | ||
174 | +++ b/drivers/media/video/sh_vou.c | ||
175 | @@ -1409,7 +1409,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) | ||
176 | goto ereset; | ||
177 | |||
178 | subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap, | ||
179 | - vou_pdata->board_info, NULL); | ||
180 | + vou_pdata->board_info, NULL, 0); | ||
181 | if (!subdev) { | ||
182 | ret = -ENOMEM; | ||
183 | goto ei2cnd; | ||
184 | diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c | ||
185 | index 052bd6d..5afb601 100644 | ||
186 | --- a/drivers/media/video/soc_camera.c | ||
187 | +++ b/drivers/media/video/soc_camera.c | ||
188 | @@ -896,7 +896,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, | ||
189 | icl->board_info->platform_data = icd; | ||
190 | |||
191 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, | ||
192 | - icl->board_info, NULL); | ||
193 | + icl->board_info, NULL, 0); | ||
194 | if (!subdev) | ||
195 | goto ei2cnd; | ||
196 | |||
197 | diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c | ||
198 | index e007e61..ffee794 100644 | ||
199 | --- a/drivers/media/video/v4l2-common.c | ||
200 | +++ b/drivers/media/video/v4l2-common.c | ||
201 | @@ -369,7 +369,7 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); | ||
202 | /* Load an i2c sub-device. */ | ||
203 | struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | ||
204 | struct i2c_adapter *adapter, struct i2c_board_info *info, | ||
205 | - const unsigned short *probe_addrs) | ||
206 | + const unsigned short *probe_addrs, int enable_devnode) | ||
207 | { | ||
208 | struct v4l2_subdev *sd = NULL; | ||
209 | struct i2c_client *client; | ||
210 | @@ -399,9 +399,12 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | ||
211 | if (!try_module_get(client->driver->driver.owner)) | ||
212 | goto error; | ||
213 | sd = i2c_get_clientdata(client); | ||
214 | + if (!enable_devnode) | ||
215 | + sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
216 | |||
217 | /* Register with the v4l2_device which increases the module's | ||
218 | use count as well. */ | ||
219 | + sd->initialized = 0; | ||
220 | if (v4l2_device_register_subdev(v4l2_dev, sd)) | ||
221 | sd = NULL; | ||
222 | /* Decrease the module use count to match the first try_module_get. */ | ||
223 | @@ -416,6 +419,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | ||
224 | if (err && err != -ENOIOCTLCMD) { | ||
225 | v4l2_device_unregister_subdev(sd); | ||
226 | sd = NULL; | ||
227 | + } else { | ||
228 | + sd->initialized = 1; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | @@ -440,7 +445,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, | ||
233 | strlcpy(info.type, client_type, sizeof(info.type)); | ||
234 | info.addr = addr; | ||
235 | |||
236 | - return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs); | ||
237 | + return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs, | ||
238 | + 0); | ||
239 | } | ||
240 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); | ||
241 | |||
242 | @@ -510,7 +516,8 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, | ||
243 | EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init); | ||
244 | |||
245 | struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | ||
246 | - struct spi_master *master, struct spi_board_info *info) | ||
247 | + struct spi_master *master, struct spi_board_info *info, | ||
248 | + int enable_devnode) | ||
249 | { | ||
250 | struct v4l2_subdev *sd = NULL; | ||
251 | struct spi_device *spi = NULL; | ||
252 | @@ -529,6 +536,8 @@ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | ||
253 | goto error; | ||
254 | |||
255 | sd = spi_get_drvdata(spi); | ||
256 | + if (!enable_devnode) | ||
257 | + sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
258 | |||
259 | /* Register with the v4l2_device which increases the module's | ||
260 | use count as well. */ | ||
261 | diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c | ||
262 | index 359e232..f22bd41 100644 | ||
263 | --- a/drivers/media/video/v4l2-dev.c | ||
264 | +++ b/drivers/media/video/v4l2-dev.c | ||
265 | @@ -408,13 +408,14 @@ static int get_index(struct video_device *vdev) | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | - * video_register_device - register video4linux devices | ||
270 | + * __video_register_device - register video4linux devices | ||
271 | * @vdev: video device structure we want to register | ||
272 | * @type: type of device to register | ||
273 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... | ||
274 | * -1 == first free) | ||
275 | * @warn_if_nr_in_use: warn if the desired device node number | ||
276 | * was already in use and another number was chosen instead. | ||
277 | + * @owner: module that owns the video device node | ||
278 | * | ||
279 | * The registration code assigns minor numbers and device node numbers | ||
280 | * based on the requested type and registers the new device node with | ||
281 | @@ -431,9 +432,11 @@ static int get_index(struct video_device *vdev) | ||
282 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) | ||
283 | * | ||
284 | * %VFL_TYPE_RADIO - A radio card | ||
285 | + * | ||
286 | + * %VFL_TYPE_SUBDEV - A subdevice | ||
287 | */ | ||
288 | -static int __video_register_device(struct video_device *vdev, int type, int nr, | ||
289 | - int warn_if_nr_in_use) | ||
290 | +int __video_register_device(struct video_device *vdev, int type, int nr, | ||
291 | + int warn_if_nr_in_use, struct module *owner) | ||
292 | { | ||
293 | int i = 0; | ||
294 | int ret; | ||
295 | @@ -466,6 +469,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | ||
296 | case VFL_TYPE_RADIO: | ||
297 | name_base = "radio"; | ||
298 | break; | ||
299 | + case VFL_TYPE_SUBDEV: | ||
300 | + name_base = "v4l-subdev"; | ||
301 | + break; | ||
302 | default: | ||
303 | printk(KERN_ERR "%s called with unknown type: %d\n", | ||
304 | __func__, type); | ||
305 | @@ -549,7 +555,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | ||
306 | goto cleanup; | ||
307 | } | ||
308 | vdev->cdev->ops = &v4l2_fops; | ||
309 | - vdev->cdev->owner = vdev->fops->owner; | ||
310 | + vdev->cdev->owner = owner; | ||
311 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); | ||
312 | if (ret < 0) { | ||
313 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); | ||
314 | @@ -598,18 +604,7 @@ cleanup: | ||
315 | vdev->minor = -1; | ||
316 | return ret; | ||
317 | } | ||
318 | - | ||
319 | -int video_register_device(struct video_device *vdev, int type, int nr) | ||
320 | -{ | ||
321 | - return __video_register_device(vdev, type, nr, 1); | ||
322 | -} | ||
323 | -EXPORT_SYMBOL(video_register_device); | ||
324 | - | ||
325 | -int video_register_device_no_warn(struct video_device *vdev, int type, int nr) | ||
326 | -{ | ||
327 | - return __video_register_device(vdev, type, nr, 0); | ||
328 | -} | ||
329 | -EXPORT_SYMBOL(video_register_device_no_warn); | ||
330 | +EXPORT_SYMBOL(__video_register_device); | ||
331 | |||
332 | /** | ||
333 | * video_unregister_device - unregister a video4linux device | ||
334 | diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c | ||
335 | index 7fe6f92..97e84df 100644 | ||
336 | --- a/drivers/media/video/v4l2-device.c | ||
337 | +++ b/drivers/media/video/v4l2-device.c | ||
338 | @@ -117,24 +117,43 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister); | ||
339 | int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | ||
340 | struct v4l2_subdev *sd) | ||
341 | { | ||
342 | + struct video_device *vdev; | ||
343 | int err; | ||
344 | |||
345 | /* Check for valid input */ | ||
346 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) | ||
347 | return -EINVAL; | ||
348 | + | ||
349 | /* Warn if we apparently re-register a subdev */ | ||
350 | WARN_ON(sd->v4l2_dev != NULL); | ||
351 | + | ||
352 | if (!try_module_get(sd->owner)) | ||
353 | return -ENODEV; | ||
354 | + | ||
355 | /* This just returns 0 if either of the two args is NULL */ | ||
356 | err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); | ||
357 | if (err) | ||
358 | return err; | ||
359 | + | ||
360 | sd->v4l2_dev = v4l2_dev; | ||
361 | spin_lock(&v4l2_dev->lock); | ||
362 | list_add_tail(&sd->list, &v4l2_dev->subdevs); | ||
363 | spin_unlock(&v4l2_dev->lock); | ||
364 | - return 0; | ||
365 | + | ||
366 | + /* Register the device node. */ | ||
367 | + vdev = &sd->devnode; | ||
368 | + strlcpy(vdev->name, sd->name, sizeof(vdev->name)); | ||
369 | + vdev->parent = v4l2_dev->dev; | ||
370 | + vdev->fops = &v4l2_subdev_fops; | ||
371 | + vdev->release = video_device_release_empty; | ||
372 | + if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) { | ||
373 | + err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, | ||
374 | + sd->owner); | ||
375 | + if (err < 0) | ||
376 | + v4l2_device_unregister_subdev(sd); | ||
377 | + } | ||
378 | + | ||
379 | + return err; | ||
380 | } | ||
381 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | ||
382 | |||
383 | @@ -143,10 +162,13 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) | ||
384 | /* return if it isn't registered */ | ||
385 | if (sd == NULL || sd->v4l2_dev == NULL) | ||
386 | return; | ||
387 | + | ||
388 | spin_lock(&sd->v4l2_dev->lock); | ||
389 | list_del(&sd->list); | ||
390 | spin_unlock(&sd->v4l2_dev->lock); | ||
391 | sd->v4l2_dev = NULL; | ||
392 | + | ||
393 | module_put(sd->owner); | ||
394 | + video_unregister_device(&sd->devnode); | ||
395 | } | ||
396 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | ||
397 | diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c | ||
398 | index 1e01554..4137e4c 100644 | ||
399 | --- a/drivers/media/video/v4l2-ioctl.c | ||
400 | +++ b/drivers/media/video/v4l2-ioctl.c | ||
401 | @@ -413,7 +413,7 @@ static unsigned long cmd_input_size(unsigned int cmd) | ||
402 | } | ||
403 | } | ||
404 | |||
405 | -static long | ||
406 | +long | ||
407 | __video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
408 | v4l2_kioctl func) | ||
409 | { | ||
410 | diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c | ||
411 | new file mode 100644 | ||
412 | index 0000000..00bd4b1 | ||
413 | --- /dev/null | ||
414 | +++ b/drivers/media/video/v4l2-subdev.c | ||
415 | @@ -0,0 +1,66 @@ | ||
416 | +/* | ||
417 | + * V4L2 subdevice support. | ||
418 | + * | ||
419 | + * Copyright (C) 2010 Nokia Corporation | ||
420 | + * | ||
421 | + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
422 | + * | ||
423 | + * This program is free software; you can redistribute it and/or modify | ||
424 | + * it under the terms of the GNU General Public License as published by | ||
425 | + * the Free Software Foundation. | ||
426 | + * | ||
427 | + * This program is distributed in the hope that it will be useful, | ||
428 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
429 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
430 | + * GNU General Public License for more details. | ||
431 | + * | ||
432 | + * You should have received a copy of the GNU General Public License | ||
433 | + * along with this program; if not, write to the Free Software | ||
434 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
435 | + */ | ||
436 | + | ||
437 | +#include <linux/types.h> | ||
438 | +#include <linux/ioctl.h> | ||
439 | +#include <linux/videodev2.h> | ||
440 | + | ||
441 | +#include <media/v4l2-device.h> | ||
442 | +#include <media/v4l2-ioctl.h> | ||
443 | + | ||
444 | +static int subdev_open(struct file *file) | ||
445 | +{ | ||
446 | + struct video_device *vdev = video_devdata(file); | ||
447 | + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); | ||
448 | + | ||
449 | + if (!sd->initialized) | ||
450 | + return -EAGAIN; | ||
451 | + | ||
452 | + return 0; | ||
453 | +} | ||
454 | + | ||
455 | +static int subdev_close(struct file *file) | ||
456 | +{ | ||
457 | + return 0; | ||
458 | +} | ||
459 | + | ||
460 | +static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) | ||
461 | +{ | ||
462 | + switch (cmd) { | ||
463 | + default: | ||
464 | + return -ENOIOCTLCMD; | ||
465 | + } | ||
466 | + | ||
467 | + return 0; | ||
468 | +} | ||
469 | + | ||
470 | +static long subdev_ioctl(struct file *file, unsigned int cmd, | ||
471 | + unsigned long arg) | ||
472 | +{ | ||
473 | + return __video_usercopy(file, cmd, arg, subdev_do_ioctl); | ||
474 | +} | ||
475 | + | ||
476 | +const struct v4l2_file_operations v4l2_subdev_fops = { | ||
477 | + .owner = THIS_MODULE, | ||
478 | + .open = subdev_open, | ||
479 | + .unlocked_ioctl = subdev_ioctl, | ||
480 | + .release = subdev_close, | ||
481 | +}; | ||
482 | diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h | ||
483 | index 565fb32..ef8965d 100644 | ||
484 | --- a/include/media/v4l2-common.h | ||
485 | +++ b/include/media/v4l2-common.h | ||
486 | @@ -146,7 +146,7 @@ struct i2c_board_info; | ||
487 | |||
488 | struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | ||
489 | struct i2c_adapter *adapter, struct i2c_board_info *info, | ||
490 | - const unsigned short *probe_addrs); | ||
491 | + const unsigned short *probe_addrs, int enable_devnode); | ||
492 | |||
493 | /* Initialize an v4l2_subdev with data from an i2c_client struct */ | ||
494 | void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, | ||
495 | @@ -179,7 +179,8 @@ struct spi_device; | ||
496 | /* Load an spi module and return an initialized v4l2_subdev struct. | ||
497 | The client_type argument is the name of the chip that's on the adapter. */ | ||
498 | struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev, | ||
499 | - struct spi_master *master, struct spi_board_info *info); | ||
500 | + struct spi_master *master, struct spi_board_info *info, | ||
501 | + int enable_devnode); | ||
502 | |||
503 | /* Initialize an v4l2_subdev with data from an spi_device struct */ | ||
504 | void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi, | ||
505 | diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h | ||
506 | index 15802a0..4fe6831 100644 | ||
507 | --- a/include/media/v4l2-dev.h | ||
508 | +++ b/include/media/v4l2-dev.h | ||
509 | @@ -21,7 +21,8 @@ | ||
510 | #define VFL_TYPE_GRABBER 0 | ||
511 | #define VFL_TYPE_VBI 1 | ||
512 | #define VFL_TYPE_RADIO 2 | ||
513 | -#define VFL_TYPE_MAX 3 | ||
514 | +#define VFL_TYPE_SUBDEV 3 | ||
515 | +#define VFL_TYPE_MAX 4 | ||
516 | |||
517 | struct v4l2_ioctl_callbacks; | ||
518 | struct video_device; | ||
519 | @@ -102,15 +103,26 @@ struct video_device | ||
520 | /* dev to video-device */ | ||
521 | #define to_video_device(cd) container_of(cd, struct video_device, dev) | ||
522 | |||
523 | +int __must_check __video_register_device(struct video_device *vdev, int type, | ||
524 | + int nr, int warn_if_nr_in_use, struct module *owner); | ||
525 | + | ||
526 | /* Register video devices. Note that if video_register_device fails, | ||
527 | the release() callback of the video_device structure is *not* called, so | ||
528 | the caller is responsible for freeing any data. Usually that means that | ||
529 | you call video_device_release() on failure. */ | ||
530 | -int __must_check video_register_device(struct video_device *vdev, int type, int nr); | ||
531 | +static inline int __must_check video_register_device(struct video_device *vdev, | ||
532 | + int type, int nr) | ||
533 | +{ | ||
534 | + return __video_register_device(vdev, type, nr, 1, vdev->fops->owner); | ||
535 | +} | ||
536 | |||
537 | /* Same as video_register_device, but no warning is issued if the desired | ||
538 | device node number was already in use. */ | ||
539 | -int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr); | ||
540 | +static inline int __must_check video_register_device_no_warn( | ||
541 | + struct video_device *vdev, int type, int nr) | ||
542 | +{ | ||
543 | + return __video_register_device(vdev, type, nr, 0, vdev->fops->owner); | ||
544 | +} | ||
545 | |||
546 | /* Unregister video devices. Will do nothing if vdev == NULL or | ||
547 | video_is_registered() returns false. */ | ||
548 | diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h | ||
549 | index 06daa6e..abb64d0 100644 | ||
550 | --- a/include/media/v4l2-ioctl.h | ||
551 | +++ b/include/media/v4l2-ioctl.h | ||
552 | @@ -316,6 +316,9 @@ extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, | ||
553 | unsigned long arg); | ||
554 | #endif | ||
555 | |||
556 | +extern long __video_usercopy(struct file *file, unsigned int cmd, | ||
557 | + unsigned long arg, v4l2_kioctl func); | ||
558 | + | ||
559 | /* Include support for obsoleted stuff */ | ||
560 | extern long video_usercopy(struct file *file, unsigned int cmd, | ||
561 | unsigned long arg, v4l2_kioctl func); | ||
562 | diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h | ||
563 | index b636444..de181db 100644 | ||
564 | --- a/include/media/v4l2-subdev.h | ||
565 | +++ b/include/media/v4l2-subdev.h | ||
566 | @@ -22,6 +22,7 @@ | ||
567 | #define _V4L2_SUBDEV_H | ||
568 | |||
569 | #include <media/v4l2-common.h> | ||
570 | +#include <media/v4l2-dev.h> | ||
571 | #include <media/v4l2-mediabus.h> | ||
572 | |||
573 | /* generic v4l2_device notify callback notification values */ | ||
574 | @@ -418,9 +419,11 @@ struct v4l2_subdev_ops { | ||
575 | #define V4L2_SUBDEV_NAME_SIZE 32 | ||
576 | |||
577 | /* Set this flag if this subdev is a i2c device. */ | ||
578 | -#define V4L2_SUBDEV_FL_IS_I2C (1U << 0) | ||
579 | +#define V4L2_SUBDEV_FL_IS_I2C (1U << 0) | ||
580 | /* Set this flag if this subdev is a spi device. */ | ||
581 | -#define V4L2_SUBDEV_FL_IS_SPI (1U << 1) | ||
582 | +#define V4L2_SUBDEV_FL_IS_SPI (1U << 1) | ||
583 | +/* Set this flag if this subdev needs a device node. */ | ||
584 | +#define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2) | ||
585 | |||
586 | /* Each instance of a subdev driver should create this struct, either | ||
587 | stand-alone or embedded in a larger struct. | ||
588 | @@ -440,8 +443,16 @@ struct v4l2_subdev { | ||
589 | /* pointer to private data */ | ||
590 | void *dev_priv; | ||
591 | void *host_priv; | ||
592 | + /* subdev device node */ | ||
593 | + struct video_device devnode; | ||
594 | + unsigned int initialized; | ||
595 | }; | ||
596 | |||
597 | +#define vdev_to_v4l2_subdev(vdev) \ | ||
598 | + container_of(vdev, struct v4l2_subdev, devnode) | ||
599 | + | ||
600 | +extern const struct v4l2_file_operations v4l2_subdev_fops; | ||
601 | + | ||
602 | static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) | ||
603 | { | ||
604 | sd->dev_priv = p; | ||
605 | @@ -474,6 +485,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd, | ||
606 | sd->grp_id = 0; | ||
607 | sd->dev_priv = NULL; | ||
608 | sd->host_priv = NULL; | ||
609 | + sd->initialized = 1; | ||
610 | } | ||
611 | |||
612 | /* Call an ops of a v4l2_subdev, doing the right checks against | ||
613 | -- | ||
614 | 1.6.6.1 | ||
615 | |||