On 30 November 2008 22:58:26 GWater wrote: > I did send you the modified patch, didn't I? > > If you didn't get it - here it is again. > > GWater
No, you didn't :) Here's slightly modified version Vasily
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.
