The crash is due to USB exchanges done at interrupt level.
These exchanges, tied to autogain, are now done by the application.
Also, there is a fix about autogain start.
Concerned subdrivers: etoms, pac7311, sonixj and spca561.
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */
}
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ __u8 brightness = sd->brightness;
+
+ for (i = 0; i < 4; i++)
+ reg_w_val(gspca_dev, ET_O_RED + i, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ int brightness = 0;
+
+ for (i = 0; i < 4; i++) {
+ reg_r(gspca_dev, ET_O_RED + i, 1);
+ brightness += gspca_dev->usb_buf[0];
+ }
+ sd->brightness = brightness >> 3;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+ __u8 contrast = sd->contrast;
+
+ memset(RGBG, contrast, sizeof(RGBG) - 2);
+ reg_w(gspca_dev, ET_G_RED, RGBG, 6);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ int contrast = 0;
+
+ for (i = 0; i < 4; i++) {
+ reg_r(gspca_dev, ET_G_RED + i, 1);
+ contrast += gspca_dev->usb_buf[0];
+ }
+ sd->contrast = contrast >> 2;
+}
+
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
}
}
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+}
+
static void Et_init1(struct gspca_dev *gspca_dev)
{
__u8 value;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->autogain = AUTOGAIN_DEF;
+ sd->ag_cnt = -1;
return 0;
}
else
Et_init2(gspca_dev);
+ setautogain(gspca_dev);
+
reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
et_video(gspca_dev, 1); /* video on */
}
{
}
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i;
- __u8 brightness = sd->brightness;
-
- for (i = 0; i < 4; i++)
- reg_w_val(gspca_dev, ET_O_RED + i, brightness);
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i;
- int brightness = 0;
-
- for (i = 0; i < 4; i++) {
- reg_r(gspca_dev, ET_O_RED + i, 1);
- brightness += gspca_dev->usb_buf[0];
- }
- sd->brightness = brightness >> 3;
-}
-
-static void setcontrast(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
- __u8 contrast = sd->contrast;
-
- memset(RGBG, contrast, sizeof(RGBG) - 2);
- reg_w(gspca_dev, ET_G_RED, RGBG, 6);
-}
-
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i;
- int contrast = 0;
-
- for (i = 0; i < 4; i++) {
- reg_r(gspca_dev, ET_G_RED + i, 1);
- contrast += gspca_dev->usb_buf[0];
- }
- sd->contrast = contrast >> 2;
-}
-
static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
#define LIMIT(color) \
(unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
-static void setautogain(struct gspca_dev *gspca_dev)
+static void do_autogain(struct gspca_dev *gspca_dev)
{
- __u8 luma = 0;
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 luma;
__u8 luma_mean = 128;
__u8 luma_delta = 20;
__u8 spring = 4;
- int Gbright = 0;
+ int Gbright;
__u8 r, g, b;
+ if (sd->ag_cnt < 0)
+ return;
+ if (--sd->ag_cnt >= 0)
+ return;
+ sd->ag_cnt = AG_CNT_START;
+
Gbright = Et_getgainG(gspca_dev);
reg_r(gspca_dev, ET_LUMA_CENTER, 4);
g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1;
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
- struct sd *sd;
int seqframe;
seqframe = data[0] & 0x3f;
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
- sd = (struct sd *) gspca_dev;
- if (sd->ag_cnt >= 0) {
- if (--sd->ag_cnt < 0) {
- sd->ag_cnt = AG_CNT_START;
- setautogain(gspca_dev);
- }
- }
return;
}
if (len) {
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val;
- if (val)
- sd->ag_cnt = AG_CNT_START;
- else
- sd->ag_cnt = -1;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
return 0;
}
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
+ .dq_callback = do_autogain,
};
/* -- module initialisation -- */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- int avg_lum;
+ int lum_sum;
+ atomic_t avg_lum;
+ atomic_t do_gain;
unsigned char brightness;
unsigned char contrast;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->autogain = AUTOGAIN_DEF;
+ sd->ag_cnt = -1;
return 0;
}
PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
}
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->autogain) {
+ sd->lum_sum = 0;
+ sd->ag_cnt = AG_CNT_START;
+ } else {
+ sd->ag_cnt = -1;
+ }
+}
+
/* this function is called at open time */
static int sd_open(struct gspca_dev *gspca_dev)
{
static void sd_start(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
reg_w(gspca_dev, 0xff, 0x01);
reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
setcontrast(gspca_dev);
setbrightness(gspca_dev);
setcolors(gspca_dev);
+ setautogain(gspca_dev);
/* set correct resolution */
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x78, 0x04);
reg_w(gspca_dev, 0x78, 0x05);
-
- if (sd->autogain) {
- sd->ag_cnt = AG_CNT_START;
- sd->avg_lum = 0;
- } else {
- sd->ag_cnt = -1;
- }
}
static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
}
-static void setautogain(struct gspca_dev *gspca_dev, int luma)
+static void do_autogain(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int luma;
int luma_mean = 128;
int luma_delta = 20;
__u8 spring = 5;
int Gbright;
+ if (!atomic_read(&sd->do_gain))
+ return;
+ atomic_set(&sd->do_gain, 0);
+
+ luma = atomic_read(&sd->avg_lum);
Gbright = reg_r(gspca_dev, 0x02);
PDEBUG(D_FRAM, "luma mean %d", luma);
if (luma < luma_mean - luma_delta ||
/* start of frame */
if (sd->ag_cnt >= 0 && p > 28) {
- sd->avg_lum += data[p - 23];
+ sd->lum_sum += data[p - 23];
if (--sd->ag_cnt < 0) {
sd->ag_cnt = AG_CNT_START;
- setautogain(gspca_dev,
- sd->avg_lum / AG_CNT_START);
- sd->avg_lum = 0;
+ atomic_set(&sd->avg_lum,
+ sd->lum_sum / AG_CNT_START);
+ sd->lum_sum = 0;
+ atomic_set(&sd->do_gain, 1);
}
}
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val;
- if (val) {
- sd->ag_cnt = AG_CNT_START;
- sd->avg_lum = 0;
- } else {
- sd->ag_cnt = -1;
- }
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
return 0;
}
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
+ .dq_callback = do_autogain,
};
/* -- module initialisation -- */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- int avg_lum;
+ atomic_t avg_lum;
unsigned int exposure;
unsigned short brightness;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->autogain = AUTOGAIN_DEF;
+ sd->ag_cnt = -1;
+
return 0;
}
reg_w1(gspca_dev, 0x05, data);
}
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MO4000:
+ case SENSOR_MI0360:
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ break;
+ }
+}
+
/* -- start the camera -- */
static void sd_start(struct gspca_dev *gspca_dev)
{
reg_w1(gspca_dev, 0x01, reg1);
setbrightness(gspca_dev);
setcontrast(gspca_dev);
+ setautogain(gspca_dev);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
}
-static void setautogain(struct gspca_dev *gspca_dev)
+static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- /* Thanks S., without your advice, autobright should not work :) */
int delta;
- int expotimes = 0;
+ int expotimes;
__u8 luma_mean = 130;
__u8 luma_delta = 20;
- delta = sd->avg_lum;
+ /* Thanks S., without your advice, autobright should not work :) */
+ if (sd->ag_cnt < 0)
+ return;
+ if (--sd->ag_cnt >= 0)
+ return;
+ sd->ag_cnt = AG_CNT_START;
+
+ delta = atomic_read(&sd->avg_lum);
+ PDEBUG(D_FRAM, "mean lum %d", delta);
if (delta < luma_mean - luma_delta ||
delta > luma_mean + luma_delta) {
switch (sd->sensor) {
sd->exposure = setexposure(gspca_dev,
(unsigned int) (expotimes << 8));
break;
- case SENSOR_MO4000:
- case SENSOR_MI0360:
+ default:
+/* case SENSOR_MO4000: */
+/* case SENSOR_MI0360: */
expotimes = sd->exposure;
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
}
}
+/* scan the URB packets */
+/* This function is run at interrupt level. */
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
frame, data, sof + 2);
if (sd->ag_cnt < 0)
return;
- if (--sd->ag_cnt >= 0)
- return;
- sd->ag_cnt = AG_CNT_START;
/* w1 w2 w3 */
/* w4 w5 w6 */
/* w7 w8 */
/* w5 */
avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
avg_lum >>= 4;
- sd->avg_lum = avg_lum;
- PDEBUG(D_PACK, "mean lum %d", avg_lum);
- setautogain(gspca_dev);
+ atomic_set(&sd->avg_lum, avg_lum);
return;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val;
- if (val)
- sd->ag_cnt = AG_CNT_START;
- else
- sd->ag_cnt = -1;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
return 0;
}
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
+ .dq_callback = do_autogain,
};
/* -- module initialisation -- */
}
}
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->chip_revision == Rev072A) {
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+ }
+}
+
static void sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
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;
default:
/* case Rev012A: */
reg_w_val(gspca_dev->dev, 0x8114, 0);
}
-static void setautogain(struct gspca_dev *gspca_dev)
+static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int expotimes = 0;
- int pixelclk = 0;
- int gainG = 0;
+ int expotimes;
+ int pixelclk;
+ int gainG;
__u8 R, Gr, Gb, B;
int y;
__u8 luma_mean = 110;
__u8 luma_delta = 20;
__u8 spring = 4;
+ if (sd->ag_cnt < 0)
+ return;
+ if (--sd->ag_cnt >= 0)
+ return;
+ sd->ag_cnt = AG_CNT_START;
+
switch (sd->chip_revision) {
case Rev072A:
reg_r(gspca_dev, 0x8621, 1);
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
- struct sd *sd = (struct sd *) gspca_dev;
-
switch (data[0]) {
case 0: /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
- if (sd->ag_cnt >= 0) {
- if (--sd->ag_cnt < 0) {
- sd->ag_cnt = AG_CNT_START;
- setautogain(gspca_dev);
- }
- }
data += SPCA561_OFFSET_DATA;
len -= SPCA561_OFFSET_DATA;
if (data[1] & 0x10) {
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val;
- if (val)
- sd->ag_cnt = AG_CNT_START;
- else
- sd->ag_cnt = -1;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
return 0;
}
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
+ .dq_callback = do_autogain,
};
/* -- module initialisation -- */