|
@@ -331,7 +331,7 @@ static const __u8 page3_7302[] = {
|
|
|
0x00
|
|
|
};
|
|
|
|
|
|
-static void reg_w_buf(struct gspca_dev *gspca_dev,
|
|
|
+static int reg_w_buf(struct gspca_dev *gspca_dev,
|
|
|
__u8 index,
|
|
|
const char *buffer, int len)
|
|
|
{
|
|
@@ -349,10 +349,11 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
|
|
|
PDEBUG(D_ERR, "reg_w_buf(): "
|
|
|
"Failed to write registers to index 0x%x, error %i",
|
|
|
index, ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void reg_w(struct gspca_dev *gspca_dev,
|
|
|
+static int reg_w(struct gspca_dev *gspca_dev,
|
|
|
__u8 index,
|
|
|
__u8 value)
|
|
|
{
|
|
@@ -369,23 +370,27 @@ static void reg_w(struct gspca_dev *gspca_dev,
|
|
|
PDEBUG(D_ERR, "reg_w(): "
|
|
|
"Failed to write register to index 0x%x, value 0x%x, error %i",
|
|
|
index, value, ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void reg_w_seq(struct gspca_dev *gspca_dev,
|
|
|
+static int reg_w_seq(struct gspca_dev *gspca_dev,
|
|
|
const __u8 *seq, int len)
|
|
|
{
|
|
|
+ int ret = 0;
|
|
|
while (--len >= 0) {
|
|
|
- reg_w(gspca_dev, seq[0], seq[1]);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, seq[0], seq[1]);
|
|
|
seq += 2;
|
|
|
}
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* load the beginning of a page */
|
|
|
-static void reg_w_page(struct gspca_dev *gspca_dev,
|
|
|
+static int reg_w_page(struct gspca_dev *gspca_dev,
|
|
|
const __u8 *page, int len)
|
|
|
{
|
|
|
int index;
|
|
|
- int ret;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
for (index = 0; index < len; index++) {
|
|
|
if (page[index] == SKIP) /* skip this index */
|
|
@@ -397,52 +402,61 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
|
|
|
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
|
0, index, gspca_dev->usb_buf, 1,
|
|
|
500);
|
|
|
- if (ret < 0)
|
|
|
+ if (ret < 0) {
|
|
|
PDEBUG(D_ERR, "reg_w_page(): "
|
|
|
"Failed to write register to index 0x%x, "
|
|
|
"value 0x%x, error %i",
|
|
|
index, page[index], ret);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* output a variable sequence */
|
|
|
-static void reg_w_var(struct gspca_dev *gspca_dev,
|
|
|
+static int reg_w_var(struct gspca_dev *gspca_dev,
|
|
|
const __u8 *seq,
|
|
|
const __u8 *page3, unsigned int page3_len,
|
|
|
const __u8 *page4, unsigned int page4_len)
|
|
|
{
|
|
|
int index, len;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
for (;;) {
|
|
|
index = *seq++;
|
|
|
len = *seq++;
|
|
|
switch (len) {
|
|
|
case END_OF_SEQUENCE:
|
|
|
- return;
|
|
|
+ return ret;
|
|
|
case LOAD_PAGE4:
|
|
|
- reg_w_page(gspca_dev, page4, page4_len);
|
|
|
+ ret = reg_w_page(gspca_dev, page4, page4_len);
|
|
|
break;
|
|
|
case LOAD_PAGE3:
|
|
|
- reg_w_page(gspca_dev, page3, page3_len);
|
|
|
+ ret = reg_w_page(gspca_dev, page3, page3_len);
|
|
|
break;
|
|
|
default:
|
|
|
if (len > USB_BUF_SZ) {
|
|
|
PDEBUG(D_ERR|D_STREAM,
|
|
|
"Incorrect variable sequence");
|
|
|
- return;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
while (len > 0) {
|
|
|
if (len < 8) {
|
|
|
- reg_w_buf(gspca_dev, index, seq, len);
|
|
|
+ ret = reg_w_buf(gspca_dev,
|
|
|
+ index, seq, len);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
seq += len;
|
|
|
break;
|
|
|
}
|
|
|
- reg_w_buf(gspca_dev, index, seq, 8);
|
|
|
+ ret = reg_w_buf(gspca_dev, index, seq, 8);
|
|
|
seq += 8;
|
|
|
index += 8;
|
|
|
len -= 8;
|
|
|
}
|
|
|
}
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
}
|
|
|
/* not reached */
|
|
|
}
|
|
@@ -472,10 +486,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|
|
}
|
|
|
|
|
|
/* This function is used by pac7302 only */
|
|
|
-static void setbrightcont(struct gspca_dev *gspca_dev)
|
|
|
+static int setbrightcont(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
int i, v;
|
|
|
+ int ret;
|
|
|
static const __u8 max[10] =
|
|
|
{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
|
|
|
0xd4, 0xec};
|
|
@@ -483,7 +498,7 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
|
|
|
{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
|
|
|
0x11, 0x0b};
|
|
|
|
|
|
- reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
|
|
|
for (i = 0; i < 10; i++) {
|
|
|
v = max[i];
|
|
|
v += (sd->brightness - BRIGHTNESS_MAX)
|
|
@@ -493,47 +508,62 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
|
|
|
v = 0;
|
|
|
else if (v > 0xff)
|
|
|
v = 0xff;
|
|
|
- reg_w(gspca_dev, 0xa2 + i, v);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0xa2 + i, v);
|
|
|
}
|
|
|
- reg_w(gspca_dev, 0xdc, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0xdc, 0x01);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* This function is used by pac7302 only */
|
|
|
-static void setcolors(struct gspca_dev *gspca_dev)
|
|
|
+static int setcolors(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
int i, v;
|
|
|
+ int ret;
|
|
|
static const int a[9] =
|
|
|
{217, -212, 0, -101, 170, -67, -38, -315, 355};
|
|
|
static const int b[9] =
|
|
|
{19, 106, 0, 19, 106, 1, 19, 106, 1};
|
|
|
|
|
|
- reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
- reg_w(gspca_dev, 0x11, 0x01);
|
|
|
- reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
v = a[i] * sd->colors / COLOR_MAX + b[i];
|
|
|
- reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
|
|
|
- reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
|
|
|
}
|
|
|
- reg_w(gspca_dev, 0xdc, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0xdc, 0x01);
|
|
|
PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void setgain(struct gspca_dev *gspca_dev)
|
|
|
+static int setgain(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
+ int ret;
|
|
|
|
|
|
- reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
- reg_w(gspca_dev, 0x10, sd->gain >> 3);
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x10, sd->gain >> 3);
|
|
|
|
|
|
/* load registers to sensor (Bit 0, auto clear) */
|
|
|
- reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void setexposure(struct gspca_dev *gspca_dev)
|
|
|
+static int setexposure(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
+ int ret;
|
|
|
__u8 reg;
|
|
|
|
|
|
/* register 2 of frame 3/4 contains the clock divider configuring the
|
|
@@ -549,47 +579,58 @@ static void setexposure(struct gspca_dev *gspca_dev)
|
|
|
the nearest multiple of 3, except when between 6 and 12? */
|
|
|
if (reg < 6 || reg > 12)
|
|
|
reg = ((reg + 1) / 3) * 3;
|
|
|
- reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
- reg_w(gspca_dev, 0x02, reg);
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x02, reg);
|
|
|
|
|
|
/* load registers to sensor (Bit 0, auto clear) */
|
|
|
- reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void sethvflip(struct gspca_dev *gspca_dev)
|
|
|
+static int sethvflip(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
+ int ret;
|
|
|
__u8 data;
|
|
|
|
|
|
- reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
|
|
|
data = (sd->hflip ? 0x08 : 0x00) | (sd->vflip ? 0x04 : 0x00);
|
|
|
- reg_w(gspca_dev, 0x21, data);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x21, data);
|
|
|
/* load registers to sensor (Bit 0, auto clear) */
|
|
|
- reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x11, 0x01);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* this function is called at probe and resume time for pac7302 */
|
|
|
static int sd_init(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
- reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
|
|
|
}
|
|
|
|
|
|
static int sd_start(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
struct sd *sd = (struct sd *) gspca_dev;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
sd->sof_read = 0;
|
|
|
|
|
|
- reg_w_var(gspca_dev, start_7302,
|
|
|
+ ret = reg_w_var(gspca_dev, start_7302,
|
|
|
page3_7302, sizeof(page3_7302),
|
|
|
NULL, 0);
|
|
|
- setbrightcont(gspca_dev);
|
|
|
- setcolors(gspca_dev);
|
|
|
- setgain(gspca_dev);
|
|
|
- setexposure(gspca_dev);
|
|
|
- sethvflip(gspca_dev);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = setbrightcont(gspca_dev);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = setcolors(gspca_dev);
|
|
|
+ if (0 <= ret)
|
|
|
+ setgain(gspca_dev);
|
|
|
+ if (0 <= ret)
|
|
|
+ setexposure(gspca_dev);
|
|
|
+ if (0 <= ret)
|
|
|
+ sethvflip(gspca_dev);
|
|
|
|
|
|
/* only resolution 640x480 is supported for pac7302 */
|
|
|
|
|
@@ -598,26 +639,34 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|
|
atomic_set(&sd->avg_lum, -1);
|
|
|
|
|
|
/* start stream */
|
|
|
- reg_w(gspca_dev, 0xff, 0x01);
|
|
|
- reg_w(gspca_dev, 0x78, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x78, 0x01);
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static void sd_stopN(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+
|
|
|
/* stop stream */
|
|
|
- reg_w(gspca_dev, 0xff, 0x01);
|
|
|
- reg_w(gspca_dev, 0x78, 0x00);
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x78, 0x00);
|
|
|
}
|
|
|
|
|
|
/* called on streamoff with alt 0 and on disconnect for pac7302 */
|
|
|
static void sd_stop0(struct gspca_dev *gspca_dev)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+
|
|
|
if (!gspca_dev->present)
|
|
|
return;
|
|
|
- reg_w(gspca_dev, 0xff, 0x01);
|
|
|
- reg_w(gspca_dev, 0x78, 0x40);
|
|
|
+ ret = reg_w(gspca_dev, 0xff, 0x01);
|
|
|
+ if (0 <= ret)
|
|
|
+ ret = reg_w(gspca_dev, 0x78, 0x40);
|
|
|
}
|
|
|
|
|
|
/* Include pac common sof detection functions */
|