Skip to content

Commit

Permalink
V4L/DVB (8604): gspca: Fix of "scheduling while atomic" crash.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jean-Francois Moine authored and Mauro Carvalho Chehab committed Aug 6, 2008
1 parent 594f5b8 commit cebf3b6
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 115 deletions.
133 changes: 72 additions & 61 deletions drivers/media/video/gspca/etoms.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,52 @@ static void Et_init2(struct gspca_dev *gspca_dev)
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;
Expand Down Expand Up @@ -492,6 +538,16 @@ static void getcolors(struct gspca_dev *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;
Expand Down Expand Up @@ -614,6 +670,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
return 0;
}

Expand Down Expand Up @@ -641,6 +698,8 @@ static void sd_start(struct gspca_dev *gspca_dev)
else
Et_init2(gspca_dev);

setautogain(gspca_dev);

reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
et_video(gspca_dev, 1); /* video on */
}
Expand All @@ -658,52 +717,6 @@ static void sd_close(struct gspca_dev *gspca_dev)
{
}

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;
Expand Down Expand Up @@ -733,15 +746,22 @@ static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
#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;
Expand All @@ -768,7 +788,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd;
int seqframe;

seqframe = data[0] & 0x3f;
Expand All @@ -783,13 +802,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
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) {
Expand Down Expand Up @@ -862,10 +874,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
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;
}

Expand All @@ -889,6 +899,7 @@ static struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};

/* -- module initialisation -- */
Expand Down
54 changes: 33 additions & 21 deletions drivers/media/video/gspca/pac7311.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ MODULE_LICENSE("GPL");
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;
Expand Down Expand Up @@ -271,6 +273,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
return 0;
}

Expand Down Expand Up @@ -311,6 +314,18 @@ static void setcolors(struct gspca_dev *gspca_dev)
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)
{
Expand All @@ -320,8 +335,6 @@ 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);
Expand Down Expand Up @@ -394,6 +407,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
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) {
Expand Down Expand Up @@ -431,13 +445,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
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)
Expand Down Expand Up @@ -473,13 +480,20 @@ static void sd_close(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 ||
Expand Down Expand Up @@ -523,12 +537,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,

/* 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);
}
}

Expand Down Expand Up @@ -677,12 +692,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
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;
}

Expand All @@ -706,6 +717,7 @@ static struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};

/* -- module initialisation -- */
Expand Down
Loading

0 comments on commit cebf3b6

Please sign in to comment.