diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-17 22:39:23 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-17 22:39:23 -0300 |
commit | fb2e83ece3c03b94ad9e9ca75d658729b684a789 (patch) | |
tree | 6c1d6b7124e5dd844b02007e66471e7e9238f707 /linux/drivers/media/video/v4l2-common.c | |
parent | 5e90c221e48890f2f2433f153d9584bc4bdd327a (diff) | |
parent | 1596f74981cbcf720947b4fd600028d24edfa783 (diff) | |
download | mediapointer-dvb-s2-fb2e83ece3c03b94ad9e9ca75d658729b684a789.tar.gz mediapointer-dvb-s2-fb2e83ece3c03b94ad9e9ca75d658729b684a789.tar.bz2 |
merge: http://linuxtv.org/hg/~hgoede/libv4l
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Priority: normal
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video/v4l2-common.c')
-rw-r--r-- | linux/drivers/media/video/v4l2-common.c | 171 |
1 files changed, 131 insertions, 40 deletions
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index a5ce43102..f94b5d92a 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: @@ -739,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, 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 *)) @@ -766,11 +768,13 @@ 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) { 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 */ @@ -783,7 +787,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) @@ -814,33 +818,27 @@ 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, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) struct i2c_board_info info; #endif - BUG_ON(!dev); -#ifdef MODULE + BUG_ON(!v4l2_dev); + if (module_name) request_module(module_name); -#endif -#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 */ @@ -856,52 +854,53 @@ 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 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); - return sd; +error: +#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) + i2c_unregister_device(client); +#endif + return sd; } 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, 22) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) struct i2c_board_info info; #endif - BUG_ON(!dev); -#ifdef MODULE + BUG_ON(!v4l2_dev); + if (module_name) request_module(module_name); -#endif -#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); @@ -918,23 +917,42 @@ 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 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); + +error: +#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) + i2c_unregister_device(client); +#endif return sd; } 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) { @@ -961,8 +979,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 }; @@ -980,4 +997,78 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) } EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); -#endif +#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 + * 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)); + /* 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 (halign >= hmaxa || + (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); |