From 40b8d50ac98f8c8779aea7459f805e5a69fdb726 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:02:15 +0000 Subject: [PATCH] staging/easycap: Implement interlaced modes and reduced framerates Interlaced modes are requested by tvtime. Reduced framerates are preferred by some userspace programs, e.g. astronomy applications. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 16 +- drivers/staging/easycap/easycap_ioctl.c | 338 ++++++++++++++++++--- drivers/staging/easycap/easycap_main.c | 78 +++-- drivers/staging/easycap/easycap_settings.c | 268 +++++++++++++--- 4 files changed, 579 insertions(+), 121 deletions(-) diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 20e51ddec1e1..7c4cf7a338c4 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -200,7 +200,17 @@ #define NTSC_M_JP 5 #define PAL_60 7 #define PAL_M 9 -#define STANDARD_MANY 10 +#define PAL_BGHIN_SLOW 10 +#define PAL_Nc_SLOW 12 +#define SECAM_SLOW 14 +#define NTSC_N_SLOW 16 +#define NTSC_N_443_SLOW 18 +#define NTSC_M_SLOW 11 +#define NTSC_443_SLOW 13 +#define NTSC_M_JP_SLOW 15 +#define PAL_60_SLOW 17 +#define PAL_M_SLOW 19 +#define STANDARD_MANY 20 /*---------------------------------------------------------------------------*/ /* * ENUMS @@ -228,7 +238,6 @@ PIXELFORMAT_MANY enum { FIELD_NONE, FIELD_INTERLACED, -FIELD_ALTERNATE, INTERLACE_MANY }; #define SETTINGS_MANY (STANDARD_MANY * \ @@ -333,6 +342,8 @@ bool ntsc; int fps; int usec; int tolerate; +int skip; +int skipped; int merit[180]; struct timeval timeval0; @@ -399,7 +410,6 @@ int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */ */ /*---------------------------------------------------------------------------*/ __u32 pixelformat; -__u32 field; int width; int height; int bytesperpixel; diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 0ed37c23c7ec..3fe13851aba0 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -40,6 +40,7 @@ * peasycap->fps * peasycap->usec * peasycap->tolerate + * peasycap->skip */ /*---------------------------------------------------------------------------*/ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) @@ -60,10 +61,18 @@ if ((struct usb_device *)NULL == peasycap->pusb_device) { } peasycap_standard = &easycap_standard[0]; while (0xFFFF != peasycap_standard->mask) { - if (std_id & peasycap_standard->v4l2_standard.id) + if (std_id == peasycap_standard->v4l2_standard.id) break; peasycap_standard++; } +if (0xFFFF == peasycap_standard->mask) { + peasycap_standard = &easycap_standard[0]; + while (0xFFFF != peasycap_standard->mask) { + if (std_id & peasycap_standard->v4l2_standard.id) + break; + peasycap_standard++; + } +} if (0xFFFF == peasycap_standard->mask) { SAM("ERROR: 0x%08X=std_id: standard not found\n", \ (unsigned int)std_id); @@ -92,10 +101,12 @@ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \ peasycap_standard->v4l2_standard.frameperiod.numerator; switch (peasycap->fps) { +case 6: case 30: { peasycap->ntsc = true; break; } +case 5: case 25: { peasycap->ntsc = false; break; @@ -106,9 +117,15 @@ default: { } } JOM(8, "%i frames-per-second\n", peasycap->fps); -peasycap->usec = 1000000 / (2 * peasycap->fps); -peasycap->tolerate = 1000 * (25 / peasycap->fps); - +if (0x8000 & peasycap_standard->mask) { + peasycap->skip = 5; + peasycap->usec = 1000000 / (2 * (5 * peasycap->fps)); + peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps)); +} else { + peasycap->skip = 0; + peasycap->usec = 1000000 / (2 * peasycap->fps); + peasycap->tolerate = 1000 * (25 / peasycap->fps); +} if (peasycap->video_isoc_streaming) { resubmit = true; kill_video_urbs(peasycap); @@ -311,7 +328,6 @@ return 0; * peasycap->format_offset * peasycap->inputset[peasycap->input].format_offset * peasycap->pixelformat - * peasycap->field * peasycap->height * peasycap->width * peasycap->bytesperpixel @@ -333,7 +349,7 @@ struct easycap_format *peasycap_format, *peasycap_best_format; __u16 mask; struct usb_device *p; int miss, multiplier, best, k; -char bf[5], *pc; +char bf[5], fo[32], *pc; __u32 uc; bool resubmit; @@ -351,13 +367,62 @@ if ((struct usb_device *)NULL == p) { return -EFAULT; } pc = &bf[0]; -uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0; -mask = easycap_standard[peasycap->standard_offset].mask; +uc = pixelformat; +memcpy((void *)pc, (void *)(&uc), 4); +bf[4] = 0; +mask = 0xFF & easycap_standard[peasycap->standard_offset].mask; SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \ width, height, pc, pixelformat, field, mask); +switch (field) { +case V4L2_FIELD_ANY: { + strcpy(&fo[0], "V4L2_FIELD_ANY "); + break; +} +case V4L2_FIELD_NONE: { + strcpy(&fo[0], "V4L2_FIELD_NONE"); + break; +} +case V4L2_FIELD_TOP: { + strcpy(&fo[0], "V4L2_FIELD_TOP"); + break; +} +case V4L2_FIELD_BOTTOM: { + strcpy(&fo[0], "V4L2_FIELD_BOTTOM"); + break; +} +case V4L2_FIELD_INTERLACED: { + strcpy(&fo[0], "V4L2_FIELD_INTERLACED"); + break; +} +case V4L2_FIELD_SEQ_TB: { + strcpy(&fo[0], "V4L2_FIELD_SEQ_TB"); + break; +} +case V4L2_FIELD_SEQ_BT: { + strcpy(&fo[0], "V4L2_FIELD_SEQ_BT"); + break; +} +case V4L2_FIELD_ALTERNATE: { + strcpy(&fo[0], "V4L2_FIELD_ALTERNATE"); + break; +} +case V4L2_FIELD_INTERLACED_TB: { + strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB"); + break; +} +case V4L2_FIELD_INTERLACED_BT: { + strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT"); + break; +} +default: { + strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN "); + break; +} +} +SAM("sought: %s\n", &fo[0]); if (V4L2_FIELD_ANY == field) { - field = V4L2_FIELD_INTERLACED; - SAM("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n"); + field = V4L2_FIELD_NONE; + SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n"); } peasycap_best_format = (struct easycap_format *)NULL; peasycap_format = &easycap_format[0]; @@ -369,7 +434,7 @@ while (0 != peasycap_format->v4l2_format.fmt.pix.width) { peasycap_format->v4l2_format.fmt.pix.width, peasycap_format->v4l2_format.fmt.pix.height); - if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ + if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \ (peasycap_format->v4l2_format.fmt.pix.field == field) && \ (peasycap_format->v4l2_format.fmt.pix.pixelformat == \ pixelformat) && \ @@ -385,7 +450,7 @@ if (0 == peasycap_format->v4l2_format.fmt.pix.width) { width, height, mask); peasycap_format = &easycap_format[0]; best = -1; while (0 != peasycap_format->v4l2_format.fmt.pix.width) { - if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ + if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \ (peasycap_format->v4l2_format.fmt.pix\ .field == field) && \ (peasycap_format->v4l2_format.fmt.pix\ @@ -432,7 +497,6 @@ SAM("actioning: %ix%i %s\n", \ peasycap->height = peasycap_format->v4l2_format.fmt.pix.height; peasycap->width = peasycap_format->v4l2_format.fmt.pix.width; peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat; -peasycap->field = peasycap_format->v4l2_format.fmt.pix.field; peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]); @@ -451,11 +515,15 @@ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { -peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ; +peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ; if (0x0100 & peasycap_format->mask) peasycap->byteswaporder = true; else peasycap->byteswaporder = false; +if (0x0200 & peasycap_format->mask) + peasycap->skip = 5; +else + peasycap->skip = 0; if (0x0800 & peasycap_format->mask) peasycap->decimatepixel = true; else @@ -472,24 +540,6 @@ peasycap->videofieldamount = multiplier * peasycap->width * \ multiplier * peasycap->height; peasycap->frame_buffer_used = peasycap->bytesperpixel * \ peasycap->width * peasycap->height; - -if (true == peasycap->offerfields) { - SAM("WARNING: %i=peasycap->field is untested: " \ - "please report problems\n", peasycap->field); - - -/* - * FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT: - * - * peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2; - * - * SO DO NOT RISK IT YET. - * - */ - - - -} if (peasycap->video_isoc_streaming) { resubmit = true; kill_video_urbs(peasycap); @@ -1386,13 +1436,191 @@ case VIDIOC_ENUM_FMT: { break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* + * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE + * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUM_FRAMESIZES: { - JOM(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n"); - return -EINVAL; + __u32 index; + struct v4l2_frmsizeenum v4l2_frmsizeenum; + + JOM(8, "VIDIOC_ENUM_FRAMESIZES\n"); + + if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \ + sizeof(struct v4l2_frmsizeenum))) + return -EFAULT; + + index = v4l2_frmsizeenum.index; + + v4l2_frmsizeenum.type = (__u32) V4L2_FRMSIZE_TYPE_DISCRETE; + + if (true == peasycap->ntsc) { + switch (index) { + case 0: { + v4l2_frmsizeenum.discrete.width = 640; + v4l2_frmsizeenum.discrete.height = 480; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 1: { + v4l2_frmsizeenum.discrete.width = 320; + v4l2_frmsizeenum.discrete.height = 240; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 2: { + v4l2_frmsizeenum.discrete.width = 720; + v4l2_frmsizeenum.discrete.height = 480; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 3: { + v4l2_frmsizeenum.discrete.width = 360; + v4l2_frmsizeenum.discrete.height = 240; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + default: { + JOM(8, "%i=index: exhausts framesizes\n", index); + return -EINVAL; + } + } + } else { + switch (index) { + case 0: { + v4l2_frmsizeenum.discrete.width = 640; + v4l2_frmsizeenum.discrete.height = 480; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 1: { + v4l2_frmsizeenum.discrete.width = 320; + v4l2_frmsizeenum.discrete.height = 240; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 2: { + v4l2_frmsizeenum.discrete.width = 704; + v4l2_frmsizeenum.discrete.height = 576; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 3: { + v4l2_frmsizeenum.discrete.width = 720; + v4l2_frmsizeenum.discrete.height = 576; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 4: { + v4l2_frmsizeenum.discrete.width = 360; + v4l2_frmsizeenum.discrete.height = 288; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + default: { + JOM(8, "%i=index: exhausts framesizes\n", index); + return -EINVAL; + } + } + } + if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \ + sizeof(struct v4l2_frmsizeenum))) + return -EFAULT; + break; } +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* + * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE + * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUM_FRAMEINTERVALS: { - JOM(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n"); - return -EINVAL; + __u32 index; + int denominator; + struct v4l2_frmivalenum v4l2_frmivalenum; + + JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n"); + + if (peasycap->fps) + denominator = peasycap->fps; + else { + if (true == peasycap->ntsc) + denominator = 30; + else + denominator = 25; + } + + if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \ + sizeof(struct v4l2_frmivalenum))) + return -EFAULT; + + index = v4l2_frmivalenum.index; + + v4l2_frmivalenum.type = (__u32) V4L2_FRMIVAL_TYPE_DISCRETE; + + switch (index) { + case 0: { + v4l2_frmivalenum.discrete.numerator = 1; + v4l2_frmivalenum.discrete.denominator = denominator; + JOM(8, "%i=index: %i/%i\n", index, \ + (int)(v4l2_frmivalenum.discrete.numerator), \ + (int)(v4l2_frmivalenum.discrete.denominator)); + break; + } + case 1: { + v4l2_frmivalenum.discrete.numerator = 1; + v4l2_frmivalenum.discrete.denominator = denominator/5; + JOM(8, "%i=index: %i/%i\n", index, \ + (int)(v4l2_frmivalenum.discrete.numerator), \ + (int)(v4l2_frmivalenum.discrete.denominator)); + break; + } + default: { + JOM(8, "%i=index: exhausts frameintervals\n", index); + return -EINVAL; + } + } + if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \ + sizeof(struct v4l2_frmivalenum))) + return -EFAULT; + break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_FMT: { @@ -1603,6 +1831,10 @@ case VIDIOC_S_STD: { sizeof(v4l2_std_id))) return -EFAULT; + JOM(8, "User requests standard: 0x%08X%08X\n", \ + (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \ + (int)(std_id & ((v4l2_std_id)0xFFFFFFFF))); + rc = adjust_standard(peasycap, std_id); if (0 > rc) { JOM(8, "WARNING: adjust_standard() returned %i\n", rc); @@ -1675,7 +1907,7 @@ case VIDIOC_QUERYBUF: { v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \ peasycap->done[index] | \ peasycap->queued[index]; - v4l2_buffer.field = peasycap->field; + v4l2_buffer.field = V4L2_FIELD_NONE; v4l2_buffer.memory = V4L2_MEMORY_MMAP; v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE; v4l2_buffer.length = FRAME_BUFFER_SIZE; @@ -1762,6 +1994,24 @@ case VIDIOC_DQBUF: if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + if (true == peasycap->offerfields) { + /*-----------------------------------------------------------*/ + /* + * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST + * V4L2_FIELD_BOTTOM + */ + /*-----------------------------------------------------------*/ + if (V4L2_FIELD_TOP == v4l2_buffer.field) + JOM(8, "user wants V4L2_FIELD_TOP\n"); + else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field) + JOM(8, "user wants V4L2_FIELD_BOTTOM\n"); + else if (V4L2_FIELD_ANY == v4l2_buffer.field) + JOM(8, "user wants V4L2_FIELD_ANY\n"); + else + JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", \ + v4l2_buffer.field); + } + if (!peasycap->video_isoc_streaming) { JOM(16, "returning -EIO because video urbs not streaming\n"); return -EIO; @@ -1811,11 +2061,10 @@ case VIDIOC_DQBUF: v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2_buffer.bytesused = peasycap->frame_buffer_used; v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; - v4l2_buffer.field = peasycap->field; - if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field) - v4l2_buffer.field = \ - 0x000F & (peasycap->\ - frame_buffer[peasycap->frame_read][0].kount); + if (true == peasycap->offerfields) + v4l2_buffer.field = V4L2_FIELD_BOTTOM; + else + v4l2_buffer.field = V4L2_FIELD_NONE; do_gettimeofday(&timeval); timeval2 = timeval; @@ -1876,10 +2125,6 @@ case VIDIOC_DQBUF: sizeof(struct v4l2_buffer))) return -EFAULT; - JOM(8, "..... user is offered frame buffer %i\n", \ - peasycap->frame_read); - peasycap->frame_lock = 1; - input = peasycap->frame_buffer[peasycap->frame_read][0].input; if (0x08 & input) { JOM(8, "user is offered frame buffer %i, input %i\n", \ @@ -1956,7 +2201,6 @@ case VIDIOC_G_PARM: { v4l2_streamparm.parm.capture.capability = 0; v4l2_streamparm.parm.capture.capturemode = 0; v4l2_streamparm.parm.capture.timeperframe.numerator = 1; - v4l2_streamparm.parm.capture.timeperframe.denominator = 30; if (peasycap->fps) { v4l2_streamparm.parm.capture.timeperframe.\ diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index b522c6eb65f6..988feee7bcbe 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -471,7 +471,7 @@ if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -ENODEV; } -rc = usb_set_interface(peasycap->pusb_device, \ +rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \ peasycap->video_altsetting_off); if (0 != rc) { @@ -1103,7 +1103,7 @@ else int easycap_dqbuf(struct easycap *peasycap, int mode) { -int miss, rc; +int ifield, miss, rc; JOT(8, "\n"); @@ -1111,16 +1111,18 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +ifield = 0; +JOM(8, "%i=ifield\n", ifield); /*---------------------------------------------------------------------------*/ /* - * WAIT FOR FIELD 0 + * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM) */ /*---------------------------------------------------------------------------*/ miss = 0; while ((peasycap->field_read == peasycap->field_fill) || \ (0 != (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) || \ - (0 != (0x00FF & peasycap->field_buffer\ + (ifield != (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))) { if (mode) return -EAGAIN; @@ -1134,7 +1136,7 @@ while ((peasycap->field_read == peasycap->field_fill) || \ ((peasycap->field_read != peasycap->field_fill) && \ (0 == (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) && \ - (0 == (0x00FF & peasycap->field_buffer\ + (ifield == (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))))))) { SAM("aborted by signal\n"); return -EIO; @@ -1176,33 +1178,20 @@ JOM(8, "first awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); if (0 != rc) SAM("ERROR: field2frame() returned %i\n", rc); - -if (true == peasycap->offerfields) { - peasycap->frame_read = peasycap->frame_fill; - (peasycap->frame_fill)++; - if (peasycap->frame_buffer_many <= peasycap->frame_fill) - peasycap->frame_fill = 0; - - if (0x01 & easycap_standard[peasycap->standard_offset].mask) { - peasycap->frame_buffer[peasycap->frame_read][0].kount = \ - V4L2_FIELD_BOTTOM; - } else { - peasycap->frame_buffer[peasycap->frame_read][0].kount = \ - V4L2_FIELD_TOP; - } -JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); -JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); -} /*---------------------------------------------------------------------------*/ /* - * WAIT FOR FIELD 1 + * WAIT FOR THE OTHER FIELD */ /*---------------------------------------------------------------------------*/ +if (ifield) + ifield = 0; +else + ifield = 1; miss = 0; while ((peasycap->field_read == peasycap->field_fill) || \ (0 != (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) || \ - (0 == (0x00FF & peasycap->field_buffer\ + (ifield != (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))) { if (mode) return -EAGAIN; @@ -1215,8 +1204,9 @@ while ((peasycap->field_read == peasycap->field_fill) || \ ((peasycap->field_read != peasycap->field_fill) && \ (0 == (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) && \ - (0 != (0x00FF & peasycap->field_buffer\ - [peasycap->field_read][0].kount))))))) { + (ifield == (0x00FF & peasycap->field_buffer\ + [peasycap->field_read][0].\ + kount))))))) { SAM("aborted by signal\n"); return -EIO; } @@ -1257,7 +1247,18 @@ JOM(8, "second awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); if (0 != rc) SAM("ERROR: field2frame() returned %i\n", rc); - +/*---------------------------------------------------------------------------*/ +/* + * WASTE THIS FRAME +*/ +/*---------------------------------------------------------------------------*/ +if (0 != peasycap->skip) { + peasycap->skipped++; + if (peasycap->skip != peasycap->skipped) + return peasycap->skip - peasycap->skipped; + peasycap->skipped = 0; +} +/*---------------------------------------------------------------------------*/ peasycap->frame_read = peasycap->frame_fill; peasycap->queued[peasycap->frame_read] = 0; peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE; @@ -1289,8 +1290,7 @@ return 0; * odd==false IS TRANSFERRED TO THE FRAME BUFFER. * * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM - * CHOOSES THE OPTION V4L2_FIELD_ALTERNATE. NO USERSPACE PROGRAM TESTED - * TO DATE HAS DONE THIS. BUGS ARE LIKELY. + * CHOOSES THE OPTION V4L2_FIELD_INTERLACED. */ /*---------------------------------------------------------------------------*/ int @@ -1315,8 +1315,10 @@ if ((struct easycap *)NULL == peasycap) { badinput = false; -JOM(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \ +JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> " \ + "frame buffer %i\n", \ peasycap->field_buffer[peasycap->field_read][0].kount,\ + peasycap->field_buffer[peasycap->field_read][0].input,\ peasycap->field_read, peasycap->frame_fill); JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); if (true == peasycap->offerfields) @@ -1374,7 +1376,7 @@ if (peasycap->field_buffer[kex][0].kount) else odd = false; -if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) { +if ((true == odd) && (false == decimatepixel)) { JOM(8, " initial skipping %4i bytes p.%4i\n", \ w3/multiplier, mad); pad += (w3 / multiplier); rad -= (w3 / multiplier); @@ -1494,7 +1496,7 @@ while (cz < wz) { * UNLESS IT IS THE LAST LINE OF AN ODD FRAME */ /*---------------------------------------------------------------------------*/ - if (((false == odd) || (cz != wz))&&(false == offerfields)) { + if ((false == odd) || (cz != wz)) { over = w3; do { if (!rad) { @@ -3162,6 +3164,15 @@ if (purb->status) { [peasycap->field_page]; pfield_buffer->pto = \ pfield_buffer->pgo; + pfield_buffer->input = 0x08 | \ + (0x07 & peasycap->input); + if ((peasycap->field_buffer[peasycap->\ + field_fill][0]).\ + input != \ + pfield_buffer->input) + (peasycap->field_buffer\ + [peasycap->field_fill]\ + [0]).kount |= 0x1000; } much = PAGE_SIZE - (int)(pfield_buffer->pto - \ @@ -3441,7 +3452,6 @@ if (0 == bInterfaceNumber) { break; } } - if (DONGLE_MANY <= dongle_this) { SAM("ERROR: too many dongles\n"); return -ENOMEM; @@ -3481,6 +3491,8 @@ if (0 == bInterfaceNumber) { peasycap->frame_buffer_many = FRAME_BUFFER_MANY; + peasycap->skip = 0; + peasycap->skipped = 0; peasycap->offerfields = 0; /*---------------------------------------------------------------------------*/ /* diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c index 67f2e4f27323..df3f17d361b1 100644 --- a/drivers/staging/easycap/easycap_settings.c +++ b/drivers/staging/easycap/easycap_settings.c @@ -33,11 +33,15 @@ * THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING: * 0 => 25 fps * 1 => 30 fps + * + * THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING: + * 0 => full framerate + * 1 => 20% framerate */ /*---------------------------------------------------------------------------*/ const struct easycap_standard easycap_standard[] = { { -.mask = 0x000F & PAL_BGHIN , +.mask = 0x00FF & PAL_BGHIN , .v4l2_standard = { .index = PAL_BGHIN, .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \ @@ -50,7 +54,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_N_443 , +.mask = 0x00FF & NTSC_N_443 , .v4l2_standard = { .index = NTSC_N_443, .id = V4L2_STD_UNKNOWN, @@ -62,7 +66,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & PAL_Nc , +.mask = 0x00FF & PAL_Nc , .v4l2_standard = { .index = PAL_Nc, .id = V4L2_STD_PAL_Nc, @@ -74,7 +78,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_N , +.mask = 0x00FF & NTSC_N , .v4l2_standard = { .index = NTSC_N, .id = V4L2_STD_UNKNOWN, @@ -86,7 +90,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & SECAM , +.mask = 0x00FF & SECAM , .v4l2_standard = { .index = SECAM, .id = V4L2_STD_SECAM, @@ -98,7 +102,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_M , +.mask = 0x00FF & NTSC_M , .v4l2_standard = { .index = NTSC_M, .id = V4L2_STD_NTSC_M, @@ -110,7 +114,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_M_JP , +.mask = 0x00FF & NTSC_M_JP , .v4l2_standard = { .index = NTSC_M_JP, .id = V4L2_STD_NTSC_M_JP, @@ -122,7 +126,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & PAL_60 , +.mask = 0x00FF & PAL_60 , .v4l2_standard = { .index = PAL_60, .id = V4L2_STD_PAL_60, @@ -134,7 +138,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_443 , +.mask = 0x00FF & NTSC_443 , .v4l2_standard = { .index = NTSC_443, .id = V4L2_STD_NTSC_443, @@ -146,7 +150,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & PAL_M , +.mask = 0x00FF & PAL_M , .v4l2_standard = { .index = PAL_M, .id = V4L2_STD_PAL_M, @@ -158,6 +162,128 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { +.mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW), +.v4l2_standard = { + .index = PAL_BGHIN_SLOW, + .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \ + V4L2_STD_PAL_I | V4L2_STD_PAL_N | \ + (((v4l2_std_id)0x01) << 32)), + .name = "PAL_BGHIN_SLOW", + .frameperiod = {1, 5}, + .framelines = 625, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW), +.v4l2_standard = { + .index = NTSC_N_443_SLOW, + .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)), + .name = "NTSC_N_443_SLOW", + .frameperiod = {1, 5}, + .framelines = 480, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & PAL_Nc_SLOW), +.v4l2_standard = { + .index = PAL_Nc_SLOW, + .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)), + .name = "PAL_Nc_SLOW", + .frameperiod = {1, 5}, + .framelines = 625, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_N_SLOW), +.v4l2_standard = { + .index = NTSC_N_SLOW, + .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)), + .name = "NTSC_N_SLOW", + .frameperiod = {1, 5}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & SECAM_SLOW), +.v4l2_standard = { + .index = SECAM_SLOW, + .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)), + .name = "SECAM_SLOW", + .frameperiod = {1, 5}, + .framelines = 625, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_M_SLOW), +.v4l2_standard = { + .index = NTSC_M_SLOW, + .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)), + .name = "NTSC_M_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW), +.v4l2_standard = { + .index = NTSC_M_JP_SLOW, + .id = (V4L2_STD_NTSC_M_JP | (((v4l2_std_id)0x01) << 32)), + .name = "NTSC_M_JP_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & PAL_60_SLOW), +.v4l2_standard = { + .index = PAL_60_SLOW, + .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)), + .name = "PAL_60_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_443_SLOW), +.v4l2_standard = { + .index = NTSC_443_SLOW, + .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)), + .name = "NTSC_443_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & PAL_M_SLOW), +.v4l2_standard = { + .index = PAL_M_SLOW, + .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)), + .name = "PAL_M_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ .mask = 0xFFFF } }; @@ -165,15 +291,16 @@ const struct easycap_standard easycap_standard[] = { /* * THE 16-BIT easycap_format.mask HAS MEANING: * (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS - * BITS 1-3: RESERVED FOR DIFFERENTIATING STANDARDS - * BITS 4-7: NUMBER OF BYTES PER PIXEL + * BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS + * BITS 5-7: NUMBER OF BYTES PER PIXEL * BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED * BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS - * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED - * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS - * (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS + * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED + * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS + * BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED + * (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS * IT FOLLOWS THAT: - * bytesperpixel IS ((0x00F0 & easycap_format.mask) >> 4) + * bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5) * byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask)) * * decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask)) @@ -197,65 +324,135 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) { mask1 = 0x0000; switch (i) { case PAL_BGHIN: { - mask1 = PAL_BGHIN; + mask1 = 0x1F & PAL_BGHIN; strcpy(&name1[0], "PAL_BGHIN"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case SECAM: { - mask1 = SECAM; + mask1 = 0x1F & SECAM; strcpy(&name1[0], "SECAM"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case PAL_Nc: { - mask1 = PAL_Nc; + mask1 = 0x1F & PAL_Nc; strcpy(&name1[0], "PAL_Nc"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case PAL_60: { - mask1 = PAL_60; + mask1 = 0x1F & PAL_60; strcpy(&name1[0], "PAL_60"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case PAL_M: { - mask1 = PAL_M; + mask1 = 0x1F & PAL_M; strcpy(&name1[0], "PAL_M"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case NTSC_M: { - mask1 = NTSC_M; + mask1 = 0x1F & NTSC_M; strcpy(&name1[0], "NTSC_M"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_443: { - mask1 = NTSC_443; + mask1 = 0x1F & NTSC_443; strcpy(&name1[0], "NTSC_443"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_M_JP: { - mask1 = NTSC_M_JP; + mask1 = 0x1F & NTSC_M_JP; strcpy(&name1[0], "NTSC_M_JP"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_N: { - mask1 = NTSC_M; + mask1 = 0x1F & NTSC_M; strcpy(&name1[0], "NTSC_N"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_N_443: { - mask1 = NTSC_N_443; + mask1 = 0x1F & NTSC_N_443; strcpy(&name1[0], "NTSC_N_443"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } + case PAL_BGHIN_SLOW: { + mask1 = 0x001F & PAL_BGHIN_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_BGHIN_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case SECAM_SLOW: { + mask1 = 0x001F & SECAM_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "SECAM_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case PAL_Nc_SLOW: { + mask1 = 0x001F & PAL_Nc_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_Nc_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case PAL_60_SLOW: { + mask1 = 0x001F & PAL_60_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_60_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case PAL_M_SLOW: { + mask1 = 0x001F & PAL_M_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_M_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case NTSC_M_SLOW: { + mask1 = 0x001F & NTSC_M_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_M_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_443_SLOW: { + mask1 = 0x001F & NTSC_443_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_443_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_M_JP_SLOW: { + mask1 = 0x001F & NTSC_M_JP_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_M_JP_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_N_SLOW: { + mask1 = 0x001F & NTSC_N_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_N_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_N_443_SLOW: { + mask1 = 0x001F & NTSC_N_443_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_N_443_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } default: return -1; } @@ -311,39 +508,39 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) { case FMT_UYVY: { strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY)); pixelformat = V4L2_PIX_FMT_UYVY; - mask3 |= (0x02 << 4); + mask3 |= (0x02 << 5); break; } case FMT_YUY2: { strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2)); pixelformat = V4L2_PIX_FMT_YUYV; - mask3 |= (0x02 << 4); + mask3 |= (0x02 << 5); mask3 |= 0x0100; break; } case FMT_RGB24: { strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24)); pixelformat = V4L2_PIX_FMT_RGB24; - mask3 |= (0x03 << 4); + mask3 |= (0x03 << 5); break; } case FMT_RGB32: { strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32)); pixelformat = V4L2_PIX_FMT_RGB32; - mask3 |= (0x04 << 4); + mask3 |= (0x04 << 5); break; } case FMT_BGR24: { strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24)); pixelformat = V4L2_PIX_FMT_BGR24; - mask3 |= (0x03 << 4); + mask3 |= (0x03 << 5); mask3 |= 0x0100; break; } case FMT_BGR32: { strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32)); pixelformat = V4L2_PIX_FMT_BGR32; - mask3 |= (0x04 << 4); + mask3 |= (0x04 << 5); mask3 |= 0x0100; break; } @@ -363,13 +560,8 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) { } case FIELD_INTERLACED: { strcpy(&name4[0], "-i"); - field = V4L2_FIELD_INTERLACED; - break; - } - case FIELD_ALTERNATE: { - strcpy(&name4[0], "-a"); mask4 |= 0x1000; - field = V4L2_FIELD_ALTERNATE; + field = V4L2_FIELD_INTERLACED; break; } default: -- 2.39.5