diff options
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 7 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_hid.c | 17 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_mass_storage.c | 21 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_midi.c | 68 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_ncm.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_rndis.c | 20 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_audio.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_ether.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_ether.h | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_ether_configfs.h | 35 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_rndis.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_serial.c | 2 |
12 files changed, 146 insertions, 37 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d21874b35cf6..9990944a7245 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -961,10 +961,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) /* In the meantime, endpoint got disabled or changed. */ ret = -ESHUTDOWN; } else if (halt) { - /* Halt */ - if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) - usb_ep_set_halt(ep->ep); - ret = -EBADMSG; + ret = usb_ep_set_halt(ep->ep); + if (!ret) + ret = -EBADMSG; } else if (unlikely(data_len == -EINVAL)) { /* * Sanity Check: even though data_len can't be used diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 5eea44823ca0..d8e359ef6eb1 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -44,6 +44,7 @@ struct f_hidg { /* configuration */ unsigned char bInterfaceSubClass; unsigned char bInterfaceProtocol; + unsigned char protocol; unsigned short report_desc_length; char *report_desc; unsigned short report_length; @@ -527,7 +528,9 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_GET_PROTOCOL): VDBG(cdev, "get_protocol\n"); - goto stall; + length = min_t(unsigned int, length, 1); + ((u8 *) req->buf)[0] = hidg->protocol; + goto respond; break; case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 @@ -539,6 +542,17 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_SET_PROTOCOL): VDBG(cdev, "set_protocol\n"); + if (value > HID_REPORT_PROTOCOL) + goto stall; + length = 0; + /* + * We assume that programs implementing the Boot protocol + * are also compatible with the Report Protocol + */ + if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { + hidg->protocol = value; + goto respond; + } goto stall; break; @@ -768,6 +782,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; + hidg->protocol = HID_REPORT_PROTOCOL; hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_ss_in_comp_desc.wBytesPerInterval = cpu_to_le16(hidg->report_length); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f95bddd6513f..d6bd0244b008 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -686,9 +686,8 @@ static int do_read(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *)bh->buf, - amount, &file_offset_tmp); + nread = kernel_read(curlun->filp, bh->buf, amount, + &file_offset_tmp); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nread); if (signal_pending(current)) @@ -883,8 +882,8 @@ static int do_write(struct fsg_common *common) /* Perform the write */ file_offset_tmp = file_offset; - nwritten = vfs_write(curlun->filp, (char __user *)bh->buf, - amount, &file_offset_tmp); + nwritten = kernel_write(curlun->filp, bh->buf, amount, + &file_offset_tmp); VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nwritten); if (signal_pending(current)) @@ -1021,9 +1020,8 @@ static int do_verify(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); + nread = kernel_read(curlun->filp, bh->buf, amount, + &file_offset_tmp); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long) file_offset, (int) nread); @@ -2453,13 +2451,6 @@ static int fsg_main_thread(void *common_) /* Allow the thread to be frozen */ set_freezable(); - /* - * Arrange for userspace references to be interpreted as kernel - * pointers. That way we can pass a kernel pointer to a routine - * that expects a __user pointer and it will work okay. - */ - set_fs(get_ds()); - /* The main loop */ while (common->state != FSG_STATE_TERMINATED) { if (exception_in_progress(common) || signal_pending(current)) { diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a5719f271bf0..5d3d7941d2c2 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -98,6 +98,7 @@ struct f_midi { DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); spinlock_t transmit_lock; unsigned int in_last_port; + unsigned char free_ref; struct gmidi_in_port in_ports_array[/* in_ports */]; }; @@ -108,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f) } static void f_midi_transmit(struct f_midi *midi); +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); @@ -163,6 +165,13 @@ static struct usb_endpoint_descriptor bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_ss_ep_comp_descriptor bulk_out_ss_comp_desc = { + .bLength = sizeof(bulk_out_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + /* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ static struct usb_ms_endpoint_descriptor_16 ms_out_desc = { /* .bLength = DYNAMIC */ @@ -180,6 +189,13 @@ static struct usb_endpoint_descriptor bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_ss_ep_comp_descriptor bulk_in_ss_comp_desc = { + .bLength = sizeof(bulk_in_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + /* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ static struct usb_ms_endpoint_descriptor_16 ms_in_desc = { /* .bLength = DYNAMIC */ @@ -755,13 +771,13 @@ static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) clear_bit(substream->number, &midi->out_triggered); } -static struct snd_rawmidi_ops gmidi_in_ops = { +static const struct snd_rawmidi_ops gmidi_in_ops = { .open = f_midi_in_open, .close = f_midi_in_close, .trigger = f_midi_in_trigger, }; -static struct snd_rawmidi_ops gmidi_out_ops = { +static const struct snd_rawmidi_ops gmidi_out_ops = { .open = f_midi_out_open, .close = f_midi_out_close, .trigger = f_midi_out_trigger @@ -818,6 +834,8 @@ static int f_midi_register_card(struct f_midi *midi) SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = midi; + rmidi->private_free = f_midi_rmidi_free; + midi->free_ref++; /* * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. @@ -853,7 +871,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_midi *midi = func_to_midi(f); struct usb_string *us; - int status, n, jack = 1, i = 0; + int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); @@ -895,7 +913,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail; /* allocate temporary function list */ - midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function), + midi_function = kcalloc((MAX_PORTS * 4) + 11, sizeof(*midi_function), GFP_KERNEL); if (!midi_function) { status = -ENOMEM; @@ -985,6 +1003,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) ms_in_desc.bNumEmbMIDIJack = midi->out_ports; /* ... and add them to the list */ + endpoint_descriptor_index = i; midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc; midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; @@ -1009,13 +1028,34 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail_f_midi; } + if (gadget_is_superspeed(c->cdev->gadget)) { + bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024); + bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024); + i = endpoint_descriptor_index; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_out_ss_comp_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &ms_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_in_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_in_ss_comp_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &ms_in_desc; + f->ss_descriptors = usb_copy_descriptors(midi_function); + if (!f->ss_descriptors) + goto fail_f_midi; + } + kfree(midi_function); return 0; fail_f_midi: kfree(midi_function); - usb_free_descriptors(f->hs_descriptors); + usb_free_all_descriptors(f); fail: f_midi_unregister_card(midi); fail_register: @@ -1197,14 +1237,21 @@ static void f_midi_free(struct usb_function *f) midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); - kfree(midi->id); mutex_lock(&opts->lock); - kfifo_free(&midi->in_req_fifo); - kfree(midi); - --opts->refcnt; + if (!--midi->free_ref) { + kfree(midi->id); + kfifo_free(&midi->in_req_fifo); + kfree(midi); + --opts->refcnt; + } mutex_unlock(&opts->lock); } +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi) +{ + f_midi_free(rmidi->private_data); +} + static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = f->config->cdev; @@ -1219,7 +1266,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) card = midi->card; midi->card = NULL; if (card) - snd_card_free(card); + snd_card_free_when_closed(card); usb_free_all_descriptors(f); } @@ -1263,6 +1310,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->buflen = opts->buflen; midi->qlen = opts->qlen; midi->in_last_port = 0; + midi->free_ref = 1; status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL); if (status) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 24e34cfcb4bd..45b334ceaf2e 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -925,8 +925,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) */ ncm->port.is_zlp_ok = gadget_is_zlp_supported(cdev->gadget); - ncm->port.no_skb_reserve = - gadget_avoids_skb_reserve(cdev->gadget); ncm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ncm\n"); net = gether_connect(&ncm->port); diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 16562e461121..e1d5853ef1e4 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -691,6 +691,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; } + rndis_iad_descriptor.bFunctionClass = rndis_opts->class; + rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; + rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; + /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, @@ -866,11 +870,23 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); /* f_rndis_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); +/* f_rndis_opts_class */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, class); + +/* f_rndis_opts_subclass */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); + +/* f_rndis_opts_protocol */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); + static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, &rndis_opts_attr_qmult, &rndis_opts_attr_ifname, + &rndis_opts_attr_class, + &rndis_opts_attr_subclass, + &rndis_opts_attr_protocol, NULL, }; @@ -916,6 +932,10 @@ static struct usb_function_instance *rndis_alloc_inst(void) } INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); + opts->class = rndis_iad_descriptor.bFunctionClass; + opts->subclass = rndis_iad_descriptor.bFunctionSubClass; + opts->protocol = rndis_iad_descriptor.bFunctionProtocol; + descs[0] = &opts->rndis_os_desc; names[0] = "rndis"; config_group_init_type_name(&opts->func_inst.group, "", diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 5dd73b9e5172..3971bbab88bd 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -79,7 +79,7 @@ struct snd_uac_chip { unsigned int p_framesize; }; -static struct snd_pcm_hardware uac_pcm_hardware = { +static const struct snd_pcm_hardware uac_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, @@ -354,7 +354,7 @@ static int uac_pcm_null(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops uac_pcm_ops = { +static const struct snd_pcm_ops uac_pcm_ops = { .open = uac_pcm_open, .close = uac_pcm_null, .ioctl = snd_pcm_lib_ioctl, diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index a8b40d07e927..bdbc3fdc7c4f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1073,7 +1073,7 @@ struct net_device *gether_connect(struct gether *link) if (result == 0) { dev->zlp = link->is_zlp_ok; - dev->no_skb_reserve = link->no_skb_reserve; + dev->no_skb_reserve = gadget_avoids_skb_reserve(dev->gadget); DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult)); dev->header_len = link->header_len; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 81d94a7ae4b4..c77145bd6b5b 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -64,7 +64,6 @@ struct gether { struct usb_ep *out_ep; bool is_zlp_ok; - bool no_skb_reserve; u16 cdc_filter; diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index c71133de17e7..e4c3f84af4c3 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -153,4 +153,39 @@ out: \ \ CONFIGFS_ATTR_RO(_f_##_opts_, ifname) +#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ + static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ + char *page) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret; \ + \ + mutex_lock(&opts->lock); \ + ret = sprintf(page, "%02x\n", opts->_n_); \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\ + const char *page, \ + size_t len) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret; \ + u8 val; \ + \ + mutex_lock(&opts->lock); \ + ret = sscanf(page, "%02hhx", &val); \ + if (ret > 0) { \ + opts->_n_ = val; \ + ret = len; \ + } \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, _n_) + #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 4eafd5050545..a35ee3c2545d 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -29,6 +29,10 @@ struct f_rndis_opts { struct usb_os_desc rndis_os_desc; char rndis_ext_compat_id[16]; + u8 class; + u8 subclass; + u8 protocol; + /* * Read/write access to configfs attributes is handled by configfs. * diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 9b0805f55ad7..4176216d54be 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -537,7 +537,7 @@ static void gs_rx_push(unsigned long _port) } /* push data to (open) tty */ - if (req->actual) { + if (req->actual && tty) { char *packet = req->buf; unsigned size = req->actual; unsigned n; |