Hi Ricardo, Thank you for the patch. On Wed, Dec 23, 2020 at 12:04:39AM +0100, Ricardo Ribalda wrote: > Provide a code path for events that can be sent without a work-queue, > this is, that do not belong to an URB and are not handled in the top > half on an irq-handled. > > Signed-off-by: Ricardo Ribalda <ribalda@xxxxxxxxxxxx> > --- > drivers/media/usb/uvc/uvc_ctrl.c | 35 +++++++++++++++++++++++++++----- > drivers/media/usb/uvc/uvcvideo.h | 2 ++ > 2 files changed, 32 insertions(+), 5 deletions(-) > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c > index 9f6174a10e73..5fe228a3213b 100644 > --- a/drivers/media/usb/uvc/uvc_ctrl.c > +++ b/drivers/media/usb/uvc/uvc_ctrl.c > @@ -1254,17 +1254,14 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, > uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); > } > > -static void uvc_ctrl_status_event_work(struct work_struct *work) > +static void __uvc_ctrl_status_event(struct uvc_device *dev, > + struct uvc_ctrl_work *w) As this function doesn't deal with the work queue, should it receive the members of uvc_ctrl_work as direct arguments ? You could then drop the separate uvc_ctrl_status_event_direct(), or rather rename this function to uvc_ctrl_status_event_direct(). Speaking of names, maybe uvc_ctrl_status_event() should be renamed to uvc_ctrl_status_event_async(), and this function become uvc_ctrl_status_event() ? > { > - struct uvc_device *dev = container_of(work, struct uvc_device, > - async_ctrl.work); > - struct uvc_ctrl_work *w = &dev->async_ctrl; > struct uvc_video_chain *chain = w->chain; > struct uvc_control_mapping *mapping; > struct uvc_control *ctrl = w->ctrl; > struct uvc_fh *handle; > unsigned int i; > - int ret; > > mutex_lock(&chain->ctrl_mutex); > > @@ -1291,6 +1288,16 @@ static void uvc_ctrl_status_event_work(struct work_struct *work) > } > > mutex_unlock(&chain->ctrl_mutex); > +} > + > +static void uvc_ctrl_status_event_work(struct work_struct *work) > +{ > + struct uvc_device *dev = container_of(work, struct uvc_device, > + async_ctrl.work); > + struct uvc_ctrl_work *w = &dev->async_ctrl; > + int ret; > + > + __uvc_ctrl_status_event(dev, w); > > /* Resubmit the URB. */ > w->urb->interval = dev->int_ep->desc.bInterval; > @@ -1321,6 +1328,24 @@ bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain, > return true; > } > > +void uvc_ctrl_status_event_direct(struct uvc_video_chain *chain, > + struct uvc_control *ctrl, const u8 *data) > +{ > + struct uvc_device *dev = chain->dev; > + struct uvc_ctrl_work w; > + > + if (list_empty(&ctrl->info.mappings)) { > + ctrl->handle = NULL; > + return; > + } > + > + w.data = data; > + w.chain = chain; > + w.ctrl = ctrl; > + > + __uvc_ctrl_status_event(dev, &w); > +} > + > static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls, > unsigned int xctrls_count, u32 id) > { > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h > index c50b0546901f..d7954dcc2b60 100644 > --- a/drivers/media/usb/uvc/uvcvideo.h > +++ b/drivers/media/usb/uvc/uvcvideo.h > @@ -845,6 +845,8 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev); > int uvc_ctrl_restore_values(struct uvc_device *dev); > bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain, > struct uvc_control *ctrl, const u8 *data); > +void uvc_ctrl_status_event_direct(struct uvc_video_chain *chain, > + struct uvc_control *ctrl, const u8 *data); > > int uvc_ctrl_begin(struct uvc_video_chain *chain); > int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, -- Regards, Laurent Pinchart