On 26 November 2008 21:13:16 Vasily Khoruzhick wrote:
> On 26 November 2008 20:42:00 Vasily Khoruzhick wrote:
> > On 26 November 2008 00:45:20 Vasily Khoruzhick wrote:
> > > Ok, here's patches with software autoexposure enabled for OV7660 and
> > > OV9650 sensors.
> > >
> > > 624f and 627b owners: please, test it
> > >
> > > Regards
> > > Vasily
> >
> > Any chance that my patches will be tested at least on one PC except my?
> > :)
> >
> > JoJo, what about you?
> >
> > Regards
> > Vasily
>
> One more patch to expose gain control to the userspace.

Fixed version of latest patch :) It seems that last bits of GAIN register of 
omnivision sensors has same weight...

Regards
Vasily
From e2d7e3b572708141785d5d5cbfcb073ab10a4253 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]>
---
 microdia-dev.c   |   21 +++++++++++++++++
 microdia-sysfs.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 microdia-v4l.c   |   18 ++++++++++++++
 microdia.h       |    3 ++
 omnivision.c     |   47 +++++++++++++++++++++++++++++++++++++
 omnivision.h     |    1 +
 6 files changed, 155 insertions(+), 2 deletions(-)

diff --git a/microdia-dev.c b/microdia-dev.c
index 622945f..81a7f51 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,
@@ -675,3 +680,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 ad274f6..59b9f10 100644
--- a/microdia-v4l.c
+++ b/microdia-v4l.c
@@ -102,6 +102,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",
@@ -827,6 +836,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;
 	}
@@ -917,6 +930,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 f300116..1c10ff5 100644
--- a/omnivision.c
+++ b/omnivision.c
@@ -843,6 +843,53 @@ 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;
+	printk(KERN_INFO "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;
+	}
+	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.3

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to