usb: f_uac2: adds support for SS and SSP
authorPawel Laszczak <pawell@cadence.com>
Wed, 10 Mar 2021 10:52:16 +0000 (11:52 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 Mar 2021 11:51:24 +0000 (12:51 +0100)
Patch adds support of SS and SSP speed.

Signed-off-by: Pawel Laszczak <pawell@cadence.com>
Link: https://lore.kernel.org/r/20210310105216.38202-1-pawell@gli-login.cadence.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/function/f_uac2.c

index 6f03e94..409741e 100644 (file)
@@ -284,6 +284,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 +379,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 +469,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 +527,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 +557,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 +672,9 @@ 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;
-
-       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);
-       }
-       hs_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);
 }
 
 static int
@@ -716,6 +789,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 +826,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;