aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/video4linux/v4l2-framework.txt16
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/v4l2-dev.c27
-rw-r--r--drivers/media/video/v4l2-device.c37
-rw-r--r--drivers/media/video/v4l2-subdev.c60
-rw-r--r--include/media/v4l2-dev.h18
-rw-r--r--include/media/v4l2-device.h6
-rw-r--r--include/media/v4l2-subdev.h14
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
319up the device, but once the subdev is registered it is completely transparent. 319up the device, but once the subdev is registered it is completely transparent.
320 320
321 321
322V4L2 sub-device userspace API
323-----------------------------
324
325Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2
326sub-devices can also be controlled directly by userspace applications.
327
328Device nodes named v4l-subdevX can be created in /dev to access sub-devices
329directly. If a sub-device supports direct userspace configuration it must set
330the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.
331
332After registering sub-devices, the v4l2_device driver can create device nodes
333for all registered sub-devices marked with V4L2_SUBDEV_FL_HAS_DEVNODE by calling
334v4l2_device_register_subdev_nodes(). Those device nodes will be automatically
335removed when sub-devices are unregistered.
336
337
322I2C sub-device drivers 338I2C 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
11omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o 11omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
12 12
13videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ 13videodev-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 */
439static int __video_register_device(struct video_device *vdev, int type, int nr, 442int __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 606EXPORT_SYMBOL(__video_register_device);
601int video_register_device(struct video_device *vdev, int type, int nr)
602{
603 return __video_register_device(vdev, type, nr, 1);
604}
605EXPORT_SYMBOL(video_register_device);
606
607int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
608{
609 return __video_register_device(vdev, type, nr, 0);
610}
611EXPORT_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}
149EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); 155EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
150 156
157int 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}
183EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
184
151void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) 185void 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}
164EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); 201EXPORT_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
29static int subdev_open(struct file *file)
30{
31 return 0;
32}
33
34static int subdev_close(struct file *file)
35{
36 return 0;
37}
38
39static 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
49static 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
55const 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
26struct v4l2_ioctl_callbacks; 27struct v4l2_ioctl_callbacks;
27struct video_device; 28struct 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
106int __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. */
109int __must_check video_register_device(struct video_device *vdev, int type, int nr); 113static 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. */
113int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr); 121static 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. */
97void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); 97void 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 */
102int __must_check
103v4l2_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
468extern const struct v4l2_file_operations v4l2_subdev_fops;
469
460static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) 470static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
461{ 471{
462 sd->dev_priv = p; 472 sd->dev_priv = p;