diff options
| -rw-r--r-- | drivers/media/video/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/media/video/gspca/ov519.c | 68 | ||||
| -rw-r--r-- | drivers/media/video/gspca/w996Xcf.c | 143 |
3 files changed, 146 insertions, 71 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c69f858c9278..7ecae636e6ad 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
| @@ -956,7 +956,8 @@ config VIDEO_OVCAMCHIP | |||
| 956 | ---help--- | 956 | ---help--- |
| 957 | This driver is DEPRECATED please use the gspca ov519 module | 957 | This driver is DEPRECATED please use the gspca ov519 module |
| 958 | instead. Note that for the ov511 / ov518 support of the gspca module | 958 | instead. Note that for the ov511 / ov518 support of the gspca module |
| 959 | you need atleast version 0.6.0 of libv4l. | 959 | you need atleast version 0.6.0 of libv4l and for the w9968cf |
| 960 | atleast version 0.6.3 of libv4l. | ||
| 960 | 961 | ||
| 961 | Support for the OmniVision OV6xxx and OV7xxx series of camera chips. | 962 | Support for the OmniVision OV6xxx and OV7xxx series of camera chips. |
| 962 | This driver is intended to be used with the ov511 and w9968cf USB | 963 | This driver is intended to be used with the ov511 and w9968cf USB |
| @@ -970,7 +971,8 @@ config USB_W9968CF | |||
| 970 | depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP | 971 | depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP |
| 971 | ---help--- | 972 | ---help--- |
| 972 | This driver is DEPRECATED please use the gspca ov519 module | 973 | This driver is DEPRECATED please use the gspca ov519 module |
| 973 | instead. | 974 | instead. Note that for the w9968cf support of the gspca module |
| 975 | you need atleast version 0.6.3 of libv4l. | ||
| 974 | 976 | ||
| 975 | Say Y here if you want support for cameras based on OV681 or | 977 | Say Y here if you want support for cameras based on OV681 or |
| 976 | Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. | 978 | Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. |
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index ef88e244df17..a63cb75aa7f1 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c | |||
| @@ -80,6 +80,10 @@ struct sd { | |||
| 80 | __u8 vflip; | 80 | __u8 vflip; |
| 81 | __u8 autobrightness; | 81 | __u8 autobrightness; |
| 82 | __u8 freq; | 82 | __u8 freq; |
| 83 | __u8 quality; | ||
| 84 | #define QUALITY_MIN 50 | ||
| 85 | #define QUALITY_MAX 70 | ||
| 86 | #define QUALITY_DEF 50 | ||
| 83 | 87 | ||
| 84 | __u8 stopped; /* Streaming is temporarily paused */ | 88 | __u8 stopped; /* Streaming is temporarily paused */ |
| 85 | 89 | ||
| @@ -104,6 +108,8 @@ struct sd { | |||
| 104 | int sensor_width; | 108 | int sensor_width; |
| 105 | int sensor_height; | 109 | int sensor_height; |
| 106 | int sensor_reg_cache[256]; | 110 | int sensor_reg_cache[256]; |
| 111 | |||
| 112 | u8 *jpeg_hdr; | ||
| 107 | }; | 113 | }; |
| 108 | 114 | ||
| 109 | /* Note this is a bit of a hack, but the w9968cf driver needs the code for all | 115 | /* Note this is a bit of a hack, but the w9968cf driver needs the code for all |
| @@ -2303,8 +2309,6 @@ static int i2c_w_mask(struct sd *sd, | |||
| 2303 | * registers while the camera is streaming */ | 2309 | * registers while the camera is streaming */ |
| 2304 | static inline int ov51x_stop(struct sd *sd) | 2310 | static inline int ov51x_stop(struct sd *sd) |
| 2305 | { | 2311 | { |
| 2306 | int ret; | ||
| 2307 | |||
| 2308 | PDEBUG(D_STREAM, "stopping"); | 2312 | PDEBUG(D_STREAM, "stopping"); |
| 2309 | sd->stopped = 1; | 2313 | sd->stopped = 1; |
| 2310 | switch (sd->bridge) { | 2314 | switch (sd->bridge) { |
| @@ -2319,10 +2323,7 @@ static inline int ov51x_stop(struct sd *sd) | |||
| 2319 | case BRIDGE_OVFX2: | 2323 | case BRIDGE_OVFX2: |
| 2320 | return reg_w_mask(sd, 0x0f, 0x00, 0x02); | 2324 | return reg_w_mask(sd, 0x0f, 0x00, 0x02); |
| 2321 | case BRIDGE_W9968CF: | 2325 | case BRIDGE_W9968CF: |
| 2322 | ret = reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */ | 2326 | return reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */ |
| 2323 | ret += reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */ | ||
| 2324 | ret += reg_w(sd, 0x16, 0x0000); /* stop video capture */ | ||
| 2325 | return ret; | ||
| 2326 | } | 2327 | } |
| 2327 | 2328 | ||
| 2328 | return 0; | 2329 | return 0; |
| @@ -3088,8 +3089,8 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
| 3088 | case BRIDGE_W9968CF: | 3089 | case BRIDGE_W9968CF: |
| 3089 | cam->cam_mode = w9968cf_vga_mode; | 3090 | cam->cam_mode = w9968cf_vga_mode; |
| 3090 | cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); | 3091 | cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); |
| 3091 | /* if (sd->sif) | 3092 | if (sd->sif) |
| 3092 | cam->nmodes--; */ | 3093 | cam->nmodes--; |
| 3093 | 3094 | ||
| 3094 | /* w9968cf needs initialisation once the sensor is known */ | 3095 | /* w9968cf needs initialisation once the sensor is known */ |
| 3095 | if (w9968cf_init(sd) < 0) | 3096 | if (w9968cf_init(sd) < 0) |
| @@ -3113,6 +3114,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
| 3113 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | | 3114 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | |
| 3114 | (1 << OV7670_FREQ_IDX); | 3115 | (1 << OV7670_FREQ_IDX); |
| 3115 | } | 3116 | } |
| 3117 | sd->quality = QUALITY_DEF; | ||
| 3116 | if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670) | 3118 | if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670) |
| 3117 | gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX; | 3119 | gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX; |
| 3118 | /* OV8610 Frequency filter control should work but needs testing */ | 3120 | /* OV8610 Frequency filter control should work but needs testing */ |
| @@ -3909,6 +3911,14 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
| 3909 | ov51x_led_control(sd, 0); | 3911 | ov51x_led_control(sd, 0); |
| 3910 | } | 3912 | } |
| 3911 | 3913 | ||
| 3914 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
| 3915 | { | ||
| 3916 | struct sd *sd = (struct sd *) gspca_dev; | ||
| 3917 | |||
| 3918 | if (sd->bridge == BRIDGE_W9968CF) | ||
| 3919 | w9968cf_stop0(sd); | ||
| 3920 | } | ||
| 3921 | |||
| 3912 | static void ov511_pkt_scan(struct gspca_dev *gspca_dev, | 3922 | static void ov511_pkt_scan(struct gspca_dev *gspca_dev, |
| 3913 | struct gspca_frame *frame, /* target */ | 3923 | struct gspca_frame *frame, /* target */ |
| 3914 | __u8 *in, /* isoc packet */ | 3924 | __u8 *in, /* isoc packet */ |
| @@ -4421,6 +4431,45 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, | |||
| 4421 | return -EINVAL; | 4431 | return -EINVAL; |
| 4422 | } | 4432 | } |
| 4423 | 4433 | ||
| 4434 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, | ||
| 4435 | struct v4l2_jpegcompression *jcomp) | ||
| 4436 | { | ||
| 4437 | struct sd *sd = (struct sd *) gspca_dev; | ||
| 4438 | |||
| 4439 | if (sd->bridge != BRIDGE_W9968CF) | ||
| 4440 | return -EINVAL; | ||
| 4441 | |||
| 4442 | memset(jcomp, 0, sizeof *jcomp); | ||
| 4443 | jcomp->quality = sd->quality; | ||
| 4444 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT | | ||
| 4445 | V4L2_JPEG_MARKER_DRI; | ||
| 4446 | return 0; | ||
| 4447 | } | ||
| 4448 | |||
| 4449 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, | ||
| 4450 | struct v4l2_jpegcompression *jcomp) | ||
| 4451 | { | ||
| 4452 | struct sd *sd = (struct sd *) gspca_dev; | ||
| 4453 | |||
| 4454 | if (sd->bridge != BRIDGE_W9968CF) | ||
| 4455 | return -EINVAL; | ||
| 4456 | |||
| 4457 | if (gspca_dev->streaming) | ||
| 4458 | return -EBUSY; | ||
| 4459 | |||
| 4460 | if (jcomp->quality < QUALITY_MIN) | ||
| 4461 | sd->quality = QUALITY_MIN; | ||
| 4462 | else if (jcomp->quality > QUALITY_MAX) | ||
| 4463 | sd->quality = QUALITY_MAX; | ||
| 4464 | else | ||
| 4465 | sd->quality = jcomp->quality; | ||
| 4466 | |||
| 4467 | /* Return resulting jcomp params to app */ | ||
| 4468 | sd_get_jcomp(gspca_dev, jcomp); | ||
| 4469 | |||
| 4470 | return 0; | ||
| 4471 | } | ||
| 4472 | |||
| 4424 | /* sub-driver description */ | 4473 | /* sub-driver description */ |
| 4425 | static const struct sd_desc sd_desc = { | 4474 | static const struct sd_desc sd_desc = { |
| 4426 | .name = MODULE_NAME, | 4475 | .name = MODULE_NAME, |
| @@ -4430,8 +4479,11 @@ static const struct sd_desc sd_desc = { | |||
| 4430 | .init = sd_init, | 4479 | .init = sd_init, |
| 4431 | .start = sd_start, | 4480 | .start = sd_start, |
| 4432 | .stopN = sd_stopN, | 4481 | .stopN = sd_stopN, |
| 4482 | .stop0 = sd_stop0, | ||
| 4433 | .pkt_scan = sd_pkt_scan, | 4483 | .pkt_scan = sd_pkt_scan, |
| 4434 | .querymenu = sd_querymenu, | 4484 | .querymenu = sd_querymenu, |
| 4485 | .get_jcomp = sd_get_jcomp, | ||
| 4486 | .set_jcomp = sd_set_jcomp, | ||
| 4435 | }; | 4487 | }; |
| 4436 | 4488 | ||
| 4437 | /* -- module initialisation -- */ | 4489 | /* -- module initialisation -- */ |
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c index 3bdc6b405e27..7378f0495082 100644 --- a/drivers/media/video/gspca/w996Xcf.c +++ b/drivers/media/video/gspca/w996Xcf.c | |||
| @@ -31,57 +31,14 @@ | |||
| 31 | the sensor drivers to v4l2 sub drivers, and properly split of this | 31 | the sensor drivers to v4l2 sub drivers, and properly split of this |
| 32 | driver from ov519.c */ | 32 | driver from ov519.c */ |
| 33 | 33 | ||
| 34 | #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ | 34 | /* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */ |
| 35 | #define CONEX_CAM | ||
| 36 | #include "jpeg.h" | ||
| 35 | 37 | ||
| 36 | /* FIXME make this runtime configurable */ | 38 | #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ |
| 37 | /* Comment/uncomment this for high/low quality of compressed video */ | ||
| 38 | #define W9968CF_DEC_FAST_LOWQUALITY_VIDEO | ||
| 39 | |||
| 40 | #ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO | ||
| 41 | static const unsigned char Y_QUANTABLE[64] = { | ||
| 42 | 16, 11, 10, 16, 24, 40, 51, 61, | ||
| 43 | 12, 12, 14, 19, 26, 58, 60, 55, | ||
| 44 | 14, 13, 16, 24, 40, 57, 69, 56, | ||
| 45 | 14, 17, 22, 29, 51, 87, 80, 62, | ||
| 46 | 18, 22, 37, 56, 68, 109, 103, 77, | ||
| 47 | 24, 35, 55, 64, 81, 104, 113, 92, | ||
| 48 | 49, 64, 78, 87, 103, 121, 120, 101, | ||
| 49 | 72, 92, 95, 98, 112, 100, 103, 99 | ||
| 50 | }; | ||
| 51 | 39 | ||
| 52 | static const unsigned char UV_QUANTABLE[64] = { | 40 | #define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET) |
| 53 | 17, 18, 24, 47, 99, 99, 99, 99, | 41 | #define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET) |
| 54 | 18, 21, 26, 66, 99, 99, 99, 99, | ||
| 55 | 24, 26, 56, 99, 99, 99, 99, 99, | ||
| 56 | 47, 66, 99, 99, 99, 99, 99, 99, | ||
| 57 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
| 58 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
| 59 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
| 60 | 99, 99, 99, 99, 99, 99, 99, 99 | ||
| 61 | }; | ||
| 62 | #else | ||
| 63 | static const unsigned char Y_QUANTABLE[64] = { | ||
| 64 | 8, 5, 5, 8, 12, 20, 25, 30, | ||
| 65 | 6, 6, 7, 9, 13, 29, 30, 27, | ||
| 66 | 7, 6, 8, 12, 20, 28, 34, 28, | ||
| 67 | 7, 8, 11, 14, 25, 43, 40, 31, | ||
| 68 | 9, 11, 18, 28, 34, 54, 51, 38, | ||
| 69 | 12, 17, 27, 32, 40, 52, 56, 46, | ||
| 70 | 24, 32, 39, 43, 51, 60, 60, 50, | ||
| 71 | 36, 46, 47, 49, 56, 50, 51, 49 | ||
| 72 | }; | ||
| 73 | |||
| 74 | static const unsigned char UV_QUANTABLE[64] = { | ||
| 75 | 8, 9, 12, 23, 49, 49, 49, 49, | ||
| 76 | 9, 10, 13, 33, 49, 49, 49, 49, | ||
| 77 | 12, 13, 28, 49, 49, 49, 49, 49, | ||
| 78 | 23, 33, 49, 49, 49, 49, 49, 49, | ||
| 79 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
| 80 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
| 81 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
| 82 | 49, 49, 49, 49, 49, 49, 49, 49 | ||
| 83 | }; | ||
| 84 | #endif | ||
| 85 | 42 | ||
| 86 | static const struct v4l2_pix_format w9968cf_vga_mode[] = { | 43 | static const struct v4l2_pix_format w9968cf_vga_mode[] = { |
| 87 | {160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, | 44 | {160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, |
| @@ -92,18 +49,18 @@ static const struct v4l2_pix_format w9968cf_vga_mode[] = { | |||
| 92 | .bytesperline = 176 * 2, | 49 | .bytesperline = 176 * 2, |
| 93 | .sizeimage = 176 * 144 * 2, | 50 | .sizeimage = 176 * 144 * 2, |
| 94 | .colorspace = V4L2_COLORSPACE_JPEG}, | 51 | .colorspace = V4L2_COLORSPACE_JPEG}, |
| 95 | {320, 240, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, | 52 | {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
| 96 | .bytesperline = 320 * 2, | 53 | .bytesperline = 320 * 2, |
| 97 | .sizeimage = 320 * 240 * 2, | 54 | .sizeimage = 320 * 240 * 2, |
| 98 | .colorspace = V4L2_COLORSPACE_JPEG}, | 55 | .colorspace = V4L2_COLORSPACE_JPEG}, |
| 99 | {352, 288, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, | 56 | {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
| 100 | .bytesperline = 352 * 2, | 57 | .bytesperline = 352 * 2, |
| 101 | .sizeimage = 352 * 288 * 2, | 58 | .sizeimage = 352 * 288 * 2, |
| 102 | .colorspace = V4L2_COLORSPACE_JPEG}, | 59 | .colorspace = V4L2_COLORSPACE_JPEG}, |
| 103 | /* {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, | 60 | {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
| 104 | .bytesperline = 640 * 2, | 61 | .bytesperline = 640 * 2, |
| 105 | .sizeimage = 640 * 480 * 2, | 62 | .sizeimage = 640 * 480 * 2, |
| 106 | .colorspace = V4L2_COLORSPACE_JPEG}, */ | 63 | .colorspace = V4L2_COLORSPACE_JPEG}, |
| 107 | }; | 64 | }; |
| 108 | 65 | ||
| 109 | static int reg_w(struct sd *sd, __u16 index, __u16 value); | 66 | static int reg_w(struct sd *sd, __u16 index, __u16 value); |
| @@ -534,17 +491,35 @@ static int w9968cf_mode_init_regs(struct sd *sd) | |||
| 534 | ret += reg_w(sd, 0x31, sd->gspca_dev.height); | 491 | ret += reg_w(sd, 0x31, sd->gspca_dev.height); |
| 535 | 492 | ||
| 536 | /* Y & UV frame buffer strides (in WORD) */ | 493 | /* Y & UV frame buffer strides (in WORD) */ |
| 494 | if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == | ||
| 495 | V4L2_PIX_FMT_JPEG) { | ||
| 496 | ret += reg_w(sd, 0x2c, sd->gspca_dev.width/2); | ||
| 497 | ret += reg_w(sd, 0x2d, sd->gspca_dev.width/4); | ||
| 498 | } else | ||
| 537 | ret += reg_w(sd, 0x2c, sd->gspca_dev.width); | 499 | ret += reg_w(sd, 0x2c, sd->gspca_dev.width); |
| 538 | 500 | ||
| 539 | ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */ | 501 | ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */ |
| 540 | ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */ | 502 | ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */ |
| 541 | 503 | ||
| 542 | /* Transfer size */ | 504 | /* Transfer size in WORDS (for UYVY format only) */ |
| 543 | /* FIXME JPEG * 4 ?? */ | ||
| 544 | val = sd->gspca_dev.width * sd->gspca_dev.height; | 505 | val = sd->gspca_dev.width * sd->gspca_dev.height; |
| 545 | ret += reg_w(sd, 0x3d, val & 0xffff); /* low bits */ | 506 | ret += reg_w(sd, 0x3d, val & 0xffff); /* low bits */ |
| 546 | ret += reg_w(sd, 0x3e, val >> 16); /* high bits */ | 507 | ret += reg_w(sd, 0x3e, val >> 16); /* high bits */ |
| 547 | 508 | ||
| 509 | if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == | ||
| 510 | V4L2_PIX_FMT_JPEG) { | ||
| 511 | /* We may get called multiple times (usb isoc bw negotiat.) */ | ||
| 512 | if (!sd->jpeg_hdr) | ||
| 513 | sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); | ||
| 514 | if (!sd->jpeg_hdr) | ||
| 515 | return -ENOMEM; | ||
| 516 | |||
| 517 | jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, | ||
| 518 | sd->gspca_dev.width, 0x22); /* JPEG 420 */ | ||
| 519 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
| 520 | ret += w9968cf_upload_quantizationtables(sd); | ||
| 521 | } | ||
| 522 | |||
| 548 | /* Video Capture Control Register */ | 523 | /* Video Capture Control Register */ |
| 549 | if (sd->sensor == SEN_OV7620) { | 524 | if (sd->sensor == SEN_OV7620) { |
| 550 | /* Seems to work around a bug in the image sensor */ | 525 | /* Seems to work around a bug in the image sensor */ |
| @@ -557,6 +532,15 @@ static int w9968cf_mode_init_regs(struct sd *sd) | |||
| 557 | 532 | ||
| 558 | val = (vs_polarity << 12) | (hs_polarity << 11); | 533 | val = (vs_polarity << 12) | (hs_polarity << 11); |
| 559 | 534 | ||
| 535 | /* NOTE: We may not have enough memory to do double buffering while | ||
| 536 | doing compression (amount of memory differs per model cam). | ||
| 537 | So we use the second image buffer also as jpeg stream buffer | ||
| 538 | (see w9968cf_init), and disable double buffering. */ | ||
| 539 | if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == | ||
| 540 | V4L2_PIX_FMT_JPEG) { | ||
| 541 | /* val |= 0x0002; YUV422P */ | ||
| 542 | val |= 0x0003; /* YUV420P */ | ||
| 543 | } else | ||
| 560 | val |= 0x0080; /* Enable HW double buffering */ | 544 | val |= 0x0080; /* Enable HW double buffering */ |
| 561 | 545 | ||
| 562 | /* val |= 0x0020; enable clamping */ | 546 | /* val |= 0x0020; enable clamping */ |
| @@ -572,18 +556,55 @@ static int w9968cf_mode_init_regs(struct sd *sd) | |||
| 572 | return ret; | 556 | return ret; |
| 573 | } | 557 | } |
| 574 | 558 | ||
| 559 | static void w9968cf_stop0(struct sd *sd) | ||
| 560 | { | ||
| 561 | if (sd->gspca_dev.present) { | ||
| 562 | reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */ | ||
| 563 | reg_w(sd, 0x16, 0x0000); /* stop video capture */ | ||
| 564 | } | ||
| 565 | |||
| 566 | kfree(sd->jpeg_hdr); | ||
| 567 | sd->jpeg_hdr = NULL; | ||
| 568 | } | ||
| 569 | |||
| 570 | /* The w9968cf docs say that a 0 sized packet means EOF (and also SOF | ||
| 571 | for the next frame). This seems to simply not be true when operating | ||
| 572 | in JPEG mode, in this case there may be empty packets within the | ||
| 573 | frame. So in JPEG mode use the JPEG SOI marker to detect SOF. | ||
| 574 | |||
| 575 | Note to make things even more interesting the w9968cf sends *PLANAR* jpeg, | ||
| 576 | to be precise it sends: SOI, SOF, DRI, SOS, Y-data, SOS, U-data, SOS, | ||
| 577 | V-data, EOI. */ | ||
| 575 | static void w9968cf_pkt_scan(struct gspca_dev *gspca_dev, | 578 | static void w9968cf_pkt_scan(struct gspca_dev *gspca_dev, |
| 576 | struct gspca_frame *frame, /* target */ | 579 | struct gspca_frame *frame, /* target */ |
| 577 | __u8 *data, /* isoc packet */ | 580 | __u8 *data, /* isoc packet */ |
| 578 | int len) /* iso packet length */ | 581 | int len) /* iso packet length */ |
| 579 | { | 582 | { |
| 580 | /* An empty packet signals EOF */ | 583 | struct sd *sd = (struct sd *) gspca_dev; |
| 581 | if (gspca_dev->empty_packet) { | 584 | |
| 582 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, | 585 | if (w9968cf_vga_mode[gspca_dev->curr_mode].pixelformat == |
| 586 | V4L2_PIX_FMT_JPEG) { | ||
| 587 | if (len >= 2 && | ||
| 588 | data[0] == 0xff && | ||
| 589 | data[1] == 0xd8) { | ||
| 590 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, | ||
| 583 | NULL, 0); | 591 | NULL, 0); |
| 584 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, | 592 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, |
| 585 | NULL, 0); | 593 | sd->jpeg_hdr, JPEG_HDR_SZ); |
| 586 | gspca_dev->empty_packet = 0; | 594 | /* Strip the ff d8, our own header (which adds |
| 595 | huffman and quantization tables) already has this */ | ||
| 596 | len -= 2; | ||
| 597 | data += 2; | ||
| 598 | } | ||
| 599 | } else { | ||
| 600 | /* In UYVY mode an empty packet signals EOF */ | ||
| 601 | if (gspca_dev->empty_packet) { | ||
| 602 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, | ||
| 603 | NULL, 0); | ||
| 604 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, | ||
| 605 | NULL, 0); | ||
| 606 | gspca_dev->empty_packet = 0; | ||
| 607 | } | ||
| 587 | } | 608 | } |
| 588 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); | 609 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); |
| 589 | } | 610 | } |
