Vasily Khoruzhick schrieb:
On 30 November 2008 22:51:04 GWater wrote:
Vasily Khoruzhick schrieb:
On 29 November 2008 11:10:38 GWater wrote:
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.
GWater
Vasily
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
It should work at least for ov96xx and ov76xx sensors, I have no
datasheet for SOI968, so I've assumed it's the same
Do you want to push it or are more modifications necessary? You have my GO.

GWater

Nope, gain adjustment for SOI968 should be done in another way (only 5 bits of GAIN register should be affected)

I did send you the modified patch, didn't I?

If you didn't get it - here it is again.

GWater
From d7a8f5b33c338b72fd793696030c1e8901445a66 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 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..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

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to