diff options
-rw-r--r-- | drivers/media/video/gspca/sonixb.c | 160 |
1 files changed, 106 insertions, 54 deletions
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index bfbd8c17d28b..f47a82902fa3 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c | |||
@@ -56,6 +56,8 @@ struct sd { | |||
56 | int prev_avg_lum; | 56 | int prev_avg_lum; |
57 | int exp_too_low_cnt; | 57 | int exp_too_low_cnt; |
58 | int exp_too_high_cnt; | 58 | int exp_too_high_cnt; |
59 | int header_read; | ||
60 | u8 header[12]; /* Header without sof marker */ | ||
59 | 61 | ||
60 | unsigned short exposure; | 62 | unsigned short exposure; |
61 | unsigned char gain; | 63 | unsigned char gain; |
@@ -1177,13 +1179,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
1177 | sd_init(gspca_dev); | 1179 | sd_init(gspca_dev); |
1178 | } | 1180 | } |
1179 | 1181 | ||
1180 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 1182 | static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) |
1181 | u8 *data, /* isoc packet */ | ||
1182 | int len) /* iso packet length */ | ||
1183 | { | 1183 | { |
1184 | int i; | ||
1185 | struct sd *sd = (struct sd *) gspca_dev; | 1184 | struct sd *sd = (struct sd *) gspca_dev; |
1186 | struct cam *cam = &gspca_dev->cam; | 1185 | int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12; |
1187 | 1186 | ||
1188 | /* frames start with: | 1187 | /* frames start with: |
1189 | * ff ff 00 c4 c4 96 synchro | 1188 | * ff ff 00 c4 c4 96 synchro |
@@ -1194,58 +1193,84 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1194 | * ll mm brightness sum outside auto exposure | 1193 | * ll mm brightness sum outside auto exposure |
1195 | * (xx xx xx xx xx) audio values for snc103 | 1194 | * (xx xx xx xx xx) audio values for snc103 |
1196 | */ | 1195 | */ |
1197 | if (len > 6 && len < 24) { | 1196 | for (i = 0; i < len; i++) { |
1198 | for (i = 0; i < len - 6; i++) { | 1197 | switch (sd->header_read) { |
1199 | if (data[0 + i] == 0xff | 1198 | case 0: |
1200 | && data[1 + i] == 0xff | 1199 | if (data[i] == 0xff) |
1201 | && data[2 + i] == 0x00 | 1200 | sd->header_read++; |
1202 | && data[3 + i] == 0xc4 | 1201 | break; |
1203 | && data[4 + i] == 0xc4 | 1202 | case 1: |
1204 | && data[5 + i] == 0x96) { /* start of frame */ | 1203 | if (data[i] == 0xff) |
1205 | int lum = -1; | 1204 | sd->header_read++; |
1206 | int pkt_type = LAST_PACKET; | 1205 | else |
1207 | int fr_h_sz = (sd->bridge == BRIDGE_103) ? | 1206 | sd->header_read = 0; |
1208 | 18 : 12; | 1207 | break; |
1209 | 1208 | case 2: | |
1210 | if (len - i < fr_h_sz) { | 1209 | if (data[i] == 0x00) |
1211 | PDEBUG(D_STREAM, "packet too short to" | 1210 | sd->header_read++; |
1212 | " get avg brightness"); | 1211 | else if (data[i] != 0xff) |
1213 | } else if (sd->bridge == BRIDGE_103) { | 1212 | sd->header_read = 0; |
1214 | lum = data[i + 9] + | 1213 | break; |
1215 | (data[i + 10] << 8); | 1214 | case 3: |
1216 | } else { | 1215 | if (data[i] == 0xc4) |
1217 | lum = data[i + 8] + (data[i + 9] << 8); | 1216 | sd->header_read++; |
1218 | } | 1217 | else if (data[i] == 0xff) |
1219 | /* When exposure changes midway a frame we | 1218 | sd->header_read = 1; |
1220 | get a lum of 0 in this case drop 2 frames | 1219 | else |
1221 | as the frames directly after an exposure | 1220 | sd->header_read = 0; |
1222 | change have an unstable image. Sometimes lum | 1221 | break; |
1223 | *really* is 0 (cam used in low light with | 1222 | case 4: |
1224 | low exposure setting), so do not drop frames | 1223 | if (data[i] == 0xc4) |
1225 | if the previous lum was 0 too. */ | 1224 | sd->header_read++; |
1226 | if (lum == 0 && sd->prev_avg_lum != 0) { | 1225 | else if (data[i] == 0xff) |
1227 | lum = -1; | 1226 | sd->header_read = 1; |
1228 | sd->frames_to_drop = 2; | 1227 | else |
1229 | sd->prev_avg_lum = 0; | 1228 | sd->header_read = 0; |
1230 | } else | 1229 | break; |
1231 | sd->prev_avg_lum = lum; | 1230 | case 5: |
1232 | atomic_set(&sd->avg_lum, lum); | 1231 | if (data[i] == 0x96) |
1233 | 1232 | sd->header_read++; | |
1234 | if (sd->frames_to_drop) { | 1233 | else if (data[i] == 0xff) |
1235 | sd->frames_to_drop--; | 1234 | sd->header_read = 1; |
1236 | pkt_type = DISCARD_PACKET; | 1235 | else |
1237 | } | 1236 | sd->header_read = 0; |
1238 | 1237 | break; | |
1239 | gspca_frame_add(gspca_dev, pkt_type, | 1238 | default: |
1240 | NULL, 0); | 1239 | sd->header[sd->header_read - 6] = data[i]; |
1241 | data += i + fr_h_sz; | 1240 | sd->header_read++; |
1242 | len -= i + fr_h_sz; | 1241 | if (sd->header_read == header_size) { |
1243 | gspca_frame_add(gspca_dev, FIRST_PACKET, | 1242 | sd->header_read = 0; |
1244 | data, len); | 1243 | return data + i + 1; |
1245 | return; | ||
1246 | } | 1244 | } |
1247 | } | 1245 | } |
1248 | } | 1246 | } |
1247 | return NULL; | ||
1248 | } | ||
1249 | |||
1250 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
1251 | u8 *data, /* isoc packet */ | ||
1252 | int len) /* iso packet length */ | ||
1253 | { | ||
1254 | int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0; | ||
1255 | struct sd *sd = (struct sd *) gspca_dev; | ||
1256 | struct cam *cam = &gspca_dev->cam; | ||
1257 | u8 *sof; | ||
1258 | |||
1259 | sof = find_sof(gspca_dev, data, len); | ||
1260 | if (sof) { | ||
1261 | if (sd->bridge == BRIDGE_103) { | ||
1262 | fr_h_sz = 18; | ||
1263 | lum_offset = 3; | ||
1264 | } else { | ||
1265 | fr_h_sz = 12; | ||
1266 | lum_offset = 2; | ||
1267 | } | ||
1268 | |||
1269 | len_after_sof = len - (sof - data); | ||
1270 | len = (sof - data) - fr_h_sz; | ||
1271 | if (len < 0) | ||
1272 | len = 0; | ||
1273 | } | ||
1249 | 1274 | ||
1250 | if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { | 1275 | if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { |
1251 | /* In raw mode we sometimes get some garbage after the frame | 1276 | /* In raw mode we sometimes get some garbage after the frame |
@@ -1259,6 +1284,33 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1259 | } | 1284 | } |
1260 | 1285 | ||
1261 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); | 1286 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); |
1287 | |||
1288 | if (sof) { | ||
1289 | int lum = sd->header[lum_offset] + | ||
1290 | (sd->header[lum_offset + 1] << 8); | ||
1291 | |||
1292 | /* When exposure changes midway a frame we | ||
1293 | get a lum of 0 in this case drop 2 frames | ||
1294 | as the frames directly after an exposure | ||
1295 | change have an unstable image. Sometimes lum | ||
1296 | *really* is 0 (cam used in low light with | ||
1297 | low exposure setting), so do not drop frames | ||
1298 | if the previous lum was 0 too. */ | ||
1299 | if (lum == 0 && sd->prev_avg_lum != 0) { | ||
1300 | lum = -1; | ||
1301 | sd->frames_to_drop = 2; | ||
1302 | sd->prev_avg_lum = 0; | ||
1303 | } else | ||
1304 | sd->prev_avg_lum = lum; | ||
1305 | atomic_set(&sd->avg_lum, lum); | ||
1306 | |||
1307 | if (sd->frames_to_drop) | ||
1308 | sd->frames_to_drop--; | ||
1309 | else | ||
1310 | gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); | ||
1311 | |||
1312 | gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof); | ||
1313 | } | ||
1262 | } | 1314 | } |
1263 | 1315 | ||
1264 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | 1316 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) |