On 8/4/19 12:09 AM, Keith Pyle wrote:
> `hdpvr_read` attempts to restart streaming if the device is read while
> it is both not ready and not disconnected.  However, the device is often
> still not ready immediately after the call to `hdpvr_start_streaming`
> returns, causing the condition `if (buf->status != BUFSTAT_READY)` to
> exit the loop without reading any further data.  By itself, this would
> merely cause a short read, which should be easily recoverable.  However,
> if no data has been read so far, this causes `hdpvr_read` to return 0,
> which results in an end-of-file for the user application.
> 
> Compensate for this by adding the ability to delay after the call to
> `hdpvr_start_streaming`, then `continue;` back to the top, so that
> `hdpvr_read` can call `wait_event_interruptible_timeout` again to wait
> for the device to become ready.  This delay complements the prior patch.
> The prior patch delays before issuing the start-streaming command, to
> give the firmware time to stabilize before receiving the command.  This
> delay is after the start-streaming command, to give the firmware time to
> bring the device to a ready state.  This delay is configurable through a
> new module parameter, `hdpvr_restart_streaming_ms_delay`, which defaults
> to a 100 millisecond delay.
> 
> To avoid an infinite loop in `hdpvr_read`, add a limit to how many times
> `hdpvr_read` can restart the device before returning.  This limit is
> configurable through a new module parameter,
> `hdpvr_restart_streaming_max_tries`, and defaults to one restart.
> Administrators may set the limit to 0 to request that `hdpvr_read` never
> attempt to restart streaming.  Previously, there was no way for
> administrators to opt out of an attempted restart.
> 
> Signed-off-by: Keith Pyle <[email protected]>
> Tested-by: Keith Pyle <[email protected]>
> ---
> Changes since v2:
> - Rewrapped comments again, per request from Hans.
> - Per advice from checkpatch.pl --strict (suggested by Hans), added
> spacing around `|` for mode permissions.  This satisfies checkpatch,
> but reduces consistency in hdpvr-core.c, which had preexisting uses that
> violate checkpatch --strict.
> - Per request from Hans, switched from pre-decrement to post-decrement.
> Changes since v1:
> - Rewrapped output at 80 columns, per request from Hans.  Literal strings
> still exceed 80 columns where necessary to keep an entire string together,
> since this makes it easier for grep to find the file and line that
> generates a given message.
> ---
>  drivers/media/usb/hdpvr/hdpvr-core.c  |  8 ++++++
>  drivers/media/usb/hdpvr/hdpvr-video.c | 36 +++++++++++++++++++++++++++
>  drivers/media/usb/hdpvr/hdpvr.h       |  2 ++
>  3 files changed, 46 insertions(+)
> 
> diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c 
> b/drivers/media/usb/hdpvr/hdpvr-core.c
> index a3d2f632fe38..1be3911e43ed 100644
> --- a/drivers/media/usb/hdpvr/hdpvr-core.c
> +++ b/drivers/media/usb/hdpvr/hdpvr-core.c
> @@ -43,6 +43,14 @@ uint hdpvr_close_to_open_ms_delay = 4000;
>  module_param(hdpvr_close_to_open_ms_delay, uint, S_IRUGO | S_IWUSR);

As per checkpatch output, use octal here.

>  MODULE_PARM_DESC(hdpvr_close_to_open_ms_delay, "delay restarting streaming 
> by the specified number of milliseconds");
>  
> +uint hdpvr_restart_streaming_max_tries = 1;
> +module_param(hdpvr_restart_streaming_max_tries, uint, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(hdpvr_restart_streaming_max_tries, "restart streaming at 
> most this many times within one read");
> +
> +uint hdpvr_restart_streaming_ms_delay = 100;
> +module_param(hdpvr_restart_streaming_ms_delay, uint, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(hdpvr_restart_streaming_ms_delay, "delay continue by the 
> specified number of milliseconds after restarting streaming");
> +
>  static uint default_video_input = HDPVR_VIDEO_INPUTS;
>  module_param(default_video_input, uint, S_IRUGO|S_IWUSR);
>  MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / 
> 1=S-Video / 2=Composite");
> diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c 
> b/drivers/media/usb/hdpvr/hdpvr-video.c
> index 7e5897dd8dff..aa7b473b501b 100644
> --- a/drivers/media/usb/hdpvr/hdpvr-video.c
> +++ b/drivers/media/usb/hdpvr/hdpvr-video.c
> @@ -441,6 +441,8 @@ static ssize_t hdpvr_read(struct file *file, char __user 
> *buffer, size_t count,
>       struct hdpvr_buffer *buf = NULL;
>       struct urb *urb;
>       unsigned int ret = 0;
> +     unsigned int restarts_remaining = hdpvr_restart_streaming_max_tries;
> +     unsigned int delay;
>       int rem, cnt;
>  
>       if (*pos)
> @@ -491,6 +493,19 @@ static ssize_t hdpvr_read(struct file *file, char __user 
> *buffer, size_t count,
>                               goto err;
>                       }
>                       if (!err) {
> +                             if (restarts_remaining == 0) {
> +                                     v4l2_dbg(MSG_BUFFER, hdpvr_debug,
> +                                              &dev->v4l2_dev,
> +                                              "timeout: no further restarts 
> allowed by hdpvr_restart_streaming_max_tries; returning to caller with 
> ret=%u",
> +                                              ret);
> +                                     /* This break will return the count of

As per coding style, put /* on a line by itself.

Besides these two points this patch looks good.

Regards,

        Hans

> +                                      * bytes copied so far, which may be 0.
> +                                      * In that situation, the user
> +                                      * application will get an EOF.
> +                                      */
> +                                     break;
> +                             }
> +                             restarts_remaining--;
>                               v4l2_info(&dev->v4l2_dev,
>                                         "timeout: restart streaming\n");
>                               mutex_lock(&dev->io_mutex);
> @@ -501,6 +516,27 @@ static ssize_t hdpvr_read(struct file *file, char __user 
> *buffer, size_t count,
>                                       ret = err;
>                                       goto err;
>                               }
> +                             /* hdpvr_start_streaming instructs the device to
> +                              * stream, but the device is usually not ready
> +                              * by the time hdpvr_start_streaming returns.
> +                              *
> +                              * Without this continue, the loop would
> +                              * terminate.  If no data had been copied by a
> +                              * prior iteration of the loop, then hdpvr_read
> +                              * would return 0, closing the file descriptor
> +                              * prematurely.  Continue back to the top of the
> +                              * loop to avoid that.
> +                              *
> +                              * The device may not be ready within 1 second,
> +                              * so the wait_event_interruptible_timeout would
> +                              * then restart streaming a second time.  Delay
> +                              * here to give the device time to stabilize
> +                              * first.
> +                              */
> +                             delay = hdpvr_restart_streaming_ms_delay;
> +                             if (delay)
> +                                     msleep(delay);
> +                             continue;
>                       }
>               }
>  
> diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
> index 32498b7120aa..f6f9ddf89faf 100644
> --- a/drivers/media/usb/hdpvr/hdpvr.h
> +++ b/drivers/media/usb/hdpvr/hdpvr.h
> @@ -44,6 +44,8 @@
>  
>  extern int hdpvr_debug;
>  extern uint hdpvr_close_to_open_ms_delay;
> +extern uint hdpvr_restart_streaming_max_tries;
> +extern uint hdpvr_restart_streaming_ms_delay;
>  
>  #define MSG_INFO     1
>  #define MSG_BUFFER   2
> 

Reply via email to