New version withz support for 6270 and 62b0.Now al that's missing are the functions to support YUV422 and bayer for sensors which offer both.
Therefore the next patch will be the final version if no one steps up and tells me how completely inefficient and disturbing my changes are.
Come guys - test this. GWaterBTW: I noticed sn9c20x_set_raw() doesn't work properly. Sometimes I only get a lot of snow. a bridge.dump shows that JPEG encoding is selected instead of raw output. This problem existed before I wrote this patch. I just researched it a bit deeper right now.
GWater schrieb:
A fixed version which makes basic video capturing possible again. (Applies on origin/development.)I included Brian's new "struct microdia_video_format" and the necessary changes. Maybe we should split this into a seperate patch lateron.Anyway - I spent the night rebooting my computer because some wrong pointer kept crashing my kernel. Either my computer is so twisted now that it can work with NULL dereferences or it actually works ;) .Please test it and post some ideas what should be done differently. I am sure my "default_fmts" array has some disadvantages and better I learn them now than later.GWater GWater schrieb:We had some problems with sensor probing and decided to use a new procdure.Here is my second try to solve that. The first two paches are not vital but I didn't want to rebase.It currently breaks the module since I have no idea how to assign the correct formats and resolutions. I also remeber Brian had developed a new system for to make YUV422 work. Maybe we can include this right now.Let's get this over done. GWater
From d6a3b66f309a300ab7189dbb6b6181426f5e8ed6 Mon Sep 17 00:00:00 2001
From: GWater <[EMAIL PROTECTED]>
Date: Sat, 22 Nov 2008 13:39:43 +0100
Subject: [PATCH] New system regarding sensor assignment
Sensors are now assigned using the dev_microdia_assign_sensor()
function.
Sensor initilization is seperated from that and probing has been removed
- new probing mechanism for 6270 and 67b0.
Brian Johnson's new "struct microdia_video_format" is introduced with
all
the necessary changes to resolution checking and applying. It will allow
support for YUV422 in the future.
FIXME:
- Only basic colorspace selection (JPEG and RAW). Sensor based functions
have yet to be introduced.
Signed-off-by: GWater <[EMAIL PROTECTED]>
---
microdia-dev.c | 232 ++++++++++++++++++++++++++++++++++++++++++++------------
microdia-v4l.c | 3 +
microdia.h | 58 +++++++++------
micron.c | 222 ++++++++----------------------------------------------
micron.h | 9 +--
omnivision.c | 221 ++++++++++++-----------------------------------------
omnivision.h | 3 +-
sn9c20x.c | 101 ++++++++++++------------
8 files changed, 356 insertions(+), 493 deletions(-)
diff --git a/microdia-dev.c b/microdia-dev.c
index f3cdf4d..1915180 100644
--- a/microdia-dev.c
+++ b/microdia-dev.c
@@ -33,63 +33,223 @@
#include "omnivision.h"
#include "micron.h"
-struct sensor_info sensors[] = {
+static struct sensor_info sensors[] = {
{
.id = OV9650_SENSOR,
.name = "OV9650",
.address = 0x30,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .hstart = 0,
+ .vstart = 7,
+ .set_hvflip = ov965x_set_hvflip,
+ .set_exposure = ov965x_set_exposure,
+ .set_auto_exposure = ov965x_set_autoexposure,
+ .flip_detect = ov965x_flip_detect,
},
{
.id = OV9655_SENSOR,
.name = "OV9655",
.address = 0x30,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .hstart = 0,
+ .vstart = 7,
},
{
.id = SOI968_SENSOR,
.name = "SOI968",
.address = 0x30,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .set_exposure = soi968_set_exposure,
+ .set_auto_exposure = ov965x_set_autoexposure,
+ .hstart = 60,
+ .vstart = 11,
},
{
.id = OV7660_SENSOR,
.name = "OV7660",
.address = 0x21,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .set_exposure = ov7660_set_exposure,
+ .set_auto_exposure = ov7660_set_autoexposure,
+ .hstart = 1,
+ .vstart = 1,
},
{
.id = OV7670_SENSOR,
.name = "OV7670",
.address = 0x21,
- .probe = ov_probe
- },
- {
- .id = MT9M111_SENSOR,
- .name = "MT9M111",
- .address = 0x5d,
- .probe = mt9m111_probe
+ .initialize = ov_initialize,
+ .flip_detect = ov7670_flip_detect,
+ .hstart = 0,
+ .vstart = 1,
},
{
.id = MT9V111_SENSOR,
.name = "MT9V111",
.address = 0x5c,
- .probe = mt9v111_probe
+ .initialize = mt9v111_initialize,
+ .set_hvflip = mt9v111_set_hvflip,
+ .set_exposure = mt9v111_set_exposure,
+ .set_auto_exposure = mt9v111_set_autoexposure,
+ .hstart = 2,
+ .vstart = 2,
+ },
+ {
+ .id = MT9M111_SENSOR,
+ .name = "MT9M111",
+ .address = 0x5d,
+ .initialize = mt9m111_initialize,
+ .hstart = 6,
+ .vstart = 2,
},
{
.id = MT9V011_SENSOR,
.name = "MT9V011",
.address = 0x5d,
- .probe = mt9v011_probe
+ .initialize = mt9v011_initialize,
+ .set_hvflip = mt9v011_set_hvflip,
+ .set_exposure = mt9v011_set_exposure,
+ .hstart = 2,
+ .vstart = 2,
},
{
.id = MT9M001_SENSOR,
.name = "MT9M001",
.address = 0x5d,
- .probe = mt9m001_probe
+ .initialize = mt9m001_initialize,
+ .hstart = 2,
+ .vstart = 2,
},
};
+static __u16 known_cams[][2] = {
+ {0x6240, MT9M001_SENSOR},
+ {0x6242, MT9M111_SENSOR},
+ {0x6248, OV9655_SENSOR},
+ {0x624e, SOI968_SENSOR},
+ {0x624f, OV9650_SENSOR},
+ {0x6253, OV9650_SENSOR},
+ {0x6260, OV7670_SENSOR},
+ {0x627b, OV7660_SENSOR},
+ {0x627f, OV9650_SENSOR},
+ {0x6288, OV9655_SENSOR},
+ {0x628e, SOI968_SENSOR},
+ {0x62a0, OV7670_SENSOR},
+ {0x62b3, OV9655_SENSOR},
+ {0x62bb, OV7660_SENSOR},
+};
+
+int dev_microdia_assign_sensor(struct usb_microdia *dev)
+{
+ int i, j, ret;
+ __u16 pid = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+ for (i = 0; i < ARRAY_SIZE(known_cams); i++) {
+ if (pid == known_cams[i][0]) {
+ for (j = 0; j < ARRAY_SIZE(sensors); j++) {
+ if (known_cams[i][1] == sensors[j].id) {
+ dev->camera.sensor = &(sensors[j]);
+ return 0;
+ }
+ }
+ }
+ }
+
+ if ((pid == 0x6270) || (pid == 0x62b0)) {
+ ret = micron_probe(dev);
+ for (j = 0; j < ARRAY_SIZE(sensors); j++) {
+ if (ret == sensors[j].id) {
+ dev->camera.sensor = &(sensors[j]);
+ return 0;
+ }
+ }
+ }
+
+ UDIA_ERROR("Could not assign sensor: "
+ "Please report to [email protected] .\n");
+
+ return -EINVAL;
+}
+
+int dev_microdia_initialize_sensor(struct usb_microdia *dev)
+{
+ int ret = -ENODEV;
+ if (dev && dev->camera.sensor->initialize)
+ ret = dev->camera.sensor->initialize(dev);
+ return ret;
+}
+
+static struct microdia_video_format default_fmts[] = {
+ {
+ .pix_fmt = V4L2_PIX_FMT_SBGGR8,
+ .desc = "Bayer 8bit (BGGR)",
+ .depth = 8,
+ .modes = {
+ {160, 120, SN9C20X_1_4_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 160, 120}},
+ {320, 240, SN9C20X_1_2_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 320, 240}},
+ {640, 480, SN9C20X_NO_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 640, 480}},
+ },
+ .set_format = sn9c20x_set_raw
+ },
+ {
+ .pix_fmt = V4L2_PIX_FMT_JPEG,
+ .desc = "JPEG (YUV 4:2:2)",
+ .depth = 16,
+ .modes = {
+ {160, 120, SN9C20X_1_4_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 160, 120}},
+ {320, 240, SN9C20X_1_2_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 320, 240}},
+ {640, 480, SN9C20X_NO_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 640, 480}},
+ },
+ .set_format = sn9c20x_set_jpeg
+ },
+ {
+ .pix_fmt = V4L2_PIX_FMT_YUYV,
+ .desc = "YUV 4:2:2 (YUYV)",
+ .depth = 16,
+ .modes = {
+ {160, 120, SN9C20X_1_4_SCALE,
+ {0, 0, 1280, 480},
+ {0, 0, 320, 120}},
+ {320, 240, SN9C20X_1_2_SCALE,
+ {0, 0, 1280, 480},
+ {0, 0, 640, 240}},
+ {640, 480, SN9C20X_NO_SCALE,
+ {0, 0, 1280, 480},
+ {0, 0, 1280, 480}},
+ },
+ .set_format = NULL
+ },
+};
+
+int dev_microdia_assign_fmts(struct usb_microdia *dev)
+{
+ int i, j;
+
+ dev->camera.fmts = default_fmts;
+ dev->camera.nfmts = ARRAY_SIZE(default_fmts);
+
+ for (i = 0; i < ARRAY_SIZE(default_fmts); i++) {
+ for (j = 0; j < N_MODES; j++) {
+ dev->camera.fmts[i].modes[j].hw_window[0] =
dev->camera.sensor->hstart;
+ dev->camera.fmts[i].modes[j].hw_window[1] =
dev->camera.sensor->vstart;
+ }
+ }
+
+ return 0;
+}
+
/**
* @brief Wrapper function for camera-setting functions
*
@@ -169,8 +329,8 @@ int dev_microdia_camera_set_gamma(struct usb_microdia *dev)
*/
int dev_microdia_camera_set_exposure(struct usb_microdia *dev)
{
- if (dev && dev->camera.set_exposure != NULL)
- return dev->camera.set_exposure(dev);
+ if (dev && dev->camera.sensor->set_exposure != NULL)
+ return dev->camera.sensor->set_exposure(dev);
return 0;
}
@@ -186,8 +346,8 @@ int dev_microdia_camera_set_exposure(struct usb_microdia
*dev)
int dev_microdia_camera_set_hvflip(struct usb_microdia *dev)
{
int ret = -ENODEV;
- if (dev && dev->camera.set_hvflip)
- ret = dev->camera.set_hvflip(dev);
+ if (dev && dev->camera.sensor->set_hvflip)
+ ret = dev->camera.sensor->set_hvflip(dev);
return ret;
}
@@ -237,8 +397,8 @@ int dev_microdia_camera_set_rgb_gain(struct usb_microdia
*dev)
int dev_microdia_camera_set_auto_exposure(struct usb_microdia *dev)
{
int ret = -ENODEV;
- if (dev && dev->camera.set_auto_exposure)
- ret = dev->camera.set_auto_exposure(dev);
+ if (dev && dev->camera.sensor->set_auto_exposure)
+ ret = dev->camera.sensor->set_auto_exposure(dev);
return ret;
}
@@ -254,39 +414,13 @@ int dev_microdia_camera_set_auto_exposure(struct
usb_microdia *dev)
int dev_microdia_camera_set_auto_whitebalance(struct usb_microdia *dev)
{
int ret = -ENODEV;
- if (dev && dev->camera.set_auto_whitebalance)
- ret = dev->camera.set_auto_whitebalance(dev);
+ if (dev && dev->camera.sensor->set_auto_whitebalance)
+ ret = dev->camera.sensor->set_auto_whitebalance(dev);
return ret;
}
/**
- * @brief function to probe sensor attached to bridge
- *
- * @param dev pointer to device structure
- *
- * @returns 0 or negative error value
- *
- * This function will probe the bridge for the proper sensor
- */
-int dev_microdia_probe_sensor(struct usb_microdia *dev)
-{
- int i, ret;
- dev->camera.sensor_flags = SN9C20X_I2C_2WIRE;
-
- for (i = 0; i < ARRAY_SIZE(sensors); i++) {
- dev->camera.sensor_slave_address = sensors[i].address;
- ret = sensors[i].probe(dev);
- if (ret == sensors[i].id) {
- UDIA_INFO("Detected sensor: %s\n", sensors[i].name);
- return ret;
- }
- }
-
- return UNKNOWN_SENSOR;
-}
-
-/**
* @brief Wrapper function for device-specific initialization functions
*
* @param dev Pointer to device structure
diff --git a/microdia-v4l.c b/microdia-v4l.c
index 8ecb94e..b8d965a 100644
--- a/microdia-v4l.c
+++ b/microdia-v4l.c
@@ -965,6 +965,9 @@ int microdia_vidioc_try_fmt_cap(struct file *file, void
*priv,
if (index >= dev->camera.nfmts)
return -EINVAL;
+ if (dev->camera.fmts[index].set_format == NULL)
+ return -EINVAL;
+
sn9c20x_get_closest_resolution(dev, &fmt->fmt.pix.width,
&fmt->fmt.pix.height);
diff --git a/microdia.h b/microdia.h
index 09f3e9f..86eb11f 100644
--- a/microdia.h
+++ b/microdia.h
@@ -317,58 +317,70 @@ enum microdia_sensors {
struct usb_microdia;
+#define N_MODES 3
+
+struct microdia_video_mode {
+ __u16 width;
+ __u16 height;
+ __u8 scale;
+ __u16 hw_window[4];
+ __u16 clr_window[4];
+};
+
struct microdia_video_format {
__u32 pix_fmt;
char desc[32];
__u8 depth;
+ struct microdia_video_mode modes[N_MODES];
int (*set_format) (struct usb_microdia *dev);
};
-struct microdia_video_resolution {
- __u16 width;
- __u16 height;
- __u8 scale;
- __u16 window[4];
-};
-
struct sensor_info {
__u8 id;
__u8 *name;
__u8 address;
- int (*probe) (struct usb_microdia *dev);
+
+ int vstart;
+ int hstart;
+
+/* sensor specific functions */
+ int (*initialize) (struct usb_microdia *dev);
+ int (*set_exposure) (struct usb_microdia *dev);
+ int (*set_auto_exposure) (struct usb_microdia *dev);
+ int (*set_auto_whitebalance) (struct usb_microdia *dev);
+ int (*flip_detect) (struct usb_microdia *dev);
+ int (*set_hvflip) (struct usb_microdia *dev);
+ int (*set_bayer) (struct usb_microdia *dev);
+ int (*set_yuv422) (struct usb_microdia *dev);
};
-extern struct sensor_info sensors[];
+static struct sensor_info sensors[];
struct microdia_camera {
- __u8 sensor_slave_address;
- __u8 sensor_flags;
- __u8 sensor;
-
/* supported resolutions */
__u8 nmodes;
- struct microdia_video_resolution *modes;
+ struct microdia_video_mode *modes;
+
/* supported video formats */
__u8 nfmts;
struct microdia_video_format *fmts;
+/* image sensor */
+ struct sensor_info *sensor;
+
+/* SCCB/I2C interface */
+ __u8 i2c_flags;
+
/* bridge functions */
- int (*initialize) (struct usb_microdia *dev);
int (*enable_video) (struct usb_microdia *dev, int enable);
/* image quality functions */
-
int (*set_contrast) (struct usb_microdia *dev);
int (*set_brightness) (struct usb_microdia *dev);
int (*set_gamma) (struct usb_microdia *dev);
- int (*set_exposure) (struct usb_microdia *dev);
- int (*flip_detect) (struct usb_microdia *dev);
- int (*set_hvflip) (struct usb_microdia *dev);
int (*set_sharpness) (struct usb_microdia *dev);
int (*set_rgb_gain) (struct usb_microdia *dev);
- int (*set_auto_exposure) (struct usb_microdia *dev);
- int (*set_auto_whitebalance) (struct usb_microdia *dev);
};
/**
@@ -424,7 +436,9 @@ void usb_microdia_delete(struct kref *);
int dev_microdia_initialize_device(struct usb_microdia *, __u32 flags);
-int dev_microdia_probe_sensor(struct usb_microdia *);
+int dev_microdia_assign_sensor(struct usb_microdia *dev);
+int dev_microdia_assign_fmts(struct usb_microdia *dev);
+int dev_microdia_initialize_sensor(struct usb_microdia *dev);
int dev_microdia_enable_video(struct usb_microdia *, int);
int dev_microdia_camera_settings(struct usb_microdia *);
int dev_microdia_camera_set_contrast(struct usb_microdia *);
diff --git a/micron.c b/micron.c
index cc70fec..396a4c3 100644
--- a/micron.c
+++ b/micron.c
@@ -29,100 +29,6 @@
#include "sn9c20x.h"
#include "micron.h"
-
-struct microdia_video_format mt9x0xx_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = sn9c20x_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_format mt9m111_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = mt9m111_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_YUYV,
- .desc = "YUV 4:2:2",
- .depth = 16,
- .set_format = mt9m111_set_yuv422
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_format mt9v111_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = sn9c20x_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_resolution micron_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {2, 2, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {2, 2, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {2, 2, 640, 480}
- },
-};
-
-struct microdia_video_resolution mt9m111_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {6, 2, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {6, 2, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {6, 2, 640, 480}
- },
-};
-
static __u8 mt9v111_init[][3] = {
/* 0x0d: Color Correction Register 8 */
{0x0d, 0x00, 0x01},
@@ -481,35 +387,6 @@ int mt9v111_initialize(struct usb_microdia *dev)
return ret;
}
-int mt9v011_probe(struct usb_microdia *dev)
-{
- __u8 buf[2];
- int ret;
-
- ret = sn9c20x_read_i2c_data(dev, 2, 0xff, buf);
- if (ret == 0) {
- if (buf[0] != 0x82)
- return -EINVAL;
- if (buf[1] == 0x43) {
- mt9v011_initialize(dev);
- dev->camera.set_hvflip = mt9v011_set_hvflip;
- dev->camera.set_exposure = mt9v011_set_exposure;
- dev->camera.modes = micron_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(micron_resolutions);
- dev->camera.fmts = mt9x0xx_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9x0xx_fmts);
- return MT9V011_SENSOR;
- }
- }
-
- /** NOTE: DNT DigiMicro 1.3 (microscope camera):
- * This device uses sensor MT9V111, but slave 0x5d is also successfully
- * read. Registers 0x00, 0x36 and 0xff of slave 0x5d return chip version
- * 0x0000. */
-
- return -EINVAL;
-}
-
int mt9v111_select_address_space(struct usb_microdia *dev, __u8 address_space)
{
__u8 buf[2];
@@ -564,36 +441,47 @@ int mt9v111_select_address_space(struct usb_microdia
*dev, __u8 address_space)
return 0;
}
-int mt9v111_probe(struct usb_microdia *dev)
+int micron_probe(struct usb_microdia *dev)
{
- __u8 buf[2];
+ __u16 buf, old;
int ret;
+ static struct sensor_info dummy;
+ dev->camera.sensor = &dummy;
+
+ dev->camera.sensor->address = 0x5d;
+
+ ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
+
+ if ((ret == 0) || (buf == 0x8243)) {
+ return MT9V011_SENSOR;
+ }
+
+ /** NOTE: DNT DigiMicro 1.3 (microscope camera):
+ * This device uses sensor MT9V111, but slave 0x5d is also successfully
+ * read. Registers 0x00, 0x36 and 0xff of slave 0x5d return chip version
+ * 0x0000. */
+
+ /* MT9V111 has a different address */
+ dev->camera.sensor->address = 0x5c;
+
+ /* Store old address-space */
+ ret = sn9c20x_read_i2c_data16(dev, 2, 0x01, &old);
+ if (ret != 0)
+ return ret;
+
/* Select address-space: sensor */
- buf[0] = 0x00; buf[1] = MT9V111_ADDRESSSPACE_SENSOR;
- ret = sn9c20x_write_i2c_data(dev, 2, 0x01, buf);
+ buf = MT9V111_ADDRESSSPACE_SENSOR & 0x00ff;
+ ret = sn9c20x_write_i2c_data16(dev, 2, 0x01, &buf);
if (ret != 0)
return ret;
- ret = sn9c20x_read_i2c_data(dev, 2, 0xff, buf);
- if (ret == 0) {
- if (buf[0] != 0x82)
- return -EINVAL;
- if (buf[1] == 0x3a) {
- mt9v111_initialize(dev);
- dev->camera.set_hvflip = mt9v111_set_hvflip;
- dev->camera.set_exposure = mt9v111_set_exposure;
- dev->camera.set_auto_exposure =
mt9v111_set_autoexposure;
- dev->camera.modes = micron_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(micron_resolutions);
- dev->camera.fmts = mt9v111_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9v111_fmts);
- return MT9V111_SENSOR;
- }
+ ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
+ if ((ret == 0) || (buf == 0x823a)) {
+ sn9c20x_write_i2c_data16(dev, 2, 0x01, &old);
+ return MT9V111_SENSOR;
}
- /** FIXME: always switch back to last register address space */
-
return -EINVAL;
}
@@ -626,27 +514,6 @@ int mt9m001_initialize(struct usb_microdia *dev)
return ret;
}
-int mt9m001_probe(struct usb_microdia *dev)
-{
- int ret;
- __u8 buf[2];
- ret = sn9c20x_read_i2c_data(dev, 2, 0x00, buf);
- if (ret == 0) {
- if (buf[0] != 0x84)
- return -EINVAL;
- if (buf[1] == 0x31) {
- mt9m001_initialize(dev);
- dev->camera.modes = micron_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(micron_resolutions);
- dev->camera.fmts = mt9x0xx_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9x0xx_fmts);
- return MT9M001_SENSOR;
- }
- }
-
- return -EINVAL;
-}
-
/**
* @brief Initialize mt9m111 sensors
*
@@ -680,31 +547,6 @@ int mt9m111_initialize(struct usb_microdia *dev)
return ret;
}
-int mt9m111_probe(struct usb_microdia *dev)
-{
- int ret;
- __u8 buf[2] = {0x00, 0x00};
-
- /* Select address-space: Sensor */
- sn9c20x_write_i2c_data(dev, 2, 0xf0, buf);
-
- ret = sn9c20x_read_i2c_data(dev, 2, 0x00, buf);
- if (ret == 0) {
- if (buf[0] != 0x14)
- return -EINVAL;
- if (buf[1] == 0x3a) {
- mt9m111_initialize(dev);
- dev->camera.modes = mt9m111_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(mt9m111_resolutions);
- dev->camera.fmts = mt9m111_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9m111_fmts);
- return MT9M111_SENSOR;
- }
- }
-
- return -EINVAL;
-}
-
int mt9m111_set_raw(struct usb_microdia *dev)
{
__u16 buf;
diff --git a/micron.h b/micron.h
index 4e2ee99..ea3cac6 100644
--- a/micron.h
+++ b/micron.h
@@ -98,7 +98,6 @@
#define MT9V111_IFP_AWB_WINBOUNDARY_BOTTOM(x) (((x/32) & 0xf) << 12)
/* bottom boundary of AWB meas. window */
int mt9v111_select_address_space(struct usb_microdia *dev, __u8 address_space);
-int mt9v111_probe(struct usb_microdia *dev);
int mt9v111_initialize(struct usb_microdia *dev);
int mt9v111_setup_autoexposure(struct usb_microdia *dev);
int mt9v111_setup_autowhitebalance(struct usb_microdia *dev);
@@ -107,18 +106,16 @@ int mt9v111_set_hvflip(struct usb_microdia *dev);
int mt9v111_set_autoexposure(struct usb_microdia *dev);
int mt9v111_set_autowhitebalance(struct usb_microdia *dev);
int mt9v111_set_autocorrections(struct usb_microdia *dev, int enable);
-int mt9v111_set_yuv422(struct usb_microdia *dev);
-int mt9v111_set_raw(struct usb_microdia *dev);
int mt9v011_set_exposure(struct usb_microdia *dev);
int mt9v011_set_hvflip(struct usb_microdia *dev);
int mt9v011_initialize(struct usb_microdia *dev);
-int mt9v011_probe(struct usb_microdia *dev);
-int mt9m111_probe(struct usb_microdia *dev);
int mt9m111_set_raw(struct usb_microdia *dev);
int mt9m111_set_yuv422(struct usb_microdia *dev);
+int mt9m111_initialize(struct usb_microdia *dev);
-int mt9m001_probe(struct usb_microdia *dev);
+int mt9m001_initialize(struct usb_microdia *dev);
+int micron_probe(struct usb_microdia *dev);
#endif
diff --git a/omnivision.c b/omnivision.c
index 36eb280..bbc6d27 100644
--- a/omnivision.c
+++ b/omnivision.c
@@ -499,195 +499,70 @@ static __u8 ov9655_init[][2] = {
{0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
};
-struct microdia_video_format ov_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = sn9c20x_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_resolution ov965x_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {0, 17, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {0, 7, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {0, 7, 640, 480}
- },
-};
-
-struct microdia_video_resolution soi968_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {60, 17, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {60, 11, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {60, 11, 640, 480}
- },
-};
-
-struct microdia_video_resolution ov7670_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {0, 1, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {0, 1, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {0, 1, 640, 480}
- },
-};
-
-struct microdia_video_resolution ov7660_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {1, 1, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {1, 1, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {1, 1, 640, 480}
- },
-};
-
-int ov_probe(struct usb_microdia *dev)
-{
- int ret;
- __u8 buf[2];
- ret = sn9c20x_read_i2c_data(dev, 2, 0x0a, buf);
- if (ret == 0) {
- if (buf[0] != 0x76 && buf[0] != 0x96)
- return -EINVAL;
- if (buf[1] == 0x60) {
- ov_initialize(dev, ov7660_init,
ARRAY_SIZE(ov7660_init));
- dev->camera.set_exposure = ov7660_set_exposure;
- dev->camera.set_auto_exposure = ov7660_set_autoexposure;
- dev->camera.modes = ov7660_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov7660_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV7660_SENSOR;
- }
- if (buf[1] == 0x70) {
- ov_initialize(dev, ov7670_init,
ARRAY_SIZE(ov7670_init));
- dev->camera.flip_detect = ov7670_flip_detect;
- dev->camera.modes = ov7670_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov7670_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV7670_SENSOR;
- }
- if (buf[1] == 0x52) {
- ov_initialize(dev, ov9650_init,
ARRAY_SIZE(ov9650_init));
- dev->camera.set_hvflip = ov965x_set_hvflip;
- dev->camera.set_exposure = ov965x_set_exposure;
- dev->camera.set_auto_exposure = ov965x_set_autoexposure;
- dev->camera.flip_detect = ov965x_flip_detect;
- dev->camera.modes = ov965x_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov965x_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV9650_SENSOR;
- }
- if (buf[1] == 0x56 || buf[1] == 0x57) {
- ov_initialize(dev, ov9655_init,
ARRAY_SIZE(ov9655_init));
- dev->camera.modes = ov7670_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov7670_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV9655_SENSOR;
- }
- if (buf[1] == 0x28) {
- ov_initialize(dev, soi968_init,
ARRAY_SIZE(soi968_init));
- dev->camera.set_exposure = soi968_set_exposure;
- dev->camera.set_auto_exposure = ov965x_set_autoexposure;
- dev->camera.modes = soi968_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(soi968_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return SOI968_SENSOR;
- }
- }
-
- return -EINVAL;
-}
-
/**
* @brief Initialize ov sensors
*
* @param dev Pointer to device structure
- * @param ov_init Data array for initialization
- * @param array_size size of ov_init
*
* @return 0 or negative error code
*
*/
-int ov_initialize(struct usb_microdia *dev, __u8 ov_init[][2], int array_size)
+int ov_initialize(struct usb_microdia *dev)
{
int i;
int ret = 0;
- __u8 value, reg;
- for (i = 0; i < array_size; i++) {
- reg = ov_init[i][0];
- value = ov_init[i][1];
- ret = sn9c20x_write_i2c_data(dev, 1, reg, &value);
- if (ret < 0) {
- UDIA_INFO("Sensor Init Error (%d). line %d\n", ret, i);
- break;
- }
+ switch (dev->camera.sensor->id) {
+ case SOI968_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ soi968_init[i][0], &soi968_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV9650_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov9650_init[i][0], &ov9650_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV9655_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov9655_init[i][0], &ov9655_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV7670_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov7670_init[i][0], &ov7670_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV7660_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov7660_init[i][0], &ov7660_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+
+ default:
+ return -EINVAL;
}
return ret;
+err:
+ UDIA_ERROR("Sensor Init failed (%d)! - line %d\n", ret, i);
+ return ret;
}
/**
diff --git a/omnivision.h b/omnivision.h
index e08092a..1403a18 100644
--- a/omnivision.h
+++ b/omnivision.h
@@ -547,7 +547,6 @@ int ov965x_set_exposure(struct usb_microdia *);
int ov965x_set_autoexposure(struct usb_microdia *dev);
int ov965x_flip_detect(struct usb_microdia *dev);
-int ov_probe(struct usb_microdia *dev);
-int ov_initialize(struct usb_microdia *dev, __u8 ov_init[][2], int array_size);
+int ov_initialize(struct usb_microdia *dev);
#endif
diff --git a/sn9c20x.c b/sn9c20x.c
index a26ae01..5db2d3d 100644
--- a/sn9c20x.c
+++ b/sn9c20x.c
@@ -44,7 +44,7 @@
*/
int sn9c20x_initialize(struct usb_microdia *dev)
{
- int ret, i, sensor;
+ int ret, i;
__u16 reg;
__u8 value;
@@ -77,7 +77,7 @@ int sn9c20x_initialize(struct usb_microdia *dev)
{0x10f8, 0x14},
{0x10fa, 0xff},
{0x10f9, 0x00},
- {0x11ba, 0x0e},
+ {0x11ba, 0x0a},
{0x11a5, 0x2d},
{0x11a6, 0x2d},
{0x11a7, 0x3a},
@@ -99,15 +99,6 @@ int sn9c20x_initialize(struct usb_microdia *dev)
{0x11bf, 0x00},
};
- __u8 lens_gain[48] = {
- 0x10, 0x21, 0x34, 0x40, 0x47, 0x4f, 0x57, 0x5f,
- 0x64, 0x68, 0x6d, 0x73, 0x79, 0x80, 0x89, 0x97,
- 0x0d, 0x1c, 0x2a, 0x33, 0x38, 0x3d, 0x44, 0x4a,
- 0x4e, 0x52, 0x56, 0x5b, 0x61, 0x68, 0x6f, 0x7a,
- 0x0d, 0x1a, 0x2a, 0x31, 0x36, 0x3b, 0x41, 0x47,
- 0x4a, 0x4e, 0x53, 0x58, 0x5d, 0x64, 0x6b, 0x76
- };
-
__u8 qtable1[64] = {
0x0d, 0x08, 0x08, 0x0d, 0x08, 0x08, 0x0d, 0x0d,
0x0d, 0x0d, 0x11, 0x0d, 0x0d, 0x11, 0x15, 0x21,
@@ -148,10 +139,6 @@ int sn9c20x_initialize(struct usb_microdia *dev)
if (ret < 0)
goto err;
- ret = sn9c20x_i2c_initialize(dev);
- if (ret < 0)
- goto err;
-
dev->camera.enable_video = sn9c20x_enable_video;
dev->camera.set_contrast = sn9c20x_set_contrast;
@@ -160,21 +147,23 @@ int sn9c20x_initialize(struct usb_microdia *dev)
dev->camera.set_sharpness = sn9c20x_set_sharpness;
dev->camera.set_rgb_gain = sn9c20x_set_rgb_gain;
- sensor = dev_microdia_probe_sensor(dev);
- if (sensor == UNKNOWN_SENSOR) {
- UDIA_ERROR("Failed to detect sensor.\n");
- ret = -ENODEV;
+ ret = dev_microdia_assign_sensor(dev);
+ if (ret < 0)
goto err;
- }
- dev->camera.sensor = sensor;
- if (!(sensor == OV9650_SENSOR || sensor == OV9655_SENSOR))
- memset(lens_gain, 0x00, 48);
+ ret = sn9c20x_i2c_initialize(dev);
+ if (ret < 0)
+ goto err;
- ret = usb_microdia_control_write(dev, 0x11c0, lens_gain, 48);
+ ret = dev_microdia_initialize_sensor(dev);
if (ret < 0)
goto err;
+ /** FIXME: Assign sensor-specific reslutions and formats
+ * Brian developed a new system for that with his YUV422
+ * patch for OV sensors. */
+ dev_microdia_assign_fmts(dev);
+
return 0;
err:
@@ -231,7 +220,7 @@ int sn9c20x_set_LEDs(struct usb_microdia *dev, int enable)
int ret;
__u8 led[2];
- int sensor = dev->camera.sensor;
+ int sensor = dev->camera.sensor->id;
if (enable) {
switch (sensor) {
@@ -303,8 +292,10 @@ int sn9c20x_i2c_initialize(struct usb_microdia *dev)
__u8 buf[9];
int ret;
- buf[0] = dev->camera.sensor_flags;
- buf[1] = dev->camera.sensor_slave_address;
+ dev->camera.i2c_flags = SN9C20X_I2C_2WIRE;
+
+ buf[0] = dev->camera.i2c_flags;
+ buf[1] = dev->camera.sensor->address;
buf[2] = 0x00;
buf[3] = 0x00;
buf[4] = 0x00;
@@ -383,9 +374,9 @@ int sn9c20x_read_i2c_data(struct usb_microdia *dev, __u8
nbytes,
memset(row, 0, 5);
/* now we issue the same command but with the read bit set
* and no slave register address */
- dev->camera.sensor_flags |= SN9C20X_I2C_READ;
+ dev->camera.i2c_flags |= SN9C20X_I2C_READ;
ret = sn9c20x_write_i2c_data(dev, nbytes - 1, 0, row);
- dev->camera.sensor_flags &= ~SN9C20X_I2C_READ;
+ dev->camera.i2c_flags &= ~SN9C20X_I2C_READ;
if (ret < 0)
return ret;
@@ -455,8 +446,8 @@ int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8
nbytes,
/* from the point of view of the bridge, the length
* includes the address */
- row[0] = dev->camera.sensor_flags | ((nbytes + 1) << 4);
- row[1] = dev->camera.sensor_slave_address;
+ row[0] = dev->camera.i2c_flags | ((nbytes + 1) << 4);
+ row[1] = dev->camera.sensor->address;
row[2] = address;
row[7] = 0x10; /* I think this means we want an ack */
@@ -464,19 +455,19 @@ int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8
nbytes,
row[i + 3] = i < nbytes ? data[i] : 0;
UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread :
waswrite), address,
+ (dev->camera.i2c_flags & SN9C20X_I2C_READ ? wasread :
waswrite), address,
row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
ret = usb_microdia_control_write(dev, 0x10c0, row, 8);
if (ret >= 0)
ret = sn9c20x_i2c_ack_wait(dev,
- dev->camera.sensor_flags & SN9C20X_I2C_400KHZ,
+ dev->camera.i2c_flags & SN9C20X_I2C_400KHZ,
&slave_error);
if (slave_error) {
UDIA_ERROR("I2C slave 0x%02x returned error during %s address
0x%02x\n",
- dev->camera.sensor_slave_address,
- (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread
: waswrite),
+ dev->camera.sensor->address,
+ (dev->camera.i2c_flags & SN9C20X_I2C_READ ? wasread :
waswrite),
address);
return -1000;
/* there should be no interference with USB errors */
@@ -485,8 +476,8 @@ int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8
nbytes,
if (ret < 0) {
/* we got no ack */
UDIA_ERROR("No ack from I2C slave 0x%02x for %s address
0x%02x\n",
- dev->camera.sensor_slave_address,
- (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread
: waswrite),
+ dev->camera.sensor->address,
+ (dev->camera.i2c_flags & SN9C20X_I2C_READ ? wasread :
waswrite),
address);
return ret;
}
@@ -678,15 +669,17 @@ int sn9c20x_get_closest_resolution(struct usb_microdia
*dev,
int *width, int *height)
{
int i;
+ int fmt_index = dev->vsettings.format.priv;
+ struct microdia_video_mode *modes = dev->camera.fmts[fmt_index].modes;
- for (i = dev->camera.nmodes - 1; i >= 0; i--) {
- if (*width >= dev->camera.modes[i].width
- && *height >= dev->camera.modes[i].height)
+ for (i = N_MODES - 1; i >= 0; i--) {
+ if (*width >= modes[i].width
+ && *height >= modes[i].height)
break;
}
- *width = dev->camera.modes[i].width;
- *height = dev->camera.modes[i].height;
+ *width = modes[i].width;
+ *height = modes[i].height;
return i;
}
@@ -710,27 +703,33 @@ int sn9c20x_set_resolution(struct usb_microdia *dev,
__u8 scale;
__u8 window[6];
__u8 clrwindow[6];
- struct microdia_video_resolution *mode;
+ struct microdia_video_mode *mode;
+ int fmt_index = dev->vsettings.format.priv;
ret = sn9c20x_get_closest_resolution(dev, &width, &height);
- mode = &dev->camera.modes[ret];
+ mode = &dev->camera.fmts[fmt_index].modes[ret];
dev->vsettings.format.width = mode->width;
dev->vsettings.format.height = mode->height;
- clrwindow[0] = 0; clrwindow[1] = mode->width >> 2;
- clrwindow[2] = 0; clrwindow[3] = mode->height >> 1;
- clrwindow[4] = ((mode->width >> 10) & 0x01) |
- ((mode->height >> 10) & 0x06);
+ clrwindow[0] = mode->clr_window[0];
+ clrwindow[1] = mode->clr_window[2] >> 2;
+ clrwindow[2] = mode->clr_window[1];
+ clrwindow[3] = mode->clr_window[3] >> 1;
+ clrwindow[4] = ((mode->clr_window[2] >> 10) & 0x01) |
+ ((mode->clr_window[3] >> 10) & 0x06);
scale = mode->scale;
if (clrwindow[4] & 0x01)
scale += 0x40;
- window[0] = mode->window[0] & 0xff; window[1] = mode->window[0] >> 8;
- window[2] = mode->window[1] & 0xff; window[3] = mode->window[1] >> 8;
- window[4] = mode->window[2] >> 4; window[5] = mode->window[3] >> 3;
+ window[0] = mode->hw_window[0] & 0xff;
+ window[1] = mode->hw_window[0] >> 8;
+ window[2] = mode->hw_window[1] & 0xff;
+ window[3] = mode->hw_window[1] >> 8;
+ window[4] = mode->hw_window[2] >> 4;
+ window[5] = mode->hw_window[3] >> 3;
usb_microdia_control_write(dev, 0x10fb, clrwindow, 5);
usb_microdia_control_write(dev, 0x1180, window, 6);
--
1.5.6.5
signature.asc
Description: OpenPGP digital signature
