diff options
-rw-r--r-- | Documentation/video4linux/v4l2-framework.txt | 16 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 27 | ||||
-rw-r--r-- | drivers/media/video/v4l2-device.c | 37 | ||||
-rw-r--r-- | drivers/media/video/v4l2-subdev.c | 60 | ||||
-rw-r--r-- | include/media/v4l2-dev.h | 18 | ||||
-rw-r--r-- | include/media/v4l2-device.h | 6 | ||||
-rw-r--r-- | include/media/v4l2-subdev.h | 14 |
8 files changed, 158 insertions, 22 deletions
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index f22f35c271f3..8b358710b2f7 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt | |||
@@ -319,6 +319,22 @@ controlled through GPIO pins. This distinction is only relevant when setting | |||
319 | up the device, but once the subdev is registered it is completely transparent. | 319 | up the device, but once the subdev is registered it is completely transparent. |
320 | 320 | ||
321 | 321 | ||
322 | V4L2 sub-device userspace API | ||
323 | ----------------------------- | ||
324 | |||
325 | Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2 | ||
326 | sub-devices can also be controlled directly by userspace applications. | ||
327 | |||
328 | Device nodes named v4l-subdevX can be created in /dev to access sub-devices | ||
329 | directly. If a sub-device supports direct userspace configuration it must set | ||
330 | the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered. | ||
331 | |||
332 | After registering sub-devices, the v4l2_device driver can create device nodes | ||
333 | for all registered sub-devices marked with V4L2_SUBDEV_FL_HAS_DEVNODE by calling | ||
334 | v4l2_device_register_subdev_nodes(). Those device nodes will be automatically | ||
335 | removed when sub-devices are unregistered. | ||
336 | |||
337 | |||
322 | I2C sub-device drivers | 338 | I2C sub-device drivers |
323 | ---------------------- | 339 | ---------------------- |
324 | 340 | ||
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ac54652396e3..7ea65163090e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o | |||
11 | omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o | 11 | omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o |
12 | 12 | ||
13 | videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ | 13 | videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ |
14 | v4l2-event.o v4l2-ctrls.o | 14 | v4l2-event.o v4l2-ctrls.o v4l2-subdev.o |
15 | 15 | ||
16 | # V4L2 core modules | 16 | # V4L2 core modules |
17 | 17 | ||
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 341764a3a990..abe04ef38066 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -408,13 +408,14 @@ static int get_index(struct video_device *vdev) | |||
408 | } | 408 | } |
409 | 409 | ||
410 | /** | 410 | /** |
411 | * video_register_device - register video4linux devices | 411 | * __video_register_device - register video4linux devices |
412 | * @vdev: video device structure we want to register | 412 | * @vdev: video device structure we want to register |
413 | * @type: type of device to register | 413 | * @type: type of device to register |
414 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... | 414 | * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... |
415 | * -1 == first free) | 415 | * -1 == first free) |
416 | * @warn_if_nr_in_use: warn if the desired device node number | 416 | * @warn_if_nr_in_use: warn if the desired device node number |
417 | * was already in use and another number was chosen instead. | 417 | * was already in use and another number was chosen instead. |
418 | * @owner: module that owns the video device node | ||
418 | * | 419 | * |
419 | * The registration code assigns minor numbers and device node numbers | 420 | * The registration code assigns minor numbers and device node numbers |
420 | * based on the requested type and registers the new device node with | 421 | * based on the requested type and registers the new device node with |
@@ -435,9 +436,11 @@ static int get_index(struct video_device *vdev) | |||
435 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) | 436 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) |
436 | * | 437 | * |
437 | * %VFL_TYPE_RADIO - A radio card | 438 | * %VFL_TYPE_RADIO - A radio card |
439 | * | ||
440 | * %VFL_TYPE_SUBDEV - A subdevice | ||
438 | */ | 441 | */ |
439 | static int __video_register_device(struct video_device *vdev, int type, int nr, | 442 | int __video_register_device(struct video_device *vdev, int type, int nr, |
440 | int warn_if_nr_in_use) | 443 | int warn_if_nr_in_use, struct module *owner) |
441 | { | 444 | { |
442 | int i = 0; | 445 | int i = 0; |
443 | int ret; | 446 | int ret; |
@@ -469,6 +472,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
469 | case VFL_TYPE_RADIO: | 472 | case VFL_TYPE_RADIO: |
470 | name_base = "radio"; | 473 | name_base = "radio"; |
471 | break; | 474 | break; |
475 | case VFL_TYPE_SUBDEV: | ||
476 | name_base = "v4l-subdev"; | ||
477 | break; | ||
472 | default: | 478 | default: |
473 | printk(KERN_ERR "%s called with unknown type: %d\n", | 479 | printk(KERN_ERR "%s called with unknown type: %d\n", |
474 | __func__, type); | 480 | __func__, type); |
@@ -552,7 +558,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, | |||
552 | goto cleanup; | 558 | goto cleanup; |
553 | } | 559 | } |
554 | vdev->cdev->ops = &v4l2_fops; | 560 | vdev->cdev->ops = &v4l2_fops; |
555 | vdev->cdev->owner = vdev->fops->owner; | 561 | vdev->cdev->owner = owner; |
556 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); | 562 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); |
557 | if (ret < 0) { | 563 | if (ret < 0) { |
558 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); | 564 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); |
@@ -597,18 +603,7 @@ cleanup: | |||
597 | vdev->minor = -1; | 603 | vdev->minor = -1; |
598 | return ret; | 604 | return ret; |
599 | } | 605 | } |
600 | 606 | EXPORT_SYMBOL(__video_register_device); | |
601 | int video_register_device(struct video_device *vdev, int type, int nr) | ||
602 | { | ||
603 | return __video_register_device(vdev, type, nr, 1); | ||
604 | } | ||
605 | EXPORT_SYMBOL(video_register_device); | ||
606 | |||
607 | int video_register_device_no_warn(struct video_device *vdev, int type, int nr) | ||
608 | { | ||
609 | return __video_register_device(vdev, type, nr, 0); | ||
610 | } | ||
611 | EXPORT_SYMBOL(video_register_device_no_warn); | ||
612 | 607 | ||
613 | /** | 608 | /** |
614 | * video_unregister_device - unregister a video4linux device | 609 | * video_unregister_device - unregister a video4linux device |
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index ce64fe16bc60..8c0ad8b372d8 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c | |||
@@ -124,16 +124,20 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
124 | /* Check for valid input */ | 124 | /* Check for valid input */ |
125 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) | 125 | if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) |
126 | return -EINVAL; | 126 | return -EINVAL; |
127 | |||
127 | /* Warn if we apparently re-register a subdev */ | 128 | /* Warn if we apparently re-register a subdev */ |
128 | WARN_ON(sd->v4l2_dev != NULL); | 129 | WARN_ON(sd->v4l2_dev != NULL); |
130 | |||
129 | if (!try_module_get(sd->owner)) | 131 | if (!try_module_get(sd->owner)) |
130 | return -ENODEV; | 132 | return -ENODEV; |
133 | |||
131 | sd->v4l2_dev = v4l2_dev; | 134 | sd->v4l2_dev = v4l2_dev; |
132 | if (sd->internal_ops && sd->internal_ops->registered) { | 135 | if (sd->internal_ops && sd->internal_ops->registered) { |
133 | err = sd->internal_ops->registered(sd); | 136 | err = sd->internal_ops->registered(sd); |
134 | if (err) | 137 | if (err) |
135 | return err; | 138 | return err; |
136 | } | 139 | } |
140 | |||
137 | /* This just returns 0 if either of the two args is NULL */ | 141 | /* This just returns 0 if either of the two args is NULL */ |
138 | err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); | 142 | err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); |
139 | if (err) { | 143 | if (err) { |
@@ -141,24 +145,57 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
141 | sd->internal_ops->unregistered(sd); | 145 | sd->internal_ops->unregistered(sd); |
142 | return err; | 146 | return err; |
143 | } | 147 | } |
148 | |||
144 | spin_lock(&v4l2_dev->lock); | 149 | spin_lock(&v4l2_dev->lock); |
145 | list_add_tail(&sd->list, &v4l2_dev->subdevs); | 150 | list_add_tail(&sd->list, &v4l2_dev->subdevs); |
146 | spin_unlock(&v4l2_dev->lock); | 151 | spin_unlock(&v4l2_dev->lock); |
152 | |||
147 | return 0; | 153 | return 0; |
148 | } | 154 | } |
149 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | 155 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); |
150 | 156 | ||
157 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | ||
158 | { | ||
159 | struct video_device *vdev; | ||
160 | struct v4l2_subdev *sd; | ||
161 | int err; | ||
162 | |||
163 | /* Register a device node for every subdev marked with the | ||
164 | * V4L2_SUBDEV_FL_HAS_DEVNODE flag. | ||
165 | */ | ||
166 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { | ||
167 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) | ||
168 | continue; | ||
169 | |||
170 | vdev = &sd->devnode; | ||
171 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); | ||
172 | vdev->v4l2_dev = v4l2_dev; | ||
173 | vdev->fops = &v4l2_subdev_fops; | ||
174 | vdev->release = video_device_release_empty; | ||
175 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, | ||
176 | sd->owner); | ||
177 | if (err < 0) | ||
178 | return err; | ||
179 | } | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); | ||
184 | |||
151 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) | 185 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) |
152 | { | 186 | { |
153 | /* return if it isn't registered */ | 187 | /* return if it isn't registered */ |
154 | if (sd == NULL || sd->v4l2_dev == NULL) | 188 | if (sd == NULL || sd->v4l2_dev == NULL) |
155 | return; | 189 | return; |
190 | |||
156 | spin_lock(&sd->v4l2_dev->lock); | 191 | spin_lock(&sd->v4l2_dev->lock); |
157 | list_del(&sd->list); | 192 | list_del(&sd->list); |
158 | spin_unlock(&sd->v4l2_dev->lock); | 193 | spin_unlock(&sd->v4l2_dev->lock); |
159 | if (sd->internal_ops && sd->internal_ops->unregistered) | 194 | if (sd->internal_ops && sd->internal_ops->unregistered) |
160 | sd->internal_ops->unregistered(sd); | 195 | sd->internal_ops->unregistered(sd); |
161 | sd->v4l2_dev = NULL; | 196 | sd->v4l2_dev = NULL; |
197 | |||
198 | video_unregister_device(&sd->devnode); | ||
162 | module_put(sd->owner); | 199 | module_put(sd->owner); |
163 | } | 200 | } |
164 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | 201 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); |
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c new file mode 100644 index 000000000000..037aa28a5ed1 --- /dev/null +++ b/drivers/media/video/v4l2-subdev.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * V4L2 subdevice support. | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
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. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/ioctl.h> | ||
24 | #include <linux/videodev2.h> | ||
25 | |||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-ioctl.h> | ||
28 | |||
29 | static int subdev_open(struct file *file) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static int subdev_close(struct file *file) | ||
35 | { | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) | ||
40 | { | ||
41 | switch (cmd) { | ||
42 | default: | ||
43 | return -ENOIOCTLCMD; | ||
44 | } | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static long subdev_ioctl(struct file *file, unsigned int cmd, | ||
50 | unsigned long arg) | ||
51 | { | ||
52 | return video_usercopy(file, cmd, arg, subdev_do_ioctl); | ||
53 | } | ||
54 | |||
55 | const struct v4l2_file_operations v4l2_subdev_fops = { | ||
56 | .owner = THIS_MODULE, | ||
57 | .open = subdev_open, | ||
58 | .unlocked_ioctl = subdev_ioctl, | ||
59 | .release = subdev_close, | ||
60 | }; | ||
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 15802a067a12..4fe6831b1851 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h | |||
@@ -21,7 +21,8 @@ | |||
21 | #define VFL_TYPE_GRABBER 0 | 21 | #define VFL_TYPE_GRABBER 0 |
22 | #define VFL_TYPE_VBI 1 | 22 | #define VFL_TYPE_VBI 1 |
23 | #define VFL_TYPE_RADIO 2 | 23 | #define VFL_TYPE_RADIO 2 |
24 | #define VFL_TYPE_MAX 3 | 24 | #define VFL_TYPE_SUBDEV 3 |
25 | #define VFL_TYPE_MAX 4 | ||
25 | 26 | ||
26 | struct v4l2_ioctl_callbacks; | 27 | struct v4l2_ioctl_callbacks; |
27 | struct video_device; | 28 | struct video_device; |
@@ -102,15 +103,26 @@ struct video_device | |||
102 | /* dev to video-device */ | 103 | /* dev to video-device */ |
103 | #define to_video_device(cd) container_of(cd, struct video_device, dev) | 104 | #define to_video_device(cd) container_of(cd, struct video_device, dev) |
104 | 105 | ||
106 | int __must_check __video_register_device(struct video_device *vdev, int type, | ||
107 | int nr, int warn_if_nr_in_use, struct module *owner); | ||
108 | |||
105 | /* Register video devices. Note that if video_register_device fails, | 109 | /* Register video devices. Note that if video_register_device fails, |
106 | the release() callback of the video_device structure is *not* called, so | 110 | the release() callback of the video_device structure is *not* called, so |
107 | the caller is responsible for freeing any data. Usually that means that | 111 | the caller is responsible for freeing any data. Usually that means that |
108 | you call video_device_release() on failure. */ | 112 | you call video_device_release() on failure. */ |
109 | int __must_check video_register_device(struct video_device *vdev, int type, int nr); | 113 | static inline int __must_check video_register_device(struct video_device *vdev, |
114 | int type, int nr) | ||
115 | { | ||
116 | return __video_register_device(vdev, type, nr, 1, vdev->fops->owner); | ||
117 | } | ||
110 | 118 | ||
111 | /* Same as video_register_device, but no warning is issued if the desired | 119 | /* Same as video_register_device, but no warning is issued if the desired |
112 | device node number was already in use. */ | 120 | device node number was already in use. */ |
113 | int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr); | 121 | static inline int __must_check video_register_device_no_warn( |
122 | struct video_device *vdev, int type, int nr) | ||
123 | { | ||
124 | return __video_register_device(vdev, type, nr, 0, vdev->fops->owner); | ||
125 | } | ||
114 | 126 | ||
115 | /* Unregister video devices. Will do nothing if vdev == NULL or | 127 | /* Unregister video devices. Will do nothing if vdev == NULL or |
116 | video_is_registered() returns false. */ | 128 | video_is_registered() returns false. */ |
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index b16f307d471a..78b11e5a6db7 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h | |||
@@ -96,6 +96,12 @@ int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
96 | wasn't registered. In that case it will do nothing. */ | 96 | wasn't registered. In that case it will do nothing. */ |
97 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); | 97 | void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); |
98 | 98 | ||
99 | /* Register device nodes for all subdev of the v4l2 device that are marked with | ||
100 | * the V4L2_SUBDEV_FL_HAS_DEVNODE flag. | ||
101 | */ | ||
102 | int __must_check | ||
103 | v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); | ||
104 | |||
99 | /* Iterate over all subdevs. */ | 105 | /* Iterate over all subdevs. */ |
100 | #define v4l2_device_for_each_subdev(sd, v4l2_dev) \ | 106 | #define v4l2_device_for_each_subdev(sd, v4l2_dev) \ |
101 | list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) | 107 | list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) |
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index da16d2f4a00b..474ef009fd3d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define _V4L2_SUBDEV_H | 22 | #define _V4L2_SUBDEV_H |
23 | 23 | ||
24 | #include <media/v4l2-common.h> | 24 | #include <media/v4l2-common.h> |
25 | #include <media/v4l2-dev.h> | ||
25 | #include <media/v4l2-mediabus.h> | 26 | #include <media/v4l2-mediabus.h> |
26 | 27 | ||
27 | /* generic v4l2_device notify callback notification values */ | 28 | /* generic v4l2_device notify callback notification values */ |
@@ -431,9 +432,11 @@ struct v4l2_subdev_internal_ops { | |||
431 | #define V4L2_SUBDEV_NAME_SIZE 32 | 432 | #define V4L2_SUBDEV_NAME_SIZE 32 |
432 | 433 | ||
433 | /* Set this flag if this subdev is a i2c device. */ | 434 | /* Set this flag if this subdev is a i2c device. */ |
434 | #define V4L2_SUBDEV_FL_IS_I2C (1U << 0) | 435 | #define V4L2_SUBDEV_FL_IS_I2C (1U << 0) |
435 | /* Set this flag if this subdev is a spi device. */ | 436 | /* Set this flag if this subdev is a spi device. */ |
436 | #define V4L2_SUBDEV_FL_IS_SPI (1U << 1) | 437 | #define V4L2_SUBDEV_FL_IS_SPI (1U << 1) |
438 | /* Set this flag if this subdev needs a device node. */ | ||
439 | #define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2) | ||
437 | 440 | ||
438 | /* Each instance of a subdev driver should create this struct, either | 441 | /* Each instance of a subdev driver should create this struct, either |
439 | stand-alone or embedded in a larger struct. | 442 | stand-alone or embedded in a larger struct. |
@@ -455,8 +458,15 @@ struct v4l2_subdev { | |||
455 | /* pointer to private data */ | 458 | /* pointer to private data */ |
456 | void *dev_priv; | 459 | void *dev_priv; |
457 | void *host_priv; | 460 | void *host_priv; |
461 | /* subdev device node */ | ||
462 | struct video_device devnode; | ||
458 | }; | 463 | }; |
459 | 464 | ||
465 | #define vdev_to_v4l2_subdev(vdev) \ | ||
466 | container_of(vdev, struct v4l2_subdev, devnode) | ||
467 | |||
468 | extern const struct v4l2_file_operations v4l2_subdev_fops; | ||
469 | |||
460 | static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) | 470 | static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) |
461 | { | 471 | { |
462 | sd->dev_priv = p; | 472 | sd->dev_priv = p; |