On Wed, Apr 19 2017, Jerry Zhang wrote:
> This allows users to make an ioctl call as the first action on a
> connection. Ex, some functions might want to get endpoint size
> before making any i/os.
>
> Previously, calling ioctls before read/write would depending on the
> timing of endpoints being enabled.
>
> ESHUTDOWN is now a possible return value and ENODEV is not, so change
> docs accordingly.
>
> Signed-off-by: Jerry Zhang <zhangje...@google.com>

Acked-by: Michal Nazarewicz <min...@mina86.com>

> ---
> Changelog since v2:
> - Updated doc to account for -ESHUTDOWN
>
> Changelog since v1:
> - Guarded against epfile->ep changing after taking lock
>
>  drivers/usb/gadget/function/f_fs.c  | 93 
> +++++++++++++++++++++----------------
>  include/uapi/linux/usb/functionfs.h |  7 +--
>  2 files changed, 58 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/usb/gadget/function/f_fs.c 
> b/drivers/usb/gadget/function/f_fs.c
> index a0085571824d..04425e6b457a 100644
> --- a/drivers/usb/gadget/function/f_fs.c
> +++ b/drivers/usb/gadget/function/f_fs.c
> @@ -1190,6 +1190,7 @@ static long ffs_epfile_ioctl(struct file *file, 
> unsigned code,
>                            unsigned long value)
>  {
>       struct ffs_epfile *epfile = file->private_data;
> +     struct ffs_ep *ep;
>       int ret;
>  
>       ENTER();
> @@ -1197,50 +1198,64 @@ static long ffs_epfile_ioctl(struct file *file, 
> unsigned code,
>       if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
>               return -ENODEV;
>  
> +     /* Wait for endpoint to be enabled */
> +     ep = epfile->ep;
> +     if (!ep) {
> +             if (file->f_flags & O_NONBLOCK)
> +                     return -EAGAIN;
> +
> +             ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
> +             if (ret)
> +                     return -EINTR;
> +     }
> +
>       spin_lock_irq(&epfile->ffs->eps_lock);
> -     if (likely(epfile->ep)) {
> -             switch (code) {
> -             case FUNCTIONFS_FIFO_STATUS:
> -                     ret = usb_ep_fifo_status(epfile->ep->ep);
> -                     break;
> -             case FUNCTIONFS_FIFO_FLUSH:
> -                     usb_ep_fifo_flush(epfile->ep->ep);
> -                     ret = 0;
> -                     break;
> -             case FUNCTIONFS_CLEAR_HALT:
> -                     ret = usb_ep_clear_halt(epfile->ep->ep);
> -                     break;
> -             case FUNCTIONFS_ENDPOINT_REVMAP:
> -                     ret = epfile->ep->num;
> -                     break;
> -             case FUNCTIONFS_ENDPOINT_DESC:
> -             {
> -                     int desc_idx;
> -                     struct usb_endpoint_descriptor *desc;
>  
> -                     switch (epfile->ffs->gadget->speed) {
> -                     case USB_SPEED_SUPER:
> -                             desc_idx = 2;
> -                             break;
> -                     case USB_SPEED_HIGH:
> -                             desc_idx = 1;
> -                             break;
> -                     default:
> -                             desc_idx = 0;
> -                     }
> -                     desc = epfile->ep->descs[desc_idx];
> +     /* In the meantime, endpoint got disabled or changed. */
> +     if (epfile->ep != ep) {
> +             spin_unlock_irq(&epfile->ffs->eps_lock);
> +             return -ESHUTDOWN;
> +     }
>  
> -                     spin_unlock_irq(&epfile->ffs->eps_lock);
> -                     ret = copy_to_user((void *)value, desc, desc->bLength);
> -                     if (ret)
> -                             ret = -EFAULT;
> -                     return ret;
> -             }
> +     switch (code) {
> +     case FUNCTIONFS_FIFO_STATUS:
> +             ret = usb_ep_fifo_status(epfile->ep->ep);
> +             break;
> +     case FUNCTIONFS_FIFO_FLUSH:
> +             usb_ep_fifo_flush(epfile->ep->ep);
> +             ret = 0;
> +             break;
> +     case FUNCTIONFS_CLEAR_HALT:
> +             ret = usb_ep_clear_halt(epfile->ep->ep);
> +             break;
> +     case FUNCTIONFS_ENDPOINT_REVMAP:
> +             ret = epfile->ep->num;
> +             break;
> +     case FUNCTIONFS_ENDPOINT_DESC:
> +     {
> +             int desc_idx;
> +             struct usb_endpoint_descriptor *desc;
> +
> +             switch (epfile->ffs->gadget->speed) {
> +             case USB_SPEED_SUPER:
> +                     desc_idx = 2;
> +                     break;
> +             case USB_SPEED_HIGH:
> +                     desc_idx = 1;
> +                     break;
>               default:
> -                     ret = -ENOTTY;
> +                     desc_idx = 0;
>               }
> -     } else {
> -             ret = -ENODEV;
> +             desc = epfile->ep->descs[desc_idx];
> +
> +             spin_unlock_irq(&epfile->ffs->eps_lock);
> +             ret = copy_to_user((void *)value, desc, desc->bLength);
> +             if (ret)
> +                     ret = -EFAULT;
> +             return ret;
> +     }
> +     default:
> +             ret = -ENOTTY;
>       }
>       spin_unlock_irq(&epfile->ffs->eps_lock);
>  
> diff --git a/include/uapi/linux/usb/functionfs.h 
> b/include/uapi/linux/usb/functionfs.h
> index b2a31a55a612..297bca230dd0 100644
> --- a/include/uapi/linux/usb/functionfs.h
> +++ b/include/uapi/linux/usb/functionfs.h
> @@ -275,13 +275,14 @@ struct usb_functionfs_event {
>  #define      FUNCTIONFS_INTERFACE_REVMAP     _IO('g', 128)
>  
>  /*
> - * Returns real bEndpointAddress of an endpoint.  If function is not
> - * active returns -ENODEV.
> + * Returns real bEndpointAddress of an endpoint. If endpoint shuts down
> + * during the call, returns -ESHUTDOWN.
>   */
>  #define      FUNCTIONFS_ENDPOINT_REVMAP      _IO('g', 129)
>  
>  /*
> - * Returns endpoint descriptor. If function is not active returns -ENODEV.
> + * Returns endpoint descriptor. If endpoint shuts down during the call,
> + * returns -ESHUTDOWN.
>   */
>  #define      FUNCTIONFS_ENDPOINT_DESC        _IOR('g', 130, \
>                                            struct usb_endpoint_descriptor)

-- 
Best regards
ミハウ “𝓶𝓲𝓷𝓪86” ナザレヴイツ
«If at first you don’t succeed, give up skydiving»
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to