📄 diskmain.cpp
字号:
else // CDisk::Identify has determined that the devce supports multi-sector transfers
{
m_bReadCommand = ATA_CMD_READ_MULTIPLE_EXT;
m_bWriteCommand = ATA_CMD_WRITE_MULTIPLE_EXT;
}
m_bDMAReadCommand = ATA_CMD_READ_DMA_EXT;
m_bDMAWriteCommand = ATA_CMD_WRITE_DMA_EXT;
}
else
{
m_fUseLBA48 = FALSE;
}
}
// ----------------------------------------------------------------------------
// Function: ValidateSg
// Map embedded pointers
//
// Parameters:
// pSgReq -
// InBufLen - The size of the actual buffer as specified by the user.
// This needs to be cross checked with pSgReq->sr_num_sg to
// prevent buffer overflows
// saveoldptrs - Your old pointers are saved here. Must be at least
// pSgReq->sr_num_sg in size
// ----------------------------------------------------------------------------
BOOL
CDisk::ValidateSg(
PSG_REQ pSgReq,
DWORD InBufLen,
DWORD dwArgType,
OUT PUCHAR * saveoldptrs
)
{
DWORD dwIndex ;
PUCHAR ptemp;
if (NULL == pSgReq) {
ASSERT(pSgReq);
return FALSE;
}
if (InBufLen < sizeof(SG_REQ)) {
ASSERT(InBufLen >= sizeof(SG_REQ));
return FALSE;
}
// pSgReq is a sterile copy of the caller's SG_REQ; we're supposed to map
// the embedded sb_bufs back into the SG_REQ
if(
!(pSgReq->sr_num_sg >= 1) ||
!(pSgReq->sr_num_sg <= MAX_SG_BUF) ||
!((sizeof(SG_REQ) + sizeof(SG_BUF)*(pSgReq->sr_num_sg-1)) == InBufLen) ||
!(pSgReq->sr_num_sec > 0))
{
ASSERT(pSgReq->sr_num_sg >= 1);
ASSERT(pSgReq->sr_num_sg <= MAX_SG_BUF);
ASSERT((sizeof(SG_REQ) + sizeof(SG_BUF)*(pSgReq->sr_num_sg-1)) == InBufLen);
ASSERT(pSgReq->sr_num_sec > 0);
return FALSE;
}
for (dwIndex = 0; dwIndex < pSgReq->sr_num_sg; dwIndex++) {
if (
(NULL == pSgReq->sr_sglist[dwIndex].sb_buf) ||
(0 == pSgReq->sr_sglist[dwIndex].sb_len)
) {
goto CleanUpLeak;
}
// Verify embedded pointer access and map user mode pointers
if (FAILED(CeOpenCallerBuffer(
(PVOID *)&ptemp,
(LPVOID)pSgReq->sr_sglist[dwIndex].sb_buf,
pSgReq->sr_sglist[dwIndex].sb_len,
dwArgType,
FALSE)))
{
goto CleanUpLeak;
}
saveoldptrs[dwIndex] = pSgReq->sr_sglist[dwIndex].sb_buf;
pSgReq->sr_sglist[dwIndex].sb_buf = ptemp;
if (NULL == pSgReq->sr_sglist[dwIndex].sb_buf) {
goto CleanUpLeak;
}
}
return TRUE;
CleanUpLeak:
if (FAILED(UnmapSg(
pSgReq->sr_sglist,
saveoldptrs,
dwIndex,
dwArgType)))
{
ASSERT(!"Cleanup call to CeCloseCallerBuffer failed unexpectedly");
return FALSE;
}
return FALSE;
}
// ----------------------------------------------------------------------------
// Function: UnmapSg
// UnMap embedded pointers, previously mapped by ValidateSg.
// Basically, an SG Array version of CeCloseCallerBuffer
//
// Parameters:
// sr_sglist - List of mapped SG buffers to unmap
// saveoldptrs - List of old unmapped pointers
// sr_sglistlen - The size of sr_sglist
// dwArgType - ARG_O_PTR/ ARG_I_PTR
// Return value - HRESULT from a failed call to CeCloseCallerBuffer
// otherwise ERROR_SUCCESS
// ----------------------------------------------------------------------------
HRESULT
CDisk::UnmapSg(
IN const SG_BUF * sr_sglist,
IN const PUCHAR * saveoldptrs,
IN DWORD sr_sglistlen,
IN DWORD dwArgType
)
{
HRESULT dwError = ERROR_SUCCESS;
ASSERT(sr_sglistlen <= MAX_SG_BUF);
for (DWORD dwIndex = 0; dwIndex < sr_sglistlen; dwIndex++) {
HRESULT dwtemp;
ASSERT(NULL != sr_sglist[dwIndex].sb_buf);
ASSERT(0 != sr_sglist[dwIndex].sb_len);
// Close pointers previously mapped in ValidateSg
dwtemp = CeCloseCallerBuffer(
(LPVOID)sr_sglist[dwIndex].sb_buf,
(LPVOID)saveoldptrs[dwIndex],
sr_sglist[dwIndex].sb_len,
dwArgType);
if (FAILED(dwtemp)) {
ASSERT(!"Cleanup call to CeCloseCallerBuffer failed unexpectedly");
dwError = dwtemp;
}
}
return dwError;
}
// ----------------------------------------------------------------------------
// Function: SendDiskPowerCommand
// Put the device into a specified power state. The optional parameter is
// programmed into the Sector Count register, which is used for the
// ATA NEW CMD IDLE and ATA CMD STANDBY commands.
//
// Parameters:
// bCmd -
// bParam -
// ----------------------------------------------------------------------------
BOOL
CDisk::SendDiskPowerCommand(
BYTE bCmd,
BYTE bParam
)
{
BYTE bError, bStatus;
BOOL fOk = TRUE;
if(ZONE_CELOG) CeLogData(TRUE, CELID_ATAPI_POWERCOMMAND, &bCmd, sizeof(bCmd), 0, CELZONE_ALWAYSON, 0, FALSE);
// HI:Check_Status (Host Idle); wait until BSY=0 and DRQ=0
// read Status register
while (1) {
bStatus = GetAltStatus();
if (!(bStatus & (0x80|0x08))) break; // BSY := Bit 7, DRQ := Bit 3
Sleep(5);
}
// HI:Device_Select; select device
SelectDevice();
// HI:Check_Status (Host Idle); wait until BSY=0 and DRQ=0
// read Status register
while (1) {
bStatus = GetAltStatus();
if (!(bStatus & (0x80|0x08))) break; // BSY := Bit 7, DRQ := Bit 3
Sleep(5);
}
// HI:Write_Parameters
WriteSectorCount(bParam);
// WriteAltDriveController(0x00); // disable interrupt (nIEN := Bit 1 of Device Control register)
// HI:Write_Command
WriteCommand(bCmd);
// transition to non-data command protocol
// HND:INTRQ_Wait
// transition to HND:Check_Status
// read Status register
while (1) { // BSY := Bit 7
bStatus = GetAltStatus();
bError = GetError();
if (bError & 0x04) { // ABRT := Bit 2
// command was aborted
DEBUGMSG(ZONE_ERROR, (_T(
"Atapi!CDisk::SendDiskPowerCommand> Failed to send command 0x%x, parameter 0x%x\r\n"
), bCmd, bParam));
fOk = FALSE;
break;
}
if (!(bStatus & 0x80)) break; // BSY := Bit 7
Sleep(5);
}
// transition to host idle protocol
return fOk;
}
// ----------------------------------------------------------------------------
// Function: GetDiskPowerInterface
// Return the power management object associated with this device
//
// Parameters:
// None
// ----------------------------------------------------------------------------
CDiskPower *
CDisk::GetDiskPowerInterface(
void
)
{
CDiskPower *pDiskPower = new CDiskPower;
return pDiskPower;
}
// ----------------------------------------------------------------------------
// Function: SetDiskPowerState
// Map a power state to an ATA power management command and issue the
// command
//
// Parameters:
// newDx -
// ----------------------------------------------------------------------------
BOOL
CDisk::SetDiskPowerState(
CEDEVICE_POWER_STATE newDx
)
{
BYTE bCmd;
if (ZONE_CELOG) {
DWORD dwDx = (DWORD) newDx;
CeLogData(TRUE, CELID_ATAPI_SETDEVICEPOWER, &dwDx, sizeof(dwDx), 0, CELZONE_ALWAYSON, 0, FALSE);
}
// on D0 go to IDLE to minimize latency during disk accesses
if(newDx == D0 || newDx == D1) {
bCmd = ATA_CMD_IDLE_IMMEDIATE;
}
else if(newDx == D2) {
bCmd = ATA_CMD_STANDBY_IMMEDIATE;
}
else if(newDx == D3 || newDx == D4) {
bCmd = ATA_CMD_SLEEP;
}
else {
DEBUGMSG(ZONE_WARNING, (_T(
"CDisk::SetDiskPowerState> Invalid power state value(%u)\r\n"
), newDx));
return FALSE;
}
// update the disk power state
return SendDiskPowerCommand(bCmd);
}
// ----------------------------------------------------------------------------
// Function: WakeUp
// Wake the device up from sleep
//
// Parameters:
// None
// ----------------------------------------------------------------------------
BOOL
CDisk::WakeUp(
)
{
if (!ResetController(FALSE)) {
return FALSE;
}
return SendIdentifyDevice(IsAtapiDevice());
}
// ----------------------------------------------------------------------------
// Function: MainIoctl
// Process IOCTL_DISK_ and DISK_IOCTL_ I/O controls
//
// Parameters:
// pIOReq -
// ----------------------------------------------------------------------------
DWORD CDisk::MainIoctl(PIOREQ pIOReq)
{
DWORD dwError = ERROR_SUCCESS;
DEBUGMSG(ZONE_IOCTL, (TEXT("Atapi!CDisk::MainIoctl> IOCTL(%x), device(%x)\r\n"), pIOReq->dwCode, m_dwDeviceId));
// If device is powering down, then fail.
if (m_dwDeviceFlags & DFLAGS_DEVICE_PWRDN) {
SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
return FALSE;
}
switch(pIOReq->dwCode) {
case IOCTL_DISK_GETINFO:
case DISK_IOCTL_GETINFO:
if (IsCDRomDevice()) {
dwError = ERROR_BAD_COMMAND;
}
else {
dwError = GetDiskInfo(pIOReq);
}
break;
case IOCTL_DISK_DEVICE_INFO:
dwError = GetDeviceInfo(pIOReq);
break;
case DISK_IOCTL_GETNAME:
case IOCTL_DISK_GETNAME:
dwError = GetDiskName(pIOReq);
break;
case DISK_IOCTL_SETINFO:
case IOCTL_DISK_SETINFO:
dwError = SetDiskInfo(pIOReq);
break;
case DISK_IOCTL_READ:
case IOCTL_DISK_READ:
case DISK_IOCTL_WRITE:
case IOCTL_DISK_WRITE:
{
PSG_REQ pUnsafeInBuf = (PSG_REQ)pIOReq->pInBuf;
BOOL fRead = (pIOReq->dwCode == DISK_IOCTL_READ || pIOReq->dwCode == IOCTL_DISK_READ);
//RETAILMSG(1,(TEXT("######### fRead %d BufLength 0x%x ##########\n"),fRead,pUnsafeInBuf->sr_sglist[0].sb_len));
if (!pIOReq->dwInBufSize || !pIOReq->pInBuf) {
dwError = ERROR_INVALID_PARAMETER;
break;
}
if (pIOReq->dwInBufSize >(sizeof(SG_REQ) + ((MAX_SG_BUF) - 1) * sizeof(SG_BUF))) {
dwError = ERROR_INVALID_PARAMETER;
// size of m_pSterileIoRequest is sizeof(SG_REQ) + ((MAX_SG_BUF) - 1) * sizeof(SG_BUF))
break;
}
// Copy the caller's SG_REQ.
if (0 == CeSafeCopyMemory((LPVOID)m_pSterileIoRequest, (LPVOID)pUnsafeInBuf, pIOReq->dwInBufSize)) {
dwError = ERROR_INVALID_PARAMETER;
break;
}
if (NULL == m_pSterileIoRequest) {
ASSERT(m_pSterileIoRequest);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -