mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Hans Verkuil <hverkuil+cisco@kernel.org>
To: "Siniša Došen" <snsdosen@gmail.com>,
	"Mauro Carvalho Chehab" <mchehab@kernel.org>
Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] media: cx231xx: fix August VGB100 video and VBI capture
Date: Thu, 12 Nov 2026 14:39:00 +0100	[thread overview]
Message-ID: <1b63100c-673f-403c-aa37-4e9088a1a042@kernel.org> (raw)
In-Reply-To: <20261012103657.28574-1-snsdosen@gmail.com>

Hi Siniša,

On 12/10/2026 12:36, Siniša Došen wrote:
> Devices sold as the August VGB100 exist in at least two hardware
> revisions, although both use USB ID 1f4d:0102. The Windows driver INF
> also contains separate entries for two VGB100 revisions. The unit tested
> here reports bcdDevice 0x4002.
> 
> Linux support for this USB ID was originally added for the Geniatech
> OTG102/EZGrabber2. A later patch fixed S-Video capture on an August
> VGB100 by correcting the input routing from the VGB100 and OTG102
> Windows INF files. That profile provides working video on an older
> VGB100 unit, but it does not initialize the 0x4002 revision correctly.
> The older unit also showed URB errors and could become unresponsive when
> capturing raw VBI.
> 
> On the 0x4002 revision the generic profile leaves the analog front end
> with the wrong reference tuning, so the decoder cannot lock reliably to
> a PAL signal. Once that is corrected, cx25840 reports 720x572 while the
> bridge delivers complete 720x576 frames, causing applications to reject
> the captured buffers.
> 
> Raw VBI capture also exposes two bugs in the common cx231xx code. The
> parser stops making progress after discarding a surplus VBI line, which
> leaves readers waiting indefinitely despite continuing USB traffic. VBI
> URBs can also remain active while their vb2 buffers are returned during
> stream shutdown.
> 
> This change adds a board profile for bcdDevice 0x4002 while leaving the
> existing OTG102 profile as the fallback for the older revision. It uses
> the AFE reference tuning and frame geometry required by the new hardware,
> corrects the raw VBI parser state, stops URBs before returning buffers,
> and avoids reinitializing the analog path when userspace reselects the
> active input.
> 
> The result was tested on the 0x4002 VGB100 with 720x576 YUYV video at
> 25 fps and raw PAL VBI capture at 1440 samples over 36 lines per frame.

This patch is mixing three things: adding a new board, and fixing two
vbi bugs.

Can you split this in three patches? That's much cleaner.

Also, regarding the addition of cx231xx_uninit_vbi_isoc(): in the corresponding
stop_streaming in cx231xx-video.c, nothing similar is happening. Instead this
is done in cx231xx_close. It's not clear to me why cx231xx_uninit_vbi_isoc needs
to be called in vbi_stop_streaming. When vbi_start_streaming is called, that in
turn calls cx231xx_init_vbi_isoc which calls cx231xx_uninit_vbi_isoc in the very
beginning. Which seems reasonable?

Thank you!

Regards,

	Hans

> 
> Signed-off-by: Siniša Došen <snsdosen@gmail.com>
> ---
>  drivers/media/usb/cx231xx/cx231xx-avcore.c | 14 +++++++++++++
>  drivers/media/usb/cx231xx/cx231xx-cards.c  | 24 ++++++++++++++++++++++
>  drivers/media/usb/cx231xx/cx231xx-vbi.c    | 18 ++++++++++++----
>  drivers/media/usb/cx231xx/cx231xx-video.c  | 12 +++++++++--
>  drivers/media/usb/cx231xx/cx231xx.h        |  1 +
>  5 files changed, 63 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
> index 0a5c635..fb71e39 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
> @@ -348,6 +348,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
>  	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
>  	case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
>  	case CX231XX_BOARD_OTG102:
> +	case CX231XX_BOARD_AUGUST_VGB100:
>  		if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
>  			while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
>  						FLD_PWRDN_ENABLE_PLL)) {
> @@ -932,6 +933,18 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
>  		status = vid_blk_write_word(dev, OUT_CTRL1, value);
>  	}
>  
> +	/*
> +	 * The generic setup derives TUNE1 from the reference clock and leaves
> +	 * 0x42 here.  The VGB100 40.02 analogue front end requires 0xbe;
> +	 * otherwise its decoder never acquires horizontal sync.
> +	 */
> +	if (dev->model == CX231XX_BOARD_AUGUST_VGB100 &&
> +	    pin_type == CX231XX_VMUX_COMPOSITE1) {
> +		status = afe_write_byte(dev, SUP_BLK_TUNE1, 0xbe);
> +		if (status < 0)
> +			return status;
> +	}
> +
>  	return status;
>  }
>  
> @@ -1729,6 +1742,7 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
>  	case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
>  	case CX231XX_BOARD_HAUPPAUGE_EXETER:
>  	case CX231XX_BOARD_OTG102:
> +	case CX231XX_BOARD_AUGUST_VGB100:
>  		func_mode = 0x03;
>  		break;
>  	case CX231XX_BOARD_CNXT_RDE_253S:
> diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
> index 69b2420..7ce160d 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-cards.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
> @@ -685,6 +685,28 @@ struct cx231xx_board cx231xx_boards[] = {
>  			}
>  		},
>  	},
> +	[CX231XX_BOARD_AUGUST_VGB100] = {
> +		.name = "August VGB100",
> +		.tuner_type = TUNER_ABSENT,
> +		.decoder = CX231XX_AVDECODER,
> +		.output_mode = OUT_MODE_VIP11,
> +		.ctl_pin_status_mask = 0xFFFFFFC4,
> +		.agc_analog_digital_select_gpio = 0x0c,
> +		.gpio_pin_status_mask = 0x4001000,
> +		.norm = V4L2_STD_PAL,
> +		.no_alt_vanc = 1,
> +		.external_av = 1,
> +		.input = {{
> +			.type = CX231XX_VMUX_COMPOSITE1,
> +			.vmux = CX231XX_VIN_2_1,
> +			.amux = CX231XX_AMUX_LINE_IN,
> +		}, {
> +			.type = CX231XX_VMUX_SVIDEO,
> +			.vmux = CX231XX_VIN_1_1 |
> +				(CX231XX_VIN_3_2 << 8),
> +			.amux = CX231XX_AMUX_LINE_IN,
> +		} },
> +	},
>  	[CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = {
>  		.name = "Hauppauge WinTV 930C-HD (1113xx) / HVR-900H (111xxx) / PCTV QuatroStick 521e",
>  		.tuner_type = TUNER_NXP_TDA18271,
> @@ -1061,6 +1083,8 @@ struct usb_device_id cx231xx_id_table[] = {
>  	 .driver_info = CX231XX_BOARD_ICONBIT_U100},
>  	{USB_DEVICE(0x0fd9, 0x0037),
>  	 .driver_info = CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2},
> +	{USB_DEVICE_VER(0x1f4d, 0x0102, 0x4002, 0x4002),
> +	 .driver_info = CX231XX_BOARD_AUGUST_VGB100},
>  	{USB_DEVICE(0x1f4d, 0x0102),
>  	 .driver_info = CX231XX_BOARD_OTG102},
>  	{USB_DEVICE(USB_VID_TERRATEC, 0x00a6),
> diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
> index 338e101..63db257 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
> @@ -234,6 +234,8 @@ static void vbi_stop_streaming(struct vb2_queue *vq)
>  {
>  	struct cx231xx *dev = vb2_get_drv_priv(vq);
>  
> +	/* Stop URB callbacks before returning their destination buffers. */
> +	cx231xx_uninit_vbi_isoc(dev);
>  	return_all_buffers(dev, VB2_BUF_STATE_ERROR);
>  }
>  
> @@ -499,8 +501,12 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
>  		cx231xx_reset_vbi_buffer(dev, dma_q);
>  	}
>  
> -	if (dma_q->current_field != field_number)
> +	if (dma_q->current_field != field_number) {
> +		/* Drop any incomplete surplus line from the previous field. */
>  		dma_q->lines_completed = 0;
> +		dma_q->bytes_left_in_line = _line_size;
> +		dma_q->is_partial_line = 0;
> +	}
>  
>  	/* get the buffer pointer */
>  	buf = dev->vbi_mode.bulk_ctl.buf;
> @@ -514,9 +520,13 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
>  
>  	if (dma_q->lines_completed >= dma_q->lines_per_field) {
>  		dma_q->bytes_left_in_line -= bytes_to_copy;
> -		dma_q->is_partial_line =
> -		    (dma_q->bytes_left_in_line == 0) ? 0 : 1;
> -		return 0;
> +		if (dma_q->bytes_left_in_line == 0) {
> +			dma_q->bytes_left_in_line = _line_size;
> +			dma_q->is_partial_line = 0;
> +		} else {
> +			dma_q->is_partial_line = 1;
> +		}
> +		return bytes_to_copy;
>  	}
>  
>  	dma_q->is_partial_line = 1;
> diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
> index 70aa99f..4fd31ab 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-video.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-video.c
> @@ -912,6 +912,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
>  	call_all(dev, pad, set_fmt, NULL, &format);
>  	v4l2_fill_pix_format(&f->fmt.pix, &format.format);
>  
> +	/* The DMA engine keeps the requested 576-line PAL geometry. */
> +	if (dev->model == CX231XX_BOARD_AUGUST_VGB100)
> +		vidioc_g_fmt_vid_cap(file, priv, f);
> +
>  	return rc;
>  }
>  
> @@ -1065,13 +1069,17 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
>  {
>  	struct cx231xx *dev = video_drvdata(file);
>  
> -	dev->mode_tv = 0;
> -
>  	if (i >= MAX_CX231XX_INPUT)
>  		return -EINVAL;
>  	if (0 == INPUT(i)->type)
>  		return -EINVAL;
>  
> +	/* Reapplying the vendor profile disturbs an active raw VBI stream. */
> +	if (dev->model == CX231XX_BOARD_AUGUST_VGB100 &&
> +	    i == dev->video_input)
> +		return 0;
> +
> +	dev->mode_tv = 0;
>  	video_mux(dev, i);
>  
>  	if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
> diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
> index 19f5036..1cb08ec 100644
> --- a/drivers/media/usb/cx231xx/cx231xx.h
> +++ b/drivers/media/usb/cx231xx/cx231xx.h
> @@ -70,6 +70,7 @@
>  #define CX231XX_BOARD_THE_IMAGING_SOURCE_DFG_USB2_PRO 25
>  #define CX231XX_BOARD_HAUPPAUGE_935C 26
>  #define CX231XX_BOARD_HAUPPAUGE_975 27
> +#define CX231XX_BOARD_AUGUST_VGB100 28
>  
>  /* Limits minimum and default number of buffers */
>  #define CX231XX_MIN_BUF                 4


      reply	other threads:[~2026-11-12 13:39 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-12 10:36 Siniša Došen
2026-11-12 13:39 ` Hans Verkuil [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1b63100c-673f-403c-aa37-4e9088a1a042@kernel.org \
    --to=hverkuil+cisco@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=snsdosen@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®