summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r--drivers/usb/gadget/function/f_ecm.c2
-rw-r--r--drivers/usb/gadget/function/f_eem.c6
-rw-r--r--drivers/usb/gadget/function/f_fs.c17
-rw-r--r--drivers/usb/gadget/function/f_hid.c3
-rw-r--r--drivers/usb/gadget/function/f_loopback.c2
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c2
-rw-r--r--drivers/usb/gadget/function/f_ncm.c10
-rw-r--r--drivers/usb/gadget/function/f_printer.c5
-rw-r--r--drivers/usb/gadget/function/f_rndis.c2
-rw-r--r--drivers/usb/gadget/function/f_serial.c2
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c3
-rw-r--r--drivers/usb/gadget/function/f_subset.c2
-rw-r--r--drivers/usb/gadget/function/f_tcm.c39
-rw-r--r--drivers/usb/gadget/function/f_uac1.c272
-rw-r--r--drivers/usb/gadget/function/f_uac2.c263
-rw-r--r--drivers/usb/gadget/function/f_uvc.c8
-rw-r--r--drivers/usb/gadget/function/u_audio.c6
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c2
18 files changed, 459 insertions, 187 deletions
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index 7f5cf488b2b1..ffe2486fce71 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -791,7 +791,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, NULL);
+ ecm_ss_function, ecm_ss_function);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index cfcc4e81fb77..2cd9942707b4 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -302,7 +302,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, NULL);
+ eem_ss_function, eem_ss_function);
if (status)
goto fail;
@@ -495,7 +495,7 @@ static int eem_unwrap(struct gether *port,
skb2 = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!skb2)) {
DBG(cdev, "unable to unframe EEM packet\n");
- continue;
+ goto next;
}
skb_trim(skb2, len - ETH_FCS_LEN);
@@ -505,7 +505,7 @@ static int eem_unwrap(struct gether *port,
GFP_ATOMIC);
if (unlikely(!skb3)) {
dev_kfree_skb_any(skb2);
- continue;
+ goto next;
}
dev_kfree_skb_any(skb2);
skb_queue_tail(list, skb3);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 801a8b668a35..d4844afeaffc 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -2640,6 +2640,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
do { /* lang_count > 0 so we can use do-while */
unsigned needed = needed_count;
+ u32 str_per_lang = str_count;
if (len < 3)
goto error_free;
@@ -2675,7 +2676,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
data += length + 1;
len -= length + 1;
- } while (--str_count);
+ } while (--str_per_lang);
s->id = 0; /* terminator */
s->s = NULL;
@@ -3566,6 +3567,9 @@ static void ffs_func_unbind(struct usb_configuration *c,
ffs->func = NULL;
}
+ /* Drain any pending AIO completions */
+ drain_workqueue(ffs->io_completion_wq);
+
if (!--opts->refcnt)
functionfs_unbind(ffs);
@@ -3826,14 +3830,9 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)
if (!len)
return NULL;
- data = kmalloc(len, GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
-
- if (copy_from_user(data, buf, len)) {
- kfree(data);
- return ERR_PTR(-EFAULT);
- }
+ data = memdup_user(buf, len);
+ if (IS_ERR(data))
+ return ERR_PTR(PTR_ERR(data));
pr_vdebug("Buffer from user space:\n");
ffs_dump_mem("", data, len);
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 1125f4715830..e55699308117 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -802,7 +802,8 @@ 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, hidg_ss_descriptors, NULL);
+ hidg_hs_descriptors, hidg_ss_descriptors,
+ hidg_ss_descriptors);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index b56ad7c3838b..ae41f556eb75 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -207,7 +207,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, NULL);
+ ss_loopback_descs, ss_loopback_descs);
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 950c9435beec..4a4703634a2a 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -351,8 +351,6 @@ static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
return container_of(f, struct fsg_dev, function);
}
-typedef void (*fsg_routine_t)(struct fsg_dev *);
-
static int exception_in_progress(struct fsg_common *common)
{
return common->state > FSG_STATE_NORMAL;
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 019bea8e09cc..855127249f24 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -583,7 +583,7 @@ static void ncm_do_notify(struct f_ncm *ncm)
data[0] = cpu_to_le32(ncm_bitrate(cdev->gadget));
data[1] = data[0];
- DBG(cdev, "notify speed %d\n", ncm_bitrate(cdev->gadget));
+ DBG(cdev, "notify speed %u\n", ncm_bitrate(cdev->gadget));
ncm->notify_state = NCM_NOTIFY_CONNECT;
break;
}
@@ -1101,11 +1101,11 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
ncm->ndp_dgram_count = 1;
/* Note: we skip opts->next_ndp_index */
- }
- /* Delay the timer. */
- hrtimer_start(&ncm->task_timer, TX_TIMEOUT_NSECS,
- HRTIMER_MODE_REL_SOFT);
+ /* Start the timer. */
+ hrtimer_start(&ncm->task_timer, TX_TIMEOUT_NSECS,
+ HRTIMER_MODE_REL_SOFT);
+ }
/* Add the datagram position entries */
ntb_ndp = skb_put_zero(ncm->skb_tx_ndp, dgram_idx_len);
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 61ce8e68f7a3..59d382fe1bbf 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -825,7 +825,7 @@ set_printer_interface(struct printer_dev *dev)
result = usb_ep_enable(dev->out_ep);
if (result != 0) {
- DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+ DBG(dev, "enable %s --> %d\n", dev->out_ep->name, result);
goto done;
}
@@ -1101,7 +1101,8 @@ 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, NULL);
+ hs_printer_function, ss_printer_function,
+ ss_printer_function);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 0739b05a0ef7..ee95e8f5f9d4 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -789,7 +789,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, NULL);
+ eth_ss_function, eth_ss_function);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index e62713846350..1ed8ff0ac2d3 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -233,7 +233,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, NULL);
+ gser_ss_function, gser_ss_function);
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 5a201ba7b155..1abf08e5164a 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -431,7 +431,8 @@ 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, NULL);
+ hs_source_sink_descs, ss_source_sink_descs,
+ ss_source_sink_descs);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 4d945254905d..51c1cae162d9 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -358,7 +358,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, NULL);
+ ss_eth_function, ss_eth_function);
if (status)
goto fail;
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 410fa89eae8f..de161ee0b1f9 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1050,19 +1050,17 @@ static void usbg_cmd_work(struct work_struct *work)
tv_nexus = tpg->tpg_nexus;
dir = get_cmd_dir(cmd->cmd_buf);
if (dir < 0) {
- transport_init_se_cmd(se_cmd,
- tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
- tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
- cmd->prio_attr, cmd->sense_iu.sense,
- cmd->unpacked_lun);
+ __target_init_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense,
+ cmd->unpacked_lun);
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, flags) < 0)
- goto out;
-
+ 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);
return;
out:
@@ -1181,19 +1179,17 @@ static void bot_cmd_work(struct work_struct *work)
tv_nexus = tpg->tpg_nexus;
dir = get_cmd_dir(cmd->cmd_buf);
if (dir < 0) {
- transport_init_se_cmd(se_cmd,
- tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
- tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
- cmd->prio_attr, cmd->sense_iu.sense,
- cmd->unpacked_lun);
+ __target_init_cmd(se_cmd,
+ tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+ tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+ cmd->prio_attr, cmd->sense_iu.sense,
+ cmd->unpacked_lun);
goto out;
}
- if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
- cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
- cmd->data_len, cmd->prio_attr, dir, 0) < 0)
- goto out;
-
+ target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+ cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+ cmd->data_len, cmd->prio_attr, dir, 0);
return;
out:
@@ -2061,7 +2057,8 @@ 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, NULL);
+ uasp_hs_function_desc, uasp_ss_function_desc,
+ uasp_ss_function_desc);
if (ret)
goto ep_fail;
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 560382e0a8f3..d04707580068 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -19,6 +19,12 @@
#include "u_audio.h"
#include "u_uac1.h"
+/* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */
+#define UAC1_CHANNEL_MASK 0x0FFF
+
+#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
+#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+
struct f_uac1 {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
@@ -30,6 +36,11 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f)
return container_of(f, struct f_uac1, g_audio.func);
}
+static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio)
+{
+ return container_of(audio->func.fi, struct f_uac1_opts, func_inst);
+}
+
/*
* DESCRIPTORS ... most are static, but strings and full
* configuration descriptors are built on demand.
@@ -42,11 +53,6 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f)
* USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture
* ALSA_Playback -> IT_3 -> OT_4 -> USB-IN
*/
-#define F_AUDIO_AC_INTERFACE 0
-#define F_AUDIO_AS_OUT_INTERFACE 1
-#define F_AUDIO_AS_IN_INTERFACE 2
-/* Number of streaming interfaces */
-#define F_AUDIO_NUM_INTERFACES 2
/* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc = {
@@ -57,73 +63,47 @@ static struct usb_interface_descriptor ac_interface_desc = {
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
};
-/*
- * The number of AudioStreaming and MIDIStreaming interfaces
- * in the Audio Interface Collection
- */
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
-
-#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
-/* 2 input terminals and 2 output terminals */
-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
- + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE)
/* B.3.2 Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
- .bLength = UAC_DT_AC_HEADER_LENGTH,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubtype = UAC_HEADER,
- .bcdADC = cpu_to_le16(0x0100),
- .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH),
- .bInCollection = F_AUDIO_NUM_INTERFACES,
- .baInterfaceNr = {
- /* Interface number of the AudioStream interfaces */
- [0] = 1,
- [1] = 2,
- }
-};
+static struct uac1_ac_header_descriptor *ac_header_desc;
-#define USB_OUT_IT_ID 1
static struct uac_input_terminal_descriptor usb_out_it_desc = {
.bLength = UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
- .bTerminalID = USB_OUT_IT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal = 0,
.wChannelConfig = cpu_to_le16(0x3),
};
-#define IO_OUT_OT_ID 2
static struct uac1_output_terminal_descriptor io_out_ot_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
- .bTerminalID = IO_OUT_OT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
.bAssocTerminal = 0,
- .bSourceID = USB_OUT_IT_ID,
+ /* .bSourceID = DYNAMIC */
};
-#define IO_IN_IT_ID 3
static struct uac_input_terminal_descriptor io_in_it_desc = {
.bLength = UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
- .bTerminalID = IO_IN_IT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
.bAssocTerminal = 0,
.wChannelConfig = cpu_to_le16(0x3),
};
-#define USB_IN_OT_ID 4
static struct uac1_output_terminal_descriptor usb_in_ot_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
- .bTerminalID = USB_IN_OT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal = 0,
- .bSourceID = IO_IN_IT_ID,
+ /* .bSourceID = DYNAMIC */
};
/* B.4.1 Standard AS Interface Descriptor */
@@ -168,7 +148,7 @@ static struct uac1_as_header_descriptor as_out_header_desc = {
.bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,
- .bTerminalLink = USB_OUT_IT_ID,
+ /* .bTerminalLink = DYNAMIC */
.bDelay = 1,
.wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
};
@@ -177,7 +157,7 @@ static struct uac1_as_header_descriptor as_in_header_desc = {
.bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,
- .bTerminalLink = USB_IN_OT_ID,
+ /* .bTerminalLink = DYNAMIC */
.bDelay = 1,
.wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
};
@@ -505,11 +485,144 @@ static void f_audio_disable(struct usb_function *f)
/*-------------------------------------------------------------------------*/
+static struct
+uac1_ac_header_descriptor *build_ac_header_desc(struct f_uac1_opts *opts)
+{
+ struct uac1_ac_header_descriptor *ac_desc;
+ int ac_header_desc_size;
+ int num_ifaces = 0;
+
+ if (EPOUT_EN(opts))
+ num_ifaces++;
+ if (EPIN_EN(opts))
+ num_ifaces++;
+
+ ac_header_desc_size = UAC_DT_AC_HEADER_SIZE(num_ifaces);
+
+ ac_desc = kzalloc(ac_header_desc_size, GFP_KERNEL);
+ if (!ac_desc)
+ return NULL;
+
+ ac_desc->bLength = ac_header_desc_size;
+ ac_desc->bDescriptorType = USB_DT_CS_INTERFACE;
+ ac_desc->bDescriptorSubtype = UAC_HEADER;
+ ac_desc->bcdADC = cpu_to_le16(0x0100);
+ ac_desc->bInCollection = num_ifaces;
+
+ /* wTotalLength and baInterfaceNr will be defined later */
+
+ return ac_desc;
+}
+
+/* Use macro to overcome line length limitation */
+#define USBDHDR(p) (struct usb_descriptor_header *)(p)
+
+static void setup_descriptor(struct f_uac1_opts *opts)
+{
+ /* patch descriptors */
+ int i = 1; /* ID's start with 1 */
+
+ if (EPOUT_EN(opts))
+ usb_out_it_desc.bTerminalID = i++;
+ if (EPIN_EN(opts))
+ io_in_it_desc.bTerminalID = i++;
+ if (EPOUT_EN(opts))
+ io_out_ot_desc.bTerminalID = i++;
+ if (EPIN_EN(opts))
+ usb_in_ot_desc.bTerminalID = i++;
+
+ usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID;
+ io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID;
+
+ as_out_header_desc.bTerminalLink = usb_out_it_desc.bTerminalID;
+ as_in_header_desc.bTerminalLink = usb_in_ot_desc.bTerminalID;
+
+ ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc->bLength);
+
+ if (EPIN_EN(opts)) {
+ u16 len = le16_to_cpu(ac_header_desc->wTotalLength);
+
+ len += sizeof(usb_in_ot_desc);
+ len += sizeof(io_in_it_desc);
+ ac_header_desc->wTotalLength = cpu_to_le16(len);
+ }
+ if (EPOUT_EN(opts)) {
+ u16 len = le16_to_cpu(ac_header_desc->wTotalLength);
+
+ len += sizeof(usb_out_it_desc);
+ len += sizeof(io_out_ot_desc);
+ ac_header_desc->wTotalLength = cpu_to_le16(len);
+ }
+
+ i = 0;
+ f_audio_desc[i++] = USBDHDR(&ac_interface_desc);
+ f_audio_desc[i++] = USBDHDR(ac_header_desc);
+
+ if (EPOUT_EN(opts)) {
+ f_audio_desc[i++] = USBDHDR(&usb_out_it_desc);
+ f_audio_desc[i++] = USBDHDR(&io_out_ot_desc);
+ }
+
+ if (EPIN_EN(opts)) {
+ f_audio_desc[i++] = USBDHDR(&io_in_it_desc);
+ f_audio_desc[i++] = USBDHDR(&usb_in_ot_desc);
+ }
+
+ if (EPOUT_EN(opts)) {
+ f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_0_desc);
+ f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_1_desc);
+ f_audio_desc[i++] = USBDHDR(&as_out_header_desc);
+ f_audio_desc[i++] = USBDHDR(&as_out_type_i_desc);
+ f_audio_desc[i++] = USBDHDR(&as_out_ep_desc);
+ f_audio_desc[i++] = USBDHDR(&as_iso_out_desc);
+ }
+ if (EPIN_EN(opts)) {
+ f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_0_desc);
+ f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_1_desc);
+ f_audio_desc[i++] = USBDHDR(&as_in_header_desc);
+ f_audio_desc[i++] = USBDHDR(&as_in_type_i_desc);
+ f_audio_desc[i++] = USBDHDR(&as_in_ep_desc);
+ f_audio_desc[i++] = USBDHDR(&as_iso_in_desc);
+ }
+ f_audio_desc[i] = NULL;
+}
+
+static int f_audio_validate_opts(struct g_audio *audio, struct device *dev)
+{
+ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio);
+
+ if (!opts->p_chmask && !opts->c_chmask) {
+ dev_err(dev, "Error: no playback and capture channels\n");
+ return -EINVAL;
+ } else if (opts->p_chmask & ~UAC1_CHANNEL_MASK) {
+ dev_err(dev, "Error: unsupported playback channels mask\n");
+ return -EINVAL;
+ } else if (opts->c_chmask & ~UAC1_CHANNEL_MASK) {
+ dev_err(dev, "Error: unsupported capture channels mask\n");
+ return -EINVAL;
+ } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
+ dev_err(dev, "Error: incorrect playback sample size\n");
+ return -EINVAL;
+ } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
+ dev_err(dev, "Error: incorrect capture sample size\n");
+ return -EINVAL;
+ } else if (!opts->p_srate) {
+ dev_err(dev, "Error: incorrect playback sampling rate\n");
+ return -EINVAL;
+ } else if (!opts->c_srate) {
+ dev_err(dev, "Error: incorrect capture sampling rate\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* audio function driver setup/binding */
static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct usb_gadget *gadget = cdev->gadget;
+ struct device *dev = &gadget->dev;
struct f_uac1 *uac1 = func_to_uac1(f);
struct g_audio *audio = func_to_g_audio(f);
struct f_uac1_opts *audio_opts;
@@ -517,13 +630,23 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_string *us;
u8 *sam_freq;
int rate;
+ int ba_iface_id;
int status;
+ status = f_audio_validate_opts(audio, dev);
+ if (status)
+ return status;
+
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1));
if (IS_ERR(us))
return PTR_ERR(us);
+
+ ac_header_desc = build_ac_header_desc(audio_opts);
+ if (!ac_header_desc)
+ return -ENOMEM;
+
ac_interface_desc.iInterface = us[STR_AC_IF].id;
usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id;
usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id;
@@ -564,40 +687,52 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
uac1->ac_intf = status;
uac1->ac_alt = 0;
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- as_out_interface_alt_0_desc.bInterfaceNumber = status;
- as_out_interface_alt_1_desc.bInterfaceNumber = status;
- ac_header_desc.baInterfaceNr[0] = status;
- uac1->as_out_intf = status;
- uac1->as_out_alt = 0;
+ ba_iface_id = 0;
+
+ if (EPOUT_EN(audio_opts)) {
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ as_out_interface_alt_0_desc.bInterfaceNumber = status;
+ as_out_interface_alt_1_desc.bInterfaceNumber = status;
+ ac_header_desc->baInterfaceNr[ba_iface_id++] = status;
+ uac1->as_out_intf = status;
+ uac1->as_out_alt = 0;
+ }
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- as_in_interface_alt_0_desc.bInterfaceNumber = status;
- as_in_interface_alt_1_desc.bInterfaceNumber = status;
- ac_header_desc.baInterfaceNr[1] = status;
- uac1->as_in_intf = status;
- uac1->as_in_alt = 0;
+ if (EPIN_EN(audio_opts)) {
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ as_in_interface_alt_0_desc.bInterfaceNumber = status;
+ as_in_interface_alt_1_desc.bInterfaceNumber = status;
+ ac_header_desc->baInterfaceNr[ba_iface_id++] = status;
+ uac1->as_in_intf = status;
+ uac1->as_in_alt = 0;
+ }
audio->gadget = gadget;
status = -ENODEV;
/* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
- if (!ep)
- goto fail;
- audio->out_ep = ep;
- audio->out_ep->desc = &as_out_ep_desc;
+ if (EPOUT_EN(audio_opts)) {
+ ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
+ if (!ep)
+ goto fail;
+ audio->out_ep = ep;
+ audio->out_ep->desc = &as_out_ep_desc;
+ }
- ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc);
- if (!ep)
- goto fail;
- audio->in_ep = ep;
- audio->in_ep->desc = &as_in_ep_desc;
+ if (EPIN_EN(audio_opts)) {
+ ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc);
+ if (!ep)
+ goto fail;
+ audio->in_ep = ep;
+ audio->in_ep->desc = &as_in_ep_desc;
+ }
+
+ setup_descriptor(audio_opts);
/* copy descriptors, and track endpoint copies */
status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL,
@@ -624,6 +759,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
err_card_register:
usb_free_all_descriptors(f);
fail:
+ kfree(ac_header_desc);
+ ac_header_desc = NULL;
return status;
}
@@ -766,6 +903,9 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
g_audio_cleanup(audio);
usb_free_all_descriptors(f);
+ kfree(ac_header_desc);
+ ac_header_desc = NULL;
+
audio->gadget = NULL;
}
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 6f03e944e0e3..7aa4c8bc5a1a 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -14,6 +14,9 @@
#include "u_audio.h"
#include "u_uac2.h"
+/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */
+#define UAC2_CHANNEL_MASK 0x07FFFFFF
+
/*
* The driver implements a simple UAC_2 topology.
* USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
@@ -284,6 +287,24 @@ static struct usb_endpoint_descriptor hs_epout_desc = {
.bInterval = 4,
};
+static struct usb_endpoint_descriptor ss_epout_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .wMaxPacketSize = DYNAMIC */
+ .bInterval = 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = {
+ .bLength = sizeof(ss_epout_desc_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ /* wBytesPerInterval = DYNAMIC */
+};
+
/* CS AS ISO OUT Endpoint */
static struct uac2_iso_endpoint_descriptor as_iso_out_desc = {
.bLength = sizeof as_iso_out_desc,
@@ -361,6 +382,24 @@ static struct usb_endpoint_descriptor hs_epin_desc = {
.bInterval = 4,
};
+static struct usb_endpoint_descriptor ss_epin_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .wMaxPacketSize = DYNAMIC */
+ .bInterval = 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = {
+ .bLength = sizeof(ss_epin_desc_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ /* wBytesPerInterval = DYNAMIC */
+};
+
/* CS AS ISO IN Endpoint */
static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
.bLength = sizeof as_iso_in_desc,
@@ -433,6 +472,38 @@ static struct usb_descriptor_header *hs_audio_desc[] = {
NULL,
};
+static struct usb_descriptor_header *ss_audio_desc[] = {
+ (struct usb_descriptor_header *)&iad_desc,
+ (struct usb_descriptor_header *)&std_ac_if_desc,
+
+ (struct usb_descriptor_header *)&ac_hdr_desc,
+ (struct usb_descriptor_header *)&in_clk_src_desc,
+ (struct usb_descriptor_header *)&out_clk_src_desc,
+ (struct usb_descriptor_header *)&usb_out_it_desc,
+ (struct usb_descriptor_header *)&io_in_it_desc,
+ (struct usb_descriptor_header *)&usb_in_ot_desc,
+ (struct usb_descriptor_header *)&io_out_ot_desc,
+
+ (struct usb_descriptor_header *)&std_as_out_if0_desc,
+ (struct usb_descriptor_header *)&std_as_out_if1_desc,
+
+ (struct usb_descriptor_header *)&as_out_hdr_desc,
+ (struct usb_descriptor_header *)&as_out_fmt1_desc,
+ (struct usb_descriptor_header *)&ss_epout_desc,
+ (struct usb_descriptor_header *)&ss_epout_desc_comp,
+ (struct usb_descriptor_header *)&as_iso_out_desc,
+
+ (struct usb_descriptor_header *)&std_as_in_if0_desc,
+ (struct usb_descriptor_header *)&std_as_in_if1_desc,
+
+ (struct usb_descriptor_header *)&as_in_hdr_desc,
+ (struct usb_descriptor_header *)&as_in_fmt1_desc,
+ (struct usb_descriptor_header *)&ss_epin_desc,
+ (struct usb_descriptor_header *)&ss_epin_desc_comp,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
struct cntrl_cur_lay3 {
__le32 dCUR;
};
@@ -459,6 +530,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
break;
case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
max_size_ep = 1024;
factor = 8000;
break;
@@ -488,6 +560,72 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
/* Use macro to overcome line length limitation */
#define USBDHDR(p) (struct usb_descriptor_header *)(p)
+static void setup_headers(struct f_uac2_opts *opts,
+ struct usb_descriptor_header **headers,
+ enum usb_device_speed speed)
+{
+ struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL;
+ struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL;
+ struct usb_endpoint_descriptor *epout_desc;
+ struct usb_endpoint_descriptor *epin_desc;
+ int i;
+
+ switch (speed) {
+ case USB_SPEED_FULL:
+ epout_desc = &fs_epout_desc;
+ epin_desc = &fs_epin_desc;
+ break;
+ case USB_SPEED_HIGH:
+ epout_desc = &hs_epout_desc;
+ epin_desc = &hs_epin_desc;
+ break;
+ default:
+ epout_desc = &ss_epout_desc;
+ epin_desc = &ss_epin_desc;
+ epout_desc_comp = &ss_epout_desc_comp;
+ epin_desc_comp = &ss_epin_desc_comp;
+ }
+
+ i = 0;
+ headers[i++] = USBDHDR(&iad_desc);
+ headers[i++] = USBDHDR(&std_ac_if_desc);
+ headers[i++] = USBDHDR(&ac_hdr_desc);
+ if (EPIN_EN(opts))
+ headers[i++] = USBDHDR(&in_clk_src_desc);
+ if (EPOUT_EN(opts)) {
+ headers[i++] = USBDHDR(&out_clk_src_desc);
+ headers[i++] = USBDHDR(&usb_out_it_desc);
+ }
+ if (EPIN_EN(opts)) {
+ headers[i++] = USBDHDR(&io_in_it_desc);
+ headers[i++] = USBDHDR(&usb_in_ot_desc);
+ }
+ if (EPOUT_EN(opts)) {
+ headers[i++] = USBDHDR(&io_out_ot_desc);
+ headers[i++] = USBDHDR(&std_as_out_if0_desc);
+ headers[i++] = USBDHDR(&std_as_out_if1_desc);
+ headers[i++] = USBDHDR(&as_out_hdr_desc);
+ headers[i++] = USBDHDR(&as_out_fmt1_desc);
+ headers[i++] = USBDHDR(epout_desc);
+ if (epout_desc_comp)
+ headers[i++] = USBDHDR(epout_desc_comp);
+
+ headers[i++] = USBDHDR(&as_iso_out_desc);
+ }
+ if (EPIN_EN(opts)) {
+ headers[i++] = USBDHDR(&std_as_in_if0_desc);
+ headers[i++] = USBDHDR(&std_as_in_if1_desc);
+ headers[i++] = USBDHDR(&as_in_hdr_desc);
+ headers[i++] = USBDHDR(&as_in_fmt1_desc);
+ headers[i++] = USBDHDR(epin_desc);
+ if (epin_desc_comp)
+ headers[i++] = USBDHDR(epin_desc_comp);
+
+ headers[i++] = USBDHDR(&as_iso_in_desc);
+ }
+ headers[i] = NULL;
+}
+
static void setup_descriptor(struct f_uac2_opts *opts)
{
/* patch descriptors */
@@ -537,71 +675,39 @@ static void setup_descriptor(struct f_uac2_opts *opts)
iad_desc.bInterfaceCount++;
}
- i = 0;
- fs_audio_desc[i++] = USBDHDR(&iad_desc);
- fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc);
- fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc);
- if (EPIN_EN(opts))
- fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc);
- if (EPOUT_EN(opts)) {
- fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc);
- fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc);
- }
- if (EPIN_EN(opts)) {
- fs_audio_desc[i++] = USBDHDR(&io_in_it_desc);
- fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc);
- }
- if (EPOUT_EN(opts)) {
- fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc);
- fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc);
- fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc);
- fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc);
- fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc);
- fs_audio_desc[i++] = USBDHDR(&fs_epout_desc);
- fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc);
- }
- if (EPIN_EN(opts)) {
- fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc);
- fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc);
- fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc);
- fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc);
- fs_audio_desc[i++] = USBDHDR(&fs_epin_desc);
- fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc);
- }
- fs_audio_desc[i] = NULL;
+ setup_headers(opts, fs_audio_desc, USB_SPEED_FULL);
+ setup_headers(opts, hs_audio_desc, USB_SPEED_HIGH);
+ setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER);
+}
- i = 0;
- hs_audio_desc[i++] = USBDHDR(&iad_desc);
- hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc);
- hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc);
- if (EPIN_EN(opts))
- hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc);
- if (EPOUT_EN(opts)) {
- hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc);
- hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc);
- }
- if (EPIN_EN(opts)) {
- hs_audio_desc[i++] = USBDHDR(&io_in_it_desc);
- hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc);
- }
- if (EPOUT_EN(opts)) {
- hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc);
- hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc);
- hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc);
- hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc);
- hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc);
- hs_audio_desc[i++] = USBDHDR(&hs_epout_desc);
- hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc);
- }
- if (EPIN_EN(opts)) {
- hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc);
- hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc);
- hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc);
- hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc);
- hs_audio_desc[i++] = USBDHDR(&hs_epin_desc);
- hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc);
+static int afunc_validate_opts(struct g_audio *agdev, struct device *dev)
+{
+ struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev);
+
+ if (!opts->p_chmask && !opts->c_chmask) {
+ dev_err(dev, "Error: no playback and capture channels\n");
+ return -EINVAL;
+ } else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) {
+ dev_err(dev, "Error: unsupported playback channels mask\n");
+ return -EINVAL;
+ } else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) {
+ dev_err(dev, "Error: unsupported capture channels mask\n");
+ return -EINVAL;
+ } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
+ dev_err(dev, "Error: incorrect playback sample size\n");
+ return -EINVAL;
+ } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
+ dev_err(dev, "Error: incorrect capture sample size\n");
+ return -EINVAL;
+ } else if (!opts->p_srate) {
+ dev_err(dev, "Error: incorrect playback sampling rate\n");
+ return -EINVAL;
+ } else if (!opts->c_srate) {
+ dev_err(dev, "Error: incorrect capture sampling rate\n");
+ return -EINVAL;
}
- hs_audio_desc[i] = NULL;
+
+ return 0;
}
static int
@@ -612,11 +718,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
struct usb_composite_dev *cdev = cfg->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct device *dev = &gadget->dev;
- struct f_uac2_opts *uac2_opts;
+ struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev);
struct usb_string *us;
int ret;
- uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
+ ret = afunc_validate_opts(agdev, dev);
+ if (ret)
+ return ret;
us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
if (IS_ERR(us))
@@ -716,6 +824,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
return ret;
}
+ ret = set_ep_max_packet_size(uac2_opts, &ss_epin_desc, USB_SPEED_SUPER,
+ true);
+ if (ret < 0) {
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+
+ ret = set_ep_max_packet_size(uac2_opts, &ss_epout_desc, USB_SPEED_SUPER,
+ false);
+ if (ret < 0) {
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+
if (EPOUT_EN(uac2_opts)) {
agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
if (!agdev->out_ep) {
@@ -739,13 +861,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
le16_to_cpu(fs_epout_desc.wMaxPacketSize),
le16_to_cpu(hs_epout_desc.wMaxPacketSize));
+ agdev->in_ep_maxpsize = max_t(u16, agdev->in_ep_maxpsize,
+ le16_to_cpu(ss_epin_desc.wMaxPacketSize));
+ agdev->out_ep_maxpsize = max_t(u16, agdev->out_ep_maxpsize,
+ le16_to_cpu(ss_epout_desc.wMaxPacketSize));
+
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
+ ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+ ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
setup_descriptor(uac2_opts);
- ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL,
- NULL);
+ ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc,
+ ss_audio_desc);
if (ret)
return ret;
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 44b4352a2676..f48a00e49794 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -633,7 +633,12 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_hs_streaming_ep.wMaxPacketSize =
cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11));
- uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
+
+ /* A high-bandwidth endpoint must specify a bInterval value of 1 */
+ if (max_packet_mult > 1)
+ uvc_hs_streaming_ep.bInterval = 1;
+ else
+ uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size);
uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
@@ -817,6 +822,7 @@ static struct usb_function_instance *uvc_alloc_inst(void)
pd->bmControls[0] = 1;
pd->bmControls[1] = 0;
pd->iProcessing = 0;
+ pd->bmVideoStandards = 0;
od = &opts->uvc_output_terminal;
od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE;
diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index 265c4d805f81..5fbceee897a3 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -549,15 +549,15 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
if (err < 0)
goto snd_fail;
- strlcpy(pcm->name, pcm_name, sizeof(pcm->name));
+ strscpy(pcm->name, pcm_name, sizeof(pcm->name));
pcm->private_data = uac;
uac->pcm = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
- strlcpy(card->driver, card_name, sizeof(card->driver));
- strlcpy(card->shortname, card_name, sizeof(card->shortname));
+ strscpy(card->driver, card_name, sizeof(card->driver));
+ strscpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id);
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 00fb58e50a15..cd28dec837dd 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -231,7 +231,7 @@ static struct config_item *uvcg_control_header_make(struct config_group *group,
h->desc.bLength = UVC_DT_HEADER_SIZE(1);
h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
h->desc.bDescriptorSubType = UVC_VC_HEADER;
- h->desc.bcdUVC = cpu_to_le16(0x0100);
+ h->desc.bcdUVC = cpu_to_le16(0x0110);
h->desc.dwClockFrequency = cpu_to_le32(48000000);
config_item_init_type_name(&h->item, name, &uvcg_control_header_type);