From 0efc193045eedcc05a28b5502f6dfaed87b434e8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Mar 2009 22:56:15 +0100 Subject: v4l2-common: add missing i2c_unregister_device. From: Hans Verkuil If the i2c sub-device cannot be found, then we must unregister the i2c_client. Otherwise this will prevent a possible probe for a different device on that same address. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index a5ce43102..32d0246d5 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -856,11 +856,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, We need better support from the kernel so that we can easily wait for the load to finish. */ if (client == NULL || client->driver == NULL) - return NULL; + goto error; /* Lock the module so we can safely get the v4l2_subdev pointer */ if (!try_module_get(client->driver->driver.owner)) - return NULL; + goto error; sd = i2c_get_clientdata(client); /* Register with the v4l2_device which increases the module's @@ -869,8 +869,15 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, sd = NULL; /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); - return sd; +error: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + /* If we have a client but no subdev, then something went wrong and + we must unregister the client. */ + if (client && sd == NULL) + i2c_unregister_device(client); +#endif + return sd; } EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); @@ -918,11 +925,11 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, We need better support from the kernel so that we can easily wait for the load to finish. */ if (client == NULL || client->driver == NULL) - return NULL; + goto error; /* Lock the module so we can safely get the v4l2_subdev pointer */ if (!try_module_get(client->driver->driver.owner)) - return NULL; + goto error; sd = i2c_get_clientdata(client); /* Register with the v4l2_device which increases the module's @@ -931,6 +938,14 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, sd = NULL; /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); + +error: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + /* If we have a client but no subdev, then something went wrong and + we must unregister the client. */ + if (client && sd == NULL) + i2c_unregister_device(client); +#endif return sd; } EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev); -- cgit v1.2.3 From edcff71d60fb21a8813c06ab97fc0d8746c238b4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 18 Mar 2009 19:48:01 +0100 Subject: v4l2-common: remove incorrect MODULE test From: Hans Verkuil v4l2-common doesn't have to be a module for it to call request_module(). Just remove that test. Priority: normal Signed-off-by: Hans Verkuil Thanks-to: Guennadi Liakhovetski --- linux/drivers/media/video/v4l2-common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 32d0246d5..426a93e8e 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -828,10 +828,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, #endif BUG_ON(!dev); -#ifdef MODULE + if (module_name) request_module(module_name); -#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) /* Setup the i2c board info with the device type and the device address. */ @@ -896,10 +896,10 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, #endif BUG_ON(!dev); -#ifdef MODULE + if (module_name) request_module(module_name); -#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) /* Setup the i2c board info with the device type and the device address. */ -- cgit v1.2.3 From 1b9ff790c05ba49e240edd1f06a6aee8f4a2b194 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 18 Mar 2009 21:00:39 +0100 Subject: adds V4L2_CID_SHARPNESS to v4l2_ctrl_query_fill() From: Janne Grunau Priority: normal Signed-off-by: Janne Grunau --- linux/drivers/media/video/v4l2-common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 32d0246d5..3c42316c3 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -570,6 +570,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_RED_BALANCE: case V4L2_CID_BLUE_BALANCE: case V4L2_CID_GAMMA: + case V4L2_CID_SHARPNESS: qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; break; case V4L2_CID_PAN_RELATIVE: -- cgit v1.2.3 From a022c34c8938f0c3a97840b5b3ceffa0ef41f775 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 1 Apr 2009 08:41:09 +0200 Subject: v4l2-common: remove legacy code From: Hans Verkuil Now that all drivers are converted to v4l2_subdev we can remove legacy code in v4l2-common. Also move the documentation of the internal API to v4l2-subdev.h where it really belongs. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index b153575fb..912859bf1 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -740,8 +740,9 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); /* ----------------------------------------------------------------- */ -/* Helper function for I2C legacy drivers */ +/* I2C Helper functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, const char *name, int (*probe)(struct i2c_client *, const struct i2c_device_id *)) @@ -767,6 +768,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver return err != -ENOMEM ? 0 : err; } EXPORT_SYMBOL(v4l2_i2c_attach); +#endif void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) -- cgit v1.2.3 From 1784ea5527ed756f946958f45f74d1f15797c366 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 30 Mar 2009 01:04:44 +0200 Subject: v4l2: use old-style i2c API for kernels < 2.6.26 instead of < 2.6.22 From: Hans Verkuil Originally the intention was to switch to the new style i2c API starting with the introduction of the API in 2.6.22. However, the i2c_new_probed_device() function has a lethal bug that wasn't fixed until 2.6.25. Or more accurately, it was only fixed in the stable series of 2.6.25 and 2.6.26. Given the fact that the new i2c API also changed starting with 2.6.26 (the addition of i2c_device_id), it is easiest to switch APIs starting with 2.6.26. This patch updates all the legacy code accordingly. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 912859bf1..60a8f299c 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -742,7 +742,7 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); /* I2C Helper functions */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, const char *name, int (*probe)(struct i2c_client *, const struct i2c_device_id *)) @@ -786,7 +786,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, } EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) /* Supporting function to find a client on a specific address on the given adapter. Used for legacy i2c drivers. */ static struct i2c_client *v4l2_i2c_legacy_find_client(struct i2c_adapter *adap, u8 addr) @@ -826,7 +826,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, struct v4l2_device *dev = i2c_get_adapdata(adapter); struct v4l2_subdev *sd = NULL; struct i2c_client *client; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) struct i2c_board_info info; #endif @@ -835,15 +835,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, if (module_name) request_module(module_name); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) /* Setup the i2c board info with the device type and the device address. */ memset(&info, 0, sizeof(info)); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) - strlcpy(info.driver_name, client_type, sizeof(info.driver_name)); -#else strlcpy(info.type, client_type, sizeof(info.type)); -#endif info.addr = addr; /* Create the i2c client */ @@ -874,7 +870,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, module_put(client->driver->driver.owner); error: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ if (client && sd == NULL) @@ -894,7 +890,7 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, struct v4l2_device *dev = i2c_get_adapdata(adapter); struct v4l2_subdev *sd = NULL; struct i2c_client *client = NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) struct i2c_board_info info; #endif @@ -903,15 +899,11 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, if (module_name) request_module(module_name); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) /* Setup the i2c board info with the device type and the device address. */ memset(&info, 0, sizeof(info)); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) - strlcpy(info.driver_name, client_type, sizeof(info.driver_name)); -#else strlcpy(info.type, client_type, sizeof(info.type)); -#endif /* Probe and create the i2c client */ client = i2c_new_probed_device(adapter, &info, addrs); @@ -943,7 +935,7 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, module_put(client->driver->driver.owner); error: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ if (client && sd == NULL) -- cgit v1.2.3 From f0312f1d7b8dd5cde4035eef2a5b0fe7effdd838 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 1 Apr 2009 08:57:53 +0200 Subject: v4l2-common: add explicit v4l2_device pointer as first arg to new_(probed)_subdev From: Hans Verkuil The functions v4l2_i2c_new_subdev and v4l2_i2c_new_probed_subdev relied on i2c_get_adapdata to return the v4l2_device. However, this is not always possible on embedded platforms. So modify the API to pass the v4l2_device pointer explicitly. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 60a8f299c..d6f41f8af 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -817,20 +817,18 @@ static struct i2c_client *v4l2_i2c_legacy_find_client(struct i2c_adapter *adap, #endif -/* Load an i2c sub-device. It assumes that i2c_get_adapdata(adapter) - returns the v4l2_device and that i2c_get_clientdata(client) - returns the v4l2_subdev. */ -struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, +/* Load an i2c sub-device. */ +struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, const char *module_name, const char *client_type, u8 addr) { - struct v4l2_device *dev = i2c_get_adapdata(adapter); struct v4l2_subdev *sd = NULL; struct i2c_client *client; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) struct i2c_board_info info; #endif - BUG_ON(!dev); + BUG_ON(!v4l2_dev); if (module_name) request_module(module_name); @@ -864,7 +862,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter, /* Register with the v4l2_device which increases the module's use count as well. */ - if (v4l2_device_register_subdev(dev, sd)) + if (v4l2_device_register_subdev(v4l2_dev, sd)) sd = NULL; /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); @@ -880,21 +878,19 @@ error: } EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); -/* Probe and load an i2c sub-device. It assumes that i2c_get_adapdata(adapter) - returns the v4l2_device and that i2c_get_clientdata(client) - returns the v4l2_subdev. */ -struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, +/* Probe and load an i2c sub-device. */ +struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, const char *module_name, const char *client_type, const unsigned short *addrs) { - struct v4l2_device *dev = i2c_get_adapdata(adapter); struct v4l2_subdev *sd = NULL; struct i2c_client *client = NULL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) struct i2c_board_info info; #endif - BUG_ON(!dev); + BUG_ON(!v4l2_dev); if (module_name) request_module(module_name); @@ -929,7 +925,7 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, /* Register with the v4l2_device which increases the module's use count as well. */ - if (v4l2_device_register_subdev(dev, sd)) + if (v4l2_device_register_subdev(v4l2_dev, sd)) sd = NULL; /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); -- cgit v1.2.3 From 402941a820682bd6f89f6705bbe643e6808facc5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 30 Mar 2009 16:40:54 +0200 Subject: v4l2-common: add v4l2_i2c_new_probed_subdev_addr From: Hans Verkuil Add utility function to probe for a single address, rather than a list of addresses. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index d6f41f8af..d75d89c88 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -941,6 +941,17 @@ error: } EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev); +struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, + const char *module_name, const char *client_type, u8 addr) +{ + unsigned short addrs[2] = { addr, I2C_CLIENT_END }; + + return v4l2_i2c_new_probed_subdev(v4l2_dev, adapter, + module_name, client_type, addrs); +} +EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr); + /* Return i2c client address of v4l2_subdev. */ unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) { -- cgit v1.2.3 From 83d87c0c4e7849713db298cea21c964f85313f3b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 May 2009 14:42:57 +0200 Subject: tuner: remove tuner_i2c_address_check From: Hans Verkuil Support for tuners with i2c addresses >= 0x65 is dropped since no tuners with addresses in the range 0x65-0x6f have been found. This patch removes addresses 0x65-0x6f from the list of tuner probe addresses, it removes the kernel warning that warned if addresses in this range appeared, and it removed a hack for the cx88 that is no longer needed now that the tuner address range is reduced. Priority: normal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/v4l2-common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index d75d89c88..0301974dc 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -978,8 +978,7 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) }; static const unsigned short tv_addrs[] = { 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x60, 0x61, 0x62, 0x63, 0x64, I2C_CLIENT_END }; -- cgit v1.2.3 From 486b64428b6255dc6cf7aa8759648f9a9bca1dbd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 May 2009 15:58:51 +0200 Subject: v4l2-device: unregister i2c_clients when unregistering the v4l2_device. From: Hans Verkuil Until now I relied on i2c_del_adapter to unregister the i2c_clients for me, however, if the i2c bus is a platform bus then it is never deleted. So instead I need to unregister i2c clients when unregistering the v4l2_device. Priority: normal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/v4l2-common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 0301974dc..8f2db1250 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -774,6 +774,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) { v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_IS_I2C; /* the owner is the same as the i2c_client's driver owner */ sd->owner = client->driver->driver.owner; /* i2c_client and v4l2_subdev point to one another */ -- cgit v1.2.3 From 51c04c87bb11afe772c5cf797a12c71c602cff8c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 30 May 2009 17:45:46 -0700 Subject: v4l2: Create helper function for bounding and aligning images From: Trent Piepho Most hardware has limits on minimum and maximum image dimensions and also requirements about alignment. For example, image width must be even or a multiple of four. Some hardware has requirements that the total image size (width * height) be a multiple of some power of two. v4l_bound_align_image() will enforce min and max width and height, power of two alignment on width and height, and power of two alignment on total image size. It uses an efficient algorithm that will try to find the "closest" image size that meets the requirements. Priority: normal Signed-off-by: Trent Piepho --- linux/drivers/media/video/v4l2-common.c | 71 +++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 8f2db1250..d81bae197 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -997,4 +997,75 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) } EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); +/* Clamp x to be between min and max, aligned to a multiple of 2^align. min + * and max don't have to be aligned, but there must be at least one valid + * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples + * of 16 between 17 and 31. */ +static unsigned int clamp_align(unsigned int x, unsigned int min, + unsigned int max, unsigned int align) +{ + /* Bits that must be zero to be aligned */ + unsigned int mask = ~((1 << align) - 1); + + /* Round to nearest aligned value */ + if (align) + x = (x + (1 << (align - 1))) & mask; + + /* Clamp to aligned value of min and max */ + if (x < min) + x = (min + ~mask) & mask; + else if (x > max) + x = max & mask; + + return x; +} + +/* Bound an image to have a width between wmin and wmax, and height between + * hmin and hmax, inclusive. Additionally, the width will be a multiple of + * 2^walign, the height will be a multiple of 2^halign, and the overall size + * (width*height) will be a multiple of 2^salign. The image may be shrunk + * or enlarged to fit the alignment constraints. + * + * The width or height maximum must not be smaller than the corresponding + * minimum. The alignments must not be so high there are no possible image + * sizes within the allowed bounds. wmin and hmin must be at least 1 + * (don't use 0). If you don't care about a certain alignment, specify 0, + * as 2^0 is 1 and one byte alignment is equivalent to no alignment. If + * you only want to adjust downward, specify a maximum that's the same as + * the initial value. + */ +void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, + unsigned int walign, + u32 *h, unsigned int hmin, unsigned int hmax, + unsigned int halign, unsigned int salign) +{ + *w = clamp_align(*w, wmin, wmax, walign); + *h = clamp_align(*h, hmin, hmax, halign); + + /* Usually we don't need to align the size and are done now. */ + if (!salign) + return; + + /* How much alignment do we have? */ + walign = __ffs(*w); + halign = __ffs(*h); + /* Enough to satisfy the image alignment? */ + if (walign + halign < salign) { + /* Max walign where there is still a valid width */ + unsigned int wmaxa = __fls(wmax ^ (wmin - 1)); + + /* up the smaller alignment until we have enough */ + do { + if (walign <= halign && walign < wmaxa) { + *w = clamp_align(*w, wmin, wmax, walign + 1); + walign = __ffs(*w); + } else { + *h = clamp_align(*h, hmin, hmax, halign + 1); + halign = __ffs(*h); + } + } while (halign + walign < salign); + } +} +EXPORT_SYMBOL_GPL(v4l_bound_align_image); + #endif -- cgit v1.2.3 From 505dee96b5f86facce4200d260ffec2fb5a737b8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 12 Jun 2009 19:31:29 +0000 Subject: v4l2: Move bounding code outside I2C ifdef block From: Trent Piepho On Fri, 12 Jun 2009, Randy Dunlap wrote: > From: Randy Dunlap > > Move v4l_bound_align_image() outside of an #ifdef CONFIG_I2C block > so that it is always built. Fixes a build error: clamp_align() should be moved as well, since it's only used by v4l_bound_align_image(). I'm attaching an alternate version that fixes this. Labeled the endif too. Reported-by: Randy Dunlap Priority: normal Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/v4l2-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index d81bae197..ba3790a98 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -997,6 +997,8 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) } EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); +#endif /* defined(CONFIG_I2C) */ + /* Clamp x to be between min and max, aligned to a multiple of 2^align. min * and max don't have to be aligned, but there must be at least one valid * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples @@ -1067,5 +1069,3 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } } EXPORT_SYMBOL_GPL(v4l_bound_align_image); - -#endif -- cgit v1.2.3 From 03d777f511d5820441ae2f3584e7441dd019faea Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 16 Jun 2009 18:14:49 -0700 Subject: v4l2: Fix flaw in alignment code From: Trent Piepho It's possible that the height alignment would be increased beyond the maximum possible value when trying to satisfy size alignment. Please fold with b4d3ec8d363d v4l2: Create helper function for bounding and aligning images Priority: high Signed-off-by: Trent Piepho --- linux/drivers/media/video/v4l2-common.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video/v4l2-common.c') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index ba3790a98..f94b5d92a 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -1055,10 +1055,13 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, if (walign + halign < salign) { /* Max walign where there is still a valid width */ unsigned int wmaxa = __fls(wmax ^ (wmin - 1)); + /* Max halign where there is still a valid height */ + unsigned int hmaxa = __fls(hmax ^ (hmin - 1)); /* up the smaller alignment until we have enough */ do { - if (walign <= halign && walign < wmaxa) { + if (halign >= hmaxa || + (walign <= halign && walign < wmaxa)) { *w = clamp_align(*w, wmin, wmax, walign + 1); walign = __ffs(*w); } else { -- cgit v1.2.3