All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree
@ 2009-10-20  1:12 laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 01/14] v4l-mc: Rename pins to pads laurent.pinchart
                   ` (14 more replies)
  0 siblings, 15 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil

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


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 01/14] v4l-mc: Rename pins to pads
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 02/14] v4l-mc: Merge input and output pads laurent.pinchart
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-mc-pin-to-pad.diff --]
[-- Type: text/plain, Size: 10502 bytes --]

Entities "connection points" are now named pads to avoid confusing them with
physical pins.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/include/linux/videodev2.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/linux/videodev2.h
+++ v4l-dvb-mc/linux/include/linux/videodev2.h
@@ -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 {
Index: v4l-dvb-mc/linux/include/media/v4l2-mc.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-mc.h
+++ v4l-dvb-mc/linux/include/media/v4l2-mc.h
@@ -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;
 }
 
Index: v4l-dvb-mc/v4l2-apps/util/v4l2-mc.cpp
===================================================================
--- v4l-dvb-mc.orig/v4l2-apps/util/v4l2-mc.cpp
+++ v4l-dvb-mc/v4l2-apps/util/v4l2-mc.cpp
@@ -223,7 +223,7 @@ static void show_topology(int fd)
 		ios.entity = ent.id;
 		ios.status = (struct v4l2_mc_io_status *)
 			malloc((ent.inputs + ent.outputs) * sizeof(struct v4l2_mc_io_status));
-		ios.remote_pins = (struct v4l2_mc_io *)
+		ios.remote_pads = (struct v4l2_mc_io *)
 			malloc(ent.total_possible_links * sizeof(struct v4l2_mc_io));
 		if (ioctl(fd, VIDIOC_MC_ENUM_LINKS, &ios) >= 0) {
 			int i;
@@ -233,46 +233,46 @@ static void show_topology(int fd)
 				int j;
 
 				printf("\tInput %d:     ", i);
-				if (ios.status[i].nr_of_remote_pins == 1) {
+				if (ios.status[i].nr_of_remote_pads == 1) {
 					printf("%s/%d %s\n",
-						entity2s(fd, ios.remote_pins[p].entity).c_str(),
-						ios.remote_pins[p].io,
-						ios.status[i].active_pins == 1 ? "(active)" : "");
+						entity2s(fd, ios.remote_pads[p].entity).c_str(),
+						ios.remote_pads[p].io,
+						ios.status[i].active_pads == 1 ? "(active)" : "");
 				}
 				else {
-					for (j = 0; j < ios.status[i].nr_of_remote_pins; j++) {
+					for (j = 0; j < ios.status[i].nr_of_remote_pads; j++) {
 						printf("\t\t\t%s/%d %s\n",
-							entity2s(fd, ios.remote_pins[p+j].entity).c_str(),
-							ios.remote_pins[p+j].io,
-							(ios.status[i].active_pins & (1 << j)) ? "(active)" : "");
+							entity2s(fd, ios.remote_pads[p+j].entity).c_str(),
+							ios.remote_pads[p+j].io,
+							(ios.status[i].active_pads & (1 << j)) ? "(active)" : "");
 					}
 				}
-				p += ios.status[i].nr_of_remote_pins;
+				p += ios.status[i].nr_of_remote_pads;
 			}
 
 			for (i = 0; i < ent.outputs; i++) {
 				int j;
 
 				printf("\tOutput %d:    ", i);
-				if (ios.status[ent.inputs + i].nr_of_remote_pins == 1) {
+				if (ios.status[ent.inputs + i].nr_of_remote_pads == 1) {
 					printf("%s/%d %s\n",
-						entity2s(fd, ios.remote_pins[p].entity).c_str(),
-						ios.remote_pins[p].io,
-						ios.status[ent.inputs + i].active_pins == 1 ? "(active)" : "");
+						entity2s(fd, ios.remote_pads[p].entity).c_str(),
+						ios.remote_pads[p].io,
+						ios.status[ent.inputs + i].active_pads == 1 ? "(active)" : "");
 				}
 				else {
-					for (j = 0; j < ios.status[ent.inputs + i].nr_of_remote_pins; j++) {
+					for (j = 0; j < ios.status[ent.inputs + i].nr_of_remote_pads; j++) {
 						printf("\t\t\t%s/%d %s\n",
-							entity2s(fd, ios.remote_pins[p+j].entity).c_str(),
-							ios.remote_pins[p+j].io,
-							(ios.status[ent.inputs + i].active_pins & (1 << j)) ? "(active)" : "");
+							entity2s(fd, ios.remote_pads[p+j].entity).c_str(),
+							ios.remote_pads[p+j].io,
+							(ios.status[ent.inputs + i].active_pads & (1 << j)) ? "(active)" : "");
 					}
 				}
-				p += ios.status[ent.inputs + i].nr_of_remote_pins;
+				p += ios.status[ent.inputs + i].nr_of_remote_pads;
 			}
 		}
 		free(ios.status);
-		free(ios.remote_pins);
+		free(ios.remote_pads);
 		printf("\n");
 	}
 }
@@ -299,29 +299,29 @@ static void dot_topology(int fd)
 		ios.entity = ent.id;
 		ios.status = (struct v4l2_mc_io_status *)
 			malloc((ent.inputs + ent.outputs) * sizeof(struct v4l2_mc_io_status));
-		ios.remote_pins = (struct v4l2_mc_io *)
+		ios.remote_pads = (struct v4l2_mc_io *)
 			malloc(ent.total_possible_links * sizeof(struct v4l2_mc_io));
 		if (ioctl(fd, VIDIOC_MC_ENUM_LINKS, &ios) >= 0) {
 			int i;
 			int p = 0;
 
 			for (i = 0; i < ent.inputs; i++)
-				p += ios.status[i].nr_of_remote_pins;
+				p += ios.status[i].nr_of_remote_pads;
 
 			for (i = 0; i < ent.outputs; i++) {
 				int j;
 
-				for (j = 0; j < ios.status[ent.inputs + i].nr_of_remote_pins; j++) {
-					printf("\tn%08x -> n%08x ", ent.id, ios.remote_pins[p+j].entity);
-					if (!(ios.status[ent.inputs + i].active_pins & (1 << j)))
+				for (j = 0; j < ios.status[ent.inputs + i].nr_of_remote_pads; j++) {
+					printf("\tn%08x -> n%08x ", ent.id, ios.remote_pads[p+j].entity);
+					if (!(ios.status[ent.inputs + i].active_pads & (1 << j)))
 						printf("[style=dashed]");
 					printf("\n");
 				}
-				p += ios.status[ent.inputs + i].nr_of_remote_pins;
+				p += ios.status[ent.inputs + i].nr_of_remote_pads;
 			}
 		}
 		free(ios.status);
-		free(ios.remote_pins);
+		free(ios.remote_pads);
 	}
 	printf("}\n");
 }
Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-device.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
@@ -114,9 +114,9 @@ static long mc_enum_entities(struct v4l2
 		int 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_de
 		return -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_de
 			struct 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_de
 			struct 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)))



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 02/14] v4l-mc: Merge input and output pads
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 01/14] v4l-mc: Rename pins to pads laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 03/14] v4l-mc: Replace the active pads bitmask by a link flag laurent.pinchart
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-mc-merge-inputs-outputs.diff --]
[-- Type: text/plain, Size: 15590 bytes --]

The media controller doesn't need separate counts of input and output
pads. Merge them into a pads count.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-device.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
@@ -107,15 +107,12 @@ static long mc_enum_entities(struct v4l2
 		strlcpy(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_de
 	if (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_de
 	if (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;
Index: v4l-dvb-mc/linux/include/linux/videodev2.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/linux/videodev2.h
+++ v4l-dvb-mc/linux/include/linux/videodev2.h
@@ -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		2
 
 struct 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;
Index: v4l-dvb-mc/linux/include/media/v4l2-mc.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-mc.h
+++ v4l-dvb-mc/linux/include/media/v4l2-mc.h
@@ -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;
 }
 
Index: v4l-dvb-mc/v4l2-apps/util/v4l2-mc.cpp
===================================================================
--- v4l-dvb-mc.orig/v4l2-apps/util/v4l2-mc.cpp
+++ v4l-dvb-mc/v4l2-apps/util/v4l2-mc.cpp
@@ -170,6 +170,18 @@ static std::string entity2s(int fd, unsi
 	return ent.name;
 }
 
+static std::string padtype2s(unsigned type)
+{
+	switch (type) {
+	case V4L2_PAD_TYPE_INPUT:
+		return "input";
+	case V4L2_PAD_TYPE_OUTPUT:
+		return "output";
+	default:
+		return "unknown";
+	}
+}
+
 static void show_topology(int fd)
 {
 	struct v4l2_mc_entity ent;
@@ -193,8 +205,7 @@ static void show_topology(int fd)
 		printf("\tDescription: %s\n", ent.descr);
 		printf("\tType:        %s\n", enttype2s(ent.type).c_str());
 		printf("\tSubtype:     %s\n", subtype2s(ent.type, ent.subtype).c_str());
-		printf("\tInputs:      %d\n", ent.inputs);
-		printf("\tOutputs:     %d\n", ent.outputs);
+		printf("\tPads:        %d\n", ent.pads);
 		printf("\tTotal Links: %d\n", ent.total_possible_links);
 
 		if (ent.type == V4L2_ENTITY_TYPE_NODE) {
@@ -222,54 +233,33 @@ static void show_topology(int fd)
 
 		ios.entity = ent.id;
 		ios.status = (struct v4l2_mc_io_status *)
-			malloc((ent.inputs + ent.outputs) * sizeof(struct v4l2_mc_io_status));
+			malloc(ent.pads * sizeof(struct v4l2_mc_io_status));
 		ios.remote_pads = (struct v4l2_mc_io *)
 			malloc(ent.total_possible_links * sizeof(struct v4l2_mc_io));
 		if (ioctl(fd, VIDIOC_MC_ENUM_LINKS, &ios) >= 0) {
 			int i;
 			int p = 0;
 
-			for (i = 0; i < ent.inputs; i++) {
+			for (i = 0; i < ent.pads; i++) {
 				int j;
 
-				printf("\tInput %d:     ", i);
+				printf("\tPad %d (%s):     ", i, padtype2s(ios.status[i].type).c_str());
 				if (ios.status[i].nr_of_remote_pads == 1) {
 					printf("%s/%d %s\n",
 						entity2s(fd, ios.remote_pads[p].entity).c_str(),
-						ios.remote_pads[p].io,
+						ios.remote_pads[p].pad,
 						ios.status[i].active_pads == 1 ? "(active)" : "");
 				}
 				else {
 					for (j = 0; j < ios.status[i].nr_of_remote_pads; j++) {
 						printf("\t\t\t%s/%d %s\n",
 							entity2s(fd, ios.remote_pads[p+j].entity).c_str(),
-							ios.remote_pads[p+j].io,
+							ios.remote_pads[p+j].pad,
 							(ios.status[i].active_pads & (1 << j)) ? "(active)" : "");
 					}
 				}
 				p += ios.status[i].nr_of_remote_pads;
 			}
-
-			for (i = 0; i < ent.outputs; i++) {
-				int j;
-
-				printf("\tOutput %d:    ", i);
-				if (ios.status[ent.inputs + i].nr_of_remote_pads == 1) {
-					printf("%s/%d %s\n",
-						entity2s(fd, ios.remote_pads[p].entity).c_str(),
-						ios.remote_pads[p].io,
-						ios.status[ent.inputs + i].active_pads == 1 ? "(active)" : "");
-				}
-				else {
-					for (j = 0; j < ios.status[ent.inputs + i].nr_of_remote_pads; j++) {
-						printf("\t\t\t%s/%d %s\n",
-							entity2s(fd, ios.remote_pads[p+j].entity).c_str(),
-							ios.remote_pads[p+j].io,
-							(ios.status[ent.inputs + i].active_pads & (1 << j)) ? "(active)" : "");
-					}
-				}
-				p += ios.status[ent.inputs + i].nr_of_remote_pads;
-			}
 		}
 		free(ios.status);
 		free(ios.remote_pads);
@@ -298,26 +288,28 @@ static void dot_topology(int fd)
 			ent.type == V4L2_ENTITY_TYPE_NODE ? "oval" : "box");
 		ios.entity = ent.id;
 		ios.status = (struct v4l2_mc_io_status *)
-			malloc((ent.inputs + ent.outputs) * sizeof(struct v4l2_mc_io_status));
+			malloc(ent.pads * sizeof(struct v4l2_mc_io_status));
 		ios.remote_pads = (struct v4l2_mc_io *)
 			malloc(ent.total_possible_links * sizeof(struct v4l2_mc_io));
 		if (ioctl(fd, VIDIOC_MC_ENUM_LINKS, &ios) >= 0) {
 			int i;
 			int p = 0;
 
-			for (i = 0; i < ent.inputs; i++)
-				p += ios.status[i].nr_of_remote_pads;
-
-			for (i = 0; i < ent.outputs; i++) {
+			for (i = 0; i < ent.pads; i++) {
 				int j;
 
-				for (j = 0; j < ios.status[ent.inputs + i].nr_of_remote_pads; j++) {
+				if (ios.status[i].type != V4L2_PAD_TYPE_OUTPUT) {
+					p += ios.status[i].nr_of_remote_pads;
+					continue;
+				}
+
+				for (j = 0; j < ios.status[i].nr_of_remote_pads; j++) {
 					printf("\tn%08x -> n%08x ", ent.id, ios.remote_pads[p+j].entity);
-					if (!(ios.status[ent.inputs + i].active_pads & (1 << j)))
+					if (!(ios.status[i].active_pads & (1 << j)))
 						printf("[style=dashed]");
 					printf("\n");
 				}
-				p += ios.status[ent.inputs + i].nr_of_remote_pads;
+				p += ios.status[i].nr_of_remote_pads;
 			}
 		}
 		free(ios.status);
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -697,9 +697,9 @@ static int __devinit ivtv_init_struct1(s
 	v4l2_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);
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-gpio.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-gpio.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-gpio.c
@@ -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);
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-streams.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -269,10 +269,10 @@ static int ivtv_reg_dev(struct ivtv *itv
 		return -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);
Index: v4l-dvb-mc/linux/drivers/media/video/msp3400-driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/msp3400-driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/msp3400-driver.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/saa7115.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/saa7115.c
+++ v4l-dvb-mc/linux/drivers/media/video/saa7115.c
@@ -1604,7 +1604,7 @@ static int saa711x_probe(struct i2c_clie
 		return -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;
Index: v4l-dvb-mc/linux/drivers/media/video/saa7127.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/saa7127.c
+++ v4l-dvb-mc/linux/drivers/media/video/saa7127.c
@@ -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.
Index: v4l-dvb-mc/linux/drivers/media/video/tuner-core.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/tuner-core.c
+++ v4l-dvb-mc/linux/drivers/media/video/tuner-core.c
@@ -1041,7 +1041,7 @@ static int tuner_probe(struct i2c_client
 	if (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;



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 03/14] v4l-mc: Replace the active pads bitmask by a link flag
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 01/14] v4l-mc: Rename pins to pads laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 02/14] v4l-mc: Merge input and output pads laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 04/14] v4l-subdev: Add pads operations laurent.pinchart
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-mc-replace-active-bitflag.diff --]
[-- Type: text/plain, Size: 2215 bytes --]

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-device.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
@@ -145,10 +145,8 @@ static long mc_enum_links(struct v4l2_de
 		for (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;
 		}
Index: v4l-dvb-mc/linux/include/linux/videodev2.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/linux/videodev2.h
+++ v4l-dvb-mc/linux/include/linux/videodev2.h
@@ -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 */
 };
Index: v4l-dvb-mc/linux/include/media/v4l2-mc.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-mc.h
+++ v4l-dvb-mc/linux/include/media/v4l2-mc.h
@@ -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



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 04/14] v4l-subdev: Add pads operations
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (2 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 03/14] v4l-mc: Replace the active pads bitmask by a link flag laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 05/14] v4l-mc: Clean up link API laurent.pinchart
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-subdev-add-pad-ops.patch --]
[-- Type: text/plain, Size: 1445 bytes --]

Add a v4l2_subdev_pad_ops structure for the operations that need to be
performed at the pad level such as format-related operations.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/include/media/v4l2-subdev.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-subdev.h
+++ v4l-dvb-mc/linux/include/media/v4l2-subdev.h
@@ -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



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 05/14] v4l-mc: Clean up link API
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (3 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 04/14] v4l-subdev: Add pads operations laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 06/14] v4l-mc: Remove subdev v4l2_dev field laurent.pinchart
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-mc-clean-up-link-api.patch --]
[-- Type: text/plain, Size: 28989 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/Makefile
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/Makefile
+++ v4l-dvb-mc/linux/drivers/media/video/Makefile
@@ -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
 
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -697,11 +697,11 @@ static int __devinit ivtv_init_struct1(s
 	v4l2_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;
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-driver.h
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -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 */
 
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-gpio.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-gpio.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-gpio.c
@@ -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);
 }
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-i2c.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-streams.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -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;
 
Index: v4l-dvb-mc/linux/drivers/media/video/msp3400-driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/msp3400-driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/msp3400-driver.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/msp3400-driver.h
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/msp3400-driver.h
+++ v4l-dvb-mc/linux/drivers/media/video/msp3400-driver.h
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/saa7115.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/saa7115.c
+++ v4l-dvb-mc/linux/drivers/media/video/saa7115.c
@@ -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_clie
 		return -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;
Index: v4l-dvb-mc/linux/drivers/media/video/saa7127.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/saa7127.c
+++ v4l-dvb-mc/linux/drivers/media/video/saa7127.c
@@ -238,8 +238,7 @@ static struct i2c_reg_value saa7127_init
 
 struct 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.
Index: v4l-dvb-mc/linux/drivers/media/video/tuner-core.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/tuner-core.c
+++ v4l-dvb-mc/linux/drivers/media/video/tuner-core.c
@@ -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_client
 	if (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;
Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-device.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
@@ -107,14 +107,8 @@ static long mc_enum_entities(struct v4l2
 		strlcpy(mc_ent.descr, ent->descr, sizeof(mc_ent.descr));
 	mc_ent.type = ent->type;
 	mc_ent.subtype = ent->subtype;
-	mc_ent.pads = ent->pads;
-	mc_ent.total_possible_links = 0;
-	if (ent->links) {
-		int l;
-
-		for (l = 0; l < ent->pads; l++)
-			mc_ent.total_possible_links += ent->links[l].nr_of_remote_pads;
-	}
+	mc_ent.pads = ent->num_pads;
+	mc_ent.links = ent->num_links;
 	mc_ent.v4l.major = ent->v4l.major;
 	mc_ent.v4l.minor = ent->v4l.minor;
 	if (copy_to_user(uent, &mc_ent, sizeof(mc_ent)))
@@ -122,12 +116,17 @@ static long mc_enum_entities(struct v4l2
 	return 0;
 }
 
+static void mc_kpad_to_upad(const struct v4l2_entity_pad *kpad, struct v4l2_mc_pad *upad)
+{
+	upad->entity = kpad->entity->id;
+	upad->index = kpad - kpad->entity->pads;
+	upad->type = kpad->type;
+}
+
 static long mc_enum_links(struct v4l2_device *v4l2_dev, struct v4l2_mc_ios __user *uios)
 {
 	struct v4l2_entity *ent;
 	struct v4l2_mc_ios ios;
-	u32 total_possible_links = 0;
-	int l;
 
 	if (copy_from_user(&ios, uios, sizeof(ios)))
 		return -EFAULT;
@@ -135,31 +134,29 @@ static long mc_enum_links(struct v4l2_de
 	ent = find_entity(v4l2_dev, ios.entity);
 	if (ent == NULL)
 		return -EINVAL;
-	if (ent->links) {
-		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->pads; l++, s++) {
-			struct v4l2_mc_io_status stat = { 0, 0 };
+	if (ios.pads) {
+		unsigned int p;
 
-			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)))
+		for (p = 0; p < ent->num_pads; p++) {
+			struct v4l2_mc_pad pad;
+			mc_kpad_to_upad(&ent->pads[p], &pad);
+			if (copy_to_user(&uios->pads[p], &pad, sizeof(pad)))
 				return -EFAULT;
 		}
 	}
 
-	if (ios.remote_pads && total_possible_links) {
-		int p = 0;
+	if (ios.links) {
+		unsigned int l;
+
+		for (l = 0; l < ent->num_links; l++) {
+			struct v4l2_mc_link link;
 
-		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])))
+			mc_kpad_to_upad(ent->links[l].source, &link.source);
+			mc_kpad_to_upad(ent->links[l].sink, &link.sink);
+			link.flags = ent->links[l].flags;
+			if (copy_to_user(&uios->links[l], &link, sizeof(link)))
 				return -EFAULT;
-			p += ent->links[l].nr_of_remote_pads;
 		}
 	}
 	if (copy_to_user(uios, &ios, sizeof(*uios)))
Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-mc.c
===================================================================
--- /dev/null
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-mc.c
@@ -0,0 +1,118 @@
+/*
+ *  V4L2 Media Controller support
+ *
+ *  Copyright (C) 2009 Laurent Pinchart <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; 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/module.h>
+#include <linux/slab.h>
+#include <media/v4l2-mc.h>
+
+/**
+ * v4l2_entity_init - Initialize a V4L2 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 v4l2_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
+ * v4l2_entity_init() where its pointer will be stored in the entity structure.
+ */
+int
+v4l2_entity_init(struct v4l2_entity *entity, u8 num_pads,
+		 struct v4l2_entity_pad *pads, u8 extra_links)
+{
+	struct v4l2_entity_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->max_links = max_links;
+	entity->num_links = 0;
+	entity->num_pads = num_pads;
+	entity->pads = pads;
+	entity->links = links;
+
+	for (i = 0; i < num_pads; i++)
+		pads[i].entity = entity;
+
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_entity_init);
+
+static struct
+v4l2_entity_link *v4l2_entity_add_link(struct v4l2_entity *entity)
+{
+	if (entity->num_links >= entity->max_links) {
+		struct v4l2_entity_link *links = entity->links;
+		unsigned int max_links = entity->max_links + 2;
+
+		links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
+		if (links == NULL)
+			return NULL;
+
+		entity->max_links = max_links;
+		entity->links = links;
+	}
+
+	return &entity->links[entity->num_links++];
+}
+
+int
+v4l2_entity_connect(struct v4l2_entity *source, u8 source_pad,
+		    struct v4l2_entity *sink, u8 sink_pad, u32 flags)
+{
+	struct v4l2_entity_link *source_link;
+	struct v4l2_entity_link *sink_link;
+
+	BUG_ON(source == NULL || sink == NULL);
+	BUG_ON(source_pad >= source->num_pads);
+	BUG_ON(sink_pad >= sink->num_pads);
+
+	source_link = v4l2_entity_add_link(source);
+	sink_link = v4l2_entity_add_link(sink);
+	if (source_link == NULL || sink_link == NULL)
+		return -ENOMEM;
+
+	source_link->source = &source->pads[source_pad];
+	source_link->sink = &sink->pads[sink_pad];
+	source_link->flags = flags;
+	sink_link->source = &source->pads[source_pad];
+	sink_link->sink = &sink->pads[sink_pad];
+	sink_link->flags = flags;
+
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_entity_connect);
+
Index: v4l-dvb-mc/linux/include/linux/videodev2.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/linux/videodev2.h
+++ v4l-dvb-mc/linux/include/linux/videodev2.h
@@ -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;
 };
 
 /*
Index: v4l-dvb-mc/linux/include/media/v4l2-mc.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-mc.h
+++ v4l-dvb-mc/linux/include/media/v4l2-mc.h
@@ -3,23 +3,35 @@
 
 #include <linux/list.h>
 
-struct v4l2_entity_io {
-	u8 nr_of_remote_pads; /* number of remote pads */
-	struct v4l2_mc_io *remote_pads; /* specify possible remote pads */
+struct v4l2_entity_link {
+	struct v4l2_entity_pad *source;	/* Source pad */
+	struct v4l2_entity_pad *sink;	/* Sink pad  */
+	u32 flags;			/* Link flags (V4L2_LINK_FLAG_*) */
+};
+
+struct v4l2_entity_pad {
+	struct v4l2_entity *entity;	/* Entity this pad belongs to */
+	u32 type;			/* Pad type (V4L2_PAD_TYPE_*) */
 };
 
 struct v4l2_entity {
 	struct list_head list;
-	struct v4l2_device *parent;
-	u32 id;
-	const char *name;
-	const char *descr;
-	u32 type;
-	u32 subtype;
-	u8 pads;
-	u8 num_pads;
-	/* points to a v4l2_entity_io array of size num_pads links */
-	struct v4l2_entity_io *links;
+	struct v4l2_device *parent;	/* Media controller this entity belongs
+					 * to */
+	u32 id;				/* Entity ID, unique in the parent media
+					 * controller context */
+	const char *name;		/* Entity name */
+	const char *descr;		/* Entity description, will be a string control */
+	u32 type;			/* Entity type (V4L2_ENTITY_TYPE_*) */
+	u32 subtype;			/* Entity subtype (type-specific) */
+
+	u8 num_pads;			/* Number of input and output pads */
+	u8 num_links;			/* Number of existing links, both active
+					 * and inactive */
+	u8 max_links;			/* Maximum number of links */
+
+	struct v4l2_entity_pad *pads;	/* Array of pads (num_pads elements) */
+	struct v4l2_entity_link *links;	/* Array of links (max_links elements) */
 
 	/* The entity's ioctl, accessible through the media controller */
 	long (*ioctl)(struct v4l2_entity *ent, unsigned int cmd, unsigned long arg);
@@ -42,35 +54,9 @@ struct v4l2_entity {
 	};
 };
 
-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_pads = num_pads;
-	ent->links = links;
-	for (i = 0; i < num_pads; i++) {
-		links[i].nr_of_remote_pads = 1;
-		links[i].remote_pads = remote_pads + i;
-	}
-}
-
-static inline void v4l2_entity_connect(struct v4l2_entity *source,
-	       struct v4l2_entity *sink, int active)
-{
-	int source_link, sink_link;
-
-	if (source == NULL || sink == NULL || source->pads >= source->num_pads)
-		return;
-
-	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].pad = sink_link;
-	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].remote_pads[0].active = active;
-}
+extern int v4l2_entity_init(struct v4l2_entity *entity, u8 num_pads,
+		struct v4l2_entity_pad *pads, u8 extra_links);
+extern int v4l2_entity_connect(struct v4l2_entity *source, u8 source_pad,
+		struct v4l2_entity *sink, u8 sink_pad, u32 flags);
 
 #endif
Index: v4l-dvb-mc/v4l2-apps/util/v4l2-mc.cpp
===================================================================
--- v4l-dvb-mc.orig/v4l2-apps/util/v4l2-mc.cpp
+++ v4l-dvb-mc/v4l2-apps/util/v4l2-mc.cpp
@@ -170,9 +170,9 @@ static std::string entity2s(int fd, unsi
 	return ent.name;
 }
 
-static std::string padtype2s(unsigned type)
+static std::string padtype2s(struct v4l2_mc_pad *pad)
 {
-	switch (type) {
+	switch (pad->type) {
 	case V4L2_PAD_TYPE_INPUT:
 		return "input";
 	case V4L2_PAD_TYPE_OUTPUT:
@@ -206,7 +206,7 @@ static void show_topology(int fd)
 		printf("\tType:        %s\n", enttype2s(ent.type).c_str());
 		printf("\tSubtype:     %s\n", subtype2s(ent.type, ent.subtype).c_str());
 		printf("\tPads:        %d\n", ent.pads);
-		printf("\tTotal Links: %d\n", ent.total_possible_links);
+		printf("\tLinks:       %d\n", ent.links);
 
 		if (ent.type == V4L2_ENTITY_TYPE_NODE) {
 			/* Output node-specific properties */
@@ -232,37 +232,40 @@ static void show_topology(int fd)
 		}
 
 		ios.entity = ent.id;
-		ios.status = (struct v4l2_mc_io_status *)
-			malloc(ent.pads * sizeof(struct v4l2_mc_io_status));
-		ios.remote_pads = (struct v4l2_mc_io *)
-			malloc(ent.total_possible_links * sizeof(struct v4l2_mc_io));
+		ios.pads = (struct v4l2_mc_pad *)
+			malloc(ent.pads * sizeof(struct v4l2_mc_pad));
+		ios.links = (struct v4l2_mc_link *)
+			malloc(ent.links * sizeof(struct v4l2_mc_link));
 		if (ioctl(fd, VIDIOC_MC_ENUM_LINKS, &ios) >= 0) {
 			int i;
 			int p = 0;
 
 			for (i = 0; i < ent.pads; i++) {
+				struct v4l2_mc_pad *pad = &ios.pads[i];
 				int j;
 
-				printf("\tPad %d (%s):     ", i, padtype2s(ios.status[i].type).c_str());
-				if (ios.status[i].nr_of_remote_pads == 1) {
-					printf("%s/%d %s\n",
-						entity2s(fd, ios.remote_pads[p].entity).c_str(),
-						ios.remote_pads[p].pad,
-						ios.status[i].active_pads == 1 ? "(active)" : "");
+				printf("\tPad %d (%s):     ", i, padtype2s(pad).c_str());
+				for (j = 0; j < ent.links; j++) {
+					struct v4l2_mc_link *link = &ios.links[j];
+					struct v4l2_mc_pad *remote;
+
+					if (link->source.index == pad->index)
+						remote = &ios.pads[link->sink.index];
+					else if (link->sink.index == pad->index)
+						remote = &ios.pads[link->source.index];
+					else
+						continue;
+
+					printf("\t\t\t%s %s/%d %s\n",
+						remote->type == V4L2_PAD_TYPE_INPUT ? "->" : "<-",
+						entity2s(fd, remote->entity).c_str(),
+						remote->index,
+						link->flags & V4L2_LINK_FLAG_ACTIVE ? "(active)" : "");
 				}
-				else {
-					for (j = 0; j < ios.status[i].nr_of_remote_pads; j++) {
-						printf("\t\t\t%s/%d %s\n",
-							entity2s(fd, ios.remote_pads[p+j].entity).c_str(),
-							ios.remote_pads[p+j].pad,
-							(ios.status[i].active_pads & (1 << j)) ? "(active)" : "");
-					}
-				}
-				p += ios.status[i].nr_of_remote_pads;
 			}
 		}
-		free(ios.status);
-		free(ios.remote_pads);
+		free(ios.pads);
+		free(ios.links);
 		printf("\n");
 	}
 }
@@ -287,33 +290,25 @@ static void dot_topology(int fd)
 		printf("\tn%08x [label=\"%s\",shape=%s]\n", ent.id, ent.name,
 			ent.type == V4L2_ENTITY_TYPE_NODE ? "oval" : "box");
 		ios.entity = ent.id;
-		ios.status = (struct v4l2_mc_io_status *)
-			malloc(ent.pads * sizeof(struct v4l2_mc_io_status));
-		ios.remote_pads = (struct v4l2_mc_io *)
-			malloc(ent.total_possible_links * sizeof(struct v4l2_mc_io));
+		ios.pads = (struct v4l2_mc_pad *)
+			malloc(ent.pads * sizeof(struct v4l2_mc_pad));
+		ios.links = (struct v4l2_mc_link *)
+			malloc(ent.links * sizeof(struct v4l2_mc_link));
 		if (ioctl(fd, VIDIOC_MC_ENUM_LINKS, &ios) >= 0) {
 			int i;
-			int p = 0;
 
-			for (i = 0; i < ent.pads; i++) {
-				int j;
-
-				if (ios.status[i].type != V4L2_PAD_TYPE_OUTPUT) {
-					p += ios.status[i].nr_of_remote_pads;
+			for (i = 0; i < ent.links; i++) {
+				if (ios.links[i].source.entity != ent.id)
 					continue;
-				}
 
-				for (j = 0; j < ios.status[i].nr_of_remote_pads; j++) {
-					printf("\tn%08x -> n%08x ", ent.id, ios.remote_pads[p+j].entity);
-					if (!(ios.status[i].active_pads & (1 << j)))
+				printf("\tn%08x -> n%08x ", ent.id, ios.links[i].sink.entity);
+					if (!(ios.links[i].flags & V4L2_LINK_FLAG_ACTIVE))
 						printf("[style=dashed]");
 					printf("\n");
-				}
-				p += ios.status[i].nr_of_remote_pads;
 			}
 		}
-		free(ios.status);
-		free(ios.remote_pads);
+		free(ios.pads);
+		free(ios.links);
 	}
 	printf("}\n");
 }



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 06/14] v4l-mc: Remove subdev v4l2_dev field
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (4 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 05/14] v4l-mc: Clean up link API laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 07/14] v4l-mc: Remove devnode " laurent.pinchart
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-mc-remove-subdev-v4l2-dev-field.diff --]
[-- Type: text/plain, Size: 4163 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/include/media/v4l2-subdev.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-subdev.h
+++ v4l-dvb-mc/linux/include/media/v4l2-subdev.h
@@ -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
Index: v4l-dvb-mc/linux/drivers/media/video/bt819.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/bt819.c
+++ v4l-dvb-mc/linux/drivers/media/video/bt819.c
@@ -256,7 +256,7 @@ static int bt819_s_std(struct v4l2_subde
 
 	v4l2_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_s
 	if (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) {
Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-device.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
@@ -333,10 +333,10 @@ int v4l2_device_register_subdev(struct v
 	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);
+	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_s
 void 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);
Index: v4l-dvb-mc/linux/drivers/media/video/zoran/zoran_card.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/zoran/zoran_card.c
+++ v4l-dvb-mc/linux/drivers/media/video/zoran/zoran_card.c
@@ -1196,7 +1196,7 @@ zoran_setup_videocodec (struct zoran *zr
 
 static 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. */



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 07/14] v4l-mc: Remove devnode v4l2_dev field
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (5 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 06/14] v4l-mc: Remove subdev v4l2_dev field laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 08/14] uvcvideo: Rely on videodev to reference-count the device laurent.pinchart
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: v4l-mc-remove-devnode-v4l2-dev-field.diff --]
[-- Type: text/plain, Size: 14485 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/radio/dsbr100.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/radio/dsbr100.c
+++ v4l-dvb-mc/linux/drivers/media/radio/dsbr100.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/radio/radio-gemtek-pci.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/radio/radio-gemtek-pci.c
+++ v4l-dvb-mc/linux/drivers/media/radio/radio-gemtek-pci.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/radio/radio-maestro.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/radio/radio-maestro.c
+++ v4l-dvb-mc/linux/drivers/media/radio/radio-maestro.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/radio/radio-maxiradio.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/radio/radio-maxiradio.c
+++ v4l-dvb-mc/linux/drivers/media/radio/radio-maxiradio.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/radio/radio-mr800.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/radio/radio-mr800.c
+++ v4l-dvb-mc/linux/drivers/media/radio/radio-mr800.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/bt8xx/bttv-driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -4204,7 +4204,7 @@ static struct video_device *vdev_init(st
 	if (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);
Index: v4l-dvb-mc/linux/drivers/media/video/cafe_ccic.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/cafe_ccic.c
+++ v4l-dvb-mc/linux/drivers/media/video/cafe_ccic.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/cx18/cx18-streams.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/cx18/cx18-streams.c
+++ v4l-dvb-mc/linux/drivers/media/video/cx18/cx18-streams.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/cx231xx/cx231xx-video.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/cx231xx/cx231xx-video.c
+++ v4l-dvb-mc/linux/drivers/media/video/cx231xx/cx231xx-video.c
@@ -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;
 
Index: v4l-dvb-mc/linux/drivers/media/video/cx23885/cx23885-video.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/cx23885/cx23885-video.c
+++ v4l-dvb-mc/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -353,7 +353,7 @@ static struct video_device *cx23885_vdev
 		return 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);
Index: v4l-dvb-mc/linux/drivers/media/video/cx88/cx88-core.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/cx88/cx88-core.c
+++ v4l-dvb-mc/linux/drivers/media/video/cx88/cx88-core.c
@@ -1057,7 +1057,7 @@ struct video_device *cx88_vdev_init(stru
 	if (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)",
Index: v4l-dvb-mc/linux/drivers/media/video/em28xx/em28xx-video.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/em28xx/em28xx-video.c
+++ v4l-dvb-mc/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -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;
 
Index: v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-streams.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ v4l-dvb-mc/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/saa7134/saa7134-core.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/saa7134/saa7134-core.c
+++ v4l-dvb-mc/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -853,7 +853,7 @@ static struct video_device *vdev_init(st
 	if (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)",
Index: v4l-dvb-mc/linux/drivers/media/video/usbvision/usbvision-video.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/usbvision/usbvision-video.c
+++ v4l-dvb-mc/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -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;
Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-dev.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-dev.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-dev.c
@@ -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_d
 	   reference 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 */
 	}
Index: v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/v4l2-device.c
+++ v4l-dvb-mc/linux/drivers/media/video/v4l2-device.c
@@ -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_n
 void 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);
 
Index: v4l-dvb-mc/linux/drivers/media/video/w9968cf.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/w9968cf.c
+++ v4l-dvb-mc/linux/drivers/media/video/w9968cf.c
@@ -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]);
Index: v4l-dvb-mc/linux/include/media/v4l2-dev.h
===================================================================
--- v4l-dvb-mc.orig/linux/include/media/v4l2-dev.h
+++ v4l-dvb-mc/linux/include/media/v4l2-dev.h
@@ -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];



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 08/14] uvcvideo: Rely on videodev to reference-count the device
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (6 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 07/14] v4l-mc: Remove devnode " laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 09/14] uvcvideo: Merge iterms, oterms and extensions linked lists laurent.pinchart
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-faba04f47c9b.diff --]
[-- Type: text/plain, Size: 9773 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

--- a/linux/drivers/media/video/uvc/uvc_driver.c	Wed Sep 02 08:12:26 2009 +0200
+++ b/linux/drivers/media/video/uvc/uvc_driver.c	Wed Sep 30 02:07:19 2009 +0200
@@ -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();
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c	Wed Sep 02 08:12:26 2009 +0200
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c	Wed Sep 30 02:07:19 2009 +0200
@@ -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;
 }
 
--- a/linux/drivers/media/video/uvc/uvcvideo.h	Wed Sep 02 08:12:26 2009 +0200
+++ b/linux/drivers/media/video/uvc/uvcvideo.h	Wed Sep 30 02:07:19 2009 +0200
@@ -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,




^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 09/14] uvcvideo: Merge iterms, oterms and extensions linked lists
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (7 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 08/14] uvcvideo: Rely on videodev to reference-count the device laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 10/14] uvcvideo: Fix extension units parsing laurent.pinchart
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-rename-extensions-to-units.patch --]
[-- Type: text/plain, Size: 8383 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_ctrl.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_ctrl.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_ctrl.c
@@ -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_c
 	int 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_c
 	int 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;
 	}
 
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
@@ -1215,7 +1215,6 @@ static int uvc_scan_chain_entity(struct 
 			return -1;
 		}
 
-		list_add_tail(&entity->chain, &chain->extensions);
 		break;
 
 	case UVC_VC_PROCESSING_UNIT:
@@ -1254,7 +1253,6 @@ static int uvc_scan_chain_entity(struct 
 		if (uvc_trace_param & UVC_TRACE_PROBE)
 			printk(" <- IT %d\n", entity->id);
 
-		list_add_tail(&entity->chain, &chain->iterms);
 		break;
 
 	case UVC_TT_STREAMING:
@@ -1267,7 +1265,6 @@ static int uvc_scan_chain_entity(struct 
 			return -1;
 		}
 
-		list_add_tail(&entity->chain, &chain->iterms);
 		break;
 
 	default:
@@ -1276,6 +1273,7 @@ static int uvc_scan_chain_entity(struct 
 		return -1;
 	}
 
+	list_add_tail(&entity->chain, &chain->entities);
 	return 0;
 }
 
@@ -1306,7 +1304,7 @@ static int uvc_scan_chain_forward(struct
 				return -EINVAL;
 			}
 
-			list_add_tail(&forward->chain, &chain->extensions);
+			list_add_tail(&forward->chain, &chain->entities);
 			if (uvc_trace_param & UVC_TRACE_PROBE) {
 				if (!found)
 					printk(" (->");
@@ -1326,7 +1324,7 @@ static int uvc_scan_chain_forward(struct
 				return -EINVAL;
 			}
 
-			list_add_tail(&forward->chain, &chain->oterms);
+			list_add_tail(&forward->chain, &chain->entities);
 			if (uvc_trace_param & UVC_TRACE_PROBE) {
 				if (!found)
 					printk(" (->");
@@ -1382,7 +1380,7 @@ static int uvc_scan_chain_backward(struc
 			if (uvc_trace_param & UVC_TRACE_PROBE)
 				printk(" %d", term->id);
 
-			list_add_tail(&term->chain, &chain->iterms);
+			list_add_tail(&term->chain, &chain->entities);
 			uvc_scan_chain_forward(chain, term, entity);
 		}
 
@@ -1403,7 +1401,7 @@ static int uvc_scan_chain(struct uvc_vid
 	int id;
 
 	entity = oterm;
-	list_add_tail(&entity->chain, &chain->oterms);
+	list_add_tail(&entity->chain, &chain->entities);
 	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
 
 	id = entity->output.bSourceID;
@@ -1443,21 +1441,25 @@ static int uvc_scan_chain(struct uvc_vid
 	return 0;
 }
 
-static unsigned int uvc_print_terms(struct list_head *terms, char *buffer)
+static unsigned int uvc_print_terms(struct list_head *terms, u16 dir,
+		char *buffer)
 {
 	struct uvc_entity *term;
 	unsigned int nterms = 0;
 	char *p = buffer;
 
 	list_for_each_entry(term, terms, chain) {
-		p += sprintf(p, "%u", term->id);
-		if (term->chain.next != terms) {
+		if (!UVC_ENTITY_IS_TERM(term) ||
+		    UVC_TERM_DIRECTION(term) != dir)
+			continue;
+
+		if (nterms)
 			p += sprintf(p, ",");
-			if (++nterms >= 4) {
-				p += sprintf(p, "...");
-				break;
-			}
+		if (++nterms >= 4) {
+			p += sprintf(p, "...");
+			break;
 		}
+		p += sprintf(p, "%u", term->id);
 	}
 
 	return p - buffer;
@@ -1468,9 +1470,9 @@ static const char *uvc_print_chain(struc
 	static char buffer[43];
 	char *p = buffer;
 
-	p += uvc_print_terms(&chain->iterms, p);
+	p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p);
 	p += sprintf(p, " -> ");
-	uvc_print_terms(&chain->oterms, p);
+	uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p);
 
 	return buffer;
 }
@@ -1501,9 +1503,7 @@ static int uvc_scan_device(struct uvc_de
 		if (chain == NULL)
 			return -ENOMEM;
 
-		INIT_LIST_HEAD(&chain->iterms);
-		INIT_LIST_HEAD(&chain->oterms);
-		INIT_LIST_HEAD(&chain->extensions);
+		INIT_LIST_HEAD(&chain->entities);
 		mutex_init(&chain->ctrl_mutex);
 		chain->dev = dev;
 
@@ -1676,13 +1676,13 @@ static int uvc_register_video(struct uvc
  * Register all video devices in all chains.
  */
 static int uvc_register_terms(struct uvc_device *dev,
-	struct uvc_video_chain *chain, struct list_head *terms)
+	struct uvc_video_chain *chain)
 {
 	struct uvc_streaming *stream;
 	struct uvc_entity *term;
 	int ret;
 
-	list_for_each_entry(term, terms, chain) {
+	list_for_each_entry(term, &chain->entities, chain) {
 		if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
 			continue;
 
@@ -1708,11 +1708,7 @@ static int uvc_register_chains(struct uv
 	int ret;
 
 	list_for_each_entry(chain, &dev->chains, list) {
-		ret = uvc_register_terms(dev, chain, &chain->iterms);
-		if (ret < 0)
-			return ret;
-
-		ret = uvc_register_terms(dev, chain, &chain->oterms);
+		ret = uvc_register_terms(dev, chain);
 		if (ret < 0)
 			return ret;
 	}
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvcvideo.h
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
@@ -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;
 };
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_v4l2.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_v4l2.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_v4l2.c
@@ -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;
 			}



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 10/14] uvcvideo: Fix extension units parsing
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (8 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 09/14] uvcvideo: Merge iterms, oterms and extensions linked lists laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 11/14] uvcvideo: Refactor chain scan laurent.pinchart
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-fix-extension-unit-parsing.diff --]
[-- Type: text/plain, Size: 1333 bytes --]

The bNrInPins field is an 8 bit integer, not a 16 bit integer.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
@@ -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];



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 11/14] uvcvideo: Refactor chain scan
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (9 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 10/14] uvcvideo: Fix extension units parsing laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 12/14] uvcvideo: Factorize common field in uvc_entity structure laurent.pinchart
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-refactor-chain-scan.diff --]
[-- Type: text/plain, Size: 3495 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
@@ -1256,13 +1256,12 @@ static int uvc_scan_chain_entity(struct 
 		break;
 
 	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_vid
 		if (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;



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 12/14] uvcvideo: Factorize common field in uvc_entity structure
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (10 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 11/14] uvcvideo: Refactor chain scan laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 13/14] uvcvideo: Register a v4l2_device laurent.pinchart
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-factor-entity-source.diff --]
[-- Type: text/plain, Size: 10152 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
@@ -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(stru
 			break;
 		}
 
-		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(st
 			return -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(st
 			return 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(st
 			return -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(st
 			return -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(st
 			return -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(struct 
 		if (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(struct 
 			printk(" <- 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(struct
 
 		switch (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(struc
 
 	switch (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(struc
 			printk(" <- 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(struc
 	case 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;
 	}
 
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_v4l2.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_v4l2.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_v4l2.c
@@ -633,8 +633,8 @@ static long uvc_v4l2_do_ioctl(struct fil
 					break;
 			}
 			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 fil
 			break;
 		}
 
-		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,
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvcvideo.h
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
@@ -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;
 };



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 13/14] uvcvideo: Register a v4l2_device
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (11 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 12/14] uvcvideo: Factorize common field in uvc_entity structure laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20  1:12 ` [RFC/PATCH 14/14] uvcvideo: Register subdevices for each entity laurent.pinchart
  2009-10-20 22:15 ` [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree Hans Verkuil
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-v4l2-device.diff --]
[-- Type: text/plain, Size: 2291 bytes --]

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.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
@@ -1544,6 +1544,9 @@ static void uvc_delete(struct uvc_device
 	uvc_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_interfac
 	if (uvc_scan_device(dev) < 0)
 		goto error;
 
-	/* Register video devices. */
+	/* Register video device nodes. */
 	if (uvc_register_chains(dev) < 0)
 		goto error;
 
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvcvideo.h
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
@@ -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;
 



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC/PATCH 14/14] uvcvideo: Register subdevices for each entity
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (12 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 13/14] uvcvideo: Register a v4l2_device laurent.pinchart
@ 2009-10-20  1:12 ` laurent.pinchart
  2009-10-20 22:15 ` [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree Hans Verkuil
  14 siblings, 0 replies; 17+ messages in thread
From: laurent.pinchart @ 2009-10-20  1:12 UTC (permalink / raw)
  To: linux-media; +Cc: sakari.ailus, hverkuil, Laurent Pinchart

[-- Attachment #1: uvc-mc.patch --]
[-- Type: text/plain, Size: 4356 bytes --]

Userspace applications can now discover the UVC device topology using
the media controller API.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvc_driver.c
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvc_driver.c
@@ -762,9 +762,12 @@ static struct uvc_entity *uvc_alloc_enti
 	struct 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;
Index: v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
===================================================================
--- v4l-dvb-mc.orig/linux/drivers/media/video/uvc/uvcvideo.h
+++ v4l-dvb-mc/linux/drivers/media/video/uvc/uvcvideo.h
@@ -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;



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree
  2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
                   ` (13 preceding siblings ...)
  2009-10-20  1:12 ` [RFC/PATCH 14/14] uvcvideo: Register subdevices for each entity laurent.pinchart
@ 2009-10-20 22:15 ` Hans Verkuil
  2009-10-20 22:32   ` Laurent Pinchart
  14 siblings, 1 reply; 17+ messages in thread
From: Hans Verkuil @ 2009-10-20 22:15 UTC (permalink / raw)
  To: laurent.pinchart; +Cc: linux-media, sakari.ailus

Hi Laurent,

> 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.

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


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree
  2009-10-20 22:15 ` [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree Hans Verkuil
@ 2009-10-20 22:32   ` Laurent Pinchart
  0 siblings, 0 replies; 17+ messages in thread
From: Laurent Pinchart @ 2009-10-20 22:32 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, sakari.ailus

On Wednesday 21 October 2009 00:15:37 Hans Verkuil wrote:
> Hi Laurent,
> 
> > 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.
> 
> While I haven't been able to do an in-depth review

Thanks for the early feedback.

> 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.

> 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).

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2009-10-20 22:32 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-20  1:12 [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 01/14] v4l-mc: Rename pins to pads laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 02/14] v4l-mc: Merge input and output pads laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 03/14] v4l-mc: Replace the active pads bitmask by a link flag laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 04/14] v4l-subdev: Add pads operations laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 05/14] v4l-mc: Clean up link API laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 06/14] v4l-mc: Remove subdev v4l2_dev field laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 07/14] v4l-mc: Remove devnode " laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 08/14] uvcvideo: Rely on videodev to reference-count the device laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 09/14] uvcvideo: Merge iterms, oterms and extensions linked lists laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 10/14] uvcvideo: Fix extension units parsing laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 11/14] uvcvideo: Refactor chain scan laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 12/14] uvcvideo: Factorize common field in uvc_entity structure laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 13/14] uvcvideo: Register a v4l2_device laurent.pinchart
2009-10-20  1:12 ` [RFC/PATCH 14/14] uvcvideo: Register subdevices for each entity laurent.pinchart
2009-10-20 22:15 ` [RFC/PATCH 00/14] Media controller update based on Hans' v4l-dvb-mc tree Hans Verkuil
2009-10-20 22:32   ` Laurent Pinchart

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.