GWater wrote: > So we did this before. >Could you post that patch again?
I suspect it's this patch, the thing is that last 4 bits (bits 7-4) in gain reg has same weight, i.e. 0x80 and 0x40 adjusts gain to same level. This is correct at least for ov9650, also bits 10-8 should be set to 0.
From 99d14e74eaec23f4762071ded20882ac2e80d426 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick <[email protected]> Date: Sun, 30 Nov 2008 23:04:09 +0200 Subject: [PATCH] Added gain V4L2 control Signed-off-by: Vasily Khoruzhick <[email protected]> Signed-off-by: GWater <[email protected]> --- microdia-dev.c | 21 +++++++++++++++++ microdia-sysfs.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- microdia-v4l.c | 18 ++++++++++++++ microdia.h | 3 ++ omnivision.c | 49 +++++++++++++++++++++++++++++++++++++++ omnivision.h | 1 + 6 files changed, 157 insertions(+), 2 deletions(-) diff --git a/microdia-dev.c b/microdia-dev.c index 2f684ce..2fd7416 100644 --- a/microdia-dev.c +++ b/microdia-dev.c @@ -44,6 +44,7 @@ static struct sensor_info sensors[] = { .set_hvflip = ov965x_set_hvflip, .set_exposure = ov965x_set_exposure, .set_auto_gain = ov_set_autogain, + .set_gain = ov_set_gain, .flip_detect = ov965x_flip_detect, .get_yavg = ov965x_get_yavg, .min_yavg = 30, @@ -58,6 +59,7 @@ static struct sensor_info sensors[] = { .initialize = ov_initialize, .set_auto_exposure = ov_set_autoexposure, .set_auto_gain = ov_set_autogain, + .set_gain = ov_set_gain, .hstart = 0, .vstart = 7, }, @@ -69,6 +71,7 @@ static struct sensor_info sensors[] = { .set_exposure = soi968_set_exposure, .set_auto_exposure = ov_set_autoexposure, .set_auto_gain = ov_set_autogain, + .set_gain = ov_set_gain, .button_detect = soi968_button_detect, .hstart = 60, .vstart = 11, @@ -80,6 +83,7 @@ static struct sensor_info sensors[] = { .initialize = ov_initialize, .set_exposure = ov7660_set_exposure, .set_auto_gain = ov_set_autogain, + .set_gain = ov_set_gain, .hstart = 1, .vstart = 1, .get_yavg = ov965x_get_yavg, @@ -96,6 +100,7 @@ static struct sensor_info sensors[] = { .set_auto_exposure = ov_set_autoexposure, .set_exposure = ov7660_set_exposure, .set_auto_gain = ov_set_autogain, + .set_gain = ov_set_gain, .flip_detect = ov7670_flip_detect, .hstart = 0, .vstart = 1, @@ -679,3 +684,19 @@ int dev_microdia_perform_soft_ae(struct usb_microdia *dev) return 0; } +/** + * @brief Wrapper function for device-specific set_gain functions + * + * @param dev Pointer to device structure + * + * @returns 0 or negative error value + * + */ +int dev_microdia_camera_set_gain(struct usb_microdia *dev) +{ + int ret = -ENODEV; + if (dev && dev->camera.sensor->set_gain) + ret = dev->camera.sensor->set_gain(dev); + + return ret; +} diff --git a/microdia-sysfs.c b/microdia-sysfs.c index bf0efbe..499f345 100644 --- a/microdia-sysfs.c +++ b/microdia-sysfs.c @@ -143,6 +143,7 @@ static ssize_t show_informations(struct device *class, struct device_attribute * "Contrast : 0x%X\n" "Whiteness : 0x%X\n" "Exposure : 0x%X\n" + "Gain : 0x%X\n" "Sharpness : 0x%X\n" "Horizontal flip : %d\n" "Vertical flip : %d\n" @@ -155,6 +156,7 @@ static ssize_t show_informations(struct device *class, struct device_attribute * 0xFFFF & dev->vsettings.contrast, 0xFFFF & dev->vsettings.whiteness, 0xFFFF & dev->vsettings.exposure, + 0xFFFF & dev->vsettings.gain, 0x3F & dev->vsettings.sharpness, dev->vsettings.hflip, dev->vsettings.vflip, @@ -300,6 +302,59 @@ static ssize_t store_exposure(struct device *class, struct device_attribute *att } /** + * @brief show_gain + * + * @param class Class device + * @param attr + * @retval buf Adress of buffer with the 'gain' value + * + * @returns Size of buffer + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +static ssize_t show_gain(struct class_device *class, char *buf) +#else +static ssize_t show_gain(struct device *class, struct device_attribute *attr, char *buf) +#endif +{ + struct video_device *vdev = to_video_device(class); + struct usb_microdia *dev = video_get_drvdata(vdev); + + return sprintf(buf, "%X\n", dev->vsettings.gain); +} + +/** + * @brief store_gain + * + * @param class Class device + * @param buf Buffer + * @param count Counter + * @param attr + * + * @returns Size of buffer + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +static ssize_t store_gain(struct class_device *class, const char *buf, + size_t count) +#else +static ssize_t store_gain(struct device *class, struct device_attribute *attr, + const char *buf, size_t count) +#endif +{ + char *endp; + unsigned long value; + + struct video_device *vdev = to_video_device(class); + struct usb_microdia *dev = video_get_drvdata(vdev); + + value = simple_strtoul(buf, &endp, 16); + + dev->vsettings.gain = (int) value; + + dev_microdia_camera_set_gain(dev); + + return strlen(buf); +} +/** * @brief show_brightness * * @param class Class device @@ -801,7 +856,8 @@ static CLASS_DEVICE_ATTR(informations, S_IRUGO, show_informations, NULL); /* static CLASS_DEVICE_ATTR(fps, S_IRUGO, show_fps, NULL); /**< FPS value */ static CLASS_DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO, show_brightness, store_brightness); /**< Brightness value */ static CLASS_DEVICE_ATTR(rgb_gain, S_IRUGO | S_IWUGO, show_rgb_gain, store_rgb_gain); /**< RGB Gain */ -static CLASS_DEVICE_ATTR(exposure, S_IRUGO | S_IWUGO, show_exposure, store_exposure); /**< Brightness exposure */ +static CLASS_DEVICE_ATTR(exposure, S_IRUGO | S_IWUGO, show_exposure, store_exposure); /**< Exposure time value */ +static CLASS_DEVICE_ATTR(gain, S_IRUGO | S_IWUGO, show_gain, store_gain); /**< Gain value */ static CLASS_DEVICE_ATTR(contrast, S_IRUGO | S_IWUGO, show_contrast, store_contrast); /**< Contrast value */ static CLASS_DEVICE_ATTR(whitebalance, S_IRUGO | S_IWUGO, show_whitebalance, store_whitebalance); /**< Whitebalance value */ static CLASS_DEVICE_ATTR(sharpness, S_IRUGO | S_IWUGO, show_sharpness, store_sharpness); /**< Sharpness value */ @@ -817,7 +873,8 @@ static DEVICE_ATTR(informations, S_IRUGO, show_informations, NULL); /**< In static DEVICE_ATTR(fps, S_IRUGO, show_fps, NULL); /**< FPS value */ static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO, show_brightness, store_brightness); /**< Brightness value */ static DEVICE_ATTR(rgb_gain, S_IRUGO | S_IWUGO, show_rgb_gain, store_rgb_gain); /**< RGB Gain */ -static DEVICE_ATTR(exposure, S_IRUGO | S_IWUGO, show_exposure, store_exposure); /**< Exposure value */ +static DEVICE_ATTR(exposure, S_IRUGO | S_IWUGO, show_exposure, store_exposure); /**< Exposure time value */ +static DEVICE_ATTR(gain, S_IRUGO | S_IWUGO, show_gain, store_gain); /**< Gain value */ static DEVICE_ATTR(contrast, S_IRUGO | S_IWUGO, show_contrast, store_contrast); /**< Contrast value */ static DEVICE_ATTR(whitebalance, S_IRUGO | S_IWUGO, show_whitebalance, store_whitebalance); /**< Whitebalance value */ static DEVICE_ATTR(sharpness, S_IRUGO | S_IWUGO, show_sharpness, store_sharpness); /**< Sharpness value */ @@ -850,6 +907,7 @@ int microdia_create_sysfs_files(struct video_device *vdev) ret = video_device_create_file(vdev, &class_device_attr_brightness); ret = video_device_create_file(vdev, &class_device_attr_rgb_gain); ret = video_device_create_file(vdev, &class_device_attr_exposure); + ret = video_device_create_file(vdev, &class_device_attr_gain); ret = video_device_create_file(vdev, &class_device_attr_contrast); ret = video_device_create_file(vdev, &class_device_attr_whitebalance); ret = video_device_create_file(vdev, &class_device_attr_sharpness); @@ -866,6 +924,7 @@ int microdia_create_sysfs_files(struct video_device *vdev) ret = video_device_create_file(vdev, &dev_attr_brightness); ret = video_device_create_file(vdev, &dev_attr_rgb_gain); ret = video_device_create_file(vdev, &dev_attr_exposure); + ret = video_device_create_file(vdev, &dev_attr_gain); ret = video_device_create_file(vdev, &dev_attr_contrast); ret = video_device_create_file(vdev, &dev_attr_whitebalance); ret = video_device_create_file(vdev, &dev_attr_sharpness); @@ -882,6 +941,7 @@ int microdia_create_sysfs_files(struct video_device *vdev) ret = device_create_file(&vdev->dev, &dev_attr_brightness); ret = device_create_file(&vdev->dev, &dev_attr_rgb_gain); ret = device_create_file(&vdev->dev, &dev_attr_exposure); + ret = device_create_file(&vdev->dev, &dev_attr_gain); ret = device_create_file(&vdev->dev, &dev_attr_contrast); ret = device_create_file(&vdev->dev, &dev_attr_whitebalance); ret = device_create_file(&vdev->dev, &dev_attr_sharpness); @@ -913,6 +973,7 @@ void microdia_remove_sysfs_files(struct video_device *vdev) video_device_remove_file(vdev, &class_device_attr_fps); video_device_remove_file(vdev, &class_device_attr_brightness); video_device_remove_file(vdev, &class_device_attr_exposure); + video_device_remove_file(vdev, &class_device_attr_gain); video_device_remove_file(vdev, &class_device_attr_rgb_gain); video_device_remove_file(vdev, &class_device_attr_contrast); video_device_remove_file(vdev, &class_device_attr_whitebalance); @@ -930,6 +991,7 @@ void microdia_remove_sysfs_files(struct video_device *vdev) video_device_remove_file(vdev, &dev_attr_brightness); video_device_remove_file(vdev, &dev_attr_rgb_gain); video_device_remove_file(vdev, &dev_attr_exposure); + video_device_remove_file(vdev, &dev_attr_gain); video_device_remove_file(vdev, &dev_attr_contrast); video_device_remove_file(vdev, &dev_attr_whitebalance); video_device_remove_file(vdev, &dev_attr_sharpness); @@ -946,6 +1008,7 @@ void microdia_remove_sysfs_files(struct video_device *vdev) device_remove_file(&vdev->dev, &dev_attr_brightness); device_remove_file(&vdev->dev, &dev_attr_rgb_gain); device_remove_file(&vdev->dev, &dev_attr_exposure); + device_remove_file(&vdev->dev, &dev_attr_gain); device_remove_file(&vdev->dev, &dev_attr_contrast); device_remove_file(&vdev->dev, &dev_attr_whitebalance); device_remove_file(&vdev->dev, &dev_attr_sharpness); diff --git a/microdia-v4l.c b/microdia-v4l.c index ce2c206..4d65f87 100644 --- a/microdia-v4l.c +++ b/microdia-v4l.c @@ -103,6 +103,15 @@ static struct v4l2_queryctrl microdia_controls[] = { .default_value = 0x1000, }, { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 0xffff, + .step = 1, + .default_value = 0x0000, + }, + { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Horizontal flip", @@ -828,6 +837,10 @@ int microdia_vidioc_g_ctrl(struct file *file, void *priv, ctrl->value = dev->vsettings.auto_whitebalance; break; + case V4L2_CID_GAIN: + ctrl->value = dev->vsettings.gain; + break; + default: return -EINVAL; } @@ -918,6 +931,11 @@ int microdia_vidioc_s_ctrl(struct file *file, void *priv, dev_microdia_camera_set_auto_whitebalance(dev); break; + case V4L2_CID_GAIN: + dev->vsettings.gain = ctrl->value; + dev_microdia_camera_set_gain(dev); + break; + default: return -EINVAL; } diff --git a/microdia.h b/microdia.h index abc7ef6..d8dae68 100644 --- a/microdia.h +++ b/microdia.h @@ -269,6 +269,7 @@ struct microdia_video { int hue; /**< Hue setting */ int hflip; /**< Horizontal flip */ int vflip; /**< Vertical flip */ + int gain; /**< Gain */ int exposure; /**< Exposure */ int sharpness; /**< Sharpness */ __u8 rgb_gain[4]; /**< RGB Gain (RGGB) */ @@ -358,6 +359,7 @@ struct sensor_info { int (*set_bayer) (struct usb_microdia *dev); int (*set_yuv422) (struct usb_microdia *dev); int (*get_yavg) (struct usb_microdia *dev); + int (*set_gain) (struct usb_microdia *dev); }; static struct sensor_info sensors[]; @@ -461,6 +463,7 @@ int dev_microdia_camera_set_auto_exposure(struct usb_microdia *dev); int dev_microdia_camera_set_auto_gain(struct usb_microdia *dev); int dev_microdia_camera_set_auto_whitebalance(struct usb_microdia *dev); int dev_microdia_perform_soft_ae(struct usb_microdia *dev); +int dev_microdia_camera_set_gain(struct usb_microdia *); /* int dev_microdia_set_camera_quality(struct usb_microdia *);*/ struct v4l2_pix_format *v4l2_enum_supported_formats(struct usb_microdia *, diff --git a/omnivision.c b/omnivision.c index 7cfc230..f80f435 100644 --- a/omnivision.c +++ b/omnivision.c @@ -843,6 +843,55 @@ int ov_set_autogain(struct usb_microdia *dev) } /** + * @brief Set gain for omnivision sensors + * + * @param dev + * + * @returns 0 or negative error value + * + * @author Vasily Khoruzhick + * + * For all Omnivision sensors and SOI968. + */ +int ov_set_gain(struct usb_microdia *dev) +{ + __u8 buf[1]; + int ret = 0; + + buf[0] = (dev->vsettings.gain >> 9) & 0x0F; + UDIA_DEBUG("gain: %d, buf: %d\n", dev->vsettings.gain, buf[0]); + + switch (dev->vsettings.gain >> 9 & 0xF0) { + case 0x00: + break; + case 0x10: + buf[0] |= 0x10; + break; + case 0x20: + buf[0] |= 0x30; + break; + case 0x30: + buf[0] |= 0x70; + break; + case 0x40: + buf[0] |= 0xF0; + break; + default: + buf[0] |= 0xFF; + break; + } + + if (dev->camera.sensor->id == SOI968_SENSOR) { + buf[0] = (buf[0] & 0x3F); + ret |= sn9c20x_write_i2c_data(dev, 1, OV965X_CTL_GAIN, buf); + } else { + ret |= sn9c20x_write_i2c_data(dev, 1, OV965X_CTL_GAIN, buf); + } + + return ret; +} + +/** * @brief Set exposure for SOI968 sensors * * @param dev diff --git a/omnivision.h b/omnivision.h index 391fbf1..5840fb7 100644 --- a/omnivision.h +++ b/omnivision.h @@ -550,4 +550,5 @@ int ov965x_get_yavg(struct usb_microdia *dev); int ov_initialize(struct usb_microdia *dev); int ov_set_autogain(struct usb_microdia *dev); int ov_set_autoexposure(struct usb_microdia *dev); +int ov_set_gain(struct usb_microdia *dev); #endif -- 1.6.0.4
signature.asc
Description: This is a digitally signed message part.
