/**
 * @file hv_drv_UsbCorePort.c
 * @brief usb core port driver
 * @details This module provide interfaces for usb port.
 * @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_UsbCoreCommonUsb.h"
#include "hv_drv_UsbCoreDevice.h"
#include "hv_drv_UsbBitWise.h"
#include "hv_drv_UsbCoreUsb.h"
#include "hv_drv_UsbCoreHub.h"
#include "hv_drv_UsbCoreHcd.h"

static void usb_port_device_release(struct device *dev) {
    struct usb_port *port_dev = to_usb_port(dev);

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

struct device_type usb_port_device_type = {
    "usb port",              //name
    usb_port_device_release, //release
};

struct device_driver usb_port_driver = {
    "usb", //name
};

int usb_hub_create_port_device(struct usb_hub *hub, int port1) {
    struct usb_port *port_dev;
    int retval;

    port_dev = USB_MALLOC(sizeof(*port_dev));
    if (!port_dev) {
        return -ENOMEM;
    }

    HV_MEMSET((void*)port_dev, 0, sizeof(*port_dev));

    hub->ports[port1 - 1] = port_dev;
    port_dev->portnum = port1;
    set_bit(port1, hub->power_bits);
    port_dev->dev.bus = &usb_bus_type;
    port_dev->dev.parent = hub->intfdev;
    port_dev->dev.type = &usb_port_device_type;
    port_dev->dev.driver = &usb_port_driver;
    if (hub_is_superspeed(hub->hdev)) {
        port_dev->is_superspeed = 1;
    }

    retval = device_register(&port_dev->dev);
    if (retval) {
        device_unregister(&port_dev->dev);
        return retval;
    }

    /* remains here, if there some uses some day */
    if (!hub_is_port_power_switchable(hub)) {
        return 0;
    }

    return 0;
}

void usb_hub_remove_port_device(struct usb_hub *hub, int port1) {
    struct usb_port *port_dev = hub->ports[port1 - 1];

    device_unregister(&port_dev->dev);
}
