/**
 * @file hv_drv_UsbCoreHcd.c
 * @brief usb core hcd driver
 * @details This module provide interfaces for usb core host controller driver.
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20230417
 * @copyright Copyright(c),2022-9, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date             <th>Details
 * <tr><td>HiView SoC Software Team   <td>20230417       <td>Create and first Version.
 * </table>
 **/

#include "hv_drv_UsbCh9.h"
#include "hv_drv_UsbCoreCh11.h"
#include "hv_drv_UsbCoreCommonUsb.h"
#include "hv_drv_UsbErrNo.h"
#include "hv_drv_UsbBitWise.h"
#include "hv_drv_UsbCoreUsb.h"
#include "hv_drv_UsbCoreHcd.h"

#define KERNEL_REL  0xff
#define KERNEL_VER  0xff

/* usb 3.0 root hub device descriptor */
static const u8 usb3_rh_dev_descriptor[18] = {
    0x12,       /*  __u8  bLength; */
    0x01,       /*  __u8  bDescriptorType; Device */
    0x00, 0x03, /*  __le16 bcdUSB; v3.0 */

    0x09,        /*  __u8  bDeviceClass; HUB_CLASSCODE */
    0x00,        /*  __u8  bDeviceSubClass; */
    0x03,       /*  __u8  bDeviceProtocol; USB 3.0 hub */
    0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */

    0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
    0x03, 0x00, /*  __le16 idProduct; device 0x0003 */
    KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

    0x03,       /*  __u8  iManufacturer; */
    0x02,       /*  __u8  iProduct; */
    0x01,       /*  __u8  iSerialNumber; */
    0x01        /*  __u8  bNumConfigurations; */
};

/* usb 2.5 (wireless USB 1.0) root hub device descriptor */
static const u8 usb25_rh_dev_descriptor[18] = {
    0x12,       /*  __u8  bLength; */
    0x01,       /*  __u8  bDescriptorType; Device */
    0x50, 0x02, /*  __le16 bcdUSB; v2.5 */

    0x09,        /*  __u8  bDeviceClass; HUB_CLASSCODE */
    0x00,        /*  __u8  bDeviceSubClass; */
    0x00,       /*  __u8  bDeviceProtocol; [ usb 2.0 no TT ] */
    0xFF,       /*  __u8  bMaxPacketSize0; always 0xFF (WUSB Spec 7.4.1). */

    0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
    0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
    KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

    0x03,       /*  __u8  iManufacturer; */
    0x02,       /*  __u8  iProduct; */
    0x01,       /*  __u8  iSerialNumber; */
    0x01        /*  __u8  bNumConfigurations; */
};

/* usb 2.0 root hub device descriptor */
static const u8 usb2_rh_dev_descriptor[18] = {
    0x12,       /*  __u8  bLength; */
    0x01,       /*  __u8  bDescriptorType; Device */
    0x00, 0x02, /*  __le16 bcdUSB; v2.0 */

    0x09,        /*  __u8  bDeviceClass; HUB_CLASSCODE */
    0x00,        /*  __u8  bDeviceSubClass; */
    0x00,       /*  __u8  bDeviceProtocol; [ usb 2.0 no TT ] */
    0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */

    0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
    0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
    KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

    0x03,       /*  __u8  iManufacturer; */
    0x02,       /*  __u8  iProduct; */
    0x01,       /*  __u8  iSerialNumber; */
    0x01        /*  __u8  bNumConfigurations; */
};

/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */

/* usb 1.1 root hub device descriptor */
static const u8 usb11_rh_dev_descriptor[18] = {
    0x12,       /*  __u8  bLength; */
    0x01,       /*  __u8  bDescriptorType; Device */
    0x10, 0x01, /*  __le16 bcdUSB; v1.1 */

    0x09,        /*  __u8  bDeviceClass; HUB_CLASSCODE */
    0x00,        /*  __u8  bDeviceSubClass; */
    0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
    0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */

    0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation 0x1d6b */
    0x01, 0x00, /*  __le16 idProduct; device 0x0001 */
    KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

    0x03,       /*  __u8  iManufacturer; */
    0x02,       /*  __u8  iProduct; */
    0x01,       /*  __u8  iSerialNumber; */
    0x01        /*  __u8  bNumConfigurations; */
};


/*-------------------------------------------------------------------------*/

/* Configuration descriptors for our root hubs */

static const u8 fs_rh_config_descriptor[] = {

    /* one configuration */
    0x09,       /*  __u8  bLength; */
    0x02,       /*  __u8  bDescriptorType; Configuration */
    0x19, 0x00, /*  __le16 wTotalLength; */
    0x01,       /*  __u8  bNumInterfaces; (1) */
    0x01,       /*  __u8  bConfigurationValue; */
    0x00,       /*  __u8  iConfiguration; */
    0xc0,       /*  __u8  bmAttributes;
                 Bit 7: must be set,
                     6: Self-powered,
                     5: Remote wakeup,
                     4..0: resvd */
    0x00,       /*  __u8  MaxPower; */

    /* USB 1.1:
     * USB 2.0, single TT organization (mandatory):
     *    one interface, protocol 0
     *
     * USB 2.0, multiple TT organization (optional):
     *    two interfaces, protocols 1 (like single TT)
     *    and 2 (multiple TT mode) ... config is
     *    sometimes settable
     *    NOT IMPLEMENTED
     */

    /* one interface */
    0x09,       /*  __u8  if_bLength; */
    0x04,       /*  __u8  if_bDescriptorType; Interface */
    0x00,       /*  __u8  if_bInterfaceNumber; */
    0x00,       /*  __u8  if_bAlternateSetting; */
    0x01,       /*  __u8  if_bNumEndpoints; */
    0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
    0x00,       /*  __u8  if_bInterfaceSubClass; */
    0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
    0x00,       /*  __u8  if_iInterface; */

    /* one endpoint (status change endpoint) */
    0x07,       /*  __u8  ep_bLength; */
    0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
    0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
    0x03,       /*  __u8  ep_bmAttributes; Interrupt */
    0x02, 0x00, /*  __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
    0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */
};

static const u8 hs_rh_config_descriptor[] = {

    /* one configuration */
    0x09,       /*  __u8  bLength; */
    0x02,       /*  __u8  bDescriptorType; Configuration */
    0x19, 0x00, /*  __le16 wTotalLength; */
    0x01,       /*  __u8  bNumInterfaces; (1) */
    0x01,       /*  __u8  bConfigurationValue; */
    0x00,       /*  __u8  iConfiguration; */
    0xc0,       /*  __u8  bmAttributes;
                 Bit 7: must be set,
                     6: Self-powered,
                     5: Remote wakeup,
                     4..0: resvd */
    0x00,       /*  __u8  MaxPower; */

    /* USB 1.1:
     * USB 2.0, single TT organization (mandatory):
     *    one interface, protocol 0
     *
     * USB 2.0, multiple TT organization (optional):
     *    two interfaces, protocols 1 (like single TT)
     *    and 2 (multiple TT mode) ... config is
     *    sometimes settable
     *    NOT IMPLEMENTED
     */

    /* one interface */
    0x09,       /*  __u8  if_bLength; */
    0x04,       /*  __u8  if_bDescriptorType; Interface */
    0x00,       /*  __u8  if_bInterfaceNumber; */
    0x00,       /*  __u8  if_bAlternateSetting; */
    0x01,       /*  __u8  if_bNumEndpoints; */
    0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
    0x00,       /*  __u8  if_bInterfaceSubClass; */
    0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
    0x00,       /*  __u8  if_iInterface; */

    /* one endpoint (status change endpoint) */
    0x07,       /*  __u8  ep_bLength; */
    0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
    0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
    0x03,       /*  __u8  ep_bmAttributes; Interrupt */
    /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
     * see hub.c:hub_configure() for details. */
    (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
    0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
};

static const u8 ss_rh_config_descriptor[] = {
    /* one configuration */
    0x09,       /*  __u8  bLength; */
    0x02,       /*  __u8  bDescriptorType; Configuration */
    0x1f, 0x00, /*  __le16 wTotalLength; */
    0x01,       /*  __u8  bNumInterfaces; (1) */
    0x01,       /*  __u8  bConfigurationValue; */
    0x00,       /*  __u8  iConfiguration; */
    0xc0,       /*  __u8  bmAttributes;
                 Bit 7: must be set,
                     6: Self-powered,
                     5: Remote wakeup,
                     4..0: resvd */
    0x00,       /*  __u8  MaxPower; */

    /* one interface */
    0x09,       /*  __u8  if_bLength; */
    0x04,       /*  __u8  if_bDescriptorType; Interface */
    0x00,       /*  __u8  if_bInterfaceNumber; */
    0x00,       /*  __u8  if_bAlternateSetting; */
    0x01,       /*  __u8  if_bNumEndpoints; */
    0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
    0x00,       /*  __u8  if_bInterfaceSubClass; */
    0x00,       /*  __u8  if_bInterfaceProtocol; */
    0x00,       /*  __u8  if_iInterface; */

    /* one endpoint (status change endpoint) */
    0x07,       /*  __u8  ep_bLength; */
    0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
    0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
    0x03,       /*  __u8  ep_bmAttributes; Interrupt */
    /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
     * see hub.c:hub_configure() for details. */
    (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
    0x0c,       /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */

    /* one SuperSpeed endpoint companion descriptor */
    0x06,        /* __u8 ss_bLength */
    0x30,        /* __u8 ss_bDescriptorType; SuperSpeed EP Companion */
    0x00,        /* __u8 ss_bMaxBurst; allows 1 TX between ACKs */
    0x00,        /* __u8 ss_bmAttributes; 1 packet per service interval */
    0x02, 0x00   /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
};

/**
 * ascii2desc() - Helper routine for producing UTF-16LE string descriptors
 * @s: Null-terminated ASCII (actually ISO-8859-1) string
 * @buf: Buffer for USB string descriptor (header + UTF-16LE)
 * @len: Length (in bytes; may be odd) of descriptor buffer.
 *
 * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len,
 * whichever is less.
 *
 * Note:
 * USB String descriptors can contain at most 126 characters; input
 * strings longer than that are truncated.
 */
static unsigned
ascii2desc(char const *s, u8 *buf, unsigned len) {
    unsigned n, t = 2 + 2*strlen(s);

    if (t > 254)
        t = 254;    /* Longest possible UTF string descriptor */
    if (len > t)
        len = t;

    t += USB_DT_STRING << 8;    /* Now t is first 16 bits to store */

    n = len;
    while (n--) {
        *buf++ = t;
        if (!n--)
            break;
        *buf++ = t >> 8;
        t = (unsigned char)*s++;
    }
    return len;
}

/**
 * rh_string() - provides string descriptors for root hub
 * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
 * @hcd: the host controller for this root hub
 * @data: buffer for output packet
 * @len: length of the provided buffer
 *
 * Produces either a manufacturer, product or serial number string for the
 * virtual root hub device.
 *
 * Return: The number of bytes filled in: the length of the descriptor or
 * of the provided buffer, whichever is less.
 */
static unsigned
rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) {
    char const *s;
    static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04};

    /* language ids */
    switch (id) {
    case 0:
        /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
        /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
        if (len > 4)
            len = 4;
        USB_MEMCPY(data, langids, len);
        return len;
    case 1:
        /* Serial number */
        s = hcd->self.bus_name;
        break;
    case 2:
        /* Product name */
        s = hcd->product_desc;
        break;
    case 3:
        /* Manufacturer */
        s = hcd->driver->description;
        break;
    default:
        /* Can't happen; caller guarantees it */
        return 0;
    }

    return ascii2desc(s, data, len);
}


const static char usb_bus_name[] = "musb bus";
static void usb_bus_init(struct usb_bus *bus) {
    HV_MEMSET(&bus->devmap, 0, sizeof(struct usb_devmap));

    bus->bus_name = usb_bus_name;
    bus->devnum_next = 1;
    bus->root_hub = NULL;
    bus->is_b_host = 0;
}

static void usb_bus_exit(struct usb_bus *bus) {

}

void usb_hcd_reset_endpoint(struct usb_device *udev,
                            struct usb_host_endpoint *ep) {
    struct usb_hcd *hcd = bus_to_hcd(udev->bus);

    if (hcd->driver->endpoint_reset)
        hcd->driver->endpoint_reset(hcd, ep);
    else {
        int epnum = usb_endpoint_num(&ep->desc);
        int is_out = usb_endpoint_dir_out(&ep->desc);
        int is_control = usb_endpoint_xfer_control(&ep->desc);

        usb_settoggle(udev, epnum, is_out, 0);
        if (is_control)
            usb_settoggle(udev, epnum, !is_out, 0);
    }
}

void usb_hcd_died(struct usb_hcd *hcd) {
    clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
    set_bit(HCD_FLAG_DEAD, &hcd->flags);

    if (hcd->rh_registered) {
        clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);

        usb_set_device_state(hcd->self.root_hub,
                             USB_STATE_NOTATTACHED);
    }
}

/**
 * register_root_hub - called by usb_add_hcd() to register a root hub
 * @hcd: host controller for this root hub
 *
 * This function registers the root hub with usb subsystem.  It sets up
 * the device in the device tree and then calls usb_new_device() to register
 * the usb device. It alse assigns the root hub's USB address (always 1).
 *
 * Return: 0 if successful. 1 if not support. A negative error code otherwise.
 */
static int register_root_hub(struct usb_hcd *hcd) {
    struct usb_device *rhdev = hcd->self.root_hub;
    const int devnum = 1;
    int retval = 0;
    rhdev->devnum = devnum;
    rhdev->bus->devnum_next = devnum + 1;
    HV_MEMSET(&rhdev->bus->devmap.devicemap, 0,
           sizeof(rhdev->bus->devmap.devicemap));
    set_bit(devnum, rhdev->bus->devmap.devicemap);

    usb_set_device_state(rhdev, USB_STATE_ADDRESS);

    /* lock here */
    rhdev->ep0.desc.wMaxPacketSize = 64;
    retval = usb_get_device_descriptor(rhdev, USB_DT_DEVICE_SIZE);


    if (retval != sizeof(rhdev->descriptor)) {

        return (retval < 0) ? retval : -EMSGSIZE;
    }

    if (unlikely(rhdev->speed == USB_SPEED_SUPER)) {
        ;   /* 3.0 device, should get bos descriptor, not support */
    }

    retval = usb_new_device(rhdev);
    if (retval) {
    } else {

        HANDLE sc = spin_lock_irq();
        hcd->rh_registered = 1;
        spin_unlock_irq(sc);

        if (test_bit(HCD_FLAG_DEAD, &hcd->flags)) {
            usb_hcd_died(hcd);
        }
    }

    return retval;
}

static void __usb_hcd_giveback_urb(struct urb *urb) {
    HANDLE sc;
    int status = urb->unlinked;

    urb->hcpriv = NULL;
    if (unlikely(urb->transfer_flags & URB_SHORT_NOT_OK) &&
            urb->actual_length < urb->transfer_buffer_length &&
            !status) {
        status = -EREMOTEIO;
    }
    urb->status = status;

    sc = spin_lock_irq();
    urb->complete(urb);
    spin_unlock_irq(sc);

    atomic_dec(&urb->use_count);
}

void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) {
    if (likely(!urb->unlinked)) {
        urb->unlinked = status;
    }

    __usb_hcd_giveback_urb(urb);
    return;

    if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
        ;
    }
}

/**
 * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
 * @hcd: host controller to which @urb was submitted
 * @urb: urb being unlinked
 *
 * Host controller drivers should call this routine before calling
 * usb_hcd_giveback_urb(). Interrupts musb be disabled. The actions
 * carried out here are required for URB completion.
 */
void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) {
    /* disabled interrupt here */
    //hcd = hcd;  /* cheat the compiler. */
    urb->ep->xfer_urb = NULL;
}

int usb_hcd_check_unlink_urb(struct usb_hcd *hcd,
                             struct urb *urb, int status) {
    if (urb->ep->xfer_urb != urb) {
        /* urb was not submitted or has already
         * completed(but may not give back). */
        return -EIDRM;
    }

    if (urb->unlinked) {
        /* urb has already been unlinked */
        return -EBUSY;
    }
    urb->unlinked = status;
    return 0;
}

static int
usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) {
    int rc;
    HANDLE sc = spin_lock_irq();

    rc = usb_hcd_check_unlink_urb(hcd, urb, status);
    if (rc) {
        goto done;
    }

    if (usb_endpoint_num(&urb->ep->desc) == 0) {
        ;   /* control endpoint, do nothing */
    } else {
        if (urb == hcd->status_urb) {
            hcd->status_urb = NULL;
            usb_hcd_unlink_urb_from_ep(hcd, urb);
            usb_hcd_giveback_urb(hcd, urb, status);
        }
    }
done:
    spin_unlock_irq(sc);
    return rc;
}

static int
unlink1(struct usb_hcd *hcd, struct urb *urb, int status) {
    int value;

    if (is_root_hub(urb->dev)) {
        value = usb_rh_urb_dequeue(hcd, urb, status);
    } else {
        value = hcd->driver->urb_dequeue(hcd, urb, status);
    }
    return value;
}

int usb_hcd_unlink_urb(struct urb *urb, int status) {
    struct usb_hcd  *hcd;
    int     retval = -EIDRM;

    HANDLE sc = spin_lock_irq();
    if (atomic_read(&urb->use_count) > 0) {
        retval = 0;
    }
    spin_unlock_irq(sc);

    if (retval == 0) {
        hcd = bus_to_hcd(urb->dev->bus);
        retval = unlink1(hcd, urb, status);
        if (retval == 0) {
            retval = -EINPROGRESS;
        } else if (retval != -EIDRM && retval != -EBUSY) {
        }
    }

    return retval;
}

struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
                               struct device *dev) {
    struct usb_hcd *hcd = NULL;

    hcd = (struct usb_hcd *)USB_MALLOC(sizeof(*hcd));
    if (hcd == NULL) {
        return NULL;
    }
    HV_MEMSET((void*)hcd, 0, sizeof(*hcd));

    dev_set_drvdata(dev, hcd);

    usb_bus_init(&hcd->self);

    hcd->self.controller = dev;
    hcd->driver = driver;
    hcd->speed = driver->flags & HCD_MASK;
    
    return hcd;
}

static void usb_put_invalidate_rhdev(struct usb_hcd *hcd) {
    struct usb_device *rhdev = NULL;

    rhdev = hcd->self.root_hub;
    hcd->self.root_hub = NULL;

    //rhdev = rhdev;
}

/**
 * finish generic HCD structure initialization
 * register usb bus and startup root hub.
 */
int usb_add_hcd(struct usb_hcd *hcd) {
    int retval = 0;
    struct usb_device *rhdev = NULL;

    hcd->authorized_default = 1;
    set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

    rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
    if (rhdev == NULL) {
        retval = -ENOMEM;
        goto err_allocate_root_hub;
    }

    hcd->self.root_hub = rhdev;
    switch (hcd->speed) {
    case HCD_USB11:
        rhdev->speed = USB_SPEED_FULL;
        break;
    case HCD_USB2:
       rhdev->speed = USB_SPEED_HIGH;
        break;
    case HCD_USB25:
        rhdev->speed = USB_SPEED_WIRELESS;
        break;
    case HCD_USB3:
        rhdev->speed = USB_SPEED_SUPER;
        break;
    default:
        retval = -EINVAL;
        goto err_set_rh_speed;
    }
    set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
    hcd->rh_pollable = 1;  

    hcd->state = HC_STATE_RUNNING;
    retval = hcd->driver->start(hcd);
    if (retval < 0) {

        goto err_hcd_driver_start;
    }
    if ((retval = register_root_hub(hcd)) != 0) {

        goto err_register_root_hub;
    }

    return retval;

err_register_root_hub:

    hcd->rh_pollable = 0;
    clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
    hcd->driver->stop(hcd);
    hcd->state = HC_STATE_HALT;
    clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);

err_hcd_driver_start:
err_set_rh_speed:

    usb_put_invalidate_rhdev(hcd);

err_allocate_root_hub:

    return retval;
}

void usb_remove_hcd(struct usb_hcd *hcd) {
    struct usb_device *rhdev = hcd->self.root_hub;
    if (rhdev == NULL)
        return;
    usb_remove_device(rhdev);
    /**
     * release the root hub
     * deregister usb bus
     */
}

void usb_destroy_hcd(struct usb_hcd *hcd) {
    usb_bus_exit(&hcd->self);
    if(hcd != NULL)
    {
        USB_FREE(hcd);
        hcd = NULL;
    }
}

int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) {
    int     rc = 0;

    if (unlikely(atomic_read(&urb->reject))) {
        rc = -EPERM;
        goto done;
    }

    if (unlikely(!urb->ep->enabled)) {
        rc = -ENOENT;
        goto done;
    }

    if (unlikely(!urb->dev->can_submit)) {
        rc = -EHOSTUNREACH;
        goto done;
    }

    if (test_bit(HCD_FLAG_RH_RUNNING, &hcd->flags)) {
        urb->unlinked = 0;
        urb->ep->xfer_urb = urb;
    } else {
        rc = -ESHUTDOWN;
        goto done;
    }

done:
    return rc;
}

static int rh_queue_status(struct usb_hcd *hcd, struct urb *urb) {
    int     retval = 0;
    unsigned int    len = 1 + (urb->dev->maxchild / 8);

    HANDLE sc = spin_lock_irq();
    if (hcd->status_urb || urb->transfer_buffer_length < len) {
        retval = -EINVAL;
        goto done;
    }

    retval = usb_hcd_link_urb_to_ep(hcd, urb);
    if (retval) {
        goto done;
    }

    hcd->status_urb = urb;
    urb->hcpriv = hcd;  /* indicate it's queued */

    retval = 0;
done:
    spin_unlock_irq(sc);
    return retval;
}

static int rh_call_control(struct usb_hcd *hcd, struct urb *urb) {
    struct usb_ctrlrequest *cmd;
    u16     typeReq, wValue, wIndex, wLength;
    u8      *ubuf = urb->transfer_buffer;
    unsigned    len = 0;
    int     status = 0;
    u8      patch_protocol = 0;
    u16     tbuff_size;
    u8      *tbuf = NULL;
    const u8    *bufp;

    HANDLE sc = spin_lock_irq();
    status = usb_hcd_link_urb_to_ep(hcd, urb);
    spin_unlock_irq(sc);

    if (status)
        return status;
    urb->hcpriv = hcd;  /* Indicate it's queued */

    cmd = (struct usb_ctrlrequest *) urb->setup_packet;
    typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
    wValue = (cmd->wValue);
    wIndex = (cmd->wIndex);
    wLength = (cmd->wLength);

    if (wLength > urb->transfer_buffer_length) {
        status = -EPIPE;
        goto error;
    }

    tbuff_size = USB_MAX(sizeof(struct usb_hub_descriptor), wLength);
    tbuf = USB_MALLOC(tbuff_size);
    if (!tbuf)
        return -ENOMEM;
    HV_MEMSET((void*)(tbuf), 0, tbuff_size);

    bufp = tbuf;
    urb->actual_length = 0;

    switch (typeReq) {
    case DeviceRequest | USB_REQ_GET_STATUS:
        tbuf[0] = (1 << USB_DEVICE_SELF_POWERED);
        tbuf[0] = 0;
        len = 2;
        break;
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
        if (wValue == USB_DEVICE_REMOTE_WAKEUP) {
            ; /* TODO */
        } else {
            goto error;
        }
        break;
    case DeviceOutRequest | USB_REQ_SET_FEATURE:
        /* TODO */
        break;
    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
        tbuf[0] = 1;
        len = 1;
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
        break;
    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
        switch (((wValue & 0xff00) >> 8) & 0xff) {
        case USB_DT_DEVICE:
            switch (hcd->speed) {
            case HCD_USB3:
                bufp = usb3_rh_dev_descriptor;
                break;
            case HCD_USB25:
                bufp = usb25_rh_dev_descriptor;
                break;
            case HCD_USB2:
                bufp = usb2_rh_dev_descriptor;
                break;
            case HCD_USB11:
                bufp = usb11_rh_dev_descriptor;
                break;
            default:
                goto error;
            }
            len = 18;
            if (hcd->has_tt)
                patch_protocol = 1;
            break;
        case USB_DT_CONFIG:
            switch (hcd->speed) {
            case HCD_USB3:
                bufp = ss_rh_config_descriptor;
                len = sizeof(ss_rh_config_descriptor);
                break;
            case HCD_USB25:
            case HCD_USB2:
                bufp = hs_rh_config_descriptor;
                len = sizeof(hs_rh_config_descriptor);
                break;
            case HCD_USB11:
                bufp = fs_rh_config_descriptor;
                len = sizeof(fs_rh_config_descriptor);
                break;
            default:
                goto error;
            }
            break;
        case USB_DT_STRING:
            if ((wValue & 0xff) < 4) {
                urb->actual_length = rh_string(wValue & 0xff,
                                               hcd, ubuf, wLength);
            } else {
                goto error;
            }
            break;
        default:
            goto error;
        }
        break;
    case DeviceRequest | USB_REQ_GET_INTERFACE:
        tbuf[0] = 0;
        len = 1;
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
        break;
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
        break;

    case EndpointRequest | USB_REQ_GET_STATUS:
        tbuf[0] = 0;
        tbuf[1] = 0;
        len = 2;
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
    case EndpointOutRequest | USB_REQ_SET_FEATURE:
        break;

    default:
        switch (typeReq) {
        case GetHubStatus:
        case GetPortStatus:
            len = 4;
            break;
        case GetHubDescriptor:
            len = sizeof(struct usb_hub_descriptor);
        case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
            break;
        }
        status = hcd->driver->hub_control(hcd,
                                          typeReq, wValue, wIndex,
                                          (char*)tbuf, wLength);
        
        status = status == 0 ? wLength : status;
        

        if (typeReq == GetHubDescriptor)
            usb_hub_adjust_deviceremovable(hcd->self.root_hub,
                                           (struct usb_hub_descriptor *) tbuf);
        break;
error:
        status = -EPIPE;
    }
    


    if (status < 0) {
        len = 0;
    } else if (status > 0) {
        len = status;
        status = 0;
    }
    

    if (len) {
        if (urb->transfer_buffer_length < len) {
            len = urb->transfer_buffer_length;
        }
        urb->actual_length = len;
        USB_MEMCPY(ubuf, bufp, len);

        if (patch_protocol &&
                len > USB_OFFSET_OF(struct usb_device_descriptor, bDeviceProtocol)) {
            ((struct usb_device_descriptor *) bufp) ->
            bDeviceProtocol |= USB_HUB_PR_HS_SINGLE_TT;
        }
    }

    if(tbuf != NULL)
    {
        USB_FREE(tbuf);
        tbuf = NULL;
    }

    sc = spin_lock_irq();
    usb_hcd_unlink_urb_from_ep(hcd, urb);
    usb_hcd_giveback_urb(hcd, urb, status);
    spin_unlock_irq(sc);

    return 0;
}

static int rh_urb_enqueue(struct usb_hcd *hcd, struct urb *urb) {
    if (usb_endpoint_xfer_int(&urb->ep->desc))
        return rh_queue_status(hcd, urb);
    if (usb_endpoint_xfer_control(&urb->ep->desc))
        return rh_call_control(hcd, urb);

    return -EINVAL;
}

void usb_repower_and_reset_hcd(struct usb_device *dev) {
    struct usb_hcd *hcd = bus_to_hcd(dev->bus);
    USB_ASSERT(hcd->driver->repower_and_reset);
    hcd->driver->repower_and_reset(hcd);
}

int usb_hcd_submit_urb(struct urb *urb) {
    int     status;
    struct usb_hcd  *hcd = bus_to_hcd(urb->dev->bus);
    
    atomic_inc(&urb->use_count);

    if (is_root_hub(urb->dev)) {
        status = rh_urb_enqueue(hcd, urb);
    } else {    /* not root hub */
        status = hcd->driver->urb_enqueue(hcd, urb);
    }

    if (unlikely(status)) {
        urb->hcpriv = NULL;
        atomic_dec(&urb->use_count);
        usb_free_urb(urb);
    }
    return status;
}

void usb_hcd_free_urb(struct urb *urb) {
    struct usb_hcd  *hcd = NULL;
    if(urb == NULL || urb->dev == NULL || urb->dev->bus == NULL)
    {
        return;
    }
    else
    {
        hcd = bus_to_hcd(urb->dev->bus);
    }
    hcd->driver->urb_free(hcd, urb);
}
