xiuos/Ubiquitous/XiUOS/board/aiit-arm32-board/third_party_driver/usb/usbh.c

410 lines
12 KiB
C

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-10-30 ZYH the first version
* 2019-12-19 tyustli port to stm32 series
*/
/**
* @file usbh.c
* @brief support aiit-arm32-board usb function
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
/*************************************************
File name: usbh.c
Description: support aiit-arm32-board usb configure
Others: take RT-Thread v4.0.2/bsp/stm32/libraries/HAL_Drivers/drv_usbh.c for references
https://github.com/RT-Thread/rt-thread/tree/v4.0.2
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. support aiit-arm32-board usb irq configure
2. support aiit-arm32-board usb host register
*************************************************/
#include <xiuos.h>
#include <usb_host.h>
#include <hardware_gpio.h>
#include <hardware_rcc.h>
#include <stm32f4xx.h>
#include <misc.h>
#include <usb_bsp.h>
#include <usb_hcd.h>
#include <usb_hcd_int.h>
static USB_OTG_CORE_HANDLE USB_OTG_Core;
static int UrbCompletionSem;
void OTG_FS_IRQHandler(int irq_num, void *arg)
{
USBH_OTG_ISR_Handler(&USB_OTG_Core);
}
DECLARE_HW_IRQ(OTG_FS_IRQn, OTG_FS_IRQHandler, NONE);
static uint8_t SOF_cb(USB_OTG_CORE_HANDLE *pdev)
{
return 0;
}
static uint8_t DevConnected_cb(USB_OTG_CORE_HANDLE *pdev)
{
UhcdPointer hcd = pdev->data;
if (!pdev->host.ConnSts) {
pdev->host.ConnSts = 1;
UsbhRootHubConnectHandler(hcd, 1, RET_FALSE);
}
return 0;
}
static uint8_t DevDisconnected_cb(USB_OTG_CORE_HANDLE *pdev)
{
UhcdPointer hcd = pdev->data;
if (pdev->host.ConnSts) {
pdev->host.ConnSts = 0;
UsbhRootHubDisconnectHandler(hcd, 1);
}
return 0;
}
static uint8_t URBChangeNotify_cb(USB_OTG_CORE_HANDLE *pdev)
{
KSemaphoreAbandon(UrbCompletionSem);
return 0;
}
static uint8_t DevPortEnabled_cb(USB_OTG_CORE_HANDLE *pdev)
{
pdev->host.PortEnabled = 1;
return 0;
}
static uint8_t DevPortDisabled_cb(USB_OTG_CORE_HANDLE *pdev)
{
pdev->host.PortEnabled = 0;
return 0;
}
static USBH_HCD_INT_cb_TypeDef USBH_HCD_INT_cb = {
.SOF = SOF_cb,
.DevConnected = DevConnected_cb,
.DevDisconnected = DevDisconnected_cb,
.DevPortEnabled = DevPortEnabled_cb,
.DevPortDisabled = DevPortDisabled_cb,
.URBChangeNotify = URBChangeNotify_cb,
};
USBH_HCD_INT_cb_TypeDef *USBH_HCD_INT_fops = &USBH_HCD_INT_cb;
static void STM32USBHostChannelOpen(USB_OTG_CORE_HANDLE *pdev, uint8_t hc_num, uint8_t epnum,
uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps)
{
pdev->host.hc[hc_num].ep_num = epnum & 0x7F;
pdev->host.hc[hc_num].ep_is_in = (epnum & 0x80 ) == 0x80;
pdev->host.hc[hc_num].DevAddr = dev_address;
pdev->host.hc[hc_num].ep_type = ep_type;
pdev->host.hc[hc_num].max_packet = mps;
pdev->host.hc[hc_num].speed = speed;
pdev->host.hc[hc_num].toggle_in = 0;
pdev->host.hc[hc_num].toggle_out = 0;
if(speed == HPRT0_PRTSPD_HIGH_SPEED) {
pdev->host.hc[hc_num].do_ping = 1;
}
USB_OTG_HC_Init(pdev, hc_num) ;
}
static x_err_t STM32USBHostResetPort(uint8 port)
{
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("reset port\n"));
HCD_ResetPort(&USB_OTG_Core);
return EOK;
}
x_err_t STM32USBHostChannelSubmitRequest(USB_OTG_CORE_HANDLE *hhcd,
uint8_t ch_num,
uint8_t direction,
uint8_t ep_type,
uint8_t token,
uint8_t *pbuff,
uint16_t length,
uint8_t do_ping)
{
SYS_KDEBUG_LOG(SYS_DEBUG_USB,
("%s: ch_num: %d, direction: %d, ", __func__, ch_num, direction));
hhcd->host.hc[ch_num].ep_is_in = direction;
hhcd->host.hc[ch_num].ep_type = ep_type;
if (token == 0U)
hhcd->host.hc[ch_num].data_pid = HC_PID_SETUP;
else
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA1;
/* Manage Data Toggle */
switch (ep_type) {
case EP_TYPE_CTRL:
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("EP_TYPE_CTRL\n"));
if ((token == 1U) && (direction == 0U)) {
if (length == 0U)
hhcd->host.hc[ch_num].toggle_out = 1U;
if (hhcd->host.hc[ch_num].toggle_out == 0U)
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA0;
else
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA1;
}
break;
case EP_TYPE_BULK:
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("EP_TYPE_BULK\n"));
if (direction == 0U) {
if (hhcd->host.hc[ch_num].toggle_out == 0U)
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA0;
else
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA1;
} else {
if (hhcd->host.hc[ch_num].toggle_in == 0U)
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA0;
else
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA1;
}
break;
case EP_TYPE_INTR:
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("EP_TYPE_INTR\n"));
if (direction == 0U) {
if (hhcd->host.hc[ch_num].toggle_out == 0U)
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA0;
else
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA1;
} else {
if (hhcd->host.hc[ch_num].toggle_in == 0U)
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA0;
else
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA1;
}
break;
case EP_TYPE_ISOC:
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("EP_TYPE_ISOC\n"));
hhcd->host.hc[ch_num].data_pid = HC_PID_DATA0;
break;
default:
break;
}
hhcd->host.hc[ch_num].xfer_buff = pbuff;
hhcd->host.hc[ch_num].XferLen = length;
hhcd->host.HC_Status[ch_num] = HC_IDLE;
return HCD_SubmitRequest(hhcd, ch_num);
}
static int STM32USBHostPipeXfer(upipe_t pipe, uint8 token, void *buffer, int nbytes, int timeouts)
{
int timeout = timeouts;
int interval = 1;
int retry = 0;
while (1) {
if (!USB_OTG_Core.host.ConnSts)
return -1;
// UrbCompletionSem = KSemaphoreCreate( 0);
KSemaphoreSetValue(UrbCompletionSem, 0);
STM32USBHostChannelSubmitRequest(
&USB_OTG_Core,
pipe->pipe_index,
(pipe->ep.bEndpointAddress & 0x80) >> 7,
pipe->ep.bmAttributes,
token,
buffer,
nbytes,
0
);
MdelayKTask(interval);
KSemaphoreObtain(UrbCompletionSem, timeout);
if (HCD_GetHCState(&USB_OTG_Core, pipe->pipe_index) == HC_NAK) {
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("nak\n"));
if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
DelayKTask((pipe->ep.bInterval * TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * TICK_PER_SECOND / 1000) : 1);
if (interval < 10) {
interval += 1;
continue;
}
USB_OTG_HC_Halt(&USB_OTG_Core, pipe->pipe_index);
STM32USBHostChannelOpen(
&USB_OTG_Core,
pipe->pipe_index,
pipe->ep.bEndpointAddress,
pipe->inst->address,
USB_OTG_SPEED_FULL,
pipe->ep.bmAttributes,
pipe->ep.wMaxPacketSize
);
if (++retry >= 10) {
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("NAK retry limit exceeded\n"));
return -1;
}
continue;
} else if (HCD_GetHCState(&USB_OTG_Core, pipe->pipe_index) == HC_STALL) {
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("stall\n"));
pipe->status = UPIPE_STATUS_STALL;
if (pipe->callback != NONE)
pipe->callback(pipe);
return -1;
} else if (HCD_GetHCState(&USB_OTG_Core, pipe->pipe_index) == URB_ERROR) {
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("error\n"));
pipe->status = UPIPE_STATUS_ERROR;
if (pipe->callback != NONE)
pipe->callback(pipe);
return -1;
} else if (URB_DONE == HCD_GetHCState(&USB_OTG_Core, pipe->pipe_index)) {
SYS_KDEBUG_LOG(SYS_DEBUG_USB, ("ok\n"));
pipe->status = UPIPE_STATUS_OK;
if (pipe->callback != NONE)
pipe->callback(pipe);
// size_t size = HAL_HCD_HC_GetXferCount(&USB_OTG_Core, pipe->pipe_index);
size_t size = USB_OTG_Core.host.XferCnt[pipe->pipe_index];
if (pipe->ep.bEndpointAddress & 0x80)
return size;
else if (pipe->ep.bEndpointAddress & 0x00)
return size;
return nbytes;
}
continue;
}
}
static uint16 pipe_bitmap;
static uint8 STM32USBHostAllocPipe()
{
for (int i = 1; i < 16; i++)
if ((pipe_bitmap & (1 << i)) == 0) {
pipe_bitmap |= (1 << i);
return i;
}
return 0xff;
}
static void STM32USBHostFreePipe(int i)
{
pipe_bitmap &= ~(1 << i);
}
static x_err_t STM32USBHostOpenPipe(upipe_t pipe)
{
pipe->pipe_index = STM32USBHostAllocPipe();
STM32USBHostChannelOpen(&USB_OTG_Core, pipe->pipe_index, pipe->ep.bEndpointAddress,
pipe->inst->address, USB_OTG_SPEED_FULL, pipe->ep.bmAttributes,
pipe->ep.wMaxPacketSize);
if (USB_OTG_Core.host.hc[pipe->pipe_index].ep_is_in)
USB_OTG_Core.host.hc[pipe->pipe_index].toggle_in = 0;
else
USB_OTG_Core.host.hc[pipe->pipe_index].toggle_out = 0;
return EOK;
}
static x_err_t STM32USBHostClosePipe(upipe_t pipe)
{
USB_OTG_HC_Halt(&USB_OTG_Core, pipe->pipe_index);
STM32USBHostFreePipe(pipe->pipe_index);
return EOK;
}
/* implement these */
static struct uhcd_ops USBHostOps = {
.reset_port = STM32USBHostResetPort,
.pipe_xfer = STM32USBHostPipeXfer,
.open_pipe = STM32USBHostOpenPipe,
.close_pipe = STM32USBHostClosePipe
};
static x_err_t STM32USBHostInit()
{
KPrintf("\nINITIALIZING HOST......\n");
USB_OTG_BSP_Init(&USB_OTG_Core);
HCD_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID);
// RegisterHwIrq(OTG_FS_IRQn, OTG_FS_IRQHandler, NONE);
USB_OTG_BSP_ENABLE_INTERRUPT(&USB_OTG_Core);
UrbCompletionSem = KSemaphoreCreate( 0);
return EOK;
}
int STM32USBHostRegister()
{
UhcdPointer uhcd = (UhcdPointer)x_malloc(sizeof(struct uhcd));
memset(uhcd, 0, sizeof(struct uhcd));
uhcd->ops = &USBHostOps;
uhcd->NumPorts = 1;
USB_OTG_Core.data = uhcd;
UsbHostInit(uhcd);
STM32USBHostInit();
return EOK;
}
long dump_usb_regs()
{
volatile uint32_t *p = (volatile uint32_t *)0x50000000;
while ((uint32_t)p < 0x50000000 + 80 * 4) {
KPrintf("0x%03X: 0x%08X\n", (uint32_t)p - 0x50000000, *p);
p++;
}
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),dump_usb_regs, dump_usb_regs, dump USB registers );
long dump_hc_regs()
{
for (int i = 0; i < USB_OTG_MAX_TX_FIFOS; i++) {
USB_OTG_HC_REGS *regs = USB_OTG_Core.regs.HC_REGS[i];
KPrintf("EP No.%d:\n", i);
KPrintf(" HCCHAR: 0x%08X\n", regs->HCCHAR);
KPrintf(" HCSPLT: 0x%08X\n", regs->HCSPLT);
KPrintf(" HCINT: 0x%08X\n", regs->HCINT);
KPrintf(" HCINTMSK: 0x%08X\n", regs->HCINTMSK);
KPrintf(" HCTSIZ: 0x%08X\n", regs->HCTSIZ);
KPrintf(" HCDMA: 0x%08X\n", regs->HCDMA);
}
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),dump_hc_regs, dump_hc_regs, dump_hc_regs );