// SPDX-License-Identifier: GPL-2.0+ /* * f_fs.c -- user mode file system API for USB composite function controllers * * Copyright (C) 2010 Samsung Electronics * Author: Michal Nazarewicz <mina86@mina86.com> * * Based on inode.c (GadgetFS) which was: * Copyright (C) 2003-2004 David Brownell * Copyright (C) 2003 Agilent Technologies
*/
/* * Buffer for holding data from partial reads which may happen since * we’re rounding user read requests to a multiple of a max packet size. * * The pointer is initialised with NULL value and may be set by * __ffs_epfile_read_data function to point to a temporary buffer. * * In normal operation, calls to __ffs_epfile_read_buffered will consume * data from said buffer and eventually free it. Importantly, while the * function is using the buffer, it sets the pointer to NULL. This is * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered * can never run concurrently (they are synchronised by epfile->mutex) * so the latter will not assign a new value to the pointer. * * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is * valid) and sets the pointer to READ_BUFFER_DROP value. This special * value is crux of the synchronisation between ffs_func_eps_disable and * __ffs_epfile_read_data. * * Once __ffs_epfile_read_data is about to finish it will try to set the * pointer back to its old value (as described above), but seeing as the * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free * the buffer. * * == State transitions == * * • ptr == NULL: (initial state) * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP * ◦ __ffs_epfile_read_buffered: nop * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == DROP: * ◦ __ffs_epfile_read_buffer_free: nop * ◦ __ffs_epfile_read_buffered: go to ptr == NULL * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == buf: * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered * is always called first * ◦ reading finishes: n/a, not in ‘and reading’ state * • ptr == NULL and reading: * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading * ◦ __ffs_epfile_read_buffered: n/a, mutex is held * ◦ __ffs_epfile_read_data: n/a, mutex is held * ◦ reading finishes and … * … all data read: free buf, go to ptr == NULL * … otherwise: go to ptr == buf and reading * • ptr == DROP and reading: * ◦ __ffs_epfile_read_buffer_free: nop * ◦ __ffs_epfile_read_buffered: n/a, mutex is held * ◦ __ffs_epfile_read_data: n/a, mutex is held * ◦ reading finishes: free buf, go to ptr == DROP
*/ struct ffs_buffer *read_buffer; #define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
if (!req) {
spin_unlock_irq(&ffs->ev.waitq.lock); return -EINVAL;
}
req->zero = len < le16_to_cpu(ffs->ev.setup.wLength);
spin_unlock_irq(&ffs->ev.waitq.lock);
req->buf = data;
req->length = len;
/* * UDC layer requires to provide a buffer even for ZLP, but should * not use it at all. Let's provide some poisoned pointer to catch * possible bug in the driver.
*/ if (req->buf == NULL)
req->buf = (void *)0xDEADBABE;
reinit_completion(&ffs->ep0req_completion);
ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); if (ret < 0) return ret;
ret = wait_for_completion_interruptible(&ffs->ep0req_completion); if (ret) {
usb_ep_dequeue(ffs->gadget->ep0, req); return -EINTR;
}
ret = ffs_ready(ffs); if (ret < 0) {
ffs->state = FFS_CLOSING; return ret;
}
return len;
} break;
case FFS_ACTIVE:
data = NULL; /* * We're called from user space, we can use _irq * rather then _irqsave
*/
spin_lock_irq(&ffs->ev.waitq.lock); switch (ffs_setup_state_clear_cancelled(ffs)) { case FFS_SETUP_CANCELLED:
ret = -EIDRM; goto done_spin;
case FFS_NO_SETUP:
ret = -ESRCH; goto done_spin;
case FFS_SETUP_PENDING: break;
}
/* FFS_SETUP_PENDING */ if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
spin_unlock_irq(&ffs->ev.waitq.lock);
ret = __ffs_ep0_stall(ffs); break;
}
/* FFS_SETUP_PENDING and not stall */
len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
spin_unlock_irq(&ffs->ev.waitq.lock);
data = ffs_prepare_buffer(buf, len); if (IS_ERR(data)) {
ret = PTR_ERR(data); break;
}
spin_lock_irq(&ffs->ev.waitq.lock);
/* * We are guaranteed to be still in FFS_ACTIVE state * but the state of setup could have changed from * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need * to check for that. If that happened we copied data * from user space in vain but it's unlikely. * * For sure we are not in FFS_NO_SETUP since this is * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP * transition can be performed and it's protected by * mutex.
*/ if (ffs_setup_state_clear_cancelled(ffs) ==
FFS_SETUP_CANCELLED) {
ret = -EIDRM;
done_spin:
spin_unlock_irq(&ffs->ev.waitq.lock);
} else { /* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len);
}
kfree(data); break;
default:
ret = -EBADFD; break;
}
mutex_unlock(&ffs->mutex); return ret;
}
/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
__releases(&ffs->ev.waitq.lock)
{ /* * n cannot be bigger than ffs->ev.count, which cannot be bigger than * size of ffs->ev.types array (which is four) so that's how much space * we reserve.
*/ struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)]; const size_t size = n * sizeof *events; unsigned i = 0;
memset(events, 0, size);
do {
events[i].type = ffs->ev.types[i]; if (events[i].type == FUNCTIONFS_SETUP) {
events[i].u.setup = ffs->ev.setup;
ffs->setup_state = FFS_SETUP_PENDING;
}
} while (++i < n);
ffs->ev.count -= n; if (ffs->ev.count)
memmove(ffs->ev.types, ffs->ev.types + n,
ffs->ev.count * sizeof *ffs->ev.types);
/* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM;
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); if (ret < 0) return ret;
/* Check state */ if (ffs->state != FFS_ACTIVE) {
ret = -EBADFD; goto done_mutex;
}
/* * We're called from user space, we can use _irq rather then * _irqsave
*/
spin_lock_irq(&ffs->ev.waitq.lock);
switch (ffs_setup_state_clear_cancelled(ffs)) { case FFS_SETUP_CANCELLED:
ret = -EIDRM; break;
case FFS_NO_SETUP:
n = len / sizeof(struct usb_functionfs_event); if (!n) {
ret = -EINVAL; break;
}
if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
ret = -EAGAIN; break;
}
if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
ffs->ev.count)) {
ret = -EINTR; break;
}
/* unlocks spinlock */ return __ffs_ep0_read_events(ffs, buf,
min_t(size_t, n, ffs->ev.count));
case FFS_SETUP_PENDING: if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
spin_unlock_irq(&ffs->ev.waitq.lock);
ret = __ffs_ep0_stall(ffs); goto done_mutex;
}
len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
spin_unlock_irq(&ffs->ev.waitq.lock);
if (len) {
data = kmalloc(len, GFP_KERNEL); if (!data) {
ret = -ENOMEM; goto done_mutex;
}
}
spin_lock_irq(&ffs->ev.waitq.lock);
/* See ffs_ep0_write() */ if (ffs_setup_state_clear_cancelled(ffs) ==
FFS_SETUP_CANCELLED) {
ret = -EIDRM; break;
}
/* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len); if ((ret > 0) && (copy_to_user(buf, data, len)))
ret = -EFAULT; goto done_mutex;
if (req->status)
io_data->status = req->status; else
io_data->status = req->actual;
complete(&io_data->done);
}
static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
{
ssize_t ret = copy_to_iter(data, data_len, iter); if (ret == data_len) return ret;
if (iov_iter_count(iter)) return -EFAULT;
/* * Dear user space developer! * * TL;DR: To stop getting below error message in your kernel log, change * user space code using functionfs to align read buffers to a max * packet size. * * Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max * packet size. When unaligned buffer is passed to functionfs, it * internally uses a larger, aligned buffer so that such UDCs are happy. * * Unfortunately, this means that host may send more data than was * requested in read(2) system call. f_fs doesn’t know what to do with * that excess data so it simply drops it. * * Was the buffer aligned in the first place, no such problem would * happen. * * Data may be dropped only in AIO reads. Synchronous reads are handled * by splitting a request into multiple parts. This splitting may still * be a problem though so it’s likely best to align the buffer * regardless of it being AIO or not.. * * This only affects OUT endpoints, i.e. reading data with a read(2), * aio_read(2) etc. system calls. Writing data to an IN endpoint is not * affected.
*/
pr_err("functionfs read size %d > requested size %zd, dropping excess data. " "Align read buffer size to max packet size to avoid the problem.\n",
data_len, ret);
return ret;
}
/* * allocate a virtually contiguous buffer and create a scatterlist describing it * @sg_table - pointer to a place to be filled with sg_table contents * @size - required buffer size
*/ staticvoid *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
{ struct page **pages; void *vaddr, *ptr; unsignedint n_pages; int i;
if (io_data->read && ret > 0) {
kthread_use_mm(io_data->mm);
ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
kthread_unuse_mm(io_data->mm);
}
io_data->kiocb->ki_complete(io_data->kiocb, ret);
if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd);
usb_ep_free_request(io_data->ep, io_data->req);
if (io_data->read)
kfree(io_data->to_free);
ffs_free_buffer(io_data);
kfree(io_data);
}
staticvoid __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
{ /* * See comment in struct ffs_epfile for full read_buffer pointer * synchronisation story.
*/ struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP); if (buf && buf != READ_BUFFER_DROP)
kfree(buf);
}
/* Assumes epfile->mutex is held. */ static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, struct iov_iter *iter)
{ /* * Null out epfile->read_buffer so ffs_func_eps_disable does not free * the buffer while we are using it. See comment in struct ffs_epfile * for full read_buffer pointer synchronisation story.
*/ struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL);
ssize_t ret; if (!buf || buf == READ_BUFFER_DROP) return 0;
ret = copy_to_iter(buf->data, buf->length, iter); if (buf->length == ret) {
kfree(buf); return ret;
}
if (iov_iter_count(iter)) {
ret = -EFAULT;
} else {
buf->length -= ret;
buf->data += ret;
}
if (cmpxchg(&epfile->read_buffer, NULL, buf))
kfree(buf);
/* * At this point read_buffer is NULL or READ_BUFFER_DROP (if * ffs_func_eps_disable has been called in the meanwhile). See comment * in struct ffs_epfile for full read_buffer pointer synchronisation * story.
*/ if (cmpxchg(&epfile->read_buffer, NULL, buf))
kfree(buf);
/* * Do we have buffered data from previous partial read? Check * that for synchronous case only because we do not have * facility to ‘wake up’ a pending asynchronous read and push * buffered data to it which we would need to make things behave * consistently.
*/ if (!io_data->aio && io_data->read) {
ret = __ffs_epfile_read_buffered(epfile, &io_data->data); if (ret) goto error_mutex;
}
/* * if we _do_ wait above, the epfile->ffs->gadget might be NULL * before the waiting completes, so do not assign to 'gadget' * earlier
*/
gadget = epfile->ffs->gadget;
spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ if (epfile->ep != ep) {
ret = -ESHUTDOWN; goto error_lock;
}
data_len = iov_iter_count(&io_data->data); /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint.
*/ if (io_data->read)
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
data = ffs_alloc_buffer(io_data, data_len); if (!data) {
ret = -ENOMEM; goto error_mutex;
} if (!io_data->read &&
!copy_from_iter_full(data, data_len, &io_data->data)) {
ret = -EFAULT; goto error_mutex;
}
}
spin_lock_irq(&epfile->ffs->eps_lock);
if (epfile->ep != ep) { /* In the meantime, endpoint got disabled or changed. */
ret = -ESHUTDOWN;
} elseif (halt) {
ret = usb_ep_set_halt(ep->ep); if (!ret)
ret = -EBADMSG;
} elseif (data_len == -EINVAL) { /* * Sanity Check: even though data_len can't be used * uninitialized at the time I write this comment, some * compilers complain about this situation. * In order to keep the code clean from warnings, data_len is * being initialized to -EINVAL during its declaration, which * means we can't rely on compiler anymore to warn no future * changes won't result in data_len being used uninitialized. * For such reason, we're adding this redundant sanity check * here.
*/
WARN(1, "%s: data_len == -EINVAL\n", __func__);
ret = -EINVAL;
} elseif (!io_data->aio) { bool interrupted = false;
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); if (ret < 0) goto error_lock;
spin_unlock_irq(&epfile->ffs->eps_lock);
if (wait_for_completion_interruptible(&io_data->done)) {
spin_lock_irq(&epfile->ffs->eps_lock); if (epfile->ep != ep) {
ret = -ESHUTDOWN; goto error_lock;
} /* * To avoid race condition with ffs_epfile_io_complete, * dequeue the request first then check * status. usb_ep_dequeue API should guarantee no race * condition with req->complete callback.
*/
usb_ep_dequeue(ep->ep, req);
spin_unlock_irq(&epfile->ffs->eps_lock);
wait_for_completion(&io_data->done);
interrupted = io_data->status < 0;
}
/* Close all attached DMABUFs */
list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) { /* Cancel any pending transfer */
spin_lock_irq(&ffs->eps_lock); if (priv->ep && priv->req)
usb_ep_dequeue(priv->ep, priv->req);
spin_unlock_irq(&ffs->eps_lock);
/* * The fence will be unref'd in ffs_dmabuf_cleanup. * It can't be done here, as the unref functions might try to lock * the resv object, which would deadlock.
*/
INIT_WORK(&dma_fence->work, ffs_dmabuf_cleanup);
queue_work(priv->ffs->io_completion_wq, &dma_fence->work);
}
if (req->flags & ~USB_FFS_DMABUF_TRANSFER_MASK) return -EINVAL;
dmabuf = dma_buf_get(req->fd); if (IS_ERR(dmabuf)) return PTR_ERR(dmabuf);
if (req->length > dmabuf->size || req->length == 0) {
ret = -EINVAL; goto err_dmabuf_put;
}
attach = ffs_dmabuf_find_attachment(epfile, dmabuf); if (IS_ERR(attach)) {
ret = PTR_ERR(attach); goto err_dmabuf_put;
}
priv = attach->importer_priv;
ep = ffs_epfile_wait_ep(file); if (IS_ERR(ep)) {
ret = PTR_ERR(ep); goto err_attachment_put;
}
ret = ffs_dma_resv_lock(dmabuf, nonblock); if (ret) goto err_attachment_put;
/* Make sure we don't have writers */
timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS);
retl = dma_resv_wait_timeout(dmabuf->resv,
dma_resv_usage_rw(epfile->in), true, timeout); if (retl == 0)
retl = -EBUSY; if (retl < 0) {
ret = (int)retl; goto err_resv_unlock;
}
ret = dma_resv_reserve_fences(dmabuf->resv, 1); if (ret) goto err_resv_unlock;
fence = kmalloc(sizeof(*fence), GFP_KERNEL); if (!fence) {
ret = -ENOMEM; goto err_resv_unlock;
}
fence->priv = priv;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */ if (epfile->ep != ep) {
ret = -ESHUTDOWN; goto err_fence_put;
}
usb_req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC); if (!usb_req) {
ret = -ENOMEM; goto err_fence_put;
}
/* * usb_ep_queue() guarantees that all transfers are processed in the * order they are enqueued, so we can use a simple incrementing * sequence number for the dma_fence.
*/
seqno = atomic_add_return(1, &epfile->seqno);
/* Wait for endpoint to be enabled */
ep = ffs_epfile_wait_ep(file); if (IS_ERR(ep)) return PTR_ERR(ep);
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */ if (epfile->ep != ep) {
spin_unlock_irq(&epfile->ffs->eps_lock); return -ESHUTDOWN;
}
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 desc1, *desc;
switch (epfile->ffs->gadget->speed) { case USB_SPEED_SUPER: case USB_SPEED_SUPER_PLUS:
desc_idx = 2; break; case USB_SPEED_HIGH:
desc_idx = 1; break; default:
desc_idx = 0;
}
/* * Set up the superblock for a mount.
*/ staticint ffs_fs_get_tree(struct fs_context *fc)
{ struct ffs_sb_fill_data *ctx = fc->fs_private; struct ffs_data *ffs; int ret;
if (!fc->source) return invalf(fc, "No source specified");
/* * potential race possible between ffs_func_eps_disable * & ffs_epfile_release therefore maintaining a local * copy of epfile will save us from use-after-free.
*/ if (epfiles) {
ffs_epfiles_destroy(epfiles, ffs->eps_count);
ffs->epfiles = NULL;
}
if (ffs->ffs_eventfd) {
eventfd_ctx_put(ffs->ffs_eventfd);
ffs->ffs_eventfd = NULL;
}
lang = ffs->stringtabs; if (lang) { for (; *lang; ++lang) { struct usb_string *str = (*lang)->strings; int id = first_id; for (; str->s; ++id, ++str)
str->id = id;
}
}
/* Parsing and building descriptors and strings *****************************/
/* * This validates if data pointed by data is a valid USB descriptor as * well as record how many interfaces, endpoints and strings are * required by given configuration. Returns address after the * descriptor or NULL if data is invalid.
*/
staticint __must_check ffs_do_single_desc(char *data, unsigned len,
ffs_entity_callback entity, void *priv, int *current_class, int *current_subclass)
{ struct usb_descriptor_header *_ds = (void *)data;
u8 length; int ret;
/* At least two bytes are required: length and type */ if (len < 2) {
pr_vdebug("descriptor too short\n"); return -EINVAL;
}
/* If we have at least as many bytes as the descriptor takes? */
length = _ds->bLength; if (len < length) {
pr_vdebug("descriptor longer then available data\n"); return -EINVAL;
}
/* Parse descriptor depending on type. */ switch (_ds->bDescriptorType) { case USB_DT_DEVICE: case USB_DT_CONFIG: case USB_DT_STRING: case USB_DT_DEVICE_QUALIFIER: /* function can't have any of those */
pr_vdebug("descriptor reserved for gadget: %d\n",
_ds->bDescriptorType); return -EINVAL;
case USB_DT_INTERFACE: { struct usb_interface_descriptor *ds = (void *)_ds;
pr_vdebug("interface descriptor\n"); if (length != sizeof *ds) goto inv_length;
case USB_TYPE_CLASS | 0x01: if (*current_class == USB_INTERFACE_CLASS_HID) {
pr_vdebug("hid descriptor\n"); if (length != sizeof(struct hid_descriptor)) goto inv_length; break;
} elseif (*current_class == USB_INTERFACE_CLASS_CCID) {
pr_vdebug("ccid descriptor\n"); if (length != sizeof(struct ccid_descriptor)) goto inv_length; break;
} elseif (*current_class == USB_CLASS_APP_SPEC &&
*current_subclass == USB_SUBCLASS_DFU) {
pr_vdebug("dfu functional descriptor\n"); if (length != sizeof(struct usb_dfu_functional_descriptor)) goto inv_length; break;
} else {
pr_vdebug("unknown descriptor: %d for class %d\n",
_ds->bDescriptorType, *current_class); return -EINVAL;
}
case USB_DT_OTG: if (length != sizeof(struct usb_otg_descriptor)) goto inv_length; break;
case USB_DT_INTERFACE_ASSOCIATION: { struct usb_interface_assoc_descriptor *ds = (void *)_ds;
pr_vdebug("interface association descriptor\n"); if (length != sizeof *ds) goto inv_length; if (ds->iFunction)
__entity(STRING, ds->iFunction);
} break;
case USB_DT_SS_ENDPOINT_COMP:
pr_vdebug("EP SS companion descriptor\n"); if (length != sizeof(struct usb_ss_ep_comp_descriptor)) goto inv_length; break;
case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_INTERFACE_POWER: case USB_DT_DEBUG: case USB_DT_SECURITY: case USB_DT_CS_RADIO_CONTROL: /* TODO */
pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType); return -EINVAL;
default: /* We should never be here */
pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType); return -EINVAL;
case FFS_INTERFACE: /* * Interfaces are indexed from zero so if we * encountered interface "n" then there are at least * "n+1" interfaces.
*/ if (*valuep >= helper->interfaces_count)
helper->interfaces_count = *valuep + 1; break;
case FFS_STRING: /* * Strings are indexed from 1 (0 is reserved * for languages list)
*/ if (*valuep > helper->ffs->strings_count)
helper->ffs->strings_count = *valuep; break;
case FFS_ENDPOINT:
d = (void *)desc;
helper->eps_count++; if (helper->eps_count >= FFS_MAX_EPS_COUNT) return -EINVAL; /* Check if descriptors for any speed were already parsed */ if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
helper->ffs->eps_addrmap[helper->eps_count] =
d->bEndpointAddress; elseif (helper->ffs->eps_addrmap[helper->eps_count] !=
d->bEndpointAddress) return -EINVAL; break;
}
if (bcd_version == 0x1) {
pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. " "Userspace driver should be fixed, accepting 0x0001 for compatibility.\n");
} elseif (bcd_version != 0x100) {
pr_vdebug("unsupported os descriptors version: 0x%x\n",
bcd_version); return -EINVAL;
} switch (w_index) { case 0x4:
*next_type = FFS_OS_DESC_EXT_COMPAT; break; case 0x5:
*next_type = FFS_OS_DESC_EXT_PROP; break; default:
pr_vdebug("unsupported os descriptor type: %d", w_index); return -EINVAL;
}
returnsizeof(*desc);
}
/* * Process all extended compatibility/extended property descriptors * of a feature descriptor
*/ staticint __must_check ffs_do_single_os_desc(char *data, unsigned len, enum ffs_os_desc_type type,
u16 feature_count,
ffs_os_desc_callback entity, void *priv, struct usb_os_desc_header *h)
{ int ret; constunsigned _len = len;
/* loop over all ext compat/ext prop descriptors */ while (feature_count--) {
ret = entity(type, h, data, len, priv); if (ret < 0) {
pr_debug("bad OS descriptor, type: %d\n", type); return ret;
}
data += ret;
len -= ret;
} return _len - len;
}
/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */ staticint __must_check ffs_do_os_descs(unsigned count, char *data, unsigned len,
ffs_os_desc_callback entity, void *priv)
{ constunsigned _len = len; unsignedlong num = 0;
for (num = 0; num < count; ++num) { int ret; enum ffs_os_desc_type type;
u16 feature_count; struct usb_os_desc_header *desc = (void *)data;
if (len < sizeof(*desc)) return -EINVAL;
/* * Record "descriptor" entity. * Process dwLength, bcdVersion, wIndex, get b/wCount. * Move the data pointer to the beginning of extended * compatibilities proper or extended properties proper * portions of the data
*/ if (le32_to_cpu(desc->dwLength) > len) return -EINVAL;
ret = __ffs_do_os_desc_header(&type, desc); if (ret < 0) {
pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
num, ret); return ret;
} /* * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
*/
feature_count = le16_to_cpu(desc->wCount); if (type == FFS_OS_DESC_EXT_COMPAT &&
(feature_count > 255 || desc->Reserved)) return -EINVAL;
len -= ret;
data += ret;
/* * Process all function/property descriptors * of this Feature Descriptor
*/
ret = ffs_do_single_os_desc(data, len, type,
feature_count, entity, priv, desc); if (ret < 0) {
pr_debug("%s returns %d\n", __func__, ret); return ret;
}
len -= ret;
data += ret;
} return _len - len;
}
/* * Validate contents of the buffer from userspace related to OS descriptors.
*/ staticint __ffs_data_do_os_desc(enum ffs_os_desc_type type, struct usb_os_desc_header *h, void *data, unsigned len, void *priv)
{ struct ffs_data *ffs = priv;
u8 length;
switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *d = data; int i;
if (len < sizeof(*d) ||
d->bFirstInterfaceNumber >= ffs->interfaces_count) return -EINVAL; if (d->Reserved1 != 1) { /* * According to the spec, Reserved1 must be set to 1 * but older kernels incorrectly rejected non-zero * values. We fix it here to avoid returning EINVAL * in response to values we used to accept.
*/
pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n");
d->Reserved1 = 1;
} for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) if (d->Reserved2[i]) return -EINVAL;
/* For each string */ do { /* str_count > 0 so we can use do-while */
size_t length = strnlen(data, len);
if (length == len) goto error_free;
/* * User may provide more strings then we need, * if that's the case we simply ignore the * rest
*/ if (needed) { /* * s->id will be set while adding * function to configuration so for * now just leave garbage here.
*/
s->s = data;
--needed;
++s;
}
data += length + 1;
len -= length + 1;
} while (--str_per_lang);
s->id = 0; /* terminator */
s->s = NULL;
++s;
} while (--lang_count);
/* Some garbage left? */ if (len) goto error_free;
/* * Abort any unhandled setup * * We do not need to worry about some cmpxchg() changing value * of ffs->setup_state without holding the lock because when * state is FFS_SETUP_PENDING cmpxchg() in several places in * the source does nothing.
*/ if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELLED;
/* * Logic of this function guarantees that there are at most four pending * evens on ffs->ev.types queue. This is important because the queue * has space for four elements only and __ffs_ep0_read_events function * depends on that limit as well. If more event types are added, those * limits have to be revisited or guaranteed to still hold.
*/ switch (type) { case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
fallthrough; case FUNCTIONFS_SUSPEND: case FUNCTIONFS_SETUP:
rem_type1 = type; /* Discard all similar events */ break;
case FUNCTIONFS_BIND: case FUNCTIONFS_UNBIND: case FUNCTIONFS_DISABLE: case FUNCTIONFS_ENABLE: /* Discard everything other then power management. */
rem_type1 = FUNCTIONFS_SUSPEND;
rem_type2 = FUNCTIONFS_RESUME;
neg = 1; break;
default:
WARN(1, "%d: unknown event, this should not happen\n", type); return;
}
/* * If ss_descriptors is not NULL, we are reading super speed * descriptors; if hs_descriptors is not NULL, we are reading high * speed descriptors; otherwise, we are reading full speed * descriptors.
*/ if (func->function.ss_descriptors) {
ep_desc_id = 2;
func->function.ss_descriptors[(long)valuep] = desc;
} elseif (func->function.hs_descriptors) {
ep_desc_id = 1;
func->function.hs_descriptors[(long)valuep] = desc;
} else {
ep_desc_id = 0;
func->function.fs_descriptors[(long)valuep] = desc;
}
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) return 0;
if (ffs_ep->descs[ep_desc_id]) {
pr_err("two %sspeed descriptors for EP %d\n",
speed_names[ep_desc_id],
usb_endpoint_num(ds)); return -EINVAL;
}
ffs_ep->descs[ep_desc_id] = ds;
ffs_dump_mem(": Original ep desc", ds, ds->bLength); if (ffs_ep->ep) {
ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress; if (!ds->wMaxPacketSize)
ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
} else { struct usb_request *req; struct usb_ep *ep;
u8 bEndpointAddress;
u16 wMaxPacketSize;
/* * We back up bEndpointAddress because autoconfig overwrites * it with physical endpoint address.
*/
bEndpointAddress = ds->bEndpointAddress; /* * We back up wMaxPacketSize because autoconfig treats * endpoint descriptors as if they were full speed.
*/
wMaxPacketSize = ds->wMaxPacketSize;
pr_vdebug("autoconfig\n");
ep = usb_ep_autoconfig(func->gadget, ds); if (!ep) return -ENOTSUPP;
ep->driver_data = func->eps + idx;
req = usb_ep_alloc_request(ep, GFP_KERNEL); if (!req) return -ENOMEM;
ffs_ep->ep = ep;
ffs_ep->req = req;
func->eps_revmap[ds->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK] = idx + 1; /* * If we use virtual address mapping, we restore * original bEndpointAddress value.
*/ if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
ds->bEndpointAddress = bEndpointAddress; /* * Restore wMaxPacketSize which was potentially * overwritten by autoconfig.
*/
ds->wMaxPacketSize = wMaxPacketSize;
}
ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
switch (type) { default: case FFS_DESCRIPTOR: /* Handled in previous pass by __ffs_func_bind_do_descs() */ return 0;
case FFS_INTERFACE:
idx = *valuep; if (func->interfaces_nums[idx] < 0) { int id = usb_interface_id(func->conf, &func->function); if (id < 0) return id;
func->interfaces_nums[idx] = id;
}
newValue = func->interfaces_nums[idx]; break;
case FFS_STRING: /* String' IDs are allocated when fsf_data is bound to cdev */
newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id; break;
case FFS_ENDPOINT: /* * USB_DT_ENDPOINT are handled in * __ffs_func_bind_do_descs().
*/ if (desc->bDescriptorType == USB_DT_ENDPOINT) return 0;
ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
func->ffs->ms_os_descs_ext_prop_data_avail +=
ext_prop->data_len;
memcpy(ext_prop_data,
usb_ext_prop_data_ptr(data, ext_prop->name_len),
ext_prop->data_len); /* unicode data reported to the host as "WCHAR"s */ switch (ext_prop->type) { case USB_EXT_PROP_UNICODE: case USB_EXT_PROP_UNICODE_ENV: case USB_EXT_PROP_UNICODE_LINK: case USB_EXT_PROP_UNICODE_MULTI:
ext_prop->data_len *= 2; break;
}
ext_prop->data = ext_prop_data;
memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
ext_prop->name_len); /* property name reported to the host as "WCHAR"s */
ext_prop->name_len *= 2;
ext_prop->name = ext_prop_name;
/* * Legacy gadget triggers binding in functionfs_ready_callback, * which already uses locking; taking the same lock here would * cause a deadlock. * * Configfs-enabled gadgets however do need ffs_dev_lock.
*/ if (!ffs_opts->no_configfs)
ffs_dev_lock();
ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
ffs_data = ffs_opts->dev->ffs_data; if (!ffs_opts->no_configfs)
ffs_dev_unlock(); if (ret) return ERR_PTR(ret);
/* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, * in each configuration its functions are bound in sequence * with list_for_each_entry, so we assume no race condition * with regard to ffs_opts->bound access
*/ if (!ffs_opts->refcnt) {
ret = functionfs_bind(func->ffs, c->cdev); if (ret) return ERR_PTR(ret);
}
ffs_opts->refcnt++;
func->function.strings = func->ffs->stringtabs;
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
eps_ptr = vla_ptr(vlabuf, d, eps); for (i = 0; i < ffs->eps_count; i++)
eps_ptr[i].num = -1;
/* Save pointers * d_eps == vlabuf, func->eps used to kfree vlabuf later
*/
func->eps = vla_ptr(vlabuf, d, eps);
func->interfaces_nums = vla_ptr(vlabuf, d, inums);
/* * Go through all the endpoint descriptors and allocate * endpoints first, so that later we can rewrite the endpoint * numbers without worrying that it may be described later on.
*/ if (full) {
func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
fs_len = ffs_do_descs(ffs->fs_descs_count,
vla_ptr(vlabuf, d, raw_descs),
d_raw_descs__sz,
__ffs_func_bind_do_descs, func); if (fs_len < 0) {
ret = fs_len; goto error;
}
} else {
fs_len = 0;
}
/* * Now handle interface numbers allocation and interface and * endpoint numbers rewriting. We can do that in one go * now.
*/
ret = ffs_do_descs(ffs->fs_descs_count +
(high ? ffs->hs_descs_count : 0) +
(super ? ffs->ss_descs_count : 0),
vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
__ffs_func_bind_do_nums, func); if (ret < 0) goto error;
func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); if (c->cdev->use_os_string) { for (i = 0; i < ffs->interfaces_count; ++i) { struct usb_os_desc *desc;
/* * Most requests directed to interface go through here * (notable exceptions are set/get interface) so we need to * handle them. All other either handled by composite or * passed to usb_configuration->setup() (if one is set). No * matter, we will handle requests directed to endpoint here * as well (as it's straightforward). Other request recipient * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP * is being used.
*/ if (ffs->state != FFS_ACTIVE) return -ENODEV;
switch (creq->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE:
ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); if (ret < 0) return ret; break;
case USB_RECIP_ENDPOINT:
ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); if (ret < 0) return ret; if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
ret = func->ffs->eps_addrmap[ret]; break;
default: if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP)
ret = le16_to_cpu(creq->wIndex); else return -EOPNOTSUPP;
}
data = memdup_user(buf, len); if (IS_ERR(data)) return data;
pr_vdebug("Buffer from user space:\n");
ffs_dump_mem("", data, len);
return data;
}
DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc);
MODULE_DESCRIPTION("user mode file system API for USB composite function controllers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Nazarewicz");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.55Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-27)
¤
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.