Enable high speed support for USB device framework and usbtty

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>
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index a263b2c..e47cb9a 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -133,6 +133,19 @@
 };
 
 
+#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 @@
 	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 @@
 			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 @@
 			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 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 @@
 		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 = 0; i < NUM_ENDPOINTS; i++) {
+			if (((ep_descriptor_ptrs[i]->bmAttributes &
+			      USB_ENDPOINT_XFERTYPE_MASK) ==
+			      USB_ENDPOINT_XFER_BULK)
+			    && is_usbd_high_speed()) {
+
+				ep_descriptor_ptrs[i]->wMaxPacketSize =
+					CONFIG_USBD_SERIAL_BULK_HS_PKTSIZE;
+			}
+
+			endpoint_instance[i + 1].tx_packetSize =
+				ep_descriptor_ptrs[i]->wMaxPacketSize;
+			endpoint_instance[i + 1].rcv_packetSize =
+				ep_descriptor_ptrs[i]->wMaxPacketSize;
+		}
+#endif
 		usbtty_init_endpoints ();
 
 	default:
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index 60347d7..eb670da 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -70,6 +70,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..46ab3f6 100644
--- a/drivers/usb/gadget/core.c
+++ b/drivers/usb/gadget/core.c
@@ -212,7 +212,6 @@
 	return (device->device_descriptor);
 }
 
-
 /**
  * usbd_device_configuration_descriptor
  * @device: which device
diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c
index 22499d3..aa8f916 100644
--- a/drivers/usb/gadget/ep0.c
+++ b/drivers/usb/gadget/ep0.c
@@ -338,12 +338,27 @@
 		}
 		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 =
+				device->qualifier_descriptor;
+
+			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;
 	}