aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Johnson <brijohn@gmail.com>2009-09-02 11:39:41 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-12 11:20:11 -0400
commite14304712939133d58a5132501e80509658e0449 (patch)
treec31ca4dfeedaaee3a6e1f319ef189b985973ed10
parentf077b0a64856c5b3bf346ae9fba8631c1fb210cf (diff)
V4L/DVB (12704): gspca - sn9c20x: Fix exposure on SOI968 sensors
Fixes broken exposure on SOI968 webcams that was causing the camera to display a black screen Signed-off-by: Brian Johnson <brijohn@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/gspca/sn9c20x.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 52a7f8edf7ac..a74c36f4c8d2 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -799,7 +799,7 @@ static u8 soi968_init[][2] = {
799 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff}, 799 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
800 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20}, 800 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
801 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e}, 801 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
802 {0x13, 0x8a}, {0x12, 0x40}, {0x17, 0x13}, 802 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
803 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79}, 803 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
804 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40}, 804 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
805 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32}, 805 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
@@ -1246,7 +1246,7 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1246 } 1246 }
1247 } 1247 }
1248 /* disable hflip and vflip */ 1248 /* disable hflip and vflip */
1249 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); 1249 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
1250 sd->hstart = 60; 1250 sd->hstart = 60;
1251 sd->vstart = 11; 1251 sd->vstart = 11;
1252 return 0; 1252 return 0;
@@ -1622,7 +1622,6 @@ static int set_exposure(struct gspca_dev *gspca_dev)
1622 switch (sd->sensor) { 1622 switch (sd->sensor) {
1623 case SENSOR_OV7660: 1623 case SENSOR_OV7660:
1624 case SENSOR_OV7670: 1624 case SENSOR_OV7670:
1625 case SENSOR_SOI968:
1626 case SENSOR_OV9655: 1625 case SENSOR_OV9655:
1627 case SENSOR_OV9650: 1626 case SENSOR_OV9650:
1628 exp[0] |= (3 << 4); 1627 exp[0] |= (3 << 4);
@@ -1647,6 +1646,8 @@ static int set_exposure(struct gspca_dev *gspca_dev)
1647 exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8; 1646 exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8;
1648 exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff; 1647 exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff;
1649 break; 1648 break;
1649 default:
1650 return 0;
1650 } 1651 }
1651 i2c_w(gspca_dev, exp); 1652 i2c_w(gspca_dev, exp);
1652 return 0; 1653 return 0;
@@ -1690,6 +1691,8 @@ static int set_gain(struct gspca_dev *gspca_dev)
1690 gain[2] = 0x30; 1691 gain[2] = 0x30;
1691 gain[3] = hv7131r_gain[sd->gain]; 1692 gain[3] = hv7131r_gain[sd->gain];
1692 break; 1693 break;
1694 default:
1695 return 0;
1693 } 1696 }
1694 i2c_w(gspca_dev, gain); 1697 i2c_w(gspca_dev, gain);
1695 return 0; 1698 return 0;
@@ -2213,15 +2216,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
2213 kfree(sd->jpeg_hdr); 2216 kfree(sd->jpeg_hdr);
2214} 2217}
2215 2218
2216static void do_autoexposure(struct gspca_dev *gspca_dev) 2219static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
2217{ 2220{
2218 struct sd *sd = (struct sd *) gspca_dev; 2221 struct sd *sd = (struct sd *) gspca_dev;
2219 int avg_lum, new_exp; 2222 s16 new_exp;
2220
2221 if (!sd->auto_exposure)
2222 return;
2223
2224 avg_lum = atomic_read(&sd->avg_lum);
2225 2223
2226 /* 2224 /*
2227 * some hardcoded values are present 2225 * some hardcoded values are present
@@ -2268,6 +2266,39 @@ static void do_autoexposure(struct gspca_dev *gspca_dev)
2268 } 2266 }
2269} 2267}
2270 2268
2269static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2270{
2271 struct sd *sd = (struct sd *) gspca_dev;
2272
2273 if (avg_lum < MIN_AVG_LUM) {
2274 if (sd->gain + 1 <= 28) {
2275 sd->gain++;
2276 set_gain(gspca_dev);
2277 }
2278 }
2279 if (avg_lum > MAX_AVG_LUM) {
2280 if (sd->gain - 1 >= 0) {
2281 sd->gain--;
2282 set_gain(gspca_dev);
2283 }
2284 }
2285}
2286
2287static void sd_dqcallback(struct gspca_dev *gspca_dev)
2288{
2289 struct sd *sd = (struct sd *) gspca_dev;
2290 int avg_lum;
2291
2292 if (!sd->auto_exposure)
2293 return;
2294
2295 avg_lum = atomic_read(&sd->avg_lum);
2296 if (sd->sensor == SENSOR_SOI968)
2297 do_autogain(gspca_dev, avg_lum);
2298 else
2299 do_autoexposure(gspca_dev, avg_lum);
2300}
2301
2271static void sd_pkt_scan(struct gspca_dev *gspca_dev, 2302static void sd_pkt_scan(struct gspca_dev *gspca_dev,
2272 struct gspca_frame *frame, /* target */ 2303 struct gspca_frame *frame, /* target */
2273 u8 *data, /* isoc packet */ 2304 u8 *data, /* isoc packet */
@@ -2335,7 +2366,7 @@ static const struct sd_desc sd_desc = {
2335 .stopN = sd_stopN, 2366 .stopN = sd_stopN,
2336 .stop0 = sd_stop0, 2367 .stop0 = sd_stop0,
2337 .pkt_scan = sd_pkt_scan, 2368 .pkt_scan = sd_pkt_scan,
2338 .dq_callback = do_autoexposure, 2369 .dq_callback = sd_dqcallback,
2339#ifdef CONFIG_VIDEO_ADV_DEBUG 2370#ifdef CONFIG_VIDEO_ADV_DEBUG
2340 .set_register = sd_dbg_s_register, 2371 .set_register = sd_dbg_s_register,
2341 .get_register = sd_dbg_g_register, 2372 .get_register = sd_dbg_g_register,