From 306637c8e1e3286f40ffe2ad10ad0e0cadef7e63 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Thu, 1 Jul 2021 14:48:13 +0800 Subject: [PATCH] usb: gadget: f_uac1: adds support for SS and SSP This adds UAC1 support of SS and SSP speed. Change-Id: I896d9e36f05eef9bb3eacfc56ef7d32aa7c89044 Signed-off-by: Frank Wang --- drivers/usb/gadget/function/f_uac1.c | 209 ++++++++++++++++++++++----- 1 file changed, 170 insertions(+), 39 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 6ff5a2f02bed..fc66ab8bbc58 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -250,6 +250,24 @@ static struct usb_endpoint_descriptor as_out_ep_desc = { .bInterval = 4, }; +static struct usb_endpoint_descriptor ss_out_ep_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE, + /* .wMaxPacketSize = DYNAMIC */ + .bInterval = 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_out_ep_desc_comp = { + .bLength = sizeof(ss_out_ep_desc_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + /* wBytesPerInterval = DYNAMIC */ +}; + /* Class-specific AS ISO OUT Endpoint Descriptor */ static struct uac_iso_endpoint_descriptor as_iso_out_desc = { .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, @@ -281,6 +299,24 @@ static struct usb_endpoint_descriptor as_in_ep_desc = { .bInterval = 4, }; +static struct usb_endpoint_descriptor ss_in_ep_desc = { + .bLength = USB_DT_ENDPOINT_AUDIO_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_in_ep_desc_comp = { + .bLength = sizeof(ss_in_ep_desc_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + /* wBytesPerInterval = DYNAMIC */ +}; + /* Class-specific AS ISO OUT Endpoint Descriptor */ static struct uac_iso_endpoint_descriptor as_iso_in_desc = { .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, @@ -323,6 +359,40 @@ static struct usb_descriptor_header *f_audio_desc[] = { NULL, }; +static struct usb_descriptor_header *f_ss_audio_desc[] = { + (struct usb_descriptor_header *)&iad_desc, + (struct usb_descriptor_header *)&ac_interface_desc, + (struct usb_descriptor_header *)&ac_header_desc, + + (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&io_out_ot_fu_desc, + (struct usb_descriptor_header *)&io_out_ot_desc, + (struct usb_descriptor_header *)&io_in_it_desc, + (struct usb_descriptor_header *)&usb_in_ot_fu_desc, + (struct usb_descriptor_header *)&usb_in_ot_desc, + + (struct usb_descriptor_header *)&as_out_interface_alt_0_desc, + (struct usb_descriptor_header *)&as_out_interface_alt_1_desc, + (struct usb_descriptor_header *)&as_out_header_desc, + + (struct usb_descriptor_header *)&as_out_type_i_desc, + + (struct usb_descriptor_header *)&ss_out_ep_desc, + (struct usb_descriptor_header *)&ss_out_ep_desc_comp, + (struct usb_descriptor_header *)&as_iso_out_desc, + + (struct usb_descriptor_header *)&as_in_interface_alt_0_desc, + (struct usb_descriptor_header *)&as_in_interface_alt_1_desc, + (struct usb_descriptor_header *)&as_in_header_desc, + + (struct usb_descriptor_header *)&as_in_type_i_desc, + + (struct usb_descriptor_header *)&ss_in_ep_desc, + (struct usb_descriptor_header *)&ss_in_ep_desc_comp, + (struct usb_descriptor_header *)&as_iso_in_desc, + NULL, +}; + enum { STR_ASSOC, STR_AC_IF, @@ -713,6 +783,75 @@ static void f_audio_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ #define USBDHDR(p) (struct usb_descriptor_header *)(p) +static void setup_headers(struct f_uac_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: + fallthrough; + case USB_SPEED_HIGH: + epout_desc = &as_out_ep_desc; + epin_desc = &as_in_ep_desc; + break; + default: + epout_desc = &ss_out_ep_desc; + epin_desc = &ss_in_ep_desc; + epout_desc_comp = &ss_out_ep_desc_comp; + epin_desc_comp = &ss_in_ep_desc_comp; + } + + i = 0; + headers[i++] = USBDHDR(&iad_desc); + headers[i++] = USBDHDR(&ac_interface_desc); + headers[i++] = USBDHDR(&ac_header_desc); + + if (EPOUT_EN(opts)) { + headers[i++] = USBDHDR(&usb_out_it_desc); + if (EPOUT_FU(opts)) + headers[i++] = USBDHDR(&io_out_ot_fu_desc); + headers[i++] = USBDHDR(&io_out_ot_desc); + } + + if (EPIN_EN(opts)) { + headers[i++] = USBDHDR(&io_in_it_desc); + if (EPIN_FU(opts)) + headers[i++] = USBDHDR(&usb_in_ot_fu_desc); + headers[i++] = USBDHDR(&usb_in_ot_desc); + } + + if (EPOUT_EN(opts)) { + headers[i++] = USBDHDR(&as_out_interface_alt_0_desc); + headers[i++] = USBDHDR(&as_out_interface_alt_1_desc); + headers[i++] = USBDHDR(&as_out_header_desc); + headers[i++] = USBDHDR(&as_out_type_i_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(&as_in_interface_alt_0_desc); + headers[i++] = USBDHDR(&as_in_interface_alt_1_desc); + headers[i++] = USBDHDR(&as_in_header_desc); + headers[i++] = USBDHDR(&as_in_type_i_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_uac_opts *opts) { int i = 1; @@ -770,43 +909,8 @@ static void setup_descriptor(struct f_uac_opts *opts) UAC_DT_AC_HEADER_SIZE(ac_header_desc.bInCollection); ac_header_desc.wTotalLength = cpu_to_le16(len + ac_header_desc.bLength); - i = 0; - f_audio_desc[i++] = USBDHDR(&iad_desc); - 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); - if (EPOUT_FU(opts)) - f_audio_desc[i++] = USBDHDR(&io_out_ot_fu_desc); - f_audio_desc[i++] = USBDHDR(&io_out_ot_desc); - } - - if (EPIN_EN(opts)) { - f_audio_desc[i++] = USBDHDR(&io_in_it_desc); - if (EPIN_FU(opts)) - f_audio_desc[i++] = USBDHDR(&usb_in_ot_fu_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; + setup_headers(opts, f_audio_desc, USB_SPEED_HIGH); + setup_headers(opts, f_ss_audio_desc, USB_SPEED_SUPER); } static int set_ep_max_packet_size(const struct f_uac_opts *opts, @@ -825,6 +929,8 @@ static int set_ep_max_packet_size(const struct f_uac_opts *opts, break; case USB_SPEED_HIGH: + fallthrough; + case USB_SPEED_SUPER: max_size_ep = 1024; factor = 8000; break; @@ -936,6 +1042,24 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) goto fail; } + status = set_ep_max_packet_size(audio_opts, &ss_out_ep_desc, + USB_SPEED_SUPER, false); + if (status < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + goto fail; + } + + ss_out_ep_desc_comp.wBytesPerInterval = ss_out_ep_desc.wMaxPacketSize; + + status = set_ep_max_packet_size(audio_opts, &ss_in_ep_desc, + USB_SPEED_SUPER, true); + if (status < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + goto fail; + } + + ss_in_ep_desc_comp.wBytesPerInterval = ss_in_ep_desc.wMaxPacketSize; + as_out_type_i_desc.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(idx); as_out_type_i_desc.bSamFreqType = idx; @@ -1001,15 +1125,22 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) audio->in_ep->desc = &as_in_ep_desc; } + ss_out_ep_desc.bEndpointAddress = as_out_ep_desc.bEndpointAddress; + ss_in_ep_desc.bEndpointAddress = as_in_ep_desc.bEndpointAddress; + setup_descriptor(audio_opts); /* copy descriptors, and track endpoint copies */ - status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, - NULL); + status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, + f_ss_audio_desc, f_ss_audio_desc); if (status) goto fail; audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize); audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize); + audio->out_ep_maxpsize = max_t(u16, audio->out_ep_maxpsize, + le16_to_cpu(ss_out_ep_desc.wMaxPacketSize)); + audio->in_ep_maxpsize = max_t(u16, audio->in_ep_maxpsize, + le16_to_cpu(ss_in_ep_desc.wMaxPacketSize)); audio->params.c_chmask = audio_opts->c_chmask; memcpy(audio->params.c_srate, audio_opts->c_srate, sizeof(audio->params.c_srate));