[U-Boot] [PATCH] Enable high speed support for USB device framework and usbtty

Marek Vasut
2012-02-27T11:41:06Z

> From: Vipin KUMAR <vipin.kumar@st.com>
>
> This patch adds the support for high speed in usb device framework and
> usbtty driver. This feature has been kept within a macro CONFIG_USBD_HS,
> so the board configuration files have to define this macro to enable high
> speed support.
>
> Along with that specific peripheral drivers also need to define a function
> to let the framework know that the enumeration has happened at high speed.
> This function prototype is "int is_usbd_high_speed(void)"
>
> Signed-off-by: Vipin Kumar <vipin.kumar@st.com>
> Signed-off-by: Amit Virdi <amit.virdi@st.com>
> ---
> README | 8 +++++++
> drivers/serial/usbtty.c | 50
> ++++++++++++++++++++++++++++++++++++++++++++- drivers/serial/usbtty.h |
> 4 +++
> drivers/usb/gadget/core.c | 14 ++++++++++++
> drivers/usb/gadget/ep0.c | 24 ++++++++++++++++++---
> include/usbdescriptors.h | 15 +++++++++++++
> include/usbdevice.h | 24 ++++++++++++++++++++-
> 7 files changed, 133 insertions(+), 6 deletions(-)
>
> diff --git a/README b/README
> index eba6378..d54bb68 100644
> --- a/README
> +++ b/README
> @@ -1165,6 +1165,14 @@ The following options need to be configured:
> Define this to have a tty type of device available to
> talk to the UDC device
>
> + CONFIG_USBD_HS
> + Define this to enable the high speed support for usb
> + device and usbtty. If this feature is enabled, a routine
> + int is_usbd_high_speed(void)
> + also needs to be defined by the driver to dynamically
poll
> + whether the enumeration has succeded at high speed or
full
> + speed.
> +
> CONFIG_SYS_CONSOLE_IS_IN_ENV
> Define this if you want stdin, stdout &/or stderr to
> be set to usbtty.
> diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
> index 550bc58..0374c7d 100644
> --- a/drivers/serial/usbtty.c
> +++ b/drivers/serial/usbtty.c
> @@ -133,6 +133,19 @@ static struct usb_device_descriptor device_descriptor
> = { };
>
>
> +#if defined(CONFIG_USBD_HS)
> +static struct usb_qualifier_descriptor qualifier_descriptor = {
> + .bLength = sizeof(struct usb_qualifier_descriptor),
> + .bDescriptorType = USB_DT_QUAL,
> + .bcdUSB = cpu_to_le16(USB_BCD_VERSION),
> + .bDeviceClass = COMMUNICATIONS_DEVICE_CLASS,
> + .bDeviceSubClass = 0x00,
> + .bDeviceProtocol = 0x00,
> + .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
> + .bNumConfigurations = NUM_CONFIGS
> +};
> +#endif
> +
> /*
> * Static CDC ACM specific descriptors
> */
> @@ -638,6 +651,9 @@ static void usbtty_init_instances (void)
> memset (device_instance, 0, sizeof (struct usb_device_instance));
> device_instance->device_state = STATE_INIT;
> device_instance->device_descriptor = &device_descriptor;
> +#if defined(CONFIG_USBD_HS)
> + device_instance->qualifier_descriptor = &qualifier_descriptor;
> +#endif
> device_instance->event = usbtty_event_handler;
> device_instance->cdc_recv_setup = usbtty_cdc_setup;
> device_instance->bus = bus_instance;
> @@ -751,6 +767,10 @@ static void usbtty_init_terminal_type(short type)
> device_descriptor.idProduct =
> cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM);
>
> +#if defined(CONFIG_USBD_HS)
> + qualifier_descriptor.bDeviceClass =
> + COMMUNICATIONS_DEVICE_CLASS;
> +#endif
> /* Assign endpoint indices */
> tx_endpoint = ACM_TX_ENDPOINT;
> rx_endpoint = ACM_RX_ENDPOINT;
> @@ -779,7 +799,9 @@ static void usbtty_init_terminal_type(short type)
> device_descriptor.bDeviceClass = 0xFF;
> device_descriptor.idProduct =
> cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL);
> -
> +#if defined(CONFIG_USBD_HS)
> + qualifier_descriptor.bDeviceClass = 0xFF;
> +#endif
> /* Assign endpoint indices */
> tx_endpoint = GSERIAL_TX_ENDPOINT;
> rx_endpoint = GSERIAL_RX_ENDPOINT;
> @@ -932,6 +954,9 @@ static int usbtty_configured (void)
> static void usbtty_event_handler (struct usb_device_instance *device,
> usb_device_event_t event, int data)
> {
> +#if defined(CONFIG_USBD_HS)
> + int i;
> +#endif
> switch (event) {
> case DEVICE_RESET:
> case DEVICE_BUS_INACTIVE:
> @@ -942,6 +967,29 @@ static void usbtty_event_handler (struct
> usb_device_instance *device, break;
>
> case DEVICE_ADDRESS_ASSIGNED:
> +#if defined(CONFIG_USBD_HS)
> + /*
> + * is_usbd_high_speed routine needs to be defined by
> + * specific gadget driver
> + * It returns TRUE if device enumerates at High speed
> + * Retuns FALSE otherwise
> + */
> + for (i = 1; i <= NUM_ENDPOINTS; i++) {

Start with i = 0 and end with i < NUM_ENDPOINTS to avoid these i-1 below. Then
fix those [i] with [i+1], there's less of those.

> + if (((ep_descriptor_ptrs[i - 1]->bmAttributes &
> + USB_ENDPOINT_XFERTYPE_MASK) ==
> + USB_ENDPOINT_XFER_BULK)
> + && is_usbd_high_speed()) {
> +
> + ep_descriptor_ptrs[i - 1]->wMaxPacketSize =
> + CONFIG_USBD_SERIAL_BULK_HS_PKTSIZE;
> + }
> +
> + endpoint_instance[i].tx_packetSize =
> + ep_descriptor_ptrs[i - 1]->wMaxPacketSize;
> + endpoint_instance[i].rcv_packetSize =
> + ep_descriptor_ptrs[i - 1]->wMaxPacketSize;
> + }
> +#endif
> usbtty_init_endpoints ();
>
> default:
> diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
> index 6731c38..bd3bcbc 100644
> --- a/drivers/serial/usbtty.h
> +++ b/drivers/serial/usbtty.h
> @@ -72,6 +72,10 @@
> #define CONFIG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE
> #define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_PACKET_SIZE
>
> +#if defined(CONFIG_USBD_HS)
> +#define CONFIG_USBD_SERIAL_BULK_HS_PKTSIZE UDC_BULK_HS_PACKET_SIZE
> +#endif
> +
> #define USBTTY_DEVICE_CLASS COMMUNICATIONS_DEVICE_CLASS
>
> #define USBTTY_BCD_DEVICE 0x00
> diff --git a/drivers/usb/gadget/core.c b/drivers/usb/gadget/core.c
> index 4f2ebab..b2212b4 100644
> --- a/drivers/usb/gadget/core.c
> +++ b/drivers/usb/gadget/core.c
> @@ -212,6 +212,20 @@ struct usb_device_descriptor
> *usbd_device_device_descriptor (struct usb_device_i return
> (device->device_descriptor);
> }
>
> +#if defined(CONFIG_USBD_HS)
> +/**
> + * usbd_device_qualifier_descriptor
> + * @device: which device
> + * @port: which port
> + *
> + * Return the specified qualifier descriptor for the specified device.
> + */
> +struct usb_qualifier_descriptor *usbd_device_qualifier_descriptor(
> + struct usb_device_instance *device, int port)

Make this static, but do you really need this function at all?

Otherwise seems ok

> +{
> + return device->qualifier_descriptor;
> +}
> +#endif
>
> /**
> * usbd_device_configuration_descriptor
> diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c
> index 22499d3..ba8f906 100644
> --- a/drivers/usb/gadget/ep0.c
> +++ b/drivers/usb/gadget/ep0.c
> @@ -338,12 +338,28 @@ static int ep0_get_descriptor (struct
> usb_device_instance *device, }
> break;
> case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
> +#if defined(CONFIG_USBD_HS)
> {
> - /* If a USB device supports both a full speed and low
speed operation
> - * we must send a Device_Qualifier descriptor here
> - */
> - return -1;
> + struct usb_qualifier_descriptor *qualifier_descriptor;
> +
> + qualifier_descriptor = usbd_device_qualifier_descriptor
> + (device, port);
> + if (!qualifier_descriptor)
> + return -1;
> +
> + /* copy descriptor for this device */
> + copy_config(urb, qualifier_descriptor,
> + sizeof(struct usb_qualifier_descriptor),
> + max);
> +
> }
> + dbg_ep0(3, "copied qualifier descriptor, actual_length: 0x%x",
> + urb->actual_length);
> +#else
> + return -1;
> +#endif
> + break;
> +
> default:
> return -1;
> }
> diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h
> index 2dec3b9..de1069f 100644
> --- a/include/usbdescriptors.h
> +++ b/include/usbdescriptors.h
> @@ -241,6 +241,21 @@ struct usb_device_descriptor {
> u8 bNumConfigurations;
> } __attribute__ ((packed));
>
> +#if defined(CONFIG_USBD_HS)
> +struct usb_qualifier_descriptor {
> + u8 bLength;
> + u8 bDescriptorType;
> +
> + u16 bcdUSB;
> + u8 bDeviceClass;
> + u8 bDeviceSubClass;
> + u8 bDeviceProtocol;
> + u8 bMaxPacketSize0;
> + u8 bNumConfigurations;
> + u8 breserved;
> +} __attribute__ ((packed));
> +#endif
> +
> struct usb_string_descriptor {
> u8 bLength;
> u8 bDescriptorType; /* 0x03 */
> diff --git a/include/usbdevice.h b/include/usbdevice.h
> index 9eb8849..e3eb748 100644
> --- a/include/usbdevice.h
> +++ b/include/usbdevice.h
> @@ -210,6 +210,10 @@ struct usb_bus_instance;
> #define USB_DT_INTERFACE 0x04
> #define USB_DT_ENDPOINT 0x05
>
> +#if defined(CONFIG_USBD_HS)
> +#define USB_DT_QUAL 0x06
> +#endif
> +
> #define USB_DT_HID (USB_TYPE_CLASS | 0x01)
> #define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
> #define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
> @@ -291,7 +295,11 @@ struct usb_bus_instance;
> * USB Spec Release number
> */
>
> +#if defined(CONFIG_USBD_HS)
> +#define USB_BCD_VERSION 0x0200
> +#else
> #define USB_BCD_VERSION 0x0110
> +#endif
>
>
> /*
> @@ -567,6 +575,9 @@ struct usb_device_instance {
> /* generic */
> char *name;
> struct usb_device_descriptor *device_descriptor; /* per device
descriptor
> */ +#if defined(CONFIG_USBD_HS)
> + struct usb_qualifier_descriptor *qualifier_descriptor;
> +#endif
>
> void (*event) (struct usb_device_instance *device, usb_device_event_t
> event, int data);
>
> @@ -659,8 +670,19 @@ struct usb_class_report_descriptor
> *usbd_device_class_report_descriptor_index( s struct
> usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct
> usb_device_instance *, int, int, int, int, int);
> int usbd_device_endpoint_transfersize (struct
usb_device_instance *,
> int, int, int, int, int); struct usb_string_descriptor *usbd_get_string
> (u8);
> -struct usb_device_descriptor *usbd_device_device_descriptor (struct
> usb_device_instance *, int); +struct usb_device_descriptor
> *usbd_device_device_descriptor(struct + usb_device_instance *,
int);
>
> +#if defined(CONFIG_USBD_HS)
> +struct usb_qualifier_descriptor *usbd_device_qualifier_descriptor(
> + struct usb_device_instance *, int);
> +/*
> + * is_usbd_high_speed routine needs to be defined by specific gadget
> driver + * It returns TRUE if device enumerates at High speed
> + * Retuns FALSE otherwise
> + */
> +int is_usbd_high_speed(void);
> +#endif
> int usbd_endpoint_halted (struct usb_device_instance *device, int
> endpoint); void usbd_rcv_complete(struct usb_endpoint_instance *endpoint,
> int len, int urb_bad); void usbd_tx_complete (struct usb_endpoint_instance
> *endpoint);