diff options
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r-- | drivers/usb/gadget/function/f_ecm.c | 22 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 103 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_tcm.c | 35 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_ether.c | 63 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_ether.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_fs.h | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/uvc_configfs.c | 121 |
7 files changed, 216 insertions, 134 deletions
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index a7ab30e603e2..c6e63ad77a40 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void) return &opts->func_inst; } +static void ecm_suspend(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Suspend\n"); + + gether_suspend(&ecm->port); +} + +static void ecm_resume(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Resume\n"); + + gether_resume(&ecm->port); +} + static void ecm_free(struct usb_function *f) { struct f_ecm *ecm; @@ -952,6 +972,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) ecm->port.func.setup = ecm_setup; ecm->port.func.disable = ecm_disable; ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; + ecm->port.func.resume = ecm_resume; return &ecm->port.func; } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index ddfc537c7526..a13c946e0663 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ssize_t ret; char *data; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, size_t n; int ret; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_private; - ENTER(); - if (ffs->state == FFS_CLOSING) return -EBUSY; @@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file) { struct ffs_data *ffs = file->private_data; - ENTER(); - ffs_data_closed(ffs); return 0; @@ -640,8 +632,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) struct usb_gadget *gadget = ffs->gadget; long ret; - ENTER(); - if (code == FUNCTIONFS_INTERFACE_REVMAP) { struct ffs_function *func = ffs->func; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; @@ -715,7 +705,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) { struct ffs_io_data *io_data = req->context; - ENTER(); if (req->status) io_data->status = req->status; else @@ -856,8 +845,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, struct ffs_io_data *io_data = req->context; struct ffs_data *ffs = io_data->ffs; - ENTER(); - io_data->status = req->status ? req->status : req->actual; usb_ep_free_request(_ep, req); @@ -1161,8 +1148,6 @@ ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb) unsigned long flags; int value; - ENTER(); - spin_lock_irqsave(&epfile->ffs->eps_lock, flags); if (io_data && io_data->ep && io_data->req) @@ -1198,8 +1181,6 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1235,8 +1216,6 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1251,7 +1230,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) p->kiocb = kiocb; if (p->aio) { p->to_free = dup_iter(&p->data, to, GFP_KERNEL); - if (!p->to_free) { + if (!iter_is_ubuf(&p->data) && !p->to_free) { kfree(p); return -ENOMEM; } @@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); @@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, struct ffs_ep *ep; int ret; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data, { struct inode *inode; - ENTER(); - inode = new_inode(sb); if (inode) { @@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, struct dentry *dentry; struct inode *inode; - ENTER(); - dentry = d_alloc_name(sb->s_root, name); if (!dentry) return NULL; @@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc) struct inode *inode; struct ffs_data *ffs = data->ffs_data; - ENTER(); - ffs->sb = sb; data->ffs_data = NULL; sb->s_fs_info = ffs; @@ -1521,8 +1490,6 @@ static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param) struct fs_parse_result result; int opt; - ENTER(); - opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result); if (opt < 0) return opt; @@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc) struct ffs_data *ffs; int ret; - ENTER(); - if (!fc->source) return invalf(fc, "No source specified"); @@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) static void ffs_fs_kill_sb(struct super_block *sb) { - ENTER(); - kill_litter_super(sb); if (sb->s_fs_info) ffs_data_closed(sb->s_fs_info); @@ -1663,8 +1626,6 @@ static int functionfs_init(void) { int ret; - ENTER(); - ret = register_filesystem(&ffs_fs_type); if (!ret) pr_info("file system registered\n"); @@ -1676,8 +1637,6 @@ static int functionfs_init(void) static void functionfs_cleanup(void) { - ENTER(); - pr_info("unloading\n"); unregister_filesystem(&ffs_fs_type); } @@ -1690,15 +1649,11 @@ static void ffs_data_reset(struct ffs_data *ffs); static void ffs_data_get(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); } static void ffs_data_opened(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && ffs->state == FFS_DEACTIVATED) { @@ -1709,8 +1664,6 @@ static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_put(struct ffs_data *ffs) { - ENTER(); - if (refcount_dec_and_test(&ffs->ref)) { pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); @@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - if (atomic_dec_and_test(&ffs->opened)) { if (ffs->no_disconnect) { ffs->state = FFS_DEACTIVATED; @@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name) if (!ffs) return NULL; - ENTER(); - ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name); if (!ffs->io_completion_wq) { kfree(ffs); @@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - ffs_closed(ffs); BUG_ON(ffs->gadget); @@ -1826,8 +1773,6 @@ static void ffs_data_clear(struct ffs_data *ffs) static void ffs_data_reset(struct ffs_data *ffs) { - ENTER(); - ffs_data_clear(ffs); ffs->raw_descs_data = NULL; @@ -1861,8 +1806,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) struct usb_gadget_strings **lang; int first_id; - ENTER(); - if (WARN_ON(ffs->state != FFS_ACTIVE || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) return -EBADFD; @@ -1894,8 +1837,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) static void functionfs_unbind(struct ffs_data *ffs) { - ENTER(); - if (!WARN_ON(!ffs->gadget)) { /* dequeue before freeing ep0req */ usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req); @@ -1914,8 +1855,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs) struct ffs_epfile *epfile, *epfiles; unsigned i, count; - ENTER(); - count = ffs->eps_count; epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) @@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) { struct ffs_epfile *epfile = epfiles; - ENTER(); - for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { @@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, u8 length; int ret; - ENTER(); - /* At least two bytes are required: length and type */ if (len < 2) { pr_vdebug("descriptor too short\n"); @@ -2204,8 +2139,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, unsigned long num = 0; int current_class = -1; - ENTER(); - for (;;) { int ret; @@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, struct ffs_desc_helper *helper = priv; struct usb_endpoint_descriptor *d; - ENTER(); - switch (type) { case FFS_DESCRIPTOR: break; @@ -2292,8 +2223,11 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, u16 bcd_version = le16_to_cpu(desc->bcdVersion); u16 w_index = le16_to_cpu(desc->wIndex); - if (bcd_version != 1) { - pr_vdebug("unsupported os descriptors version: %d", + 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"); + } else if (bcd_version != 0x100) { + pr_vdebug("unsupported os descriptors version: 0x%x\n", bcd_version); return -EINVAL; } @@ -2326,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, int ret; const unsigned _len = len; - ENTER(); - /* loop over all ext compat/ext prop descriptors */ while (feature_count--) { ret = entity(type, h, data, len, priv); @@ -2349,8 +2281,6 @@ static int __must_check ffs_do_os_descs(unsigned count, const unsigned _len = len; unsigned long num = 0; - ENTER(); - for (num = 0; num < count; ++num) { int ret; enum ffs_os_desc_type type; @@ -2413,8 +2343,6 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, struct ffs_data *ffs = priv; u8 length; - ENTER(); - switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *d = data; @@ -2490,8 +2418,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, int ret = -EINVAL, i; struct ffs_desc_helper helper; - ENTER(); - if (get_unaligned_le32(data + 4) != len) goto error; @@ -2622,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, const char *data = _data; struct usb_string *s; - ENTER(); - if (len < 16 || get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data + 4) != len) @@ -3082,8 +3006,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, struct ffs_data *ffs_data; int ret; - ENTER(); - /* * Legacy gadget triggers binding in functionfs_ready_callback, * which already uses locking; taking the same lock here would @@ -3160,8 +3082,6 @@ static int _ffs_func_bind(struct usb_configuration *c, vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; - ENTER(); - /* Has descriptors only for speeds gadget does not support */ if (!(full | high | super)) return -ENOTSUPP; @@ -3365,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f, unsigned long flags; int ret; - ENTER(); - pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); @@ -3441,13 +3359,11 @@ static bool ffs_func_req_match(struct usb_function *f, static void ffs_func_suspend(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); } static void ffs_func_resume(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); } @@ -3611,7 +3527,6 @@ static void ffs_func_unbind(struct usb_configuration *c, unsigned count = ffs->eps_count; unsigned long flags; - ENTER(); if (ffs->func == func) { ffs_func_eps_disable(func); ffs->func = NULL; @@ -3651,8 +3566,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) { struct ffs_function *func; - ENTER(); - func = kzalloc(sizeof(*func), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); @@ -3753,7 +3666,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) int ret = 0; struct ffs_dev *ffs_dev; - ENTER(); ffs_dev_lock(); ffs_dev = _ffs_find_dev(dev_name); @@ -3776,7 +3688,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) static void ffs_release_dev(struct ffs_dev *ffs_dev) { - ENTER(); ffs_dev_lock(); if (ffs_dev && ffs_dev->mounted) { @@ -3798,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs) struct ffs_dev *ffs_obj; int ret = 0; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; @@ -3831,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs) struct f_fs_opts *opts; struct config_item *ci; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 658e2e21fdd0..79ed2e6e576a 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1054,7 +1054,7 @@ static void usbg_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense, - cmd->unpacked_lun); + cmd->unpacked_lun, NULL); goto out; } @@ -1183,7 +1183,7 @@ static void bot_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense, - cmd->unpacked_lun); + cmd->unpacked_lun, NULL); goto out; } @@ -1253,11 +1253,6 @@ static int usbg_check_true(struct se_portal_group *se_tpg) return 1; } -static int usbg_check_false(struct se_portal_group *se_tpg) -{ - return 0; -} - static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg) { struct usbg_tpg *tpg = container_of(se_tpg, @@ -1274,11 +1269,6 @@ static u16 usbg_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) -{ - return 1; -} - static void usbg_release_cmd(struct se_cmd *se_cmd) { struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, @@ -1289,20 +1279,6 @@ static void usbg_release_cmd(struct se_cmd *se_cmd) target_free_tag(se_sess, se_cmd); } -static u32 usbg_sess_get_index(struct se_session *se_sess) -{ - return 0; -} - -static void usbg_set_default_node_attrs(struct se_node_acl *nacl) -{ -} - -static int usbg_get_cmd_state(struct se_cmd *se_cmd) -{ - return 0; -} - static void usbg_queue_tm_rsp(struct se_cmd *se_cmd) { } @@ -1691,16 +1667,9 @@ static const struct target_core_fabric_ops usbg_ops = { .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, .tpg_check_demo_mode = usbg_check_true, - .tpg_check_demo_mode_cache = usbg_check_false, - .tpg_check_demo_mode_write_protect = usbg_check_false, - .tpg_check_prod_mode_write_protect = usbg_check_false, - .tpg_get_inst_index = usbg_tpg_get_inst_index, .release_cmd = usbg_release_cmd, - .sess_get_index = usbg_sess_get_index, .sess_get_initiator_sid = NULL, .write_pending = usbg_send_write_request, - .set_default_node_attributes = usbg_set_default_node_attrs, - .get_cmd_state = usbg_get_cmd_state, .queue_data_in = usbg_send_read_response, .queue_status = usbg_send_status_response, .queue_tm_rsp = usbg_queue_tm_rsp, diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index f259975dfba4..6956ad8ba8dd 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -437,6 +437,20 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } +static int ether_wakeup_host(struct gether *port) +{ + int ret; + struct usb_function *func = &port->func; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (func->func_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + return ret; +} + static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -456,6 +470,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, in = NULL; cdc_filter = 0; } + + if (dev->port_usb && dev->port_usb->is_suspend) { + DBG(dev, "Port suspended. Triggering wakeup\n"); + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->lock, flags); + ether_wakeup_host(dev->port_usb); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&dev->lock, flags); if (!in) { @@ -1014,6 +1037,45 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); +void gether_suspend(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (atomic_read(&dev->tx_qlen)) { + /* + * There is a transfer in progress. So we trigger a remote + * wakeup to inform the host. + */ + ether_wakeup_host(dev->port_usb); + return; + } + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = true; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_suspend); + +void gether_resume(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (netif_queue_stopped(dev->net)) + netif_start_queue(dev->net); + + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = false; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_resume); + /* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep @@ -1176,6 +1238,7 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; + link->is_suspend = false; spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 40144546d1b0..851ee10d6e63 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -79,6 +79,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); + bool is_suspend; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ @@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len); void gether_cleanup(struct eth_dev *dev); +void gether_suspend(struct gether *link); +void gether_resume(struct gether *link); + /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *); void gether_disconnect(struct gether *); diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index f102ec23f3af..4b3365f23fd7 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -32,8 +32,6 @@ # define ffs_dump_mem(prefix, ptr, len) do { } while (0) #endif /* VERBOSE_DEBUG */ -#define ENTER() pr_vdebug("%s()\n", __func__) - struct f_fs_opts; struct ffs_dev { diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 62b759bb7613..9bf0e985acfa 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8); #undef UVCG_DEFAULT_PROCESSING_ATTR +static ssize_t uvcg_default_processing_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_processing_unit_descriptor *pd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + pd = &opts->uvc_processing; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > pd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + pd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_processing_bm_controls_show( struct config_item *item, char *page) { @@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_processing_attrs[] = { &uvcg_default_processing_attr_b_unit_id, @@ -445,6 +503,65 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, #undef UVCG_DEFAULT_CAMERA_ATTR +static ssize_t uvcg_default_camera_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_camera_terminal_descriptor *cd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> + ci_parent; + opts = to_f_uvc_opts(opts_item); + cd = &opts->uvc_camera_terminal; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > cd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + cd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_camera_bm_controls_show( struct config_item *item, char *page) { @@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_camera_attrs[] = { &uvcg_default_camera_attr_b_terminal_id, |