[media] gspca - ov519: Propagate errors to higher level

Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Jean-François Moine 2010-11-12 07:54:02 -03:00 committed by Mauro Carvalho Chehab
parent 83db76886c
commit f8f20188e8
2 changed files with 326 additions and 490 deletions

File diff suppressed because it is too large Load diff

View file

@ -59,18 +59,21 @@ static const struct v4l2_pix_format w9968cf_vga_mode[] = {
.colorspace = V4L2_COLORSPACE_JPEG}, .colorspace = V4L2_COLORSPACE_JPEG},
}; };
static int reg_w(struct sd *sd, u16 index, u16 value); static void reg_w(struct sd *sd, u16 index, u16 value);
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Write 64-bit data to the fast serial bus registers. Write 64-bit data to the fast serial bus registers.
Return 0 on success, -1 otherwise. Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_write_fsb(struct sd *sd, u16* data) static void w9968cf_write_fsb(struct sd *sd, u16* data)
{ {
struct usb_device *udev = sd->gspca_dev.dev; struct usb_device *udev = sd->gspca_dev.dev;
u16 value; u16 value;
int ret; int ret;
if (sd->gspca_dev.usb_err < 0)
return;
value = *data++; value = *data++;
memcpy(sd->gspca_dev.usb_buf, data, 6); memcpy(sd->gspca_dev.usb_buf, data, 6);
@ -79,20 +82,21 @@ static int w9968cf_write_fsb(struct sd *sd, u16* data)
value, 0x06, sd->gspca_dev.usb_buf, 6, 500); value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
if (ret < 0) { if (ret < 0) {
err("Write FSB registers failed (%d)", ret); err("Write FSB registers failed (%d)", ret);
return ret; sd->gspca_dev.usb_err = ret;
} }
return 0;
} }
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Write data to the serial bus control register. Write data to the serial bus control register.
Return 0 on success, a negative number otherwise. Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_write_sb(struct sd *sd, u16 value) static void w9968cf_write_sb(struct sd *sd, u16 value)
{ {
int ret; int ret;
if (sd->gspca_dev.usb_err < 0)
return;
/* We don't use reg_w here, as that would cause all writes when /* We don't use reg_w here, as that would cause all writes when
bitbanging i2c to be logged, making the logs impossible to read */ bitbanging i2c to be logged, making the logs impossible to read */
ret = usb_control_msg(sd->gspca_dev.dev, ret = usb_control_msg(sd->gspca_dev.dev,
@ -105,10 +109,8 @@ static int w9968cf_write_sb(struct sd *sd, u16 value)
if (ret < 0) { if (ret < 0) {
err("Write SB reg [01] %04x failed", value); err("Write SB reg [01] %04x failed", value);
return ret; sd->gspca_dev.usb_err = ret;
} }
return 0;
} }
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
@ -119,6 +121,9 @@ static int w9968cf_read_sb(struct sd *sd)
{ {
int ret; int ret;
if (sd->gspca_dev.usb_err < 0)
return -1;
/* We don't use reg_r here, as the w9968cf is special and has 16 /* We don't use reg_r here, as the w9968cf is special and has 16
bit registers instead of 8 bit */ bit registers instead of 8 bit */
ret = usb_control_msg(sd->gspca_dev.dev, ret = usb_control_msg(sd->gspca_dev.dev,
@ -126,11 +131,13 @@ static int w9968cf_read_sb(struct sd *sd)
1, 1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0x01, sd->gspca_dev.usb_buf, 2, 500); 0, 0x01, sd->gspca_dev.usb_buf, 2, 500);
if (ret >= 0) if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0] | ret = sd->gspca_dev.usb_buf[0] |
(sd->gspca_dev.usb_buf[1] << 8); (sd->gspca_dev.usb_buf[1] << 8);
else } else {
err("Read SB reg [01] failed"); err("Read SB reg [01] failed");
sd->gspca_dev.usb_err = ret;
}
udelay(W9968CF_I2C_BUS_DELAY); udelay(W9968CF_I2C_BUS_DELAY);
@ -142,12 +149,12 @@ static int w9968cf_read_sb(struct sd *sd)
This function is called by w9968cf_start_transfer(). This function is called by w9968cf_start_transfer().
Return 0 on success, a negative number otherwise. Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_upload_quantizationtables(struct sd *sd) static void w9968cf_upload_quantizationtables(struct sd *sd)
{ {
u16 a, b; u16 a, b;
int ret = 0, i, j; int i, j;
ret += reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */ reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
for (i = 0, j = 0; i < 32; i++, j += 2) { for (i = 0, j = 0; i < 32; i++, j += 2) {
a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8); a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8);
@ -155,9 +162,7 @@ static int w9968cf_upload_quantizationtables(struct sd *sd)
reg_w(sd, 0x40 + i, a); reg_w(sd, 0x40 + i, a);
reg_w(sd, 0x60 + i, b); reg_w(sd, 0x60 + i, b);
} }
ret += reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */ reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
return ret;
} }
/**************************************************************************** /****************************************************************************
@ -168,50 +173,39 @@ static int w9968cf_upload_quantizationtables(struct sd *sd)
* i2c_adap_read_byte() * * i2c_adap_read_byte() *
****************************************************************************/ ****************************************************************************/
static int w9968cf_smbus_start(struct sd *sd) static void w9968cf_smbus_start(struct sd *sd)
{ {
int ret = 0; w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
return ret;
} }
static int w9968cf_smbus_stop(struct sd *sd) static void w9968cf_smbus_stop(struct sd *sd)
{ {
int ret = 0; w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
return ret;
} }
static int w9968cf_smbus_write_byte(struct sd *sd, u8 v) static void w9968cf_smbus_write_byte(struct sd *sd, u8 v)
{ {
u8 bit; u8 bit;
int ret = 0, sda; int sda;
for (bit = 0 ; bit < 8 ; bit++) { for (bit = 0 ; bit < 8 ; bit++) {
sda = (v & 0x80) ? 2 : 0; sda = (v & 0x80) ? 2 : 0;
v <<= 1; v <<= 1;
/* SDE=1, SDA=sda, SCL=0 */ /* SDE=1, SDA=sda, SCL=0 */
ret += w9968cf_write_sb(sd, 0x10 | sda); w9968cf_write_sb(sd, 0x10 | sda);
/* SDE=1, SDA=sda, SCL=1 */ /* SDE=1, SDA=sda, SCL=1 */
ret += w9968cf_write_sb(sd, 0x11 | sda); w9968cf_write_sb(sd, 0x11 | sda);
/* SDE=1, SDA=sda, SCL=0 */ /* SDE=1, SDA=sda, SCL=0 */
ret += w9968cf_write_sb(sd, 0x10 | sda); w9968cf_write_sb(sd, 0x10 | sda);
} }
return ret;
} }
static int w9968cf_smbus_read_byte(struct sd *sd, u8* v) static void w9968cf_smbus_read_byte(struct sd *sd, u8 *v)
{ {
u8 bit; u8 bit;
int ret = 0;
/* No need to ensure SDA is high as we are always called after /* No need to ensure SDA is high as we are always called after
read_ack which ends with SDA high */ read_ack which ends with SDA high */
@ -219,51 +213,40 @@ static int w9968cf_smbus_read_byte(struct sd *sd, u8* v)
for (bit = 0 ; bit < 8 ; bit++) { for (bit = 0 ; bit < 8 ; bit++) {
*v <<= 1; *v <<= 1;
/* SDE=1, SDA=1, SCL=1 */ /* SDE=1, SDA=1, SCL=1 */
ret += w9968cf_write_sb(sd, 0x0013); w9968cf_write_sb(sd, 0x0013);
*v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0; *v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0;
/* SDE=1, SDA=1, SCL=0 */ /* SDE=1, SDA=1, SCL=0 */
ret += w9968cf_write_sb(sd, 0x0012); w9968cf_write_sb(sd, 0x0012);
} }
return ret;
} }
static int w9968cf_smbus_write_nack(struct sd *sd) static void w9968cf_smbus_write_nack(struct sd *sd)
{ {
int ret = 0;
/* No need to ensure SDA is high as we are always called after /* No need to ensure SDA is high as we are always called after
read_byte which ends with SDA high */ read_byte which ends with SDA high */
ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
return ret;
} }
static int w9968cf_smbus_read_ack(struct sd *sd) static void w9968cf_smbus_read_ack(struct sd *sd)
{ {
int ret = 0, sda; int sda;
/* Ensure SDA is high before raising clock to avoid a spurious stop */ /* Ensure SDA is high before raising clock to avoid a spurious stop */
ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
sda = w9968cf_read_sb(sd); sda = w9968cf_read_sb(sd);
ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
if (sda < 0) if (sda >= 0 && (sda & 0x08)) {
ret += sda;
else if (sda & 0x08) {
PDEBUG(D_USBI, "Did not receive i2c ACK"); PDEBUG(D_USBI, "Did not receive i2c ACK");
ret += -1; sd->gspca_dev.usb_err = -EIO;
} }
return ret;
} }
/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value) static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
{ {
u16* data = (u16 *)sd->gspca_dev.usb_buf; u16* data = (u16 *)sd->gspca_dev.usb_buf;
int ret = 0;
data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0); data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0);
data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0; data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0;
@ -276,7 +259,7 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0); data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0);
data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0; data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0;
ret += w9968cf_write_fsb(sd, data); w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0); data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0);
data[0] |= (reg & 0x40) ? 0x0540 : 0x0; data[0] |= (reg & 0x40) ? 0x0540 : 0x0;
@ -290,7 +273,7 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[2] |= (reg & 0x01) ? 0x5400 : 0x0; data[2] |= (reg & 0x01) ? 0x5400 : 0x0;
data[3] = 0x001d; data[3] = 0x001d;
ret += w9968cf_write_fsb(sd, data); w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
data[0] |= (value & 0x40) ? 0x0540 : 0x0; data[0] |= (value & 0x40) ? 0x0540 : 0x0;
@ -304,14 +287,9 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[2] |= (value & 0x01) ? 0x5400 : 0x0; data[2] |= (value & 0x01) ? 0x5400 : 0x0;
data[3] = 0xfe1d; data[3] = 0xfe1d;
ret += w9968cf_write_fsb(sd, data); w9968cf_write_fsb(sd, data);
if (!ret)
PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg); PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
else
PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
return ret;
} }
/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
@ -321,28 +299,28 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
u8 value; u8 value;
/* Fast serial bus data control disable */ /* Fast serial bus data control disable */
ret += w9968cf_write_sb(sd, 0x0013); /* don't change ! */ w9968cf_write_sb(sd, 0x0013); /* don't change ! */
ret += w9968cf_smbus_start(sd); w9968cf_smbus_start(sd);
ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr); w9968cf_smbus_write_byte(sd, sd->sensor_addr);
ret += w9968cf_smbus_read_ack(sd); w9968cf_smbus_read_ack(sd);
ret += w9968cf_smbus_write_byte(sd, reg); w9968cf_smbus_write_byte(sd, reg);
ret += w9968cf_smbus_read_ack(sd); w9968cf_smbus_read_ack(sd);
ret += w9968cf_smbus_stop(sd); w9968cf_smbus_stop(sd);
ret += w9968cf_smbus_start(sd); w9968cf_smbus_start(sd);
ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1); w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
ret += w9968cf_smbus_read_ack(sd); w9968cf_smbus_read_ack(sd);
ret += w9968cf_smbus_read_byte(sd, &value); w9968cf_smbus_read_byte(sd, &value);
/* signal we don't want to read anymore, the v4l1 driver used to /* signal we don't want to read anymore, the v4l1 driver used to
send an ack here which is very wrong! (and then fixed send an ack here which is very wrong! (and then fixed
the issues this gave by retrying reads) */ the issues this gave by retrying reads) */
ret += w9968cf_smbus_write_nack(sd); w9968cf_smbus_write_nack(sd);
ret += w9968cf_smbus_stop(sd); w9968cf_smbus_stop(sd);
/* Fast serial bus data control re-enable */ /* Fast serial bus data control re-enable */
ret += w9968cf_write_sb(sd, 0x0030); w9968cf_write_sb(sd, 0x0030);
if (!ret) { if (sd->gspca_dev.usb_err >= 0) {
ret = value; ret = value;
PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value); PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
} else } else
@ -355,29 +333,21 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
Turn on the LED on some webcams. A beep should be heard too. Turn on the LED on some webcams. A beep should be heard too.
Return 0 on success, a negative number otherwise. Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_configure(struct sd *sd) static void w9968cf_configure(struct sd *sd)
{ {
int ret = 0; reg_w(sd, 0x00, 0xff00); /* power-down */
reg_w(sd, 0x00, 0xbf17); /* reset everything */
ret += reg_w(sd, 0x00, 0xff00); /* power-down */ reg_w(sd, 0x00, 0xbf10); /* normal operation */
ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */ reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */ reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
ret += reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */ reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
ret += reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */ reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
ret += reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
ret += reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
if (ret)
PDEBUG(D_ERR, "Couldn't turn on the LED");
sd->stopped = 1; sd->stopped = 1;
return ret;
} }
static int w9968cf_init(struct sd *sd) static void w9968cf_init(struct sd *sd)
{ {
int ret = 0;
unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2), unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2),
y0 = 0x0000, y0 = 0x0000,
u0 = y0 + hw_bufsize / 2, u0 = y0 + hw_bufsize / 2,
@ -386,43 +356,41 @@ static int w9968cf_init(struct sd *sd)
u1 = y1 + hw_bufsize / 2, u1 = y1 + hw_bufsize / 2,
v1 = u1 + hw_bufsize / 4; v1 = u1 + hw_bufsize / 4;
ret += reg_w(sd, 0x00, 0xff00); /* power off */ reg_w(sd, 0x00, 0xff00); /* power off */
ret += reg_w(sd, 0x00, 0xbf10); /* power on */ reg_w(sd, 0x00, 0xbf10); /* power on */
ret += reg_w(sd, 0x03, 0x405d); /* DRAM timings */ reg_w(sd, 0x03, 0x405d); /* DRAM timings */
ret += reg_w(sd, 0x04, 0x0030); /* SDRAM timings */ reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
ret += reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */ reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
ret += reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */ reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */
ret += reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */ reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
ret += reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */ reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */
ret += reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */ reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
ret += reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */ reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */
ret += reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */ reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
ret += reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */ reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */
ret += reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */ reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
ret += reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */ reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */
ret += reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */ reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
ret += reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */ reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */
ret += reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */ reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
ret += reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */ reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */
ret += reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */ reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
ret += reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */ reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */
ret += reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */ reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
ret += reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/ reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
ret += reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */ reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
ret += reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */ reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
return ret;
} }
static int w9968cf_set_crop_window(struct sd *sd) static void w9968cf_set_crop_window(struct sd *sd)
{ {
int ret = 0, start_cropx, start_cropy, x, y, fw, fh, cw, ch, int start_cropx, start_cropy, x, y, fw, fh, cw, ch,
max_width, max_height; max_width, max_height;
if (sd->sif) { if (sd->sif) {
@ -464,42 +432,40 @@ static int w9968cf_set_crop_window(struct sd *sd)
x = (max_width - cw) / 2; x = (max_width - cw) / 2;
y = (max_height - ch) / 2; y = (max_height - ch) / 2;
ret += reg_w(sd, 0x10, start_cropx + x); reg_w(sd, 0x10, start_cropx + x);
ret += reg_w(sd, 0x11, start_cropy + y); reg_w(sd, 0x11, start_cropy + y);
ret += reg_w(sd, 0x12, start_cropx + x + cw); reg_w(sd, 0x12, start_cropx + x + cw);
ret += reg_w(sd, 0x13, start_cropy + y + ch); reg_w(sd, 0x13, start_cropy + y + ch);
return ret;
} }
static int w9968cf_mode_init_regs(struct sd *sd) static void w9968cf_mode_init_regs(struct sd *sd)
{ {
int ret = 0, val, vs_polarity, hs_polarity; int val, vs_polarity, hs_polarity;
ret += w9968cf_set_crop_window(sd); w9968cf_set_crop_window(sd);
ret += reg_w(sd, 0x14, sd->gspca_dev.width); reg_w(sd, 0x14, sd->gspca_dev.width);
ret += reg_w(sd, 0x15, sd->gspca_dev.height); reg_w(sd, 0x15, sd->gspca_dev.height);
/* JPEG width & height */ /* JPEG width & height */
ret += reg_w(sd, 0x30, sd->gspca_dev.width); reg_w(sd, 0x30, sd->gspca_dev.width);
ret += reg_w(sd, 0x31, sd->gspca_dev.height); reg_w(sd, 0x31, sd->gspca_dev.height);
/* Y & UV frame buffer strides (in WORD) */ /* Y & UV frame buffer strides (in WORD) */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) { V4L2_PIX_FMT_JPEG) {
ret += reg_w(sd, 0x2c, sd->gspca_dev.width / 2); reg_w(sd, 0x2c, sd->gspca_dev.width / 2);
ret += reg_w(sd, 0x2d, sd->gspca_dev.width / 4); reg_w(sd, 0x2d, sd->gspca_dev.width / 4);
} else } else
ret += reg_w(sd, 0x2c, sd->gspca_dev.width); reg_w(sd, 0x2c, sd->gspca_dev.width);
ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */ reg_w(sd, 0x00, 0xbf17); /* reset everything */
ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */ reg_w(sd, 0x00, 0xbf10); /* normal operation */
/* Transfer size in WORDS (for UYVY format only) */ /* Transfer size in WORDS (for UYVY format only) */
val = sd->gspca_dev.width * sd->gspca_dev.height; val = sd->gspca_dev.width * sd->gspca_dev.height;
ret += reg_w(sd, 0x3d, val & 0xffff); /* low bits */ reg_w(sd, 0x3d, val & 0xffff); /* low bits */
ret += reg_w(sd, 0x3e, val >> 16); /* high bits */ reg_w(sd, 0x3e, val >> 16); /* high bits */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) { V4L2_PIX_FMT_JPEG) {
@ -507,7 +473,7 @@ static int w9968cf_mode_init_regs(struct sd *sd)
jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
sd->gspca_dev.width, 0x22); /* JPEG 420 */ sd->gspca_dev.width, 0x22); /* JPEG 420 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality); jpeg_set_qual(sd->jpeg_hdr, sd->quality);
ret += w9968cf_upload_quantizationtables(sd); w9968cf_upload_quantizationtables(sd);
} }
/* Video Capture Control Register */ /* Video Capture Control Register */
@ -539,11 +505,9 @@ static int w9968cf_mode_init_regs(struct sd *sd)
val |= 0x8000; /* capt. enable */ val |= 0x8000; /* capt. enable */
ret += reg_w(sd, 0x16, val); reg_w(sd, 0x16, val);
sd->gspca_dev.empty_packet = 0; sd->gspca_dev.empty_packet = 0;
return ret;
} }
static void w9968cf_stop0(struct sd *sd) static void w9968cf_stop0(struct sd *sd)