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/spca561.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/spca561.c')
-rw-r--r-- | drivers/media/video/gspca/spca561.c | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index a26174508cb9..1073ac3d2ec6 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c | |||
@@ -644,6 +644,18 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
644 | } | 644 | } |
645 | } | 645 | } |
646 | 646 | ||
647 | static void setautogain(struct gspca_dev *gspca_dev) | ||
648 | { | ||
649 | struct sd *sd = (struct sd *) gspca_dev; | ||
650 | |||
651 | if (sd->chip_revision == Rev072A) { | ||
652 | if (sd->autogain) | ||
653 | sd->ag_cnt = AG_CNT_START; | ||
654 | else | ||
655 | sd->ag_cnt = -1; | ||
656 | } | ||
657 | } | ||
658 | |||
647 | static void sd_start(struct gspca_dev *gspca_dev) | 659 | static void sd_start(struct gspca_dev *gspca_dev) |
648 | { | 660 | { |
649 | struct sd *sd = (struct sd *) gspca_dev; | 661 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -671,6 +683,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
671 | reg_w_val(dev, 0x8500, mode); /* mode */ | 683 | reg_w_val(dev, 0x8500, mode); /* mode */ |
672 | reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ | 684 | reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ |
673 | reg_w_val(dev, 0x8112, 0x10 | 0x20); | 685 | reg_w_val(dev, 0x8112, 0x10 | 0x20); |
686 | setautogain(gspca_dev); | ||
674 | break; | 687 | break; |
675 | default: | 688 | default: |
676 | /* case Rev012A: */ | 689 | /* case Rev012A: */ |
@@ -720,18 +733,24 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
720 | reg_w_val(gspca_dev->dev, 0x8114, 0); | 733 | reg_w_val(gspca_dev->dev, 0x8114, 0); |
721 | } | 734 | } |
722 | 735 | ||
723 | static void setautogain(struct gspca_dev *gspca_dev) | 736 | static void do_autogain(struct gspca_dev *gspca_dev) |
724 | { | 737 | { |
725 | struct sd *sd = (struct sd *) gspca_dev; | 738 | struct sd *sd = (struct sd *) gspca_dev; |
726 | int expotimes = 0; | 739 | int expotimes; |
727 | int pixelclk = 0; | 740 | int pixelclk; |
728 | int gainG = 0; | 741 | int gainG; |
729 | __u8 R, Gr, Gb, B; | 742 | __u8 R, Gr, Gb, B; |
730 | int y; | 743 | int y; |
731 | __u8 luma_mean = 110; | 744 | __u8 luma_mean = 110; |
732 | __u8 luma_delta = 20; | 745 | __u8 luma_delta = 20; |
733 | __u8 spring = 4; | 746 | __u8 spring = 4; |
734 | 747 | ||
748 | if (sd->ag_cnt < 0) | ||
749 | return; | ||
750 | if (--sd->ag_cnt >= 0) | ||
751 | return; | ||
752 | sd->ag_cnt = AG_CNT_START; | ||
753 | |||
735 | switch (sd->chip_revision) { | 754 | switch (sd->chip_revision) { |
736 | case Rev072A: | 755 | case Rev072A: |
737 | reg_r(gspca_dev, 0x8621, 1); | 756 | reg_r(gspca_dev, 0x8621, 1); |
@@ -795,18 +814,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
795 | __u8 *data, /* isoc packet */ | 814 | __u8 *data, /* isoc packet */ |
796 | int len) /* iso packet length */ | 815 | int len) /* iso packet length */ |
797 | { | 816 | { |
798 | struct sd *sd = (struct sd *) gspca_dev; | ||
799 | |||
800 | switch (data[0]) { | 817 | switch (data[0]) { |
801 | case 0: /* start of frame */ | 818 | case 0: /* start of frame */ |
802 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, | 819 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, |
803 | data, 0); | 820 | data, 0); |
804 | if (sd->ag_cnt >= 0) { | ||
805 | if (--sd->ag_cnt < 0) { | ||
806 | sd->ag_cnt = AG_CNT_START; | ||
807 | setautogain(gspca_dev); | ||
808 | } | ||
809 | } | ||
810 | data += SPCA561_OFFSET_DATA; | 821 | data += SPCA561_OFFSET_DATA; |
811 | len -= SPCA561_OFFSET_DATA; | 822 | len -= SPCA561_OFFSET_DATA; |
812 | if (data[1] & 0x10) { | 823 | if (data[1] & 0x10) { |
@@ -944,10 +955,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
944 | struct sd *sd = (struct sd *) gspca_dev; | 955 | struct sd *sd = (struct sd *) gspca_dev; |
945 | 956 | ||
946 | sd->autogain = val; | 957 | sd->autogain = val; |
947 | if (val) | 958 | if (gspca_dev->streaming) |
948 | sd->ag_cnt = AG_CNT_START; | 959 | setautogain(gspca_dev); |
949 | else | ||
950 | sd->ag_cnt = -1; | ||
951 | return 0; | 960 | return 0; |
952 | } | 961 | } |
953 | 962 | ||
@@ -971,6 +980,7 @@ static const struct sd_desc sd_desc = { | |||
971 | .stop0 = sd_stop0, | 980 | .stop0 = sd_stop0, |
972 | .close = sd_close, | 981 | .close = sd_close, |
973 | .pkt_scan = sd_pkt_scan, | 982 | .pkt_scan = sd_pkt_scan, |
983 | .dq_callback = do_autogain, | ||
974 | }; | 984 | }; |
975 | 985 | ||
976 | /* -- module initialisation -- */ | 986 | /* -- module initialisation -- */ |