usb: gadget: function: f_fs: Let ffs_epfile_ioctl wait for enable.
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. Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Jerry Zhang <zhangjerry@google.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
Родитель
8a8b161df5
Коммит
222155de45
|
@ -1189,6 +1189,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
|
||||||
unsigned long value)
|
unsigned long value)
|
||||||
{
|
{
|
||||||
struct ffs_epfile *epfile = file->private_data;
|
struct ffs_epfile *epfile = file->private_data;
|
||||||
|
struct ffs_ep *ep;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
@ -1196,50 +1197,64 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
|
||||||
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
|
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
|
||||||
return -ENODEV;
|
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);
|
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) {
|
/* In the meantime, endpoint got disabled or changed. */
|
||||||
case USB_SPEED_SUPER:
|
if (epfile->ep != ep) {
|
||||||
desc_idx = 2;
|
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||||
break;
|
return -ESHUTDOWN;
|
||||||
case USB_SPEED_HIGH:
|
}
|
||||||
desc_idx = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
desc_idx = 0;
|
|
||||||
}
|
|
||||||
desc = epfile->ep->descs[desc_idx];
|
|
||||||
|
|
||||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
switch (code) {
|
||||||
ret = copy_to_user((void *)value, desc, desc->bLength);
|
case FUNCTIONFS_FIFO_STATUS:
|
||||||
if (ret)
|
ret = usb_ep_fifo_status(epfile->ep->ep);
|
||||||
ret = -EFAULT;
|
break;
|
||||||
return ret;
|
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:
|
default:
|
||||||
ret = -ENOTTY;
|
desc_idx = 0;
|
||||||
}
|
}
|
||||||
} else {
|
desc = epfile->ep->descs[desc_idx];
|
||||||
ret = -ENODEV;
|
|
||||||
|
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);
|
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||||
|
|
||||||
|
|
|
@ -275,13 +275,14 @@ struct usb_functionfs_event {
|
||||||
#define FUNCTIONFS_INTERFACE_REVMAP _IO('g', 128)
|
#define FUNCTIONFS_INTERFACE_REVMAP _IO('g', 128)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns real bEndpointAddress of an endpoint. If function is not
|
* Returns real bEndpointAddress of an endpoint. If endpoint shuts down
|
||||||
* active returns -ENODEV.
|
* during the call, returns -ESHUTDOWN.
|
||||||
*/
|
*/
|
||||||
#define FUNCTIONFS_ENDPOINT_REVMAP _IO('g', 129)
|
#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, \
|
#define FUNCTIONFS_ENDPOINT_DESC _IOR('g', 130, \
|
||||||
struct usb_endpoint_descriptor)
|
struct usb_endpoint_descriptor)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче