Vasily Khoruzhick schrieb:
On 28 November 2008 22:12:07 GWater wrote:Oh, I never got that patch I think. (Otherwise I would have pushed it ;) .)Patch attached :)Anyway - it is correct that we currently don't have any more functions to cover with V4L2 CIDs but this is easy to change. I still can only think of black-level calibration but if we go over the datasheets we may find some other expert stuff.Sounds OK, btw it seems that datasheet for my ov9650 lies too often, even for gain registers :( so I'm afraid I will not be very usefull here.First thing we should think about is how to add V4L2-controls specific for sensors, but not globally.I just keep talking about these things because I really like madwifi and these guys also implemented everything they could find and a bit more. Makes it easier for the users to decide they want and does not bind them to the default settings some developer hardcoded into the driver. GWater BTW The AUTO-exposure CID I put in there only works for >=2.6.25 . I'll try to fix this. GWaterVasily
I tested your patch and while it basically change exposure it also made some problems. Mostly because the registers of the sensorsare not the same. (Do you have all the omnivision datasheets - if not I can mailthem to you, including one that has always worked for SOI968.)
So my question is - did you check whether your function ov_set_gain actually works for all these sensors? If not I would remove the "links".
GWater I attached a changed version of your patch that works for me. GWater
From 72631226bde93112cb7aa13fc9e44b91f698f1f9 Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <[EMAIL PROTECTED]>
Date: Wed, 26 Nov 2008 22:39:41 +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 | 52 +++++++++++++++++++++++++++++++++++++++++
omnivision.h | 1 +
6 files changed, 160 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 d85eb67..de65b3c 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..2884efd 100644
--- a/omnivision.c
+++ b/omnivision.c
@@ -843,6 +843,58 @@ 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);
+ ret |= sn9c20x_read_i2c_data(dev, 1, OV965X_CTL_VREF, buf);
+ buf[0] = (buf[0] & 0x3F);
+ ret |= sn9c20x_write_i2c_data(dev, 1, OV965X_CTL_VREF, 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: OpenPGP digital signature
