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/sonixj.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/sonixj.c')
-rw-r--r-- | drivers/media/video/gspca/sonixj.c | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index b60ff600a757..245a30ec5fb1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c | |||
@@ -32,7 +32,7 @@ MODULE_LICENSE("GPL"); | |||
32 | struct sd { | 32 | struct sd { |
33 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 33 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
34 | 34 | ||
35 | int avg_lum; | 35 | atomic_t avg_lum; |
36 | unsigned int exposure; | 36 | unsigned int exposure; |
37 | 37 | ||
38 | unsigned short brightness; | 38 | unsigned short brightness; |
@@ -781,6 +781,8 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
781 | sd->contrast = CONTRAST_DEF; | 781 | sd->contrast = CONTRAST_DEF; |
782 | sd->colors = COLOR_DEF; | 782 | sd->colors = COLOR_DEF; |
783 | sd->autogain = AUTOGAIN_DEF; | 783 | sd->autogain = AUTOGAIN_DEF; |
784 | sd->ag_cnt = -1; | ||
785 | |||
784 | return 0; | 786 | return 0; |
785 | } | 787 | } |
786 | 788 | ||
@@ -946,6 +948,22 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
946 | reg_w1(gspca_dev, 0x05, data); | 948 | reg_w1(gspca_dev, 0x05, data); |
947 | } | 949 | } |
948 | 950 | ||
951 | static void setautogain(struct gspca_dev *gspca_dev) | ||
952 | { | ||
953 | struct sd *sd = (struct sd *) gspca_dev; | ||
954 | |||
955 | switch (sd->sensor) { | ||
956 | case SENSOR_HV7131R: | ||
957 | case SENSOR_MO4000: | ||
958 | case SENSOR_MI0360: | ||
959 | if (sd->autogain) | ||
960 | sd->ag_cnt = AG_CNT_START; | ||
961 | else | ||
962 | sd->ag_cnt = -1; | ||
963 | break; | ||
964 | } | ||
965 | } | ||
966 | |||
949 | /* -- start the camera -- */ | 967 | /* -- start the camera -- */ |
950 | static void sd_start(struct gspca_dev *gspca_dev) | 968 | static void sd_start(struct gspca_dev *gspca_dev) |
951 | { | 969 | { |
@@ -1078,6 +1096,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
1078 | reg_w1(gspca_dev, 0x01, reg1); | 1096 | reg_w1(gspca_dev, 0x01, reg1); |
1079 | setbrightness(gspca_dev); | 1097 | setbrightness(gspca_dev); |
1080 | setcontrast(gspca_dev); | 1098 | setcontrast(gspca_dev); |
1099 | setautogain(gspca_dev); | ||
1081 | } | 1100 | } |
1082 | 1101 | ||
1083 | static void sd_stopN(struct gspca_dev *gspca_dev) | 1102 | static void sd_stopN(struct gspca_dev *gspca_dev) |
@@ -1124,16 +1143,23 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
1124 | { | 1143 | { |
1125 | } | 1144 | } |
1126 | 1145 | ||
1127 | static void setautogain(struct gspca_dev *gspca_dev) | 1146 | static void do_autogain(struct gspca_dev *gspca_dev) |
1128 | { | 1147 | { |
1129 | struct sd *sd = (struct sd *) gspca_dev; | 1148 | struct sd *sd = (struct sd *) gspca_dev; |
1130 | /* Thanks S., without your advice, autobright should not work :) */ | ||
1131 | int delta; | 1149 | int delta; |
1132 | int expotimes = 0; | 1150 | int expotimes; |
1133 | __u8 luma_mean = 130; | 1151 | __u8 luma_mean = 130; |
1134 | __u8 luma_delta = 20; | 1152 | __u8 luma_delta = 20; |
1135 | 1153 | ||
1136 | delta = sd->avg_lum; | 1154 | /* Thanks S., without your advice, autobright should not work :) */ |
1155 | if (sd->ag_cnt < 0) | ||
1156 | return; | ||
1157 | if (--sd->ag_cnt >= 0) | ||
1158 | return; | ||
1159 | sd->ag_cnt = AG_CNT_START; | ||
1160 | |||
1161 | delta = atomic_read(&sd->avg_lum); | ||
1162 | PDEBUG(D_FRAM, "mean lum %d", delta); | ||
1137 | if (delta < luma_mean - luma_delta || | 1163 | if (delta < luma_mean - luma_delta || |
1138 | delta > luma_mean + luma_delta) { | 1164 | delta > luma_mean + luma_delta) { |
1139 | switch (sd->sensor) { | 1165 | switch (sd->sensor) { |
@@ -1145,8 +1171,9 @@ static void setautogain(struct gspca_dev *gspca_dev) | |||
1145 | sd->exposure = setexposure(gspca_dev, | 1171 | sd->exposure = setexposure(gspca_dev, |
1146 | (unsigned int) (expotimes << 8)); | 1172 | (unsigned int) (expotimes << 8)); |
1147 | break; | 1173 | break; |
1148 | case SENSOR_MO4000: | 1174 | default: |
1149 | case SENSOR_MI0360: | 1175 | /* case SENSOR_MO4000: */ |
1176 | /* case SENSOR_MI0360: */ | ||
1150 | expotimes = sd->exposure; | 1177 | expotimes = sd->exposure; |
1151 | expotimes += (luma_mean - delta) >> 6; | 1178 | expotimes += (luma_mean - delta) >> 6; |
1152 | if (expotimes < 0) | 1179 | if (expotimes < 0) |
@@ -1159,6 +1186,8 @@ static void setautogain(struct gspca_dev *gspca_dev) | |||
1159 | } | 1186 | } |
1160 | } | 1187 | } |
1161 | 1188 | ||
1189 | /* scan the URB packets */ | ||
1190 | /* This function is run at interrupt level. */ | ||
1162 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 1191 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
1163 | struct gspca_frame *frame, /* target */ | 1192 | struct gspca_frame *frame, /* target */ |
1164 | __u8 *data, /* isoc packet */ | 1193 | __u8 *data, /* isoc packet */ |
@@ -1175,9 +1204,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1175 | frame, data, sof + 2); | 1204 | frame, data, sof + 2); |
1176 | if (sd->ag_cnt < 0) | 1205 | if (sd->ag_cnt < 0) |
1177 | return; | 1206 | return; |
1178 | if (--sd->ag_cnt >= 0) | ||
1179 | return; | ||
1180 | sd->ag_cnt = AG_CNT_START; | ||
1181 | /* w1 w2 w3 */ | 1207 | /* w1 w2 w3 */ |
1182 | /* w4 w5 w6 */ | 1208 | /* w4 w5 w6 */ |
1183 | /* w7 w8 */ | 1209 | /* w7 w8 */ |
@@ -1192,9 +1218,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1192 | /* w5 */ | 1218 | /* w5 */ |
1193 | avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; | 1219 | avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; |
1194 | avg_lum >>= 4; | 1220 | avg_lum >>= 4; |
1195 | sd->avg_lum = avg_lum; | 1221 | atomic_set(&sd->avg_lum, avg_lum); |
1196 | PDEBUG(D_PACK, "mean lum %d", avg_lum); | ||
1197 | setautogain(gspca_dev); | ||
1198 | return; | 1222 | return; |
1199 | } | 1223 | } |
1200 | if (gspca_dev->last_packet_type == LAST_PACKET) { | 1224 | if (gspca_dev->last_packet_type == LAST_PACKET) { |
@@ -1321,10 +1345,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
1321 | struct sd *sd = (struct sd *) gspca_dev; | 1345 | struct sd *sd = (struct sd *) gspca_dev; |
1322 | 1346 | ||
1323 | sd->autogain = val; | 1347 | sd->autogain = val; |
1324 | if (val) | 1348 | if (gspca_dev->streaming) |
1325 | sd->ag_cnt = AG_CNT_START; | 1349 | setautogain(gspca_dev); |
1326 | else | ||
1327 | sd->ag_cnt = -1; | ||
1328 | return 0; | 1350 | return 0; |
1329 | } | 1351 | } |
1330 | 1352 | ||
@@ -1348,6 +1370,7 @@ static const struct sd_desc sd_desc = { | |||
1348 | .stop0 = sd_stop0, | 1370 | .stop0 = sd_stop0, |
1349 | .close = sd_close, | 1371 | .close = sd_close, |
1350 | .pkt_scan = sd_pkt_scan, | 1372 | .pkt_scan = sd_pkt_scan, |
1373 | .dq_callback = do_autogain, | ||
1351 | }; | 1374 | }; |
1352 | 1375 | ||
1353 | /* -- module initialisation -- */ | 1376 | /* -- module initialisation -- */ |