#include <linux/usb/gadgetfs.h> #include <linux/usb/gadget.h> #include <linux/usb/composite.h> /* for USB_GADGET_DELAYED_STATUS */
/* Undef helpers from linux/usb/composite.h as gadgetfs redefines them */ #undef DBG #undef ERROR #undef INFO
/* * The gadgetfs API maps each endpoint to a file descriptor so that you * can use standard synchronous read/write calls for I/O. There's some * O_NONBLOCK and O_ASYNC/FASYNC style i/o support. Example usermode * drivers show how this works in practice. You can also use AIO to * eliminate I/O gaps between requests, to help when streaming data. * * Key parts that must be USB-specific are protocols defining how the * read/write operations relate to the hardware state machines. There * are two types of files. One type is for the device, implementing ep0. * The other type is for each IN or OUT endpoint. In both cases, the * user mode driver must configure the hardware before using it. * * - First, dev_config() is called when /dev/gadget/$CHIP is configured * (by writing configuration and device descriptors). Afterwards it * may serve as a source of device events, used to handle all control * requests other than basic enumeration. * * - Then, after a SET_CONFIGURATION control request, ep_config() is * called when each /dev/gadget/ep* file is configured (by writing * endpoint descriptors). Afterwards these files are used to write() * IN data or to read() OUT data. To halt the endpoint, a "wrong * direction" request is issued (like reading an IN endpoint). * * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe * not possible on all hardware. For example, precise fault handling with * respect to data left in endpoint fifos after aborted operations; or * selective clearing of endpoint halts, to implement SET_INTERFACE.
*/
#define DRIVER_DESC "USB Gadget filesystem" #define DRIVER_VERSION "24 Aug 2004"
/* /dev/gadget/$CHIP represents ep0 and the whole device */ enum ep0_state { /* DISABLED is the initial state. */
STATE_DEV_DISABLED = 0,
/* Only one open() of /dev/gadget/$CHIP; only one file tracks * ep0/device i/o modes and binding to the controller. Driver * must always write descriptors to initialize the device, then * the device becomes UNCONNECTED until enumeration.
*/
STATE_DEV_OPENED,
/* From then on, ep0 fd is in either of two basic modes: * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it * - SETUP: read/write will transfer control data and succeed; * or if "wrong direction", performs protocol stall
*/
STATE_DEV_UNCONNECTED,
STATE_DEV_CONNECTED,
STATE_DEV_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be * accessible again (DEV_DISABLED) until all fds are closed.
*/
STATE_DEV_UNBOUND,
};
/* enough for the whole queue: most events invalidate others */ #define N_EVENT 5
/* most "how to use the hardware" policy choices are in userspace: * mapping endpoint roles (which the driver needs) to the capabilities * which the usb controller has. most of those capabilities are exposed * implicitly, starting with the driver name and then endpoint names.
*/
/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso) * * After opening, configure non-control endpoints. Then use normal * stream read() and write() requests; and maybe ioctl() to get more * precise FIFO status when recovering from cancellation.
*/
if (!req->context) return; if (req->status)
epdata->status = req->status; else
epdata->status = req->actual;
complete ((struct completion *)req->context);
}
/* tasklock endpoint, returning when it's connected. * still need dev->lock to use epdata->ep.
*/ staticint
get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write)
{ int val;
if (f_flags & O_NONBLOCK) { if (!mutex_trylock(&epdata->lock)) goto nonblock; if (epdata->state != STATE_EP_ENABLED &&
(!is_write || epdata->state != STATE_EP_READY)) {
mutex_unlock(&epdata->lock);
nonblock:
val = -EAGAIN;
} else
val = 0; return val;
}
val = mutex_lock_interruptible(&epdata->lock); if (val < 0) return val;
switch (epdata->state) { case STATE_EP_ENABLED: return 0; case STATE_EP_READY: /* not configured yet */ if (is_write) return 0;
fallthrough; case STATE_EP_UNBOUND: /* clean disconnect */ break; // case STATE_EP_DISABLED: /* "can't happen" */ default: /* error! */
pr_debug ("%s: ep %p not available, state %d\n",
shortname, epdata, epdata->state);
}
mutex_unlock(&epdata->lock); return -ENODEV;
}
/* if this was a write or a read returning no data then we * don't need to copy anything to userspace, so we can * complete the aio request immediately.
*/ if (priv->to_free == NULL || unlikely(req->actual == 0)) {
kfree(req->buf);
kfree(priv->to_free);
kfree(priv);
iocb->private = NULL;
iocb->ki_complete(iocb,
req->actual ? req->actual : (long)req->status);
} else { /* ep_copy_to_user() won't report both; we hide some faults */ if (unlikely(0 != req->status))
DBG(epdata->dev, "%s fault %d len %d\n",
ep->name, req->status, req->actual);
kiocb_set_cancel_fn(iocb, ep_aio_cancel);
get_ep(epdata);
priv->epdata = epdata;
priv->actual = 0;
priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */
/* each kiocb is coupled to one usb_request, but we can't * allocate or submit those if the host disconnected.
*/
spin_lock_irq(&epdata->dev->lock);
value = -ENODEV; if (unlikely(epdata->ep == NULL)) goto fail;
req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
value = -ENOMEM; if (unlikely(!req)) goto fail;
/* ENDPOINT INITIALIZATION * * fd = open ("/dev/gadget/$ENDPOINT", O_RDWR) * status = write (fd, descriptors, sizeof descriptors) * * That write establishes the endpoint configuration, configuring * the controller to process bulk, interrupt, or isochronous transfers * at the right maxpacket size, and so on. * * The descriptors are message type 1, identified by a host order u32 * at the beginning of what's written. Descriptor order is: full/low * speed descriptor, then optional high speed descriptor.
*/ static ssize_t
ep_config (struct ep_data *data, constchar *buf, size_t len)
{ struct usb_ep *ep;
u32 tag; int value, length = len;
if (data->state != STATE_EP_READY) {
value = -EL2HLT; goto fail;
}
value = len; if (len < USB_DT_ENDPOINT_SIZE + 4) goto fail0;
/* we might need to change message format someday */
memcpy(&tag, buf, 4); if (tag != 1) {
DBG(data->dev, "config %s, bad tag %d\n", data->name, tag); goto fail0;
}
buf += 4;
len -= 4;
/* NOTE: audio endpoint extensions not accepted here; * just don't include the extra bytes.
*/
/* full/low speed descriptor, then high speed */
memcpy(&data->desc, buf, USB_DT_ENDPOINT_SIZE); if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
|| data->desc.bDescriptorType != USB_DT_ENDPOINT) goto fail0; if (len != USB_DT_ENDPOINT_SIZE) { if (len != 2 * USB_DT_ENDPOINT_SIZE) goto fail0;
memcpy(&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT_SIZE); if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
|| data->hs_desc.bDescriptorType
!= USB_DT_ENDPOINT) {
DBG(data->dev, "config %s, bad hs length or type\n",
data->name); goto fail0;
}
}
spin_lock_irq (&data->dev->lock); if (data->dev->state == STATE_DEV_UNBOUND) {
value = -ENOENT; goto gone;
} else {
ep = data->ep; if (ep == NULL) {
value = -ENODEV; goto gone;
}
} switch (data->dev->gadget->speed) { case USB_SPEED_LOW: case USB_SPEED_FULL:
ep->desc = &data->desc; break; case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */
ep->desc = &data->hs_desc; break; default:
DBG(data->dev, "unconnected, %s init abandoned\n",
data->name);
value = -EINVAL; goto gone;
}
value = usb_ep_enable(ep); if (value == 0) {
data->state = STATE_EP_ENABLED;
value = length;
}
gone:
spin_unlock_irq (&data->dev->lock); if (value < 0) {
fail:
data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0;
} return value;
fail0:
value = -EINVAL; goto fail;
}
staticint
ep_open (struct inode *inode, struct file *fd)
{ struct ep_data *data = inode->i_private; int value = -EBUSY;
/* EP0 IMPLEMENTATION can be partly in userspace. * * Drivers that use this facility receive various events, including * control requests the kernel doesn't handle. Drivers that don't * use this facility may be too simple-minded for real applications.
*/
/* for control OUT, data must still get to userspace */
spin_lock_irqsave(&dev->lock, flags); if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0); if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
}
/* clean up as appropriate */ if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
spin_unlock_irqrestore(&dev->lock, flags);
}
if (dev->gadget_registered) {
usb_gadget_unregister_driver (&gadgetfs_driver);
dev->gadget_registered = false;
}
/* at this point "good" hardware has disconnected the * device from USB; the host won't see it any more. * alternatively, all host requests will time out.
*/
kfree (dev->buf);
dev->buf = NULL;
/* other endpoints were all decoupled from this device */
spin_lock_irq(&dev->lock);
dev->state = STATE_DEV_DISABLED;
spin_unlock_irq(&dev->lock);
/* The in-kernel gadget driver handles most ep0 issues, in particular * enumerating the single configuration (as provided from user space). * * Unrecognized ep0 requests may be handled in user space.
*/
if (w_length > RBUF_SIZE) { if (ctrl->bRequestType & USB_DIR_IN) { /* Cast away the const, we are going to overwrite on purpose. */
__le16 *temp = (__le16 *)&ctrl->wLength;
/* host may have given up waiting for response. we can miss control * requests handled lower down (device/endpoint status and features); * then ep0_{read,write} will report the wrong status. controller * driver will have aborted pending i/o.
*/
} elseif (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) goto unrecognized; switch (w_value >> 8) {
case USB_DT_DEVICE:
value = min (w_length, (u16) sizeof *dev->dev);
dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
req->buf = dev->dev; break; case USB_DT_DEVICE_QUALIFIER: if (!dev->hs_config) break;
value = min (w_length, (u16) sizeof (struct usb_qualifier_descriptor));
make_qualifier (dev); break; case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_CONFIG:
value = config_buf (dev,
w_value >> 8,
w_value & 0xff); if (value >= 0)
value = min (w_length, (u16) value); break; case USB_DT_STRING: goto unrecognized;
default: // all others are errors break;
} break;
/* currently one config, two speeds */ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) goto unrecognized; if (0 == (u8) w_value) {
value = 0;
dev->current_config = 0;
usb_gadget_vbus_draw(gadget, 8 /* mA */ ); // user mode expected to disable endpoints
} else {
u8 config, power;
if (gadget_is_dualspeed(gadget)
&& gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue;
power = dev->hs_config->bMaxPower;
} else {
config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}
if (config == (u8) w_value) {
value = 0;
dev->current_config = config;
usb_gadget_vbus_draw(gadget, 2 * power);
}
}
/* report SET_CONFIGURATION like any other control request, * except that usermode may not stall this. the next * request mustn't be allowed start until this finishes: * endpoints and threads set up, etc. * * NOTE: older PXA hardware (before PXA 255: without UDCCFR) * has bad/racey automagic that prevents synchronizing here. * even kernel mode drivers often miss them.
*/ if (value == 0) {
INFO (dev, "configuration #%d\n", dev->current_config);
usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); if (dev->usermode_setup) {
dev->setup_can_stall = 0; goto delegate;
}
} break;
#ifndef CONFIG_USB_PXA25X /* PXA automagically handles this request too */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != 0x80) goto unrecognized;
*(u8 *)req->buf = dev->current_config;
value = min (w_length, (u16) 1); break; #endif
/* read DATA stage for OUT right away */ if (unlikely (!dev->setup_in && w_length)) {
value = setup_req (gadget->ep0, dev->req,
w_length); if (value < 0) break;
/* we can't currently stall these */
dev->setup_can_stall = 0;
}
/* state changes when reader collects event */
event = next_event (dev, GADGETFS_SETUP);
event->u.setup = *ctrl;
ep0_readable (dev);
spin_unlock (&dev->lock); /* * Return USB_GADGET_DELAYED_STATUS as a workaround to * stop some UDC drivers (e.g. dwc3) from automatically * proceeding with the status stage for 0-length * transfers. * Should be removed once all UDC drivers are fixed to * always delay the status stage until a response is * queued to EP0.
*/ return w_length == 0 ? USB_GADGET_DELAYED_STATUS : 0;
}
}
/* proceed with data transfer and status phases? */ if (value >= 0 && dev->state != STATE_DEV_SETUP) {
req->length = value;
req->zero = value < w_length;
/* we've already been disconnected ... no i/o is active */ if (dev->req)
usb_ep_free_request (gadget->ep0, dev->req);
DBG (dev, "%s done\n", __func__);
put_dev (dev);
}
INFO (dev, "suspended from state %d\n", dev->state);
spin_lock_irqsave(&dev->lock, flags); switch (dev->state) { case STATE_DEV_SETUP: // VERY odd... host died?? case STATE_DEV_CONNECTED: case STATE_DEV_UNCONNECTED:
next_event (dev, GADGETFS_SUSPEND);
ep0_readable (dev);
fallthrough; default: break;
}
spin_unlock_irqrestore(&dev->lock, flags);
}
/*----------------------------------------------------------------------*/ /* DEVICE INITIALIZATION * * fd = open ("/dev/gadget/$CHIP", O_RDWR) * status = write (fd, descriptors, sizeof descriptors) * * That write establishes the device configuration, so the kernel can * bind to the controller ... guaranteeing it can handle enumeration * at all necessary speeds. Descriptor order is: * * . message tag (u32, host order) ... for now, must be zero; it * would change to support features like multi-config devices * . full/low speed config ... all wTotalLength bytes (with interface, * class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; * this one's optional except for high-speed hardware * . device descriptor * * Endpoints are not yet enabled. Drivers must wait until device * configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that * $CHIP file is open. Events must then be read from that descriptor, * such as configuration notifications.
*/
staticint is_valid_config(struct usb_config_descriptor *config, unsignedint total)
{ return config->bDescriptorType == USB_DT_CONFIG
&& config->bLength == USB_DT_CONFIG_SIZE
&& total >= USB_DT_CONFIG_SIZE
&& config->bConfigurationValue != 0
&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; /* FIXME if gadget->is_otg, _must_ include an otg descriptor */ /* FIXME check lengths: walk to end */
}
/* we might need to change message format someday */ if (copy_from_user (&tag, buf, 4)) return -EFAULT; if (tag != 0) return -EINVAL;
buf += 4;
length -= 4;
kbuf = memdup_user(buf, length); if (IS_ERR(kbuf)) return PTR_ERR(kbuf);
spin_lock_irq (&dev->lock);
value = -EINVAL; if (dev->buf) {
spin_unlock_irq(&dev->lock);
kfree(kbuf); return value;
}
dev->buf = kbuf;
/* full or low speed config */
dev->config = (void *) kbuf;
total = le16_to_cpu(dev->config->wTotalLength); if (!is_valid_config(dev->config, total) ||
total > length - USB_DT_DEVICE_SIZE) goto fail;
kbuf += total;
length -= total;
/* optional high speed config */ if (kbuf [1] == USB_DT_CONFIG) {
dev->hs_config = (void *) kbuf;
total = le16_to_cpu(dev->hs_config->wTotalLength); if (!is_valid_config(dev->hs_config, total) ||
total > length - USB_DT_DEVICE_SIZE) goto fail;
kbuf += total;
length -= total;
} else {
dev->hs_config = NULL;
}
/* could support multiple configs, using another encoding! */
/* triggers gadgetfs_bind(); then we can enumerate. */
spin_unlock_irq (&dev->lock); if (dev->hs_config)
gadgetfs_driver.max_speed = USB_SPEED_HIGH; else
gadgetfs_driver.max_speed = USB_SPEED_FULL;
value = usb_gadget_register_driver(&gadgetfs_driver); if (value != 0) {
spin_lock_irq(&dev->lock); goto fail;
} else { /* at this point "good" hardware has for the first time * let the USB the host see us. alternatively, if users * unplug/replug that will clear all the error state. * * note: everything running before here was guaranteed * to choke driver model style diagnostics. from here * on, they can work ... except in cleanup paths that * kick in after the ep0 descriptor is closed.
*/
value = len;
dev->gadget_registered = true;
} return value;
/* FILESYSTEM AND SUPERBLOCK OPERATIONS * * Mounting the filesystem creates a controller file, used first for * device configuration then later for event monitoring.
*/
/* FIXME PAM etc could set this security policy without mount options * if epfiles inherited ownership and permissons from ep0 ...
*/
/* the ep0 file is named after the controller we expect; * user mode code can use it for sanity checks, like we do.
*/
dev = dev_new (); if (!dev) goto Enomem;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.