Commit 222155de authored by Jerry Zhang's avatar Jerry Zhang Committed by Felipe Balbi

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: default avatarMichal Nazarewicz <mina86@mina86.com>
Signed-off-by: default avatarJerry Zhang <zhangjerry@google.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 8a8b161d
...@@ -1189,6 +1189,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, ...@@ -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, ...@@ -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 { ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment