Media controller update based on Hans' v4l-dvb-mc tree
cover Media controller update based on Hans' v4l-dvb-mc tree
Hi everybody,
here's a set of patches to clean up and extend Hans' initial media controller implementation.
Patches prefixed by v4l deal with the v4l core code and update existing drivers when required by an API change. The core now offers two functions to deal with entities and links:
- v4l2_entity_init() will initialize an entity. For subdevices the v4l2_subdev_init() performs part of the entity initialization as well, which leads me to believe that the API is currently ill-defined.
- v4l2_entity_connect() creates a link between two entities. All possible links should be created using that function before the subdevice is registered.
As I don't own any ivtv hardware the media controller code was difficult to test so I've implemented media controller support in the UVC driver for testing purpose. The code can be found in patches prefixed by uvc.
This is mostly playground code. There are known and unknown bugs (especially in the ivtv driver as I haven't been able to test that code; v4l2_entity_connect is definitely called with bad parameters in there) as well as design issues. There's a lot of code missing. I'm mostly interested in getting feedback on the changes, especially the new v4l2_entity_pad and v4l2_entity_link objects. Feel free to comment on the public userspace API too, I realized after changing it to mimic the new kernel API that the way the previous API exposed "local" and "remote" pads instead of pads and links is probably more space efficient.
I'll keep playing with the code and I'll start porting the OMAP3 camera driver to the in-progress media controller API. I'll discover problems (and hopefully solutions) along the way so another round of patches can be expected later, maybe in a week. Of course I'll appreciate comments before that, as the earlier I get feedback the easier it will be to incorporate it in the code. No pressure though, I know that a few developers have left for the kernel summit in Japan.
--
Regards,
Laurent Pinchart
PATCH 1/14 v4l-mc: Rename pins to pads
Entities "connection points" are now named pads to avoid confusing them with physical pins.
linux/include/linux/videodev2.h +3 -3
@@ -1561,8 +1561,8 @@ struct v4l2_mc_io { };struct v4l2_mc_io_status { -__u32 active_pins; -__u8 nr_of_remote_pins; +__u32 active_pads; +__u8 nr_of_remote_pads; };struct v4l2_mc_entity {
@@ -1598,7 +1598,7 @@ struct v4l2_mc_ios {/* Should have enough room for inputs+outputs elements */ struct v4l2_mc_io_status *status;/* Should have enough room for total_possible_links elements */ -struct v4l2_mc_io *remote_pins; +struct v4l2_mc_io *remote_pads; };struct v4l2_mc_link {
linux/include/media/v4l2-mc.h +10 -10
@@ -4,9 +4,9 @@#include <linux/list.h> struct v4l2_entity_io { -u32 active;/* bitmask of active remote pins */ -u8 nr_of_remote_pins;/* number of remote pins */ -struct v4l2_mc_io *remote_pins;/* specify possible remote pins */ +u32 active;/* bitmask of active remote pads */ +u8 nr_of_remote_pads;/* number of remote pads */ +struct v4l2_mc_io *remote_pads;/* specify possible remote pads */ };struct v4l2_entity {
@@ -46,7 +46,7 @@ struct v4l2_entity { };static inline void v4l2_entity_prep (struct v4l2_entity *ent,u8 num_inputs,u8 num_outputs, -struct v4l2_entity_io *links,struct v4l2_mc_io *remote_pins) +struct v4l2_entity_io *links,struct v4l2_mc_io *remote_pads) {int i;
@@ -54,8 +54,8 @@ static inline void v4l2_entity_prep(stru ent->num_outputs = num_outputs; ent->links = links;for (i =0 ; i < num_inputs + num_outputs; i++) { - links[i].nr_of_remote_pins =1 ; - links[i].remote_pins = remote_pins + i; + links[i].nr_of_remote_pads =1 ; + links[i].remote_pads = remote_pads + i; } }
@@ -71,11 +71,11 @@ static inline void v4l2_entity_connect(s source_link = source->num_inputs + source->outputs++; sink_link = sink->inputs++; - source->links[source_link].remote_pins[0 ].entity = sink->id; - source->links[source_link].remote_pins[0 ].io = sink_link; + source->links[source_link].remote_pads[0 ].entity = sink->id; + source->links[source_link].remote_pads[0 ].io = sink_link; source->links[source_link].active = active; - sink->links[sink_link].remote_pins[0 ].entity = source->id; - sink->links[sink_link].remote_pins[0 ].io = source_link; + sink->links[sink_link].remote_pads[0 ].entity = source->id; + sink->links[sink_link].remote_pads[0 ].io = source_link; sink->links[sink_link].active = active; }
v4l2-apps/util/v4l2-mc.cpp +27 -27
109 lines not on this page · raw message
linux/drivers/media/video/v4l2-device.c +15 -15
@@ -114,9 +114,9 @@ static long mc_enum_entities(struct v4l2int l;for (l =0 ; l < ent->inputs; l++) - mc_ent.total_possible_links += ent->links[l].nr_of_remote_pins; + mc_ent.total_possible_links += ent->links[l].nr_of_remote_pads;for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++) - mc_ent.total_possible_links += ent->links[l].nr_of_remote_pins; + mc_ent.total_possible_links += ent->links[l].nr_of_remote_pads; } mc_ent.v4l.major = ent->v4l.major; mc_ent.v4l.minor = ent->v4l.minor;
@@ -140,9 +140,9 @@ static long mc_enum_links(struct v4l2_dereturn -EINVAL ;if (ent->links) {for (l =0 ; l < ent->inputs; l++) - total_possible_links += ent->links[l].nr_of_remote_pins; + total_possible_links += ent->links[l].nr_of_remote_pads;for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++) - total_possible_links += ent->links[l].nr_of_remote_pins; + total_possible_links += ent->links[l].nr_of_remote_pads; }if (ios.status) {int s =0 ;
@@ -151,8 +151,8 @@ static long mc_enum_links(struct v4l2_destruct v4l2_mc_io_status stat = {0 ,0 };if (ent->links) { - stat.active_pins = ent->links[l].active; - stat.nr_of_remote_pins = ent->links[l].nr_of_remote_pins; + stat.active_pads = ent->links[l].active; + stat.nr_of_remote_pads = ent->links[l].nr_of_remote_pads; }if (copy_to_user (uios->status + s, &stat,sizeof (stat)))return -EFAULT ;
@@ -161,28 +161,28 @@ static long mc_enum_links(struct v4l2_destruct v4l2_mc_io_status stat = {0 ,0 };if (ent->links) { - stat.active_pins = ent->links[l].active; - stat.nr_of_remote_pins = ent->links[l].nr_of_remote_pins; + stat.active_pads = ent->links[l].active; + stat.nr_of_remote_pads = ent->links[l].nr_of_remote_pads; }if (copy_to_user (uios->status + s, &stat,sizeof (stat)))return -EFAULT ; } } -if (ios.remote_pins && total_possible_links) { +if (ios.remote_pads && total_possible_links) {int p =0 ;for (l =0 ; l < ent->inputs; l++) { -if (copy_to_user (uios->remote_pins + p, ent->links[l].remote_pins, - ent->links[l].nr_of_remote_pins *sizeof (ent->links[l].remote_pins[0 ]))) +if (copy_to_user (uios->remote_pads + p, ent->links[l].remote_pads, + ent->links[l].nr_of_remote_pads *sizeof (ent->links[l].remote_pads[0 ])))return -EFAULT ; - p += ent->links[l].nr_of_remote_pins; + p += ent->links[l].nr_of_remote_pads; }for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++) { -if (copy_to_user (uios->remote_pins + p, ent->links[l].remote_pins, - ent->links[l].nr_of_remote_pins *sizeof (ent->links[l].remote_pins[0 ]))) +if (copy_to_user (uios->remote_pads + p, ent->links[l].remote_pads, + ent->links[l].nr_of_remote_pads *sizeof (ent->links[l].remote_pads[0 ])))return -EFAULT ; - p += ent->links[l].nr_of_remote_pins; + p += ent->links[l].nr_of_remote_pads; } }if (copy_to_user (uios, &ios,sizeof (*uios)))
PATCH 2/14 v4l-mc: Merge input and output pads
In reply to [email protected]The media controller doesn't need separate counts of input and output pads. Merge them into a pads count.
linux/drivers/media/video/v4l2-device.c +5 -26
@@ -107,15 +107,12 @@ static long mc_enum_entities(struct v4l2strlcpy (mc_ent.descr, ent->descr,sizeof (mc_ent.descr)); mc_ent.type = ent->type; mc_ent.subtype = ent->subtype; - mc_ent.inputs = ent->inputs; - mc_ent.outputs = ent->outputs; + mc_ent.pads = ent->pads; mc_ent.total_possible_links =0 ;if (ent->links) {int l; -for (l =0 ; l < ent->inputs; l++) - mc_ent.total_possible_links += ent->links[l].nr_of_remote_pads; -for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++) +for (l =0 ; l < ent->pads; l++) mc_ent.total_possible_links += ent->links[l].nr_of_remote_pads; } mc_ent.v4l.major = ent->v4l.major;
@@ -139,25 +136,13 @@ static long mc_enum_links(struct v4l2_deif (ent ==NULL )return -EINVAL ;if (ent->links) { -for (l =0 ; l < ent->inputs; l++) - total_possible_links += ent->links[l].nr_of_remote_pads; -for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++) +for (l =0 ; l < ent->pads; l++) total_possible_links += ent->links[l].nr_of_remote_pads; }if (ios.status) {int s =0 ; -for (l =0 ; l < ent->inputs; l++, s++) { -struct v4l2_mc_io_status stat = {0 ,0 }; - -if (ent->links) { - stat.active_pads = ent->links[l].active; - stat.nr_of_remote_pads = ent->links[l].nr_of_remote_pads; - } -if (copy_to_user (uios->status + s, &stat,sizeof (stat))) -return -EFAULT ; - } -for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++, s++) { +for (l =0 ; l < ent->pads; l++, s++) {struct v4l2_mc_io_status stat = {0 ,0 };if (ent->links) {
@@ -172,13 +157,7 @@ static long mc_enum_links(struct v4l2_deif (ios.remote_pads && total_possible_links) {int p =0 ; -for (l =0 ; l < ent->inputs; l++) { -if (copy_to_user (uios->remote_pads + p, ent->links[l].remote_pads, - ent->links[l].nr_of_remote_pads *sizeof (ent->links[l].remote_pads[0 ]))) -return -EFAULT ; - p += ent->links[l].nr_of_remote_pads; - } -for (l = ent->num_inputs; l < ent->num_inputs + ent->outputs; l++) { +for (l =0 ; l < ent->pads; l++) {if (copy_to_user (uios->remote_pads + p, ent->links[l].remote_pads, ent->links[l].nr_of_remote_pads *sizeof (ent->links[l].remote_pads[0 ])))return -EFAULT ;
linux/include/linux/videodev2.h +6 -4
@@ -1554,15 +1554,18 @@ struct v4l2_dbg_chip_ident {#define V4L2_SUBDEV_TYPE_VID_ENCODER 2#define V4L2_SUBDEV_TYPE_MISC 3 +#define V4L2_PAD_TYPE_INPUT 1 +#define V4L2_PAD_TYPE_OUTPUT 2struct v4l2_mc_io {__u32 entity;/* entity ID */ -__u8 io;/* input or output index */ +__u8 pad;/* pad index */ };struct v4l2_mc_io_status {__u32 active_pads;__u8 nr_of_remote_pads; +__u32 type;/* pad type */ };struct v4l2_mc_entity {
@@ -1571,8 +1574,7 @@ struct v4l2_mc_entity {char descr[256 ];__u32 type;__u32 subtype; -__u8 inputs; -__u8 outputs; +__u8 pads;__u32 total_possible_links;union {
@@ -1595,7 +1597,7 @@ struct v4l2_mc_entity {struct v4l2_mc_ios {__u32 entity; -/* Should have enough room for inputs+outputs elements */ +/* Should have enough room for pads elements */ struct v4l2_mc_io_status *status;/* Should have enough room for total_possible_links elements */ struct v4l2_mc_io *remote_pads;
linux/include/media/v4l2-mc.h +11 -16
@@ -17,11 +17,9 @@ struct v4l2_entity {const char *descr;u32 type;u32 subtype; -u8 inputs; -u8 outputs; -u8 num_inputs; -u8 num_outputs; -/* points to a v4l2_entity_io array of size num_inputs + num_outputs links */ +u8 pads; +u8 num_pads; +/* points to a v4l2_entity_io array of size num_pads links */ struct v4l2_entity_io *links;/* The entity's ioctl, accessible through the media controller */
@@ -45,15 +43,14 @@ struct v4l2_entity { }; }; -static inline void v4l2_entity_prep (struct v4l2_entity *ent,u8 num_inputs,u8 num_outputs, +static inline void v4l2_entity_prep (struct v4l2_entity *ent,u8 num_pads,struct v4l2_entity_io *links,struct v4l2_mc_io *remote_pads) {int i; - ent->num_inputs = num_inputs; - ent->num_outputs = num_outputs; + ent->num_pads = num_pads; ent->links = links; -for (i =0 ; i < num_inputs + num_outputs; i++) { +for (i =0 ; i < num_pads; i++) { links[i].nr_of_remote_pads =1 ; links[i].remote_pads = remote_pads + i; }
@@ -64,18 +61,16 @@ static inline void v4l2_entity_connect(s {int source_link, sink_link; -if (source ==NULL || sink ==NULL || - source->outputs >= source->num_outputs || - sink->inputs >= sink->num_inputs) +if (source ==NULL || sink ==NULL || source->pads >= source->num_pads)return ; - source_link = source->num_inputs + source->outputs++; - sink_link = sink->inputs++; + source_link = source->pads++; + sink_link = sink->pads++; source->links[source_link].remote_pads[0 ].entity = sink->id; - source->links[source_link].remote_pads[0 ].io = sink_link; + source->links[source_link].remote_pads[0 ].pad = sink_link; source->links[source_link].active = active; sink->links[sink_link].remote_pads[0 ].entity = source->id; - sink->links[sink_link].remote_pads[0 ].io = source_link; + sink->links[sink_link].remote_pads[0 ].pad = source_link; sink->links[sink_link].active = active; }
v4l2-apps/util/v4l2-mc.cpp +28 -36
122 lines not on this page · raw message
linux/drivers/media/video/ivtv/ivtv-driver.c +2 -2
@@ -697,9 +697,9 @@ static int __devinit ivtv_init_struct1(sv4l2_subdev_init (&itv->sd_encoder,NULL );v4l2_subdev_init (&itv->sd_decoder,NULL );strlcpy (itv->sd_encoder.name,"MPEG encoder" ,sizeof (itv->sd_encoder.name)); -v4l2_entity_prep (&itv->sd_encoder.entity,SD_ENC_NUM_INPUTS ,SD_ENC_NUM_OUTPUTS , +v4l2_entity_prep (&itv->sd_encoder.entity,SD_ENC_NUM_INPUTS +SD_ENC_NUM_OUTPUTS , itv->sd_enc_links, itv->sd_enc_remote); -v4l2_entity_prep (&itv->sd_decoder.entity,SD_DEC_NUM_INPUTS ,SD_DEC_NUM_OUTPUTS , +v4l2_entity_prep (&itv->sd_decoder.entity,SD_DEC_NUM_INPUTS +SD_DEC_NUM_OUTPUTS , itv->sd_dec_links, itv->sd_dec_remote);strlcpy (itv->sd_decoder.name,"MPEG decoder" ,sizeof (itv->sd_decoder.name)); err =v4l2_device_register_subdev (&itv->v4l2_dev, &itv->sd_encoder);
linux/drivers/media/video/ivtv/ivtv-gpio.c +1 -1
@@ -374,7 +374,7 @@ int ivtv_gpio_init(struct ivtv *itv)write_reg (itv->card->gpio_init.direction | pin,IVTV_REG_GPIO_DIR );v4l2_subdev_init (&itv->sd_gpio, &subdev_ops);snprintf (itv->sd_gpio.name,sizeof (itv->sd_gpio.name),"%s-gpio" , itv->v4l2_dev.name); -v4l2_entity_prep (&itv->sd_gpio.entity,0 ,1 , &itv->sd_gpio_links, &itv->sd_gpio_remote); +v4l2_entity_prep (&itv->sd_gpio.entity,1 , &itv->sd_gpio_links, &itv->sd_gpio_remote); itv->sd_gpio.grp_id =IVTV_HW_GPIO ;v4l2_entity_connect (&itv->sd_gpio.entity, &itv->sd_encoder.entity,1 );return v4l2_device_register_subdev (&itv->v4l2_dev, &itv->sd_gpio);
linux/drivers/media/video/ivtv/ivtv-streams.c +2 -2
@@ -269,10 +269,10 @@ static int ivtv_reg_dev(struct ivtv *itvreturn -ENOMEM ; }if (type <=IVTV_ENC_STREAM_TYPE_RAD || type ==IVTV_DEC_STREAM_TYPE_VBI ) -v4l2_entity_prep (&s->vdev->entity,1 ,0 , +v4l2_entity_prep (&s->vdev->entity,1 , itv->stream_links + type, itv->stream_remote + type);else -v4l2_entity_prep (&s->vdev->entity,0 ,1 , +v4l2_entity_prep (&s->vdev->entity,1 , itv->stream_links + type, itv->stream_remote + type);if (type <=IVTV_ENC_STREAM_TYPE_RAD )v4l2_entity_connect (&itv->sd_encoder.entity, &s->vdev->entity,1 );
linux/drivers/media/video/msp3400-driver.c +1 -1
@@ -764,7 +764,7 @@ static int msp_probe(struct i2c_client * sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &msp_ops); -v4l2_entity_prep (&sd->entity,0 ,1 , &state->sd_output, &state->remote_input); +v4l2_entity_prep (&sd->entity,1 , &state->sd_output, &state->remote_input); state->v4l2_std =V4L2_STD_NTSC ; state->audmode =V4L2_TUNER_MODE_STEREO ;
linux/drivers/media/video/saa7115.c +1 -1
@@ -1604,7 +1604,7 @@ static int saa711x_probe(struct i2c_cliereturn -ENOMEM ; sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &saa711x_ops); -v4l2_entity_prep (&sd->entity,0 ,1 , &state->sd_output, &state->remote_input); +v4l2_entity_prep (&sd->entity,1 , &state->sd_output, &state->remote_input); state->input =-1 ; state->output =SAA7115_IPORT_ON ; state->enable =1 ;
linux/drivers/media/video/saa7127.c +1 -1
@@ -740,7 +740,7 @@ static int saa7127_probe(struct i2c_clie sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &saa7127_ops); -v4l2_entity_prep (&sd->entity,1 ,0 , &state->sd_input, &state->remote_output); +v4l2_entity_prep (&sd->entity,1 , &state->sd_input, &state->remote_output);/* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0.
linux/drivers/media/video/tuner-core.c +1 -1
@@ -1041,7 +1041,7 @@ static int tuner_probe(struct i2c_clientif (NULL == t)return -ENOMEM ;v4l2_i2c_subdev_init (&t->sd, client, &tuner_ops); -v4l2_entity_prep (&t->sd.entity,0 ,1 , &t->sd_output, &t->remote_input); +v4l2_entity_prep (&t->sd.entity,1 , &t->sd_output, &t->remote_input); t->i2c = client; t->name ="(tuner unset)" ; t->type =UNSET ;
PATCH 3/14 v4l-mc: Replace the active pads bitmask by a link flag
In reply to [email protected]linux/drivers/media/video/v4l2-device.c +1 -3
@@ -145,10 +145,8 @@ static long mc_enum_links(struct v4l2_defor (l =0 ; l < ent->pads; l++, s++) {struct v4l2_mc_io_status stat = {0 ,0 }; -if (ent->links) { - stat.active_pads = ent->links[l].active; +if (ent->links) stat.nr_of_remote_pads = ent->links[l].nr_of_remote_pads; - }if (copy_to_user (uios->status + s, &stat,sizeof (stat)))return -EFAULT ; }
linux/include/linux/videodev2.h +1 -1
@@ -1560,10 +1560,10 @@ struct v4l2_dbg_chip_ident {struct v4l2_mc_io {__u32 entity;/* entity ID */ __u8 pad;/* pad index */ +__u8 active;/* link is active */ };struct v4l2_mc_io_status { -__u32 active_pads;__u8 nr_of_remote_pads;__u32 type;/* pad type */ };
linux/include/media/v4l2-mc.h +2 -3
@@ -4,7 +4,6 @@#include <linux/list.h> struct v4l2_entity_io { -u32 active;/* bitmask of active remote pads */ u8 nr_of_remote_pads;/* number of remote pads */ struct v4l2_mc_io *remote_pads;/* specify possible remote pads */ };
@@ -68,10 +67,10 @@ static inline void v4l2_entity_connect(s sink_link = sink->pads++; source->links[source_link].remote_pads[0 ].entity = sink->id; source->links[source_link].remote_pads[0 ].pad = sink_link; - source->links[source_link].active = active; + source->links[source_link].remote_pads[0 ].active = active; sink->links[sink_link].remote_pads[0 ].entity = source->id; sink->links[sink_link].remote_pads[0 ].pad = source_link; - sink->links[sink_link].active = active; + sink->links[sink_link].remote_pads[0].active = active; }#endif
PATCH 4/14 v4l-subdev: Add pads operations
In reply to [email protected]Add a v4l2_subdev_pad_ops structure for the operations that need to be performed at the pad level such as format-related operations.
linux/include/media/v4l2-subdev.h +10 -0
@@ -232,11 +232,21 @@ struct v4l2_subdev_video_ops {int (*enum_frameintervals)(struct v4l2_subdev *sd,struct v4l2_frmivalenum *fival); }; +struct v4l2_subdev_pad_ops { +int (*enum_fmt)(struct v4l2_subdev *sd,unsigned int pad,struct v4l2_fmtdesc *fmtdesc); +int (*enum_framesizes)(struct v4l2_subdev *sd,unsigned int pad,struct v4l2_frmsizeenum *fsize); +int (*enum_frameintervals)(struct v4l2_subdev *sd,unsigned int pad,struct v4l2_frmivalenum *fival); +int (*get_fmt)(struct v4l2_subdev *sd,unsigned int pad,struct v4l2_format *fmt); +int (*try_fmt)(struct v4l2_subdev *sd,unsigned int pad,struct v4l2_format *fmt); +int (*set_fmt)(struct v4l2_subdev *sd,unsigned int pad,struct v4l2_format *fmt); +}; +struct v4l2_subdev_ops {const struct v4l2_subdev_core_ops *core;const struct v4l2_subdev_tuner_ops *tuner;const struct v4l2_subdev_audio_ops *audio;const struct v4l2_subdev_video_ops *video; +const struct v4l2_subdev_pad_ops *pad; };#define V4L2_SUBDEV_NAME_SIZE 32
PATCH 5/14 v4l-mc: Clean up link API
In reply to [email protected]Make the link API easier to use and more intuitive by introducing pad and link objects.
The entity API is now made of two functions:
- v4l2_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.
- v4l2_entity_connect() connects two entities. An entry in the link array of each entity is allocated and stores pointers to source and sink pads.
linux/drivers/media/video/Makefile +1 -1
@@ -10,7 +10,7 @@ stkwebcam-objs := stk-webcam.o stk-senso omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o -videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o +videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-mc.o # V4L2 core modules
linux/drivers/media/video/ivtv/ivtv-driver.c +5 -5
@@ -697,11 +697,11 @@ static int __devinit ivtv_init_struct1(sv4l2_subdev_init (&itv->sd_encoder,NULL );v4l2_subdev_init (&itv->sd_decoder,NULL );strlcpy (itv->sd_encoder.name,"MPEG encoder" ,sizeof (itv->sd_encoder.name)); -v4l2_entity_prep (&itv->sd_encoder.entity,SD_ENC_NUM_INPUTS +SD_ENC_NUM_OUTPUTS , - itv->sd_enc_links, itv->sd_enc_remote); -v4l2_entity_prep (&itv->sd_decoder.entity,SD_DEC_NUM_INPUTS +SD_DEC_NUM_OUTPUTS , - itv->sd_dec_links, itv->sd_dec_remote);strlcpy (itv->sd_decoder.name,"MPEG decoder" ,sizeof (itv->sd_decoder.name)); +v4l2_entity_init (&itv->sd_encoder.entity,SD_ENC_NUM_PADS , + itv->sd_encoder_pads,0 ); +v4l2_entity_init (&itv->sd_decoder.entity,SD_DEC_NUM_PADS , + itv->sd_decoder_pads,0 ); err =v4l2_device_register_subdev (&itv->v4l2_dev, &itv->sd_encoder);if (err)return err;
@@ -1020,7 +1020,7 @@ static int __devinit ivtv_probe(struct p retval =v4l2_device_register_subdev (&itv->v4l2_dev, &itv->sd_decoder);if (retval) goto free_io; -v4l2_entity_connect (&itv->sd_encoder.entity, &itv->sd_decoder.entity,0 ); +v4l2_entity_connect (&itv->sd_encoder.entity,0 , &itv->sd_decoder.entity,0 ,0 ); }else { itv->dec_mem = itv->enc_mem;
linux/drivers/media/video/ivtv/ivtv-driver.h +7 -12
@@ -321,6 +321,8 @@ struct ivtv_stream {const char *name;/* name of the stream */ int type;/* stream type */ +struct v4l2_entity_pad pad; +u32 id;spinlock_t qlock;/* locks access to the queues */ unsigned long s_flags;/* status flags, see above */
@@ -615,18 +617,13 @@ struct ivtv {struct v4l2_device v4l2_dev;struct v4l2_subdev sd_gpio;/* GPIO sub-device */ -struct v4l2_entity_io sd_gpio_links; -struct v4l2_mc_io sd_gpio_remote; +struct v4l2_entity_pad sd_gpio_pad;struct v4l2_subdev sd_encoder;/* Bridge encoder sub-device */ -#define SD_ENC_NUM_INPUTS (10) -#define SD_ENC_NUM_OUTPUTS (10) -struct v4l2_entity_io sd_enc_links[SD_ENC_NUM_INPUTS +SD_ENC_NUM_OUTPUTS ]; -struct v4l2_mc_io sd_enc_remote[SD_ENC_NUM_INPUTS +SD_ENC_NUM_OUTPUTS ]; +#define SD_ENC_NUM_PADS 20/* 10 inputs, 10 outputs */ +struct v4l2_entity_pad sd_encoder_pads[SD_ENC_NUM_PADS ];struct v4l2_subdev sd_decoder;/* Bridge decoder sub-device */ -#define SD_DEC_NUM_INPUTS (10) -#define SD_DEC_NUM_OUTPUTS (10) -struct v4l2_entity_io sd_dec_links[SD_DEC_NUM_INPUTS +SD_DEC_NUM_OUTPUTS ]; -struct v4l2_mc_io sd_dec_remote[SD_DEC_NUM_INPUTS +SD_DEC_NUM_OUTPUTS ]; +#define SD_DEC_NUM_PADS 20/* 10 inputs, 10 outputs */ +struct v4l2_entity_pad sd_decoder_pads[SD_DEC_NUM_PADS ];u16 instance;/* High-level state info */
@@ -653,8 +650,6 @@ struct ivtv {/* Streams */ int stream_buf_size[IVTV_MAX_STREAMS ];/* stream buffer size */ struct ivtv_stream streams[IVTV_MAX_STREAMS ];/* stream data */ -struct v4l2_entity_io stream_links[IVTV_MAX_STREAMS ]; -struct v4l2_mc_io stream_remote[IVTV_MAX_STREAMS ];atomic_t capturing;/* count number of active capture streams */ atomic_t decoding;/* count number of active decoding streams */
linux/drivers/media/video/ivtv/ivtv-gpio.c +4 -2
@@ -374,8 +374,10 @@ int ivtv_gpio_init(struct ivtv *itv)write_reg (itv->card->gpio_init.direction | pin,IVTV_REG_GPIO_DIR );v4l2_subdev_init (&itv->sd_gpio, &subdev_ops);snprintf (itv->sd_gpio.name,sizeof (itv->sd_gpio.name),"%s-gpio" , itv->v4l2_dev.name); -v4l2_entity_prep (&itv->sd_gpio.entity,1 , &itv->sd_gpio_links, &itv->sd_gpio_remote); + itv->sd_gpio_pad.type =V4L2_PAD_TYPE_OUTPUT ; +v4l2_entity_init (&itv->sd_gpio.entity,1 , &itv->sd_gpio_pad,0 ); itv->sd_gpio.grp_id =IVTV_HW_GPIO ; -v4l2_entity_connect (&itv->sd_gpio.entity, &itv->sd_encoder.entity,1 ); +v4l2_entity_connect (&itv->sd_gpio.entity,0 , &itv->sd_encoder.entity,0 , +V4L2_LINK_FLAG_ACTIVE );return v4l2_device_register_subdev (&itv->v4l2_dev, &itv->sd_gpio); }
linux/drivers/media/video/ivtv/ivtv-i2c.c +12 -8
@@ -170,21 +170,24 @@ int ivtv_i2c_register(struct ivtv *itv, 0, itv->card_i2c->radio);if (sd) { sd->grp_id =1 << idx; -v4l2_entity_connect (&sd->entity, &itv->sd_encoder.entity,1 ); +v4l2_entity_connect (&sd->entity,0 , &itv->sd_encoder.entity,0 , +V4L2_LINK_FLAG_ACTIVE ); } sd =v4l2_i2c_new_subdev (&itv->v4l2_dev, adap, mod, type,0 , itv->card_i2c->demod);if (sd) { sd->grp_id =1 << idx; -v4l2_entity_connect (&sd->entity, &itv->sd_encoder.entity,1 ); +v4l2_entity_connect (&sd->entity,0 , &itv->sd_encoder.entity,0 , +V4L2_LINK_FLAG_ACTIVE ); } sd =v4l2_i2c_new_subdev (&itv->v4l2_dev, adap, mod, type,0 , itv->card_i2c->tv);if (sd) { sd->grp_id =1 << idx; -v4l2_entity_connect (&sd->entity, &itv->sd_encoder.entity,1 ); +v4l2_entity_connect (&sd->entity,0 , &itv->sd_encoder.entity,0 , +V4L2_LINK_FLAG_ACTIVE ); }return sd ?0 :-1 ; }
@@ -193,15 +196,16 @@ int ivtv_i2c_register(struct ivtv *itv,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])); -v4l2_entity_connect (&sd->entity, &itv->sd_encoder.entity,1 ); }else { sd =v4l2_i2c_new_subdev (&itv->v4l2_dev, adap, mod, type, hw_addrs[idx],NULL ); -if (hw ==IVTV_HW_SAA7127 ) -v4l2_entity_connect (&itv->sd_decoder.entity, &sd->entity,1 ); -else -v4l2_entity_connect (&sd->entity, &itv->sd_encoder.entity,1 ); } +if (hw ==IVTV_HW_SAA7127 ) +v4l2_entity_connect (&itv->sd_decoder.entity,0 , &sd->entity,0 , +V4L2_LINK_FLAG_ACTIVE ); +else +v4l2_entity_connect (&sd->entity,0 , &itv->sd_encoder.entity,0 , +V4L2_LINK_FLAG_ACTIVE );if (sd) sd->grp_id =1 << idx;return sd ?0 :-1 ;
linux/drivers/media/video/ivtv/ivtv-streams.c +14 -12
@@ -268,18 +268,20 @@ static int ivtv_reg_dev(struct ivtv *itv s->vdev =NULL ;return -ENOMEM ; } -if (type <=IVTV_ENC_STREAM_TYPE_RAD || type ==IVTV_DEC_STREAM_TYPE_VBI ) -v4l2_entity_prep (&s->vdev->entity,1 , - itv->stream_links + type, itv->stream_remote + type); -else -v4l2_entity_prep (&s->vdev->entity,1 , - itv->stream_links + type, itv->stream_remote + type); -if (type <=IVTV_ENC_STREAM_TYPE_RAD ) -v4l2_entity_connect (&itv->sd_encoder.entity, &s->vdev->entity,1 ); -else if (type ==IVTV_DEC_STREAM_TYPE_VBI ) -v4l2_entity_connect (&itv->sd_decoder.entity, &s->vdev->entity,1 ); -else -v4l2_entity_connect (&s->vdev->entity, &itv->sd_decoder.entity,1 ); +v4l2_entity_init (&s->vdev->entity,1 , &s->pad,0 ); +if (type <=IVTV_ENC_STREAM_TYPE_RAD ) { + s->pad.type =V4L2_PAD_TYPE_INPUT ; +v4l2_entity_connect (&itv->sd_encoder.entity,0 , &s->vdev->entity,0 , +V4L2_LINK_FLAG_ACTIVE ); + }else if (type ==IVTV_DEC_STREAM_TYPE_VBI ) { + s->pad.type =V4L2_PAD_TYPE_INPUT ; +v4l2_entity_connect (&itv->sd_decoder.entity,0 , &s->vdev->entity,0 , +V4L2_LINK_FLAG_ACTIVE ); + }else { + s->pad.type =V4L2_PAD_TYPE_OUTPUT ; +v4l2_entity_connect (&s->vdev->entity,0 , &itv->sd_decoder.entity,0 , +V4L2_LINK_FLAG_ACTIVE ); + } num = s->vdev->num;
linux/drivers/media/video/msp3400-driver.c +2 -1
@@ -764,7 +764,8 @@ static int msp_probe(struct i2c_client * sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &msp_ops); -v4l2_entity_prep (&sd->entity,1 , &state->sd_output, &state->remote_input); + state->sd_pad.type =V4L2_PAD_TYPE_OUTPUT ; +v4l2_entity_init (&sd->entity,1 , &state->sd_pad,0 ); state->v4l2_std =V4L2_STD_NTSC ; state->audmode =V4L2_TUNER_MODE_STEREO ;
linux/drivers/media/video/msp3400-driver.h +1 -2
@@ -51,8 +51,7 @@ extern int msp_stereo_thresh;struct msp_state {struct v4l2_subdev sd; -struct v4l2_entity_io sd_output; -struct v4l2_mc_io remote_input; +struct v4l2_entity_pad sd_pad;int rev1, rev2;int ident;u8 has_nicam;
linux/drivers/media/video/saa7115.c +3 -3
@@ -74,8 +74,7 @@ I2C_CLIENT_INSMOD;struct saa711x_state {struct v4l2_subdev sd; -struct v4l2_entity_io sd_output; -struct v4l2_mc_io remote_input; +struct v4l2_entity_pad sd_pad;v4l2_std_id std;int input;int output;
@@ -1604,7 +1603,8 @@ static int saa711x_probe(struct i2c_cliereturn -ENOMEM ; sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &saa711x_ops); -v4l2_entity_prep (&sd->entity,1 , &state->sd_output, &state->remote_input); + state->sd_pad.type =V4L2_PAD_TYPE_OUTPUT ; +v4l2_entity_init (&sd->entity,1 , &state->sd_pad,0 ); state->input =-1 ; state->output =SAA7115_IPORT_ON ; state->enable =1 ;
linux/drivers/media/video/saa7127.c +3 -3
@@ -238,8 +238,7 @@ static struct i2c_reg_value saa7127_initstruct saa7127_state {struct v4l2_subdev sd; -struct v4l2_entity_io sd_input; -struct v4l2_mc_io remote_output; +struct v4l2_entity_pad sd_pad;v4l2_std_id std;u32 ident;enum saa7127_input_type input_type;
@@ -740,7 +739,8 @@ static int saa7127_probe(struct i2c_clie sd = &state->sd;v4l2_i2c_subdev_init (sd, client, &saa7127_ops); -v4l2_entity_prep (&sd->entity,1 , &state->sd_input, &state->remote_output); + state->sd_pad.type =V4L2_PAD_TYPE_OUTPUT ; +v4l2_entity_init (&sd->entity,1 , &state->sd_pad,0 );/* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0.
linux/drivers/media/video/tuner-core.c +3 -3
@@ -80,8 +80,7 @@ struct tuner {struct dvb_frontend fe;struct i2c_client *i2c;struct v4l2_subdev sd; -struct v4l2_entity_io sd_output; -struct v4l2_mc_io remote_input; +struct v4l2_entity_pad sd_pad;struct list_head list; unsigned int using_v4l2:1;
@@ -1041,7 +1040,8 @@ static int tuner_probe(struct i2c_clientif (NULL == t)return -ENOMEM ;v4l2_i2c_subdev_init (&t->sd, client, &tuner_ops); -v4l2_entity_prep (&t->sd.entity,1 , &t->sd_output, &t->remote_input); + t->sd_pad.type =V4L2_PAD_TYPE_OUTPUT ; +v4l2_entity_init (&t->sd.entity,1 , &t->sd_pad,0 ); t->i2c = client; t->name ="(tuner unset)" ; t->type =UNSET ;
linux/drivers/media/video/v4l2-device.c +24 -27
81 lines not on this page · raw message
linux/drivers/media/video/v4l2-mc.c new file +118 -0
118 lines not on this page · raw message
linux/include/linux/videodev2.h +14 -15
@@ -1557,14 +1557,9 @@ struct v4l2_dbg_chip_ident {#define V4L2_PAD_TYPE_INPUT 1#define V4L2_PAD_TYPE_OUTPUT 2 -struct v4l2_mc_io { +struct v4l2_mc_pad {__u32 entity;/* entity ID */ -__u8 pad;/* pad index */ -__u8 active;/* link is active */ -}; - -struct v4l2_mc_io_status { -__u8 nr_of_remote_pads; +__u32 index;/* pad index */ __u32 type;/* pad type */ };
@@ -1575,7 +1570,7 @@ struct v4l2_mc_entity {__u32 type;__u32 subtype;__u8 pads; -__u32 total_possible_links; +__u32 links;union {/* Node specifications */
@@ -1595,17 +1590,21 @@ struct v4l2_mc_entity { }; }; +#define V4L2_LINK_FLAG_ACTIVE (1 << 0) +#define V4L2_LINK_FLAG_PERMANENT (1 << 1) + +struct v4l2_mc_link { +struct v4l2_mc_pad source; +struct v4l2_mc_pad sink; +__u32 flags; +}; +struct v4l2_mc_ios {__u32 entity;/* Should have enough room for pads elements */ -struct v4l2_mc_io_status *status; +struct v4l2_mc_pad *pads;/* Should have enough room for total_possible_links elements */ -struct v4l2_mc_io *remote_pads; -}; - -struct v4l2_mc_link { -struct v4l2_mc_io source; -struct v4l2_mc_io sink; +struct v4l2_mc_link *links; };/*
linux/include/media/v4l2-mc.h +29 -43
87 lines not on this page · raw message
v4l2-apps/util/v4l2-mc.cpp +37 -42
123 lines not on this page · raw message
PATCH 6/14 v4l-mc: Remove subdev v4l2_dev field
In reply to [email protected]A pointer to the v4l2_device is stored in the v4l2_entity structure that v4l2_subdev derives from. There is no need to hold an extra copy of the pointer.
linux/include/media/v4l2-subdev.h +2 -4
@@ -261,7 +261,6 @@ struct v4l2_subdev {struct v4l2_entity entity;struct module *owner;u32 flags; -struct v4l2_device *v4l2_dev;const struct v4l2_subdev_ops *ops;/* name must be unique */ char name[V4L2_SUBDEV_NAME_SIZE ];
@@ -290,7 +289,6 @@ static inline void v4l2_subdev_init(stru sd->entity.subtype =V4L2_SUBDEV_TYPE_MISC ; sd->entity.name = sd->name; sd->ops = ops; - sd->v4l2_dev =NULL ; sd->flags =0 ; sd->name[0 ] ='\0' ; sd->grp_id =0 ;
@@ -308,7 +306,7 @@ static inline void v4l2_subdev_init(stru/* Send a notification to v4l2_device. */ #define v4l2_subdev_notify (sd, notification, arg) \ - ((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \ - (sd)->v4l2_dev->notify((sd), (notification), (arg))) + ((!(sd) || !(sd)->entity.parent || !(sd)->entity.parent->notify) ? \ + -ENODEV : (sd)->entity.parent->notify((sd), (notification), (arg)))#endif
linux/drivers/media/video/bt819.c +2 -2
@@ -256,7 +256,7 @@ static int bt819_s_std(struct v4l2_subdev4l2_dbg (1 , debug, sd,"set norm %llx\n" , (unsigned long long )std); -if (sd->v4l2_dev ==NULL || sd->v4l2_dev->notify ==NULL ) +if (sd->entity.parent ==NULL || sd->entity.parent->notify ==NULL )v4l2_err (sd,"no notify found!\n" );if (std &V4L2_STD_NTSC ) {
@@ -308,7 +308,7 @@ static int bt819_s_routing(struct v4l2_sif (input <0 || input >7 )return -EINVAL ; -if (sd->v4l2_dev ==NULL || sd->v4l2_dev->notify ==NULL ) +if (sd->entity.parent ==NULL || sd->entity.parent->notify ==NULL )v4l2_err (sd,"no notify found!\n" );if (decoder->input != input) {
linux/drivers/media/video/v4l2-device.c +6 -6
@@ -333,10 +333,10 @@ int v4l2_device_register_subdev(struct vif (v4l2_dev ==NULL || sd ==NULL || !sd->name[0 ])return -EINVAL ;/* Warn if we apparently re-register a subdev */ -WARN_ON (sd->v4l2_dev !=NULL ); +WARN_ON (sd->entity.parent !=NULL );if (!try_module_get (sd->owner))return -ENODEV ; - sd->v4l2_dev = v4l2_dev; + sd->entity.parent = v4l2_dev;spin_lock (&v4l2_dev->lock); sd->entity.id = v4l2_dev->subdev_id++;list_add_tail (&sd->entity.list, &v4l2_dev->subdevs);
@@ -348,12 +348,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_register_svoid v4l2_device_unregister_subdev (struct v4l2_subdev *sd) {/* return if it isn't registered */ -if (sd ==NULL || sd->v4l2_dev ==NULL ) +if (sd ==NULL || sd->entity.parent ==NULL )return ; -spin_lock (&sd->v4l2_dev->lock); +spin_lock (&sd->entity.parent->lock);list_del (&sd->entity.list); -spin_unlock (&sd->v4l2_dev->lock); - sd->v4l2_dev =NULL ; +spin_unlock (&sd->entity.parent->lock); + sd->entity.parent =NULL ;module_put (sd->owner); }EXPORT_SYMBOL_GPL (v4l2_device_unregister_subdev);
linux/drivers/media/video/zoran/zoran_card.c +1 -1
@@ -1196,7 +1196,7 @@ zoran_setup_videocodec (struct zoran *zrstatic void zoran_subdev_notify (struct v4l2_subdev *sd,unsigned int cmd,void *arg) { -struct zoran *zr =to_zoran (sd->v4l2_dev); +struct zoran *zr =to_zoran (sd->entity.parent);/* Bt819 needs to reset its FIFO buffer using #FRST pin and LML33 card uses GPIO(7) for that. */
PATCH 7/14 v4l-mc: Remove devnode v4l2_dev field
In reply to [email protected]A pointer to the v4l2_device is stored in the v4l2_entity structure that video_device derives from. There is no need to hold an extra copy of the pointer.
linux/drivers/media/radio/dsbr100.c +1 -1
@@ -657,7 +657,7 @@ static int usb_dsbr100_probe(struct usb_ }strlcpy (radio->videodev.name, v4l2_dev->name,sizeof (radio->videodev.name)); - radio->videodev.v4l2_dev = v4l2_dev; + radio->videodev.entity.parent = v4l2_dev; radio->videodev.fops = &usb_dsbr100_fops; radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; radio->videodev.release = usb_dsbr100_video_device_release;
linux/drivers/media/radio/radio-gemtek-pci.c +1 -1
@@ -414,7 +414,7 @@ static int __devinit gemtek_pci_probe(st }strlcpy (card->vdev.name, v4l2_dev->name,sizeof (card->vdev.name)); - card->vdev.v4l2_dev = v4l2_dev; + card->vdev.entity.parent = v4l2_dev; card->vdev.fops = &gemtek_pci_fops; card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops; card->vdev.release = video_device_release_empty;
linux/drivers/media/radio/radio-maestro.c +1 -1
@@ -373,7 +373,7 @@ static int __devinit maestro_probe(struc dev->io =pci_resource_start (pdev,0 ) +GPIO_DATA ;strlcpy (dev->vdev.name, v4l2_dev->name,sizeof (dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.entity.parent = v4l2_dev; dev->vdev.fops = &maestro_fops; dev->vdev.ioctl_ops = &maestro_ioctl_ops; dev->vdev.release = video_device_release_empty;
linux/drivers/media/radio/radio-maxiradio.c +1 -1
@@ -397,7 +397,7 @@ static int __devinit maxiradio_init_one( dev->io =pci_resource_start (pdev,0 );strlcpy (dev->vdev.name, v4l2_dev->name,sizeof (dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.entity.parent = v4l2_dev; dev->vdev.fops = &maxiradio_fops; dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; dev->vdev.release = video_device_release_empty;
linux/drivers/media/radio/radio-mr800.c +1 -1
@@ -700,7 +700,7 @@ static int usb_amradio_probe(struct usb_ }strlcpy (radio->videodev->name, v4l2_dev->name,sizeof (radio->videodev->name)); - radio->videodev->v4l2_dev = v4l2_dev; + radio->videodev->entity.parent = v4l2_dev; radio->videodev->fops = &usb_amradio_fops; radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops; radio->videodev->release = usb_amradio_video_device_release;
linux/drivers/media/video/bt8xx/bttv-driver.c +1 -1
@@ -4204,7 +4204,7 @@ static struct video_device *vdev_init(stif (NULL == vfd)return NULL ; *vfd = *template; - vfd->v4l2_dev = &btv->c.v4l2_dev; + vfd->entity.parent = &btv->c.v4l2_dev; vfd->release = video_device_release; vfd->debug = bttv_debug;video_set_drvdata (vfd, btv);
linux/drivers/media/video/cafe_ccic.c +1 -1
@@ -1972,7 +1972,7 @@ static int cafe_pci_probe(struct pci_dev cam->vdev = cafe_v4l_template; cam->vdev.debug =0 ;/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/ - cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.entity.parent = &cam->v4l2_dev; ret =video_register_device (&cam->vdev,VFL_TYPE_GRABBER ,-1 );if (ret) goto out_smbus;
linux/drivers/media/video/cx18/cx18-streams.c +1 -1
@@ -182,7 +182,7 @@ static int cx18_prep_dev(struct cx18 *cx cx->v4l2_dev.name, s->name); s->video_dev->num = num; - s->video_dev->v4l2_dev = &cx->v4l2_dev; + s->video_dev->entity.parent = &cx->v4l2_dev; s->video_dev->fops = &cx18_v4l2_enc_fops; s->video_dev->release = video_device_release; s->video_dev->tvnorms =V4L2_STD_ALL ;
linux/drivers/media/video/cx231xx/cx231xx-video.c +1 -1
@@ -2320,7 +2320,7 @@ static struct video_device *cx231xx_vdev *vfd = *template; vfd->minor =-1 ; - vfd->v4l2_dev = &dev->v4l2_dev; + vfd->entity.parent = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug;
linux/drivers/media/video/cx23885/cx23885-video.c +1 -1
@@ -353,7 +353,7 @@ static struct video_device *cx23885_vdevreturn NULL ; *vfd = *template; vfd->minor =-1 ; - vfd->v4l2_dev = &dev->v4l2_dev; + vfd->entity.parent = &dev->v4l2_dev; vfd->release = video_device_release;snprintf (vfd->name,sizeof (vfd->name),"%s %s (%s)" , dev->name, type, cx23885_boards[dev->board].name);
linux/drivers/media/video/cx88/cx88-core.c +1 -1
@@ -1057,7 +1057,7 @@ struct video_device *cx88_vdev_init(struif (NULL == vfd)return NULL ; *vfd = *template; - vfd->v4l2_dev = &core->v4l2_dev; + vfd->entity.parent = &core->v4l2_dev; vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
linux/drivers/media/video/em28xx/em28xx-video.c +1 -1
@@ -2154,7 +2154,7 @@ static struct video_device *em28xx_vdev_ *vfd = *template; vfd->minor =-1 ; - vfd->v4l2_dev = &dev->v4l2_dev; + vfd->entity.parent = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug;
linux/drivers/media/video/ivtv/ivtv-streams.c +1 -1
@@ -207,7 +207,7 @@ static int ivtv_prep_dev(struct ivtv *it itv->v4l2_dev.name, s->name); s->vdev->num = num; - s->vdev->v4l2_dev = &itv->v4l2_dev; + s->vdev->entity.parent = &itv->v4l2_dev; s->vdev->fops = ivtv_stream_info[type].fops; s->vdev->release = video_device_release; s->vdev->tvnorms =V4L2_STD_ALL ;
linux/drivers/media/video/saa7134/saa7134-core.c +1 -1
@@ -853,7 +853,7 @@ static struct video_device *vdev_init(stif (NULL == vfd)return NULL ; *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; + vfd->entity.parent = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
linux/drivers/media/video/usbvision/usbvision-video.c +1 -1
@@ -1406,7 +1406,7 @@ static struct video_device *usbvision_vd } *vdev = *vdev_template;// vdev->minor = -1; - vdev->v4l2_dev = &usbvision->v4l2_dev; + vdev->entity.parent = &usbvision->v4l2_dev;snprintf (vdev->name,sizeof (vdev->name),"%s" , name);video_set_drvdata (vdev, usbvision);return vdev;
linux/drivers/media/video/v4l2-dev.c +4 -4
@@ -439,8 +439,8 @@ int video_register_device(struct video_d vdev->vfl_type = type; vdev->cdev =NULL ; -if (vdev->v4l2_dev && vdev->v4l2_dev->dev) - vdev->parent = vdev->v4l2_dev->dev; +if (vdev->entity.parent && vdev->entity.parent->dev) + vdev->parent = vdev->entity.parent->dev;/* Part 2: find a free minor, kernel number and device index. */ #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
@@ -573,13 +573,13 @@ int video_register_device(struct video_dreference to the device goes away. */ vdev->dev.release = v4l2_device_release; -if (vdev->v4l2_dev) { +if (vdev->entity.parent) { vdev->entity.type =V4L2_ENTITY_TYPE_NODE ; vdev->entity.subtype =V4L2_NODE_TYPE_V4L ; vdev->entity.v4l.major =VIDEO_MAJOR ; vdev->entity.v4l.minor = vdev->minor; vdev->entity.name = vdev->name; - ret =v4l2_device_register_node (vdev->v4l2_dev, vdev); + ret =v4l2_device_register_node (vdev->entity.parent, vdev);if (ret <0 )printk (KERN_ERR "error\n" );/* TODO */ }
linux/drivers/media/video/v4l2-device.c +11 -11
@@ -196,10 +196,10 @@ static long mc_ioctl(struct file *filp,switch (cmd) {case VIDIOC_MC_ENUM_ENTITIES : -return mc_enum_entities (vdev->v4l2_dev, (struct v4l2_mc_entity __user *)arg); +return mc_enum_entities (vdev->entity.parent, (struct v4l2_mc_entity __user *)arg);case VIDIOC_MC_ENUM_LINKS : -return mc_enum_links (vdev->v4l2_dev, (struct v4l2_mc_ios __user *)arg); +return mc_enum_links (vdev->entity.parent, (struct v4l2_mc_ios __user *)arg);case VIDIOC_MC_G_ENTITY : id = fh->ent ? fh->ent->id :0 ;
@@ -208,17 +208,17 @@ static long mc_ioctl(struct file *filp,case VIDIOC_MC_S_ENTITY :if (copy_from_user (&id, uarg,sizeof (*uarg)))return -EFAULT ; - ent =find_entity (vdev->v4l2_dev, id); + ent =find_entity (vdev->entity.parent, id);if (ent ==NULL )return -EINVAL ; fh->ent = ent;break ;case VIDIOC_MC_MAKE_LINK : -return mc_make_link (vdev->v4l2_dev, (struct v4l2_mc_link __user *)arg); +return mc_make_link (vdev->entity.parent, (struct v4l2_mc_link __user *)arg);case VIDIOC_MC_DELETE_LINK : -return mc_delete_link (vdev->v4l2_dev, (struct v4l2_mc_link __user *)arg); +return mc_delete_link (vdev->entity.parent, (struct v4l2_mc_link __user *)arg);default :if (fh->ent ==NULL || fh->ent->ioctl ==NULL )
@@ -264,7 +264,7 @@ int v4l2_device_register(struct device * vdev = &v4l2_dev->mc;snprintf (vdev->name,sizeof (vdev->name),"media controller" ); - vdev->v4l2_dev = v4l2_dev; + vdev->entity.parent = v4l2_dev; vdev->fops = &mc_fops; vdev->release = video_device_release_empty;return video_register_device (vdev,VFL_TYPE_MC ,-1 );
@@ -363,7 +363,7 @@ int v4l2_device_register_node(struct v4l/* Check for valid input */ if (v4l2_dev ==NULL || vdev ==NULL )return -EINVAL ; - vdev->v4l2_dev = v4l2_dev; + vdev->entity.parent = v4l2_dev;spin_lock (&v4l2_dev->lock); vdev->entity.id = v4l2_dev->devnode_id++;list_add_tail (&vdev->entity.list, &v4l2_dev->devnodes);
@@ -375,12 +375,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_register_nvoid v4l2_device_unregister_node (struct video_device *vdev) {/* return if it isn't registered */ -if (vdev ==NULL || vdev->v4l2_dev ==NULL ) +if (vdev ==NULL || vdev->entity.parent ==NULL )return ; -spin_lock (&vdev->v4l2_dev->lock); +spin_lock (&vdev->entity.parent->lock);list_del (&vdev->entity.list); -spin_unlock (&vdev->v4l2_dev->lock); - vdev->v4l2_dev =NULL ; +spin_unlock (&vdev->entity.parent->lock); + vdev->entity.parent =NULL ; }EXPORT_SYMBOL_GPL (v4l2_device_unregister_node);
linux/drivers/media/video/w9968cf.c +1 -1
@@ -3502,7 +3502,7 @@ w9968cf_usb_probe(struct usb_interface* cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release;video_set_drvdata (cam->v4ldev, cam); - cam->v4ldev->v4l2_dev = &cam->v4l2_dev; + cam->v4ldev->entity.parent = &cam->v4l2_dev; err =video_register_device (cam->v4ldev,VFL_TYPE_GRABBER , video_nr[dev_nr]);
linux/include/media/v4l2-dev.h +1 -3
@@ -29,7 +29,6 @@struct v4l2_ioctl_callbacks ;struct video_device ;struct v4l2_alsa_device ; -struct v4l2_device ;/* Flag to mark the video_device struct as unregistered. Drivers can set this flag if they want to block all future
@@ -71,9 +70,8 @@ struct video_device#endif struct cdev *cdev;/* character device */ -/* Set either parent or v4l2_dev if your driver uses v4l2_device */ +/* Set either parent or entity.parent if your driver uses v4l2_device */ struct device *parent;/* device parent */ -struct v4l2_device *v4l2_dev;/* v4l2_device parent */ /* device info */ char name[32 ];
PATCH 8/14 uvcvideo: Rely on videodev to reference-count the device
In reply to [email protected]The uvcvideo driver has a driver-wide lock and a reference count to protect against a disconnect/open race. Now that videodev handles the race itself, reference-counting in the driver can be removed.
This is a backport from the v4l-dvb tree.
linux/drivers/media/video/uvc/uvc_driver.c +79 -76
@@ -1531,22 +1531,92 @@*/ /* +* Delete the UVC device. +* +* Called by the kernel when the last reference to the uvc_device structure +* is released. +* +* As this function is called after or during disconnect(), all URBs have +* already been canceled by the USB core. There is no need to kill the +* interrupt URB manually. +*/ +static void uvc_delete (struct uvc_device *dev) +{ +struct list_head *p, *n; + +usb_put_intf (dev->intf); +usb_put_dev (dev->udev); + +uvc_status_cleanup (dev); +uvc_ctrl_cleanup_device (dev); + +list_for_each_safe (p, n, &dev->chains) { +struct uvc_video_chain *chain; + chain = list_entry(p, struct uvc_video_chain, list); +kfree (chain); + } + +list_for_each_safe (p, n, &dev->entities) { +struct uvc_entity *entity; + entity = list_entry(p, struct uvc_entity, list); +kfree (entity); + } + +list_for_each_safe (p, n, &dev->streams) { +struct uvc_streaming *streaming; + streaming = list_entry(p, struct uvc_streaming, list); +usb_driver_release_interface (&uvc_driver.driver, + streaming->intf); +usb_put_intf (streaming->intf); +kfree (streaming->format); +kfree (streaming->header.bmaControls); +kfree (streaming); + } + +kfree (dev); +} + +static void uvc_release (struct video_device *vdev) +{ +struct uvc_streaming *stream =video_get_drvdata (vdev); +struct uvc_device *dev = stream->dev; + +video_device_release (vdev); + +/* Decrement the registered streams count and delete the device when it +* reaches zero. +*/ +if (atomic_dec_and_test (&dev->nstreams)) +uvc_delete (dev); +} + +/* * Unregister the video devices. */ static void uvc_unregister_video (struct uvc_device *dev) {struct uvc_streaming *stream; +/* Unregistering all video devices might result in uvc_delete() being +* called from inside the loop if there's no open file handle. To avoid +* that, increment the stream count before iterating over the streams +* and decrement it when done. +*/ +atomic_inc (&dev->nstreams); +list_for_each_entry (stream, &dev->streams, list) {if (stream->vdev ==NULL )continue ; -if (stream->vdev->minor ==-1 ) -video_device_release (stream->vdev); -else -video_unregister_device (stream->vdev); +video_unregister_device (stream->vdev); stream->vdev =NULL ; } + +/* Decrement the stream count and call uvc_delete explicitly if there +* are no stream left. +*/ +if (atomic_dec_and_test (&dev->nstreams)) +uvc_delete (dev); } static int uvc_register_video(struct uvc_device *dev,
@@ -1580,7 +1650,7 @@ vdev->parent = &dev->intf->dev; vdev->minor =-1 ; vdev->fops = &uvc_fops; - vdev->release = video_device_release; + vdev->release = uvc_release;strlcpy (vdev->name, dev->name,sizeof vdev->name);/* Set the driver data before calling video_register_device, otherwise
@@ -1598,6 +1668,7 @@return ret; } +atomic_inc (&dev->nstreams);return 0 ; }
@@ -1653,61 +1724,6 @@* USB probe, disconnect, suspend and resume */ -/* -* Delete the UVC device. -* -* Called by the kernel when the last reference to the uvc_device structure -* is released. -* -* Unregistering the video devices is done here because every opened instance -* must be closed before the device can be unregistered. An alternative would -* have been to use another reference count for uvc_v4l2_open/uvc_release, and -* unregister the video devices on disconnect when that reference count drops -* to zero. -* -* As this function is called after or during disconnect(), all URBs have -* already been canceled by the USB core. There is no need to kill the -* interrupt URB manually. -*/ -void uvc_delete (struct kref *kref) -{ - struct uvc_device *dev = container_of(kref, struct uvc_device, kref); -struct list_head *p, *n; - -/* Unregister the video devices. */ -uvc_unregister_video (dev); -usb_put_intf (dev->intf); -usb_put_dev (dev->udev); - -uvc_status_cleanup (dev); -uvc_ctrl_cleanup_device (dev); - -list_for_each_safe (p, n, &dev->chains) { -struct uvc_video_chain *chain; - chain = list_entry(p, struct uvc_video_chain, list); -kfree (chain); - } - -list_for_each_safe (p, n, &dev->entities) { -struct uvc_entity *entity; - entity = list_entry(p, struct uvc_entity, list); -kfree (entity); - } - -list_for_each_safe (p, n, &dev->streams) { -struct uvc_streaming *streaming; - streaming = list_entry(p, struct uvc_streaming, list); -usb_driver_release_interface (&uvc_driver.driver, - streaming->intf); -usb_put_intf (streaming->intf); -kfree (streaming->format); -kfree (streaming->header.bmaControls); -kfree (streaming); - } - -kfree (dev); -} -static int uvc_probe (struct usb_interface *intf,const struct usb_device_id *id) {
@@ -1730,7 +1746,7 @@INIT_LIST_HEAD (&dev->entities);INIT_LIST_HEAD (&dev->chains);INIT_LIST_HEAD (&dev->streams); -kref_init (&dev->kref); +atomic_set (&dev->nstreams,0 );atomic_set (&dev->users,0 ); dev->udev =usb_get_dev (udev);
@@ -1792,7 +1808,7 @@return 0 ; error: -kref_put (&dev->kref, uvc_delete); +uvc_unregister_video (dev);return -ENODEV ; }
@@ -1809,21 +1825,9 @@ UVC_SC_VIDEOSTREAMING)return ; -/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide -* lock is needed to prevent uvc_disconnect from releasing its -* reference to the uvc_device instance after uvc_v4l2_open() received -* the pointer to the device (video_devdata) but before it got the -* chance to increase the reference count (kref_get). -* -* Note that the reference can't be released with the lock held, -* otherwise a AB-BA deadlock can occur with videodev_lock that -* videodev acquires in videodev_open() and video_unregister_device(). -*/ -mutex_lock (&uvc_driver.open_mutex); dev->state |=UVC_DEV_DISCONNECTED ; -mutex_unlock (&uvc_driver.open_mutex); -kref_put (&dev->kref, uvc_delete); +uvc_unregister_video (dev); }static int uvc_suspend (struct usb_interface *intf,pm_message_t message)
@@ -2165,7 +2169,6 @@INIT_LIST_HEAD (&uvc_driver.devices);INIT_LIST_HEAD (&uvc_driver.controls); -mutex_init (&uvc_driver.open_mutex);mutex_init (&uvc_driver.ctrl_mutex);uvc_ctrl_init ();
linux/drivers/media/video/uvc/uvc_v4l2.c +8 -24
@@ -376,25 +376,18 @@*/ static int uvc_acquire_privileges (struct uvc_fh *handle) { -int ret =0 ; -/* Always succeed if the handle is already privileged. */ if (handle->state ==UVC_HANDLE_ACTIVE )return 0 ;/* Check if the device already has a privileged handle. */ -mutex_lock (&uvc_driver.open_mutex);if (atomic_inc_return (&handle->stream->active) !=1 ) {atomic_dec (&handle->stream->active); - ret = -EBUSY ; - goto done; +return -EBUSY ; } handle->state =UVC_HANDLE_ACTIVE ; - -done: -mutex_unlock (&uvc_driver.open_mutex); -return ret; +return 0 ; }static void uvc_dismiss_privileges (struct uvc_fh *handle)
@@ -421,18 +414,15 @@int ret =0 ;uvc_trace (UVC_TRACE_CALLS ,"uvc_v4l2_open\n" ); -mutex_lock (&uvc_driver.open_mutex); stream =video_drvdata (file); -if (stream->dev->state &UVC_DEV_DISCONNECTED ) { - ret = -ENODEV ; - goto done; - } +if (stream->dev->state &UVC_DEV_DISCONNECTED ) +return -ENODEV ;#if LINUX_VERSION_CODE >=KERNEL_VERSION (2 ,6 ,19 ) ret =usb_autopm_get_interface (stream->dev->intf);if (ret <0 ) - goto done; +return ret;#endif /* Create the device handle. */
@@ -441,8 +431,7 @@#if LINUX_VERSION_CODE >=KERNEL_VERSION (2 ,6 ,19 )usb_autopm_put_interface (stream->dev->intf);#endif - ret = -ENOMEM ; - goto done; +return -ENOMEM ; }if (atomic_inc_return (&stream->dev->users) ==1 ) {
@@ -453,7 +442,7 @@#endif atomic_dec (&stream->dev->users);kfree (handle); - goto done; +return ret; } }
@@ -462,11 +451,7 @@ handle->state =UVC_HANDLE_PASSIVE ; file->private_data = handle; -kref_get (&stream->dev->kref); - -done: -mutex_unlock (&uvc_driver.open_mutex); -return ret; +return 0 ; }static int uvc_v4l2_release (struct file *file)
@@ -498,7 +483,6 @@#if LINUX_VERSION_CODE >=KERNEL_VERSION (2 ,6 ,19 )usb_autopm_put_interface (stream->dev->intf);#endif -kref_put (&stream->dev->kref, uvc_delete);return 0 ; }
linux/drivers/media/video/uvc/uvcvideo.h +1 -4
@@ -476,7 +476,6 @@char name[32 ];enum uvc_device_state state; -struct kref kref;struct list_head list;atomic_t users;
@@ -489,6 +488,7 @@/* Video Streaming interfaces */ struct list_head streams; +atomic_t nstreams;/* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep;
@@ -512,8 +512,6 @@struct uvc_driver {struct usb_driver driver; -struct mutex open_mutex;/* protects from open/disconnect race */ -struct list_head devices;/* struct uvc_device list */ struct list_head controls;/* struct uvc_control_info list */ struct mutex ctrl_mutex;/* protects controls and devices
@@ -572,7 +570,6 @@/* Core driver */ extern struct uvc_driver uvc_driver; -extern void uvc_delete (struct kref *kref);/* Video buffers queue management. */ extern void uvc_queue_init(struct uvc_video_queue *queue,
PATCH 9/14 uvcvideo: Merge iterms, oterms and extensions linked lists
In reply to [email protected]All terminals and units are now added to a single linked list of entities per chain. This makes terminals and units handling code more generic.
linux/drivers/media/video/uvc/uvc_ctrl.c +5 -24
@@ -744,17 +744,7 @@ struct uvc_control *uvc_find_control(str v4l2_id &=V4L2_CTRL_ID_MASK ;/* Find the control. */ -__uvc_find_control (chain->processing, v4l2_id, mapping, &ctrl, next); -if (ctrl && !next) -return ctrl; - -list_for_each_entry (entity, &chain->iterms, chain) { -__uvc_find_control (entity, v4l2_id, mapping, &ctrl, next); -if (ctrl && !next) -return ctrl; - } - -list_for_each_entry (entity, &chain->extensions, chain) { +list_for_each_entry (entity, &chain->entities, chain) {__uvc_find_control (entity, v4l2_id, mapping, &ctrl, next);if (ctrl && !next)return ctrl;
@@ -946,17 +936,7 @@ int __uvc_ctrl_commit(struct uvc_video_cint ret =0 ;/* Find the control. */ - ret =uvc_ctrl_commit_entity (chain->dev, chain->processing, rollback); -if (ret <0 ) - goto done; - -list_for_each_entry (entity, &chain->iterms, chain) { - ret =uvc_ctrl_commit_entity (chain->dev, entity, rollback); -if (ret <0 ) - goto done; - } - -list_for_each_entry (entity, &chain->extensions, chain) { +list_for_each_entry (entity, &chain->entities, chain) { ret =uvc_ctrl_commit_entity (chain->dev, entity, rollback);if (ret <0 ) goto done;
@@ -1070,8 +1050,9 @@ int uvc_xu_ctrl_query(struct uvc_video_cint ret;/* Find the extension unit. */ -list_for_each_entry (entity, &chain->extensions, chain) { -if (entity->id == xctrl->unit) +list_for_each_entry (entity, &chain->entities, chain) { +if (UVC_ENTITY_TYPE (entity) ==UVC_VC_EXTENSION_UNIT && + entity->id == xctrl->unit)break ; }
linux/drivers/media/video/uvc/uvc_driver.c +22 -26
140 lines not on this page · raw message
linux/drivers/media/video/uvc/uvcvideo.h +2 -3
@@ -76,6 +76,7 @@ struct uvc_xu_control {#define UVC_TERM_INPUT 0x0000#define UVC_TERM_OUTPUT 0x8000 +#define UVC_TERM_DIRECTION (term) ((term)->type & 0x8000)#define UVC_ENTITY_TYPE (entity) ((entity)->type & 0x7fff)#define UVC_ENTITY_IS_UNIT (entity) (((entity)->type & 0xff00) == 0)
@@ -409,11 +410,9 @@ struct uvc_video_chain {struct uvc_device *dev;struct list_head list; -struct list_head iterms;/* Input terminals */ -struct list_head oterms;/* Output terminals */ +struct list_head entities;/* All entities */ struct uvc_entity *processing;/* Processing unit */ struct uvc_entity *selector;/* Selector unit */ -struct list_head extensions;/* Extension units */ struct mutex ctrl_mutex; };
linux/drivers/media/video/uvc/uvc_v4l2.c +7 -3
@@ -628,12 +628,16 @@ static long uvc_v4l2_do_ioctl(struct fil (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {if (index !=0 )return -EINVAL ; - iterm =list_first_entry (&chain->iterms, - struct uvc_entity, chain); +list_for_each_entry (iterm, &chain->entities, chain) { +if (UVC_ENTITY_IS_ITERM (iterm)) +break ; + } pin = iterm->id; } else if (pin < selector->selector.bNrInPins) { pin = selector->selector.baSourceID[index]; -list_for_each_entry (iterm, chain->iterms.next, chain) { +list_for_each_entry (iterm, &chain->entities, chain) { +if (!UVC_ENTITY_IS_ITERM (iterm)) +continue ;if (iterm->id == pin)break ; }
PATCH 10/14 uvcvideo: Fix extension units parsing
In reply to [email protected]The bNrInPins field is an 8 bit integer, not a 16 bit integer.
linux/drivers/media/video/uvc/uvc_driver.c +2 -2
@@ -835,7 +835,7 @@ static int uvc_parse_vendor_control(stru unit->type =UVC_VC_EXTENSION_UNIT ;memcpy (unit->extension.guidExtensionCode, &buffer[4 ],16 ); unit->extension.bNumControls = buffer[20 ]; - unit->extension.bNrInPins =get_unaligned_le16 (&buffer[21 ]); + unit->extension.bNrInPins = buffer[21 ]; unit->extension.baSourceID = (__u8 *)unit +sizeof *unit;memcpy (unit->extension.baSourceID, &buffer[22 ], p); unit->extension.bControlSize = buffer[22 +p];
@@ -1099,7 +1099,7 @@ static int uvc_parse_standard_control(st unit->type = buffer[2 ];memcpy (unit->extension.guidExtensionCode, &buffer[4 ],16 ); unit->extension.bNumControls = buffer[20 ]; - unit->extension.bNrInPins =get_unaligned_le16 (&buffer[21 ]); + unit->extension.bNrInPins = buffer[21 ]; unit->extension.baSourceID = (__u8 *)unit +sizeof *unit;memcpy (unit->extension.baSourceID, &buffer[22 ], p); unit->extension.bControlSize = buffer[22 +p];
PATCH 11/14 uvcvideo: Refactor chain scan
In reply to [email protected]Don't handle the first output terminal in a chain in a special way. Use uvc_scan_chain_entity() like for all other entities, making the chain scan code more generic.
linux/drivers/media/video/uvc/uvc_driver.c +43 -32
@@ -1256,13 +1256,12 @@ static int uvc_scan_chain_entity(structbreak ;case UVC_TT_STREAMING : -if (uvc_trace_param &UVC_TRACE_PROBE ) -printk (" <- IT %d\n" , entity->id); - -if (!UVC_ENTITY_IS_ITERM (entity)) { -uvc_trace (UVC_TRACE_DESCR ,"Unsupported input " -"terminal %u.\n" , entity->id); -return -1 ; +if (UVC_ENTITY_IS_ITERM (entity)) { +if (uvc_trace_param &UVC_TRACE_PROBE ) +printk (" <- IT %d\n" , entity->id); + }else { +if (uvc_trace_param &UVC_TRACE_PROBE ) +printk (" OT %d" , entity->id); }break ;
@@ -1342,10 +1341,11 @@ static int uvc_scan_chain_forward(struct }static int uvc_scan_chain_backward (struct uvc_video_chain *chain, -struct uvc_entity *entity) +struct uvc_entity **_entity) { +struct uvc_entity *entity = *_entity;struct uvc_entity *term; -int id =-1 , i; +int id = -EINVAL , i;switch (UVC_ENTITY_TYPE (entity)) {case UVC_VC_EXTENSION_UNIT :
@@ -1389,34 +1389,49 @@ static int uvc_scan_chain_backward(struc id =0 ;break ; + +case UVC_ITT_VENDOR_SPECIFIC : +case UVC_ITT_CAMERA : +case UVC_ITT_MEDIA_TRANSPORT_INPUT : +case UVC_OTT_VENDOR_SPECIFIC : +case UVC_OTT_DISPLAY : +case UVC_OTT_MEDIA_TRANSPORT_OUTPUT : +case UVC_TT_STREAMING : + id =UVC_ENTITY_IS_OTERM (entity) ? entity->output.bSourceID :0 ; +break ; + } + +if (id <=0 ) { + *_entity =NULL ; +return id; + } + + entity =uvc_entity_by_id (chain->dev, id); +if (entity ==NULL ) { +uvc_trace (UVC_TRACE_DESCR ,"Found reference to " +"unknown entity %d.\n" , id); +return -EINVAL ; } -return id; + *_entity = entity; +return 0 ; }static int uvc_scan_chain (struct uvc_video_chain *chain, -struct uvc_entity *oterm) +struct uvc_entity *term) {struct uvc_entity *entity, *prev; -int id; - entity = oterm; -list_add_tail (&entity->chain, &chain->entities); -uvc_trace (UVC_TRACE_PROBE ,"Scanning UVC chain: OT %d" , entity->id); +uvc_trace (UVC_TRACE_PROBE ,"Scanning UVC chain:" ); - id = entity->output.bSourceID; -while (id !=0 ) { - prev = entity; - entity =uvc_entity_by_id (chain->dev, id); -if (entity ==NULL ) { -uvc_trace (UVC_TRACE_DESCR ,"Found reference to " -"unknown entity %d.\n" , id); -return -EINVAL ; - } + entity = term; + prev =NULL ; +while (entity !=NULL ) { +/* Entity must not be part of an existing chain */ if (entity->chain.next || entity->chain.prev) {uvc_trace (UVC_TRACE_DESCR ,"Found reference to " -"entity %d already in chain.\n" , id); +"entity %d already in chain.\n" , entity->id);return -EINVAL ; }
@@ -1428,14 +1443,10 @@ static int uvc_scan_chain(struct uvc_vidif (uvc_scan_chain_forward (chain, entity, prev) <0 )return -EINVAL ; -/* Stop when a terminal is found. */ -if (UVC_ENTITY_IS_TERM (entity)) -break ; -/* Backward scan */ - id =uvc_scan_chain_backward (chain, entity); -if (id <0 ) -return id; + prev = entity; +if (uvc_scan_chain_backward (chain, &entity) <0 ) +return -EINVAL ; }return 0 ;
PATCH 12/14 uvcvideo: Factorize common field in uvc_entity structure
In reply to [email protected]The bNrInPins and baSourceID fields are common among all entities (some of use bSourceID but this is conceptually the same). Move those two fields out of entity type-specific unions into the uvc_entity structure top level.
linux/drivers/media/video/uvc/uvc_driver.c +51 -68
@@ -248,29 +248,9 @@ static struct uvc_entity *uvc_entity_by_ entity = list_entry(&dev->entities, struct uvc_entity, list);list_for_each_entry_continue (entity, &dev->entities, list) { -switch (UVC_ENTITY_TYPE (entity)) { -case UVC_TT_STREAMING : -if (entity->output.bSourceID == id) +for (i =0 ; i < entity->bNrInPins; ++i) +if (entity->baSourceID[i] == id)return entity; -break ; - -case UVC_VC_PROCESSING_UNIT : -if (entity->processing.bSourceID == id) -return entity; -break ; - -case UVC_VC_SELECTOR_UNIT : -for (i =0 ; i < entity->selector.bNrInPins; ++i) -if (entity->selector.baSourceID[i] == id) -return entity; -break ; - -case UVC_VC_EXTENSION_UNIT : -for (i =0 ; i < entity->extension.bNrInPins; ++i) -if (entity->extension.baSourceID[i] == id) -return entity; -break ; - } }return NULL ;
@@ -776,6 +756,28 @@ error:return ret; } +static struct uvc_entity *uvc_alloc_entity (u16 type,u8 id, +unsigned int num_pads,unsigned int extra_size) +{ +struct uvc_entity *entity; +unsigned int num_inputs; +unsigned int size; + + num_inputs = (type &UVC_TERM_OUTPUT ) ? num_pads : num_pads -1 ; + size =sizeof (*entity) + extra_size + num_inputs; + entity =kzalloc (size,GFP_KERNEL ); +if (entity ==NULL ) +return NULL ; + + entity->id = id; + entity->type = type; + + entity->bNrInPins = num_inputs; + entity->baSourceID = ((__u8 *)entity) +sizeof (*entity) + extra_size; + +return entity; +} +/* Parse vendor-specific extensions. */ static int uvc_parse_vendor_control (struct uvc_device *dev,const unsigned char *buffer,int buflen)
@@ -827,21 +829,18 @@ static int uvc_parse_vendor_control(strubreak ; } - unit =kzalloc (sizeof *unit + p +2 *n,GFP_KERNEL ); + unit =uvc_alloc_entity (UVC_VC_EXTENSION_UNIT , buffer[3 ], + p +1 ,2 *n);if (unit ==NULL )return -ENOMEM ; - unit->id = buffer[3 ]; - unit->type =UVC_VC_EXTENSION_UNIT ;memcpy (unit->extension.guidExtensionCode, &buffer[4 ],16 ); unit->extension.bNumControls = buffer[20 ]; - unit->extension.bNrInPins = buffer[21 ]; - unit->extension.baSourceID = (__u8 *)unit +sizeof *unit; -memcpy (unit->extension.baSourceID, &buffer[22 ], p); +memcpy (unit->baSourceID, &buffer[22 ], p); unit->extension.bControlSize = buffer[22 +p]; - unit->extension.bmControls = (__u8 *)unit +sizeof *unit + p; - unit->extension.bmControlsType = (__u8 *)unit +sizeof *unit - + p + n; + unit->extension.bmControls = (__u8 *)unit +sizeof (*unit); + unit->extension.bmControlsType = (__u8 *)unit +sizeof (*unit) + + n;memcpy (unit->extension.bmControls, &buffer[23 +p],2 *n);if (buffer[24 +p+2 *n] !=0 )
@@ -938,13 +937,11 @@ static int uvc_parse_standard_control(streturn -EINVAL ; } - term =kzalloc (sizeof *term + n + p,GFP_KERNEL ); + term =uvc_alloc_entity (type |UVC_TERM_INPUT , buffer[3 ], +1 , n + p);if (term ==NULL )return -ENOMEM ; - term->id = buffer[3 ]; - term->type = type |UVC_TERM_INPUT ; -if (UVC_ENTITY_TYPE (term) ==UVC_ITT_CAMERA ) { term->camera.bControlSize = n; term->camera.bmControls = (__u8 *)term +sizeof *term;
@@ -999,13 +996,12 @@ static int uvc_parse_standard_control(streturn 0 ; } - term =kzalloc (sizeof *term,GFP_KERNEL ); + term =uvc_alloc_entity (type |UVC_TERM_OUTPUT , buffer[3 ], +1 ,0 );if (term ==NULL )return -ENOMEM ; - term->id = buffer[3 ]; - term->type = type |UVC_TERM_OUTPUT ; - term->output.bSourceID = buffer[7 ]; +memcpy (term->baSourceID, &buffer[7 ],1 );if (buffer[8 ] !=0 ) usb_string(udev, buffer[8], term->name,
@@ -1026,15 +1022,11 @@ static int uvc_parse_standard_control(streturn -EINVAL ; } - unit =kzalloc (sizeof *unit + p,GFP_KERNEL ); + unit =uvc_alloc_entity (buffer[2 ], buffer[3 ], p +1 ,0 );if (unit ==NULL )return -ENOMEM ; - unit->id = buffer[3 ]; - unit->type = buffer[2 ]; - unit->selector.bNrInPins = buffer[4 ]; - unit->selector.baSourceID = (__u8 *)unit +sizeof *unit; -memcpy (unit->selector.baSourceID, &buffer[5 ], p); +memcpy (unit->baSourceID, &buffer[5 ], p);if (buffer[5 +p] !=0 ) usb_string(udev, buffer[5+p], unit->name,
@@ -1056,13 +1048,11 @@ static int uvc_parse_standard_control(streturn -EINVAL ; } - unit =kzalloc (sizeof *unit + n,GFP_KERNEL ); + unit =uvc_alloc_entity (buffer[2 ], buffer[3 ],2 , n);if (unit ==NULL )return -ENOMEM ; - unit->id = buffer[3 ]; - unit->type = buffer[2 ]; - unit->processing.bSourceID = buffer[4 ]; +memcpy (unit->baSourceID, &buffer[4 ],1 ); unit->processing.wMaxMultiplier =get_unaligned_le16 (&buffer[5 ]); unit->processing.bControlSize = buffer[7 ];
@@ -1091,19 +1081,15 @@ static int uvc_parse_standard_control(streturn -EINVAL ; } - unit =kzalloc (sizeof *unit + p + n,GFP_KERNEL ); + unit =uvc_alloc_entity (buffer[2 ], buffer[3 ], p +1 , n);if (unit ==NULL )return -ENOMEM ; - unit->id = buffer[3 ]; - unit->type = buffer[2 ];memcpy (unit->extension.guidExtensionCode, &buffer[4 ],16 ); unit->extension.bNumControls = buffer[20 ]; - unit->extension.bNrInPins = buffer[21 ]; - unit->extension.baSourceID = (__u8 *)unit +sizeof *unit; -memcpy (unit->extension.baSourceID, &buffer[22 ], p); +memcpy (unit->baSourceID, &buffer[22 ], p); unit->extension.bControlSize = buffer[22 +p]; - unit->extension.bmControls = (__u8 *)unit +sizeof *unit + p; + unit->extension.bmControls = (__u8 *)unit +sizeof *unit;memcpy (unit->extension.bmControls, &buffer[23 +p], n);if (buffer[23 +p+n] !=0 )
@@ -1209,7 +1195,7 @@ static int uvc_scan_chain_entity(structif (uvc_trace_param &UVC_TRACE_PROBE )printk (" <- XU %d" , entity->id); -if (entity->extension.bNrInPins !=1 ) { +if (entity->bNrInPins !=1 ) {uvc_trace (UVC_TRACE_DESCR ,"Extension unit %d has more " "than 1 input pin.\n" , entity->id);return -1 ;
@@ -1235,7 +1221,7 @@ static int uvc_scan_chain_entity(structprintk (" <- SU %d" , entity->id);/* Single-input selector units are ignored. */ -if (entity->selector.bNrInPins ==1 ) +if (entity->bNrInPins ==1 )break ;if (chain->selector !=NULL ) {
@@ -1296,7 +1282,7 @@ static int uvc_scan_chain_forward(structswitch (UVC_ENTITY_TYPE (forward)) {case UVC_VC_EXTENSION_UNIT : -if (forward->extension.bNrInPins !=1 ) { +if (forward->bNrInPins !=1 ) {uvc_trace (UVC_TRACE_DESCR ,"Extension unit %d " "has more than 1 input pin.\n" , entity->id);
@@ -1349,17 +1335,14 @@ static int uvc_scan_chain_backward(strucswitch (UVC_ENTITY_TYPE (entity)) {case UVC_VC_EXTENSION_UNIT : - id = entity->extension.baSourceID[0 ]; -break ; -case UVC_VC_PROCESSING_UNIT : - id = entity->processing.bSourceID; + id = entity->baSourceID[0 ];break ;case UVC_VC_SELECTOR_UNIT :/* Single-input selector units are ignored. */ -if (entity->selector.bNrInPins ==1 ) { - id = entity->selector.baSourceID[0 ]; +if (entity->bNrInPins ==1 ) { + id = entity->baSourceID[0 ];break ; }
@@ -1367,8 +1350,8 @@ static int uvc_scan_chain_backward(strucprintk (" <- IT" ); chain->selector = entity; -for (i =0 ; i < entity->selector.bNrInPins; ++i) { - id = entity->selector.baSourceID[i]; +for (i =0 ; i < entity->bNrInPins; ++i) { + id = entity->baSourceID[i]; term =uvc_entity_by_id (chain->dev, id);if (term ==NULL || !UVC_ENTITY_IS_ITERM (term)) { uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
@@ -1397,7 +1380,7 @@ static int uvc_scan_chain_backward(struccase UVC_OTT_DISPLAY :case UVC_OTT_MEDIA_TRANSPORT_OUTPUT :case UVC_TT_STREAMING : - id =UVC_ENTITY_IS_OTERM (entity) ? entity->output.bSourceID :0 ; + id =UVC_ENTITY_IS_OTERM (entity) ? entity->baSourceID[0 ] :0 ;break ; }
linux/drivers/media/video/uvc/uvc_v4l2.c +3 -3
@@ -633,8 +633,8 @@ static long uvc_v4l2_do_ioctl(struct filbreak ; } pin = iterm->id; - }else if (pin < selector->selector.bNrInPins) { - pin = selector->selector.baSourceID[index]; + }else if (pin < selector->bNrInPins) { + pin = selector->baSourceID[index];list_for_each_entry (iterm, &chain->entities, chain) {if (!UVC_ENTITY_IS_ITERM (iterm))continue ;
@@ -688,7 +688,7 @@ static long uvc_v4l2_do_ioctl(struct filbreak ; } -if (input ==0 || input > chain->selector->selector.bNrInPins) +if (input ==0 || input > chain->selector->bNrInPins)return -EINVAL ; return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
linux/drivers/media/video/uvc/uvcvideo.h +3 -6
@@ -294,11 +294,9 @@ struct uvc_entity { } media;struct { -__u8 bSourceID; } output;struct { -__u8 bSourceID;__u16 wMaxMultiplier;__u8 bControlSize;__u8 *bmControls;
@@ -306,21 +304,20 @@ struct uvc_entity { } processing;struct { -__u8 bNrInPins; -__u8 *baSourceID; } selector;struct {__u8 guidExtensionCode[16 ];__u8 bNumControls; -__u8 bNrInPins; -__u8 *baSourceID;__u8 bControlSize;__u8 *bmControls;__u8 *bmControlsType; } extension; }; +__u8 bNrInPins; +__u8 *baSourceID; +unsigned int ncontrols;struct uvc_control *controls; };
PATCH 13/14 uvcvideo: Register a v4l2_device
In reply to [email protected]As a first step to the media controller integration register a v4l2_device for each UVC control interface and make the video_device a child of the v4l2_device.
linux/drivers/media/video/uvc/uvc_driver.c +9 -2
@@ -1544,6 +1544,9 @@ static void uvc_delete(struct uvc_deviceuvc_status_cleanup (dev);uvc_ctrl_cleanup_device (dev); +if (dev->vdev.name[0 ]) +v4l2_device_unregister (&dev->vdev); +list_for_each_safe (p, n, &dev->chains) {struct uvc_video_chain *chain; chain = list_entry(p, struct uvc_video_chain, list);
@@ -1641,7 +1644,7 @@ static int uvc_register_video(struct uvc* unregistered before the reference is released, so we don't need to * get another one. */ - vdev->parent = &dev->intf->dev; + vdev->entity.parent = &dev->vdev; vdev->minor =-1 ; vdev->fops = &uvc_fops; vdev->release = uvc_release;
@@ -1772,6 +1775,10 @@ static int uvc_probe(struct usb_interfac "linux-uvc-devel mailing list.\n"); } +/* Register the V4L2 device. */ +if (v4l2_device_register (&intf->dev, &dev->vdev) <0 ) + goto error; +/* Initialize controls. */ if (uvc_ctrl_init_device (dev) <0 ) goto error;
@@ -1780,7 +1787,7 @@ static int uvc_probe(struct usb_interfacif (uvc_scan_device (dev) <0 ) goto error; -/* Register video devices. */ +/* Register video device nodes. */ if (uvc_register_chains (dev) <0 ) goto error;
linux/drivers/media/video/uvc/uvcvideo.h +2 -0
@@ -68,6 +68,7 @@ struct uvc_xu_control {#include <linux/poll.h> #include <linux/usb/video.h> +#include <media/v4l2-device.h> #include "compat.h" /* --------------------------------------------------------------------------
@@ -476,6 +477,7 @@ struct uvc_device {atomic_t users;/* Video control interface */ +struct v4l2_device vdev;__u16 uvc_version;__u32 clock_frequency;
PATCH 14/14 uvcvideo: Register subdevices for each entity
In reply to [email protected]Userspace applications can now discover the UVC device topology using the media controller API.
linux/drivers/media/video/uvc/uvc_driver.c +91 -2
@@ -762,9 +762,12 @@ static struct uvc_entity *uvc_alloc_entistruct uvc_entity *entity;unsigned int num_inputs;unsigned int size; +unsigned int i; + extra_size =ALIGN (extra_size,sizeof (*entity->pads)); num_inputs = (type &UVC_TERM_OUTPUT ) ? num_pads : num_pads -1 ; - size =sizeof (*entity) + extra_size + num_inputs; + size =sizeof (*entity) + extra_size +sizeof (*entity->pads) * num_pads + + num_inputs; entity =kzalloc (size,GFP_KERNEL );if (entity ==NULL )return NULL ;
@@ -772,8 +775,17 @@ static struct uvc_entity *uvc_alloc_enti entity->id = id; entity->type = type; + entity->num_links =0 ; + entity->num_pads = num_pads; + entity->pads = ((void *)(entity +1 )) + extra_size; + +for (i =0 ; i < num_inputs; ++i) + entity->pads[i].type =V4L2_PAD_TYPE_INPUT ; +if (!UVC_ENTITY_IS_OTERM (entity)) + entity->pads[num_pads-1 ].type =V4L2_PAD_TYPE_OUTPUT ; + entity->bNrInPins = num_inputs; - entity->baSourceID = ((__u8 *)entity) +sizeof (*entity) + extra_size; + entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);return entity; }
@@ -1158,6 +1170,77 @@ next_descriptor: }/* ------------------------------------------------------------------------ +* Video subdevices registration and unregistration +*/ + +static int uvc_mc_register_subdev (struct uvc_video_chain *chain, +struct uvc_entity *entity) +{ +const u32 flags =V4L2_LINK_FLAG_ACTIVE |V4L2_LINK_FLAG_PERMANENT ; +struct uvc_entity *remote; +unsigned int i; +u8 remote_pad; +int ret; + +for (i =0 ; i < entity->num_pads; ++i) { +if (entity->pads[i].type !=V4L2_PAD_TYPE_INPUT ) +continue ; + + remote =uvc_entity_by_id (chain->dev, entity->baSourceID[i]); +if (remote ==NULL ) +return -EINVAL ; + + remote_pad = remote->num_pads -1 ; + ret =v4l2_entity_connect (&remote->subdev.entity, remote_pad, + &entity->subdev.entity, i, flags); +if (ret <0 ) +return ret; + } + +return v4l2_device_register_subdev (&chain->dev->vdev, &entity->subdev); +} + +static struct v4l2_subdev_ops uvc_subdev_ops = { +}; + +static int uvc_mc_init_subdev (struct uvc_video_chain *chain, +struct uvc_entity *entity) +{ +v4l2_subdev_init (&entity->subdev, &uvc_subdev_ops); +snprintf (entity->subdev.name,sizeof (entity->subdev.name),"uvc-%u" , + entity->id); + +return v4l2_entity_init (&entity->subdev.entity, entity->num_pads, + entity->pads,0 ); +} + +static int uvc_mc_register_subdevs (struct uvc_video_chain *chain) +{ +struct uvc_entity *entity; +int ret; + +list_for_each_entry (entity, &chain->entities, chain) { + ret =uvc_mc_init_subdev (chain, entity); +if (ret <0 ) { +uvc_printk (KERN_INFO ,"Failed to initialize subdev for " +"entity %u\n" , entity->id); +return ret; + } + } + +list_for_each_entry (entity, &chain->entities, chain) { + ret =uvc_mc_register_subdev (chain, entity); +if (ret <0 ) { +uvc_printk (KERN_INFO ,"Failed to register subdev for " +"entity %u\n" , entity->id); +return ret; + } + } + +return 0 ; +} + +/* ------------------------------------------------------------------------ * UVC device scan */
@@ -1708,6 +1791,12 @@ static int uvc_register_chains(struct uv ret =uvc_register_terms (dev, chain);if (ret <0 )return ret; + + ret =uvc_mc_register_subdevs (chain); +if (ret <0 ) { +uvc_printk (KERN_INFO ,"Failed to register subdevs " +"(%d).\n" , ret); + } }return 0 ;
linux/drivers/media/video/uvc/uvcvideo.h +6 -0
@@ -278,6 +278,12 @@ struct uvc_entity {__u16 type;char name[64 ]; +/* Media controller-related fields. */ +struct v4l2_subdev subdev; +unsigned int num_pads; +unsigned int num_links; +struct v4l2_entity_pad *pads; + union { struct { __u16 wObjectiveFocalLengthMin;
Hi Laurent,
Quoted 38 lines
Hi everybody,
here's a set of patches to clean up and extend Hans' initial media controller
implementation.Patches prefixed by v4l deal with the v4l core code and update existing drivers when required by an API change. The core now offers two functions to
deal with entities and links:-
v4l2_entity_init()will initialize an entity. For subdevices thev4l2_subdev_init()performs part of the entity initialization as well, which
leads me to believe that the API is currently ill-defined.-
v4l2_entity_connect()creates a link between two entities. All possible links should be created using that function before the subdevice is registered.As I don't own any ivtv hardware the media controller code was difficult to
test so I've implemented media controller support in the UVC driver for testing purpose. The code can be found in patches prefixed by uvc.This is mostly playground code. There are known and unknown bugs (especially
in the ivtv driver as I haven't been able to test that code;v4l2_entity_connectis definitely called with bad parameters in there) as well
as design issues. There's a lot of code missing. I'm mostly interested in getting feedback on the changes, especially the newv4l2_entity_padandv4l2_entity_linkobjects. Feel free to comment on the public userspace API too, I realized after changing it to mimic the new kernel API that the way the previous API exposed "local" and "remote" pads instead of pads and links
is probably more space efficient.
Quoted 9 lines
I'll keep playing with the code and I'll start porting the OMAP3 camera driver
to the in-progress media controller API. I'll discover problems (and hopefully solutions) along the way so another round of patches can be expected
later, maybe in a week. Of course I'll appreciate comments before that, as the earlier I get feedback the easier it will be to incorporate it in the code. No pressure though, I know that a few developers have left for the kernel summit in Japan.
While I haven't been able to do an in-depth review it is clear to me that the switch to 'pads' is definitely the right direction. That leads to much cleaner code.
With regards to the code kernel API to set up all these relationships: I expect we'll end up with a few generic core functions that do all the hard work, and a bunch of static inline convenience functions on top of that. That tends to work quite well.
One tip: it might be useful to have a tree ready with just a single driver that is converted to use mc, links and pads (e.g. uvc). That makes it easy to experiment with different data structures and APIs. It's much harder to do this if you have a lot of dependencies on your code.
Keep up the good work! I'm so pleased to see so much activity from so many people after the v4l-dvb mini-summit!
Regards,
Hans
Quoted 41 lines · On Wednesday 21 October 2009 00:15:37 Hans Verkuil wrote:
Hi Laurent,
Quoted 31 lines
Hi everybody,
here's a set of patches to clean up and extend Hans' initial media controller implementation.
Patches prefixed by v4l deal with the v4l core code and update existing drivers when required by an API change. The core now offers two functions to deal with entities and links:
-
v4l2_entity_init()will initialize an entity. For subdevices thev4l2_subdev_init()performs part of the entity initialization as well, which leads me to believe that the API is currently ill-defined.-
v4l2_entity_connect()creates a link between two entities. All possible links should be created using that function before the subdevice is registered.As I don't own any ivtv hardware the media controller code was difficult to test so I've implemented media controller support in the UVC driver for testing purpose. The code can be found in patches prefixed by uvc.
This is mostly playground code. There are known and unknown bugs (especially in the ivtv driver as I haven't been able to test that code;
v4l2_entity_connectis definitely called with bad parameters in there) as well as design issues. There's a lot of code missing. I'm mostly interested in getting feedback on the changes, especially the newv4l2_entity_padandv4l2_entity_linkobjects. Feel free to comment on the public userspace API too, I realized after changing it to mimic the new kernel API that the way the previous API exposed "local" and "remote" pads instead of pads and links is probably more space efficient.Quoted 7 lines
I'll keep playing with the code and I'll start porting the OMAP3 camera driver to the in-progress media controller API. I'll discover problems (and hopefully solutions) along the way so another round of patches can be expected later, maybe in a week. Of course I'll appreciate comments before that, as the earlier I get feedback the easier it will be to incorporate it in the code. No pressure though, I know that a few developers have left for the kernel summit in Japan.
Quoted 1 line
While I haven't been able to do an in-depth review
Thanks for the early feedback.
Quoted 7 lines
it is clear to me that the switch to 'pads' is definitely the right direction. That leads to much cleaner code.
With regards to the code kernel API to set up all these relationships: I expect we'll end up with a few generic core functions that do all the hard work, and a bunch of static inline convenience functions on top of that. That tends to work quite well.
That's what I predict as well.
Quoted 4 lines
One tip: it might be useful to have a tree ready with just a single driver that is converted to use mc, links and pads (e.g. uvc). That makes it easy to experiment with different data structures and APIs. It's much harder to do this if you have a lot of dependencies on your code.
Good point. I'll setup a tree on linuxtv.org. Next step is the implementation of device nodes for subdevs. I'd like to reorganise the videodev core code for that, as we will have a dirty structures dependency otherwise (the v4l2_subdev structure will have two v4l2_entity fields, one as a direct child as v4l2_subdev inherits from v4l2_entity, and one through the video_device structure used for the subdev device node).
Signature · 3 lines
Regards, Laurent Pinchart