Commit 7879d459 authored by Jean-Francois Moine's avatar Jean-Francois Moine Committed by Mauro Carvalho Chehab

V4L/DVB (8672): gspca: Big rewrite of spca561.

Bug register/value inversions in USB exchanges.
Exposure and gain controls added for rev 12a.
Separate the functions and controls of the revisions 12a and 72a.
Signed-off-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent a0b508c2
...@@ -32,85 +32,44 @@ MODULE_LICENSE("GPL"); ...@@ -32,85 +32,44 @@ MODULE_LICENSE("GPL");
struct sd { struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */ struct gspca_dev gspca_dev; /* !! must be the first item */
unsigned short contrast; __u16 contrast; /* rev72a only */
__u8 brightness; #define CONTRAST_MIN 0x0000
__u8 white; #define CONTRAST_DEF 0x2000
#define CONTRAST_MAX 0x3fff
__u16 exposure; /* rev12a only */
#define EXPOSURE_MIN 0x0120
#define EXPOSURE_DEF 0x20ae
#define EXPOSURE_MAX 0x5720
__u8 brightness; /* rev72a only */
#define BRIGHTNESS_MIN 0
#define BRIGHTNESS_DEF 32
#define BRIGHTNESS_MAX 63
__u8 white; /* rev12a only */
#define WHITE_MIN 0
#define WHITE_DEF 0x40
#define WHITE_MAX 0x7f
__u8 autogain; __u8 autogain;
#define AUTOGAIN_MIN 0
#define AUTOGAIN_DEF 1
#define AUTOGAIN_MAX 1
__u8 gain; /* rev12a only */
#define GAIN_MIN 0x0
#define GAIN_DEF 0x24
#define GAIN_MAX 0x24
__u8 chip_revision; __u8 chip_revision;
#define Rev012A 0
#define Rev072A 1
signed char ag_cnt; signed char ag_cnt;
#define AG_CNT_START 13 #define AG_CNT_START 13
}; };
/* V4L2 controls supported by the driver */
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_setwhite(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
.maximum = 63,
.step = 1,
#define BRIGHTNESS_DEF 32
.default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
{
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
.maximum = 0x3fff,
.step = 1,
#define CONTRAST_DEF 0x2000
.default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
.get = sd_getcontrast,
},
{
{
.id = V4L2_CID_DO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "While Balance",
.minimum = 0,
.maximum = 0x7f,
.step = 1,
#define WHITE_DEF 40
.default_value = WHITE_DEF,
},
.set = sd_setwhite,
.get = sd_getwhite,
},
{
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Auto Gain",
.minimum = 0,
.maximum = 1,
.step = 1,
#define AUTOGAIN_DEF 1
.default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
},
};
static struct v4l2_pix_format sif_mode[] = { static struct v4l2_pix_format sif_mode[] = {
{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 160, .bytesperline = 160,
...@@ -160,12 +119,8 @@ static struct v4l2_pix_format sif_mode[] = { ...@@ -160,12 +119,8 @@ static struct v4l2_pix_format sif_mode[] = {
#define SPCA561_INDEX_I2C_BASE 0x8800 #define SPCA561_INDEX_I2C_BASE 0x8800
#define SPCA561_SNAPBIT 0x20 #define SPCA561_SNAPBIT 0x20
#define SPCA561_SNAPCTRL 0x40 #define SPCA561_SNAPCTRL 0x40
enum {
Rev072A = 0,
Rev012A,
};
static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value) static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
{ {
int ret; int ret;
...@@ -215,12 +170,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, ...@@ -215,12 +170,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, len, 500); index, gspca_dev->usb_buf, len, 500);
} }
static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
{
reg_w_val(gspca_dev->dev, 0x92, 0x8804);
reg_w_val(gspca_dev->dev, mode, 0x8802);
}
static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
{ {
int retry = 60; int retry = 60;
...@@ -229,9 +178,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) ...@@ -229,9 +178,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
DataLow = valeur; DataLow = valeur;
DataHight = valeur >> 8; DataHight = valeur >> 8;
reg_w_val(gspca_dev->dev, reg, 0x8801); reg_w_val(gspca_dev->dev, 0x8801, reg);
reg_w_val(gspca_dev->dev, DataLow, 0x8805); reg_w_val(gspca_dev->dev, 0x8805, DataLow);
reg_w_val(gspca_dev->dev, DataHight, 0x8800); reg_w_val(gspca_dev->dev, 0x8800, DataHight);
while (retry--) { while (retry--) {
reg_r(gspca_dev, 0x8803, 1); reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf[0]) if (!gspca_dev->usb_buf[0])
...@@ -245,9 +194,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) ...@@ -245,9 +194,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
__u8 value; __u8 value;
__u8 vallsb; __u8 vallsb;
reg_w_val(gspca_dev->dev, 0x92, 0x8804); reg_w_val(gspca_dev->dev, 0x8804, 0x92);
reg_w_val(gspca_dev->dev, reg, 0x8801); reg_w_val(gspca_dev->dev, 0x8801, reg);
reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802); reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
while (retry--) { while (retry--) {
reg_r(gspca_dev, 0x8803, 1); reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf) if (!gspca_dev->usb_buf)
...@@ -459,17 +408,6 @@ static const __u16 spca561_init_data[][2] = { ...@@ -459,17 +408,6 @@ static const __u16 spca561_init_data[][2] = {
{} {}
}; };
static void sensor_reset(struct gspca_dev *gspca_dev)
{
reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
reg_w_val(gspca_dev->dev, 0x8112, 0x00);
reg_w_val(gspca_dev->dev, 0x8114, 0x00);
reg_w_val(gspca_dev->dev, 0x8118, 0x21);
i2c_init(gspca_dev, 0x14);
i2c_write(gspca_dev, 1, 0x0d);
i2c_write(gspca_dev, 0, 0x0d);
}
/******************** QC Express etch2 stuff ********************/ /******************** QC Express etch2 stuff ********************/
static const __u16 Pb100_1map8300[][2] = { static const __u16 Pb100_1map8300[][2] = {
...@@ -479,9 +417,9 @@ static const __u16 Pb100_1map8300[][2] = { ...@@ -479,9 +417,9 @@ static const __u16 Pb100_1map8300[][2] = {
{0x8303, 0x0125}, /* image area */ {0x8303, 0x0125}, /* image area */
{0x8304, 0x0169}, {0x8304, 0x0169},
{0x8328, 0x000b}, {0x8328, 0x000b},
{0x833c, 0x0001}, {0x833c, 0x0001}, /*fixme: win:07*/
{0x832f, 0x0419}, {0x832f, 0x1904}, /*fixme: was 0419*/
{0x8307, 0x00aa}, {0x8307, 0x00aa},
{0x8301, 0x0003}, {0x8301, 0x0003},
{0x8302, 0x000e}, {0x8302, 0x000e},
...@@ -547,7 +485,7 @@ static const __u16 spca561_161rev12A_data2[][2] = { ...@@ -547,7 +485,7 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{0xdf, 0x863c}, /* df */ {0xdf, 0x863c}, /* df */
{0xf0, 0x8505}, {0xf0, 0x8505},
{0x32, 0x850a}, {0x32, 0x850a},
{0x99, 0x8700}, /* - white balance - new */ /* {0x99, 0x8700}, * - white balance - new (removed) */
{} {}
}; };
...@@ -566,9 +504,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev, ...@@ -566,9 +504,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev,
} }
static void init_161rev12A(struct gspca_dev *gspca_dev) static void init_161rev12A(struct gspca_dev *gspca_dev)
{ {
sensor_reset(gspca_dev); /* sensor_reset(gspca_dev); (not in win) */
write_vector(gspca_dev, spca561_161rev12A_data1); write_vector(gspca_dev, spca561_161rev12A_data1);
sensor_mapwrite(gspca_dev, Pb100_1map8300); sensor_mapwrite(gspca_dev, Pb100_1map8300);
/*fixme: should be in sd_start*/
write_vector(gspca_dev, spca561_161rev12A_data2); write_vector(gspca_dev, spca561_161rev12A_data2);
sensor_mapwrite(gspca_dev, Pb100_2map8300); sensor_mapwrite(gspca_dev, Pb100_2map8300);
} }
...@@ -605,32 +544,29 @@ static int sd_config(struct gspca_dev *gspca_dev, ...@@ -605,32 +544,29 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->epaddr = 0x01; cam->epaddr = 0x01;
gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
cam->cam_mode = sif_mode; cam->cam_mode = sif_mode;
cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; cam->nmodes = ARRAY_SIZE(sif_mode);
sd->chip_revision = id->driver_info; sd->chip_revision = id->driver_info;
sd->brightness = BRIGHTNESS_DEF; sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF; sd->contrast = CONTRAST_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->white = WHITE_DEF; sd->white = WHITE_DEF;
sd->exposure = EXPOSURE_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->gain = GAIN_DEF;
return 0; return 0;
} }
/* this function is called at open time */ /* this function is called at open time */
static int sd_open(struct gspca_dev *gspca_dev) static int sd_open_12a(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; PDEBUG(D_STREAM, "Chip revision: 012a");
init_161rev12A(gspca_dev);
switch (sd->chip_revision) { return 0;
case Rev072A: }
PDEBUG(D_STREAM, "Chip revision id: 072a"); static int sd_open_72a(struct gspca_dev *gspca_dev)
write_vector(gspca_dev, spca561_init_data); {
break; PDEBUG(D_STREAM, "Chip revision: 072a");
default: write_vector(gspca_dev, spca561_init_data);
/* case Rev012A: */
PDEBUG(D_STREAM, "Chip revision id: 012a");
init_161rev12A(gspca_dev);
break;
}
return 0; return 0;
} }
...@@ -639,28 +575,20 @@ static void setcontrast(struct gspca_dev *gspca_dev) ...@@ -639,28 +575,20 @@ static void setcontrast(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev; struct usb_device *dev = gspca_dev->dev;
__u8 lowb; __u8 lowb;
int expotimes;
switch (sd->chip_revision) { switch (sd->chip_revision) {
case Rev072A: case Rev072A:
lowb = sd->contrast >> 8; lowb = sd->contrast >> 8;
reg_w_val(dev, lowb, 0x8651); reg_w_val(dev, 0x8651, lowb);
reg_w_val(dev, lowb, 0x8652); reg_w_val(dev, 0x8652, lowb);
reg_w_val(dev, lowb, 0x8653); reg_w_val(dev, 0x8653, lowb);
reg_w_val(dev, lowb, 0x8654); reg_w_val(dev, 0x8654, lowb);
break; break;
default: { default: {
/* case Rev012A: { */ /* case Rev012A: { */
__u8 Reg8391[] = static const __u8 Reg8391[] =
{ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
/* Write camera sensor settings */
expotimes = (sd->contrast >> 5) & 0x07ff;
/* exposure is in 8309 2b, range 0120 - 5720 */
Reg8391[0] = expotimes & 0xff; /* exposure */
Reg8391[1] = 0x18 | (expotimes >> 8);
Reg8391[2] = sd->brightness; /* gain */
/* gain in 8335, 2b range 0000 - 2400 */
reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
break; break;
...@@ -668,32 +596,44 @@ static void setcontrast(struct gspca_dev *gspca_dev) ...@@ -668,32 +596,44 @@ static void setcontrast(struct gspca_dev *gspca_dev)
} }
} }
/* rev12a only */
static void setwhite(struct gspca_dev *gspca_dev) static void setwhite(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
__u16 white; __u16 white;
__u8 reg8614, reg8616; __u8 reg8614, reg8616;
switch (sd->chip_revision) { white = sd->white;
case Rev072A: if (sd->white == 0) {
/* no such hardware */ PDEBUG(D_CONF, "Discarding null whiteness");
break; return;
default:
/* case Rev012A: */
white = sd->white;
if (sd->white == 0) {
PDEBUG(D_CONF, "Discarding null whiteness");
break;
}
/* try to emulate MS-win as possible */
if (white < 0x45)
reg8616 = white;
else
reg8616 = 0x93 + (white >> 2);
reg8614 = 0x28 + (white >> 4);
reg_w_val(gspca_dev->dev, reg8616, 0x8616);
reg_w_val(gspca_dev->dev, reg8614, 0x8614);
} }
/* try to emulate MS-win as possible */
if (white < 0x45)
reg8616 = white;
else
reg8616 = 0x93 + (white >> 2);
reg8614 = 0x28 + (white >> 4);
reg_w_val(gspca_dev->dev, 0x8616, reg8616);
reg_w_val(gspca_dev->dev, 0x8614, reg8614);
}
/* rev 12a only */
static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
reg_w_val(dev, 0x8309, sd->gain);
}
/* rev 12a only */
static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
reg_w_val(dev, 0x8335, sd->gain);
} }
static void setautogain(struct gspca_dev *gspca_dev) static void setautogain(struct gspca_dev *gspca_dev)
...@@ -708,67 +648,67 @@ static void setautogain(struct gspca_dev *gspca_dev) ...@@ -708,67 +648,67 @@ static void setautogain(struct gspca_dev *gspca_dev)
} }
} }
static void sd_start(struct gspca_dev *gspca_dev) static void sd_start_12a(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev; struct usb_device *dev = gspca_dev->dev;
int Clck; int Clck;
__u8 Reg8307[] = { 0xaa, 0x00 }; __u8 Reg8307[] = { 0xaa, 0x00 };
int mode; int mode;
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
switch (sd->chip_revision) { switch (mode) {
case Rev072A: case 0:
switch (mode) { case 1:
default: Clck = 0x8a;
/* case 0: break;
case 1: */ case 2:
Clck = 0x25; Clck = 0x85;
break;
case 2:
Clck = 0x22;
break;
case 3:
Clck = 0x21;
break;
}
reg_w_val(dev, 0x8500, mode); /* mode */
reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
reg_w_val(dev, 0x8112, 0x10 | 0x20);
setautogain(gspca_dev);
break; break;
default: default:
/* case Rev012A: */ Clck = 0x83;
switch (mode) { break;
case 0: }
case 1: if (mode <= 1) {
Clck = 0x8a; /* Use compression on 320x240 and above */
break; reg_w_val(dev, 0x8500, 0x10 | mode);
case 2: } else {
Clck = 0x85; /* I couldn't get the compression to work below 320x240
break; * Fortunately at these resolutions the bandwidth
default: * is sufficient to push raw frames at ~20fps */
Clck = 0x83; reg_w_val(dev, 0x8500, mode);
break; } /* -- qq@kuku.eu.org */
} reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
if (mode <= 1) { reg_w_val(gspca_dev->dev, 0x8700, Clck);
/* Use compression on 320x240 and above */ /* 0x8f 0x85 0x27 clock */
reg_w_val(dev, 0x8500, 0x10 | mode); reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
} else { reg_w_val(gspca_dev->dev, 0x850b, 0x03);
/* I couldn't get the compression to work below 320x240 setcontrast(gspca_dev);
* Fortunately at these resolutions the bandwidth setwhite(gspca_dev);
* is sufficient to push raw frames at ~20fps */ }
reg_w_val(dev, 0x8500, mode); static void sd_start_72a(struct gspca_dev *gspca_dev)
} /* -- qq@kuku.eu.org */ {
reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); struct usb_device *dev = gspca_dev->dev;
reg_w_val(gspca_dev->dev, 0x8700, Clck); int Clck;
/* 0x8f 0x85 0x27 clock */ int mode;
reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
reg_w_val(gspca_dev->dev, 0x850b, 0x03); mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
setcontrast(gspca_dev); switch (mode) {
setwhite(gspca_dev); default:
/* case 0:
case 1: */
Clck = 0x25;
break;
case 2:
Clck = 0x22;
break;
case 3:
Clck = 0x21;
break; break;
} }
reg_w_val(dev, 0x8500, mode); /* mode */
reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
reg_w_val(dev, 0x8112, 0x10 | 0x20);
setautogain(gspca_dev);
} }
static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev)
...@@ -787,6 +727,7 @@ static void sd_close(struct gspca_dev *gspca_dev) ...@@ -787,6 +727,7 @@ static void sd_close(struct gspca_dev *gspca_dev)
reg_w_val(gspca_dev->dev, 0x8114, 0); reg_w_val(gspca_dev->dev, 0x8114, 0);
} }
/* rev72a only */
static void do_autogain(struct gspca_dev *gspca_dev) static void do_autogain(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -895,24 +836,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, ...@@ -895,24 +836,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
} }
/* rev 72a only */
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 value; __u8 value;
switch (sd->chip_revision) { value = sd->brightness;
case Rev072A: reg_w_val(gspca_dev->dev, 0x8611, value);
value = sd->brightness; reg_w_val(gspca_dev->dev, 0x8612, value);
reg_w_val(gspca_dev->dev, value, 0x8611); reg_w_val(gspca_dev->dev, 0x8613, value);
reg_w_val(gspca_dev->dev, value, 0x8612); reg_w_val(gspca_dev->dev, 0x8614, value);
reg_w_val(gspca_dev->dev, value, 0x8613);
reg_w_val(gspca_dev->dev, value, 0x8614);
break;
default:
/* case Rev012A: */
setcontrast(gspca_dev);
break;
}
} }
static void getbrightness(struct gspca_dev *gspca_dev) static void getbrightness(struct gspca_dev *gspca_dev)
...@@ -920,52 +854,38 @@ static void getbrightness(struct gspca_dev *gspca_dev) ...@@ -920,52 +854,38 @@ static void getbrightness(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
__u16 tot; __u16 tot;
switch (sd->chip_revision) { tot = 0;
case Rev072A: reg_r(gspca_dev, 0x8611, 1);
tot = 0; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8611, 1); reg_r(gspca_dev, 0x8612, 1);
tot += gspca_dev->usb_buf[0]; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8612, 1); reg_r(gspca_dev, 0x8613, 1);
tot += gspca_dev->usb_buf[0]; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8613, 1); reg_r(gspca_dev, 0x8614, 1);
tot += gspca_dev->usb_buf[0]; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8614, 1); sd->brightness = tot >> 2;
tot += gspca_dev->usb_buf[0];
sd->brightness = tot >> 2;
break;
default:
/* case Rev012A: */
/* no way to read sensor settings */
break;
}
} }
/* rev72a only */
static void getcontrast(struct gspca_dev *gspca_dev) static void getcontrast(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
__u16 tot; __u16 tot;
switch (sd->chip_revision) { tot = 0;
case Rev072A: reg_r(gspca_dev, 0x8651, 1);
tot = 0; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8651, 1); reg_r(gspca_dev, 0x8652, 1);
tot += gspca_dev->usb_buf[0]; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8652, 1); reg_r(gspca_dev, 0x8653, 1);
tot += gspca_dev->usb_buf[0]; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8653, 1); reg_r(gspca_dev, 0x8654, 1);
tot += gspca_dev->usb_buf[0]; tot += gspca_dev->usb_buf[0];
reg_r(gspca_dev, 0x8654, 1); sd->contrast = tot << 6;
tot += gspca_dev->usb_buf[0];
sd->contrast = tot << 6;
break;
default:
/* case Rev012A: */
/* no way to read sensor settings */
break;
}
PDEBUG(D_CONF, "get contrast %d", sd->contrast); PDEBUG(D_CONF, "get contrast %d", sd->contrast);
} }
/* rev 72a only */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -985,6 +905,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) ...@@ -985,6 +905,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
return 0; return 0;
} }
/* rev 72a only */
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -1022,7 +943,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) ...@@ -1022,7 +943,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0; return 0;
} }
/* white balance - new */ /* rev12a only */
static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -1041,20 +962,173 @@ static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) ...@@ -1041,20 +962,173 @@ static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
return 0; return 0;
} }
/* rev12a only */
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->exposure = val;
if (gspca_dev->streaming)
setexposure(gspca_dev);
return 0;
}
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->exposure;
return 0;
}
/* rev12a only */
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->gain = val;
if (gspca_dev->streaming)
setgain(gspca_dev);
return 0;
}
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->gain;
return 0;
}
/* control tables */
static struct ctrl sd_ctrls_12a[] = {
{
{
.id = V4L2_CID_DO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "While Balance",
.minimum = WHITE_MIN,
.maximum = WHITE_MAX,
.step = 1,
.default_value = WHITE_DEF,
},
.set = sd_setwhite,
.get = sd_getwhite,
},
{
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = EXPOSURE_MIN,
.maximum = EXPOSURE_MAX,
.step = 1,
.default_value = EXPOSURE_DEF,
},
.set = sd_setexposure,
.get = sd_getexposure,
},
{
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Auto Gain",
.minimum = AUTOGAIN_MIN,
.maximum = AUTOGAIN_MAX,
.step = 1,
.default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
},
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = GAIN_MIN,
.maximum = GAIN_MAX,
.step = 1,
.default_value = GAIN_DEF,
},
.set = sd_setgain,
.get = sd_getgain,
},
};
static struct ctrl sd_ctrls_72a[] = {
{
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = BRIGHTNESS_MIN,
.maximum = BRIGHTNESS_MAX,
.step = 1,
.default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
{
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = CONTRAST_MIN,
.maximum = CONTRAST_MAX,
.step = 1,
.default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
.get = sd_getcontrast,
},
{
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Auto Gain",
.minimum = AUTOGAIN_MIN,
.maximum = AUTOGAIN_MAX,
.step = 1,
.default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
},
};
/* sub-driver description */ /* sub-driver description */
static const struct sd_desc sd_desc = { static const struct sd_desc sd_desc_12a = {
.name = MODULE_NAME, .name = MODULE_NAME,
.ctrls = sd_ctrls, .ctrls = sd_ctrls_12a,
.nctrls = ARRAY_SIZE(sd_ctrls), .nctrls = ARRAY_SIZE(sd_ctrls_12a),
.config = sd_config, .config = sd_config,
.open = sd_open, .open = sd_open_12a,
.start = sd_start, .start = sd_start_12a,
.stopN = sd_stopN,
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
/* .dq_callback = do_autogain, * fixme */
};
static const struct sd_desc sd_desc_72a = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_72a,
.nctrls = ARRAY_SIZE(sd_ctrls_72a),
.config = sd_config,
.open = sd_open_72a,
.start = sd_start_72a,
.stopN = sd_stopN, .stopN = sd_stopN,
.stop0 = sd_stop0, .stop0 = sd_stop0,
.close = sd_close, .close = sd_close,
.pkt_scan = sd_pkt_scan, .pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain, .dq_callback = do_autogain,
}; };
static const struct sd_desc *sd_desc[2] = {
&sd_desc_12a,
&sd_desc_72a
};
/* -- module initialisation -- */ /* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = { static const __devinitdata struct usb_device_id device_table[] = {
...@@ -1082,7 +1156,9 @@ MODULE_DEVICE_TABLE(usb, device_table); ...@@ -1082,7 +1156,9 @@ MODULE_DEVICE_TABLE(usb, device_table);
static int sd_probe(struct usb_interface *intf, static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), return gspca_dev_probe(intf, id,
sd_desc[id->driver_info],
sizeof(struct sd),
THIS_MODULE); THIS_MODULE);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment