Discussion:
[PATCH 00/59] Media controller (core and V4L2) and assorted patches
Laurent Pinchart
2010-11-25 02:48:35 UTC
Permalink
Hi everybody,

This (too big) patch set adds support for the media controller and the V4L2
subdev pad-level APIs to the MeeGo kernel.

The first 28 patches have been backported from upstream (2.6.36 or 2.6.37-rc).
They are required by the rest of the code. I'm aware that they don't pass
checkpatch.pl but there's not much I can do about that (fixing the warnings
would make later merges from upstream more difficult).

The next 31 patches contain V4L2 subdev device node support, the media
controller API and the V4L2 subdev pad-level API. They have all been posted
to the linux-media mailing list and went through several rounds of review.
The stream of comments eventually died with all developers happy with the
result (or at least too tired to complain).

Taking review to the next step I've posted the media controller patches (36
to 47) to linux-omap and LKML minutes ago.

All the patches are available in the media-2.6.35-0003-subdev-pad branch of the
http://git.linuxtv.org/pinchartl/media.git git tree.

The patches conflict with the OMAP3 ISP support for the N900 and should replace
it. A new version of the OMAP3 ISP driver based on those patches is available
in the media-2.6.35-0006-rx51 branch of the above git tree. I will arrange its
submission to meego-kernel with Ilkka Koskinen.

Antti Koskipaa (1):
v4l: v4l2_subdev userspace crop API

Guennadi Liakhovetski (2):
V4L/DVB: mediabus: fix ambiguous pixel code names
V4L/DVB: V4L2: mediabus: add 12-bit Bayer and YUV420 pixel formats

Hans Verkuil (6):
V4L/DVB: v4l: add new YUV mediabus formats
V4L/DVB: v4l: add RGB444 mediabus formats
V4L/DVB: v4l2: Add new control handling framework
V4L/DVB: v4l2-ctrls: reorder 'case' statements to match order in
header
V4L/DVB: Documentation: add v4l2-controls.txt documenting the new
controls API
V4L/DVB: v4l2: hook up the new control framework into the core
framework

Laurent Pinchart (43):
v4l: Load I2C modules based on modalias
v4l: Remove hardcoded module names passed to v4l2_i2c_new_subdev*
go7007: Add MODULE_DEVICE_TABLE to the go7007 I2C modules
go7007: Fix the TW2804 I2C type name
go7007: Don't use module names to load I2C modules
zoran: Don't use module names to load I2C modules
pvrusb2: Don't use module names to load I2C modules
sh_vou: Don't use module names to load I2C modules
radio-si4713: Don't use module names to load I2C modules
soc_camera: Don't use module names to load I2C modules
vpfe_capture: Don't use module names to load I2C modules
vpif_display: Don't use module names to load I2C modules
vpif_capture: Don't use module names to load I2C modules
ivtv: Don't use module names to load I2C modules
cx18: Don't use module names to load I2C modules
V4L/DVB: v4l: Use v4l2_get_subdevdata instead of accessing
v4l2_subdev::priv
V4L/DVB: v4l: Add a v4l2_subdev host private data field
v4l: Share code between video_usercopy and video_ioctl2
v4l: subdev: Don't require core operations
v4l: subdev: Merge v4l2_i2c_new_subdev_cfg and v4l2_i2c_new_subdev
v4l: subdev: Add device node support
v4l: subdev: Uninline the v4l2_subdev_init function
v4l: subdev: Control ioctls support
media: Media device node support
media: Media device
media: Entities, pads and links
media: Media device information query
media: Entities, pads and links enumeration
media: Links setup
media: Entity locking and pipeline management
v4l: Add a media_device pointer to the v4l2_device structure
v4l: Make video_device inherit from media_entity
v4l: Make v4l2_subdev inherit from media_entity
v4l: Move the media/v4l2-mediabus.h header to include/linux
v4l: Replace enums with fixed-sized fields in public structure
v4l: Rename V4L2_MBUS_FMT_GREY8_1X8 to V4L2_MBUS_FMT_Y8_1X8
v4l: Group media bus pixel codes by types and sort them
alphabetically
v4l: Add 8-bit YUYV on 16-bit bus and SGRBG10 media bus pixel codes
v4l: Add remaining RAW10 patterns w DPCM pixel code variants
v4l: v4l2_subdev pad-level operations
v4l: v4l2_subdev userspace format API - documentation binary files
v4l: v4l2_subdev userspace format API
v4l: v4l2_subdev userspace frame interval API

Mauro Carvalho Chehab (1):
V4L/DVB: v4l2-ctrls: Whitespace cleanups

Randy Dunlap (1):
V4L/DVB: v4l2-ctrls.c: needs to include slab.h

Sakari Ailus (3):
v4l: subdev: Events support
media: Entity graph traversal
media: Reference count and power handling

Sascha Hauer (1):
v4l2-mediabus: Add pixelcodes for BGR565 formats

Stanimir Varbanov (1):
v4l: Create v4l2 subdev file handle structure

Documentation/DocBook/Makefile | 5 +-
Documentation/DocBook/media-entities.tmpl | 50 +
Documentation/DocBook/media.tmpl | 3 +
Documentation/DocBook/v4l/bayer.pdf | Bin 0 -> 12116 bytes
Documentation/DocBook/v4l/bayer.png | Bin 0 -> 9725 bytes
Documentation/DocBook/v4l/dev-subdev.xml | 307 +++
Documentation/DocBook/v4l/media-controller.xml | 89 +
Documentation/DocBook/v4l/media-func-close.xml | 59 +
Documentation/DocBook/v4l/media-func-ioctl.xml | 116 +
Documentation/DocBook/v4l/media-func-open.xml | 94 +
.../DocBook/v4l/media-ioc-device-info.xml | 133 ++
.../DocBook/v4l/media-ioc-enum-entities.xml | 287 +++
Documentation/DocBook/v4l/media-ioc-enum-links.xml | 202 ++
Documentation/DocBook/v4l/media-ioc-setup-link.xml | 90 +
Documentation/DocBook/v4l/pipeline.pdf | Bin 0 -> 20276 bytes
Documentation/DocBook/v4l/pipeline.png | Bin 0 -> 12130 bytes
Documentation/DocBook/v4l/subdev-formats.xml | 2410 ++++++++++++++++++++
Documentation/DocBook/v4l/v4l2.xml | 7 +
Documentation/DocBook/v4l/vidioc-streamon.xml | 9 +
.../v4l/vidioc-subdev-enum-frame-interval.xml | 146 ++
.../DocBook/v4l/vidioc-subdev-enum-frame-size.xml | 148 ++
.../DocBook/v4l/vidioc-subdev-enum-mbus-code.xml | 113 +
Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml | 143 ++
Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml | 168 ++
.../DocBook/v4l/vidioc-subdev-g-frame-interval.xml | 135 ++
Documentation/media-framework.txt | 380 +++
Documentation/video4linux/v4l2-controls.txt | 648 ++++++
Documentation/video4linux/v4l2-framework.txt | 129 +-
arch/arm/mach-mx3/mach-pcm037.c | 2 -
arch/arm/mach-mx3/mx31moboard-marxbot.c | 1 -
arch/arm/mach-mx3/mx31moboard-smartbot.c | 1 -
arch/arm/mach-pxa/em-x270.c | 1 -
arch/arm/mach-pxa/ezx.c | 2 -
arch/arm/mach-pxa/mioa701.c | 1 -
arch/arm/mach-pxa/pcm990-baseboard.c | 2 -
arch/sh/boards/mach-ap325rxa/setup.c | 3 +-
arch/sh/boards/mach-ecovec24/setup.c | 4 -
arch/sh/boards/mach-kfr2r09/setup.c | 1 -
arch/sh/boards/mach-migor/setup.c | 2 -
arch/sh/boards/mach-se/7724/setup.c | 1 -
drivers/media/Kconfig | 22 +
drivers/media/Makefile | 10 +-
drivers/media/media-device.c | 379 +++
drivers/media/media-devnode.c | 321 +++
drivers/media/media-entity.c | 680 ++++++
drivers/media/radio/radio-si4713.c | 4 +-
drivers/media/video/Makefile | 2 +-
drivers/media/video/ak881x.c | 6 +-
drivers/media/video/au0828/au0828-cards.c | 4 +-
drivers/media/video/bt8xx/bttv-cards.c | 22 +-
drivers/media/video/cafe_ccic.c | 2 +-
drivers/media/video/cx18/cx18-i2c.c | 23 +-
drivers/media/video/cx231xx/cx231xx-cards.c | 4 +-
drivers/media/video/cx23885/cx23885-cards.c | 2 +-
drivers/media/video/cx23885/cx23885-video.c | 6 +-
drivers/media/video/cx88/cx88-cards.c | 8 +-
drivers/media/video/cx88/cx88-video.c | 4 +-
drivers/media/video/davinci/vpfe_capture.c | 4 +-
drivers/media/video/davinci/vpif_capture.c | 4 +-
drivers/media/video/davinci/vpif_display.c | 4 +-
drivers/media/video/em28xx/em28xx-cards.c | 18 +-
drivers/media/video/ivtv/ivtv-i2c.c | 39 +-
drivers/media/video/mt9m001.c | 28 +-
drivers/media/video/mt9m111.c | 36 +-
drivers/media/video/mt9t031.c | 24 +-
drivers/media/video/mt9t112.c | 26 +-
drivers/media/video/mt9v022.c | 30 +-
drivers/media/video/mxb.c | 14 +-
drivers/media/video/ov772x.c | 26 +-
drivers/media/video/ov9640.c | 26 +-
drivers/media/video/pvrusb2/pvrusb2-hdw.c | 11 +-
drivers/media/video/pxa_camera.c | 8 +-
drivers/media/video/rj54n1cb0c.c | 34 +-
drivers/media/video/saa7134/saa7134-cards.c | 8 +-
drivers/media/video/saa7134/saa7134-core.c | 4 +-
drivers/media/video/sh_mobile_ceu_camera.c | 16 +-
drivers/media/video/sh_vou.c | 10 +-
drivers/media/video/soc_camera.c | 4 +-
drivers/media/video/soc_mediabus.c | 10 +-
drivers/media/video/tw9910.c | 28 +-
drivers/media/video/usbvision/usbvision-i2c.c | 6 +-
drivers/media/video/v4l2-common.c | 503 +----
drivers/media/video/v4l2-ctrls.c | 1852 +++++++++++++++
drivers/media/video/v4l2-dev.c | 82 +-
drivers/media/video/v4l2-device.c | 73 +-
drivers/media/video/v4l2-ioctl.c | 262 +--
drivers/media/video/v4l2-subdev.c | 337 +++
drivers/media/video/vino.c | 4 +-
drivers/media/video/w9968cf.c | 2 +-
drivers/media/video/zoran/zoran.h | 2 -
drivers/media/video/zoran/zoran_card.c | 23 +-
drivers/staging/go7007/go7007-driver.c | 43 +-
drivers/staging/go7007/go7007-usb.c | 2 +-
drivers/staging/go7007/wis-ov7640.c | 1 +
drivers/staging/go7007/wis-saa7113.c | 1 +
drivers/staging/go7007/wis-saa7115.c | 1 +
drivers/staging/go7007/wis-sony-tuner.c | 1 +
drivers/staging/go7007/wis-tw2804.c | 1 +
drivers/staging/go7007/wis-tw9903.c | 1 +
drivers/staging/go7007/wis-uda1342.c | 1 +
drivers/staging/tm6000/tm6000-cards.c | 4 +-
include/linux/Kbuild | 3 +
include/linux/media.h | 127 +
include/linux/v4l2-mediabus.h | 104 +
include/linux/v4l2-subdev.h | 141 ++
include/media/media-device.h | 92 +
include/media/media-devnode.h | 97 +
include/media/media-entity.h | 144 ++
include/media/sh_vou.h | 1 -
include/media/soc_mediabus.h | 3 +-
include/media/v4l2-common.h | 21 +-
include/media/v4l2-ctrls.h | 460 ++++
include/media/v4l2-dev.h | 29 +-
include/media/v4l2-device.h | 8 +
include/media/v4l2-ioctl.h | 3 +
include/media/v4l2-mediabus.h | 48 +-
include/media/v4l2-subdev.h | 121 +-
117 files changed, 11277 insertions(+), 1130 deletions(-)
create mode 100644 Documentation/DocBook/v4l/bayer.pdf
create mode 100644 Documentation/DocBook/v4l/bayer.png
create mode 100644 Documentation/DocBook/v4l/dev-subdev.xml
create mode 100644 Documentation/DocBook/v4l/media-controller.xml
create mode 100644 Documentation/DocBook/v4l/media-func-close.xml
create mode 100644 Documentation/DocBook/v4l/media-func-ioctl.xml
create mode 100644 Documentation/DocBook/v4l/media-func-open.xml
create mode 100644 Documentation/DocBook/v4l/media-ioc-device-info.xml
create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-entities.xml
create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-links.xml
create mode 100644 Documentation/DocBook/v4l/media-ioc-setup-link.xml
create mode 100644 Documentation/DocBook/v4l/pipeline.pdf
create mode 100644 Documentation/DocBook/v4l/pipeline.png
create mode 100644 Documentation/DocBook/v4l/subdev-formats.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
create mode 100644 Documentation/media-framework.txt
create mode 100644 Documentation/video4linux/v4l2-controls.txt
create mode 100644 drivers/media/media-device.c
create mode 100644 drivers/media/media-devnode.c
create mode 100644 drivers/media/media-entity.c
create mode 100644 drivers/media/video/v4l2-ctrls.c
create mode 100644 drivers/media/video/v4l2-subdev.c
create mode 100644 include/linux/media.h
create mode 100644 include/linux/v4l2-mediabus.h
create mode 100644 include/linux/v4l2-subdev.h
create mode 100644 include/media/media-device.h
create mode 100644 include/media/media-devnode.h
create mode 100644 include/media/media-entity.h
create mode 100644 include/media/v4l2-ctrls.h
--
Regards,

Laurent Pinchart
Laurent Pinchart
2010-11-25 02:48:36 UTC
Permalink
When creating a new sub-device, The V4L I2C subdev API has historically
required drivers to pass the name of the module that implements support
for the I2C device.

I2C modules can be loaded based on modaliases instead of the module
name. As the I2C device type name is already available to the
v4l2_i2c_new_subdev* functions, make the module name argument optional
and create a modalias based on the type name when no module name is
provided.

All in-tree drivers call those functions with a non-NULL module name
argument, this change is thus harmless.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/v4l2-common.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 4e53b0b..9b97832 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -847,6 +847,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,

if (module_name)
request_module(module_name);
+ else
+ request_module(I2C_MODULE_PREFIX "%s", info->type);

/* Create the i2c client */
if (info->addr == 0 && probe_addrs)
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:37 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the drivers
modified here use.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/au0828/au0828-cards.c | 4 ++--
drivers/media/video/bt8xx/bttv-cards.c | 22 +++++++++++-----------
drivers/media/video/cafe_ccic.c | 2 +-
drivers/media/video/cx231xx/cx231xx-cards.c | 4 ++--
drivers/media/video/cx23885/cx23885-cards.c | 2 +-
drivers/media/video/cx23885/cx23885-video.c | 6 +++---
drivers/media/video/cx88/cx88-cards.c | 8 ++++----
drivers/media/video/cx88/cx88-video.c | 4 ++--
drivers/media/video/em28xx/em28xx-cards.c | 18 +++++++++---------
drivers/media/video/mxb.c | 14 +++++++-------
drivers/media/video/saa7134/saa7134-cards.c | 8 ++++----
drivers/media/video/saa7134/saa7134-core.c | 4 ++--
drivers/media/video/usbvision/usbvision-i2c.c | 6 +++---
drivers/media/video/vino.c | 4 ++--
drivers/media/video/w9968cf.c | 2 +-
drivers/staging/tm6000/tm6000-cards.c | 4 ++--
16 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 57dd919..0453816 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "au8522", "au8522", 0x8e >> 1, NULL);
+ NULL, "au8522", 0x8e >> 1, NULL);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.tuner_addr, NULL);
+ NULL, "tuner", dev->board.tuner_addr, NULL);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");

diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 7af56cd..87d8b00 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -3529,7 +3529,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
struct v4l2_subdev *sd;

sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs);
+ &btv->c.i2c_adap, NULL, "saa6588", 0, addrs);
btv->has_saa6588 = (sd != NULL);
}

@@ -3554,7 +3554,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};

btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs);
+ &btv->c.i2c_adap, NULL, "msp3400", 0, addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
@@ -3568,7 +3568,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};

if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+ &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
return;
goto no_audio;
}
@@ -3576,7 +3576,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
case 3: {
/* The user specified that we should probe for tvaudio */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
@@ -3596,11 +3596,11 @@ void __devinit bttv_init_card2(struct bttv *btv)
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400",
+ &btv->c.i2c_adap, NULL, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400",
+ &btv->c.i2c_adap, NULL, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
}

@@ -3616,13 +3616,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
};

if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+ &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
return;
}

/* Now see if we can find one of the tvaudio devices. */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;

@@ -3646,13 +3646,13 @@ void __devinit bttv_init_tuner(struct bttv *btv)
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));

tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index be35e69..14176f0 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -1953,7 +1953,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,

cam->sensor_addr = 0x42;
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
- "ov7670", "ov7670", cam->sensor_addr, NULL);
+ NULL, "ov7670", cam->sensor_addr, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 6bdc0ef..9c78f7a 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -314,7 +314,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.decoder == CX231XX_AVDECODER) {
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[0].i2c_adap,
- "cx25840", "cx25840", 0x88 >> 1, NULL);
+ NULL, "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840 == NULL)
cx231xx_info("cx25840 subdev registration failure\n");
cx25840_call(dev, core, load_fw);
@@ -324,7 +324,7 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", 0xc2 >> 1, NULL);
+ NULL, "tuner", 0xc2 >> 1, NULL);
if (dev->sd_tuner == NULL)
cx231xx_info("tuner subdev registration failure\n");

diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index d639186..6f12988 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -1110,7 +1110,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
- "cx25840", "cx25840", 0x88 >> 1, NULL);
+ NULL, "cx25840", 0x88 >> 1, NULL);
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
break;
}
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 4e44dcd..0cca263 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -1494,11 +1494,11 @@ int cx23885_video_register(struct cx23885_dev *dev)
if (dev->tuner_addr)
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", dev->tuner_addr, NULL);
+ NULL, "tuner", dev->tuner_addr, NULL);
else
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
+ &dev->i2c_bus[1].i2c_adap, NULL,
+ "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
if (sd) {
struct tuner_setup tun_setup;

diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 2918a6e..d277ed7 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -3481,19 +3481,19 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
later code configures a tea5767.
*/
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "tuner", "tuner",
+ NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
if (has_demod)
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, "tuner", "tuner",
+ &core->i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (core->board.tuner_addr == ADDR_UNSET) {
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, "tuner", "tuner",
+ &core->i2c_adap, NULL, "tuner",
0, has_demod ? tv_addrs + 4 : tv_addrs);
} else {
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "tuner", "tuner", core->board.tuner_addr, NULL);
+ NULL, "tuner", core->board.tuner_addr, NULL);
}
}

diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 0fab65c..1e374ae 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1872,14 +1872,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,

if (core->board.audio_chip == V4L2_IDENT_WM8775)
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "wm8775", "wm8775", 0x36 >> 1, NULL);
+ NULL, "wm8775", 0x36 >> 1, NULL);

if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
/* This probes for a tda9874 as is used on some
Pixelview Ultra boards. */
v4l2_i2c_new_subdev(&core->v4l2_dev,
&core->i2c_adap,
- "tvaudio", "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
+ NULL, "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
}

switch (core->boardnr) {
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3a4fd85..4935438 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -2495,39 +2495,39 @@ void em28xx_card_setup(struct em28xx *dev)
/* request some modules */
if (dev->board.has_msp34xx)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "msp3400", "msp3400", 0, msp3400_addrs);
+ NULL, "msp3400", 0, msp3400_addrs);

if (dev->board.decoder == EM28XX_SAA711X)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "saa7115", "saa7115_auto", 0, saa711x_addrs);
+ NULL, "saa7115_auto", 0, saa711x_addrs);

if (dev->board.decoder == EM28XX_TVP5150)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvp5150", "tvp5150", 0, tvp5150_addrs);
+ NULL, "tvp5150", 0, tvp5150_addrs);

if (dev->em28xx_sensor == EM28XX_MT9V011) {
struct v4l2_subdev *sd;

sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "mt9v011", "mt9v011", 0, mt9v011_addrs);
+ &dev->i2c_adap, NULL, "mt9v011", 0, mt9v011_addrs);
v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
}


if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvaudio", "tvaudio", dev->board.tvaudio_addr, NULL);
+ NULL, "tvaudio", dev->board.tvaudio_addr, NULL);

if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);

if (dev->board.radio.type)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.radio_addr, NULL);
+ NULL, "tuner", dev->board.radio_addr, NULL);

if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
@@ -2535,14 +2535,14 @@ void em28xx_card_setup(struct em28xx *dev)
struct v4l2_subdev *sd;

sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(type));

if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->tuner_addr, NULL);
+ NULL, "tuner", dev->tuner_addr, NULL);
}
}

diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index ef0c817..005afc1 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -186,19 +186,19 @@ static int mxb_probe(struct saa7146_dev *dev)
}

mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "saa7115", "saa7111", I2C_SAA7111A, NULL);
+ NULL, "saa7111", I2C_SAA7111A, NULL);
mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6420", "tea6420", I2C_TEA6420_1, NULL);
+ NULL, "tea6420", I2C_TEA6420_1, NULL);
mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6420", "tea6420", I2C_TEA6420_2, NULL);
+ NULL, "tea6420", I2C_TEA6420_2, NULL);
mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6415c", "tea6415c", I2C_TEA6415C, NULL);
+ NULL, "tea6415c", I2C_TEA6415C, NULL);
mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tda9840", "tda9840", I2C_TDA9840, NULL);
+ NULL, "tda9840", I2C_TDA9840, NULL);
mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tuner", "tuner", I2C_TUNER, NULL);
+ NULL, "tuner", I2C_TUNER, NULL);
if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) {
+ NULL, "saa5246a", I2C_SAA5246A, NULL)) {
printk(KERN_INFO "mxb: found teletext decoder\n");
}

diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 07f6bb8..404c7d4 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -7520,22 +7520,22 @@ int saa7134_board_init2(struct saa7134_dev *dev)
so we do not need to probe for a radio tuner device. */
if (dev->radio_type != UNSET)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, NULL, "tuner",
dev->radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == ADDR_UNSET) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;

v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(type));
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, NULL, "tuner",
dev->tuner_addr, NULL);
}
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 90f2318..91f0c8c 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -991,7 +991,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (card_is_empress(dev)) {
struct v4l2_subdev *sd =
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "saa6752hs", "saa6752hs",
+ NULL, "saa6752hs",
saa7134_boards[dev->board].empress_addr, NULL);

if (sd)
@@ -1002,7 +1002,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct v4l2_subdev *sd;

sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "saa6588", "saa6588",
+ &dev->i2c_adap, NULL, "saa6588",
0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 42ba287..aca7525 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -248,7 +248,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
hit-and-miss. */
mdelay(10);
v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, "saa7115",
+ &usbvision->i2c_adap, NULL,
"saa7115_auto", 0, saa711x_addrs);
break;
}
@@ -258,14 +258,14 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
struct tuner_setup tun_setup;

sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, "tuner",
+ &usbvision->i2c_adap, NULL,
"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
/* depending on whether we found a demod or not, select
the tuner type. */
type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;

sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, "tuner",
+ &usbvision->i2c_adap, NULL,
"tuner", 0, v4l2_i2c_tuner_addrs(type));

if (usbvision->tuner_type != -1) {
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 3eb15f7..e5e005d 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -4334,10 +4334,10 @@ static int __init vino_module_init(void)

vino_drvdata->decoder =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- "saa7191", "saa7191", 0, I2C_ADDRS(0x45));
+ NULL, "saa7191", 0, I2C_ADDRS(0x45));
vino_drvdata->camera =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- "indycam", "indycam", 0, I2C_ADDRS(0x2b));
+ NULL, "indycam", 0, I2C_ADDRS(0x2b));

dprintk("init complete!\n");

diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index d807eea..836f77f 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -3519,7 +3519,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
w9968cf_i2c_init(cam);
cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
&cam->i2c_adapter,
- "ovcamchip", "ovcamchip", 0, addrs);
+ NULL, "ovcamchip", 0, addrs);

usb_set_intfdata(intf, cam);
mutex_unlock(&cam->dev_mutex);
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 6a9ae40..820c4f5 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -537,7 +537,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)

/* Load tuner module */
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->tuner_addr, NULL);
+ NULL, "tuner", dev->tuner_addr, NULL);

memset(&tun_setup, 0, sizeof(tun_setup));
tun_setup.type = dev->tuner_type;
@@ -673,7 +673,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)

if (dev->caps.has_tda9874)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvaudio", "tvaudio", I2C_ADDR_TDA9874, NULL);
+ NULL, "tvaudio", I2C_ADDR_TDA9874, NULL);

/* register and initialize V4L2 */
rc = tm6000_v4l2_register(dev);
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:38 UTC
Permalink
The device table is required to load modules based on modaliases.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/staging/go7007/wis-ov7640.c | 1 +
drivers/staging/go7007/wis-saa7113.c | 1 +
drivers/staging/go7007/wis-saa7115.c | 1 +
drivers/staging/go7007/wis-sony-tuner.c | 1 +
drivers/staging/go7007/wis-tw2804.c | 1 +
drivers/staging/go7007/wis-tw9903.c | 1 +
drivers/staging/go7007/wis-uda1342.c | 1 +
7 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
index 4f0cbdd..6bc9470 100644
--- a/drivers/staging/go7007/wis-ov7640.c
+++ b/drivers/staging/go7007/wis-ov7640.c
@@ -81,6 +81,7 @@ static const struct i2c_device_id wis_ov7640_id[] = {
{ "wis_ov7640", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_ov7640_id);

static struct i2c_driver wis_ov7640_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
index 72f5c1f..05e0e10 100644
--- a/drivers/staging/go7007/wis-saa7113.c
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -308,6 +308,7 @@ static const struct i2c_device_id wis_saa7113_id[] = {
{ "wis_saa7113", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);

static struct i2c_driver wis_saa7113_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
index cd950b6..46cff59 100644
--- a/drivers/staging/go7007/wis-saa7115.c
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -441,6 +441,7 @@ static const struct i2c_device_id wis_saa7115_id[] = {
{ "wis_saa7115", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);

static struct i2c_driver wis_saa7115_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index 981c9b3..8f1b7d4 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -692,6 +692,7 @@ static const struct i2c_device_id wis_sony_tuner_id[] = {
{ "wis_sony_tuner", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);

static struct i2c_driver wis_sony_tuner_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
index ee28a99..5b218c5 100644
--- a/drivers/staging/go7007/wis-tw2804.c
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -331,6 +331,7 @@ static const struct i2c_device_id wis_tw2804_id[] = {
{ "wis_tw2804", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);

static struct i2c_driver wis_tw2804_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
index 80d4726..9230f4a 100644
--- a/drivers/staging/go7007/wis-tw9903.c
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -313,6 +313,7 @@ static const struct i2c_device_id wis_tw9903_id[] = {
{ "wis_tw9903", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_tw9903_id);

static struct i2c_driver wis_tw9903_driver = {
.driver = {
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
index 5c4eb49..0127be2 100644
--- a/drivers/staging/go7007/wis-uda1342.c
+++ b/drivers/staging/go7007/wis-uda1342.c
@@ -86,6 +86,7 @@ static const struct i2c_device_id wis_uda1342_id[] = {
{ "wis_uda1342", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wis_uda1342_id);

static struct i2c_driver wis_uda1342_driver = {
.driver = {
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:39 UTC
Permalink
The TW2804 I2C sub-device type name was incorrectly set to wis_twTW2804
for the adlink mpg24 board. Rename it to wis_tw2804.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/staging/go7007/go7007-usb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
index 20ed930..bea9f4d 100644
--- a/drivers/staging/go7007/go7007-usb.c
+++ b/drivers/staging/go7007/go7007-usb.c
@@ -394,7 +394,7 @@ static struct go7007_usb_board board_adlink_mpg24 = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_twTW2804",
+ .type = "wis_tw2804",
.id = I2C_DRIVERID_WIS_TW2804,
.addr = 0x00, /* yes, really */
},
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:40 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the go7007
driver uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/staging/go7007/go7007-driver.c | 43 ++-----------------------------
1 files changed, 3 insertions(+), 40 deletions(-)

diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index 372a7c6..0a1d925 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -194,51 +194,15 @@ int go7007_reset_encoder(struct go7007 *go)
* Attempt to instantiate an I2C client by ID, probably loading a module.
*/
static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
- int id, int addr)
+ int addr)
{
struct go7007 *go = i2c_get_adapdata(adapter);
struct v4l2_device *v4l2_dev = &go->v4l2_dev;
- char *modname;

- switch (id) {
- case I2C_DRIVERID_WIS_SAA7115:
- modname = "wis-saa7115";
- break;
- case I2C_DRIVERID_WIS_SAA7113:
- modname = "wis-saa7113";
- break;
- case I2C_DRIVERID_WIS_UDA1342:
- modname = "wis-uda1342";
- break;
- case I2C_DRIVERID_WIS_SONY_TUNER:
- modname = "wis-sony-tuner";
- break;
- case I2C_DRIVERID_WIS_TW9903:
- modname = "wis-tw9903";
- break;
- case I2C_DRIVERID_WIS_TW2804:
- modname = "wis-tw2804";
- break;
- case I2C_DRIVERID_WIS_OV7640:
- modname = "wis-ov7640";
- break;
- case I2C_DRIVERID_S2250:
- modname = "s2250";
- break;
- default:
- modname = NULL;
- break;
- }
-
- if (v4l2_i2c_new_subdev(v4l2_dev, adapter, modname, type, addr, NULL))
+ if (v4l2_i2c_new_subdev(v4l2_dev, adapter, NULL, type, addr, NULL))
return 0;

- if (modname != NULL)
- printk(KERN_INFO
- "go7007: probing for module %s failed\n", modname);
- else
- printk(KERN_INFO
- "go7007: sensor %u seems to be unsupported!\n", id);
+ printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
return -1;
}

@@ -277,7 +241,6 @@ int go7007_register_encoder(struct go7007 *go)
for (i = 0; i < go->board_info->num_i2c_devs; ++i)
init_i2c_module(&go->i2c_adapter,
go->board_info->i2c_devs[i].type,
- go->board_info->i2c_devs[i].id,
go->board_info->i2c_devs[i].addr);
if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
i2c_clients_command(&go->i2c_adapter,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:41 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the zoran driver
uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/zoran/zoran.h | 2 --
drivers/media/video/zoran/zoran_card.c | 23 +++--------------------
2 files changed, 3 insertions(+), 22 deletions(-)

diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index 8997add..1af52f7 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -341,10 +341,8 @@ struct card_info {
enum card_type type;
char name[32];
const char *i2c_decoder; /* i2c decoder device */
- const char *mod_decoder; /* i2c decoder module */
const unsigned short *addrs_decoder;
const char *i2c_encoder; /* i2c encoder device */
- const char *mod_encoder; /* i2c encoder module */
const unsigned short *addrs_encoder;
u16 video_vfe, video_codec; /* videocodec types */
u16 audio_chip; /* audio type */
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index bfcd3ae..0aac376 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -379,7 +379,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC10_old,
.name = "DC10(old)",
.i2c_decoder = "vpx3220a",
- .mod_decoder = "vpx3220",
.addrs_decoder = vpx3220_addrs,
.video_codec = CODEC_TYPE_ZR36050,
.video_vfe = CODEC_TYPE_ZR36016,
@@ -409,10 +408,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC10_new,
.name = "DC10(new)",
.i2c_decoder = "saa7110",
- .mod_decoder = "saa7110",
.addrs_decoder = saa7110_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36060,

@@ -440,10 +437,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC10plus,
.name = "DC10plus",
.i2c_decoder = "saa7110",
- .mod_decoder = "saa7110",
.addrs_decoder = saa7110_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36060,

@@ -472,10 +467,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC30,
.name = "DC30",
.i2c_decoder = "vpx3220a",
- .mod_decoder = "vpx3220",
.addrs_decoder = vpx3220_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36050,
.video_vfe = CODEC_TYPE_ZR36016,
@@ -505,10 +498,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC30plus,
.name = "DC30plus",
.i2c_decoder = "vpx3220a",
- .mod_decoder = "vpx3220",
.addrs_decoder = vpx3220_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36050,
.video_vfe = CODEC_TYPE_ZR36016,
@@ -538,10 +529,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = LML33,
.name = "LML33",
.i2c_decoder = "bt819a",
- .mod_decoder = "bt819",
.addrs_decoder = bt819_addrs,
.i2c_encoder = "bt856",
- .mod_encoder = "bt856",
.addrs_encoder = bt856_addrs,
.video_codec = CODEC_TYPE_ZR36060,

@@ -569,10 +558,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = LML33R10,
.name = "LML33R10",
.i2c_decoder = "saa7114",
- .mod_decoder = "saa7115",
.addrs_decoder = saa7114_addrs,
.i2c_encoder = "adv7170",
- .mod_encoder = "adv7170",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36060,

@@ -600,10 +587,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = BUZ,
.name = "Buz",
.i2c_decoder = "saa7111",
- .mod_decoder = "saa7115",
.addrs_decoder = saa7111_addrs,
.i2c_encoder = "saa7185",
- .mod_encoder = "saa7185",
.addrs_encoder = saa7185_addrs,
.video_codec = CODEC_TYPE_ZR36060,

@@ -633,10 +618,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
/* AverMedia chose not to brand the 6-Eyes. Thus it
can't be autodetected, and requires card=x. */
.i2c_decoder = "ks0127",
- .mod_decoder = "ks0127",
.addrs_decoder = ks0127_addrs,
.i2c_encoder = "bt866",
- .mod_encoder = "bt866",
.addrs_encoder = bt866_addrs,
.video_codec = CODEC_TYPE_ZR36060,

@@ -1359,13 +1342,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
}

zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter, zr->card.mod_decoder, zr->card.i2c_decoder,
+ &zr->i2c_adapter, NULL, zr->card.i2c_decoder,
0, zr->card.addrs_decoder);

- if (zr->card.mod_encoder)
+ if (zr->card.i2c_encoder)
zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
&zr->i2c_adapter,
- zr->card.mod_encoder, zr->card.i2c_encoder,
+ NULL, zr->card.i2c_encoder,
0, zr->card.addrs_encoder);

dprintk(2,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:42 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the pvrusb2
driver uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Acked-By: Mike Isely <***@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/pvrusb2/pvrusb2-hdw.c | 11 ++---------
1 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 70ea578..bef2027 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2082,20 +2082,13 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
return -EINVAL;
}

- /* Note how the 2nd and 3rd arguments are the same for
- * v4l2_i2c_new_subdev(). Why?
- * Well the 2nd argument is the module name to load, while the 3rd
- * argument is documented in the framework as being the "chipid" -
- * and every other place where I can find examples of this, the
- * "chipid" appears to just be the module name again. So here we
- * just do the same thing. */
if (i2ccnt == 1) {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with specified i2c address 0x%x",
mid, i2caddr[0]);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- fname, fname,
+ NULL, fname,
i2caddr[0], NULL);
} else {
pvr2_trace(PVR2_TRACE_INIT,
@@ -2103,7 +2096,7 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
" Setting up with address probe list",
mid);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- fname, fname,
+ NULL, fname,
0, i2caddr);
}
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:43 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, remove the module names hardcoded in platform data
and pass a NULL module name to those functions.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the sh_vou
platform data uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
arch/sh/boards/mach-ecovec24/setup.c | 1 -
arch/sh/boards/mach-se/7724/setup.c | 1 -
drivers/media/video/sh_vou.c | 2 +-
include/media/sh_vou.h | 1 -
4 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 1d7b495..4a9fa5d 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -793,7 +793,6 @@ static struct sh_vou_pdata sh_vou_pdata = {
.flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
.board_info = &ak8813,
.i2c_adap = 0,
- .module_name = "ak881x",
};

static struct resource sh_vou_resources[] = {
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 552ebd9..8cc1d72 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -550,7 +550,6 @@ static struct sh_vou_pdata sh_vou_pdata = {
.flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
.board_info = &ak8813,
.i2c_adap = 0,
- .module_name = "ak881x",
};

static struct resource sh_vou_resources[] = {
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index f5b892a..b805d30 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -1392,7 +1392,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
goto ereset;

subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
- vou_pdata->module_name, vou_pdata->board_info, NULL);
+ NULL, vou_pdata->board_info, NULL);
if (!subdev) {
ret = -ENOMEM;
goto ei2cnd;
diff --git a/include/media/sh_vou.h b/include/media/sh_vou.h
index a3ef302..ec3ba9a 100644
--- a/include/media/sh_vou.h
+++ b/include/media/sh_vou.h
@@ -28,7 +28,6 @@ struct sh_vou_pdata {
int i2c_adap;
struct i2c_board_info *board_info;
unsigned long flags;
- char *module_name;
};

#endif
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:45 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, remove the module names hardcoded in platform data
and pass a NULL module name to those functions.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the soc_camera
platform data uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
arch/arm/mach-mx3/mach-pcm037.c | 2 --
arch/arm/mach-mx3/mx31moboard-marxbot.c | 1 -
arch/arm/mach-mx3/mx31moboard-smartbot.c | 1 -
arch/arm/mach-pxa/em-x270.c | 1 -
arch/arm/mach-pxa/ezx.c | 2 --
arch/arm/mach-pxa/mioa701.c | 1 -
arch/arm/mach-pxa/pcm990-baseboard.c | 2 --
arch/sh/boards/mach-ap325rxa/setup.c | 1 -
arch/sh/boards/mach-ecovec24/setup.c | 3 ---
arch/sh/boards/mach-kfr2r09/setup.c | 1 -
arch/sh/boards/mach-migor/setup.c | 2 --
drivers/media/video/soc_camera.c | 2 +-
12 files changed, 1 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-mx3/mach-pcm037.c b/arch/arm/mach-mx3/mach-pcm037.c
index cce4106..dfa4465 100644
--- a/arch/arm/mach-mx3/mach-pcm037.c
+++ b/arch/arm/mach-mx3/mach-pcm037.c
@@ -317,7 +317,6 @@ static struct soc_camera_link iclink_mt9v022 = {
.bus_id = 0, /* Must match with the camera ID */
.board_info = &pcm037_i2c_camera[1],
.i2c_adapter_id = 2,
- .module_name = "mt9v022",
};

static struct soc_camera_link iclink_mt9t031 = {
@@ -325,7 +324,6 @@ static struct soc_camera_link iclink_mt9t031 = {
.power = pcm037_camera_power,
.board_info = &pcm037_i2c_camera[0],
.i2c_adapter_id = 2,
- .module_name = "mt9t031",
};

static struct i2c_board_info pcm037_i2c_devices[] = {
diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-mx3/mx31moboard-marxbot.c
index 4930f8c..44a9b20 100644
--- a/arch/arm/mach-mx3/mx31moboard-marxbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-marxbot.c
@@ -183,7 +183,6 @@ static struct soc_camera_link base_iclink = {
.reset = marxbot_basecam_reset,
.board_info = &marxbot_i2c_devices[0],
.i2c_adapter_id = 0,
- .module_name = "mt9t031",
};

static struct platform_device marxbot_camera[] = {
diff --git a/arch/arm/mach-mx3/mx31moboard-smartbot.c b/arch/arm/mach-mx3/mx31moboard-smartbot.c
index 293eea6..a655556 100644
--- a/arch/arm/mach-mx3/mx31moboard-smartbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-smartbot.c
@@ -92,7 +92,6 @@ static struct soc_camera_link base_iclink = {
.reset = smartbot_cam_reset,
.board_info = &smartbot_i2c_devices[0],
.i2c_adapter_id = 0,
- .module_name = "mt9t031",
};

static struct platform_device smartbot_camera[] = {
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 0517c17..0c95476 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -1015,7 +1015,6 @@ static struct soc_camera_link iclink = {
.power = em_x270_sensor_power,
.board_info = &em_x270_i2c_cam_info[0],
.i2c_adapter_id = 0,
- .module_name = "mt9m111",
};

static struct platform_device em_x270_camera = {
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index 626c82b..70dfe08 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -753,7 +753,6 @@ static struct soc_camera_link a780_iclink = {
.flags = SOCAM_SENSOR_INVERT_PCLK,
.i2c_adapter_id = 0,
.board_info = &a780_camera_i2c_board_info,
- .module_name = "mt9m111",
.power = a780_camera_power,
.reset = a780_camera_reset,
};
@@ -1025,7 +1024,6 @@ static struct soc_camera_link a910_iclink = {
.bus_id = 0,
.i2c_adapter_id = 0,
.board_info = &a910_camera_i2c_board_info,
- .module_name = "mt9m111",
.power = a910_camera_power,
.reset = a910_camera_reset,
};
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index fa6a708..a197dab 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -707,7 +707,6 @@ static struct soc_camera_link iclink = {
.bus_id = 0, /* Match id in pxa27x_device_camera in device.c */
.board_info = &mioa701_i2c_devices[0],
.i2c_adapter_id = 0,
- .module_name = "mt9m111",
};

struct i2c_pxa_platform_data i2c_pdata = {
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index f56ae10..f33647a 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -453,7 +453,6 @@ static struct soc_camera_link iclink[] = {
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
- .module_name = "mt9v022",
}, {
.bus_id = 0, /* Must match with the camera ID */
.board_info = &pcm990_camera_i2c[1],
@@ -461,7 +460,6 @@ static struct soc_camera_link iclink[] = {
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
- .module_name = "mt9m001",
},
};

diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 3a170bd..7a94f4f 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -481,7 +481,6 @@ static struct soc_camera_link ov7725_link = {
.power = ov7725_power,
.board_info = &ap325rxa_i2c_camera[0],
.i2c_adapter_id = 0,
- .module_name = "ov772x",
.priv = &ov7725_info,
};

diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 4a9fa5d..ae0b138 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -620,7 +620,6 @@ static struct soc_camera_link tw9910_link = {
.bus_id = 1,
.power = tw9910_power,
.board_info = &i2c_camera[0],
- .module_name = "tw9910",
.priv = &tw9910_info,
};

@@ -644,7 +643,6 @@ static struct soc_camera_link mt9t112_link1 = {
.power = mt9t112_power1,
.bus_id = 0,
.board_info = &i2c_camera[1],
- .module_name = "mt9t112",
.priv = &mt9t112_info1,
};

@@ -667,7 +665,6 @@ static struct soc_camera_link mt9t112_link2 = {
.power = mt9t112_power2,
.bus_id = 1,
.board_info = &i2c_camera[2],
- .module_name = "mt9t112",
.priv = &mt9t112_info2,
};

diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 68994a1..1742849 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -333,7 +333,6 @@ static struct soc_camera_link rj54n1_link = {
.power = camera_power,
.board_info = &kfr2r09_i2c_camera,
.i2c_adapter_id = 1,
- .module_name = "rj54n1cb0c",
.priv = &rj54n1_priv,
};

diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 662debe..03af848 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -450,7 +450,6 @@ static struct soc_camera_link ov7725_link = {
.power = ov7725_power,
.board_info = &migor_i2c_camera[0],
.i2c_adapter_id = 0,
- .module_name = "ov772x",
.priv = &ov7725_info,
};

@@ -463,7 +462,6 @@ static struct soc_camera_link tw9910_link = {
.power = tw9910_power,
.board_info = &migor_i2c_camera[1],
.i2c_adapter_id = 0,
- .module_name = "tw9910",
.priv = &tw9910_info,
};

diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 475757b..11b5b84 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -895,7 +895,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
icl->board_info->platform_data = icd;

subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- icl->module_name, icl->board_info, NULL);
+ NULL, icl->board_info, NULL);
if (!subdev)
goto ei2cnd;
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:44 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

As no board seems to use this driver, no platform data has been checked.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/radio/radio-si4713.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index 13554ab..045b10f 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -291,7 +291,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
goto unregister_v4l2_dev;
}

- sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, "si4713_i2c",
+ sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL,
pdata->subdev_board_info, NULL);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:47 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, don't use the module names hardcoded in platform
data by passing a NULL module name to those functions.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the vpif_display
platform data uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/davinci/vpif_display.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index da07607..4be501b 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -1551,7 +1551,7 @@ static __init int vpif_probe(struct platform_device *pdev)

for (i = 0; i < subdev_count; i++) {
vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
- i2c_adap, subdevdata[i].name,
+ i2c_adap, NULL,
&subdevdata[i].board_info,
NULL);
if (!vpif_obj.sd[i]) {
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:46 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, don't use the module names hardcoded in platform
data by passing a NULL module name to those functions.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the vpfe_capture
platform data uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/davinci/vpfe_capture.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 1c25882..f68b66d 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -1980,7 +1980,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
vpfe_dev->sd[i] =
v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
i2c_adap,
- sdinfo->name,
+ NULL,
&sdinfo->board_info,
NULL);
if (vpfe_dev->sd[i]) {
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:49 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

The sub-devices without a listed module name don't result in and I2C
sub-device being created, as they either are IR devices or don't have an
I2C address listed. It's thus safe to rely on modaliases only.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the ivtv driver
uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/ivtv/ivtv-i2c.c | 39 +++++-----------------------------
1 files changed, 6 insertions(+), 33 deletions(-)

diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index a5b92d1..2c291f8 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -120,31 +120,6 @@ static const u8 hw_addrs[] = {
};

/* This array should match the IVTV_HW_ defines */
-static const char *hw_modules[] = {
- "cx25840",
- "saa7115",
- "saa7127",
- "msp3400",
- "tuner",
- "wm8775",
- "cs53l32a",
- NULL,
- "saa7115",
- "upd64031a",
- "upd64083",
- "saa717x",
- "wm8739",
- "vp27smpx",
- "m52790",
- NULL,
- NULL, /* IVTV_HW_I2C_IR_RX_AVER */
- NULL, /* IVTV_HW_I2C_IR_RX_HAUP_EXT */
- NULL, /* IVTV_HW_I2C_IR_RX_HAUP_INT */
- NULL, /* IVTV_HW_Z8F0811_IR_TX_HAUP */
- NULL, /* IVTV_HW_Z8F0811_IR_RX_HAUP */
-};
-
-/* This array should match the IVTV_HW_ defines */
static const char * const hw_devicenames[] = {
"cx25840",
"saa7115",
@@ -255,7 +230,6 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
{
struct v4l2_subdev *sd;
struct i2c_adapter *adap = &itv->i2c_adap;
- const char *mod = hw_modules[idx];
const char *type = hw_devicenames[idx];
u32 hw = 1 << idx;

@@ -264,17 +238,17 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
if (hw == IVTV_HW_TUNER) {
/* special tuner handling */
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type,
+ adap, NULL, type,
0, itv->card_i2c->radio);
if (sd)
sd->grp_id = 1 << idx;
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type,
+ adap, NULL, type,
0, itv->card_i2c->demod);
if (sd)
sd->grp_id = 1 << idx;
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type,
+ adap, NULL, type,
0, itv->card_i2c->tv);
if (sd)
sd->grp_id = 1 << idx;
@@ -291,10 +265,10 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
/* It's an I2C device other than an analog tuner or IR chip */
if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type, 0, I2C_ADDRS(hw_addrs[idx]));
+ adap, NULL, type, 0, I2C_ADDRS(hw_addrs[idx]));
} else {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type, hw_addrs[idx], NULL);
+ adap, NULL, type, hw_addrs[idx], NULL);
}
if (sd)
sd->grp_id = 1 << idx;
@@ -698,8 +672,7 @@ int init_ivtv_i2c(struct ivtv *itv)
/* Sanity checks for the I2C hardware arrays. They must be the
* same size.
*/
- if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
- ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules)) {
+ if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) {
IVTV_ERR("Mismatched I2C hardware arrays\n");
return -ENODEV;
}
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:48 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, don't use the module names hardcoded in platform
data by passing a NULL module name to those functions.

The only platform using the VPIF capture device (DM646x EVM) hardcodes
the module names to invalid values (tvp514x-0 and tvp514x-1). As this is
already broken, there's no risk of breaking it more.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/davinci/vpif_capture.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index a7f48b5..cc881ca 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -2013,7 +2013,7 @@ static __init int vpif_probe(struct platform_device *pdev)
vpif_obj.sd[i] =
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
i2c_adap,
- subdevdata->name,
+ NULL,
&subdevdata->board_info,
NULL);
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:50 UTC
Permalink
With the v4l2_i2c_new_subdev* functions now supporting loading modules
based on modaliases, replace the hardcoded module name passed to those
functions by NULL.

The sub-devices without a listed module name don't result in and I2C
sub-device being created, as they either are IR devices or don't have an
I2C address listed. It's thus safe to rely on modaliases only.

All corresponding I2C modules have been checked, and all of them include
a module aliases table with names corresponding to what the cx18 driver
uses.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/cx18/cx18-i2c.c | 23 +++++------------------
1 files changed, 5 insertions(+), 18 deletions(-)

diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 809f7d3..3b67984 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -71,19 +71,6 @@ static const u8 hw_bus[] = {
};

/* This array should match the CX18_HW_ defines */
-static const char * const hw_modules[] = {
- "tuner", /* CX18_HW_TUNER */
- NULL, /* CX18_HW_TVEEPROM */
- "cs5345", /* CX18_HW_CS5345 */
- NULL, /* CX18_HW_DVB */
- NULL, /* CX18_HW_418_AV */
- NULL, /* CX18_HW_GPIO_MUX */
- NULL, /* CX18_HW_GPIO_RESET_CTRL */
- NULL, /* CX18_HW_Z8F0811_IR_TX_HAUP */
- NULL, /* CX18_HW_Z8F0811_IR_RX_HAUP */
-};
-
-/* This array should match the CX18_HW_ defines */
static const char * const hw_devicenames[] = {
"tuner",
"tveeprom",
@@ -125,7 +112,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
struct v4l2_subdev *sd;
int bus = hw_bus[idx];
struct i2c_adapter *adap = &cx->i2c_adap[bus];
- const char *mod = hw_modules[idx];
const char *type = hw_devicenames[idx];
u32 hw = 1 << idx;

@@ -135,15 +121,15 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->radio);
+ adap, NULL, type, 0, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->demod);
+ adap, NULL, type, 0, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->tv);
+ adap, NULL, type, 0, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
@@ -157,7 +143,8 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return -1;

/* It's an I2C device other than an analog tuner or IR chip */
- sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, NULL, type, hw_addrs[idx],
+ NULL);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:51 UTC
Permalink
Replace direct access to the v4l2_subdev priv field with the inline
v4l2_get_subdevdata method.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Acked-by: Hans Verkuil <***@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/mt9m001.c | 26 +++++++++++++-------------
drivers/media/video/mt9m111.c | 20 ++++++++++----------
drivers/media/video/mt9t031.c | 24 ++++++++++++------------
drivers/media/video/mt9t112.c | 14 +++++++-------
drivers/media/video/mt9v022.c | 26 +++++++++++++-------------
drivers/media/video/ov772x.c | 18 +++++++++---------
drivers/media/video/ov9640.c | 12 ++++++------
drivers/media/video/rj54n1cb0c.c | 26 +++++++++++++-------------
drivers/media/video/soc_camera.c | 2 +-
drivers/media/video/tw9910.c | 20 ++++++++++----------
10 files changed, 94 insertions(+), 94 deletions(-)

diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 79f096d..fcb4cd9 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -157,7 +157,7 @@ static int mt9m001_init(struct i2c_client *client)

static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

/* Switch to master "normal" mode or stop sensor readout */
if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
@@ -206,7 +206,7 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)

static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_rect rect = a->c;
struct soc_camera_device *icd = client->dev.platform_data;
@@ -271,7 +271,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)

static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);

a->c = mt9m001->rect;
@@ -297,7 +297,7 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9m001_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);

mf->width = mt9m001->rect.width;
@@ -312,7 +312,7 @@ static int mt9m001_g_fmt(struct v4l2_subdev *sd,
static int mt9m001_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_crop a = {
.c = {
@@ -340,7 +340,7 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd,
static int mt9m001_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
const struct mt9m001_datafmt *fmt;

@@ -367,7 +367,7 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd,
static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);

if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -386,7 +386,7 @@ static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
static int mt9m001_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -406,7 +406,7 @@ static int mt9m001_g_register(struct v4l2_subdev *sd,
static int mt9m001_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -468,7 +468,7 @@ static struct soc_camera_ops mt9m001_ops = {

static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
int data;

@@ -494,7 +494,7 @@ static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)

static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
@@ -683,7 +683,7 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)

static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);

*lines = mt9m001->y_skip_top;
@@ -704,7 +704,7 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);

if (index >= mt9m001->num_fmts)
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index fbd0fc7..a30fe35 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -434,7 +434,7 @@ static int mt9m111_make_rect(struct i2c_client *client,
static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct v4l2_rect rect = a->c;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;

@@ -449,7 +449,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)

static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);

a->c = mt9m111->rect;
@@ -475,7 +475,7 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9m111_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);

mf->width = mt9m111->rect.width;
@@ -537,7 +537,7 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
static int mt9m111_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct mt9m111_datafmt *fmt;
struct mt9m111 *mt9m111 = to_mt9m111(client);
struct v4l2_rect rect = {
@@ -572,7 +572,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
static int mt9m111_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
const struct mt9m111_datafmt *fmt;
bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
@@ -612,7 +612,7 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd,
static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);

if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -631,7 +631,7 @@ static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
static int mt9m111_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int val;

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
@@ -652,7 +652,7 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
static int mt9m111_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
@@ -800,7 +800,7 @@ static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)

static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
int data;

@@ -843,7 +843,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)

static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
const struct v4l2_queryctrl *qctrl;
int ret;
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index a9a28b2..9bd44a8 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -163,7 +163,7 @@ static int mt9t031_disable(struct i2c_client *client)

static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;

if (enable)
@@ -393,7 +393,7 @@ static int mt9t031_set_params(struct i2c_client *client,
static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct v4l2_rect rect = a->c;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);

rect.width = ALIGN(rect.width, 2);
@@ -410,7 +410,7 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)

static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);

a->c = mt9t031->rect;
@@ -436,7 +436,7 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9t031_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);

mf->width = mt9t031->rect.width / mt9t031->xskip;
@@ -451,7 +451,7 @@ static int mt9t031_g_fmt(struct v4l2_subdev *sd,
static int mt9t031_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
u16 xskip, yskip;
struct v4l2_rect rect = mt9t031->rect;
@@ -490,7 +490,7 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);

if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -509,7 +509,7 @@ static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
static int mt9t031_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -528,7 +528,7 @@ static int mt9t031_g_register(struct v4l2_subdev *sd,
static int mt9t031_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -545,7 +545,7 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,

static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
int data;

@@ -577,7 +577,7 @@ static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)

static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
const struct v4l2_queryctrl *qctrl;
int data;
@@ -703,7 +703,7 @@ static int mt9t031_runtime_resume(struct device *dev)
struct soc_camera_device *icd = container_of(vdev->parent,
struct soc_camera_device, dev);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);

int ret;
@@ -780,7 +780,7 @@ static int mt9t031_video_probe(struct i2c_client *client)

static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);

*lines = mt9t031->y_skip_top;
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index e4bf1db..74d8dd4 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -804,7 +804,7 @@ static struct soc_camera_ops mt9t112_ops = {
static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);

id->ident = priv->model;
@@ -817,7 +817,7 @@ static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
static int mt9t112_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;

reg->size = 2;
@@ -831,7 +831,7 @@ static int mt9t112_g_register(struct v4l2_subdev *sd,
static int mt9t112_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;

mt9t112_reg_write(ret, client, reg->reg, reg->val);
@@ -858,7 +858,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
************************************************************************/
static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
int ret = 0;

@@ -968,7 +968,7 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)

static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct v4l2_rect *rect = &a->c;

return mt9t112_set_params(client, rect->width, rect->height,
@@ -978,7 +978,7 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9t112_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);

if (!priv->format) {
@@ -1000,7 +1000,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,
static int mt9t112_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

/* TODO: set colorspace */
return mt9t112_set_params(client, mf->width, mf->height, mf->code);
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index e7cd23c..1a02f67 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -184,7 +184,7 @@ static int mt9v022_init(struct i2c_client *client)

static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);

if (enable)
@@ -273,7 +273,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)

static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_rect rect = a->c;
int ret;
@@ -334,7 +334,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)

static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);

a->c = mt9v022->rect;
@@ -360,7 +360,7 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9v022_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);

mf->width = mt9v022->rect.width;
@@ -375,7 +375,7 @@ static int mt9v022_g_fmt(struct v4l2_subdev *sd,
static int mt9v022_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_crop a = {
.c = {
@@ -425,7 +425,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
static int mt9v022_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
const struct mt9v022_datafmt *fmt;
int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
@@ -451,7 +451,7 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd,
static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);

if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -470,7 +470,7 @@ static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
static int mt9v022_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -490,7 +490,7 @@ static int mt9v022_g_register(struct v4l2_subdev *sd,
static int mt9v022_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -568,7 +568,7 @@ static struct soc_camera_ops mt9v022_ops = {

static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct v4l2_queryctrl *qctrl;
unsigned long range;
int data;
@@ -625,7 +625,7 @@ static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int data;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct v4l2_queryctrl *qctrl;

qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -820,7 +820,7 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)

static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);

*lines = mt9v022->y_skip_top;
@@ -841,7 +841,7 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);

if (index >= mt9v022->num_fmts)
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 34034a7..4330c1f 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -599,7 +599,7 @@ static int ov772x_reset(struct i2c_client *client)

static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);

if (!enable) {
@@ -645,7 +645,7 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)

static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);

switch (ctrl->id) {
@@ -664,7 +664,7 @@ static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)

static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);
int ret = 0;
u8 val;
@@ -715,7 +715,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);

id->ident = priv->model;
@@ -728,7 +728,7 @@ static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
static int ov772x_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;

reg->size = 1;
@@ -747,7 +747,7 @@ static int ov772x_g_register(struct v4l2_subdev *sd,
static int ov772x_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->reg > 0xff ||
reg->val > 0xff)
@@ -954,7 +954,7 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int ov772x_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);

if (!priv->win || !priv->cfmt) {
@@ -977,7 +977,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
static int ov772x_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);
int ret = ov772x_set_params(client, &mf->width, &mf->height,
mf->code);
@@ -991,7 +991,7 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd,
static int ov772x_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(client);
const struct ov772x_win_size *win;
int i;
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 7ce9e05..faa71f3 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -308,7 +308,7 @@ static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd)
/* Get status of additional camera capabilities */
static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
struct ov9640_priv, subdev);

@@ -326,7 +326,7 @@ static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* Set status of additional camera capabilities */
static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
struct ov9640_priv, subdev);

@@ -360,7 +360,7 @@ static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
struct ov9640_priv, subdev);

@@ -374,7 +374,7 @@ static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
static int ov9640_get_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
u8 val;

@@ -395,7 +395,7 @@ static int ov9640_get_register(struct v4l2_subdev *sd,
static int ov9640_set_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->reg & ~0xff || reg->val & ~0xff)
return -EINVAL;
@@ -558,7 +558,7 @@ static int ov9640_prog_dflt(struct i2c_client *client)
static int ov9640_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9640_reg_alt alts = {0};
enum v4l2_colorspace cspace;
enum v4l2_mbus_pixelcode code = mf->code;
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index 47fd207..a626a2a 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -493,7 +493,7 @@ static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,

static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

/* Switch between preview and still shot modes */
return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
@@ -503,7 +503,7 @@ static int rj54n1_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */

if (flags & SOCAM_PCLK_SAMPLE_RISING)
@@ -560,7 +560,7 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,

static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct v4l2_rect *rect = &a->c;
int dummy = 0, output_w, output_h,
@@ -595,7 +595,7 @@ static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)

static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);

a->c = rj54n1->rect;
@@ -621,7 +621,7 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int rj54n1_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);

mf->code = rj54n1->fmt->code;
@@ -641,7 +641,7 @@ static int rj54n1_g_fmt(struct v4l2_subdev *sd,
static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
s32 *out_w, s32 *out_h)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
output_w = *out_w, output_h = *out_h;
@@ -983,7 +983,7 @@ static int rj54n1_reg_init(struct i2c_client *client)
static int rj54n1_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct rj54n1_datafmt *fmt;
int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
@@ -1014,7 +1014,7 @@ static int rj54n1_try_fmt(struct v4l2_subdev *sd,
static int rj54n1_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct rj54n1_datafmt *fmt;
int output_w, output_h, max_w, max_h,
@@ -1145,7 +1145,7 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
@@ -1163,7 +1163,7 @@ static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
static int rj54n1_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
reg->reg < 0x400 || reg->reg > 0x1fff)
@@ -1185,7 +1185,7 @@ static int rj54n1_g_register(struct v4l2_subdev *sd,
static int rj54n1_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
reg->reg < 0x400 || reg->reg > 0x1fff)
@@ -1248,7 +1248,7 @@ static struct soc_camera_ops rj54n1_ops = {

static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
int data;

@@ -1283,7 +1283,7 @@ static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int data;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct v4l2_queryctrl *qctrl;

diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 11b5b84..2b4a2d9 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -899,7 +899,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
if (!subdev)
goto ei2cnd;

- client = subdev->priv;
+ client = v4l2_get_subdevdata(subdev);

/* Use to_i2c_client(dev) to recover the i2c client */
dev_set_drvdata(&icd->dev, &client->dev);
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 445dc93..d5e4949 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -469,7 +469,7 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
*/
static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
u8 val;
int ret;
@@ -511,7 +511,7 @@ static int tw9910_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 val = VSSL_VVALID | HSSL_DVALID;

/*
@@ -565,7 +565,7 @@ static int tw9910_enum_input(struct soc_camera_device *icd,
static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);

id->ident = V4L2_IDENT_TW9910;
@@ -578,7 +578,7 @@ static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
static int tw9910_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;

if (reg->reg > 0xff)
@@ -600,7 +600,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd,
static int tw9910_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);

if (reg->reg > 0xff ||
reg->val > 0xff)
@@ -613,7 +613,7 @@ static int tw9910_s_register(struct v4l2_subdev *sd,
static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct v4l2_rect *rect = &a->c;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
struct soc_camera_device *icd = client->dev.platform_data;
int ret = -EINVAL;
@@ -701,7 +701,7 @@ tw9910_set_fmt_error:

static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);

if (!priv->scale) {
@@ -748,7 +748,7 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int tw9910_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);

if (!priv->scale) {
@@ -778,7 +778,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
static int tw9910_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
/* See tw9910_s_crop() - no proper cropping support */
struct v4l2_crop a = {
@@ -813,7 +813,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
static int tw9910_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_device *icd = client->dev.platform_data;
const struct tw9910_scale_ctrl *scale;
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:52 UTC
Permalink
The existing priv field stores subdev private data owned by the subdev
driver. Host (bridge) drivers might need to store per-subdev
host-specific data, such as a pointer to platform data.

Add a v4l2_subdev host_priv field to store host-specific data, and
rename the existing priv field to dev_priv.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Acked-by: Hans Verkuil <***@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
Documentation/video4linux/v4l2-framework.txt | 5 +++++
include/media/v4l2-subdev.h | 20 ++++++++++++++++----
2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index e831aac..f5fdb39 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -192,6 +192,11 @@ You also need a way to go from the low-level struct to v4l2_subdev. For the
common i2c_client struct the i2c_set_clientdata() call is used to store a
v4l2_subdev pointer, for other busses you may have to use other methods.

+Bridges might also need to store per-subdev private data, such as a pointer to
+bridge-specific per-subdev private data. The v4l2_subdev structure provides
+host private data for that purpose that can be accessed with
+v4l2_get_subdev_hostdata() and v4l2_set_subdev_hostdata().
+
From the bridge driver perspective you load the sub-device module and somehow
obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
i2c_get_clientdata(). For other busses something similar needs to be done.
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 02c6f4d..fcdd247 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -420,17 +420,28 @@ struct v4l2_subdev {
/* can be used to group similar subdevs, value is driver-specific */
u32 grp_id;
/* pointer to private data */
- void *priv;
+ void *dev_priv;
+ void *host_priv;
};

static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
{
- sd->priv = p;
+ sd->dev_priv = p;
}

static inline void *v4l2_get_subdevdata(const struct v4l2_subdev *sd)
{
- return sd->priv;
+ return sd->dev_priv;
+}
+
+static inline void v4l2_set_subdev_hostdata(struct v4l2_subdev *sd, void *p)
+{
+ sd->host_priv = p;
+}
+
+static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
+{
+ return sd->host_priv;
}

static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
@@ -444,7 +455,8 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
sd->flags = 0;
sd->name[0] = '\0';
sd->grp_id = 0;
- sd->priv = NULL;
+ sd->dev_priv = NULL;
+ sd->host_priv = NULL;
}

/* Call an ops of a v4l2_subdev, doing the right checks against
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:53 UTC
Permalink
From: Guennadi Liakhovetski <***@axis700.grange>

Endianness notation is meaningless for 8 bit YUYV codes. Switch pixel code
names to explicitly state the order of colour components in the data
stream.

Signed-off-by: Guennadi Liakhovetski <***@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
arch/sh/boards/mach-ap325rxa/setup.c | 2 +-
drivers/media/video/ak881x.c | 6 +++---
drivers/media/video/mt9m111.c | 16 ++++++++--------
drivers/media/video/mt9t112.c | 12 ++++++------
drivers/media/video/ov772x.c | 8 ++++----
drivers/media/video/ov9640.c | 14 +++++++-------
drivers/media/video/pxa_camera.c | 8 ++++----
drivers/media/video/rj54n1cb0c.c | 8 ++++----
drivers/media/video/sh_mobile_ceu_camera.c | 16 ++++++++--------
drivers/media/video/sh_vou.c | 8 ++++----
drivers/media/video/soc_mediabus.c | 8 ++++----
drivers/media/video/tw9910.c | 8 ++++----
include/media/v4l2-mediabus.h | 8 ++++----
13 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 7a94f4f..18b45c6 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -316,7 +316,7 @@ static struct soc_camera_platform_info camera_info = {
.format_name = "UYVY",
.format_depth = 16,
.format = {
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.field = V4L2_FIELD_NONE,
.width = 640,
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 1573392..b388654 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -126,7 +126,7 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 0, 720, 2,
&mf->height, 0, ak881x->lines, 1, 0);
mf->field = V4L2_FIELD_INTERLACED;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;

return 0;
@@ -136,7 +136,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
if (mf->field != V4L2_FIELD_INTERLACED ||
- mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EINVAL;

return ak881x_try_g_mbus_fmt(sd, mf);
@@ -148,7 +148,7 @@ static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
if (index)
return -EINVAL;

- *code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
return 0;
}

diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index a30fe35..a70f482 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -143,10 +143,10 @@ static const struct mt9m111_datafmt *mt9m111_find_datafmt(
}

static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
@@ -505,22 +505,22 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
case V4L2_MBUS_FMT_RGB565_2X8_LE:
ret = mt9m111_setfmt_rgb565(client);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 0;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 0;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(client);
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 74d8dd4..bffa9ee 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -121,22 +121,22 @@ struct mt9t112_priv {

static const struct mt9t112_format mt9t112_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 0,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8_BE,
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 1,
}, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 2,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 3,
@@ -972,7 +972,7 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
struct v4l2_rect *rect = &a->c;

return mt9t112_set_params(client, rect->width, rect->height,
- V4L2_MBUS_FMT_YUYV8_2X8_BE);
+ V4L2_MBUS_FMT_UYVY8_2X8);
}

static int mt9t112_g_fmt(struct v4l2_subdev *sd,
@@ -983,7 +983,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,

if (!priv->format) {
int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
- V4L2_MBUS_FMT_YUYV8_2X8_BE);
+ V4L2_MBUS_FMT_UYVY8_2X8);
if (ret < 0)
return ret;
}
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 4330c1f..a84b770 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -440,21 +440,21 @@ static const struct regval_list ov772x_vga_regs[] = {
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = 0x0,
@@ -960,7 +960,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
if (!priv->win || !priv->cfmt) {
u32 width = VGA_WIDTH, height = VGA_HEIGHT;
int ret = ov772x_set_params(client, &width, &height,
- V4L2_MBUS_FMT_YUYV8_2X8_LE);
+ V4L2_MBUS_FMT_YUYV8_2X8);
if (ret < 0)
return ret;
}
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index faa71f3..99e9e1d 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -155,7 +155,7 @@ static const struct ov9640_reg ov9640_regs_rgb[] = {
};

static enum v4l2_mbus_pixelcode ov9640_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ V4L2_MBUS_FMT_UYVY8_2X8,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
};
@@ -430,7 +430,7 @@ static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
{
switch (code) {
default:
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
alt->com12 = OV9640_COM12_YUV_AVG;
alt->com13 = OV9640_COM13_Y_DELAY_EN |
OV9640_COM13_YUV_DLY(0x01);
@@ -493,7 +493,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width,
}

/* select color matrix configuration for given color encoding */
- if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) {
+ if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
matrix_regs = ov9640_regs_yuv;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
} else {
@@ -579,8 +579,8 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
cspace = V4L2_COLORSPACE_SRGB;
break;
default:
- code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
cspace = V4L2_COLORSPACE_JPEG;
}

@@ -606,8 +606,8 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}

diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index fb242f6..ae5cd0c 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1284,7 +1284,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
}

switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
formats++;
if (xlate) {
xlate->host_fmt = &pxa_camera_formats[0];
@@ -1293,9 +1293,9 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
dev_dbg(dev, "Providing format %s using code %d\n",
pxa_camera_formats[0].name, code);
}
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
case V4L2_MBUS_FMT_RGB565_2X8_LE:
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
if (xlate)
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index a626a2a..b238411 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -127,8 +127,8 @@ static const struct rj54n1_datafmt *rj54n1_find_datafmt(
}

static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
@@ -1046,12 +1046,12 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,

/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
switch (mf->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 961bfa2..f4e6a3f 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -743,16 +743,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
switch (cam->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
break;
default:
@@ -965,10 +965,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
cam->extra_fmt = NULL;

switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
if (cam->extra_fmt)
break;

diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index b805d30..4a8bf7a 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -677,7 +677,7 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
@@ -725,7 +725,7 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
(unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EIO;

if (mbfmt.width != geo.output.width ||
@@ -936,7 +936,7 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
@@ -981,7 +981,7 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
(unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EIO;

geo.output.width = mbfmt.width;
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index 8b63b65..9139121 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -18,28 +18,28 @@
#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)

static const struct soc_mbus_pixelfmt mbus_fmt[] = {
- [MBUS_IDX(YUYV8_2X8_LE)] = {
+ [MBUS_IDX(YUYV8_2X8)] = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8_LE)] = {
+ [MBUS_IDX(YVYU8_2X8)] = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YUYV8_2X8_BE)] = {
+ [MBUS_IDX(UYVY8_2X8)] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8_BE)] = {
+ [MBUS_IDX(VYUY8_2X8)] = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index d5e4949..0347bbe 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -768,7 +768,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,

mf->width = priv->scale->width;
mf->height = priv->scale->height;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mf->field = V4L2_FIELD_INTERLACED_BT;

@@ -797,7 +797,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
/*
* check color format
*/
- if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE)
+ if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
return -EINVAL;

mf->colorspace = V4L2_COLORSPACE_JPEG;
@@ -824,7 +824,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
return -EINVAL;
}

- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;

/*
@@ -909,7 +909,7 @@ static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
if (index)
return -EINVAL;

- *code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
return 0;
}

diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 865cda7..a870965 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -24,10 +24,10 @@
*/
enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_FIXED = 1,
- V4L2_MBUS_FMT_YUYV8_2X8_LE,
- V4L2_MBUS_FMT_YVYU8_2X8_LE,
- V4L2_MBUS_FMT_YUYV8_2X8_BE,
- V4L2_MBUS_FMT_YVYU8_2X8_BE,
+ V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_YVYU8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_VYUY8_2X8,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:54 UTC
Permalink
From: Guennadi Liakhovetski <***@gmx.de>

These formats belong to the standard format set, defined by the MIPI CSI-2
specification.

Signed-off-by: Guennadi Liakhovetski <***@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
include/media/v4l2-mediabus.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index a870965..f0cf2e7 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -41,6 +41,11 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SBGGR12_1X12,
+ V4L2_MBUS_FMT_YUYV8_1_5X8,
+ V4L2_MBUS_FMT_YVYU8_1_5X8,
+ V4L2_MBUS_FMT_UYVY8_1_5X8,
+ V4L2_MBUS_FMT_VYUY8_1_5X8,
};

/**
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:55 UTC
Permalink
From: Sascha Hauer <***@pengutronix.de>

Signed-off-by: Sascha Hauer <***@pengutronix.de>
Acked-by: Robert Jarzmik <***@free.fr>
Signed-off-by: Guennadi Liakhovetski <***@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
include/media/v4l2-mediabus.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index f0cf2e7..b16aa78 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -32,6 +32,8 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
V4L2_MBUS_FMT_RGB565_2X8_BE,
+ V4L2_MBUS_FMT_BGR565_2X8_LE,
+ V4L2_MBUS_FMT_BGR565_2X8_BE,
V4L2_MBUS_FMT_SBGGR8_1X8,
V4L2_MBUS_FMT_SBGGR10_1X10,
V4L2_MBUS_FMT_GREY8_1X8,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:56 UTC
Permalink
From: Hans Verkuil <***@xs4all.nl>

Needed for tvp7002 and tvp514x drivers.

Signed-off-by: Hans Verkuil <***@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
include/media/v4l2-mediabus.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index b16aa78..46b4ebd 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -28,6 +28,10 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_YVYU8_2X8,
V4L2_MBUS_FMT_UYVY8_2X8,
V4L2_MBUS_FMT_VYUY8_2X8,
+ V4L2_MBUS_FMT_YVYU10_2X10,
+ V4L2_MBUS_FMT_YUYV10_2X10,
+ V4L2_MBUS_FMT_YVYU10_1X20,
+ V4L2_MBUS_FMT_YUYV10_1X20,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:57 UTC
Permalink
From: Hans Verkuil <***@xs4all.nl>

These are needed for the ov7670 driver.

Signed-off-by: Hans Verkuil <***@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
include/media/v4l2-mediabus.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 46b4ebd..8e65598 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -32,6 +32,8 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_YUYV10_2X10,
V4L2_MBUS_FMT_YVYU10_1X20,
V4L2_MBUS_FMT_YUYV10_1X20,
+ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:58 UTC
Permalink
From: Hans Verkuil <***@xs4all.nl>

Add a new framework to handle controls which makes life for driver
developers much easier.

Note that this patch moves some of the control support that used to be in
v4l2-common.c to v4l2-ctrls.c. The tables were copied unchanged. The body
of v4l2_ctrl_query_fill() was copied to a new v4l2_ctrl_fill() function
in v4l2-ctrls.c. This new function doesn't use the v4l2_queryctrl
struct anymore, which makes it more general.

The remainder of v4l2-ctrls.c is all new. Highlights include:

- No need to implement VIDIOC_QUERYCTRL, QUERYMENU, S_CTRL, G_CTRL,
S_EXT_CTRLS, G_EXT_CTRLS or TRY_EXT_CTRLS in either bridge drivers
or subdevs. New wrapper functions are provided that can just be plugged in.
Once everything has been converted these wrapper functions can be removed as well.

- When subdevices are added their controls can be automatically merged
with the bridge driver's controls.

- Most drivers just need to implement s_ctrl to set the controls.
The framework handles the locking and tries to be as 'atomic' as possible.

- Ready for the subdev device nodes: the same mechanism applies to subdevs
and their device nodes as well. Sub-device drivers can make controls
local, preventing them from being merged with bridge drivers.

- Takes care of backwards compatibility handling of VIDIOC_S_CTRL and
VIDIOC_G_CTRL. Handling of V4L2_CID_PRIVATE_BASE is fully transparent.
CTRL_CLASS controls are automatically added.

Signed-off-by: Hans Verkuil <***@xs4all.nl>
Reviewed-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/Makefile | 2 +-
drivers/media/video/v4l2-common.c | 479 +----------
drivers/media/video/v4l2-ctrls.c | 1847 +++++++++++++++++++++++++++++++++++++
include/media/v4l2-ctrls.h | 460 +++++++++
include/media/v4l2-dev.h | 4 +
include/media/v4l2-device.h | 4 +
include/media/v4l2-subdev.h | 3 +
7 files changed, 2324 insertions(+), 475 deletions(-)
create mode 100644 drivers/media/video/v4l2-ctrls.c
create mode 100644 include/media/v4l2-ctrls.h

diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index cc93859..2ea34a6 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o

videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o
+ v4l2-event.o v4l2-ctrls.o

# V4L2 core modules

diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 9b97832..120b4ac 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -62,6 +62,7 @@
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>

#include <linux/videodev2.h>
@@ -172,487 +173,17 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
}
EXPORT_SYMBOL(v4l2_ctrl_check);

-/* Returns NULL or a character pointer array containing the menu for
- the given control ID. The pointer array ends with a NULL pointer.
- An empty string signifies a menu entry that is invalid. This allows
- drivers to disable certain options if it is not supported. */
-const char **v4l2_ctrl_get_menu(u32 id)
-{
- static const char *mpeg_audio_sampling_freq[] = {
- "44.1 kHz",
- "48 kHz",
- "32 kHz",
- NULL
- };
- static const char *mpeg_audio_encoding[] = {
- "MPEG-1/2 Layer I",
- "MPEG-1/2 Layer II",
- "MPEG-1/2 Layer III",
- "MPEG-2/4 AAC",
- "AC-3",
- NULL
- };
- static const char *mpeg_audio_l1_bitrate[] = {
- "32 kbps",
- "64 kbps",
- "96 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "288 kbps",
- "320 kbps",
- "352 kbps",
- "384 kbps",
- "416 kbps",
- "448 kbps",
- NULL
- };
- static const char *mpeg_audio_l2_bitrate[] = {
- "32 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- "384 kbps",
- NULL
- };
- static const char *mpeg_audio_l3_bitrate[] = {
- "32 kbps",
- "40 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- NULL
- };
- static const char *mpeg_audio_ac3_bitrate[] = {
- "32 kbps",
- "40 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- "384 kbps",
- "448 kbps",
- "512 kbps",
- "576 kbps",
- "640 kbps",
- NULL
- };
- static const char *mpeg_audio_mode[] = {
- "Stereo",
- "Joint Stereo",
- "Dual",
- "Mono",
- NULL
- };
- static const char *mpeg_audio_mode_extension[] = {
- "Bound 4",
- "Bound 8",
- "Bound 12",
- "Bound 16",
- NULL
- };
- static const char *mpeg_audio_emphasis[] = {
- "No Emphasis",
- "50/15 us",
- "CCITT J17",
- NULL
- };
- static const char *mpeg_audio_crc[] = {
- "No CRC",
- "16-bit CRC",
- NULL
- };
- static const char *mpeg_video_encoding[] = {
- "MPEG-1",
- "MPEG-2",
- "MPEG-4 AVC",
- NULL
- };
- static const char *mpeg_video_aspect[] = {
- "1x1",
- "4x3",
- "16x9",
- "2.21x1",
- NULL
- };
- static const char *mpeg_video_bitrate_mode[] = {
- "Variable Bitrate",
- "Constant Bitrate",
- NULL
- };
- static const char *mpeg_stream_type[] = {
- "MPEG-2 Program Stream",
- "MPEG-2 Transport Stream",
- "MPEG-1 System Stream",
- "MPEG-2 DVD-compatible Stream",
- "MPEG-1 VCD-compatible Stream",
- "MPEG-2 SVCD-compatible Stream",
- NULL
- };
- static const char *mpeg_stream_vbi_fmt[] = {
- "No VBI",
- "Private packet, IVTV format",
- NULL
- };
- static const char *camera_power_line_frequency[] = {
- "Disabled",
- "50 Hz",
- "60 Hz",
- NULL
- };
- static const char *camera_exposure_auto[] = {
- "Auto Mode",
- "Manual Mode",
- "Shutter Priority Mode",
- "Aperture Priority Mode",
- NULL
- };
- static const char *colorfx[] = {
- "None",
- "Black & White",
- "Sepia",
- "Negative",
- "Emboss",
- "Sketch",
- "Sky blue",
- "Grass green",
- "Skin whiten",
- "Vivid",
- NULL
- };
- static const char *tune_preemphasis[] = {
- "No preemphasis",
- "50 useconds",
- "75 useconds",
- NULL,
- };
-
- switch (id) {
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- return mpeg_audio_sampling_freq;
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return mpeg_audio_encoding;
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- return mpeg_audio_l1_bitrate;
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- return mpeg_audio_l2_bitrate;
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- return mpeg_audio_l3_bitrate;
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- return mpeg_audio_ac3_bitrate;
- case V4L2_CID_MPEG_AUDIO_MODE:
- return mpeg_audio_mode;
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- return mpeg_audio_mode_extension;
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- return mpeg_audio_emphasis;
- case V4L2_CID_MPEG_AUDIO_CRC:
- return mpeg_audio_crc;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return mpeg_video_encoding;
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- return mpeg_video_aspect;
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return mpeg_video_bitrate_mode;
- case V4L2_CID_MPEG_STREAM_TYPE:
- return mpeg_stream_type;
- case V4L2_CID_MPEG_STREAM_VBI_FMT:
- return mpeg_stream_vbi_fmt;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- return camera_power_line_frequency;
- case V4L2_CID_EXPOSURE_AUTO:
- return camera_exposure_auto;
- case V4L2_CID_COLORFX:
- return colorfx;
- case V4L2_CID_TUNE_PREEMPHASIS:
- return tune_preemphasis;
- default:
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_menu);
-
-/* Return the control name. */
-const char *v4l2_ctrl_get_name(u32 id)
-{
- switch (id) {
- /* USER controls */
- case V4L2_CID_USER_CLASS: return "User Controls";
- case V4L2_CID_BRIGHTNESS: return "Brightness";
- case V4L2_CID_CONTRAST: return "Contrast";
- case V4L2_CID_SATURATION: return "Saturation";
- case V4L2_CID_HUE: return "Hue";
- case V4L2_CID_AUDIO_VOLUME: return "Volume";
- case V4L2_CID_AUDIO_BALANCE: return "Balance";
- case V4L2_CID_AUDIO_BASS: return "Bass";
- case V4L2_CID_AUDIO_TREBLE: return "Treble";
- case V4L2_CID_AUDIO_MUTE: return "Mute";
- case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
- case V4L2_CID_BLACK_LEVEL: return "Black Level";
- case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
- case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
- case V4L2_CID_RED_BALANCE: return "Red Balance";
- case V4L2_CID_BLUE_BALANCE: return "Blue Balance";
- case V4L2_CID_GAMMA: return "Gamma";
- case V4L2_CID_EXPOSURE: return "Exposure";
- case V4L2_CID_AUTOGAIN: return "Gain, Automatic";
- case V4L2_CID_GAIN: return "Gain";
- case V4L2_CID_HFLIP: return "Horizontal Flip";
- case V4L2_CID_VFLIP: return "Vertical Flip";
- case V4L2_CID_HCENTER: return "Horizontal Center";
- case V4L2_CID_VCENTER: return "Vertical Center";
- case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency";
- case V4L2_CID_HUE_AUTO: return "Hue, Automatic";
- case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
- case V4L2_CID_SHARPNESS: return "Sharpness";
- case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
- case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
- case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
- case V4L2_CID_COLOR_KILLER: return "Color Killer";
- case V4L2_CID_COLORFX: return "Color Effects";
- case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
- case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
- case V4L2_CID_ROTATE: return "Rotate";
- case V4L2_CID_BG_COLOR: return "Background Color";
-
- /* MPEG controls */
- case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
- case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
- case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
- case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
- case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
- case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
- case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
- case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
- case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
- case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
- case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
- case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
- case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
- case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
- case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
- case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
- case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
- case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
- case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
- case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
-
- /* CAMERA controls */
- case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
- case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure";
- case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute";
- case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate";
- case V4L2_CID_PAN_RELATIVE: return "Pan, Relative";
- case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative";
- case V4L2_CID_PAN_RESET: return "Pan, Reset";
- case V4L2_CID_TILT_RESET: return "Tilt, Reset";
- case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute";
- case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute";
- case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
- case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
- case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic";
- case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
- case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
- case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
- case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
- case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
- case V4L2_CID_PRIVACY: return "Privacy";
-
- /* FM Radio Modulator control */
- case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
- case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
- case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
- case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
- case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
- case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
- case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
- case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
- case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
- case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
- case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
- case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
- case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
- case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
-
- default:
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_name);
-
/* Fill in a struct v4l2_queryctrl */
int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
{
- const char *name = v4l2_ctrl_get_name(qctrl->id);
+ const char *name;
+
+ v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
+ &min, &max, &step, &def, &qctrl->flags);

- qctrl->flags = 0;
if (name == NULL)
return -EINVAL;

- switch (qctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_LOUDNESS:
- case V4L2_CID_AUTO_WHITE_BALANCE:
- case V4L2_CID_AUTOGAIN:
- case V4L2_CID_HFLIP:
- case V4L2_CID_VFLIP:
- case V4L2_CID_HUE_AUTO:
- case V4L2_CID_CHROMA_AGC:
- case V4L2_CID_COLOR_KILLER:
- case V4L2_CID_MPEG_AUDIO_MUTE:
- case V4L2_CID_MPEG_VIDEO_MUTE:
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
- case V4L2_CID_FOCUS_AUTO:
- case V4L2_CID_PRIVACY:
- case V4L2_CID_AUDIO_LIMITER_ENABLED:
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
- case V4L2_CID_PILOT_TONE_ENABLED:
- qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
- min = 0;
- max = step = 1;
- break;
- case V4L2_CID_PAN_RESET:
- case V4L2_CID_TILT_RESET:
- qctrl->type = V4L2_CTRL_TYPE_BUTTON;
- qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- min = max = step = def = 0;
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- case V4L2_CID_MPEG_AUDIO_MODE:
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- case V4L2_CID_MPEG_AUDIO_CRC:
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- case V4L2_CID_MPEG_STREAM_TYPE:
- case V4L2_CID_MPEG_STREAM_VBI_FMT:
- case V4L2_CID_EXPOSURE_AUTO:
- case V4L2_CID_COLORFX:
- case V4L2_CID_TUNE_PREEMPHASIS:
- qctrl->type = V4L2_CTRL_TYPE_MENU;
- step = 1;
- break;
- case V4L2_CID_RDS_TX_PS_NAME:
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- qctrl->type = V4L2_CTRL_TYPE_STRING;
- break;
- case V4L2_CID_USER_CLASS:
- case V4L2_CID_CAMERA_CLASS:
- case V4L2_CID_MPEG_CLASS:
- case V4L2_CID_FM_TX_CLASS:
- qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
- qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- min = max = step = def = 0;
- break;
- case V4L2_CID_BG_COLOR:
- qctrl->type = V4L2_CTRL_TYPE_INTEGER;
- step = 1;
- min = 0;
- /* Max is calculated as RGB888 that is 2^24 */
- max = 0xFFFFFF;
- break;
- default:
- qctrl->type = V4L2_CTRL_TYPE_INTEGER;
- break;
- }
- switch (qctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- case V4L2_CID_MPEG_AUDIO_MODE:
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
- case V4L2_CID_MPEG_STREAM_TYPE:
- qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- case V4L2_CID_RED_BALANCE:
- case V4L2_CID_BLUE_BALANCE:
- case V4L2_CID_GAMMA:
- case V4L2_CID_SHARPNESS:
- case V4L2_CID_CHROMA_GAIN:
- case V4L2_CID_RDS_TX_DEVIATION:
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
- case V4L2_CID_AUDIO_LIMITER_DEVIATION:
- case V4L2_CID_AUDIO_COMPRESSION_GAIN:
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
- case V4L2_CID_PILOT_TONE_DEVIATION:
- case V4L2_CID_PILOT_TONE_FREQUENCY:
- case V4L2_CID_TUNE_POWER_LEVEL:
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
- break;
- case V4L2_CID_PAN_RELATIVE:
- case V4L2_CID_TILT_RELATIVE:
- case V4L2_CID_FOCUS_RELATIVE:
- case V4L2_CID_IRIS_RELATIVE:
- case V4L2_CID_ZOOM_RELATIVE:
- qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- break;
- }
qctrl->minimum = min;
qctrl->maximum = max;
qctrl->step = step;
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
new file mode 100644
index 0000000..8489894
--- /dev/null
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -0,0 +1,1847 @@
+/*
+ V4L2 controls framework implementation.
+
+ Copyright (C) 2010 Hans Verkuil <***@xs4all.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/ctype.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+
+/* Internal temporary helper struct, one for each v4l2_ext_control */
+struct ctrl_helper {
+ /* The control corresponding to the v4l2_ext_control ID field. */
+ struct v4l2_ctrl *ctrl;
+ /* Used internally to mark whether this control was already
+ processed. */
+ bool handled;
+};
+
+/* Returns NULL or a character pointer array containing the menu for
+ the given control ID. The pointer array ends with a NULL pointer.
+ An empty string signifies a menu entry that is invalid. This allows
+ drivers to disable certain options if it is not supported. */
+const char **v4l2_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_audio_sampling_freq[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz",
+ NULL
+ };
+ static const char *mpeg_audio_encoding[] = {
+ "MPEG-1/2 Layer I",
+ "MPEG-1/2 Layer II",
+ "MPEG-1/2 Layer III",
+ "MPEG-2/4 AAC",
+ "AC-3",
+ NULL
+ };
+ static const char *mpeg_audio_l1_bitrate[] = {
+ "32 kbps",
+ "64 kbps",
+ "96 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "288 kbps",
+ "320 kbps",
+ "352 kbps",
+ "384 kbps",
+ "416 kbps",
+ "448 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l2_bitrate[] = {
+ "32 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_ac3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ "448 kbps",
+ "512 kbps",
+ "576 kbps",
+ "640 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_mode[] = {
+ "Stereo",
+ "Joint Stereo",
+ "Dual",
+ "Mono",
+ NULL
+ };
+ static const char *mpeg_audio_mode_extension[] = {
+ "Bound 4",
+ "Bound 8",
+ "Bound 12",
+ "Bound 16",
+ NULL
+ };
+ static const char *mpeg_audio_emphasis[] = {
+ "No Emphasis",
+ "50/15 us",
+ "CCITT J17",
+ NULL
+ };
+ static const char *mpeg_audio_crc[] = {
+ "No CRC",
+ "16-bit CRC",
+ NULL
+ };
+ static const char *mpeg_video_encoding[] = {
+ "MPEG-1",
+ "MPEG-2",
+ "MPEG-4 AVC",
+ NULL
+ };
+ static const char *mpeg_video_aspect[] = {
+ "1x1",
+ "4x3",
+ "16x9",
+ "2.21x1",
+ NULL
+ };
+ static const char *mpeg_video_bitrate_mode[] = {
+ "Variable Bitrate",
+ "Constant Bitrate",
+ NULL
+ };
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+ static const char *mpeg_stream_vbi_fmt[] = {
+ "No VBI",
+ "Private packet, IVTV format",
+ NULL
+ };
+ static const char *camera_power_line_frequency[] = {
+ "Disabled",
+ "50 Hz",
+ "60 Hz",
+ NULL
+ };
+ static const char *camera_exposure_auto[] = {
+ "Auto Mode",
+ "Manual Mode",
+ "Shutter Priority Mode",
+ "Aperture Priority Mode",
+ NULL
+ };
+ static const char *colorfx[] = {
+ "None",
+ "Black & White",
+ "Sepia",
+ "Negative",
+ "Emboss",
+ "Sketch",
+ "Sky blue",
+ "Grass green",
+ "Skin whiten",
+ "Vivid",
+ NULL
+ };
+ static const char *tune_preemphasis[] = {
+ "No preemphasis",
+ "50 useconds",
+ "75 useconds",
+ NULL,
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return mpeg_audio_sampling_freq;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return mpeg_audio_encoding;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return mpeg_audio_l1_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return mpeg_audio_l2_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ return mpeg_audio_ac3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return mpeg_audio_mode;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return mpeg_audio_mode_extension;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return mpeg_audio_emphasis;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return mpeg_audio_crc;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return mpeg_video_encoding;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return mpeg_video_aspect;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return mpeg_video_bitrate_mode;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ return mpeg_stream_vbi_fmt;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ return camera_power_line_frequency;
+ case V4L2_CID_EXPOSURE_AUTO:
+ return camera_exposure_auto;
+ case V4L2_CID_COLORFX:
+ return colorfx;
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ return tune_preemphasis;
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
+{
+ switch (id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS: return "User Controls";
+ case V4L2_CID_BRIGHTNESS: return "Brightness";
+ case V4L2_CID_CONTRAST: return "Contrast";
+ case V4L2_CID_SATURATION: return "Saturation";
+ case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_AUDIO_VOLUME: return "Volume";
+ case V4L2_CID_AUDIO_BALANCE: return "Balance";
+ case V4L2_CID_AUDIO_BASS: return "Bass";
+ case V4L2_CID_AUDIO_TREBLE: return "Treble";
+ case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+ case V4L2_CID_BLACK_LEVEL: return "Black Level";
+ case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
+ case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
+ case V4L2_CID_RED_BALANCE: return "Red Balance";
+ case V4L2_CID_BLUE_BALANCE: return "Blue Balance";
+ case V4L2_CID_GAMMA: return "Gamma";
+ case V4L2_CID_EXPOSURE: return "Exposure";
+ case V4L2_CID_AUTOGAIN: return "Gain, Automatic";
+ case V4L2_CID_GAIN: return "Gain";
+ case V4L2_CID_HFLIP: return "Horizontal Flip";
+ case V4L2_CID_VFLIP: return "Vertical Flip";
+ case V4L2_CID_HCENTER: return "Horizontal Center";
+ case V4L2_CID_VCENTER: return "Vertical Center";
+ case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency";
+ case V4L2_CID_HUE_AUTO: return "Hue, Automatic";
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
+ case V4L2_CID_SHARPNESS: return "Sharpness";
+ case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
+ case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
+ case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
+ case V4L2_CID_COLOR_KILLER: return "Color Killer";
+ case V4L2_CID_COLORFX: return "Color Effects";
+ case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
+ case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
+ case V4L2_CID_ROTATE: return "Rotate";
+ case V4L2_CID_BG_COLOR: return "Background Color";
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+ case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
+ case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
+ case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
+ case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
+ case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
+ case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
+ case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+ case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
+ case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
+ case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+ case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
+
+ /* CAMERA controls */
+ case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
+ case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure";
+ case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute";
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate";
+ case V4L2_CID_PAN_RELATIVE: return "Pan, Relative";
+ case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative";
+ case V4L2_CID_PAN_RESET: return "Pan, Reset";
+ case V4L2_CID_TILT_RESET: return "Tilt, Reset";
+ case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute";
+ case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute";
+ case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
+ case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
+ case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic";
+ case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
+ case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
+ case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
+ case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
+ case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
+ case V4L2_CID_PRIVACY: return "Privacy";
+
+ /* FM Radio Modulator control */
+ case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
+ case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
+ case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
+ case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
+ case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
+ case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
+ case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+ case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
+ case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
+ case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
+ case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
+ case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
+
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
+void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+ s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags)
+{
+ *name = v4l2_ctrl_get_name(id);
+ *flags = 0;
+
+ switch (id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HUE_AUTO:
+ case V4L2_CID_CHROMA_AGC:
+ case V4L2_CID_COLOR_KILLER:
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+ case V4L2_CID_FOCUS_AUTO:
+ case V4L2_CID_PRIVACY:
+ case V4L2_CID_AUDIO_LIMITER_ENABLED:
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+ case V4L2_CID_PILOT_TONE_ENABLED:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
+ case V4L2_CID_PAN_RESET:
+ case V4L2_CID_TILT_RESET:
+ *type = V4L2_CTRL_TYPE_BUTTON;
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ *min = *max = *step = *def = 0;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ case V4L2_CID_EXPOSURE_AUTO:
+ case V4L2_CID_COLORFX:
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ *type = V4L2_CTRL_TYPE_MENU;
+ break;
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ *type = V4L2_CTRL_TYPE_STRING;
+ break;
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_CAMERA_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ case V4L2_CID_FM_TX_CLASS:
+ *type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ /* You can neither read not write these */
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
+ *min = *max = *step = *def = 0;
+ break;
+ case V4L2_CID_BG_COLOR:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *step = 1;
+ *min = 0;
+ /* Max is calculated as RGB888 that is 2^24 */
+ *max = 0xFFFFFF;
+ break;
+ default:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ *flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ case V4L2_CID_GAMMA:
+ case V4L2_CID_SHARPNESS:
+ case V4L2_CID_CHROMA_GAIN:
+ case V4L2_CID_RDS_TX_DEVIATION:
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ case V4L2_CID_PILOT_TONE_FREQUENCY:
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ *flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ case V4L2_CID_PAN_RELATIVE:
+ case V4L2_CID_TILT_RELATIVE:
+ case V4L2_CID_FOCUS_RELATIVE:
+ case V4L2_CID_IRIS_RELATIVE:
+ case V4L2_CID_ZOOM_RELATIVE:
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ break;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_fill);
+
+/* Helper function to determine whether the control type is compatible with
+ VIDIOC_G/S_CTRL. */
+static bool type_is_int(const struct v4l2_ctrl *ctrl)
+{
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ case V4L2_CTRL_TYPE_STRING:
+ /* Nope, these need v4l2_ext_control */
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* Helper function: copy the current control value back to the caller */
+static int cur_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ u32 len;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(ctrl->cur.string);
+ if (c->size < len + 1) {
+ c->size = len + 1;
+ return -ENOSPC;
+ }
+ return copy_to_user(c->string, ctrl->cur.string,
+ len + 1) ? -EFAULT : 0;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ c->value64 = ctrl->cur.val64;
+ break;
+ default:
+ c->value = ctrl->cur.val;
+ break;
+ }
+ return 0;
+}
+
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ int ret;
+ u32 size;
+
+ ctrl->has_new = 1;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ctrl->val64 = c->value64;
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ size = c->size;
+ if (size == 0)
+ return -ERANGE;
+ if (size > ctrl->maximum + 1)
+ size = ctrl->maximum + 1;
+ ret = copy_from_user(ctrl->string, c->string, size);
+ if (!ret) {
+ char last = ctrl->string[size - 1];
+
+ ctrl->string[size - 1] = 0;
+ /* If the string was longer than ctrl->maximum,
+ then return an error. */
+ if (strlen(ctrl->string) == ctrl->maximum && last)
+ return -ERANGE;
+ }
+ return ret ? -EFAULT : 0;
+ default:
+ ctrl->val = c->value;
+ break;
+ }
+ return 0;
+}
+
+/* Helper function: copy the new control value back to the caller */
+static int new_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ u32 len;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(ctrl->string);
+ if (c->size < len + 1) {
+ c->size = ctrl->maximum + 1;
+ return -ENOSPC;
+ }
+ return copy_to_user(c->string, ctrl->string,
+ len + 1) ? -EFAULT : 0;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ c->value64 = ctrl->val64;
+ break;
+ default:
+ c->value = ctrl->val;
+ break;
+ }
+ return 0;
+}
+
+/* Copy the new value to the current value. */
+static void new_to_cur(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl == NULL)
+ return;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ /* strings are always 0-terminated */
+ strcpy(ctrl->cur.string, ctrl->string);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ctrl->cur.val64 = ctrl->val64;
+ break;
+ default:
+ ctrl->cur.val = ctrl->val;
+ break;
+ }
+}
+
+/* Copy the current value to the new value */
+static void cur_to_new(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl == NULL)
+ return;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ /* strings are always 0-terminated */
+ strcpy(ctrl->string, ctrl->cur.string);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ctrl->val64 = ctrl->cur.val64;
+ break;
+ default:
+ ctrl->val = ctrl->cur.val;
+ break;
+ }
+}
+
+/* Return non-zero if one or more of the controls in the cluster has a new
+ value that differs from the current value. */
+static int cluster_changed(struct v4l2_ctrl *master)
+{
+ int diff = 0;
+ int i;
+
+ for (i = 0; !diff && i < master->ncontrols; i++) {
+ struct v4l2_ctrl *ctrl = master->cluster[i];
+
+ if (ctrl == NULL)
+ continue;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_BUTTON:
+ /* Button controls are always 'different' */
+ return 1;
+ case V4L2_CTRL_TYPE_STRING:
+ /* strings are always 0-terminated */
+ diff = strcmp(ctrl->string, ctrl->cur.string);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ diff = ctrl->val64 != ctrl->cur.val64;
+ break;
+ default:
+ diff = ctrl->val != ctrl->cur.val;
+ break;
+ }
+ }
+ return diff;
+}
+
+/* Validate a new control */
+static int validate_new(struct v4l2_ctrl *ctrl)
+{
+ s32 val = ctrl->val;
+ char *s = ctrl->string;
+ u32 offset;
+ size_t len;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ /* Round towards the closest legal value */
+ val += ctrl->step / 2;
+ if (val < ctrl->minimum)
+ val = ctrl->minimum;
+ if (val > ctrl->maximum)
+ val = ctrl->maximum;
+ offset = val - ctrl->minimum;
+ offset = ctrl->step * (offset / ctrl->step);
+ val = ctrl->minimum + offset;
+ ctrl->val = val;
+ return 0;
+
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ ctrl->val = !!ctrl->val;
+ return 0;
+
+ case V4L2_CTRL_TYPE_MENU:
+ if (val < ctrl->minimum || val > ctrl->maximum)
+ return -ERANGE;
+ if (ctrl->qmenu[val][0] == '\0' ||
+ (ctrl->menu_skip_mask & (1 << val)))
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CTRL_TYPE_BUTTON:
+ case V4L2_CTRL_TYPE_CTRL_CLASS:
+ ctrl->val64 = 0;
+ return 0;
+
+ case V4L2_CTRL_TYPE_INTEGER64:
+ return 0;
+
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(s);
+ if (len < ctrl->minimum)
+ return -ERANGE;
+ if ((len - ctrl->minimum) % ctrl->step)
+ return -ERANGE;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static inline u32 node2id(struct list_head *node)
+{
+ return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
+}
+
+/* Set the handler's error code if it wasn't set earlier already */
+static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
+{
+ if (hdl->error == 0)
+ hdl->error = err;
+ return err;
+}
+
+/* Initialize the handler */
+int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint)
+{
+ mutex_init(&hdl->lock);
+ INIT_LIST_HEAD(&hdl->ctrls);
+ INIT_LIST_HEAD(&hdl->ctrl_refs);
+ hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
+ hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets,
+ GFP_KERNEL);
+ hdl->error = hdl->buckets ? 0 : -ENOMEM;
+ return hdl->error;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_init);
+
+/* Free all controls and control refs */
+void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl_ref *ref, *next_ref;
+ struct v4l2_ctrl *ctrl, *next_ctrl;
+
+ if (hdl == NULL || hdl->buckets == NULL)
+ return;
+
+ mutex_lock(&hdl->lock);
+ /* Free all nodes */
+ list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
+ list_del(&ref->node);
+ kfree(ref);
+ }
+ /* Free all controls owned by the handler */
+ list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
+ list_del(&ctrl->node);
+ kfree(ctrl);
+ }
+ kfree(hdl->buckets);
+ hdl->buckets = NULL;
+ hdl->cached = NULL;
+ hdl->error = 0;
+ mutex_unlock(&hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_free);
+
+/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
+ be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
+ with applications that do not use the NEXT_CTRL flag.
+
+ We just find the n-th private user control. It's O(N), but that should not
+ be an issue in this particular case. */
+static struct v4l2_ctrl_ref *find_private_ref(
+ struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref;
+
+ id -= V4L2_CID_PRIVATE_BASE;
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ /* Search for private user controls that are compatible with
+ VIDIOC_G/S_CTRL. */
+ if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
+ V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
+ if (!type_is_int(ref->ctrl))
+ continue;
+ if (id == 0)
+ return ref;
+ id--;
+ }
+ }
+ return NULL;
+}
+
+/* Find a control with the given ID. */
+static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref;
+ int bucket;
+
+ id &= V4L2_CTRL_ID_MASK;
+
+ /* Old-style private controls need special handling */
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ return find_private_ref(hdl, id);
+ bucket = id % hdl->nr_of_buckets;
+
+ /* Simple optimization: cache the last control found */
+ if (hdl->cached && hdl->cached->ctrl->id == id)
+ return hdl->cached;
+
+ /* Not in cache, search the hash */
+ ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
+ while (ref && ref->ctrl->id != id)
+ ref = ref->next;
+
+ if (ref)
+ hdl->cached = ref; /* cache it! */
+ return ref;
+}
+
+/* Find a control with the given ID. Take the handler's lock first. */
+static struct v4l2_ctrl_ref *find_ref_lock(
+ struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = NULL;
+
+ if (hdl) {
+ mutex_lock(&hdl->lock);
+ ref = find_ref(hdl, id);
+ mutex_unlock(&hdl->lock);
+ }
+ return ref;
+}
+
+/* Find a control with the given ID. */
+struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
+
+ return ref ? ref->ctrl : NULL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_find);
+
+/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
+static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl_ref *new_ref;
+ u32 id = ctrl->id;
+ u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1;
+ int bucket = id % hdl->nr_of_buckets; /* which bucket to use */
+
+ /* Automatically add the control class if it is not yet present. */
+ if (id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
+ if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
+ return hdl->error;
+
+ if (hdl->error)
+ return hdl->error;
+
+ new_ref = kzalloc(sizeof(*new_ref), GFP_KERNEL);
+ if (!new_ref)
+ return handler_set_err(hdl, -ENOMEM);
+ new_ref->ctrl = ctrl;
+ if (ctrl->handler == hdl) {
+ /* By default each control starts in a cluster of its own.
+ new_ref->ctrl is basically a cluster array with one
+ element, so that's perfect to use as the cluster pointer.
+ But only do this for the handler that owns the control. */
+ ctrl->cluster = &new_ref->ctrl;
+ ctrl->ncontrols = 1;
+ }
+
+ INIT_LIST_HEAD(&new_ref->node);
+
+ mutex_lock(&hdl->lock);
+
+ /* Add immediately at the end of the list if the list is empty, or if
+ the last element in the list has a lower ID.
+ This ensures that when elements are added in ascending order the
+ insertion is an O(1) operation. */
+ if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
+ list_add_tail(&new_ref->node, &hdl->ctrl_refs);
+ goto insert_in_hash;
+ }
+
+ /* Find insert position in sorted list */
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ if (ref->ctrl->id < id)
+ continue;
+ /* Don't add duplicates */
+ if (ref->ctrl->id == id) {
+ kfree(new_ref);
+ goto unlock;
+ }
+ list_add(&new_ref->node, ref->node.prev);
+ break;
+ }
+
+insert_in_hash:
+ /* Insert the control node in the hash */
+ new_ref->next = hdl->buckets[bucket];
+ hdl->buckets[bucket] = new_ref;
+
+unlock:
+ mutex_unlock(&hdl->lock);
+ return 0;
+}
+
+/* Add a new control */
+static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, const char *name, enum v4l2_ctrl_type type,
+ s32 min, s32 max, u32 step, s32 def,
+ u32 flags, const char **qmenu, void *priv)
+{
+ struct v4l2_ctrl *ctrl;
+ unsigned sz_extra = 0;
+
+ if (hdl->error)
+ return NULL;
+
+ /* Sanity checks */
+ if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
+ def < min || def > max || max < min ||
+ (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
+ (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+ (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
+ handler_set_err(hdl, -ERANGE);
+ return NULL;
+ }
+
+ if (type == V4L2_CTRL_TYPE_BUTTON)
+ flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ else if (type == V4L2_CTRL_TYPE_STRING)
+ sz_extra += 2 * (max + 1);
+
+ ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
+ if (ctrl == NULL) {
+ handler_set_err(hdl, -ENOMEM);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&ctrl->node);
+ ctrl->handler = hdl;
+ ctrl->ops = ops;
+ ctrl->id = id;
+ ctrl->name = name;
+ ctrl->type = type;
+ ctrl->flags = flags;
+ ctrl->minimum = min;
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->qmenu = qmenu;
+ ctrl->priv = priv;
+ ctrl->cur.val = ctrl->val = ctrl->default_value = def;
+
+ if (ctrl->type == V4L2_CTRL_TYPE_STRING) {
+ ctrl->cur.string = (char *)&ctrl[1] + sz_extra - (max + 1);
+ ctrl->string = (char *)&ctrl[1] + sz_extra - 2 * (max + 1);
+ if (ctrl->minimum)
+ memset(ctrl->cur.string, ' ', ctrl->minimum);
+ }
+ if (handler_new_ref(hdl, ctrl)) {
+ kfree(ctrl);
+ return NULL;
+ }
+ mutex_lock(&hdl->lock);
+ list_add_tail(&ctrl->node, &hdl->ctrls);
+ mutex_unlock(&hdl->lock);
+ return ctrl;
+}
+
+struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_config *cfg, void *priv)
+{
+ bool is_menu;
+ struct v4l2_ctrl *ctrl;
+ const char *name = cfg->name;
+ const char **qmenu = cfg->qmenu;
+ enum v4l2_ctrl_type type = cfg->type;
+ u32 flags = cfg->flags;
+ s32 min = cfg->min;
+ s32 max = cfg->max;
+ u32 step = cfg->step;
+ s32 def = cfg->def;
+
+ if (name == NULL)
+ v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
+ &def, &flags);
+
+ is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU);
+ if (is_menu)
+ WARN_ON(step);
+ else
+ WARN_ON(cfg->menu_skip_mask);
+ if (is_menu && qmenu == NULL)
+ qmenu = v4l2_ctrl_get_menu(cfg->id);
+
+ ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
+ type, min, max,
+ is_menu ? cfg->menu_skip_mask : step,
+ def, flags, qmenu, priv);
+ if (ctrl) {
+ ctrl->is_private = cfg->is_private;
+ ctrl->is_volatile = cfg->is_volatile;
+ }
+ return ctrl;
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_custom);
+
+/* Helper function for standard non-menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 min, s32 max, u32 step, s32 def)
+{
+ const char *name;
+ enum v4l2_ctrl_type type;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type == V4L2_CTRL_TYPE_MENU) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, id, name, type,
+ min, max, step, def, flags, NULL, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std);
+
+/* Helper function for standard menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 mask, s32 def)
+{
+ const char **qmenu = v4l2_ctrl_get_menu(id);
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s32 min;
+ s32 step;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type != V4L2_CTRL_TYPE_MENU) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, id, name, type,
+ 0, max, mask, def, flags, qmenu, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
+
+/* Add a control from another handler to this handler */
+struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl)
+{
+ if (hdl == NULL || hdl->error)
+ return NULL;
+ if (ctrl == NULL) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ if (ctrl->handler == hdl)
+ return ctrl;
+ return handler_new_ref(hdl, ctrl) ? NULL : ctrl;
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_ctrl);
+
+/* Add the controls from another handler to our own. */
+int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl_handler *add)
+{
+ struct v4l2_ctrl *ctrl;
+ int ret = 0;
+
+ /* Do nothing if either handler is NULL or if they are the same */
+ if (!hdl || !add || hdl == add)
+ return 0;
+ if (hdl->error)
+ return hdl->error;
+ mutex_lock(&add->lock);
+ list_for_each_entry(ctrl, &add->ctrls, node) {
+ /* Skip handler-private controls. */
+ if (ctrl->is_private)
+ continue;
+ ret = handler_new_ref(hdl, ctrl);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&add->lock);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_handler);
+
+/* Cluster controls */
+void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
+{
+ int i;
+
+ /* The first control is the master control and it must not be NULL */
+ BUG_ON(controls[0] == NULL);
+
+ for (i = 0; i < ncontrols; i++) {
+ if (controls[i]) {
+ controls[i]->cluster = controls;
+ controls[i]->ncontrols = ncontrols;
+ }
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_cluster);
+
+/* Activate/deactivate a control. */
+void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
+{
+ if (ctrl == NULL)
+ return;
+
+ if (!active)
+ /* set V4L2_CTRL_FLAG_INACTIVE */
+ set_bit(4, &ctrl->flags);
+ else
+ /* clear V4L2_CTRL_FLAG_INACTIVE */
+ clear_bit(4, &ctrl->flags);
+}
+EXPORT_SYMBOL(v4l2_ctrl_activate);
+
+/* Grab/ungrab a control.
+ Typically used when streaming starts and you want to grab controls,
+ preventing the user from changing them.
+
+ Just call this and the framework will block any attempts to change
+ these controls. */
+void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
+{
+ if (ctrl == NULL)
+ return;
+
+ if (grabbed)
+ /* set V4L2_CTRL_FLAG_GRABBED */
+ set_bit(1, &ctrl->flags);
+ else
+ /* clear V4L2_CTRL_FLAG_GRABBED */
+ clear_bit(1, &ctrl->flags);
+}
+EXPORT_SYMBOL(v4l2_ctrl_grab);
+
+/* Log the control name and value */
+static void log_ctrl(const struct v4l2_ctrl *ctrl,
+ const char *prefix, const char *colon)
+{
+ int fl_inact = ctrl->flags & V4L2_CTRL_FLAG_INACTIVE;
+ int fl_grabbed = ctrl->flags & V4L2_CTRL_FLAG_GRABBED;
+
+ if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
+ return;
+ if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return;
+
+ printk(KERN_INFO "%s%s%s: ", prefix, colon, ctrl->name);
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ printk(KERN_CONT "%d", ctrl->cur.val);
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ printk(KERN_CONT "%s", ctrl->cur.val ? "true" : "false");
+ break;
+ case V4L2_CTRL_TYPE_MENU:
+ printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ printk(KERN_CONT "%lld", ctrl->cur.val64);
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ printk(KERN_CONT "%s", ctrl->cur.string);
+ break;
+ default:
+ printk(KERN_CONT "unknown type %d", ctrl->type);
+ break;
+ }
+ if (fl_inact && fl_grabbed)
+ printk(KERN_CONT " (inactive, grabbed)\n");
+ else if (fl_inact)
+ printk(KERN_CONT " (inactive)\n");
+ else if (fl_grabbed)
+ printk(KERN_CONT " (grabbed)\n");
+ else
+ printk(KERN_CONT "\n");
+}
+
+/* Log all controls owned by the handler */
+void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
+ const char *prefix)
+{
+ struct v4l2_ctrl *ctrl;
+ const char *colon = "";
+ int len;
+
+ if (hdl == NULL)
+ return;
+ if (prefix == NULL)
+ prefix = "";
+ len = strlen(prefix);
+ if (len && prefix[len - 1] != ' ')
+ colon = ": ";
+ mutex_lock(&hdl->lock);
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
+ log_ctrl(ctrl, prefix, colon);
+ mutex_unlock(&hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
+
+/* Call s_ctrl for all controls owned by the handler */
+int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl *ctrl;
+ int ret = 0;
+
+ if (hdl == NULL)
+ return 0;
+ mutex_lock(&hdl->lock);
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ ctrl->done = false;
+
+ list_for_each_entry(ctrl, &hdl->ctrls, node) {
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int i;
+
+ /* Skip if this control was already handled by a cluster. */
+ if (ctrl->done)
+ continue;
+
+ for (i = 0; i < master->ncontrols; i++)
+ cur_to_new(master->cluster[i]);
+
+ /* Skip button controls and read-only controls. */
+ if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+ continue;
+ ret = master->ops->s_ctrl(master);
+ if (ret)
+ break;
+ for (i = 0; i < master->ncontrols; i++)
+ if (master->cluster[i])
+ master->cluster[i]->done = true;
+ }
+ mutex_unlock(&hdl->lock);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
+
+/* Implement VIDIOC_QUERYCTRL */
+int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+{
+ u32 id = qc->id & V4L2_CTRL_ID_MASK;
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl *ctrl;
+
+ if (hdl == NULL)
+ return -EINVAL;
+
+ mutex_lock(&hdl->lock);
+
+ /* Try to find it */
+ ref = find_ref(hdl, id);
+
+ if ((qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) && !list_empty(&hdl->ctrl_refs)) {
+ /* Find the next control with ID > qc->id */
+
+ /* Did we reach the end of the control list? */
+ if (id >= node2id(hdl->ctrl_refs.prev)) {
+ ref = NULL; /* Yes, so there is no next control */
+ } else if (ref) {
+ /* We found a control with the given ID, so just get
+ the next one in the list. */
+ ref = list_entry(ref->node.next, typeof(*ref), node);
+ } else {
+ /* No control with the given ID exists, so start
+ searching for the next largest ID. We know there
+ is one, otherwise the first 'if' above would have
+ been true. */
+ list_for_each_entry(ref, &hdl->ctrl_refs, node)
+ if (id < ref->ctrl->id)
+ break;
+ }
+ }
+ mutex_unlock(&hdl->lock);
+ if (!ref)
+ return -EINVAL;
+
+ ctrl = ref->ctrl;
+ memset(qc, 0, sizeof(*qc));
+ qc->id = ctrl->id;
+ strlcpy(qc->name, ctrl->name, sizeof(qc->name));
+ qc->minimum = ctrl->minimum;
+ qc->maximum = ctrl->maximum;
+ qc->default_value = ctrl->default_value;
+ if (qc->type == V4L2_CTRL_TYPE_MENU)
+ qc->step = 1;
+ else
+ qc->step = ctrl->step;
+ qc->flags = ctrl->flags;
+ qc->type = ctrl->type;
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_queryctrl);
+
+int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ return v4l2_queryctrl(sd->ctrl_handler, qc);
+}
+EXPORT_SYMBOL(v4l2_subdev_queryctrl);
+
+/* Implement VIDIOC_QUERYMENU */
+int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
+{
+ struct v4l2_ctrl *ctrl;
+ u32 i = qm->index;
+
+ ctrl = v4l2_ctrl_find(hdl, qm->id);
+ if (!ctrl)
+ return -EINVAL;
+
+ qm->reserved = 0;
+ /* Sanity checks */
+ if (ctrl->qmenu == NULL ||
+ i < ctrl->minimum || i > ctrl->maximum)
+ return -EINVAL;
+ /* Use mask to see if this menu item should be skipped */
+ if (ctrl->menu_skip_mask & (1 << i))
+ return -EINVAL;
+ /* Empty menu items should also be skipped */
+ if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
+ return -EINVAL;
+ strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_querymenu);
+
+int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm)
+{
+ return v4l2_querymenu(sd->ctrl_handler, qm);
+}
+EXPORT_SYMBOL(v4l2_subdev_querymenu);
+
+
+
+/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
+
+ It is not a fully atomic operation, just best-effort only. After all, if
+ multiple controls have to be set through multiple i2c writes (for example)
+ then some initial writes may succeed while others fail. Thus leaving the
+ system in an inconsistent state. The question is how much effort you are
+ willing to spend on trying to make something atomic that really isn't.
+
+ From the point of view of an application the main requirement is that
+ when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
+ error should be returned without actually affecting any controls.
+
+ If all the values are correct, then it is acceptable to just give up
+ in case of low-level errors.
+
+ It is important though that the application can tell when only a partial
+ configuration was done. The way we do that is through the error_idx field
+ of struct v4l2_ext_controls: if that is equal to the count field then no
+ controls were affected. Otherwise all controls before that index were
+ successful in performing their 'get' or 'set' operation, the control at
+ the given index failed, and you don't know what happened with the controls
+ after the failed one. Since if they were part of a control cluster they
+ could have been successfully processed (if a cluster member was encountered
+ at index < error_idx), they could have failed (if a cluster member was at
+ error_idx), or they may not have been processed yet (if the first cluster
+ member appeared after error_idx).
+
+ It is all fairly theoretical, though. In practice all you can do is to
+ bail out. If error_idx == count, then it is an application bug. If
+ error_idx < count then it is only an application bug if the error code was
+ EBUSY. That usually means that something started streaming just when you
+ tried to set the controls. In all other cases it is a driver/hardware
+ problem and all you can do is to retry or bail out.
+
+ Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
+ never modifies controls the error_idx is just set to whatever control
+ has an invalid value.
+ */
+
+/* Prepare for the extended g/s/try functions.
+ Find the controls in the control array and do some basic checks. */
+static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers,
+ bool try)
+{
+ u32 i;
+
+ for (i = 0; i < cs->count; i++) {
+ struct v4l2_ext_control *c = &cs->controls[i];
+ struct v4l2_ctrl *ctrl;
+ u32 id = c->id & V4L2_CTRL_ID_MASK;
+
+ if (try)
+ cs->error_idx = i;
+
+ if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
+ return -EINVAL;
+
+ /* Old-style private controls are not allowed for
+ extended controls */
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ return -EINVAL;
+ ctrl = v4l2_ctrl_find(hdl, id);
+ if (ctrl == NULL)
+ return -EINVAL;
+ if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+
+ helpers[i].ctrl = ctrl;
+ helpers[i].handled = false;
+ }
+ return 0;
+}
+
+typedef int (*cluster_func)(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl);
+
+/* Walk over all controls in v4l2_ext_controls belonging to the same cluster
+ and call the provided function. */
+static int cluster_walk(unsigned from,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers,
+ cluster_func f)
+{
+ struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
+ int ret = 0;
+ int i;
+
+ /* Find any controls from the same cluster and call the function */
+ for (i = from; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+
+ if (!helpers[i].handled && ctrl->cluster == cluster)
+ ret = f(&cs->controls[i], ctrl);
+ }
+ return ret;
+}
+
+static void cluster_done(unsigned from,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers)
+{
+ struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
+ int i;
+
+ /* Find any controls from the same cluster and mark them as handled */
+ for (i = from; i < cs->count; i++)
+ if (helpers[i].ctrl->cluster == cluster)
+ helpers[i].handled = true;
+}
+
+/* Handles the corner case where cs->count == 0. It checks whether the
+ specified control class exists. If that class ID is 0, then it checks
+ whether there are any controls at all. */
+static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class)
+{
+ if (ctrl_class == 0)
+ return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0;
+ return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL;
+}
+
+
+
+/* Get extended controls. Allocates the helpers array if needed. */
+int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+{
+ struct ctrl_helper helper[4];
+ struct ctrl_helper *helpers = helper;
+ int ret;
+ int i;
+
+ cs->error_idx = cs->count;
+ cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+
+ if (hdl == NULL)
+ return -EINVAL;
+
+ if (cs->count == 0)
+ return class_check(hdl, cs->ctrl_class);
+
+ if (cs->count > ARRAY_SIZE(helper)) {
+ helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+ if (helpers == NULL)
+ return -ENOMEM;
+ }
+
+ ret = prepare_ext_ctrls(hdl, cs, helpers, false);
+
+ for (i = 0; !ret && i < cs->count; i++)
+ if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ ret = -EACCES;
+
+ for (i = 0; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+
+ if (helpers[i].handled)
+ continue;
+
+ cs->error_idx = i;
+
+ v4l2_ctrl_lock(master);
+ /* g_volatile_ctrl will update the current control values */
+ if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
+ ret = master->ops->g_volatile_ctrl(master);
+ /* If OK, then copy the current control values to the caller */
+ if (!ret)
+ ret = cluster_walk(i, cs, helpers, cur_to_user);
+ v4l2_ctrl_unlock(master);
+ cluster_done(i, cs, helpers);
+ }
+
+ if (cs->count > ARRAY_SIZE(helper))
+ kfree(helpers);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_g_ext_ctrls);
+
+int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
+{
+ return v4l2_g_ext_ctrls(sd->ctrl_handler, cs);
+}
+EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls);
+
+/* Helper function to get a single control */
+static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+{
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret = 0;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ return -EACCES;
+
+ v4l2_ctrl_lock(master);
+ /* g_volatile_ctrl will update the current control values */
+ if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
+ ret = master->ops->g_volatile_ctrl(master);
+ *val = ctrl->cur.val;
+ v4l2_ctrl_unlock(master);
+ return ret;
+}
+
+int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+
+ if (ctrl == NULL || !type_is_int(ctrl))
+ return -EINVAL;
+ return get_ctrl(ctrl, &control->value);
+}
+EXPORT_SYMBOL(v4l2_g_ctrl);
+
+int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control)
+{
+ return v4l2_g_ctrl(sd->ctrl_handler, control);
+}
+EXPORT_SYMBOL(v4l2_subdev_g_ctrl);
+
+s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+ s32 val = 0;
+
+ /* It's a driver bug if this happens. */
+ WARN_ON(!type_is_int(ctrl));
+ get_ctrl(ctrl, &val);
+ return val;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
+
+
+/* Core function that calls try/s_ctrl and ensures that the new value is
+ copied to the current value on a set.
+ Must be called with ctrl->handler->lock held. */
+static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
+{
+ bool try = !set;
+ int ret = 0;
+ int i;
+
+ /* Go through the cluster and either validate the new value or
+ (if no new value was set), copy the current value to the new
+ value, ensuring a consistent view for the control ops when
+ called. */
+ for (i = 0; !ret && i < master->ncontrols; i++) {
+ struct v4l2_ctrl *ctrl = master->cluster[i];
+
+ if (ctrl == NULL)
+ continue;
+
+ if (ctrl->has_new) {
+ /* Double check this: it may have changed since the
+ last check in try_or_set_ext_ctrls(). */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+ return -EBUSY;
+
+ /* Validate if required */
+ if (!set)
+ ret = validate_new(ctrl);
+ continue;
+ }
+ /* No new value was set, so copy the current and force
+ a call to try_ctrl later, since the values for the cluster
+ may now have changed and the end result might be invalid. */
+ try = true;
+ cur_to_new(ctrl);
+ }
+
+ /* For larger clusters you have to call try_ctrl again to
+ verify that the controls are still valid after the
+ 'cur_to_new' above. */
+ if (!ret && master->ops->try_ctrl && try)
+ ret = master->ops->try_ctrl(master);
+
+ /* Don't set if there is no change */
+ if (!ret && set && cluster_changed(master)) {
+ ret = master->ops->s_ctrl(master);
+ /* If OK, then make the new values permanent. */
+ if (!ret)
+ for (i = 0; i < master->ncontrols; i++)
+ new_to_cur(master->cluster[i]);
+ }
+ return ret;
+}
+
+/* Try or set controls. */
+static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers,
+ bool set)
+{
+ unsigned i, j;
+ int ret = 0;
+
+ cs->error_idx = cs->count;
+ for (i = 0; i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+
+ if (!set)
+ cs->error_idx = i;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return -EACCES;
+ /* This test is also done in try_set_control_cluster() which
+ is called in atomic context, so that has the final say,
+ but it makes sense to do an up-front check as well. Once
+ an error occurs in try_set_control_cluster() some other
+ controls may have been set already and we want to do a
+ best-effort to avoid that. */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+ return -EBUSY;
+ }
+
+ for (i = 0; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+
+ cs->error_idx = i;
+
+ if (helpers[i].handled)
+ continue;
+
+ v4l2_ctrl_lock(ctrl);
+
+ /* Reset the 'has_new' flags of the cluster */
+ for (j = 0; j < master->ncontrols; j++)
+ if (master->cluster[j])
+ master->cluster[j]->has_new = 0;
+
+ /* Copy the new caller-supplied control values.
+ user_to_new() sets 'has_new' to 1. */
+ ret = cluster_walk(i, cs, helpers, user_to_new);
+
+ if (!ret)
+ ret = try_or_set_control_cluster(master, set);
+
+ /* Copy the new values back to userspace. */
+ if (!ret)
+ ret = cluster_walk(i, cs, helpers, new_to_user);
+
+ v4l2_ctrl_unlock(ctrl);
+ cluster_done(i, cs, helpers);
+ }
+ return ret;
+}
+
+/* Try or try-and-set controls */
+static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ bool set)
+{
+ struct ctrl_helper helper[4];
+ struct ctrl_helper *helpers = helper;
+ int ret;
+ int i;
+
+ cs->error_idx = cs->count;
+ cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+
+ if (hdl == NULL)
+ return -EINVAL;
+
+ if (cs->count == 0)
+ return class_check(hdl, cs->ctrl_class);
+
+ if (cs->count > ARRAY_SIZE(helper)) {
+ helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+ if (!helpers)
+ return -ENOMEM;
+ }
+ ret = prepare_ext_ctrls(hdl, cs, helpers, !set);
+ if (ret)
+ goto free;
+
+ /* First 'try' all controls and abort on error */
+ ret = try_or_set_ext_ctrls(hdl, cs, helpers, false);
+ /* If this is a 'set' operation and the initial 'try' failed,
+ then set error_idx to count to tell the application that no
+ controls changed value yet. */
+ if (set)
+ cs->error_idx = cs->count;
+ if (!ret && set) {
+ /* Reset 'handled' state */
+ for (i = 0; i < cs->count; i++)
+ helpers[i].handled = false;
+ ret = try_or_set_ext_ctrls(hdl, cs, helpers, true);
+ }
+
+free:
+ if (cs->count > ARRAY_SIZE(helper))
+ kfree(helpers);
+ return ret;
+}
+
+int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(hdl, cs, false);
+}
+EXPORT_SYMBOL(v4l2_try_ext_ctrls);
+
+int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(hdl, cs, true);
+}
+EXPORT_SYMBOL(v4l2_s_ext_ctrls);
+
+int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(sd->ctrl_handler, cs, false);
+}
+EXPORT_SYMBOL(v4l2_subdev_try_ext_ctrls);
+
+int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(sd->ctrl_handler, cs, true);
+}
+EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
+
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+{
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret;
+ int i;
+
+ v4l2_ctrl_lock(ctrl);
+
+ /* Reset the 'has_new' flags of the cluster */
+ for (i = 0; i < master->ncontrols; i++)
+ if (master->cluster[i])
+ master->cluster[i]->has_new = 0;
+
+ ctrl->val = *val;
+ ctrl->has_new = 1;
+ ret = try_or_set_control_cluster(master, false);
+ if (!ret)
+ ret = try_or_set_control_cluster(master, true);
+ *val = ctrl->cur.val;
+ v4l2_ctrl_unlock(ctrl);
+ return ret;
+}
+
+int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+
+ if (ctrl == NULL || !type_is_int(ctrl))
+ return -EINVAL;
+
+ return set_ctrl(ctrl, &control->value);
+}
+EXPORT_SYMBOL(v4l2_s_ctrl);
+
+int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control)
+{
+ return v4l2_s_ctrl(sd->ctrl_handler, control);
+}
+EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
+
+int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
+{
+ /* It's a driver bug if this happens. */
+ WARN_ON(!type_is_int(ctrl));
+ return set_ctrl(ctrl, &val);
+}
+EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
new file mode 100644
index 0000000..9b7bea9
--- /dev/null
+++ b/include/media/v4l2-ctrls.h
@@ -0,0 +1,460 @@
+/*
+ V4L2 controls support header.
+
+ Copyright (C) 2010 Hans Verkuil <***@xs4all.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _V4L2_CTRLS_H
+#define _V4L2_CTRLS_H
+
+#include <linux/list.h>
+#include <linux/device.h>
+
+/* forward references */
+struct v4l2_ctrl_handler;
+struct v4l2_ctrl;
+struct video_device;
+struct v4l2_subdev;
+
+/** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
+ * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
+ * for volatile (and usually read-only) controls such as a control
+ * that returns the current signal strength which changes
+ * continuously.
+ * If not set, then the currently cached value will be returned.
+ * @try_ctrl: Test whether the control's value is valid. Only relevant when
+ * the usual min/max/step checks are not sufficient.
+ * @s_ctrl: Actually set the new control value. s_ctrl is compulsory. The
+ * ctrl->handler->lock is held when these ops are called, so no
+ * one else can access controls owned by that handler.
+ */
+struct v4l2_ctrl_ops {
+ int (*g_volatile_ctrl)(struct v4l2_ctrl *ctrl);
+ int (*try_ctrl)(struct v4l2_ctrl *ctrl);
+ int (*s_ctrl)(struct v4l2_ctrl *ctrl);
+};
+
+/** struct v4l2_ctrl - The control structure.
+ * @node: The list node.
+ * @handler: The handler that owns the control.
+ * @cluster: Point to start of cluster array.
+ * @ncontrols: Number of controls in cluster array.
+ * @has_new: Internal flag: set when there is a valid new value.
+ * @done: Internal flag: set for each processed control.
+ * @is_private: If set, then this control is private to its handler and it
+ * will not be added to any other handlers. Drivers can set
+ * this flag.
+ * @is_volatile: If set, then this control is volatile. This means that the
+ * control's current value cannot be cached and needs to be
+ * retrieved through the g_volatile_ctrl op. Drivers can set
+ * this flag.
+ * @ops: The control ops.
+ * @id: The control ID.
+ * @name: The control name.
+ * @type: The control type.
+ * @minimum: The control's minimum value.
+ * @maximum: The control's maximum value.
+ * @default_value: The control's default value.
+ * @step: The control's step value for non-menu controls.
+ * @menu_skip_mask: The control's skip mask for menu controls. This makes it
+ * easy to skip menu items that are not valid. If bit X is set,
+ * then menu item X is skipped. Of course, this only works for
+ * menus with <= 32 menu items. There are no menus that come
+ * close to that number, so this is OK. Should we ever need more,
+ * then this will have to be extended to a u64 or a bit array.
+ * @qmenu: A const char * array for all menu items. Array entries that are
+ * empty strings ("") correspond to non-existing menu items (this
+ * is in addition to the menu_skip_mask above). The last entry
+ * must be NULL.
+ * @flags: The control's flags.
+ * @cur: The control's current value.
+ * @val: The control's new s32 value.
+ * @val64: The control's new s64 value.
+ * @string: The control's new string value.
+ * @priv: The control's private pointer. For use by the driver. It is
+ * untouched by the control framework. Note that this pointer is
+ * not freed when the control is deleted. Should this be needed
+ * then a new internal bitfield can be added to tell the framework
+ * to free this pointer.
+ */
+struct v4l2_ctrl {
+ /* Administrative fields */
+ struct list_head node;
+ struct v4l2_ctrl_handler *handler;
+ struct v4l2_ctrl **cluster;
+ unsigned ncontrols;
+ unsigned int has_new:1;
+ unsigned int done:1;
+
+ unsigned int is_private:1;
+ unsigned int is_volatile:1;
+
+ const struct v4l2_ctrl_ops *ops;
+ u32 id;
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s32 minimum, maximum, default_value;
+ union {
+ u32 step;
+ u32 menu_skip_mask;
+ };
+ const char **qmenu;
+ unsigned long flags;
+ union {
+ s32 val;
+ s64 val64;
+ char *string;
+ } cur;
+ union {
+ s32 val;
+ s64 val64;
+ char *string;
+ };
+ void *priv;
+};
+
+/** struct v4l2_ctrl_ref - The control reference.
+ * @node: List node for the sorted list.
+ * @next: Single-link list node for the hash.
+ * @ctrl: The actual control information.
+ *
+ * Each control handler has a list of these refs. The list_head is used to
+ * keep a sorted-by-control-ID list of all controls, while the next pointer
+ * is used to link the control in the hash's bucket.
+ */
+struct v4l2_ctrl_ref {
+ struct list_head node;
+ struct v4l2_ctrl_ref *next;
+ struct v4l2_ctrl *ctrl;
+};
+
+/** struct v4l2_ctrl_handler - The control handler keeps track of all the
+ * controls: both the controls owned by the handler and those inherited
+ * from other handlers.
+ * @lock: Lock to control access to this handler and its controls.
+ * @ctrls: The list of controls owned by this handler.
+ * @ctrl_refs: The list of control references.
+ * @cached: The last found control reference. It is common that the same
+ * control is needed multiple times, so this is a simple
+ * optimization.
+ * @buckets: Buckets for the hashing. Allows for quick control lookup.
+ * @nr_of_buckets: Total number of buckets in the array.
+ * @error: The error code of the first failed control addition.
+ */
+struct v4l2_ctrl_handler {
+ struct mutex lock;
+ struct list_head ctrls;
+ struct list_head ctrl_refs;
+ struct v4l2_ctrl_ref *cached;
+ struct v4l2_ctrl_ref **buckets;
+ u16 nr_of_buckets;
+ int error;
+};
+
+/** struct v4l2_ctrl_config - Control configuration structure.
+ * @ops: The control ops.
+ * @id: The control ID.
+ * @name: The control name.
+ * @type: The control type.
+ * @min: The control's minimum value.
+ * @max: The control's maximum value.
+ * @step: The control's step value for non-menu controls.
+ * @def: The control's default value.
+ * @flags: The control's flags.
+ * @menu_skip_mask: The control's skip mask for menu controls. This makes it
+ * easy to skip menu items that are not valid. If bit X is set,
+ * then menu item X is skipped. Of course, this only works for
+ * menus with <= 32 menu items. There are no menus that come
+ * close to that number, so this is OK. Should we ever need more,
+ * then this will have to be extended to a u64 or a bit array.
+ * @qmenu: A const char * array for all menu items. Array entries that are
+ * empty strings ("") correspond to non-existing menu items (this
+ * is in addition to the menu_skip_mask above). The last entry
+ * must be NULL.
+ * @is_private: If set, then this control is private to its handler and it
+ * will not be added to any other handlers.
+ * @is_volatile: If set, then this control is volatile. This means that the
+ * control's current value cannot be cached and needs to be
+ * retrieved through the g_volatile_ctrl op.
+ */
+struct v4l2_ctrl_config {
+ const struct v4l2_ctrl_ops *ops;
+ u32 id;
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s32 min;
+ s32 max;
+ u32 step;
+ s32 def;
+ u32 flags;
+ u32 menu_skip_mask;
+ const char **qmenu;
+ unsigned int is_private:1;
+ unsigned int is_volatile:1;
+};
+
+/** v4l2_ctrl_fill() - Fill in the control fields based on the control ID.
+ *
+ * This works for all standard V4L2 controls.
+ * For non-standard controls it will only fill in the given arguments
+ * and @name will be NULL.
+ *
+ * This function will overwrite the contents of @name, @type and @flags.
+ * The contents of @min, @max, @step and @def may be modified depending on
+ * the type.
+ *
+ * Do not use in drivers! It is used internally for backwards compatibility
+ * control handling only. Once all drivers are converted to use the new
+ * control framework this function will no longer be exported.
+ */
+void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+ s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags);
+
+
+/** v4l2_ctrl_handler_init() - Initialize the control handler.
+ * @hdl: The control handler.
+ * @nr_of_controls_hint: A hint of how many controls this handler is
+ * expected to refer to. This is the total number, so including
+ * any inherited controls. It doesn't have to be precise, but if
+ * it is way off, then you either waste memory (too many buckets
+ * are allocated) or the control lookup becomes slower (not enough
+ * buckets are allocated, so there are more slow list lookups).
+ * It will always work, though.
+ *
+ * Returns an error if the buckets could not be allocated. This error will
+ * also be stored in @hdl->error.
+ */
+int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint);
+
+/** v4l2_ctrl_handler_free() - Free all controls owned by the handler and free
+ * the control list.
+ * @hdl: The control handler.
+ *
+ * Does nothing if @hdl == NULL.
+ */
+void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl);
+
+/** v4l2_ctrl_handler_setup() - Call the s_ctrl op for all controls belonging
+ * to the handler to initialize the hardware to the current control values.
+ * @hdl: The control handler.
+ *
+ * Button controls will be skipped, as are read-only controls.
+ *
+ * If @hdl == NULL, then this just returns 0.
+ */
+int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl);
+
+/** v4l2_ctrl_handler_log_status() - Log all controls owned by the handler.
+ * @hdl: The control handler.
+ * @prefix: The prefix to use when logging the control values. If the
+ * prefix does not end with a space, then ": " will be added
+ * after the prefix. If @prefix == NULL, then no prefix will be
+ * used.
+ *
+ * For use with VIDIOC_LOG_STATUS.
+ *
+ * Does nothing if @hdl == NULL.
+ */
+void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
+ const char *prefix);
+
+/** v4l2_ctrl_new_custom() - Allocate and initialize a new custom V4L2
+ * control.
+ * @hdl: The control handler.
+ * @cfg: The control's configuration data.
+ * @priv: The control's driver-specific private data.
+ *
+ * If the &v4l2_ctrl struct could not be allocated then NULL is returned
+ * and @hdl->error is set to the error code (if it wasn't set already).
+ */
+struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_config *cfg, void *priv);
+
+/** v4l2_ctrl_new_std() - Allocate and initialize a new standard V4L2 non-menu control.
+ * @hdl: The control handler.
+ * @ops: The control ops.
+ * @id: The control ID.
+ * @min: The control's minimum value.
+ * @max: The control's maximum value.
+ * @step: The control's step value
+ * @def: The control's default value.
+ *
+ * If the &v4l2_ctrl struct could not be allocated, or the control
+ * ID is not known, then NULL is returned and @hdl->error is set to the
+ * appropriate error code (if it wasn't set already).
+ *
+ * If @id refers to a menu control, then this function will return NULL.
+ *
+ * Use v4l2_ctrl_new_std_menu() when adding menu controls.
+ */
+struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 min, s32 max, u32 step, s32 def);
+
+/** v4l2_ctrl_new_std_menu() - Allocate and initialize a new standard V4L2 menu control.
+ * @hdl: The control handler.
+ * @ops: The control ops.
+ * @id: The control ID.
+ * @max: The control's maximum value.
+ * @mask: The control's skip mask for menu controls. This makes it
+ * easy to skip menu items that are not valid. If bit X is set,
+ * then menu item X is skipped. Of course, this only works for
+ * menus with <= 32 menu items. There are no menus that come
+ * close to that number, so this is OK. Should we ever need more,
+ * then this will have to be extended to a u64 or a bit array.
+ * @def: The control's default value.
+ *
+ * Same as v4l2_ctrl_new_std(), but @min is set to 0 and the @mask value
+ * determines which menu items are to be skipped.
+ *
+ * If @id refers to a non-menu control, then this function will return NULL.
+ */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 mask, s32 def);
+
+/** v4l2_ctrl_add_ctrl() - Add a control from another handler to this handler.
+ * @hdl: The control handler.
+ * @ctrl: The control to add.
+ *
+ * It will return NULL if it was unable to add the control reference.
+ * If the control already belonged to the handler, then it will do
+ * nothing and just return @ctrl.
+ */
+struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl);
+
+/** v4l2_ctrl_add_handler() - Add all controls from handler @add to
+ * handler @hdl.
+ * @hdl: The control handler.
+ * @add: The control handler whose controls you want to add to
+ * the @hdl control handler.
+ *
+ * Does nothing if either of the two is a NULL pointer.
+ * In case of an error @hdl->error will be set to the error code (if it
+ * wasn't set already).
+ */
+int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl_handler *add);
+
+
+/** v4l2_ctrl_cluster() - Mark all controls in the cluster as belonging to that cluster.
+ * @ncontrols: The number of controls in this cluster.
+ * @controls: The cluster control array of size @ncontrols.
+ */
+void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls);
+
+
+/** v4l2_ctrl_find() - Find a control with the given ID.
+ * @hdl: The control handler.
+ * @id: The control ID to find.
+ *
+ * If @hdl == NULL this will return NULL as well. Will lock the handler so
+ * do not use from inside &v4l2_ctrl_ops.
+ */
+struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id);
+
+/** v4l2_ctrl_activate() - Make the control active or inactive.
+ * @ctrl: The control to (de)activate.
+ * @active: True if the control should become active.
+ *
+ * This sets or clears the V4L2_CTRL_FLAG_INACTIVE flag atomically.
+ * Does nothing if @ctrl == NULL.
+ * This will usually be called from within the s_ctrl op.
+ *
+ * This function can be called regardless of whether the control handler
+ * is locked or not.
+ */
+void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
+
+/** v4l2_ctrl_grab() - Mark the control as grabbed or not grabbed.
+ * @ctrl: The control to (de)activate.
+ * @grabbed: True if the control should become grabbed.
+ *
+ * This sets or clears the V4L2_CTRL_FLAG_GRABBED flag atomically.
+ * Does nothing if @ctrl == NULL.
+ * This will usually be called when starting or stopping streaming in the
+ * driver.
+ *
+ * This function can be called regardless of whether the control handler
+ * is locked or not.
+ */
+void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
+
+/** v4l2_ctrl_lock() - Helper function to lock the handler
+ * associated with the control.
+ * @ctrl: The control to lock.
+ */
+static inline void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl)
+{
+ mutex_lock(&ctrl->handler->lock);
+}
+
+/** v4l2_ctrl_lock() - Helper function to unlock the handler
+ * associated with the control.
+ * @ctrl: The control to unlock.
+ */
+static inline void v4l2_ctrl_unlock(struct v4l2_ctrl *ctrl)
+{
+ mutex_unlock(&ctrl->handler->lock);
+}
+
+/** v4l2_ctrl_g_ctrl() - Helper function to get the control's value from within a driver.
+ * @ctrl: The control.
+ *
+ * This returns the control's value safely by going through the control
+ * framework. This function will lock the control's handler, so it cannot be
+ * used from within the &v4l2_ctrl_ops functions.
+ *
+ * This function is for integer type controls only.
+ */
+s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
+
+/** v4l2_ctrl_s_ctrl() - Helper function to set the control's value from within a driver.
+ * @ctrl: The control.
+ * @val: The new value.
+ *
+ * This set the control's new value safely by going through the control
+ * framework. This function will lock the control's handler, so it cannot be
+ * used from within the &v4l2_ctrl_ops functions.
+ *
+ * This function is for integer type controls only.
+ */
+int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
+
+
+/* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
+int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
+int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);
+int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
+int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
+int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
+int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
+int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
+
+/* Helpers for subdevices. If the associated ctrl_handler == NULL then they
+ will all return -EINVAL. */
+int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
+int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm);
+int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs);
+int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs);
+int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs);
+int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+
+#endif
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index bebe44b..1efcacb 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -27,6 +27,7 @@
struct v4l2_ioctl_callbacks;
struct video_device;
struct v4l2_device;
+struct v4l2_ctrl_handler;

/* Flag to mark the video_device struct as registered.
Drivers can clear this flag if they want to block all future
@@ -67,6 +68,9 @@ struct video_device
struct device *parent; /* device parent */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */

+ /* Control handler associated with this device node. May be NULL. */
+ struct v4l2_ctrl_handler *ctrl_handler;
+
/* device info */
char name[32];
int vfl_type;
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
index 5d5d550..8bcbd7a 100644
--- a/include/media/v4l2-device.h
+++ b/include/media/v4l2-device.h
@@ -32,6 +32,8 @@

#define V4L2_DEVICE_NAME_SIZE (20 + 16)

+struct v4l2_ctrl_handler;
+
struct v4l2_device {
/* dev->driver_data points to this struct.
Note: dev might be NULL if there is no parent device
@@ -47,6 +49,8 @@ struct v4l2_device {
/* notify callback called by some sub-devices. */
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
+ /* The control handler. May be NULL. */
+ struct v4l2_ctrl_handler *ctrl_handler;
};

/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index fcdd247..bf1fb71 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -35,6 +35,7 @@
#define V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ 0x00000001

struct v4l2_device;
+struct v4l2_ctrl_handler;
struct v4l2_subdev;
struct tuner_setup;

@@ -415,6 +416,8 @@ struct v4l2_subdev {
u32 flags;
struct v4l2_device *v4l2_dev;
const struct v4l2_subdev_ops *ops;
+ /* The control handler of this subdev. May be NULL. */
+ struct v4l2_ctrl_handler *ctrl_handler;
/* name must be unique */
char name[V4L2_SUBDEV_NAME_SIZE];
/* can be used to group similar subdevs, value is driver-specific */
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:48:59 UTC
Permalink
From: Hans Verkuil <***@xs4all.nl>

To make it easier to determine whether all controls are added in v4l2-ctrls.c
the case statements inside the switch are re-ordered to match the header.

Signed-off-by: Hans Verkuil <***@xs4all.nl>
Reviewed-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/v4l2-ctrls.c | 30 +++++++++++++++++-------------
1 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 8489894..939243a 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -266,6 +266,7 @@ const char *v4l2_ctrl_get_name(u32 id)
{
switch (id) {
/* USER controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
case V4L2_CID_USER_CLASS: return "User Controls";
case V4L2_CID_BRIGHTNESS: return "Brightness";
case V4L2_CID_CONTRAST: return "Contrast";
@@ -296,28 +297,37 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_SHARPNESS: return "Sharpness";
case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
- case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
case V4L2_CID_COLOR_KILLER: return "Color Killer";
case V4L2_CID_COLORFX: return "Color Effects";
case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
case V4L2_CID_ROTATE: return "Rotate";
case V4L2_CID_BG_COLOR: return "Background Color";
+ case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";

/* MPEG controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+ case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
+ case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+ case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
@@ -330,16 +340,9 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
- case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
- case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
- case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
- case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
- case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
- case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";

/* CAMERA controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure";
case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute";
@@ -353,14 +356,15 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic";
- case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
- case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
case V4L2_CID_PRIVACY: return "Privacy";
+ case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
+ case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";

/* FM Radio Modulator control */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:00 UTC
Permalink
From: Hans Verkuil <***@xs4all.nl>

Signed-off-by: Hans Verkuil <***@xs4all.nl>
Reviewed-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
Documentation/video4linux/v4l2-controls.txt | 648 +++++++++++++++++++++++++++
1 files changed, 648 insertions(+), 0 deletions(-)
create mode 100644 Documentation/video4linux/v4l2-controls.txt

diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
new file mode 100644
index 0000000..8773778
--- /dev/null
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -0,0 +1,648 @@
+Introduction
+============
+
+The V4L2 control API seems simple enough, but quickly becomes very hard to
+implement correctly in drivers. But much of the code needed to handle controls
+is actually not driver specific and can be moved to the V4L core framework.
+
+After all, the only part that a driver developer is interested in is:
+
+1) How do I add a control?
+2) How do I set the control's value? (i.e. s_ctrl)
+
+And occasionally:
+
+3) How do I get the control's value? (i.e. g_volatile_ctrl)
+4) How do I validate the user's proposed control value? (i.e. try_ctrl)
+
+All the rest is something that can be done centrally.
+
+The control framework was created in order to implement all the rules of the
+V4L2 specification with respect to controls in a central place. And to make
+life as easy as possible for the driver developer.
+
+Note that the control framework relies on the presence of a struct v4l2_device
+for V4L2 drivers and struct v4l2_subdev for sub-device drivers.
+
+
+Objects in the framework
+========================
+
+There are two main objects:
+
+The v4l2_ctrl object describes the control properties and keeps track of the
+control's value (both the current value and the proposed new value).
+
+v4l2_ctrl_handler is the object that keeps track of controls. It maintains a
+list of v4l2_ctrl objects that it owns and another list of references to
+controls, possibly to controls owned by other handlers.
+
+
+Basic usage for V4L2 and sub-device drivers
+===========================================
+
+1) Prepare the driver:
+
+1.1) Add the handler to your driver's top-level struct:
+
+ struct foo_dev {
+ ...
+ struct v4l2_ctrl_handler ctrl_handler;
+ ...
+ };
+
+ struct foo_dev *foo;
+
+1.2) Initialize the handler:
+
+ v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
+
+ The second argument is a hint telling the function how many controls this
+ handler is expected to handle. It will allocate a hashtable based on this
+ information. It is a hint only.
+
+1.3) Hook the control handler into the driver:
+
+1.3.1) For V4L2 drivers do this:
+
+ struct foo_dev {
+ ...
+ struct v4l2_device v4l2_dev;
+ ...
+ struct v4l2_ctrl_handler ctrl_handler;
+ ...
+ };
+
+ foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;
+
+ Where foo->v4l2_dev is of type struct v4l2_device.
+
+ Finally, remove all control functions from your v4l2_ioctl_ops:
+ vidioc_queryctrl, vidioc_querymenu, vidioc_g_ctrl, vidioc_s_ctrl,
+ vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
+ Those are now no longer needed.
+
+1.3.2) For sub-device drivers do this:
+
+ struct foo_dev {
+ ...
+ struct v4l2_subdev sd;
+ ...
+ struct v4l2_ctrl_handler ctrl_handler;
+ ...
+ };
+
+ foo->sd.ctrl_handler = &foo->ctrl_handler;
+
+ Where foo->sd is of type struct v4l2_subdev.
+
+ And set all core control ops in your struct v4l2_subdev_core_ops to these
+ helpers:
+
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+
+ Note: this is a temporary solution only. Once all V4L2 drivers that depend
+ on subdev drivers are converted to the control framework these helpers will
+ no longer be needed.
+
+1.4) Clean up the handler at the end:
+
+ v4l2_ctrl_handler_free(&foo->ctrl_handler);
+
+
+2) Add controls:
+
+You add non-menu controls by calling v4l2_ctrl_new_std:
+
+ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 min, s32 max, u32 step, s32 def);
+
+Menu controls are added by calling v4l2_ctrl_new_std_menu:
+
+ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 skip_mask, s32 def);
+
+These functions are typically called right after the v4l2_ctrl_handler_init:
+
+ v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
+ v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 128);
+ v4l2_ctrl_new_std_menu(&foo->ctrl_handler, &foo_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
+ ...
+ if (foo->ctrl_handler.error) {
+ int err = foo->ctrl_handler.error;
+
+ v4l2_ctrl_handler_free(&foo->ctrl_handler);
+ return err;
+ }
+
+The v4l2_ctrl_new_std function returns the v4l2_ctrl pointer to the new
+control, but if you do not need to access the pointer outside the control ops,
+then there is no need to store it.
+
+The v4l2_ctrl_new_std function will fill in most fields based on the control
+ID except for the min, max, step and default values. These are passed in the
+last four arguments. These values are driver specific while control attributes
+like type, name, flags are all global. The control's current value will be set
+to the default value.
+
+The v4l2_ctrl_new_std_menu function is very similar but it is used for menu
+controls. There is no min argument since that is always 0 for menu controls,
+and instead of a step there is a skip_mask argument: if bit X is 1, then menu
+item X is skipped.
+
+Note that if something fails, the function will return NULL or an error and
+set ctrl_handler->error to the error code. If ctrl_handler->error was already
+set, then it will just return and do nothing. This is also true for
+v4l2_ctrl_handler_init if it cannot allocate the internal data structure.
+
+This makes it easy to init the handler and just add all controls and only check
+the error code at the end. Saves a lot of repetitive error checking.
+
+It is recommended to add controls in ascending control ID order: it will be
+a bit faster that way.
+
+3) Optionally force initial control setup:
+
+ v4l2_ctrl_handler_setup(&foo->ctrl_handler);
+
+This will call s_ctrl for all controls unconditionally. Effectively this
+initializes the hardware to the default control values. It is recommended
+that you do this as this ensures that both the internal data structures and
+the hardware are in sync.
+
+4) Finally: implement the v4l2_ctrl_ops
+
+ static const struct v4l2_ctrl_ops foo_ctrl_ops = {
+ .s_ctrl = foo_s_ctrl,
+ };
+
+Usually all you need is s_ctrl:
+
+ static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
+ {
+ struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ write_reg(0x123, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ write_reg(0x456, ctrl->val);
+ break;
+ }
+ return 0;
+ }
+
+The control ops are called with the v4l2_ctrl pointer as argument.
+The new control value has already been validated, so all you need to do is
+to actually update the hardware registers.
+
+You're done! And this is sufficient for most of the drivers we have. No need
+to do any validation of control values, or implement QUERYCTRL/QUERYMENU. And
+G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
+
+
+==============================================================================
+
+The remainder of this document deals with more advanced topics and scenarios.
+In practice the basic usage as described above is sufficient for most drivers.
+
+===============================================================================
+
+
+Inheriting Controls
+===================
+
+When a sub-device is registered with a V4L2 driver by calling
+v4l2_device_register_subdev() and the ctrl_handler fields of both v4l2_subdev
+and v4l2_device are set, then the controls of the subdev will become
+automatically available in the V4L2 driver as well. If the subdev driver
+contains controls that already exist in the V4L2 driver, then those will be
+skipped (so a V4L2 driver can always override a subdev control).
+
+What happens here is that v4l2_device_register_subdev() calls
+v4l2_ctrl_add_handler() adding the controls of the subdev to the controls
+of v4l2_device.
+
+
+Accessing Control Values
+========================
+
+The v4l2_ctrl struct contains these two unions:
+
+ /* The current control value. */
+ union {
+ s32 val;
+ s64 val64;
+ char *string;
+ } cur;
+
+ /* The new control value. */
+ union {
+ s32 val;
+ s64 val64;
+ char *string;
+ };
+
+Within the control ops you can freely use these. The val and val64 speak for
+themselves. The string pointers point to character buffers of length
+ctrl->maximum + 1, and are always 0-terminated.
+
+In most cases 'cur' contains the current cached control value. When you create
+a new control this value is made identical to the default value. After calling
+v4l2_ctrl_handler_setup() this value is passed to the hardware. It is generally
+a good idea to call this function.
+
+Whenever a new value is set that new value is automatically cached. This means
+that most drivers do not need to implement the g_volatile_ctrl() op. The
+exception is for controls that return a volatile register such as a signal
+strength read-out that changes continuously. In that case you will need to
+implement g_volatile_ctrl like this:
+
+ static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+ {
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->cur.val = read_reg(0x123);
+ break;
+ }
+ }
+
+The 'new value' union is not used in g_volatile_ctrl. In general controls
+that need to implement g_volatile_ctrl are read-only controls.
+
+To mark a control as volatile you have to set the is_volatile flag:
+
+ ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
+ if (ctrl)
+ ctrl->is_volatile = 1;
+
+For try/s_ctrl the new values (i.e. as passed by the user) are filled in and
+you can modify them in try_ctrl or set them in s_ctrl. The 'cur' union
+contains the current value, which you can use (but not change!) as well.
+
+If s_ctrl returns 0 (OK), then the control framework will copy the new final
+values to the 'cur' union.
+
+While in g_volatile/s/try_ctrl you can access the value of all controls owned
+by the same handler since the handler's lock is held. If you need to access
+the value of controls owned by other handlers, then you have to be very careful
+not to introduce deadlocks.
+
+Outside of the control ops you have to go through to helper functions to get
+or set a single control value safely in your driver:
+
+ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
+ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
+
+These functions go through the control framework just as VIDIOC_G/S_CTRL ioctls
+do. Don't use these inside the control ops g_volatile/s/try_ctrl, though, that
+will result in a deadlock since these helpers lock the handler as well.
+
+You can also take the handler lock yourself:
+
+ mutex_lock(&state->ctrl_handler.lock);
+ printk(KERN_INFO "String value is '%s'\n", ctrl1->cur.string);
+ printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
+ mutex_unlock(&state->ctrl_handler.lock);
+
+
+Menu Controls
+=============
+
+The v4l2_ctrl struct contains this union:
+
+ union {
+ u32 step;
+ u32 menu_skip_mask;
+ };
+
+For menu controls menu_skip_mask is used. What it does is that it allows you
+to easily exclude certain menu items. This is used in the VIDIOC_QUERYMENU
+implementation where you can return -EINVAL if a certain menu item is not
+present. Note that VIDIOC_QUERYCTRL always returns a step value of 1 for
+menu controls.
+
+A good example is the MPEG Audio Layer II Bitrate menu control where the
+menu is a list of standardized possible bitrates. But in practice hardware
+implementations will only support a subset of those. By setting the skip
+mask you can tell the framework which menu items should be skipped. Setting
+it to 0 means that all menu items are supported.
+
+You set this mask either through the v4l2_ctrl_config struct for a custom
+control, or by calling v4l2_ctrl_new_std_menu().
+
+
+Custom Controls
+===============
+
+Driver specific controls can be created using v4l2_ctrl_new_custom():
+
+ static const struct v4l2_ctrl_config ctrl_filter = {
+ .ops = &ctrl_custom_ops,
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ .name = "Spatial Filter",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 15,
+ .step = 1,
+ };
+
+ ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_filter, NULL);
+
+The last argument is the priv pointer which can be set to driver-specific
+private data.
+
+The v4l2_ctrl_config struct also has fields to set the is_private and is_volatile
+flags.
+
+If the name field is not set, then the framework will assume this is a standard
+control and will fill in the name, type and flags fields accordingly.
+
+
+Active and Grabbed Controls
+===========================
+
+If you get more complex relationships between controls, then you may have to
+activate and deactivate controls. For example, if the Chroma AGC control is
+on, then the Chroma Gain control is inactive. That is, you may set it, but
+the value will not be used by the hardware as long as the automatic gain
+control is on. Typically user interfaces can disable such input fields.
+
+You can set the 'active' status using v4l2_ctrl_activate(). By default all
+controls are active. Note that the framework does not check for this flag.
+It is meant purely for GUIs. The function is typically called from within
+s_ctrl.
+
+The other flag is the 'grabbed' flag. A grabbed control means that you cannot
+change it because it is in use by some resource. Typical examples are MPEG
+bitrate controls that cannot be changed while capturing is in progress.
+
+If a control is set to 'grabbed' using v4l2_ctrl_grab(), then the framework
+will return -EBUSY if an attempt is made to set this control. The
+v4l2_ctrl_grab() function is typically called from the driver when it
+starts or stops streaming.
+
+
+Control Clusters
+================
+
+By default all controls are independent from the others. But in more
+complex scenarios you can get dependencies from one control to another.
+In that case you need to 'cluster' them:
+
+ struct foo {
+ struct v4l2_ctrl_handler ctrl_handler;
+#define AUDIO_CL_VOLUME (0)
+#define AUDIO_CL_MUTE (1)
+ struct v4l2_ctrl *audio_cluster[2];
+ ...
+ };
+
+ state->audio_cluster[AUDIO_CL_VOLUME] =
+ v4l2_ctrl_new_std(&state->ctrl_handler, ...);
+ state->audio_cluster[AUDIO_CL_MUTE] =
+ v4l2_ctrl_new_std(&state->ctrl_handler, ...);
+ v4l2_ctrl_cluster(ARRAY_SIZE(state->audio_cluster), state->audio_cluster);
+
+From now on whenever one or more of the controls belonging to the same
+cluster is set (or 'gotten', or 'tried'), only the control ops of the first
+control ('volume' in this example) is called. You effectively create a new
+composite control. Similar to how a 'struct' works in C.
+
+So when s_ctrl is called with V4L2_CID_AUDIO_VOLUME as argument, you should set
+all two controls belonging to the audio_cluster:
+
+ static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
+ {
+ struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME: {
+ struct v4l2_ctrl *mute = ctrl->cluster[AUDIO_CL_MUTE];
+
+ write_reg(0x123, mute->val ? 0 : ctrl->val);
+ break;
+ }
+ case V4L2_CID_CONTRAST:
+ write_reg(0x456, ctrl->val);
+ break;
+ }
+ return 0;
+ }
+
+In the example above the following are equivalent for the VOLUME case:
+
+ ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
+ ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
+
+Note that controls in a cluster may be NULL. For example, if for some
+reason mute was never added (because the hardware doesn't support that
+particular feature), then mute will be NULL. So in that case we have a
+cluster of 2 controls, of which only 1 is actually instantiated. The
+only restriction is that the first control of the cluster must always be
+present, since that is the 'master' control of the cluster. The master
+control is the one that identifies the cluster and that provides the
+pointer to the v4l2_ctrl_ops struct that is used for that cluster.
+
+Obviously, all controls in the cluster array must be initialized to either
+a valid control or to NULL.
+
+
+VIDIOC_LOG_STATUS Support
+=========================
+
+This ioctl allow you to dump the current status of a driver to the kernel log.
+The v4l2_ctrl_handler_log_status(ctrl_handler, prefix) can be used to dump the
+value of the controls owned by the given handler to the log. You can supply a
+prefix as well. If the prefix didn't end with a space, then ': ' will be added
+for you.
+
+
+Different Handlers for Different Video Nodes
+============================================
+
+Usually the V4L2 driver has just one control handler that is global for
+all video nodes. But you can also specify different control handlers for
+different video nodes. You can do that by manually setting the ctrl_handler
+field of struct video_device.
+
+That is no problem if there are no subdevs involved but if there are, then
+you need to block the automatic merging of subdev controls to the global
+control handler. You do that by simply setting the ctrl_handler field in
+struct v4l2_device to NULL. Now v4l2_device_register_subdev() will no longer
+merge subdev controls.
+
+After each subdev was added, you will then have to call v4l2_ctrl_add_handler
+manually to add the subdev's control handler (sd->ctrl_handler) to the desired
+control handler. This control handler may be specific to the video_device or
+for a subset of video_device's. For example: the radio device nodes only have
+audio controls, while the video and vbi device nodes share the same control
+handler for the audio and video controls.
+
+If you want to have one handler (e.g. for a radio device node) have a subset
+of another handler (e.g. for a video device node), then you should first add
+the controls to the first handler, add the other controls to the second
+handler and finally add the first handler to the second. For example:
+
+ v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_VOLUME, ...);
+ v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
+ v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
+ v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);
+ v4l2_ctrl_add_handler(&video_ctrl_handler, &radio_ctrl_handler);
+
+Or you can add specific controls to a handler:
+
+ volume = v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_AUDIO_VOLUME, ...);
+ v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_BRIGHTNESS, ...);
+ v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_CONTRAST, ...);
+ v4l2_ctrl_add_ctrl(&radio_ctrl_handler, volume);
+
+What you should not do is make two identical controls for two handlers.
+For example:
+
+ v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
+ v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_AUDIO_MUTE, ...);
+
+This would be bad since muting the radio would not change the video mute
+control. The rule is to have one control for each hardware 'knob' that you
+can twiddle.
+
+
+Finding Controls
+================
+
+Normally you have created the controls yourself and you can store the struct
+v4l2_ctrl pointer into your own struct.
+
+But sometimes you need to find a control from another handler that you do
+not own. For example, if you have to find a volume control from a subdev.
+
+You can do that by calling v4l2_ctrl_find:
+
+ struct v4l2_ctrl *volume;
+
+ volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME);
+
+Since v4l2_ctrl_find will lock the handler you have to be careful where you
+use it. For example, this is not a good idea:
+
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
+ v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);
+
+...and in video_ops.s_ctrl:
+
+ case V4L2_CID_BRIGHTNESS:
+ contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST);
+ ...
+
+When s_ctrl is called by the framework the ctrl_handler.lock is already taken, so
+attempting to find another control from the same handler will deadlock.
+
+It is recommended not to use this function from inside the control ops.
+
+
+Inheriting Controls
+===================
+
+When one control handler is added to another using v4l2_ctrl_add_handler, then
+by default all controls from one are merged to the other. But a subdev might
+have low-level controls that make sense for some advanced embedded system, but
+not when it is used in consumer-level hardware. In that case you want to keep
+those low-level controls local to the subdev. You can do this by simply
+setting the 'is_private' flag of the control to 1:
+
+ static const struct v4l2_ctrl_config ctrl_private = {
+ .ops = &ctrl_custom_ops,
+ .id = V4L2_CID_...,
+ .name = "Some Private Control",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .max = 15,
+ .step = 1,
+ .is_private = 1,
+ };
+
+ ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_private, NULL);
+
+These controls will now be skipped when v4l2_ctrl_add_handler is called.
+
+
+V4L2_CTRL_TYPE_CTRL_CLASS Controls
+==================================
+
+Controls of this type can be used by GUIs to get the name of the control class.
+A fully featured GUI can make a dialog with multiple tabs with each tab
+containing the controls belonging to a particular control class. The name of
+each tab can be found by querying a special control with ID <control class | 1>.
+
+Drivers do not have to care about this. The framework will automatically add
+a control of this type whenever the first control belonging to a new control
+class is added.
+
+
+Differences from the Spec
+=========================
+
+There are a few places where the framework acts slightly differently from the
+V4L2 Specification. Those differences are described in this section. We will
+have to see whether we need to adjust the spec or not.
+
+1) It is no longer required to have all controls contained in a
+v4l2_ext_control array be from the same control class. The framework will be
+able to handle any type of control in the array. You need to set ctrl_class
+to 0 in order to enable this. If ctrl_class is non-zero, then it will still
+check that all controls belong to that control class.
+
+If you set ctrl_class to 0 and count to 0, then it will only return an error
+if there are no controls at all.
+
+2) Clarified the way error_idx works. For get and set it will be equal to
+count if nothing was done yet. If it is less than count then only the controls
+up to error_idx-1 were successfully applied.
+
+3) When attempting to read a button control the framework will return -EACCES
+instead of -EINVAL as stated in the spec. It seems to make more sense since
+button controls are write-only controls.
+
+4) Attempting to write to a read-only control will return -EACCES instead of
+-EINVAL as the spec says.
+
+5) The spec does not mention what should happen when you try to set/get a
+control class controls. ivtv currently returns -EINVAL (indicating that the
+control ID does not exist) while the framework will return -EACCES, which
+makes more sense.
+
+
+Proposals for Extensions
+========================
+
+Some ideas for future extensions to the spec:
+
+1) Add a V4L2_CTRL_FLAG_HEX to have values shown as hexadecimal instead of
+decimal. Useful for e.g. video_mute_yuv.
+
+2) It is possible to mark in the controls array which controls have been
+successfully written and which failed by for example adding a bit to the
+control ID. Not sure if it is worth the effort, though.
+
+3) Trying to set volatile inactive controls should result in -EACCESS.
+
+4) Add a new flag to mark volatile controls. Any application that wants
+to store the state of the controls can then skip volatile inactive controls.
+Currently it is not possible to detect such controls.
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:01 UTC
Permalink
From: Hans Verkuil <***@xs4all.nl>

Add the calls needed to automatically merge subdev controls into a bridge
control handler.

Hook up the control framework in __video_ioctl2 and video_register_device.

Signed-off-by: Hans Verkuil <***@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/v4l2-dev.c | 8 +++++-
drivers/media/video/v4l2-device.c | 7 +++++
drivers/media/video/v4l2-ioctl.c | 46 ++++++++++++++++++++++++++----------
3 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 0ca7ec9..773ffe1 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -447,8 +447,12 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,

vdev->vfl_type = type;
vdev->cdev = NULL;
- if (vdev->v4l2_dev && vdev->v4l2_dev->dev)
- vdev->parent = vdev->v4l2_dev->dev;
+ if (vdev->v4l2_dev) {
+ if (vdev->v4l2_dev->dev)
+ vdev->parent = vdev->v4l2_dev->dev;
+ if (vdev->ctrl_handler == NULL)
+ vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
+ }

/* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 5a7dc4a..0b08f96 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -26,6 +26,7 @@
#endif
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>

int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
{
@@ -115,6 +116,8 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
struct v4l2_subdev *sd)
{
+ int err;
+
/* Check for valid input */
if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
return -EINVAL;
@@ -122,6 +125,10 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
WARN_ON(sd->v4l2_dev != NULL);
if (!try_module_get(sd->owner))
return -ENODEV;
+ /* This just returns 0 if either of the two args is NULL */
+ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
+ if (err)
+ return err;
sd->v4l2_dev = v4l2_dev;
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 0eeceae..dd9283f 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -26,6 +26,7 @@
#endif
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
@@ -1259,9 +1260,12 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_queryctrl *p = arg;

- if (!ops->vidioc_queryctrl)
+ if (vfd->ctrl_handler)
+ ret = v4l2_queryctrl(vfd->ctrl_handler, p);
+ else if (ops->vidioc_queryctrl)
+ ret = ops->vidioc_queryctrl(file, fh, p);
+ else
break;
- ret = ops->vidioc_queryctrl(file, fh, p);
if (!ret)
dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, "
"step=%d, default=%d, flags=0x%08x\n",
@@ -1276,7 +1280,9 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_control *p = arg;

- if (ops->vidioc_g_ctrl)
+ if (vfd->ctrl_handler)
+ ret = v4l2_g_ctrl(vfd->ctrl_handler, p);
+ else if (ops->vidioc_g_ctrl)
ret = ops->vidioc_g_ctrl(file, fh, p);
else if (ops->vidioc_g_ext_ctrls) {
struct v4l2_ext_controls ctrls;
@@ -1306,11 +1312,16 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control ctrl;

- if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
+ if (!vfd->ctrl_handler &&
+ !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
break;

dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);

+ if (vfd->ctrl_handler) {
+ ret = v4l2_s_ctrl(vfd->ctrl_handler, p);
+ break;
+ }
if (ops->vidioc_s_ctrl) {
ret = ops->vidioc_s_ctrl(file, fh, p);
break;
@@ -1332,10 +1343,12 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls *p = arg;

p->error_idx = p->count;
- if (!ops->vidioc_g_ext_ctrls)
- break;
- if (check_ext_ctrls(p, 0))
+ if (vfd->ctrl_handler)
+ ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
+ else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0))
ret = ops->vidioc_g_ext_ctrls(file, fh, p);
+ else
+ break;
v4l_print_ext_ctrls(cmd, vfd, p, !ret);
break;
}
@@ -1344,10 +1357,12 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls *p = arg;

p->error_idx = p->count;
- if (!ops->vidioc_s_ext_ctrls)
+ if (!vfd->ctrl_handler && !ops->vidioc_s_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
- if (check_ext_ctrls(p, 0))
+ if (vfd->ctrl_handler)
+ ret = v4l2_s_ext_ctrls(vfd->ctrl_handler, p);
+ else if (check_ext_ctrls(p, 0))
ret = ops->vidioc_s_ext_ctrls(file, fh, p);
break;
}
@@ -1356,10 +1371,12 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls *p = arg;

p->error_idx = p->count;
- if (!ops->vidioc_try_ext_ctrls)
+ if (!vfd->ctrl_handler && !ops->vidioc_try_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
- if (check_ext_ctrls(p, 0))
+ if (vfd->ctrl_handler)
+ ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
+ else if (check_ext_ctrls(p, 0))
ret = ops->vidioc_try_ext_ctrls(file, fh, p);
break;
}
@@ -1367,9 +1384,12 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_querymenu *p = arg;

- if (!ops->vidioc_querymenu)
+ if (vfd->ctrl_handler)
+ ret = v4l2_querymenu(vfd->ctrl_handler, p);
+ else if (ops->vidioc_querymenu)
+ ret = ops->vidioc_querymenu(file, fh, p);
+ else
break;
- ret = ops->vidioc_querymenu(file, fh, p);
if (!ret)
dbgarg(cmd, "id=0x%x, index=%d, name=%s\n",
p->id, p->index, p->name);
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:02 UTC
Permalink
From: Mauro Carvalho Chehab <***@redhat.com>

Fixes 37 checkpatch.pl warnings like:

WARNING: please, no space before tabs
+^Icase V4L2_CID_MPEG_VIDEO_PULLDOWN: ^Ireturn "Video Pulldown";$

Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/v4l2-ctrls.c | 74 +++++++++++++++++++-------------------
1 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 939243a..84c1a53 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -267,17 +267,17 @@ const char *v4l2_ctrl_get_name(u32 id)
switch (id) {
/* USER controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
- case V4L2_CID_USER_CLASS: return "User Controls";
- case V4L2_CID_BRIGHTNESS: return "Brightness";
- case V4L2_CID_CONTRAST: return "Contrast";
- case V4L2_CID_SATURATION: return "Saturation";
- case V4L2_CID_HUE: return "Hue";
- case V4L2_CID_AUDIO_VOLUME: return "Volume";
- case V4L2_CID_AUDIO_BALANCE: return "Balance";
- case V4L2_CID_AUDIO_BASS: return "Bass";
- case V4L2_CID_AUDIO_TREBLE: return "Treble";
- case V4L2_CID_AUDIO_MUTE: return "Mute";
- case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+ case V4L2_CID_USER_CLASS: return "User Controls";
+ case V4L2_CID_BRIGHTNESS: return "Brightness";
+ case V4L2_CID_CONTRAST: return "Contrast";
+ case V4L2_CID_SATURATION: return "Saturation";
+ case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_AUDIO_VOLUME: return "Volume";
+ case V4L2_CID_AUDIO_BALANCE: return "Balance";
+ case V4L2_CID_AUDIO_BASS: return "Bass";
+ case V4L2_CID_AUDIO_TREBLE: return "Treble";
+ case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
case V4L2_CID_BLACK_LEVEL: return "Black Level";
case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
@@ -307,38 +307,38 @@ const char *v4l2_ctrl_get_name(u32 id)

/* MPEG controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
- case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
- case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
- case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
- case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
- case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
- case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
+ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+ case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
+ case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
- case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
- case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
+ case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
+ case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
- case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
- case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
- case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
- case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
- case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
- case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
- case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
- case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
+ case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
+ case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
+ case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
+ case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
- case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
+ case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";

/* CAMERA controls */
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:03 UTC
Permalink
From: Randy Dunlap <***@oracle.com>

v4l2-ctrls.c needs to include slab.h to prevent build errors:

drivers/media/video/v4l2-ctrls.c:766: error: implicit declaration of function 'kzalloc'
drivers/media/video/v4l2-ctrls.c:786: error: implicit declaration of function 'kfree'
drivers/media/video/v4l2-ctrls.c:1528: error: implicit declaration of function 'kmalloc'

Signed-off-by: Randy Dunlap <***@oracle.com>
Signed-off-by: Mauro Carvalho Chehab <***@redhat.com>
---
drivers/media/video/v4l2-ctrls.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 84c1a53..ea8d32c 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -19,6 +19,7 @@
*/

#include <linux/ctype.h>
+#include <linux/slab.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:05 UTC
Permalink
There's no reason to require subdevices to implement the core
operations. Remove the check for non-NULL core operations when
initializing the subdev.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/media/v4l2-subdev.h | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index bf1fb71..7694177 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -451,8 +451,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
const struct v4l2_subdev_ops *ops)
{
INIT_LIST_HEAD(&sd->list);
- /* ops->core MUST be set */
- BUG_ON(!ops || !ops->core);
+ BUG_ON(!ops);
sd->ops = ops;
sd->v4l2_dev = NULL;
sd->flags = 0;
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:04 UTC
Permalink
The two functions are mostly identical. They handle the copy_from_user
and copy_to_user operations related with V4L2 ioctls and call the real
ioctl handler.

Create a __video_usercopy function that implements the core of
video_usercopy and video_ioctl2, and call that function from both.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
drivers/media/video/v4l2-ioctl.c | 218 ++++++++++++-------------------------
1 files changed, 71 insertions(+), 147 deletions(-)

diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index dd9283f..1e01554 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -374,35 +374,62 @@ video_fix_command(unsigned int cmd)
}
#endif

-/*
- * Obsolete usercopy function - Should be removed soon
- */
-long
-video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+/* In some cases, only a few fields are used as input, i.e. when the app sets
+ * "index" and then the driver fills in the rest of the structure for the thing
+ * with that index. We only need to copy up the first non-input field. */
+static unsigned long cmd_input_size(unsigned int cmd)
+{
+ /* Size of structure up to and including 'field' */
+#define CMDINSIZE(cmd, type, field) \
+ case VIDIOC_##cmd: \
+ return offsetof(struct v4l2_##type, field) + \
+ sizeof(((struct v4l2_##type *)0)->field);
+
+ switch (cmd) {
+ CMDINSIZE(ENUM_FMT, fmtdesc, type);
+ CMDINSIZE(G_FMT, format, type);
+ CMDINSIZE(QUERYBUF, buffer, type);
+ CMDINSIZE(G_PARM, streamparm, type);
+ CMDINSIZE(ENUMSTD, standard, index);
+ CMDINSIZE(ENUMINPUT, input, index);
+ CMDINSIZE(G_CTRL, control, id);
+ CMDINSIZE(G_TUNER, tuner, index);
+ CMDINSIZE(QUERYCTRL, queryctrl, id);
+ CMDINSIZE(QUERYMENU, querymenu, index);
+ CMDINSIZE(ENUMOUTPUT, output, index);
+ CMDINSIZE(G_MODULATOR, modulator, index);
+ CMDINSIZE(G_FREQUENCY, frequency, tuner);
+ CMDINSIZE(CROPCAP, cropcap, type);
+ CMDINSIZE(G_CROP, crop, type);
+ CMDINSIZE(ENUMAUDIO, audio, index);
+ CMDINSIZE(ENUMAUDOUT, audioout, index);
+ CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
+ CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
+ CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
+ CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
+ CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
+ default:
+ return _IOC_SIZE(cmd);
+ }
+}
+
+static long
+__video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
v4l2_kioctl func)
{
char sbuf[128];
void *mbuf = NULL;
- void *parg = NULL;
+ void *parg = (void *)arg;
long err = -EINVAL;
int is_ext_ctrl;
size_t ctrls_size = 0;
void __user *user_ptr = NULL;

-#ifdef __OLD_VIDIOC_
- cmd = video_fix_command(cmd);
-#endif
is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
cmd == VIDIOC_TRY_EXT_CTRLS);

/* Copy arguments into temp kernel buffer */
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE:
- parg = NULL;
- break;
- case _IOC_READ:
- case _IOC_WRITE:
- case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_DIR(cmd) != _IOC_NONE) {
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
@@ -414,11 +441,21 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
}

err = -EFAULT;
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ unsigned long n = cmd_input_size(cmd);
+
+ if (copy_from_user(parg, (void __user *)arg, n))
goto out;
- break;
+
+ /* zero out anything we don't copy from userspace */
+ if (n < _IOC_SIZE(cmd))
+ memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+ } else {
+ /* read-only ioctl */
+ memset(parg, 0, _IOC_SIZE(cmd));
+ }
}
+
if (is_ext_ctrl) {
struct v4l2_ext_controls *p = parg;

@@ -440,7 +477,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
}
}

- /* call driver */
+ /* Handles IOCTL */
err = func(file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
@@ -469,6 +506,19 @@ out:
kfree(mbuf);
return err;
}
+
+/*
+ * Obsolete usercopy function - Should be removed soon
+ */
+long
+video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ v4l2_kioctl func)
+{
+#ifdef __OLD_VIDIOC_
+ cmd = video_fix_command(cmd);
+#endif
+ return __video_usercopy(file, cmd, arg, func);
+}
EXPORT_SYMBOL(video_usercopy);

static void dbgbuf(unsigned int cmd, struct video_device *vfd,
@@ -2041,138 +2091,12 @@ static long __video_do_ioctl(struct file *file,
return ret;
}

-/* In some cases, only a few fields are used as input, i.e. when the app sets
- * "index" and then the driver fills in the rest of the structure for the thing
- * with that index. We only need to copy up the first non-input field. */
-static unsigned long cmd_input_size(unsigned int cmd)
-{
- /* Size of structure up to and including 'field' */
-#define CMDINSIZE(cmd, type, field) \
- case VIDIOC_##cmd: \
- return offsetof(struct v4l2_##type, field) + \
- sizeof(((struct v4l2_##type *)0)->field);
-
- switch (cmd) {
- CMDINSIZE(ENUM_FMT, fmtdesc, type);
- CMDINSIZE(G_FMT, format, type);
- CMDINSIZE(QUERYBUF, buffer, type);
- CMDINSIZE(G_PARM, streamparm, type);
- CMDINSIZE(ENUMSTD, standard, index);
- CMDINSIZE(ENUMINPUT, input, index);
- CMDINSIZE(G_CTRL, control, id);
- CMDINSIZE(G_TUNER, tuner, index);
- CMDINSIZE(QUERYCTRL, queryctrl, id);
- CMDINSIZE(QUERYMENU, querymenu, index);
- CMDINSIZE(ENUMOUTPUT, output, index);
- CMDINSIZE(G_MODULATOR, modulator, index);
- CMDINSIZE(G_FREQUENCY, frequency, tuner);
- CMDINSIZE(CROPCAP, cropcap, type);
- CMDINSIZE(G_CROP, crop, type);
- CMDINSIZE(ENUMAUDIO, audio, index);
- CMDINSIZE(ENUMAUDOUT, audioout, index);
- CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
- CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
- CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
- CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
- CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
- default:
- return _IOC_SIZE(cmd);
- }
-}
-
long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
- char sbuf[128];
- void *mbuf = NULL;
- void *parg = (void *)arg;
- long err = -EINVAL;
- int is_ext_ctrl;
- size_t ctrls_size = 0;
- void __user *user_ptr = NULL;
-
#ifdef __OLD_VIDIOC_
cmd = video_fix_command(cmd);
#endif
- is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
- cmd == VIDIOC_TRY_EXT_CTRLS);
-
- /* Copy arguments into temp kernel buffer */
- if (_IOC_DIR(cmd) != _IOC_NONE) {
- if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
- parg = sbuf;
- } else {
- /* too big to allocate from stack */
- mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
- if (NULL == mbuf)
- return -ENOMEM;
- parg = mbuf;
- }
-
- err = -EFAULT;
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- unsigned long n = cmd_input_size(cmd);
-
- if (copy_from_user(parg, (void __user *)arg, n))
- goto out;
-
- /* zero out anything we don't copy from userspace */
- if (n < _IOC_SIZE(cmd))
- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
- } else {
- /* read-only ioctl */
- memset(parg, 0, _IOC_SIZE(cmd));
- }
- }
-
- if (is_ext_ctrl) {
- struct v4l2_ext_controls *p = parg;
-
- /* In case of an error, tell the caller that it wasn't
- a specific control that caused it. */
- p->error_idx = p->count;
- user_ptr = (void __user *)p->controls;
- if (p->count) {
- ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
- /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
- mbuf = kmalloc(ctrls_size, GFP_KERNEL);
- err = -ENOMEM;
- if (NULL == mbuf)
- goto out_ext_ctrl;
- err = -EFAULT;
- if (copy_from_user(mbuf, user_ptr, ctrls_size))
- goto out_ext_ctrl;
- p->controls = mbuf;
- }
- }
-
- /* Handles IOCTL */
- err = __video_do_ioctl(file, cmd, parg);
- if (err == -ENOIOCTLCMD)
- err = -EINVAL;
- if (is_ext_ctrl) {
- struct v4l2_ext_controls *p = parg;
-
- p->controls = (void *)user_ptr;
- if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
- err = -EFAULT;
- goto out_ext_ctrl;
- }
- if (err < 0)
- goto out;
-
-out_ext_ctrl:
- /* Copy results into user buffer */
- switch (_IOC_DIR(cmd)) {
- case _IOC_READ:
- case (_IOC_WRITE | _IOC_READ):
- if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
- err = -EFAULT;
- break;
- }
-
-out:
- kfree(mbuf);
- return err;
+ return __video_usercopy(file, cmd, arg, __video_do_ioctl);
}
EXPORT_SYMBOL(video_ioctl2);
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:06 UTC
Permalink
v4l2_i2c_new_subdev_cfg is called by v4l2_i2c_new_subdev only. Merge the
two functions into v4l2_i2c_new_subdev.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
drivers/media/video/v4l2-common.c | 7 ++-----
include/media/v4l2-common.h | 15 +--------------
2 files changed, 3 insertions(+), 19 deletions(-)

diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 120b4ac..b504d3f 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -430,10 +430,9 @@ error:
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);

-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
- int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs)
{
struct i2c_board_info info;
@@ -443,13 +442,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
memset(&info, 0, sizeof(info));
strlcpy(info.type, client_type, sizeof(info.type));
info.addr = addr;
- info.irq = irq;
- info.platform_data = platform_data;

return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
&info, probe_addrs);
}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);

/* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 98b3264..6fc3d7a 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -139,24 +139,11 @@ struct v4l2_subdev_ops;
/* Load an i2c module and return an initialized v4l2_subdev struct.
Only call request_module if module_name != NULL.
The client_type argument is the name of the chip that's on the adapter. */
-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
- int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs);

-/* Load an i2c module and return an initialized v4l2_subdev struct.
- Only call request_module if module_name != NULL.
- The client_type argument is the name of the chip that's on the adapter. */
-static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
- u8 addr, const unsigned short *probe_addrs)
-{
- return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, module_name,
- client_type, 0, NULL, addr, probe_addrs);
-}
-
struct i2c_board_info;

struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:07 UTC
Permalink
Create a device node named subdevX for every registered subdev.

As the device node is registered before the subdev core::s_config
function is called, return -EGAIN on open until initialization
completes.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Vimarsh Zutshi <***@nokia.com>
---
Documentation/video4linux/v4l2-framework.txt | 18 +++++++
drivers/media/radio/radio-si4713.c | 2 +-
drivers/media/video/Makefile | 2 +-
drivers/media/video/davinci/vpfe_capture.c | 2 +-
drivers/media/video/davinci/vpif_capture.c | 2 +-
drivers/media/video/davinci/vpif_display.c | 2 +-
drivers/media/video/sh_vou.c | 2 +-
drivers/media/video/soc_camera.c | 2 +-
drivers/media/video/v4l2-common.c | 15 +++++-
drivers/media/video/v4l2-dev.c | 27 ++++------
drivers/media/video/v4l2-device.c | 24 +++++++++-
drivers/media/video/v4l2-ioctl.c | 2 +-
drivers/media/video/v4l2-subdev.c | 66 ++++++++++++++++++++++++++
include/media/v4l2-common.h | 6 ++-
include/media/v4l2-dev.h | 18 ++++++-
include/media/v4l2-ioctl.h | 3 +
include/media/v4l2-subdev.h | 16 ++++++-
17 files changed, 174 insertions(+), 35 deletions(-)
create mode 100644 drivers/media/video/v4l2-subdev.c

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index f5fdb39..3aed3a4 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -319,6 +319,24 @@ controlled through GPIO pins. This distinction is only relevant when setting
up the device, but once the subdev is registered it is completely transparent.


+V4L2 sub-device userspace API
+-----------------------------
+
+Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2
+sub-devices can also be controlled directly by userspace applications.
+
+When a sub-device is registered, a device node named v4l-subdevX can be created
+in /dev. If the sub-device supports direct userspace configuration it must set
+the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.
+
+For I2C and SPI sub-devices, the v4l2_device driver can disable registration of
+the device node if it wants to control the sub-device on its own. In that case
+it must set the v4l2_i2c_new_subdev_board or v4l2_spi_new_subdev enable_devnode
+argument to 0. Setting the argument to 1 will only enable device node
+registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE
+flag.
+
+
I2C sub-device drivers
----------------------

diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index 045b10f..83ae1f3 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -292,7 +292,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
}

sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL,
- pdata->subdev_board_info, NULL);
+ pdata->subdev_board_info, NULL, 0);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
rval = -ENODEV;
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2ea34a6..6f8a93d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o

videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o v4l2-ctrls.o
+ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o

# V4L2 core modules

diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index f68b66d..09f8bf7 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -1982,7 +1982,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
i2c_adap,
NULL,
&sdinfo->board_info,
- NULL);
+ NULL, 0);
if (vpfe_dev->sd[i]) {
v4l2_info(&vpfe_dev->v4l2_dev,
"v4l2 sub device %s registered\n",
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index cc881ca..aa02db3 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -2015,7 +2015,7 @@ static __init int vpif_probe(struct platform_device *pdev)
i2c_adap,
NULL,
&subdevdata->board_info,
- NULL);
+ NULL, 0);

if (!vpif_obj.sd[i]) {
vpif_err("Error registering v4l2 subdevice\n");
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 4be501b..3b67c24 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -1553,7 +1553,7 @@ static __init int vpif_probe(struct platform_device *pdev)
vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
i2c_adap, NULL,
&subdevdata[i].board_info,
- NULL);
+ NULL, 0);
if (!vpif_obj.sd[i]) {
vpif_err("Error registering v4l2 subdevice\n");
goto probe_subdev_out;
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index 4a8bf7a..9f10141 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -1392,7 +1392,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
goto ereset;

subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
- NULL, vou_pdata->board_info, NULL);
+ NULL, vou_pdata->board_info, NULL, 0);
if (!subdev) {
ret = -ENOMEM;
goto ei2cnd;
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 2b4a2d9..0aa90e8 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -895,7 +895,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
icl->board_info->platform_data = icd;

subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- NULL, icl->board_info, NULL);
+ NULL, icl->board_info, NULL, 0);
if (!subdev)
goto ei2cnd;

diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index b504d3f..6785fa7 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -369,7 +369,8 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs)
+ struct i2c_board_info *info, const unsigned short *probe_addrs,
+ int enable_devnode)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
@@ -401,9 +402,12 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
if (!try_module_get(client->driver->driver.owner))
goto error;
sd = i2c_get_clientdata(client);
+ if (!enable_devnode)
+ sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE;

/* Register with the v4l2_device which increases the module's
use count as well. */
+ sd->initialized = 0;
if (v4l2_device_register_subdev(v4l2_dev, sd))
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
@@ -418,6 +422,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
+ } else {
+ sd->initialized = 1;
}
}

@@ -444,7 +450,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
info.addr = addr;

return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
- &info, probe_addrs);
+ &info, probe_addrs, 0);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);

@@ -514,7 +520,8 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);

struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
- struct spi_master *master, struct spi_board_info *info)
+ struct spi_master *master, struct spi_board_info *info,
+ int enable_devnode)
{
struct v4l2_subdev *sd = NULL;
struct spi_device *spi = NULL;
@@ -533,6 +540,8 @@ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
goto error;

sd = spi_get_drvdata(spi);
+ if (!enable_devnode)
+ sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE;

/* Register with the v4l2_device which increases the module's
use count as well. */
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 773ffe1..166cfd8 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -376,13 +376,14 @@ static int get_index(struct video_device *vdev)
}

/**
- * video_register_device - register video4linux devices
+ * __video_register_device - register video4linux devices
* @vdev: video device structure we want to register
* @type: type of device to register
* @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...
* -1 == first free)
* @warn_if_nr_in_use: warn if the desired device node number
* was already in use and another number was chosen instead.
+ * @owner: module that owns the video device node
*
* The registration code assigns minor numbers and device node numbers
* based on the requested type and registers the new device node with
@@ -401,9 +402,11 @@ static int get_index(struct video_device *vdev)
* %VFL_TYPE_VBI - Vertical blank data (undecoded)
*
* %VFL_TYPE_RADIO - A radio card
+ *
+ * %VFL_TYPE_SUBDEV - A subdevice
*/
-static int __video_register_device(struct video_device *vdev, int type, int nr,
- int warn_if_nr_in_use)
+int __video_register_device(struct video_device *vdev, int type, int nr,
+ int warn_if_nr_in_use, struct module *owner)
{
int i = 0;
int ret;
@@ -439,6 +442,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
case VFL_TYPE_RADIO:
name_base = "radio";
break;
+ case VFL_TYPE_SUBDEV:
+ name_base = "v4l-subdev";
+ break;
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
__func__, type);
@@ -529,7 +535,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
vdev->cdev->ops = &v4l2_unlocked_fops;
else
vdev->cdev->ops = &v4l2_fops;
- vdev->cdev->owner = vdev->fops->owner;
+ vdev->cdev->owner = owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
if (ret < 0) {
printk(KERN_ERR "%s: cdev_add failed\n", __func__);
@@ -578,18 +584,7 @@ cleanup:
vdev->minor = -1;
return ret;
}
-
-int video_register_device(struct video_device *vdev, int type, int nr)
-{
- return __video_register_device(vdev, type, nr, 1);
-}
-EXPORT_SYMBOL(video_register_device);
-
-int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
-{
- return __video_register_device(vdev, type, nr, 0);
-}
-EXPORT_SYMBOL(video_register_device_no_warn);
+EXPORT_SYMBOL(__video_register_device);

/**
* video_unregister_device - unregister a video4linux device
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 0b08f96..318e911 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -116,24 +116,43 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
struct v4l2_subdev *sd)
{
+ struct video_device *vdev;
int err;

/* Check for valid input */
if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
return -EINVAL;
+
/* Warn if we apparently re-register a subdev */
WARN_ON(sd->v4l2_dev != NULL);
+
if (!try_module_get(sd->owner))
return -ENODEV;
+
/* This just returns 0 if either of the two args is NULL */
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
if (err)
return err;
+
sd->v4l2_dev = v4l2_dev;
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
spin_unlock(&v4l2_dev->lock);
- return 0;
+
+ /* Register the device node. */
+ vdev = &sd->devnode;
+ strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+ vdev->parent = v4l2_dev->dev;
+ vdev->fops = &v4l2_subdev_fops;
+ vdev->release = video_device_release_empty;
+ if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) {
+ err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+ sd->owner);
+ if (err < 0)
+ v4l2_device_unregister_subdev(sd);
+ }
+
+ return err;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);

@@ -142,10 +161,13 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
/* return if it isn't registered */
if (sd == NULL || sd->v4l2_dev == NULL)
return;
+
spin_lock(&sd->v4l2_dev->lock);
list_del(&sd->list);
spin_unlock(&sd->v4l2_dev->lock);
sd->v4l2_dev = NULL;
+
module_put(sd->owner);
+ video_unregister_device(&sd->devnode);
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 1e01554..4137e4c 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -413,7 +413,7 @@ static unsigned long cmd_input_size(unsigned int cmd)
}
}

-static long
+long
__video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
v4l2_kioctl func)
{
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
new file mode 100644
index 0000000..00bd4b1
--- /dev/null
+++ b/drivers/media/video/v4l2-subdev.c
@@ -0,0 +1,66 @@
+/*
+ * V4L2 subdevice support.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Laurent Pinchart <***@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+static int subdev_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+ if (!sd->initialized)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int subdev_close(struct file *file)
+{
+ return 0;
+}
+
+static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static long subdev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
+}
+
+const struct v4l2_file_operations v4l2_subdev_fops = {
+ .owner = THIS_MODULE,
+ .open = subdev_open,
+ .unlocked_ioctl = subdev_ioctl,
+ .release = subdev_close,
+};
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 6fc3d7a..496d158 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -148,7 +148,8 @@ struct i2c_board_info;

struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs);
+ struct i2c_board_info *info, const unsigned short *probe_addrs,
+ int enable_devnode);

/* Initialize an v4l2_subdev with data from an i2c_client struct */
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
@@ -181,7 +182,8 @@ struct spi_device;
/* Load an spi module and return an initialized v4l2_subdev struct.
The client_type argument is the name of the chip that's on the adapter. */
struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
- struct spi_master *master, struct spi_board_info *info);
+ struct spi_master *master, struct spi_board_info *info,
+ int enable_devnode);

/* Initialize an v4l2_subdev with data from an spi_device struct */
void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 1efcacb..96a2e6b 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -22,7 +22,8 @@
#define VFL_TYPE_VBI 1
#define VFL_TYPE_RADIO 2
#define VFL_TYPE_VTX 3
-#define VFL_TYPE_MAX 4
+#define VFL_TYPE_SUBDEV 4
+#define VFL_TYPE_MAX 5

struct v4l2_ioctl_callbacks;
struct video_device;
@@ -102,15 +103,26 @@ struct video_device
/* dev to video-device */
#define to_video_device(cd) container_of(cd, struct video_device, dev)

+int __must_check __video_register_device(struct video_device *vdev, int type,
+ int nr, int warn_if_nr_in_use, struct module *owner);
+
/* Register video devices. Note that if video_register_device fails,
the release() callback of the video_device structure is *not* called, so
the caller is responsible for freeing any data. Usually that means that
you call video_device_release() on failure. */
-int __must_check video_register_device(struct video_device *vdev, int type, int nr);
+static inline int __must_check video_register_device(struct video_device *vdev,
+ int type, int nr)
+{
+ return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
+}

/* Same as video_register_device, but no warning is issued if the desired
device node number was already in use. */
-int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr);
+static inline int __must_check video_register_device_no_warn(
+ struct video_device *vdev, int type, int nr)
+{
+ return __video_register_device(vdev, type, nr, 0, vdev->fops->owner);
+}

/* Unregister video devices. Will do nothing if vdev == NULL or
video_is_registered() returns false. */
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 06daa6e..abb64d0 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -316,6 +316,9 @@ extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd,
unsigned long arg);
#endif

+extern long __video_usercopy(struct file *file, unsigned int cmd,
+ unsigned long arg, v4l2_kioctl func);
+
/* Include support for obsoleted stuff */
extern long video_usercopy(struct file *file, unsigned int cmd,
unsigned long arg, v4l2_kioctl func);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 7694177..2f79002 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -22,6 +22,7 @@
#define _V4L2_SUBDEV_H

#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
#include <media/v4l2-mediabus.h>

/* generic v4l2_device notify callback notification values */
@@ -403,9 +404,11 @@ struct v4l2_subdev_ops {
#define V4L2_SUBDEV_NAME_SIZE 32

/* Set this flag if this subdev is a i2c device. */
-#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
/* Set this flag if this subdev is a spi device. */
-#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
+#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
+/* Set this flag if this subdev needs a device node. */
+#define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2)

/* Each instance of a subdev driver should create this struct, either
stand-alone or embedded in a larger struct.
@@ -425,8 +428,16 @@ struct v4l2_subdev {
/* pointer to private data */
void *dev_priv;
void *host_priv;
+ /* subdev device node */
+ struct video_device devnode;
+ unsigned int initialized;
};

+#define vdev_to_v4l2_subdev(vdev) \
+ container_of(vdev, struct v4l2_subdev, devnode)
+
+extern const struct v4l2_file_operations v4l2_subdev_fops;
+
static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
{
sd->dev_priv = p;
@@ -459,6 +470,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
sd->grp_id = 0;
sd->dev_priv = NULL;
sd->host_priv = NULL;
+ sd->initialized = 1;
}

/* Call an ops of a v4l2_subdev, doing the right checks against
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:08 UTC
Permalink
The function isn't small or performance sensitive enough to be inlined.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
drivers/media/video/v4l2-subdev.c | 42 +++++++++++++++++++++++++-----------
include/media/v4l2-subdev.h | 16 +------------
2 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 00bd4b1..0deff78 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -1,22 +1,23 @@
/*
- * V4L2 subdevice support.
+ * V4L2 sub-device
*
- * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010 Nokia Corporation
*
- * Contact: Laurent Pinchart <***@ideasonboard.com>
+ * Contact: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/types.h>
@@ -64,3 +65,18 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
.unlocked_ioctl = subdev_ioctl,
.release = subdev_close,
};
+
+void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+{
+ INIT_LIST_HEAD(&sd->list);
+ BUG_ON(!ops);
+ sd->ops = ops;
+ sd->v4l2_dev = NULL;
+ sd->flags = 0;
+ sd->name[0] = '\0';
+ sd->grp_id = 0;
+ sd->dev_priv = NULL;
+ sd->host_priv = NULL;
+ sd->initialized = 1;
+}
+EXPORT_SYMBOL(v4l2_subdev_init);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 2f79002..babcc85 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -458,20 +458,8 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
return sd->host_priv;
}

-static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
- const struct v4l2_subdev_ops *ops)
-{
- INIT_LIST_HEAD(&sd->list);
- BUG_ON(!ops);
- sd->ops = ops;
- sd->v4l2_dev = NULL;
- sd->flags = 0;
- sd->name[0] = '\0';
- sd->grp_id = 0;
- sd->dev_priv = NULL;
- sd->host_priv = NULL;
- sd->initialized = 1;
-}
+void v4l2_subdev_init(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_ops *ops);

/* Call an ops of a v4l2_subdev, doing the right checks against
NULL pointers.
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:09 UTC
Permalink
Pass the control-related ioctls to the subdev driver through the core
operations.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/video4linux/v4l2-framework.txt | 16 ++++++++++++++++
drivers/media/video/v4l2-subdev.c | 24 ++++++++++++++++++++++++
2 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 3aed3a4..33e7c92 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -336,6 +336,22 @@ argument to 0. Setting the argument to 1 will only enable device node
registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE
flag.

+The device node handles a subset of the V4L2 API.
+
+VIDIOC_QUERYCTRL
+VIDIOC_QUERYMENU
+VIDIOC_G_CTRL
+VIDIOC_S_CTRL
+VIDIOC_G_EXT_CTRLS
+VIDIOC_S_EXT_CTRLS
+VIDIOC_TRY_EXT_CTRLS
+
+ The controls ioctls are identical to the ones defined in V4L2. They
+ behave identically, with the only exception that they deal only with
+ controls implemented in the sub-device. Depending on the driver, those
+ controls can be also be accessed through one (or several) V4L2 device
+ nodes.
+

I2C sub-device drivers
----------------------
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 0deff78..806ec30 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -45,7 +45,31 @@ static int subdev_close(struct file *file)

static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
switch (cmd) {
+ case VIDIOC_QUERYCTRL:
+ return v4l2_subdev_call(sd, core, queryctrl, arg);
+
+ case VIDIOC_QUERYMENU:
+ return v4l2_subdev_call(sd, core, querymenu, arg);
+
+ case VIDIOC_G_CTRL:
+ return v4l2_subdev_call(sd, core, g_ctrl, arg);
+
+ case VIDIOC_S_CTRL:
+ return v4l2_subdev_call(sd, core, s_ctrl, arg);
+
+ case VIDIOC_G_EXT_CTRLS:
+ return v4l2_subdev_call(sd, core, g_ext_ctrls, arg);
+
+ case VIDIOC_S_EXT_CTRLS:
+ return v4l2_subdev_call(sd, core, s_ext_ctrls, arg);
+
+ case VIDIOC_TRY_EXT_CTRLS:
+ return v4l2_subdev_call(sd, core, try_ext_ctrls, arg);
+
default:
return -ENOIOCTLCMD;
}
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:10 UTC
Permalink
From: Sakari Ailus <***@maxwell.research.nokia.com>

Provide v4l2_subdevs with v4l2_event support. Subdev drivers only need very
little to support events.

Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
Signed-off-by: David Cohen <***@nokia.com>
Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/video4linux/v4l2-framework.txt | 18 ++++++
drivers/media/video/v4l2-subdev.c | 75 +++++++++++++++++++++++++-
include/media/v4l2-subdev.h | 10 ++++
3 files changed, 102 insertions(+), 1 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 33e7c92..774ce90 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -352,6 +352,24 @@ VIDIOC_TRY_EXT_CTRLS
controls can be also be accessed through one (or several) V4L2 device
nodes.

+VIDIOC_DQEVENT
+VIDIOC_SUBSCRIBE_EVENT
+VIDIOC_UNSUBSCRIBE_EVENT
+
+ The events ioctls are identical to the ones defined in V4L2. They
+ behave identically, with the only exception that they deal only with
+ events generated by the sub-device. Depending on the driver, those
+ events can also be reported by one (or several) V4L2 device nodes.
+
+ Sub-device drivers that want to use events need to set the
+ V4L2_SUBDEV_USES_EVENTS v4l2_subdev::flags and initialize
+ v4l2_subdev::nevents to events queue depth before registering the
+ sub-device. After registration events can be queued as usual on the
+ v4l2_subdev::devnode device node.
+
+ To properly support events, the poll() file operation is also
+ implemented.
+

I2C sub-device drivers
----------------------
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 806ec30..002281c 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -20,26 +20,68 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

-#include <linux/types.h>
#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/types.h>
#include <linux/videodev2.h>

#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>

static int subdev_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh;
+ int ret;

if (!sd->initialized)
return -EAGAIN;

+ if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
+ vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
+ if (vfh == NULL)
+ return -ENOMEM;
+
+ ret = v4l2_fh_init(vfh, vdev);
+ if (ret)
+ goto err;
+
+ ret = v4l2_event_init(vfh);
+ if (ret)
+ goto err;
+
+ ret = v4l2_event_alloc(vfh, sd->nevents);
+ if (ret)
+ goto err;
+
+ v4l2_fh_add(vfh);
+ file->private_data = vfh;
+ }
+
return 0;
+
+err:
+ if (vfh != NULL) {
+ v4l2_fh_exit(vfh);
+ kfree(vfh);
+ }
+
+ return ret;
}

static int subdev_close(struct file *file)
{
+ struct v4l2_fh *vfh = file->private_data;
+
+ if (vfh != NULL) {
+ v4l2_fh_del(vfh);
+ v4l2_fh_exit(vfh);
+ kfree(vfh);
+ }
+
return 0;
}

@@ -47,6 +89,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *fh = file->private_data;

switch (cmd) {
case VIDIOC_QUERYCTRL:
@@ -70,6 +113,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_TRY_EXT_CTRLS:
return v4l2_subdev_call(sd, core, try_ext_ctrls, arg);

+ case VIDIOC_DQEVENT:
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+
+ return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_SUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
+
default:
return -ENOIOCTLCMD;
}
@@ -83,11 +138,29 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
}

+static unsigned int subdev_poll(struct file *file, poll_table *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *fh = file->private_data;
+
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return POLLERR;
+
+ poll_wait(file, &fh->events->wait, wait);
+
+ if (v4l2_event_pending(fh))
+ return POLLPRI;
+
+ return 0;
+}
+
const struct v4l2_file_operations v4l2_subdev_fops = {
.owner = THIS_MODULE,
.open = subdev_open,
.unlocked_ioctl = subdev_ioctl,
.release = subdev_close,
+ .poll = subdev_poll,
};

void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index babcc85..4bd5c34 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -37,6 +37,8 @@

struct v4l2_device;
struct v4l2_ctrl_handler;
+struct v4l2_event_subscription;
+struct v4l2_fh;
struct v4l2_subdev;
struct tuner_setup;

@@ -135,6 +137,10 @@ struct v4l2_subdev_core_ops {
int (*s_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
#endif
int (*s_power)(struct v4l2_subdev *sd, int on);
+ int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub);
+ int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub);
};

/* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
@@ -409,6 +415,8 @@ struct v4l2_subdev_ops {
#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
/* Set this flag if this subdev needs a device node. */
#define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2)
+/* Set this flag if this subdev generates events. */
+#define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3)

/* Each instance of a subdev driver should create this struct, either
stand-alone or embedded in a larger struct.
@@ -431,6 +439,8 @@ struct v4l2_subdev {
/* subdev device node */
struct video_device devnode;
unsigned int initialized;
+ /* number of events to be allocated on open */
+ unsigned int nevents;
};

#define vdev_to_v4l2_subdev(vdev) \
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:11 UTC
Permalink
The media_devnode structure provides support for registering and
unregistering character devices using a dynamic major number. Reference
counting is handled internally, making device drivers easier to write
without having to solve the open/disconnect race condition issue over
and over again.

The code is based on video/v4l2-dev.c.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
drivers/media/Kconfig | 13 ++
drivers/media/Makefile | 10 +-
drivers/media/media-devnode.c | 321 +++++++++++++++++++++++++++++++++++++++++
include/media/media-devnode.h | 97 +++++++++++++
4 files changed, 439 insertions(+), 2 deletions(-)
create mode 100644 drivers/media/media-devnode.c
create mode 100644 include/media/media-devnode.h

diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index a28541b..6b946e6 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -14,6 +14,19 @@ if MEDIA_SUPPORT
comment "Multimedia core support"

#
+# Media controller
+#
+
+config MEDIA_CONTROLLER
+ bool "Media Controller API (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ Enable the media controller API used to query media devices internal
+ topology and configure it dynamically.
+
+ This API is mostly used by camera interfaces in embedded platforms.
+
+#
# V4L core and enabled API's
#

diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 499b081..3a08991 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,7 +2,13 @@
# Makefile for the kernel multimedia device drivers.
#

+media-objs := media-devnode.o
+
+ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+ obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+endif
+
obj-y += common/ IR/ video/

-obj-$(CONFIG_VIDEO_DEV) += radio/
-obj-$(CONFIG_DVB_CORE) += dvb/
+obj-$(CONFIG_VIDEO_DEV) += radio/
+obj-$(CONFIG_DVB_CORE) += dvb/
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
new file mode 100644
index 0000000..7804b70
--- /dev/null
+++ b/drivers/media/media-devnode.c
@@ -0,0 +1,321 @@
+/*
+ * Media device node
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Based on drivers/media/video/v4l2_dev.c code authored by
+ * Mauro Carvalho Chehab <***@infradead.org> (version 2)
+ * Alan Cox, <***@lxorguk.ukuu.org.uk> (version 1)
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * --
+ *
+ * Generic media device node infrastructure to register and unregister
+ * character devices using a dynamic major number and proper reference
+ * counting.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <media/media-devnode.h>
+
+#define MEDIA_NUM_DEVICES 256
+#define MEDIA_NAME "media"
+
+static dev_t media_dev_t;
+
+/*
+ * Active devices
+ */
+static DEFINE_MUTEX(media_devnode_lock);
+static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
+
+/* Called when the last user of the media device exits. */
+static void media_devnode_release(struct device *cd)
+{
+ struct media_devnode *mdev = to_media_devnode(cd);
+
+ mutex_lock(&media_devnode_lock);
+
+ /* Delete the cdev on this minor as well */
+ cdev_del(&mdev->cdev);
+
+ /* Mark device node number as free */
+ clear_bit(mdev->minor, media_devnode_nums);
+
+ mutex_unlock(&media_devnode_lock);
+
+ /* Release media_devnode and perform other cleanups as needed. */
+ if (mdev->release)
+ mdev->release(mdev);
+}
+
+static struct bus_type media_bus_type = {
+ .name = MEDIA_NAME,
+};
+
+static ssize_t media_read(struct file *filp, char __user *buf,
+ size_t sz, loff_t *off)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+
+ if (!mdev->fops->read)
+ return -EINVAL;
+ if (!media_devnode_is_registered(mdev))
+ return -EIO;
+ return mdev->fops->read(filp, buf, sz, off);
+}
+
+static ssize_t media_write(struct file *filp, const char __user *buf,
+ size_t sz, loff_t *off)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+
+ if (!mdev->fops->write)
+ return -EINVAL;
+ if (!media_devnode_is_registered(mdev))
+ return -EIO;
+ return mdev->fops->write(filp, buf, sz, off);
+}
+
+static unsigned int media_poll(struct file *filp,
+ struct poll_table_struct *poll)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+
+ if (!media_devnode_is_registered(mdev))
+ return POLLERR | POLLHUP;
+ if (!mdev->fops->poll)
+ return DEFAULT_POLLMASK;
+ return mdev->fops->poll(filp, poll);
+}
+
+static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+
+ if (!mdev->fops->ioctl)
+ return -ENOTTY;
+
+ if (!media_devnode_is_registered(mdev))
+ return -EIO;
+
+ return mdev->fops->ioctl(filp, cmd, arg);
+}
+
+/* Override for the open function */
+static int media_open(struct inode *inode, struct file *filp)
+{
+ struct media_devnode *mdev;
+ int ret;
+
+ /* Check if the media device is available. This needs to be done with
+ * the media_devnode_lock held to prevent an open/unregister race:
+ * without the lock, the device could be unregistered and freed between
+ * the media_devnode_is_registered() and get_device() calls, leading to
+ * a crash.
+ */
+ mutex_lock(&media_devnode_lock);
+ mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
+ /* return ENXIO if the media device has been removed
+ already or if it is not registered anymore. */
+ if (!media_devnode_is_registered(mdev)) {
+ mutex_unlock(&media_devnode_lock);
+ return -ENXIO;
+ }
+ /* and increase the device refcount */
+ get_device(&mdev->dev);
+ mutex_unlock(&media_devnode_lock);
+
+ filp->private_data = mdev;
+
+ if (mdev->fops->open) {
+ ret = mdev->fops->open(filp);
+ if (ret) {
+ put_device(&mdev->dev);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Override for the release function */
+static int media_release(struct inode *inode, struct file *filp)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+ int ret = 0;
+
+ if (mdev->fops->release)
+ mdev->fops->release(filp);
+
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+ put_device(&mdev->dev);
+ filp->private_data = NULL;
+ return ret;
+}
+
+static const struct file_operations media_devnode_fops = {
+ .owner = THIS_MODULE,
+ .read = media_read,
+ .write = media_write,
+ .open = media_open,
+ .unlocked_ioctl = media_ioctl,
+ .release = media_release,
+ .poll = media_poll,
+ .llseek = no_llseek,
+};
+
+/**
+ * media_devnode_register - register a media device node
+ * @mdev: media device node structure we want to register
+ *
+ * The registration code assigns minor numbers and registers the new device node
+ * with the kernel. An error is returned if no free minor number can be found,
+ * or if the registration of the device node fails.
+ *
+ * Zero is returned on success.
+ *
+ * Note that if the media_devnode_register call fails, the release() callback of
+ * the media_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
+int __must_check media_devnode_register(struct media_devnode *mdev)
+{
+ int minor;
+ int ret;
+
+ /* Part 1: Find a free minor number */
+ mutex_lock(&media_devnode_lock);
+ minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES);
+ if (minor == MEDIA_NUM_DEVICES) {
+ mutex_unlock(&media_devnode_lock);
+ printk(KERN_ERR "could not get a free minor\n");
+ return -ENFILE;
+ }
+
+ set_bit(mdev->minor, media_devnode_nums);
+ mutex_unlock(&media_devnode_lock);
+
+ mdev->minor = minor;
+
+ /* Part 2: Initialize and register the character device */
+ cdev_init(&mdev->cdev, &media_devnode_fops);
+ mdev->cdev.owner = mdev->fops->owner;
+
+ ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+ goto error;
+ }
+
+ /* Part 3: Register the media device */
+ mdev->dev.bus = &media_bus_type;
+ mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
+ mdev->dev.release = media_devnode_release;
+ if (mdev->parent)
+ mdev->dev.parent = mdev->parent;
+ dev_set_name(&mdev->dev, "media%d", mdev->minor);
+ ret = device_register(&mdev->dev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: device_register failed\n", __func__);
+ goto error;
+ }
+
+ /* Part 4: Activate this minor. The char device can now be used. */
+ set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+
+ return 0;
+
+error:
+ cdev_del(&mdev->cdev);
+ clear_bit(mdev->minor, media_devnode_nums);
+ return ret;
+}
+
+/**
+ * media_devnode_unregister - unregister a media device node
+ * @mdev: the device node to unregister
+ *
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+ *
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
+void media_devnode_unregister(struct media_devnode *mdev)
+{
+ /* Check if mdev was ever registered at all */
+ if (!media_devnode_is_registered(mdev))
+ return;
+
+ mutex_lock(&media_devnode_lock);
+ clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+ mutex_unlock(&media_devnode_lock);
+ device_unregister(&mdev->dev);
+}
+
+/*
+ * Initialise media for linux
+ */
+static int __init media_devnode_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Linux media interface: v0.10\n");
+ ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
+ MEDIA_NAME);
+ if (ret < 0) {
+ printk(KERN_WARNING "media: unable to allocate major\n");
+ return ret;
+ }
+
+ ret = bus_register(&media_bus_type);
+ if (ret < 0) {
+ unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
+ printk(KERN_WARNING "media: bus_register failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void __exit media_devnode_exit(void)
+{
+ bus_unregister(&media_bus_type);
+ unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
+}
+
+module_init(media_devnode_init)
+module_exit(media_devnode_exit)
+
+MODULE_AUTHOR("Laurent Pinchart <***@ideasonboard.com>");
+MODULE_DESCRIPTION("Device node registration for media drivers");
+MODULE_LICENSE("GPL");
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
new file mode 100644
index 0000000..01cd034
--- /dev/null
+++ b/include/media/media-devnode.h
@@ -0,0 +1,97 @@
+/*
+ * Media device node
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * --
+ *
+ * Common functions for media-related drivers to register and unregister media
+ * device nodes.
+ */
+
+#ifndef _MEDIA_DEVNODE_H
+#define _MEDIA_DEVNODE_H
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+/*
+ * Flag to mark the media_devnode struct as registered. Drivers must not touch
+ * this flag directly, it will be set and cleared by media_devnode_register and
+ * media_devnode_unregister.
+ */
+#define MEDIA_FLAG_REGISTERED 0
+
+struct media_file_operations {
+ struct module *owner;
+ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ long (*ioctl) (struct file *, unsigned int, unsigned long);
+ int (*open) (struct file *);
+ int (*release) (struct file *);
+};
+
+/**
+ * struct media_devnode - Media device node
+ * @parent: parent device
+ * @minor: device node minor number
+ * @flags: flags, combination of the MEDIA_FLAG_* constants
+ *
+ * This structure represents a media-related device node.
+ *
+ * The @parent is a physical device. It must be set by core or device drivers
+ * before registering the node.
+ */
+struct media_devnode {
+ /* device ops */
+ const struct media_file_operations *fops;
+
+ /* sysfs */
+ struct device dev; /* media device */
+ struct cdev cdev; /* character device */
+ struct device *parent; /* device parent */
+
+ /* device info */
+ int minor;
+ unsigned long flags; /* Use bitops to access flags */
+
+ /* callbacks */
+ void (*release)(struct media_devnode *mdev);
+};
+
+/* dev to media_devnode */
+#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+
+int __must_check media_devnode_register(struct media_devnode *mdev);
+void media_devnode_unregister(struct media_devnode *mdev);
+
+static inline struct media_devnode *media_devnode_data(struct file *filp)
+{
+ return filp->private_data;
+}
+
+static inline int media_devnode_is_registered(struct media_devnode *mdev)
+{
+ return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+}
+
+#endif /* _MEDIA_DEVNODE_H */
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:12 UTC
Permalink
The media_device structure abstracts functions common to all kind of
media devices (v4l2, dvb, alsa, ...). It manages media entities and
offers a userspace API to discover and configure the media device
internal topology.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/DocBook/media-entities.tmpl | 2 +
Documentation/DocBook/media.tmpl | 3 +
Documentation/DocBook/v4l/media-controller.xml | 56 +++++++++++++
Documentation/media-framework.txt | 68 ++++++++++++++++
drivers/media/Makefile | 2 +-
drivers/media/media-device.c | 100 ++++++++++++++++++++++++
include/media/media-device.h | 66 ++++++++++++++++
7 files changed, 296 insertions(+), 1 deletions(-)
create mode 100644 Documentation/DocBook/v4l/media-controller.xml
create mode 100644 Documentation/media-framework.txt
create mode 100644 drivers/media/media-device.c
create mode 100644 include/media/media-device.h

diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index 5d4d40f4..ccc7b2d 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -317,6 +317,8 @@
<!ENTITY sub-media-entities SYSTEM "media-entities.tmpl">
<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">

+<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
+
<!-- Function Reference -->
<!ENTITY close SYSTEM "v4l/func-close.xml">
<!ENTITY ioctl SYSTEM "v4l/func-ioctl.xml">
diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
index eea564b..1ea39ed 100644
--- a/Documentation/DocBook/media.tmpl
+++ b/Documentation/DocBook/media.tmpl
@@ -106,6 +106,9 @@ Foundation. A copy of the license is included in the chapter entitled
&sub-remote_controllers;
</chapter>
</part>
+<part id="media_common">
+&sub-media-controller;
+</part>

&sub-fdl-appendix;

diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
new file mode 100644
index 0000000..253ddb4
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -0,0 +1,56 @@
+<partinfo>
+ <authorgroup>
+ <author>
+ <firstname>Laurent</firstname>
+ <surname>Pinchart</surname>
+ <affiliation><address><email>***@ideasonboard.com</email></address></affiliation>
+ <contrib>Initial version.</contrib>
+ </author>
+ </authorgroup>
+ <copyright>
+ <year>2010</year>
+ <holder>Laurent Pinchart</holder>
+ </copyright>
+
+ <revhistory>
+ <!-- Put document revisions here, newest first. -->
+ <revision>
+ <revnumber>1.0.0</revnumber>
+ <date>2010-11-10</date>
+ <authorinitials>lp</authorinitials>
+ <revremark>Initial revision</revremark>
+ </revision>
+ </revhistory>
+</partinfo>
+
+<title>Media Controller API</title>
+
+<chapter id="media_controller">
+ <title>Media Controller</title>
+
+ <section id="media-controller-intro">
+ <title>Introduction</title>
+ <para>Media devices increasingly handle multiple related functions. Many USB
+ cameras include microphones, video capture hardware can also output video,
+ or SoC camera interfaces also perform memory-to-memory operations similar to
+ video codecs.</para>
+ <para>Independent functions, even when implemented in the same hardware, can
+ be modelled as separate devices. A USB camera with a microphone will be
+ presented to userspace applications as V4L2 and ALSA capture devices. The
+ devices' relationships (when using a webcam, end-users shouldn't have to
+ manually select the associated USB microphone), while not made available
+ directly to applications by the drivers, can usually be retrieved from
+ sysfs.</para>
+ <para>With more and more advanced SoC devices being introduced, the current
+ approach will not scale. Device topologies are getting increasingly complex
+ and can't always be represented by a tree structure. Hardware blocks are
+ shared between different functions, creating dependencies between seemingly
+ unrelated devices.</para>
+ <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
+ applications to access hardware parameters. As newer hardware expose an
+ increasingly high number of those parameters, drivers need to guess what
+ applications really require based on limited information, thereby
+ implementing policies that belong to userspace.</para>
+ <para>The media controller API aims at solving those problems.</para>
+ </section>
+</chapter>
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
new file mode 100644
index 0000000..84fa43a
--- /dev/null
+++ b/Documentation/media-framework.txt
@@ -0,0 +1,68 @@
+Linux kernel media framework
+============================
+
+This document describes the Linux kernel media framework, its data structures,
+functions and their usage.
+
+
+Introduction
+------------
+
+The media controller API is documented in DocBook format in
+Documentation/DocBook/v4l/media-controller.xml. This document will focus on
+the kernel-side implementation of the media framework.
+
+
+Media device
+------------
+
+A media device is represented by a struct media_device instance, defined in
+include/media/media-device.h. Allocation of the structure is handled by the
+media device driver, usually by embedding the media_device instance in a
+larger driver-specific structure.
+
+Drivers register media device instances by calling
+
+ media_device_register(struct media_device *mdev);
+
+The caller is responsible for initializing the media_device structure before
+registration. The following fields must be set:
+
+ - dev must point to the parent device (usually a pci_dev, usb_interface or
+ platform_device instance).
+
+ - model must be filled with the device model name as a NUL-terminated UTF-8
+ string. The device/model revision must not be stored in this field.
+
+The following fields are optional:
+
+ - serial is a unique serial number stored as a NUL-terminated ASCII string.
+ The field is big enough to store a GUID in text form. If the hardware
+ doesn't provide a unique serial number this field must be left empty.
+
+ - bus_info represents the location of the device in the system as a
+ NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
+ "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
+ the usb_make_path() function must be used. This field is used by
+ applications to distinguish between otherwise identical devices that don't
+ provide a serial number.
+
+ - hw_revision is the hardware device revision in a driver-specific format.
+ When possible the revision should be formatted with the KERNEL_VERSION
+ macro.
+
+ - driver_version is formatted with the KERNEL_VERSION macro. The version
+ minor must be incremented when new features are added to the userspace API
+ without breaking binary compatibility. The version major must be
+ incremented when binary compatibility is broken.
+
+Upon successful registration a character device named media[0-9]+ is created.
+The device major and minor numbers are dynamic. The model name is exported as
+a sysfs attribute.
+
+Drivers unregister media device instances by calling
+
+ media_device_unregister(struct media_device *mdev);
+
+Unregistering a media device that hasn't been registered is *NOT* safe.
+
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 3a08991..019d3e0 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel multimedia device drivers.
#

-media-objs := media-devnode.o
+media-objs := media-device.o media-devnode.o

ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
obj-$(CONFIG_MEDIA_SUPPORT) += media.o
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
new file mode 100644
index 0000000..57a9c6b
--- /dev/null
+++ b/drivers/media/media-device.c
@@ -0,0 +1,100 @@
+/*
+ * Media device
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#include <media/media-device.h>
+#include <media/media-devnode.h>
+
+static const struct media_file_operations media_device_fops = {
+ .owner = THIS_MODULE,
+};
+
+/* -----------------------------------------------------------------------------
+ * sysfs
+ */
+
+static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct media_device *mdev = to_media_device(to_media_devnode(cd));
+
+ return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
+}
+
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+/* -----------------------------------------------------------------------------
+ * Registration/unregistration
+ */
+
+static void media_device_release(struct media_devnode *mdev)
+{
+}
+
+/**
+ * media_device_register - register a media device
+ * @mdev: The media device
+ *
+ * The caller is responsible for initializing the media device before
+ * registration. The following fields must be set:
+ *
+ * - dev must point to the parent device
+ * - model must be filled with the device model name
+ */
+int __must_check media_device_register(struct media_device *mdev)
+{
+ int ret;
+
+ if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
+ return -EINVAL;
+
+ /* Register the device node. */
+ mdev->devnode.fops = &media_device_fops;
+ mdev->devnode.parent = mdev->dev;
+ mdev->devnode.release = media_device_release;
+ ret = media_devnode_register(&mdev->devnode);
+ if (ret < 0)
+ return ret;
+
+ ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
+ if (ret < 0) {
+ media_devnode_unregister(&mdev->devnode);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register);
+
+/**
+ * media_device_unregister - unregister a media device
+ * @mdev: The media device
+ *
+ */
+void media_device_unregister(struct media_device *mdev)
+{
+ device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+ media_devnode_unregister(&mdev->devnode);
+}
+EXPORT_SYMBOL_GPL(media_device_unregister);
diff --git a/include/media/media-device.h b/include/media/media-device.h
new file mode 100644
index 0000000..930a17a
--- /dev/null
+++ b/include/media/media-device.h
@@ -0,0 +1,66 @@
+/*
+ * Media device
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MEDIA_DEVICE_H
+#define _MEDIA_DEVICE_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+
+#include <media/media-devnode.h>
+
+/**
+ * struct media_device - Media device
+ * @dev: Parent device
+ * @devnode: Media device node
+ * @model: Device model name
+ * @serial: Device serial number (optional)
+ * @bus_info: Unique and stable device location identifier
+ * @hw_revision: Hardware device revision
+ * @driver_version: Device driver version
+ *
+ * This structure represents an abstract high-level media device. It allows easy
+ * access to entities and provides basic media device-level support. The
+ * structure can be allocated directly or embedded in a larger structure.
+ *
+ * The parent @dev is a physical device. It must be set before registering the
+ * media device.
+ *
+ * @model is a descriptive model name exported through sysfs. It doesn't have to
+ * be unique.
+ */
+struct media_device {
+ /* dev->driver_data points to this struct. */
+ struct device *dev;
+ struct media_devnode devnode;
+
+ u8 model[32];
+ u8 serial[40];
+ u8 bus_info[32];
+ u32 hw_revision;
+ u32 driver_version;
+};
+
+int __must_check media_device_register(struct media_device *mdev);
+void media_device_unregister(struct media_device *mdev);
+
+#endif
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:13 UTC
Permalink
As video hardware pipelines become increasingly complex and
configurable, the current hardware description through v4l2 subdevices
reaches its limits. In addition to enumerating and configuring
subdevices, video camera drivers need a way to discover and modify at
runtime how those subdevices are connected. This is done through new
elements called entities, pads and links.

An entity is a basic media hardware building block. It can correspond to
a large variety of logical blocks such as physical hardware devices
(CMOS sensor for instance), logical hardware devices (a building block
in a System-on-Chip image processing pipeline), DMA channels or physical
connectors.

A pad is a connection endpoint through which an entity can interact with
other entities. Data (not restricted to video) produced by an entity
flows from the entity's output to one or more entity inputs. Pads should
not be confused with physical pins at chip boundaries.

A link is a point-to-point oriented connection between two pads, either
on the same entity or on different entities. Data flows from a source
pad to a sink pad.

Links are stored in the source entity. To make backwards graph walk
faster, a copy of all links is also stored in the sink entity. The copy
is known as a backlink and is only used to help graph traversal.

The entity API is made of three functions:

- media_entity_init() initializes an entity. The caller must provide an
array of pads as well as an estimated number of links. The links array
is allocated dynamically and will be reallocated if it grows beyond the
initial estimate.

- media_entity_cleanup() frees resources allocated for an entity. It
must be called during the cleanup phase after unregistering the entity
and before freeing it.

- media_entity_create_link() creates a link between two entities. An
entry in the link array of each entity is allocated and stores pointers
to source and sink pads.

When a media device is unregistered, all its entities are unregistered
automatically.

The code is based on Hans Verkuil <***@xs4all.nl> initial work.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/DocBook/v4l/media-controller.xml | 20 +++
Documentation/media-framework.txt | 149 ++++++++++++++++++++++++
drivers/media/Makefile | 2 +-
drivers/media/media-device.c | 53 +++++++++
drivers/media/media-entity.c | 147 +++++++++++++++++++++++
include/media/media-device.h | 19 +++
include/media/media-entity.h | 118 +++++++++++++++++++
7 files changed, 507 insertions(+), 1 deletions(-)
create mode 100644 drivers/media/media-entity.c
create mode 100644 include/media/media-entity.h

diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
index 253ddb4..f89228d 100644
--- a/Documentation/DocBook/v4l/media-controller.xml
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -53,4 +53,24 @@
implementing policies that belong to userspace.</para>
<para>The media controller API aims at solving those problems.</para>
</section>
+
+ <section id="media-controller-model">
+ <title>Media device model</title>
+ <para>Discovering a device internal topology, and configuring it at runtime,
+ is one of the goals of the media controller API. To achieve this, hardware
+ devices are modelled as an oriented graph of building blocks called entities
+ connected through pads.</para>
+ <para>An entity is a basic media hardware or software building block. It can
+ correspond to a large variety of logical blocks such as physical hardware
+ devices (CMOS sensor for instance), logical hardware devices (a building
+ block in a System-on-Chip image processing pipeline), DMA channels or
+ physical connectors.</para>
+ <para>A pad is a connection endpoint through which an entity can interact
+ with other entities. Data (not restricted to video) produced by an entity
+ flows from the entity's output to one or more entity inputs. Pads should not
+ be confused with physical pins at chip boundaries.</para>
+ <para>A link is a point-to-point oriented connection between two pads,
+ either on the same entity or on different entities. Data flows from a source
+ pad to a sink pad.</para>
+ </section>
</chapter>
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 84fa43a..0332162 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -13,6 +13,30 @@ Documentation/DocBook/v4l/media-controller.xml. This document will focus on
the kernel-side implementation of the media framework.


+Abstract media device model
+---------------------------
+
+Discovering a device internal topology, and configuring it at runtime, is one
+of the goals of the media framework. To achieve this, hardware devices are
+modeled as an oriented graph of building blocks called entities connected
+through pads.
+
+An entity is a basic media hardware building block. It can correspond to
+a large variety of logical blocks such as physical hardware devices
+(CMOS sensor for instance), logical hardware devices (a building block
+in a System-on-Chip image processing pipeline), DMA channels or physical
+connectors.
+
+A pad is a connection endpoint through which an entity can interact with
+other entities. Data (not restricted to video) produced by an entity
+flows from the entity's output to one or more entity inputs. Pads should
+not be confused with physical pins at chip boundaries.
+
+A link is a point-to-point oriented connection between two pads, either
+on the same entity or on different entities. Data flows from a source
+pad to a sink pad.
+
+
Media device
------------

@@ -66,3 +90,128 @@ Drivers unregister media device instances by calling

Unregistering a media device that hasn't been registered is *NOT* safe.

+
+Entities, pads and links
+------------------------
+
+- Entities
+
+Entities are represented by a struct media_entity instance, defined in
+include/media/media-entity.h. The structure is usually embedded into a
+higher-level structure, such as a v4l2_subdev or video_device instance,
+although drivers can allocate entities directly.
+
+Drivers initialize entities by calling
+
+ media_entity_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads, u16 extra_links);
+
+The media_entity name, type, flags, revision and group_id fields can be
+initialized before or after calling media_entity_init. Entities embedded in
+higher-level standard structures can have some of those fields set by the
+higher-level framework.
+
+As the number of pads is known in advance, the pads array is not allocated
+dynamically but is managed by the entity driver. Most drivers will embed the
+pads array in a driver-specific structure, avoiding dynamic allocation.
+
+Drivers must set the direction of every pad in the pads array before calling
+media_entity_init. The function will initialize the other pads fields.
+
+Unlike the number of pads, the total number of links isn't always known in
+advance by the entity driver. As an initial estimate, media_entity_init
+pre-allocates a number of links equal to the number of pads plus an optional
+number of extra links. The links array will be reallocated if it grows beyond
+the initial estimate.
+
+Drivers register entities with a media device by calling
+
+ media_device_register_entity(struct media_device *mdev,
+ struct media_entity *entity);
+
+When registered the entity is assigned an ID. Entity IDs are positive integers
+and are guaranteed to be unique in the context of the media device. The
+framework doesn't guarantee that IDs will always be continuous.
+
+Drivers unregister entities by calling
+
+ media_device_unregister_entity(struct media_entity *entity);
+
+Unregistering an entity will not change the IDs of the other entities, and the
+ID will never be reused for a newly registered entity.
+
+When a media device is unregistered, all its entities are unregistered
+automatically. No manual entities unregistration is then required.
+
+Drivers free resources associated with an entity by calling
+
+ media_entity_cleanup(struct media_entity *entity);
+
+This function must be called during the cleanup phase after unregistering the
+entity. Note that the media_entity instance itself must be freed explicitly by
+the driver if required.
+
+Entities have flags that describe the entity capabilities and state.
+
+ MEDIA_ENTITY_FLAG_DEFAULT indicates the default entity for a given
+ type. This can be used to report the default audio and video devices
+ or the default camera sensor.
+
+Logical entity groups can be defined by setting the group ID of all member
+entities to the same non-zero value. An entity group serves no purpose in the
+kernel, but is reported to userspace during entities enumeration. The group_id
+field belongs to the media device driver and must not by touched by entity
+drivers.
+
+Media device drivers should define groups if several entities are logically
+bound together. Example usages include reporting
+
+ - ALSA, VBI and video nodes that carry the same media stream
+ - lens and flash controllers associated with a sensor
+
+- Pads
+
+Pads are represented by a struct media_pad instance, defined in
+include/media/media-entity.h. Each entity stores its pads in a pads array
+managed by the entity driver. Drivers usually embed the array in a
+driver-specific structure.
+
+Pads are identified by their entity and their 0-based index in the pads array.
+Both information are stored in the media_pad structure, making the media_pad
+pointer the canonical way to store and pass link references.
+
+Pads have flags that describe the pad capabilities and state.
+
+ MEDIA_PAD_FLAG_INPUT indicates that the pad supports sinking data.
+ MEDIA_PAD_FLAG_OUTPUT indicates that the pad supports sourcing data.
+
+One and only one of MEDIA_PAD_FLAG_INPUT and MEDIA_PAD_FLAG_OUTPUT must be set
+for each pad.
+
+- Links
+
+Links are represented by a struct media_link instance, defined in
+include/media/media-entity.h. Each entity stores all links originating at or
+targetting any of its pads in a links array. A given link is thus stored
+twice, once in the source entity and once in the target entity. The array is
+pre-allocated and grows dynamically as needed.
+
+Drivers create links by calling
+
+ media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad,
+ u32 flags);
+
+An entry in the link array of each entity is allocated and stores pointers
+to source and sink pads.
+
+Links have flags that describe the link capabilities and state.
+
+ MEDIA_LINK_FLAG_ACTIVE indicates that the link is active and can be
+ used to transfer media data. When two or more links target a sink pad,
+ only one of them can be active at a time.
+ MEDIA_LINK_FLAG_IMMUTABLE indicates that the link active state can't
+ be modified at runtime. If MEDIA_LINK_FLAG_IMMUTABLE is set, then
+ MEDIA_LINK_FLAG_ACTIVE must also be set since an immutable link is
+ always active.
+
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 019d3e0..b890248 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel multimedia device drivers.
#

-media-objs := media-device.o media-devnode.o
+media-objs := media-device.o media-devnode.o media-entity.o

ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
obj-$(CONFIG_MEDIA_SUPPORT) += media.o
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 57a9c6b..2163610 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -25,6 +25,7 @@

#include <media/media-device.h>
#include <media/media-devnode.h>
+#include <media/media-entity.h>

static const struct media_file_operations media_device_fops = {
.owner = THIS_MODULE,
@@ -69,6 +70,10 @@ int __must_check media_device_register(struct media_device *mdev)
if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
return -EINVAL;

+ mdev->entity_id = 1;
+ INIT_LIST_HEAD(&mdev->entities);
+ spin_lock_init(&mdev->lock);
+
/* Register the device node. */
mdev->devnode.fops = &media_device_fops;
mdev->devnode.parent = mdev->dev;
@@ -94,7 +99,55 @@ EXPORT_SYMBOL_GPL(media_device_register);
*/
void media_device_unregister(struct media_device *mdev)
{
+ struct media_entity *entity;
+ struct media_entity *next;
+
+ list_for_each_entry_safe(entity, next, &mdev->entities, list)
+ media_device_unregister_entity(entity);
+
device_remove_file(&mdev->devnode.dev, &dev_attr_model);
media_devnode_unregister(&mdev->devnode);
}
EXPORT_SYMBOL_GPL(media_device_unregister);
+
+/**
+ * media_device_register_entity - Register an entity with a media device
+ * @mdev: The media device
+ * @entity: The entity
+ */
+int __must_check media_device_register_entity(struct media_device *mdev,
+ struct media_entity *entity)
+{
+ /* Warn if we apparently re-register an entity */
+ WARN_ON(entity->parent != NULL);
+ entity->parent = mdev;
+
+ spin_lock(&mdev->lock);
+ entity->id = mdev->entity_id++;
+ list_add_tail(&entity->list, &mdev->entities);
+ spin_unlock(&mdev->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register_entity);
+
+/**
+ * media_device_unregister_entity - Unregister an entity
+ * @entity: The entity
+ *
+ * If the entity has never been registered this function will return
+ * immediately.
+ */
+void media_device_unregister_entity(struct media_entity *entity)
+{
+ struct media_device *mdev = entity->parent;
+
+ if (mdev == NULL)
+ return;
+
+ spin_lock(&mdev->lock);
+ list_del(&entity->list);
+ spin_unlock(&mdev->lock);
+ entity->parent = NULL;
+}
+EXPORT_SYMBOL_GPL(media_device_unregister_entity);
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
new file mode 100644
index 0000000..e4ba2bc
--- /dev/null
+++ b/drivers/media/media-entity.c
@@ -0,0 +1,147 @@
+/*
+ * Media entity
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <media/media-entity.h>
+
+/**
+ * media_entity_init - Initialize a media entity
+ *
+ * @num_pads: Total number of input and output pads.
+ * @extra_links: Initial estimate of the number of extra links.
+ * @pads: Array of 'num_pads' pads.
+ *
+ * The total number of pads is an intrinsic property of entities known by the
+ * entity driver, while the total number of links depends on hardware design
+ * and is an extrinsic property unknown to the entity driver. However, in most
+ * use cases the entity driver can guess the number of links which can safely
+ * be assumed to be equal to or larger than the number of pads.
+ *
+ * For those reasons the links array can be preallocated based on the entity
+ * driver guess and will be reallocated later if extra links need to be
+ * created.
+ *
+ * This function allocates a links array with enough space to hold at least
+ * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will
+ * be set to the number of allocated elements.
+ *
+ * The pads array is managed by the entity driver and passed to
+ * media_entity_init() where its pointer will be stored in the entity structure.
+ */
+int
+media_entity_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads, u16 extra_links)
+{
+ struct media_link *links;
+ unsigned int max_links = num_pads + extra_links;
+ unsigned int i;
+
+ links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL);
+ if (links == NULL)
+ return -ENOMEM;
+
+ entity->group_id = 0;
+ entity->max_links = max_links;
+ entity->num_links = 0;
+ entity->num_backlinks = 0;
+ entity->num_pads = num_pads;
+ entity->pads = pads;
+ entity->links = links;
+
+ for (i = 0; i < num_pads; i++) {
+ pads[i].entity = entity;
+ pads[i].index = i;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_entity_init);
+
+void
+media_entity_cleanup(struct media_entity *entity)
+{
+ kfree(entity->links);
+}
+EXPORT_SYMBOL_GPL(media_entity_cleanup);
+
+static struct media_link *media_entity_add_link(struct media_entity *entity)
+{
+ if (entity->num_links >= entity->max_links) {
+ struct media_link *links = entity->links;
+ unsigned int max_links = entity->max_links + 2;
+ unsigned int i;
+
+ links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
+ if (links == NULL)
+ return NULL;
+
+ for (i = 0; i < entity->num_links; i++)
+ links[i].reverse->reverse = &links[i];
+
+ entity->max_links = max_links;
+ entity->links = links;
+ }
+
+ return &entity->links[entity->num_links++];
+}
+
+int
+media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad, u32 flags)
+{
+ struct media_link *link;
+ struct media_link *backlink;
+
+ BUG_ON(source == NULL || sink == NULL);
+ BUG_ON(source_pad >= source->num_pads);
+ BUG_ON(sink_pad >= sink->num_pads);
+
+ link = media_entity_add_link(source);
+ if (link == NULL)
+ return -ENOMEM;
+
+ link->source = &source->pads[source_pad];
+ link->sink = &sink->pads[sink_pad];
+ link->flags = flags;
+
+ /* Create the backlink. Backlinks are used to help graph traversal and
+ * are not reported to userspace.
+ */
+ backlink = media_entity_add_link(sink);
+ if (backlink == NULL) {
+ source->num_links--;
+ return -ENOMEM;
+ }
+
+ backlink->source = &source->pads[source_pad];
+ backlink->sink = &sink->pads[sink_pad];
+ backlink->flags = flags;
+
+ link->reverse = backlink;
+ backlink->reverse = link;
+
+ sink->num_backlinks++;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(media_entity_create_link);
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 930a17a..acd6a29 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -25,8 +25,10 @@

#include <linux/device.h>
#include <linux/list.h>
+#include <linux/spinlock.h>

#include <media/media-devnode.h>
+#include <media/media-entity.h>

/**
* struct media_device - Media device
@@ -37,6 +39,9 @@
* @bus_info: Unique and stable device location identifier
* @hw_revision: Hardware device revision
* @driver_version: Device driver version
+ * @entity_id: ID of the next entity to be registered
+ * @entities: List of registered entities
+ * @lock: Entities list lock
*
* This structure represents an abstract high-level media device. It allows easy
* access to entities and provides basic media device-level support. The
@@ -58,9 +63,23 @@ struct media_device {
u8 bus_info[32];
u32 hw_revision;
u32 driver_version;
+
+ u32 entity_id;
+ struct list_head entities;
+
+ /* Protects the entities list */
+ spinlock_t lock;
};

int __must_check media_device_register(struct media_device *mdev);
void media_device_unregister(struct media_device *mdev);

+int __must_check media_device_register_entity(struct media_device *mdev,
+ struct media_entity *entity);
+void media_device_unregister_entity(struct media_entity *entity);
+
+/* Iterate over all entities. */
+#define media_device_for_each_entity(entity, mdev) \
+ list_for_each_entry(entity, &(mdev)->entities, list)
+
#endif
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
new file mode 100644
index 0000000..60b4f09
--- /dev/null
+++ b/include/media/media-entity.h
@@ -0,0 +1,118 @@
+/*
+ * Media entity
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MEDIA_ENTITY_H
+#define _MEDIA_ENTITY_H
+
+#include <linux/list.h>
+
+#define MEDIA_ENTITY_TYPE_SHIFT 16
+#define MEDIA_ENTITY_TYPE_MASK 0x00ff0000
+#define MEDIA_ENTITY_SUBTYPE_MASK 0x0000ffff
+
+#define MEDIA_ENTITY_TYPE_NODE (1 << MEDIA_ENTITY_TYPE_SHIFT)
+#define MEDIA_ENTITY_TYPE_NODE_V4L (MEDIA_ENTITY_TYPE_NODE + 1)
+#define MEDIA_ENTITY_TYPE_NODE_FB (MEDIA_ENTITY_TYPE_NODE + 2)
+#define MEDIA_ENTITY_TYPE_NODE_ALSA (MEDIA_ENTITY_TYPE_NODE + 3)
+#define MEDIA_ENTITY_TYPE_NODE_DVB (MEDIA_ENTITY_TYPE_NODE + 4)
+
+#define MEDIA_ENTITY_TYPE_SUBDEV (2 << MEDIA_ENTITY_TYPE_SHIFT)
+#define MEDIA_ENTITY_TYPE_SUBDEV_SENSOR (MEDIA_ENTITY_TYPE_SUBDEV + 1)
+#define MEDIA_ENTITY_TYPE_SUBDEV_FLASH (MEDIA_ENTITY_TYPE_SUBDEV + 2)
+#define MEDIA_ENTITY_TYPE_SUBDEV_LENS (MEDIA_ENTITY_TYPE_SUBDEV + 3)
+
+#define MEDIA_ENTITY_FLAG_DEFAULT (1 << 0)
+
+#define MEDIA_LINK_FLAG_ACTIVE (1 << 0)
+#define MEDIA_LINK_FLAG_IMMUTABLE (1 << 1)
+
+#define MEDIA_PAD_FLAG_INPUT (1 << 0)
+#define MEDIA_PAD_FLAG_OUTPUT (1 << 1)
+
+struct media_link {
+ struct media_pad *source; /* Source pad */
+ struct media_pad *sink; /* Sink pad */
+ struct media_link *reverse; /* Link in the reverse direction */
+ unsigned long flags; /* Link flags (MEDIA_LINK_FLAG_*) */
+};
+
+struct media_pad {
+ struct media_entity *entity; /* Entity this pad belongs to */
+ u16 index; /* Pad index in the entity pads array */
+ unsigned long flags; /* Pad flags (MEDIA_PAD_FLAG_*) */
+};
+
+struct media_entity {
+ struct list_head list;
+ struct media_device *parent; /* Media device this entity belongs to*/
+ u32 id; /* Entity ID, unique in the parent media
+ * device context */
+ const char *name; /* Entity name */
+ u32 type; /* Entity type (MEDIA_ENTITY_TYPE_*) */
+ u32 revision; /* Entity revision, driver specific */
+ unsigned long flags; /* Entity flags (MEDIA_ENTITY_FLAG_*) */
+ u32 group_id; /* Entity group ID */
+
+ u16 num_pads; /* Number of input and output pads */
+ u16 num_links; /* Number of existing links, both active
+ * and inactive */
+ u16 num_backlinks; /* Number of backlinks */
+ u16 max_links; /* Maximum number of links */
+
+ struct media_pad *pads; /* Pads array (num_pads elements) */
+ struct media_link *links; /* Links array (max_links elements)*/
+
+ union {
+ /* Node specifications */
+ struct {
+ u32 major;
+ u32 minor;
+ } v4l;
+ struct {
+ u32 major;
+ u32 minor;
+ } fb;
+ int alsa;
+ int dvb;
+
+ /* Sub-device specifications */
+ /* Nothing needed yet */
+ };
+};
+
+static inline u32 media_entity_type(struct media_entity *entity)
+{
+ return entity->type & MEDIA_ENTITY_TYPE_MASK;
+}
+
+static inline u32 media_entity_subtype(struct media_entity *entity)
+{
+ return entity->type & MEDIA_ENTITY_SUBTYPE_MASK;
+}
+
+int media_entity_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads, u16 extra_links);
+void media_entity_cleanup(struct media_entity *entity);
+int media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad, u32 flags);
+
+#endif
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:14 UTC
Permalink
From: Sakari Ailus <***@maxwell.research.nokia.com>

Add media entity graph traversal. The traversal follows active links by
depth first. Traversing graph backwards is prevented by comparing the next
possible entity in the graph with the previous one. Multiply connected
graphs are thus not supported.

Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Vimarsh Zutshi <***@nokia.com>
---
Documentation/media-framework.txt | 42 +++++++++++++
drivers/media/media-entity.c | 115 +++++++++++++++++++++++++++++++++++++
include/media/media-entity.h | 15 +++++
3 files changed, 172 insertions(+), 0 deletions(-)

diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 0332162..27a38a1 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -215,3 +215,45 @@ Links have flags that describe the link capabilities and state.
MEDIA_LINK_FLAG_ACTIVE must also be set since an immutable link is
always active.

+
+Graph traversal
+---------------
+
+The media framework provides APIs to iterate over entities in a graph.
+
+To iterate over all entities belonging to a media device, drivers can use the
+media_device_for_each_entity macro, defined in include/media/media-device.h.
+
+ struct media_entity *entity;
+
+ media_device_for_each_entity(entity, mdev) {
+ /* entity will point to each entity in turn */
+ ...
+ }
+
+Drivers might also need to iterate over all entities in a graph that can be
+reached only through active links starting at a given entity. The media
+framework provides a depth-first graph traversal API for that purpose.
+
+Note that graphs with cycles (whether directed or undirected) are *NOT*
+supported by the graph traversal API. To prevent infinite loops, the graph
+traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
+currently defined as 16.
+
+Drivers initiate a graph traversal by calling
+
+ media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *entity);
+
+The graph structure, provided by the caller, is initialized to start graph
+traversal at the given entity.
+
+Drivers can then retrieve the next entity by calling
+
+ media_entity_graph_walk_next(struct media_entity_graph *graph);
+
+When the graph traversal is complete the function will return NULL.
+
+Graph traversal can be interrupted at any moment. No cleanup function call is
+required and the graph structure can be freed normally.
+
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index e4ba2bc..6230f74 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -84,6 +84,121 @@ media_entity_cleanup(struct media_entity *entity)
}
EXPORT_SYMBOL_GPL(media_entity_cleanup);

+/* -----------------------------------------------------------------------------
+ * Graph traversal
+ */
+
+static struct media_entity *
+media_entity_other(struct media_entity *entity, struct media_link *link)
+{
+ if (link->source->entity == entity)
+ return link->sink->entity;
+ else
+ return link->source->entity;
+}
+
+/* push an entity to traversal stack */
+static void stack_push(struct media_entity_graph *graph,
+ struct media_entity *entity)
+{
+ if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
+ WARN_ON(1);
+ return;
+ }
+ graph->top++;
+ graph->stack[graph->top].link = 0;
+ graph->stack[graph->top].entity = entity;
+}
+
+static struct media_entity *stack_pop(struct media_entity_graph *graph)
+{
+ struct media_entity *entity;
+
+ entity = graph->stack[graph->top].entity;
+ graph->top--;
+
+ return entity;
+}
+
+#define stack_peek(en) ((en)->stack[(en)->top - 1].entity)
+#define link_top(en) ((en)->stack[(en)->top].link)
+#define stack_top(en) ((en)->stack[(en)->top].entity)
+
+/**
+ * media_entity_graph_walk_start - Start walking the media graph at a given entity
+ * @graph: Media graph structure that will be used to walk the graph
+ * @entity: Starting entity
+ *
+ * This function initializes the graph traversal structure to walk the entities
+ * graph starting at the given entity. The traversal structure must not be
+ * modified by the caller during graph traversal. When done the structure can
+ * safely be freed.
+ */
+void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *entity)
+{
+ graph->top = 0;
+ graph->stack[graph->top].entity = NULL;
+ stack_push(graph, entity);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
+
+/**
+ * media_entity_graph_walk_next - Get the next entity in the graph
+ * @graph: Media graph structure
+ *
+ * Perform a depth-first traversal of the given media entities graph.
+ *
+ * The graph structure must have been previously initialized with a call to
+ * media_entity_graph_walk_start().
+ *
+ * Return the next entity in the graph or NULL if the whole graph have been
+ * traversed.
+ */
+struct media_entity *
+media_entity_graph_walk_next(struct media_entity_graph *graph)
+{
+ if (stack_top(graph) == NULL)
+ return NULL;
+
+ /*
+ * Depth first search. Push entity to stack and continue from
+ * top of the stack until no more entities on the level can be
+ * found.
+ */
+ while (link_top(graph) < stack_top(graph)->num_links) {
+ struct media_entity *entity = stack_top(graph);
+ struct media_link *link = &entity->links[link_top(graph)];
+ struct media_entity *next;
+
+ /* The link is not active so we do not follow. */
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE)) {
+ link_top(graph)++;
+ continue;
+ }
+
+ /* Get the entity in the other end of the link . */
+ next = media_entity_other(entity, link);
+
+ /* Was it the entity we came here from? */
+ if (next == stack_peek(graph)) {
+ link_top(graph)++;
+ continue;
+ }
+
+ /* Push the new entity to stack and start over. */
+ link_top(graph)++;
+ stack_push(graph, next);
+ }
+
+ return stack_pop(graph);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+
+/* -----------------------------------------------------------------------------
+ * Links management
+ */
+
static struct media_link *media_entity_add_link(struct media_entity *entity)
{
if (entity->num_links >= entity->max_links) {
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 60b4f09..721f450 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -109,10 +109,25 @@ static inline u32 media_entity_subtype(struct media_entity *entity)
return entity->type & MEDIA_ENTITY_SUBTYPE_MASK;
}

+#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
+
+struct media_entity_graph {
+ struct {
+ struct media_entity *entity;
+ int link;
+ } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
+ int top;
+};
+
int media_entity_init(struct media_entity *entity, u16 num_pads,
struct media_pad *pads, u16 extra_links);
void media_entity_cleanup(struct media_entity *entity);
int media_entity_create_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags);

+void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *entity);
+struct media_entity *
+media_entity_graph_walk_next(struct media_entity_graph *graph);
+
#endif
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:15 UTC
Permalink
From: Sakari Ailus <***@maxwell.research.nokia.com>

Basically these are the interface functions:

media_entity_get() - acquire entity
media_entity_put() - release entity

If the entity is of node type, the power change is distributed to
all connected entities. For non-nodes it only affects that very
node. A mutex is used to serialise access to the entity graph.

In the background there's a depth-first search algorithm that traverses the
active links in the graph. All these functions parse the graph to implement
whatever they're to do.

The module counters are increased/decreased in media_entity_get/put to
prevent module unloading when an entity is referenced.

Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Stanimir Varbanov <***@mm-sol.com>
---
Documentation/media-framework.txt | 37 +++++++++
drivers/media/media-device.c | 1 +
drivers/media/media-entity.c | 146 +++++++++++++++++++++++++++++++++++++
include/media/media-device.h | 4 +
include/media/media-entity.h | 15 ++++
5 files changed, 203 insertions(+), 0 deletions(-)

diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 27a38a1..9fdbc50 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -257,3 +257,40 @@ When the graph traversal is complete the function will return NULL.
Graph traversal can be interrupted at any moment. No cleanup function call is
required and the graph structure can be freed normally.

+
+Reference counting and power handling
+-------------------------------------
+
+Before accessing type-specific entities operations (such as the V4L2
+sub-device operations), drivers must acquire a reference to the entity. This
+ensures that the entity will be powered on and ready to accept requests.
+Similarly, after being done with an entity, drivers must release the
+reference.
+
+ media_entity_get(struct media_entity *entity)
+
+The function will increase the entity reference count. If the entity is a node
+(MEDIA_ENTITY_TYPE_NODE type), the reference count of all entities it is
+connected to, both directly or indirectly, through active links is increased.
+This ensures that the whole media pipeline will be ready to process
+
+Acquiring a reference to an entity increases the media device module reference
+count to prevent module unloading when an entity is being used.
+
+media_entity_get will return a pointer to the entity if successful, or NULL
+otherwise.
+
+ media_entity_put(struct media_entity *entity)
+
+The function will decrease the entity reference count and, for node entities,
+like media_entity_get, the reference count of all connected entities. Calling
+media_entity_put with a NULL argument is valid and will return immediately.
+
+When the first reference to an entity is acquired, or the last reference
+released, the entity's set_power operation is called. Entity drivers must
+implement the operation if they need to perform any power management task,
+such as turning powers or clocks on or off. If no power management is
+required, drivers don't need to provide a set_power operation. The operation
+is allowed to fail when turning power on, in which case the media_entity_get
+function will return NULL.
+
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 2163610..52e5985 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -73,6 +73,7 @@ int __must_check media_device_register(struct media_device *mdev)
mdev->entity_id = 1;
INIT_LIST_HEAD(&mdev->entities);
spin_lock_init(&mdev->lock);
+ mutex_init(&mdev->graph_mutex);

/* Register the device node. */
mdev->devnode.fops = &media_device_fops;
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 6230f74..c15f16b 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <media/media-entity.h>
+#include <media/media-device.h>

/**
* media_entity_init - Initialize a media entity
@@ -196,6 +197,151 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);

/* -----------------------------------------------------------------------------
+ * Power state handling
+ */
+
+/* Apply use count to an entity. */
+static void media_entity_use_apply_one(struct media_entity *entity, int change)
+{
+ entity->use_count += change;
+ WARN_ON(entity->use_count < 0);
+}
+
+/*
+ * Apply use count change to an entity and change power state based on
+ * new use count.
+ */
+static int media_entity_power_apply_one(struct media_entity *entity, int change)
+{
+ int ret;
+
+ if (entity->use_count == 0 && change > 0 &&
+ entity->ops && entity->ops->set_power) {
+ ret = entity->ops->set_power(entity, 1);
+ if (ret)
+ return ret;
+ }
+
+ media_entity_use_apply_one(entity, change);
+
+ if (entity->use_count == 0 && change < 0 &&
+ entity->ops && entity->ops->set_power)
+ entity->ops->set_power(entity, 0);
+
+ return 0;
+}
+
+/*
+ * Apply power change to all connected entities. This ignores the
+ * nodes.
+ */
+static int media_entity_power_apply(struct media_entity *entity, int change)
+{
+ struct media_entity_graph graph;
+ struct media_entity *first = entity;
+ int ret = 0;
+
+ if (!change)
+ return 0;
+
+ media_entity_graph_walk_start(&graph, entity);
+
+ while (!ret && (entity = media_entity_graph_walk_next(&graph)))
+ if (media_entity_type(entity) != MEDIA_ENTITY_TYPE_NODE)
+ ret = media_entity_power_apply_one(entity, change);
+
+ if (!ret)
+ return 0;
+
+ media_entity_graph_walk_start(&graph, first);
+
+ while ((first = media_entity_graph_walk_next(&graph))
+ && first != entity)
+ if (media_entity_type(first) != MEDIA_ENTITY_TYPE_NODE)
+ media_entity_power_apply_one(first, -change);
+
+ return ret;
+}
+
+/*
+ * Apply use count change to graph and change power state of entities
+ * accordingly.
+ */
+static int media_entity_node_power_change(struct media_entity *entity,
+ int change)
+{
+ /* Apply use count to node. */
+ media_entity_use_apply_one(entity, change);
+
+ /* Apply power change to connected non-nodes. */
+ return media_entity_power_apply(entity, change);
+}
+
+/*
+ * Node entity use changes are reflected on power state of all
+ * connected (directly or indirectly) entities whereas non-node entity
+ * use count changes are limited to that very entity.
+ */
+static int media_entity_use_change(struct media_entity *entity, int change)
+{
+ if (media_entity_type(entity) == MEDIA_ENTITY_TYPE_NODE)
+ return media_entity_node_power_change(entity, change);
+ else
+ return media_entity_power_apply_one(entity, change);
+}
+
+static struct media_entity *__media_entity_get(struct media_entity *entity)
+{
+ if (media_entity_use_change(entity, 1))
+ return NULL;
+
+ return entity;
+}
+
+static void __media_entity_put(struct media_entity *entity)
+{
+ media_entity_use_change(entity, -1);
+}
+
+/* user open()s media entity */
+struct media_entity *media_entity_get(struct media_entity *entity)
+{
+ struct media_entity *e;
+
+ if (entity == NULL)
+ return NULL;
+
+ if (entity->parent->dev &&
+ !try_module_get(entity->parent->dev->driver->owner))
+ return NULL;
+
+ mutex_lock(&entity->parent->graph_mutex);
+ e = __media_entity_get(entity);
+ mutex_unlock(&entity->parent->graph_mutex);
+
+ if (e == NULL && entity->parent->dev)
+ module_put(entity->parent->dev->driver->owner);
+
+ return e;
+}
+EXPORT_SYMBOL_GPL(media_entity_get);
+
+/* user release()s media entity */
+void media_entity_put(struct media_entity *entity)
+{
+ if (entity == NULL)
+ return;
+
+ mutex_lock(&entity->parent->graph_mutex);
+ __media_entity_put(entity);
+ mutex_unlock(&entity->parent->graph_mutex);
+
+ if (entity->parent->dev)
+ module_put(entity->parent->dev->driver->owner);
+}
+EXPORT_SYMBOL_GPL(media_entity_put);
+
+/* -----------------------------------------------------------------------------
* Links management
*/

diff --git a/include/media/media-device.h b/include/media/media-device.h
index acd6a29..461cb29 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -25,6 +25,7 @@

#include <linux/device.h>
#include <linux/list.h>
+#include <linux/mutex.h>
#include <linux/spinlock.h>

#include <media/media-devnode.h>
@@ -42,6 +43,7 @@
* @entity_id: ID of the next entity to be registered
* @entities: List of registered entities
* @lock: Entities list lock
+ * @graph_mutex: Entities graph operation lock
*
* This structure represents an abstract high-level media device. It allows easy
* access to entities and provides basic media device-level support. The
@@ -69,6 +71,8 @@ struct media_device {

/* Protects the entities list */
spinlock_t lock;
+ /* Serializes graph operations. */
+ struct mutex graph_mutex;
};

int __must_check media_device_register(struct media_device *mdev);
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 721f450..b9694b5 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -61,6 +61,10 @@ struct media_pad {
unsigned long flags; /* Pad flags (MEDIA_PAD_FLAG_*) */
};

+struct media_entity_operations {
+ int (*set_power)(struct media_entity *entity, int power);
+};
+
struct media_entity {
struct list_head list;
struct media_device *parent; /* Media device this entity belongs to*/
@@ -81,6 +85,10 @@ struct media_entity {
struct media_pad *pads; /* Pads array (num_pads elements) */
struct media_link *links; /* Links array (max_links elements)*/

+ const struct media_entity_operations *ops; /* Entity operations */
+
+ int use_count; /* Use count for the entity. */
+
union {
/* Node specifications */
struct {
@@ -125,9 +133,16 @@ void media_entity_cleanup(struct media_entity *entity);
int media_entity_create_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags);

+struct media_entity *media_entity_get(struct media_entity *entity);
+void media_entity_put(struct media_entity *entity);
+
void media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity);
struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph);

+#define media_entity_call(entity, operation, args...) \
+ (((entity)->ops && (entity)->ops->operation) ? \
+ (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
+
#endif
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:16 UTC
Permalink
Create the following ioctl and implement it at the media device level to
query device information.

- MEDIA_IOC_DEVICE_INFO: Query media device information

The ioctl and its data structure are defined in the new kernel header
linux/media.h available to userspace applications.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/DocBook/media-entities.tmpl | 12 ++
Documentation/DocBook/v4l/media-controller.xml | 10 ++
Documentation/DocBook/v4l/media-func-close.xml | 59 +++++++++
Documentation/DocBook/v4l/media-func-ioctl.xml | 116 +++++++++++++++++
Documentation/DocBook/v4l/media-func-open.xml | 94 ++++++++++++++
.../DocBook/v4l/media-ioc-device-info.xml | 132 ++++++++++++++++++++
drivers/media/media-device.c | 57 +++++++++
include/linux/Kbuild | 1 +
include/linux/media.h | 45 +++++++
include/media/media-device.h | 3 +
10 files changed, 529 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/media-func-close.xml
create mode 100644 Documentation/DocBook/v4l/media-func-ioctl.xml
create mode 100644 Documentation/DocBook/v4l/media-func-open.xml
create mode 100644 Documentation/DocBook/v4l/media-ioc-device-info.xml
create mode 100644 include/linux/media.h

diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index ccc7b2d..9ea1dc9 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -11,6 +11,10 @@
<!ENTITY func-select "<link linkend='func-select'><function>select()</function></link>">
<!ENTITY func-write "<link linkend='func-write'><function>write()</function></link>">

+<!ENTITY media-func-close "<link linkend='media-func-close'><function>close()</function></link>">
+<!ENTITY media-func-ioctl "<link linkend='media-func-ioctl'><function>ioctl()</function></link>">
+<!ENTITY media-func-open "<link linkend='media-func-open'><function>open()</function></link>">
+
<!-- Ioctls -->
<!ENTITY VIDIOC-CROPCAP "<link linkend='vidioc-cropcap'><constant>VIDIOC_CROPCAP</constant></link>">
<!ENTITY VIDIOC-DBG-G-CHIP-IDENT "<link linkend='vidioc-dbg-g-chip-ident'><constant>VIDIOC_DBG_G_CHIP_IDENT</constant></link>">
@@ -87,6 +91,8 @@
<!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
<!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">

+<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
+
<!-- Types -->
<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">

@@ -181,6 +187,8 @@
<!ENTITY v4l2-vbi-format "struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link>">
<!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">

+<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
+
<!-- Error Codes -->
<!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
<!ENTITY EAGAIN "<errorcode>EAGAIN</errorcode> error code">
@@ -318,6 +326,10 @@
<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">

<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
+<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
+<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
+<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
+<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">

<!-- Function Reference -->
<!ENTITY close SYSTEM "v4l/func-close.xml">
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
index f89228d..a46b786 100644
--- a/Documentation/DocBook/v4l/media-controller.xml
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -74,3 +74,13 @@
pad to a sink pad.</para>
</section>
</chapter>
+
+<appendix id="media-user-func">
+ <title>Function Reference</title>
+ <!-- Keep this alphabetically sorted. -->
+ &sub-media-open;
+ &sub-media-close;
+ &sub-media-ioctl;
+ <!-- All ioctls go here. -->
+ &sub-media-ioc-device-info;
+</appendix>
diff --git a/Documentation/DocBook/v4l/media-func-close.xml b/Documentation/DocBook/v4l/media-func-close.xml
new file mode 100644
index 0000000..be149c8
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-func-close.xml
@@ -0,0 +1,59 @@
+<refentry id="media-func-close">
+ <refmeta>
+ <refentrytitle>media close()</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>media-close</refname>
+ <refpurpose>Close a media device</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>int <function>close</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>Closes the media device. Resources associated with the file descriptor
+ are freed. The device configuration remain unchanged.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para><function>close</function> returns 0 on success. On error, -1 is
+ returned, and <varname>errno</varname> is set appropriately. Possible error
+ codes are:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBADF</errorcode></term>
+ <listitem>
+ <para><parameter>fd</parameter> is not a valid open file descriptor.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-func-ioctl.xml b/Documentation/DocBook/v4l/media-func-ioctl.xml
new file mode 100644
index 0000000..bda8604
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-func-ioctl.xml
@@ -0,0 +1,116 @@
+<refentry id="media-func-ioctl">
+ <refmeta>
+ <refentrytitle>media ioctl()</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>media-ioctl</refname>
+ <refpurpose>Control a media device</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>void *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>Media ioctl request code as defined in the media.h header file,
+ for example MEDIA_IOC_SETUP_LINK.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para>Pointer to a request-specific structure.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+ <para>The <function>ioctl()</function> function manipulates media device
+ parameters. The argument <parameter>fd</parameter> must be an open file
+ descriptor.</para>
+ <para>The ioctl <parameter>request</parameter> code specifies the media
+ function to be called. It has encoded in it whether the argument is an
+ input, output or read/write parameter, and the size of the argument
+ <parameter>argp</parameter> in bytes.</para>
+ <para>Macros and structures definitions specifying media ioctl requests and
+ their parameters are located in the media.h header file. All media ioctl
+ requests, their respective function and parameters are specified in
+ <xref linkend="media-user-func" />.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para><function>ioctl()</function> returns <returnvalue>0</returnvalue> on
+ success. On failure, <returnvalue>-1</returnvalue> is returned, and the
+ <varname>errno</varname> variable is set appropriately. Generic error codes
+ are listed below, and request-specific error codes are listed in the
+ individual requests descriptions.</para>
+ <para>When an ioctl that takes an output or read/write parameter fails,
+ the parameter remains unmodified.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBADF</errorcode></term>
+ <listitem>
+ <para><parameter>fd</parameter> is not a valid open file descriptor.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EFAULT</errorcode></term>
+ <listitem>
+ <para><parameter>argp</parameter> references an inaccessible memory
+ area.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The <parameter>request</parameter> or the data pointed to by
+ <parameter>argp</parameter> is not valid. This is a very common error
+ code, see the individual ioctl requests listed in
+ <xref linkend="media-user-func" /> for actual causes.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENOMEM</errorcode></term>
+ <listitem>
+ <para>Insufficient kernel memory was available to complete the
+ request.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENOTTY</errorcode></term>
+ <listitem>
+ <para><parameter>fd</parameter> is not associated with a character
+ special device.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-func-open.xml b/Documentation/DocBook/v4l/media-func-open.xml
new file mode 100644
index 0000000..f7df034
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-func-open.xml
@@ -0,0 +1,94 @@
+<refentry id="media-func-open">
+ <refmeta>
+ <refentrytitle>media open()</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>media-open</refname>
+ <refpurpose>Open a media device</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>int <function>open</function></funcdef>
+ <paramdef>const char *<parameter>device_name</parameter></paramdef>
+ <paramdef>int <parameter>flags</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>device_name</parameter></term>
+ <listitem>
+ <para>Device to be opened.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>flags</parameter></term>
+ <listitem>
+ <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
+ or <constant>O_RDWR</constant>. Other flags have no effect.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>Description</title>
+ <para>To open a media device applications call <function>open()</function>
+ with the desired device name. The function has no side effects; the device
+ configuration remain unchanged.</para>
+ <para>When the device is opened in read-only mode, attemps to modify its
+ configuration will result in an error, and <varname>errno</varname> will be
+ set to <errorcode>EBADF</errorcode>.</para>
+ </refsect1>
+ <refsect1>
+ <title>Return Value</title>
+
+ <para><function>open</function> returns the new file descriptor on success.
+ On error, -1 is returned, and <varname>errno</varname> is set appropriately.
+ Possible error codes are:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EACCES</errorcode></term>
+ <listitem>
+ <para>The requested access to the file is not allowed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EMFILE</errorcode></term>
+ <listitem>
+ <para>The process already has the maximum number of files open.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENFILE</errorcode></term>
+ <listitem>
+ <para>The system limit on the total number of open files has been
+ reached.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENOMEM</errorcode></term>
+ <listitem>
+ <para>Insufficient kernel memory was available.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENXIO</errorcode></term>
+ <listitem>
+ <para>No device corresponding to this device special file exists.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
new file mode 100644
index 0000000..ffd0fb8
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml
@@ -0,0 +1,132 @@
+<refentry id="media-ioc-device-info">
+ <refmeta>
+ <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>MEDIA_IOC_DEVICE_INFO</refname>
+ <refpurpose>Query device information</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct media_device_info *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>MEDIA_IOC_DEVICE_INFO</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
+ ioctl. To query device information, applications call the ioctl with a
+ pointer to a &media-device-info;. The driver fills the structure and returns
+ the information to the application.
+ The ioctl never fails.</para>
+
+ <table pgwide="1" frame="none" id="media-device-info">
+ <title>struct <structname>media_device_info</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u8</entry>
+ <entry><structfield>driver</structfield>[16]</entry>
+ <entry><para>Name of the driver implementing the media API as a
+ NUL-terminated ASCII string. The driver version is stored in the
+ <structfield>driver_version</structfield> field.</para>
+ <para>Driver specific applications can use this information to
+ verify the driver identity. It is also useful to work around
+ known bugs, or to identify drivers in error reports.</para></entry>
+ </row>
+ <row>
+ <entry>__u8</entry>
+ <entry><structfield>model</structfield>[32]</entry>
+ <entry>Device model name as a NUL-terminated UTF-8 string. The
+ device version is stored in the <structfield>device_version</structfield>
+ field and is not be appended to the model name.</entry>
+ </row>
+ <row>
+ <entry>__u8</entry>
+ <entry><structfield>serial</structfield>[40]</entry>
+ <entry>Serial number as a NUL-terminated ASCII string.</entry>
+ </row>
+ <row>
+ <entry>__u8</entry>
+ <entry><structfield>bus_info</structfield>[32]</entry>
+ <entry>Location of the device in the system as a NUL-terminated
+ ASCII string. This includes the bus type name (PCI, USB, ...) and a
+ bus-specific identifier.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>media_version</structfield></entry>
+ <entry>Media API version, formatted with the
+ <constant>KERNEL_VERSION()</constant> macro.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>hw_revision</structfield></entry>
+ <entry>Hardware device revision in a driver-specific format.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>media_version</structfield></entry>
+ <entry>Media device driver version, formatted with the
+ <constant>KERNEL_VERSION()</constant> macro. Together with the
+ <structfield>driver</structfield> field this identifies a particular
+ driver.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[31]</entry>
+ <entry>Reserved for future extensions. Drivers and applications must
+ set this array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
+ fields can be used to distinguish between multiple instances of otherwise
+ identical hardware. The serial number takes precedence when provided and can
+ be assumed to be unique. If the serial number is an empty string, the
+ <structfield>bus_info</structfield> field can be used instead. The
+ <structfield>bus_info</structfield> field is guaranteed to be unique, but
+ can vary across reboots or device unplug/replug.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return value</title>
+ <para>This function doesn't return specific error codes.</para>
+ </refsect1>
+</refentry>
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 52e5985..d02038a 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -22,13 +22,70 @@

#include <linux/types.h>
#include <linux/ioctl.h>
+#include <linux/media.h>

#include <media/media-device.h>
#include <media/media-devnode.h>
#include <media/media-entity.h>

+/* -----------------------------------------------------------------------------
+ * Userspace API
+ */
+
+static int media_device_open(struct file *filp)
+{
+ return 0;
+}
+
+static int media_device_close(struct file *filp)
+{
+ return 0;
+}
+
+static int media_device_get_info(struct media_device *dev,
+ struct media_device_info __user *__info)
+{
+ struct media_device_info info;
+
+ memset(&info, 0, sizeof(info));
+
+ strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
+ strlcpy(info.model, dev->model, sizeof(info.model));
+ strlcpy(info.serial, dev->serial, sizeof(info.serial));
+ strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
+
+ info.media_version = MEDIA_API_VERSION;
+ info.hw_revision = dev->hw_revision;
+ info.driver_version = dev->driver_version;
+
+ return copy_to_user(__info, &info, sizeof(*__info));
+}
+
+static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct media_devnode *devnode = media_devnode_data(filp);
+ struct media_device *dev = to_media_device(devnode);
+ long ret;
+
+ switch (cmd) {
+ case MEDIA_IOC_DEVICE_INFO:
+ ret = media_device_get_info(dev,
+ (struct media_device_info __user *)arg);
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+
static const struct media_file_operations media_device_fops = {
.owner = THIS_MODULE,
+ .open = media_device_open,
+ .ioctl = media_device_ioctl,
+ .release = media_device_close,
};

/* -----------------------------------------------------------------------------
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2fc8e14..efc9718 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -112,6 +112,7 @@ header-y += magic.h
header-y += major.h
header-y += map_to_7segment.h
header-y += matroxfb.h
+header-y += media.h
header-y += meye.h
header-y += minix_fs.h
header-y += mmtimer.h
diff --git a/include/linux/media.h b/include/linux/media.h
new file mode 100644
index 0000000..8108fe9
--- /dev/null
+++ b/include/linux/media.h
@@ -0,0 +1,45 @@
+/*
+ * Multimedia device API
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LINUX_MEDIA_H
+#define __LINUX_MEDIA_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0)
+
+struct media_device_info {
+ __u8 driver[16];
+ __u8 model[32];
+ __u8 serial[40];
+ __u8 bus_info[32];
+ __u32 media_version;
+ __u32 hw_revision;
+ __u32 driver_version;
+ __u32 reserved[31];
+};
+
+#define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
+
+#endif /* __LINUX_MEDIA_H */
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 461cb29..bf2eb2c 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -75,6 +75,9 @@ struct media_device {
struct mutex graph_mutex;
};

+/* media_devnode to media_device */
+#define to_media_device(node) container_of(node, struct media_device, devnode)
+
int __must_check media_device_register(struct media_device *mdev);
void media_device_unregister(struct media_device *mdev);
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:17 UTC
Permalink
Create the following two ioctls and implement them at the media device
level to enumerate entities, pads and links.

- MEDIA_IOC_ENUM_ENTITIES: Enumerate entities and their properties
- MEDIA_IOC_ENUM_LINKS: Enumerate all pads and links for a given entity

Entity IDs can be non-contiguous. Userspace applications should
enumerate entities using the MEDIA_ENTITY_ID_FLAG_NEXT flag. When the
flag is set in the entity ID, the MEDIA_IOC_ENUM_ENTITIES will return
the next entity with an ID bigger than the requested one.

Only forward links that originate at one of the entity's source pads are
returned during the enumeration process.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/DocBook/media-entities.tmpl | 8 +
Documentation/DocBook/v4l/media-controller.xml | 2 +
.../DocBook/v4l/media-ioc-device-info.xml | 3 +-
.../DocBook/v4l/media-ioc-enum-entities.xml | 287 ++++++++++++++++++++
Documentation/DocBook/v4l/media-ioc-enum-links.xml | 202 ++++++++++++++
drivers/media/media-device.c | 123 +++++++++
include/linux/media.h | 81 ++++++
include/media/media-entity.h | 24 +--
8 files changed, 706 insertions(+), 24 deletions(-)
create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-entities.xml
create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-links.xml

diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index 9ea1dc9..ef186ca 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -92,6 +92,8 @@
<!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">

<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
+<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
+<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">

<!-- Types -->
<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
@@ -188,6 +190,10 @@
<!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">

<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
+<!ENTITY media-entity-desc "struct&nbsp;<link linkend='media-entity-desc'>media_entity_desc</link>">
+<!ENTITY media-links-enum "struct&nbsp;<link linkend='media-links-enum'>media_links_enum</link>">
+<!ENTITY media-pad-desc "struct&nbsp;<link linkend='media-pad-desc'>media_pad_desc</link>">
+<!ENTITY media-link-desc "struct&nbsp;<link linkend='media-link-desc'>media_link_desc</link>">

<!-- Error Codes -->
<!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
@@ -330,6 +336,8 @@
<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
+<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">

<!-- Function Reference -->
<!ENTITY close SYSTEM "v4l/func-close.xml">
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
index a46b786..2c4fd2b 100644
--- a/Documentation/DocBook/v4l/media-controller.xml
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -83,4 +83,6 @@
&sub-media-ioctl;
<!-- All ioctls go here. -->
&sub-media-ioc-device-info;
+ &sub-media-ioc-enum-entities;
+ &sub-media-ioc-enum-links;
</appendix>
diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
index ffd0fb8..aa25c31 100644
--- a/Documentation/DocBook/v4l/media-ioc-device-info.xml
+++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml
@@ -27,7 +27,8 @@
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
- <para>&fd;</para>
+ <para>File descriptor returned by
+ <link linkend='media-func-open'><function>open()</function></link>.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
new file mode 100644
index 0000000..edb1acc
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
@@ -0,0 +1,287 @@
+<refentry id="media-ioc-enum-entities">
+ <refmeta>
+ <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
+ <refpurpose>Enumerate entities and their properties</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct media_entity_desc *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>File descriptor returned by
+ <link linkend='media-func-open'><function>open()</function></link>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>MEDIA_IOC_ENUM_ENTITIES</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+ <para>To query the attributes of an entity, applications set the id field
+ of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
+ ioctl with a pointer to this structure. The driver fills the rest of the
+ structure or returns an &EINVAL; when the id is invalid.</para>
+ <para>Entities can be enumerated by or'ing the id with the
+ <constant>MEDIA_ENTITY_ID_FLAG_NEXT</constant> flag. The driver will return
+ information about the entity with the smallest id strictly larger than the
+ requested one ('next entity'), or the &EINVAL; if there is none.</para>
+ <para>Entity IDs can be non-contiguous. Applications must
+ <emphasis>not</emphasis> try to enumerate entities by calling
+ MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
+ <para>Two or more entities that share a common non-zero
+ <structfield>group_id</structfield> value are considered as logically
+ grouped. Groups are used to report
+ <itemizedlist>
+ <listitem>ALSA, VBI and video nodes that carry the same media
+ stream</listitem>
+ <listitem>lens and flash controllers associated with a sensor</listitem>
+ </itemizedlist>
+ </para>
+
+ <table pgwide="1" frame="none" id="media-entity-desc">
+ <title>struct <structname>media_entity_desc</structname></title>
+ <tgroup cols="5">
+ <colspec colname="c1" />
+ <colspec colname="c2" />
+ <colspec colname="c3" />
+ <colspec colname="c4" />
+ <colspec colname="c5" />
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity id, set by the application. When the id is or'ed with
+ <constant>MEDIA_ENTITY_ID_FLAG_NEXT</constant>, the driver clears
+ the flag and returns the first entity with a larger id.</entry>
+ </row>
+ <row>
+ <entry>char</entry>
+ <entry><structfield>name</structfield>[32]</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>type</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>revision</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity revision in a driver/hardware specific format.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>group_id</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Entity group ID</entry>
+ </row>
+ <row>
+ <entry>__u16</entry>
+ <entry><structfield>pads</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Number of pads</entry>
+ </row>
+ <row>
+ <entry>__u16</entry>
+ <entry><structfield>links</structfield></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Total number of outbound links. Inbound links are not counted
+ in this field.</entry>
+ </row>
+ <row>
+ <entry>union</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>struct</entry>
+ <entry><structfield>v4l</structfield></entry>
+ <entry></entry>
+ <entry>Valid for V4L sub-devices and nodes only.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>major</structfield></entry>
+ <entry>V4L device node major number. For V4L sub-devices with no
+ device node, set by the driver to 0.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>minor</structfield></entry>
+ <entry>V4L device node minor number. For V4L sub-devices with no
+ device node, set by the driver to 0.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>struct</entry>
+ <entry><structfield>fb</structfield></entry>
+ <entry></entry>
+ <entry>Valid for frame buffer nodes only.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>major</structfield></entry>
+ <entry>Frame buffer device node major number.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>minor</structfield></entry>
+ <entry>Frame buffer device node minor number.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>int</entry>
+ <entry><structfield>alsa</structfield></entry>
+ <entry></entry>
+ <entry>ALSA card number</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>int</entry>
+ <entry><structfield>dvb</structfield></entry>
+ <entry></entry>
+ <entry>DVB card number</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>__u8</entry>
+ <entry><structfield>raw</structfield>[184]</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-entity-type">
+ <title>Media entity types</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_NODE</constant></entry>
+ <entry>Unknown device node</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_NODE_V4L</constant></entry>
+ <entry>V4L video, radio or vbi device node</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_NODE_FB</constant></entry>
+ <entry>Frame buffer device node</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_NODE_ALSA</constant></entry>
+ <entry>ALSA card</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_NODE_DVB</constant></entry>
+ <entry>DVB card</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_SUBDEV</constant></entry>
+ <entry>Unknown V4L sub-device</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_SUBDEV_SENSOR</constant></entry>
+ <entry>Video sensor</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_SUBDEV_FLASH</constant></entry>
+ <entry>Flash controller</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_ENTITY_TYPE_SUBDEV_LENS</constant></entry>
+ <entry>Lens controller</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-entity-flag">
+ <title>Media entity flags</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_ENTITY_FLAG_DEFAULT</constant></entry>
+ <entry>Default entity for its type. Used to discover the default
+ audio, VBI and video devices, the default camera sensor, ...</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &media-entity-desc; <structfield>id</structfield> references
+ a non-existing entity.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
new file mode 100644
index 0000000..ede6d73
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
@@ -0,0 +1,202 @@
+<refentry id="media-ioc-enum-links">
+ <refmeta>
+ <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>MEDIA_IOC_ENUM_LINKS</refname>
+ <refpurpose>Enumerate all pads and links for a given entity</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct media_links_enum *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>File descriptor returned by
+ <link linkend='media-func-open'><function>open()</function></link>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>MEDIA_IOC_ENUM_LINKS</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>To enumerate pads and/or links for a given entity, applications set
+ the entity field of a &media-links-enum; structure and initialize the
+ &media-pad-desc; and &media-link-desc; structure arrays pointed by the
+ <structfield>pads</structfield> and <structfield>links</structfield> fields.
+ They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
+ structure.</para>
+ <para>If the <structfield>pads</structfield> field is not NULL, the driver
+ fills the <structfield>pads</structfield> array with information about the
+ entity's pads. The array must have enough room to store all the entity's
+ pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
+ ioctl.</para>
+ <para>If the <structfield>links</structfield> field is not NULL, the driver
+ fills the <structfield>links</structfield> array with information about the
+ entity's outbound links. The array must have enough room to store all the
+ entity's outbound links. The number of outbound links can be retrieved with
+ the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
+ <para>Only forward links that originate at one of the entity's source pads
+ are returned during the enumeration process.</para>
+
+ <table pgwide="1" frame="none" id="media-links-enum">
+ <title>struct <structname>media_links_enum</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>entity</structfield></entry>
+ <entry>Entity id, set by the application.</entry>
+ </row>
+ <row>
+ <entry>struct &media-pad-desc;</entry>
+ <entry>*<structfield>pads</structfield></entry>
+ <entry>Pointer to a pads array allocated by the application. Ignored
+ if NULL.</entry>
+ </row>
+ <row>
+ <entry>struct &media-link-desc;</entry>
+ <entry>*<structfield>links</structfield></entry>
+ <entry>Pointer to a links array allocated by the application. Ignored
+ if NULL.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-pad-desc">
+ <title>struct <structname>media_pad_desc</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>entity</structfield></entry>
+ <entry>ID of the entity this pad belongs to.</entry>
+ </row>
+ <row>
+ <entry>__u16</entry>
+ <entry><structfield>index</structfield></entry>
+ <entry>0-based pad index.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-pad-flag">
+ <title>Media pad flags</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_PAD_FLAG_INPUT</constant></entry>
+ <entry>Input pad, relative to the entity. Input pads sink data and
+ are targets of links.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_PAD_FLAG_OUTPUT</constant></entry>
+ <entry>Output pad, relative to the entity. Output pads source data
+ and are origins of links.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="media-link-desc">
+ <title>struct <structname>media_links_enum</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>struct &media-pad-desc;</entry>
+ <entry><structfield>source</structfield></entry>
+ <entry>Pad at the origin of this link.</entry>
+ </row>
+ <row>
+ <entry>struct &media-pad-desc;</entry>
+ <entry><structfield>sink</structfield></entry>
+ <entry>Pad at the target of this link.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="none" pgwide="1" id="media-link-flag">
+ <title>Media link flags</title>
+ <tgroup cols="2">
+ <colspec colname="c1"/>
+ <colspec colname="c2"/>
+ <tbody valign="top">
+ <row>
+ <entry><constant>MEDIA_LINK_FLAG_ACTIVE</constant></entry>
+ <entry>The link is active and can be used to transfer media data.
+ When two or more links target a sink pad, only one of them can be
+ active at a time.</entry>
+ </row>
+ <row>
+ <entry><constant>MEDIA_LINK_FLAG_IMMUTABLE</constant></entry>
+ <entry>The link active state can't be modified at runtime. An
+ immutable link is always active.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>One and only one of <constant>MEDIA_PAD_FLAG_INPUT</constant> and
+ <constant>MEDIA_PAD_FLAG_OUTPUT</constant> must be set for every pad.</para>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &media-links-enum; <structfield>id</structfield> references
+ a non-existing entity.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index d02038a..2e4fe0c 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -61,6 +61,117 @@ static int media_device_get_info(struct media_device *dev,
return copy_to_user(__info, &info, sizeof(*__info));
}

+static struct media_entity *find_entity(struct media_device *mdev, u32 id)
+{
+ struct media_entity *entity;
+ int next = id & MEDIA_ENTITY_ID_FLAG_NEXT;
+
+ id &= ~MEDIA_ENTITY_ID_FLAG_NEXT;
+
+ spin_lock(&mdev->lock);
+
+ media_device_for_each_entity(entity, mdev) {
+ if ((entity->id == id && !next) ||
+ (entity->id > id && next)) {
+ spin_unlock(&mdev->lock);
+ return entity;
+ }
+ }
+
+ spin_unlock(&mdev->lock);
+
+ return NULL;
+}
+
+static long media_device_enum_entities(struct media_device *mdev,
+ struct media_entity_desc __user *uent)
+{
+ struct media_entity *ent;
+ struct media_entity_desc u_ent;
+
+ if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
+ return -EFAULT;
+
+ ent = find_entity(mdev, u_ent.id);
+
+ if (ent == NULL)
+ return -EINVAL;
+
+ u_ent.id = ent->id;
+ u_ent.name[0] = '\0';
+ if (ent->name)
+ strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
+ u_ent.type = ent->type;
+ u_ent.revision = ent->revision;
+ u_ent.flags = ent->flags;
+ u_ent.group_id = ent->group_id;
+ u_ent.pads = ent->num_pads;
+ u_ent.links = ent->num_links - ent->num_backlinks;
+ u_ent.v4l.major = ent->v4l.major;
+ u_ent.v4l.minor = ent->v4l.minor;
+ if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
+ return -EFAULT;
+ return 0;
+}
+
+static void media_device_kpad_to_upad(const struct media_pad *kpad,
+ struct media_pad_desc *upad)
+{
+ upad->entity = kpad->entity->id;
+ upad->index = kpad->index;
+ upad->flags = kpad->flags;
+}
+
+static long media_device_enum_links(struct media_device *mdev,
+ struct media_links_enum __user *ulinks)
+{
+ struct media_entity *entity;
+ struct media_links_enum links;
+
+ if (copy_from_user(&links, ulinks, sizeof(links)))
+ return -EFAULT;
+
+ entity = find_entity(mdev, links.entity);
+ if (entity == NULL)
+ return -EINVAL;
+
+ if (links.pads) {
+ unsigned int p;
+
+ for (p = 0; p < entity->num_pads; p++) {
+ struct media_pad_desc pad;
+ media_device_kpad_to_upad(&entity->pads[p], &pad);
+ if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
+ return -EFAULT;
+ }
+ }
+
+ if (links.links) {
+ struct media_link_desc __user *ulink;
+ unsigned int l;
+
+ for (l = 0, ulink = links.links; l < entity->num_links; l++) {
+ struct media_link_desc link;
+
+ /* Ignore backlinks. */
+ if (entity->links[l].source->entity != entity)
+ continue;
+
+ media_device_kpad_to_upad(entity->links[l].source,
+ &link.source);
+ media_device_kpad_to_upad(entity->links[l].sink,
+ &link.sink);
+ link.flags = entity->links[l].flags;
+ if (copy_to_user(ulink, &link, sizeof(*ulink)))
+ return -EFAULT;
+ ulink++;
+ }
+ }
+ if (copy_to_user(ulinks, &links, sizeof(*ulinks)))
+ return -EFAULT;
+ return 0;
+}
+
static long media_device_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -74,6 +185,18 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
(struct media_device_info __user *)arg);
break;

+ case MEDIA_IOC_ENUM_ENTITIES:
+ ret = media_device_enum_entities(dev,
+ (struct media_entity_desc __user *)arg);
+ break;
+
+ case MEDIA_IOC_ENUM_LINKS:
+ mutex_lock(&dev->graph_mutex);
+ ret = media_device_enum_links(dev,
+ (struct media_links_enum __user *)arg);
+ mutex_unlock(&dev->graph_mutex);
+ break;
+
default:
ret = -ENOIOCTLCMD;
}
diff --git a/include/linux/media.h b/include/linux/media.h
index 8108fe9..2f6a81c 100644
--- a/include/linux/media.h
+++ b/include/linux/media.h
@@ -40,6 +40,87 @@ struct media_device_info {
__u32 reserved[31];
};

+#define MEDIA_ENTITY_ID_FLAG_NEXT (1 << 31)
+
+#define MEDIA_ENTITY_TYPE_SHIFT 16
+#define MEDIA_ENTITY_TYPE_MASK 0x00ff0000
+#define MEDIA_ENTITY_SUBTYPE_MASK 0x0000ffff
+
+#define MEDIA_ENTITY_TYPE_NODE (1 << MEDIA_ENTITY_TYPE_SHIFT)
+#define MEDIA_ENTITY_TYPE_NODE_V4L (MEDIA_ENTITY_TYPE_NODE + 1)
+#define MEDIA_ENTITY_TYPE_NODE_FB (MEDIA_ENTITY_TYPE_NODE + 2)
+#define MEDIA_ENTITY_TYPE_NODE_ALSA (MEDIA_ENTITY_TYPE_NODE + 3)
+#define MEDIA_ENTITY_TYPE_NODE_DVB (MEDIA_ENTITY_TYPE_NODE + 4)
+
+#define MEDIA_ENTITY_TYPE_SUBDEV (2 << MEDIA_ENTITY_TYPE_SHIFT)
+#define MEDIA_ENTITY_TYPE_SUBDEV_SENSOR (MEDIA_ENTITY_TYPE_SUBDEV + 1)
+#define MEDIA_ENTITY_TYPE_SUBDEV_FLASH (MEDIA_ENTITY_TYPE_SUBDEV + 2)
+#define MEDIA_ENTITY_TYPE_SUBDEV_LENS (MEDIA_ENTITY_TYPE_SUBDEV + 3)
+
+#define MEDIA_ENTITY_FLAG_DEFAULT (1 << 0)
+
+struct media_entity_desc {
+ __u32 id;
+ char name[32];
+ __u32 type;
+ __u32 revision;
+ __u32 flags;
+ __u32 group_id;
+ __u16 pads;
+ __u16 links;
+
+ __u32 reserved[4];
+
+ union {
+ /* Node specifications */
+ struct {
+ __u32 major;
+ __u32 minor;
+ } v4l;
+ struct {
+ __u32 major;
+ __u32 minor;
+ } fb;
+ int alsa;
+ int dvb;
+
+ /* Sub-device specifications */
+ /* Nothing needed yet */
+ __u8 raw[184];
+ };
+};
+
+#define MEDIA_PAD_FLAG_INPUT (1 << 0)
+#define MEDIA_PAD_FLAG_OUTPUT (1 << 1)
+
+struct media_pad_desc {
+ __u32 entity; /* entity ID */
+ __u16 index; /* pad index */
+ __u32 flags; /* pad flags */
+ __u32 reserved[2];
+};
+
+#define MEDIA_LINK_FLAG_ACTIVE (1 << 0)
+#define MEDIA_LINK_FLAG_IMMUTABLE (1 << 1)
+
+struct media_link_desc {
+ struct media_pad_desc source;
+ struct media_pad_desc sink;
+ __u32 flags;
+ __u32 reserved[2];
+};
+
+struct media_links_enum {
+ __u32 entity;
+ /* Should have enough room for pads elements */
+ struct media_pad_desc __user *pads;
+ /* Should have enough room for links elements */
+ struct media_link_desc __user *links;
+ __u32 reserved[4];
+};
+
#define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
+#define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc)
+#define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum)

#endif /* __LINUX_MEDIA_H */
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index b9694b5..42ea2af 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -24,29 +24,7 @@
#define _MEDIA_ENTITY_H

#include <linux/list.h>
-
-#define MEDIA_ENTITY_TYPE_SHIFT 16
-#define MEDIA_ENTITY_TYPE_MASK 0x00ff0000
-#define MEDIA_ENTITY_SUBTYPE_MASK 0x0000ffff
-
-#define MEDIA_ENTITY_TYPE_NODE (1 << MEDIA_ENTITY_TYPE_SHIFT)
-#define MEDIA_ENTITY_TYPE_NODE_V4L (MEDIA_ENTITY_TYPE_NODE + 1)
-#define MEDIA_ENTITY_TYPE_NODE_FB (MEDIA_ENTITY_TYPE_NODE + 2)
-#define MEDIA_ENTITY_TYPE_NODE_ALSA (MEDIA_ENTITY_TYPE_NODE + 3)
-#define MEDIA_ENTITY_TYPE_NODE_DVB (MEDIA_ENTITY_TYPE_NODE + 4)
-
-#define MEDIA_ENTITY_TYPE_SUBDEV (2 << MEDIA_ENTITY_TYPE_SHIFT)
-#define MEDIA_ENTITY_TYPE_SUBDEV_SENSOR (MEDIA_ENTITY_TYPE_SUBDEV + 1)
-#define MEDIA_ENTITY_TYPE_SUBDEV_FLASH (MEDIA_ENTITY_TYPE_SUBDEV + 2)
-#define MEDIA_ENTITY_TYPE_SUBDEV_LENS (MEDIA_ENTITY_TYPE_SUBDEV + 3)
-
-#define MEDIA_ENTITY_FLAG_DEFAULT (1 << 0)
-
-#define MEDIA_LINK_FLAG_ACTIVE (1 << 0)
-#define MEDIA_LINK_FLAG_IMMUTABLE (1 << 1)
-
-#define MEDIA_PAD_FLAG_INPUT (1 << 0)
-#define MEDIA_PAD_FLAG_OUTPUT (1 << 1)
+#include <linux/media.h>

struct media_link {
struct media_pad *source; /* Source pad */
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:18 UTC
Permalink
Create the following ioctl and implement it at the media device level to
setup links.

- MEDIA_IOC_SETUP_LINK: Modify the properties of a given link

The only property that can currently be modified is the ACTIVE link flag
to activate/deactivate a link. Links marked with the IMMUTABLE link flag
can not be activated or deactivated.

Activating and deactivating a link has effects on entities' use count.
Those changes are automatically propagated through the graph.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Stanimir Varbanov <***@mm-sol.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/DocBook/media-entities.tmpl | 2 +
Documentation/DocBook/v4l/media-controller.xml | 1 +
Documentation/DocBook/v4l/media-ioc-setup-link.xml | 90 +++++++++
Documentation/media-framework.txt | 49 +++++
drivers/media/media-device.c | 45 +++++
drivers/media/media-entity.c | 208 ++++++++++++++++++++
include/linux/media.h | 1 +
include/media/media-entity.h | 8 +
8 files changed, 404 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/media-ioc-setup-link.xml

diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index ef186ca..65ba6c7 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -94,6 +94,7 @@
<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
+<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">

<!-- Types -->
<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
@@ -338,6 +339,7 @@
<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
+<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">

<!-- Function Reference -->
<!ENTITY close SYSTEM "v4l/func-close.xml">
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
index 2c4fd2b..2dc25e1 100644
--- a/Documentation/DocBook/v4l/media-controller.xml
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -85,4 +85,5 @@
&sub-media-ioc-device-info;
&sub-media-ioc-enum-entities;
&sub-media-ioc-enum-links;
+ &sub-media-ioc-setup-link;
</appendix>
diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
new file mode 100644
index 0000000..84323d0
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
@@ -0,0 +1,90 @@
+<refentry id="media-ioc-setup-link">
+ <refmeta>
+ <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>MEDIA_IOC_SETUP_LINK</refname>
+ <refpurpose>Modify the properties of a link</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>File descriptor returned by
+ <link linkend='media-func-open'><function>open()</function></link>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>MEDIA_IOC_ENUM_LINKS</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>To change link properties applications fill a &media-link-desc; with
+ link identification information (source and sink pad) and the new requested
+ link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
+ that structure.</para>
+ <para>The only configurable property is the <constant>ACTIVE</constant> link
+ flag to activate/deactivate a link. Links marked with the
+ <constant>IMMUTABLE</constant> link flag can not be activated or
+ deactivated.</para>
+ <para>Link activation has no side effect on other links. If an active link
+ at the sink pad prevents the link from being activated, the driver returns
+ with an &EBUSY;.</para>
+ <para>If the specified link can't be found the driver returns with an
+ &EINVAL;.</para>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBUSY</errorcode></term>
+ <listitem>
+ <para>The link properties can't be changed because the link is
+ currently busy. This can be caused, for instance, by an active media
+ stream (audio or video) on the link. The ioctl shouldn't be retried if
+ no other action is performed before to fix the problem.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &media-link-desc; references a non-existing link, or the
+ link is immutable and an attempt to modify its configuration was made.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 9fdbc50..e2987b7 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -257,6 +257,16 @@ When the graph traversal is complete the function will return NULL.
Graph traversal can be interrupted at any moment. No cleanup function call is
required and the graph structure can be freed normally.

+Helper functions can be used to find a link between two given pads, or a pad
+connected to another pad through an active link
+
+ media_entity_find_link(struct media_pad *source,
+ struct media_pad *sink);
+
+ media_entity_remote_source(struct media_pad *pad);
+
+Refer to the kerneldoc documentation for more information.
+

Reference counting and power handling
-------------------------------------
@@ -294,3 +304,42 @@ required, drivers don't need to provide a set_power operation. The operation
is allowed to fail when turning power on, in which case the media_entity_get
function will return NULL.

+
+Links setup
+-----------
+
+Link properties can be modified at runtime by calling
+
+ media_entity_setup_link(struct media_link *link, u32 flags);
+
+The flags argument contains the requested new link flags.
+
+The only configurable property is the ACTIVE link flag to activate/deactivate
+a link. Links marked with the IMMUTABLE link flag can not be activated or
+deactivated.
+
+When a link is activated or deactivated, the media framework calls the
+link_setup operation for the two entities at the source and sink of the link,
+in that order. If the second link_setup call fails, another link_setup call is
+made on the first entity to restore the original link flags.
+
+Entity drivers must implement the link_setup operation if any of their links
+is non-immutable. The operation must either configure the hardware or store
+the configuration information to be applied later.
+
+Link activation must not have any side effect on other links. If an active
+link at a sink pad prevents another link at the same pad from being
+deactivated, the link_setup operation must return -EBUSY and can't implicitly
+deactivate the first active link.
+
+Activating and deactivating a link has effects on entities' reference counts.
+When two sub-graphs are connected, the reference count of each of them is
+incremented by the total reference count of all node entities in the other
+sub-graph. When two sub-graphs are disconnected, the reverse operation is
+performed. In both cases the set_power operations are called accordingly,
+ensuring that the link_setup calls are made with power active on the source
+and sink entities.
+
+In other words, activating or deactivating a link propagates reference count
+changes through the graph, and the final state is identical to what it would
+have been if the link had been active or inactive from the start.
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 2e4fe0c..7c74200 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev,
return 0;
}

+static long media_device_setup_link(struct media_device *mdev,
+ struct media_link_desc __user *_ulink)
+{
+ struct media_link *link = NULL;
+ struct media_link_desc ulink;
+ struct media_entity *source;
+ struct media_entity *sink;
+ int ret;
+
+ if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
+ return -EFAULT;
+
+ /* Find the source and sink entities and link.
+ */
+ source = find_entity(mdev, ulink.source.entity);
+ sink = find_entity(mdev, ulink.sink.entity);
+
+ if (source == NULL || sink == NULL)
+ return -EINVAL;
+
+ if (ulink.source.index >= source->num_pads ||
+ ulink.sink.index >= sink->num_pads)
+ return -EINVAL;
+
+ link = media_entity_find_link(&source->pads[ulink.source.index],
+ &sink->pads[ulink.sink.index]);
+ if (link == NULL)
+ return -EINVAL;
+
+ /* Setup the link on both entities. */
+ ret = __media_entity_setup_link(link, ulink.flags);
+
+ if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
+ return -EFAULT;
+
+ return ret;
+}
+
static long media_device_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
mutex_unlock(&dev->graph_mutex);
break;

+ case MEDIA_IOC_SETUP_LINK:
+ mutex_lock(&dev->graph_mutex);
+ ret = media_device_setup_link(dev,
+ (struct media_link_desc __user *)arg);
+ mutex_unlock(&dev->graph_mutex);
+ break;
+
default:
ret = -ENOIOCTLCMD;
}
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index c15f16b..5ebda28 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -200,6 +200,25 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
* Power state handling
*/

+/*
+ * Return power count of nodes directly or indirectly connected to
+ * a given entity.
+ */
+static int media_entity_count_node(struct media_entity *entity)
+{
+ struct media_entity_graph graph;
+ int use = 0;
+
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ if (media_entity_type(entity) == MEDIA_ENTITY_TYPE_NODE)
+ use += entity->use_count;
+ }
+
+ return use;
+}
+
/* Apply use count to an entity. */
static void media_entity_use_apply_one(struct media_entity *entity, int change)
{
@@ -263,6 +282,32 @@ static int media_entity_power_apply(struct media_entity *entity, int change)
return ret;
}

+/* Apply the power state changes when connecting two entities. */
+static int media_entity_power_connect(struct media_entity *one,
+ struct media_entity *theother)
+{
+ int power_one = media_entity_count_node(one);
+ int power_theother = media_entity_count_node(theother);
+ int ret = 0;
+
+ ret = media_entity_power_apply(one, power_theother);
+ if (ret < 0)
+ return ret;
+
+ return media_entity_power_apply(theother, power_one);
+}
+
+static void media_entity_power_disconnect(struct media_entity *one,
+ struct media_entity *theother)
+{
+ int power_one = media_entity_count_node(one);
+ int power_theother = media_entity_count_node(theother);
+
+ /* Powering off entities is assumed to never fail. */
+ media_entity_power_apply(one, -power_theother);
+ media_entity_power_apply(theother, -power_one);
+}
+
/*
* Apply use count change to graph and change power state of entities
* accordingly.
@@ -406,3 +451,166 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
return 0;
}
EXPORT_SYMBOL_GPL(media_entity_create_link);
+
+static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
+{
+ const u32 mask = MEDIA_LINK_FLAG_ACTIVE;
+ int ret;
+
+ /* Notify both entities. */
+ ret = media_entity_call(link->source->entity, link_setup,
+ link->source, link->sink, flags);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = media_entity_call(link->sink->entity, link_setup,
+ link->sink, link->source, flags);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ media_entity_call(link->source->entity, link_setup,
+ link->source, link->sink, link->flags);
+ return ret;
+ }
+
+ link->flags = (link->flags & ~mask) | (flags & mask);
+ link->reverse->flags = link->flags;
+
+ return 0;
+}
+
+/**
+ * __media_entity_setup_link - Configure a media link
+ * @link: The link being configured
+ * @flags: Link configuration flags
+ *
+ * The bulk of link setup is handled by the two entities connected through the
+ * link. This function notifies both entities of the link configuration change.
+ *
+ * If the link is immutable or if the current and new configuration are
+ * identical, return immediately.
+ *
+ * The user is expected to hold link->source->parent->mutex. If not,
+ * media_entity_setup_link() should be used instead.
+ */
+int __media_entity_setup_link(struct media_link *link, u32 flags)
+{
+ struct media_entity *source, *sink;
+ int ret = -EBUSY;
+
+ if (link == NULL)
+ return -EINVAL;
+
+ if (link->flags & MEDIA_LINK_FLAG_IMMUTABLE)
+ return link->flags == flags ? 0 : -EINVAL;
+
+ if (link->flags == flags)
+ return 0;
+
+ source = __media_entity_get(link->source->entity);
+ if (!source)
+ return ret;
+
+ sink = __media_entity_get(link->sink->entity);
+ if (!sink)
+ goto err___media_entity_get;
+
+ if (flags & MEDIA_LINK_FLAG_ACTIVE) {
+ ret = media_entity_power_connect(source, sink);
+ if (ret < 0)
+ goto err_media_entity_power_connect;
+ }
+
+ ret = __media_entity_setup_link_notify(link, flags);
+ if (ret < 0)
+ goto err___media_entity_setup_link_notify;
+
+ if (!(flags & MEDIA_LINK_FLAG_ACTIVE))
+ media_entity_power_disconnect(source, sink);
+
+ __media_entity_put(sink);
+ __media_entity_put(source);
+
+ return 0;
+
+err___media_entity_setup_link_notify:
+ if (flags & MEDIA_LINK_FLAG_ACTIVE)
+ media_entity_power_disconnect(source, sink);
+err_media_entity_power_connect:
+ __media_entity_put(sink);
+err___media_entity_get:
+ __media_entity_put(source);
+
+ return ret;
+}
+
+int media_entity_setup_link(struct media_link *link, u32 flags)
+{
+ int ret;
+
+ mutex_lock(&link->source->entity->parent->graph_mutex);
+ ret = __media_entity_setup_link(link, flags);
+ mutex_unlock(&link->source->entity->parent->graph_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(media_entity_setup_link);
+
+/**
+ * media_entity_find_link - Find a link between two pads
+ * @source: Source pad
+ * @sink: Sink pad
+ *
+ * Return a pointer to the link between the two entities. If no such link
+ * exists, return NULL.
+ */
+struct media_link *
+media_entity_find_link(struct media_pad *source, struct media_pad *sink)
+{
+ struct media_link *link;
+ unsigned int i;
+
+ for (i = 0; i < source->entity->num_links; ++i) {
+ link = &source->entity->links[i];
+
+ if (link->source->entity == source->entity &&
+ link->source->index == source->index &&
+ link->sink->entity == sink->entity &&
+ link->sink->index == sink->index)
+ return link;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(media_entity_find_link);
+
+/**
+ * media_entity_remote_source - Find the source pad at the remote end of a link
+ * @pad: Sink pad at the local end of the link
+ *
+ * Search for a remote source pad connected to the given sink pad by iterating
+ * over all links originating or terminating at that pad until an active link is
+ * found.
+ *
+ * Return a pointer to the pad at the remote end of the first found active link,
+ * or NULL if no active link has been found.
+ */
+struct media_pad *media_entity_remote_source(struct media_pad *pad)
+{
+ unsigned int i;
+
+ for (i = 0; i < pad->entity->num_links; i++) {
+ struct media_link *link = &pad->entity->links[i];
+
+ if (!(link->flags & MEDIA_LINK_FLAG_ACTIVE))
+ continue;
+
+ if (link->source == pad)
+ return link->sink;
+
+ if (link->sink == pad)
+ return link->source;
+ }
+
+ return NULL;
+
+}
+EXPORT_SYMBOL_GPL(media_entity_remote_source);
diff --git a/include/linux/media.h b/include/linux/media.h
index 2f6a81c..1df5b6e 100644
--- a/include/linux/media.h
+++ b/include/linux/media.h
@@ -122,5 +122,6 @@ struct media_links_enum {
#define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
#define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc)
#define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum)
+#define MEDIA_IOC_SETUP_LINK _IOWR('M', 4, struct media_link_desc)

#endif /* __LINUX_MEDIA_H */
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 42ea2af..11bef651 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -40,6 +40,9 @@ struct media_pad {
};

struct media_entity_operations {
+ int (*link_setup)(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags);
int (*set_power)(struct media_entity *entity, int power);
};

@@ -110,6 +113,11 @@ int media_entity_init(struct media_entity *entity, u16 num_pads,
void media_entity_cleanup(struct media_entity *entity);
int media_entity_create_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags);
+int __media_entity_setup_link(struct media_link *link, u32 flags);
+int media_entity_setup_link(struct media_link *link, u32 flags);
+struct media_link *media_entity_find_link(struct media_pad *source,
+ struct media_pad *sink);
+struct media_pad *media_entity_remote_source(struct media_pad *pad);

struct media_entity *media_entity_get(struct media_entity *entity);
void media_entity_put(struct media_entity *entity);
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:20 UTC
Permalink
The pointer will later be used to register/unregister media entities
when registering/unregistering a v4l2_subdev or a video_device.

With the introduction of media devices, device drivers need to store a
pointer to a driver-specific structure in the device's drvdata.
v4l2_device can't claim ownership of the drvdata anymore.

To maintain compatibility with drivers that rely on v4l2_device storing
a pointer to itself in the device's drvdata, v4l2_device_register() will
keep doing so if the drvdata is NULL.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/video4linux/v4l2-framework.txt | 17 ++++++++++++-----
drivers/media/video/v4l2-device.c | 13 +++++++------
include/media/v4l2-device.h | 4 ++++
3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 774ce90..1166af4 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -83,11 +83,17 @@ You must register the device instance:

v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);

-Registration will initialize the v4l2_device struct and link dev->driver_data
-to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived
-from dev (driver name followed by the bus_id, to be precise). If you set it
-up before calling v4l2_device_register then it will be untouched. If dev is
-NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
+Registration will initialize the v4l2_device struct. If the dev->driver_data
+field is NULL, it will be linked to v4l2_dev. Drivers that use the media
+device framework in addition to the V4L2 framework need to set
+dev->driver_data manually to point to the driver-specific device structure
+that embed the struct v4l2_device instance. This is achieved by a
+dev_set_drvdata() call before registering the V4L2 device instance.
+
+If v4l2_dev->name is empty then it will be set to a value derived from dev
+(driver name followed by the bus_id, to be precise). If you set it up before
+calling v4l2_device_register then it will be untouched. If dev is NULL, then
+you *must* setup v4l2_dev->name before calling v4l2_device_register.

You can use v4l2_device_set_name() to set the name based on a driver name and
a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
@@ -108,6 +114,7 @@ You unregister with:

v4l2_device_unregister(struct v4l2_device *v4l2_dev);

+If the dev->driver_data field points to v4l2_dev, it will be reset to NULL.
Unregistering will also automatically unregister all subdevs from the device.

If you have a hotpluggable device (e.g. a USB device), then when a disconnect
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 318e911..8447466 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -46,9 +46,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
if (!v4l2_dev->name[0])
snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
dev->driver->name, dev_name(dev));
- if (dev_get_drvdata(dev))
- v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
- dev_set_drvdata(dev, v4l2_dev);
+ if (!dev_get_drvdata(dev))
+ dev_set_drvdata(dev, v4l2_dev);
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_device_register);
@@ -71,10 +70,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_set_name);

void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
{
- if (v4l2_dev->dev) {
+ if (v4l2_dev->dev == NULL)
+ return;
+
+ if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
dev_set_drvdata(v4l2_dev->dev, NULL);
- v4l2_dev->dev = NULL;
- }
+ v4l2_dev->dev = NULL;
}
EXPORT_SYMBOL_GPL(v4l2_device_disconnect);

diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
index 8bcbd7a..fc3bdbf 100644
--- a/include/media/v4l2-device.h
+++ b/include/media/v4l2-device.h
@@ -21,6 +21,7 @@
#ifndef _V4L2_DEVICE_H
#define _V4L2_DEVICE_H

+#include <media/media-device.h>
#include <media/v4l2-subdev.h>

/* Each instance of a V4L2 device should create the v4l2_device struct,
@@ -39,6 +40,9 @@ struct v4l2_device {
Note: dev might be NULL if there is no parent device
as is the case with e.g. ISA devices. */
struct device *dev;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_device *mdev;
+#endif
/* used to keep track of the registered subdevs */
struct list_head subdevs;
/* lock this struct; can be used by the driver as well if this
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:19 UTC
Permalink
Link states must not be modified while streaming is in progress on a
graph they belong or connect to. The entity locking API helps drivers
enforcing that requirement.

When starting streaming on a graph, drivers lock all entities in the
graph with a call to media_entity_graph_lock(). Similarly, when stopping
the stream, they unlock the entities with a call to
media_entity_graph_unlock().

The media_entity_graph_lock() function takes a pointer to a media
pipeline and stores it in every entity in the graph. Drivers should
embed the media_pipeline structure in higher-level pipeline structures
and can then access the pipeline through the media_entity structure.

Link configuration will fail with -EBUSY if either end of the link is a
locked entity.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/media-framework.txt | 35 ++++++++++++++++++++
drivers/media/media-entity.c | 64 +++++++++++++++++++++++++++++++++++++
include/media/media-entity.h | 10 ++++++
3 files changed, 109 insertions(+), 0 deletions(-)

diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index e2987b7..3131e1e 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -343,3 +343,38 @@ and sink entities.
In other words, activating or deactivating a link propagates reference count
changes through the graph, and the final state is identical to what it would
have been if the link had been active or inactive from the start.
+
+
+Entity locking and pipelines
+----------------------------
+
+When starting streaming, drivers must lock all entities in the graph to
+prevent link states from being modified during streaming by calling
+
+ media_entity_graph_lock(struct media_entity *entity,
+ struct media_pipeline *pipe);
+
+The function will lock all entities connected to the given entity through
+active links, either directly or indirectly.
+
+The media_pipeline instance pointed to by the pipe argument will be stored in
+every entity in the graph. Drivers should embed the media_pipeline structure
+in higher-level pipeline structures and can then access the pipeline through
+the media_entity pipe field.
+
+Calls to media_entity_graph_lock() can be nested. The pipeline pointer must be
+identical for all nested calls to the function.
+
+When stopping the stream, drivers must unlock the entities with
+
+ media_entity_graph_unlock(struct media_entity *entity);
+
+If multiple calls to media_entity_graph_lock() have been made the same number
+of media_entity_graph_unlock() calls are required to unlock the graph. The
+media_entity pipe field is reset to NULL on the last nested unlock call.
+
+Link configuration will fail with -EBUSY if either end of the link is a
+locked entity. If other operations need to be disallowed on locked entities
+(such as changing entities configuration parameters) drivers can explictly
+check the media_entity lock_count field to find out if an entity is locked.
+This operation must be done with the media_device graph_mutex held.
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 5ebda28..3e2670e 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -196,6 +196,67 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
}
EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);

+/**
+ * media_entity_graph_lock - Lock all entities in a graph
+ * @entity: Starting entity
+ * @pipe: Media pipeline to be assigned to all entities in the graph.
+ *
+ * Lock all entities connected to a given entity through active links, either
+ * directly or indirectly. The given pipeline is assigned to every entity in
+ * the graph and stored in the media_entity pipe field.
+ *
+ * Calls to this function can be nested, in which case the same number of
+ * media_entity_graph_unlock() calls will be required to unlock the graph. The
+ * pipeline pointer must be identical for all nested calls to
+ * media_entity_graph_lock().
+ */
+void media_entity_graph_lock(struct media_entity *entity,
+ struct media_pipeline *pipe)
+{
+ struct media_device *mdev = entity->parent;
+ struct media_entity_graph graph;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ entity->lock_count++;
+ WARN_ON(entity->pipe && entity->pipe != pipe);
+ entity->pipe = pipe;
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_lock);
+
+/**
+ * media_entity_graph_unlock - Unlock all entities in a graph
+ * @entity: Starting entity
+ *
+ * Unlock all entities connected to a given entity through active links, either
+ * directly or indirectly. The media_entity pipe field is reset to NULL on the
+ * last nested unlock call.
+ */
+void media_entity_graph_unlock(struct media_entity *entity)
+{
+ struct media_device *mdev = entity->parent;
+ struct media_entity_graph graph;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ entity->lock_count--;
+ if (entity->lock_count == 0)
+ entity->pipe = NULL;
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_unlock);
+
/* -----------------------------------------------------------------------------
* Power state handling
*/
@@ -505,6 +566,9 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
if (link->flags == flags)
return 0;

+ if (link->source->entity->lock_count || link->sink->entity->lock_count)
+ return -EBUSY;
+
source = __media_entity_get(link->source->entity);
if (!source)
return ret;
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 11bef651..74030f2 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -26,6 +26,9 @@
#include <linux/list.h>
#include <linux/media.h>

+struct media_pipeline {
+};
+
struct media_link {
struct media_pad *source; /* Source pad */
struct media_pad *sink; /* Sink pad */
@@ -68,8 +71,11 @@ struct media_entity {

const struct media_entity_operations *ops; /* Entity operations */

+ int lock_count; /* Lock count for the entity. */
int use_count; /* Use count for the entity. */

+ struct media_pipeline *pipe; /* Pipeline this entity belongs to. */
+
union {
/* Node specifications */
struct {
@@ -111,6 +117,7 @@ struct media_entity_graph {
int media_entity_init(struct media_entity *entity, u16 num_pads,
struct media_pad *pads, u16 extra_links);
void media_entity_cleanup(struct media_entity *entity);
+
int media_entity_create_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags);
int __media_entity_setup_link(struct media_link *link, u32 flags);
@@ -126,6 +133,9 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity);
struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph);
+void media_entity_graph_lock(struct media_entity *entity,
+ struct media_pipeline *pipe);
+void media_entity_graph_unlock(struct media_entity *entity);

#define media_entity_call(entity, operation, args...) \
(((entity)->ops && (entity)->ops->operation) ? \
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:21 UTC
Permalink
V4L2 devices are media entities. As such they need to inherit from
(include) the media_entity structure.

When registering/unregistering the device, the media entity is
automatically registered/unregistered. The entity is acquired on device
open and released on device close.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/video4linux/v4l2-framework.txt | 38 +++++++++++++++++++--
drivers/media/video/v4l2-dev.c | 47 +++++++++++++++++++++++---
include/media/v4l2-dev.h | 7 ++++
3 files changed, 84 insertions(+), 8 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 1166af4..f1ac9f6a 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -71,6 +71,10 @@ sub-device instances, the video_device struct stores V4L2 device node data
and in the future a v4l2_fh struct will keep track of filehandle instances
(this is not yet implemented).

+The V4L2 framework also optionally integrates with the media framework. If a
+driver sets the struct v4l2_device mdev field, sub-devices and video nodes
+will automatically appear in the media framework as entities.
+

struct v4l2_device
------------------
@@ -84,11 +88,14 @@ You must register the device instance:
v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);

Registration will initialize the v4l2_device struct. If the dev->driver_data
-field is NULL, it will be linked to v4l2_dev. Drivers that use the media
-device framework in addition to the V4L2 framework need to set
+field is NULL, it will be linked to v4l2_dev.
+
+Drivers that want integration with the media device framework need to set
dev->driver_data manually to point to the driver-specific device structure
that embed the struct v4l2_device instance. This is achieved by a
-dev_set_drvdata() call before registering the V4L2 device instance.
+dev_set_drvdata() call before registering the V4L2 device instance. They must
+also set the struct v4l2_device mdev field to point to a properly initialized
+and registered media_device instance.

If v4l2_dev->name is empty then it will be set to a value derived from dev
(driver name followed by the bus_id, to be precise). If you set it up before
@@ -528,6 +535,21 @@ If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
The v4l2_file_operations struct is a subset of file_operations. The main
difference is that the inode argument is omitted since it is never used.

+If integration with the media framework is needed, you must initialize the
+media_entity struct embedded in the video_device struct (entity field) by
+calling media_entity_init():
+
+ struct media_pad *pad = &my_vdev->pad;
+ int err;
+
+ err = media_entity_init(&vdev->entity, 1, pad, 0);
+
+The pads array must have been previously initialized. There is no need to
+manually set the struct media_entity type and name fields.
+
+A reference to the entity will be automatically acquired/released when the
+video device is opened/closed.
+

video_device registration
-------------------------
@@ -541,6 +563,9 @@ for you.
return err;
}

+If the v4l2_device parent device has a non-NULL mdev field, the video device
+entity will be automatically registered with the media device.
+
Which device is registered depends on the type argument. The following
types exist:

@@ -618,6 +643,13 @@ those will still be passed on since some buffer ioctls may still be needed.
When the last user of the video device node exits, then the vdev->release()
callback is called and you can do the final cleanup there.

+Don't forget to cleanup the media entity associated with the video device if
+it has been initialized:
+
+ media_entity_cleanup(&vdev->entity);
+
+This can be done from the release callback.
+

video_device helper functions
-----------------------------
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 166cfd8..02ea978 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -269,6 +269,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
static int v4l2_open(struct inode *inode, struct file *filp)
{
struct video_device *vdev;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_entity *entity = NULL;
+#endif
int ret = 0;

/* Check if the video device is available */
@@ -283,12 +286,27 @@ static int v4l2_open(struct inode *inode, struct file *filp)
/* and increase the device refcount */
video_get(vdev);
mutex_unlock(&videodev_lock);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+ entity = media_entity_get(&vdev->entity);
+ if (!entity) {
+ ret = -EBUSY;
+ video_put(vdev);
+ return ret;
+ }
+ }
+#endif
if (vdev->fops->open)
ret = vdev->fops->open(filp);

/* decrease the refcount in case of an error */
- if (ret)
+ if (ret) {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+ media_entity_put(entity);
+#endif
video_put(vdev);
+ }
return ret;
}

@@ -300,7 +318,10 @@ static int v4l2_release(struct inode *inode, struct file *filp)

if (vdev->fops->release)
vdev->fops->release(filp);
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+ media_entity_put(&vdev->entity);
+#endif
/* decrease the refcount unconditionally since the release()
return value is ignored. */
video_put(vdev);
@@ -566,12 +587,25 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
name_base, nr, video_device_node_name(vdev));
-
- /* Part 5: Activate this minor. The char device can now be used. */
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ /* Part 5: Register the entity. */
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+ vdev->entity.type = MEDIA_ENTITY_TYPE_NODE_V4L;
+ vdev->entity.name = vdev->name;
+ vdev->entity.v4l.major = VIDEO_MAJOR;
+ vdev->entity.v4l.minor = vdev->minor;
+ ret = media_device_register_entity(vdev->v4l2_dev->mdev,
+ &vdev->entity);
+ if (ret < 0)
+ printk(KERN_ERR "error\n"); /* TODO */
+ }
+#endif
+ /* Part 6: Activate this minor. The char device can now be used. */
set_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_lock(&videodev_lock);
video_device[vdev->minor] = vdev;
mutex_unlock(&videodev_lock);
+
return 0;

cleanup:
@@ -598,7 +632,10 @@ void video_unregister_device(struct video_device *vdev)
/* Check if vdev was ever registered at all */
if (!vdev || !video_is_registered(vdev))
return;
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+ media_device_unregister_entity(&vdev->entity);
+#endif
clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
device_unregister(&vdev->dev);
}
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 96a2e6b..e7d1550 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -16,6 +16,8 @@
#include <linux/mutex.h>
#include <linux/videodev2.h>

+#include <media/media-entity.h>
+
#define VIDEO_MAJOR 81

#define VFL_TYPE_GRABBER 0
@@ -58,6 +60,9 @@ struct v4l2_file_operations {

struct video_device
{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_entity entity;
+#endif
/* device ops */
const struct v4l2_file_operations *fops;

@@ -100,6 +105,8 @@ struct video_device
const struct v4l2_ioctl_ops *ioctl_ops;
};

+#define media_entity_to_video_device(entity) \
+ container_of(entity, struct video_device, entity)
/* dev to video-device */
#define to_video_device(cd) container_of(cd, struct video_device, dev)
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:22 UTC
Permalink
V4L2 subdevices are media entities. As such they need to inherit from
(include) the media_entity structure.

When registering/unregistering the subdevice, the media entity is
automatically registered/unregistered. The entity is acquired on device
open and released on device close.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/video4linux/v4l2-framework.txt | 23 ++++++++++++++
drivers/media/video/v4l2-device.c | 39 ++++++++++++++++++++----
drivers/media/video/v4l2-subdev.c | 41 ++++++++++++++++++++++++-
include/media/v4l2-subdev.h | 10 ++++++
4 files changed, 104 insertions(+), 9 deletions(-)

diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index f1ac9f6a..c8c37be 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -268,6 +268,26 @@ A sub-device driver initializes the v4l2_subdev struct using:
Afterwards you need to initialize subdev->name with a unique name and set the
module owner. This is done for you if you use the i2c helper functions.

+If integration with the media framework is needed, you must initialize the
+media_entity struct embedded in the v4l2_subdev struct (entity field) by
+calling media_entity_init():
+
+ struct media_pad *pads = &my_sd->pads;
+ int err;
+
+ err = media_entity_init(&sd->entity, npads, pads, 0);
+
+The pads array must have been previously initialized. There is no need to
+manually set the struct media_entity type and name fields, but the revision
+field must be initialized if needed.
+
+A reference to the entity will be automatically acquired/released when the
+subdev device node (if any) is opened/closed.
+
+Don't forget to cleanup the media entity before the sub-device is destroyed:
+
+ media_entity_cleanup(&sd->entity);
+
A device (bridge) driver needs to register the v4l2_subdev with the
v4l2_device:

@@ -277,6 +297,9 @@ This can fail if the subdev module disappeared before it could be registered.
After this function was called successfully the subdev->dev field points to
the v4l2_device.

+If the v4l2_device parent device has a non-NULL mdev field, the sub-device
+entity will be automatically registered with the media device.
+
You can unregister a sub-device using:

v4l2_device_unregister_subdev(sd);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 8447466..7ac4d0f 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -115,8 +115,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
EXPORT_SYMBOL_GPL(v4l2_device_unregister);

int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
- struct v4l2_subdev *sd)
+ struct v4l2_subdev *sd)
{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_entity *entity = &sd->entity;
+#endif
struct video_device *vdev;
int err;

@@ -134,7 +137,16 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
if (err)
return err;
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ /* Register the entity. */
+ if (v4l2_dev->mdev) {
+ err = media_device_register_entity(v4l2_dev->mdev, entity);
+ if (err < 0) {
+ module_put(sd->owner);
+ return err;
+ }
+ }
+#endif
sd->v4l2_dev = v4l2_dev;
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
@@ -149,26 +161,39 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) {
err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
sd->owner);
- if (err < 0)
+ if (err < 0) {
v4l2_device_unregister_subdev(sd);
+ return err;
+ }
}
-
- return err;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ entity->v4l.major = VIDEO_MAJOR;
+ entity->v4l.minor = vdev->minor;
+#endif
+ return 0;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);

void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
{
+ struct v4l2_device *v4l2_dev;
+
/* return if it isn't registered */
if (sd == NULL || sd->v4l2_dev == NULL)
return;

- spin_lock(&sd->v4l2_dev->lock);
+ v4l2_dev = sd->v4l2_dev;
+
+ spin_lock(&v4l2_dev->lock);
list_del(&sd->list);
- spin_unlock(&sd->v4l2_dev->lock);
+ spin_unlock(&v4l2_dev->lock);
sd->v4l2_dev = NULL;

module_put(sd->owner);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (v4l2_dev->mdev)
+ media_device_unregister_entity(&sd->entity);
+#endif
video_unregister_device(&sd->devnode);
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 002281c..3f09e23 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -34,7 +34,10 @@ static int subdev_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
- struct v4l2_fh *vfh;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_entity *entity;
+#endif
+ struct v4l2_fh *vfh = NULL;
int ret;

if (!sd->initialized)
@@ -60,11 +63,20 @@ static int subdev_open(struct file *file)
v4l2_fh_add(vfh);
file->private_data = vfh;
}
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->v4l2_dev->mdev) {
+ entity = media_entity_get(&sd->entity);
+ if (!entity) {
+ ret = -EBUSY;
+ goto err;
+ }
+ }
+#endif
return 0;

err:
if (vfh != NULL) {
+ v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
kfree(vfh);
}
@@ -74,8 +86,16 @@ err:

static int subdev_close(struct file *file)
{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+#endif
struct v4l2_fh *vfh = file->private_data;

+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->v4l2_dev->mdev)
+ media_entity_put(&sd->entity);
+#endif
if (vfh != NULL) {
v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
@@ -175,5 +195,22 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
sd->dev_priv = NULL;
sd->host_priv = NULL;
sd->initialized = 1;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ sd->entity.name = sd->name;
+ sd->entity.type = MEDIA_ENTITY_TYPE_SUBDEV;
+#endif
}
EXPORT_SYMBOL(v4l2_subdev_init);
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+int v4l2_subdev_set_power(struct media_entity *entity, int power)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+
+ dev_dbg(entity->parent->dev,
+ "%s power%s\n", entity->name, power ? "on" : "off");
+
+ return v4l2_subdev_call(sd, core, s_power, power);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_set_power);
+#endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 4bd5c34..c1b92a8 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -21,6 +21,7 @@
#ifndef _V4L2_SUBDEV_H
#define _V4L2_SUBDEV_H

+#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-mediabus.h>
@@ -422,6 +423,9 @@ struct v4l2_subdev_ops {
stand-alone or embedded in a larger struct.
*/
struct v4l2_subdev {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_entity entity;
+#endif
struct list_head list;
struct module *owner;
u32 flags;
@@ -443,6 +447,8 @@ struct v4l2_subdev {
unsigned int nevents;
};

+#define media_entity_to_v4l2_subdev(ent) \
+ container_of(ent, struct v4l2_subdev, entity)
#define vdev_to_v4l2_subdev(vdev) \
container_of(vdev, struct v4l2_subdev, devnode)

@@ -471,6 +477,10 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
void v4l2_subdev_init(struct v4l2_subdev *sd,
const struct v4l2_subdev_ops *ops);

+#if defined(CONFIG_MEDIA_CONTROLLER)
+int v4l2_subdev_set_power(struct media_entity *entity, int power);
+#endif
+
/* Call an ops of a v4l2_subdev, doing the right checks against
NULL pointers.
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:23 UTC
Permalink
The header defines the v4l2_mbus_framefmt structure which will be used
by the V4L2 subdevs userspace API.

Change the type of the v4l2_mbus_framefmt::code field to __u32, as enum
sizes can differ between different ABIs on the same architectures.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/linux/Kbuild | 1 +
include/linux/v4l2-mediabus.h | 78 +++++++++++++++++++++++++++++++++++++++++
include/media/soc_mediabus.h | 3 +-
include/media/v4l2-mediabus.h | 61 +-------------------------------
4 files changed, 81 insertions(+), 62 deletions(-)
create mode 100644 include/linux/v4l2-mediabus.h

diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index efc9718..450cbed 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -167,6 +167,7 @@ header-y += udf_fs_i.h
header-y += ultrasound.h
header-y += un.h
header-y += utime.h
+header-y += v4l2-mediabus.h
header-y += veth.h
header-y += videotext.h
header-y += x25.h
diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
new file mode 100644
index 0000000..a62cd64
--- /dev/null
+++ b/include/linux/v4l2-mediabus.h
@@ -0,0 +1,78 @@
+/*
+ * Media Bus API header
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <***@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_V4L2_MEDIABUS_H
+#define __LINUX_V4L2_MEDIABUS_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+/*
+ * These pixel codes uniquely identify data formats on the media bus. Mostly
+ * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
+ * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
+ * data format is fixed. Additionally, "2X8" means that one pixel is transferred
+ * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
+ * transferred over the bus: "LE" means that the least significant bits are
+ * transferred first, "BE" means that the most significant bits are transferred
+ * first, and "PADHI" and "PADLO" define which bits - low or high, in the
+ * incomplete high byte, are filled with padding bits.
+ */
+enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_FIXED = 1,
+ V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_YVYU8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_VYUY8_2X8,
+ V4L2_MBUS_FMT_YVYU10_2X10,
+ V4L2_MBUS_FMT_YUYV10_2X10,
+ V4L2_MBUS_FMT_YVYU10_1X20,
+ V4L2_MBUS_FMT_YUYV10_1X20,
+ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ V4L2_MBUS_FMT_RGB565_2X8_LE,
+ V4L2_MBUS_FMT_RGB565_2X8_BE,
+ V4L2_MBUS_FMT_BGR565_2X8_LE,
+ V4L2_MBUS_FMT_BGR565_2X8_BE,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_SBGGR10_1X10,
+ V4L2_MBUS_FMT_GREY8_1X8,
+ V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ V4L2_MBUS_FMT_SGRBG8_1X8,
+ V4L2_MBUS_FMT_SBGGR12_1X12,
+ V4L2_MBUS_FMT_YUYV8_1_5X8,
+ V4L2_MBUS_FMT_YVYU8_1_5X8,
+ V4L2_MBUS_FMT_UYVY8_1_5X8,
+ V4L2_MBUS_FMT_VYUY8_1_5X8,
+};
+
+/**
+ * struct v4l2_mbus_framefmt - frame format on the media bus
+ * @width: frame width
+ * @height: frame height
+ * @code: data format code
+ * @field: used interlacing type
+ * @colorspace: colorspace of the data
+ */
+struct v4l2_mbus_framefmt {
+ __u32 width;
+ __u32 height;
+ __u32 code;
+ enum v4l2_field field;
+ enum v4l2_colorspace colorspace;
+};
+
+#endif
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
index 037cd7b..6243147 100644
--- a/include/media/soc_mediabus.h
+++ b/include/media/soc_mediabus.h
@@ -12,8 +12,7 @@
#define SOC_MEDIABUS_H

#include <linux/videodev2.h>
-
-#include <media/v4l2-mediabus.h>
+#include <linux/v4l2-mediabus.h>

/**
* enum soc_mbus_packing - data packing types on the media-bus
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 8e65598..971c7fa 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -11,66 +11,7 @@
#ifndef V4L2_MEDIABUS_H
#define V4L2_MEDIABUS_H

-/*
- * These pixel codes uniquely identify data formats on the media bus. Mostly
- * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
- * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
- * data format is fixed. Additionally, "2X8" means that one pixel is transferred
- * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
- * transferred over the bus: "LE" means that the least significant bits are
- * transferred first, "BE" means that the most significant bits are transferred
- * first, and "PADHI" and "PADLO" define which bits - low or high, in the
- * incomplete high byte, are filled with padding bits.
- */
-enum v4l2_mbus_pixelcode {
- V4L2_MBUS_FMT_FIXED = 1,
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_YVYU8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_VYUY8_2X8,
- V4L2_MBUS_FMT_YVYU10_2X10,
- V4L2_MBUS_FMT_YUYV10_2X10,
- V4L2_MBUS_FMT_YVYU10_1X20,
- V4L2_MBUS_FMT_YUYV10_1X20,
- V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
- V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
- V4L2_MBUS_FMT_RGB565_2X8_LE,
- V4L2_MBUS_FMT_RGB565_2X8_BE,
- V4L2_MBUS_FMT_BGR565_2X8_LE,
- V4L2_MBUS_FMT_BGR565_2X8_BE,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_GREY8_1X8,
- V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
- V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SBGGR12_1X12,
- V4L2_MBUS_FMT_YUYV8_1_5X8,
- V4L2_MBUS_FMT_YVYU8_1_5X8,
- V4L2_MBUS_FMT_UYVY8_1_5X8,
- V4L2_MBUS_FMT_VYUY8_1_5X8,
-};
-
-/**
- * struct v4l2_mbus_framefmt - frame format on the media bus
- * @width: frame width
- * @height: frame height
- * @code: data format code
- * @field: used interlacing type
- * @colorspace: colorspace of the data
- */
-struct v4l2_mbus_framefmt {
- __u32 width;
- __u32 height;
- enum v4l2_mbus_pixelcode code;
- enum v4l2_field field;
- enum v4l2_colorspace colorspace;
-};
+#include <linux/v4l2-mediabus.h>

static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
const struct v4l2_mbus_framefmt *mbus_fmt)
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:24 UTC
Permalink
The v4l2_mbus_framefmt structure will be part of the public userspace
API and used (albeit indirectly) as an ioctl argument. As such, its size
must be fixed across userspace ABIs.

Replace the v4l2_field and v4l2_colorspace enums by __u32 fields.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/linux/v4l2-mediabus.h | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index a62cd64..a25e19f 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -63,16 +63,16 @@ enum v4l2_mbus_pixelcode {
* struct v4l2_mbus_framefmt - frame format on the media bus
* @width: frame width
* @height: frame height
- * @code: data format code
- * @field: used interlacing type
- * @colorspace: colorspace of the data
+ * @code: data format code (from enum v4l2_mbus_pixelcode)
+ * @field: used interlacing type (from enum v4l2_field)
+ * @colorspace: colorspace of the data (from enum v4l2_colorspace)
*/
struct v4l2_mbus_framefmt {
- __u32 width;
- __u32 height;
- __u32 code;
- enum v4l2_field field;
- enum v4l2_colorspace colorspace;
+ __u32 width;
+ __u32 height;
+ __u32 code;
+ __u32 field;
+ __u32 colorspace;
};

#endif
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:25 UTC
Permalink
For consistency with the V4L2_MBUS_FMT_Y10_1X10 format.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
drivers/media/video/mt9m001.c | 2 +-
drivers/media/video/mt9v022.c | 4 ++--
drivers/media/video/soc_mediabus.c | 2 +-
include/linux/v4l2-mediabus.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index fcb4cd9..3aaedf6 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -79,7 +79,7 @@ static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
/* Order important - see above */
{V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
};

struct mt9m001 {
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 1a02f67..8ded876 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -95,7 +95,7 @@ static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
/* Order important - see above */
{V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
};

struct mt9v022 {
@@ -392,7 +392,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
* icd->try_fmt(), datawidth is from our supported format list
*/
switch (mf->code) {
- case V4L2_MBUS_FMT_GREY8_1X8:
+ case V4L2_MBUS_FMT_Y8_1X8:
case V4L2_MBUS_FMT_Y10_1X10:
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
return -EINVAL;
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index 9139121..d9c297d 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -88,7 +88,7 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = {
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(GREY8_1X8)] = {
+ [MBUS_IDX(Y8_1X8)] = {
.fourcc = V4L2_PIX_FMT_GREY,
.name = "Grey",
.bits_per_sample = 8,
diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index a25e19f..1171cac 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -45,7 +45,7 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_BGR565_2X8_BE,
V4L2_MBUS_FMT_SBGGR8_1X8,
V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_GREY8_1X8,
+ V4L2_MBUS_FMT_Y8_1X8,
V4L2_MBUS_FMT_Y10_1X10,
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:26 UTC
Permalink
Adding new pixel codes at the end of the enumeration will soon create a
mess, so group the pixel codes by type and sort them by bus_width, bits
per component, samples per pixel and order of subsamples.

As the codes are part of the kernel ABI their value can't change when a
new code is inserted in the enumeration, so they are given an explicit
numerical value. When inserting a new pixel code developers must use and
update the next free value.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/linux/v4l2-mediabus.h | 77 ++++++++++++++++++++++++----------------
1 files changed, 46 insertions(+), 31 deletions(-)

diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index 1171cac..ed5ac25 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -24,39 +24,54 @@
* transferred first, "BE" means that the most significant bits are transferred
* first, and "PADHI" and "PADLO" define which bits - low or high, in the
* incomplete high byte, are filled with padding bits.
+ *
+ * The pixel codes are grouped by type, bus_width, bits per component, samples
+ * per pixel and order of subsamples. Numerical values are sorted using generic
+ * numerical sort order (8 thus comes before 10).
+ *
+ * As their value can't change when a new pixel code is inserted in the
+ * enumeration, the pixel codes are explicitly given a numerical value. The next
+ * free values for each category are listed below, update them when inserting
+ * new pixel codes.
*/
enum v4l2_mbus_pixelcode {
- V4L2_MBUS_FMT_FIXED = 1,
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_YVYU8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_VYUY8_2X8,
- V4L2_MBUS_FMT_YVYU10_2X10,
- V4L2_MBUS_FMT_YUYV10_2X10,
- V4L2_MBUS_FMT_YVYU10_1X20,
- V4L2_MBUS_FMT_YUYV10_1X20,
- V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
- V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
- V4L2_MBUS_FMT_RGB565_2X8_LE,
- V4L2_MBUS_FMT_RGB565_2X8_BE,
- V4L2_MBUS_FMT_BGR565_2X8_LE,
- V4L2_MBUS_FMT_BGR565_2X8_BE,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
- V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SBGGR12_1X12,
- V4L2_MBUS_FMT_YUYV8_1_5X8,
- V4L2_MBUS_FMT_YVYU8_1_5X8,
- V4L2_MBUS_FMT_UYVY8_1_5X8,
- V4L2_MBUS_FMT_VYUY8_1_5X8,
+ V4L2_MBUS_FMT_FIXED = 0x0001,
+
+ /* RGB - next is 0x1009 */
+ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
+ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
+ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
+ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE = 0x1004,
+ V4L2_MBUS_FMT_BGR565_2X8_BE = 0x1005,
+ V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
+ V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
+ V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
+
+ /* YUV (including grey) - next is 0x200f */
+ V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
+ V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
+ V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
+ V4L2_MBUS_FMT_YUYV8_1_5X8 = 0x2004,
+ V4L2_MBUS_FMT_YVYU8_1_5X8 = 0x2005,
+ V4L2_MBUS_FMT_UYVY8_2X8 = 0x2006,
+ V4L2_MBUS_FMT_VYUY8_2X8 = 0x2007,
+ V4L2_MBUS_FMT_YUYV8_2X8 = 0x2008,
+ V4L2_MBUS_FMT_YVYU8_2X8 = 0x2009,
+ V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
+ V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
+ V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
+ V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
+ V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
+
+ /* Bayer - next is 0x3009 */
+ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
+ V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
+ V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
+ V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
};

/**
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:27 UTC
Permalink
Add the following media bus format code definitions:

- V4L2_MBUS_FMT_SGRBG10_1X10 for 10-bit GRBG Bayer
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 for 10-bit DPCM compressed GRBG Bayer
- V4L2_MBUS_FMT_YUYV16_1X16 for 8-bit YUYV on 16-bit bus
- V4L2_MBUS_FMT_UYVY16_1X16 for 8-bit UYVY on 16-bit bus
- V4L2_MBUS_FMT_YVYU16_1X16 for 8-bit YVYU on 16-bit bus
- V4L2_MBUS_FMT_VYUY16_1X16 for 8-bit VYUY on 16-bit bus

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/linux/v4l2-mediabus.h | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index ed5ac25..b091366 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -47,7 +47,7 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,

- /* YUV (including grey) - next is 0x200f */
+ /* YUV (including grey) - next is 0x2013 */
V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
@@ -60,17 +60,23 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
+ V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f,
+ V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
+ V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
+ V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012,
V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,

- /* Bayer - next is 0x3009 */
+ /* Bayer - next is 0x300b */
V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
+ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
+ V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
};
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:28 UTC
Permalink
This adds following formats:
- V4L2_MBUS_FMT_SRGGB10_1X10
- V4L2_MBUS_FMT_SGBRG10_1X10
- V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8
- V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8
- V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8

Signed-off-by: Sergio Aguirre <***@ti.com>
Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/linux/v4l2-mediabus.h | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index b091366..99cfd38 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -67,16 +67,21 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,

- /* Bayer - next is 0x300b */
+ /* Bayer - next is 0x3010 */
V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
+ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b,
+ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c,
V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
+ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 = 0x300d,
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
+ V4L2_MBUS_FMT_SGBRG10_1X10 = 0x300e,
V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
+ V4L2_MBUS_FMT_SRGGB10_1X10 = 0x300f,
V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
};
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:29 UTC
Permalink
From: Stanimir Varbanov <***@mm-sol.com>

Used for storing subdev information per file handle and hold V4L2 file
handle.

Signed-off-by: Stanimir Varbanov <***@mm-sol.com>
Signed-off-by: Antti Koskipaa <***@nokia.com>
Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
drivers/media/Kconfig | 9 ++++
drivers/media/video/v4l2-subdev.c | 84 +++++++++++++++++++++++++------------
include/media/v4l2-subdev.h | 29 +++++++++++++
3 files changed, 95 insertions(+), 27 deletions(-)

diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 6b946e6..eaf4734 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -82,6 +82,15 @@ config VIDEO_V4L1_COMPAT

If you are unsure as to whether this is required, answer Y.

+config VIDEO_V4L2_SUBDEV_API
+ bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
+ depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
+ ---help---
+ Enables the V4L2 sub-device pad-level userspace API used to configure
+ video format, size and frame rate between hardware blocks.
+
+ This API is mostly used by camera interfaces in embedded platforms.
+
#
# DVB Core
#
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 3f09e23..56ad9b2 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -30,39 +30,69 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>

+static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
+{
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ /* Allocate try format and crop in the same memory block */
+ fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
+ * sd->entity.num_pads, GFP_KERNEL);
+ if (fh->try_fmt == NULL)
+ return -ENOMEM;
+
+ fh->try_crop = (struct v4l2_rect *)
+ (fh->try_fmt + sd->entity.num_pads);
+#endif
+ return 0;
+}
+
+static void subdev_fh_free(struct v4l2_subdev_fh *fh)
+{
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ kfree(fh->try_fmt);
+ fh->try_fmt = NULL;
+ fh->try_crop = NULL;
+#endif
+}
+
static int subdev_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_subdev_fh *subdev_fh;
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity *entity;
#endif
- struct v4l2_fh *vfh = NULL;
int ret;

if (!sd->initialized)
return -EAGAIN;

- if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
- vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
- if (vfh == NULL)
- return -ENOMEM;
+ subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
+ if (subdev_fh == NULL)
+ return -ENOMEM;

- ret = v4l2_fh_init(vfh, vdev);
- if (ret)
- goto err;
+ ret = subdev_fh_init(subdev_fh, sd);
+ if (ret) {
+ kfree(subdev_fh);
+ return ret;
+ }
+
+ ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
+ if (ret)
+ goto err;

- ret = v4l2_event_init(vfh);
+ if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
+ ret = v4l2_event_init(&subdev_fh->vfh);
if (ret)
goto err;

- ret = v4l2_event_alloc(vfh, sd->nevents);
+ ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
if (ret)
goto err;
-
- v4l2_fh_add(vfh);
- file->private_data = vfh;
}
+
+ v4l2_fh_add(&subdev_fh->vfh);
+ file->private_data = &subdev_fh->vfh;
#if defined(CONFIG_MEDIA_CONTROLLER)
if (sd->v4l2_dev->mdev) {
entity = media_entity_get(&sd->entity);
@@ -75,11 +105,10 @@ static int subdev_open(struct file *file)
return 0;

err:
- if (vfh != NULL) {
- v4l2_fh_del(vfh);
- v4l2_fh_exit(vfh);
- kfree(vfh);
- }
+ v4l2_fh_del(&subdev_fh->vfh);
+ v4l2_fh_exit(&subdev_fh->vfh);
+ subdev_fh_free(subdev_fh);
+ kfree(subdev_fh);

return ret;
}
@@ -91,16 +120,17 @@ static int subdev_close(struct file *file)
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
#endif
struct v4l2_fh *vfh = file->private_data;
+ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);

#if defined(CONFIG_MEDIA_CONTROLLER)
if (sd->v4l2_dev->mdev)
media_entity_put(&sd->entity);
#endif
- if (vfh != NULL) {
- v4l2_fh_del(vfh);
- v4l2_fh_exit(vfh);
- kfree(vfh);
- }
+ v4l2_fh_del(vfh);
+ v4l2_fh_exit(vfh);
+ subdev_fh_free(subdev_fh);
+ kfree(subdev_fh);
+ file->private_data = NULL;

return 0;
}
@@ -109,7 +139,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
- struct v4l2_fh *fh = file->private_data;
+ struct v4l2_fh *vfh = file->private_data;

switch (cmd) {
case VIDIOC_QUERYCTRL:
@@ -137,13 +167,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
return -ENOIOCTLCMD;

- return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
+ return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);

case VIDIOC_SUBSCRIBE_EVENT:
- return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
+ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);

case VIDIOC_UNSUBSCRIBE_EVENT:
- return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);

default:
return -ENOIOCTLCMD;
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c1b92a8..adfaa06 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -24,6 +24,7 @@
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
#include <media/v4l2-mediabus.h>

/* generic v4l2_device notify callback notification values */
@@ -452,6 +453,34 @@ struct v4l2_subdev {
#define vdev_to_v4l2_subdev(vdev) \
container_of(vdev, struct v4l2_subdev, devnode)

+/*
+ * Used for storing subdev information per file handle
+ */
+struct v4l2_subdev_fh {
+ struct v4l2_fh vfh;
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ struct v4l2_mbus_framefmt *try_fmt;
+ struct v4l2_rect *try_crop;
+#endif
+};
+
+#define to_v4l2_subdev_fh(fh) \
+ container_of(fh, struct v4l2_subdev_fh, vfh)
+
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+static inline struct v4l2_mbus_framefmt *
+v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+ return &fh->try_fmt[pad];
+}
+
+static inline struct v4l2_rect *
+v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+ return &fh->try_crop[pad];
+}
+#endif
+
extern const struct v4l2_file_operations v4l2_subdev_fops;

static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:30 UTC
Permalink
Add a v4l2_subdev_pad_ops structure for the operations that need to be
performed at the pad level such as format-related operations.

Pad format-related operations use v4l2_mbus_framefmt instead of
v4l2_format.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
include/media/v4l2-subdev.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index adfaa06..3a304da 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -42,6 +42,7 @@ struct v4l2_ctrl_handler;
struct v4l2_event_subscription;
struct v4l2_fh;
struct v4l2_subdev;
+struct v4l2_subdev_fh;
struct tuner_setup;

/* decode_vbi_line */
@@ -399,6 +400,9 @@ struct v4l2_subdev_ir_ops {
struct v4l2_subdev_ir_parameters *params);
};

+struct v4l2_subdev_pad_ops {
+};
+
struct v4l2_subdev_ops {
const struct v4l2_subdev_core_ops *core;
const struct v4l2_subdev_tuner_ops *tuner;
@@ -407,6 +411,7 @@ struct v4l2_subdev_ops {
const struct v4l2_subdev_vbi_ops *vbi;
const struct v4l2_subdev_ir_ops *ir;
const struct v4l2_subdev_sensor_ops *sensor;
+ const struct v4l2_subdev_pad_ops *pad;
};

#define V4L2_SUBDEV_NAME_SIZE 32
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:31 UTC
Permalink
Add images used by the V4L2 subdev userspace format API documentation.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/DocBook/v4l/bayer.pdf | Bin 0 -> 12116 bytes
Documentation/DocBook/v4l/bayer.png | Bin 0 -> 9725 bytes
Documentation/DocBook/v4l/pipeline.pdf | Bin 0 -> 20276 bytes
Documentation/DocBook/v4l/pipeline.png | Bin 0 -> 12130 bytes
4 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/bayer.pdf
create mode 100644 Documentation/DocBook/v4l/bayer.png
create mode 100644 Documentation/DocBook/v4l/pipeline.pdf
create mode 100644 Documentation/DocBook/v4l/pipeline.png

diff --git a/Documentation/DocBook/v4l/bayer.pdf b/Documentation/DocBook/v4l/bayer.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..905e60e6cd429f026afdfa6fb4dab3f1683adb8a
GIT binary patch
literal 12116
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

literal 0
HcmV?d00001

diff --git a/Documentation/DocBook/v4l/bayer.png b/Documentation/DocBook/v4l/bayer.png
new file mode 100644
index 0000000000000000000000000000000000000000..9b15fb22e8173c83c3da6df73cd7cdc7d8f41736
GIT binary patch
literal 9725
zcmY*<1ymeOv-ZN`?(Qy|;1(=cfZzm{1p+***@oZuQ@AxQAxK>~!35LjUGH!QMCu;3xM
zySqC-@4er5&-***@Jre><Ar>47Ry6UNO`h&i%IxztQ0RR9X*3?in1OPB0kJn{*z(@Jw
z9eV8XgyC(dt_-LgWZD7%fB=1MBQ*df01p!rfJIG?fq_W~;K9HI5U>FWDKQB6nQ<`0
zF#rG}9SkY}IRzOe0}#Lj0MMv1QxVY95U3Di12{1N+yHVWer6UXV=`=P78eIHAb`t{
zhl3qU7zdL(8b$)}rUGC|0`PfLM0mJ)`FY4ekPH%lJP$ql6B!vneCDT`(n4GS6`;Nl
z1wf)tTtW;W*#Xc303;r!$T098=b*UV!Tcy6upj_IH78RA!FeXY93!Qw>T`hl!***@0
zng<hK>)***@Y-0Ocy%KN3E%A7_0ac*9Cy%0iZN~cx9w7{W^YGhLz*>gPK){804PO
z`r)0a<h-oPl03hql}&*83r{QgC1nn48!JEpU_*n%#5r_X3nc4!@8jU<>gEh~e315h
zaP;yHeQUCAB#WC5aPTYg_4fgk;H+6Ze-ZMqZ7oPp3ILP?f`S7!p&I6}B0vQIP=&E#
z?FOhJi3<w@)B|E8VSt|iqnL*+S8!wuEdG5QPc<MX%FQ>iFevh&BFZE>A?ZhyJ9j-h
z$3HYyDGy0WANGUA6#oGrk_~r4-bl5GITW|O%WIcuRq)KY--+=$j)&xZ&fWbGsrE}|
zGcFH;<}1v6km_>O?$Fvx4pZuRU0s}3{Jk`)^kFY2&a&4ex%{s4M`&Rc(jWO(e<=K2
zuS^x9GP`c<<w%D6ko(7mhjVz?d6oTf`R799L-1(OR%7%&q9=RQI(|H|{THgXYkZ)+
z!E+v&***@ZQKnO-ytJ8G-1>wOq%***@I^V>bf?bH}|P#_~!TEpTWVtzFG5$fl>7E!*x&F
zkCkt&%dy=PE6ab|8`i#*Zueb}HuTNhU;gc#nwe_cs{6U!{CBN%b|bZYx9#_C*VX*O
z-D=y=;mG{P!{*lJ;vsT$@2=zgboylKVe8N3_VU)=-Nnw{<x%bR_VwEF)yCP(^7+!<
z#l-E&<nhVf_3`oM#l_a;&h172@#W6L#r^%&<>B4+`OW?P?ZVZ~<=xHx!|l!W{lo3U
z&A;N5zvJJ9VWXw43W&vK)_7F#-)fk80|3;?k4Gj3ahhKDV<WDQrj8o!G(HtAJ--{e
z_74ES2GCShG76a9%O?(@8mmXW!N9M3k;rN~6H~?dEh;Wn$E+9%Egp5|sAjvQz|Q$H
z3EI+r>$&!-a9P>;x0qvZu__)`09As5s!j)9dRbj~;W}`Q^8*<r7AGvlwSB#@?PkB_
zq*|<2R?J^Ywsvwsz5*e;+b_Q{`|vq<***@cG>(0IDgqF+8-a+ZJA;Ix_M34Ov
z;ETgS^XK6tn3K2h_1apdTBT*$9hjnRHc-%e<pO^-W}=gp3Tw-R`iGyw;pHN0YTeBp
zBQDvrbszDFP}NhTnf@@l1Wn!)CI7)(ThPh+>y``@w5@;%p1V%|d#Fvzp<5z~Eoa0o
zEM2387kAcE=)>*lx}!***@Xnrm;~le>u7kJWmn|6-(@PU|}R(T=s|s`KU9fwQqj
zu<R}A1L+;?9?Q}T;hsG}PbhmZevmrlIiS3_C!8{Ph~gOb7%T?v)9nanRx2`Nwt45{
zTt{KkXx1iG<AFG2cXdz`BVJ}an-=lQ^3U(IaK`EI#^o|!iFWWmELuHB1RaajoR;t;
z6dgv(JhfdSgQ!NMV$WLpiiP$$tzl|~3vyWFj<!E9zN-MFZ3+vJa`4zSHb>e>H9K4^
zmv6Sst^LnPwJ}`uy6zd6r>w-@1!|*@***@eZtYieUAT#`Wc%jk=WjOLUOI36b5b
zrDGYuq`4(nR5#NpYdKxiSH(***@tZ^)0a8@@B{7WQ`8#***@4kPEuBGpc-rEd4oZ1
znl`Xpy=***@ILzJ^9kft5z$}8}5)+#1R*logrgH9(ivvbtK>GM0R3L_GK8OK8(3pxC
zVfS1UAGut51wA6B4=-_wxq?QG9L(T>@x(ZA1>a!`nbO-D`W_I-jQ?ITx4QHnwkY}p
z^~?+Y)Lq*@;1vXQnz5FIF!k+x-=(C6B)KYe{j&6j;DQ^PE#***@w35JkW@***@_xOj&
z>n;z&vuNe-Z~Dl^4KB{QOExR)RoKm&8|f|XCM)gXl8|S9*+ewvujht|lf!CVB+Bu@
zy*OL9nG>v9o)DbOQ__}tp`D1%Ac2m3;}8`N92bU7iiaz0a2X9m_;rOmx5Wl0RViF^
zUdG*{@sc#_zRNkX#4YA0w7Tl$^;zq{b~***@g7bqp7^***@y0$v6aEOp?=U~P
zRJ#F1{QF95npI~VsekIq9mzLLZ}0&HeH2g9IB8t>YLD%oX1yV-d;KDl0K_b-jU69M
z8!ptl1X%uYsaj-32AO$vXxMw%<^!8hH^&=K_=6bx)0Tscycf|yKqgxjb_KkUv!%g`
zaTJgcDXtA*%***@DcXm6$kIjvb;f)yG0LO7nF^ankV30r1ZEqK}hEoti(Fz6SUeK
z5Rkia7MWmS*0B}N-5kR3Iz0-MhJHrMbL3X?wHaF_lT#eRv^_5)tzSL729;o}kBw5r
z1#KV~1=%&K^G;a#>`XCeA~YGS$Y#S<h&aG_vf5bj-uV&0m`fZ1Mm*CTsElC~%7_r1
z!vJUk6M|^`s<eEb5F)eUIUvG!^2MK;WvvUIbvDOYy!tuKfw083>Uq)jWX=0^G!%Qv
zng`;tsuVYKe9n}`4k<oJB8NN_6Vu%G;zUq2I&{~Ravkjbc0A{mf8e^bt?81>^wzpC
z5kidI^6l7-oj}&P4rUcmiuU*-<+;r+Q`Q`i!`yp4U4^4XQ7l1hze5u+Nz{}wGHuY2
***@UuT}%%eED0pEsG$vXqPmw!^<6`K<0=k@)g;54!)t&Tk`J%J{*~u%nlJ}AEXU&
zw`j4(_m5r`^+VnQ!m}#0=V|Tq@}D_v!`t#OT5Kg!{j>Q)zgfSqLZxO;Dk|+%4x18_
zJUhybV}=M=jB_2#p&}DjGmVdlv$j_uW`5cDU@^YV{Ka|nj>#***@E>ldTWv8)MKz
zp~M^t9C=Yq&*Y)jN#bwh1$X*ev|6QDo^NZ7I3zqWj0a)IQ{UY2m8aP{O+LDexR7aQ
zgZ!e=***@vuo3pG>oE;B>xndR)$+n8zMWGCH}m(c2E``OpxsFyENbMibXZY7L^`9dg$
z8r#***@u((6UDot_Xqd}***@i0P$P(65k)EH(Pu6I;%on?wr9ZB^r0lPjAljRU#pu`
zZitSe6xjf(98WF=D7V&$qHStcWRBev#O10*PxT}ep{+ZAG_smTJq_KOwAMUMIun${
z6kM~`$mHzwLM##k11v~EB7xnM8L#U&GAE@@B2lU1IR#YT7#Hs_U+$4Xz#!$?stAuu
zb1L!8TG><1%xLCyU8&QjsYVe%zsNsw<9{s{<##y8H`5yd`d=ZvTR5cKmQLAk)fqv1
zv7OHruxYK{***@gHdgNdUY2agIy2CCA?Ksy{X4CRVh<F5HGO10z=KEGzyC5}4jWNh3e
z?_{S+>YCEvk`In1qh6rqL`|XY2;qE8T9euUCcAjWYEZYb77yzHjXSK-C!DiM2J9%S
zZ82i{mslZKY4U5sH((w8VDqm@&%t&zN2ds?Z>Ap35m8{Wr<Lm~I59{m0jQ3O=({V;
z;S!mXL78|xj6*dwPtUDPoPdp{zA`n(I<K)S&p?Bt=@w={NUfQNrur|ESDZB3de0BK
z*UIDiE*gsNXro=C_(}a?QcqY3)MfQc(@CQrpKJ{_p~jzM%=qN5*%bP{#Vy)9Na3Tx
z<<xc|zTw~V=31ApcT5|81J=F{^Yy#JfiwMPzlB<mmczMh#Gs0B#S)0r9NW{a*>^a3
zDRWY#jRSm5QqL&A?m-w_#@}qZo~jr&uW6`vPpJD-qZx4trLKQY?7MAlUaqfrwIqf<
zM%U&)$==il^5cJ|Zaq6ilf22{)c4!cmtJsVXny7s<r{0i??3+}uf$#M&l#-R6eBm}
z#~fWm1s6`;m&WZp_i{OBPCh$djoVqz;08|}1nT{n%VFvz(h4mpz7)Z}yQ00z(5*v#
zQGECUH9+t|vcw=AYD$~>8fZ~&8yzu(e_#UVcw;l4#+w9mj@>BSNlj^FLeRc=+YOx1
zN0$LM5m3Er;A^l?cp0BgU|***@GAL~Y63`{bS-0T%}$PmF4{Jz#_9~9cU{VrG={mje=
zo^CjHv%F3hf&IMJOg<x2ZHz4%Dgn!K=r`&Gt<BI2!4A=)WVASfIX0M(KU89<xX;-@
znosXB!1`kDjn_S{Szu3d#cS4U;QbaUAv~})***@AfH2d?By0O3*#V~1QMNzjO)7<5LS
zV#fC*r9cB!nr&V0BJ7}tMWGFX9{PP}QgdV>uFpp_>bXkJxNStF$bM(***@8WSw1|veT
z-(l>OF;<%N=_skY|C6(&$0a$_1HF6sm{YS5bN9eXk_OI>***@Z!rM>?GFDQF}
z6JZ;;id-M>f7)|9Z}n|TH!2#`D$;2?c8^`S5sy>}c%A9av|X$`h-b2fd7$n{Q+kH>
z(***@v@(#kmV1mZ(Fd&09o0ju5uxnr>g%+***@4h@+yRfX5Xp$M9JxHk!X8yrE
z^dgY&)*eU6_bOqAE=i*WH&w&zEH%<***@RK=YU6Mj}BuvwC<8I?bIu%YFA(5k68NT#m
zue6nkkPu#tHT8XEey3+Q+nW+=C;a1k;JBOW*_sFIA=hsmJks${pcC%BFp9&gFRg!1
***@9Kh{kJ&-&W*hGBW~ITPg<(oEWBp3KC*DG6J9Y<|#u
z$z99F?*mMTZCYO+e`hURz9-52kSRu#lRSpdKrBDxN-%29uBhZYPcct4H2;Uczt6U&
ze++V-36T^)wELv$v5Qy(W8GCR91>X~***@w0H1R`tBF5-k5JboRtl04p
zYUnS}cROf`Q2lR&;5aUD#M-c{6cvPhPnaG)YNuqFh&If^tHFa0yBkE5*gqzTWr)A0
zQ{YyaJ)8uRL`{hGX$v80qeDHDFJWwY!bS%omhHzD^u0d5f*fbmrzwYbHpLYNmGnuE
***@Y%BOJTLeLvmCqHW}ZujDzc4$L~7BP0~***@JuO00p_9t9tCQt}5z~Vrun~
zc%xs=3$ZAkya*~Ifxun****@h!1j}v>J5Fk=Z?z}9GeXAeMO}q~8l9Uqn
z2fWoh(o(bUzzh!)pF4UAuxuoO6ED^cKQ+?3*Rqs=<UA6rahBmYmfw?j!L2WFK_qu<
zb&VB87}Q%P=}1XhkY9YJ`6$%)$l+2ct42HY{UiIhE!CCj_F^e*@1*rXE&t8`lQxg}
z+`zKk4$(l!KOP~rI8dGQFA01G5%hFUZLMLv6)~m+4e<{n%khj2EXvDpJp>@7=TZGn
z;(btMn!0NA;MS&pO$X{m3`JSBemN#$t)7O;=yL~6uKBl>gml5SpiAvHrFo~^^uq#(
zx;<fL_}OpU5rgv^h5$}eLeRMdmC$<%qf(Y;HE7ZGUbFezvqX!>Z}MZSCu#M{u&BB<
zJc=M>h{oKzl|UiO7)6SswYl4-;fn{y&<c6S&_9f+)lDLZYOexE$eTf{JLh10ok6;1
zy>T(w_%xLZl}nk6u_cwz30g$ln#6&{=aEP1Cj#-{CtQYLkN=9h-h7Gh*+l?AujQTk
zai>+-cNd53uXMJ`rp8r4@{***@Yr%^K?***@sn89j8ea{byoow9^oQEH}
z#l1lCvf8*VE7=JN3Gl7pbmlKi1P?`UTn~fe%AHI$M3<eC*td!Ug_B&zaO~DUpu-9r
z7wk+EKj7hy4F9Nl!na7qK|o+Nl>}tkFPkKD^v1Rh{ft}g3g(S77AZvyVs3QQmI|+2
z;J$d*1bc$pefg|kR{!Vh^|dVvm=GSmqG(KWFF_9vZ<aHod?d3VAmOgw1Xdq!I<?U9
zm~2yIJr<nc&yx&gB+DQfX!sI2S_)h9i)$+vbnxA%ZZ7n{(KfbzlZJMd3FobD4dFKr
zUbh$`Iq`-Y)lmkv_qumNO0mirshmd3AII|hi5uD--_rySTRx*okbvB!;(>$pOP}B$
zPW)$R0kBkekeR%!vq91s&84B~sfj$5^NjT$3v1`&TX!}_wNVvz-7hkvhE>b4aE+>;
zDn-*z)ZpmH+g{_EhZC!OTnFtwAS;***@Is<W5>5y=ofJDO2}K;e|+kY>91*@n2$F
zLl;yCF~VniEEk^!ckVc%{Yf+wowY-K;`wpV_8muomK`yQf*|_g_i}8MrM5D)cs*^A
z?=FG}Zs&%87?COz?vli#41Y$|l7ZZb&8!wXQWKbiWM~$u{8>$?i5js$p=***@5ifu
z2_Ovr>N%@F{`=y<!J}=Na(nyE0c=7{=C_3Xr(pVsjGXHi;wa@;{)>C|m!6dS62#A=
z>***@0aq(C(pr*a+*>(bpZ)A!>IzjEr^S64-<U}80Q#AV$1^|UD3^10HcIHY40Ye>IY
z9k_Ha6N<RJgY?}!_cW(thvX4T&fR$0cP2$LZ_4a;i5)2E4Iv!YnMtAxoQ0HK{#~5G
znN{y=T5<SNEyp;-=R=OLjj9+jTJCqTT{3-)+<%@n49bByC2iMO0QaAnGVUOGMj9;_
z#rE*QP*8QFHK|p)N0S&md=B=8p|60AzK-=VM3tZ0Vjv9s6~RZAN8VQHP11emwoXlI
z-YhO*LFs-eHI>WTk?JJiETrjPVrbGdaKvmWVtV=$7*@Z0sWrlJdOkg8>+6@|JZUWo
z*>O44%eZK+HvE~$?}*Fa7bI}b@<V-X(***@4255mF5w+zRdbocQ-uamz-&#N-Lf
zb^TTFJadiP1y}I=)Z}iU9?#s#V5h^***@yyIWwRNIKBw4D%h=3bz`V}0<{?MwC2
z{3ExA4Be(^=F<(UN4&#~zpqUBpG;tYxF*O<jyO9Y$~35TfEgd`V=1_8;gnQk3kCxZ
zw}0E~***@fZC%k99hpFA>(hk$Dh`wN%+dqTp)}oxjCd&ebw3f1TuMl8q9)7|K9mCdw
z)ye1Z&-Bm=***@GG>x^F?b5)~4U8S8%9mTy1~QmeTwtb*uD#Vb>q28XG#t7mxZBuBhO
zaX8b$)Ev}H4L>4{F~5+Ey8-i5*D5`K^pK_-)`le;n*9=>)?B6GRdI}I!4Ij}wyYmr
zxy$IU*iFM~zu$b(&CKPc_MvL)ls+T8XYJDgS-tG_Gf~+*DS7YKt%#RRoF-MjLvOOJ
z7__eU`ipfbq!v6poSnCg<D15W<7Vz-`=2DY$Erbb6CkWO{vH~>*%&4`zl}|>Ss9^>
z+FT9n=WO&-xQLf{GcA(o%;=a(***@O-@MDq>@=Xc?v%3U^D(`)8s2qNhGGPWRa
z5jYg>ER`<&)emdu4XMS3e62exY&5Z-`+BzZYy0BR*cmqbqusUrIXX#Ub3*(pd|$=(
zhhVMA$4wKHY^r6)SF6x9il&***@d0bg#T}<KkRugq4b_H4-KThV=_H&inyUkX0dFpK0
zW50<{{Vs*q7Vuurj(>G@-T=zT*cI$@G(>(KM4AA~J?~***@bgW+C2pjXN+A(pag)>
zw)?a3wikI^htL*}VRw5*fD9Qtkr98F50L-D!6*hu!-TtiCIrDhXuT+U^GFQ>m}W3A
zK)^i##&*oUu#iZY>&Bk&w&kBBAS2P<p$#JFn@&$bCFhmt6&;);`8v>5z|$Cta2EZh
zGm&wcXsrf!&I+yV{LI0M>0%#UNgu&H6k+K9qng<|+}Pu5K{<<m4^DSKebaJj6!hwO
zl$KQ+hn~4KH1Lhx(***@GgH(OxcidFPn-;8IG-)#bYv>y~PT}#9>JD(kncJ^bWGcrv;
zPp8>KJ*1QOqoBrg@`tC{NFdB!+;(8*2y{rNU|lZ_LX^c5DHs_gqRpyNi{4X65y*?=
z{k^wRk1THMs2+#a9DxZtt4Bt5BoX4)z^a+$Ae85T`;Q*?`k1nI45XQVIBoybrl(!L
zQI2UQTX>;|1>GXu?Uu{OgoN74eoj0VD=J6bynt3Lql27ap#+QESb}+PlvNOeZ&-yj
zVgnG<M8G8h3{cG*WlqF7W60lM*n)9-)x2>K3J8{;{$t5N1tOsNFEukqJ4*pvWd2n-
z|J(R)***@CZloq2wUxXphwa5i*}EW-FX&Ui}dCP|dHdTRI>hSxqPRykV}w39M|S`P>O
zNxm0qAMsc9e{~`-J3Ztlw;goNNKMKnV=Yw;-i|4XC}cLk7OYLegEwi5BFaRSjL>G%
zS;98<_d6~Wh;31%CK^)}TI50w!{#o7DzRe{65vCINj${S%F38D6cmUQRZ<X06}q(V
z##v+QZ-iEs{***@Udz*OHl(ANR^QjPHACfCX<1z($UA{5o?@SeY9?fr#G={
zyg)*NL`***@F4gx~B<BR|C#Q)0w1gQVIXP(;d(GCAM{r~#L8sUtG7Ufen<d3i~Ts#&|
zyYPx66=&;YgY4j=Md6Z^_J}xc#HoEM09<n4{jB|w7f<)cQLD}gPFBw#ru(_b;RzEA
zE<Rs9<*l+x(Z&n2g`95GAy)<R^b);0KPu<5S$QCxZp2M{EIz)4LYDU-7Ghkoav3-i
z<$NSsZO+M+<_tOVa{Pi0OjTnUM{<zPwWezcR!@od#q(Q7GiNjM3f|ZYE$Xqmlk%+%
znJ5xG8px-QB`HpnR35x`hearp{c)j#C!-!71(mIzkKJfIF+!}rn%n7vnP^|0s1(-v
zsMQsZtg+Wb8WHVG6Ow=PYkv7nVBwiV-D4bK+}wD25mmB45L1)C>srr&8{***@pD7KH@
z4qB;InL-!lEG1SXR#YS=9tvGbg(lu7FD%lIY*wa|j0J}#oJabFxEH_0KdPyb)YwUn
zuWlQ7{(eZJL15Q$tfn~eFzDm<_s|9YRnaHi=BKNdf$X?0V*glXZ)4m!6oEsK3Y?8T
z#}0W?O)L$O?1lrRPs5HLawm^GIEZ{Ps0nEP0|6?~e_+H1`CqV|MyiE`o)J#*s<;*&
z=9E=VFzPGK8J2P?eLu^F7p|7Dgr#V`!}@;JZ_cDIzCd|9Qodzxg*8_m3o$2L=P)%p
zPP*M3Ol^OY<*rcv&*oA^***@2Y5O;eBR4cPagrCo)R8PlLYB?v+WQ
zG{;M!XKq{Tet+***@iZ@WdT`(***@2Gpr1!d8Grl)>$&LXv<od>??***@EF>ERo_RAn
zH)+m`A0O9#$***@c%4CXj<<qvs`oQXM*x@~Qh!x^EneP5!{nrIib&>6d6_TZ)QIXWi
***@7dG-PvSkgo^+F%b6hI9PG(9+J$Uu_E+Iz<gJ?-<^-gkWYZjw|vHd%V%|{X$dozBV
za3~n^G1Hxs3?J9<LrX-8a^^o}vIXpX-OLHkk}***@q8(tjg<m<IsOSzwp5
zQZl^W(!***@eJyJi3VL;cOP8>lRP!XCTjuK=D`
zu2=j_9CXN1LSV8_(ce}k?)<J<d$XaUJ3<6Ia<LLQ_{A1mJGD?3^REY^mkxfIov57f
zX3A}y_I%$Pos-YQEiy8QFx*y7pTCrnJWt(3&#gEV)-#&(qMLU&hO{ZsY-***@oaEklR
zrlLE`4$pTSl#Q!o*W-=ww92cz#81c8q)A!D*-***@9Hl14JC1JC;-_B;UII}wjCXamM
z-TDtarEA1=ZpltV!r)reoC-6|YvkrOi2>88Joj~20Xc!c7WpQJ+2={|`y=Hb%e5a#
zlWVNUUuJ7Bq3|xr+g9z_0<M(W0-+hPO+@wbJ#9frA1I%B&%I^$dG1d<Gs_ip#ozg9
z2j>L(o;dRob;_H)z>zCel)}{$97)ear^hw<nIbu#u~T~qO>u&pe-N$OSgbE8#Xm~=
zRkhczuw)***@W-bEJw5bW)decDrk$Om^QR63?XQ^(J(4EhqS6Aw+k=gLEY-yrVFQwoi
z7Kq)P>L3C(X92$}3ANd>K%xxA`X!|81BYmMVO}<TwOo^ZA9$%XID|QH`$%bQ<bq;E
zMHP5Cn43_X{nBllnup)^ifX+Ow_bWLkSiplNrcjOv#}kdT!`k-(#f|o4%iTj2>F;Q
zXan{l)5m`X;BKZ*CPZpn^qBt9StGfZMMXxP_^#8yM|}I^VW-wMv+*?HV||l@#ReW!
z{ja}<g(U?NI48I4W_00gt^pvSDe4ST%Ia`$&g-Jq01uQz1uRV7ACCugAFsIb3cIyP
zi}mw`8BO(l|1H-rMoSE7Ak3BT{ethUTADgM*j4NOU(AsYaAEa%yU>veuPi1w<;1xx
z7b^i;RYCCmpB4DE_zCBD;R&Qf2_qJ;tG!!^4F9U^!FyT*vUw--WdWBQmVvAy=xs81
zTNl|F*47};J^NOf+&!t$***@O?PhiItj(q0BE)L(s`J?7cwa8JuOy5tR~fS)YC?{Itm
z(e_NihVc?ZVXrMxPmI&oM4anXr<6&MSg`qwWkw~y5Ho11>bwS9hQ`@j<-wB{Gylh$
zy^jM6Y1i;S-0v?O1Q4q969X<a;+yY%``;;LMMJ5fza`Ep-||t~FmNkaj(#d|FSUv8
zS1VgxTSh7iJ=<f3!Y&v8sgc=q#1Kn0;l-VQN$4N-rRzhCaB@+zD+R=<`RQS_58G$H
zpy)uk%^UJv`vQUl4O9&;JH3s{6=P28BKbw)Dz{GTs^x2CIeb>***@mjfoOK4-
zS24vpV`Qysax8Ezr8gliMCeqX4=bE#vTt$SR{GMom;GD+e7xMp2<Is((hh*L3Hzt_
zd?zCVSuSBQ_D|i33h`q9JBH=Ff`G;p-mbsmO7^UWo#oB1!-vu%$pe$dYTWrEzkTR9
zNY(p_bF-%K_?o3f1tRd%^diY6hZ(M)rk77Yco%-+aBEk^W%*D>Cu_vb%dX)0+w`c;
z|2?EjE5{UCf={lMC#2gBP3-R*7+_*j)XqDj^#&a*1!t>vPMECQ*K*MK=s1Kq%sQ~|
zYmjTHlB}2GD_N2deR;Cu?!a=aPC}!-Pf>XVAa2w`;Ivlgml1qoKRnw<uUs;f6EM#@
z)1s8s6_^vuBs{8jURa-cv~RD*LiZ>=&fOHZK6=4*8vfxf8%<DrG66zh%FrA<jitg7
z%qn>LlIlPk=pV)V;xt%fvrf6E_=gPmKy{r)#5T;bzxwT)%uY_ksO6x+*E_O=9EI>P
zV6>S1rlfkP2_y#n?5I|0hU(YfR+PokH!PnEX9m+***@b8$``M++fHD}_6_~$
zC|`qlYIg}j&}>Toxqu7=A$8;SDw129fZv1X;uAiY{kZ3+f#bY<xF#ES7x|9N=GxOw
zS>CHoZC2S&5~$!$=?a#vvg}SEp@)xDYQR>W%e>Mk9Q$+Ql%+VKprZ7wVkOU^`***@V
zW!***@ou6wp4WfR3`9)|-<MLsc7xVMSM2?SA8;e|l`BzK&B70#{em7g|H%Py2lNRuN*
z*E{P4BdsaU{*I}00Y&(o>lp=@Vt}*KHC{+l5qN4UWDp(TR&}Od99$SdKdza{K<+Is
z?WLV)Or>***@rC?7pYx-KY#?***@Q;%3^!u{LRu&<s+(U$rn=98sM)P(ozI
zWGf`s|K>U7vNFSnIfC>1Ojx`WiiZXU3ZJWEW&#}gIEh$7tT{iln=K9Ux;kQG_KXv}
z^NsgtnA*mK2BJTp8<71o3S^K@=c&Nt#82>SHhDR!U_oIe$9{Ux$E`Nb|Lz62whRkx
zf>{a53FiA1I6;r%Q=***@2)gmja&>{&w>n8SBc_+0;N}!&;&@^<!pVzP7f99*C{=CpA
zji!mQd{=gQyb^~$60E_?WCSgtE}TK;EfFORT3Y)9pV`=Ed$vy;1u{<0rNo2ViU>kG
z`)|C7Y6n1-9lrhnZ-CSZxg))i8EG*-gWAwhv4dn`N21ef)RMui(_|cf#rjrEgMr3=
zJEaf?0_yCoC71-!oc#SWKrxy%`***@zZ_zsJ5v)}Uot69$U^w{)1ltNZ!
z!+|I1t)cK~D99nZ&b8KE`ZI0KR5!kPz+osHE3|E}hg-h=t{!i^guI{a1V_c`JDF{P
zSFGN^Clr`nZlf`yIv$D!aJVXyU)Uaf|HRj_(-ED5Y<5%xC)Fj4uzCdG?RM9koVeaf
zR$ii<9AFt;{nTw3xpe$LDK2a~SLk51ahaVetCr_cSe#6VmtH3bK7X@)&?***@0M|b+3
***@cV9p%uqf%DV?8zFue_3Ne^27-***@98UTm$aBrIPU?-***@GQ~#***@O3
zOESH&4zAgZKfs^n6Q*$CnQdjXhNt`V6(***@B6t|I$GfOkJNejG-Tb3V4W|WukgOM
zhlbFN9h6K+hJHWr;@ZAN;AQgQTR{Kp#r~MVc)35S>Wyvsl*!LgS|6^-L`%Z$#ZuoR
zoQt}*8m$`^6}5_(h*JFzIr@+C|4;-q_z#rPU;cxr2(|x!06YFa`2UG%R{5<W44I#h
Ulq-hwxG4posiv!1sSJ(ye?2;OE&u=k

literal 0
HcmV?d00001

diff --git a/Documentation/DocBook/v4l/pipeline.pdf b/Documentation/DocBook/v4l/pipeline.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..ee3e37f04b6a788e255ce26d1607e77ba2c119a3
GIT binary patch
literal 20276
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
V%8y_8ZbSy1$UvHzIeI!F{{we5{PX|-

literal 0
HcmV?d00001

diff --git a/Documentation/DocBook/v4l/pipeline.png b/Documentation/DocBook/v4l/pipeline.png
new file mode 100644
index 0000000000000000000000000000000000000000..f19b86c2c24d07d5ae437820944d25489a447d7a
GIT binary patch
literal 12130
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
B;b8y(

literal 0
HcmV?d00001
--
1.7.2.2
Arjan van de Ven
2010-11-25 16:33:36 UTC
Permalink
Post by Laurent Pinchart
Add images used by the V4L2 subdev userspace format API documentation.
---
Documentation/DocBook/v4l/bayer.pdf | Bin 0 -> 12116 bytes
Documentation/DocBook/v4l/bayer.png | Bin 0 -> 9725 bytes
Documentation/DocBook/v4l/pipeline.pdf | Bin 0 -> 20276 bytes
Documentation/DocBook/v4l/pipeline.png | Bin 0 -> 12130 bytes
4 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/bayer.pdf
create mode 100644 Documentation/DocBook/v4l/bayer.png
create mode 100644 Documentation/DocBook/v4l/pipeline.pdf
create mode 100644 Documentation/DocBook/v4l/pipeline.png
diff --git a/Documentation/DocBook/v4l/bayer.pdf b/Documentation/DocBook/v4l/bayer.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..905e60e6cd429f026afdfa6fb4dab3f1683adb8a
GIT binary patch
eh sorry...


patch can't grok this.
Laurent Pinchart
2010-11-25 16:53:25 UTC
Permalink
Hi Arjan,
Post by Arjan van de Ven
Post by Laurent Pinchart
Add images used by the V4L2 subdev userspace format API documentation.
---
Documentation/DocBook/v4l/bayer.pdf | Bin 0 -> 12116 bytes
Documentation/DocBook/v4l/bayer.png | Bin 0 -> 9725 bytes
Documentation/DocBook/v4l/pipeline.pdf | Bin 0 -> 20276 bytes
Documentation/DocBook/v4l/pipeline.png | Bin 0 -> 12130 bytes
4 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/bayer.pdf
create mode 100644 Documentation/DocBook/v4l/bayer.png
create mode 100644 Documentation/DocBook/v4l/pipeline.pdf
create mode 100644 Documentation/DocBook/v4l/pipeline.png
diff --git a/Documentation/DocBook/v4l/bayer.pdf
b/Documentation/DocBook/v4l/bayer.pdf new file mode 100644
index
0000000000000000000000000000000000000000..905e60e6cd429f026afdfa6fb4dab3
f1683adb8a GIT binary patch
eh sorry...
patch can't grok this.
Sorry about that.

As stated in the cover letter all the patches are available in the
media-2.6.35-0003-subdev-pad branch of the
http://git.linuxtv.org/pinchartl/media.git git tree, so once the review will
be complete the easiest way to get the patches will be to pull from that tree.
--
Regards,

Laurent Pinchart
Arjan van de Ven
2010-11-25 16:54:15 UTC
Permalink
Post by Laurent Pinchart
Sorry about that.
As stated in the cover letter all the patches are available in the
media-2.6.35-0003-subdev-pad branch of the
http://git.linuxtv.org/pinchartl/media.git git tree, so once the review will
be complete the easiest way to get the patches will be to pull from that tree.
except that we do not use git.....
distribution kernels like meego use quilt not git.
Laurent Pinchart
2010-11-25 16:58:52 UTC
Permalink
Hi Arjan,
Post by Arjan van de Ven
Post by Laurent Pinchart
Sorry about that.
As stated in the cover letter all the patches are available in the
media-2.6.35-0003-subdev-pad branch of the
http://git.linuxtv.org/pinchartl/media.git git tree, so once the review
will be complete the easiest way to get the patches will be to pull from
that tree.
except that we do not use git.....
distribution kernels like meego use quilt not git.
I can see this being a problem. We could drop the documentation patches
completely, but that wouldn't be nice. Am I the first one to push binary
content to the MeeGo kernel ? Is there a procedure to handle that ?
--
Regards,

Laurent Pinchart
Arjan van de Ven
2010-11-25 17:04:53 UTC
Permalink
Post by Laurent Pinchart
Hi Arjan,
Post by Arjan van de Ven
Post by Laurent Pinchart
Sorry about that.
As stated in the cover letter all the patches are available in the
media-2.6.35-0003-subdev-pad branch of the
http://git.linuxtv.org/pinchartl/media.git git tree, so once the review
will be complete the easiest way to get the patches will be to pull from
that tree.
except that we do not use git.....
distribution kernels like meego use quilt not git.
I can see this being a problem. We could drop the documentation patches
completely, but that wouldn't be nice. Am I the first one to push binary
content to the MeeGo kernel ? Is there a procedure to handle that ?
you aren't the first one that tries to push binary content.
you are the first one where that content isn't a driver;-)

no we do sources (prefered form and all) only

I'll just ignore this patch

Laurent Pinchart
2010-11-25 02:49:33 UTC
Permalink
The three new ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL,
VIDIOC_SUBDEV_G_FRAME_INTERVAL and VIDIOC_SUBDEV_S_FRAME_INTERVAL can be
used to enumerate and configure a subdev's frame rate from userspace.

Two new video::g/s_frame_interval subdev operations are introduced to
support those ioctls. The existing video::g/s_parm operations are
deprecated and shouldn't be used anymore.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/DocBook/media-entities.tmpl | 6 +
Documentation/DocBook/v4l/v4l2.xml | 2 +
.../v4l/vidioc-subdev-enum-frame-interval.xml | 146 ++++++++++++++++++++
.../DocBook/v4l/vidioc-subdev-g-frame-interval.xml | 135 ++++++++++++++++++
drivers/media/video/v4l2-subdev.c | 16 ++
include/linux/v4l2-subdev.h | 36 +++++
include/media/v4l2-subdev.h | 7 +
7 files changed, 348 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml

diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index bcdc1d4..b9abb09 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -89,7 +89,9 @@
<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
<!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
<!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
<!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
@@ -190,6 +192,8 @@
<!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
<!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
<!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
+<!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
+<!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
@@ -321,10 +325,12 @@
<!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
<!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
<!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
+<!ENTITY sub-subdev-enum-frame-interval SYSTEM "v4l/vidioc-subdev-enum-frame-interval.xml">
<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
+<!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
<!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
<!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
<!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 3a59b82..7806562 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -470,9 +470,11 @@ and discussions on the V4L mailing list.</revremark>
&sub-reqbufs;
&sub-s-hw-freq-seek;
&sub-streamon;
+ &sub-subdev-enum-frame-interval;
&sub-subdev-enum-frame-size;
&sub-subdev-enum-mbus-code;
&sub-subdev-g-fmt;
+ &sub-subdev-g-frame-interval;
&sub-subscribe-event;
<!-- End of ioctls. -->
&sub-mmap;
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
new file mode 100644
index 0000000..bcea9d49
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
@@ -0,0 +1,146 @@
+<refentry id="vidioc-subdev-enum-frame-interval">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refname>
+ <refpurpose>Enumerate frame intervals</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_frame_interval_enum *
+ <parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>This ioctl lets applications enumerate available frame intervals on a
+ given sub-device pad. Frame intervals only makes sense for sub-devices that
+ can control the frame period on their own. This includes, for instance,
+ image sensors and TV tuners.</para>
+
+ <para>For the common use case of image sensors, the frame intervals
+ available on the sub-device output pad depend on the frame format and size
+ on the same pad. Applications must thus specify the desired format and size
+ when enumerating frame intervals.</para>
+
+ <para>To enumerate frame intervals applications initialize the
+ <structfield>index</structfield>, <structfield>pad</structfield>,
+ <structfield>code</structfield>, <structfield>width</structfield> and
+ <structfield>height</structfield> fields of
+ &v4l2-subdev-frame-interval-enum; and call the
+ <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer
+ to this structure. Drivers fill the rest of the structure or return
+ an &EINVAL; if one of the input fields is invalid. All frame intervals are
+ enumerable by beginning at index zero and incrementing by one until
+ <errorcode>EINVAL</errorcode> is returned.</para>
+
+ <para>Available frame intervals may depend on the current 'try' formats
+ at other pads of the sub-device, as well as on the current active links. See
+ &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
+
+ <para>Sub-devices that support the frame interval enumeration ioctl should
+ implemented it on a single pad only. Its behaviour when supported on
+ multiple pads of the same sub-device is not defined.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval-enum">
+ <title>struct <structname>v4l2_subdev_frame_interval_enum</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>index</structfield></entry>
+ <entry>Number of the format in the enumeration, set by the
+ application.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media controller API.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>code</structfield></entry>
+ <entry>The media bus format code, as defined in
+ <xref linkend="v4l2-mbus-format" />.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>width</structfield></entry>
+ <entry>Frame width, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>height</structfield></entry>
+ <entry>Frame height, in pixels.</entry>
+ </row>
+ <row>
+ <entry>&v4l2-fract;</entry>
+ <entry><structfield>interval</structfield></entry>
+ <entry>Period, in seconds, between consecutive video frames.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[9]</entry>
+ <entry>Reserved for future extensions. Applications and drivers must
+ set the array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-frame-interval-enum;
+ <structfield>pad</structfield> references a non-existing pad, one of
+ the <structfield>code</structfield>, <structfield>width</structfield>
+ or <structfield>height</structfield> fields are invalid for the given
+ pad or the <structfield>index</structfield> field is out of bounds.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
new file mode 100644
index 0000000..1d0e0e1
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
@@ -0,0 +1,135 @@
+<refentry id="vidioc-subdev-g-frame-interval">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_G_FRAME_INTERVAL</refname>
+ <refname>VIDIOC_SUBDEV_S_FRAME_INTERVAL</refname>
+ <refpurpose>Get or set the frame interval on a subdev pad</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_frame_interval *<parameter>argp</parameter>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>These ioctls are used to get and set the frame interval at specific
+ subdev pads in the image pipeline. The frame interval only makes sense for
+ sub-devices that can control the frame period on their own. This includes,
+ for instance, image sensors and TV tuners. Sub-devices that don't support
+ frame intervals must not implement these ioctls.</para>
+
+ <para>To retrieve the current frame interval applications set the
+ <structfield>pad</structfield> field of a &v4l2-subdev-frame-interval; to
+ the desired pad number as reported by the media controller API. When they
+ call the <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> ioctl with a
+ pointer to this structure the driver fills the members of the
+ <structfield>interval</structfield> field.</para>
+
+ <para>To change the current frame interval applications set both the
+ <structfield>pad</structfield> field and all members of the
+ <structfield>interval</structfield> field. When they call the
+ <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant> ioctl with a pointer to
+ this structure the driver verifies the requested interval, adjusts it based
+ on the hardware capabilities and configures the device. Upon return the
+ &v4l2-subdev-frame-interval; contains the current frame interval as would be
+ returned by a <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> call.
+ </para>
+
+ <para>Drivers must not return an error solely because the requested interval
+ doesn't match the device capabilities. They must instead modify the interval
+ to match what the hardware can provide. The modified interval should be as
+ close as possible to the original request.</para>
+
+ <para>Sub-devices that support the frame interval ioctls should implement
+ them on a single pad only. Their behaviour when supported on multiple pads
+ of the same sub-device is not defined.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval">
+ <title>struct <structname>v4l2_subdev_frame_interval</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media controller API.</entry>
+ </row>
+ <row>
+ <entry>&v4l2-fract;</entry>
+ <entry><structfield>interval</structfield></entry>
+ <entry>Period, in seconds, between consecutive video frames.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[5]</entry>
+ <entry>Reserved for future extensions. Applications and drivers must
+ set the array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBUSY</errorcode></term>
+ <listitem>
+ <para>The frame interval can't be changed because the pad is currently
+ busy. This can be caused, for instance, by an active video stream on
+ the pad. The ioctl must not be retried without performing another
+ action to fix the problem first. Only returned by
+ <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-frame-interval; <structfield>pad</structfield>
+ references a non-existing pad, or the pad doesn't support frame
+ intervals.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index a8e66f6..196a37c 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -223,6 +223,22 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh,
fse);
}
+
+ case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
+ return v4l2_subdev_call(sd, video, g_frame_interval, arg);
+
+ case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
+ return v4l2_subdev_call(sd, video, s_frame_interval, arg);
+
+ case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
+ struct v4l2_subdev_frame_interval_enum *fie = arg;
+
+ if (fie->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
+ fie);
+ }
#endif
default:
return -ENOIOCTLCMD;
diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
index 039c6e4..7af0c34 100644
--- a/include/linux/v4l2-subdev.h
+++ b/include/linux/v4l2-subdev.h
@@ -80,11 +80,47 @@ struct v4l2_subdev_frame_size_enum {
__u32 reserved[9];
};

+/**
+ * struct v4l2_subdev_frame_interval - Pad-level frame rate
+ * @pad: pad number, as reported by the media API
+ * @interval: frame interval in seconds
+ */
+struct v4l2_subdev_frame_interval {
+ __u32 pad;
+ struct v4l2_fract interval;
+ __u32 reserved[5];
+};
+
+/**
+ * struct v4l2_subdev_frame_interval_enum - Frame interval enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: frame interval index during enumeration
+ * @code: format code (from enum v4l2_mbus_pixelcode)
+ * @width: frame width in pixels
+ * @height: frame height in pixels
+ * @interval: frame interval in seconds
+ */
+struct v4l2_subdev_frame_interval_enum {
+ __u32 index;
+ __u32 pad;
+ __u32 code;
+ __u32 width;
+ __u32 height;
+ struct v4l2_fract interval;
+ __u32 reserved[9];
+};
+
#define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format)
#define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format)
+#define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
+ _IOWR('V', 21, struct v4l2_subdev_frame_interval)
+#define VIDIOC_SUBDEV_S_FRAME_INTERVAL \
+ _IOWR('V', 22, struct v4l2_subdev_frame_interval)
#define VIDIOC_SUBDEV_ENUM_MBUS_CODE \
_IOWR('V', 2, struct v4l2_subdev_mbus_code_enum)
#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
_IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
+#define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+ _IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)

#endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 322557a..424537b 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -246,6 +246,10 @@ struct v4l2_subdev_video_ops {
int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
+ int (*g_frame_interval)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval);
+ int (*s_frame_interval)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval);
int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
int (*enum_dv_presets) (struct v4l2_subdev *sd,
@@ -407,6 +411,9 @@ struct v4l2_subdev_pad_ops {
int (*enum_frame_size)(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse);
+ int (*enum_frame_interval)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_interval_enum *fie);
int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format);
int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:32 UTC
Permalink
Add a userspace API to get, set and enumerate the media format on a
subdev pad.

The format at the output of a subdev usually depends on the format at
its input(s). The try format operation is thus not suitable for probing
format at individual pads, as it can't modify the device state and thus
can't remember the format tried at the input to compute the output
format.

To fix the problem, pass an extra argument to the get/set format
operations to select the 'try' or 'active' format.

The try format is used when probing the subdev. Setting the try format
must not change the device configuration but can store data for later
reuse. Data storage is provided at the file-handle level so applications
probing the subdev concurently won't interfere with each other.

The active format is used when configuring the subdev. It's identical to
the format handled by the usual get/set operations.

Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
Signed-off-by: Stanimir Varbanov <***@mm-sol.com>
Signed-off-by: Sakari Ailus <***@maxwell.research.nokia.com>
---
Documentation/DocBook/Makefile | 5 +-
Documentation/DocBook/media-entities.tmpl | 16 +
Documentation/DocBook/v4l/dev-subdev.xml | 274 +++
Documentation/DocBook/v4l/subdev-formats.xml | 2410 ++++++++++++++++++++
Documentation/DocBook/v4l/v4l2.xml | 4 +
Documentation/DocBook/v4l/vidioc-streamon.xml | 9 +
.../DocBook/v4l/vidioc-subdev-enum-frame-size.xml | 148 ++
.../DocBook/v4l/vidioc-subdev-enum-mbus-code.xml | 113 +
Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml | 168 ++
drivers/media/video/v4l2-subdev.c | 49 +
include/linux/Kbuild | 1 +
include/linux/v4l2-subdev.h | 90 +
include/media/v4l2-subdev.h | 10 +
13 files changed, 3296 insertions(+), 1 deletions(-)
create mode 100644 Documentation/DocBook/v4l/dev-subdev.xml
create mode 100644 Documentation/DocBook/v4l/subdev-formats.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
create mode 100644 include/linux/v4l2-subdev.h

diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index c7e5dc7..c0959bf 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -53,7 +53,10 @@ MAN := $(patsubst %.xml, %.9, $(BOOKS))
mandocs: $(MAN)

build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
- cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/
+ cp $(srctree)/Documentation/DocBook/dvb/*.png \
+ $(srctree)/Documentation/DocBook/v4l/*.gif \
+ $(srctree)/Documentation/DocBook/v4l/*.png \
+ $(objtree)/Documentation/DocBook/media/

xmldoclinks:
ifneq ($(objtree),$(srctree))
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index 65ba6c7..bcdc1d4 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -86,6 +86,10 @@
<!ENTITY VIDIOC-S-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_S_PRIORITY</constant></link>">
<!ENTITY VIDIOC-S-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_S_STD</constant></link>">
<!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
<!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
<!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
<!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
@@ -107,6 +111,7 @@
<!ENTITY v4l2-field "enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link>">
<!ENTITY v4l2-frmivaltypes "enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link>">
<!ENTITY v4l2-frmsizetypes "enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link>">
+<!ENTITY v4l2-mbus-pixelcode "enum&nbsp;<link linkend='v4l2-mbus-pixelcode'>v4l2_mbus_pixelcode</link>">
<!ENTITY v4l2-memory "enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link>">
<!ENTITY v4l2-mpeg-audio-ac3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link>">
<!ENTITY v4l2-mpeg-audio-crc "enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link>">
@@ -130,6 +135,7 @@
<!ENTITY v4l2-mpeg-video-encoding "enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link>">
<!ENTITY v4l2-power-line-frequency "enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link>">
<!ENTITY v4l2-priority "enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link>">
+<!ENTITY v4l2-subdev-format-whence "enum&nbsp;<link linkend='v4l2-subdev-format-whence'>v4l2_subdev_format_whence</link>">
<!ENTITY v4l2-tuner-type "enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link>">
<!ENTITY v4l2-preemphasis "enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link>">

@@ -171,6 +177,7 @@
<!ENTITY v4l2-hw-freq-seek "struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link>">
<!ENTITY v4l2-input "struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link>">
<!ENTITY v4l2-jpegcompression "struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link>">
+<!ENTITY v4l2-mbus-framefmt "struct&nbsp;<link linkend='v4l2-mbus-framefmt'>v4l2_mbus_framefmt</link>">
<!ENTITY v4l2-modulator "struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link>">
<!ENTITY v4l2-mpeg-vbi-fmt-ivtv "struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link>">
<!ENTITY v4l2-output "struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link>">
@@ -183,6 +190,9 @@
<!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
<!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
<!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
+<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
+<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
+<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
<!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
<!ENTITY v4l2-streamparm "struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link>">
<!ENTITY v4l2-timecode "struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link>">
@@ -212,6 +222,7 @@
<!ENTITY ENXIO "<errorcode>ENXIO</errorcode> error code">
<!ENTITY EMFILE "<errorcode>EMFILE</errorcode> error code">
<!ENTITY EPERM "<errorcode>EPERM</errorcode> error code">
+<!ENTITY EPIPE "<errorcode>EPIPE</errorcode> error code">
<!ENTITY ERANGE "<errorcode>ERANGE</errorcode> error code">

<!-- Subsections -->
@@ -230,6 +241,7 @@
<!ENTITY sub-dev-raw-vbi SYSTEM "v4l/dev-raw-vbi.xml">
<!ENTITY sub-dev-rds SYSTEM "v4l/dev-rds.xml">
<!ENTITY sub-dev-sliced-vbi SYSTEM "v4l/dev-sliced-vbi.xml">
+<!ENTITY sub-dev-subdev SYSTEM "v4l/dev-subdev.xml">
<!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
<!ENTITY sub-driver SYSTEM "v4l/driver.xml">
<!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
@@ -309,6 +321,10 @@
<!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
<!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
<!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
+<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
+<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
+<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
+<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
<!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
<!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
<!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
new file mode 100644
index 0000000..12fdca4
--- /dev/null
+++ b/Documentation/DocBook/v4l/dev-subdev.xml
@@ -0,0 +1,274 @@
+ <title>Sub-device Interface</title>
+
+ <para>The complex nature of V4L2 devices, where hardware is often made of
+ several integrated circuits that need to interact with each other in a
+ controlled way, leads to complex V4L2 drivers. The drivers usually reflect
+ the hardware model in software, and model the different hardware components
+ as software blocks called sub-devices.</para>
+
+ <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
+ implements the media device API, they will automatically inherit from media
+ entities. Applications will be able to enumerate the sub-devices and discover
+ the hardware topology using the media entities, pads and links enumeration
+ API.</para>
+
+ <para>In addition to make sub-devices discoverable, drivers can also choose
+ to make them directly configurable by applications. When both the sub-device
+ driver and the V4L2 device driver support this, sub-devices will feature a
+ character device node on which ioctls can be called to
+ <itemizedlist>
+ <listitem>query, read and write sub-devices controls</listitem>
+ <listitem>subscribe and unsubscribe to events and retrieve them</listitem>
+ <listitem>negotiate image formats on individual pads</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>Sub-device character device nodes, conventionally named
+ <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
+
+ <section>
+ <title>Controls</title>
+ <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
+ usually merge all controls and expose them through video device nodes.
+ Applications can control all sub-devices through a single interface.</para>
+
+ <para>Complex devices sometimes implement the same control in different
+ pieces of hardware. This situation is common in embedded platforms, where
+ both sensors and image processing hardware implement identical functions,
+ such as contrast adjustment, white balance or faulty pixels correction. As
+ the V4L2 controls API doesn't support several identical controls in a single
+ device, all but one of the identical controls are hidden.</para>
+
+ <para>Applications can access those hidden controls through the sub-device
+ node with the V4L2 control API described in <xref linkend="control" />. The
+ ioctls behave identically as when issued on V4L2 device nodes, with the
+ exception that they deal only with controls implemented in the sub-device.
+ </para>
+
+ <para>Depending on the driver, those controls might also be exposed through
+ one (or several) V4L2 device nodes.</para>
+ </section>
+
+ <section>
+ <title>Events</title>
+ <para>V4L2 sub-devices can notify applications of events as described in
+ <xref linkend="event" />. The API behaves identically as when used on V4L2
+ device nodes, with the exception that it only deals with events generated by
+ the sub-device. Depending on the driver, those events might also be reported
+ on one (or several) V4L2 device nodes.</para>
+ </section>
+
+ <section id="pad-level-formats">
+ <title>Pad-level Formats</title>
+
+ <warning>Pad-level formats are only applicable to very complex device that
+ need to expose low-level format configuration to user space. Generic V4L2
+ applications do <emphasis>not</emphasis> need to use the API described in
+ this section.</warning>
+
+ <note>For the purpose of this section, the term
+ <wordasword>format</wordasword> means the combination of media bus data
+ format, frame width and frame height.</note>
+
+ <para>Image formats are typically negotiated on video capture and output
+ devices using the <link linkend="crop">cropping and scaling</link> ioctls.
+ The driver is responsible for configuring every block in the video pipeline
+ according to the requested format at the pipeline input and/or
+ output.</para>
+
+ <para>For complex devices, such as often found in embedded systems,
+ identical image sizes at the output of a pipeline can be achieved using
+ different hardware configurations. One such exemple is shown on
+ <xref linkend="pipeline-scaling" xrefstyle="template: Figure %n" />, where
+ image scaling can be performed on both the video sensor and the host image
+ processing hardware.</para>
+
+ <figure id="pipeline-scaling">
+ <title>Image Format Negotation on Pipelines</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="pipeline.pdf" format="PS" />
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="pipeline.png" format="PNG" />
+ </imageobject>
+ <textobject>
+ <phrase>High quality and high speed pipeline configuration</phrase>
+ </textobject>
+ </mediaobject>
+ </figure>
+
+ <para>The sensor scaler is usually of less quality than the host scaler, but
+ scaling on the sensor is required to achieve higher frame rates. Depending
+ on the use case (quality vs. speed), the pipeline must be configured
+ differently. Applications need to configure the formats at every point in
+ the pipeline explicitly.</para>
+
+ <para>Drivers that implement the <link linkend="media-controller-intro">media
+ API</link> can expose pad-level image format configuration to applications.
+ When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
+ &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
+
+ <para>Applications are responsible for configuring coherent parameters on
+ the whole pipeline and making sure that connected pads have compatible
+ formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
+ time, and an &EPIPE; is then returned if the configuration is
+ invalid.</para>
+
+ <para>Pad-level image format configuration support can be tested by calling
+ the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
+ pad-level format configuration is not supported by the sub-device.</para>
+
+ <section>
+ <title>Format Negotiation</title>
+
+ <para>Acceptable formats on pads can (and usually do) depend on a number
+ of external parameters, such as formats on other pads, active links, or
+ even controls. Finding a combination of formats on all pads in a video
+ pipeline, acceptable to both application and driver, can't rely on formats
+ enumeration only. A format negotiation mechanism is required.</para>
+
+ <para>Central to the format negotiation mechanism are the get/set format
+ operations. When called with the <structfield>which</structfield> argument
+ set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
+ &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
+ formats parameters that are not connected to the hardware configuration.
+ Modifying those 'try' formats leaves the device state untouched (this
+ applies to both the software state stored in the driver and the hardware
+ state stored in the device itself).</para>
+
+ <para>While not kept as part of the device state, try formats are stored
+ in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
+ the last try format set <emphasis>on the same sub-device file
+ handle</emphasis>. Several applications querying the same sub-device at
+ the same time will thus not interact with each other.</para>
+
+ <para>To find out whether a particular format is supported by the device,
+ applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
+ needed, change the requested <structfield>format</structfield> based on
+ device requirements and return the possibly modified value. Applications
+ can then choose to try a different format or accept the returned value and
+ continue.</para>
+
+ <para>Formats returned by the driver during a negotiation iteration are
+ guaranteed to be supported by the device. In particular, drivers guarantee
+ that a returned format will not be further changed if passed to an
+ &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
+ formats on other pads or links' configuration are not changed).</para>
+
+ <para>Drivers automatically propagate formats inside sub-devices. When a
+ try or active format is set on a pad, corresponding formats on other pads
+ of the same sub-device can be modified by the driver. Drivers are free to
+ modify formats as required by the device. However, they should comply with
+ the following rules when possible:
+ <itemizedlist>
+ <listitem>Formats should be propagated from sink pads to source pads.
+ Modifying a format on a source pad should not modify the format on any
+ sink pad.</listitem>
+ <listitem>Sub-devices that scale frames using variable scaling factors
+ should reset the scale factors to default values when sink pads formats
+ are modified. If the 1:1 scaling ratio is supported, this means that
+ source pads formats should be reset to the sink pads formats.</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>Formats are not propagated across links, as that would involve
+ propagating them from one sub-device file handle to another. Applications
+ must then take care to configure both ends of every link explicitly with
+ compatible formats. Identical formats on the two ends of a link are
+ guaranteed to be compatible. Drivers are free to accept different formats
+ matching device requirements as being compatible.</para>
+
+ <para><xref linkend="sample-pipeline-config" xrefstyle="template:Table %n"/>
+ shows a sample configuration sequence for the pipeline described in
+ <xref linkend="pipeline-scaling" xrefstyle="template:Figure %n"/> (table
+ columns list entity names and pad numbers).</para>
+
+ <table pgwide="0" frame="none" id="sample-pipeline-config">
+ <title>Sample Pipeline Configuration</title>
+ <tgroup cols="3">
+ <colspec colname="what"/>
+ <colspec colname="sensor-0" />
+ <colspec colname="frontend-0" />
+ <colspec colname="frontend-1" />
+ <colspec colname="scaler-0" />
+ <colspec colname="scaler-1" />
+ <thead>
+ <row>
+ <entry></entry>
+ <entry>Sensor/0</entry>
+ <entry>Frontend/0</entry>
+ <entry>Frontend/1</entry>
+ <entry>Scaler/0</entry>
+ <entry>Scaler/1</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Initial state</entry>
+ <entry>2048x1536</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ </row>
+ <row>
+ <entry>Configure frontend input</entry>
+ <entry>2048x1536</entry>
+ <entry><emphasis>2048x1536</emphasis></entry>
+ <entry><emphasis>2046x1534</emphasis></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ </row>
+ <row>
+ <entry>Configure scaler input</entry>
+ <entry>2048x1536</entry>
+ <entry>2048x1536</entry>
+ <entry>2046x1534</entry>
+ <entry><emphasis>2046x1534</emphasis></entry>
+ <entry><emphasis>2046x1534</emphasis></entry>
+ </row>
+ <row>
+ <entry>Configure scaler output</entry>
+ <entry>2048x1536</entry>
+ <entry>2048x1536</entry>
+ <entry>2046x1534</entry>
+ <entry>2046x1534</entry>
+ <entry><emphasis>1280x960</emphasis></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ <orderedlist>
+ <listitem>Initial state. The sensor output is set to its native 3MP
+ resolution. Resolutions on the host frontend and scaler input and output
+ pads are undefined.</listitem>
+ <listitem>The application configures the frontend input pad resolution to
+ 2048x1536. The driver propagates the format to the frontend output pad.
+ Note that the propagated output format can be different, as in this case,
+ than the input format, as the hardware might need to crop pixels (for
+ instance when converting a Bayer filter pattern to RGB or YUV).</listitem>
+ <listitem>The application configures the scaler input pad resolution to
+ 2046x1534 to match the frontend output resolution. The driver propagates
+ the format to the scaler output pad.</listitem>
+ <listitem>The application configures the scaler output pad resolution to
+ 1280x960.</listitem>
+ </orderedlist>
+ </para>
+
+ <para>When satisfied with the try results, applications can set the active
+ formats by setting the <structfield>which</structfield> argument to
+ <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
+ exactly as try formats by drivers. To avoid modifying the hardware state
+ during format negotiation, applications should negotiate try formats first
+ and then modify the active settings using the try formats returned during
+ the last negotiation iteration. This guarantees that the active format
+ will be applied as-is by the driver without being modified.
+ </para>
+ </section>
+
+ </section>
+
+ &sub-subdev-formats;
diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
new file mode 100644
index 0000000..3688f27
--- /dev/null
+++ b/Documentation/DocBook/v4l/subdev-formats.xml
@@ -0,0 +1,2410 @@
+<section id="v4l2-mbus-format">
+ <title>Media Bus Formats</title>
+
+ <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
+ <title>struct <structname>v4l2_mbus_framefmt</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>width</structfield></entry>
+ <entry>Image width, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>height</structfield></entry>
+ <entry>Image height, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>code</structfield></entry>
+ <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>field</structfield></entry>
+ <entry>Field order, from &v4l2-field;. See
+ <xref linkend="field-order" /> for details.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>colorspace</structfield></entry>
+ <entry>Image colorspace, from &v4l2-colorspace;. See
+ <xref linkend="colorspaces" /> for details.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <section id="v4l2-mbus-pixelcode">
+ <title>Media Bus Pixel Codes</title>
+
+ <para>The media bus pixel codes describe image formats as flowing over
+ physical busses (both between separate physical components and inside SoC
+ devices). This should not be confused with the V4L2 pixel formats that
+ describe, using four character codes, image formats as stored in memory.
+ </para>
+
+ <para>While there is a relationship between image formats on busses and
+ image formats in memory (a raw Bayer image won't be magically converted to
+ JPEG just by storing it to memory), there is no one-to-one correspondance
+ between them.</para>
+
+ <section>
+ <title>Packed RGB Formats</title>
+
+ <para>Those formats transfer pixel data as red, green and blue components.
+ The format code is made of the following information.
+ <itemizedlist>
+ <listitem>The red, green and blue components order code, as encoded in a
+ pixel sample. Possible values are RGB and BGR.</listitem>
+ <listitem>The number of bits per component, for each component. The values
+ can be different for all components. Common values are 555 and 565.
+ </listitem>
+ <listitem>The number of bus samples per pixel. Pixels that are wider than
+ the bus width must be transferred in multiple samples. Common values are
+ 1 and 2.</listitem>
+ <listitem>The bus width.</listitem>
+ <listitem>For formats where the total number of bits per pixel is smaller
+ than the number of bus samples per pixel times the bus width, a padding
+ value stating if the bytes are padded in their most high order bits
+ (PADHI) or low order bits (PADLO).</listitem>
+ <listitem>For formats where the number of bus samples per pixel is larger
+ than 1, an endianness value stating if the pixel is transferred MSB first
+ (BE) or LSB first (LE).</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
+ green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
+ samples per pixel with the most significant bits (padding, red and half of
+ the green value) transferred first will be named
+ <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
+ </para>
+
+ <para>The following tables list existing packet RGB formats.</para>
+
+ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
+ <title>RGB formats</title>
+ <tgroup cols="11">
+ <colspec colname="id" align="left" />
+ <colspec colname="code" align="center"/>
+ <colspec colname="bit" />
+ <colspec colnum="4" colname="b07" align="center" />
+ <colspec colnum="5" colname="b06" align="center" />
+ <colspec colnum="6" colname="b05" align="center" />
+ <colspec colnum="7" colname="b04" align="center" />
+ <colspec colnum="8" colname="b03" align="center" />
+ <colspec colnum="9" colname="b02" align="center" />
+ <colspec colnum="10" colname="b01" align="center" />
+ <colspec colnum="11" colname="b00" align="center" />
+ <spanspec namest="b07" nameend="b00" spanname="b0" />
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Code</entry>
+ <entry></entry>
+ <entry spanname="b0">Data organization</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>Bit</entry>
+ <entry>7</entry>
+ <entry>6</entry>
+ <entry>5</entry>
+ <entry>4</entry>
+ <entry>3</entry>
+ <entry>2</entry>
+ <entry>1</entry>
+ <entry>0</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
+ <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
+ <entry>0x1001</entry>
+ <entry></entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
+ <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
+ <entry>0x1002</entry>
+ <entry></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
+ <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
+ <entry>0x1003</entry>
+ <entry></entry>
+ <entry>0</entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
+ <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
+ <entry>0x1004</entry>
+ <entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>0</entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
+ <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
+ <entry>0x1005</entry>
+ <entry></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
+ <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
+ <entry>0x1006</entry>
+ <entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
+ <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
+ <entry>0x1007</entry>
+ <entry></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
+ <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
+ <entry>0x1008</entry>
+ <entry></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section>
+ <title>Bayer Formats</title>
+
+ <para>Those formats transfer pixel data as red, green and blue components.
+ The format code is made of the following information.
+ <itemizedlist>
+ <listitem>The red, green and blue components order code, as encoded in a
+ pixel sample. The possible values are shown in <xref
+ linkend="bayer-patterns" />.</listitem>
+ <listitem>The number of bits per pixel component. All components are
+ transferred on the same number of bits. Common values are 8, 10 and 12.
+ </listitem>
+ <listitem>If the pixel components are DPCM-compressed, a mention of the
+ DPCM compression and the number of bits per compressed pixel component.
+ </listitem>
+ <listitem>The number of bus samples per pixel. Pixels that are wider than
+ the bus width must be transferred in multiple samples. Common values are
+ 1 and 2.</listitem>
+ <listitem>The bus width.</listitem>
+ <listitem>For formats where the total number of bits per pixel is smaller
+ than the number of bus samples per pixel times the bus width, a padding
+ value stating if the bytes are padded in their most high order bits
+ (PADHI) or low order bits (PADLO).</listitem>
+ <listitem>For formats where the number of bus samples per pixel is larger
+ than 1, an endianness value stating if the pixel is transferred MSB first
+ (BE) or LSB first (LE).</listitem>
+ </itemizedlist>
+ </para>
+
+ <para>For instance, a format with uncompressed 10-bit Bayer components
+ arranged in a red, green, green, blue pattern transferred as 2 8-bit
+ samples per pixel with the least significant bits transferred first will
+ be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
+ </para>
+
+ <figure id="bayer-patterns">
+ <title>Bayer Patterns</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="bayer.pdf" format="PS" />
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="bayer.png" format="PNG" />
+ </imageobject>
+ <textobject>
+ <phrase>Bayer filter color patterns</phrase>
+ </textobject>
+ </mediaobject>
+ </figure>
+
+ <para>The following table lists existing packet Bayer formats. The data
+ organization is given as an example for the first pixel only.</para>
+
+ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
+ <title>Bayer Formats</title>
+ <tgroup cols="15">
+ <colspec colname="id" align="left" />
+ <colspec colname="code" align="center"/>
+ <colspec colname="bit" />
+ <colspec colnum="4" colname="b11" align="center" />
+ <colspec colnum="5" colname="b10" align="center" />
+ <colspec colnum="6" colname="b09" align="center" />
+ <colspec colnum="7" colname="b08" align="center" />
+ <colspec colnum="8" colname="b07" align="center" />
+ <colspec colnum="9" colname="b06" align="center" />
+ <colspec colnum="10" colname="b05" align="center" />
+ <colspec colnum="11" colname="b04" align="center" />
+ <colspec colnum="12" colname="b03" align="center" />
+ <colspec colnum="13" colname="b02" align="center" />
+ <colspec colnum="14" colname="b01" align="center" />
+ <colspec colnum="15" colname="b00" align="center" />
+ <spanspec namest="b11" nameend="b00" spanname="b0" />
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Code</entry>
+ <entry></entry>
+ <entry spanname="b0">Data organization</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>Bit</entry>
+ <entry>11</entry>
+ <entry>10</entry>
+ <entry>9</entry>
+ <entry>8</entry>
+ <entry>7</entry>
+ <entry>6</entry>
+ <entry>5</entry>
+ <entry>4</entry>
+ <entry>3</entry>
+ <entry>2</entry>
+ <entry>1</entry>
+ <entry>0</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
+ <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
+ <entry>0x3001</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
+ <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
+ <entry>0x3002</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
+ <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
+ <entry>0x300b</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
+ <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
+ <entry>0x300c</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
+ <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
+ <entry>0x3009</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
+ <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
+ <entry>0x300d</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>r<subscript>7</subscript></entry>
+ <entry>r<subscript>6</subscript></entry>
+ <entry>r<subscript>5</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
+ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
+ <entry>0x3003</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>b<subscript>9</subscript></entry>
+ <entry>b<subscript>8</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
+ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
+ <entry>0x3004</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>b<subscript>9</subscript></entry>
+ <entry>b<subscript>8</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
+ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
+ <entry>0x3005</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>9</subscript></entry>
+ <entry>b<subscript>8</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
+ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
+ <entry>0x3006</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ <entry>0</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>9</subscript></entry>
+ <entry>b<subscript>8</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
+ <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
+ <entry>0x3007</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>9</subscript></entry>
+ <entry>b<subscript>8</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGBRG10-1X10">
+ <entry>V4L2_MBUS_FMT_SGBRG10_1X10</entry>
+ <entry>0x300e</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>9</subscript></entry>
+ <entry>g<subscript>8</subscript></entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGRBG10-1X10">
+ <entry>V4L2_MBUS_FMT_SGRBG10_1X10</entry>
+ <entry>0x300a</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>9</subscript></entry>
+ <entry>g<subscript>8</subscript></entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SRGGB10-1X10">
+ <entry>V4L2_MBUS_FMT_SRGGB10_1X10</entry>
+ <entry>0x300f</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>r<subscript>9</subscript></entry>
+ <entry>r<subscript>8</subscript></entry>
+ <entry>r<subscript>7</subscript></entry>
+ <entry>r<subscript>6</subscript></entry>
+ <entry>r<subscript>5</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SBGGR12-1X12">
+ <entry>V4L2_MBUS_FMT_SBGGR12_1X12</entry>
+ <entry>0x3008</entry>
+ <entry></entry>
+ <entry>b<subscript>11</subscript></entry>
+ <entry>b<subscript>10</subscript></entry>
+ <entry>b<subscript>9</subscript></entry>
+ <entry>b<subscript>8</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section>
+ <title>Packed YUV Formats</title>
+
+ <para>Those data formats transfer pixel data as (possibly downsampled) Y, U
+ and V components. The format code is made of the following information.
+ <itemizedlist>
+ <listitem>The Y, U and V components order code, as transferred on the
+ bus. Possible values are YUYV, UYVY, YVYU and VYUY.</listitem>
+ <listitem>The number of bits per pixel component. All components are
+ transferred on the same number of bits. Common values are 8, 10 and 12.
+ </listitem>
+ <listitem>The number of bus samples per pixel. Pixels that are wider than
+ the bus width must be transferred in multiple samples. Common values are
+ 1, 1.5 (encoded as 1_5) and 2.</listitem>
+ <listitem>The bus width. When the bus width is larger than the number of
+ bits per pixel component, several components are packed in a single bus
+ sample. The components are ordered as specified by the order code, with
+ components on the left of the code transferred in the high order bits.
+ Common values are 8 and 16.
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>For instance, a format where pixels are encoded as 8-bit YUV values
+ downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
+ U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
+ </para>
+
+ <para>The following table lisst existing packet YUV formats.</para>
+
+ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
+ <title>YUV Formats</title>
+ <tgroup cols="23">
+ <colspec colname="id" align="left" />
+ <colspec colname="code" align="center"/>
+ <colspec colname="bit" />
+ <colspec colnum="4" colname="b19" align="center" />
+ <colspec colnum="5" colname="b18" align="center" />
+ <colspec colnum="6" colname="b17" align="center" />
+ <colspec colnum="7" colname="b16" align="center" />
+ <colspec colnum="8" colname="b15" align="center" />
+ <colspec colnum="9" colname="b14" align="center" />
+ <colspec colnum="10" colname="b13" align="center" />
+ <colspec colnum="11" colname="b12" align="center" />
+ <colspec colnum="12" colname="b11" align="center" />
+ <colspec colnum="13" colname="b10" align="center" />
+ <colspec colnum="14" colname="b09" align="center" />
+ <colspec colnum="15" colname="b08" align="center" />
+ <colspec colnum="16" colname="b07" align="center" />
+ <colspec colnum="17" colname="b06" align="center" />
+ <colspec colnum="18" colname="b05" align="center" />
+ <colspec colnum="19" colname="b04" align="center" />
+ <colspec colnum="20" colname="b03" align="center" />
+ <colspec colnum="21" colname="b02" align="center" />
+ <colspec colnum="22" colname="b01" align="center" />
+ <colspec colnum="23" colname="b00" align="center" />
+ <spanspec namest="b19" nameend="b00" spanname="b0" />
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Code</entry>
+ <entry></entry>
+ <entry spanname="b0">Data organization</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry>Bit</entry>
+ <entry>19</entry>
+ <entry>18</entry>
+ <entry>17</entry>
+ <entry>16</entry>
+ <entry>15</entry>
+ <entry>14</entry>
+ <entry>13</entry>
+ <entry>12</entry>
+ <entry>11</entry>
+ <entry>10</entry>
+ <entry>9</entry>
+ <entry>8</entry>
+ <entry>7</entry>
+ <entry>6</entry>
+ <entry>5</entry>
+ <entry>4</entry>
+ <entry>3</entry>
+ <entry>2</entry>
+ <entry>1</entry>
+ <entry>0</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row id="V4L2-MBUS-FMT-Y8-1X8">
+ <entry>V4L2_MBUS_FMT_Y8_1X8</entry>
+ <entry>0x2001</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
+ <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
+ <entry>0x2002</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-VYUY8-1_5X8">
+ <entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
+ <entry>0x2003</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YUYV8-1_5X8">
+ <entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
+ <entry>0x2004</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YVYU8-1_5X8">
+ <entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
+ <entry>0x2005</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-UYVY8-2X8">
+ <entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
+ <entry>0x2006</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-VYUY8-2X8">
+ <entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
+ <entry>0x2007</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YUYV8-2X8">
+ <entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
+ <entry>0x2008</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YVYU8-2X8">
+ <entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
+ <entry>0x2009</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-Y10-1X10">
+ <entry>V4L2_MBUS_FMT_Y10_1X10</entry>
+ <entry>0x200a</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YUYV10-2X10">
+ <entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
+ <entry>0x200b</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>9</subscript></entry>
+ <entry>u<subscript>8</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>9</subscript></entry>
+ <entry>v<subscript>8</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YVYU10-2X10">
+ <entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
+ <entry>0x200c</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>9</subscript></entry>
+ <entry>v<subscript>8</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>9</subscript></entry>
+ <entry>u<subscript>8</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-UYVY8-1X16">
+ <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
+ <entry>0x200f</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-VYUY8-1X16">
+ <entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
+ <entry>0x2010</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YUYV8-1X16">
+ <entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
+ <entry>0x2011</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YVYU8-1X16">
+ <entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
+ <entry>0x2012</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YUYV10-1X20">
+ <entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
+ <entry>0x200d</entry>
+ <entry></entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>u<subscript>9</subscript></entry>
+ <entry>u<subscript>8</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>v<subscript>9</subscript></entry>
+ <entry>v<subscript>8</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YVYU10-1X20">
+ <entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
+ <entry>0x200e</entry>
+ <entry></entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>v<subscript>9</subscript></entry>
+ <entry>v<subscript>8</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>u<subscript>9</subscript></entry>
+ <entry>u<subscript>8</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+ </section>
+</section>
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 7c3c098..3a59b82 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -402,6 +402,7 @@ and discussions on the V4L mailing list.</revremark>
<section id="radio"> &sub-dev-radio; </section>
<section id="rds"> &sub-dev-rds; </section>
<section id="event"> &sub-dev-event; </section>
+ <section id="subdev"> &sub-dev-subdev; </section>
</chapter>

<chapter id="driver">
@@ -469,6 +470,9 @@ and discussions on the V4L mailing list.</revremark>
&sub-reqbufs;
&sub-s-hw-freq-seek;
&sub-streamon;
+ &sub-subdev-enum-frame-size;
+ &sub-subdev-enum-mbus-code;
+ &sub-subdev-g-fmt;
&sub-subscribe-event;
<!-- End of ioctls. -->
&sub-mmap;
diff --git a/Documentation/DocBook/v4l/vidioc-streamon.xml b/Documentation/DocBook/v4l/vidioc-streamon.xml
index e42bff1..75ed39b 100644
--- a/Documentation/DocBook/v4l/vidioc-streamon.xml
+++ b/Documentation/DocBook/v4l/vidioc-streamon.xml
@@ -93,6 +93,15 @@ synchronize with other events.</para>
been allocated (memory mapping) or enqueued (output) yet.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><errorcode>EPIPE</errorcode></term>
+ <listitem>
+ <para>The driver implements <link
+ linkend="pad-level-formats">pad-level format configuration</link> and
+ the pipeline configuration is invalid.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
new file mode 100644
index 0000000..209e983
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
@@ -0,0 +1,148 @@
+<refentry id="vidioc-subdev-enum-frame-size">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refname>
+ <refpurpose>Enumerate media bus frame sizes</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_frame_size_enum *
+ <parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>This ioctl allows applications to enumerate all frame sizes
+ supported by a sub-device on the given pad for the given media bus format.
+ Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
+ ioctl.</para>
+
+ <para>To enumerate frame sizes applications initialize the
+ <structfield>pad</structfield>, <structfield>code</structfield> and
+ <structfield>index</structfield> fields of the
+ &v4l2-subdev-mbus-code-enum; and call the
+ <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to
+ the structure. Drivers fill the minimum and maximum frame sizes or return
+ an &EINVAL; if one of the input parameters is invalid.</para>
+
+ <para>Sub-devices that only support discrete frame sizes (such as most
+ sensors) will return one or more frame sizes with identical minimum and
+ maximum values.</para>
+
+ <para>Not all possible sizes in given [minimum, maximum] ranges need to be
+ supported. For instance, a scaler that uses a fixed-point scaling ratio
+ might not be able to produce every frame size between the minimum and
+ maximum values. Applications must use the &VIDIOC-SUBDEV-S-FMT; ioctl to
+ try the sub-device for an exact supported frame size.</para>
+
+ <para>Available frame sizes may depend on the current 'try' formats at other
+ pads of the sub-device, as well as on the current active links and the
+ current values of V4L2 controls. See &VIDIOC-SUBDEV-G-FMT; for more
+ information about try formats.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-frame-size-enum">
+ <title>struct <structname>v4l2_subdev_frame_size_enum</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>index</structfield></entry>
+ <entry>Number of the format in the enumeration, set by the
+ application.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media controller API.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>code</structfield></entry>
+ <entry>The media bus format code, as defined in
+ <xref linkend="v4l2-mbus-format" />.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>min_width</structfield></entry>
+ <entry>Minimum frame width, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>max_width</structfield></entry>
+ <entry>Maximum frame width, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>min_height</structfield></entry>
+ <entry>Minimum frame height, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>max_height</structfield></entry>
+ <entry>Maximum frame height, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[9]</entry>
+ <entry>Reserved for future extensions. Applications and drivers must
+ set the array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-frame-size-enum; <structfield>pad</structfield>
+ references a non-existing pad, the <structfield>code</structfield> is
+ invalid for the given pad or the <structfield>index</structfield>
+ field is out of bounds.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
new file mode 100644
index 0000000..d2c4fd2
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
@@ -0,0 +1,113 @@
+<refentry id="vidioc-subdev-enum-mbus-code">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_MBUS_CODE</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_ENUM_MBUS_CODE</refname>
+ <refpurpose>Enumerate media bus formats</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_mbus_code_enum *
+ <parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_ENUM_MBUS_CODE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>To enumerate media bus formats available at a given sub-device pad
+ applications initialize the <structfield>pad</structfield> and
+ <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
+ call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a
+ pointer to this structure. Drivers fill the rest of the structure or return
+ an &EINVAL; if either the <structfield>pad</structfield> or
+ <structfield>index</structfield> are invalid. All media bus formats are
+ enumerable by beginning at index zero and incrementing by one until
+ <errorcode>EINVAL</errorcode> is returned.</para>
+
+ <para>Available media bus formats may depend on the current 'try' formats
+ at other pads of the sub-device, as well as on the current active links. See
+ &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-mbus-code-enum">
+ <title>struct <structname>v4l2_subdev_mbus_code_enum</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media controller API.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>index</structfield></entry>
+ <entry>Number of the format in the enumeration, set by the
+ application.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>code</structfield></entry>
+ <entry>The media bus format code, as defined in
+ <xref linkend="v4l2-mbus-format" />.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[5]</entry>
+ <entry>Reserved for future extensions. Applications and drivers must
+ set the array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-mbus-code-enum; <structfield>pad</structfield>
+ references a non-existing pad, or the <structfield>index</structfield>
+ field is out of bounds.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
new file mode 100644
index 0000000..465f8e4
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
@@ -0,0 +1,168 @@
+<refentry id="vidioc-subdev-g-fmt">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_G_FMT</refname>
+ <refname>VIDIOC_SUBDEV_S_FMT</refname>
+ <refpurpose>Get or set the data format on a subdev pad</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_format *<parameter>argp</parameter>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>These ioctls are used to negotiate the frame format at specific
+ subdev pads in the image pipeline.</para>
+
+ <para>To retrieve the current format applications set the
+ <structfield>pad</structfield> field of a &v4l2-subdev-format; to the
+ desired pad number as reported by the media API and the
+ <structfield>which</structfield> field to
+ <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. When they call the
+ <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl with a pointer to this
+ structure the driver fills the members of the <structfield>format</structfield>
+ field.</para>
+
+ <para>To change the current format applications set both the
+ <structfield>pad</structfield> and <structfield>which</structfield> fields
+ and all members of the <structfield>format</structfield> field. When they
+ call the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl with a pointer to this
+ structure the driver verifies the requested format, adjusts it based on the
+ hardware capabilities and configures the device. Upon return the
+ &v4l2-subdev-format; contains the current format as would be returned by a
+ <constant>VIDIOC_SUBDEV_G_FMT</constant> call.</para>
+
+ <para>Applications can query the device capabilities by setting the
+ <structfield>which</structfield> to
+ <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' formats are not
+ applied to the device by the driver, but are changed exactly as active
+ formats and stored in the sub-device file handle. Two applications querying
+ the same sub-device would thus not interact with each other.</para>
+
+ <para>For instance, to try a format at the output pad of a sub-device,
+ applications would first set the try format at the sub-device input with the
+ <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl. They would then either
+ retrieve the default format at the output pad with the
+ <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl, or set the desired output
+ pad format with the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl and check
+ the returned value.</para>
+
+ <para>Try formats do not depend on active formats, but can depend on the
+ current links configuration or sub-device controls value. For instance, a
+ low-pass noise filter might crop pixels at the frame boundaries, modifying
+ its output frame size.</para>
+
+ <para>Drivers must not return an error solely because the requested format
+ doesn't match the device capabilities. They must instead modify the format
+ to match what the hardware can provide. The modified format should be as
+ close as possible to the original request.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-format">
+ <title>struct <structname>v4l2_subdev_format</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media controller API.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>which</structfield></entry>
+ <entry>Format to modified, from &v4l2-subdev-format-whence;.</entry>
+ </row>
+ <row>
+ <entry>&v4l2-mbus-framefmt;</entry>
+ <entry><structfield>format</structfield></entry>
+ <entry>Definition of an image format, see <xref
+ linkend="v4l2-mbus-framefmt" /> for details.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-format-whence">
+ <title>enum <structname>v4l2_subdev_format_whence</structname></title>
+ <tgroup cols="3">
+ &cs-def;
+ <tbody valign="top">
+ <row>
+ <entry>V4L2_SUBDEV_FORMAT_TRY</entry>
+ <entry>0</entry>
+ <entry>Try formats, used for querying device capabilities.</entry>
+ </row>
+ <row>
+ <entry>V4L2_SUBDEV_FORMAT_ACTIVE</entry>
+ <entry>1</entry>
+ <entry>Active formats, applied to the hardware.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBUSY</errorcode></term>
+ <listitem>
+ <para>The format can't be changed because the pad is currently busy.
+ This can be caused, for instance, by an active video stream on the
+ pad. The ioctl must not be retried without performing another action
+ to fix the problem first. Only returned by
+ <constant>VIDIOC_SUBDEV_S_FMT</constant></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-format; <structfield>pad</structfield>
+ references a non-existing pad, or the <structfield>which</structfield>
+ field references a non-existing format.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 56ad9b2..a8e66f6 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -140,6 +140,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+#endif

switch (cmd) {
case VIDIOC_QUERYCTRL:
@@ -174,7 +177,53 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)

case VIDIOC_UNSUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ case VIDIOC_SUBDEV_G_FMT: {
+ struct v4l2_subdev_format *format = arg;
+
+ if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
+ format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (format->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format);
+ }
+
+ case VIDIOC_SUBDEV_S_FMT: {
+ struct v4l2_subdev_format *format = arg;
+
+ if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
+ format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (format->pad >= sd->entity.num_pads)
+ return -EINVAL;

+ return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format);
+ }
+
+ case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
+ struct v4l2_subdev_mbus_code_enum *code = arg;
+
+ if (code->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh,
+ code);
+ }
+
+ case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
+ struct v4l2_subdev_frame_size_enum *fse = arg;
+
+ if (fse->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh,
+ fse);
+ }
+#endif
default:
return -ENOIOCTLCMD;
}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 450cbed..257812e 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -168,6 +168,7 @@ header-y += ultrasound.h
header-y += un.h
header-y += utime.h
header-y += v4l2-mediabus.h
+header-y += v4l2-subdev.h
header-y += veth.h
header-y += videotext.h
header-y += x25.h
diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
new file mode 100644
index 0000000..039c6e4
--- /dev/null
+++ b/include/linux/v4l2-subdev.h
@@ -0,0 +1,90 @@
+/*
+ * V4L2 subdev userspace API
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <***@ideasonboard.com>
+ * Sakari Ailus <***@maxwell.research.nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LINUX_V4L2_SUBDEV_H
+#define __LINUX_V4L2_SUBDEV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/v4l2-mediabus.h>
+
+/**
+ * enum v4l2_subdev_format_whence - Media bus format type
+ * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
+ * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
+ */
+enum v4l2_subdev_format_whence {
+ V4L2_SUBDEV_FORMAT_TRY = 0,
+ V4L2_SUBDEV_FORMAT_ACTIVE = 1,
+};
+
+/**
+ * struct v4l2_subdev_format - Pad-level media bus format
+ * @which: format type (from enum v4l2_subdev_format_whence)
+ * @pad: pad number, as reported by the media API
+ * @format: media bus format (format code and frame size)
+ */
+struct v4l2_subdev_format {
+ __u32 which;
+ __u32 pad;
+ struct v4l2_mbus_framefmt format;
+ __u32 reserved[9];
+};
+
+/**
+ * struct v4l2_subdev_mbus_code_enum - Media bus format enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: format index during enumeration
+ * @code: format code (from enum v4l2_mbus_pixelcode)
+ */
+struct v4l2_subdev_mbus_code_enum {
+ __u32 pad;
+ __u32 index;
+ __u32 code;
+ __u32 reserved[5];
+};
+
+/**
+ * struct v4l2_subdev_frame_size_enum - Media bus format enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: format index during enumeration
+ * @code: format code (from enum v4l2_mbus_pixelcode)
+ */
+struct v4l2_subdev_frame_size_enum {
+ __u32 index;
+ __u32 pad;
+ __u32 code;
+ __u32 min_width;
+ __u32 max_width;
+ __u32 min_height;
+ __u32 max_height;
+ __u32 reserved[9];
+};
+
+#define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format)
+#define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format)
+#define VIDIOC_SUBDEV_ENUM_MBUS_CODE \
+ _IOWR('V', 2, struct v4l2_subdev_mbus_code_enum)
+#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
+ _IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
+
+#endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 3a304da..322557a 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -21,6 +21,7 @@
#ifndef _V4L2_SUBDEV_H
#define _V4L2_SUBDEV_H

+#include <linux/v4l2-subdev.h>
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
@@ -401,6 +402,15 @@ struct v4l2_subdev_ir_ops {
};

struct v4l2_subdev_pad_ops {
+ int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code);
+ int (*enum_frame_size)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse);
+ int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format);
+ int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format);
};

struct v4l2_subdev_ops {
--
1.7.2.2
Laurent Pinchart
2010-11-25 02:49:34 UTC
Permalink
From: Antti Koskipaa <***@nokia.com>

This patch adds the VIDIOC_SUBDEV_S_CROP and G_CROP ioctls to the
userland API. CROPCAP is not implemented because it's redundant.

Signed-off-by: Antti Koskipaa <***@nokia.com>
Signed-off-by: Laurent Pinchart <***@ideasonboard.com>
---
Documentation/DocBook/media-entities.tmpl | 4 +
Documentation/DocBook/v4l/dev-subdev.xml | 33 +++++
Documentation/DocBook/v4l/v4l2.xml | 1 +
Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml | 143 ++++++++++++++++++++
drivers/media/video/v4l2-subdev.c | 26 ++++
include/linux/v4l2-subdev.h | 15 ++
include/media/v4l2-subdev.h | 4 +
7 files changed, 226 insertions(+), 0 deletions(-)
create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml

diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index b9abb09..61bd5c4 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -88,8 +88,10 @@
<!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-G-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_G_CROP</constant></link>">
<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
<!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-S-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_S_CROP</constant></link>">
<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
<!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
<!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
@@ -195,6 +197,7 @@
<!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
<!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
+<!ENTITY v4l2-subdev-crop "struct&nbsp;<link linkend='v4l2-subdev-crop'>v4l2_subdev_crop</link>">
<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
<!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
@@ -329,6 +332,7 @@
<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
+<!ENTITY sub-subdev-g-crop SYSTEM "v4l/vidioc-subdev-g-crop.xml">
<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
<!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
<!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
index 12fdca4..a8da916 100644
--- a/Documentation/DocBook/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/v4l/dev-subdev.xml
@@ -269,6 +269,39 @@
</para>
</section>

+ <section>
+ <title>Cropping and scaling</title>
+
+ <para>Many sub-devices support cropping frames on their input or output
+ pads (or possible even on both). Cropping is used to select the area of
+ interest in an image, typically on a video sensor or video decoder. It can
+ also be used as part of digital zoom implementations to select the area of
+ the image that will be scaled up.</para>
+
+ <para>Crop settings are defined by a crop rectangle and represented in a
+ &v4l2-rect; by the coordinates of the top left corner and the rectangle
+ size. Both the coordinates and sizes are expressed in pixels.</para>
+
+ <para>The crop rectangle is retrieved and set using the
+ &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
+ formats, drivers store try and active crop rectangles. The format
+ negotiation mechanism applies to crop settings as well.</para>
+
+ <para>On input pads, cropping is applied relatively to the current pad
+ format. The pad format represents the image size as received by the
+ sub-device from the previous block in the pipeline, and the crop rectangle
+ represents the sub-image that will be transmitted further inside the
+ sub-device for processing. The crop rectangle be entirely containted
+ inside the input image size.</para>
+
+ <para>Input crop rectangle are reset to their default value when the input
+ image format is modified. Drivers should use the input image size as the
+ crop rectangle default value, but hardware requirements may prevent this.
+ </para>
+
+ <para>Cropping behaviour on output pads is not defined.</para>
+
+ </section>
</section>

&sub-subdev-formats;
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 7806562..c0fe94b 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -473,6 +473,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-subdev-enum-frame-interval;
&sub-subdev-enum-frame-size;
&sub-subdev-enum-mbus-code;
+ &sub-subdev-g-crop;
&sub-subdev-g-fmt;
&sub-subdev-g-frame-interval;
&sub-subscribe-event;
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
new file mode 100644
index 0000000..b71c9a3
--- /dev/null
+++ b/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
@@ -0,0 +1,143 @@
+<refentry id="vidioc-subdev-g-crop">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_G_CROP</refname>
+ <refname>VIDIOC_SUBDEV_S_CROP</refname>
+ <refpurpose>Get or set the crop rectangle on a subdev pad</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>const struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>To retrieve the current crop rectangle applications set the
+ <structfield>pad</structfield> field of a &v4l2-subdev-crop; to the
+ desired pad number as reported by the media API and the
+ <structfield>which</structfield> field to
+ <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. They then call the
+ <constant>VIDIOC_SUBDEV_G_CROP</constant> ioctl with a pointer to this
+ structure. The driver fills the members of the <structfield>rect</structfield>
+ field or returns &EINVAL; if the input arguments are invalid, or if cropping
+ is not supported on the given pad.</para>
+
+ <para>To change the current crop rectangle applications set both the
+ <structfield>pad</structfield> and <structfield>which</structfield> fields
+ and all members of the <structfield>rect</structfield> field. They then call
+ the <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctl with a pointer to this
+ structure. The driver verifies the requested crop rectangle, adjusts it
+ based on the hardware capabilities and configures the device. Upon return
+ the &v4l2-subdev-crop; contains the current format as would be returned
+ by a <constant>VIDIOC_SUBDEV_G_CROP</constant> call.</para>
+
+ <para>Applications can query the device capabilities by setting the
+ <structfield>which</structfield> to
+ <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' crop
+ rectangles are not applied to the device by the driver, but are mangled
+ exactly as active crop rectangles and stored in the sub-device file handle.
+ Two applications querying the same sub-device would thus not interact with
+ each other.</para>
+
+ <para>Drivers must not return an error solely because the requested crop
+ rectangle doesn't match the device capabilities. They must instead modify
+ the rectangle to match what the hardware can provide. The modified format
+ should be as close as possible to the original request.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-crop">
+ <title>struct <structname>v4l2_subdev_crop</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media framework.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>which</structfield></entry>
+ <entry>Crop rectangle to get or set, from
+ &v4l2-subdev-format-whence;.</entry>
+ </row>
+ <row>
+ <entry>&v4l2-rect;</entry>
+ <entry><structfield>rect</structfield></entry>
+ <entry>Crop rectangle boundaries, in pixels.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBUSY</errorcode></term>
+ <listitem>
+ <para>The crop rectangle can't be changed because the pad is currently
+ busy. This can be caused, for instance, by an active video stream on
+ the pad. The ioctl must not be retried without performing another
+ action to fix the problem first. Only returned by
+ <constant>VIDIOC_SUBDEV_S_CROP</constant></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-crop; <structfield>pad</structfield>
+ references a non-existing pad, the <structfield>which</structfield>
+ field references a non-existing format, or cropping is not supported
+ on the given subdev pad.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 196a37c..438c70f 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -204,6 +204,32 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format);
}

+ case VIDIOC_SUBDEV_G_CROP: {
+ struct v4l2_subdev_crop *crop = arg;
+
+ if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
+ crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (crop->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+ }
+
+ case VIDIOC_SUBDEV_S_CROP: {
+ struct v4l2_subdev_crop *crop = arg;
+
+ if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
+ crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (crop->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+ }
+
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
struct v4l2_subdev_mbus_code_enum *code = arg;

diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
index 7af0c34..e084200 100644
--- a/include/linux/v4l2-subdev.h
+++ b/include/linux/v4l2-subdev.h
@@ -51,6 +51,19 @@ struct v4l2_subdev_format {
};

/**
+ * struct v4l2_subdev_crop - Pad-level crop settings
+ * @which: format type (from enum v4l2_subdev_format_whence)
+ * @pad: pad number, as reported by the media API
+ * @rect: pad crop rectangle boundaries
+ */
+struct v4l2_subdev_crop {
+ __u32 which;
+ __u32 pad;
+ struct v4l2_rect rect;
+ __u32 reserved[10];
+};
+
+/**
* struct v4l2_subdev_mbus_code_enum - Media bus format enumeration
* @pad: pad number, as reported by the media API
* @index: format index during enumeration
@@ -122,5 +135,7 @@ struct v4l2_subdev_frame_interval_enum {
_IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
#define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
_IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
+#define VIDIOC_SUBDEV_G_CROP _IOWR('V', 59, struct v4l2_subdev_crop)
+#define VIDIOC_SUBDEV_S_CROP _IOWR('V', 60, struct v4l2_subdev_crop)

#endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 424537b..5e570d2 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -418,6 +418,10 @@ struct v4l2_subdev_pad_ops {
struct v4l2_subdev_format *format);
int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format);
+ int (*set_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop);
+ int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop);
};

struct v4l2_subdev_ops {
--
1.7.2.2
Arjan van de Ven
2010-11-25 04:02:10 UTC
Permalink
Post by Laurent Pinchart
Hi everybody,
This (too big) patch set adds support for the media controller and the V4L2
subdev pad-level APIs to the MeeGo kernel.
yikes. thats a lot.

the big question is... why?
what does it bring to MeeGo thats not there today?
Greg KH
2010-11-25 05:20:21 UTC
Permalink
Post by Laurent Pinchart
Hi everybody,
This (too big) patch set adds support for the media controller and the V4L2
subdev pad-level APIs to the MeeGo kernel.
The first 28 patches have been backported from upstream (2.6.36 or 2.6.37-rc).
They are required by the rest of the code. I'm aware that they don't pass
checkpatch.pl but there's not much I can do about that (fixing the warnings
would make later merges from upstream more difficult).
The next 31 patches contain V4L2 subdev device node support, the media
controller API and the V4L2 subdev pad-level API. They have all been posted
to the linux-media mailing list and went through several rounds of review.
The stream of comments eventually died with all developers happy with the
result (or at least too tired to complain).
I'd like to complain about them, you are adding functionality to the v4l
core that should be in the core kernel itself.

Please repost them to lkml and cc: me at the least before continuing.
I'll be able to review them next week after vacation.

thanks,

greg k-h
Laurent Pinchart
2010-11-25 08:40:38 UTC
Permalink
Hi Greg,
Post by Greg KH
Post by Laurent Pinchart
Hi everybody,
This (too big) patch set adds support for the media controller and the
V4L2 subdev pad-level APIs to the MeeGo kernel.
The first 28 patches have been backported from upstream (2.6.36 or
2.6.37-rc). They are required by the rest of the code. I'm aware that
they don't pass checkpatch.pl but there's not much I can do about that
(fixing the warnings would make later merges from upstream more
difficult).
The next 31 patches contain V4L2 subdev device node support, the media
controller API and the V4L2 subdev pad-level API. They have all been
posted to the linux-media mailing list and went through several rounds
of review. The stream of comments eventually died with all developers
happy with the result (or at least too tired to complain).
I'd like to complain about them, you are adding functionality to the v4l
core that should be in the core kernel itself.
Are you talking about the media controller patches ? If so I've posted them
yesterday to LKML. If you're talking about the V4L2 subdev API (device nodes
and pad-level API), please let me know and I'll repost those to LKML as well.
Post by Greg KH
Please repost them to lkml and cc: me at the least before continuing.
I'll be able to review them next week after vacation.
I haven't CC'ed you on yesterday's submission to LKML. Should I repost ?
--
Regards,

Laurent Pinchart
Loading...