diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-04 17:50:43 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-04 17:50:43 +0300 |
commit | 048ff8629e117d8411a787559417c781bcd78d7e (patch) | |
tree | 2cff07ed5c13a096d1c880139873870146cca74a /drivers/usb/gadget | |
parent | 7ddb58cb0ecae8e8b6181d736a87667cc9ab8389 (diff) | |
parent | a0548b26901f082684ad1fb3ba397d2de3a1406a (diff) | |
download | linux-048ff8629e117d8411a787559417c781bcd78d7e.tar.xz |
Merge tag 'usb-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH:
"Here is the big set of USB and Thunderbolt driver updates for
5.16-rc1.
Nothing major in here, just lots of little cleanups and additions for
new hardware, all of which have been in linux-next for a while with no
reported problems.
Included in here are:
- tiny Thunderbolt driver updates
- USB typec driver updates
- USB serial driver updates
- USB gadget driver updates
- dwc2 and dwc3 controller driver updates
- tiny USB host driver updates
- minor USB driver fixes and updates
- USB dts updates for various platforms"
* tag 'usb-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (123 commits)
usb: gadget: Mark USB_FSL_QE broken on 64-bit
usb: gadget: f_mass_storage: Disable eps during disconnect
usb: gadget: udc: core: Revise comments for USB ep enable/disable
USB: serial: keyspan: fix memleak on probe errors
USB: serial: cp210x: use usb_control_msg_recv() and usb_control_msg_send()
USB: serial: ch314: use usb_control_msg_recv()
USB: iowarrior: fix control-message timeouts
Documentation: USB: fix example bulk-message timeout
usb: dwc2: stm32mp15: set otg_rev
usb: dwc2: add otg_rev and otg_caps information for gadget driver
dt-bindings: usb: dwc2: adopt otg properties defined in usb-drd.yaml
dt-bindings: usb: dwc2: Add reference to usb-drd.yaml
usb: gadget: uvc: implement dwPresentationTime and scrSourceClock
usb: gadget: uvc: use on returned header len in video_encode_isoc_sg
usb:gadget: f_uac1: fixed sync playback
Docs: usb: remove :c:func: for usb_register and usb_deregister
Docs: usb: update struct usb_driver
usb: gadget: configfs: change config attributes file operation
usb: gadget: configfs: add cfg_to_gadget_info() helper
usb: dwc3: Align DWC3_EP_* flag macros
...
Diffstat (limited to 'drivers/usb/gadget')
23 files changed, 353 insertions, 103 deletions
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 477e72a1d11e..36c611d1d8d0 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -73,6 +73,11 @@ static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) group); } +static inline struct gadget_info *cfg_to_gadget_info(struct config_usb_cfg *cfg) +{ + return container_of(cfg->c.cdev, struct gadget_info, cdev); +} + struct gadget_strings { struct usb_gadget_strings stringtab_dev; struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; @@ -413,8 +418,7 @@ static int config_usb_cfg_link( struct config_item *usb_func_ci) { struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci); - struct usb_composite_dev *cdev = cfg->c.cdev; - struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + struct gadget_info *gi = cfg_to_gadget_info(cfg); struct config_group *group = to_config_group(usb_func_ci); struct usb_function_instance *fi = container_of(group, @@ -464,8 +468,7 @@ static void config_usb_cfg_unlink( struct config_item *usb_func_ci) { struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci); - struct usb_composite_dev *cdev = cfg->c.cdev; - struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + struct gadget_info *gi = cfg_to_gadget_info(cfg); struct config_group *group = to_config_group(usb_func_ci); struct usb_function_instance *fi = container_of(group, @@ -505,12 +508,15 @@ static struct configfs_item_operations gadget_config_item_ops = { static ssize_t gadget_config_desc_MaxPower_show(struct config_item *item, char *page) { - return sprintf(page, "%u\n", to_config_usb_cfg(item)->c.MaxPower); + struct config_usb_cfg *cfg = to_config_usb_cfg(item); + + return sprintf(page, "%u\n", cfg->c.MaxPower); } static ssize_t gadget_config_desc_MaxPower_store(struct config_item *item, const char *page, size_t len) { + struct config_usb_cfg *cfg = to_config_usb_cfg(item); u16 val; int ret; ret = kstrtou16(page, 0, &val); @@ -518,20 +524,22 @@ static ssize_t gadget_config_desc_MaxPower_store(struct config_item *item, return ret; if (DIV_ROUND_UP(val, 8) > 0xff) return -ERANGE; - to_config_usb_cfg(item)->c.MaxPower = val; + cfg->c.MaxPower = val; return len; } static ssize_t gadget_config_desc_bmAttributes_show(struct config_item *item, char *page) { - return sprintf(page, "0x%02x\n", - to_config_usb_cfg(item)->c.bmAttributes); + struct config_usb_cfg *cfg = to_config_usb_cfg(item); + + return sprintf(page, "0x%02x\n", cfg->c.bmAttributes); } static ssize_t gadget_config_desc_bmAttributes_store(struct config_item *item, const char *page, size_t len) { + struct config_usb_cfg *cfg = to_config_usb_cfg(item); u8 val; int ret; ret = kstrtou8(page, 0, &val); @@ -542,7 +550,7 @@ static ssize_t gadget_config_desc_bmAttributes_store(struct config_item *item, if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP)) return -EINVAL; - to_config_usb_cfg(item)->c.bmAttributes = val; + cfg->c.bmAttributes = val; return len; } diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 1eb4fa2e623f..ed5a92c474e5 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -181,7 +181,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig); * This function can be used during function bind for endpoints obtained * from usb_ep_autoconfig(). It unclaims endpoint claimed by * usb_ep_autoconfig() to make it available for other functions. Endpoint - * which was released is no longer invalid and shouldn't be used in + * which was released is no longer valid and shouldn't be used in * context of function which released it. */ void usb_ep_autoconfig_release(struct usb_ep *ep) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 6ad669dde41c..752439690fda 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -588,7 +588,7 @@ static int sleep_thread(struct fsg_common *common, bool can_freeze, static int do_read(struct fsg_common *common) { struct fsg_lun *curlun = common->curlun; - u32 lba; + u64 lba; struct fsg_buffhd *bh; int rc; u32 amount_left; @@ -603,7 +603,10 @@ static int do_read(struct fsg_common *common) if (common->cmnd[0] == READ_6) lba = get_unaligned_be24(&common->cmnd[1]); else { - lba = get_unaligned_be32(&common->cmnd[2]); + if (common->cmnd[0] == READ_16) + lba = get_unaligned_be64(&common->cmnd[2]); + else /* READ_10 or READ_12 */ + lba = get_unaligned_be32(&common->cmnd[2]); /* * We allow DPO (Disable Page Out = don't save data in the @@ -716,7 +719,7 @@ static int do_read(struct fsg_common *common) static int do_write(struct fsg_common *common) { struct fsg_lun *curlun = common->curlun; - u32 lba; + u64 lba; struct fsg_buffhd *bh; int get_some_more; u32 amount_left_to_req, amount_left_to_write; @@ -740,7 +743,10 @@ static int do_write(struct fsg_common *common) if (common->cmnd[0] == WRITE_6) lba = get_unaligned_be24(&common->cmnd[1]); else { - lba = get_unaligned_be32(&common->cmnd[2]); + if (common->cmnd[0] == WRITE_16) + lba = get_unaligned_be64(&common->cmnd[2]); + else /* WRITE_10 or WRITE_12 */ + lba = get_unaligned_be32(&common->cmnd[2]); /* * We allow DPO (Disable Page Out = don't save data in the @@ -1115,6 +1121,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) u32 lba = get_unaligned_be32(&common->cmnd[2]); int pmi = common->cmnd[8]; u8 *buf = (u8 *)bh->buf; + u32 max_lba; /* Check the PMI and LBA fields */ if (pmi > 1 || (pmi == 0 && lba != 0)) { @@ -1122,12 +1129,37 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) return -EINVAL; } - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ + if (curlun->num_sectors < 0x100000000ULL) + max_lba = curlun->num_sectors - 1; + else + max_lba = 0xffffffff; + put_unaligned_be32(max_lba, &buf[0]); /* Max logical block */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ return 8; } +static int do_read_capacity_16(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + u64 lba = get_unaligned_be64(&common->cmnd[2]); + int pmi = common->cmnd[14]; + u8 *buf = (u8 *)bh->buf; + + /* Check the PMI and LBA fields */ + if (pmi > 1 || (pmi == 0 && lba != 0)) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + put_unaligned_be64(curlun->num_sectors - 1, &buf[0]); + /* Max logical block */ + put_unaligned_be32(curlun->blksize, &buf[8]); /* Block length */ + + /* It is safe to keep other fields zeroed */ + memset(&buf[12], 0, 32 - 12); + return 32; +} + static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) { struct fsg_lun *curlun = common->curlun; @@ -1874,6 +1906,17 @@ static int do_scsi_command(struct fsg_common *common) reply = do_read(common); break; + case READ_16: + common->data_size_from_cmnd = + get_unaligned_be32(&common->cmnd[10]); + reply = check_command_size_in_blocks(common, 16, + DATA_DIR_TO_HOST, + (1<<1) | (0xff<<2) | (0xf<<10), 1, + "READ(16)"); + if (reply == 0) + reply = do_read(common); + break; + case READ_CAPACITY: common->data_size_from_cmnd = 8; reply = check_command(common, 10, DATA_DIR_TO_HOST, @@ -1926,6 +1969,25 @@ static int do_scsi_command(struct fsg_common *common) reply = do_request_sense(common, bh); break; + case SERVICE_ACTION_IN_16: + switch (common->cmnd[1] & 0x1f) { + + case SAI_READ_CAPACITY_16: + common->data_size_from_cmnd = + get_unaligned_be32(&common->cmnd[10]); + reply = check_command(common, 16, DATA_DIR_TO_HOST, + (1<<1) | (0xff<<2) | (0xf<<10) | + (1<<14), 1, + "READ CAPACITY(16)"); + if (reply == 0) + reply = do_read_capacity_16(common, bh); + break; + + default: + goto unknown_cmnd; + } + break; + case START_STOP: common->data_size_from_cmnd = 0; reply = check_command(common, 6, DATA_DIR_NONE, @@ -1997,6 +2059,17 @@ static int do_scsi_command(struct fsg_common *common) reply = do_write(common); break; + case WRITE_16: + common->data_size_from_cmnd = + get_unaligned_be32(&common->cmnd[10]); + reply = check_command_size_in_blocks(common, 16, + DATA_DIR_FROM_HOST, + (1<<1) | (0xff<<2) | (0xf<<10), 1, + "WRITE(16)"); + if (reply == 0) + reply = do_write(common); + break; + /* * Some mandatory commands that we recognize but don't implement. * They don't mean much in this setting. It's left as an exercise @@ -2269,6 +2342,16 @@ static void fsg_disable(struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in_enabled = 0; + } + if (fsg->bulk_out_enabled) { + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } + __raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE, NULL); } diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 5b3502df4e13..03f50643fbba 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -1321,6 +1321,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) audio->params.c_fu.volume_res = audio_opts->c_volume_res; } audio->params.req_number = audio_opts->req_number; + audio->params.fb_max = FBACK_FAST_MAX; if (FUOUT_EN(audio_opts) || FUIN_EN(audio_opts)) audio->notify = audio_notify; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index ef55b8bb5870..36fa6ef0581b 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include "u_audio.h" + #include "u_uac2.h" /* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ @@ -674,8 +675,9 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, ssize = uac2_opts->c_ssize; } - if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { - // Win10 requires max packet size + 1 frame + if (is_playback || (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { + // playback is always async, capture only when configured + // Win10 requires max packet size + 1 frame srate = srate * (1000 + uac2_opts->fb_max) / 1000; // updated srate is always bigger, therefore DIV_ROUND_UP always yields +1 max_size_bw = num_channels(chmask) * ssize * @@ -760,15 +762,15 @@ static void setup_headers(struct f_uac2_opts *opts, headers[i++] = USBDHDR(&out_clk_src_desc); headers[i++] = USBDHDR(&usb_out_it_desc); - if (FUOUT_EN(opts)) - headers[i++] = USBDHDR(out_feature_unit_desc); - } + if (FUOUT_EN(opts)) + headers[i++] = USBDHDR(out_feature_unit_desc); + } if (EPIN_EN(opts)) { headers[i++] = USBDHDR(&io_in_it_desc); - if (FUIN_EN(opts)) - headers[i++] = USBDHDR(in_feature_unit_desc); + if (FUIN_EN(opts)) + headers[i++] = USBDHDR(in_feature_unit_desc); headers[i++] = USBDHDR(&usb_in_ot_desc); } @@ -776,10 +778,10 @@ static void setup_headers(struct f_uac2_opts *opts, if (EPOUT_EN(opts)) headers[i++] = USBDHDR(&io_out_ot_desc); - if (FUOUT_EN(opts) || FUIN_EN(opts)) - headers[i++] = USBDHDR(ep_int_desc); + if (FUOUT_EN(opts) || FUIN_EN(opts)) + headers[i++] = USBDHDR(ep_int_desc); - if (EPOUT_EN(opts)) { + if (EPOUT_EN(opts)) { headers[i++] = USBDHDR(&std_as_out_if0_desc); headers[i++] = USBDHDR(&std_as_out_if1_desc); headers[i++] = USBDHDR(&as_out_hdr_desc); @@ -1931,7 +1933,7 @@ static struct usb_function_instance *afunc_alloc_inst(void) opts->c_volume_res = UAC2_DEF_RES_DB; opts->req_number = UAC2_DEF_REQ_NUM; - opts->fb_max = UAC2_DEF_FB_MAX; + opts->fb_max = FBACK_FAST_MAX; return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 9d87c0fb8f92..71bb5e477dba 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -417,6 +417,7 @@ uvc_register_video(struct uvc_device *uvc) int ret; /* TODO reference counting. */ + memset(&uvc->vdev, 0, sizeof(uvc->video)); uvc->vdev.v4l2_dev = &uvc->v4l2_dev; uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev; uvc->vdev.fops = &uvc_v4l2_fops; @@ -884,12 +885,13 @@ static void uvc_free(struct usb_function *f) kfree(uvc); } -static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) +static void uvc_function_unbind(struct usb_configuration *c, + struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct uvc_device *uvc = to_uvc(f); - uvcg_info(f, "%s\n", __func__); + uvcg_info(f, "%s()\n", __func__); device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); video_unregister_device(&uvc->vdev); @@ -943,7 +945,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) /* Register the function. */ uvc->func.name = "uvc"; uvc->func.bind = uvc_function_bind; - uvc->func.unbind = uvc_unbind; + uvc->func.unbind = uvc_function_unbind; uvc->func.get_alt = uvc_function_get_alt; uvc->func.set_alt = uvc_function_set_alt; uvc->func.disable = uvc_function_disable; diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index ad16163b5ff8..c46400be5464 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -29,6 +29,7 @@ enum { UAC_FBACK_CTRL, + UAC_P_PITCH_CTRL, UAC_MUTE_CTRL, UAC_VOLUME_CTRL, }; @@ -74,13 +75,9 @@ struct snd_uac_chip { struct snd_card *card; struct snd_pcm *pcm; - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; + unsigned long long p_interval_mil; + unsigned long long p_residue_mil; unsigned int p_framesize; }; @@ -153,6 +150,11 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) struct snd_pcm_runtime *runtime; struct uac_rtd_params *prm = req->context; struct snd_uac_chip *uac = prm->uac; + struct g_audio *audio_dev = uac->audio_dev; + struct uac_params *params = &audio_dev->params; + unsigned int frames, p_pktsize; + unsigned long long pitched_rate_mil, p_pktsize_residue_mil, + residue_frames_mil, div_result; /* i/f shutting down */ if (!prm->ep_enabled) { @@ -192,19 +194,42 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) * If there is a residue from this division, add it to the * residue accumulator. */ - req->length = uac->p_pktsize; - uac->p_residue += uac->p_pktsize_residue; + pitched_rate_mil = (unsigned long long) + params->p_srate * prm->pitch; + div_result = pitched_rate_mil; + do_div(div_result, uac->p_interval_mil); + frames = (unsigned int) div_result; + + pr_debug("p_srate %d, pitch %d, interval_mil %llu, frames %d\n", + params->p_srate, prm->pitch, uac->p_interval_mil, frames); + + p_pktsize = min_t(unsigned int, + uac->p_framesize * frames, + ep->maxpacket); + + if (p_pktsize < ep->maxpacket) { + residue_frames_mil = pitched_rate_mil - frames * uac->p_interval_mil; + p_pktsize_residue_mil = uac->p_framesize * residue_frames_mil; + } else + p_pktsize_residue_mil = 0; + + req->length = p_pktsize; + uac->p_residue_mil += p_pktsize_residue_mil; /* - * Whenever there are more bytes in the accumulator than we + * Whenever there are more bytes in the accumulator p_residue_mil than we * need to add one more sample frame, increase this packet's * size and decrease the accumulator. */ - if (uac->p_residue / uac->p_interval >= uac->p_framesize) { + div_result = uac->p_residue_mil; + do_div(div_result, uac->p_interval_mil); + if ((unsigned int) div_result >= uac->p_framesize) { req->length += uac->p_framesize; - uac->p_residue -= uac->p_framesize * - uac->p_interval; + uac->p_residue_mil -= uac->p_framesize * + uac->p_interval_mil; + pr_debug("increased req length to %d\n", req->length); } + pr_debug("remains uac->p_residue_mil %llu\n", uac->p_residue_mil); req->actual = req->length; } @@ -371,7 +396,7 @@ static int uac_pcm_open(struct snd_pcm_substream *substream) c_srate = params->c_srate; p_chmask = params->p_chmask; c_chmask = params->c_chmask; - uac->p_residue = 0; + uac->p_residue_mil = 0; runtime->hw = uac_pcm_hardware; @@ -566,12 +591,17 @@ int u_audio_start_playback(struct g_audio *audio_dev) unsigned int factor; const struct usb_endpoint_descriptor *ep_desc; int req_len, i; + unsigned int p_interval, p_pktsize; ep = audio_dev->in_ep; prm = &uac->p_prm; config_ep_by_speed(gadget, &audio_dev->func, ep); ep_desc = ep->desc; + /* + * Always start with original frequency + */ + prm->pitch = 1000000; /* pre-calculate the playback endpoint's interval */ if (gadget->speed == USB_SPEED_FULL) @@ -582,20 +612,15 @@ int u_audio_start_playback(struct g_audio *audio_dev) /* pre-compute some values for iso_complete() */ uac->p_framesize = params->p_ssize * num_channels(params->p_chmask); - uac->p_interval = factor / (1 << (ep_desc->bInterval - 1)); - uac->p_pktsize = min_t(unsigned int, + p_interval = factor / (1 << (ep_desc->bInterval - 1)); + uac->p_interval_mil = (unsigned long long) p_interval * 1000000; + p_pktsize = min_t(unsigned int, uac->p_framesize * - (params->p_srate / uac->p_interval), + (params->p_srate / p_interval), ep->maxpacket); - if (uac->p_pktsize < ep->maxpacket) - uac->p_pktsize_residue = uac->p_framesize * - (params->p_srate % uac->p_interval); - else - uac->p_pktsize_residue = 0; - - req_len = uac->p_pktsize; - uac->p_residue = 0; + req_len = p_pktsize; + uac->p_residue_mil = 0; prm->ep_enabled = true; usb_ep_enable(ep); @@ -925,6 +950,13 @@ static struct snd_kcontrol_new u_audio_controls[] = { .get = u_audio_pitch_get, .put = u_audio_pitch_put, }, + [UAC_P_PITCH_CTRL] { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Playback Pitch 1000000", + .info = u_audio_pitch_info, + .get = u_audio_pitch_get, + .put = u_audio_pitch_put, + }, [UAC_MUTE_CTRL] { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "", /* will be filled later */ @@ -1062,6 +1094,22 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, goto snd_fail; } + if (p_chmask) { + kctl = snd_ctl_new1(&u_audio_controls[UAC_P_PITCH_CTRL], + &uac->p_prm); + if (!kctl) { + err = -ENOMEM; + goto snd_fail; + } + + kctl->id.device = pcm->device; + kctl->id.subdevice = 0; + + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; + } + for (i = 0; i <= SNDRV_PCM_STREAM_LAST; i++) { struct uac_rtd_params *prm; struct uac_fu_params *fu; diff --git a/drivers/usb/gadget/function/u_audio.h b/drivers/usb/gadget/function/u_audio.h index 001a79a46022..8dfdae1721cd 100644 --- a/drivers/usb/gadget/function/u_audio.h +++ b/drivers/usb/gadget/function/u_audio.h @@ -14,11 +14,17 @@ /* * Same maximum frequency deviation on the slower side as in * sound/usb/endpoint.c. Value is expressed in per-mil deviation. - * The maximum deviation on the faster side will be provided as - * parameter, as it impacts the endpoint required bandwidth. */ #define FBACK_SLOW_MAX 250 +/* + * Maximum frequency deviation on the faster side, default value for UAC1/2. + * Value is expressed in per-mil deviation. + * UAC2 provides the value as a parameter as it impacts the endpoint required + * bandwidth. + */ +#define FBACK_FAST_MAX 5 + /* Feature Unit parameters */ struct uac_fu_params { int id; /* Feature Unit ID */ diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 85a3f6d4b5af..e0ad5aed6ac9 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -754,6 +754,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, struct eth_dev *dev; struct net_device *net; int status; + u8 addr[ETH_ALEN]; net = alloc_etherdev(sizeof *dev); if (!net) @@ -773,9 +774,10 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, dev->qmult = qmult; snprintf(net->name, sizeof(net->name), "%s%%d", netname); - if (get_ether_addr(dev_addr, net->dev_addr)) + if (get_ether_addr(dev_addr, addr)) dev_warn(&g->dev, "using random %s ethernet address\n", "self"); + eth_hw_addr_set(net, addr); if (get_ether_addr(host_addr, dev->host_mac)) dev_warn(&g->dev, "using random %s ethernet address\n", "host"); diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index a73b35774c44..e0c8e3513bfd 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -30,7 +30,6 @@ #define UAC2_DEF_RES_DB (1*256) /* 1 dB */ #define UAC2_DEF_REQ_NUM 2 -#define UAC2_DEF_FB_MAX 5 #define UAC2_DEF_INT_REQ_NUM 10 struct f_uac2_opts { diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 255a61bd6a6a..c3607a32b986 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -68,6 +68,8 @@ extern unsigned int uvc_gadget_trace_param; #define UVC_MAX_REQUEST_SIZE 64 #define UVC_MAX_EVENTS 4 +#define UVCG_REQUEST_HEADER_LEN 12 + /* ------------------------------------------------------------------------ * Structures */ @@ -76,7 +78,7 @@ struct uvc_request { u8 *req_buffer; struct uvc_video *video; struct sg_table sgt; - u8 header[2]; + u8 header[UVCG_REQUEST_HEADER_LEN]; }; struct uvc_video { @@ -126,6 +128,7 @@ struct uvc_device { enum uvc_state state; struct usb_function func; struct uvc_video video; + bool func_connected; /* Descriptors */ struct { @@ -156,6 +159,7 @@ static inline struct uvc_device *to_uvc(struct usb_function *f) struct uvc_file_handle { struct v4l2_fh vfh; struct uvc_video *device; + bool is_uvc_app_handle; }; #define to_uvc_file_handle(handle) \ diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 7d00ad7c154c..d852ac9e47e7 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -142,7 +142,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, struct device *dev, enum v4l2 queue->queue.mem_ops = &vb2_vmalloc_memops; } - queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; queue->queue.dev = dev; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 4ca89eab6159..a2c78690c5c2 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -169,7 +169,8 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) if (ret < 0) return ret; - schedule_work(&video->pump); + if (uvc->state == UVC_STATE_STREAMING) + schedule_work(&video->pump); return ret; } @@ -227,17 +228,55 @@ static int uvc_v4l2_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct uvc_device *uvc = video_get_drvdata(fh->vdev); + struct uvc_file_handle *handle = to_uvc_file_handle(fh); + int ret; + if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) return -EINVAL; - return v4l2_event_subscribe(fh, sub, 2, NULL); + if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) + return -EBUSY; + + ret = v4l2_event_subscribe(fh, sub, 2, NULL); + if (ret < 0) + return ret; + + if (sub->type == UVC_EVENT_SETUP) { + uvc->func_connected = true; + handle->is_uvc_app_handle = true; + uvc_function_connect(uvc); + } + + return 0; +} + +static void uvc_v4l2_disable(struct uvc_device *uvc) +{ + uvc->func_connected = false; + uvc_function_disconnect(uvc); + uvcg_video_enable(&uvc->video, 0); + uvcg_free_buffers(&uvc->video.queue); } static int uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { - return v4l2_event_unsubscribe(fh, sub); + struct uvc_device *uvc = video_get_drvdata(fh->vdev); + struct uvc_file_handle *handle = to_uvc_file_handle(fh); + int ret; + + ret = v4l2_event_unsubscribe(fh, sub); + if (ret < 0) + return ret; + + if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) { + uvc_v4l2_disable(uvc); + handle->is_uvc_app_handle = false; + } + + return 0; } static long @@ -292,7 +331,6 @@ uvc_v4l2_open(struct file *file) handle->device = &uvc->video; file->private_data = &handle->vfh; - uvc_function_connect(uvc); return 0; } @@ -304,11 +342,9 @@ uvc_v4l2_release(struct file *file) struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); struct uvc_video *video = handle->device; - uvc_function_disconnect(uvc); - mutex_lock(&video->mutex); - uvcg_video_enable(video, 0); - uvcg_free_buffers(&video->queue); + if (handle->is_uvc_app_handle) + uvc_v4l2_disable(uvc); mutex_unlock(&video->mutex); file->private_data = NULL; diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index b4a763e5f70e..7f59a0c47402 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -12,6 +12,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/video.h> +#include <asm/unaligned.h> #include <media/v4l2-dev.h> @@ -27,13 +28,41 @@ static int uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf, u8 *data, int len) { - data[0] = UVCG_REQUEST_HEADER_LEN; + struct uvc_device *uvc = container_of(video, struct uvc_device, video); + struct usb_composite_dev *cdev = uvc->func.config->cdev; + struct timespec64 ts = ns_to_timespec64(buf->buf.vb2_buf.timestamp); + int pos = 2; + data[1] = UVC_STREAM_EOH | video->fid; - if (buf->bytesused - video->queue.buf_used <= len - UVCG_REQUEST_HEADER_LEN) + if (video->queue.buf_used == 0 && ts.tv_sec) { + /* dwClockFrequency is 48 MHz */ + u32 pts = ((u64)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC) * 48; + + data[1] |= UVC_STREAM_PTS; + put_unaligned_le32(pts, &data[pos]); + pos += 4; + } + + if (cdev->gadget->ops->get_frame) { + u32 sof, stc; + + sof = usb_gadget_frame_number(cdev->gadget); + ktime_get_ts64(&ts); + stc = ((u64)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC) * 48; + + data[1] |= UVC_STREAM_SCR; + put_unaligned_le32(stc, &data[pos]); + put_unaligned_le16(sof, &data[pos+4]); + pos += 6; + } + + data[0] = pos; + + if (buf->bytesused - video->queue.buf_used <= len - pos) data[1] |= UVC_STREAM_EOF; - return 2; + return pos; } static int @@ -104,22 +133,22 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video, unsigned int len = video->req_size; unsigned int sg_left, part = 0; unsigned int i; - int ret; + int header_len; sg = ureq->sgt.sgl; sg_init_table(sg, ureq->sgt.nents); /* Init the header. */ - ret = uvc_video_encode_header(video, buf, ureq->header, + header_len = uvc_video_encode_header(video, buf, ureq->header, video->req_size); - sg_set_buf(sg, ureq->header, UVCG_REQUEST_HEADER_LEN); - len -= ret; + sg_set_buf(sg, ureq->header, header_len); + len -= header_len; if (pending <= len) len = pending; req->length = (len == pending) ? - len + UVCG_REQUEST_HEADER_LEN : video->req_size; + len + header_len : video->req_size; /* Init the pending sgs with payload */ sg = sg_next(sg); @@ -148,7 +177,7 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video, req->num_sgs = i + 1; req->length -= len; - video->queue.buf_used += req->length - UVCG_REQUEST_HEADER_LEN; + video->queue.buf_used += req->length - header_len; if (buf->bytesused == video->queue.buf_used || !buf->sg) { video->queue.buf_used = 0; @@ -199,9 +228,12 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n", ret); - /* Isochronous endpoints can't be halted. */ - if (usb_endpoint_xfer_bulk(video->ep->desc)) - usb_ep_set_halt(video->ep); + /* If the endpoint is disabled the descriptor may be NULL. */ + if (video->ep->desc) { + /* Isochronous endpoints can't be halted. */ + if (usb_endpoint_xfer_bulk(video->ep->desc)) + usb_ep_set_halt(video->ep); + } } return ret; @@ -213,6 +245,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) struct uvc_request *ureq = req->context; struct uvc_video *video = ureq->video; struct uvc_video_queue *queue = &video->queue; + struct uvc_device *uvc = video->uvc; unsigned long flags; switch (req->status) { @@ -235,7 +268,8 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) list_add_tail(&req->list, &video->req_free); spin_unlock_irqrestore(&video->req_lock, flags); - schedule_work(&video->pump); + if (uvc->state == UVC_STATE_STREAMING) + schedule_work(&video->pump); } static int @@ -302,8 +336,8 @@ uvc_video_alloc_requests(struct uvc_video *video) list_add_tail(&video->ureq[i].req->list, &video->req_free); /* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */ sg_alloc_table(&video->ureq[i].sgt, - DIV_ROUND_UP(req_size - 2, PAGE_SIZE) + 2, - GFP_KERNEL); + DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN, + PAGE_SIZE) + 2, GFP_KERNEL); } video->req_size = req_size; @@ -329,12 +363,12 @@ static void uvcg_video_pump(struct work_struct *work) { struct uvc_video *video = container_of(work, struct uvc_video, pump); struct uvc_video_queue *queue = &video->queue; - struct usb_request *req; + struct usb_request *req = NULL; struct uvc_buffer *buf; unsigned long flags; int ret; - while (1) { + while (video->ep->enabled) { /* Retrieve the first available USB request, protected by the * request lock. */ @@ -384,6 +418,9 @@ static void uvcg_video_pump(struct work_struct *work) video->req_int_count++; } + if (!req) + return; + spin_lock_irqsave(&video->req_lock, flags); list_add_tail(&req->list, &video->req_free); spin_unlock_irqrestore(&video->req_lock, flags); diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index 9bf19475f6f9..03adeefa343b 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -12,8 +12,6 @@ #ifndef __UVC_VIDEO_H__ #define __UVC_VIDEO_H__ -#define UVCG_REQUEST_HEADER_LEN 2 - struct uvc_video; int uvcg_video_enable(struct uvc_video *video, int enable); diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 5b27d289443f..3912cc805f3a 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -99,8 +99,10 @@ static int do_config(struct usb_configuration *c) list_for_each_entry(e, &hidg_func_list, node) { e->f = usb_get_function(e->fi); - if (IS_ERR(e->f)) + if (IS_ERR(e->f)) { + status = PTR_ERR(e->f); goto put; + } status = usb_add_function(c, e->f); if (status < 0) { usb_put_function(e->f); diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 8c614bb86c66..69394dc1cdfb 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -330,6 +330,7 @@ config USB_AMD5536UDC config USB_FSL_QE tristate "Freescale QE/CPM USB Device Controller" depends on FSL_SOC && (QUICC_ENGINE || CPM) + depends on !64BIT || BROKEN help Some of Freescale PowerPC processors have a Full Speed QE/CPM2 USB controller, which support device mode with 4 diff --git a/drivers/usb/gadget/udc/amd5536udc.h b/drivers/usb/gadget/udc/amd5536udc.h index 3296f3fcee48..055436016503 100644 --- a/drivers/usb/gadget/udc/amd5536udc.h +++ b/drivers/usb/gadget/udc/amd5536udc.h @@ -572,7 +572,6 @@ struct udc { struct extcon_specific_cable_nb extcon_nb; struct notifier_block nb; struct delayed_work drd_work; - struct workqueue_struct *drd_wq; u32 conn_type; }; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 14fdf918ecfe..568534a0d17c 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -6,6 +6,8 @@ * Author: Felipe Balbi <balbi@ti.com> */ +#define pr_fmt(fmt) "UDC core: " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> @@ -89,7 +91,7 @@ EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); * configurable, with more generic names like "ep-a". (remember that for * USB, "in" means "towards the USB host".) * - * This routine must be called in process context. + * This routine may be called in an atomic (interrupt) context. * * returns zero, or a negative error code. */ @@ -134,7 +136,7 @@ EXPORT_SYMBOL_GPL(usb_ep_enable); * gadget drivers must call usb_ep_enable() again before queueing * requests to the endpoint. * - * This routine must be called in process context. + * This routine may be called in an atomic (interrupt) context. * * returns zero, or a negative error code. */ @@ -1555,14 +1557,14 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!driver->match_existing_only) { list_add_tail(&driver->pending, &gadget_driver_pending_list); - pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", + pr_info("couldn't find an available UDC - added [%s] to list of pending drivers\n", driver->function); ret = 0; } mutex_unlock(&udc_lock); if (ret) - pr_warn("udc-core: couldn't find an available UDC or it's busy\n"); + pr_warn("couldn't find an available UDC or it's busy: %d\n", ret); return ret; found: ret = udc_bind_to_driver(udc, driver); diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 3e1267d38774..3757a772a55e 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -553,12 +553,12 @@ static int start_dma(struct goku_ep *ep, struct goku_request *req) master &= ~MST_R_BITS; if (unlikely(req->req.length == 0)) - master = MST_RD_ENA | MST_RD_EOPB; + master |= MST_RD_ENA | MST_RD_EOPB; else if ((req->req.length % ep->ep.maxpacket) != 0 || req->req.zero) - master = MST_RD_ENA | MST_EOPB_ENA; + master |= MST_RD_ENA | MST_EOPB_ENA; else - master = MST_RD_ENA | MST_EOPB_DIS; + master |= MST_RD_ENA | MST_EOPB_DIS; ep->dev->int_enable |= INT_MSTRDEND; diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index a09ec1d826b2..52cdfd8212d6 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -2325,7 +2325,7 @@ static int pxa25x_udc_probe(struct platform_device *pdev) pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); /* insist on Intel/ARM/XScale */ - asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); + asm("mrc p15, 0, %0, c0, c0" : "=r" (chiprev)); if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { pr_err("%s: not XScale!\n", driver_name); return -ENODEV; diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index 99805d60a7ab..8bbb89c80348 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -243,11 +243,6 @@ static int udc_plat_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - if (dev->drd_wq) { - flush_workqueue(dev->drd_wq); - destroy_workqueue(dev->drd_wq); - } - phy_power_off(dev->udc_phy); phy_exit(dev->udc_phy); extcon_unregister_notifier(dev->edev, EXTCON_USB, &dev->nb); diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index fb4ffedd6f0d..f5ca670776a3 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -11,6 +11,7 @@ * USB peripheral controller (at91_udc.c). */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/dma-mapping.h> @@ -171,6 +172,7 @@ struct xusb_ep { * @addr: the usb device base address * @lock: instance of spinlock * @dma_enabled: flag indicating whether the dma is included in the system + * @clk: pointer to struct clk * @read_fn: function pointer to read device registers * @write_fn: function pointer to write to device registers */ @@ -188,6 +190,7 @@ struct xusb_udc { void __iomem *addr; spinlock_t lock; bool dma_enabled; + struct clk *clk; unsigned int (*read_fn)(void __iomem *); void (*write_fn)(void __iomem *, u32, u32); @@ -2092,6 +2095,27 @@ static int xudc_probe(struct platform_device *pdev) udc->gadget.ep0 = &udc->ep[XUSB_EP_NUMBER_ZERO].ep_usb; udc->gadget.name = driver_name; + udc->clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); + if (IS_ERR(udc->clk)) { + if (PTR_ERR(udc->clk) != -ENOENT) { + ret = PTR_ERR(udc->clk); + goto fail; + } + + /* + * Clock framework support is optional, continue on, + * anyways if we don't find a matching clock + */ + dev_warn(&pdev->dev, "s_axi_aclk clock property is not found\n"); + udc->clk = NULL; + } + + ret = clk_prepare_enable(udc->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } + spin_lock_init(&udc->lock); /* Check for IP endianness */ @@ -2147,6 +2171,7 @@ static int xudc_remove(struct platform_device *pdev) struct xusb_udc *udc = platform_get_drvdata(pdev); usb_del_gadget_udc(&udc->gadget); + clk_disable_unprepare(udc->clk); return 0; } |