/* ********************************************************************************************************* * uC/USB-Host * The Embedded USB Host Stack * * Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com * * SPDX-License-Identifier: APACHE-2.0 * * This software is subject to an open source license and is distributed by * Silicon Laboratories Inc. pursuant to the terms of the Apache License, * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. * ********************************************************************************************************* */ /* ********************************************************************************************************* * NOTICE * * Semidrive modified this file to adapt it for ssdk platform. * The modifications are only intended for use with Semidrive chips. * Copyright of all the modifications belongs to Semidrive Semiconductor. * ********************************************************************************************************* */ /* ********************************************************************************************************* * * USB HOST CORE OPERATIONS * * Filename : usbh_core.c * Version : V3.42.01 ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #define USBH_CORE_MODULE #define MICRIUM_SOURCE #include "usbh_core.h" #include "usbh_class.h" #include "usbh_hub.h" /* ********************************************************************************************************* * LOCAL DEFINES ********************************************************************************************************* */ /* ********************************************************************************************************* * USB HOST DRIVER FUNCTIONS ********************************************************************************************************* */ #define USBH_HCD_Init(p_hc, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->Init(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_Start(p_hc, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->Start(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_Stop(p_hc, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->Stop(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_SpdGet(p_hc, p_spd, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ *(p_spd) = (p_hc)->HC_Drv.API_Ptr->SpdGet(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_Suspend(p_hc, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->Suspend(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_Resume(p_hc, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->Resume(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_FrmNbrGet(p_hc, p_frm_nbr, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ *(p_frm_nbr) = (p_hc)->HC_Drv.API_Ptr->FrmNbrGet(&(p_hc)->HC_Drv, (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) \ #define USBH_HCD_EP_Open(p_hc, p_ep, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->EP_Open(&(p_hc)->HC_Drv, \ (p_ep), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) #define USBH_HCD_EP_Close(p_hc, p_ep, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->EP_Close(&(p_hc)->HC_Drv, \ (p_ep), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) #define USBH_HCD_EP_Abort(p_hc, p_ep, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->EP_Abort(&(p_hc)->HC_Drv, \ (p_ep), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) #define USBH_HCD_EP_IsHalt(p_hc, p_ep, b_ret, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ *(b_ret) = (p_hc)->HC_Drv.API_Ptr->EP_IsHalt(&(p_hc)->HC_Drv, \ (p_ep), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) #define USBH_HCD_URB_Submit(p_hc, p_urb, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->URB_Submit(&(p_hc)->HC_Drv, \ (p_urb), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) #define USBH_HCD_URB_Complete(p_hc, p_urb, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->URB_Complete(&(p_hc)->HC_Drv, \ (p_urb), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) #define USBH_HCD_URB_Abort(p_hc, p_urb, p_err) do { \ USBH_OS_MutexLock((p_hc)->HCD_Mutex); \ (p_hc)->HC_Drv.API_Ptr->URB_Abort(&(p_hc)->HC_Drv, \ (p_urb), \ (p_err)); \ USBH_OS_MutexUnlock((p_hc)->HCD_Mutex); \ } while (0) /* ********************************************************************************************************* * LOCAL CONSTANTS ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL DATA TYPES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL TABLES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL GLOBAL VARIABLES ********************************************************************************************************* */ static volatile USBH_URB *USBH_URB_HeadPtr; static volatile USBH_URB *USBH_URB_TailPtr; static volatile USBH_HSEM USBH_URB_Sem; /* ********************************************************************************************************* * HOST MAIN STRUCTURE ********************************************************************************************************* */ static USBH_HOST USBH_Host; static CPU_INT32U USBH_Version; /* ********************************************************************************************************* * LOCAL FUNCTION PROTOTYPES ********************************************************************************************************* */ static USBH_ERR USBH_EP_Open (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP_TYPE ep_type, USBH_EP_DIR ep_dir, USBH_EP *p_ep); static CPU_INT32U USBH_SyncXfer (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_ISOC_DESC *p_isoc_desc, USBH_TOKEN token, CPU_INT32U timeout_ms, USBH_ERR *p_err); static USBH_ERR USBH_AsyncXfer (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_ISOC_DESC *p_isoc_desc, USBH_TOKEN token, void *p_fnct, void *p_fnct_arg); static CPU_INT16U USBH_SyncCtrlXfer(USBH_EP *p_ep, CPU_INT08U b_req, CPU_INT08U bm_req_type, CPU_INT16U w_val, CPU_INT16U w_ix, void *p_arg, CPU_INT16U w_len, CPU_INT32U timeout_ms, USBH_ERR *p_err); static void USBH_URB_Abort (USBH_URB *p_urb); static void USBH_URB_Notify (USBH_URB *p_urb); static USBH_ERR USBH_URB_Submit (USBH_URB *p_urb); static void USBH_URB_Clr (USBH_URB *p_urb); static USBH_ERR USBH_DfltEP_Open (USBH_DEV *p_dev); static USBH_ERR USBH_DevDescRd (USBH_DEV *p_dev); static USBH_ERR USBH_CfgRd (USBH_DEV *p_dev, CPU_INT08U cfg_ix); static USBH_ERR USBH_CfgParse (USBH_DEV *p_dev, USBH_CFG *p_cfg); static USBH_ERR USBH_DevAddrSet (USBH_DEV *p_dev); static CPU_INT32U USBH_StrDescGet (USBH_DEV *p_dev, CPU_INT08U desc_ix, CPU_INT16U lang_id, void *p_buf, CPU_INT32U buf_len, USBH_ERR *p_err); #if (USBH_CFG_PRINT_LOG == DEF_ENABLED) static void USBH_StrDescPrint(USBH_DEV *p_dev, CPU_INT08U *p_str_prefix, CPU_INT08U desc_idx); #endif static USBH_DESC_HDR *USBH_NextDescGet (void *p_buf, CPU_INT32U *p_offset); static void USBH_FmtSetupReq (USBH_SETUP_REQ *p_setup_req, void *p_buf_dest); static void USBH_ParseDevDesc(USBH_DEV_DESC *p_dev_desc, void *p_buf_src); static void USBH_ParseCfgDesc(USBH_CFG_DESC *p_cfg_desc, void *p_buf_src); static void USBH_ParseIF_Desc(USBH_IF_DESC *p_if_desc, void *p_buf_src); static void USBH_ParseEP_Desc(USBH_EP_DESC *p_ep_desc, void *p_buf_src); static void USBH_AsyncTask (void *p_arg); /* ********************************************************************************************************* * LOCAL CONFIGURATION ERRORS ********************************************************************************************************* */ /* ********************************************************************************************************* ********************************************************************************************************* * GLOBAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * USBH_VersionGet() * * Description : Get the uC/USB-Host software version. * * Argument(s) : None. * * Return(s) : uC/USB-Host version. * * Note(s) : The value returned is multiplied by 10000. For example, version 3.40.02, would be * returned as 34002. ********************************************************************************************************* */ CPU_INT32U USBH_VersionGet (void) { CPU_INT32U version; version = USBH_VERSION; return (version); } /* ********************************************************************************************************* * USBH_Init() * * Description : Allocates and initializes resources required by USB Host stack. * * Argument(s) : async_task_info Information on asynchronous task. * * hub_task_info Information on hub task. * * Return(s) : USBH_ERR_NONE, If host stack initialization succeed. * USBH_ERR_ALLOC, If memory pool allocation failed. * * ----- RETURNED BY USBH_ClassDrvReg() : ----- * USBH_ERR_NONE, If the class driver is registered. * USBH_ERR_INVALID_ARG, If invalid argument(s) passed to 'p_host'/ 'p_class_drv'. * USBH_ERR_CLASS_DRV_ALLOC, If maximum class driver limit reached. * * ----- RETURNED BY USBH_OS_MutexCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, if mutex creation failed. * * ----- RETURNED BY USBH_OS_SemCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, If semaphore creation failed. * * ----- RETURNED BY USBH_OS_TaskCreate() : ----- * USBH_ERR_OS_TASK_CREATE, Task failed to be created. * * Note(s) : USBH_Init() must be called: * (1) Only once from a product s application. * (2) After product s OS has been initialized. ********************************************************************************************************* */ USBH_ERR USBH_Init (USBH_KERNEL_TASK_INFO *async_task_info, USBH_KERNEL_TASK_INFO *hub_task_info) { USBH_ERR err; LIB_ERR err_lib; CPU_SIZE_T octets_reqd; CPU_INT08U ix; USBH_Version = USBH_VERSION; (void)USBH_Version; USBH_URB_HeadPtr = (USBH_URB *)0; USBH_URB_TailPtr = (USBH_URB *)0; err = USBH_OS_LayerInit(); if (err != USBH_ERR_NONE) { return (err); } USBH_Host.HC_NbrNext = 0u; USBH_Host.State = USBH_HOST_STATE_NONE; for (ix = 0u; ix < USBH_CFG_MAX_NBR_CLASS_DRVS; ix++) { /* Clr class drv struct table. */ USBH_ClassDrvList[ix].ClassDrvPtr = (USBH_CLASS_DRV *)0; USBH_ClassDrvList[ix].NotifyFnctPtr = (USBH_CLASS_NOTIFY_FNCT)0; USBH_ClassDrvList[ix].NotifyArgPtr = (void *)0; USBH_ClassDrvList[ix].InUse = 0u; } err = USBH_ClassDrvReg( &USBH_HUB_Drv, /* Reg HUB class drv. */ USBH_HUB_ClassNotify, (void *)0); if (err != USBH_ERR_NONE) { return (err); } err = USBH_OS_SemCreate((USBH_HSEM *)&USBH_URB_Sem, /* Create a Semaphore for sync I/O req. */ 0u); if (err != USBH_ERR_NONE) { return (err); } /* Create a task for processing async req. */ err = USBH_OS_TaskCreate( "USBH_Asynctask", async_task_info->Prio, USBH_AsyncTask, (void *)0, (CPU_INT32U *)async_task_info->StackPtr, async_task_info->StackSize, &USBH_Host.HAsyncTask); if (err != USBH_ERR_NONE) { return (err); } /* Create a task for processing hub events. */ err = USBH_OS_TaskCreate( "USBH_HUB_EventTask", hub_task_info->Prio, USBH_HUB_EventTask, (void *)0, (CPU_INT32U *)hub_task_info->StackPtr, hub_task_info->StackSize, &USBH_Host.HHubTask); if (err != USBH_ERR_NONE) { return (err); } for (ix = 0u; ix < USBH_MAX_NBR_DEVS; ix++) { /* Init USB dev list. */ USBH_Host.DevList[ix].DevAddr = ix + 1; /* USB addr is ix + 1. Addr 0 is rsvd. */ err = USBH_OS_MutexCreate(&USBH_Host.DevList[ix].DfltEP_Mutex); if (err != USBH_ERR_NONE) { USBH_PRINT_ERR(err); return (err); } } Mem_PoolCreate ( &USBH_Host.IsocDescPool, /* Create mem pool for USB isoc desc struct. */ (void *)USBH_Host.IsocDesc, sizeof(USBH_Host.IsocDesc), USBH_CFG_MAX_ISOC_DESC, sizeof(USBH_ISOC_DESC), sizeof(CPU_ALIGN), &octets_reqd, &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { return (USBH_ERR_ALLOC); } Mem_PoolCreate ( &USBH_Host.DevPool, /* Create mem pool for USB device struct. */ (void *)USBH_Host.DevList, sizeof(USBH_Host.DevList), USBH_MAX_NBR_DEVS, sizeof(USBH_DEV), sizeof(CPU_ALIGN), &octets_reqd, &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { return (USBH_ERR_ALLOC); } Mem_PoolCreate ( &USBH_Host.AsyncURB_Pool, /* Create mem pool for extra URB used in async comm. */ (void *)0, (USBH_CFG_MAX_NBR_DEVS * USBH_CFG_MAX_EXTRA_URB_PER_DEV * sizeof(USBH_URB)), (USBH_CFG_MAX_NBR_DEVS * USBH_CFG_MAX_EXTRA_URB_PER_DEV), sizeof(USBH_URB), sizeof(CPU_ALIGN), &octets_reqd, &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { return (USBH_ERR_ALLOC); } err = USBH_ERR_NONE; return (err); } /* ********************************************************************************************************* * USBH_Suspend() * * Description : Suspends USB Host Stack by calling suspend for every class driver loaded * and then calling the host controller suspend. * * Argument(s) : None. * * Return(s) : USBH_ERR_NONE If host is suspended. * Host controller driver error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_Suspend (void) { CPU_INT08U ix; USBH_HC *hc; USBH_ERR err; for (ix = 0u; ix < USBH_Host.HC_NbrNext; ix++) { hc = &USBH_Host.HC_Tbl[ix]; USBH_ClassSuspend(hc->HC_Drv.RH_DevPtr); /* Suspend RH, and all downstream dev. */ USBH_HCD_Suspend(hc, &err); /* Suspend HC. */ } USBH_Host.State = USBH_HOST_STATE_SUSPENDED; return (err); } /* ********************************************************************************************************* * USBH_Resume() * * Description : Resumes USB Host Stack by calling host controller resume and then * calling resume for every class driver loaded. * * Argument(s) : None. * * Return(s) : USBH_ERR_NONE, If host is resumed. * Host controller driver error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_Resume (void) { CPU_INT08U ix; USBH_HC *hc; USBH_ERR err; for (ix = 0u; ix < USBH_Host.HC_NbrNext; ix++) { hc = &USBH_Host.HC_Tbl[ix]; USBH_HCD_Resume(hc, &err); /* Resume HC. */ USBH_ClassResume(hc->HC_Drv.RH_DevPtr); /* Resume RH, and all downstream dev. */ } USBH_Host.State = USBH_HOST_STATE_RESUMED; return (err); } /* ********************************************************************************************************* * USBH_HC_Add() * * Description : Add a host controller. * * Argument(s) : p_hc_cfg Pointer to specific USB host controller configuration. * * p_drv_api Pointer to specific USB host controller driver API. * * p_hc_rh_api Pointer to specific USB host controller root hub driver API. * * p_hc_bsp_api Pointer to specific USB host controller board-specific API. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Host controller successfully added. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_hc_cfg' / 'p_drv_api' / * 'p_hc_rh_api' / 'p_hc_bsp_api'. * USBH_ERR_HC_ALLOC Maximum number of host controller reached. * USBH_ERR_DEV_ALLOC Cannot allocate device structure for root hub. * Host controller driver error, Otherwise. * * ----- RETURNED BY USBH_OS_MutexCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, if mutex creation failed. * * Return(s) : Host Controller index, if host controller successfully added. * USBH_HC_NBR_NONE, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT08U USBH_HC_Add (USBH_HC_CFG *p_hc_cfg, USBH_HC_DRV_API *p_drv_api, USBH_HC_RH_API *p_hc_rh_api, USBH_HC_BSP_API *p_hc_bsp_api, USBH_ERR *p_err) { USBH_DEV *p_rh_dev; CPU_INT08U hc_nbr; LIB_ERR err_lib; USBH_HC *p_hc; USBH_HC_DRV *p_hc_drv; CPU_SR_ALLOC(); if ((p_hc_cfg == (USBH_HC_CFG *)0) || /* ------------------ VALIDATE ARGS ------------------- */ (p_drv_api == (USBH_HC_DRV_API *)0) || (p_hc_rh_api == (USBH_HC_RH_API *)0) || (p_hc_bsp_api == (USBH_HC_BSP_API *)0)) { *p_err = USBH_ERR_INVALID_ARG; return (USBH_HC_NBR_NONE); } CPU_CRITICAL_ENTER(); hc_nbr = USBH_Host.HC_NbrNext; if (hc_nbr >= USBH_CFG_MAX_NBR_HC) { /* Chk if HC nbr is valid. */ CPU_CRITICAL_EXIT(); *p_err = USBH_ERR_HC_ALLOC; return (USBH_HC_NBR_NONE); } USBH_Host.HC_NbrNext++; CPU_CRITICAL_EXIT(); p_hc = &USBH_Host.HC_Tbl[hc_nbr]; p_hc_drv = &p_hc->HC_Drv; /* Alloc dev struct for RH. */ p_rh_dev = (USBH_DEV *)Mem_PoolBlkGet( &USBH_Host.DevPool, (CPU_SIZE_T)sizeof(USBH_DEV), &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { *p_err = USBH_ERR_DEV_ALLOC; return (USBH_HC_NBR_NONE); } p_rh_dev->IsRootHub = (CPU_BOOLEAN)DEF_TRUE; p_rh_dev->HC_Ptr = p_hc; p_hc->HostPtr = &USBH_Host; if (p_hc_rh_api == (USBH_HC_RH_API *)0) { p_hc->IsVirRootHub = DEF_FALSE; } else { p_hc->IsVirRootHub = DEF_TRUE; } p_hc_drv->HC_CfgPtr = p_hc_cfg; p_hc_drv->DataPtr = (void *)0; p_hc_drv->RH_DevPtr = p_rh_dev; p_hc_drv->API_Ptr = p_drv_api; p_hc_drv->BSP_API_Ptr = p_hc_bsp_api; p_hc_drv->RH_API_Ptr = p_hc_rh_api; p_hc_drv->Nbr = hc_nbr; *p_err = USBH_OS_MutexCreate(&p_hc->HCD_Mutex); /* Create mutex to sync access to HCD. */ if (*p_err != USBH_ERR_NONE) { return (USBH_HC_NBR_NONE); } USBH_HCD_Init(p_hc, p_err); /* Init HCD. */ if (*p_err != USBH_ERR_NONE) { return (USBH_HC_NBR_NONE); } USBH_HCD_SpdGet(p_hc, &p_rh_dev->DevSpd, p_err); return (hc_nbr); } /* ********************************************************************************************************* * USBH_HC_Start() * * Description : Start given host controller. * * Argument(s) : hc_nbr Host controller number. * * Return(s) : USBH_ERR_NONE If host controller successfully started. * USBH_ERR_INVALID_ARG If invalid argument passed to 'hc_nbr'. * Host controller driver error, Otherwise. * * ----- RETURNED BY USBH_DevConn() : ----- * USBH_ERR_DESC_INVALID If device contains 0 configurations * USBH_ERR_CFG_ALLOC If maximum number of configurations reached. * USBH_ERR_DESC_INVALID, If invalid descriptor was fetched. * USBH_ERR_CFG_MAX_CFG_LEN, If cannot allocate descriptor * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * USBH_ERR_DRIVER_NOT_FOUND If no class driver was found. * USBH_ERR_OS_SIGNAL_CREATE, If semaphore or mutex creation failed. * Host controller driver error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_HC_Start (CPU_INT08U hc_nbr) { USBH_ERR err; USBH_HC *p_hc; USBH_DEV *p_rh_dev; if (hc_nbr >= USBH_Host.HC_NbrNext) { /* Chk if HC nbr is valid. */ return (USBH_ERR_INVALID_ARG); } p_hc = &USBH_Host.HC_Tbl[hc_nbr]; p_rh_dev = p_hc->HC_Drv.RH_DevPtr; err = USBH_DevConn(p_rh_dev); /* Add RH of given HC. */ if (err == USBH_ERR_NONE) { USBH_Host.State = USBH_HOST_STATE_RESUMED; } else { USBH_DevDisconn(p_rh_dev); } USBH_HCD_Start(p_hc, &err); return (err); } /* ********************************************************************************************************* * USBH_HC_Stop() * * Description : Stop the given host controller. * * Argument(s) : hc_nbr Host controller number. * * Return(s) : USBH_ERR_NONE, If host controller successfully stoped. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'hc_nbr'. * Host controller driver error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_HC_Stop (CPU_INT08U hc_nbr) { USBH_ERR err; USBH_HC *p_hc; USBH_DEV *p_rh_dev; if (hc_nbr >= USBH_Host.HC_NbrNext) { /* Chk if HC nbr is valid. */ return (USBH_ERR_INVALID_ARG); } p_hc = &USBH_Host.HC_Tbl[hc_nbr]; p_rh_dev = p_hc->HC_Drv.RH_DevPtr; USBH_HCD_Stop(p_hc, &err); USBH_DevDisconn(p_rh_dev); /* Disconn RH dev. */ return (err); } /* ********************************************************************************************************* * USBH_HC_PortEn() * * Description : Enable given port of given host controller's root hub. * * Argument(s) : hc_nbr Host controller number. * * port_nbr Port number. * * Return(s) : USBH_ERR_NONE, If port successfully enabled. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'hc_nbr'. * * ----- RETURNED BY USBH_HUB_PortEn() : ----- * USBH_ERR_INVALID_ARG, If invalid parameter passed to 'p_hub_dev'. * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_HC_PortEn (CPU_INT08U hc_nbr, CPU_INT08U port_nbr) { USBH_ERR err; USBH_HC *p_hc; if (hc_nbr >= USBH_Host.HC_NbrNext) { /* Chk if HC nbr is valid. */ return (USBH_ERR_INVALID_ARG); } p_hc = &USBH_Host.HC_Tbl[hc_nbr]; err = USBH_HUB_PortEn(p_hc->RH_ClassDevPtr, port_nbr); return (err); } /* ********************************************************************************************************* * USBH_HC_PortDis() * * Description : Disable given port of given host controller's root hub. * * Argument(s) : hc_nbr Host controller number. * * port_nbr Port number. * * Return(s) : USBH_ERR_NONE, If port successfully disabled. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'hc_nbr'. * * ----- RETURNED BY USBH_HUB_PortDis() : ----- * USBH_ERR_INVALID_ARG, If invalid parameter passed to 'p_hub_dev'. * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : None ********************************************************************************************************* */ USBH_ERR USBH_HC_PortDis (CPU_INT08U hc_nbr, CPU_INT08U port_nbr) { USBH_ERR err; USBH_HC *p_hc; if (hc_nbr >= USBH_Host.HC_NbrNext) { /* Chk if HC nbr is valid. */ return (USBH_ERR_INVALID_ARG); } p_hc = &USBH_Host.HC_Tbl[hc_nbr]; err = USBH_HUB_PortDis(p_hc->RH_ClassDevPtr, port_nbr); return (err); } /* ********************************************************************************************************* * USBH_HC_FrameNbrGet() * * Description : Get current frame number. * * Argument(s) : hc_nbr Index of Host Controller. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Frame number successfully fetched. * USBH_ERR_INVALID_ARG Invalid argument passed to hc_nbr. * Host controller drivers error code, Otherwise. * * Return(s) : Curent frame number processed by Host Controller, If success. * 0, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_HC_FrameNbrGet (CPU_INT08U hc_nbr, USBH_ERR *p_err) { CPU_INT32U frame_nbr; USBH_HC *p_hc; if (hc_nbr >= USBH_Host.HC_NbrNext) { /* Chk if HC nbr is valid. */ *p_err = USBH_ERR_INVALID_ARG; return (0u); } p_hc = &USBH_Host.HC_Tbl[hc_nbr]; USBH_HCD_FrmNbrGet(p_hc, &frame_nbr, p_err); return (frame_nbr); } /* ********************************************************************************************************* ********************************************************************************************************* * DEVICE ENUMERATION FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * USBH_DevConn() * * Description : Enumerates newly connected USB device. Reads device and configuration descriptor from * device and loads appropriate class driver(s). * * Argument(s) : p_dev Pointer to USB device structure. * * Return(s) : USBH_ERR_NONE If device connection is successful. * USBH_ERR_DESC_INVALID If device contains 0 configurations * USBH_ERR_CFG_ALLOC If maximum number of configurations reached. * * ----- RETURNED BY USBH_CfgRd() : ----- * USBH_ERR_DESC_INVALID, If invalid configuration descriptor was fetched. * USBH_ERR_CFG_MAX_CFG_LEN, If configuration descriptor length > USBH_CFG_MAX_CFG_DATA_LEN * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * ----- RETURNED BY USBH_CDC_RespRx() : ----- * USBH_ERR_DESC_INVALID, If an invalid device descriptor was fetched. * USBH_ERR_DEV_NOT_RESPONDING, If device is not responding. * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * ----- RETURNED BY USBH_DevAddrSet() : ----- * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * * ----- RETURNED BY USBH_ClassDrvConn() : ----- * USBH_ERR_DRIVER_NOT_FOUND If no class driver was found. * USBH_ERR_UNKNOWN Unknown error occurred. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * ----- RETURNED BY USBH_DfltEP_Open() : ----- * USBH_ERR_OS_SIGNAL_CREATE, If semaphore or mutex creation failed. * Host controller driver error, Otherwise. * * -------- RETURNED BY USBH_CfgRd() : -------- * USBH_ERR_NULL_PTR If configuration read returns a null pointer. * Host controller driver error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_DevConn (USBH_DEV *p_dev) { USBH_ERR err; CPU_INT08U nbr_cfgs; CPU_INT08U cfg_ix; p_dev->SelCfg = 0u; p_dev->ClassDrvRegPtr = (USBH_CLASS_DRV_REG *)0; Mem_Clr(p_dev->DevDesc, USBH_LEN_DESC_DEV); err = USBH_DfltEP_Open(p_dev); if (err != USBH_ERR_NONE) { return (err); } err = USBH_DevDescRd(p_dev); /* ------------------- RD DEV DESC -------------------- */ if (err != USBH_ERR_NONE) { return (err); } err = USBH_DevAddrSet(p_dev); /* -------------- ASSIGN NEW ADDR TO DEV -------------- */ if (err != USBH_ERR_NONE) { return (err); } #if (USBH_CFG_PRINT_LOG == DEF_ENABLED) USBH_PRINT_LOG("Port %d: Device Address: %d Speed: %cS.\r\n", p_dev->PortNbr, p_dev->DevAddr, "NLFH"[p_dev->DevSpd]); #endif #if (USBH_CFG_PRINT_LOG == DEF_ENABLED) /* -------- PRINT MANUFACTURER AND PRODUCT STR -------- */ if(p_dev->DevDesc[14] != 0u) { /* iManufacturer = 0 -> no str desc for manufacturer. */ USBH_StrDescPrint( p_dev, (CPU_INT08U *)"Manufacturer : ", p_dev->DevDesc[14]); } if(p_dev->DevDesc[15] != 0u) { /* iProduct = 0 -> no str desc for product. */ USBH_StrDescPrint( p_dev, (CPU_INT08U *)"Product : ", p_dev->DevDesc[15]); } #endif nbr_cfgs = USBH_DevCfgNbrGet(p_dev); /* ---------- GET NBR OF CFG PRESENT IN DEV ----------- */ if (nbr_cfgs == 0u) { return (USBH_ERR_DESC_INVALID); } else if (nbr_cfgs > USBH_CFG_MAX_NBR_CFGS) { return (USBH_ERR_CFG_ALLOC); } else { /* Empty Else Statement */ } for (cfg_ix = 0u; cfg_ix < nbr_cfgs; cfg_ix++) { /* -------------------- RD ALL CFG -------------------- */ err = USBH_CfgRd(p_dev, cfg_ix); if (err != USBH_ERR_NONE) { return (err); } } err = USBH_ClassDrvConn(p_dev); /* ------------- PROBE/LOAD CLASS DRV(S) -------------- */ return (err); } /* ********************************************************************************************************* * USBH_DevDisconn() * * Description : Unload class drivers & close default endpoint. * * Argument(s) : p_dev Pointer to USB device structure. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ void USBH_DevDisconn (USBH_DEV *p_dev) { USBH_ClassDrvDisconn(p_dev); /* Unload class drv(s). */ USBH_EP_Close(&p_dev->DfltEP); /* Close dflt EPs. */ } /* ********************************************************************************************************* * USBH_DevCfgNbrGet() * * Description : Get number of configurations supported by specified device. * * Argument(s) : p_dev Pointer to USB device. * * Return(s) : Number of configurations. * * Note(s) : (1) USB2.0 spec, section 9.6.1 states that offset 17 of standard device descriptor * contains number of configurations. ********************************************************************************************************* */ CPU_INT08U USBH_DevCfgNbrGet (USBH_DEV *p_dev) { return (p_dev->DevDesc[17]); /* See Note (1). */ } /* ********************************************************************************************************* * USBH_DevDescGet() * * Description : Get device descriptor of specified USB device. * * Argument(s) : p_dev Pointer to USB device. * * p_dev_desc Pointer to device descriptor. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ void USBH_DevDescGet (USBH_DEV *p_dev, USBH_DEV_DESC *p_dev_desc) { USBH_ParseDevDesc( p_dev_desc, (void *)p_dev->DevDesc); } /* ********************************************************************************************************* * USBH_CfgSet() * * Description : Select a configration in specified device. * * Argument(s) : p_dev Pointer to USB device * * cfg_nbr Configuration number to be selected * * Return(s) : USBH_ERR_NONE, If given configuration was successfully selected. * * ----- RETURNED BY USBH_SET_CFG() : ----- * USBH_ERR_UNKNOWN Unknown error occurred. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : (1) (a) The SET_CONFIGURATION request is described in "Universal Serial Bus Specification * Revision 2.0", section 9.4.6. * * (b) If the device is in the default state, the behaviour of the device is not * specified. Implementations stall such request. * * (c) If the device is in the addressed state & * * (1) ... the configuration number is zero, then the device remains in the address state. * (2) ... the configuration number is non-zero & matches a valid configuration * number, then that configuration is selected & the device enters the * configured state. * (3) ... the configuration number is non-zero & does NOT match a valid configuration * number, then the device responds with a request error. * * (d) If the device is in the configured state & * * (1) ... the configuration number is zero, then the device enters the address state. * (2) ... the configuration number is non-zero & matches a valid configuration * number, then that configuration is selected & the device remains in the * configured state. * (3) ... the configuration number is non-zero & does NOT match a valid configuration * number, then the device responds with a request error. ********************************************************************************************************* */ USBH_ERR USBH_CfgSet (USBH_DEV *p_dev, CPU_INT08U cfg_nbr) { USBH_ERR err; USBH_SET_CFG(p_dev, cfg_nbr, &err); /* See Note (1). */ if (err == USBH_ERR_NONE) { p_dev->SelCfg = cfg_nbr; } return (err); } /* ********************************************************************************************************* * USBH_CfgGet() * * Description : Get a pointer to specified configuration data of specified device. * * Argument(s) : p_dev Pointer to USB device. * * cfg_ix Zero based index of configuration. * * Return(s) : Pointer to configuration, If configuration number is valid. * 0, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_CFG *USBH_CfgGet (USBH_DEV *p_dev, CPU_INT08U cfg_ix) { CPU_INT08U nbr_cfgs; if (p_dev == (USBH_DEV *)0) { return ((USBH_CFG *)0); } nbr_cfgs = USBH_DevCfgNbrGet(p_dev); /* Get nbr of cfg(s) present in dev. */ if ((cfg_ix >= nbr_cfgs) || (nbr_cfgs == 0u)) { return ((USBH_CFG *)0); } return (&p_dev->CfgList[cfg_ix]); /* Get cfg struct. */ } /* ********************************************************************************************************* * USBH_CfgIF_NbrGet() * * Description : Get number of interfaces in given configuration. * * Argument(s) : p_cfg Pointer to configuration * * Return(s) : Number of interfaces. * * Note(s) : (1) USB2.0 spec, section 9.6.1 states that offset 4 of standard configuration descriptor * represents number of interfaces in the configuration. ********************************************************************************************************* */ CPU_INT08U USBH_CfgIF_NbrGet (USBH_CFG *p_cfg) { if (p_cfg != (USBH_CFG *)0) { return (p_cfg->CfgData[4]); /* See Note (1). */ } else { return (0u); } } /* ********************************************************************************************************* * USBH_CfgDescGet() * * Description : Get configuration descriptor data. * * Argument(s) : p_cfg Pointer to USB configuration * * p_cfg_desc Pointer to a variable that will contain configuration descriptor. * * Return(s) : USBH_ERR_NONE If a valid configuration descriptor is found. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_cfg' / 'p_cfg_desc'. * USBH_ERR_DESC_INVALID If an invalid configuration descriptor was found. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_CfgDescGet (USBH_CFG *p_cfg, USBH_CFG_DESC *p_cfg_desc) { USBH_DESC_HDR *p_desc; if ((p_cfg == (USBH_CFG *)0) || (p_cfg_desc == (USBH_CFG_DESC *)0)) { return (USBH_ERR_INVALID_ARG); } p_desc = (USBH_DESC_HDR *)p_cfg->CfgData; /* Check for valid cfg desc. */ if ((p_desc->bLength == USBH_LEN_DESC_CFG ) && (p_desc->bDescriptorType == USBH_DESC_TYPE_CFG)) { USBH_ParseCfgDesc( p_cfg_desc, (void *)p_desc); return (USBH_ERR_NONE); } else { return (USBH_ERR_DESC_INVALID); } } /* ********************************************************************************************************* * USBH_CfgExtraDescGet() * * Description : Get extra descriptor immediately following configuration descriptor. * * Argument(s) : p_cfg Pointer to USB configuration. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE, If a valid extra descriptor is present. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_cfg'. * USBH_ERR_DESC_EXTRA_NOT_FOUND, If extra descriptor is not present. * * Return(s) : Pointer to extra descriptor, If a valid extra descriptor is present. * 0, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_DESC_HDR *USBH_CfgExtraDescGet(USBH_CFG *p_cfg, USBH_ERR *p_err) { USBH_DESC_HDR *p_desc; USBH_DESC_HDR *p_extra_desc; CPU_INT32U cfg_off; if (p_cfg == (USBH_CFG *)0) { *p_err = USBH_ERR_INVALID_ARG; return ((USBH_DESC_HDR *)0); } p_desc = (USBH_DESC_HDR *)p_cfg->CfgData; /* Get config desc data. */ if ((p_desc->bLength == USBH_LEN_DESC_CFG ) && (p_desc->bDescriptorType == USBH_DESC_TYPE_CFG) && (p_cfg->CfgDataLen > (p_desc->bLength + 2u))) { cfg_off = p_desc->bLength; p_extra_desc = USBH_NextDescGet(p_desc, &cfg_off); /* Get desc that follows config desc. */ /* No extra desc present. */ if (p_extra_desc->bDescriptorType != USBH_DESC_TYPE_IF) { *p_err = USBH_ERR_NONE; return (p_extra_desc); } } *p_err = USBH_ERR_DESC_EXTRA_NOT_FOUND; return ((USBH_DESC_HDR *)0); } /* ********************************************************************************************************* * USBH_IF_Set() * * Description : Select specified alternate setting of interface. * * Argument(s) : p_if Pointer to interface. * * alt_nbr Alternate setting number to select. * * Return(s) : USBH_ERR_NONE, If specified alternate setting was successfully selected. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_if' / 'alt_nbr'. * * ----- RETURNED BY USBH_CtrlTx() : ----- * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : (1) The standard SET_INTERFACE request is defined in the Universal Serial Bus * specification revision 2.0, section 9.4.10 ********************************************************************************************************* */ USBH_ERR USBH_IF_Set (USBH_IF *p_if, CPU_INT08U alt_nbr) { CPU_INT08U nbr_alts; CPU_INT08U if_nbr; USBH_DEV *p_dev; USBH_ERR err; if (p_if == (USBH_IF *)0) { return (USBH_ERR_INVALID_ARG); } nbr_alts = USBH_IF_AltNbrGet(p_if); /* Get nbr of alternate settings in IF. */ if (alt_nbr >= nbr_alts) { return (USBH_ERR_INVALID_ARG); } if_nbr = USBH_IF_NbrGet(p_if); /* Get IF nbr. */ p_dev = p_if->DevPtr; USBH_SET_IF(p_dev, if_nbr, alt_nbr, &err); /* See Note (1). */ if (err != USBH_ERR_NONE) { return (err); } p_if->AltIxSel = alt_nbr; /* Update selected alternate setting. */ return (err); } /* ********************************************************************************************************* * USBH_IF_Get() * * Description : Get specified interface from given configuration. * * Argument(s) : p_cfg Pointer to configuration. * * if_ix Zero based index of the Interface. * * Return(s) : Pointer to interface data, If interface number is valid. * 0, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_IF *USBH_IF_Get (USBH_CFG *p_cfg, CPU_INT08U if_ix) { CPU_INT08U nbr_ifs; nbr_ifs = USBH_CfgIF_NbrGet(p_cfg); /* Get nbr of IFs. */ if ((if_ix < nbr_ifs) && (if_ix < USBH_CFG_MAX_NBR_IFS)) { return (&p_cfg->IF_List[if_ix]); /* Return IF structure at selected ix. */ } else { return ((USBH_IF *)0); } } /* ********************************************************************************************************* * USBH_IF_AltNbrGet() * * Description : Get number of alternate settings supported by the given interface. * * Argument(s) : p_if Pointer to interface. * * Return(s) : Number of alternate settings. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT08U USBH_IF_AltNbrGet (USBH_IF *p_if) { USBH_DESC_HDR *p_desc; CPU_INT32U if_off; CPU_INT08U nbr_alts; nbr_alts = 0u; if_off = 0u; p_desc = (USBH_DESC_HDR *)p_if->IF_DataPtr; while (if_off < p_if->IF_DataLen) { /* Cnt nbr of alternate settings. */ p_desc = USBH_NextDescGet((void *)p_desc, &if_off); if (p_desc->bDescriptorType == USBH_DESC_TYPE_IF) { nbr_alts++; } } return (nbr_alts); } /* ********************************************************************************************************* * USBH_IF_NbrGet() * * Description : Get number of given interface. * * Argument(s) : p_if Pointer to interface. * * Return(s) : Interface number. * * Note(s) : (1) USB2.0 spec, section 9.6.5 states that offset 2 (bInterfaceNumber) of standard * interface descriptor contains the interface number of this interface. ********************************************************************************************************* */ CPU_INT08U USBH_IF_NbrGet (USBH_IF *p_if) { return (p_if->IF_DataPtr[2]); /* See Note (1) */ } /* ********************************************************************************************************* * USBH_IF_EP_NbrGet() * * Description : Determine number of endpoints in given alternate setting of interface. * * Argument(s) : p_if Pointer to interface. * * alt_ix Alternate setting index. * * Return(s) : Number of endpoints. * * Note(s) : (1) USB2.0 spec, section 9.6.5 states that offset 4 of standard interface descriptor * (bNumEndpoints) contains the number of endpoints in this interface descriptor. ********************************************************************************************************* */ CPU_INT08U USBH_IF_EP_NbrGet (USBH_IF *p_if, CPU_INT08U alt_ix) { USBH_DESC_HDR *p_desc; CPU_INT32U if_off; if_off = 0u; p_desc = (USBH_DESC_HDR *)p_if->IF_DataPtr; while (if_off < p_if->IF_DataLen) { p_desc = USBH_NextDescGet((void *)p_desc, &if_off); /* IF desc. */ if (p_desc->bDescriptorType == USBH_DESC_TYPE_IF) { if (alt_ix == ((CPU_INT08U *)p_desc)[3]) { /* Chk alternate setting. */ return (((CPU_INT08U *)p_desc)[4]); /* IF desc offset 4 contains nbr of EPs. */ } } } return (0u); } /* ********************************************************************************************************* * USBH_IF_DescGet() * * Description : Get descriptor of interface at specified alternate setting index. * * Argument(s) : p_if Pointer to USB interface. * * alt_ix Alternate setting index. * * p_if_desc Pointer to a variable to hold the interface descriptor data. * * Return(s) : USBH_ERR_NONE If interface descritor was found. * USBH_ERR_INVALID_ARG Invalid argument passed to 'alt_ix'. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_IF_DescGet (USBH_IF *p_if, CPU_INT08U alt_ix, USBH_IF_DESC *p_if_desc) { USBH_DESC_HDR *p_desc; CPU_INT32U if_off; if_off = 0u; p_desc = (USBH_DESC_HDR *)p_if->IF_DataPtr; while (if_off < p_if->IF_DataLen) { p_desc = USBH_NextDescGet((void *)p_desc, &if_off); if ((p_desc->bLength == USBH_LEN_DESC_IF ) && (p_desc->bDescriptorType == USBH_DESC_TYPE_IF) && (alt_ix == ((CPU_INT08U *)p_desc)[3])) { USBH_ParseIF_Desc(p_if_desc, (void *)p_desc); return (USBH_ERR_NONE); } } return (USBH_ERR_INVALID_ARG); } /* ********************************************************************************************************* * USBH_IF_ExtraDescGet() * * Description : Get the descriptor immediately following the interface descriptor. * * Argument(s) : p_if Pointer to USB interface. * * alt_ix Alternate setting number. * * p_data_len Length of extra interface descriptor. * * Return(s) : Pointer to extra descriptor, If success. * 0, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT08U *USBH_IF_ExtraDescGet (USBH_IF *p_if, CPU_INT08U alt_ix, CPU_INT16U *p_data_len) { USBH_DESC_HDR *p_desc; CPU_INT08U *p_data; CPU_INT32U if_off; if ((p_if == (USBH_IF *)0) || (p_if->IF_DataPtr == (CPU_INT08U *)0)) { return ((CPU_INT08U *)0); } if_off = 0u; p_desc = (USBH_DESC_HDR *)p_if->IF_DataPtr; while (if_off < p_if->IF_DataLen) { p_desc = USBH_NextDescGet((void* )p_desc, &if_off); /* Get next desc from IF. */ if ((p_desc->bLength == USBH_LEN_DESC_IF ) && (p_desc->bDescriptorType == USBH_DESC_TYPE_IF) && (alt_ix == ((CPU_INT08U *)p_desc)[3])) { if (if_off < p_if->IF_DataLen) { /* Get desc that follows selected alternate setting. */ p_desc = USBH_NextDescGet((void *)p_desc, &if_off); p_data = (CPU_INT08U *)p_desc; *p_data_len = 0u; while ((p_desc->bDescriptorType != USBH_DESC_TYPE_IF) && (p_desc->bDescriptorType != USBH_DESC_TYPE_EP)) { *p_data_len += p_desc->bLength; p_desc = USBH_NextDescGet((void* )p_desc, /* Get next desc from IF. */ &if_off); if (if_off >= p_if->IF_DataLen) { break; } } if (*p_data_len == 0) { return ((CPU_INT08U *)0); } else { return ((CPU_INT08U *)p_data); } } } } return ((CPU_INT08U *)0); } /* ********************************************************************************************************* * USBH_BulkInOpen() * * Description : Open a bulk IN endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to USB interface. * * p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE If the bulk IN endpoint is opened successfully. * * ----- RETURNED BY USBH_EP_Open() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_BulkInOpen (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP *p_ep) { USBH_ERR err; err = USBH_EP_Open(p_dev, p_if, USBH_EP_TYPE_BULK, USBH_EP_DIR_IN, p_ep); return (err); } /* ********************************************************************************************************* * USBH_BulkOutOpen() * * Description : Open a bulk OUT endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to USB interface. * * p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE If the bulk OUT endpoint is opened successfully. * * ----- RETURNED BY USBH_EP_Open() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_BulkOutOpen (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP *p_ep) { USBH_ERR err; err = USBH_EP_Open(p_dev, p_if, USBH_EP_TYPE_BULK, USBH_EP_DIR_OUT, p_ep); return (err); } /* ********************************************************************************************************* * USBH_IntrInOpen() * * Description : Open an interrupt IN endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to USB interface. * * p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE If the interrupt IN endpoint is opened successfully. * * ----- RETURNED BY USBH_EP_Open() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_IntrInOpen (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP *p_ep) { USBH_ERR err; err = USBH_EP_Open(p_dev, p_if, USBH_EP_TYPE_INTR, USBH_EP_DIR_IN, p_ep); return (err); } /* ********************************************************************************************************* * USBH_IntrOutOpen() * * Description : Open and interrupt OUT endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to USB interface. * * p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE If the interrupt OUT endpoint is opened successfully. * * ----- RETURNED BY USBH_EP_Open() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_IntrOutOpen (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP *p_ep) { USBH_ERR err; err = USBH_EP_Open(p_dev, p_if, USBH_EP_TYPE_INTR, USBH_EP_DIR_OUT, p_ep); return (err); } /* ********************************************************************************************************* * USBH_IsocInOpen() * * Description : Open an isochronous IN endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to USB interface. * * p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE If the isochronous IN endpoint is opened successfully. * * ----- RETURNED BY USBH_EP_Open() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_IsocInOpen (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP *p_ep) { USBH_ERR err; err = USBH_EP_Open(p_dev, p_if, USBH_EP_TYPE_ISOC, USBH_EP_DIR_IN, p_ep); return (err); } /* ********************************************************************************************************* * USBH_IsocOutOpen() * * Description : Open an isochronous OUT endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to USB interface. * * p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE If the isochronous OUT endpoint is opened successfully. * * ----- RETURNED BY USBH_EP_Open() : ----- * USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found. * USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed. * Host controller drivers error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_IsocOutOpen (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP *p_ep) { USBH_ERR err; err = USBH_EP_Open(p_dev, p_if, USBH_EP_TYPE_ISOC, USBH_EP_DIR_OUT, p_ep); return (err); } /* ********************************************************************************************************* * USBH_CtrlTx() * * Description : Issue control request to device and send data to it. * * Argument(s) : p_dev Pointer to USB device. * * b_req One-byte value that specifies request. * * bm_req_type One-byte value that specifies direction, type and the recipient of * request. * * w_val Two-byte value used to pass information to device. * * w_ix Two-byte value used to pass an index or offset (such as interface or * endpoint number) to device. * * p_data Pointer to data buffer to transmit. * * w_len Two-byte value containing buffer length in octets. * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * USBH_ERR_NONE Control transfer successfully transmitted. * * ----- RETURNED BY USBH_SyncCtrlXfer() : ----- * USBH_ERR_NONE Control transfer successfully completed. * USBH_ERR_UNKNOWN Unknown error occurred. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * Host controller drivers error code, Otherwise. * * ----- RETURNED BY USBH_HUB_RHCtrlReq() : ----- * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * * Return(s) : Number of octets transmitted. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT16U USBH_CtrlTx (USBH_DEV *p_dev, CPU_INT08U b_req, CPU_INT08U bm_req_type, CPU_INT16U w_val, CPU_INT16U w_ix, void *p_data, CPU_INT16U w_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT16U xfer_len; (void)USBH_OS_MutexLock(p_dev->DfltEP_Mutex); if ((p_dev->IsRootHub == DEF_TRUE) && /* Check if RH features are supported. */ (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE)) { xfer_len = USBH_HUB_RH_CtrlReq(p_dev->HC_Ptr, /* Send req to virtual HUB. */ b_req, bm_req_type, w_val, w_ix, p_data, w_len, p_err); } else { xfer_len = USBH_SyncCtrlXfer(&p_dev->DfltEP, b_req, bm_req_type, w_val, w_ix, p_data, w_len, timeout_ms, p_err); } (void)USBH_OS_MutexUnlock(p_dev->DfltEP_Mutex); return (xfer_len); } /* ********************************************************************************************************* * USBH_CtrlRx() * * Description : Issue control request to device and receive data from it. * * Argument(s) : p_dev Pointer to USB device. * * b_req One-byte value that specifies request. * * bm_req_type One-byte value that specifies direction, type and the recipient of * request. * * w_val Two-byte value used to pass information to device. * * w_ix Two-byte value used to pass an index or offset (such as interface or * endpoint number) to device. * * p_data Pointer to destination buffer to receive data. * * w_len Two-byte value containing buffer length in octets. * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Control transfer successfully received. * * ----- RETURNED BY USBH_SyncCtrlXfer() : ----- * USBH_ERR_NONE Control transfer successfully completed. * USBH_ERR_UNKNOWN Unknown error occurred. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * Host controller drivers error code, Otherwise. * * ----- RETURNED BY USBH_HUB_RHCtrlReq() : ----- * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * * Return(s) : Number of octets received. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT16U USBH_CtrlRx (USBH_DEV *p_dev, CPU_INT08U b_req, CPU_INT08U bm_req_type, CPU_INT16U w_val, CPU_INT16U w_ix, void *p_data, CPU_INT16U w_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT16U xfer_len; (void)USBH_OS_MutexLock(p_dev->DfltEP_Mutex); if ((p_dev->IsRootHub == DEF_TRUE) && /* Check if RH features are supported. */ (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE)) { xfer_len = USBH_HUB_RH_CtrlReq(p_dev->HC_Ptr, /* Send req to virtual HUB. */ b_req, bm_req_type, w_val, w_ix, p_data, w_len, p_err); } else { xfer_len = USBH_SyncCtrlXfer(&p_dev->DfltEP, b_req, bm_req_type, w_val, w_ix, p_data, w_len, timeout_ms, p_err); } (void)USBH_OS_MutexUnlock(p_dev->DfltEP_Mutex); return (xfer_len); } /* ********************************************************************************************************* * USBH_BulkTx() * * Description : Issue bulk request to transmit data to device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Bulk transfer successfully transmitted. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not OUT. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_NONE, URB is successfully submitted to host controller. * Host controller drivers error code, Otherwise. * * Return(s) : Number of octets transmitted. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_BulkTx (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT08U ep_type; CPU_INT08U ep_dir; CPU_INT32U xfer_len; if (p_ep == (USBH_EP *)0) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_BULK) || (ep_dir != USBH_EP_DIR_OUT )) { *p_err = USBH_ERR_EP_INVALID_TYPE; return (0u); } xfer_len = USBH_SyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_OUT, timeout_ms, p_err); return (xfer_len); } /* ********************************************************************************************************* * USBH_BulkTxAsync() * * Description : Issue asynchronous bulk request to transmit data to device. * * Argument(s) : p_ep Pointer to endpoint. * * buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * p_fnct Function that will be invoked upon completion of transmit operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If request is successfully submitted. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE If endpoint type is not bulk or direction is not OUT. * * ----- RETURNED BY USBH_AsyncXfer() : ----- * USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when transfer is completed. ********************************************************************************************************* */ USBH_ERR USBH_BulkTxAsync (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_XFER_CMPL_FNCT fnct, void *p_fnct_arg) { USBH_ERR err; CPU_INT08U ep_type; CPU_INT08U ep_dir; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_BULK) || (ep_dir != USBH_EP_DIR_OUT )) { return (USBH_ERR_EP_INVALID_TYPE); } err = USBH_AsyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_OUT, (void *)fnct, p_fnct_arg); return (err); } /* ********************************************************************************************************* * USBH_BulkRx() * * Description : Issue bulk request to receive data from device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to destination buffer to receive data. * * buf_len Buffer length in octets. * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Bulk transfer successfully received. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_NONE, URB is successfully submitted to host controller. * Host controller drivers error code, Otherwise. * * Return(s) : Number of octets received. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_BulkRx (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT08U ep_type; CPU_INT08U ep_dir; CPU_INT32U xfer_len; if (p_ep == (USBH_EP *)0) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_BULK) || (ep_dir != USBH_EP_DIR_IN )) { *p_err = USBH_ERR_EP_INVALID_TYPE; return (0u); } xfer_len = USBH_SyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_IN, timeout_ms, p_err); return (xfer_len); } /* ********************************************************************************************************* * USBH_BulkRxAsync() * * Description : Issue asynchronous bulk request to receive data from device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to destination buffer to receive data. * * buf_len Buffer length in octets. * * fnct Function that will be invoked upon completion of receive operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If request is successfully submitted. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE If endpoint type is not Bulk or direction is not IN. * * ----- RETURNED BY USBH_AsyncXfer() : ----- * USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when the transfer is completed. ********************************************************************************************************* */ USBH_ERR USBH_BulkRxAsync (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_XFER_CMPL_FNCT fnct, void *p_fnct_arg) { USBH_ERR err; CPU_INT08U ep_type; CPU_INT08U ep_dir; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_BULK) || (ep_dir != USBH_EP_DIR_IN )) { return (USBH_ERR_EP_INVALID_TYPE); } err = USBH_AsyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_IN, (void *)fnct, p_fnct_arg); return (err); } /* ********************************************************************************************************* * USBH_IntrTx() * * Description : Issue interrupt request to transmit data to device * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Interrupt transfer successfully transmitted. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not interrupt or direction is not OUT. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_NONE, URB is successfully submitted to host controller. * Host controller drivers error code, Otherwise. * * Return(s) : Number of octets transmitted. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_IntrTx (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT08U ep_type; CPU_INT08U ep_dir; CPU_INT32U xfer_len; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_INTR) || (ep_dir != USBH_EP_DIR_OUT )) { return (USBH_ERR_EP_INVALID_TYPE); } xfer_len = USBH_SyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_OUT, timeout_ms, p_err); return (xfer_len); } /* ********************************************************************************************************* * USBH_IntrTxAsync() * * Description : Issue asynchronous interrupt request to transmit data to device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * fnct Function that will be invoked upon completion of transmit operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If request is successfully submitted. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE If endpoint type is not interrupt or direction is not OUT. * * ----- RETURNED BY USBH_AsyncXfer() : ----- * USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when the transfer is completed. ********************************************************************************************************* */ USBH_ERR USBH_IntrTxAsync (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_XFER_CMPL_FNCT fnct, void *p_fnct_arg) { USBH_ERR err; CPU_INT08U ep_type; CPU_INT08U ep_dir; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_INTR) || (ep_dir != USBH_EP_DIR_OUT )) { return (USBH_ERR_EP_INVALID_TYPE); } err = USBH_AsyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_OUT, (void *)fnct, p_fnct_arg); return (err); } /* ********************************************************************************************************* * USBH_IntrRx() * * Description : Issue interrupt request to receive data from device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to destination buffer to receive data. * * buf_len Buffer length in octets. * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Interrupt transfer successfully received. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not interrupt or direction is not IN. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_NONE, URB is successfully submitted to host controller. * Host controller drivers error code, Otherwise. * * Return(s) : Number of octets received. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_IntrRx (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT08U ep_type; CPU_INT08U ep_dir; CPU_INT32U xfer_len; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_INTR) || (ep_dir != USBH_EP_DIR_IN )) { return (USBH_ERR_EP_INVALID_TYPE); } xfer_len = USBH_SyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_IN, timeout_ms, p_err); return (xfer_len); } /* ********************************************************************************************************* * USBH_IntrRxAsync() * * Description : Issue asynchronous interrupt request to receive data from device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * fnct Function that will be invoked upon completion of receive operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If request is successfully submitted. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE If endpoint type is not interrupt or direction is not IN. * * ----- RETURNED BY USBH_AsyncXfer() : ----- * USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when the transfer is completed. ********************************************************************************************************* */ USBH_ERR USBH_IntrRxAsync (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_XFER_CMPL_FNCT fnct, void *p_fnct_arg) { USBH_ERR err; CPU_INT08U ep_type; CPU_INT08U ep_dir; /* Argument checks for valid settings */ if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } if (p_ep->IsOpen == DEF_FALSE) { return (USBH_ERR_EP_INVALID_STATE); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_INTR) || (ep_dir != USBH_EP_DIR_IN )) { return (USBH_ERR_EP_INVALID_TYPE); } err = USBH_AsyncXfer( p_ep, p_buf, buf_len, (USBH_ISOC_DESC *)0, USBH_TOKEN_IN, (void *)fnct, p_fnct_arg); return (err); } /* ********************************************************************************************************* * USBH_IsocTx() * * Description : Issue isochronous request to transmit data to device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * start_frm Transfer start frame number. * * nbr_frm Number of frames. * * p_frm_len * * p_frm_err * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Isochronous transfer successfully transmitted. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not isochronous or direction is not OUT. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_NONE, URB is successfully submitted to host controller. * Host controller drivers error code, Otherwise. * * Return(s) : Number of octets transmitted. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_IsocTx (USBH_EP *p_ep, CPU_INT08U *p_buf, CPU_INT32U buf_len, CPU_INT32U start_frm, CPU_INT32U nbr_frm, CPU_INT16U *p_frm_len, USBH_ERR *p_frm_err, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT08U ep_type; CPU_INT08U ep_dir; CPU_INT32U xfer_len; USBH_ISOC_DESC isoc_desc; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_ISOC) || (ep_dir != USBH_EP_DIR_OUT )) { return (USBH_ERR_EP_INVALID_TYPE); } isoc_desc.BufPtr = p_buf; isoc_desc.BufLen = buf_len; isoc_desc.StartFrm = start_frm; isoc_desc.NbrFrm = nbr_frm; isoc_desc.FrmLen = p_frm_len; isoc_desc.FrmErr = p_frm_err; xfer_len = USBH_SyncXfer(p_ep, p_buf, buf_len, &isoc_desc, USBH_TOKEN_OUT, timeout_ms, p_err); return (xfer_len); } /* ********************************************************************************************************* * USBH_IsocTxAsync() * * Description : Issue asynchronous isochronous request to transmit data to device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer to transmit. * * buf_len Buffer length in octets. * * start_frm * * nbr_frm * * p_frm_len * * p_frm_err * * fnct Function that will be invoked upon completion of transmit operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If request is successfully submitted. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE If endpoint type is not isochronous or direction is not OUT. * * ----- RETURNED BY USBH_AsyncXfer() : ----- * USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when the transfer is completed. ********************************************************************************************************* */ USBH_ERR USBH_IsocTxAsync (USBH_EP *p_ep, CPU_INT08U *p_buf, CPU_INT32U buf_len, CPU_INT32U start_frm, CPU_INT32U nbr_frm, CPU_INT16U *p_frm_len, USBH_ERR *p_frm_err, USBH_ISOC_CMPL_FNCT fnct, void *p_fnct_arg) { USBH_ERR err; CPU_INT08U ep_type; CPU_INT08U ep_dir; LIB_ERR err_lib; USBH_ISOC_DESC *p_isoc_desc; MEM_POOL *p_isoc_desc_pool; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_ISOC) || (ep_dir != USBH_EP_DIR_OUT )) { return (USBH_ERR_EP_INVALID_TYPE); } p_isoc_desc_pool = &p_ep->DevPtr->HC_Ptr->HostPtr->IsocDescPool; p_isoc_desc = Mem_PoolBlkGet(p_isoc_desc_pool, sizeof(USBH_ISOC_DESC), &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { return (USBH_ERR_DESC_ALLOC); } p_isoc_desc->BufPtr = p_buf; p_isoc_desc->BufLen = buf_len; p_isoc_desc->StartFrm = start_frm; p_isoc_desc->NbrFrm = nbr_frm; p_isoc_desc->FrmLen = p_frm_len; p_isoc_desc->FrmErr = p_frm_err; err = USBH_AsyncXfer( p_ep, p_buf, buf_len, p_isoc_desc, USBH_TOKEN_OUT, (void *)fnct, p_fnct_arg); if (err != USBH_ERR_NONE) { Mem_PoolBlkFree(p_isoc_desc_pool, p_isoc_desc, &err_lib); } return (err); } /* ********************************************************************************************************* * USBH_IsocRx() * * Description : Issue isochronous request to receive data from device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to destination buffer to receive data. * * buf_len Buffer length in octets. * * start_frm * * nbr_frm * * p_frm_len * * p_frm_err * * timeout_ms Timeout, in milliseconds. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE Isochronous transfer successfully received. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE Endpoint type is not isochronous or direction is not IN. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_NONE, URB is successfully submitted to host controller. * Host controller drivers error code, Otherwise. * * Return(s) : Number of octets received. * * Note(s) : None. ********************************************************************************************************* */ CPU_INT32U USBH_IsocRx (USBH_EP *p_ep, CPU_INT08U *p_buf, CPU_INT32U buf_len, CPU_INT32U start_frm, CPU_INT32U nbr_frm, CPU_INT16U *p_frm_len, USBH_ERR *p_frm_err, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT08U ep_type; CPU_INT08U ep_dir; CPU_INT32U xfer_len; USBH_ISOC_DESC isoc_desc; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_ISOC) || (ep_dir != USBH_EP_DIR_IN )) { return (USBH_ERR_EP_INVALID_TYPE); } isoc_desc.BufPtr = p_buf; isoc_desc.BufLen = buf_len; isoc_desc.StartFrm = start_frm; isoc_desc.NbrFrm = nbr_frm; isoc_desc.FrmLen = p_frm_len; isoc_desc.FrmErr = p_frm_err; xfer_len = USBH_SyncXfer(p_ep, p_buf, buf_len, &isoc_desc, USBH_TOKEN_IN, timeout_ms, p_err); return (xfer_len); } /* ********************************************************************************************************* * USBH_IsocRxAsync() * * Description : Issue asynchronous isochronous request to receive data from device. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to destination buffer to receive data. * * buf_len Buffer length in octets. * * start_frm * * nbr_frm * * p_frm_len * * p_frm_err * * fnct Function that will be invoked upon completion of receive operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If request is successfully submitted. * USBH_ERR_INVALID_ARG If invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_TYPE If endpoint type is not isochronous or direction is not IN. * * ----- RETURNED BY USBH_AsyncXfer() : ----- * USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when the transfer is completed. ********************************************************************************************************* */ USBH_ERR USBH_IsocRxAsync (USBH_EP *p_ep, CPU_INT08U *p_buf, CPU_INT32U buf_len, CPU_INT32U start_frm, CPU_INT32U nbr_frm, CPU_INT16U *p_frm_len, USBH_ERR *p_frm_err, USBH_ISOC_CMPL_FNCT fnct, void *p_fnct_arg) { USBH_ERR err; CPU_INT08U ep_type; CPU_INT08U ep_dir; USBH_ISOC_DESC *p_isoc_desc; MEM_POOL *p_isoc_desc_pool; LIB_ERR err_lib; if (p_ep == (USBH_EP *)0) { return (USBH_ERR_INVALID_ARG); } ep_type = USBH_EP_TypeGet(p_ep); ep_dir = USBH_EP_DirGet(p_ep); if ((ep_type != USBH_EP_TYPE_ISOC) || (ep_dir != USBH_EP_DIR_IN )) { return (USBH_ERR_EP_INVALID_TYPE); } p_isoc_desc_pool = &p_ep->DevPtr->HC_Ptr->HostPtr->IsocDescPool; p_isoc_desc = Mem_PoolBlkGet(p_isoc_desc_pool, sizeof(USBH_ISOC_DESC), &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { return (USBH_ERR_DESC_ALLOC); } p_isoc_desc->BufPtr = p_buf; p_isoc_desc->BufLen = buf_len; p_isoc_desc->StartFrm = start_frm; p_isoc_desc->NbrFrm = nbr_frm; p_isoc_desc->FrmLen = p_frm_len; p_isoc_desc->FrmErr = p_frm_err; err = USBH_AsyncXfer( p_ep, p_buf, buf_len, p_isoc_desc, USBH_TOKEN_IN, (void *)fnct, p_fnct_arg); if (err != USBH_ERR_NONE) { Mem_PoolBlkFree(p_isoc_desc_pool, p_isoc_desc, &err_lib); } return (err); } /* ********************************************************************************************************* * USBH_EP_LogNbrGet() * * Description : Get logical number of given endpoint. * * Argument(s) : p_ep Pointer to endpoint * * Return(s) : Logical number of given endpoint, * * Note(s) : (1) USB2.0 spec, section 9.6.6 states that bits 3...0 in offset 2 of standard endpoint * descriptor (bEndpointAddress) contains the endpoint logical number. ********************************************************************************************************* */ CPU_INT08U USBH_EP_LogNbrGet (USBH_EP *p_ep) { return ((CPU_INT08U )p_ep->Desc.bEndpointAddress & 0x7Fu); /* See Note (1). */ } /* ********************************************************************************************************* * USBH_EP_DirGet() * * Description : Get the direction of given endpoint. * * Argument(s) : p_ep Pointer to endpoint structure. * * Return(s) : USBH_EP_DIR_NONE, If endpoint is of type control. * USBH_EP_DIR_OUT, If endpoint direction is OUT. * USBH_EP_DIR_IN, If endpoint direction is IN. * * Note(s) : (1) USB2.0 spec, section 9.6.6 states that bit 7 in offset 2 of standard endpoint * descriptor (bEndpointAddress) gives the direction of that endpoint. * * (a) 0 = OUT endpoint * (b) 1 = IN endpoint ********************************************************************************************************* */ CPU_INT08U USBH_EP_DirGet (USBH_EP *p_ep) { CPU_INT08U ep_type; ep_type = USBH_EP_TypeGet(p_ep); if (ep_type == USBH_EP_TYPE_CTRL) { return (USBH_EP_DIR_NONE); } if (((CPU_INT08U )p_ep->Desc.bEndpointAddress & 0x80u) != 0u) { /* See Note (1). */ return (USBH_EP_DIR_IN); } else { return (USBH_EP_DIR_OUT); } } /* ********************************************************************************************************* * USBH_EP_MaxPktSizeGet() * * Description : Get the maximum packet size of the given endpoint * * Argument(s) : p_ep Pointer to endpoint structure * * Return(s) : Maximum Packet Size of the given endpoint * * Note(s) : (1) USB2.0 spec, section 9.6.6 states that offset 4 of standard endpoint descriptor * (wMaxPacketSize) gives the maximum packet size supported by this endpoint. ********************************************************************************************************* */ CPU_INT16U USBH_EP_MaxPktSizeGet (USBH_EP *p_ep) { return ((CPU_INT16U)p_ep->Desc.wMaxPacketSize & 0x07FFu); /* See Note (1). */ } /* ********************************************************************************************************* * USBH_EP_TypeGet() * * Description : Get type of the given endpoint * * Argument(s) : p_ep Pointer to endpoint * * Return(s) : Type of the given endpoint * * Note(s) : (1) USB2.0 spec, section 9.6.6 states that bits 1:0 in offset 3 of standard endpoint * descriptor (bmAttributes) gives type of the endpoint. * * (a) 00 = Control * (b) 01 = Isochronous * (c) 10 = Bulk * (d) 11 = Interrupt ********************************************************************************************************* */ CPU_INT08U USBH_EP_TypeGet (USBH_EP *p_ep) { return ((CPU_INT08U )p_ep->Desc.bmAttributes & 0x03u); /* See Note (1). */ } /* ********************************************************************************************************* * USBH_EP_Get() * * Description : Get endpoint specified by given index / alternate setting / interface. * * Argument(s) : p_if Pointer to interface. * * alt_ix Alternate setting index. * * ep_ix Endpoint index. * * p_ep Pointer to endpoint structure. * * Return(s) : USBH_ERR_NONE, If endpoint was found. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_if' / 'p_ep'. * USBH_ERR_EP_NOT_FOUND, If endpoint was not found. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_EP_Get (USBH_IF *p_if, CPU_INT08U alt_ix, CPU_INT08U ep_ix, USBH_EP *p_ep) { USBH_DESC_HDR *p_desc; CPU_INT32U if_off; CPU_INT08U ix; if ((p_if == (USBH_IF *)0) || (p_ep == (USBH_EP *)0)) { return (USBH_ERR_INVALID_ARG); } ix = 0u; if_off = 0u; p_desc = (USBH_DESC_HDR *)p_if->IF_DataPtr; while (if_off < p_if->IF_DataLen) { p_desc = USBH_NextDescGet((void *)p_desc, &if_off); if (p_desc->bDescriptorType == USBH_DESC_TYPE_IF) { /* Chk if IF desc. */ if (alt_ix == ((CPU_INT08U *)p_desc)[3]) { /* Compare alternate setting ix. */ break; } } } while (if_off < p_if->IF_DataLen) { p_desc = USBH_NextDescGet((void *)p_desc, &if_off); if (p_desc->bDescriptorType == USBH_DESC_TYPE_EP) { /* Chk if EP desc. */ if (ix == ep_ix) { /* Compare EP ix. */ USBH_ParseEP_Desc(&p_ep->Desc, (void *)p_desc); return (USBH_ERR_NONE); } ix++; } } return (USBH_ERR_EP_NOT_FOUND); } /* ********************************************************************************************************* * USBH_EP_StallSet() * * Description : Set the STALL condition on endpoint. * * Argument(s) : p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE, If endpoint STALL state is set. * * ----- RETURNED BY USBH_CtrlTx() : ----- * USBH_ERR_UNKNOWN Unknown error occurred. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_EP_StallSet (USBH_EP *p_ep) { USBH_ERR err; USBH_DEV *p_dev; p_dev = p_ep->DevPtr; (void)USBH_CtrlTx( p_dev, USBH_REQ_SET_FEATURE, USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_STD | USBH_REQ_RECIPIENT_EP, USBH_FEATURE_SEL_EP_HALT, p_ep->Desc.bEndpointAddress, (void *)0, 0u, USBH_CFG_STD_REQ_TIMEOUT, &err); if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); } return (err); } /* ********************************************************************************************************* * USBH_EP_StallClr() * * Description : Clear the STALL condition on endpoint. * * Argument(s) : p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE, If endpoint STALL state is cleared. * * ----- RETURNED BY USBH_CtrlTx() : ----- * USBH_ERR_UNKNOWN Unknown error occurred. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : (1) The standard CLEAR_FEATURE request is defined in the Universal Serial Bus * specification revision 2.0, section 9.4.1. ********************************************************************************************************* */ USBH_ERR USBH_EP_StallClr (USBH_EP *p_ep) { USBH_ERR err; USBH_DEV *p_dev; p_dev = p_ep->DevPtr; (void)USBH_CtrlTx( p_dev, USBH_REQ_CLR_FEATURE, /* See Note (1) */ USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_STD | USBH_REQ_RECIPIENT_EP, USBH_FEATURE_SEL_EP_HALT, p_ep->Desc.bEndpointAddress, (void *)0, 0u, USBH_CFG_STD_REQ_TIMEOUT, &err); if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); } return (err); } /* ********************************************************************************************************* * USBH_EP_Reset() * * Description : This function is used to reset the opened endpoint * * Argument(s) : p_dev Pointer to USB device. * * p_ep Pointer to endpoint. Default endpoint if null is passed. * * Return(s) : USBH_ERR_NONE, If endpoint successfully reseted. * Host controller driver error, otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_EP_Reset (USBH_DEV *p_dev, USBH_EP *p_ep) { USBH_EP *p_ep_t; USBH_ERR err; if (p_ep == (USBH_EP *)0) { p_ep_t = &p_dev->DfltEP; } else { p_ep_t = p_ep; } if ((p_dev->IsRootHub == DEF_TRUE) && /* Do nothing if virtual RH. */ (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE)) { return (USBH_ERR_NONE); } USBH_HCD_EP_Abort(p_dev->HC_Ptr, /* Abort pending xfers on EP. */ p_ep_t, &err); if (err != USBH_ERR_NONE) { return (err); } USBH_HCD_EP_Close(p_dev->HC_Ptr, /* Close / open EP. */ p_ep_t, &err); if (err != USBH_ERR_NONE) { return (err); } USBH_HCD_EP_Open(p_dev->HC_Ptr, p_ep_t, &err); if (err != USBH_ERR_NONE) { return (err); } return (USBH_ERR_NONE); } /* ********************************************************************************************************* * USBH_EP_Close() * * Description : Closes given endpoint and makes it unavailable for I/O transfers. * * Argument(s) : p_ep Pointer to endpoint. * * Return(s) : USBH_ERR_NONE, If endpoint successfully closed. * USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_ep'. * Host controller driver error, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_EP_Close (USBH_EP *p_ep) { USBH_ERR err; USBH_DEV *p_dev; USBH_URB *p_async_urb; LIB_ERR err_lib; if(p_ep == (USBH_EP *)0) { return(USBH_ERR_INVALID_ARG); } p_ep->IsOpen = DEF_FALSE; p_dev = p_ep->DevPtr; err = USBH_ERR_NONE; if (!((p_dev->IsRootHub == DEF_TRUE) && (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE))){ USBH_URB_Abort(&p_ep->URB); /* Abort any pending URB. */ } if (p_ep->URB.Sem != (USBH_HSEM )0) { /* Close EP sem and mutex. */ (void)USBH_OS_SemDestroy(p_ep->URB.Sem); p_ep->URB.Sem = (USBH_HSEM )0; } if (p_ep->Mutex != (USBH_HMUTEX )0) { (void)USBH_OS_MutexDestroy(p_ep->Mutex); p_ep->Mutex = (USBH_HMUTEX )0; } if (!((p_dev->IsRootHub == DEF_TRUE) && /* Close EP on HC. */ (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE))){ USBH_HCD_EP_Close(p_ep->DevPtr->HC_Ptr, p_ep, &err); } if(p_ep->XferNbrInProgress > 1u) { p_async_urb = p_ep->URB.AsyncURB_NxtPtr; while (p_async_urb != 0) { /* Free extra URB. */ Mem_PoolBlkFree( &p_ep->DevPtr->HC_Ptr->HostPtr->AsyncURB_Pool, (void *)p_async_urb, &err_lib); p_async_urb = p_async_urb->AsyncURB_NxtPtr; } p_ep->XferNbrInProgress = 0u; } return (err); } /* ********************************************************************************************************* * USBH_URB_Done() * * Description : Handle a USB request block (URB) that has been completed by host controller. * * Argument(s) : p_urb Pointer to URB. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ void USBH_URB_Done (USBH_URB *p_urb) { CPU_SR_ALLOC(); if (p_urb->State == USBH_URB_STATE_SCHEDULED) { /* URB must be in scheduled state. */ p_urb->State = USBH_URB_STATE_QUEUED; /* Set URB state to done. */ if (p_urb->FnctPtr != (void *)0) { /* Check if req is async. */ CPU_CRITICAL_ENTER(); p_urb->NxtPtr = (USBH_URB *)0; if (USBH_URB_HeadPtr == (USBH_URB *)0) { USBH_URB_HeadPtr = p_urb; USBH_URB_TailPtr = p_urb; } else { USBH_URB_TailPtr->NxtPtr = p_urb; USBH_URB_TailPtr = p_urb; } CPU_CRITICAL_EXIT(); (void)USBH_OS_SemPost(USBH_URB_Sem); } else { (void)USBH_OS_SemPost(p_urb->Sem); /* Post notification to waiting task. */ } } } /* ********************************************************************************************************* * USBH_URB_Complete() * * Description : Handle a URB after transfer has been completed or aborted. * * Argument(s) : p_urb Pointer to URB. * * Return(s) : USBH_ERR_NONE * * Note(s) : None. ********************************************************************************************************* */ USBH_ERR USBH_URB_Complete (USBH_URB *p_urb) { USBH_DEV *p_dev; USBH_ERR err; LIB_ERR err_lib; USBH_URB *p_async_urb_to_remove; USBH_URB *p_prev_async_urb; USBH_URB urb_temp; USBH_EP *p_ep; CPU_SR_ALLOC(); p_ep = p_urb->EP_Ptr; p_dev = p_ep->DevPtr; if (p_urb->State == USBH_URB_STATE_QUEUED) { USBH_HCD_URB_Complete(p_dev->HC_Ptr, /* Call HC to cleanup completed URB. */ p_urb, &err); } else if (p_urb->State == USBH_URB_STATE_ABORTED) { USBH_HCD_URB_Abort(p_dev->HC_Ptr, /* Call HC to abort URB. */ p_urb, &err); p_urb->Err = USBH_ERR_URB_ABORT; p_urb->XferLen = 0u; } else { /* Empty Else Statement */ } Mem_Copy((void *)&urb_temp, /* Copy urb locally before freeing it. */ (void *) p_urb, sizeof(USBH_URB)); /* --------- FREE URB BEFORE NOTIFYING CLASS ---------- */ if((p_urb != &p_ep->URB) && /* Is the URB an extra URB for async function? */ (p_urb->FnctPtr != 0 )) { p_async_urb_to_remove = &p_ep->URB; p_prev_async_urb = &p_ep->URB; while (p_async_urb_to_remove->AsyncURB_NxtPtr != 0) { /* Srch extra URB to remove. */ /* Extra URB found */ if(p_async_urb_to_remove->AsyncURB_NxtPtr == p_urb) { /* Remove from Q. */ p_prev_async_urb->AsyncURB_NxtPtr = p_urb->AsyncURB_NxtPtr; break; } p_prev_async_urb = p_async_urb_to_remove; p_async_urb_to_remove = p_async_urb_to_remove->AsyncURB_NxtPtr; } /* Free extra URB. */ Mem_PoolBlkFree( &p_dev->HC_Ptr->HostPtr->AsyncURB_Pool, (void *)p_urb, &err_lib); } CPU_CRITICAL_ENTER(); if (p_ep->XferNbrInProgress > 0u) { p_ep->XferNbrInProgress--; } CPU_CRITICAL_EXIT(); if ((urb_temp.State == USBH_URB_STATE_QUEUED) || (urb_temp.State == USBH_URB_STATE_ABORTED)) { USBH_URB_Notify(&urb_temp); } return (USBH_ERR_NONE); } /* ********************************************************************************************************* * USBH_StrGet() * * Description : Read specified string descriptor, remove header and extract string data. * * Argument(s) : p_dev Pointer to USB device. * * desc_ix Index of string descriptor. * * lang_id Language identifier. * * p_buf Buffer in which the string descriptor will be stored. * * buf_len Buffer length in octets. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE String descriptor successfully fetched. * USBH_ERR_INVALID_ARG Invalid argument passed to 'desc_ix'. * USBH_ERR_DESC_INVALID Invalid string / lang id descriptor. * * ----- RETURNED BY USBH_StrDescGet() : ----- * USBH_ERR_DESC_INVALID, Invalid string descriptor fetched. * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Return(s) : Length of string received. * * Note(s) : (1) The string descriptor MUST be at least four bytes : * * (a) Byte 0 = Length * (b) Byte 1 = Type * (c) Bytes 2-3 = Default language ID ********************************************************************************************************* */ CPU_INT32U USBH_StrGet (USBH_DEV *p_dev, CPU_INT08U desc_ix, CPU_INT16U lang_id, CPU_INT08U *p_buf, CPU_INT32U buf_len, USBH_ERR *p_err) { CPU_INT32U ix; CPU_INT32U str_len; CPU_INT08U *p_str; USBH_DESC_HDR *p_hdr; if (desc_ix == 0u) { /* Invalid desc ix. */ *p_err = USBH_ERR_INVALID_ARG; return (0u); } lang_id = p_dev->LangID; if (lang_id == 0u) { /* If lang ID is zero, get dflt used by the dev. */ str_len = USBH_StrDescGet(p_dev, 0u, 0u, p_buf, buf_len, p_err); if (str_len < 4u) { /* See Note #1. */ *p_err = USBH_ERR_DESC_INVALID; return (0u); } lang_id = MEM_VAL_GET_INT16U(&p_buf[2u]); /* Rd language ID into CPU endianness. */ if (lang_id == 0u) { *p_err = USBH_ERR_DESC_INVALID; return (0u); } else { p_dev->LangID = lang_id; } } p_str = p_buf; p_hdr = (USBH_DESC_HDR *)p_buf; str_len = USBH_StrDescGet(p_dev, /* Rd str desc with lang ID. */ desc_ix, lang_id, p_hdr, buf_len, p_err); if (str_len > USBH_LEN_DESC_HDR) { str_len = (p_hdr->bLength - 2u); /* Remove 2-byte header. */ if (str_len > (buf_len - 2u)) { str_len = (buf_len - 2u); } for (ix = 0u; ix < str_len; ix++) { p_str[ix] = p_str[2u + ix]; /* Str starts from byte 3 in desc. */ } p_str[ix] = 0u; p_str[++ix] = 0u; str_len = str_len / 2u; /* Len of ANSI str. */ return (str_len); } else { *p_err = USBH_ERR_DESC_INVALID; return (0u); } } /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * USBH_EP_Open() * * Description : Open an endpoint. * * Argument(s) : p_dev Pointer to USB device. * * p_if Pointer to interface containing endpoint. * * ep_type Endpoint type. * * ep_dir Endpoint direction. * * p_ep Pointer to endpoint passed by class. * * Return(s) : USBH_ERR_NONE If endpoint is successfully opened. * USBH_ERR_EP_ALLOC If USBH_CFG_MAX_NBR_EPS reached. * USBH_ERR_EP_NOT_FOUND If endpoint with given type and direction not found. * Host controller drivers error, Otherwise. * * ----- RETURNED BY USBH_OS_MutexCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, if mutex creation failed. * * ----- RETURNED BY USBH_OS_SemCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, If semaphore creation failed. * * Note(s) : (1) A full-speed interrupt endpoint can specify a desired period from 1 ms to 255 ms. * Low-speed endpoints are limited to specifying only 10 ms to 255 ms. High-speed * endpoints can specify a desired period 2^(bInterval-1) x 125us, where bInterval is in * the range [1 .. 16]. * * (2) Full-/high-speed isochronous endpoints must specify a desired period as * 2^(bInterval-1) x F, where bInterval is in the range [1 .. 16] and F is 125us for * high-speed and 1ms for full-speed. ********************************************************************************************************* */ static USBH_ERR USBH_EP_Open (USBH_DEV *p_dev, USBH_IF *p_if, USBH_EP_TYPE ep_type, USBH_EP_DIR ep_dir, USBH_EP *p_ep) { CPU_INT08U ep_desc_dir; CPU_INT08U ep_desc_type; CPU_INT08U ep_ix; CPU_INT08U nbr_eps; CPU_BOOLEAN ep_found; USBH_ERR err; if (p_ep->IsOpen == DEF_TRUE) { return (USBH_ERR_NONE); } USBH_URB_Clr(&p_ep->URB); ep_found = DEF_FALSE; ep_desc_type = 0u; nbr_eps = USBH_IF_EP_NbrGet(p_if, p_if->AltIxSel); if (nbr_eps > USBH_CFG_MAX_NBR_EPS) { err = USBH_ERR_EP_ALLOC; return (err); } for (ep_ix = 0u; ep_ix < nbr_eps; ep_ix++) { USBH_EP_Get(p_if, p_if->AltIxSel, ep_ix, p_ep); ep_desc_type = p_ep->Desc.bmAttributes & 0x03u; /* EP type from desc. */ ep_desc_dir = p_ep->Desc.bEndpointAddress & 0x80u; /* EP dir from desc. */ if (ep_desc_type == ep_type) { if ((ep_desc_type == USBH_EP_TYPE_CTRL) || (ep_desc_dir == ep_dir)) { ep_found = DEF_TRUE; break; } } } if (ep_found == DEF_FALSE) { return (USBH_ERR_EP_NOT_FOUND); /* Class specified EP not found. */ } p_ep->Interval = 0u; if (ep_desc_type == USBH_EP_TYPE_INTR) { /* ------------ DETERMINE POLLING INTERVAL ------------ */ if (p_ep->Desc.bInterval > 0) { /* See Note #1. */ if ((p_dev->DevSpd == USBH_DEV_SPD_LOW ) || (p_dev->DevSpd == USBH_DEV_SPD_FULL)) { if (p_dev->HubHS_Ptr != (USBH_HUB_DEV *) 0) { p_ep->Interval = 8u * p_ep->Desc.bInterval; /* 1 (1ms)frame = 8 (125us)microframe. */ } else { p_ep->Interval = p_ep->Desc.bInterval; } } else { /* DevSpd == USBH_DEV_SPD_HIGH */ p_ep->Interval = 1 << (p_ep->Desc.bInterval - 1); /* For HS, interval is 2 ^ (bInterval - 1). */ } } } else if (ep_desc_type == USBH_EP_TYPE_ISOC) { p_ep->Interval = 1 << (p_ep->Desc.bInterval - 1); /* Isoc interval is 2 ^ (bInterval - 1). See Note #2. */ } else { /* Empty Else Statement */ } p_ep->DevAddr = p_dev->DevAddr; p_ep->DevSpd = p_dev->DevSpd; p_ep->DevPtr = p_dev; if (!((p_dev->IsRootHub == DEF_TRUE) && (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE))){ USBH_HCD_EP_Open(p_dev->HC_Ptr, p_ep, &err); if (err != USBH_ERR_NONE) { return (err); } } err = USBH_OS_SemCreate(&p_ep->URB.Sem, 0u); /* Sem for I/O wait. */ if (err != USBH_ERR_NONE) { return (err); } err = USBH_OS_MutexCreate(&p_ep->Mutex); /* Mutex to sync I/O req on same EP. */ if (err != USBH_ERR_NONE) { return (err); } p_ep->IsOpen = DEF_TRUE; p_ep->URB.EP_Ptr = p_ep; return (err); } /* ********************************************************************************************************* * USBH_SyncTransfer() * * Description : Perform synchronous transfer on endpoint. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer. * * buf_len Number of data bytes in buffer. * * p_isoc_desc Pointer to isochronous descriptor. * * token USB token to issue. * * timeout_ms Timeout, in milliseconds. * * p_err Variable that will receive the return error code from this function. * USBH_ERR_NONE Transfer successfully completed. * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * * ----- RETURNED BY USBH_URB_Submit() : ----- * USBH_ERR_NONE, URB is successfully submitted to host controller. * USBH_ERR_EP_INVALID_STATE, Endpoint is in halt state. * Host controller drivers error code, Otherwise. * * ----- RETURNED BY USBH_OS_SemWait() : ----- * USBH_ERR_INVALID_ARG If invalid argument passed to 'sem'. * USBH_ERR_OS_TIMEOUT If semaphore pend reached specified timeout. * USBH_ERR_OS_ABORT If pend on semaphore was aborted. * USBH_ERR_OS_FAIL Otherwise. * * Return(s) : Number of bytes transmitted or received. * * Note(s) : None. ********************************************************************************************************* */ static CPU_INT32U USBH_SyncXfer (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_ISOC_DESC *p_isoc_desc, USBH_TOKEN token, CPU_INT32U timeout_ms, USBH_ERR *p_err) { CPU_INT32U len; USBH_URB *p_urb; /* Argument checks for valid settings */ if (p_ep == (USBH_EP *)0) { *p_err = USBH_ERR_INVALID_ARG; return (0u); } if (p_ep->IsOpen == DEF_FALSE) { *p_err = USBH_ERR_EP_INVALID_STATE; return (0u); } (void)USBH_OS_MutexLock(p_ep->Mutex); p_urb = &p_ep->URB; p_urb->EP_Ptr = p_ep; p_urb->IsocDescPtr = p_isoc_desc; p_urb->UserBufPtr = p_buf; p_urb->UserBufLen = buf_len; p_urb->DMA_BufLen = 0u; p_urb->DMA_BufPtr = (void *)0; p_urb->XferLen = 0u; p_urb->FnctPtr = 0u; p_urb->FnctArgPtr = 0u; p_urb->State = USBH_URB_STATE_NONE; p_urb->ArgPtr = (void *)0; p_urb->Token = token; *p_err = USBH_URB_Submit(p_urb); if (*p_err == USBH_ERR_NONE) { /* Transfer URB to HC. */ *p_err = USBH_OS_SemWait(p_urb->Sem, timeout_ms); /* Wait on URB completion notification. */ } if (*p_err == USBH_ERR_NONE) { USBH_URB_Complete(p_urb); *p_err = p_urb->Err; } else { USBH_URB_Abort(p_urb); } len = p_urb->XferLen; p_urb->State = USBH_URB_STATE_NONE; (void)USBH_OS_MutexUnlock(p_ep->Mutex); return (len); } /* ********************************************************************************************************* * USBH_AsyncXfer() * * Description : Perform asynchronous transfer on endpoint. * * Argument(s) : p_ep Pointer to endpoint. * * p_buf Pointer to data buffer. * * buf_len Number of data bytes in buffer. * * p_isoc_desc Pointer to isochronous descriptor. * * token USB token to issue. * * p_fnct Function that will be invoked upon completion of receive operation. * * p_fnct_arg Pointer to argument that will be passed as parameter of 'p_fnct'. * * Return(s) : USBH_ERR_NONE If transfer successfully submitted. * USBH_ERR_EP_INVALID_STATE If endpoint is not opened. * USBH_ERR_ALLOC If URB cannot be allocated. * USBH_ERR_UNKNOWN If unknown error occured. * * ----- RETURNED BY USBH_URB_Submit() : ----- * USBH_ERR_NONE, If URB is successfully submitted to host controller. * USBH_ERR_EP_INVALID_STATE, If endpoint is in halt state. * Host controller drivers error code, Otherwise. * * Note(s) : (1) This function returns immediately. The URB completion will be invoked by the * asynchronous I/O task when the transfer is completed. ********************************************************************************************************* */ static USBH_ERR USBH_AsyncXfer (USBH_EP *p_ep, void *p_buf, CPU_INT32U buf_len, USBH_ISOC_DESC *p_isoc_desc, USBH_TOKEN token, void *p_fnct, void *p_fnct_arg) { USBH_ERR err; USBH_URB *p_urb; USBH_URB *p_async_urb; MEM_POOL *p_async_urb_pool; LIB_ERR err_lib; if (p_ep->IsOpen == DEF_FALSE) { return (USBH_ERR_EP_INVALID_STATE); } if((p_ep->URB.State != USBH_URB_STATE_SCHEDULED) && /* Chk if no xfer is pending or in progress on EP. */ (p_ep->XferNbrInProgress == 0u )) { p_urb = &p_ep->URB; /* Use URB struct associated to EP. */ } else if (p_ep->XferNbrInProgress >= 1u) { /* Get a new URB struct from the URB async pool. */ p_async_urb_pool = &p_ep->DevPtr->HC_Ptr->HostPtr->AsyncURB_Pool; p_urb = (USBH_URB *)Mem_PoolBlkGet(p_async_urb_pool, sizeof(USBH_URB), &err_lib); if (err_lib != LIB_MEM_ERR_NONE) { return (USBH_ERR_ALLOC); } USBH_URB_Clr(p_urb); p_async_urb = &p_ep->URB; /* Get head of extra async URB Q. */ while (p_async_urb->AsyncURB_NxtPtr != 0) { /* Srch tail of extra async URB Q. */ p_async_urb = p_async_urb->AsyncURB_NxtPtr; } p_async_urb->AsyncURB_NxtPtr = p_urb; /* Insert new URB at end of extra async URB Q. */ } else { return (USBH_ERR_UNKNOWN); } p_ep->XferNbrInProgress++; p_urb->EP_Ptr = p_ep; /* ------------------- PREPARE URB -------------------- */ p_urb->IsocDescPtr = p_isoc_desc; p_urb->UserBufPtr = p_buf; p_urb->UserBufLen = buf_len; p_urb->XferLen = 0u; p_urb->FnctPtr = (void *)p_fnct; p_urb->FnctArgPtr = p_fnct_arg; p_urb->State = USBH_URB_STATE_NONE; p_urb->ArgPtr = (void *)0; p_urb->Token = token; err = USBH_URB_Submit(p_urb); /* See Note (1). */ return (err); } /* ********************************************************************************************************* * USBH_SyncCtrlXfer() * * Description : Perform synchronous control transfer on endpoint. * * Argument(s) : p_ep Pointer to endpoint. * * b_req One-byte value that specifies request. * * bm_req_type One-byte value that specifies direction, type and recipient of request. * * w_value Two-byte value used to pass information to device. * * w_ix Two-byte value used to pass an index or offset (such as an interface or * endpoint number) to device. * * p_arg Pointer to data buffer. * * w_len Two-byte value containing number of data bytes in data stage. * * timeout_ms Timeout, in milliseconds. * * p_err Variable that will receive the return error code from this function. * * USBH_ERR_NONE Control transfer successfully completed. * USBH_ERR_UNKNOWN Unknown error occurred. * * ----- RETURNED BY USBH_SyncXfer() : ----- * USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE Endpoint is not opened. * Host controller drivers error code, Otherwise. * * Return(s) : Number of bytes transfered. * * Note(s) : None. ********************************************************************************************************* */ static CPU_INT16U USBH_SyncCtrlXfer (USBH_EP *p_ep, CPU_INT08U b_req, CPU_INT08U bm_req_type, CPU_INT16U w_val, CPU_INT16U w_ix, void *p_arg, CPU_INT16U w_len, CPU_INT32U timeout_ms, USBH_ERR *p_err) { USBH_SETUP_REQ setup; ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, setup_buf, 8); CPU_BOOLEAN is_in; CPU_INT32U len; CPU_INT16U rtn_len; CPU_INT08U *p_data_08; setup.bmRequestType = bm_req_type; /* ------------------- SETUP STAGE -------------------- */ setup.bRequest = b_req; setup.wValue = w_val; setup.wIndex = w_ix; setup.wLength = w_len; USBH_FmtSetupReq(&setup, setup_buf); is_in = (bm_req_type & USBH_REQ_DIR_MASK) != 0u ? DEF_TRUE : DEF_FALSE; len = USBH_SyncXfer( p_ep, (void *)&setup_buf[0u], USBH_LEN_SETUP_PKT, (USBH_ISOC_DESC *) 0, USBH_TOKEN_SETUP, timeout_ms, p_err); if (*p_err != USBH_ERR_NONE) { return (0u); } if (len != USBH_LEN_SETUP_PKT) { *p_err = USBH_ERR_UNKNOWN; return (0u); } if (w_len > 0u) { /* -------------------- DATA STAGE -------------------- */ p_data_08 = (CPU_INT08U *)p_arg; rtn_len = USBH_SyncXfer( p_ep, (void *)p_data_08, w_len, (USBH_ISOC_DESC *)0, (is_in ? USBH_TOKEN_IN : USBH_TOKEN_OUT), timeout_ms, p_err); if (*p_err != USBH_ERR_NONE) { return (0u); } } else { rtn_len = 0u; } (void)USBH_SyncXfer( p_ep, /* ------------------- STATUS STAGE ------------------- */ (void *)0, 0u, (USBH_ISOC_DESC *)0, ((w_len && is_in) ? USBH_TOKEN_OUT : USBH_TOKEN_IN), timeout_ms, p_err); if (*p_err != USBH_ERR_NONE) { return (0u); } return (rtn_len); } /* ********************************************************************************************************* * USBH_URB_Abort() * * Description : Abort pending URB. * * Argument(s) : p_urb Pointer to URB. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_URB_Abort (USBH_URB *p_urb) { CPU_BOOLEAN cmpl; CPU_SR_ALLOC(); cmpl = DEF_FALSE; CPU_CRITICAL_ENTER(); if (p_urb->State == USBH_URB_STATE_SCHEDULED) { p_urb->State = USBH_URB_STATE_ABORTED; /* Abort scheduled URB. */ cmpl = DEF_TRUE; /* Mark URB as completion pending. */ } else if (p_urb->State == USBH_URB_STATE_QUEUED) { /* Is URB queued in async Q? */ /* URB is in async lst. */ #if (USBH_CFG_PRINT_LOG == DEF_ENABLED) USBH_PRINT_LOG("URB is in ASYNC QUEUE\r\n"); #endif p_urb->State = USBH_URB_STATE_ABORTED; } else { /* Empty Else Statement */ } CPU_CRITICAL_EXIT(); if (cmpl == DEF_TRUE) { USBH_URB_Complete(p_urb); } } /* ********************************************************************************************************* * USBH_URB_Notify() * * Description : Notify application about state of given URB. * * Argument(s) : p_urb Pointer to URB. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_URB_Notify (USBH_URB *p_urb) { CPU_INT16U nbr_frm; CPU_INT16U *p_frm_len; CPU_INT32U buf_len; CPU_INT32U xfer_len; CPU_INT32U start_frm; void *p_buf; void *p_arg; USBH_EP *p_ep; USBH_ISOC_DESC *p_isoc_desc; USBH_XFER_CMPL_FNCT p_xfer_fnct; USBH_ISOC_CMPL_FNCT p_isoc_fnct; USBH_ERR *p_frm_err; USBH_ERR err; LIB_ERR err_lib; CPU_SR_ALLOC(); p_ep = p_urb->EP_Ptr; p_isoc_desc = p_urb->IsocDescPtr; CPU_CRITICAL_ENTER(); if ((p_urb->State == USBH_URB_STATE_ABORTED) && (p_urb->FnctPtr == (void *)0 )) { p_urb->State = USBH_URB_STATE_NONE; (void)USBH_OS_SemWaitAbort(p_urb->Sem); } if (p_urb->FnctPtr != (void *)0) { /* Save URB info. */ p_buf = p_urb->UserBufPtr; buf_len = p_urb->UserBufLen; xfer_len = p_urb->XferLen; p_arg = p_urb->FnctArgPtr; err = p_urb->Err; p_urb->State = USBH_URB_STATE_NONE; if (p_isoc_desc == (USBH_ISOC_DESC *)0) { p_xfer_fnct = (USBH_XFER_CMPL_FNCT)p_urb->FnctPtr; CPU_CRITICAL_EXIT(); p_xfer_fnct(p_ep, p_buf, buf_len, xfer_len, p_arg, err); } else { p_isoc_fnct = (USBH_ISOC_CMPL_FNCT)p_urb->FnctPtr; start_frm = p_isoc_desc->StartFrm; nbr_frm = p_isoc_desc->NbrFrm; p_frm_len = p_isoc_desc->FrmLen; p_frm_err = p_isoc_desc->FrmErr; CPU_CRITICAL_EXIT(); Mem_PoolBlkFree(&p_ep->DevPtr->HC_Ptr->HostPtr->IsocDescPool, p_isoc_desc, &err_lib); p_isoc_fnct(p_ep, p_buf, buf_len, xfer_len, start_frm, nbr_frm, p_frm_len, p_frm_err, p_arg, err); } } else { CPU_CRITICAL_EXIT(); } } /* ********************************************************************************************************* * USBH_URB_Submit() * * Description : Submit given URB to host controller. * * Argument(s) : p_urb Pointer to URB. * * Return(s) : USBH_ERR_NONE, If URB is successfully submitted to host controller. * USBH_ERR_EP_INVALID_STATE, If endpoint is in halt state. * Host controller drivers error code, Otherwise. * * Note(s) : None. ********************************************************************************************************* */ static USBH_ERR USBH_URB_Submit (USBH_URB *p_urb) { USBH_ERR err; CPU_BOOLEAN ep_is_halt; USBH_DEV *p_dev; p_dev = p_urb->EP_Ptr->DevPtr; USBH_HCD_EP_IsHalt(p_dev->HC_Ptr, /* Check EP's state. */ p_urb->EP_Ptr, &ep_is_halt, &err); if ((ep_is_halt == DEF_TRUE) && (err == USBH_ERR_NONE)) { return (USBH_ERR_EP_INVALID_STATE); } p_urb->State = USBH_URB_STATE_SCHEDULED; /* Set URB state to scheduled. */ p_urb->Err = USBH_ERR_NONE; USBH_HCD_URB_Submit(p_dev->HC_Ptr, p_urb, &err); return (err); } /* ********************************************************************************************************* * USBH_URB_Clr() * * Description : Clear URB structure * * Argument(s) : p_urb Pointer to URB structure to clear. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_URB_Clr (USBH_URB *p_urb) { p_urb->Err = USBH_ERR_NONE; p_urb->State = USBH_URB_STATE_NONE; p_urb->AsyncURB_NxtPtr = (USBH_URB *)0; } /* ********************************************************************************************************* * USBH_DfltEP_Open() * * Description : Open default control endpoint of given USB device. * * Argument(s) : p_dev Pointer to USB device * * Return(s) : USBH_ERR_NONE, If control endpoint was successfully opened. * Host controller driver error, otherwise. * * ----- RETURNED BY USBH_OS_SemCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, If semaphore creation failed. * * ----- RETURNED BY USBH_OS_MutexCreate() : ----- * USBH_ERR_OS_SIGNAL_CREATE, If mutex creation failed. * * Note(s) : (1) The maximum packet size is unknown until device descriptor is read. For initial * transfer, the "Universal Serial Bus Specification Revision 2.0", Section 5.5.3 states * that a maximum packet size of 8 should be used for low speed devices and * a maximum packet size of 64 should be used for high speed devices. ********************************************************************************************************* */ static USBH_ERR USBH_DfltEP_Open (USBH_DEV *p_dev) { CPU_INT16U ep_max_pkt_size; USBH_EP *p_ep; USBH_ERR err; p_ep = &p_dev->DfltEP; if (p_ep->IsOpen == DEF_TRUE) { return (USBH_ERR_NONE); } p_ep->DevAddr = 0u; p_ep->DevSpd = p_dev->DevSpd; p_ep->DevPtr = p_dev; if (p_dev->DevSpd == USBH_DEV_SPD_LOW) { /* See Note (1). */ ep_max_pkt_size = 8u; } else { ep_max_pkt_size = 64u; } p_ep->Desc.bLength = 7u; p_ep->Desc.bDescriptorType = USBH_DESC_TYPE_EP; p_ep->Desc.bEndpointAddress = 0u; p_ep->Desc.bmAttributes = USBH_EP_TYPE_CTRL; p_ep->Desc.wMaxPacketSize = ep_max_pkt_size; p_ep->Desc.bInterval = 0u; if (!((p_dev->IsRootHub == DEF_TRUE) && /* Chk if RH fncts are supported before calling HCD. */ (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE))){ USBH_HCD_EP_Open(p_dev->HC_Ptr, /* Open EP. */ p_ep, &err); if (err != USBH_ERR_NONE) { return (err); } } err = USBH_OS_SemCreate(&p_ep->URB.Sem, 0u); /* Create OS resources needed for EP. */ if (err != USBH_ERR_NONE) { return (err); } err = USBH_OS_MutexCreate(&p_ep->Mutex); if (err != USBH_ERR_NONE) { return (err); } p_ep->URB.EP_Ptr = p_ep; p_ep->IsOpen = DEF_TRUE; return (err); } /* ********************************************************************************************************* * USBH_DevDescRd() * * Description : Read device descriptor from device. * * Argument(s) : p_dev Pointer to USB device * * Return(s) : USBH_ERR_NONE, If a valid device descriptor was fetched. * USBH_ERR_DESC_INVALID, If an invalid device descriptor was fetched. * USBH_ERR_DEV_NOT_RESPONDING, If device is not responding. * * ----- RETURNED BY USBH_CtrlTx() : ----- * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : (1) (a) The GET_DESCRIPTOR request is described in "Universal Serial Bus Specification * Revision 2.0", section 9.4.3. * * (b) According the USB Spec, when host doesn't know the control max packet size, it * should assume 8 byte pkt size and request only 8 bytes from device descriptor. ********************************************************************************************************* */ static USBH_ERR USBH_DevDescRd (USBH_DEV *p_dev) { USBH_ERR err; CPU_INT08U retry; USBH_DEV_DESC dev_desc; ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, dev_desc_buf, USBH_LEN_DESC_DEV); retry = 3u; while (retry > 0u) { retry--; /* ---------- READ FIRST 8 BYTES OF DEV DESC ---------- */ USBH_GET_DESC(p_dev, USBH_DESC_TYPE_DEV, 0u, dev_desc_buf, 8u, /* See Note (1). */ &err); if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); USBH_OS_DlyMS(100u); } else { Mem_Copy(p_dev->DevDesc, dev_desc_buf, 8u); break; } } if (err != (USBH_ERR_NONE)) { return (err); } if (!((p_dev->IsRootHub == DEF_TRUE) && (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE))){ /* Retrieve EP 0 max pkt size. */ p_dev->DfltEP.Desc.wMaxPacketSize = MEM_VAL_GET_INT08U(&p_dev->DevDesc[7u]); if (p_dev->DfltEP.Desc.wMaxPacketSize > 64u) { return (USBH_ERR_DESC_INVALID); } USBH_HCD_EP_Close(p_dev->HC_Ptr, &p_dev->DfltEP, &err); USBH_HCD_EP_Open(p_dev->HC_Ptr, /* Modify EP with new max pkt size. */ &p_dev->DfltEP, &err); if (err != USBH_ERR_NONE) { USBH_PRINT_ERR(err); return (err); } } retry = 3u; while(retry > 0u) { retry--; /* ---------------- RD FULL DEV DESC. ----------------- */ USBH_GET_DESC(p_dev, USBH_DESC_TYPE_DEV, 0u, dev_desc_buf, USBH_LEN_DESC_DEV, &err); if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); USBH_OS_DlyMS(100u); } else { Mem_Copy(p_dev->DevDesc, dev_desc_buf, USBH_LEN_DESC_DEV); break; } } if (err != USBH_ERR_NONE) { return (err); } /* ---------------- VALIDATE DEV DESC ----------------- */ USBH_DevDescGet(p_dev, &dev_desc); if ((dev_desc.bLength < USBH_LEN_DESC_DEV) || (dev_desc.bDescriptorType != USBH_DESC_TYPE_DEV) || (dev_desc.bNbrConfigurations == 0u)) { return (USBH_ERR_DESC_INVALID); } if ((dev_desc.bDeviceClass != USBH_CLASS_CODE_USE_IF_DESC ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_AUDIO ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_CDC_CTRL ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_HID ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_PHYSICAL ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_IMAGE ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_PRINTER ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_MASS_STORAGE ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_HUB ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_CDC_DATA ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_SMART_CARD ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_CONTENT_SECURITY ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_VIDEO ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_PERSONAL_HEALTHCARE) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_DIAGNOSTIC_DEV ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_WIRELESS_CTRLR ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_MISCELLANEOUS ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_APP_SPECIFIC ) && (dev_desc.bDeviceClass != USBH_CLASS_CODE_VENDOR_SPECIFIC )) { return (USBH_ERR_DESC_INVALID); } return (USBH_ERR_NONE); } /* ********************************************************************************************************* * USBH_CfgRd() * * Description : Read configuration descriptor for a given configuration number. * * Argument(s) : p_dev Pointer to USB device. * * cfg_ix Configuration number. * * Return(s) : USBH_ERR_NONE, If valid configuration descriptor was fetched. * USBH_ERR_DESC_INVALID, If invalid configuration descriptor was fetched. * USBH_ERR_CFG_MAX_CFG_LEN, If configuration descriptor length > USBH_CFG_MAX_CFG_DATA_LEN * USBH_ERR_NULL_PTR If an invalid null pointer was obtain for 'p_cfg'. * * ----- RETURNED BY USBH_GET_DESC() : ----- * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : (1) The standard GET_DESCRIPTOR request is described in "Universal Serial Bus * Specification Revision 2.0", section 9.4.3. * * (2) According to "Universal Serial Bus Specification Revision 2.0", the standard * configuration descriptor is of length 9 bytes. * * (3) Offset 2 of standard configuration descriptor contains the total length of that * configuration which includes all interfaces and endpoint descriptors. ********************************************************************************************************* */ static USBH_ERR USBH_CfgRd (USBH_DEV *p_dev, CPU_INT08U cfg_ix) { CPU_INT16U w_tot_len; CPU_INT16U b_read; USBH_ERR err; USBH_CFG *p_cfg; CPU_INT08U retry; p_cfg = USBH_CfgGet(p_dev, cfg_ix); if (p_cfg == (USBH_CFG *)0) { return (USBH_ERR_NULL_PTR); } retry = 3u; while(retry > 0u) { retry--; b_read = USBH_GET_DESC(p_dev, /* See Note (1). */ USBH_DESC_TYPE_CFG, cfg_ix, p_cfg->CfgData, USBH_LEN_DESC_CFG, /* See Note (2). */ &err); if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); USBH_OS_DlyMS(100u); } else { break; } } if (err != USBH_ERR_NONE) { return (err); } if (b_read < USBH_LEN_DESC_CFG) { return (USBH_ERR_DESC_INVALID); } if (p_cfg->CfgData[1] != USBH_DESC_TYPE_CFG) { return (USBH_ERR_DESC_INVALID); } w_tot_len = MEM_VAL_GET_INT16U_LITTLE(&p_cfg->CfgData[2]); /* See Note (3). */ if (w_tot_len > USBH_CFG_MAX_CFG_DATA_LEN) { /* Chk total len of config desc. */ return (USBH_ERR_CFG_MAX_CFG_LEN); } retry = 3u; while(retry > 0u) { retry--; b_read = USBH_GET_DESC(p_dev, /* Read full config desc. */ USBH_DESC_TYPE_CFG, cfg_ix, p_cfg->CfgData, w_tot_len, &err); if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); USBH_OS_DlyMS(100u); } else { break; } } if (err != USBH_ERR_NONE) { return (err); } if (b_read < w_tot_len) { return (USBH_ERR_DESC_INVALID); } if (p_cfg->CfgData[1] != USBH_DESC_TYPE_CFG) { /* Validate config desc. */ return (USBH_ERR_DESC_INVALID); } p_cfg->CfgDataLen = w_tot_len; err = USBH_CfgParse(p_dev, p_cfg); return (err); } /* ********************************************************************************************************* * USBH_CfgParse() * * Description : Parse given configuration descriptor. * * Argument(s) : p_dev Pointer to USB Device. * * p_cfg Pointer to USB configuration. * * Return(s) : USBH_ERR_NONE If configuration descriptor successfully parsed. * USBH_ERR_IF_ALLOC If number of interfaces > USBH_CFG_MAX_NBR_IFS. * USBH_ERR_DESC_INVALID If any descriptor in this configuration is invalid. * * Note(s) : None. ********************************************************************************************************* */ static USBH_ERR USBH_CfgParse (USBH_DEV *p_dev, USBH_CFG *p_cfg) { CPU_INT08S if_ix; CPU_INT08U nbr_ifs; CPU_INT32U cfg_off; USBH_IF *p_if; USBH_DESC_HDR *p_desc; USBH_CFG_DESC cfg_desc; USBH_IF_DESC if_desc; USBH_EP_DESC ep_desc; cfg_off = 0u; p_desc = (USBH_DESC_HDR *)p_cfg->CfgData; /* ---------------- VALIDATE CFG DESC ----------------- */ USBH_ParseCfgDesc(&cfg_desc, p_desc); if ((cfg_desc.bMaxPower > 250u) || (cfg_desc.bNbrInterfaces == 0u)) { return (USBH_ERR_DESC_INVALID); } nbr_ifs = USBH_CfgIF_NbrGet(p_cfg); /* Nbr of IFs present in config. */ if (nbr_ifs > USBH_CFG_MAX_NBR_IFS) { return (USBH_ERR_IF_ALLOC); } if_ix = 0u; p_if = (USBH_IF *)0; while (cfg_off < p_cfg->CfgDataLen) { p_desc = USBH_NextDescGet((void *)p_desc, &cfg_off); /* ---------- VALIDATE INTERFACE DESCRIPTOR ----------- */ if (p_desc->bDescriptorType == USBH_DESC_TYPE_IF) { USBH_ParseIF_Desc(&if_desc, p_desc); if ((if_desc.bInterfaceClass != USBH_CLASS_CODE_AUDIO ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_CDC_CTRL ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_HID ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_PHYSICAL ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_IMAGE ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_PRINTER ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_MASS_STORAGE ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_HUB ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_CDC_DATA ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_SMART_CARD ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_CONTENT_SECURITY ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_VIDEO ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_PERSONAL_HEALTHCARE) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_DIAGNOSTIC_DEV ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_WIRELESS_CTRLR ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_MISCELLANEOUS ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_APP_SPECIFIC ) && (if_desc.bInterfaceClass != USBH_CLASS_CODE_VENDOR_SPECIFIC )) { return (USBH_ERR_DESC_INVALID); } if ((if_desc.bNbrEndpoints > 30u)) { return (USBH_ERR_DESC_INVALID); } if (if_desc.bAlternateSetting == 0u) { p_if = &p_cfg->IF_List[if_ix]; p_if->DevPtr = (USBH_DEV *)p_dev; p_if->IF_DataPtr = (CPU_INT08U *)p_desc; p_if->IF_DataLen = 0u; if_ix++; } } if (p_desc->bDescriptorType == USBH_DESC_TYPE_EP) { USBH_ParseEP_Desc(&ep_desc, p_desc); if ((ep_desc.bEndpointAddress == 0x00u) || (ep_desc.bEndpointAddress == 0x80u) || (ep_desc.wMaxPacketSize == 0u)){ return (USBH_ERR_DESC_INVALID); } } if (p_if != (USBH_IF *)0) { p_if->IF_DataLen += p_desc->bLength; } } if (if_ix != nbr_ifs) { /* IF count must match max nbr of IFs. */ return (USBH_ERR_DESC_INVALID); } return (USBH_ERR_NONE); } /* ********************************************************************************************************* * USBH_DevAddrSet() * * Description : Assign address to given USB device. * * Argument(s) : p_dev Pointer to USB device. * * Return(s) : USBH_ERR_NONE, If device address was successfully set. * Host controller driver error, Otherwise. * * ----- RETURNED BY USBH_SET_ADDR() : ----- * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Note(s) : (1) The SET_ADDRESS request is described in "Universal Serial Bus Specification * Revision 2.0", section 9.4.6. * * (2) USB 2.0 spec states that after issuing SET_ADDRESS request, the host must wait * at least 2 millisecs. During this time the device will go into the addressed state. ********************************************************************************************************* */ static USBH_ERR USBH_DevAddrSet (USBH_DEV *p_dev) { USBH_ERR err; CPU_INT08U retry; retry = 3u; while(retry > 0u) { retry--; USBH_SET_ADDR(p_dev, p_dev->DevAddr, &err); /* See Note (1). */ if (err != USBH_ERR_NONE) { USBH_EP_Reset(p_dev, (USBH_EP *)0); USBH_OS_DlyMS(100u); } else { break; } } if (err != USBH_ERR_NONE) { return (err); } if ((p_dev->IsRootHub == DEF_TRUE) && (p_dev->HC_Ptr->IsVirRootHub == DEF_TRUE)) { return (USBH_ERR_NONE); } USBH_HCD_EP_Close(p_dev->HC_Ptr, &p_dev->DfltEP, &err); p_dev->DfltEP.DevAddr = p_dev->DevAddr; /* Update addr. */ USBH_HCD_EP_Open(p_dev->HC_Ptr, /* Modify ctrl EP with new USB addr. */ &p_dev->DfltEP, &err); if (err != USBH_ERR_NONE) { return (err); } USBH_OS_DlyMS(2u); /* See Note (2). */ return (err); } /* ********************************************************************************************************* * USBH_StrDescGet() * * Description : Read specified string descriptor from USB device. * * Argument(s) : p_dev Pointer to USB device. * * desc_ix Index of the string descriptor. * * lang_id Language identifier. * * p_buf Buffer in which the string descriptor will be stored. * * buf_len Buffer length, in octets. * * p_err Pointer to variable that will receive the return error code from this function : * * USBH_ERR_NONE, String descriptor successfully fetched. * USBH_ERR_DESC_INVALID, Invalid string descriptor fetched. * * ----- RETURNED BY USBH_CtrlRx() : ----- * USBH_ERR_UNKNOWN, Unknown error occurred. * USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'. * USBH_ERR_EP_INVALID_STATE, Endpoint is not opened. * USBH_ERR_HC_IO, Root hub input/output error. * USBH_ERR_EP_STALL, Root hub does not support request. * Host controller drivers error code, Otherwise. * * Return(s) : Length of string descriptor. * * Note(s) : None. ********************************************************************************************************* */ static CPU_INT32U USBH_StrDescGet (USBH_DEV *p_dev, CPU_INT08U desc_ix, CPU_INT16U lang_id, void *p_buf, CPU_INT32U buf_len, USBH_ERR *p_err) { CPU_INT32U len; CPU_INT32U req_len; CPU_INT08U i; USBH_DESC_HDR *p_hdr; if(desc_ix == USBH_STRING_DESC_LANGID) { req_len = 0x04u; /* Size of lang ID = 4. */ } else { req_len = USBH_LEN_DESC_HDR; } req_len = DEF_MIN(req_len, buf_len); for (i = 0u; i < USBH_CFG_STD_REQ_RETRY; i++) { /* Retry up to 3 times. */ len = USBH_CtrlRx(p_dev, USBH_REQ_GET_DESC, USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_RECIPIENT_DEV, (USBH_DESC_TYPE_STR << 8u) | desc_ix, lang_id, p_buf, req_len, USBH_CFG_STD_REQ_TIMEOUT, p_err); if ((len == 0u ) || (*p_err == USBH_ERR_EP_STALL)) { USBH_EP_Reset(p_dev, (USBH_EP *)0); /* Rst EP to clr HC halt state. */ } else { break; } } if (*p_err != USBH_ERR_NONE) { return (0u); } p_hdr = (USBH_DESC_HDR *)p_buf; if ((len == req_len ) && /* Chk desc hdr. */ (p_hdr->bLength != 0u ) && (p_hdr->bDescriptorType == USBH_DESC_TYPE_STR)) { len = p_hdr->bLength; if (desc_ix == USBH_STRING_DESC_LANGID) { return (len); } } else { *p_err = USBH_ERR_DESC_INVALID; return (0u); } if (len > buf_len) { len = buf_len; } /* Get full str desc. */ for (i = 0u; i < USBH_CFG_STD_REQ_RETRY; i++) { /* Retry up to 3 times. */ len = USBH_CtrlRx(p_dev, USBH_REQ_GET_DESC, USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_RECIPIENT_DEV, (USBH_DESC_TYPE_STR << 8) | desc_ix, lang_id, p_buf, len, USBH_CFG_STD_REQ_TIMEOUT, p_err); if ((len == 0u ) || (*p_err == USBH_ERR_EP_STALL)) { USBH_EP_Reset(p_dev, (USBH_EP *)0); } else { break; } } if (*p_err != USBH_ERR_NONE) { return (0u); } if (len == 0u) { *p_err = USBH_ERR_DESC_INVALID; return (0u); } return (len); } /* ********************************************************************************************************* * USBH_StrDescPrint() * * Description : Print specified string index to default output terminal. * * Argument(s) : p_dev Pointer to USB device. * * str_prefix Caller's specific prefix string to add. * * desc_ix String descriptor index. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ #if (USBH_CFG_PRINT_LOG == DEF_ENABLED) static void USBH_StrDescPrint (USBH_DEV *p_dev, CPU_INT08U *str_prefix, CPU_INT08U desc_ix) { USBH_ERR err; CPU_INT32U str_len; ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, str, USBH_CFG_MAX_STR_LEN); CPU_INT16U ch; CPU_INT32U ix; CPU_INT32U buf_len; str_len = USBH_StrGet(p_dev, desc_ix, USBH_STRING_DESC_LANGID, &str[0], USBH_CFG_MAX_STR_LEN, &err); USBH_PRINT_LOG("%s", str_prefix); /* Print prefix str. */ if (str_len > 0u) { /* Print unicode string rd from the dev. */ buf_len = str_len * 2u; for (ix = 0u; (buf_len - ix) >= 2u; ix += 2u) { ch = MEM_VAL_GET_INT16U_LITTLE(&str[ix]); if (ch == 0u) { break; } USBH_PRINT_LOG("%c", ch); } } USBH_PRINT_LOG("\r\n"); } #endif /* ********************************************************************************************************* * USBH_NextDescGet() * * Description : Get pointer to next descriptor in buffer that contains configuration data. * * Argument(s) : p_buf Pointer to current header in buffer. * * p_off Pointer to buffer offset. * * Return(s) : Pointer to next descriptor header. * * Note(s) : None. ********************************************************************************************************* */ static USBH_DESC_HDR *USBH_NextDescGet (void *p_buf, CPU_INT32U *p_offset) { USBH_DESC_HDR *p_next_hdr; USBH_DESC_HDR *p_hdr; p_hdr = (USBH_DESC_HDR *)p_buf; /* Current desc hdr. */ if (*p_offset == 0u) { /* 1st desc in buf. */ p_next_hdr = p_hdr; } else { /* Next desc is at end of current desc. */ p_next_hdr = (USBH_DESC_HDR *)((CPU_INT08U *)p_buf + p_hdr->bLength); } *p_offset += p_hdr->bLength; /* Update buf offset. */ return (p_next_hdr); } /* ********************************************************************************************************* * USBH_FmtSetupReq() * * Description : Format setup request from setup request structure. * * Argument(s) : p_setup_req Variable that holds setup request information. * * p_buf_dest Pointer to buffer that will receive setup request. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_FmtSetupReq (USBH_SETUP_REQ *p_setup_req, void *p_buf_dest) { USBH_SETUP_REQ *p_buf_dest_setup_req; p_buf_dest_setup_req = (USBH_SETUP_REQ *)p_buf_dest; p_buf_dest_setup_req->bmRequestType = p_setup_req->bmRequestType; p_buf_dest_setup_req->bRequest = p_setup_req->bRequest; p_buf_dest_setup_req->wValue = MEM_VAL_GET_INT16U_LITTLE(&p_setup_req->wValue); p_buf_dest_setup_req->wIndex = MEM_VAL_GET_INT16U_LITTLE(&p_setup_req->wIndex); p_buf_dest_setup_req->wLength = MEM_VAL_GET_INT16U_LITTLE(&p_setup_req->wLength); } /* ********************************************************************************************************* * USBH_ParseDevDesc() * * Description : Parse device descriptor into device descriptor structure. * * Argument(s) : p_dev_desc Variable that will hold parsed device descriptor. * * p_buf_src Pointer to buffer that holds device descriptor. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_ParseDevDesc (USBH_DEV_DESC *p_dev_desc, void *p_buf_src) { USBH_DEV_DESC *p_buf_src_dev_desc; p_buf_src_dev_desc = (USBH_DEV_DESC *)p_buf_src; p_dev_desc->bLength = p_buf_src_dev_desc->bLength; p_dev_desc->bDescriptorType = p_buf_src_dev_desc->bDescriptorType; p_dev_desc->bcdUSB = MEM_VAL_GET_INT16U_LITTLE(&p_buf_src_dev_desc->bcdUSB); p_dev_desc->bDeviceClass = p_buf_src_dev_desc->bDeviceClass; p_dev_desc->bDeviceSubClass = p_buf_src_dev_desc->bDeviceSubClass; p_dev_desc->bDeviceProtocol = p_buf_src_dev_desc->bDeviceProtocol; p_dev_desc->bMaxPacketSize0 = p_buf_src_dev_desc->bMaxPacketSize0; p_dev_desc->idVendor = MEM_VAL_GET_INT16U_LITTLE(&p_buf_src_dev_desc->idVendor); p_dev_desc->idProduct = MEM_VAL_GET_INT16U_LITTLE(&p_buf_src_dev_desc->idProduct); p_dev_desc->bcdDevice = MEM_VAL_GET_INT16U_LITTLE(&p_buf_src_dev_desc->bcdDevice); p_dev_desc->iManufacturer = p_buf_src_dev_desc->iManufacturer; p_dev_desc->iProduct = p_buf_src_dev_desc->iProduct; p_dev_desc->iSerialNumber = p_buf_src_dev_desc->iSerialNumber; p_dev_desc->bNbrConfigurations = p_buf_src_dev_desc->bNbrConfigurations; } /* ********************************************************************************************************* * USBH_ParseCfgDesc() * * Description : Parse configuration descriptor into configuration descriptor structure. * * Argument(s) : p_cfg_desc Variable that will hold parsed configuration descriptor. * * p_buf_src Pointer to buffer that holds configuration descriptor. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_ParseCfgDesc (USBH_CFG_DESC *p_cfg_desc, void *p_buf_src) { USBH_CFG_DESC *p_buf_src_cfg_desc; p_buf_src_cfg_desc = (USBH_CFG_DESC *)p_buf_src; p_cfg_desc->bLength = p_buf_src_cfg_desc->bLength; p_cfg_desc->bDescriptorType = p_buf_src_cfg_desc->bDescriptorType; p_cfg_desc->wTotalLength = MEM_VAL_GET_INT16U_LITTLE(&p_buf_src_cfg_desc->wTotalLength); p_cfg_desc->bNbrInterfaces = p_buf_src_cfg_desc->bNbrInterfaces; p_cfg_desc->bConfigurationValue = p_buf_src_cfg_desc->bConfigurationValue; p_cfg_desc->iConfiguration = p_buf_src_cfg_desc->iConfiguration; p_cfg_desc->bmAttributes = p_buf_src_cfg_desc->bmAttributes; p_cfg_desc->bMaxPower = p_buf_src_cfg_desc->bMaxPower; } /* ********************************************************************************************************* * USBH_ParseIF_Desc() * * Description : Parse interface descriptor into interface descriptor structure. * * Argument(s) : p_if_desc Variable that will hold parsed interface descriptor. * * p_buf_src Pointer to buffer that holds interface descriptor. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_ParseIF_Desc (USBH_IF_DESC *p_if_desc, void *p_buf_src) { USBH_IF_DESC *p_buf_src_if_desc; p_buf_src_if_desc = (USBH_IF_DESC *)p_buf_src; p_if_desc->bLength = p_buf_src_if_desc->bLength; p_if_desc->bDescriptorType = p_buf_src_if_desc->bDescriptorType; p_if_desc->bInterfaceNumber = p_buf_src_if_desc->bInterfaceNumber; p_if_desc->bAlternateSetting = p_buf_src_if_desc->bAlternateSetting; p_if_desc->bNbrEndpoints = p_buf_src_if_desc->bNbrEndpoints; p_if_desc->bInterfaceClass = p_buf_src_if_desc->bInterfaceClass; p_if_desc->bInterfaceSubClass = p_buf_src_if_desc->bInterfaceSubClass; p_if_desc->bInterfaceProtocol = p_buf_src_if_desc->bInterfaceProtocol; p_if_desc->iInterface = p_buf_src_if_desc->iInterface; } /* ********************************************************************************************************* * USBH_ParseEP_Desc() * * Description : Parse endpoint descriptor into endpoint descriptor structure. * * Argument(s) : p_ep_desc Variable that will hold the parsed endpoint descriptor. * * p_buf_src Pointer to buffer that holds endpoint descriptor. * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_ParseEP_Desc (USBH_EP_DESC *p_ep_desc, void *p_buf_src) { USBH_EP_DESC *p_buf_desc; p_buf_desc = (USBH_EP_DESC *)p_buf_src; p_ep_desc->bLength = p_buf_desc->bLength; p_ep_desc->bDescriptorType = p_buf_desc->bDescriptorType; p_ep_desc->bEndpointAddress = p_buf_desc->bEndpointAddress; p_ep_desc->bmAttributes = p_buf_desc->bmAttributes; p_ep_desc->wMaxPacketSize = MEM_VAL_GET_INT16U_LITTLE(&p_buf_desc->wMaxPacketSize); p_ep_desc->bInterval = p_buf_desc->bInterval; /* Following fields only relevant for isoc EPs. */ if ((p_ep_desc->bmAttributes & 0x03) == USBH_EP_TYPE_ISOC) { p_ep_desc->bRefresh = p_buf_desc->bRefresh; p_ep_desc->bSynchAddress = p_buf_desc->bSynchAddress; } } /* ********************************************************************************************************* * USBH_AsyncTask() * * Description : Task that process asynchronous URBs * * Argument(s) : p_arg Pointer to a variable (Here it is 0) * * Return(s) : None. * * Note(s) : None. ********************************************************************************************************* */ static void USBH_AsyncTask (void *p_arg) { USBH_URB *p_urb; CPU_SR_ALLOC(); (void)p_arg; while (DEF_TRUE) { (void)USBH_OS_SemWait(USBH_URB_Sem, 0u); /* Wait for URBs processed by HC. */ CPU_CRITICAL_ENTER(); p_urb = (USBH_URB *)USBH_URB_HeadPtr; if (USBH_URB_HeadPtr == USBH_URB_TailPtr) { USBH_URB_HeadPtr = (USBH_URB *)0; USBH_URB_TailPtr = (USBH_URB *)0; } else { USBH_URB_HeadPtr = USBH_URB_HeadPtr->NxtPtr; } CPU_CRITICAL_EXIT(); if (p_urb != (USBH_URB *)0) { USBH_URB_Complete(p_urb); } } }