mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-30 14:46:47 +07:00
V4L/DVB (13137): gspca_mr97310a: Add controls for vga cams with sensor type 0
This patch adds controls for vga cams with sensor type 0, in order to correctly report the present controls, the probing of the sensor type has been moved from sd_start to sd_config, since this made the sensor type probing unreliable the detection method was changed. Note this requires the camera to enter streaming mode, so sd_config now briefly makes the camera stream. Signed-off-by: Theodore Kilgore <kilgota@banach.math.auburn.edu> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
9d2ba7ad80
commit
930bf78c20
@ -1,23 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
* Mars MR97310A library
|
* Mars MR97310A library
|
||||||
*
|
*
|
||||||
|
* The original mr97310a driver, which supported the Aiptek Pencam VGA+, is
|
||||||
* Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
|
* Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
|
||||||
*
|
*
|
||||||
* Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
|
* Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
|
||||||
* and for the routines for detecting and classifying these various cameras,
|
* and for the routines for detecting and classifying these various cameras,
|
||||||
|
* is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
|
||||||
*
|
*
|
||||||
|
* Support for the control settings for the CIF cameras is
|
||||||
|
* Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com> and
|
||||||
|
* Thomas Kaiser <thomas@kaiser-linux.li>
|
||||||
|
*
|
||||||
|
* Support for the control settings for the VGA cameras is
|
||||||
* Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
|
* Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
|
||||||
*
|
*
|
||||||
* Acknowledgements:
|
* Several previously unsupported cameras are owned and have been tested by
|
||||||
|
* Hans de Goede <hdgoede@redhat.com> and
|
||||||
|
* Thomas Kaiser <thomas@kaiser-linux.li> and
|
||||||
|
* Theodore Kilgore <kilgota@auburn.edu>
|
||||||
*
|
*
|
||||||
* The MR97311A support in gspca/mars.c has been helpful in understanding some
|
* The MR97311A support in gspca/mars.c has been helpful in understanding some
|
||||||
* of the registers in these cameras.
|
* of the registers in these cameras.
|
||||||
*
|
*
|
||||||
* Hans de Goede <hdgoede@redhat.com> and
|
|
||||||
* Thomas Kaiser <thomas@kaiser-linux.li>
|
|
||||||
* have assisted with their experience. Each of them has also helped by
|
|
||||||
* testing a previously unsupported camera.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
@ -40,11 +45,9 @@
|
|||||||
#define CAM_TYPE_CIF 0
|
#define CAM_TYPE_CIF 0
|
||||||
#define CAM_TYPE_VGA 1
|
#define CAM_TYPE_VGA 1
|
||||||
|
|
||||||
#define MR97310A_BRIGHTNESS_MIN -254
|
|
||||||
#define MR97310A_BRIGHTNESS_MAX 255
|
|
||||||
#define MR97310A_BRIGHTNESS_DEFAULT 0
|
#define MR97310A_BRIGHTNESS_DEFAULT 0
|
||||||
|
|
||||||
#define MR97310A_EXPOSURE_MIN 300
|
#define MR97310A_EXPOSURE_MIN 0
|
||||||
#define MR97310A_EXPOSURE_MAX 4095
|
#define MR97310A_EXPOSURE_MAX 4095
|
||||||
#define MR97310A_EXPOSURE_DEFAULT 1000
|
#define MR97310A_EXPOSURE_DEFAULT 1000
|
||||||
|
|
||||||
@ -82,6 +85,7 @@ struct sensor_w_data {
|
|||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void sd_stopN(struct gspca_dev *gspca_dev);
|
||||||
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
|
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_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
|
||||||
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
|
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
|
||||||
@ -94,14 +98,16 @@ static void setgain(struct gspca_dev *gspca_dev);
|
|||||||
|
|
||||||
/* V4L2 controls supported by the driver */
|
/* V4L2 controls supported by the driver */
|
||||||
static struct ctrl sd_ctrls[] = {
|
static struct ctrl sd_ctrls[] = {
|
||||||
|
/* Seprate brightness control description for Argus QuickClix as it has
|
||||||
|
different limits from to other mr97310a camera's */
|
||||||
{
|
{
|
||||||
#define BRIGHTNESS_IDX 0
|
#define NORM_BRIGHTNESS_IDX 0
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_BRIGHTNESS,
|
.id = V4L2_CID_BRIGHTNESS,
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
.name = "Brightness",
|
.name = "Brightness",
|
||||||
.minimum = MR97310A_BRIGHTNESS_MIN,
|
.minimum = -254,
|
||||||
.maximum = MR97310A_BRIGHTNESS_MAX,
|
.maximum = 255,
|
||||||
.step = 1,
|
.step = 1,
|
||||||
.default_value = MR97310A_BRIGHTNESS_DEFAULT,
|
.default_value = MR97310A_BRIGHTNESS_DEFAULT,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
@ -110,7 +116,22 @@ static struct ctrl sd_ctrls[] = {
|
|||||||
.get = sd_getbrightness,
|
.get = sd_getbrightness,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
#define EXPOSURE_IDX 1
|
#define ARGUS_QC_BRIGHTNESS_IDX 1
|
||||||
|
{
|
||||||
|
.id = V4L2_CID_BRIGHTNESS,
|
||||||
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
|
.name = "Brightness",
|
||||||
|
.minimum = 0,
|
||||||
|
.maximum = 15,
|
||||||
|
.step = 1,
|
||||||
|
.default_value = MR97310A_BRIGHTNESS_DEFAULT,
|
||||||
|
.flags = 0,
|
||||||
|
},
|
||||||
|
.set = sd_setbrightness,
|
||||||
|
.get = sd_getbrightness,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
#define EXPOSURE_IDX 2
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_EXPOSURE,
|
.id = V4L2_CID_EXPOSURE,
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
@ -125,7 +146,7 @@ static struct ctrl sd_ctrls[] = {
|
|||||||
.get = sd_getexposure,
|
.get = sd_getexposure,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
#define GAIN_IDX 2
|
#define GAIN_IDX 3
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_GAIN,
|
.id = V4L2_CID_GAIN,
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
@ -230,12 +251,17 @@ static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
buf = data;
|
buf = data;
|
||||||
rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
|
if (sd->cam_type == CAM_TYPE_CIF) {
|
||||||
|
rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
|
||||||
|
confirm_reg = sd->sensor_type ? 0x13 : 0x11;
|
||||||
|
} else {
|
||||||
|
rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1);
|
||||||
|
confirm_reg = 0x11;
|
||||||
|
}
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
buf = 0x01;
|
buf = 0x01;
|
||||||
confirm_reg = sd->sensor_type ? 0x13 : 0x11;
|
|
||||||
rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
|
rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
@ -243,18 +269,26 @@ static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cam_get_response16(struct gspca_dev *gspca_dev)
|
static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose)
|
||||||
{
|
{
|
||||||
__u8 *data = gspca_dev->usb_buf;
|
|
||||||
int err_code;
|
int err_code;
|
||||||
|
|
||||||
data[0] = 0x21;
|
gspca_dev->usb_buf[0] = reg;
|
||||||
err_code = mr_write(gspca_dev, 1);
|
err_code = mr_write(gspca_dev, 1);
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
err_code = mr_read(gspca_dev, 16);
|
err_code = mr_read(gspca_dev, 16);
|
||||||
return err_code;
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PDEBUG(D_PROBE, "Register: %02x reads %02x%02x%02x", reg,
|
||||||
|
gspca_dev->usb_buf[0],
|
||||||
|
gspca_dev->usb_buf[1],
|
||||||
|
gspca_dev->usb_buf[2]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
||||||
@ -264,7 +298,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
u8 status = 0;
|
u8 status = 0;
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
|
|
||||||
err_code = cam_get_response16(gspca_dev);
|
err_code = cam_get_response16(gspca_dev, 0x21, 0);
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
@ -275,7 +309,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
err_code = cam_get_response16(gspca_dev);
|
err_code = cam_get_response16(gspca_dev, 0x21, 0);
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
@ -285,7 +319,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
err_code = cam_get_response16(gspca_dev);
|
err_code = cam_get_response16(gspca_dev, 0x21, 0);
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
@ -295,7 +329,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
err_code = cam_get_response16(gspca_dev);
|
err_code = cam_get_response16(gspca_dev, 0x21, 0);
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
@ -306,7 +340,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
while (status != 0x0a && tries < 256) {
|
while (status != 0x0a && tries < 256) {
|
||||||
err_code = cam_get_response16(gspca_dev);
|
err_code = cam_get_response16(gspca_dev, 0x21, 0);
|
||||||
status = data[0];
|
status = data[0];
|
||||||
tries++;
|
tries++;
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
@ -323,7 +357,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
err_code = cam_get_response16(gspca_dev);
|
err_code = cam_get_response16(gspca_dev, 0x21, 0);
|
||||||
status = data[0];
|
status = data[0];
|
||||||
tries++;
|
tries++;
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
@ -342,22 +376,34 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 get_sensor_id(struct gspca_dev *gspca_dev)
|
static int stream_start(struct gspca_dev *gspca_dev)
|
||||||
{
|
{
|
||||||
int err_code;
|
gspca_dev->usb_buf[0] = 0x01;
|
||||||
|
gspca_dev->usb_buf[1] = 0x01;
|
||||||
|
return mr_write(gspca_dev, 2);
|
||||||
|
}
|
||||||
|
|
||||||
gspca_dev->usb_buf[0] = 0x1e;
|
static void stream_stop(struct gspca_dev *gspca_dev)
|
||||||
err_code = mr_write(gspca_dev, 1);
|
{
|
||||||
if (err_code < 0)
|
gspca_dev->usb_buf[0] = 0x01;
|
||||||
return err_code;
|
gspca_dev->usb_buf[1] = 0x00;
|
||||||
|
if (mr_write(gspca_dev, 2) < 0)
|
||||||
|
PDEBUG(D_ERR, "Stream Stop failed");
|
||||||
|
}
|
||||||
|
|
||||||
err_code = mr_read(gspca_dev, 16);
|
static void lcd_stop(struct gspca_dev *gspca_dev)
|
||||||
if (err_code < 0)
|
{
|
||||||
return err_code;
|
gspca_dev->usb_buf[0] = 0x19;
|
||||||
|
gspca_dev->usb_buf[1] = 0x54;
|
||||||
|
if (mr_write(gspca_dev, 2) < 0)
|
||||||
|
PDEBUG(D_ERR, "LCD Stop failed");
|
||||||
|
}
|
||||||
|
|
||||||
PDEBUG(D_PROBE, "Byte zero reported is %01x", gspca_dev->usb_buf[0]);
|
static int isoc_enable(struct gspca_dev *gspca_dev)
|
||||||
|
{
|
||||||
return gspca_dev->usb_buf[0];
|
gspca_dev->usb_buf[0] = 0x00;
|
||||||
|
gspca_dev->usb_buf[1] = 0x4d; /* ISOC transfering enable... */
|
||||||
|
return mr_write(gspca_dev, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this function is called at probe time */
|
/* this function is called at probe time */
|
||||||
@ -366,60 +412,172 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
struct cam *cam;
|
struct cam *cam;
|
||||||
__u8 *data = gspca_dev->usb_buf;
|
|
||||||
int err_code;
|
int err_code;
|
||||||
|
|
||||||
cam = &gspca_dev->cam;
|
cam = &gspca_dev->cam;
|
||||||
cam->cam_mode = vga_mode;
|
cam->cam_mode = vga_mode;
|
||||||
cam->nmodes = ARRAY_SIZE(vga_mode);
|
cam->nmodes = ARRAY_SIZE(vga_mode);
|
||||||
|
sd->do_lcd_stop = 0;
|
||||||
|
|
||||||
|
/* Now, logical layout of the driver must fall sacrifice to the
|
||||||
|
* realities of the hardware supported. We have to sort out several
|
||||||
|
* cameras which share the USB ID but are in fact different inside.
|
||||||
|
* We need to start the initialization process for the cameras in
|
||||||
|
* order to classify them. Some of the supported cameras require the
|
||||||
|
* memory pointer to be set to 0 as the very first item of business
|
||||||
|
* or else they will not stream. So we do that immediately.
|
||||||
|
*/
|
||||||
|
err_code = zero_the_pointer(gspca_dev);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
|
||||||
if (id->idProduct == 0x010e) {
|
if (id->idProduct == 0x010e) {
|
||||||
sd->cam_type = CAM_TYPE_CIF;
|
sd->cam_type = CAM_TYPE_CIF;
|
||||||
cam->nmodes--;
|
cam->nmodes--;
|
||||||
|
err_code = stream_start(gspca_dev);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
err_code = cam_get_response16(gspca_dev, 0x06, 1);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
/*
|
||||||
|
* The various CIF cameras share the same USB ID but use
|
||||||
|
* different init routines and different controls. We need to
|
||||||
|
* detect which one is connected!
|
||||||
|
*
|
||||||
|
* A list of known CIF cameras follows. They all report either
|
||||||
|
* 0002 for type 0 or 0003 for type 1.
|
||||||
|
* If you have another to report, please do
|
||||||
|
*
|
||||||
|
* Name sd->sensor_type reported by
|
||||||
|
*
|
||||||
|
* Sakar Spy-shot 0 T. Kilgore
|
||||||
|
* Innovage 0 T. Kilgore
|
||||||
|
* Vivitar Mini 0 H. De Goede
|
||||||
|
* Vivitar Mini 0 E. Rodriguez
|
||||||
|
* Vivitar Mini 1 T. Kilgore
|
||||||
|
* Elta-Media 8212dc 1 T. Kaiser
|
||||||
|
* Philips dig. keych. 1 T. Kilgore
|
||||||
|
*/
|
||||||
|
switch (gspca_dev->usb_buf[1]) {
|
||||||
|
case 2:
|
||||||
|
sd->sensor_type = 0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sd->sensor_type = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PDEBUG(D_ERR, "Unknown CIF Sensor id : %02x",
|
||||||
|
gspca_dev->usb_buf[1]);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d",
|
||||||
|
sd->sensor_type);
|
||||||
|
} else {
|
||||||
|
sd->cam_type = CAM_TYPE_VGA;
|
||||||
|
|
||||||
data[0] = 0x01;
|
/*
|
||||||
data[1] = 0x01;
|
* VGA cams also have two different sensor types. Detection
|
||||||
err_code = mr_write(gspca_dev, 2);
|
* requires a two-step process.
|
||||||
|
*
|
||||||
|
* Here is a report on the result of the first test for the
|
||||||
|
* known MR97310a VGA cameras. If you have another to report,
|
||||||
|
* please do.
|
||||||
|
*
|
||||||
|
* Name byte just read sd->sensor_type
|
||||||
|
* sd->do_lcd_stop
|
||||||
|
* Aiptek Pencam VGA+ 0x31 0 1
|
||||||
|
* ION digital 0x31 0 1
|
||||||
|
* Sakar Digital 77379 0x31 0 1
|
||||||
|
* Argus DC-1620 0x30 1 0
|
||||||
|
* Argus QuickClix 0x30 1 1 (see note)
|
||||||
|
* Note that this test fails to distinguish sd->sensor_type
|
||||||
|
* for the two cameras which have reported 0x30.
|
||||||
|
* Another test will be run on them.
|
||||||
|
* But the sd->do_lcd_stop setting is needed, too.
|
||||||
|
*/
|
||||||
|
|
||||||
|
err_code = cam_get_response16(gspca_dev, 0x20, 1);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
sd->sensor_type = gspca_dev->usb_buf[0] & 1;
|
||||||
|
sd->do_lcd_stop = (~gspca_dev->usb_buf[0]) & 1;
|
||||||
|
err_code = stream_start(gspca_dev);
|
||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
msleep(200);
|
|
||||||
data[0] = get_sensor_id(gspca_dev);
|
|
||||||
/*
|
/*
|
||||||
* Known CIF cameras. If you have another to report, please do
|
* A second test can now resolve any remaining ambiguity in the
|
||||||
|
* identification of the camera's sensor type. Specifically,
|
||||||
|
* it now gives the correct sensor_type for the Argus DC-1620
|
||||||
|
* and the Argus QuickClix.
|
||||||
*
|
*
|
||||||
* Name byte just read sd->sensor_type
|
* This second test is only run if needed,
|
||||||
* reported by
|
* but additional results from testing some other cameras
|
||||||
* Sakar Spy-shot 0x28 T. Kilgore 0
|
* are recorded here, too:
|
||||||
* Innovage 0xf5 (unstable) T. Kilgore 0
|
*
|
||||||
* Vivitar Mini 0x53 H. De Goede 0
|
* Name gspca_dev->usb_buf[] sd->sensor_type
|
||||||
* Vivitar Mini 0x04 / 0x24 E. Rodriguez 0
|
*
|
||||||
* Vivitar Mini 0x08 T. Kilgore 1
|
* Aiptek Pencam VGA+ 0300 (test not needed) 1
|
||||||
* Elta-Media 8212dc 0x23 T. Kaiser 1
|
* ION digital 0350 (test not needed) 1
|
||||||
* Philips dig. keych. 0x37 T. Kilgore 1
|
* Argus DC-1620 0450 (remains as type 0) 0
|
||||||
|
* Argus QuickClix 0420 (corrected to type 1) 1
|
||||||
|
*
|
||||||
|
* This test even seems able to distinguish one VGA cam from
|
||||||
|
* another which may be useful. However, the CIF type 1 cameras
|
||||||
|
* do not like it.
|
||||||
*/
|
*/
|
||||||
if ((data[0] & 0x78) == 8 ||
|
|
||||||
((data[0] & 0x2) == 0x2 && data[0] != 0x53))
|
|
||||||
sd->sensor_type = 1;
|
|
||||||
else
|
|
||||||
sd->sensor_type = 0;
|
|
||||||
|
|
||||||
PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d",
|
if (!sd->sensor_type) {
|
||||||
sd->sensor_type);
|
err_code = cam_get_response16(gspca_dev, 0x07, 1);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
|
||||||
if (force_sensor_type != -1) {
|
switch (gspca_dev->usb_buf[1]) {
|
||||||
sd->sensor_type = !! force_sensor_type;
|
case 0x50:
|
||||||
PDEBUG(D_PROBE, "Forcing sensor type to: %d",
|
break;
|
||||||
sd->sensor_type);
|
case 0x20:
|
||||||
|
sd->sensor_type = 1;
|
||||||
|
PDEBUG(D_PROBE, "sensor_type corrected to 1");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PDEBUG(D_ERR, "Unknown VGA Sensor id : %02x",
|
||||||
|
gspca_dev->usb_buf[1]);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
|
||||||
|
sd->sensor_type);
|
||||||
|
}
|
||||||
|
/* Stop streaming as we've started it to probe the sensor type. */
|
||||||
|
sd_stopN(gspca_dev);
|
||||||
|
|
||||||
|
if (force_sensor_type != -1) {
|
||||||
|
sd->sensor_type = !!force_sensor_type;
|
||||||
|
PDEBUG(D_PROBE, "Forcing sensor type to: %d",
|
||||||
|
sd->sensor_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup controls depending on camera type */
|
||||||
|
if (sd->cam_type == CAM_TYPE_CIF) {
|
||||||
|
/* No brightness for sensor_type 0 */
|
||||||
if (sd->sensor_type == 0)
|
if (sd->sensor_type == 0)
|
||||||
gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
|
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
|
||||||
|
(1 << ARGUS_QC_BRIGHTNESS_IDX);
|
||||||
|
else
|
||||||
|
gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX);
|
||||||
} else {
|
} else {
|
||||||
sd->cam_type = CAM_TYPE_VGA;
|
/* All controls need to be disabled if VGA sensor_type is 0 */
|
||||||
PDEBUG(D_PROBE, "MR97310A VGA camera detected");
|
if (sd->sensor_type == 0)
|
||||||
gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) |
|
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
|
||||||
(1 << EXPOSURE_IDX) | (1 << GAIN_IDX);
|
(1 << ARGUS_QC_BRIGHTNESS_IDX) |
|
||||||
|
(1 << EXPOSURE_IDX) |
|
||||||
|
(1 << GAIN_IDX);
|
||||||
|
else if (sd->do_lcd_stop)
|
||||||
|
/* Argus QuickClix has different brightness limits */
|
||||||
|
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX);
|
||||||
|
else
|
||||||
|
gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX);
|
||||||
}
|
}
|
||||||
|
|
||||||
sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
|
sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
|
||||||
@ -455,11 +613,6 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Note: Some of the above descriptions guessed from MR97113A driver */
|
/* Note: Some of the above descriptions guessed from MR97113A driver */
|
||||||
data[0] = 0x01;
|
|
||||||
data[1] = 0x01;
|
|
||||||
err_code = mr_write(gspca_dev, 2);
|
|
||||||
if (err_code < 0)
|
|
||||||
return err_code;
|
|
||||||
|
|
||||||
memcpy(data, startup_string, 11);
|
memcpy(data, startup_string, 11);
|
||||||
if (sd->sensor_type)
|
if (sd->sensor_type)
|
||||||
@ -533,22 +686,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
|
|||||||
err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
|
err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
|
||||||
ARRAY_SIZE(cif_sensor1_init_data));
|
ARRAY_SIZE(cif_sensor1_init_data));
|
||||||
}
|
}
|
||||||
if (err_code < 0)
|
return err_code;
|
||||||
return err_code;
|
|
||||||
|
|
||||||
setbrightness(gspca_dev);
|
|
||||||
setexposure(gspca_dev);
|
|
||||||
setgain(gspca_dev);
|
|
||||||
|
|
||||||
msleep(200);
|
|
||||||
|
|
||||||
data[0] = 0x00;
|
|
||||||
data[1] = 0x4d; /* ISOC transfering enable... */
|
|
||||||
err_code = mr_write(gspca_dev, 2);
|
|
||||||
if (err_code < 0)
|
|
||||||
return err_code;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start_vga_cam(struct gspca_dev *gspca_dev)
|
static int start_vga_cam(struct gspca_dev *gspca_dev)
|
||||||
@ -558,84 +696,8 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
|
|||||||
int err_code;
|
int err_code;
|
||||||
const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
|
const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
|
||||||
0x00, 0x00, 0x00, 0x50, 0xc0};
|
0x00, 0x00, 0x00, 0x50, 0xc0};
|
||||||
|
|
||||||
/* What some of these mean is explained in start_cif_cam(), above */
|
/* What some of these mean is explained in start_cif_cam(), above */
|
||||||
sd->sof_read = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We have to know which camera we have, because the register writes
|
|
||||||
* depend upon the camera. This test, run before we actually enter
|
|
||||||
* the initialization routine, distinguishes most of the cameras, If
|
|
||||||
* needed, another routine is done later, too.
|
|
||||||
*/
|
|
||||||
memset(data, 0, 16);
|
|
||||||
data[0] = 0x20;
|
|
||||||
err_code = mr_write(gspca_dev, 1);
|
|
||||||
if (err_code < 0)
|
|
||||||
return err_code;
|
|
||||||
|
|
||||||
err_code = mr_read(gspca_dev, 16);
|
|
||||||
if (err_code < 0)
|
|
||||||
return err_code;
|
|
||||||
|
|
||||||
PDEBUG(D_PROBE, "Byte reported is %02x", data[0]);
|
|
||||||
|
|
||||||
msleep(200);
|
|
||||||
/*
|
|
||||||
* Known VGA cameras. If you have another to report, please do
|
|
||||||
*
|
|
||||||
* Name byte just read sd->sensor_type
|
|
||||||
* sd->do_lcd_stop
|
|
||||||
* Aiptek Pencam VGA+ 0x31 0 1
|
|
||||||
* ION digital 0x31 0 1
|
|
||||||
* Argus DC-1620 0x30 1 0
|
|
||||||
* Argus QuickClix 0x30 1 1 (not caught here)
|
|
||||||
*/
|
|
||||||
sd->sensor_type = data[0] & 1;
|
|
||||||
sd->do_lcd_stop = (~data[0]) & 1;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Streaming setup begins here. */
|
|
||||||
|
|
||||||
|
|
||||||
data[0] = 0x01;
|
|
||||||
data[1] = 0x01;
|
|
||||||
err_code = mr_write(gspca_dev, 2);
|
|
||||||
if (err_code < 0)
|
|
||||||
return err_code;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A second test can now resolve any remaining ambiguity in the
|
|
||||||
* identification of the camera type,
|
|
||||||
*/
|
|
||||||
if (!sd->sensor_type) {
|
|
||||||
data[0] = get_sensor_id(gspca_dev);
|
|
||||||
if (data[0] == 0x7f) {
|
|
||||||
sd->sensor_type = 1;
|
|
||||||
PDEBUG(D_PROBE, "sensor_type corrected to 1");
|
|
||||||
}
|
|
||||||
msleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force_sensor_type != -1) {
|
|
||||||
sd->sensor_type = !! force_sensor_type;
|
|
||||||
PDEBUG(D_PROBE, "Forcing sensor type to: %d",
|
|
||||||
sd->sensor_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Known VGA cameras.
|
|
||||||
* This test is only run if the previous test returned 0x30, but
|
|
||||||
* here is the information for all others, too, just for reference.
|
|
||||||
*
|
|
||||||
* Name byte just read sd->sensor_type
|
|
||||||
*
|
|
||||||
* Aiptek Pencam VGA+ 0xfb (this test not run) 1
|
|
||||||
* ION digital 0xbd (this test not run) 1
|
|
||||||
* Argus DC-1620 0xe5 (no change) 0
|
|
||||||
* Argus QuickClix 0x7f (reclassified) 1
|
|
||||||
*/
|
|
||||||
memcpy(data, startup_string, 11);
|
memcpy(data, startup_string, 11);
|
||||||
if (!sd->sensor_type) {
|
if (!sd->sensor_type) {
|
||||||
data[5] = 0x00;
|
data[5] = 0x00;
|
||||||
@ -704,14 +766,6 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
|
|||||||
err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
|
err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
|
||||||
ARRAY_SIZE(vga_sensor1_init_data));
|
ARRAY_SIZE(vga_sensor1_init_data));
|
||||||
}
|
}
|
||||||
if (err_code < 0)
|
|
||||||
return err_code;
|
|
||||||
|
|
||||||
msleep(200);
|
|
||||||
data[0] = 0x00;
|
|
||||||
data[1] = 0x4d; /* ISOC transfering enable... */
|
|
||||||
err_code = mr_write(gspca_dev, 2);
|
|
||||||
|
|
||||||
return err_code;
|
return err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,82 +773,101 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
int err_code;
|
int err_code;
|
||||||
struct cam *cam;
|
|
||||||
|
|
||||||
cam = &gspca_dev->cam;
|
|
||||||
sd->sof_read = 0;
|
sd->sof_read = 0;
|
||||||
/*
|
|
||||||
* Some of the supported cameras require the memory pointer to be
|
/* Some of the VGA cameras require the memory pointer
|
||||||
* set to 0, or else they will not stream.
|
* to be set to 0 again. We have been forced to start the
|
||||||
*/
|
* stream somewhere else to detect the hardware, and closed it,
|
||||||
zero_the_pointer(gspca_dev);
|
* and now since we are restarting the stream we need to do a
|
||||||
msleep(200);
|
* completely fresh and clean start. */
|
||||||
|
err_code = zero_the_pointer(gspca_dev);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
|
||||||
|
err_code = stream_start(gspca_dev);
|
||||||
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
|
||||||
if (sd->cam_type == CAM_TYPE_CIF) {
|
if (sd->cam_type == CAM_TYPE_CIF) {
|
||||||
err_code = start_cif_cam(gspca_dev);
|
err_code = start_cif_cam(gspca_dev);
|
||||||
} else {
|
} else {
|
||||||
err_code = start_vga_cam(gspca_dev);
|
err_code = start_vga_cam(gspca_dev);
|
||||||
}
|
}
|
||||||
return err_code;
|
if (err_code < 0)
|
||||||
|
return err_code;
|
||||||
|
|
||||||
|
setbrightness(gspca_dev);
|
||||||
|
setexposure(gspca_dev);
|
||||||
|
setgain(gspca_dev);
|
||||||
|
|
||||||
|
return isoc_enable(gspca_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sd_stopN(struct gspca_dev *gspca_dev)
|
static void sd_stopN(struct gspca_dev *gspca_dev)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
int result;
|
|
||||||
|
|
||||||
gspca_dev->usb_buf[0] = 1;
|
|
||||||
gspca_dev->usb_buf[1] = 0;
|
|
||||||
result = mr_write(gspca_dev, 2);
|
|
||||||
if (result < 0)
|
|
||||||
PDEBUG(D_ERR, "Camera Stop failed");
|
|
||||||
|
|
||||||
|
stream_stop(gspca_dev);
|
||||||
/* Not all the cams need this, but even if not, probably a good idea */
|
/* Not all the cams need this, but even if not, probably a good idea */
|
||||||
zero_the_pointer(gspca_dev);
|
zero_the_pointer(gspca_dev);
|
||||||
if (sd->do_lcd_stop) {
|
if (sd->do_lcd_stop)
|
||||||
gspca_dev->usb_buf[0] = 0x19;
|
lcd_stop(gspca_dev);
|
||||||
gspca_dev->usb_buf[1] = 0x54;
|
|
||||||
result = mr_write(gspca_dev, 2);
|
|
||||||
if (result < 0)
|
|
||||||
PDEBUG(D_ERR, "Camera Stop failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setbrightness(struct gspca_dev *gspca_dev)
|
static void setbrightness(struct gspca_dev *gspca_dev)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
u8 val;
|
u8 val;
|
||||||
|
u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */
|
||||||
if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX))
|
u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
|
||||||
|
const u8 quick_clix_table[] =
|
||||||
|
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
|
||||||
|
{ 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15};
|
||||||
|
/*
|
||||||
|
* This control is disabled for CIF type 1 and VGA type 0 cameras.
|
||||||
|
* It does not quite act linearly for the Argus QuickClix camera,
|
||||||
|
* but it does control brightness. The values are 0 - 15 only, and
|
||||||
|
* the table above makes them act consecutively.
|
||||||
|
*/
|
||||||
|
if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) &&
|
||||||
|
(gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (sd->cam_type == CAM_TYPE_VGA) {
|
||||||
|
sign_reg += 4;
|
||||||
|
value_reg += 4;
|
||||||
|
}
|
||||||
|
|
||||||
/* Note register 7 is also seen as 0x8x or 0xCx in dumps */
|
/* Note register 7 is also seen as 0x8x or 0xCx in dumps */
|
||||||
if (sd->brightness > 0) {
|
if (sd->brightness > 0) {
|
||||||
sensor_write1(gspca_dev, 7, 0x00);
|
sensor_write1(gspca_dev, sign_reg, 0x00);
|
||||||
val = sd->brightness;
|
val = sd->brightness;
|
||||||
} else {
|
} else {
|
||||||
sensor_write1(gspca_dev, 7, 0x01);
|
sensor_write1(gspca_dev, sign_reg, 0x01);
|
||||||
val = 257 - sd->brightness;
|
val = (257 - sd->brightness);
|
||||||
}
|
}
|
||||||
sensor_write1(gspca_dev, 8, val);
|
/* Use lookup table for funky Argus QuickClix brightness */
|
||||||
|
if (sd->do_lcd_stop)
|
||||||
|
val = quick_clix_table[val];
|
||||||
|
|
||||||
|
sensor_write1(gspca_dev, value_reg, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setexposure(struct gspca_dev *gspca_dev)
|
static void setexposure(struct gspca_dev *gspca_dev)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
u8 val;
|
int exposure;
|
||||||
|
|
||||||
if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
|
if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sd->sensor_type) {
|
if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
|
||||||
val = sd->exposure >> 4;
|
/* This cam does not like very low exposure settings */
|
||||||
sensor_write1(gspca_dev, 3, val);
|
exposure = (sd->exposure < 300) ? 300 : sd->exposure;
|
||||||
val = sd->exposure & 0xf;
|
sensor_write1(gspca_dev, 3, exposure >> 4);
|
||||||
sensor_write1(gspca_dev, 4, val);
|
sensor_write1(gspca_dev, 4, exposure & 0x0f);
|
||||||
} else {
|
} else {
|
||||||
u8 clockdiv;
|
|
||||||
int exposure;
|
|
||||||
|
|
||||||
/* We have both a clock divider and an exposure register.
|
/* We have both a clock divider and an exposure register.
|
||||||
We first calculate the clock divider, as that determines
|
We first calculate the clock divider, as that determines
|
||||||
the maximum exposure and then we calculayte the exposure
|
the maximum exposure and then we calculayte the exposure
|
||||||
@ -802,7 +875,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
|
|||||||
|
|
||||||
Note our 0 - 4095 exposure is mapped to 0 - 511
|
Note our 0 - 4095 exposure is mapped to 0 - 511
|
||||||
milliseconds exposure time */
|
milliseconds exposure time */
|
||||||
clockdiv = (60 * sd->exposure + 7999) / 8000;
|
u8 clockdiv = (60 * sd->exposure + 7999) / 8000;
|
||||||
|
|
||||||
/* Limit framerate to not exceed usb bandwidth */
|
/* Limit framerate to not exceed usb bandwidth */
|
||||||
if (clockdiv < 3 && gspca_dev->width >= 320)
|
if (clockdiv < 3 && gspca_dev->width >= 320)
|
||||||
@ -810,6 +883,9 @@ static void setexposure(struct gspca_dev *gspca_dev)
|
|||||||
else if (clockdiv < 2)
|
else if (clockdiv < 2)
|
||||||
clockdiv = 2;
|
clockdiv = 2;
|
||||||
|
|
||||||
|
if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4)
|
||||||
|
clockdiv = 4;
|
||||||
|
|
||||||
/* Frame exposure time in ms = 1000 * clockdiv / 60 ->
|
/* Frame exposure time in ms = 1000 * clockdiv / 60 ->
|
||||||
exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
|
exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
|
||||||
exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
|
exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
|
||||||
@ -832,7 +908,7 @@ static void setgain(struct gspca_dev *gspca_dev)
|
|||||||
if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
|
if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sd->sensor_type) {
|
if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
|
||||||
sensor_write1(gspca_dev, 0x0e, sd->gain);
|
sensor_write1(gspca_dev, 0x0e, sd->gain);
|
||||||
} else {
|
} else {
|
||||||
sensor_write1(gspca_dev, 0x10, sd->gain);
|
sensor_write1(gspca_dev, 0x10, sd->gain);
|
||||||
|
Loading…
Reference in New Issue
Block a user