/*
 *  usb_user_device_init.c
 *
 * Change Logs:
 * Date          Author      Notes
 * 2024-01-13    weijiac     user usb funcion  implementation routine
 */
#include "usb_common.h"
#include "hal_usbd.h"
#include "hal_usbd_init.h"
#include "hal_usbd_reg.h"
#include "usb_device.h"
#include "debug.h"

struct udcd _udcd;
udevice_t _udevice;

static struct ep_id _ep_pool[] =
{
    {0x0,  USB_EP_ATTR_CONTROL,     USB_DIR_INOUT,      64, ID_ASSIGNED  },
    {0x1,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0x2,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0x3,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0x4,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0x5,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0x6,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0x7,  0x0f,                    USB_DIR_INOUT,      512, ID_UNASSIGNED},
    {0xFF, USB_EP_ATTR_TYPE_MASK,   USB_DIR_MASK,       0, ID_ASSIGNED  },
};

static rt_err_t _ep_set_stall(rt_uint8_t address)
{
#ifdef USB_DEBUG
    debug("ep %d send satll\n\r",address); 
#endif
    hal_usbd_set_stall(address);
    return RT_EOK;
}

static rt_err_t _ep_clear_stall(rt_uint8_t address)
{
#ifdef USB_DEBUG
    debug("ep %d clear satll\n\r");
#endif
    hal_usbd_clear_stall(address);
    return RT_EOK;
}

static rt_err_t _set_address(rt_uint8_t address)
{
    hal_usbd_set_address(address);
    return RT_EOK;
}

static rt_err_t _set_config(rt_uint8_t address)
{
    return RT_EOK;
}

static rt_err_t _ep_enable(uep_t ep)
{
    RT_ASSERT(ep != RT_NULL);
    RT_ASSERT(ep->ep_desc != RT_NULL);
    hal_usbd_activate_endpoint(ep->ep_desc->bEndpointAddress);
    return RT_EOK;
}

static rt_err_t _ep_disable(uep_t ep)
{
    RT_ASSERT(ep != RT_NULL);
    RT_ASSERT(ep->ep_desc != RT_NULL);
    hal_usbd_deactivate_endpoint(ep->ep_desc->bEndpointAddress);
    return RT_EOK;
}

static rt_size_t _ep_read(rt_uint8_t address, void *buffer)
{
    rt_size_t size = 0;
    RT_ASSERT(buffer != RT_NULL);
    size = hal_usbd_receive(address, buffer);
    return size;
}

static rt_size_t _ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
{
    size = hal_usbd_receive_count(address);
    return size;
}

static rt_size_t _ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
{
    hal_usbd_send(address, buffer, size);
    return size;
}


static rt_err_t _ep0_send_status(void)
{
    hal_usbd_send(0x00, NULL, 0);
    return RT_EOK;
}

static rt_err_t _suspend(void)
{
    return RT_EOK;
}

static rt_err_t _wakeup(void)
{
    return RT_EOK;
}

static struct udcd_ops _udc_ops =
{
    _set_address,
    _set_config,
    _ep_set_stall,
    _ep_clear_stall,
    _ep_enable,
    _ep_disable,
    _ep_read_prepare,
    _ep_read,
    _ep_write,
    _ep0_send_status,
    _suspend,
    _wakeup,
};
void _usb_ep_out_init(rt_uint8_t address, rt_uint8_t type)
{
    uint8_t hal_usb_type = 0;

    switch (type)
    {
    case (1 << USB_EP_ATTR_ISOC):
        hal_usb_type = TYPE_ISO;
        //debug("addr %d, ep_out,type TYPE_ISO \n\r",address);
        break;

    case (1 << USB_EP_ATTR_BULK):
        hal_usb_type = TYPE_BULK;
        //debug("addr %d, ep_out,type TYPE_BULK \n\r",address);
        break;

    case (1 << USB_EP_ATTR_INT):
        hal_usb_type = TYPE_INT;
        //debug("addr %d, ep_out,type TYPE_INT \n\r",address);
        break;

    default:
        break;
    }

    endpoint_OUT_init(address, hal_usb_type);
}
void _usb_ep_in_init(rt_uint8_t address, rt_uint8_t type)
{
    uint8_t hal_usb_type = 0;

    switch (type)
    {
    case (1 << USB_EP_ATTR_ISOC):
        hal_usb_type = TYPE_ISO;
        //debug("addr %d, ep_in,type TYPE_ISO \n\r",address);
        break;

    case (1 << USB_EP_ATTR_BULK):
        hal_usb_type = TYPE_BULK;
        //debug("addr %d, ep_in,type TYPE_BULK \n\r",address);
        break;

    case (1 << USB_EP_ATTR_INT):
        hal_usb_type = TYPE_INT;
        //debug("addr %d, ep_in,type TYPE_INT \n\r",address);
        break;

    default:
        break;
    }

    endpoint_IN_init(address, hal_usb_type);
}
const static struct udevice_ep_init_ops _ep_ops =
{
    _usb_ep_out_init,
    _usb_ep_in_init,
};

//此处仅仅初始化一个 usb_device,有多个device切换需求的，可以初始化多个，然后调用
void usb_device_init(void)
{
    _udcd.ep_pool = _ep_pool;
    _udcd.ep0.id = &_ep_pool[0];
    _udcd.ops = &_udc_ops;
    _udcd.ep_ops = &_ep_ops;
#ifdef USB_HS_ENABLE
    _udcd.device_is_hs = RT_TRUE;
#endif
    _udevice = rt_usbd_device_new();
#ifdef USB_DEBUG
    debug("_udevice %08x\n\r", _udevice);
#endif
    rt_usbd_device_set_controller(_udevice, &_udcd);
    //第一个调用 rt_usbd_device_new返回的设备为1，第二个为2
    rt_usbd_set_udevice(1);
#ifdef USB_DEBUG
    debug("rt_usbd_get_curr_device %08x\n\r", rt_usbd_get_curr_device());
#endif
}
