/*
 * (C) Copyright 2017 Fuzhou Rockchip Electronics Co., Ltd
 * Seth Liu 2017.03.01
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include "RKDevice.h"

const char *szManufName[] = { "SAMSUNG", "TOSHIBA", "HYNIX", "INFINEON",
	"MICRON", "RENESAS", "ST", "INTEL" };

void CRKDevice::SetVendorID(USHORT value) {
	m_vid = value;
}
void CRKDevice::SetProductID(USHORT value) {
	m_pid = value;
}
void CRKDevice::SetDeviceType(ENUM_RKDEVICE_TYPE value) {
	m_device = value;
}
void CRKDevice::SetOsType(ENUM_OS_TYPE value) {
	m_os = value;
}

void CRKDevice::SetUsbType(ENUM_RKUSB_TYPE value) {
	m_usb = value;
}
void CRKDevice::SetBcdUsb(USHORT value) {
	m_bcdUsb = value;
}
void CRKDevice::SetLayerName(char *value) {
	strcpy(m_layerName, value);
}
void CRKDevice::SetLocationID(DWORD value) {
	m_locationID = value;
}

void CRKDevice::SetCallBackPointer(ProgressPromptCB value) {
	if (value) {
		m_callBackProc = value;
	}
}
CRKLog *CRKDevice::GetLogObjectPointer() {
	return m_pLog;
}

CRKComm *CRKDevice::GetCommObjectPointer() {
	return m_pComm;
}

USHORT CRKDevice::GetVendorID() {
	return m_vid;
}
USHORT CRKDevice::GetProductID() {
	return m_pid;
}
ENUM_RKDEVICE_TYPE CRKDevice::GetDeviceType() {
	return m_device;
}
ENUM_OS_TYPE CRKDevice::GetOsType() {
	return m_os;
}

ENUM_RKUSB_TYPE CRKDevice::GetUsbType() {
	return m_usb;
}

USHORT CRKDevice::GetBcdUsb() {
	return m_bcdUsb;
}
DWORD CRKDevice::GetLocationID() {
	return m_locationID;
}
char *CRKDevice::GetLayerName() {
	return m_layerName;
}

string CRKDevice::GetLayerString(DWORD dwLocationID) {
	char szLocation[32] = "\0";
	sprintf(szLocation, "%d-%d", dwLocationID >> 8, dwLocationID & 0xff);
	return szLocation;
}

CRKDevice::CRKDevice(STRUCT_RKDEVICE_DESC &device) {
	VendorID.setContainer(this);
	VendorID.getter(&CRKDevice::GetVendorID);
	VendorID.setter(&CRKDevice::SetVendorID);

	ProductID.setContainer(this);
	ProductID.getter(&CRKDevice::GetProductID);
	ProductID.setter(&CRKDevice::SetProductID);

	DeviceType.setContainer(this);
	DeviceType.getter(&CRKDevice::GetDeviceType);
	DeviceType.setter(&CRKDevice::SetDeviceType);

	UsbType.setContainer(this);
	UsbType.getter(&CRKDevice::GetUsbType);
	UsbType.setter(&CRKDevice::SetUsbType);

	LayerName.setContainer(this);
	LayerName.getter(&CRKDevice::GetLayerName);
	LayerName.setter(&CRKDevice::SetLayerName);

	BcdUsb.setContainer(this);
	BcdUsb.getter(&CRKDevice::GetBcdUsb);
	BcdUsb.setter(&CRKDevice::SetBcdUsb);

	LocationID.setContainer(this);
	LocationID.getter(&CRKDevice::GetLocationID);
	LocationID.setter(&CRKDevice::SetLocationID);

	OsType.setContainer(this);
	OsType.getter(&CRKDevice::GetOsType);
	OsType.setter(&CRKDevice::SetOsType);

	LogObjectPointer.setContainer(this);
	LogObjectPointer.getter(&CRKDevice::GetLogObjectPointer);

	CommObjectPointer.setContainer(this);
	CommObjectPointer.getter(&CRKDevice::GetCommObjectPointer);

	CallBackPointer.setContainer(this);
	CallBackPointer.setter(&CRKDevice::SetCallBackPointer);

	m_vid = device.usVid;
	m_pid = device.usPid;
	m_usb = device.emUsbType;
	m_device = device.emDeviceType;
	m_bcdUsb = device.usbcdUsb;
	m_locationID = device.uiLocationID;
	strcpy(m_layerName, GetLayerString(m_locationID).c_str());

	memset(m_flashInfo.blockState, 0, IDBLOCK_TOP);
	m_flashInfo.usPhyBlokcPerIDB = 1;
	m_flashInfo.uiSecNumPerIDB = 0;
	m_callBackProc = NULL;
	m_chipData = NULL;
	m_pImage = NULL;
	m_pLog = NULL;
	m_pComm = NULL;
	m_pFlashInfoData = NULL;
	m_usFlashInfoDataLen = 0;
	m_usFlashInfoDataOffset = 0;
	m_bEmmc = false;
	m_bDirectLba = false;
	m_bFirst4mAccess = false;
}
CRKDevice::~CRKDevice() {
	if (m_pComm) {
		delete m_pComm;
		m_pComm = NULL;
	}
	if (m_chipData) {
		delete[] m_chipData;
		m_chipData = NULL;
	}

	if (m_pFlashInfoData) {
		delete[] m_pFlashInfoData;
		m_pFlashInfoData = NULL;
	}
}
bool CRKDevice::SetObject(CRKImage *pImage, CRKComm *pComm, CRKLog *pLog) {
	if (!pComm) {
		return false;
	}
	m_pImage = pImage;
	m_pComm = pComm;
	m_pLog = pLog;
	if (m_pImage) {
		m_os = m_pImage->OsType;
	} else
		m_os = RK_OS;
	return true;
}
int CRKDevice::EraseEmmcBlock(UCHAR ucFlashCS, DWORD dwPos, DWORD dwCount) {
	int sectorOffset, nWrittenBlcok, iRet;
	BYTE emptyData[4 * (SECTOR_SIZE + SPARE_SIZE)];
	memset(emptyData, 0xff, 4 * (SECTOR_SIZE + SPARE_SIZE));
	nWrittenBlcok = 0;
	while (dwCount > 0) {
		sectorOffset =
				(ucFlashCS * m_flashInfo.uiBlockNum + dwPos + nWrittenBlcok) *
				m_flashInfo.uiSectorPerBlock;
		iRet = m_pComm->RKU_WriteSector(sectorOffset, 4, emptyData);
		if ((iRet != ERR_SUCCESS) && (iRet != ERR_FOUND_BAD_BLOCK)) {
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:EraseEmmcBlock-->RKU_WriteSector "
						"failed, RetCode(%d)",
						m_layerName, iRet);
			}
			return iRet;
		}
		dwCount--;
		nWrittenBlcok++;
	}
	return ERR_SUCCESS;
}
int CRKDevice::EraseEmmcByWriteLBA(DWORD dwSectorPos, DWORD dwCount) {
	int nWritten, iRet;
	BYTE emptyData[32 * SECTOR_SIZE];
	memset(emptyData, 0xff, 32 * SECTOR_SIZE);

	while (dwCount > 0) {
		nWritten = (dwCount < 32) ? dwCount : 32;
		iRet = m_pComm->RKU_WriteLBA(dwSectorPos, nWritten, emptyData);
		if (iRet != ERR_SUCCESS) {
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:EraseEmmcByWriteLBA-->RKU_WriteLBA "
						"failed, RetCode(%d)",
						m_layerName, iRet);
			}
			return iRet;
		}
		dwCount -= nWritten;
		dwSectorPos += nWritten;
	}
	return ERR_SUCCESS;
}
bool CRKDevice::EraseEmmc() {
	UINT uiCount, uiEraseCount, uiSectorOffset, uiTotalCount;
	UINT uiErase = 1024 * 32;
	int iRet = ERR_SUCCESS, iLoopTimes = 0;
	uiTotalCount = uiCount = m_flashInfo.uiFlashSize * 2 * 1024;
	uiSectorOffset = 0;
	DWORD dwLayerID;
	dwLayerID = m_locationID;
	ENUM_CALL_STEP emCallStep = CALL_FIRST;

	while (uiCount) {
		if (uiCount >= uiErase) {
			uiEraseCount = uiErase;
		} else
			uiEraseCount = uiCount;
		iRet = m_pComm->RKU_EraseLBA(uiSectorOffset, uiEraseCount);

		if (iRet != ERR_SUCCESS) {
			if (m_pLog) {
				m_pLog->Record("ERROR:EraseEmmc-->RKU_EraseLBA "
							   "failed,RetCode(%d),offset=0x%x,count=0x%x",
						iRet, uiSectorOffset, uiEraseCount);
			}
			return false;
		}
		uiCount -= uiEraseCount;
		uiSectorOffset += uiEraseCount;
		iLoopTimes++;
		if (iLoopTimes % 8 == 0) {
			if (m_callBackProc) {
				m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS, uiTotalCount,
						uiSectorOffset, emCallStep);
				emCallStep = CALL_MIDDLE;
			}
		}
	}
	if (m_callBackProc) {
		emCallStep = CALL_LAST;
		m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS, uiTotalCount,
				uiTotalCount, emCallStep);
	}
	return true;
}
bool CRKDevice::GetFlashInfo() {
	STRUCT_FLASHINFO_CMD info;
	BYTE flashID[5];
	int iRet;
	UINT uiRead;
	iRet = m_pComm->RKU_ReadFlashInfo((PBYTE)&info, &uiRead);
	if (ERR_SUCCESS == iRet) {
		if ((info.usBlockSize == 0) || (info.bPageSize == 0)) {
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:GetFlashInfo-->RKU_ReadFlashInfo "
						"failed,pagesize or blocksize is zero",
						m_layerName);
			}
			return false;
		}
		if (info.bManufCode <= 7) {
			strcpy(m_flashInfo.szManufacturerName,
					szManufName[info.bManufCode]);
		} else {
			strcpy(m_flashInfo.szManufacturerName, "UNKNOWN");
		}
		m_flashInfo.uiFlashSize = info.uiFlashSize / 2 / 1024;
		m_flashInfo.uiPageSize = info.bPageSize / 2;
		m_flashInfo.usBlockSize = info.usBlockSize / 2;
		m_flashInfo.bECCBits = info.bECCBits;
		m_flashInfo.bAccessTime = info.bAccessTime;
		m_flashInfo.uiBlockNum =
				m_flashInfo.uiFlashSize * 1024 / m_flashInfo.usBlockSize;
		m_flashInfo.uiSectorPerBlock = info.usBlockSize;
		m_flashInfo.bFlashCS = info.bFlashCS;
		m_flashInfo.usValidSecPerBlock =
				(info.usBlockSize / info.bPageSize) * 4;
		if (m_pFlashInfoData) {
			delete[] m_pFlashInfoData;
			m_pFlashInfoData = NULL;
		}
		m_usFlashInfoDataLen = BYTE2SECTOR(uiRead);
		m_pFlashInfoData = new BYTE[SECTOR_SIZE * m_usFlashInfoDataLen];
		memset(m_pFlashInfoData, 0, SECTOR_SIZE * m_usFlashInfoDataLen);
		memcpy(m_pFlashInfoData, (PBYTE)&info, uiRead);
		if (m_pLog) {
			string strFlashInfo;
			m_pLog->PrintBuffer(strFlashInfo, m_pFlashInfoData, 11);
			m_pLog->Record("<LAYER %s> INFO:FlashInfo:%s", m_layerName,
					strFlashInfo.c_str());
		}
	} else {
		if (m_pLog) {
			m_pLog->Record("<LAYER %s> ERROR:GetFlashInfo-->RKU_ReadFlashInfo "
						   "failed, RetCode(%d)",
					m_layerName, iRet);
		}
		return false;
	}
	iRet = m_pComm->RKU_ReadFlashID(flashID);
	if (ERR_SUCCESS == iRet) {
		DWORD *pID = (DWORD *)flashID;
		if (*pID == 0x434d4d45) /*emmc*/ {
			m_bEmmc = true;
		} else
			m_bEmmc = false;
	} else {
		if (m_pLog) {
			m_pLog->Record("<LAYER %s> ERROR:GetFlashInfo-->RKU_ReadFlashID "
						   "failed, RetCode(%d)",
					m_layerName, iRet);
		}
		return false;
	}
	return true;
}
bool CRKDevice::TestDevice() {
	int iResult, iTryCount;
	DWORD dwTotal, dwCurrent, dwLayerID;
	dwLayerID = m_locationID;
	ENUM_CALL_STEP emCallStep = CALL_FIRST;
	do {
		iTryCount = 3;
		while (iTryCount > 0) {
			iResult = m_pComm->RKU_TestDeviceReady(&dwTotal, &dwCurrent);
			if ((iResult == ERR_SUCCESS) || (iResult == ERR_DEVICE_UNREADY)) {
				break;
			}
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:TestDevice-->RKU_TestDeviceReady "
						"failed, RetCode(%d)",
						m_layerName, iResult);
			}
			iTryCount--;
			sleep(1);
		}
		if (iTryCount <= 0) {
			return false;
		}

		if (iResult == ERR_SUCCESS) {
			if (emCallStep == CALL_MIDDLE) {
				if (m_callBackProc) {
					dwCurrent = dwTotal;
					emCallStep = CALL_LAST;
					m_callBackProc(dwLayerID, TESTDEVICE_PROGRESS, dwTotal,
							dwCurrent, emCallStep);
				}
			}
			break;
		}
		if (dwCurrent > dwTotal) {
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:TestDevice-->RKU_TestDeviceReady "
						"failed,Total=%d, Current=%d",
						m_layerName, dwTotal, dwCurrent);
			}
			return false;
		}
		if (UsbType == RKUSB_LOADER) {
			if (dwTotal == 0) {
				if (m_pLog) {
					m_pLog->Record(
							"<LAYER %s> ERROR:TestDevice-->RKU_TestDeviceReady "
							"failed, Total is zero",
							m_layerName);
				}
				return false;
			}
		}
		if (m_callBackProc) {
			m_callBackProc(dwLayerID, TESTDEVICE_PROGRESS, dwTotal, dwCurrent,
					emCallStep);
			emCallStep = CALL_MIDDLE;
		}
		sleep(1);
	} while (iResult == ERR_DEVICE_UNREADY);
	return true;
}
bool CRKDevice::ResetDevice() {
	int iRet;
	iRet = m_pComm->RKU_ResetDevice();
	if (iRet == ERR_SUCCESS) {
		return true;
	} else {
		bool bRet = false;
		if ((iRet == -2) || (iRet == -4)) {
			bRet = true;
		}
		if (m_pLog) {
			m_pLog->Record("<LAYER %s> ERROR:ResetDevice-->RKU_ResetDevice "
						   "failed, RetCode(%d)",
					m_layerName, iRet);
		}
		return bRet;
	}
}

bool CRKDevice::PowerOffDevice() {
	int iRet;
	iRet = m_pComm->RKU_ResetDevice(RST_POWEROFF_SUBCODE);
	if (iRet == ERR_SUCCESS) {
		return true;
	} else {
		if (m_pLog) {
			m_pLog->Record("<LAYER %s> ERROR:PowerOffDevice-->RKU_ResetDevice "
						   "failed, RetCode(%d)",
					m_layerName, iRet);
		}
		return false;
	}
}
bool CRKDevice::CheckChip() {
	int iRet;
	BYTE bChipInfo[CHIPINFO_LEN];
	ENUM_RKDEVICE_TYPE curDeviceType = RKNONE_DEVICE;
	memset(bChipInfo, 0, CHIPINFO_LEN);
	iRet = m_pComm->RKU_ReadChipInfo(bChipInfo);
	if (iRet == ERR_SUCCESS) {
		if (!m_chipData) {
			m_chipData = new BYTE[CHIPINFO_LEN];
		}
		memset(m_chipData, 0, CHIPINFO_LEN);
		memcpy(m_chipData, bChipInfo, CHIPINFO_LEN);
		DWORD *pValue;
		pValue = (DWORD *)(&bChipInfo[0]);

		if ((ENUM_RKDEVICE_TYPE)(*pValue) == m_device) {
			return true;
		}
		if (*pValue == 0x524B3237) {
			curDeviceType = RK27_DEVICE;
		} else if (*pValue == 0x32373341) {
			curDeviceType = RKCAYMAN_DEVICE;
		} else if (*pValue == 0x524B3238) {
			curDeviceType = RK28_DEVICE;
		} else if (*pValue == 0x32383158) {
			curDeviceType = RK281X_DEVICE;
		} else if (*pValue == 0x32383242) {
			curDeviceType = RKPANDA_DEVICE;
		} else if (*pValue == 0x32393058) {
			curDeviceType = RK29_DEVICE;
		} else if (*pValue == 0x32393258) {
			curDeviceType = RK292X_DEVICE;
		} else if (*pValue == 0x33303041) {
			curDeviceType = RK30_DEVICE;
		} else if (*pValue == 0x33313041) {
			curDeviceType = RK30B_DEVICE;
		} else if (*pValue == 0x33313042) {
			curDeviceType = RK31_DEVICE;
		} else if (*pValue == 0x33323041) {
			curDeviceType = RK32_DEVICE;
		} else if (*pValue == 0x32363243) {
			curDeviceType = RKSMART_DEVICE;
		} else if (*pValue == 0x6E616E6F) {
			curDeviceType = RKNANO_DEVICE;
		} else if (*pValue == 0x4E4F5243) {
			curDeviceType = RKCROWN_DEVICE;
		}

		if (curDeviceType == m_device) {
			return true;
		} else {
			if (m_pLog) {
				m_pLog->Record("<LAYER %s> ERROR:CheckChip-->Chip is not "
							   "match, firmware(0x%x), device(0x%x)",
						m_layerName, m_device, *pValue);
			}
			return false;
		}
	} else {
		if (m_pLog) {
			m_pLog->Record("<LAYER %s> ERROR:CheckChip-->RKU_ReadChipInfo "
						   "failed,RetCode(%d)",
					m_layerName, iRet);
		}
		return false;
	}
}

int CRKDevice::DownloadBoot() {
	UCHAR i;
	DWORD dwSize, dwDelay;
	PBYTE pBuffer = NULL;
	for (i = 0; i < m_pImage->m_bootObject->Entry471Count; i++) {
		if (!m_pImage->m_bootObject->GetEntryProperty(
					ENTRY471, i, dwSize, dwDelay)) {
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:DownloadBoot-->GetEntry471Property "
						"failed,index(%d)",
						m_layerName, i);
			}
			return -2;
		}
		if (dwSize > 0) {
			pBuffer = new BYTE[dwSize];
			if (!m_pImage->m_bootObject->GetEntryData(ENTRY471, i, pBuffer)) {
				if (m_pLog) {
					m_pLog->Record(
							"<LAYER %s> ERROR:DownloadBoot-->GetEntry471Data "
							"failed,index(%d)",
							m_layerName, i);
				}
				delete[] pBuffer;
				return -3;
			}
			if (!Boot_VendorRequest(0x0471, pBuffer, dwSize)) {
				if (m_pLog) {
					m_pLog->Record("<LAYER %s> "
								   "ERROR:DownloadBoot-->Boot_VendorRequest471 "
								   "failed,index(%d)",
							m_layerName, i);
				}
				delete[] pBuffer;
				return -4;
			}
			delete[] pBuffer;
			pBuffer = NULL;
			if (dwDelay > 0) {
				usleep(dwDelay * 1000);
			}
		}
	}

	for (i = 0; i < m_pImage->m_bootObject->Entry472Count; i++) {
		if (!m_pImage->m_bootObject->GetEntryProperty(
					ENTRY472, i, dwSize, dwDelay)) {
			if (m_pLog) {
				m_pLog->Record(
						"<LAYER %s> ERROR:DownloadBoot-->GetEntry472Property "
						"failed,index(%d)",
						m_layerName, i);
			}
			return -2;
		}
		if (dwSize > 0) {
			pBuffer = new BYTE[dwSize];
			if (!m_pImage->m_bootObject->GetEntryData(ENTRY472, i, pBuffer)) {
				if (m_pLog) {
					m_pLog->Record(
							"<LAYER %s> ERROR:DownloadBoot-->GetEntry472Data "
							"failed,index(%d)",
							m_layerName, i);
				}
				delete[] pBuffer;
				return -3;
			}
			if (!Boot_VendorRequest(0x0472, pBuffer, dwSize)) {
				if (m_pLog) {
					m_pLog->Record("<LAYER %s> "
								   "ERROR:DownloadBoot-->Boot_VendorRequest472 "
								   "failed,index(%d)",
							m_layerName, i);
				}
				delete[] pBuffer;
				return -4;
			}
			delete[] pBuffer;
			pBuffer = NULL;
			if (dwDelay > 0) {
				usleep(dwDelay * 1000);
			}
		}
	}
	sleep(1);
	return 0;
}
bool CRKDevice::Boot_VendorRequest(
		DWORD requestCode, PBYTE pBuffer, DWORD dwDataSize) {
	int iRet;
	iRet = m_pComm->RKU_DeviceRequest(requestCode, pBuffer, dwDataSize);
	return (iRet == ERR_SUCCESS) ? true : false;
}
int CRKDevice::EraseAllBlocks(bool force_block_erase) {
	int i;
	UINT uiBlockCount;
	int iRet = ERR_SUCCESS, iErasePos = 0, iEraseBlockNum = 0, iEraseTimes = 0,
		iCSIndex = 0;
	BYTE bCSCount = 0;
	for (i = 0; i < 8; i++) {
		if (m_flashInfo.bFlashCS & (1 << i)) {
			bCSCount++;
		}
	}
	ReadCapability();
	DWORD dwLayerID;
	dwLayerID = LocationID;
	ENUM_CALL_STEP emCallStep = CALL_FIRST;
	if (!force_block_erase) {
		if ((m_bEmmc) || (m_bDirectLba)) {
			if (!EraseEmmc()) {
				if (m_pLog) {
					m_pLog->Record("<LAYER %s> "
								   "ERROR:EraseAllBlocks-->EraseEmmc failed",
							m_layerName);
				}
				return -1;
			}
			return 0;
		}
	}
	for (i = 0; i < 8; i++) {
		if (m_flashInfo.bFlashCS & (1 << i)) {
			uiBlockCount = m_flashInfo.uiBlockNum;
			iErasePos = 0;
			iEraseTimes = 0;
			while (uiBlockCount > 0) {
				iEraseBlockNum = (uiBlockCount < MAX_ERASE_BLOCKS) ?
						  uiBlockCount :
						  MAX_ERASE_BLOCKS;
				iRet = m_pComm->RKU_EraseBlock(
						i, iErasePos, iEraseBlockNum, ERASE_FORCE);
				if ((iRet != ERR_SUCCESS) && (iRet != ERR_FOUND_BAD_BLOCK)) {
					if (m_pLog) {
						m_pLog->Record("<LAYER %s> "
									   "ERROR:EraseAllBlocks-->RKU_EraseBlock "
									   "failed,RetCode(%d)",
								m_layerName, iRet);
					}
					return -1;
				}
				iErasePos += iEraseBlockNum;
				uiBlockCount -= iEraseBlockNum;
				iEraseTimes++;
				if (iEraseTimes % 8 == 0) {
					if (m_callBackProc) {
						m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS,
								m_flashInfo.uiBlockNum * bCSCount,
								iCSIndex * m_flashInfo.uiBlockNum + iErasePos,
								emCallStep);
						emCallStep = CALL_MIDDLE;
					}
				}
			}
			iCSIndex++;
		}
	}

	if (m_callBackProc) {
		emCallStep = CALL_LAST;
		m_callBackProc(dwLayerID, ERASEFLASH_PROGRESS,
				m_flashInfo.uiBlockNum * bCSCount,
				iCSIndex * m_flashInfo.uiBlockNum, emCallStep);
	}
	return 0;
}
bool CRKDevice::ReadCapability() {
	int ret;
	BYTE data[8];
	ret = m_pComm->RKU_ReadCapability(data);
	if (ret != ERR_SUCCESS) {
		if (m_pLog) {
			m_pLog->Record(
					"ERROR:ReadCapability-->RKU_ReadCapability failed,err(%d)",
					ret);
		}
		return false;
	}
	if (data[0] & 0x1) {
		m_bDirectLba = true;
	} else
		m_bDirectLba = false;
	if (data[0] & 0x4) {
		m_bFirst4mAccess = true;
	} else
		m_bFirst4mAccess = false;
	return true;
}
