/** * @brief USBH_RegisterClass * Link class driver to Host Core. * @param phost : Host Handle * @param pclass: Class handle * @retval USBH Status */ USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass) { USBH_StatusTypeDef status = USBH_OK; if(pclass != 0) { if(phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS) { /* link the class to the USB Host handle */ phost->pClass[phost->ClassNumber++] = pclass; status = USBH_OK; } else { USBH_ErrLog("Max Class Number reached"); status = USBH_FAIL; } } else { USBH_ErrLog("Invalid Class handle"); status = USBH_FAIL; } return status; }
/** * @brief Writes Sector(s) * @param lun : lun id * @param *buff: Data to be written * @param sector: Sector address (LBA) * @param count: Number of sectors to write (1..128) * @retval DRESULT: Operation result */ DRESULT USBH_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count) { DRESULT res = RES_ERROR; MSC_LUNTypeDef info; USBH_StatusTypeDef status = USBH_OK; if ((DWORD)buff & 3) /* DMA Alignment issue, do single up to aligned buffer */ { #if _USE_BUFF_WO_ALIGNMENT == 0 while (count--) { memcpy (scratch, &buff[count * _MAX_SS], _MAX_SS); status = USBH_MSC_Write(&usb_msc_host_param[lun], lun, sector + count, (BYTE *)scratch, 1) ; if(status == USBH_FAIL) { break; } } #else return res; #endif } else { status = USBH_MSC_Write(&usb_msc_host_param[lun], lun, sector, (BYTE *)buff, count); } if(status == USBH_OK) { res = RES_OK; } else { USBH_MSC_GetLUNInfo(&usb_msc_host_param[lun], lun, &info); switch (info.sense.asc) { case SCSI_ASC_WRITE_PROTECTED: USBH_ErrLog("USB Disk is Write protected!"); res = RES_WRPRT; break; case SCSI_ASC_LOGICAL_UNIT_NOT_READY: case SCSI_ASC_MEDIUM_NOT_PRESENT: case SCSI_ASC_NOT_READY_TO_READY_CHANGE: USBH_ErrLog("USB Disk is not ready!"); res = RES_NOTRDY; break; default: res = RES_ERROR; break; } } return res; }
void* fakemalloc(size_t size){ if (size > 256){ USBH_ErrLog("fakemalloc: can't allocate..."); } if (memused){ USBH_ErrLog("fakemalloc: already taken..."); } memused = 1; return (void*)mem; }
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, BYTE count) { DRESULT res = RES_ERROR; MSC_LUNTypeDef info; USBH_StatusTypeDef status = USBH_OK; DWORD scratch [_MAX_SS / 4]; if ((DWORD)buff & 3) /* DMA Alignment issue, do single up to aligned buffer */ { while (count--) { memcpy (scratch, &buff[count * _MAX_SS], _MAX_SS); status = USBH_MSC_Write(&hUSBHost_HS, pdrv, sector + count, (BYTE *)scratch, 1) ; if(status == USBH_FAIL) { break; } } } else { status = USBH_MSC_Write(&hUSBHost_HS, pdrv, sector, (BYTE *)buff, count); } if(status == USBH_OK) { res = RES_OK; } else { USBH_MSC_GetLUNInfo(&hUSBHost_HS, pdrv, &info); switch (info.sense.asc) { case SCSI_ASC_WRITE_PROTECTED: USBH_ErrLog("USB Disk is Write protected!"); res = RES_WRPRT; break; case SCSI_ASC_LOGICAL_UNIT_NOT_READY: case SCSI_ASC_MEDIUM_NOT_PRESENT: case SCSI_ASC_NOT_READY_TO_READY_CHANGE: USBH_ErrLog("USB Disk is not ready!"); res = RES_NOTRDY; break; default: res = RES_ERROR; break; } } return res; }
/** * @brief Reads Sector(s) * @param lun : lun id * @param *buff: Data buffer to store read data * @param sector: Sector address (LBA) * @param count: Number of sectors to read (1..128) * @retval DRESULT: Operation result */ DRESULT USBH_read(BYTE lun, BYTE *buff, DWORD sector, UINT count) { DRESULT res = RES_ERROR; MSC_LUNTypeDef info; USBH_StatusTypeDef status = USBH_OK; if ((DWORD)buff & 3) /* DMA Alignment issue, do single up to aligned buffer */ { #if _USE_BUFF_WO_ALIGNMENT == 0 while ((count--)&&(status == USBH_OK)) { status = USBH_MSC_Read(&HOST_HANDLE, lun, sector + count, (uint8_t *)scratch, 1); if(status == USBH_OK) { memcpy (&buff[count * _MAX_SS] ,scratch, _MAX_SS); } else { break; } } #else return res; #endif } else { status = USBH_MSC_Read(&HOST_HANDLE, lun, sector, buff, count); } if(status == USBH_OK) { res = RES_OK; } else { USBH_MSC_GetLUNInfo(&HOST_HANDLE, lun, &info); switch (info.sense.asc) { case SCSI_ASC_LOGICAL_UNIT_NOT_READY: case SCSI_ASC_MEDIUM_NOT_PRESENT: case SCSI_ASC_NOT_READY_TO_READY_CHANGE: USBH_ErrLog ("USB Disk is not ready!"); res = RES_NOTRDY; break; default: res = RES_ERROR; break; } } return res; }
/** * @brief Reads Sector * @param pdrv: Physical drive number * @param *buff: Data buffer to store read data * @param sector: Sector address (LBA) * @param count: Number of sectors to read * @retval DRESULT: Operation result */ DRESULT disk_read (BYTE pdrv, BYTE *buff, DWORD sector, BYTE count) { DRESULT res = RES_ERROR; MSC_LUNTypeDef info; USBH_StatusTypeDef status = USBH_OK; DWORD scratch [_MAX_SS / 4]; if ((DWORD)buff & 3) /* DMA Alignment issue, do single up to aligned buffer */ { while ((count--)&&(status == USBH_OK)) { status = USBH_MSC_Read(&hUSBHost, pdrv, sector + count, (uint8_t *)scratch, 1); if(status == USBH_OK) { memcpy(&buff[count * _MAX_SS], scratch, _MAX_SS); } else { break; } } } else { status = USBH_MSC_Read(&hUSBHost, pdrv, sector, buff, count); } if(status == USBH_OK) { res = RES_OK; } else { USBH_MSC_GetLUNInfo(&hUSBHost, pdrv, &info); switch (info.sense.asc) { case SCSI_ASC_LOGICAL_UNIT_NOT_READY: case SCSI_ASC_MEDIUM_NOT_PRESENT: case SCSI_ASC_NOT_READY_TO_READY_CHANGE: USBH_ErrLog("USB Disk is not ready!"); res = RES_NOTRDY; break; default: res = RES_ERROR; break; } } return res; }
/** * @brief HCD_Init * Initialize the HOST Core. * @param phost: Host Handle * @param pUsrFunc: User Callback * @retval USBH Status */ USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id) { /* Check whether the USB Host handle is valid */ if(phost == NULL) { USBH_ErrLog("Invalid Host handle"); return USBH_FAIL; } /* Set DRiver ID */ phost->id = id; /* Unlink class*/ phost->pActiveClass = NULL; phost->ClassNumber = 0; /* Restore default states and prepare EP0 */ DeInitStateMachine(phost); /* Assign User process */ if(pUsrFunc != NULL) { phost->pUser = pUsrFunc; } #if (USBH_USE_OS == 1) /* Create USB Host Queue */ osMessageQDef(USBH_Queue, 10, uint16_t); phost->os_event = osMessageCreate (osMessageQ(USBH_Queue), NULL); /*Create USB Host Task */ #if defined (USBH_PROCESS_STACK_SIZE) osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, USBH_PROCESS_STACK_SIZE); #else osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, 8 * configMINIMAL_STACK_SIZE); #endif phost->thread = osThreadCreate (osThread(USBH_Thread), phost); #endif /* Initialize low level driver */ USBH_LL_Init(phost); return USBH_OK; }
/** * @brief USBH_SelectInterface * Select current interface. * @param phost: Host Handle * @param interface: Interface number * @retval USBH Status */ USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface) { USBH_StatusTypeDef status = USBH_OK; if(interface < phost->device.CfgDesc.bNumInterfaces) { phost->device.current_interface = interface; USBH_UsrLog ("Switching to Interface (#%d)", interface); USBH_UsrLog ("Class : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass ); USBH_UsrLog ("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass ); USBH_UsrLog ("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol ); } else { USBH_ErrLog ("Cannot Select This Interface."); status = USBH_FAIL; } return status; }
/** * @brief USBH_HandleControl * Handles the USB control transfer state machine * @param phost: Host Handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost) { uint8_t direction; USBH_StatusTypeDef status = USBH_BUSY; USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; switch (phost->Control.state) { case CTRL_SETUP: /* send a SETUP packet */ USBH_CtlSendSetup (phost, (uint8_t *)phost->Control.setup.d8 , phost->Control.pipe_out); phost->Control.state = CTRL_SETUP_WAIT; break; case CTRL_SETUP_WAIT: URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out); /* case SETUP packet sent successfully */ if(URB_Status == USBH_URB_DONE) { direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK); /* check if there is a data stage */ if (phost->Control.setup.b.wLength.w != 0 ) { if (direction == USB_D2H) { /* Data Direction is IN */ phost->Control.state = CTRL_DATA_IN; } else { /* Data Direction is OUT */ phost->Control.state = CTRL_DATA_OUT; } } /* No DATA stage */ else { /* If there is No Data Transfer Stage */ if (direction == USB_D2H) { /* Data Direction is IN */ phost->Control.state = CTRL_STATUS_OUT; } else { /* Data Direction is OUT */ phost->Control.state = CTRL_STATUS_IN; } } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if(URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_DATA_IN: /* Issue an IN token */ phost->Control.timer = phost->Timer; USBH_CtlReceiveData(phost, phost->Control.buff, phost->Control.length, phost->Control.pipe_in); phost->Control.state = CTRL_DATA_IN_WAIT; break; case CTRL_DATA_IN_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); /* check is DATA packet transfered successfully */ if (URB_Status == USBH_URB_DONE) { phost->Control.state = CTRL_STATUS_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } /* manage error cases*/ if (URB_Status == USBH_URB_STALL) { /* In stall case, return to previous machine state*/ status = USBH_NOT_SUPPORTED; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { /* Device error */ phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_DATA_OUT: USBH_CtlSendData (phost, phost->Control.buff, phost->Control.length , phost->Control.pipe_out, 1); phost->Control.timer = phost->Timer; phost->Control.state = CTRL_DATA_OUT_WAIT; break; case CTRL_DATA_OUT_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); if (URB_Status == USBH_URB_DONE) { /* If the Setup Pkt is sent successful, then change the state */ phost->Control.state = CTRL_STATUS_IN; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } /* handle error cases */ else if (URB_Status == USBH_URB_STALL) { /* In stall case, return to previous machine state*/ phost->Control.state = CTRL_STALLED; status = USBH_NOT_SUPPORTED; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_NOTREADY) { /* Nack received from device */ phost->Control.state = CTRL_DATA_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { /* device error */ phost->Control.state = CTRL_ERROR; status = USBH_FAIL; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_STATUS_IN: /* Send 0 bytes out packet */ USBH_CtlReceiveData (phost, 0, 0, phost->Control.pipe_in); phost->Control.timer = phost->Timer; phost->Control.state = CTRL_STATUS_IN_WAIT; break; case CTRL_STATUS_IN_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); if ( URB_Status == USBH_URB_DONE) { /* Control transfers completed, Exit the State Machine */ phost->Control.state = CTRL_COMPLETE; status = USBH_OK; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if(URB_Status == USBH_URB_STALL) { /* Control transfers completed, Exit the State Machine */ status = USBH_NOT_SUPPORTED; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_STATUS_OUT: USBH_CtlSendData (phost, 0, 0, phost->Control.pipe_out, 1); phost->Control.timer = phost->Timer; phost->Control.state = CTRL_STATUS_OUT_WAIT; break; case CTRL_STATUS_OUT_WAIT: URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); if (URB_Status == USBH_URB_DONE) { status = USBH_OK; phost->Control.state = CTRL_COMPLETE; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_NOTREADY) { phost->Control.state = CTRL_STATUS_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } else if (URB_Status == USBH_URB_ERROR) { phost->Control.state = CTRL_ERROR; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); #endif } break; case CTRL_ERROR: /* After a halt condition is encountered or an error is detected by the host, a control endpoint is allowed to recover by accepting the next Setup PID; i.e., recovery actions via some other pipe are not required for control endpoints. For the Default Control Pipe, a device reset will ultimately be required to clear the halt or error condition if the next Setup PID is not accepted. */ if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT) { /* try to recover control */ USBH_LL_Stop(phost); /* Do the transmission again, starting from SETUP Packet */ phost->Control.state = CTRL_SETUP; phost->RequestState = CMD_SEND; } else { phost->Control.errorcount = 0; USBH_ErrLog("Control error"); status = USBH_FAIL; } break; default: break; } return status; }
/** * @brief USBH_Process * Background process of the USB Core. * @param phost: Host Handle * @retval USBH Status */ USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) { __IO USBH_StatusTypeDef status = USBH_FAIL; uint8_t idx = 0; switch (phost->gState) { case HOST_IDLE : if (phost->device.is_connected) { /* Wait for 200 ms after connection */ phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT; USBH_Delay(200); USBH_LL_ResetPort(phost); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); #endif } break; case HOST_DEV_WAIT_FOR_ATTACHMENT: break; case HOST_DEV_ATTACHED : USBH_UsrLog("USB Device Attached"); /* Wait for 100 ms after Reset */ USBH_Delay(100); phost->device.speed = USBH_LL_GetSpeed(phost); phost->gState = HOST_ENUMERATION; phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00); phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80); /* Open Control pipes */ USBH_OpenPipe (phost, phost->Control.pipe_in, 0x80, phost->device.address, phost->device.speed, USBH_EP_CONTROL, phost->Control.pipe_size); /* Open Control pipes */ USBH_OpenPipe (phost, phost->Control.pipe_out, 0x00, phost->device.address, phost->device.speed, USBH_EP_CONTROL, phost->Control.pipe_size); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); #endif break; case HOST_ENUMERATION: /* Check for enumeration status */ if ( USBH_HandleEnum(phost) == USBH_OK) { /* The function shall return USBH_OK when full enumeration is complete */ USBH_UsrLog ("Enumeration done."); phost->device.current_interface = 0; if(phost->device.DevDesc.bNumConfigurations == 1) { USBH_UsrLog ("This device has only 1 configuration."); phost->gState = HOST_SET_CONFIGURATION; } else { phost->gState = HOST_INPUT; } } break; case HOST_INPUT: { /* user callback for end of device basic enumeration */ if(phost->pUser != NULL) { phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION); phost->gState = HOST_SET_CONFIGURATION; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif } } break; case HOST_SET_CONFIGURATION: /* set configuration */ if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK) { phost->gState = HOST_CHECK_CLASS; USBH_UsrLog ("Default configuration set."); } break; case HOST_CHECK_CLASS: if(phost->ClassNumber == 0) { USBH_UsrLog ("No Class has been registered."); } else { phost->pActiveClass = NULL; for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++) { if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass) { phost->pActiveClass = phost->pClass[idx]; } } if(phost->pActiveClass != NULL) { if(phost->pActiveClass->Init(phost)== USBH_OK) { phost->gState = HOST_CLASS_REQUEST; USBH_UsrLog ("%s class started.", phost->pActiveClass->Name); /* Inform user that a class has been activated */ phost->pUser(phost, HOST_USER_CLASS_SELECTED); } else { phost->gState = HOST_ABORT_STATE; USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name); } } else { phost->gState = HOST_ABORT_STATE; USBH_UsrLog ("No registered class for this device."); } } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif break; case HOST_CLASS_REQUEST: /* process class standard control requests state machine */ if(phost->pActiveClass != NULL) { status = phost->pActiveClass->Requests(phost); if(status == USBH_OK) { phost->gState = HOST_CLASS; } } else { phost->gState = HOST_ABORT_STATE; USBH_ErrLog ("Invalid Class Driver."); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif } break; case HOST_CLASS: /* process class state machine */ if(phost->pActiveClass != NULL) { phost->pActiveClass->BgndProcess(phost); } break; case HOST_DEV_DISCONNECTED : DeInitStateMachine(phost); /* Re-Initilaize Host for new Enumeration */ if(phost->pActiveClass != NULL) { phost->pActiveClass->DeInit(phost); phost->pActiveClass = NULL; } break; case HOST_ABORT_STATE: default : break; } return USBH_OK; }