From d635711daa98be86d4c7fd01499c34f566b54ccb Mon Sep 17 00:00:00 2001 From: AndrĂ© Fabian Silva Delgado Date: Fri, 10 Jun 2016 05:30:17 -0300 Subject: Linux-libre 4.6.2-gnu --- drivers/usb/gadget/function/f_acm.c | 6 +- drivers/usb/gadget/function/f_ecm.c | 2 +- drivers/usb/gadget/function/f_eem.c | 2 +- drivers/usb/gadget/function/f_fs.c | 161 ++++++++++---------- drivers/usb/gadget/function/f_hid.c | 2 +- drivers/usb/gadget/function/f_loopback.c | 2 +- drivers/usb/gadget/function/f_mass_storage.c | 44 +++--- drivers/usb/gadget/function/f_mass_storage.h | 2 - drivers/usb/gadget/function/f_midi.c | 211 +++++++++++++-------------- drivers/usb/gadget/function/f_ncm.c | 2 +- drivers/usb/gadget/function/f_obex.c | 3 +- drivers/usb/gadget/function/f_phonet.c | 2 +- drivers/usb/gadget/function/f_printer.c | 2 +- drivers/usb/gadget/function/f_rndis.c | 7 +- drivers/usb/gadget/function/f_serial.c | 2 +- drivers/usb/gadget/function/f_sourcesink.c | 2 +- drivers/usb/gadget/function/f_subset.c | 2 +- drivers/usb/gadget/function/f_tcm.c | 195 +++++++++++-------------- drivers/usb/gadget/function/f_uac1.c | 3 +- drivers/usb/gadget/function/f_uac2.c | 3 +- drivers/usb/gadget/function/rndis.c | 20 +-- drivers/usb/gadget/function/tcm.h | 2 + drivers/usb/gadget/function/uvc_configfs.c | 198 ++++++++++--------------- 23 files changed, 396 insertions(+), 479 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 2fa1e80a3..a30766ca4 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -685,7 +685,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function, - acm_ss_function); + acm_ss_function, NULL); if (status) goto fail; @@ -777,10 +777,10 @@ static ssize_t f_acm_port_num_show(struct config_item *item, char *page) return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num); } -CONFIGFS_ATTR_RO(f_acm_port_, num); +CONFIGFS_ATTR_RO(f_acm_, port_num); static struct configfs_attribute *acm_attrs[] = { - &f_acm_port_attr_num, + &f_acm_attr_port_num, NULL, }; diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index 7ad60ee41..4c488d15b 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -786,7 +786,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) fs_ecm_notify_desc.bEndpointAddress; status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function, - ecm_ss_function); + ecm_ss_function, NULL); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c index cad35a502..d58bfc32b 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -309,7 +309,7 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function, - eem_ss_function); + eem_ss_function, NULL); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 79d895c2d..73515d54e 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read && ret > 0) { use_mm(io_data->mm); ret = copy_to_iter(io_data->buf, ret, &io_data->data); - if (iov_iter_count(&io_data->data)) + if (ret != io_data->req->actual && iov_iter_count(&io_data->data)) ret = -EFAULT; unuse_mm(io_data->mm); } @@ -683,44 +683,38 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) { struct ffs_epfile *epfile = file->private_data; + struct usb_request *req; struct ffs_ep *ep; char *data = NULL; ssize_t ret, data_len = -EINVAL; int halt; /* Are we still active? */ - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { - ret = -ENODEV; - goto error; - } + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) + return -ENODEV; /* Wait for endpoint to be enabled */ ep = epfile->ep; if (!ep) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto error; - } + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); - if (ret) { - ret = -EINTR; - goto error; - } + if (ret) + return -EINTR; } /* Do we halt? */ halt = (!io_data->read == !epfile->in); - if (halt && epfile->isoc) { - ret = -EINVAL; - goto error; - } + if (halt && epfile->isoc) + return -EINVAL; /* Allocate & copy */ if (!halt) { /* * if we _do_ wait above, the epfile->ffs->gadget might be NULL - * before the waiting completes, so do not assign to 'gadget' earlier + * before the waiting completes, so do not assign to 'gadget' + * earlier */ struct usb_gadget *gadget = epfile->ffs->gadget; size_t copied; @@ -762,17 +756,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (epfile->ep != ep) { /* In the meantime, endpoint got disabled or changed. */ ret = -ESHUTDOWN; - spin_unlock_irq(&epfile->ffs->eps_lock); } else if (halt) { /* Halt */ if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) usb_ep_set_halt(ep->ep); - spin_unlock_irq(&epfile->ffs->eps_lock); ret = -EBADMSG; - } else { - /* Fire the request */ - struct usb_request *req; - + } else if (unlikely(data_len == -EINVAL)) { /* * Sanity Check: even though data_len can't be used * uninitialized at the time I write this comment, some @@ -784,80 +773,80 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * For such reason, we're adding this redundant sanity check * here. */ - if (unlikely(data_len == -EINVAL)) { - WARN(1, "%s: data_len == -EINVAL\n", __func__); - ret = -EINVAL; - goto error_lock; - } - - if (io_data->aio) { - req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); - if (unlikely(!req)) - goto error_lock; - - req->buf = data; - req->length = data_len; + WARN(1, "%s: data_len == -EINVAL\n", __func__); + ret = -EINVAL; + } else if (!io_data->aio) { + DECLARE_COMPLETION_ONSTACK(done); + bool interrupted = false; - io_data->buf = data; - io_data->ep = ep->ep; - io_data->req = req; - io_data->ffs = epfile->ffs; + req = ep->req; + req->buf = data; + req->length = data_len; - req->context = io_data; - req->complete = ffs_epfile_async_io_complete; + req->context = &done; + req->complete = ffs_epfile_io_complete; - ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); - if (unlikely(ret)) { - usb_ep_free_request(ep->ep, req); - goto error_lock; - } - ret = -EIOCBQUEUED; + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + if (unlikely(ret < 0)) + goto error_lock; - spin_unlock_irq(&epfile->ffs->eps_lock); - } else { - DECLARE_COMPLETION_ONSTACK(done); + spin_unlock_irq(&epfile->ffs->eps_lock); - req = ep->req; - req->buf = data; - req->length = data_len; + if (unlikely(wait_for_completion_interruptible(&done))) { + /* + * 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); + interrupted = ep->status < 0; + } - req->context = &done; - req->complete = ffs_epfile_io_complete; + /* + * XXX We may end up silently droping data here. Since data_len + * (i.e. req->length) may be bigger than len (after being + * rounded up to maxpacketsize), we may end up with more data + * then user space has space for. + */ + ret = interrupted ? -EINTR : ep->status; + if (io_data->read && ret > 0) { + ret = copy_to_iter(data, ret, &io_data->data); + if (!ret) + ret = -EFAULT; + } + goto error_mutex; + } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) { + ret = -ENOMEM; + } else { + req->buf = data; + req->length = data_len; - ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + io_data->buf = data; + io_data->ep = ep->ep; + io_data->req = req; + io_data->ffs = epfile->ffs; - spin_unlock_irq(&epfile->ffs->eps_lock); + req->context = io_data; + req->complete = ffs_epfile_async_io_complete; - if (unlikely(ret < 0)) { - /* nop */ - } else if (unlikely( - wait_for_completion_interruptible(&done))) { - ret = -EINTR; - usb_ep_dequeue(ep->ep, req); - } else { - /* - * XXX We may end up silently droping data - * here. Since data_len (i.e. req->length) may - * be bigger than len (after being rounded up - * to maxpacketsize), we may end up with more - * data then user space has space for. - */ - ret = ep->status; - if (io_data->read && ret > 0) { - ret = copy_to_iter(data, ret, &io_data->data); - if (!ret) - ret = -EFAULT; - } - } - kfree(data); + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + if (unlikely(ret)) { + usb_ep_free_request(ep->ep, req); + goto error_lock; } - } - mutex_unlock(&epfile->mutex); - return ret; + ret = -EIOCBQUEUED; + /* + * Do not kfree the buffer in this function. It will be freed + * by ffs_user_copy_worker. + */ + data = NULL; + } error_lock: spin_unlock_irq(&epfile->ffs->eps_lock); +error_mutex: mutex_unlock(&epfile->mutex); error: kfree(data); @@ -1157,8 +1146,8 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) ffs->sb = sb; data->ffs_data = NULL; sb->s_fs_info = ffs; - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_blocksize = PAGE_SIZE; + sb->s_blocksize_bits = PAGE_SHIFT; sb->s_magic = FUNCTIONFS_MAGIC; sb->s_op = &ffs_sb_operations; sb->s_time_gran = 1; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 99285b416..51980c505 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -646,7 +646,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_fs_out_ep_desc.bEndpointAddress; status = usb_assign_descriptors(f, hidg_fs_descriptors, - hidg_hs_descriptors, NULL); + hidg_hs_descriptors, NULL, NULL); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index ddc3aad88..3a9f8f9c7 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -211,7 +211,7 @@ autoconf_fail: ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs, - ss_loopback_descs); + ss_loopback_descs, NULL); if (ret) return ret; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 223ccf89d..5c6d4d7ca 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, } EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); -int fsg_common_run_thread(struct fsg_common *common) -{ - common->state = FSG_STATE_IDLE; - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); - if (IS_ERR(common->thread_task)) { - common->state = FSG_STATE_TERMINATED; - return PTR_ERR(common->thread_task); - } - - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - - wake_up_process(common->thread_task); - - return 0; -} -EXPORT_SYMBOL_GPL(fsg_common_run_thread); - static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); @@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref) if (common->state != FSG_STATE_TERMINATED) { raise_exception(common, FSG_STATE_EXIT); wait_for_completion(&common->thread_notifier); + common->thread_task = NULL; } for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { @@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) if (ret) return ret; fsg_common_set_inquiry_string(fsg->common, NULL, NULL); - ret = fsg_common_run_thread(fsg->common); - if (ret) + } + + if (!common->thread_task) { + common->state = FSG_STATE_IDLE; + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + int ret = PTR_ERR(common->thread_task); + common->thread_task = NULL; + common->state = FSG_STATE_TERMINATED; return ret; + } + DBG(common, "I/O thread pid: %d\n", + task_pid_nr(common->thread_task)); + wake_up_process(common->thread_task); } fsg->gadget = gadget; @@ -3093,7 +3087,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function, - fsg_ss_function); + fsg_ss_function, fsg_ss_function); if (ret) goto autoconf_fail; @@ -3484,12 +3478,12 @@ static struct usb_function_instance *fsg_alloc_inst(void) opts->lun0.lun = opts->common->luns[0]; opts->lun0.lun_id = 0; - config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); - opts->default_groups[0] = &opts->lun0.group; - opts->func_inst.group.default_groups = opts->default_groups; config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type); + config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); + configfs_add_default_group(&opts->lun0.group, &opts->func_inst.group); + return &opts->func_inst; release_buffers: diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 445df6775..b6a9918ea 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn); -int fsg_common_run_thread(struct fsg_common *common); - void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index fb1fe96d3..58fc199a1 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,7 @@ static const char f_midi_longname[] = "MIDI Gadget"; * USB <- IN endpoint <- rawmidi */ struct gmidi_in_port { - struct f_midi *midi; + struct snd_rawmidi_substream *substream; int active; uint8_t cable; uint8_t state; @@ -78,9 +79,7 @@ struct f_midi { struct snd_rawmidi *rmidi; u8 ms_id; - struct snd_rawmidi_substream *in_substream[MAX_PORTS]; struct snd_rawmidi_substream *out_substream[MAX_PORTS]; - struct gmidi_in_port *in_port[MAX_PORTS]; unsigned long out_triggered; struct tasklet_struct tasklet; @@ -91,7 +90,10 @@ struct f_midi { unsigned int buflen, qlen; /* This fifo is used as a buffer ring for pre-allocated IN usb_requests */ DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); + spinlock_t transmit_lock; unsigned int in_last_port; + + struct gmidi_in_port in_ports_array[/* in_ports */]; }; static inline struct f_midi *func_to_midi(struct usb_function *f) @@ -358,7 +360,9 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* allocate a bunch of read buffers and queue them all at once. */ for (i = 0; i < midi->qlen && err == 0; i++) { struct usb_request *req = - midi_alloc_ep_req(midi->out_ep, midi->buflen); + midi_alloc_ep_req(midi->out_ep, + max_t(unsigned, midi->buflen, + bulk_out_desc.wMaxPacketSize)); if (req == NULL) return -ENOMEM; @@ -518,98 +522,102 @@ static void f_midi_drop_out_substreams(struct f_midi *midi) { unsigned int i; - for (i = 0; i < MAX_PORTS; i++) { - struct gmidi_in_port *port = midi->in_port[i]; - struct snd_rawmidi_substream *substream = midi->in_substream[i]; + for (i = 0; i < midi->in_ports; i++) { + struct gmidi_in_port *port = midi->in_ports_array + i; + struct snd_rawmidi_substream *substream = port->substream; + if (port->active && substream) + snd_rawmidi_drop_output(substream); + } +} - if (!port) - break; +static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep) +{ + struct usb_request *req = NULL; + unsigned int len, i; + bool active = false; + int err; + + /* + * We peek the request in order to reuse it if it fails to enqueue on + * its endpoint + */ + len = kfifo_peek(&midi->in_req_fifo, &req); + if (len != 1) { + ERROR(midi, "%s: Couldn't get usb request\n", __func__); + return -1; + } + + /* + * If buffer overrun, then we ignore this transmission. + * IMPORTANT: This will cause the user-space rawmidi device to block + * until a) usb requests have been completed or b) snd_rawmidi_write() + * times out. + */ + if (req->length > 0) + return 0; + + for (i = midi->in_last_port; i < midi->in_ports; ++i) { + struct gmidi_in_port *port = midi->in_ports_array + i; + struct snd_rawmidi_substream *substream = port->substream; if (!port->active || !substream) continue; - snd_rawmidi_drop_output(substream); + while (req->length + 3 < midi->buflen) { + uint8_t b; + + if (snd_rawmidi_transmit(substream, &b, 1) != 1) { + port->active = 0; + break; + } + f_midi_transmit_byte(req, port, b); + } + + active = !!port->active; + if (active) + break; + } + midi->in_last_port = active ? i : 0; + + if (req->length <= 0) + goto done; + + err = usb_ep_queue(ep, req, GFP_ATOMIC); + if (err < 0) { + ERROR(midi, "%s failed to queue req: %d\n", + midi->in_ep->name, err); + req->length = 0; /* Re-use request next time. */ + } else { + /* Upon success, put request at the back of the queue. */ + kfifo_skip(&midi->in_req_fifo); + kfifo_put(&midi->in_req_fifo, req); } + +done: + return active; } static void f_midi_transmit(struct f_midi *midi) { struct usb_ep *ep = midi->in_ep; - bool active; + int ret; + unsigned long flags; /* We only care about USB requests if IN endpoint is enabled */ if (!ep || !ep->enabled) goto drop_out; - do { - struct usb_request *req = NULL; - unsigned int len, i; + spin_lock_irqsave(&midi->transmit_lock, flags); - active = false; - - /* We peek the request in order to reuse it if it fails - * to enqueue on its endpoint */ - len = kfifo_peek(&midi->in_req_fifo, &req); - if (len != 1) { - ERROR(midi, "%s: Couldn't get usb request\n", __func__); + do { + ret = f_midi_do_transmit(midi, ep); + if (ret < 0) { + spin_unlock_irqrestore(&midi->transmit_lock, flags); goto drop_out; } + } while (ret); - /* If buffer overrun, then we ignore this transmission. - * IMPORTANT: This will cause the user-space rawmidi device to block until a) usb - * requests have been completed or b) snd_rawmidi_write() times out. */ - if (req->length > 0) - return; - - for (i = midi->in_last_port; i < MAX_PORTS; i++) { - struct gmidi_in_port *port = midi->in_port[i]; - struct snd_rawmidi_substream *substream = midi->in_substream[i]; - - if (!port) { - /* Reset counter when we reach the last available port */ - midi->in_last_port = 0; - break; - } - - if (!port->active || !substream) - continue; - - while (req->length + 3 < midi->buflen) { - uint8_t b; - - if (snd_rawmidi_transmit(substream, &b, 1) != 1) { - port->active = 0; - break; - } - f_midi_transmit_byte(req, port, b); - } - - active = !!port->active; - /* Check if last port is still active, which means that - * there is still data on that substream but this current - * request run out of space. */ - if (active) { - midi->in_last_port = i; - /* There is no need to re-iterate though midi ports. */ - break; - } - } - - if (req->length > 0) { - int err; - - err = usb_ep_queue(ep, req, GFP_ATOMIC); - if (err < 0) { - ERROR(midi, "%s failed to queue req: %d\n", - midi->in_ep->name, err); - req->length = 0; /* Re-use request next time. */ - } else { - /* Upon success, put request at the back of the queue. */ - kfifo_skip(&midi->in_req_fifo); - kfifo_put(&midi->in_req_fifo, req); - } - } - } while (active); + spin_unlock_irqrestore(&midi->transmit_lock, flags); return; @@ -626,13 +634,15 @@ static void f_midi_in_tasklet(unsigned long data) static int f_midi_in_open(struct snd_rawmidi_substream *substream) { struct f_midi *midi = substream->rmidi->private_data; + struct gmidi_in_port *port; - if (!midi->in_port[substream->number]) + if (substream->number >= midi->in_ports) return -EINVAL; VDBG(midi, "%s()\n", __func__); - midi->in_substream[substream->number] = substream; - midi->in_port[substream->number]->state = STATE_UNKNOWN; + port = midi->in_ports_array + substream->number; + port->substream = substream; + port->state = STATE_UNKNOWN; return 0; } @@ -648,11 +658,11 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) { struct f_midi *midi = substream->rmidi->private_data; - if (!midi->in_port[substream->number]) + if (substream->number >= midi->in_ports) return; VDBG(midi, "%s() %d\n", __func__, up); - midi->in_port[substream->number]->active = up; + midi->in_ports_array[substream->number].active = up; if (up) tasklet_hi_schedule(&midi->tasklet); } @@ -1128,14 +1138,11 @@ static void f_midi_free(struct usb_function *f) { struct f_midi *midi; struct f_midi_opts *opts; - int i; midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); kfree(midi->id); mutex_lock(&opts->lock); - for (i = opts->in_ports - 1; i >= 0; --i) - kfree(midi->in_port[i]); kfifo_free(&midi->in_req_fifo); kfree(midi); --opts->refcnt; @@ -1163,7 +1170,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) { - struct f_midi *midi; + struct f_midi *midi = NULL; struct f_midi_opts *opts; int status, i; @@ -1172,37 +1179,26 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) mutex_lock(&opts->lock); /* sanity check */ if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) { - mutex_unlock(&opts->lock); - return ERR_PTR(-EINVAL); + status = -EINVAL; + goto setup_fail; } /* allocate and initialize one new instance */ - midi = kzalloc(sizeof(*midi), GFP_KERNEL); + midi = kzalloc( + sizeof(*midi) + opts->in_ports * sizeof(*midi->in_ports_array), + GFP_KERNEL); if (!midi) { - mutex_unlock(&opts->lock); - return ERR_PTR(-ENOMEM); + status = -ENOMEM; + goto setup_fail; } - for (i = 0; i < opts->in_ports; i++) { - struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); - - if (!port) { - status = -ENOMEM; - mutex_unlock(&opts->lock); - goto setup_fail; - } - - port->midi = midi; - port->active = 0; - port->cable = i; - midi->in_port[i] = port; - } + for (i = 0; i < opts->in_ports; i++) + midi->in_ports_array[i].cable = i; /* set up ALSA midi devices */ midi->id = kstrdup(opts->id, GFP_KERNEL); if (opts->id && !midi->id) { status = -ENOMEM; - mutex_unlock(&opts->lock); goto setup_fail; } midi->in_ports = opts->in_ports; @@ -1216,6 +1212,8 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) if (status) goto setup_fail; + spin_lock_init(&midi->transmit_lock); + ++opts->refcnt; mutex_unlock(&opts->lock); @@ -1229,8 +1227,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) return &midi->func; setup_fail: - for (--i; i >= 0; i--) - kfree(midi->in_port[i]); + mutex_unlock(&opts->lock); kfree(midi); return ERR_PTR(status); } diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 7ad798ace..97f0a9bc8 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1432,7 +1432,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) fs_ncm_notify_desc.bEndpointAddress; status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, - NULL); + NULL, NULL); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index d6396e090..d43e86cea 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -364,7 +364,8 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f) obex_hs_ep_out_desc.bEndpointAddress = obex_fs_ep_out_desc.bEndpointAddress; - status = usb_assign_descriptors(f, fs_function, hs_function, NULL); + status = usb_assign_descriptors(f, fs_function, hs_function, NULL, + NULL); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c index 157441dbf..0473d619d 100644 --- a/drivers/usb/gadget/function/f_phonet.c +++ b/drivers/usb/gadget/function/f_phonet.c @@ -541,7 +541,7 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f) /* Do not try to bind Phonet twice... */ status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function, - NULL); + NULL, NULL); if (status) goto err; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 26ccad5d8..c45104e3a 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1051,7 +1051,7 @@ autoconf_fail: ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; ret = usb_assign_descriptors(f, fs_printer_function, - hs_printer_function, ss_printer_function); + hs_printer_function, ss_printer_function, NULL); if (ret) return ret; diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index e587767e3..c8005823b 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -783,7 +783,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress; status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function, - eth_ss_function); + eth_ss_function, NULL); if (status) goto fail; @@ -889,7 +889,6 @@ static void rndis_free_inst(struct usb_function_instance *f) free_netdev(opts->net); } - kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */ kfree(opts); } @@ -916,10 +915,10 @@ static struct usb_function_instance *rndis_alloc_inst(void) descs[0] = &opts->rndis_os_desc; names[0] = "rndis"; - usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, - names, THIS_MODULE); config_group_init_type_name(&opts->func_inst.group, "", &rndis_func_type); + usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, + names, THIS_MODULE); return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 6bb44d613..cb00ada21 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -236,7 +236,7 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f) gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function, - gser_ss_function); + gser_ss_function, NULL); if (status) goto fail; dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 242ba5caf..df0189ddf 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -437,7 +437,7 @@ no_iso: ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; ret = usb_assign_descriptors(f, fs_source_sink_descs, - hs_source_sink_descs, ss_source_sink_descs); + hs_source_sink_descs, ss_source_sink_descs, NULL); if (ret) return ret; diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c index 829c78de9..434b983f3 100644 --- a/drivers/usb/gadget/function/f_subset.c +++ b/drivers/usb/gadget/function/f_subset.c @@ -362,7 +362,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) fs_subset_out_desc.bEndpointAddress; status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function, - ss_eth_function); + ss_eth_function, NULL); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index bad007b5a..2ace02954 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -41,13 +41,6 @@ static inline struct f_uas *to_f_uas(struct usb_function *f) return container_of(f, struct f_uas, function); } -static void usbg_cmd_release(struct kref *); - -static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd) -{ - kref_put(&cmd->ref, usbg_cmd_release); -} - /* Start bot.c code */ static int bot_enqueue_cmd_cbw(struct f_uas *fu) @@ -68,7 +61,7 @@ static void bot_status_complete(struct usb_ep *ep, struct usb_request *req) struct usbg_cmd *cmd = req->context; struct f_uas *fu = cmd->fu; - usbg_cleanup_cmd(cmd); + transport_generic_free_cmd(&cmd->se_cmd, 0); if (req->status < 0) { pr_err("ERR %s(%d)\n", __func__, __LINE__); return; @@ -605,7 +598,7 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req) break; case UASP_QUEUE_COMMAND: - usbg_cleanup_cmd(cmd); + transport_generic_free_cmd(&cmd->se_cmd, 0); usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); break; @@ -615,7 +608,7 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req) return; cleanup: - usbg_cleanup_cmd(cmd); + transport_generic_free_cmd(&cmd->se_cmd, 0); } static int uasp_send_status_response(struct usbg_cmd *cmd) @@ -977,7 +970,7 @@ static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req) return; cleanup: - usbg_cleanup_cmd(cmd); + transport_generic_free_cmd(&cmd->se_cmd, 0); } static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req) @@ -1046,7 +1039,7 @@ static void usbg_cmd_work(struct work_struct *work) struct se_cmd *se_cmd; struct tcm_usbg_nexus *tv_nexus; struct usbg_tpg *tpg; - int dir; + int dir, flags = (TARGET_SCF_UNKNOWN_SIZE | TARGET_SCF_ACK_KREF); se_cmd = &cmd->se_cmd; tpg = cmd->fu->tpg; @@ -1060,9 +1053,9 @@ static void usbg_cmd_work(struct work_struct *work) goto out; } - if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, - cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0) + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, + cmd->sense_iu.sense, cmd->unpacked_lun, 0, + cmd->prio_attr, dir, flags) < 0) goto out; return; @@ -1070,42 +1063,64 @@ static void usbg_cmd_work(struct work_struct *work) out: transport_send_check_condition_and_sense(se_cmd, TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); + transport_generic_free_cmd(&cmd->se_cmd, 0); } +static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, + struct tcm_usbg_nexus *tv_nexus, u32 scsi_tag) +{ + struct se_session *se_sess = tv_nexus->tvn_se_sess; + struct usbg_cmd *cmd; + int tag; + + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); + if (tag < 0) + return ERR_PTR(-ENOMEM); + + cmd = &((struct usbg_cmd *)se_sess->sess_cmd_map)[tag]; + memset(cmd, 0, sizeof(*cmd)); + cmd->se_cmd.map_tag = tag; + cmd->se_cmd.tag = cmd->tag = scsi_tag; + cmd->fu = fu; + + return cmd; +} + +static void usbg_release_cmd(struct se_cmd *); + static int usbg_submit_command(struct f_uas *fu, void *cmdbuf, unsigned int len) { struct command_iu *cmd_iu = cmdbuf; struct usbg_cmd *cmd; - struct usbg_tpg *tpg; - struct tcm_usbg_nexus *tv_nexus; + struct usbg_tpg *tpg = fu->tpg; + struct tcm_usbg_nexus *tv_nexus = tpg->tpg_nexus; u32 cmd_len; + u16 scsi_tag; if (cmd_iu->iu_id != IU_ID_COMMAND) { pr_err("Unsupported type %d\n", cmd_iu->iu_id); return -EINVAL; } - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); - if (!cmd) - return -ENOMEM; - - cmd->fu = fu; - - /* XXX until I figure out why I can't free in on complete */ - kref_init(&cmd->ref); - kref_get(&cmd->ref); + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + pr_err("Missing nexus, ignoring command\n"); + return -EINVAL; + } - tpg = fu->tpg; cmd_len = (cmd_iu->len & ~0x3) + 16; if (cmd_len > USBG_MAX_CMD) - goto err; + return -EINVAL; + scsi_tag = be16_to_cpup(&cmd_iu->tag); + cmd = usbg_get_cmd(fu, tv_nexus, scsi_tag); + if (IS_ERR(cmd)) { + pr_err("usbg_get_cmd failed\n"); + return -ENOMEM; + } memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); - cmd->tag = be16_to_cpup(&cmd_iu->tag); - cmd->se_cmd.tag = cmd->tag; if (fu->flags & USBG_USE_STREAMS) { if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) goto err; @@ -1117,12 +1132,6 @@ static int usbg_submit_command(struct f_uas *fu, cmd->stream = &fu->stream[0]; } - tv_nexus = tpg->tpg_nexus; - if (!tv_nexus) { - pr_err("Missing nexus, ignoring command\n"); - goto err; - } - switch (cmd_iu->prio_attr & 0x7) { case UAS_HEAD_TAG: cmd->prio_attr = TCM_HEAD_TAG; @@ -1148,7 +1157,7 @@ static int usbg_submit_command(struct f_uas *fu, return 0; err: - kfree(cmd); + usbg_release_cmd(&cmd->se_cmd); return -EINVAL; } @@ -1182,7 +1191,7 @@ static void bot_cmd_work(struct work_struct *work) out: transport_send_check_condition_and_sense(se_cmd, TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); + transport_generic_free_cmd(&cmd->se_cmd, 0); } static int bot_submit_command(struct f_uas *fu, @@ -1190,7 +1199,7 @@ static int bot_submit_command(struct f_uas *fu, { struct bulk_cb_wrap *cbw = cmdbuf; struct usbg_cmd *cmd; - struct usbg_tpg *tpg; + struct usbg_tpg *tpg = fu->tpg; struct tcm_usbg_nexus *tv_nexus; u32 cmd_len; @@ -1207,28 +1216,20 @@ static int bot_submit_command(struct f_uas *fu, if (cmd_len < 1 || cmd_len > 16) return -EINVAL; - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); - if (!cmd) - return -ENOMEM; - - cmd->fu = fu; - - /* XXX until I figure out why I can't free in on complete */ - kref_init(&cmd->ref); - kref_get(&cmd->ref); - - tpg = fu->tpg; - - memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); - - cmd->bot_tag = cbw->Tag; - tv_nexus = tpg->tpg_nexus; if (!tv_nexus) { pr_err("Missing nexus, ignoring command\n"); - goto err; + return -ENODEV; } + cmd = usbg_get_cmd(fu, tv_nexus, cbw->Tag); + if (IS_ERR(cmd)) { + pr_err("usbg_get_cmd failed\n"); + return -ENOMEM; + } + memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); + + cmd->bot_tag = cbw->Tag; cmd->prio_attr = TCM_SIMPLE_TAG; cmd->unpacked_lun = cbw->Lun; cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; @@ -1239,9 +1240,6 @@ static int bot_submit_command(struct f_uas *fu, queue_work(tpg->workqueue, &cmd->work); return 0; -err: - kfree(cmd); - return -EINVAL; } /* Start fabric.c code */ @@ -1282,20 +1280,14 @@ static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) return 1; } -static void usbg_cmd_release(struct kref *ref) -{ - struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, - ref); - - transport_generic_free_cmd(&cmd->se_cmd, 0); -} - static void usbg_release_cmd(struct se_cmd *se_cmd) { struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, se_cmd); + struct se_session *se_sess = se_cmd->se_sess; + kfree(cmd->data_buf); - kfree(cmd); + percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); } static int usbg_shutdown_session(struct se_session *se_sess) @@ -1579,55 +1571,48 @@ out: return ret; } +static int usbg_alloc_sess_cb(struct se_portal_group *se_tpg, + struct se_session *se_sess, void *p) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + + tpg->tpg_nexus = p; + return 0; +} + static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) { - struct se_portal_group *se_tpg; struct tcm_usbg_nexus *tv_nexus; - int ret; + int ret = 0; mutex_lock(&tpg->tpg_mutex); if (tpg->tpg_nexus) { ret = -EEXIST; pr_debug("tpg->tpg_nexus already exists\n"); - goto err_unlock; + goto out_unlock; } - se_tpg = &tpg->se_tpg; - ret = -ENOMEM; tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); - if (!tv_nexus) - goto err_unlock; - tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); - if (IS_ERR(tv_nexus->tvn_se_sess)) - goto err_free; + if (!tv_nexus) { + ret = -ENOMEM; + goto out_unlock; + } - /* - * Since we are running in 'demo mode' this call with generate a - * struct se_node_acl for the tcm_vhost struct se_portal_group with - * the SCSI Initiator port name of the passed configfs group 'name'. - */ - tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( - se_tpg, name); - if (!tv_nexus->tvn_se_sess->se_node_acl) { + tv_nexus->tvn_se_sess = target_alloc_session(&tpg->se_tpg, + USB_G_DEFAULT_SESSION_TAGS, + sizeof(struct usbg_cmd), + TARGET_PROT_NORMAL, name, + tv_nexus, usbg_alloc_sess_cb); + if (IS_ERR(tv_nexus->tvn_se_sess)) { #define MAKE_NEXUS_MSG "core_tpg_check_initiator_node_acl() failed for %s\n" pr_debug(MAKE_NEXUS_MSG, name); #undef MAKE_NEXUS_MSG - goto err_session; + ret = PTR_ERR(tv_nexus->tvn_se_sess); + kfree(tv_nexus); } - /* - * Now register the TCM vHost virtual I_T Nexus as active. - */ - transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, - tv_nexus->tvn_se_sess, tv_nexus); - tpg->tpg_nexus = tv_nexus; - mutex_unlock(&tpg->tpg_mutex); - return 0; -err_session: - transport_free_session(tv_nexus->tvn_se_sess); -err_free: - kfree(tv_nexus); -err_unlock: +out_unlock: mutex_unlock(&tpg->tpg_mutex); return ret; } @@ -1735,11 +1720,7 @@ static void usbg_port_unlink(struct se_portal_group *se_tpg, static int usbg_check_stop_free(struct se_cmd *se_cmd) { - struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, - se_cmd); - - kref_put(&cmd->ref, usbg_cmd_release); - return 1; + return target_put_sess_cmd(se_cmd); } static const struct target_core_fabric_ops usbg_ops = { @@ -2098,7 +2079,7 @@ static int tcm_bind(struct usb_configuration *c, struct usb_function *f) uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; ret = usb_assign_descriptors(f, uasp_fs_function_desc, - uasp_hs_function_desc, uasp_ss_function_desc); + uasp_hs_function_desc, uasp_ss_function_desc, NULL); if (ret) goto ep_fail; diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 6a2346b99..f2ac0cbc2 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -721,7 +721,8 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; /* copy descriptors, and track endpoint copies */ - status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL); + status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, + NULL); if (status) goto fail; return 0; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 044ca79d3..186d4b162 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -1100,7 +1100,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; - ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL); + ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, + NULL); if (ret) goto err; diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 70d3917cc..943c21aaf 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -914,7 +914,7 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v) params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED; params->resp_avail = resp_avail; params->v = v; - INIT_LIST_HEAD(&(params->resp_queue)); + INIT_LIST_HEAD(¶ms->resp_queue); pr_debug("%s: configNr = %d\n", __func__, i); return params; @@ -1006,13 +1006,10 @@ EXPORT_SYMBOL_GPL(rndis_add_hdr); void rndis_free_response(struct rndis_params *params, u8 *buf) { - rndis_resp_t *r; - struct list_head *act, *tmp; + rndis_resp_t *r, *n; - list_for_each_safe(act, tmp, &(params->resp_queue)) - { - r = list_entry(act, rndis_resp_t, list); - if (r && r->buf == buf) { + list_for_each_entry_safe(r, n, ¶ms->resp_queue, list) { + if (r->buf == buf) { list_del(&r->list); kfree(r); } @@ -1022,14 +1019,11 @@ EXPORT_SYMBOL_GPL(rndis_free_response); u8 *rndis_get_next_response(struct rndis_params *params, u32 *length) { - rndis_resp_t *r; - struct list_head *act, *tmp; + rndis_resp_t *r, *n; if (!length) return NULL; - list_for_each_safe(act, tmp, &(params->resp_queue)) - { - r = list_entry(act, rndis_resp_t, list); + list_for_each_entry_safe(r, n, ¶ms->resp_queue, list) { if (!r->send) { r->send = 1; *length = r->length; @@ -1053,7 +1047,7 @@ static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length) r->length = length; r->send = 0; - list_add_tail(&r->list, &(params->resp_queue)); + list_add_tail(&r->list, ¶ms->resp_queue); return r; } diff --git a/drivers/usb/gadget/function/tcm.h b/drivers/usb/gadget/function/tcm.h index b75c6f3e1..a27e6e34d 100644 --- a/drivers/usb/gadget/function/tcm.h +++ b/drivers/usb/gadget/function/tcm.h @@ -23,6 +23,8 @@ enum { #define USB_G_ALT_INT_BBB 0 #define USB_G_ALT_INT_UAS 1 +#define USB_G_DEFAULT_SESSION_TAGS 128 + struct tcm_usbg_nexus { struct se_session *tvn_se_sess; }; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index ad8c9b055..66753ba7a 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -272,11 +272,6 @@ static struct config_item_type uvcg_default_processing_type = { /* struct uvcg_processing {}; */ -static struct config_group *uvcg_processing_default_groups[] = { - &uvcg_default_processing.group, - NULL, -}; - /* control/processing */ static struct uvcg_processing_grp { struct config_group group; @@ -394,11 +389,6 @@ static struct config_item_type uvcg_default_camera_type = { /* struct uvcg_camera {}; */ -static struct config_group *uvcg_camera_default_groups[] = { - &uvcg_default_camera.group, - NULL, -}; - /* control/terminal/camera */ static struct uvcg_camera_grp { struct config_group group; @@ -477,11 +467,6 @@ static struct config_item_type uvcg_default_output_type = { /* struct uvcg_output {}; */ -static struct config_group *uvcg_output_default_groups[] = { - &uvcg_default_output.group, - NULL, -}; - /* control/terminal/output */ static struct uvcg_output_grp { struct config_group group; @@ -491,12 +476,6 @@ static struct config_item_type uvcg_output_grp_type = { .ct_owner = THIS_MODULE, }; -static struct config_group *uvcg_terminal_default_groups[] = { - &uvcg_camera_grp.group, - &uvcg_output_grp.group, - NULL, -}; - /* control/terminal */ static struct uvcg_terminal_grp { struct config_group group; @@ -619,12 +598,6 @@ static struct config_item_type uvcg_control_class_type = { .ct_owner = THIS_MODULE, }; -static struct config_group *uvcg_control_class_default_groups[] = { - &uvcg_control_class_fs.group, - &uvcg_control_class_ss.group, - NULL, -}; - /* control/class */ static struct uvcg_control_class_grp { struct config_group group; @@ -634,14 +607,6 @@ static struct config_item_type uvcg_control_class_grp_type = { .ct_owner = THIS_MODULE, }; -static struct config_group *uvcg_control_default_groups[] = { - &uvcg_control_header_grp.group, - &uvcg_processing_grp.group, - &uvcg_terminal_grp.group, - &uvcg_control_class_grp.group, - NULL, -}; - /* control */ static struct uvcg_control_grp { struct config_group group; @@ -1780,11 +1745,6 @@ static struct config_item_type uvcg_default_color_matching_type = { /* struct uvcg_color_matching {}; */ -static struct config_group *uvcg_color_matching_default_groups[] = { - &uvcg_default_color_matching.group, - NULL, -}; - /* streaming/color_matching */ static struct uvcg_color_matching_grp { struct config_group group; @@ -2145,13 +2105,6 @@ static struct config_item_type uvcg_streaming_class_type = { .ct_owner = THIS_MODULE, }; -static struct config_group *uvcg_streaming_class_default_groups[] = { - &uvcg_streaming_class_fs.group, - &uvcg_streaming_class_hs.group, - &uvcg_streaming_class_ss.group, - NULL, -}; - /* streaming/class */ static struct uvcg_streaming_class_grp { struct config_group group; @@ -2161,15 +2114,6 @@ static struct config_item_type uvcg_streaming_class_grp_type = { .ct_owner = THIS_MODULE, }; -static struct config_group *uvcg_streaming_default_groups[] = { - &uvcg_streaming_header_grp.group, - &uvcg_uncompressed_grp.group, - &uvcg_mjpeg_grp.group, - &uvcg_color_matching_grp.group, - &uvcg_streaming_class_grp.group, - NULL, -}; - /* streaming */ static struct uvcg_streaming_grp { struct config_group group; @@ -2179,12 +2123,6 @@ static struct config_item_type uvcg_streaming_grp_type = { .ct_owner = THIS_MODULE, }; -static struct config_group *uvcg_default_groups[] = { - &uvcg_control_grp.group, - &uvcg_streaming_grp.group, - NULL, -}; - static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) { return container_of(to_config_group(item), struct f_uvc_opts, @@ -2273,59 +2211,64 @@ static struct config_item_type uvc_func_type = { .ct_owner = THIS_MODULE, }; -static inline void uvcg_init_group(struct config_group *g, - struct config_group **default_groups, - const char *name, - struct config_item_type *type) -{ - g->default_groups = default_groups; - config_group_init_type_name(g, name, type); -} - int uvcg_attach_configfs(struct f_uvc_opts *opts) { config_group_init_type_name(&uvcg_control_header_grp.group, "header", &uvcg_control_header_grp_type); + config_group_init_type_name(&uvcg_default_processing.group, - "default", - &uvcg_default_processing_type); - uvcg_init_group(&uvcg_processing_grp.group, - uvcg_processing_default_groups, - "processing", - &uvcg_processing_grp_type); + "default", &uvcg_default_processing_type); + config_group_init_type_name(&uvcg_processing_grp.group, + "processing", &uvcg_processing_grp_type); + configfs_add_default_group(&uvcg_default_processing.group, + &uvcg_processing_grp.group); + config_group_init_type_name(&uvcg_default_camera.group, - "default", - &uvcg_default_camera_type); - uvcg_init_group(&uvcg_camera_grp.group, - uvcg_camera_default_groups, - "camera", - &uvcg_camera_grp_type); + "default", &uvcg_default_camera_type); + config_group_init_type_name(&uvcg_camera_grp.group, + "camera", &uvcg_camera_grp_type); + configfs_add_default_group(&uvcg_default_camera.group, + &uvcg_camera_grp.group); + config_group_init_type_name(&uvcg_default_output.group, - "default", - &uvcg_default_output_type); - uvcg_init_group(&uvcg_output_grp.group, - uvcg_output_default_groups, - "output", - &uvcg_output_grp_type); - uvcg_init_group(&uvcg_terminal_grp.group, - uvcg_terminal_default_groups, - "terminal", - &uvcg_terminal_grp_type); + "default", &uvcg_default_output_type); + config_group_init_type_name(&uvcg_output_grp.group, + "output", &uvcg_output_grp_type); + configfs_add_default_group(&uvcg_default_output.group, + &uvcg_output_grp.group); + + config_group_init_type_name(&uvcg_terminal_grp.group, + "terminal", &uvcg_terminal_grp_type); + configfs_add_default_group(&uvcg_camera_grp.group, + &uvcg_terminal_grp.group); + configfs_add_default_group(&uvcg_output_grp.group, + &uvcg_terminal_grp.group); + config_group_init_type_name(&uvcg_control_class_fs.group, - "fs", - &uvcg_control_class_type); + "fs", &uvcg_control_class_type); config_group_init_type_name(&uvcg_control_class_ss.group, - "ss", - &uvcg_control_class_type); - uvcg_init_group(&uvcg_control_class_grp.group, - uvcg_control_class_default_groups, + "ss", &uvcg_control_class_type); + config_group_init_type_name(&uvcg_control_class_grp.group, "class", &uvcg_control_class_grp_type); - uvcg_init_group(&uvcg_control_grp.group, - uvcg_control_default_groups, + configfs_add_default_group(&uvcg_control_class_fs.group, + &uvcg_control_class_grp.group); + configfs_add_default_group(&uvcg_control_class_ss.group, + &uvcg_control_class_grp.group); + + config_group_init_type_name(&uvcg_control_grp.group, "control", &uvcg_control_grp_type); + configfs_add_default_group(&uvcg_control_header_grp.group, + &uvcg_control_grp.group); + configfs_add_default_group(&uvcg_processing_grp.group, + &uvcg_control_grp.group); + configfs_add_default_group(&uvcg_terminal_grp.group, + &uvcg_control_grp.group); + configfs_add_default_group(&uvcg_control_class_grp.group, + &uvcg_control_grp.group); + config_group_init_type_name(&uvcg_streaming_header_grp.group, "header", &uvcg_streaming_header_grp_type); @@ -2338,30 +2281,47 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts) config_group_init_type_name(&uvcg_default_color_matching.group, "default", &uvcg_default_color_matching_type); - uvcg_init_group(&uvcg_color_matching_grp.group, - uvcg_color_matching_default_groups, + config_group_init_type_name(&uvcg_color_matching_grp.group, "color_matching", &uvcg_color_matching_grp_type); + configfs_add_default_group(&uvcg_default_color_matching.group, + &uvcg_color_matching_grp.group); + config_group_init_type_name(&uvcg_streaming_class_fs.group, - "fs", - &uvcg_streaming_class_type); + "fs", &uvcg_streaming_class_type); config_group_init_type_name(&uvcg_streaming_class_hs.group, - "hs", - &uvcg_streaming_class_type); + "hs", &uvcg_streaming_class_type); config_group_init_type_name(&uvcg_streaming_class_ss.group, - "ss", - &uvcg_streaming_class_type); - uvcg_init_group(&uvcg_streaming_class_grp.group, - uvcg_streaming_class_default_groups, - "class", - &uvcg_streaming_class_grp_type); - uvcg_init_group(&uvcg_streaming_grp.group, - uvcg_streaming_default_groups, - "streaming", - &uvcg_streaming_grp_type); - uvcg_init_group(&opts->func_inst.group, - uvcg_default_groups, + "ss", &uvcg_streaming_class_type); + config_group_init_type_name(&uvcg_streaming_class_grp.group, + "class", &uvcg_streaming_class_grp_type); + configfs_add_default_group(&uvcg_streaming_class_fs.group, + &uvcg_streaming_class_grp.group); + configfs_add_default_group(&uvcg_streaming_class_hs.group, + &uvcg_streaming_class_grp.group); + configfs_add_default_group(&uvcg_streaming_class_ss.group, + &uvcg_streaming_class_grp.group); + + config_group_init_type_name(&uvcg_streaming_grp.group, + "streaming", &uvcg_streaming_grp_type); + configfs_add_default_group(&uvcg_streaming_header_grp.group, + &uvcg_streaming_grp.group); + configfs_add_default_group(&uvcg_uncompressed_grp.group, + &uvcg_streaming_grp.group); + configfs_add_default_group(&uvcg_mjpeg_grp.group, + &uvcg_streaming_grp.group); + configfs_add_default_group(&uvcg_color_matching_grp.group, + &uvcg_streaming_grp.group); + configfs_add_default_group(&uvcg_streaming_class_grp.group, + &uvcg_streaming_grp.group); + + config_group_init_type_name(&opts->func_inst.group, "", &uvc_func_type); + configfs_add_default_group(&uvcg_control_grp.group, + &opts->func_inst.group); + configfs_add_default_group(&uvcg_streaming_grp.group, + &opts->func_inst.group); + return 0; } -- cgit v1.2.3-54-g00ecf