|
@@ -7,6 +7,7 @@
|
|
|
* Change Logs:
|
|
|
* Date Author Notes
|
|
|
* 2020-5-4 CHChen First version
|
|
|
+* 2021-11-5 Wayne Revise
|
|
|
*
|
|
|
******************************************************************************/
|
|
|
#include <rtconfig.h>
|
|
@@ -30,6 +31,28 @@
|
|
|
|
|
|
#define NU_MAX_USBH_HUB_PORT_DEV USB_HUB_PORT_NUM
|
|
|
|
|
|
+#define NU_USBHOST_HUB_POLLING_LOCK
|
|
|
+#if defined(NU_USBHOST_HUB_POLLING_LOCK)
|
|
|
+#define NU_USBHOST_MUTEX_INIT() { \
|
|
|
+ s_sUSBHDev.lock = rt_mutex_create("usbhost_lock", RT_IPC_FLAG_PRIO); \
|
|
|
+ RT_ASSERT(s_sUSBHDev.lock != RT_NULL); \
|
|
|
+ }
|
|
|
+
|
|
|
+#define NU_USBHOST_LOCK() { \
|
|
|
+ rt_err_t result = rt_mutex_take(s_sUSBHDev.lock, RT_WAITING_FOREVER); \
|
|
|
+ RT_ASSERT(result == RT_EOK); \
|
|
|
+ }
|
|
|
+
|
|
|
+#define NU_USBHOST_UNLOCK() { \
|
|
|
+ rt_err_t result = rt_mutex_release(s_sUSBHDev.lock); \
|
|
|
+ RT_ASSERT(result == RT_EOK); \
|
|
|
+ }
|
|
|
+#else
|
|
|
+#define NU_USBHOST_MUTEX_INIT()
|
|
|
+#define NU_USBHOST_LOCK()
|
|
|
+#define NU_USBHOST_UNLOCK()
|
|
|
+#endif
|
|
|
+
|
|
|
/* Private typedef --------------------------------------------------------------*/
|
|
|
typedef struct nu_port_dev
|
|
|
{
|
|
@@ -52,21 +75,18 @@ typedef struct nu_port_ctrl
|
|
|
|
|
|
struct nu_usbh_dev
|
|
|
{
|
|
|
- uhcd_t uhcd;
|
|
|
+ struct uhcd uhcd;
|
|
|
rt_thread_t polling_thread;
|
|
|
+ rt_mutex_t lock;
|
|
|
S_NU_RH_PORT_CTRL asPortCtrl[NU_MAX_USBH_PORT];
|
|
|
};
|
|
|
|
|
|
/* Private variables ------------------------------------------------------------*/
|
|
|
-static struct nu_usbh_dev s_sUSBHDev =
|
|
|
-{
|
|
|
- .uhcd = RT_NULL,
|
|
|
-};
|
|
|
+static struct nu_usbh_dev s_sUSBHDev;
|
|
|
|
|
|
static S_NU_RH_PORT_CTRL *
|
|
|
GetRHPortControlFromPipe(
|
|
|
- upipe_t pipe
|
|
|
-)
|
|
|
+ upipe_t pipe)
|
|
|
{
|
|
|
uinst_t inst;
|
|
|
int port;
|
|
@@ -94,8 +114,7 @@ GetRHPortControlFromPipe(
|
|
|
|
|
|
static S_NU_PORT_DEV *
|
|
|
GetPortDevFromPipe(
|
|
|
- upipe_t pipe
|
|
|
-)
|
|
|
+ upipe_t pipe)
|
|
|
{
|
|
|
S_NU_RH_PORT_CTRL *psRHPortCtrl = GetRHPortControlFromPipe(pipe);
|
|
|
int i;
|
|
@@ -118,97 +137,226 @@ GetPortDevFromPipe(
|
|
|
|
|
|
if (i >= NU_MAX_USBH_HUB_PORT_DEV)
|
|
|
return RT_NULL;
|
|
|
+
|
|
|
return &psRHPortCtrl->asHubPortDev[i];
|
|
|
}
|
|
|
|
|
|
-static S_NU_PORT_DEV *
|
|
|
-AllocateNewUDev(
|
|
|
- S_NU_RH_PORT_CTRL *psRHPortCtrl
|
|
|
-)
|
|
|
+static rt_err_t nu_reset_port(rt_uint8_t port)
|
|
|
{
|
|
|
- int i;
|
|
|
- for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++)
|
|
|
+ S_NU_RH_PORT_CTRL *psPortCtrl;
|
|
|
+
|
|
|
+ if (port > NU_MAX_USBH_PORT)
|
|
|
{
|
|
|
- if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
|
|
|
- break;
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: port index over NU_MAX_USBH_PORT\n", __func__));
|
|
|
+ return RT_EIO;
|
|
|
}
|
|
|
|
|
|
- if (i >= NU_MAX_USBH_HUB_PORT_DEV)
|
|
|
- return RT_NULL;
|
|
|
-
|
|
|
- psRHPortCtrl->asHubPortDev[i].pUDev = alloc_device();
|
|
|
+ psPortCtrl = &s_sUSBHDev.asPortCtrl[port - 1];
|
|
|
+ if (psPortCtrl->sRHPortDev.pUDev == NULL)
|
|
|
+ {
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__));
|
|
|
+ return RT_EIO;
|
|
|
+ }
|
|
|
|
|
|
- if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
|
|
|
- return RT_NULL;
|
|
|
+ usbh_reset_port(psPortCtrl->sRHPortDev.pUDev);
|
|
|
|
|
|
- return &psRHPortCtrl->asHubPortDev[i];
|
|
|
+ return RT_EOK;
|
|
|
}
|
|
|
|
|
|
static EP_INFO_T *GetFreePipe(
|
|
|
S_NU_RH_PORT_CTRL *psPortCtrl,
|
|
|
S_NU_PORT_DEV *psPortDev,
|
|
|
- rt_uint8_t *pu8PipeIndex
|
|
|
-)
|
|
|
+ rt_uint8_t *pu8PipeIndex)
|
|
|
{
|
|
|
- rt_uint8_t i;
|
|
|
- if (psPortCtrl == NULL)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- for (i = 1; i < NU_MAX_USBH_PIPE; i ++)
|
|
|
+ if (psPortCtrl != NULL)
|
|
|
{
|
|
|
- if (psPortDev->apsEPInfo[i] == NULL)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (i >= NU_MAX_USBH_PIPE)
|
|
|
- return RT_NULL;
|
|
|
-
|
|
|
- EP_INFO_T *psEPInfo = rt_malloc(sizeof(EP_INFO_T));
|
|
|
+ int i;
|
|
|
+ /* Find free Pipe */
|
|
|
+ for (i = 0; i < NU_MAX_USBH_PIPE; i ++)
|
|
|
+ {
|
|
|
+ if (psPortDev->apsEPInfo[i] == NULL)
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- psPortDev->apsEPInfo[i] = psEPInfo;
|
|
|
- *pu8PipeIndex = i;
|
|
|
- return psEPInfo;
|
|
|
+ if (i < NU_MAX_USBH_PIPE)
|
|
|
+ {
|
|
|
+ EP_INFO_T *psEPInfo = rt_malloc(sizeof(EP_INFO_T));
|
|
|
+ if (psEPInfo != RT_NULL)
|
|
|
+ {
|
|
|
+ psPortDev->apsEPInfo[i] = psEPInfo;
|
|
|
+ *pu8PipeIndex = i;
|
|
|
+ return psEPInfo;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return RT_NULL;
|
|
|
}
|
|
|
|
|
|
static void FreePipe(
|
|
|
S_NU_RH_PORT_CTRL *psPortCtrl,
|
|
|
S_NU_PORT_DEV *psPortDev,
|
|
|
- rt_uint8_t u8PipeIndex
|
|
|
-)
|
|
|
+ rt_uint8_t u8PipeIndex)
|
|
|
{
|
|
|
- if (psPortCtrl == NULL)
|
|
|
- return;
|
|
|
-
|
|
|
- if (u8PipeIndex >= NU_MAX_USBH_PIPE)
|
|
|
- return;
|
|
|
-
|
|
|
- if (psPortDev->apsEPInfo[u8PipeIndex])
|
|
|
+ if ((psPortCtrl != RT_NULL) &&
|
|
|
+ (u8PipeIndex < NU_MAX_USBH_PIPE) &&
|
|
|
+ (psPortDev->apsEPInfo[u8PipeIndex] != RT_NULL))
|
|
|
{
|
|
|
rt_free(psPortDev->apsEPInfo[u8PipeIndex]);
|
|
|
psPortDev->apsEPInfo[u8PipeIndex] = RT_NULL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static rt_err_t nu_reset_port(rt_uint8_t port)
|
|
|
+static S_NU_PORT_DEV *
|
|
|
+AllocateNewUDev(
|
|
|
+ S_NU_RH_PORT_CTRL *psRHPortCtrl)
|
|
|
+{
|
|
|
+ if (psRHPortCtrl != RT_NULL)
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ /* Find free Dev */
|
|
|
+ for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++)
|
|
|
+ {
|
|
|
+ if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i < NU_MAX_USBH_HUB_PORT_DEV)
|
|
|
+ {
|
|
|
+ psRHPortCtrl->asHubPortDev[i].pUDev = alloc_device();
|
|
|
+ if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
|
|
|
+ {
|
|
|
+ return RT_NULL;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return &psRHPortCtrl->asHubPortDev[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return RT_NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static rt_err_t nu_open_pipe(upipe_t pipe)
|
|
|
{
|
|
|
S_NU_RH_PORT_CTRL *psPortCtrl;
|
|
|
+ S_NU_PORT_DEV *psPortDev;
|
|
|
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_reset_port\n"));
|
|
|
- if (port > NU_MAX_USBH_PORT)
|
|
|
+ psPortCtrl = GetRHPortControlFromPipe(pipe);
|
|
|
+ if (psPortCtrl == RT_NULL)
|
|
|
{
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_reset_port ERROR: port index over NU_MAX_USBH_PORT\n"));
|
|
|
- return RT_EIO;
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: RHPort not found\n", __func__));
|
|
|
+ goto exit_nu_open_pipe;
|
|
|
}
|
|
|
|
|
|
- psPortCtrl = &s_sUSBHDev.asPortCtrl[port - 1];
|
|
|
if (psPortCtrl->sRHPortDev.pUDev == NULL)
|
|
|
{
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_reset_port ERROR: udev not found\n"));
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__));
|
|
|
+ goto exit_nu_open_pipe;
|
|
|
+ }
|
|
|
+
|
|
|
+ psPortDev = GetPortDevFromPipe(pipe);
|
|
|
+
|
|
|
+ if ((psPortDev == NULL) || (psPortDev->pUDev == NULL))
|
|
|
+ {
|
|
|
+ //allocate new dev for hub device
|
|
|
+ psPortDev = AllocateNewUDev(psPortCtrl);
|
|
|
+
|
|
|
+ if (psPortDev == RT_NULL)
|
|
|
+ {
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev allocate failed\n"));
|
|
|
+ goto exit_nu_open_pipe;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pipe->inst->speed)
|
|
|
+ {
|
|
|
+ psPortDev->pUDev->speed = SPEED_FULL;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ psPortDev->pUDev->speed = SPEED_HIGH;
|
|
|
+ }
|
|
|
+
|
|
|
+ psPortDev->pUDev->parent = NULL;
|
|
|
+ psPortDev->pUDev->hc_driver = psPortCtrl->sRHPortDev.pUDev->hc_driver;
|
|
|
+ psPortDev->port_num = pipe->inst->port;
|
|
|
+ psPortDev->pUDev->port_num = pipe->inst->port;
|
|
|
+ psPortDev->bEnumDone = FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ //For ep0 control transfer
|
|
|
+ if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
|
|
|
+ {
|
|
|
+ pipe->pipe_index = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int pksz;
|
|
|
+ EP_INFO_T *psEPInfo = GetFreePipe(psPortCtrl, psPortDev, &pipe->pipe_index);
|
|
|
+ if (psEPInfo == RT_NULL)
|
|
|
+ {
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: get free pipe failed\n", __func__));
|
|
|
+ goto exit_nu_open_pipe;
|
|
|
+ }
|
|
|
+
|
|
|
+ psEPInfo->bEndpointAddress = pipe->ep.bEndpointAddress;
|
|
|
+ psEPInfo->bmAttributes = pipe->ep.bmAttributes;
|
|
|
+
|
|
|
+ pksz = pipe->ep.wMaxPacketSize;
|
|
|
+ pksz = (pksz & 0x07ff) * (1 + ((pksz >> 11) & 3));
|
|
|
+ psEPInfo->wMaxPacketSize = pksz;
|
|
|
+
|
|
|
+ psEPInfo->bInterval = pipe->ep.bInterval;
|
|
|
+ psEPInfo->hw_pipe = NULL;
|
|
|
+ psEPInfo->bToggle = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return RT_EOK;
|
|
|
+
|
|
|
+exit_nu_open_pipe:
|
|
|
+
|
|
|
+ return -RT_ERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static rt_err_t nu_close_pipe(upipe_t pipe)
|
|
|
+{
|
|
|
+ S_NU_RH_PORT_CTRL *psPortCtrl;
|
|
|
+ S_NU_PORT_DEV *psPortDev;
|
|
|
+
|
|
|
+ psPortCtrl = GetRHPortControlFromPipe(pipe);
|
|
|
+ if (psPortCtrl == RT_NULL)
|
|
|
+ {
|
|
|
return RT_EIO;
|
|
|
}
|
|
|
|
|
|
- usbh_reset_port(psPortCtrl->sRHPortDev.pUDev);
|
|
|
+ psPortDev = GetPortDevFromPipe(pipe);
|
|
|
|
|
|
+ //For ep0 control transfer
|
|
|
+ if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
|
|
|
+ {
|
|
|
+ if ((psPortDev) && (psPortDev->bRHParent == FALSE) && (psPortDev->bEnumDone == TRUE))
|
|
|
+ {
|
|
|
+ if (psPortDev->pUDev)
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < NU_MAX_USBH_PIPE; i++)
|
|
|
+ {
|
|
|
+ if (psPortDev->apsEPInfo[i] != NULL)
|
|
|
+ {
|
|
|
+ usbh_quit_xfer(psPortDev->pUDev, psPortDev->apsEPInfo[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ free_device(psPortDev->pUDev);
|
|
|
+ psPortDev->pUDev = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (psPortDev != NULL)
|
|
|
+ {
|
|
|
+ FreePipe(psPortCtrl, psPortDev, pipe->pipe_index);
|
|
|
+ }
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
@@ -216,14 +364,12 @@ static int nu_ctrl_xfer(
|
|
|
S_NU_PORT_DEV *psPortDev,
|
|
|
struct urequest *psSetup,
|
|
|
void *buffer,
|
|
|
- int timeouts
|
|
|
-)
|
|
|
+ int timeouts)
|
|
|
{
|
|
|
- uint32_t xfer_len;
|
|
|
+ uint32_t xfer_len = 0;
|
|
|
int ret;
|
|
|
|
|
|
ret = usbh_ctrl_xfer(psPortDev->pUDev, psSetup->request_type, psSetup->bRequest, psSetup->wValue, psSetup->wIndex, psSetup->wLength, buffer, &xfer_len, timeouts * 10);
|
|
|
-
|
|
|
if (ret < 0)
|
|
|
{
|
|
|
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer failed %d\n", ret));
|
|
@@ -250,18 +396,26 @@ static int nu_ctrl_xfer(
|
|
|
static int nu_bulk_xfer(
|
|
|
S_NU_PORT_DEV *psPortDev,
|
|
|
UTR_T *psUTR,
|
|
|
- int timeouts
|
|
|
-)
|
|
|
+ int timeouts)
|
|
|
{
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = usbh_bulk_xfer(psUTR);
|
|
|
-
|
|
|
+ int ret = usbh_bulk_xfer(psUTR);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
//wait transfer done
|
|
|
- rt_completion_wait(&(psPortDev->utr_completion), timeouts);
|
|
|
+ if (rt_completion_wait(&(psPortDev->utr_completion), timeouts) < 0)
|
|
|
+ {
|
|
|
+ rt_kprintf("Request Timeout in %d ms!! (bulk_xfer)\n", timeouts);
|
|
|
+
|
|
|
+ rt_kprintf("psUTR->buff: %08x\n", psUTR->buff);
|
|
|
+ rt_kprintf("psUTR->data_len: %d\n", psUTR->data_len);
|
|
|
+ rt_kprintf("psUTR->xfer_len: %d\n", psUTR->xfer_len);
|
|
|
+ rt_kprintf("psUTR->ep: %08x\n", psUTR->ep);
|
|
|
+ rt_kprintf("psUTR->bIsTransferDone: %08x\n", psUTR->bIsTransferDone);
|
|
|
+ rt_kprintf("psUTR->status: %08x\n", psUTR->status);
|
|
|
+ rt_kprintf("psUTR->td_cnt: %08x\n", psUTR->td_cnt);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -269,8 +423,7 @@ static int nu_int_xfer(
|
|
|
upipe_t pipe,
|
|
|
S_NU_PORT_DEV *psPortDev,
|
|
|
UTR_T *psUTR,
|
|
|
- int timeouts
|
|
|
-)
|
|
|
+ int timeouts)
|
|
|
{
|
|
|
int ret;
|
|
|
int retry = 3;
|
|
@@ -306,9 +459,8 @@ static void int_xfer_done_cb(UTR_T *psUTR)
|
|
|
|
|
|
if (psUTR->status != 0)
|
|
|
{
|
|
|
- rt_kprintf("Interrupt xfer failed %d\n", psUTR->status);
|
|
|
- free_utr(psUTR);
|
|
|
- return;
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("Interrupt xfer failed %d\n", psUTR->status));
|
|
|
+ goto exit_int_xfer_done_cb;
|
|
|
}
|
|
|
|
|
|
if (pipe->callback != RT_NULL)
|
|
@@ -320,6 +472,8 @@ static void int_xfer_done_cb(UTR_T *psUTR)
|
|
|
rt_usbh_event_signal(&msg);
|
|
|
}
|
|
|
|
|
|
+exit_int_xfer_done_cb:
|
|
|
+
|
|
|
free_utr(psUTR);
|
|
|
}
|
|
|
|
|
@@ -327,29 +481,37 @@ static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes
|
|
|
{
|
|
|
S_NU_RH_PORT_CTRL *psPortCtrl;
|
|
|
S_NU_PORT_DEV *psPortDev;
|
|
|
+ UTR_T *psUTR = NULL;
|
|
|
+ int i32XferLen = -1;
|
|
|
+
|
|
|
+ void *buffer_nonch = buffer;
|
|
|
+
|
|
|
+ NU_USBHOST_LOCK();
|
|
|
|
|
|
psPortCtrl = GetRHPortControlFromPipe(pipe);
|
|
|
if (psPortCtrl == RT_NULL)
|
|
|
{
|
|
|
- return RT_EIO;
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
}
|
|
|
|
|
|
psPortDev = GetPortDevFromPipe(pipe);
|
|
|
-
|
|
|
if (psPortDev->pUDev == NULL)
|
|
|
{
|
|
|
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: udev not found\n"));
|
|
|
- return -RT_ERROR;
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
}
|
|
|
|
|
|
//ctrl xfer
|
|
|
if (pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+
|
|
|
if (token == USBH_PID_SETUP)
|
|
|
{
|
|
|
- struct urequest *psSetup;
|
|
|
- psSetup = (struct urequest *)buffer;
|
|
|
+ struct urequest *psSetup = (struct urequest *)buffer_nonch;
|
|
|
+ RT_ASSERT(buffer_nonch != RT_NULL);
|
|
|
|
|
|
+ /* Read data from USB device. */
|
|
|
if (psSetup->request_type & USB_REQ_TYPE_DIR_IN)
|
|
|
{
|
|
|
//Store setup request
|
|
@@ -357,85 +519,90 @@ static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- //Trigger USBHostLib Ctril_Xfer
|
|
|
- nu_ctrl_xfer(psPortDev, psSetup, NULL, timeouts);
|
|
|
+ /* Write data to USB device. */
|
|
|
+ //Trigger USBHostLib Ctrl_Xfer
|
|
|
+ ret = nu_ctrl_xfer(psPortDev, psSetup, NULL, timeouts);
|
|
|
+ if (ret != psSetup->wLength)
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
}
|
|
|
- return nbytes;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//token == USBH_PID_DATA
|
|
|
- if (buffer == RT_NULL)
|
|
|
- return nbytes;
|
|
|
-
|
|
|
- if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
|
|
|
+ if (buffer_nonch && ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN))
|
|
|
{
|
|
|
+ /* Read data from USB device. */
|
|
|
//Trigger USBHostLib Ctril_Xfer
|
|
|
- nu_ctrl_xfer(psPortDev, &psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], buffer, timeouts);
|
|
|
+ ret = nu_ctrl_xfer(psPortDev, &psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], buffer_nonch, timeouts);
|
|
|
+ if (ret != nbytes)
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: can not handle ctrl xfer case: buffer!=NULL and USB_DIR_OUT\n"));
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("%d == USBH_PID_DATA, nil buf-%d \n", token, nbytes));
|
|
|
}
|
|
|
- return nbytes;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //others xfer
|
|
|
- rt_completion_init(&(psPortDev->utr_completion));
|
|
|
|
|
|
- //setup UTR
|
|
|
- UTR_T *psUTR;
|
|
|
- int i32XferLen;
|
|
|
-
|
|
|
- psUTR = alloc_utr(psPortDev->pUDev);
|
|
|
- if (!psUTR)
|
|
|
+ } //else
|
|
|
+ i32XferLen = nbytes;
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
+ } // if ( pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL )
|
|
|
+ else
|
|
|
{
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: unable alloc UTR\n"));
|
|
|
- return -(RT_ERROR);
|
|
|
- }
|
|
|
|
|
|
- psUTR->ep = psPortDev->apsEPInfo[pipe->pipe_index];
|
|
|
- psUTR->buff = buffer;
|
|
|
- psUTR->data_len = nbytes;
|
|
|
- psUTR->xfer_len = 0;
|
|
|
- psUTR->func = xfer_done_cb;
|
|
|
- psUTR->context = psPortDev;
|
|
|
- psUTR->bIsTransferDone = 0;
|
|
|
- psUTR->status = 0;
|
|
|
+ psUTR = alloc_utr(psPortDev->pUDev);
|
|
|
|
|
|
- if (pipe->ep.bmAttributes == USB_EP_ATTR_BULK)
|
|
|
- {
|
|
|
- if (nu_bulk_xfer(psPortDev, psUTR, timeouts) < 0)
|
|
|
+ if (!psUTR)
|
|
|
{
|
|
|
- free_utr(psUTR);
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: bulk transfer failed\n"));
|
|
|
- return -(RT_ERROR);
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: unable alloc UTR\n"));
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
|
|
|
- {
|
|
|
- psUTR->func = int_xfer_done_cb;
|
|
|
- psUTR->context = pipe;
|
|
|
+ psUTR->ep = psPortDev->apsEPInfo[pipe->pipe_index];
|
|
|
+ psUTR->buff = buffer_nonch;
|
|
|
+ psUTR->data_len = nbytes;
|
|
|
+ psUTR->xfer_len = 0;
|
|
|
+ psUTR->func = xfer_done_cb;
|
|
|
+ psUTR->context = psPortDev;
|
|
|
+ psUTR->bIsTransferDone = 0;
|
|
|
+ psUTR->status = 0;
|
|
|
+
|
|
|
+ //others xfer
|
|
|
+ rt_completion_init(&(psPortDev->utr_completion));
|
|
|
|
|
|
- if (nu_int_xfer(pipe, psPortDev, psUTR, timeouts) < 0)
|
|
|
+ if (pipe->ep.bmAttributes == USB_EP_ATTR_BULK)
|
|
|
{
|
|
|
- free_utr(psUTR);
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: int transfer failed\n"));
|
|
|
- return -(RT_ERROR);
|
|
|
+ if (nu_bulk_xfer(psPortDev, psUTR, timeouts) < 0)
|
|
|
+ {
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: bulk transfer failed\n"));
|
|
|
+ goto failreport_nu_pipe_xfer;
|
|
|
+ }
|
|
|
}
|
|
|
+ else if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
|
|
|
+ {
|
|
|
+ psUTR->func = int_xfer_done_cb;
|
|
|
+ psUTR->context = pipe;
|
|
|
|
|
|
- return nbytes;
|
|
|
- }
|
|
|
+ if (nu_int_xfer(pipe, psPortDev, psUTR, timeouts) < 0)
|
|
|
+ {
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: int transfer failed\n"));
|
|
|
+ //goto exit_nu_pipe_xfer;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ i32XferLen = nbytes;
|
|
|
+ }
|
|
|
+ goto exit2_nu_pipe_xfer;
|
|
|
+ }
|
|
|
+ else if (pipe->ep.bmAttributes == USB_EP_ATTR_ISOC)
|
|
|
+ {
|
|
|
+ //TODO: ISO transfer
|
|
|
+ RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: isoc transfer not support\n"));
|
|
|
+ goto exit_nu_pipe_xfer;
|
|
|
+ }
|
|
|
|
|
|
- //TODO: ISO transfer
|
|
|
- if (pipe->ep.bmAttributes == USB_EP_ATTR_ISOC)
|
|
|
- {
|
|
|
- free_utr(psUTR);
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: isoc transfer not support\n"));
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ } //else
|
|
|
+
|
|
|
+failreport_nu_pipe_xfer:
|
|
|
|
|
|
if (psUTR->bIsTransferDone == 0)
|
|
|
{
|
|
@@ -462,169 +629,42 @@ static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes
|
|
|
}
|
|
|
|
|
|
i32XferLen = psUTR->xfer_len;
|
|
|
- free_utr(psUTR);
|
|
|
|
|
|
//Call callback
|
|
|
if (pipe->callback != RT_NULL)
|
|
|
{
|
|
|
- struct uhost_msg msg;
|
|
|
- msg.type = USB_MSG_CALLBACK;
|
|
|
- msg.content.cb.function = pipe->callback;
|
|
|
- msg.content.cb.context = pipe->user_data;
|
|
|
- rt_usbh_event_signal(&msg);
|
|
|
- }
|
|
|
-
|
|
|
- if (pipe->status != UPIPE_STATUS_OK)
|
|
|
- return -(RT_ERROR);
|
|
|
-
|
|
|
- if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
|
|
|
- {
|
|
|
- return i32XferLen;
|
|
|
+ pipe->callback(pipe);
|
|
|
}
|
|
|
- else if ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_OUT)
|
|
|
- {
|
|
|
- return i32XferLen;
|
|
|
- }
|
|
|
-
|
|
|
- return nbytes;
|
|
|
-}
|
|
|
-
|
|
|
-static rt_err_t nu_open_pipe(upipe_t pipe)
|
|
|
-{
|
|
|
- S_NU_RH_PORT_CTRL *psPortCtrl;
|
|
|
- S_NU_PORT_DEV *psPortDev;
|
|
|
-
|
|
|
- psPortCtrl = GetRHPortControlFromPipe(pipe);
|
|
|
- if (psPortCtrl == RT_NULL)
|
|
|
- {
|
|
|
- return RT_EIO;
|
|
|
- }
|
|
|
-
|
|
|
- if (psPortCtrl->sRHPortDev.pUDev == NULL)
|
|
|
- {
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev not found\n"));
|
|
|
- return RT_EIO;
|
|
|
- }
|
|
|
-
|
|
|
- psPortDev = GetPortDevFromPipe(pipe);
|
|
|
|
|
|
- if ((psPortDev == NULL) || (psPortDev->pUDev == NULL))
|
|
|
- {
|
|
|
- //allocate new dev for hub device
|
|
|
- psPortDev = AllocateNewUDev(psPortCtrl);
|
|
|
+exit_nu_pipe_xfer:
|
|
|
|
|
|
- if (psPortDev == RT_NULL)
|
|
|
- {
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev allocate failed\n"));
|
|
|
- return RT_EIO;
|
|
|
- }
|
|
|
-
|
|
|
- if (pipe->inst->speed)
|
|
|
- {
|
|
|
- psPortDev->pUDev->speed = SPEED_FULL;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- psPortDev->pUDev->speed = SPEED_HIGH;
|
|
|
- }
|
|
|
-
|
|
|
- psPortDev->pUDev->parent = NULL;
|
|
|
- psPortDev->pUDev->hc_driver = psPortCtrl->sRHPortDev.pUDev->hc_driver;
|
|
|
- psPortDev->port_num = pipe->inst->port;
|
|
|
- psPortDev->pUDev->port_num = pipe->inst->port;
|
|
|
- psPortDev->bEnumDone = FALSE;
|
|
|
- }
|
|
|
-
|
|
|
- //For ep0 control transfer
|
|
|
- if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
|
|
|
- {
|
|
|
- pipe->pipe_index = 0;
|
|
|
- return RT_EOK;
|
|
|
- }
|
|
|
-
|
|
|
- EP_INFO_T *psEPInfo = GetFreePipe(psPortCtrl, psPortDev, &pipe->pipe_index);
|
|
|
-
|
|
|
- if (psEPInfo == RT_NULL)
|
|
|
- {
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: get free pipe failed\n"));
|
|
|
- return RT_ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- int pksz;
|
|
|
+ if (psUTR)
|
|
|
+ free_utr(psUTR);
|
|
|
|
|
|
- psEPInfo->bEndpointAddress = pipe->ep.bEndpointAddress;
|
|
|
- psEPInfo->bmAttributes = pipe->ep.bmAttributes;
|
|
|
+exit2_nu_pipe_xfer:
|
|
|
|
|
|
- pksz = pipe->ep.wMaxPacketSize;
|
|
|
- pksz = (pksz & 0x07ff) * (1 + ((pksz >> 11) & 3));
|
|
|
- psEPInfo->wMaxPacketSize = pksz;
|
|
|
|
|
|
- psEPInfo->bInterval = pipe->ep.bInterval;
|
|
|
- psEPInfo->hw_pipe = NULL;
|
|
|
- psEPInfo->bToggle = 0;
|
|
|
+ NU_USBHOST_UNLOCK();
|
|
|
|
|
|
- return RT_EOK;
|
|
|
+ return i32XferLen;
|
|
|
}
|
|
|
|
|
|
-static rt_err_t nu_close_pipe(upipe_t pipe)
|
|
|
-{
|
|
|
- S_NU_RH_PORT_CTRL *psPortCtrl;
|
|
|
- S_NU_PORT_DEV *psPortDev;
|
|
|
-
|
|
|
- RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_close_pipe\n"));
|
|
|
- psPortCtrl = GetRHPortControlFromPipe(pipe);
|
|
|
- if (psPortCtrl == RT_NULL)
|
|
|
- {
|
|
|
- return RT_EIO;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- psPortDev = GetPortDevFromPipe(pipe);
|
|
|
-
|
|
|
- //For ep0 control transfer
|
|
|
- if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
|
|
|
- {
|
|
|
- if ((psPortDev) && (psPortDev->bRHParent == FALSE) && (psPortDev->bEnumDone == TRUE))
|
|
|
- {
|
|
|
- if (psPortDev->pUDev)
|
|
|
- {
|
|
|
- int i;
|
|
|
- for (i = 0; i < NU_MAX_USBH_PIPE; i++)
|
|
|
- {
|
|
|
- if (psPortDev->apsEPInfo[i] != NULL)
|
|
|
- {
|
|
|
- usbh_quit_xfer(psPortDev->pUDev, psPortDev->apsEPInfo[i]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- free_device(psPortDev->pUDev);
|
|
|
- psPortDev->pUDev = NULL;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (psPortDev != NULL)
|
|
|
- {
|
|
|
- FreePipe(psPortCtrl, psPortDev, pipe->pipe_index);
|
|
|
- }
|
|
|
-
|
|
|
- return RT_EOK;
|
|
|
-}
|
|
|
-
|
|
|
-//Pooling USB root hub status task
|
|
|
+/* Polling USB root hub status task */
|
|
|
static void nu_usbh_rh_thread_entry(void *parameter)
|
|
|
{
|
|
|
while (1)
|
|
|
{
|
|
|
+ NU_USBHOST_LOCK();
|
|
|
usbh_polling_root_hubs();
|
|
|
+ NU_USBHOST_UNLOCK();
|
|
|
+
|
|
|
rt_thread_mdelay(NU_USBHOST_HUB_POLLING_INTERVAL);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void nu_hcd_connect_callback(
|
|
|
struct udev_t *udev,
|
|
|
- int param
|
|
|
-)
|
|
|
+ int param)
|
|
|
{
|
|
|
int i;
|
|
|
int port_index;
|
|
@@ -646,14 +686,18 @@ static void nu_hcd_connect_callback(
|
|
|
port_index = i + 1;
|
|
|
psPortCtrl->sRHPortDev.pUDev = udev;
|
|
|
psPortCtrl->sRHPortDev.bRHParent = TRUE;
|
|
|
+
|
|
|
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb connected\n"));
|
|
|
- rt_usbh_root_hub_connect_handler(s_sUSBHDev.uhcd, port_index, RT_FALSE);
|
|
|
+
|
|
|
+ if (udev->speed == SPEED_HIGH)
|
|
|
+ rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_TRUE);
|
|
|
+ else
|
|
|
+ rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_FALSE);
|
|
|
}
|
|
|
|
|
|
static void nu_hcd_disconnect_callback(
|
|
|
struct udev_t *udev,
|
|
|
- int param
|
|
|
-)
|
|
|
+ int param)
|
|
|
{
|
|
|
int i;
|
|
|
int port_index;
|
|
@@ -685,9 +729,11 @@ static void nu_hcd_disconnect_callback(
|
|
|
psPortCtrl->sRHPortDev.pUDev = NULL;
|
|
|
|
|
|
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n"));
|
|
|
- rt_usbh_root_hub_disconnect_handler(s_sUSBHDev.uhcd, port_index);
|
|
|
+
|
|
|
+ rt_usbh_root_hub_disconnect_handler(&s_sUSBHDev.uhcd, port_index);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/* USB host operations -----------------------------------------------------------*/
|
|
|
static struct uhcd_ops nu_uhcd_ops =
|
|
|
{
|
|
@@ -700,25 +746,20 @@ static struct uhcd_ops nu_uhcd_ops =
|
|
|
static rt_err_t nu_hcd_init(rt_device_t device)
|
|
|
{
|
|
|
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
|
|
|
+
|
|
|
usbh_core_init();
|
|
|
|
|
|
//install connect/disconnect callback
|
|
|
usbh_install_conn_callback(nu_hcd_connect_callback, nu_hcd_disconnect_callback);
|
|
|
- usbh_polling_root_hubs();
|
|
|
|
|
|
//create thread for polling usbh port status
|
|
|
/* create usb hub thread */
|
|
|
pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL,
|
|
|
NU_USBH_THREAD_STACK_SIZE, 8, 20);
|
|
|
- if (pNuUSBHDev->polling_thread != RT_NULL)
|
|
|
- {
|
|
|
- /* startup usb host thread */
|
|
|
- rt_thread_startup(pNuUSBHDev->polling_thread);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- return -(RT_EEMPTY);
|
|
|
- }
|
|
|
+ RT_ASSERT(pNuUSBHDev->polling_thread != RT_NULL);
|
|
|
+
|
|
|
+ /* startup usb host thread */
|
|
|
+ rt_thread_startup(pNuUSBHDev->polling_thread);
|
|
|
|
|
|
return RT_EOK;
|
|
|
}
|
|
@@ -797,7 +838,17 @@ static struct rt_device_pm_ops device_pm_ops =
|
|
|
|
|
|
int nu_usbh_register(void)
|
|
|
{
|
|
|
- rt_err_t res = -RT_ERROR;
|
|
|
+ rt_err_t res;
|
|
|
+ uhcd_t psUHCD;
|
|
|
+
|
|
|
+ psUHCD = (uhcd_t)&s_sUSBHDev.uhcd;
|
|
|
+
|
|
|
+ psUHCD->parent.type = RT_Device_Class_USBHost;
|
|
|
+ psUHCD->parent.init = nu_hcd_init;
|
|
|
+ psUHCD->parent.user_data = &s_sUSBHDev;
|
|
|
+
|
|
|
+ psUHCD->ops = &nu_uhcd_ops;
|
|
|
+ psUHCD->num_ports = NU_MAX_USBH_PORT;
|
|
|
|
|
|
#if !defined(BSP_USING_OTG)
|
|
|
SYS_UnlockReg();
|
|
@@ -809,22 +860,9 @@ int nu_usbh_register(void)
|
|
|
#endif
|
|
|
|
|
|
|
|
|
- rt_memset(&s_sUSBHDev, 0x0, sizeof(struct nu_usbh_dev));
|
|
|
-
|
|
|
- uhcd_t uhcd = (uhcd_t)rt_malloc(sizeof(struct uhcd));
|
|
|
- RT_ASSERT(res != RT_NULL);
|
|
|
+ NU_USBHOST_MUTEX_INIT();
|
|
|
|
|
|
- rt_memset((void *)uhcd, 0, sizeof(struct uhcd));
|
|
|
-
|
|
|
- uhcd->parent.type = RT_Device_Class_USBHost;
|
|
|
- uhcd->parent.init = nu_hcd_init;
|
|
|
- uhcd->parent.user_data = &s_sUSBHDev;
|
|
|
-
|
|
|
- uhcd->ops = &nu_uhcd_ops;
|
|
|
- uhcd->num_ports = NU_MAX_USBH_PORT;
|
|
|
- s_sUSBHDev.uhcd = uhcd;
|
|
|
-
|
|
|
- res = rt_device_register(&uhcd->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
|
|
|
+ res = rt_device_register(&psUHCD->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
|
|
|
RT_ASSERT(res == RT_EOK);
|
|
|
|
|
|
/*initialize the usb host function */
|
|
@@ -832,10 +870,10 @@ int nu_usbh_register(void)
|
|
|
RT_ASSERT(res == RT_EOK);
|
|
|
|
|
|
#if defined(RT_USING_PM)
|
|
|
- rt_pm_device_register(&uhcd->parent, &device_pm_ops);
|
|
|
+ rt_pm_device_register(&psUHCD->parent, &device_pm_ops);
|
|
|
#endif
|
|
|
|
|
|
- return RT_EOK;
|
|
|
+ return 0;
|
|
|
}
|
|
|
INIT_DEVICE_EXPORT(nu_usbh_register);
|
|
|
|