/* * (C) Copyright 2017 Fuzhou Rockchip Electronics Co., Ltd * Seth Liu 2017.03.01 * * SPDX-License-Identifier: GPL-2.0+ */ #include "RKComm.h" #include "RKLog.h" #include "Endian.h" extern unsigned short CRC_CCITT(unsigned char* p, UINT CalculateNumber); CRKComm::CRKComm(CRKLog *pLog) { memset(&m_deviceDesc,0,sizeof(STRUCT_RKDEVICE_DESC)); m_log = pLog; } CRKComm::~CRKComm() { } CRKUsbComm::CRKUsbComm(STRUCT_RKDEVICE_DESC devDesc, CRKLog *pLog, bool &bRet):CRKComm(pLog) { bRet = InitializeUsb(devDesc); } CRKUsbComm::~CRKUsbComm() { UninitializeUsb(); } bool CRKUsbComm::InitializeUsb(STRUCT_RKDEVICE_DESC devDesc) { m_pUsbHandle = NULL; m_pipeBulkIn = m_pipeBulkOut = 0; m_interfaceNum = -1; if (!devDesc.pUsbHandle) { return false; } memcpy(&m_deviceDesc, &devDesc, sizeof(STRUCT_RKDEVICE_DESC)); int iRet; iRet = libusb_open((libusb_device *)devDesc.pUsbHandle, (libusb_device_handle **)&m_pUsbHandle); if (iRet!=0) { if (m_log) { m_log->Record("Error:InitializeUsb-->open device failed,err=%d", iRet); } return false; } struct libusb_config_descriptor *pConfigDesc=NULL; iRet = libusb_get_active_config_descriptor((libusb_device *)devDesc.pUsbHandle, &pConfigDesc); if (iRet!=0) { if (m_log) { m_log->Record("Error:InitializeUsb-->get device config descriptor failed, err=%d", iRet); } return false; } int i, j, k; const struct libusb_interface *pInterface; const struct libusb_endpoint_descriptor *pEndpointDesc; const struct libusb_interface_descriptor *pInterfaceDesc; for(i = 0; i < pConfigDesc->bNumInterfaces; i++) { pInterface = pConfigDesc->interface + i; for(j = 0; j < pInterface->num_altsetting; j++) { pInterfaceDesc = pInterface->altsetting+j; if (m_deviceDesc.emUsbType == RKUSB_MSC) { if( (pInterfaceDesc->bInterfaceClass != 8) || (pInterfaceDesc->bInterfaceSubClass != 6) || (pInterfaceDesc->bInterfaceProtocol != 0x50)) continue; } else { if( (pInterfaceDesc->bInterfaceClass != 0xff) || (pInterfaceDesc->bInterfaceSubClass != 6) || (pInterfaceDesc->bInterfaceProtocol != 5)) continue; } for(k = 0; k < pInterfaceDesc->bNumEndpoints; k++) { pEndpointDesc = pInterfaceDesc->endpoint+k; if ((pEndpointDesc->bEndpointAddress & 0x80) == 0) { if (m_pipeBulkOut == 0) m_pipeBulkOut = pEndpointDesc->bEndpointAddress; } else { if (m_pipeBulkIn == 0) m_pipeBulkIn = pEndpointDesc->bEndpointAddress; } if ((m_pipeBulkIn != 0) && (m_pipeBulkOut != 0)) {//found it m_interfaceNum = i; libusb_free_config_descriptor(pConfigDesc); iRet = libusb_claim_interface((libusb_device_handle *)m_pUsbHandle, m_interfaceNum); if (iRet != 0) { if (m_log) { m_log->Record("Error:libusb_claim_interface failed,err=%d", iRet); } return false; } return true; } } } } libusb_free_config_descriptor(pConfigDesc); return false; } void CRKUsbComm::UninitializeUsb() { if (m_pUsbHandle) { libusb_close((libusb_device_handle *)m_pUsbHandle); m_pUsbHandle = NULL; } memset(&m_deviceDesc, 0, sizeof(STRUCT_RKDEVICE_DESC)); m_pipeBulkIn = m_pipeBulkOut = 0; return ; } bool CRKUsbComm::Reset_Usb_Config(STRUCT_RKDEVICE_DESC devDesc) { bool bRet; UninitializeUsb(); bRet = InitializeUsb(devDesc); return bRet; } bool CRKUsbComm::Reset_Usb_Device() { int iRet = -1; if (m_pUsbHandle) { iRet=libusb_reset_device((libusb_device_handle *)m_pUsbHandle); } return (iRet == 0) ? true : false; } bool CRKUsbComm::RKU_Read(BYTE* lpBuffer, DWORD dwSize) { int iRet; int nRead; iRet = libusb_bulk_transfer((libusb_device_handle *)m_pUsbHandle, m_pipeBulkIn, lpBuffer, dwSize, &nRead, CMD_TIMEOUT); if (iRet!=0) { if (m_log) { m_log->Record("Error:RKU_Read failed,err=%d", iRet); } return false; } if (nRead != (int)dwSize) { if (m_log) { m_log->Record("Error:RKU_Read failed, size=%d, read=%d", dwSize, nRead); } return false; } return true; } bool CRKUsbComm::RKU_Write(BYTE* lpBuffer, DWORD dwSize) { int iRet; int nWrite; iRet = libusb_bulk_transfer((libusb_device_handle *)m_pUsbHandle, m_pipeBulkOut, lpBuffer, dwSize, &nWrite, CMD_TIMEOUT); if (iRet != 0) { if (m_log) { m_log->Record("Error:RKU_Write failed, err=%d", iRet); } return false; } if (nWrite != (int)dwSize) { if (m_log) { m_log->Record("Error:RKU_Write failed, size=%d, read=%d", dwSize, nWrite); } return false; } return true; } int CRKUsbComm::RandomInteger(int low, int high) { int k; double d; d = (double)rand() / ((double)RAND_MAX + 1); k = (int)(d * (high - low + 1)); return (low + k); } DWORD CRKUsbComm::MakeCBWTag() { DWORD tag = 0; int i = 0; for(i=0; i<4; i++){ tag <<= 8; tag += RandomInteger(0, 0xFF); } return tag; } void CRKUsbComm::InitializeCBW(PCBW pCBW, USB_OPERATION_CODE code) { memset(pCBW,0, sizeof(CBW)); pCBW->dwCBWSignature = CBW_SIGN; pCBW->dwCBWTag = MakeCBWTag(); pCBW->cbwcb.ucOperCode = code; switch(code) { case TEST_UNIT_READY: /* Test Unit Ready : 0 */ case READ_FLASH_ID: /* Read Flash ID : 1 */ case READ_FLASH_INFO: case READ_CHIP_INFO: case READ_EFUSE: pCBW->ucCBWFlags= DIRECTION_IN; pCBW->ucCBWCBLength = 0x06; break; case DEVICE_RESET: /* Reset Device : 0xff */ case ERASE_SYSTEMDISK: case SET_RESET_FLAG: pCBW->ucCBWFlags = DIRECTION_OUT; pCBW->ucCBWCBLength = 0x06; break; case TEST_BAD_BLOCK: /* Test Bad Block : 3 */ case READ_SECTOR: /* Read Pages : 4 */ case READ_LBA: /* Read Pages : 4 */ case READ_SDRAM: /* Write Pages : 15 */ case READ_SPI_FLASH: case READ_NEW_EFUSE: pCBW->ucCBWFlags = DIRECTION_IN; pCBW->ucCBWCBLength = 0x0a; break; case WRITE_SECTOR: /* Write Pages : 5 */ case WRITE_LBA: /* Write Pages : 15 */ case WRITE_SDRAM: /* Write Pages : 15 */ case EXECUTE_SDRAM: case ERASE_NORMAL: /* Erase Blocks : 6 */ case ERASE_FORCE: /* Read Spare : 11 */ case WRITE_EFUSE: case WRITE_SPI_FLASH: case WRITE_NEW_EFUSE: pCBW->ucCBWFlags = DIRECTION_OUT; pCBW->ucCBWCBLength = 0x0a; break; default: break; } } bool CRKUsbComm::RKU_ClearBuffer(CBW& cbw, CSW& csw) { DWORD dwReadBytes=0; DWORD dwTotalRead=0; int iTryCount; iTryCount = 3; do { dwReadBytes = RKU_Read_EX((BYTE*)&csw, sizeof(CSW) ); if (UFI_CHECK_SIGN(cbw,csw)) { return true; } if (dwReadBytes != sizeof(CSW)) { iTryCount--; sleep(3); } dwTotalRead += dwReadBytes; if (dwTotalRead >= MAX_CLEAR_LEN) { break; } }while ( iTryCount > 0 ); return false; } DWORD CRKUsbComm::RKU_Read_EX(BYTE* lpBuffer, DWORD dwSize) { int iRet; int nRead; iRet = libusb_bulk_transfer((libusb_device_handle *)m_pUsbHandle, m_pipeBulkIn, lpBuffer, dwSize, &nRead, 5000); if (iRet != 0) { if (m_log) { m_log->Record("Error:RKU_Read_EX failed, err=%d", iRet); } return 0; } return nRead; } int CRKUsbComm::RKU_EraseBlock(BYTE ucFlashCS, DWORD dwPos, DWORD dwCount, BYTE ucEraseType) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_EraseBlock failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; USHORT usCount; usCount = dwCount; if(dwCount > MAX_ERASE_BLOCKS) return ERR_CROSS_BORDER; InitializeCBW(&cbw, (USB_OPERATION_CODE)ucEraseType); cbw.ucCBWLUN = ucFlashCS; cbw.cbwcb.dwAddress = EndianU32_LtoB(dwPos); cbw.cbwcb.usLength = EndianU16_LtoB(usCount); if(!RKU_Write((BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read((BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; if(csw.ucCSWStatus == 1) return ERR_FOUND_BAD_BLOCK; return ERR_SUCCESS; } int CRKUsbComm::RKU_ReadChipInfo(BYTE* lpBuffer) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_ReadChipInfo failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; InitializeCBW(&cbw, READ_CHIP_INFO); if(!RKU_Write((BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read(lpBuffer, 16)) { return ERR_DEVICE_READ_FAILED; } if(!RKU_Read( (BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; return ERR_SUCCESS; } int CRKUsbComm::RKU_ReadFlashID(BYTE* lpBuffer) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_ReadChipInfo failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; InitializeCBW(&cbw, READ_FLASH_ID); if(!RKU_Write((BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read(lpBuffer, 5)) { return ERR_DEVICE_READ_FAILED; } if(!RKU_Read( (BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; return ERR_SUCCESS; } int CRKUsbComm::RKU_ReadFlashInfo(BYTE* lpBuffer, UINT *puiRead) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_ReadFlashInfo failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; InitializeCBW(&cbw, READ_FLASH_INFO); if(!RKU_Write((BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } DWORD dwRead; dwRead = RKU_Read_EX(lpBuffer, 512); if ((dwRead < 11) || (dwRead > 512)) { return ERR_DEVICE_READ_FAILED; } if (puiRead) { *puiRead = dwRead; } /* if(!RKU_Read(hDev, lpBuffer, 11)) { return ERR_DEVICE_READ_FAILED; } */ if(!RKU_Read((BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; return ERR_SUCCESS; } int CRKUsbComm::RKU_ReadLBA(DWORD dwPos, DWORD dwCount, BYTE* lpBuffer, BYTE bySubCode) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_ReadLBA failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; USHORT wSectorSize; USHORT usSectorLen; wSectorSize = 512; usSectorLen=dwCount; InitializeCBW(&cbw, READ_LBA); cbw.cbwcb.dwAddress = EndianU32_LtoB(dwPos); cbw.cbwcb.usLength = EndianU16_LtoB(usSectorLen); cbw.cbwcb.ucReserved = bySubCode; if(!RKU_Write((BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } DWORD dwTotal; dwTotal = usSectorLen * wSectorSize; if(!RKU_Read(lpBuffer, dwTotal)) { return ERR_DEVICE_READ_FAILED; } if(!RKU_Read((BYTE*)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; if(csw.ucCSWStatus == 1) return ERR_FAILED; return ERR_SUCCESS; } int CRKUsbComm::RKU_ResetDevice(BYTE bySubCode) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_ResetDevice failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; InitializeCBW(&cbw, DEVICE_RESET); cbw.cbwcb.ucReserved = bySubCode; if(!RKU_Write((BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read((BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) { bool bRet; bRet = RKU_ClearBuffer(cbw, csw); if (!bRet) { return ERR_CMD_NOTMATCH; } } if(csw.ucCSWStatus == 1) return ERR_FAILED; return ERR_SUCCESS; } int CRKUsbComm::RKU_TestDeviceReady(DWORD *dwTotal, DWORD *dwCurrent, BYTE bySubCode) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_TestDeviceReady failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; InitializeCBW(&cbw, TEST_UNIT_READY); cbw.cbwcb.ucReserved = bySubCode; if(!RKU_Write( (BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read( (BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) { bool bRet; bRet = RKU_ClearBuffer(cbw ,csw); if (!bRet) { return ERR_CMD_NOTMATCH; } } if ((dwTotal!=NULL)&&(dwCurrent!=NULL)) { *dwCurrent = (csw.dwCBWDataResidue >>16); *dwTotal = (csw.dwCBWDataResidue & 0x0000FFFF); *dwTotal = EndianU16_BtoL(*dwTotal); *dwCurrent = EndianU16_BtoL(*dwCurrent); } if(csw.ucCSWStatus == 1) { return ERR_DEVICE_UNREADY; } return ERR_DEVICE_READY; } int CRKUsbComm::RKU_WriteLBA(DWORD dwPos, DWORD dwCount, BYTE* lpBuffer, BYTE bySubCode) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_WriteLBA failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; USHORT wSectorSize; USHORT usCount; wSectorSize = 512; usCount = dwCount; DWORD dwTotal = usCount * wSectorSize; InitializeCBW(&cbw, WRITE_LBA); cbw.cbwcb.dwAddress = EndianU32_LtoB(dwPos); cbw.cbwcb.usLength = EndianU16_LtoB(usCount); cbw.cbwcb.ucReserved = bySubCode; if(!RKU_Write( (BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Write( lpBuffer, dwTotal)) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read( (BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; if(csw.ucCSWStatus == 1) return ERR_FAILED; return ERR_SUCCESS; } int CRKUsbComm::RKU_WriteSector(DWORD dwPos, DWORD dwCount, BYTE *lpBuffer) { if ((m_deviceDesc.emUsbType != RKUSB_LOADER) && (m_deviceDesc.emUsbType != RKUSB_MASKROM)) { if (m_log) { m_log->Record("Error:RKU_WriteSector failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } CBW cbw; CSW csw; USHORT wSectorSize; USHORT usCount; usCount=dwCount; if(usCount > 32) return ERR_CROSS_BORDER; wSectorSize = 528; InitializeCBW(&cbw, WRITE_SECTOR); cbw.cbwcb.dwAddress = EndianU32_LtoB(dwPos); cbw.cbwcb.usLength = EndianU16_LtoB(usCount); if(!RKU_Write( (BYTE *)&cbw, sizeof(CBW))) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Write( lpBuffer, usCount * wSectorSize)) { return ERR_DEVICE_WRITE_FAILED; } if(!RKU_Read( (BYTE *)&csw, sizeof(CSW))) { return ERR_DEVICE_READ_FAILED; } if( !UFI_CHECK_SIGN(cbw, csw) ) return ERR_CMD_NOTMATCH; if(csw.ucCSWStatus == 1) return ERR_FAILED; return ERR_SUCCESS; } int CRKUsbComm::RKU_DeviceRequest(DWORD dwRequest, BYTE *lpBuffer, DWORD dwDataSize) { if (m_deviceDesc.emUsbType != RKUSB_MASKROM) { if (m_log) { m_log->Record("Error:RKU_DeviceRequest failed,device not support"); } return ERR_DEVICE_NOT_SUPPORT; } if ((dwRequest != 0x0471) && (dwRequest != 0x0472)) { if (m_log) { m_log->Record("Error:RKU_DeviceRequest failed,request not support"); } return ERR_REQUEST_NOT_SUPPORT; } bool bSendPendPacket = false; USHORT crcValue = 0xffff; BYTE *pData = NULL; pData = new BYTE[dwDataSize + 5]; memset(pData, 0, dwDataSize + 5); memcpy(pData, lpBuffer, dwDataSize); switch(dwDataSize % 4096) { case 4095: ++dwDataSize; break; case 4094: bSendPendPacket = true; break; case 0: default: break; } crcValue = CRC_CCITT(pData, dwDataSize); pData[dwDataSize] = (crcValue & 0xff00) >> 8; pData[dwDataSize+1] = crcValue & 0x00ff; dwDataSize += 2; UINT nSendBytes = 0; DWORD dwTotalSended = 0; int iRet; while(dwTotalSended < dwDataSize) { nSendBytes = ( (dwDataSize - dwTotalSended) > 4096) ? 4096 : (dwDataSize - dwTotalSended); iRet = libusb_control_transfer((libusb_device_handle *)m_pUsbHandle, 0x40, 0xC, 0, dwRequest, pData + dwTotalSended, nSendBytes, CMD_TIMEOUT); if (iRet != (int)nSendBytes) { if (m_log) { m_log->Record("Error:RKU_DeviceRequest-->DeviceRequest vendor=0x%x failed, err=%d",dwRequest, iRet); } delete []pData; return ERR_REQUEST_FAIL; } dwTotalSended += nSendBytes; } if(bSendPendPacket) { BYTE ucFillByte = 0; iRet = libusb_control_transfer((libusb_device_handle *)m_pUsbHandle, 0x40, 0xC, 0, dwRequest, &ucFillByte, 1, CMD_TIMEOUT); if (iRet != 0) { if (m_log) { m_log->Record("Error:RKU_DeviceRequest-->DeviceRequest vendor=0x%x failed, err=%d", dwRequest, iRet); } delete []pData; return ERR_REQUEST_FAIL; } } delete []pData; return ERR_SUCCESS; }