From 36a516d953e02523e78ce27fbff91a968a9e5751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Tue, 23 Jun 2009 12:22:48 -0300 Subject: V4L/DVB (12221): gspca - stv06xx-hdcs: Actually update the sensor state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index 3039ec208f3..ec7f5536a8a 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -174,7 +174,9 @@ static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state) } ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val); - if (ret < 0) + + /* Update the state if the write succeeded */ + if (!ret) hdcs->state = state; return ret; -- cgit v1.2.3 From ac51295ccc0ff922fea62cfc6f72cddf9c6c7306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 24 Jun 2009 04:30:56 -0300 Subject: V4L/DVB (12222): gspca - stv06xx-hdcs: Fix sensor sequence bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All hdcs registers use bit 0 as a read/write flag and needs to be shifted one bit to the left. This wasn't accounted for when doing a sequence of writes. Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index ec7f5536a8a..a45171be3f8 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -131,9 +131,11 @@ static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) (reg + len > 0xff))) return -EINVAL; - for (i = 0; i < len; i++, reg++) { - regs[2*i] = reg; - regs[2*i+1] = vals[i]; + for (i = 0; i < len; i++) { + regs[2 * i] = reg; + regs[2 * i + 1] = vals[i]; + /* All addresses are shifted left one bit as bit 0 toggles r/w */ + reg += 2; } return stv06xx_write_sensor_bytes(sd, regs, len); -- cgit v1.2.3 From c0ea8f5b7264c813ee885f02b663ee3106f98afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 1 Jul 2009 02:56:44 -0300 Subject: V4L/DVB (12223): gspca - stv06xx-hdcs: Correct the pixelformat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index a45171be3f8..e5024c8496e 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -64,7 +64,7 @@ static struct v4l2_pix_format hdcs1x00_mode[] = { { HDCS_1X00_DEF_WIDTH, HDCS_1X00_DEF_HEIGHT, - V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, .sizeimage = HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT, @@ -80,7 +80,7 @@ static struct v4l2_pix_format hdcs1020_mode[] = { { HDCS_1020_DEF_WIDTH, HDCS_1020_DEF_HEIGHT, - V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, .sizeimage = HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT, -- cgit v1.2.3 From 641f75caa874fffd679b64f850adee37103b0c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 8 Jul 2009 14:47:16 -0300 Subject: V4L/DVB (12224): gspca - m5602-s5k4aa: Remove erroneous register writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A couple of erroneous register writes snuck in that made the image go haywire. Remove these. Many thanks to Grégory Lardière for finding this out Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/m5602/m5602_s5k4aa.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index 191bcd71897..0163903d1c0 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -474,9 +474,6 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set vertical flip to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) return err; @@ -522,9 +519,6 @@ static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set horizontal flip to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) return err; -- cgit v1.2.3 From c43221df762c33e832e8855cae77989b6bf69fa6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 12 Jul 2009 10:23:23 -0300 Subject: V4L/DVB (12233): em28xx: rename is_27xx to is_webcam Just renames the flag, to use a clearer name. Later patches will use this flag to properly set some drivers behaviors for webcams. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 4 ++-- drivers/media/video/em28xx/em28xx-core.c | 4 ++-- drivers/media/video/em28xx/em28xx-video.c | 4 ++-- drivers/media/video/em28xx/em28xx.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index ebd24a25fb8..8f869468280 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -450,7 +450,7 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_SILVERCREST_WEBCAM] = { .name = "Silvercrest Webcam 1.3mpix", .tuner_type = TUNER_ABSENT, - .is_27xx = 1, + .is_webcam = 1, .decoder = EM28XX_MT9V011, .input = { { .type = EM28XX_VMUX_COMPOSITE1, @@ -1772,7 +1772,7 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_info("chip ID is em2750\n"); break; case CHIP_ID_EM2820: - if (dev->board.is_27xx) + if (dev->board.is_webcam) em28xx_info("chip is em2710\n"); else em28xx_info("chip ID is em2820\n"); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 079ab4d563a..8649bdb7eb9 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -652,7 +652,7 @@ int em28xx_set_outfmt(struct em28xx *dev) outfmt = dev->format->reg; - if (dev->board.is_27xx) { + if (dev->board.is_webcam) { vinmode = 0x0d; vinctl = 0x00; } else { @@ -707,7 +707,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) u8 mode; /* the em2800 scaler only supports scaling down to 50% */ - if (dev->board.is_27xx) { + if (dev->board.is_webcam) { /* FIXME: Don't use the scaler yet */ mode = 0; } else if (dev->board.is_em2800) { diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 14316c91217..89ab2e3b9a2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -726,7 +726,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; } - if (dev->board.is_27xx) { + if (dev->board.is_webcam) { /* FIXME: This is the only supported fmt */ width = 640; height = 480; @@ -768,7 +768,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, struct em28xx_fmt *fmt; /* FIXME: This is the only supported fmt */ - if (dev->board.is_27xx) { + if (dev->board.is_webcam) { width = 640; height = 480; } diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d90fef46376..dc92e9ef85a 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -390,7 +390,7 @@ struct em28xx_board { unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; - unsigned int is_27xx:1; + unsigned int is_webcam:1; unsigned int valid:1; unsigned char xclk, i2c_speed; -- cgit v1.2.3 From 8a2e6990f44d4cebaafcc0af1a786912ae733bb2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 12 Jul 2009 10:26:36 -0300 Subject: V4L/DVB (12234): em28xx-cards: use is_webcam flag for devices that are known to be webcams By having the webcam devices marked as such, it will help the em28xx driver to do the right thing on those devices. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 8f869468280..9e71f034665 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -207,7 +207,8 @@ struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { .name = "Unknown EM2750/EM2751 webcam grabber", .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, - .tuner_type = TUNER_ABSENT, /* This is a webcam */ + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -239,7 +240,8 @@ struct em28xx_board em28xx_boards[] = { .name = "Huaqi DLCW-130", .valid = EM28XX_BOARD_NOT_VALIDATED, .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, - .tuner_type = TUNER_ABSENT, /* This is a webcam */ + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -440,7 +442,8 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { .name = "Videology 20K14XUSB USB2.0", .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* This is a webcam */ + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -500,7 +503,8 @@ struct em28xx_board em28xx_boards[] = { /* Beijing Huaqi Information Digital Technology Co., Ltd */ .name = "NetGMBH Cam", .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* This is a webcam */ + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, -- cgit v1.2.3 From 8b220793d6fd309176438721088515be893630cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 12 Jul 2009 10:56:21 -0300 Subject: V4L/DVB (12235): em28xx: detects sensors also with the generic em2750/2750 entry Webcams in general don't have eeprom. So, the sensor hint code should be called to properly detect what sensor is inside. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 9e71f034665..e64e1242a1b 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -205,7 +205,7 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = { */ struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { - .name = "Unknown EM2750/EM2751 webcam grabber", + .name = "EM2710/EM2750/EM2751 webcam grabber", .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, .tuner_type = TUNER_ABSENT, .is_webcam = 1, @@ -1720,7 +1720,8 @@ static int em28xx_hint_sensor(struct em28xx *dev) __be16 version_be; u16 version; - if (dev->model != EM2820_BOARD_UNKNOWN) + if (dev->model != EM2820_BOARD_UNKNOWN && + dev->model != EM2750_BOARD_UNKNOWN) return 0; dev->i2c_client.addr = 0xba >> 1; @@ -1738,11 +1739,11 @@ static int em28xx_hint_sensor(struct em28xx *dev) sensor_name = "mt9v011"; break; default: - printk("Unknown Sensor 0x%04x\n", be16_to_cpu(version)); + printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version)); return -EINVAL; } - em28xx_errdev("Sensor is %s, assuming that webcam is %s\n", + em28xx_errdev("Sensor is %s, using model %s entry.\n", sensor_name, em28xx_boards[dev->model].name); return 0; -- cgit v1.2.3 From 527f09a981e398331c2f8d8f7af83cd46e6a06cc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 12 Jul 2009 11:04:15 -0300 Subject: V4L/DVB (12236): em28xx: stop abusing of board->decoder for sensor information Instead of using em28xx board decoder field for storing sensor information, let's use instead a separate field for it. Also, as sensors are currently autodetected, there's no need of having it at the boards description. So, move it to the main em28xx struct. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 4 ++-- drivers/media/video/em28xx/em28xx.h | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index e64e1242a1b..530170ae016 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -454,7 +454,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Silvercrest Webcam 1.3mpix", .tuner_type = TUNER_ABSENT, .is_webcam = 1, - .decoder = EM28XX_MT9V011, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -1737,6 +1736,7 @@ static int em28xx_hint_sensor(struct em28xx *dev) case MT9V011_VERSION: dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; sensor_name = "mt9v011"; + dev->em28xx_sensor = EM28XX_MT9V011; break; default: printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version)); @@ -2267,7 +2267,7 @@ void em28xx_card_setup(struct em28xx *dev) v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, "tvp5150", "tvp5150", tvp5150_addrs); - if (dev->board.decoder == EM28XX_MT9V011) + if (dev->em28xx_sensor == EM28XX_MT9V011) v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index dc92e9ef85a..655dd78cc07 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -358,9 +358,13 @@ struct em28xx_input { #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) enum em28xx_decoder { - EM28XX_NODECODER, + EM28XX_NODECODER = 0, EM28XX_TVP5150, EM28XX_SAA711X, +}; + +enum em28xx_sensor { + EM28XX_NOSENSOR = 0, EM28XX_MT9V011, }; @@ -474,6 +478,8 @@ struct em28xx { struct v4l2_device v4l2_dev; struct em28xx_board board; + enum em28xx_sensor em28xx_sensor; + unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; unsigned int has_alsa_audio:1; -- cgit v1.2.3 From 9873740b2f41b37ec074afd4b8910b87dbebc0db Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 13 Jul 2009 01:03:37 -0300 Subject: V4L/DVB (12237): mt9v011: implement VIDIOC_QUERYCTRL Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v011.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 1fe8fc9183a..241382f5ba2 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -215,6 +215,23 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return -EINVAL; } +static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + int i; + + v4l2_dbg(1, debug, sd, "queryctrl called\n"); + + for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++) + if (qc->id && qc->id == mt9v011_qctrl[i].id) { + memcpy(qc, &(mt9v011_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + + static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct mt9v011 *core = to_mt9v011(sd); @@ -338,6 +355,7 @@ static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, } static const struct v4l2_subdev_core_ops mt9v011_core_ops = { + .queryctrl = mt9v011_queryctrl, .g_ctrl = mt9v011_g_ctrl, .s_ctrl = mt9v011_s_ctrl, .reset = mt9v011_reset, -- cgit v1.2.3 From b04fb6615285d18df34ffd6cdd51db7a8a78dda0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 13 Jul 2009 01:28:21 -0300 Subject: V4L/DVB (12238): em28xx: call sensor detection code for all webcam entries With the previous approach, autodetection were working only for the two generic entries (em275x and em2820 unknown ones). So, if someone would try to force probing an specific device, the code would not properly run the autodetection code. With the new approach, the sensor autodetection will be run not only for the two generic entries, but also do webcam specific ones. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 530170ae016..1318766b35b 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -234,6 +234,7 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_UNKNOWN] = { .name = "Unknown EM2750/28xx video grabber", .tuner_type = TUNER_ABSENT, + .is_webcam = 1, /* To enable sensor probe */ }, [EM2750_BOARD_DLCW_130] = { /* Beijing Huaqi Information Digital Technology Co., Ltd */ @@ -1719,10 +1720,6 @@ static int em28xx_hint_sensor(struct em28xx *dev) __be16 version_be; u16 version; - if (dev->model != EM2820_BOARD_UNKNOWN && - dev->model != EM2750_BOARD_UNKNOWN) - return 0; - dev->i2c_client.addr = 0xba >> 1; cmd = 0; i2c_master_send(&dev->i2c_client, &cmd, 1); @@ -1777,10 +1774,7 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_info("chip ID is em2750\n"); break; case CHIP_ID_EM2820: - if (dev->board.is_webcam) - em28xx_info("chip is em2710\n"); - else - em28xx_info("chip ID is em2820\n"); + em28xx_info("chip ID is em2710 or em2820\n"); break; case CHIP_ID_EM2840: em28xx_info("chip ID is em2840\n"); @@ -2415,7 +2409,13 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return errCode; } - em28xx_hint_sensor(dev); + /* + * If the device can be a webcam, seek for a sensor. + * If sensor is not found, then it isn't a webcam. + */ + if (dev->board.is_webcam) + if (em28xx_hint_sensor(dev) < 0) + dev->board.is_webcam = 0; /* Do board specific init and eeprom reading */ em28xx_card_setup(dev); -- cgit v1.2.3 From 5569996421fa1cfc1fc0d9e683ac1def46ea985d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 13 Jul 2009 20:15:02 -0300 Subject: V4L/DVB (12239): em28xx: fix webcam scaling While trying to fix an mt9v001 webcam, I noticed that HSCALE/VSCALE do work with em28xx + webcam. The issue is that the scaling setup depends on the number of visible rows/cols of the input image. With mt9v011 (Silvercrest), the resolution is 640x480. So, the scaling is different from a normal TV image (720x480 on NTSC). This were causing a wrong scaling and a previous patch disabled scaling. As each sensor have their different resolution setting, the xres/yres should be adjusted accordingly with the input sensor. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 6 +++--- drivers/media/video/em28xx/em28xx-core.c | 5 +---- drivers/media/video/em28xx/em28xx-video.c | 16 +++------------- drivers/media/video/em28xx/em28xx.h | 15 +++++++++++---- 4 files changed, 18 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 1318766b35b..d4a7e6075cc 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -58,8 +58,6 @@ static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -#define MT9V011_VERSION 0x8243 - /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ static unsigned long em28xx_devused; @@ -1730,10 +1728,12 @@ static int em28xx_hint_sensor(struct em28xx *dev) version = be16_to_cpu(version_be); switch (version) { - case MT9V011_VERSION: + case 0x8243: /* mt9v011 640x480 1.3 Mpix sensor */ dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; sensor_name = "mt9v011"; dev->em28xx_sensor = EM28XX_MT9V011; + dev->sensor_xres = 640; + dev->sensor_yres = 480; break; default: printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version)); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 8649bdb7eb9..c7fcce71394 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -707,10 +707,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) u8 mode; /* the em2800 scaler only supports scaling down to 50% */ - if (dev->board.is_webcam) { - /* FIXME: Don't use the scaler yet */ - mode = 0; - } else if (dev->board.is_em2800) { + if (dev->board.is_em2800) { mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); } else { u8 buf[2]; diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 89ab2e3b9a2..ff37b4c15f4 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -657,8 +657,8 @@ static void get_scale(struct em28xx *dev, unsigned int width, unsigned int height, unsigned int *hscale, unsigned int *vscale) { - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); *hscale = (((unsigned long)maxw) << 12) / width - 4096L; if (*hscale >= 0x4000) @@ -726,11 +726,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; } - if (dev->board.is_webcam) { - /* FIXME: This is the only supported fmt */ - width = 640; - height = 480; - } else if (dev->board.is_em2800) { + if (dev->board.is_em2800) { /* the em2800 can only scale down to 50% */ height = height > (3 * maxh / 4) ? maxh : maxh / 2; width = width > (3 * maxw / 4) ? maxw : maxw / 2; @@ -767,12 +763,6 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, { struct em28xx_fmt *fmt; - /* FIXME: This is the only supported fmt */ - if (dev->board.is_webcam) { - width = 640; - height = 480; - } - fmt = format_by_fourcc(fourcc); if (!fmt) return -EINVAL; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 655dd78cc07..71444ddbe40 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -479,6 +479,7 @@ struct em28xx { struct em28xx_board board; enum em28xx_sensor em28xx_sensor; + int sensor_xres, sensor_yres; unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; @@ -760,17 +761,23 @@ static inline int em28xx_gamma_set(struct em28xx *dev, s32 val) /*FIXME: maxw should be dependent of alt mode */ static inline unsigned int norm_maxw(struct em28xx *dev) { + if (dev->board.is_webcam) + return dev->sensor_xres; + if (dev->board.max_range_640_480) return 640; - else - return 720; + + return 720; } static inline unsigned int norm_maxh(struct em28xx *dev) { + if (dev->board.is_webcam) + return dev->sensor_yres; + if (dev->board.max_range_640_480) return 480; - else - return (dev->norm & V4L2_STD_625_50) ? 576 : 480; + + return (dev->norm & V4L2_STD_625_50) ? 576 : 480; } #endif -- cgit v1.2.3 From e11206e67f738b04d0c508795adc9bff504bc875 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jul 2009 02:38:18 -0300 Subject: V4L/DVB (12240): mt9v011: add a function to calculate frames per second rate It is possible to adjust the fps rate by changing some register values. This is function of the connected Xtal at the camera sensor, being a 27 MHz cristal needed, in order to support 640x480 at 30 fps. For now, it will only calculate the values for fps. Later patches may introduce V4L2 ioctls, to allow frequency rate adjustments. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v011.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 241382f5ba2..f7b5279a7d5 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "mt9v011.h" #include @@ -57,6 +58,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = { struct mt9v011 { struct v4l2_subdev sd; unsigned width, height; + unsigned xtal; u16 global_gain, red_bal, blue_bal; }; @@ -131,7 +133,7 @@ static const struct i2c_reg_value mt9v011_init_default[] = { { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, { R20_MT9V011_READ_MODE, 0x1000 }, - { R07_MT9V011_OUT_CTRL, 0x000a }, /* chip enable */ + { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ }; static void set_balance(struct v4l2_subdev *sd) @@ -154,6 +156,31 @@ static void set_balance(struct v4l2_subdev *sd) mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); } +static void calc_fps(struct v4l2_subdev *sd) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned height, width, hblank, vblank, speed; + unsigned row_time, t_time; + u64 frames_per_ms; + unsigned tmp; + + height = mt9v011_read(sd, R03_MT9V011_HEIGHT); + width = mt9v011_read(sd, R04_MT9V011_WIDTH); + hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); + vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); + speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED); + + row_time = (width + 113 + hblank) * (speed + 2); + t_time = row_time * (height + vblank + 1); + + frames_per_ms = core->xtal * 1000l; + do_div(frames_per_ms, t_time); + tmp = frames_per_ms; + + v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", + tmp / 1000, tmp % 1000, t_time); +} + static void set_res(struct v4l2_subdev *sd) { struct mt9v011 *core = to_mt9v011(sd); @@ -179,6 +206,8 @@ static void set_res(struct v4l2_subdev *sd) mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); + + calc_fps(sd); }; static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) @@ -413,6 +442,7 @@ static int mt9v011_probe(struct i2c_client *c, core->global_gain = 0x0024; core->width = 640; core->height = 480; + core->xtal = 27000000; /* Hz */ v4l_info(c, "chip found @ 0x%02x (%s)\n", c->addr << 1, c->adapter->name); -- cgit v1.2.3 From c180604a87c5abb0a117998009d01a4499d58653 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jul 2009 02:39:19 -0300 Subject: V4L/DVB (12241): mt9v011: Fix vstart vstart calculus were wrong. Fix it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v011.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index f7b5279a7d5..d7b15dd836e 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -202,7 +202,7 @@ static void set_res(struct v4l2_subdev *sd) mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); - vstart = 8 + (640 - core->height) / 2; + vstart = 8 + (480 - core->height) / 2; mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); -- cgit v1.2.3 From 2ea472ff704a8a94b3b9abec438db23e512be337 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jul 2009 03:14:21 -0300 Subject: V4L/DVB (12242): mt9v011: implement core->s_config to allow adjusting xtal frequency Since frames per second is a function of cristal frequency, and this is device-specific, add a function that allows adjusting it, via subdev->core->s_config callback. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9v011.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index d7b15dd836e..b2260de645f 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -340,6 +340,22 @@ static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return 0; } +static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned *xtal = data; + + v4l2_dbg(1, debug, sd, "s_config called\n"); + + if (xtal) { + core->xtal = *xtal; + v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n", + *xtal / 1000000, (*xtal / 1000) % 1000); + } + + return 0; +} + #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9v011_g_register(struct v4l2_subdev *sd, @@ -388,6 +404,7 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { .g_ctrl = mt9v011_g_ctrl, .s_ctrl = mt9v011_s_ctrl, .reset = mt9v011_reset, + .s_config = mt9v011_s_config, .g_chip_ident = mt9v011_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9v011_g_register, -- cgit v1.2.3 From d36bb4e77257ed0df86deca3f69794f037f68c7d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jul 2009 03:18:39 -0300 Subject: V4L/DVB (12243): em28xx: allow specifying sensor xtal frequency In order to properly estimate fps, mt9v011 sensor driver needs to know what is the used frequency on the sensor cristal. Adds the proper fields and initialization code for specifying the cristal frequency. Also, based on experimentation, it was noticed that the Silvercrest is outputing data at 7 fps. This means that it should be using a 6.3 MHz cristal. This information needs to be double checked later, by opening the device. Anyway, by using this value for xtal, at least now we have the correct fps report. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 11 ++++++++--- drivers/media/video/em28xx/em28xx.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index d4a7e6075cc..82536dd6b0f 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1734,6 +1734,7 @@ static int em28xx_hint_sensor(struct em28xx *dev) dev->em28xx_sensor = EM28XX_MT9V011; dev->sensor_xres = 640; dev->sensor_yres = 480; + dev->sensor_xtal = 6300000; break; default: printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version)); @@ -2261,9 +2262,13 @@ void em28xx_card_setup(struct em28xx *dev) v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, "tvp5150", "tvp5150", tvp5150_addrs); - if (dev->em28xx_sensor == EM28XX_MT9V011) - v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "mt9v011", "mt9v011", mt9v011_addrs); + if (dev->em28xx_sensor == EM28XX_MT9V011) { + struct v4l2_subdev *sd; + + sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, + &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs); + v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal); + } if (dev->board.adecoder == EM28XX_TVAUDIO) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 71444ddbe40..ce76633786c 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -478,8 +478,10 @@ struct em28xx { struct v4l2_device v4l2_dev; struct em28xx_board board; + /* Webcam specific fields */ enum em28xx_sensor em28xx_sensor; int sensor_xres, sensor_yres; + int sensor_xtal; unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; -- cgit v1.2.3 From 579d315218e8a3f696e375c5f6917da6488bec8a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jul 2009 12:33:25 -0300 Subject: V4L/DVB (12244): em28xx: adjust vinmode/vinctl based on the stream input format Depending on the video input format, vinmode/vinctl needs adjustments. For TV, this is not relevant, since the supported decoders output data at the same format. However, webcam sensors may have different formats, so, this needs to be adjusted based on the device. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 11 +++++++++++ drivers/media/video/em28xx/em28xx-core.c | 17 +++-------------- drivers/media/video/em28xx/em28xx.h | 3 +++ 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 82536dd6b0f..e793aee1672 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1735,6 +1735,11 @@ static int em28xx_hint_sensor(struct em28xx *dev) dev->sensor_xres = 640; dev->sensor_yres = 480; dev->sensor_xtal = 6300000; + + /* probably means GRGB 16 bit bayer */ + dev->vinmode = 0x0d; + dev->vinctl = 0x00; + break; default: printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version)); @@ -2414,6 +2419,12 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return errCode; } + /* + * Default format, used for tvp5150 or saa711x output formats + */ + dev->vinmode = 0x10; + dev->vinctl = 0x11; + /* * If the device can be a webcam, seek for a sensor. * If sensor is not found, then it isn't a webcam. diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index c7fcce71394..5b78e199abd 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -648,28 +648,17 @@ int em28xx_capture_start(struct em28xx *dev, int start) int em28xx_set_outfmt(struct em28xx *dev) { int ret; - int vinmode, vinctl, outfmt; - - outfmt = dev->format->reg; - - if (dev->board.is_webcam) { - vinmode = 0x0d; - vinctl = 0x00; - } else { - vinmode = 0x10; - vinctl = 0x11; - } ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, - outfmt | 0x20, 0xff); + dev->format->reg | 0x20, 0xff); if (ret < 0) return ret; - ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode); + ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); if (ret < 0) return ret; - return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl); + return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, dev->vinctl); } static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index ce76633786c..766ab59b8d5 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -483,6 +483,9 @@ struct em28xx { int sensor_xres, sensor_yres; int sensor_xtal; + /* Vinmode/Vinctl used at the driver */ + int vinmode, vinctl; + unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; unsigned int has_alsa_audio:1; -- cgit v1.2.3 From b80fd2d811b48a92051f86d257b00f373e69a6d7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jul 2009 21:08:22 -0300 Subject: V4L/DVB (12245): em28xx: add support for mt9m001 webcams Thanks to Wally for bringing the issue and helping with the tests. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 41 +++++++++++++++++++++++++++++++ drivers/media/video/em28xx/em28xx.h | 1 + 2 files changed, 42 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index e793aee1672..1bd789a52e6 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -211,6 +211,7 @@ struct em28xx_board em28xx_boards[] = { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, .amux = EM28XX_AMUX_VIDEO, + .gpio = silvercrest_reg_seq, } }, }, [EM2800_BOARD_UNKNOWN] = { @@ -1706,6 +1707,32 @@ static inline void em28xx_set_model(struct em28xx *dev) EM28XX_I2C_FREQ_100_KHZ; } +/* FIXME: Should be replaced by a proper mt9m001 driver */ +static int em28xx_initialize_mt9m001(struct em28xx *dev) +{ + int i; + unsigned char regs[][3] = { + { 0x0d, 0x00, 0x01, }, + { 0x0d, 0x00, 0x00, }, + { 0x04, 0x05, 0x00, }, /* hres = 1280 */ + { 0x03, 0x04, 0x00, }, /* vres = 1024 */ + { 0x20, 0x11, 0x00, }, + { 0x06, 0x00, 0x10, }, + { 0x2b, 0x00, 0x24, }, + { 0x2e, 0x00, 0x24, }, + { 0x35, 0x00, 0x24, }, + { 0x2d, 0x00, 0x20, }, + { 0x2c, 0x00, 0x20, }, + { 0x09, 0x0a, 0xd4, }, + { 0x35, 0x00, 0x57, }, + }; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, ®s[i][0], 3); + + return 0; +} + /* HINT method: webcam I2C chips * * This method work for webcams with Micron sensors @@ -1740,6 +1767,19 @@ static int em28xx_hint_sensor(struct em28xx *dev) dev->vinmode = 0x0d; dev->vinctl = 0x00; + break; + case 0x8431: + dev->model = EM2750_BOARD_UNKNOWN; + sensor_name = "mt9m001"; + dev->em28xx_sensor = EM28XX_MT9M001; + em28xx_initialize_mt9m001(dev); + dev->sensor_xres = 1280; + dev->sensor_yres = 1024; + + /* probably means BGGR 16 bit bayer */ + dev->vinmode = 0x0c; + dev->vinctl = 0x00; + break; default: printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version)); @@ -2275,6 +2315,7 @@ void em28xx_card_setup(struct em28xx *dev) v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal); } + if (dev->board.adecoder == EM28XX_TVAUDIO) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "tvaudio", "tvaudio", dev->board.tvaudio_addr); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 766ab59b8d5..45bd513f62d 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -366,6 +366,7 @@ enum em28xx_decoder { enum em28xx_sensor { EM28XX_NOSENSOR = 0, EM28XX_MT9V011, + EM28XX_MT9M001, }; enum em28xx_adecoder { -- cgit v1.2.3 From 4fb202a8d9d936f7080ab631140b447a0625e36c Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Sun, 12 Jul 2009 17:51:12 -0300 Subject: V4L/DVB (12257): em28xx: make tuning work for Terratec Cinergy T XS USB (mt352 variant) The Terratec Cinergy T XS USB can have either a zl10353 or an mt352. Add support for the MT352 variant. Thanks to Jelle de Jong for providing a unit to test/debug with. Cc: Jelle de Jong Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-dvb.c | 47 ++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 3da97c32b8f..d57f7583ac6 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -31,6 +31,8 @@ #include "lgdt330x.h" #include "zl10353.h" #include "s5h1409.h" +#include "mt352.h" +#include "mt352_priv.h" /* FIXME */ MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab "); @@ -258,6 +260,41 @@ static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { }; #endif +static int mt352_terratec_xs_init(struct dvb_frontend *fe) +{ + /* Values extracted from a USB trace of the Terratec Windows driver */ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0xa0 }; + static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 }; + static u8 rs_err_cfg[] = { RS_ERR_PER_1, 0x00, 0x4d }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + static u8 trl_nom_cfg[] = { TRL_NOMINAL_RATE_1, 0x64, 0x00 }; + static u8 tps_given_cfg[] = { TPS_GIVEN_1, 0x40, 0x80, 0x50 }; + static u8 tuner_go[] = { TUNER_GO, 0x5d}; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg)); + mt352_write(fe, rs_err_cfg, sizeof(rs_err_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + mt352_write(fe, trl_nom_cfg, sizeof(trl_nom_cfg)); + mt352_write(fe, tps_given_cfg, sizeof(tps_given_cfg)); + mt352_write(fe, tuner_go, sizeof(tuner_go)); + return 0; +} + +static struct mt352_config terratec_xs_mt352_cfg = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .if2 = 45600, + .demod_init = mt352_terratec_xs_init, +}; + /* ------------------------------------------------------------------ */ static int attach_xc3028(u8 addr, struct em28xx *dev) @@ -458,13 +495,11 @@ static int dvb_init(struct em28xx *dev) if (dvb->frontend == NULL) { /* This board could have either a zl10353 or a mt352. If the chip id isn't for zl10353, try mt352 */ - - /* FIXME: make support for mt352 work */ - printk(KERN_ERR "version of this board with mt352 not " - "currently supported\n"); - result = -EINVAL; - goto out_free; + dvb->frontend = dvb_attach(mt352_attach, + &terratec_xs_mt352_cfg, + &dev->i2c_adap); } + if (attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; -- cgit v1.2.3 From ff69786b4ccd0d5b99a60ba0be98237f9b7d8f52 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Sun, 12 Jul 2009 18:44:19 -0300 Subject: V4L/DVB (12258): em28xx: fix typo in mt352 init sequence for Terratec Cinergy T XS USB Andy walls pointed out that we were passing 0x5d to the TUNER_GO register, instead of 0x01. Set the register properly (note the code did still work with the incorrect value, so this does not address a regression). Thanks to Andy Walls for noticing the issue. Cc: Andy Walls Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index d57f7583ac6..f3f0e8fe73c 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -272,7 +272,7 @@ static int mt352_terratec_xs_init(struct dvb_frontend *fe) static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; static u8 trl_nom_cfg[] = { TRL_NOMINAL_RATE_1, 0x64, 0x00 }; static u8 tps_given_cfg[] = { TPS_GIVEN_1, 0x40, 0x80, 0x50 }; - static u8 tuner_go[] = { TUNER_GO, 0x5d}; + static u8 tuner_go[] = { TUNER_GO, 0x01}; mt352_write(fe, clock_config, sizeof(clock_config)); udelay(200); -- cgit v1.2.3 From d5b3ba9cb375620a109d79f2e3a7bc21e9b75d8f Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Wed, 8 Jul 2009 21:51:35 -0300 Subject: V4L/DVB (12260): em28xx: make support work for the Pinnacle Hybrid Pro (eb1a:2881) Setup the GPIOs properly and enable support for the DVB side of the Pinnacle Hybrid Pro USB stick. Thanks to Andreas Lunderhage for testing patches and providing a remote debug environment. Cc: Andreas Lunderhage Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 24 ++++++++++++++++++++---- drivers/media/video/em28xx/em28xx-dvb.c | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 1bd789a52e6..ba20065c24b 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -157,6 +157,20 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { { -1, -1, -1, -1}, }; +/* Pinnacle Hybrid Pro eb1a:2881 */ +static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { + {EM28XX_R08_GPIO, 0x6f, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */ + {EM2880_R04_GPO, 0x0c, 0xff, 1}, + { -1, -1, -1, -1}, +}; + + /* Callback for the most boards */ static struct em28xx_reg_seq default_tuner_gpio[] = { {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, @@ -1253,25 +1267,26 @@ struct em28xx_board em28xx_boards[] = { }, [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { .name = "Pinnacle Hybrid Pro", - .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, + .has_dvb = 1, + .dvb_gpio = pinnacle_hybrid_pro_digital, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, + .gpio = pinnacle_hybrid_pro_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, + .gpio = pinnacle_hybrid_pro_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, - .gpio = default_analog, + .gpio = pinnacle_hybrid_pro_analog, } }, }, [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { @@ -1641,6 +1656,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = { {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, + {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028}, }; /* I2C devicelist hash table for devices with generic USB IDs */ diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index f3f0e8fe73c..5ebc274c1b2 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -489,6 +489,7 @@ static int dvb_init(struct em28xx *dev) } break; case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: dvb->frontend = dvb_attach(zl10353_attach, &em28xx_terratec_xs_zl10353_xc3028, &dev->i2c_adap); -- cgit v1.2.3 From 44010440ca2693a07b1252ee836a23804412575e Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Wed, 8 Jul 2009 22:18:15 -0300 Subject: V4L/DVB (12261): em28xx: set GPIO properly for Pinnacle Hybrid Pro analog support Set the GPIO properly for the analog side of the Pinnacle Hybrid Pro, or else the emp202 doesn't get detected properly. Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index ba20065c24b..476acb02a3d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -159,7 +159,7 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { /* Pinnacle Hybrid Pro eb1a:2881 */ static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { - {EM28XX_R08_GPIO, 0x6f, ~EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; -- cgit v1.2.3 From 5343e446014b93f740d5502f9f3bfa3f66dcbc7c Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Wed, 15 Jul 2009 00:35:47 -0300 Subject: V4L/DVB (12262): em28xx: Make sure the tuner is initialized if generic empia USB id was used In cases where the device has a generic Empia USB ID, the call in the precard setup phase did not set the tuner GPIO. As a result, the tuner may not be taken out of reset before attempting initialization in the analog driver. This problem was not seen before with the EVGA inDtube, since that particular board has the analog GPIO setup to include taking the tuner out of reset. Thanks to Andreas Lunderhage for testing patches and providing a remote debug environment for the Pinnacle 320e. Cc: Andreas Lunderhage Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 476acb02a3d..5aef7ddd091 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2286,6 +2286,7 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, so make the call now so the analog GPIOs are set properly before probing the i2c bus. */ + em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; case EM2820_BOARD_SILVERCREST_WEBCAM: -- cgit v1.2.3 From e16e5a3739cfd208de00d49def10fcfa6ceff46f Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Wed, 15 Jul 2009 00:37:22 -0300 Subject: V4L/DVB (12263): em28xx: set demod profile for Pinnacle Hybrid Pro 320e The Pinnacle Hybrid Pro 320e was missing a demod config for the xc3028, which is required for digital tuning to work properly. Add the missing profile. Thanks to Andreas Lunderhage for testing patches and providing a remote debug environment. Cc: Andreas Lunderhage Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 5aef7ddd091..320f1f60276 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1990,6 +1990,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) ctl->demod = XC3028_FE_ZARLINK456; break; case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: ctl->demod = XC3028_FE_ZARLINK456; break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: -- cgit v1.2.3 From a84f79aed688a94197387830df3a2f2068f49dc0 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Sun, 12 Jul 2009 17:05:02 -0300 Subject: V4L/DVB (12265): em28xx: fix tuning problem in HVR-900 (R1) When the change was introduced in the zl10353 for the i2c gate behavior, this broke the HVR-900 which was not behind a gate. Use a version of the zl10353 config profile that indicates the tuner is not behind such a gate. Without this patch the first tune succeeds, but subsequent tuning attempts will fail. The change also renames the terratec zl10353 profile I wrote to be more generic, since it is shared by the non-terratec device. Thanks to Michael Krufky for providing a HVR-900 and DVB-T environment to test with. Cc: Michael Krufky Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-dvb.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 5ebc274c1b2..cf0ac7f2a30 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -245,7 +245,7 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK }; -static struct zl10353_config em28xx_terratec_xs_zl10353_xc3028 = { +static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { .demod_address = (0x1e >> 1), .no_tuner = 1, .disable_i2c_gate_ctrl = 1, @@ -477,7 +477,6 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_KWORLD_DVB_310U: case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->frontend = dvb_attach(zl10353_attach, @@ -488,10 +487,19 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + dvb->frontend = dvb_attach(zl10353_attach, + &em28xx_zl10353_xc3028_no_i2c_gate, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; case EM2880_BOARD_TERRATEC_HYBRID_XS: case EM2881_BOARD_PINNACLE_HYBRID_PRO: dvb->frontend = dvb_attach(zl10353_attach, - &em28xx_terratec_xs_zl10353_xc3028, + &em28xx_zl10353_xc3028_no_i2c_gate, &dev->i2c_adap); if (dvb->frontend == NULL) { /* This board could have either a zl10353 or a mt352. -- cgit v1.2.3 From 27954930f047df73a16253db2750345034e56c40 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 8 Jul 2009 05:21:50 -0300 Subject: V4L/DVB (12267): gspca - sonixj: Bad sensor init of non ov76xx sensors. The bug was introduced when adding the light frequency control Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 0d02f41fa7d..bad309b90cc 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1634,6 +1634,8 @@ static void setfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (gspca_dev->ctrl_dis & (1 << FREQ_IDX)) + return; if (sd->sensor == SENSOR_OV7660) { switch (sd->freq) { case 0: /* Banding filter disabled */ -- cgit v1.2.3 From a2f5a8117cb185fc347f35e369a6320e6aa9d82d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 10 Jul 2009 20:03:43 -0300 Subject: V4L/DVB (12269): af9013: auto-detect parameters in case of garbage given by app Request demodulator auto-detect transmission parameters in case of garbage parameters provided by application for compatibility. That's needed at least for MPlayer compatibility currently. Thanks to Jelle de Jong for reporting issue and providing SSH access to Devin for debugging. Thanks to Devin Heitmueller for hard debug work he did to find that bug. Cc: Devin Heitmueller Cc: Jelle de Jong Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/af9013.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 136c5863d81..12e018b4107 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -527,6 +527,10 @@ static int af9013_set_ofdm_params(struct af9013_state *state, u8 i, buf[3] = {0, 0, 0}; *auto_mode = 0; /* set if parameters are requested to auto set */ + /* Try auto-detect transmission parameters in case of AUTO requested or + garbage parameters given by application for compatibility. + MPlayer seems to provide garbage parameters currently. */ + switch (params->transmission_mode) { case TRANSMISSION_MODE_AUTO: *auto_mode = 1; @@ -536,7 +540,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (1 << 0); break; default: - return -EINVAL; + deb_info("%s: invalid transmission_mode\n", __func__); + *auto_mode = 1; } switch (params->guard_interval) { @@ -554,7 +559,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 2); break; default: - return -EINVAL; + deb_info("%s: invalid guard_interval\n", __func__); + *auto_mode = 1; } switch (params->hierarchy_information) { @@ -572,7 +578,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 4); break; default: - return -EINVAL; + deb_info("%s: invalid hierarchy_information\n", __func__); + *auto_mode = 1; }; switch (params->constellation) { @@ -587,7 +594,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[1] |= (2 << 6); break; default: - return -EINVAL; + deb_info("%s: invalid constellation\n", __func__); + *auto_mode = 1; } /* Use HP. How and which case we can switch to LP? */ @@ -611,7 +619,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[2] |= (4 << 0); break; default: - return -EINVAL; + deb_info("%s: invalid code_rate_HP\n", __func__); + *auto_mode = 1; } switch (params->code_rate_LP) { @@ -638,7 +647,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, if (params->hierarchy_information == HIERARCHY_AUTO) break; default: - return -EINVAL; + deb_info("%s: invalid code_rate_LP\n", __func__); + *auto_mode = 1; } switch (params->bandwidth) { @@ -651,7 +661,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[1] |= (2 << 2); break; default: - return -EINVAL; + deb_info("%s: invalid bandwidth\n", __func__); + buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */ } /* program */ -- cgit v1.2.3 From af1d9afa75082663ea9e2b67b9381d1af403f52b Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Sun, 19 Jul 2009 05:29:20 -0300 Subject: V4L/DVB (12282): gspca - main: Support for vidioc_g_chip_ident and vidioc_g/s_register. Signed-off-by: Brian Johnson Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 73 +++++++++++++++++++++++++++++++++++++++ drivers/media/video/gspca/gspca.h | 9 +++++ 2 files changed, 82 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 1e89600986c..b8561dfb6c8 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -727,6 +727,74 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev, return -EINVAL; } +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + int ret; + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->get_chip_ident) + return -EINVAL; + + if (!gspca_dev->sd_desc->get_register) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + + return ret; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + int ret; + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->get_chip_ident) + return -EINVAL; + + if (!gspca_dev->sd_desc->set_register) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + + return ret; +} +#endif + +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + int ret; + struct gspca_dev *gspca_dev = priv; + + if (!gspca_dev->sd_desc->get_chip_ident) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->present) + ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + + return ret; +} + static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fmtdesc) { @@ -1883,6 +1951,11 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_s_parm = vidioc_s_parm, .vidioc_s_std = vidioc_s_std, .vidioc_enum_framesizes = vidioc_enum_framesizes, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index bd1faff8864..46c4effdfcd 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -69,6 +69,10 @@ typedef void (*cam_v_op) (struct gspca_dev *); typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *); typedef int (*cam_jpg_op) (struct gspca_dev *, struct v4l2_jpegcompression *); +typedef int (*cam_reg_op) (struct gspca_dev *, + struct v4l2_dbg_register *); +typedef int (*cam_ident_op) (struct gspca_dev *, + struct v4l2_dbg_chip_ident *); typedef int (*cam_streamparm_op) (struct gspca_dev *, struct v4l2_streamparm *); typedef int (*cam_qmnu_op) (struct gspca_dev *, @@ -105,6 +109,11 @@ struct sd_desc { cam_qmnu_op querymenu; cam_streamparm_op get_streamparm; cam_streamparm_op set_streamparm; +#ifdef CONFIG_VIDEO_ADV_DEBUG + cam_reg_op set_register; + cam_reg_op get_register; +#endif + cam_ident_op get_chip_ident; }; /* packet types when moving from iso buf to frame buf */ -- cgit v1.2.3 From 26e744b6b61066203fd57de0d3962353621e06f8 Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Sun, 19 Jul 2009 05:52:58 -0300 Subject: V4L/DVB (12283): gspca - sn9c20x: New subdriver for sn9c201 and sn9c202 bridges. Signed-off-by: Brian Johnson Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/Kconfig | 16 + drivers/media/video/gspca/Makefile | 2 + drivers/media/video/gspca/sn9c20x.c | 2433 +++++++++++++++++++++++++++++++++++ 3 files changed, 2451 insertions(+) create mode 100644 drivers/media/video/gspca/sn9c20x.c (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 578dc4ffc96..34f46f2bc04 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -102,6 +102,22 @@ config USB_GSPCA_PAC7311 To compile this driver as a module, choose M here: the module will be called gspca_pac7311. +config USB_GSPCA_SN9C20X + tristate "SN9C20X USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + sn9c20x chips (SN9C201 and SN9C202). + + To compile this driver as a module, choose M here: the + module will be called gspca_sn9c20x. + +config USB_GSPCA_SN9C20X_EVDEV + bool "Enable evdev support" + depends on USB_GSPCA_SN9C20X + ---help--- + Say Y here in order to enable evdev support for sn9c20x webcam button. + config USB_GSPCA_SONIXB tristate "SONIX Bayer USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 8a6643e8eb9..f6d3b86e9ad 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o +obj-$(CONFIG_USB_GSPCA_SN9C20X) += gspca_sn9c20x.o obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o obj-$(CONFIG_USB_GSPCA_SONIXJ) += gspca_sonixj.o obj-$(CONFIG_USB_GSPCA_SPCA500) += gspca_spca500.o @@ -35,6 +36,7 @@ gspca_ov519-objs := ov519.o gspca_ov534-objs := ov534.o gspca_pac207-objs := pac207.o gspca_pac7311-objs := pac7311.o +gspca_sn9c20x-objs := sn9c20x.o gspca_sonixb-objs := sonixb.o gspca_sonixj-objs := sonixj.o gspca_spca500-objs := spca500.o diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c new file mode 100644 index 00000000000..78ab26ceb90 --- /dev/null +++ b/drivers/media/video/gspca/sn9c20x.c @@ -0,0 +1,2433 @@ +/* + * Sonix sn9c201 sn9c202 library + * Copyright (C) 2008-2009 microdia project + * Copyright (C) 2009 Brian Johnson + * + * 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 + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "gspca.h" +#include "jpeg.h" + +#include +#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV +#include +#include +#include +#include +#endif + +MODULE_AUTHOR("Brian Johnson , " + "microdia project "); +MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#define MODULE_NAME "sn9c20x" + +#define MODE_RAW 0x10 +#define MODE_JPEG 0x20 +#define MODE_SXGA 0x80 + +#define SENSOR_OV9650 0 +#define SENSOR_OV9655 1 +#define SENSOR_SOI968 2 +#define SENSOR_OV7660 3 +#define SENSOR_OV7670 4 +#define SENSOR_MT9V011 5 +#define SENSOR_MT9V111 6 +#define SENSOR_MT9V112 7 +#define SENSOR_MT9M001 8 +#define SENSOR_MT9M111 9 +#define SENSOR_HV7131R 10 +#define SENSOR_MT9VPRB 20 + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; + +#define MIN_AVG_LUM 80 +#define MAX_AVG_LUM 130 + atomic_t avg_lum; + u8 old_step; + u8 older_step; + u8 exposure_step; + + u8 brightness; + u8 contrast; + u8 saturation; + s16 hue; + u8 gamma; + u8 red; + u8 blue; + + u8 hflip; + u8 vflip; + u8 gain; + u16 exposure; + u8 auto_exposure; + + u8 i2c_addr; + u8 sensor; + u8 hstart; + u8 vstart; + + u8 *jpeg_hdr; + u8 quality; + +#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV + struct input_dev *input_dev; + u8 input_gpio; + struct task_struct *input_task; +#endif +}; + +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_setcontrast(struct gspca_dev *gspca_dev, s32 val); +static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val); +static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val); +static int sd_sethue(struct gspca_dev *gspca_dev, s32 val); +static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val); +static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val); +static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val); +static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val); +static int sd_gethflip(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 int sd_setexposure(struct gspca_dev *gspca_dev, s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val); +static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val); +static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val); + +static struct ctrl sd_ctrls[] = { + { +#define BRIGHTNESS_IDX 0 + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define BRIGHTNESS_DEFAULT 0x7f + .default_value = BRIGHTNESS_DEFAULT, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { +#define CONTRAST_IDX 1 + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define CONTRAST_DEFAULT 0x7f + .default_value = CONTRAST_DEFAULT, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { +#define SATURATION_IDX 2 + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define SATURATION_DEFAULT 0x7f + .default_value = SATURATION_DEFAULT, + }, + .set = sd_setsaturation, + .get = sd_getsaturation, + }, + { +#define HUE_IDX 3 + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -180, + .maximum = 180, + .step = 1, +#define HUE_DEFAULT 0 + .default_value = HUE_DEFAULT, + }, + .set = sd_sethue, + .get = sd_gethue, + }, + { +#define GAMMA_IDX 4 + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0, + .maximum = 0xff, + .step = 1, +#define GAMMA_DEFAULT 0x10 + .default_value = GAMMA_DEFAULT, + }, + .set = sd_setgamma, + .get = sd_getgamma, + }, + { +#define BLUE_IDX 5 + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 0x7f, + .step = 1, +#define BLUE_DEFAULT 0x28 + .default_value = BLUE_DEFAULT, + }, + .set = sd_setbluebalance, + .get = sd_getbluebalance, + }, + { +#define RED_IDX 6 + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 0x7f, + .step = 1, +#define RED_DEFAULT 0x28 + .default_value = RED_DEFAULT, + }, + .set = sd_setredbalance, + .get = sd_getredbalance, + }, + { +#define HFLIP_IDX 7 + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEFAULT 0 + .default_value = HFLIP_DEFAULT, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { +#define VFLIP_IDX 8 + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEFAULT 0 + .default_value = VFLIP_DEFAULT, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, + { +#define EXPOSURE_IDX 9 + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 0x1780, + .step = 1, +#define EXPOSURE_DEFAULT 0x33 + .default_value = EXPOSURE_DEFAULT, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { +#define GAIN_IDX 10 + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 28, + .step = 1, +#define GAIN_DEFAULT 0x00 + .default_value = GAIN_DEFAULT, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { +#define AUTOGAIN_IDX 11 + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTO_EXPOSURE_DEFAULT 1 + .default_value = AUTO_EXPOSURE_DEFAULT, + }, + .set = sd_setautoexposure, + .get = sd_getautoexposure, + }, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 240, + .sizeimage = 240 * 120, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0 | MODE_JPEG}, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 | MODE_RAW}, + {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 240, + .sizeimage = 240 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 480, + .sizeimage = 480 * 240 , + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1 | MODE_JPEG}, + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW}, + {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 480, + .sizeimage = 480 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 960, + .sizeimage = 960 * 480, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2 | MODE_JPEG}, + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 | MODE_RAW}, + {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 960, + .sizeimage = 960 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, +}; + +static const struct v4l2_pix_format sxga_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 240, + .sizeimage = 240 * 120, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0 | MODE_JPEG}, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 | MODE_RAW}, + {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 240, + .sizeimage = 240 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 480, + .sizeimage = 480 * 240 , + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1 | MODE_JPEG}, + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW}, + {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 480, + .sizeimage = 480 * 240 , + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 960, + .sizeimage = 960 * 480, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2 | MODE_JPEG}, + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 | MODE_RAW}, + {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE, + .bytesperline = 960, + .sizeimage = 960 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = (1280 * 1024) + 64, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3 | MODE_RAW | MODE_SXGA}, +}; + +static const int hsv_red_x[] = { + 41, 44, 46, 48, 50, 52, 54, 56, + 58, 60, 62, 64, 66, 68, 70, 72, + 74, 76, 78, 80, 81, 83, 85, 87, + 88, 90, 92, 93, 95, 97, 98, 100, + 101, 102, 104, 105, 107, 108, 109, 110, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 123, 124, 125, 125, + 126, 127, 127, 128, 128, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 129, 129, 129, 128, 128, 127, 127, 126, + 125, 125, 124, 123, 122, 122, 121, 120, + 119, 118, 117, 116, 115, 114, 112, 111, + 110, 109, 107, 106, 105, 103, 102, 101, + 99, 98, 96, 94, 93, 91, 90, 88, + 86, 84, 83, 81, 79, 77, 75, 74, + 72, 70, 68, 66, 64, 62, 60, 58, + 56, 54, 52, 49, 47, 45, 43, 41, + 39, 36, 34, 32, 30, 28, 25, 23, + 21, 19, 16, 14, 12, 9, 7, 5, + 3, 0, -1, -3, -6, -8, -10, -12, + -15, -17, -19, -22, -24, -26, -28, -30, + -33, -35, -37, -39, -41, -44, -46, -48, + -50, -52, -54, -56, -58, -60, -62, -64, + -66, -68, -70, -72, -74, -76, -78, -80, + -81, -83, -85, -87, -88, -90, -92, -93, + -95, -97, -98, -100, -101, -102, -104, -105, + -107, -108, -109, -110, -112, -113, -114, -115, + -116, -117, -118, -119, -120, -121, -122, -123, + -123, -124, -125, -125, -126, -127, -127, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -127, -127, -126, -125, -125, -124, -123, + -122, -122, -121, -120, -119, -118, -117, -116, + -115, -114, -112, -111, -110, -109, -107, -106, + -105, -103, -102, -101, -99, -98, -96, -94, + -93, -91, -90, -88, -86, -84, -83, -81, + -79, -77, -75, -74, -72, -70, -68, -66, + -64, -62, -60, -58, -56, -54, -52, -49, + -47, -45, -43, -41, -39, -36, -34, -32, + -30, -28, -25, -23, -21, -19, -16, -14, + -12, -9, -7, -5, -3, 0, 1, 3, + 6, 8, 10, 12, 15, 17, 19, 22, + 24, 26, 28, 30, 33, 35, 37, 39, 41 +}; + +static const int hsv_red_y[] = { + 82, 80, 78, 76, 74, 73, 71, 69, + 67, 65, 63, 61, 58, 56, 54, 52, + 50, 48, 46, 44, 41, 39, 37, 35, + 32, 30, 28, 26, 23, 21, 19, 16, + 14, 12, 10, 7, 5, 3, 0, -1, + -3, -6, -8, -10, -13, -15, -17, -19, + -22, -24, -26, -29, -31, -33, -35, -38, + -40, -42, -44, -46, -48, -51, -53, -55, + -57, -59, -61, -63, -65, -67, -69, -71, + -73, -75, -77, -79, -81, -82, -84, -86, + -88, -89, -91, -93, -94, -96, -98, -99, + -101, -102, -104, -105, -106, -108, -109, -110, + -112, -113, -114, -115, -116, -117, -119, -120, + -120, -121, -122, -123, -124, -125, -126, -126, + -127, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, + -127, -127, -126, -125, -125, -124, -123, -122, + -121, -120, -119, -118, -117, -116, -115, -114, + -113, -111, -110, -109, -107, -106, -105, -103, + -102, -100, -99, -97, -96, -94, -92, -91, + -89, -87, -85, -84, -82, -80, -78, -76, + -74, -73, -71, -69, -67, -65, -63, -61, + -58, -56, -54, -52, -50, -48, -46, -44, + -41, -39, -37, -35, -32, -30, -28, -26, + -23, -21, -19, -16, -14, -12, -10, -7, + -5, -3, 0, 1, 3, 6, 8, 10, + 13, 15, 17, 19, 22, 24, 26, 29, + 31, 33, 35, 38, 40, 42, 44, 46, + 48, 51, 53, 55, 57, 59, 61, 63, + 65, 67, 69, 71, 73, 75, 77, 79, + 81, 82, 84, 86, 88, 89, 91, 93, + 94, 96, 98, 99, 101, 102, 104, 105, + 106, 108, 109, 110, 112, 113, 114, 115, + 116, 117, 119, 120, 120, 121, 122, 123, + 124, 125, 126, 126, 127, 128, 128, 129, + 129, 130, 130, 131, 131, 131, 131, 132, + 132, 132, 132, 132, 132, 132, 132, 132, + 132, 132, 132, 131, 131, 131, 130, 130, + 130, 129, 129, 128, 127, 127, 126, 125, + 125, 124, 123, 122, 121, 120, 119, 118, + 117, 116, 115, 114, 113, 111, 110, 109, + 107, 106, 105, 103, 102, 100, 99, 97, + 96, 94, 92, 91, 89, 87, 85, 84, 82 +}; + +static const int hsv_green_x[] = { + -124, -124, -125, -125, -125, -125, -125, -125, + -125, -126, -126, -125, -125, -125, -125, -125, + -125, -124, -124, -124, -123, -123, -122, -122, + -121, -121, -120, -120, -119, -118, -117, -117, + -116, -115, -114, -113, -112, -111, -110, -109, + -108, -107, -105, -104, -103, -102, -100, -99, + -98, -96, -95, -93, -92, -91, -89, -87, + -86, -84, -83, -81, -79, -77, -76, -74, + -72, -70, -69, -67, -65, -63, -61, -59, + -57, -55, -53, -51, -49, -47, -45, -43, + -41, -39, -37, -35, -33, -30, -28, -26, + -24, -22, -20, -18, -15, -13, -11, -9, + -7, -4, -2, 0, 1, 3, 6, 8, + 10, 12, 14, 17, 19, 21, 23, 25, + 27, 29, 32, 34, 36, 38, 40, 42, + 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 66, 68, 70, 71, 73, + 75, 77, 78, 80, 82, 83, 85, 87, + 88, 90, 91, 93, 94, 96, 97, 98, + 100, 101, 102, 104, 105, 106, 107, 108, + 109, 111, 112, 113, 113, 114, 115, 116, + 117, 118, 118, 119, 120, 120, 121, 122, + 122, 123, 123, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 125, 126, 126, 125, + 125, 125, 125, 125, 125, 124, 124, 124, + 123, 123, 122, 122, 121, 121, 120, 120, + 119, 118, 117, 117, 116, 115, 114, 113, + 112, 111, 110, 109, 108, 107, 105, 104, + 103, 102, 100, 99, 98, 96, 95, 93, + 92, 91, 89, 87, 86, 84, 83, 81, + 79, 77, 76, 74, 72, 70, 69, 67, + 65, 63, 61, 59, 57, 55, 53, 51, + 49, 47, 45, 43, 41, 39, 37, 35, + 33, 30, 28, 26, 24, 22, 20, 18, + 15, 13, 11, 9, 7, 4, 2, 0, + -1, -3, -6, -8, -10, -12, -14, -17, + -19, -21, -23, -25, -27, -29, -32, -34, + -36, -38, -40, -42, -44, -46, -48, -50, + -52, -54, -56, -58, -60, -62, -64, -66, + -68, -70, -71, -73, -75, -77, -78, -80, + -82, -83, -85, -87, -88, -90, -91, -93, + -94, -96, -97, -98, -100, -101, -102, -104, + -105, -106, -107, -108, -109, -111, -112, -113, + -113, -114, -115, -116, -117, -118, -118, -119, + -120, -120, -121, -122, -122, -123, -123, -124, -124 +}; + +static const int hsv_green_y[] = { + -100, -99, -98, -97, -95, -94, -93, -91, + -90, -89, -87, -86, -84, -83, -81, -80, + -78, -76, -75, -73, -71, -70, -68, -66, + -64, -63, -61, -59, -57, -55, -53, -51, + -49, -48, -46, -44, -42, -40, -38, -36, + -34, -32, -30, -27, -25, -23, -21, -19, + -17, -15, -13, -11, -9, -7, -4, -2, + 0, 1, 3, 5, 7, 9, 11, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 59, 61, + 63, 65, 67, 68, 70, 72, 74, 75, + 77, 78, 80, 82, 83, 85, 86, 88, + 89, 90, 92, 93, 95, 96, 97, 98, + 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 112, 113, 114, + 115, 115, 116, 116, 117, 117, 118, 118, + 119, 119, 119, 120, 120, 120, 120, 120, + 121, 121, 121, 121, 121, 121, 120, 120, + 120, 120, 120, 119, 119, 119, 118, 118, + 117, 117, 116, 116, 115, 114, 114, 113, + 112, 111, 111, 110, 109, 108, 107, 106, + 105, 104, 103, 102, 100, 99, 98, 97, + 95, 94, 93, 91, 90, 89, 87, 86, + 84, 83, 81, 80, 78, 76, 75, 73, + 71, 70, 68, 66, 64, 63, 61, 59, + 57, 55, 53, 51, 49, 48, 46, 44, + 42, 40, 38, 36, 34, 32, 30, 27, + 25, 23, 21, 19, 17, 15, 13, 11, + 9, 7, 4, 2, 0, -1, -3, -5, + -7, -9, -11, -14, -16, -18, -20, -22, + -24, -26, -28, -30, -32, -34, -36, -38, + -40, -42, -44, -46, -48, -50, -52, -54, + -56, -58, -59, -61, -63, -65, -67, -68, + -70, -72, -74, -75, -77, -78, -80, -82, + -83, -85, -86, -88, -89, -90, -92, -93, + -95, -96, -97, -98, -100, -101, -102, -103, + -104, -105, -106, -107, -108, -109, -110, -111, + -112, -112, -113, -114, -115, -115, -116, -116, + -117, -117, -118, -118, -119, -119, -119, -120, + -120, -120, -120, -120, -121, -121, -121, -121, + -121, -121, -120, -120, -120, -120, -120, -119, + -119, -119, -118, -118, -117, -117, -116, -116, + -115, -114, -114, -113, -112, -111, -111, -110, + -109, -108, -107, -106, -105, -104, -103, -102, -100 +}; + +static const int hsv_blue_x[] = { + 112, 113, 114, 114, 115, 116, 117, 117, + 118, 118, 119, 119, 120, 120, 120, 121, + 121, 121, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 121, 121, + 121, 120, 120, 120, 119, 119, 118, 118, + 117, 116, 116, 115, 114, 113, 113, 112, + 111, 110, 109, 108, 107, 106, 105, 104, + 103, 102, 100, 99, 98, 97, 95, 94, + 93, 91, 90, 88, 87, 85, 84, 82, + 80, 79, 77, 76, 74, 72, 70, 69, + 67, 65, 63, 61, 60, 58, 56, 54, + 52, 50, 48, 46, 44, 42, 40, 38, + 36, 34, 32, 30, 28, 26, 24, 22, + 19, 17, 15, 13, 11, 9, 7, 5, + 2, 0, -1, -3, -5, -7, -9, -12, + -14, -16, -18, -20, -22, -24, -26, -28, + -31, -33, -35, -37, -39, -41, -43, -45, + -47, -49, -51, -53, -54, -56, -58, -60, + -62, -64, -66, -67, -69, -71, -73, -74, + -76, -78, -79, -81, -83, -84, -86, -87, + -89, -90, -92, -93, -94, -96, -97, -98, + -99, -101, -102, -103, -104, -105, -106, -107, + -108, -109, -110, -111, -112, -113, -114, -114, + -115, -116, -117, -117, -118, -118, -119, -119, + -120, -120, -120, -121, -121, -121, -122, -122, + -122, -122, -122, -122, -122, -122, -122, -122, + -122, -122, -121, -121, -121, -120, -120, -120, + -119, -119, -118, -118, -117, -116, -116, -115, + -114, -113, -113, -112, -111, -110, -109, -108, + -107, -106, -105, -104, -103, -102, -100, -99, + -98, -97, -95, -94, -93, -91, -90, -88, + -87, -85, -84, -82, -80, -79, -77, -76, + -74, -72, -70, -69, -67, -65, -63, -61, + -60, -58, -56, -54, -52, -50, -48, -46, + -44, -42, -40, -38, -36, -34, -32, -30, + -28, -26, -24, -22, -19, -17, -15, -13, + -11, -9, -7, -5, -2, 0, 1, 3, + 5, 7, 9, 12, 14, 16, 18, 20, + 22, 24, 26, 28, 31, 33, 35, 37, + 39, 41, 43, 45, 47, 49, 51, 53, + 54, 56, 58, 60, 62, 64, 66, 67, + 69, 71, 73, 74, 76, 78, 79, 81, + 83, 84, 86, 87, 89, 90, 92, 93, + 94, 96, 97, 98, 99, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112 +}; + +static const int hsv_blue_y[] = { + -11, -13, -15, -17, -19, -21, -23, -25, + -27, -29, -31, -33, -35, -37, -39, -41, + -43, -45, -46, -48, -50, -52, -54, -55, + -57, -59, -61, -62, -64, -66, -67, -69, + -71, -72, -74, -75, -77, -78, -80, -81, + -83, -84, -86, -87, -88, -90, -91, -92, + -93, -95, -96, -97, -98, -99, -100, -101, + -102, -103, -104, -105, -106, -106, -107, -108, + -109, -109, -110, -111, -111, -112, -112, -113, + -113, -114, -114, -114, -115, -115, -115, -115, + -116, -116, -116, -116, -116, -116, -116, -116, + -116, -115, -115, -115, -115, -114, -114, -114, + -113, -113, -112, -112, -111, -111, -110, -110, + -109, -108, -108, -107, -106, -105, -104, -103, + -102, -101, -100, -99, -98, -97, -96, -95, + -94, -93, -91, -90, -89, -88, -86, -85, + -84, -82, -81, -79, -78, -76, -75, -73, + -71, -70, -68, -67, -65, -63, -62, -60, + -58, -56, -55, -53, -51, -49, -47, -45, + -44, -42, -40, -38, -36, -34, -32, -30, + -28, -26, -24, -22, -20, -18, -16, -14, + -12, -10, -8, -6, -4, -2, 0, 1, + 3, 5, 7, 9, 11, 13, 15, 17, + 19, 21, 23, 25, 27, 29, 31, 33, + 35, 37, 39, 41, 43, 45, 46, 48, + 50, 52, 54, 55, 57, 59, 61, 62, + 64, 66, 67, 69, 71, 72, 74, 75, + 77, 78, 80, 81, 83, 84, 86, 87, + 88, 90, 91, 92, 93, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 106, 107, 108, 109, 109, 110, 111, + 111, 112, 112, 113, 113, 114, 114, 114, + 115, 115, 115, 115, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 115, 115, 115, + 115, 114, 114, 114, 113, 113, 112, 112, + 111, 111, 110, 110, 109, 108, 108, 107, + 106, 105, 104, 103, 102, 101, 100, 99, + 98, 97, 96, 95, 94, 93, 91, 90, + 89, 88, 86, 85, 84, 82, 81, 79, + 78, 76, 75, 73, 71, 70, 68, 67, + 65, 63, 62, 60, 58, 56, 55, 53, + 51, 49, 47, 45, 44, 42, 40, 38, + 36, 34, 32, 30, 28, 26, 24, 22, + 20, 18, 16, 14, 12, 10, 8, 6, + 4, 2, 0, -1, -3, -5, -7, -9, -11 +}; + +static u16 i2c_ident[] = { + V4L2_IDENT_OV9650, + V4L2_IDENT_OV9655, + V4L2_IDENT_SOI968, + V4L2_IDENT_OV7660, + V4L2_IDENT_OV7670, + V4L2_IDENT_MT9V011, + V4L2_IDENT_MT9V111, + V4L2_IDENT_MT9V112, + V4L2_IDENT_MT9M001C12ST, + V4L2_IDENT_MT9M111, + V4L2_IDENT_HV7131R, +}; + +static u16 bridge_init[][2] = { + {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c}, + {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40}, + {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10}, + {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00}, + {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50}, + {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50}, + {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04}, + {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05}, + {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00}, + {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d}, + {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04}, + {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8}, + {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32}, + {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd}, + {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01}, + {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f}, + {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f}, + {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01}, + {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80} +}; + +/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */ +static u8 ov_gain[] = { + 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */, + 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */, + 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */, + 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */, + 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */, + 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */, + 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */, + 0x70 /* 8x */ +}; + +/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */ +static u16 micron1_gain[] = { + /* 1x 1.25x 1.5x 1.75x */ + 0x0020, 0x0028, 0x0030, 0x0038, + /* 2x 2.25x 2.5x 2.75x */ + 0x00a0, 0x00a4, 0x00a8, 0x00ac, + /* 3x 3.25x 3.5x 3.75x */ + 0x00b0, 0x00b4, 0x00b8, 0x00bc, + /* 4x 4.25x 4.5x 4.75x */ + 0x00c0, 0x00c4, 0x00c8, 0x00cc, + /* 5x 5.25x 5.5x 5.75x */ + 0x00d0, 0x00d4, 0x00d8, 0x00dc, + /* 6x 6.25x 6.5x 6.75x */ + 0x00e0, 0x00e4, 0x00e8, 0x00ec, + /* 7x 7.25x 7.5x 7.75x */ + 0x00f0, 0x00f4, 0x00f8, 0x00fc, + /* 8x */ + 0x01c0 +}; + +/* mt9m001 sensor uses a different gain formula then other micron sensors */ +/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */ +static u16 micron2_gain[] = { + /* 1x 1.25x 1.5x 1.75x */ + 0x0008, 0x000a, 0x000c, 0x000e, + /* 2x 2.25x 2.5x 2.75x */ + 0x0010, 0x0012, 0x0014, 0x0016, + /* 3x 3.25x 3.5x 3.75x */ + 0x0018, 0x001a, 0x001c, 0x001e, + /* 4x 4.25x 4.5x 4.75x */ + 0x0020, 0x0051, 0x0052, 0x0053, + /* 5x 5.25x 5.5x 5.75x */ + 0x0054, 0x0055, 0x0056, 0x0057, + /* 6x 6.25x 6.5x 6.75x */ + 0x0058, 0x0059, 0x005a, 0x005b, + /* 7x 7.25x 7.5x 7.75x */ + 0x005c, 0x005d, 0x005e, 0x005f, + /* 8x */ + 0x0060 +}; + +/* Gain = .5 + bit[7:0] / 16 */ +static u8 hv7131r_gain[] = { + 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */, + 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */, + 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */, + 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */, + 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */, + 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */, + 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */, + 0x78 /* 8x */ +}; + +static u8 soi968_init[][2] = { + {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f}, + {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00}, + {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c}, + {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff}, + {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20}, + {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e}, + {0x13, 0x8a}, {0x12, 0x40}, {0x17, 0x13}, + {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79}, + {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40}, + {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32}, + {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80}, +}; + +static u8 ov7660_init[][2] = { + {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3}, + {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40}, + {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a}, + {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43}, + {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6}, + {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50}, +}; + +static u8 ov7670_init[][2] = { + {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01}, + {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00}, + {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0}, + {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00}, + {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07}, + {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75}, + {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8}, + {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5}, + {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27}, + {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b}, + {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a}, + {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00}, + {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00}, + {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80}, + {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82}, + {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20}, + {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c}, + {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66}, + {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11}, + {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40}, + {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02}, + {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a}, + {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08}, + {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04}, + {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30}, + {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88}, + {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30}, + {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99}, + {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0}, + {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e}, + {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01}, + {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20}, + {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0}, + {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30}, + {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06}, + {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a}, + {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a}, + {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84}, + {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d}, + {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d}, + {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00}, + {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, + {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60}, + {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, + {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e}, + {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56}, + {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03}, + {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47}, + {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74}, + {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2}, + {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00}, + {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a}, + {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00}, + {0x93, 0x00}, +}; + +static u8 ov9650_init[][2] = { + {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78}, + {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03}, + {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00}, + {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00}, + {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c}, + {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2}, + {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07}, + {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00}, + {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04}, + {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68}, + {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80}, + {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00}, + {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00}, + {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30}, + {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf}, + {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00}, + {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01}, + {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19}, + {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1}, + {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80}, + {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00}, + {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20}, + {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf}, + {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88}, + {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00}, + {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8}, + {0xaa, 0x92}, {0xab, 0x0a}, +}; + +static u8 ov9655_init[][2] = { + {0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61}, + {0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24}, + {0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08}, + {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x32, 0xbf}, + {0x34, 0x3d}, {0x35, 0x00}, {0x36, 0xf8}, {0x38, 0x12}, + {0x39, 0x57}, {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, + {0x3d, 0x19}, {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, + {0x42, 0x80}, {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, + {0x48, 0x3c}, {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, + {0x4d, 0xdc}, {0x4e, 0xdc}, {0x69, 0x02}, {0x6c, 0x04}, + {0x6f, 0x9e}, {0x70, 0x05}, {0x71, 0x78}, {0x77, 0x02}, + {0x8a, 0x23}, {0x8c, 0x0d}, {0x90, 0x7e}, {0x91, 0x7c}, + {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, {0xa6, 0x60}, + {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, {0xab, 0x04}, + {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, {0xaf, 0x80}, + {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, {0xb6, 0xaf}, + {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, {0xbe, 0x3b}, + {0xbf, 0x3a}, {0xc0, 0xe2}, {0xc1, 0xc8}, {0xc2, 0x01}, + {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0}, + {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x12, 0x61}, + {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a}, + {0x03, 0x12}, {0x17, 0x14}, {0x18, 0x00}, {0x19, 0x01}, + {0x1a, 0x3d}, {0x32, 0xbf}, {0x11, 0x80}, {0x2a, 0x10}, + {0x2b, 0x0a}, {0x92, 0x00}, {0x93, 0x00}, {0x1e, 0x04}, + {0x1e, 0x04}, {0x10, 0x7c}, {0x04, 0x03}, {0xa1, 0x00}, + {0x2d, 0x00}, {0x2e, 0x00}, {0x00, 0x00}, {0x01, 0x80}, + {0x02, 0x80}, {0x12, 0x61}, {0x36, 0xfa}, {0x8c, 0x8d}, + {0xc0, 0xaa}, {0x69, 0x0a}, {0x03, 0x12}, {0x17, 0x14}, + {0x18, 0x00}, {0x19, 0x01}, {0x1a, 0x3d}, {0x32, 0xbf}, + {0x11, 0x80}, {0x2a, 0x10}, {0x2b, 0x0a}, {0x92, 0x00}, + {0x93, 0x00}, {0x04, 0x01}, {0x10, 0x1f}, {0xa1, 0x00}, + {0x00, 0x0a}, {0xa1, 0x00}, {0x10, 0x5d}, {0x04, 0x03}, + {0x00, 0x01}, {0xa1, 0x00}, {0x10, 0x7c}, {0x04, 0x03}, + {0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13}, +}; + +static u16 mt9v112_init[][2] = { + {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020}, + {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b}, + {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001}, + {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a}, + {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58}, + {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001}, + {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020}, + {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020}, + {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020}, + {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c}, + {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2}, + {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0}, + {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020}, + {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c}, + {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae}, + {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae}, +}; + +static u16 mt9v111_init[][2] = { + {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000}, + {0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1}, + {0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002}, + {0x21, 0x0000}, {0x25, 0x4024}, {0x26, 0xff03}, + {0x27, 0xff10}, {0x2b, 0x7828}, {0x2c, 0xb43c}, + {0x2d, 0xf0a0}, {0x2e, 0x0c64}, {0x2f, 0x0064}, + {0x67, 0x4010}, {0x06, 0x301e}, {0x08, 0x0480}, + {0x01, 0x0004}, {0x02, 0x0016}, {0x03, 0x01e6}, + {0x04, 0x0286}, {0x05, 0x0004}, {0x06, 0x0000}, + {0x07, 0x3002}, {0x08, 0x0008}, {0x0c, 0x0000}, + {0x0d, 0x0000}, {0x0e, 0x0000}, {0x0f, 0x0000}, + {0x10, 0x0000}, {0x11, 0x0000}, {0x12, 0x00b0}, + {0x13, 0x007c}, {0x14, 0x0000}, {0x15, 0x0000}, + {0x16, 0x0000}, {0x17, 0x0000}, {0x18, 0x0000}, + {0x19, 0x0000}, {0x1a, 0x0000}, {0x1b, 0x0000}, + {0x1c, 0x0000}, {0x1d, 0x0000}, {0x30, 0x0000}, + {0x30, 0x0005}, {0x31, 0x0000}, {0x02, 0x0016}, + {0x03, 0x01e1}, {0x04, 0x0281}, {0x05, 0x0004}, + {0x06, 0x0000}, {0x07, 0x3002}, {0x06, 0x002d}, + {0x05, 0x0004}, {0x09, 0x0064}, {0x2b, 0x00a0}, + {0x2c, 0x00a0}, {0x2d, 0x00a0}, {0x2e, 0x00a0}, + {0x02, 0x0016}, {0x03, 0x01e1}, {0x04, 0x0281}, + {0x05, 0x0004}, {0x06, 0x002d}, {0x07, 0x3002}, + {0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004}, +}; + +static u16 mt9v011_init[][2] = { + {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000}, + {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1}, + {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006}, + {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000}, + {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000}, + {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000}, + {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000}, + {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000}, + {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000}, + {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000}, + {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000}, + {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000}, + {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024}, + {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000}, + {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100}, + {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1}, + {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000}, + {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000}, + {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000}, + {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101}, + {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003}, + {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0}, + {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000}, + {0x06, 0x0029}, {0x05, 0x0009}, +}; + +static u16 mt9m001_init[][2] = { + {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e}, + {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501}, + {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002}, + {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000}, + {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000}, + {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000}, + {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2}, + {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003}, + {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a}, + {0x2e, 0x0029}, {0x07, 0x0002}, +}; + +static u16 mt9m111_init[][2] = { + {0xf0, 0x0000}, {0x0d, 0x0008}, {0x0d, 0x0009}, + {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300}, + {0x9b, 0x4300}, {0xa1, 0x0280}, {0xa4, 0x0200}, + {0x06, 0x308e}, {0xf0, 0x0000}, +}; + +static u8 hv7131r_init[][2] = { + {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08}, + {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0}, + {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08}, + {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07}, + {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62}, + {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10}, + {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00}, + {0x23, 0x09}, {0x01, 0x08}, +}; + +int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) +{ + struct usb_device *dev = gspca_dev->dev; + int result; + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + reg, + 0x00, + gspca_dev->usb_buf, + length, + 500); + if (unlikely(result < 0 || result != length)) { + err("Read register failed 0x%02X", reg); + return -EIO; + } + return 0; +} + +int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length) +{ + struct usb_device *dev = gspca_dev->dev; + int result; + memcpy(gspca_dev->usb_buf, buffer, length); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + reg, + 0x00, + gspca_dev->usb_buf, + length, + 500); + if (unlikely(result < 0 || result != length)) { + err("Write register failed index 0x%02X", reg); + return -EIO; + } + return 0; +} + +int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) +{ + u8 data[1] = {value}; + return reg_w(gspca_dev, reg, data, 1); +} + +int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) +{ + int i; + reg_w(gspca_dev, 0x10c0, buffer, 8); + for (i = 0; i < 5; i++) { + reg_r(gspca_dev, 0x10c0, 1); + if (gspca_dev->usb_buf[0] & 0x04) { + if (gspca_dev->usb_buf[0] & 0x08) + return -1; + return 0; + } + msleep(1); + } + return -1; +} + +int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + u8 row[8]; + + /* + * from the point of view of the bridge, the length + * includes the address + */ + row[0] = 0x81 | (2 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = val; + row[4] = 0x00; + row[5] = 0x00; + row[6] = 0x00; + row[7] = 0x10; + + return i2c_w(gspca_dev, row); +} + +int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; + + /* + * from the point of view of the bridge, the length + * includes the address + */ + row[0] = 0x81 | (3 << 4); + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = (val >> 8) & 0xff; + row[4] = val & 0xff; + row[5] = 0x00; + row[6] = 0x00; + row[7] = 0x10; + + return i2c_w(gspca_dev, row); +} + +int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; + + row[0] = 0x81 | 0x10; + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = 0; + row[4] = 0; + row[5] = 0; + row[6] = 0; + row[7] = 0x10; + reg_w(gspca_dev, 0x10c0, row, 8); + msleep(1); + row[0] = 0x81 | (2 << 4) | 0x02; + row[2] = 0; + reg_w(gspca_dev, 0x10c0, row, 8); + msleep(1); + reg_r(gspca_dev, 0x10c2, 5); + *val = gspca_dev->usb_buf[3]; + return 0; +} + +int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 row[8]; + + row[0] = 0x81 | 0x10; + row[1] = sd->i2c_addr; + row[2] = reg; + row[3] = 0; + row[4] = 0; + row[5] = 0; + row[6] = 0; + row[7] = 0x10; + reg_w(gspca_dev, 0x10c0, row, 8); + msleep(1); + row[0] = 0x81 | (3 << 4) | 0x02; + row[2] = 0; + reg_w(gspca_dev, 0x10c0, row, 8); + msleep(1); + reg_r(gspca_dev, 0x10c2, 5); + *val = (gspca_dev->usb_buf[2] << 8) | gspca_dev->usb_buf[3]; + return 0; +} + +static int ov9650_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { + if (i2c_w1(gspca_dev, ov9650_init[i][0], + ov9650_init[i][1]) < 0) { + err("OV9650 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 1; + sd->vstart = 7; + return 0; +} + +static int ov9655_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { + if (i2c_w1(gspca_dev, ov9655_init[i][0], + ov9655_init[i][1]) < 0) { + err("OV9655 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 0; + sd->vstart = 7; + return 0; +} + +static int soi968_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { + if (i2c_w1(gspca_dev, soi968_init[i][0], + soi968_init[i][1]) < 0) { + err("SOI968 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 60; + sd->vstart = 11; + return 0; +} + +static int ov7660_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { + if (i2c_w1(gspca_dev, ov7660_init[i][0], + ov7660_init[i][1]) < 0) { + err("OV7660 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 1; + sd->vstart = 1; + return 0; +} + +static int ov7670_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { + if (i2c_w1(gspca_dev, ov7670_init[i][0], + ov7670_init[i][1]) < 0) { + err("OV7670 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 0; + sd->vstart = 1; + return 0; +} + +static int mt9v_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u16 value; + int ret; + + sd->i2c_addr = 0x5d; + ret = i2c_r2(gspca_dev, 0xff, &value); + if ((ret == 0) && (value == 0x8243)) { + for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { + if (i2c_w2(gspca_dev, mt9v011_init[i][0], + mt9v011_init[i][1]) < 0) { + err("MT9V011 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 2; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V011; + info("MT9V011 sensor detected"); + return 0; + } + + sd->i2c_addr = 0x5c; + i2c_w2(gspca_dev, 0x01, 0x0004); + ret = i2c_r2(gspca_dev, 0xff, &value); + if ((ret == 0) && (value == 0x823a)) { + for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { + if (i2c_w2(gspca_dev, mt9v111_init[i][0], + mt9v111_init[i][1]) < 0) { + err("MT9V111 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 2; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V111; + info("MT9V111 sensor detected"); + return 0; + } + + sd->i2c_addr = 0x5d; + ret = i2c_w2(gspca_dev, 0xf0, 0x0000); + if (ret < 0) { + sd->i2c_addr = 0x48; + i2c_w2(gspca_dev, 0xf0, 0x0000); + } + ret = i2c_r2(gspca_dev, 0x00, &value); + if ((ret == 0) && (value == 0x1229)) { + for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { + if (i2c_w2(gspca_dev, mt9v112_init[i][0], + mt9v112_init[i][1]) < 0) { + err("MT9V112 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 6; + sd->vstart = 2; + sd->sensor = SENSOR_MT9V112; + info("MT9V112 sensor detected"); + return 0; + } + + return -ENODEV; +} + +static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { + if (i2c_w2(gspca_dev, mt9m111_init[i][0], + mt9m111_init[i][1]) < 0) { + err("MT9M111 sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 0; + sd->vstart = 2; + return 0; +} + +static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { + if (i2c_w2(gspca_dev, mt9m001_init[i][0], + mt9m001_init[i][1]) < 0) { + err("MT9M001 sensor initialization failed"); + return -ENODEV; + } + } + /* disable hflip and vflip */ + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); + sd->hstart = 2; + sd->vstart = 2; + return 0; +} + +static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) +{ + int i; + struct sd *sd = (struct sd *) gspca_dev; + + for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { + if (i2c_w1(gspca_dev, hv7131r_init[i][0], + hv7131r_init[i][1]) < 0) { + err("HV7131R Sensor initialization failed"); + return -ENODEV; + } + } + sd->hstart = 0; + sd->vstart = 1; + return 0; +} + +#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV +static int input_kthread(void *data) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *)data; + struct sd *sd = (struct sd *) gspca_dev; + + DECLARE_WAIT_QUEUE_HEAD(wait); + set_freezable(); + for (;;) { + if (kthread_should_stop()) + break; + + if (reg_r(gspca_dev, 0x1005, 1) < 0) + continue; + + input_report_key(sd->input_dev, + KEY_CAMERA, + gspca_dev->usb_buf[0] & sd->input_gpio); + input_sync(sd->input_dev); + + wait_event_freezable_timeout(wait, + kthread_should_stop(), + msecs_to_jiffies(100)); + } + return 0; +} + + +static int sn9c20x_input_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + if (sd->input_gpio == 0) + return 0; + + sd->input_dev = input_allocate_device(); + if (!sd->input_dev) + return -ENOMEM; + + sd->input_dev->name = "SN9C20X Webcam"; + + sd->input_dev->phys = kasprintf(GFP_KERNEL, "usb-%s-%s", + gspca_dev->dev->bus->bus_name, + gspca_dev->dev->devpath); + + if (!sd->input_dev->phys) + return -ENOMEM; + + usb_to_input_id(gspca_dev->dev, &sd->input_dev->id); + sd->input_dev->dev.parent = &gspca_dev->dev->dev; + + set_bit(EV_KEY, sd->input_dev->evbit); + set_bit(KEY_CAMERA, sd->input_dev->keybit); + + if (input_register_device(sd->input_dev)) + return -EINVAL; + + sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%d", + gspca_dev->vdev.minor); + + if (IS_ERR(sd->input_task)) + return -EINVAL; + + return 0; +} + +static void sn9c20x_input_cleanup(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + if (sd->input_task != NULL && !IS_ERR(sd->input_task)) + kthread_stop(sd->input_task); + + if (sd->input_dev != NULL) { + input_unregister_device(sd->input_dev); + kfree(sd->input_dev->phys); + input_free_device(sd->input_dev); + sd->input_dev = NULL; + } +} +#endif + +static int set_cmatrix(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 hue_coord, hue_index = 180 + sd->hue; + u8 cmatrix[21]; + memset(cmatrix, 0, 21); + + cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26; + cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; + cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; + cmatrix[18] = sd->brightness - 0x80; + + hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8; + cmatrix[6] = (unsigned char)(hue_coord & 0xff); + cmatrix[7] = (unsigned char)((hue_coord >> 8) & 0x0f); + + hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8; + cmatrix[8] = (unsigned char)(hue_coord & 0xff); + cmatrix[9] = (unsigned char)((hue_coord >> 8) & 0x0f); + + hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8; + cmatrix[10] = (unsigned char)(hue_coord & 0xff); + cmatrix[11] = (unsigned char)((hue_coord >> 8) & 0x0f); + + hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8; + cmatrix[12] = (unsigned char)(hue_coord & 0xff); + cmatrix[13] = (unsigned char)((hue_coord >> 8) & 0x0f); + + hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8; + cmatrix[14] = (unsigned char)(hue_coord & 0xff); + cmatrix[15] = (unsigned char)((hue_coord >> 8) & 0x0f); + + hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8; + cmatrix[16] = (unsigned char)(hue_coord & 0xff); + cmatrix[17] = (unsigned char)((hue_coord >> 8) & 0x0f); + + return reg_w(gspca_dev, 0x10e1, cmatrix, 21); +} + +static int set_gamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 gamma[17]; + u8 gval = sd->gamma * 0xb8 / 0x100; + + + gamma[0] = 0x0a; + gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); + gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8); + gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8); + gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8); + gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8); + gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8); + gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8); + gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8); + gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8); + gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8); + gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8); + gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8); + gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8); + gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8); + gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); + gamma[16] = 0xf5; + + return reg_w(gspca_dev, 0x1190, gamma, 17); +} + +static int set_redblue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + reg_w1(gspca_dev, 0x118c, sd->red); + reg_w1(gspca_dev, 0x118f, sd->blue); + return 0; +} + +static int set_hvflip(struct gspca_dev *gspca_dev) +{ + u8 value, tslb; + u16 value2; + struct sd *sd = (struct sd *) gspca_dev; + switch (sd->sensor) { + case SENSOR_OV9650: + i2c_r1(gspca_dev, 0x1e, &value); + value &= ~0x30; + tslb = 0x01; + if (sd->hflip) + value |= 0x20; + if (sd->vflip) { + value |= 0x10; + tslb = 0x49; + } + i2c_w1(gspca_dev, 0x1e, value); + i2c_w1(gspca_dev, 0x3a, tslb); + break; + case SENSOR_MT9V111: + case SENSOR_MT9V011: + i2c_r2(gspca_dev, 0x20, &value2); + value2 &= ~0xc0a0; + if (sd->hflip) + value2 |= 0x8080; + if (sd->vflip) + value2 |= 0x4020; + i2c_w2(gspca_dev, 0x20, value2); + break; + case SENSOR_MT9M111: + case SENSOR_MT9V112: + i2c_r2(gspca_dev, 0x20, &value2); + value2 &= ~0x0003; + if (sd->hflip) + value2 |= 0x0002; + if (sd->vflip) + value2 |= 0x0001; + i2c_w2(gspca_dev, 0x20, value2); + break; + case SENSOR_HV7131R: + i2c_r1(gspca_dev, 0x01, &value); + value &= ~0x03; + if (sd->vflip) + value |= 0x01; + if (sd->hflip) + value |= 0x02; + i2c_w1(gspca_dev, 0x01, value); + break; + } + return 0; +} + +static int set_exposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: + case SENSOR_SOI968: + case SENSOR_OV9655: + case SENSOR_OV9650: + exp[0] |= (3 << 4); + exp[2] = 0x2d; + exp[3] = sd->exposure & 0xff; + exp[4] = sd->exposure >> 8; + break; + case SENSOR_MT9M001: + case SENSOR_MT9M111: + case SENSOR_MT9V112: + case SENSOR_MT9V111: + case SENSOR_MT9V011: + exp[0] |= (3 << 4); + exp[2] = 0x09; + exp[3] = sd->exposure >> 8; + exp[4] = sd->exposure & 0xff; + break; + case SENSOR_HV7131R: + exp[0] |= (4 << 4); + exp[2] = 0x25; + exp[3] = ((sd->exposure * 0xffffff) / 0xffff) >> 16; + exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8; + exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff; + break; + } + i2c_w(gspca_dev, exp); + return 0; +} + +static int set_gain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: + case SENSOR_SOI968: + case SENSOR_OV9655: + case SENSOR_OV9650: + gain[0] |= (2 << 4); + gain[3] = ov_gain[sd->gain]; + break; + case SENSOR_MT9V011: + case SENSOR_MT9V111: + gain[0] |= (3 << 4); + gain[2] = 0x35; + gain[3] = micron1_gain[sd->gain] >> 8; + gain[4] = micron1_gain[sd->gain] & 0xff; + break; + case SENSOR_MT9V112: + case SENSOR_MT9M111: + gain[0] |= (3 << 4); + gain[2] = 0x2f; + gain[3] = micron1_gain[sd->gain] >> 8; + gain[4] = micron1_gain[sd->gain] & 0xff; + break; + case SENSOR_MT9M001: + gain[0] |= (3 << 4); + gain[2] = 0x2f; + gain[3] = micron2_gain[sd->gain] >> 8; + gain[4] = micron2_gain[sd->gain] & 0xff; + break; + case SENSOR_HV7131R: + gain[0] |= (2 << 4); + gain[2] = 0x30; + gain[3] = hv7131r_gain[sd->gain]; + break; + } + i2c_w(gspca_dev, gain); + return 0; +} + +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) + return set_cmatrix(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_setcontrast(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->contrast = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->contrast; + return 0; +} + +static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->saturation = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->saturation; + return 0; +} + +static int sd_sethue(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hue = val; + if (gspca_dev->streaming) + return set_cmatrix(gspca_dev); + return 0; +} + +static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->hue; + return 0; +} + +static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gamma = val; + if (gspca_dev->streaming) + return set_gamma(gspca_dev); + return 0; +} + +static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->gamma; + return 0; +} + +static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red = val; + if (gspca_dev->streaming) + return set_redblue(gspca_dev); + return 0; +} + +static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->red; + return 0; +} + +static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue = val; + if (gspca_dev->streaming) + return set_redblue(gspca_dev); + return 0; +} + +static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->blue; + return 0; +} + +static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + return set_hvflip(gspca_dev); + return 0; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + return set_hvflip(gspca_dev); + return 0; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->vflip; + 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) + return set_exposure(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) + return set_gain(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; +} + +static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + sd->auto_exposure = val; + return 0; +} + +static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + *val = sd->auto_exposure; + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int sd_dbg_g_register(struct gspca_dev *gspca_dev, + struct v4l2_dbg_register *reg) +{ + struct sd *sd = (struct sd *) gspca_dev; + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (reg->match.addr != 0) + return -EINVAL; + if (reg->reg < 0x1000 || reg->reg > 0x11ff) + return -EINVAL; + if (reg_r(gspca_dev, reg->reg, 1) < 0) + return -EINVAL; + reg->val = gspca_dev->usb_buf[0]; + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (reg->match.addr != sd->i2c_addr) + return -EINVAL; + if (sd->sensor >= SENSOR_MT9V011 && + sd->sensor <= SENSOR_MT9M111) { + if (i2c_r2(gspca_dev, reg->reg, (u16 *)®->val) < 0) + return -EINVAL; + } else { + if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) + return -EINVAL; + } + return 0; + } + return -EINVAL; +} + +static int sd_dbg_s_register(struct gspca_dev *gspca_dev, + struct v4l2_dbg_register *reg) +{ + struct sd *sd = (struct sd *) gspca_dev; + switch (reg->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (reg->match.addr != 0) + return -EINVAL; + if (reg->reg < 0x1000 || reg->reg > 0x11ff) + return -EINVAL; + if (reg_w1(gspca_dev, reg->reg, reg->val) < 0) + return -EINVAL; + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (reg->match.addr != sd->i2c_addr) + return -EINVAL; + if (sd->sensor >= SENSOR_MT9V011 && + sd->sensor <= SENSOR_MT9M111) { + if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0) + return -EINVAL; + } else { + if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0) + return -EINVAL; + } + return 0; + } + return -EINVAL; +} +#endif + +static int sd_chip_ident(struct gspca_dev *gspca_dev, + struct v4l2_dbg_chip_ident *chip) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (chip->match.type) { + case V4L2_CHIP_MATCH_HOST: + if (chip->match.addr != 0) + return -EINVAL; + chip->revision = 0; + chip->ident = V4L2_IDENT_SN9C20X; + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + if (chip->match.addr != sd->i2c_addr) + return -EINVAL; + chip->revision = 0; + chip->ident = i2c_ident[sd->sensor]; + return 0; + } + return -EINVAL; +} + +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; + + sd->sensor = (id->driver_info >> 8) & 0xff; + sd->i2c_addr = id->driver_info & 0xff; + + switch (sd->sensor) { + case SENSOR_OV9650: + cam->cam_mode = sxga_mode; + cam->nmodes = ARRAY_SIZE(sxga_mode); + break; + default: + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } + + sd->old_step = 0; + sd->older_step = 0; + sd->exposure_step = 16; + + sd->brightness = BRIGHTNESS_DEFAULT; + sd->contrast = CONTRAST_DEFAULT; + sd->saturation = SATURATION_DEFAULT; + sd->hue = HUE_DEFAULT; + sd->gamma = GAMMA_DEFAULT; + sd->red = RED_DEFAULT; + sd->blue = BLUE_DEFAULT; + + sd->hflip = HFLIP_DEFAULT; + sd->vflip = VFLIP_DEFAULT; + sd->exposure = EXPOSURE_DEFAULT; + sd->gain = GAIN_DEFAULT; + sd->auto_exposure = AUTO_EXPOSURE_DEFAULT; + + sd->quality = 95; + +#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV + sd->input_gpio = (id->driver_info >> 16) & 0xff; + if (sn9c20x_input_init(gspca_dev) < 0) + return -ENODEV; +#endif + return 0; +} + +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + u8 value; + u8 i2c_init[9] = + {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}; + + for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { + value = bridge_init[i][1]; + if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { + err("Device initialization failed"); + return -ENODEV; + } + } + + if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { + err("Device initialization failed"); + return -ENODEV; + } + + switch (sd->sensor) { + case SENSOR_OV9650: + if (ov9650_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV9650 sensor detected"); + break; + case SENSOR_OV9655: + if (ov9655_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV9655 sensor detected"); + break; + case SENSOR_SOI968: + if (soi968_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("SOI968 sensor detected"); + break; + case SENSOR_OV7660: + if (ov7660_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV7660 sensor detected"); + break; + case SENSOR_OV7670: + if (ov7670_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("OV7670 sensor detected"); + break; + case SENSOR_MT9VPRB: + if (mt9v_init_sensor(gspca_dev) < 0) + return -ENODEV; + break; + case SENSOR_MT9M111: + if (mt9m111_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("MT9M111 sensor detected"); + break; + case SENSOR_MT9M001: + if (mt9m001_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("MT9M001 sensor detected"); + break; + case SENSOR_HV7131R: + if (hv7131r_init_sensor(gspca_dev) < 0) + return -ENODEV; + info("HV7131R sensor detected"); + break; + default: + info("Unsupported Sensor"); + return -ENODEV; + } + + return 0; +} + +static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 value; + switch (sd->sensor) { + case SENSOR_OV9650: + if (mode & MODE_SXGA) { + i2c_w1(gspca_dev, 0x17, 0x1b); + i2c_w1(gspca_dev, 0x18, 0xbc); + i2c_w1(gspca_dev, 0x19, 0x01); + i2c_w1(gspca_dev, 0x1a, 0x82); + i2c_r1(gspca_dev, 0x12, &value); + i2c_w1(gspca_dev, 0x12, value & 0x07); + } else { + i2c_w1(gspca_dev, 0x17, 0x24); + i2c_w1(gspca_dev, 0x18, 0xc5); + i2c_w1(gspca_dev, 0x19, 0x00); + i2c_w1(gspca_dev, 0x1a, 0x3c); + i2c_r1(gspca_dev, 0x12, &value); + i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40); + } + break; + } +} + +#define HW_WIN(mode, hstart, vstart) \ +((const u8 []){hstart & 0xff, hstart >> 8, \ +vstart & 0xff, vstart >> 8, \ +(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ +(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)}) + +#define CLR_WIN(width, height) \ +((const u8 [])\ +{0, width >> 2, 0, height >> 1,\ +((width >> 10) & 0x01) | ((height >> 8) & 0x6)}) + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + int width = gspca_dev->width; + int height = gspca_dev->height; + u8 fmt, scale = 0; + + sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (sd->jpeg_hdr == NULL) + return -ENOMEM; + + jpeg_define(sd->jpeg_hdr, height, width, + 0x21); + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + + if (mode & MODE_RAW) + fmt = 0x2d; + else if (mode & MODE_JPEG) + fmt = 0x2c; + else + fmt = 0x2f; + + switch (mode & 0x0f) { + case 3: + scale = 0xc0; + info("Set 1280x1024"); + break; + case 2: + scale = 0x80; + info("Set 640x480"); + break; + case 1: + scale = 0x90; + info("Set 320x240"); + break; + case 0: + scale = 0xa0; + info("Set 160x120"); + break; + } + + configure_sensor_output(gspca_dev, mode); + reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64); + reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64); + reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5); + reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6); + reg_w1(gspca_dev, 0x1189, scale); + reg_w1(gspca_dev, 0x10e0, fmt); + + set_cmatrix(gspca_dev); + set_gamma(gspca_dev); + set_redblue(gspca_dev); + set_gain(gspca_dev); + set_exposure(gspca_dev); + set_hvflip(gspca_dev); + + reg_r(gspca_dev, 0x1061, 1); + reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02); + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + reg_r(gspca_dev, 0x1061, 1); + reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); +} + +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + kfree(sd->jpeg_hdr); +} + +static void do_autoexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum, new_exp; + + if (!sd->auto_exposure) + return; + + avg_lum = atomic_read(&sd->avg_lum); + + /* + * some hardcoded values are present + * like those for maximal/minimal exposure + * and exposure steps + */ + if (avg_lum < MIN_AVG_LUM) { + if (sd->exposure > 0x1770) + return; + + new_exp = sd->exposure + sd->exposure_step; + if (new_exp > 0x1770) + new_exp = 0x1770; + if (new_exp < 0x10) + new_exp = 0x10; + sd->exposure = new_exp; + set_exposure(gspca_dev); + + sd->older_step = sd->old_step; + sd->old_step = 1; + + if (sd->old_step ^ sd->older_step) + sd->exposure_step /= 2; + else + sd->exposure_step += 2; + } + if (avg_lum > MAX_AVG_LUM) { + if (sd->exposure < 0x10) + return; + new_exp = sd->exposure - sd->exposure_step; + if (new_exp > 0x1700) + new_exp = 0x1770; + if (new_exp < 0x10) + new_exp = 0x10; + sd->exposure = new_exp; + set_exposure(gspca_dev); + sd->older_step = sd->old_step; + sd->old_step = 0; + + if (sd->old_step ^ sd->older_step) + sd->exposure_step /= 2; + else + sd->exposure_step += 2; + } +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + int avg_lum; + static unsigned char frame_header[] = + {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; + if (len == 64 && memcmp(data, frame_header, 6) == 0) { + avg_lum = ((data[35] >> 2) & 3) | + (data[20] << 2) | + (data[19] << 10); + avg_lum += ((data[35] >> 4) & 3) | + (data[22] << 2) | + (data[21] << 10); + avg_lum += ((data[35] >> 6) & 3) | + (data[24] << 2) | + (data[23] << 10); + avg_lum += (data[36] & 3) | + (data[26] << 2) | + (data[25] << 10); + avg_lum += ((data[36] >> 2) & 3) | + (data[28] << 2) | + (data[27] << 10); + avg_lum += ((data[36] >> 4) & 3) | + (data[30] << 2) | + (data[29] << 10); + avg_lum += ((data[36] >> 6) & 3) | + (data[32] << 2) | + (data[31] << 10); + avg_lum += ((data[44] >> 4) & 3) | + (data[34] << 2) | + (data[33] << 10); + avg_lum >>= 9; + atomic_set(&sd->avg_lum, avg_lum); + gspca_frame_add(gspca_dev, LAST_PACKET, + frame, data, len); + return; + } + if (gspca_dev->last_packet_type == LAST_PACKET) { + if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv + & MODE_JPEG) { + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); + } else { + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + } + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); + } +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autoexposure, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .set_register = sd_dbg_s_register, + .get_register = sd_dbg_g_register, +#endif + .get_chip_ident = sd_chip_ident, +}; + +#define SN9C20X(sensor, i2c_addr, button_mask) \ + .driver_info = (button_mask << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (i2c_addr) + +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, 0x10)}, + {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)}, + {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)}, + {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, + {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)}, + {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)}, + {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static void sd_disconnect(struct usb_interface *intf) +{ +#ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + sn9c20x_input_cleanup(gspca_dev); +#endif + + gspca_disconnect(intf); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = sd_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, + .reset_resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + info("registered"); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + info("deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); -- cgit v1.2.3 From 3eb0237d445c23e9f46b11a07bce986eca450640 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 19 Jul 2009 07:09:32 -0300 Subject: V4L/DVB (12284): gspca - jpeg subdrivers: Check the result of kmalloc(jpeg header). Signed-off-by: Julia Lawall Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/conex.c | 2 ++ drivers/media/video/gspca/mars.c | 2 ++ drivers/media/video/gspca/sonixj.c | 2 ++ drivers/media/video/gspca/spca500.c | 2 ++ drivers/media/video/gspca/stk014.c | 2 ++ drivers/media/video/gspca/sunplus.c | 2 ++ drivers/media/video/gspca/zc3xx.c | 2 ++ 7 files changed, 14 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 219cfa6fb87..8d48ea1742c 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -846,6 +846,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 75e8d14e4ac..de769caf013 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -201,6 +201,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index bad309b90cc..d6332ab8066 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1737,6 +1737,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 8806b2ff82b..fab7ef85a6c 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -670,6 +670,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index f25be20cf1a..47628964801 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -333,6 +333,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 9623f294bda..5127bbf9dd2 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -973,6 +973,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 08422d315e6..3d2756f7874 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -7243,6 +7243,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + if (!sd->jpeg_hdr) + return -ENOMEM; jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(sd->jpeg_hdr, sd->quality); -- cgit v1.2.3 From c15b95edb98f184e73f756511a60a7994cd9d840 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 19 Jul 2009 18:03:23 -0300 Subject: V4L/DVB (12286): sn9c20x: reorder includes to be like other drivers This is not just pure cosmetic, since the order affects the out-of-tree module build at the -hg development tree. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sn9c20x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 78ab26ceb90..fcfbbd329b4 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -18,10 +18,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "gspca.h" -#include "jpeg.h" - -#include #ifdef CONFIG_USB_GSPCA_SN9C20X_EVDEV #include #include @@ -29,6 +25,11 @@ #include #endif +#include "gspca.h" +#include "jpeg.h" + +#include + MODULE_AUTHOR("Brian Johnson , " "microdia project "); MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); -- cgit v1.2.3 From 68b7f7616add4b1de0fe75015ba3884d2d9ff796 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 11 Jun 2009 19:31:22 -0300 Subject: V4L/DVB (12291): b2c2: fix frontends compiled into kernel A recent patch didn't take into account that frontends can be compiled into the kernel. Or that frontends compiled as modules can't be used by the b2c2 driver if it is not a module itself. Some frontends require multiple drivers, e.g. a demod driver and a tuner driver. The code for the frontend support was getting added if the demod driver was available. Change this to also require any needed tuner or SEC drivers as well. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 67 +++++++++++++++++-------------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index efb4a6c2b57..9a6307a347b 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -20,8 +20,14 @@ #include "tuner-simple.h" #include "stv0297.h" + +/* Can we use the specified front-end? Remember that if we are compiled + * into the kernel we can't call code that's in modules. */ +#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \ + (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE))) + /* lnb control */ -#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) +#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299) static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct flexcop_device *fc = fe->dvb->priv; @@ -49,8 +55,7 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage } #endif -#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \ - || defined(CONFIG_DVB_MT312_MODULE) +#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312) static int flexcop_sleep(struct dvb_frontend* fe) { struct flexcop_device *fc = fe->dvb->priv; @@ -61,7 +66,7 @@ static int flexcop_sleep(struct dvb_frontend* fe) #endif /* SkyStar2 DVB-S rev 2.3 */ -#if defined(CONFIG_DVB_MT312_MODULE) +#if FE_SUPPORTED(MT312) static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ @@ -193,10 +198,12 @@ static int skystar2_rev23_attach(struct flexcop_device *fc, } return 0; } +#else +#define skystar2_rev23_attach NULL #endif /* SkyStar2 DVB-S rev 2.6 */ -#if defined(CONFIG_DVB_STV0299_MODULE) +#if FE_SUPPORTED(STV0299) static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) { @@ -321,10 +328,12 @@ static int skystar2_rev26_attach(struct flexcop_device *fc, } return 0; } +#else +#define skystar2_rev26_attach NULL #endif /* SkyStar2 DVB-S rev 2.7 */ -#if defined(CONFIG_DVB_S5H1420_MODULE) +#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000) static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { .demod_address = 0x53, .invert = 1, @@ -385,10 +394,12 @@ fail: fc->fc_i2c_adap[0].no_base_addr = 0; return 0; } +#else +#define skystar2_rev27_attach NULL #endif /* SkyStar2 rev 2.8 */ -#if defined(CONFIG_DVB_CX24123_MODULE) +#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113) static struct cx24123_config skystar2_rev2_8_cx24123_config = { .demod_address = 0x55, .dont_use_pll = 1, @@ -433,10 +444,12 @@ static int skystar2_rev28_attach(struct flexcop_device *fc, * IR-receiver (PIC16F818) - but the card has no input for that ??? */ return 1; } +#else +#define skystar2_rev28_attach NULL #endif /* AirStar DVB-T */ -#if defined(CONFIG_DVB_MT352_MODULE) +#if FE_SUPPORTED(MT352) static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) { static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; @@ -495,10 +508,12 @@ static int airstar_dvbt_attach(struct flexcop_device *fc, } return 0; } +#else +#define airstar_dvbt_attach NULL #endif /* AirStar ATSC 1st generation */ -#if defined(CONFIG_DVB_BCM3510_MODULE) +#if FE_SUPPORTED(BCM3510) static int flexcop_fe_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char* name) { @@ -517,10 +532,12 @@ static int airstar_atsc1_attach(struct flexcop_device *fc, fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); return fc->fe != NULL; } +#else +#define airstar_atsc1_attach NULL #endif /* AirStar ATSC 2nd generation */ -#if defined(CONFIG_DVB_NXT200X_MODULE) +#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) static struct nxt200x_config samsung_tbmv_config = { .demod_address = 0x0a, }; @@ -535,10 +552,12 @@ static int airstar_atsc2_attach(struct flexcop_device *fc, return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV); } +#else +#define airstar_atsc2_attach NULL #endif /* AirStar ATSC 3rd generation */ -#if defined(CONFIG_DVB_LGDT330X_MODULE) +#if FE_SUPPORTED(LGDT330X) static struct lgdt330x_config air2pc_atsc_hd5000_config = { .demod_address = 0x59, .demod_chip = LGDT3303, @@ -556,10 +575,12 @@ static int airstar_atsc3_attach(struct flexcop_device *fc, return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, TUNER_LG_TDVS_H06XF); } +#else +#define airstar_atsc3_attach NULL #endif /* CableStar2 DVB-C */ -#if defined(CONFIG_DVB_STV0297_MODULE) +#if FE_SUPPORTED(STV0297) static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { @@ -698,39 +719,23 @@ static int cablestar2_attach(struct flexcop_device *fc, fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; return 1; } +#else +#define cablestar2_attach NULL #endif static struct { flexcop_device_type_t type; int (*attach)(struct flexcop_device *, struct i2c_adapter *); } flexcop_frontends[] = { -#if defined(CONFIG_DVB_S5H1420_MODULE) { FC_SKY_REV27, skystar2_rev27_attach }, -#endif -#if defined(CONFIG_DVB_CX24123_MODULE) { FC_SKY_REV28, skystar2_rev28_attach }, -#endif -#if defined(CONFIG_DVB_STV0299_MODULE) { FC_SKY_REV26, skystar2_rev26_attach }, -#endif -#if defined(CONFIG_DVB_MT352_MODULE) { FC_AIR_DVBT, airstar_dvbt_attach }, -#endif -#if defined(CONFIG_DVB_NXT200X_MODULE) { FC_AIR_ATSC2, airstar_atsc2_attach }, -#endif -#if defined(CONFIG_DVB_LGDT330X_MODULE) { FC_AIR_ATSC3, airstar_atsc3_attach }, -#endif -#if defined(CONFIG_DVB_BCM3510_MODULE) { FC_AIR_ATSC1, airstar_atsc1_attach }, -#endif -#if defined(CONFIG_DVB_STV0297_MODULE) { FC_CABLE, cablestar2_attach }, -#endif -#if defined(CONFIG_DVB_MT312_MODULE) { FC_SKY_REV23, skystar2_rev23_attach }, -#endif }; /* try to figure out the frontend */ @@ -738,6 +743,8 @@ int flexcop_frontend_init(struct flexcop_device *fc) { int i; for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { + if (!flexcop_frontends[i].attach) + continue; /* type needs to be set before, because of some workarounds * done based on the probed card type */ fc->dev_type = flexcop_frontends[i].type; -- cgit v1.2.3 From 2c90577841a76f1935ff3437ffb552b41f5c28fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Jul 2009 08:14:17 -0300 Subject: V4L/DVB (12300): bttv: fix regression: tvaudio must be loaded before tuner Both tvaudio and the tuner share i2c address 0x42. The tvaudio module can check whether it really is a tda9840, but the tuner can't. So the tvaudio module must be loaded before the tuner module. This was also the case for 2.6.29, but the order was swapped in 2.6.30. Thanks to Krzysztof Grygiencz for reporting and testing this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-cards.c | 92 +++++++++++++++++---------------- drivers/media/video/bt8xx/bttv-driver.c | 1 + drivers/media/video/bt8xx/bttv.h | 1 + 3 files changed, 50 insertions(+), 44 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index fdb4adff3d2..ca6558c394b 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3324,8 +3324,6 @@ void __devinit bttv_init_card1(struct bttv *btv) /* initialization part two -- after registering i2c bus */ void __devinit bttv_init_card2(struct bttv *btv) { - int addr=ADDR_UNSET; - btv->tuner_type = UNSET; if (BTTV_BOARD_UNKNOWN == btv->c.type) { @@ -3470,9 +3468,6 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->pll.pll_current = -1; /* tuner configuration (from card list / autodetect / insmod option) */ - if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) - addr = bttv_tvcards[btv->c.type].tuner_addr; - if (UNSET != bttv_tvcards[btv->c.type].tuner_type) if (UNSET == btv->tuner_type) btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; @@ -3496,40 +3491,6 @@ void __devinit bttv_init_card2(struct bttv *btv) if (UNSET == btv->tuner_type) btv->tuner_type = TUNER_ABSENT; - if (btv->tuner_type != TUNER_ABSENT) { - struct tuner_setup tun_setup; - - /* Load tuner module before issuing tuner config call! */ - if (bttv_tvcards[btv->c.type].has_radio) - v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", "tuner", - v4l2_i2c_tuner_addrs(ADDRS_RADIO)); - v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", "tuner", - v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", "tuner", - v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); - - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = btv->tuner_type; - tun_setup.addr = addr; - - if (bttv_tvcards[btv->c.type].has_radio) - tun_setup.mode_mask |= T_RADIO; - - bttv_call_all(btv, tuner, s_type_addr, &tun_setup); - } - - if (btv->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &btv->tda9887_conf; - - bttv_call_all(btv, tuner, s_config, &tda9887_cfg); - } - btv->dig = bttv_tvcards[btv->c.type].has_dig_in ? bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET; btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ? @@ -3540,15 +3501,15 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->has_remote = remote[btv->c.nr]; if (bttv_tvcards[btv->c.type].has_radio) - btv->has_radio=1; + btv->has_radio = 1; if (bttv_tvcards[btv->c.type].has_remote) - btv->has_remote=1; + btv->has_remote = 1; if (!bttv_tvcards[btv->c.type].no_gpioirq) - btv->gpioirq=1; + btv->gpioirq = 1; if (bttv_tvcards[btv->c.type].volume_gpio) - btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio; + btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio; if (bttv_tvcards[btv->c.type].audio_mode_gpio) - btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio; + btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio; if (btv->tuner_type == TUNER_ABSENT) return; /* no tuner or related drivers to load */ @@ -3666,6 +3627,49 @@ no_audio: } +/* initialize the tuner */ +void __devinit bttv_init_tuner(struct bttv *btv) +{ + int addr = ADDR_UNSET; + + if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) + addr = bttv_tvcards[btv->c.type].tuner_addr; + + if (btv->tuner_type != TUNER_ABSENT) { + struct tuner_setup tun_setup; + + /* Load tuner module before issuing tuner config call! */ + if (bttv_tvcards[btv->c.type].has_radio) + v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", "tuner", + v4l2_i2c_tuner_addrs(ADDRS_RADIO)); + v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", "tuner", + v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + v4l2_i2c_new_probed_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", "tuner", + v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); + + tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = addr; + + if (bttv_tvcards[btv->c.type].has_radio) + tun_setup.mode_mask |= T_RADIO; + + bttv_call_all(btv, tuner, s_type_addr, &tun_setup); + } + + if (btv->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &btv->tda9887_conf; + + bttv_call_all(btv, tuner, s_config, &tda9887_cfg); + } +} + /* ----------------------------------------------------------------------- */ static void modtec_eeprom(struct bttv *btv) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index d147d29bb0d..8cc6dd28d6a 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -4419,6 +4419,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, /* some card-specific stuff (needs working i2c) */ bttv_init_card2(btv); + bttv_init_tuner(btv); init_irqreg(btv); /* register video4linux + input */ diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 3d36daf206f..3ec2402c6b4 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -283,6 +283,7 @@ extern struct tvcard bttv_tvcards[]; extern void bttv_idcard(struct bttv *btv); extern void bttv_init_card1(struct bttv *btv); extern void bttv_init_card2(struct bttv *btv); +extern void bttv_init_tuner(struct bttv *btv); /* card-specific funtions */ extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); -- cgit v1.2.3 From 12a34cc8a9a49219ab643c8ec329078eec272b47 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 19 Jul 2009 18:19:18 -0300 Subject: V4L/DVB (12302): cx23885-417: fix broken IOCTL handling IOCTLS will never get handled if we dont connect video_ioctl2 to mpeg_fops.ioctl Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-417.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 428f0c45e6b..2ea7181ae8f 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1677,6 +1677,7 @@ static struct v4l2_file_operations mpeg_fops = { .read = mpeg_read, .poll = mpeg_poll, .mmap = mpeg_mmap, + .ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { -- cgit v1.2.3 From ca4e771f7b878b7bab02dedb539f7742f9b4f50e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 19 Jul 2009 17:55:35 -0300 Subject: V4L/DVB (12303): cx23885: check pointers before dereferencing in dprintk macro When enabling debug with v4l_debug set to 2 or greater, the driver OOPS's on startup. Checks dev pointer before dereferencing, in order to prevent this OOPS. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-417.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 2ea7181ae8f..e0cf21e0b1b 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -58,7 +58,8 @@ MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); #define dprintk(level, fmt, arg...)\ do { if (v4l_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\ + printk(KERN_DEBUG "%s: " fmt, \ + (dev) ? dev->name : "cx23885[?]", ## arg); \ } while (0) static struct cx23885_tvnorm cx23885_tvnorms[] = { -- cgit v1.2.3