diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2008-08-03 06:52:53 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-08-06 05:57:25 -0400 |
commit | cebf3b67f7f80fd69bd1ff5787fee69ab8fd3c2a (patch) | |
tree | 606952be0566fa22515d142978d51d1a14be95e7 /drivers/media/video/gspca/pac7311.c | |
parent | 594f5b8b3cce6d3137ebf260b7386520b2534385 (diff) |
V4L/DVB (8604): gspca: Fix of "scheduling while atomic" crash.
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>
Diffstat (limited to 'drivers/media/video/gspca/pac7311.c')
-rw-r--r-- | drivers/media/video/gspca/pac7311.c | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index ea3d7021f401..815bea6edc44 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c | |||
@@ -31,7 +31,9 @@ MODULE_LICENSE("GPL"); | |||
31 | struct sd { | 31 | struct sd { |
32 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 32 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
33 | 33 | ||
34 | int avg_lum; | 34 | int lum_sum; |
35 | atomic_t avg_lum; | ||
36 | atomic_t do_gain; | ||
35 | 37 | ||
36 | unsigned char brightness; | 38 | unsigned char brightness; |
37 | unsigned char contrast; | 39 | unsigned char contrast; |
@@ -271,6 +273,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
271 | sd->contrast = CONTRAST_DEF; | 273 | sd->contrast = CONTRAST_DEF; |
272 | sd->colors = COLOR_DEF; | 274 | sd->colors = COLOR_DEF; |
273 | sd->autogain = AUTOGAIN_DEF; | 275 | sd->autogain = AUTOGAIN_DEF; |
276 | sd->ag_cnt = -1; | ||
274 | return 0; | 277 | return 0; |
275 | } | 278 | } |
276 | 279 | ||
@@ -311,6 +314,18 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
311 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); | 314 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); |
312 | } | 315 | } |
313 | 316 | ||
317 | static void setautogain(struct gspca_dev *gspca_dev) | ||
318 | { | ||
319 | struct sd *sd = (struct sd *) gspca_dev; | ||
320 | |||
321 | if (sd->autogain) { | ||
322 | sd->lum_sum = 0; | ||
323 | sd->ag_cnt = AG_CNT_START; | ||
324 | } else { | ||
325 | sd->ag_cnt = -1; | ||
326 | } | ||
327 | } | ||
328 | |||
314 | /* this function is called at open time */ | 329 | /* this function is called at open time */ |
315 | static int sd_open(struct gspca_dev *gspca_dev) | 330 | static int sd_open(struct gspca_dev *gspca_dev) |
316 | { | 331 | { |
@@ -320,8 +335,6 @@ static int sd_open(struct gspca_dev *gspca_dev) | |||
320 | 335 | ||
321 | static void sd_start(struct gspca_dev *gspca_dev) | 336 | static void sd_start(struct gspca_dev *gspca_dev) |
322 | { | 337 | { |
323 | struct sd *sd = (struct sd *) gspca_dev; | ||
324 | |||
325 | reg_w(gspca_dev, 0xff, 0x01); | 338 | reg_w(gspca_dev, 0xff, 0x01); |
326 | reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); | 339 | reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); |
327 | reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); | 340 | reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); |
@@ -394,6 +407,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
394 | setcontrast(gspca_dev); | 407 | setcontrast(gspca_dev); |
395 | setbrightness(gspca_dev); | 408 | setbrightness(gspca_dev); |
396 | setcolors(gspca_dev); | 409 | setcolors(gspca_dev); |
410 | setautogain(gspca_dev); | ||
397 | 411 | ||
398 | /* set correct resolution */ | 412 | /* set correct resolution */ |
399 | switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { | 413 | switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { |
@@ -431,13 +445,6 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
431 | reg_w(gspca_dev, 0xff, 0x01); | 445 | reg_w(gspca_dev, 0xff, 0x01); |
432 | reg_w(gspca_dev, 0x78, 0x04); | 446 | reg_w(gspca_dev, 0x78, 0x04); |
433 | reg_w(gspca_dev, 0x78, 0x05); | 447 | reg_w(gspca_dev, 0x78, 0x05); |
434 | |||
435 | if (sd->autogain) { | ||
436 | sd->ag_cnt = AG_CNT_START; | ||
437 | sd->avg_lum = 0; | ||
438 | } else { | ||
439 | sd->ag_cnt = -1; | ||
440 | } | ||
441 | } | 448 | } |
442 | 449 | ||
443 | static void sd_stopN(struct gspca_dev *gspca_dev) | 450 | static void sd_stopN(struct gspca_dev *gspca_dev) |
@@ -473,13 +480,20 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
473 | reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ | 480 | reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ |
474 | } | 481 | } |
475 | 482 | ||
476 | static void setautogain(struct gspca_dev *gspca_dev, int luma) | 483 | static void do_autogain(struct gspca_dev *gspca_dev) |
477 | { | 484 | { |
485 | struct sd *sd = (struct sd *) gspca_dev; | ||
486 | int luma; | ||
478 | int luma_mean = 128; | 487 | int luma_mean = 128; |
479 | int luma_delta = 20; | 488 | int luma_delta = 20; |
480 | __u8 spring = 5; | 489 | __u8 spring = 5; |
481 | int Gbright; | 490 | int Gbright; |
482 | 491 | ||
492 | if (!atomic_read(&sd->do_gain)) | ||
493 | return; | ||
494 | atomic_set(&sd->do_gain, 0); | ||
495 | |||
496 | luma = atomic_read(&sd->avg_lum); | ||
483 | Gbright = reg_r(gspca_dev, 0x02); | 497 | Gbright = reg_r(gspca_dev, 0x02); |
484 | PDEBUG(D_FRAM, "luma mean %d", luma); | 498 | PDEBUG(D_FRAM, "luma mean %d", luma); |
485 | if (luma < luma_mean - luma_delta || | 499 | if (luma < luma_mean - luma_delta || |
@@ -523,12 +537,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
523 | 537 | ||
524 | /* start of frame */ | 538 | /* start of frame */ |
525 | if (sd->ag_cnt >= 0 && p > 28) { | 539 | if (sd->ag_cnt >= 0 && p > 28) { |
526 | sd->avg_lum += data[p - 23]; | 540 | sd->lum_sum += data[p - 23]; |
527 | if (--sd->ag_cnt < 0) { | 541 | if (--sd->ag_cnt < 0) { |
528 | sd->ag_cnt = AG_CNT_START; | 542 | sd->ag_cnt = AG_CNT_START; |
529 | setautogain(gspca_dev, | 543 | atomic_set(&sd->avg_lum, |
530 | sd->avg_lum / AG_CNT_START); | 544 | sd->lum_sum / AG_CNT_START); |
531 | sd->avg_lum = 0; | 545 | sd->lum_sum = 0; |
546 | atomic_set(&sd->do_gain, 1); | ||
532 | } | 547 | } |
533 | } | 548 | } |
534 | 549 | ||
@@ -677,12 +692,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
677 | struct sd *sd = (struct sd *) gspca_dev; | 692 | struct sd *sd = (struct sd *) gspca_dev; |
678 | 693 | ||
679 | sd->autogain = val; | 694 | sd->autogain = val; |
680 | if (val) { | 695 | if (gspca_dev->streaming) |
681 | sd->ag_cnt = AG_CNT_START; | 696 | setautogain(gspca_dev); |
682 | sd->avg_lum = 0; | ||
683 | } else { | ||
684 | sd->ag_cnt = -1; | ||
685 | } | ||
686 | return 0; | 697 | return 0; |
687 | } | 698 | } |
688 | 699 | ||
@@ -706,6 +717,7 @@ static struct sd_desc sd_desc = { | |||
706 | .stop0 = sd_stop0, | 717 | .stop0 = sd_stop0, |
707 | .close = sd_close, | 718 | .close = sd_close, |
708 | .pkt_scan = sd_pkt_scan, | 719 | .pkt_scan = sd_pkt_scan, |
720 | .dq_callback = do_autogain, | ||
709 | }; | 721 | }; |
710 | 722 | ||
711 | /* -- module initialisation -- */ | 723 | /* -- module initialisation -- */ |