From 89f9a2b48dabb22e84ddf4ca07284499aa5fc152 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 29 Jul 2009 13:02:50 +0200 Subject: gspca_pac207: remove a number of unneeded (repeated) register writes From: Hans de Goede gspca_pac207: remove a number of unneeded (repeated) register writes Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/pac207.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 95a97ab68..f20d21b1c 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -169,13 +169,9 @@ static const __u8 pac207_sensor_init[][8] = { {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0}, {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, - {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02}, {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00}, }; - /* 48 reg_72 Rate Control end BalSize_4a =0x36 */ -static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; - static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, const u8 *buffer, u16 length) { @@ -274,7 +270,6 @@ static int sd_init(struct gspca_dev *gspca_dev) * Bit_1=LED, * Bit_2=Compression test mode enable */ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ - pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ return 0; } @@ -289,9 +284,7 @@ static int sd_start(struct gspca_dev *gspca_dev) pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8); pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8); pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8); - pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8); - pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8); - pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4); + pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8); /* Compression Balance */ if (gspca_dev->width == 176) -- cgit v1.2.3 From 2f1c03be87cb8cd9f645aaf4c5c7206f3141ddad Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 29 Jul 2009 13:03:17 +0200 Subject: gspca_pac207: enable higher framerates / lower exposure settings From: Hans de Goede Now that we've figured out the higher compression settings (supported in libv4l-0.6.0 and later, so after this patch the driver should be used with libv4l-0.6.0 or higher only!), we can enable higher framerates. Which means lower exposure times, which is important for the use of the pac207 in full daylight. This patch also tweakes the brightness default and the per color gain balances to use the values which are adviced by Pixart in the pac207 application note. Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/pac207.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index f20d21b1c..96659433d 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -35,25 +35,17 @@ MODULE_LICENSE("GPL"); #define PAC207_BRIGHTNESS_MIN 0 #define PAC207_BRIGHTNESS_MAX 255 -#define PAC207_BRIGHTNESS_DEFAULT 4 /* power on default: 4 */ - -/* An exposure value of 4 also works (3 does not) but then we need to lower - the compression balance setting when in 352x288 mode, otherwise the usb - bandwidth is not enough and packets get dropped resulting in corrupt - frames. The problem with this is that when the compression balance gets - lowered below 0x80, the pac207 starts using a different compression - algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix - and currently we do not know how to decompress these lines, so for now - we use a minimum exposure value of 5 */ -#define PAC207_EXPOSURE_MIN 5 +#define PAC207_BRIGHTNESS_DEFAULT 46 + +#define PAC207_EXPOSURE_MIN 3 #define PAC207_EXPOSURE_MAX 26 -#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 ?? */ -#define PAC207_EXPOSURE_KNEE 11 /* 4 = 30 fps, 11 = 8, 15 = 6 */ +#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ +#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */ #define PAC207_GAIN_MIN 0 #define PAC207_GAIN_MAX 31 #define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ -#define PAC207_GAIN_KNEE 20 +#define PAC207_GAIN_KNEE 31 #define PAC207_AUTOGAIN_DEADZONE 30 @@ -166,8 +158,8 @@ static const struct v4l2_pix_format sif_mode[] = { }; static const __u8 pac207_sensor_init[][8] = { - {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0}, - {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, + {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84}, + {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30}, {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00}, {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00}, }; @@ -290,7 +282,7 @@ static int sd_start(struct gspca_dev *gspca_dev) if (gspca_dev->width == 176) pac207_write_reg(gspca_dev, 0x4a, 0xff); else - pac207_write_reg(gspca_dev, 0x4a, 0x88); + pac207_write_reg(gspca_dev, 0x4a, 0x30); pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ pac207_write_reg(gspca_dev, 0x08, sd->brightness); @@ -339,7 +331,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, + 100, PAC207_AUTOGAIN_DEADZONE, PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } -- cgit v1.2.3 From 5c78539069b4f258563e13e160393079e04a6d37 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 14 Aug 2009 11:51:52 +0200 Subject: gspca: mr97310a add support for CIF and more VGA camera's From: Theodore Kilgore This patch adds supports for mr97310a camera's with CIF sensors (2 different types) and for VGA mr97310a camera with a different sensor then supported until now. This patch also add support for controls for one of the 2 CIF sensors, this was written by Thomas Kaiser Priority: normal Signed-off-by: Theodore Kilgore Signed-off-by: Thomas Kaiser Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 797 ++++++++++++++++++++++++----- 1 file changed, 682 insertions(+), 115 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 301325134..3a3edf82a 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -3,6 +3,21 @@ * * Copyright (C) 2009 Kyle Guinn * + * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+ + * and for the routines for detecting and classifying these various cameras, + * + * Copyright (C) 2009 Theodore Kilgore + * + * Acknowledgements: + * + * The MR97311A support in gspca/mars.c has been helpful in understanding some + * of the registers in these cameras. + * + * Hans de Goede and + * Thomas Kaiser + * have assisted with their experience. Each of them has also helped by + * testing a previously unsupported camera. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,7 +37,23 @@ #include "gspca.h" -MODULE_AUTHOR("Kyle Guinn "); +#define CAM_TYPE_CIF 0 +#define CAM_TYPE_VGA 1 + +#define MR97310A_BRIGHTNESS_MIN -254 +#define MR97310A_BRIGHTNESS_MAX 255 +#define MR97310A_BRIGHTNESS_DEFAULT 0 + +#define MR97310A_EXPOSURE_MIN 300 +#define MR97310A_EXPOSURE_MAX 4095 +#define MR97310A_EXPOSURE_DEFAULT 1000 + +#define MR97310A_GAIN_MIN 0 +#define MR97310A_GAIN_MAX 31 +#define MR97310A_GAIN_DEFAULT 25 + +MODULE_AUTHOR("Kyle Guinn ," + "Theodore Kilgore "); MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -30,10 +61,75 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ u8 sof_read; + u8 cam_type; /* 0 is CIF and 1 is VGA */ + u8 sensor_type; /* We use 0 and 1 here, too. */ + u8 do_lcd_stop; + u8 regs[15]; + + int brightness; + u16 exposure; + u8 autogain; + u8 gain; }; +struct sensor_w_data { + u8 reg; + u8 flags; + u8 data[16]; + int len; +}; + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); + /* V4L2 controls supported by the driver */ static struct ctrl sd_ctrls[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = MR97310A_BRIGHTNESS_MIN, + .maximum = MR97310A_BRIGHTNESS_MAX, + .step = 1, + .default_value = MR97310A_BRIGHTNESS_DEFAULT, + .flags = 0, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = MR97310A_EXPOSURE_MIN, + .maximum = MR97310A_EXPOSURE_MAX, + .step = 1, + .default_value = MR97310A_EXPOSURE_DEFAULT, + .flags = 0, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = MR97310A_GAIN_MIN, + .maximum = MR97310A_GAIN_MAX, + .step = 1, + .default_value = MR97310A_GAIN_DEFAULT, + .flags = 0, + }, + .set = sd_setgain, + .get = sd_getgain, + }, }; static const struct v4l2_pix_format vga_mode[] = { @@ -65,7 +161,7 @@ static const struct v4l2_pix_format vga_mode[] = { }; /* the bytes to write are in gspca_dev->usb_buf */ -static int reg_w(struct gspca_dev *gspca_dev, int len) +static int mr_write(struct gspca_dev *gspca_dev, int len) { int rc; @@ -78,15 +174,200 @@ static int reg_w(struct gspca_dev *gspca_dev, int len) return rc; } +/* the bytes are read into gspca_dev->usb_buf */ +static int mr_read(struct gspca_dev *gspca_dev, int len) +{ + int rc; + + rc = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, len, NULL, 500); + if (rc < 0) + PDEBUG(D_ERR, "reg read [%02x] error %d", + gspca_dev->usb_buf[0], rc); + return rc; +} + +static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags, + const u8 *data, int len) +{ + gspca_dev->usb_buf[0] = 0x1f; + gspca_dev->usb_buf[1] = flags; + gspca_dev->usb_buf[2] = reg; + memcpy(gspca_dev->usb_buf + 3, data, len); + + return mr_write(gspca_dev, len + 3); +} + +static int sensor_write_regs(struct gspca_dev *gspca_dev, + const struct sensor_w_data *data, int len) +{ + int i, rc; + + for (i = 0; i < len; i++) { + rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags, + data[i].data, data[i].len); + if (rc < 0) + return rc; + } + + return 0; +} + +static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) +{ + u8 buf; + int rc; + + buf = data; + rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1); + if (rc < 0) + return rc; + + buf = 0x01; + rc = sensor_write_reg(gspca_dev, 0x13, 0x00, &buf, 1); + if (rc < 0) + return rc; + + return 0; +} + +static int cam_get_response16(struct gspca_dev *gspca_dev) +{ + __u8 *data = gspca_dev->usb_buf; + int err_code; + + data[0] = 0x21; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + return err_code; +} + +static int zero_the_pointer(struct gspca_dev *gspca_dev) +{ + __u8 *data = gspca_dev->usb_buf; + int err_code; + u8 status = 0; + int tries = 0; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + err_code = mr_write(gspca_dev, 1); + data[0] = 0x19; + data[1] = 0x51; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0xba; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + if (err_code < 0) + return err_code; + + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + while (status != 0x0a && tries < 256) { + err_code = cam_get_response16(gspca_dev); + status = data[0]; + tries++; + if (err_code < 0) + return err_code; + } + PDEBUG(D_ERR, "status is %02x", status); + + tries = 0; + while (tries < 4) { + data[0] = 0x19; + data[1] = 0x00; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + err_code = cam_get_response16(gspca_dev); + status = data[0]; + tries++; + if (err_code < 0) + return err_code; + } + PDEBUG(D_ERR, "Read 16 bytes from camera"); + + data[0] = 0x19; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + if (err_code < 0) + return err_code; + + return 0; +} + +static u8 get_sensor_id(struct gspca_dev *gspca_dev) +{ + int err_code; + + gspca_dev->usb_buf[0] = 0x1e; + err_code = mr_write(gspca_dev, 1); + if (err_code < 0) + return err_code; + + err_code = mr_read(gspca_dev, 16); + if (err_code < 0) + return err_code; + + PDEBUG(D_ERR, "Read 16 bytes from camera"); + PDEBUG(D_ERR, "Byte zero reported is %01x", gspca_dev->usb_buf[0]); + + return gspca_dev->usb_buf[0]; +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { + struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); + sd->cam_type = CAM_TYPE_VGA; + PDEBUG(D_PROBE, + "MR97310A camera detected" + " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + if (id->idProduct == 0x010e) { + cam->nmodes--; + sd->cam_type = CAM_TYPE_CIF; + } return 0; } @@ -96,183 +377,468 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int sd_start(struct gspca_dev *gspca_dev) +static int adjust_cif_sensor(struct gspca_dev *gspca_dev) +{ + /* + * FIXME: The following sequence resets brightness, contrast, and + * related settings. Some of the values are adjustable, presumably + * based upon what is detected in the frames. Here, only some + * vaules are used which are compromises. When more is known about + * what is done here, this needs to be moved out to presently + * nonexistent functions which do controls. The same control messages + * do work for all of the CIF cameras. + */ + + const struct sensor_w_data cif_sensor1_adjust_data[] = { + {0x02, 0x01, {0x10, 0x12, 0x0a}, 3}, + /* Last or possibly two last bytes adjustable, above. */ + {0x13, 0x04, {0x01}, 1}, /* seems to mean "write" */ + {0x05, 0x01, {0x22, 0x00, 0x81, 0x06}, 4}, + /* Last or possibly two last bytes adjustable, above. */ + {0x13, 0x04, {0x01}, 1}, + {0x09, 0x02, {0x05, 0x00, 0x00, 0x05, 0x07, 0x16}, 6}, + /* Last or possibly two last bytes adjustable, above. */ + {0x13, 0x04, {0x01}, 1}, + {0, 0, {0}, 0} + }; + + return sensor_write_regs(gspca_dev, cif_sensor1_adjust_data, + ARRAY_SIZE(cif_sensor1_adjust_data)); +} + +static int start_cif_cam(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 *data = gspca_dev->usb_buf; int err_code; - - sd->sof_read = 0; - - /* Note: register descriptions guessed from MR97113A driver */ - + const __u8 startup_string[] = { + 0x00, + 0x0d, + 0x01, + 0x00, /* Hsize/8 for 352 or 320 */ + 0x00, /* Vsize/4 for 288 or 240 */ + 0x13, /* or 0xbb, depends on sensor */ + 0x00, /* Hstart, depends on res. */ + 0x00, /* reserved ? */ + 0x00, /* Vstart, depends on res. and sensor */ + 0x50, /* 0x54 to get 176 or 160 */ + 0xc0 + }; + + /* Note: Some of the above descriptions guessed from MR97113A driver */ + sd->sensor_type = 0; data[0] = 0x01; data[1] = 0x01; - err_code = reg_w(gspca_dev, 2); + err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - data[0] = 0x00; - data[1] = 0x0d; - data[2] = 0x01; - data[5] = 0x2b; - data[7] = 0x00; - data[9] = 0x50; /* reg 8, no scale down */ - data[10] = 0xc0; + msleep(200); + data[0] = get_sensor_id(gspca_dev); + /* + * Known CIF cameras. If you have another to report, please do + * + * Name byte just read sd->sensor_type + * reported by + * Sakar Spy-shot 0x28 T. Kilgore 0 + * Innovage 0xf5 (unstable) T. Kilgore 0 + * Vivitar Mini 0x53 H. De Goede 0 + * Vivitar Mini 0x08 T. Kilgore 1 + * Elta-Media 8212dc 0x23 T. Kaiser 1 + * Philips dig. keych. 0x37 T. Kilgore 1 + */ + if ((data[0] & 0x78) == 8 || (data[0] & 0x2) == 0x2) + sd->sensor_type = 1; + + PDEBUG(D_ERR, "Sensor type is %01x", sd->sensor_type); + memcpy(data, startup_string, 11); + if (sd->sensor_type) + data[5] = 0xbb; switch (gspca_dev->width) { case 160: - data[9] |= 0x0c; /* reg 8, 4:1 scale down */ + data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ /* fall thru */ case 320: - data[9] |= 0x04; /* reg 8, 2:1 scale down */ - /* fall thru */ - case 640: default: - data[3] = 0x50; /* reg 2, H size */ - data[4] = 0x78; /* reg 3, V size */ - data[6] = 0x04; /* reg 5, H start */ - data[8] = 0x03; /* reg 7, V start */ + data[3] = 0x28; /* reg 2, H size/8 */ + data[4] = 0x3c; /* reg 3, V size/4 */ + data[6] = 0x14; /* reg 5, H start */ + data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */ break; - case 176: - data[9] |= 0x04; /* reg 8, 2:1 scale down */ + data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */ /* fall thru */ case 352: - data[3] = 0x2c; /* reg 2, H size */ - data[4] = 0x48; /* reg 3, V size */ - data[6] = 0x94; /* reg 5, H start */ - data[8] = 0x63; /* reg 7, V start */ + data[3] = 0x2c; /* reg 2, H size/8 */ + data[4] = 0x48; /* reg 3, V size/4 */ + data[6] = 0x06; /* reg 5, H start */ + data[8] = 0x06 + sd->sensor_type; /* reg 7, V start */ break; } - - err_code = reg_w(gspca_dev, 11); + err_code = mr_write(gspca_dev, 11); if (err_code < 0) return err_code; - data[0] = 0x0a; - data[1] = 0x80; - err_code = reg_w(gspca_dev, 2); + if (!sd->sensor_type) { + const struct sensor_w_data cif_sensor0_init_data[] = { + {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01, + 0x0f, 0x14, 0x0f, 0x10}, 8}, + {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5}, + {0x12, 0x00, {0x07}, 1}, + {0x1f, 0x00, {0x06}, 1}, + {0x27, 0x00, {0x04}, 1}, + {0x29, 0x00, {0x0c}, 1}, + {0x40, 0x00, {0x40, 0x00, 0x04}, 3}, + {0x50, 0x00, {0x60}, 1}, + {0x60, 0x00, {0x06}, 1}, + {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6}, + {0x72, 0x00, {0x1e, 0x56}, 2}, + {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02, + 0x31, 0x80, 0x00}, 9}, + {0x11, 0x00, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data, + ARRAY_SIZE(cif_sensor0_init_data)); + } else { /* sd->sensor_type = 1 */ + const struct sensor_w_data cif_sensor1_init_data[] = { + {0x02, 0x00, {0x10}, 1}, + {0x03, 0x01, {0x12}, 1}, + {0x04, 0x01, {0x05}, 1}, + {0x05, 0x01, {0x65}, 1}, + {0x06, 0x01, {0x32}, 1}, + {0x07, 0x01, {0x00}, 1}, + {0x08, 0x02, {0x06}, 1}, + {0x09, 0x02, {0x0e}, 1}, + {0x0a, 0x02, {0x05}, 1}, + {0x0b, 0x02, {0x05}, 1}, + {0x0c, 0x02, {0x0f}, 1}, + {0x0d, 0x02, {0x00}, 1}, + {0x0e, 0x02, {0x0c}, 1}, + {0x0f, 0x00, {0x00}, 1}, + {0x10, 0x00, {0x06}, 1}, + {0x11, 0x00, {0x07}, 1}, + {0x12, 0x00, {0x00}, 1}, + {0x13, 0x00, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data, + ARRAY_SIZE(cif_sensor1_init_data)); + } if (err_code < 0) return err_code; - data[0] = 0x14; - data[1] = 0x0a; - err_code = reg_w(gspca_dev, 2); + msleep(200); + data[0] = 0x00; + data[1] = 0x4d; /* ISOC transfering enable... */ + err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - data[0] = 0x1b; - data[1] = 0x00; - err_code = reg_w(gspca_dev, 2); + msleep(200); + err_code = adjust_cif_sensor(gspca_dev); if (err_code < 0) return err_code; - data[0] = 0x15; - data[1] = 0x16; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; + msleep(200); + return 0; +} - data[0] = 0x16; - data[1] = 0x10; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; +static int start_vga_cam(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 *data = gspca_dev->usb_buf; + int err_code; + const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x50, 0xc0}; - data[0] = 0x17; - data[1] = 0x3a; - err_code = reg_w(gspca_dev, 2); - if (err_code < 0) - return err_code; + /* What some of these mean is explained in start_cif_cam(), above */ + sd->sof_read = 0; - data[0] = 0x18; - data[1] = 0x68; - err_code = reg_w(gspca_dev, 2); + /* + * We have to know which camera we have, because the register writes + * depend upon the camera. This test, run before we actually enter + * the initialization routine, distinguishes most of the cameras, If + * needed, another routine is done later, too. + */ + memset(data, 0, 16); + data[0] = 0x20; + err_code = mr_write(gspca_dev, 1); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x00; - data[2] = 0x02; - data[3] = 0x06; - data[4] = 0x59; - data[5] = 0x0c; - data[6] = 0x16; - data[7] = 0x00; - data[8] = 0x07; - data[9] = 0x00; - data[10] = 0x01; - err_code = reg_w(gspca_dev, 11); + err_code = mr_read(gspca_dev, 16); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x04; - data[2] = 0x11; - data[3] = 0x01; - err_code = reg_w(gspca_dev, 4); - if (err_code < 0) - return err_code; + PDEBUG(D_ERR, "Read 16 bytes from camera"); + PDEBUG(D_ERR, "Byte reported is %02x", data[0]); - data[0] = 0x1f; - data[1] = 0x00; - data[2] = 0x0a; - data[3] = 0x00; - data[4] = 0x01; - data[5] = 0x00; - data[6] = 0x00; - data[7] = 0x01; - data[8] = 0x00; - data[9] = 0x0a; - err_code = reg_w(gspca_dev, 10); - if (err_code < 0) - return err_code; + msleep(200); + /* + * Known VGA cameras. If you have another to report, please do + * + * Name byte just read sd->sensor_type + * sd->do_lcd_stop + * Aiptek Pencam VGA+ 0x31 0 1 + * ION digital 0x31 0 1 + * Argus DC-1620 0x30 1 0 + * Argus QuickClix 0x30 1 1 (not caught here) + */ + sd->sensor_type = data[0] & 1; + sd->do_lcd_stop = (~data[0]) & 1; - data[0] = 0x1f; - data[1] = 0x04; - data[2] = 0x11; - data[3] = 0x01; - err_code = reg_w(gspca_dev, 4); + + + /* Streaming setup begins here. */ + + + data[0] = 0x01; + data[1] = 0x01; + err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x00; - data[2] = 0x12; - data[3] = 0x00; - data[4] = 0x63; - data[5] = 0x00; - data[6] = 0x70; - data[7] = 0x00; - data[8] = 0x00; - err_code = reg_w(gspca_dev, 9); + /* + * A second test can now resolve any remaining ambiguity in the + * identification of the camera type, + */ + if (!sd->sensor_type) { + data[0] = get_sensor_id(gspca_dev); + if (data[0] == 0x7f) { + sd->sensor_type = 1; + PDEBUG(D_ERR, "sensor_type corrected to 1"); + } + msleep(200); + } + + /* + * Known VGA cameras. + * This test is only run if the previous test returned 0x30, but + * here is the information for all others, too, just for reference. + * + * Name byte just read sd->sensor_type + * + * Aiptek Pencam VGA+ 0xfb (this test not run) 1 + * ION digital 0xbd (this test not run) 1 + * Argus DC-1620 0xe5 (no change) 0 + * Argus QuickClix 0x7f (reclassified) 1 + */ + memcpy(data, startup_string, 11); + if (!sd->sensor_type) { + data[5] = 0x00; + data[10] = 0x91; + } + + switch (gspca_dev->width) { + case 160: + data[9] |= 0x0c; /* reg 8, 4:1 scale down */ + /* fall thru */ + case 320: + data[9] |= 0x04; /* reg 8, 2:1 scale down */ + /* fall thru */ + case 640: + default: + data[3] = 0x50; /* reg 2, H size/8 */ + data[4] = 0x78; /* reg 3, V size/4 */ + data[6] = 0x04; /* reg 5, H start */ + data[8] = 0x03; /* reg 7, V start */ + if (sd->do_lcd_stop) + data[8] = 0x04; /* Bayer tile shifted */ + break; + + case 176: + data[9] |= 0x04; /* reg 8, 2:1 scale down */ + /* fall thru */ + case 352: + data[3] = 0x2c; /* reg 2, H size */ + data[4] = 0x48; /* reg 3, V size */ + data[6] = 0x94; /* reg 5, H start */ + data[8] = 0x63; /* reg 7, V start */ + if (sd->do_lcd_stop) + data[8] = 0x64; /* Bayer tile shifted */ + break; + } + + err_code = mr_write(gspca_dev, 11); if (err_code < 0) return err_code; - data[0] = 0x1f; - data[1] = 0x04; - data[2] = 0x11; - data[3] = 0x01; - err_code = reg_w(gspca_dev, 4); + if (!sd->sensor_type) { + /* The only known sensor_type 0 cam is the Argus DC-1620 */ + const struct sensor_w_data vga_sensor0_init_data[] = { + {0x01, 0x00, {0x0c, 0x00, 0x04}, 3}, + {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4}, + {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4}, + {0x25, 0x00, {0x03, 0xa9, 0x80}, 3}, + {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data, + ARRAY_SIZE(vga_sensor0_init_data)); + } else { /* sd->sensor_type = 1 */ + const struct sensor_w_data vga_sensor1_init_data[] = { + {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, + 0x07, 0x00, 0x01}, 8}, + {0x11, 0x04, {0x01}, 1}, + /*{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, */ + {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, + 0x00, 0x0a}, 7}, + {0x11, 0x04, {0x01}, 1}, + {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6}, + {0x11, 0x04, {0x01}, 1}, + {0, 0, {0}, 0} + }; + err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data, + ARRAY_SIZE(vga_sensor1_init_data)); + } if (err_code < 0) return err_code; + msleep(200); data[0] = 0x00; data[1] = 0x4d; /* ISOC transfering enable... */ - err_code = reg_w(gspca_dev, 2); + err_code = mr_write(gspca_dev, 2); + + return err_code; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err_code; + struct cam *cam; + + /* TEST TEST */ + int i; + for (i = 2; i <= 14; i++) + sd->regs[i] = sd_ctrls[i - 2].qctrl.default_value; + + cam = &gspca_dev->cam; + sd->sof_read = 0; + /* + * Some of the supported cameras require the memory pointer to be + * set to 0, or else they will not stream. + */ + zero_the_pointer(gspca_dev); + msleep(200); + if (sd->cam_type == CAM_TYPE_CIF) { + PDEBUG(D_ERR, "CIF camera"); + err_code = start_cif_cam(gspca_dev); + } else { + PDEBUG(D_ERR, "VGA camera"); + err_code = start_vga_cam(gspca_dev); + } return err_code; } static void sd_stopN(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; int result; gspca_dev->usb_buf[0] = 1; gspca_dev->usb_buf[1] = 0; - result = reg_w(gspca_dev, 2); + result = mr_write(gspca_dev, 2); if (result < 0) PDEBUG(D_ERR, "Camera Stop failed"); + + /* Not all the cams need this, but even if not, probably a good idea */ + zero_the_pointer(gspca_dev); + if (sd->do_lcd_stop) { + gspca_dev->usb_buf[0] = 0x19; + gspca_dev->usb_buf[1] = 0x54; + result = mr_write(gspca_dev, 2); + if (result < 0) + PDEBUG(D_ERR, "Camera Stop failed"); + } +} + +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + if (sd->brightness > 0) { + sensor_write1(gspca_dev, 7, 0); + val = sd->brightness; + } else { + sensor_write1(gspca_dev, 7, 1); + val = 257 - sd->brightness; + } + sensor_write1(gspca_dev, 8, val); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + val = sd->exposure >> 4; + sensor_write1(gspca_dev, 3, val); + val = sd->exposure & 0xf; + sensor_write1(gspca_dev, 4, val); +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sensor_write1(gspca_dev, 3, sd->gain); +} + +static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->brightness = val; + if (gspca_dev->streaming) + setbrightness(gspca_dev); + return 0; +} + +static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->brightness; + return 0; +} + +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; } /* Include pac common sof detection functions */ @@ -320,8 +886,9 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x08ca, 0x0111)}, - {USB_DEVICE(0x093a, 0x010f)}, + {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */ + {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */ + {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */ {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3 From a701e8b02349206dd6c5b3a050bcf945091e1c38 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 14 Aug 2009 11:56:32 +0200 Subject: gspca: mr97310a fix detection of sensortype for vivicam with id byte of 0x53 From: Hans de Goede gspca: mr97310a fix detection of sensortype for vivicam with id byte of 0x53 Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 3a3edf82a..db2f84e63 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -447,7 +447,8 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) * Elta-Media 8212dc 0x23 T. Kaiser 1 * Philips dig. keych. 0x37 T. Kilgore 1 */ - if ((data[0] & 0x78) == 8 || (data[0] & 0x2) == 0x2) + if ((data[0] & 0x78) == 8 || + ((data[0] & 0x2) == 0x2 && data[0] != 0x53)) sd->sensor_type = 1; PDEBUG(D_ERR, "Sensor type is %01x", sd->sensor_type); -- cgit v1.2.3 From 7ba548f6dd9dbb151271b980bf96189a73979a12 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 14 Aug 2009 15:15:52 +0200 Subject: gspca_mr97310a: cleanup/fixup control handling From: Hans de Goede gspca_mr97310a: cleanup/fixup control handling Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 98 ++++++++++++++---------------- 1 file changed, 45 insertions(+), 53 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index db2f84e63..3bdf06469 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -64,11 +64,9 @@ struct sd { u8 cam_type; /* 0 is CIF and 1 is VGA */ u8 sensor_type; /* We use 0 and 1 here, too. */ u8 do_lcd_stop; - u8 regs[15]; int brightness; u16 exposure; - u8 autogain; u8 gain; }; @@ -85,10 +83,14 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static void setbrightness(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); /* V4L2 controls supported by the driver */ static struct ctrl sd_ctrls[] = { { +#define BRIGHTNESS_IDX 0 { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -103,6 +105,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getbrightness, }, { +#define EXPOSURE_IDX 1 { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -117,6 +120,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getexposure, }, { +#define GAIN_IDX 2 { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -360,14 +364,24 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - sd->cam_type = CAM_TYPE_VGA; + PDEBUG(D_PROBE, "MR97310A camera detected" " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + if (id->idProduct == 0x010e) { - cam->nmodes--; sd->cam_type = CAM_TYPE_CIF; + cam->nmodes--; + } else { + sd->cam_type = CAM_TYPE_VGA; + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | + (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); } + + sd->brightness = MR97310A_BRIGHTNESS_DEFAULT; + sd->exposure = MR97310A_EXPOSURE_DEFAULT; + sd->gain = MR97310A_GAIN_DEFAULT; + return 0; } @@ -377,35 +391,6 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int adjust_cif_sensor(struct gspca_dev *gspca_dev) -{ - /* - * FIXME: The following sequence resets brightness, contrast, and - * related settings. Some of the values are adjustable, presumably - * based upon what is detected in the frames. Here, only some - * vaules are used which are compromises. When more is known about - * what is done here, this needs to be moved out to presently - * nonexistent functions which do controls. The same control messages - * do work for all of the CIF cameras. - */ - - const struct sensor_w_data cif_sensor1_adjust_data[] = { - {0x02, 0x01, {0x10, 0x12, 0x0a}, 3}, - /* Last or possibly two last bytes adjustable, above. */ - {0x13, 0x04, {0x01}, 1}, /* seems to mean "write" */ - {0x05, 0x01, {0x22, 0x00, 0x81, 0x06}, 4}, - /* Last or possibly two last bytes adjustable, above. */ - {0x13, 0x04, {0x01}, 1}, - {0x09, 0x02, {0x05, 0x00, 0x00, 0x05, 0x07, 0x16}, 6}, - /* Last or possibly two last bytes adjustable, above. */ - {0x13, 0x04, {0x01}, 1}, - {0, 0, {0}, 0} - }; - - return sensor_write_regs(gspca_dev, cif_sensor1_adjust_data, - ARRAY_SIZE(cif_sensor1_adjust_data)); -} - static int start_cif_cam(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -452,6 +437,11 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) sd->sensor_type = 1; PDEBUG(D_ERR, "Sensor type is %01x", sd->sensor_type); + + if (sd->sensor_type == 0) + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | + (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); + memcpy(data, startup_string, 11); if (sd->sensor_type) data[5] = 0xbb; @@ -504,18 +494,15 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) ARRAY_SIZE(cif_sensor0_init_data)); } else { /* sd->sensor_type = 1 */ const struct sensor_w_data cif_sensor1_init_data[] = { + /* Reg 3,4, 7,8 get set by the controls */ {0x02, 0x00, {0x10}, 1}, - {0x03, 0x01, {0x12}, 1}, - {0x04, 0x01, {0x05}, 1}, - {0x05, 0x01, {0x65}, 1}, - {0x06, 0x01, {0x32}, 1}, - {0x07, 0x01, {0x00}, 1}, - {0x08, 0x02, {0x06}, 1}, + {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */ + {0x06, 0x01, {0x00}, 1}, {0x09, 0x02, {0x0e}, 1}, {0x0a, 0x02, {0x05}, 1}, {0x0b, 0x02, {0x05}, 1}, {0x0c, 0x02, {0x0f}, 1}, - {0x0d, 0x02, {0x00}, 1}, + {0x0d, 0x02, {0x07}, 1}, {0x0e, 0x02, {0x0c}, 1}, {0x0f, 0x00, {0x00}, 1}, {0x10, 0x00, {0x06}, 1}, @@ -530,19 +517,18 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) if (err_code < 0) return err_code; + setbrightness(gspca_dev); + setexposure(gspca_dev); + setgain(gspca_dev); + msleep(200); + data[0] = 0x00; data[1] = 0x4d; /* ISOC transfering enable... */ err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - msleep(200); - err_code = adjust_cif_sensor(gspca_dev); - if (err_code < 0) - return err_code; - - msleep(200); return 0; } @@ -711,11 +697,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int err_code; struct cam *cam; - /* TEST TEST */ - int i; - for (i = 2; i <= 14; i++) - sd->regs[i] = sd_ctrls[i - 2].qctrl.default_value; - cam = &gspca_dev->cam; sd->sof_read = 0; /* @@ -760,11 +741,16 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; + + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX)) + return; + + /* Note register 7 is also seen as 0x8x or 0xCx in dumps */ if (sd->brightness > 0) { - sensor_write1(gspca_dev, 7, 0); + sensor_write1(gspca_dev, 7, 0x00); val = sd->brightness; } else { - sensor_write1(gspca_dev, 7, 1); + sensor_write1(gspca_dev, 7, 0x01); val = 257 - sd->brightness; } sensor_write1(gspca_dev, 8, val); @@ -775,6 +761,9 @@ static void setexposure(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; + if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) + return; + val = sd->exposure >> 4; sensor_write1(gspca_dev, 3, val); val = sd->exposure & 0xf; @@ -785,6 +774,9 @@ static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (gspca_dev->ctrl_dis & (1 << GAIN_IDX)) + return; + sensor_write1(gspca_dev, 3, sd->gain); } -- cgit v1.2.3 From a7cb5b967c6700a7b3cd5d489d92871e2fd5ba16 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 14 Aug 2009 15:40:26 +0200 Subject: gspca_mr97310a: Move detection of CIF sensor type to probe() function From: Hans de Goede gspca_mr97310a: Move detection of CIF sensor type to probe() function, so that the right controls are set to disabled from the start, rather then having them disappear all of a sudden when the stream is started. Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 59 +++++++++++++++++------------- 1 file changed, 34 insertions(+), 25 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 3bdf06469..1a6532fa8 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -360,6 +360,8 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; + __u8 *data = gspca_dev->usb_buf; + int err_code; cam = &gspca_dev->cam; cam->cam_mode = vga_mode; @@ -372,6 +374,38 @@ static int sd_config(struct gspca_dev *gspca_dev, if (id->idProduct == 0x010e) { sd->cam_type = CAM_TYPE_CIF; cam->nmodes--; + + data[0] = 0x01; + data[1] = 0x01; + err_code = mr_write(gspca_dev, 2); + if (err_code < 0) + return err_code; + + msleep(200); + data[0] = get_sensor_id(gspca_dev); + /* + * Known CIF cameras. If you have another to report, please do + * + * Name byte just read sd->sensor_type + * reported by + * Sakar Spy-shot 0x28 T. Kilgore 0 + * Innovage 0xf5 (unstable) T. Kilgore 0 + * Vivitar Mini 0x53 H. De Goede 0 + * Vivitar Mini 0x08 T. Kilgore 1 + * Elta-Media 8212dc 0x23 T. Kaiser 1 + * Philips dig. keych. 0x37 T. Kilgore 1 + */ + if ((data[0] & 0x78) == 8 || + ((data[0] & 0x2) == 0x2 && data[0] != 0x53)) + sd->sensor_type = 1; + else + sd->sensor_type = 0; + + PDEBUG(D_ERR, "Sensor type is %01x", sd->sensor_type); + + if (sd->sensor_type == 0) + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | + (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); } else { sd->cam_type = CAM_TYPE_VGA; gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | @@ -411,37 +445,12 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) }; /* Note: Some of the above descriptions guessed from MR97113A driver */ - sd->sensor_type = 0; data[0] = 0x01; data[1] = 0x01; err_code = mr_write(gspca_dev, 2); if (err_code < 0) return err_code; - msleep(200); - data[0] = get_sensor_id(gspca_dev); - /* - * Known CIF cameras. If you have another to report, please do - * - * Name byte just read sd->sensor_type - * reported by - * Sakar Spy-shot 0x28 T. Kilgore 0 - * Innovage 0xf5 (unstable) T. Kilgore 0 - * Vivitar Mini 0x53 H. De Goede 0 - * Vivitar Mini 0x08 T. Kilgore 1 - * Elta-Media 8212dc 0x23 T. Kaiser 1 - * Philips dig. keych. 0x37 T. Kilgore 1 - */ - if ((data[0] & 0x78) == 8 || - ((data[0] & 0x2) == 0x2 && data[0] != 0x53)) - sd->sensor_type = 1; - - PDEBUG(D_ERR, "Sensor type is %01x", sd->sensor_type); - - if (sd->sensor_type == 0) - gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | - (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); - memcpy(data, startup_string, 11); if (sd->sensor_type) data[5] = 0xbb; -- cgit v1.2.3 From 30f3a12506fbaced440cb99a0a893825dbec6f1f Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 14 Aug 2009 16:05:38 +0200 Subject: gspca_mr97310a: make the probing a bit less chatty From: Hans de Goede gspca_mr97310a: make the probing a bit less chatty Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 1a6532fa8..7540ea94e 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -305,7 +305,8 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev) if (err_code < 0) return err_code; } - PDEBUG(D_ERR, "status is %02x", status); + if (status != 0x0a) + PDEBUG(D_ERR, "status is %02x", status); tries = 0; while (tries < 4) { @@ -321,7 +322,6 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev) if (err_code < 0) return err_code; } - PDEBUG(D_ERR, "Read 16 bytes from camera"); data[0] = 0x19; err_code = mr_write(gspca_dev, 1); @@ -348,8 +348,7 @@ static u8 get_sensor_id(struct gspca_dev *gspca_dev) if (err_code < 0) return err_code; - PDEBUG(D_ERR, "Read 16 bytes from camera"); - PDEBUG(D_ERR, "Byte zero reported is %01x", gspca_dev->usb_buf[0]); + PDEBUG(D_PROBE, "Byte zero reported is %01x", gspca_dev->usb_buf[0]); return gspca_dev->usb_buf[0]; } @@ -367,10 +366,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - PDEBUG(D_PROBE, - "MR97310A camera detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - if (id->idProduct == 0x010e) { sd->cam_type = CAM_TYPE_CIF; cam->nmodes--; @@ -401,13 +396,15 @@ static int sd_config(struct gspca_dev *gspca_dev, else sd->sensor_type = 0; - PDEBUG(D_ERR, "Sensor type is %01x", sd->sensor_type); + PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d", + sd->sensor_type); if (sd->sensor_type == 0) gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); } else { sd->cam_type = CAM_TYPE_VGA; + PDEBUG(D_PROBE, "MR97310A VGA camera detected"); gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); } @@ -568,8 +565,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev) if (err_code < 0) return err_code; - PDEBUG(D_ERR, "Read 16 bytes from camera"); - PDEBUG(D_ERR, "Byte reported is %02x", data[0]); + PDEBUG(D_PROBE, "Byte reported is %02x", data[0]); msleep(200); /* @@ -604,7 +600,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev) data[0] = get_sensor_id(gspca_dev); if (data[0] == 0x7f) { sd->sensor_type = 1; - PDEBUG(D_ERR, "sensor_type corrected to 1"); + PDEBUG(D_PROBE, "sensor_type corrected to 1"); } msleep(200); } @@ -715,10 +711,8 @@ static int sd_start(struct gspca_dev *gspca_dev) zero_the_pointer(gspca_dev); msleep(200); if (sd->cam_type == CAM_TYPE_CIF) { - PDEBUG(D_ERR, "CIF camera"); err_code = start_cif_cam(gspca_dev); } else { - PDEBUG(D_ERR, "VGA camera"); err_code = start_vga_cam(gspca_dev); } return err_code; -- cgit v1.2.3 From 1043cd3f4a29434ea131163d1a1d4a21da04150b Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Fri, 14 Aug 2009 22:11:36 +0200 Subject: gspca_mr97310a: Add controls for CIF type 0 sensor cams From: Hans de Goede gspca_mr97310a: Add controls for CIF type 0 sensor cams Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 56 +++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 9 deletions(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 7540ea94e..1ee3d1ee5 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -220,7 +220,8 @@ static int sensor_write_regs(struct gspca_dev *gspca_dev, static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) { - u8 buf; + struct sd *sd = (struct sd *) gspca_dev; + u8 buf, confirm_reg; int rc; buf = data; @@ -229,7 +230,8 @@ static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) return rc; buf = 0x01; - rc = sensor_write_reg(gspca_dev, 0x13, 0x00, &buf, 1); + confirm_reg = sd->sensor_type ? 0x13 : 0x11; + rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1); if (rc < 0) return rc; @@ -400,8 +402,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor_type); if (sd->sensor_type == 0) - gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) | - (1 << EXPOSURE_IDX) | (1 << GAIN_IDX); + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX); } else { sd->cam_type = CAM_TYPE_VGA; PDEBUG(D_PROBE, "MR97310A VGA camera detected"); @@ -767,10 +768,43 @@ static void setexposure(struct gspca_dev *gspca_dev) if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) return; - val = sd->exposure >> 4; - sensor_write1(gspca_dev, 3, val); - val = sd->exposure & 0xf; - sensor_write1(gspca_dev, 4, val); + if (sd->sensor_type) { + val = sd->exposure >> 4; + sensor_write1(gspca_dev, 3, val); + val = sd->exposure & 0xf; + sensor_write1(gspca_dev, 4, val); + } else { + u8 clockdiv; + int exposure; + + /* We have both a clock divider and an exposure register. + We first calculate the clock divider, as that determines + the maximum exposure and then we calculayte the exposure + register setting (which goes from 0 - 511). + + Note our 0 - 4095 exposure is mapped to 0 - 511 + milliseconds exposure time */ + clockdiv = (60 * sd->exposure + 7999) / 8000; + + /* Limit framerate to not exceed usb bandwidth */ + if (clockdiv < 3 && gspca_dev->width >= 320) + clockdiv = 3; + else if (clockdiv < 2) + clockdiv = 2; + + /* Frame exposure time in ms = 1000 * clockdiv / 60 -> + exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */ + exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv); + if (exposure > 511) + exposure = 511; + + /* exposure register value is reversed! */ + exposure = 511 - exposure; + + sensor_write1(gspca_dev, 0x02, clockdiv); + sensor_write1(gspca_dev, 0x0e, exposure & 0xff); + sensor_write1(gspca_dev, 0x0f, exposure >> 8); + } } static void setgain(struct gspca_dev *gspca_dev) @@ -780,7 +814,11 @@ static void setgain(struct gspca_dev *gspca_dev) if (gspca_dev->ctrl_dis & (1 << GAIN_IDX)) return; - sensor_write1(gspca_dev, 3, sd->gain); + if (sd->sensor_type) { + sensor_write1(gspca_dev, 3, sd->gain); + } else { + sensor_write1(gspca_dev, 0x10, sd->gain); + } } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -- cgit v1.2.3 From f56e5f83c8445db50b3cba3013170785c52ac486 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Mon, 17 Aug 2009 17:25:17 +0200 Subject: gspca_mr97310a: Use correct register for CIF type 1 sensor gain settings From: Hans de Goede gspca_mr97310a: Use correct register for CIF type 1 sensor gain settings Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 1ee3d1ee5..8190a1d4d 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -815,7 +815,7 @@ static void setgain(struct gspca_dev *gspca_dev) return; if (sd->sensor_type) { - sensor_write1(gspca_dev, 3, sd->gain); + sensor_write1(gspca_dev, 0x0e, sd->gain); } else { sensor_write1(gspca_dev, 0x10, sd->gain); } -- cgit v1.2.3 From 187a80bf44bebae8fd3a7ff804ecc523aaf6f3ea Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Wed, 2 Sep 2009 14:55:16 +0200 Subject: gspca_mr97310a: Allow overriding of detected sensor type From: Hans de Goede gspca_mr97310a: Allow overriding of detected sensor type Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 8190a1d4d..169cdb65c 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -57,6 +57,11 @@ MODULE_AUTHOR("Kyle Guinn ," MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); MODULE_LICENSE("GPL"); +/* global parameters */ +int force_sensor_type = -1; +module_param(force_sensor_type, int, 0644); +MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ @@ -401,6 +406,12 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d", sd->sensor_type); + if (force_sensor_type != -1) { + sd->sensor_type = !! force_sensor_type; + PDEBUG(D_PROBE, "Forcing sensor type to: %d", + sd->sensor_type); + } + if (sd->sensor_type == 0) gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX); } else { @@ -606,6 +617,12 @@ static int start_vga_cam(struct gspca_dev *gspca_dev) msleep(200); } + if (force_sensor_type != -1) { + sd->sensor_type = !! force_sensor_type; + PDEBUG(D_PROBE, "Forcing sensor type to: %d", + sd->sensor_type); + } + /* * Known VGA cameras. * This test is only run if the previous test returned 0x30, but -- cgit v1.2.3 From 4b70cc85ac708fdb3107b4d17851e70e6bf9ecc6 Mon Sep 17 00:00:00 2001 From: "hans@rhel5-devel.localdomain" Date: Thu, 3 Sep 2009 09:14:36 +0200 Subject: gspca_mr97310a: Add one more vivitar mini cam to the list of CIF cams From: Hans de Goede gspca_mr97310a: Add one more vivitar mini cam to the list of CIF cams Priority: normal Signed-off-by: Hans de Goede --- linux/drivers/media/video/gspca/mr97310a.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux/drivers/media/video/gspca') diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c index 169cdb65c..140c8f320 100644 --- a/linux/drivers/media/video/gspca/mr97310a.c +++ b/linux/drivers/media/video/gspca/mr97310a.c @@ -393,6 +393,7 @@ static int sd_config(struct gspca_dev *gspca_dev, * Sakar Spy-shot 0x28 T. Kilgore 0 * Innovage 0xf5 (unstable) T. Kilgore 0 * Vivitar Mini 0x53 H. De Goede 0 + * Vivitar Mini 0x04 / 0x24 E. Rodriguez 0 * Vivitar Mini 0x08 T. Kilgore 1 * Elta-Media 8212dc 0x23 T. Kaiser 1 * Philips dig. keych. 0x37 T. Kilgore 1 -- cgit v1.2.3