📄 disk.c
字号:
UsbDiskAttach(
HANDLE UsbTransport,
LPCWSTR pHardwareKey,
DWORD dwLun,
UCHAR bInterfaceSubClass
)
{
BOOL bRc = TRUE;
DWORD dwErr = ERROR_SUCCESS;
PSCSI_DEVICE pDevice = NULL;
REG_VALUE_DESCR rdTimeouts[] = {
MEDIA_POLL_SZ, REG_DWORD, sizeof(DWORD), (PUCHAR)(NULL),
READ_SECTOR_SZ, REG_DWORD, sizeof(DWORD), (PUCHAR)(NULL),
WRITE_SECTOR_SZ, REG_DWORD, sizeof(DWORD), (PUCHAR)(NULL),
SCSI_COMMAND_SZ, REG_DWORD, sizeof(DWORD), (PUCHAR)(NULL),
UNIT_ATTENTION_SZ, REG_DWORD, sizeof(DWORD), (PUCHAR)(NULL),
NULL, 0, 0, NULL
};
DEBUGMSG(ZONE_INIT, (TEXT("USBDISK6>DiskAttach\n")));
if (!UsbTransport || !pHardwareKey) {
SetLastError(ERROR_INVALID_PARAMETER);
DEBUGMSG( ZONE_ERR, (TEXT("Invalid Parameter\n")));
return NULL;
}
// try to accept all disks, probe the device, then unload if we can't controll it.
if ( !((bInterfaceSubClass >= USBMSC_SUBCLASS_RBC) && (bInterfaceSubClass <= USBMSC_SUBCLASS_SCSI)) ) {
DEBUGMSG( ZONE_ERR, (TEXT("Unsupported Disk bInterfaceSubClass:0x%x\n"), bInterfaceSubClass));
return NULL;
}
do {
//
// alloc at least 1 disk device context
//
pDevice = (PSCSI_DEVICE)LocalAlloc( LPTR, sizeof(SCSI_DEVICE) );
if ( !pDevice ) {
DEBUGMSG( ZONE_ERR, (TEXT("LocalAlloc error:%d\n"), GetLastError() ));
bRc = FALSE;
break;
}
// create sterile I/O request
pDevice->pSterileIoRequest = (PSG_REQ)LocalAlloc(
LPTR,
(sizeof(SG_REQ) + ((MAX_SG_BUF - 1) * sizeof(SG_BUF)))
);
if (NULL == pDevice->pSterileIoRequest) {
bRc = FALSE;
break;
}
pDevice->Sig = USBSCSI_SIG;
pDevice->hUsbTransport = UsbTransport;
pDevice->ActivePath = LocalAlloc(LPTR, wcslen(pHardwareKey)*sizeof(WCHAR)+sizeof(WCHAR));
if (!pDevice->ActivePath) {
DEBUGMSG( ZONE_ERR, (TEXT("LocalAlloc ERROR:%d\n"), GetLastError()));
bRc = FALSE;
break;
}
wcscpy(pDevice->ActivePath, pHardwareKey);
DEBUGMSG(ZONE_INIT, (TEXT("ActivePath:%s\n"), pDevice->ActivePath));
pDevice->DiskSubClass = bInterfaceSubClass;
InitializeCriticalSection( &pDevice->Lock );
if ( !InitializeRemoveLock( &pDevice->RemoveLock) ) {
DEBUGMSG( ZONE_ERR, (TEXT("InitializeRemoveLock failed\n")));
bRc = FALSE;
break;
}
//
// Grab the RemoveLock, which balances
// the ReleaseRemoveLockAndWait on UsbDiskDetach
//
AcquireRemoveLock(&pDevice->RemoveLock,NULL);
//
// set state flags
//
pDevice->MediumType = SCSI_MEDIUM_UNKNOWN;
pDevice->DeviceType = SCSI_DEVICE_UNKNOWN;
pDevice->Flags.MediumPresent = FALSE;
pDevice->Flags.MediumChanged = TRUE;
pDevice->Flags.DeviceRemoved = FALSE;
pDevice->Flags.PoweredDown = FALSE;
pDevice->Lun = (UCHAR)dwLun;
//
// Check registry for timeout values
//
rdTimeouts[0].Data = (PUCHAR)(&pDevice->Timeouts.MediaPollInterval);
rdTimeouts[1].Data = (PUCHAR)(&pDevice->Timeouts.ReadSector);
rdTimeouts[2].Data = (PUCHAR)(&pDevice->Timeouts.WriteSector);
rdTimeouts[3].Data = (PUCHAR)(&pDevice->Timeouts.ScsiCommandTimeout);
rdTimeouts[4].Data = (PUCHAR)(&pDevice->Timeouts.UnitAttnRepeat);
if ( !GetSetKeyValues(pHardwareKey,
&rdTimeouts[0],
GET,
FALSE) ) {
//
// use defaults
//
pDevice->Timeouts.MediaPollInterval = SCSI_MEDIA_POLL_INTERVAL;
pDevice->Timeouts.ReadSector = SCSI_READ_SECTOR_TIMEOUT;
pDevice->Timeouts.WriteSector = SCSI_WRITE_SECTOR_TIMEOUT;
pDevice->Timeouts.ScsiCommandTimeout = SCSI_COMMAND_TIMEOUT;
pDevice->Timeouts.UnitAttnRepeat = UNIT_ATTENTION_REPEAT;
// stuff defaults back in reg for tuning
if ( !GetSetKeyValues(pHardwareKey,
&rdTimeouts[0],
SET,
TRUE) ) {
DEBUGMSG(ZONE_ERR, (TEXT("GetSetKeyValues ERROR:%d\n"), GetLastError() ));
}
}
// let the user try a zero value, but complain in the debugger
ASSERT(pDevice->Timeouts.MediaPollInterval);
ASSERT(pDevice->Timeouts.ReadSector);
ASSERT(pDevice->Timeouts.WriteSector);
ASSERT(pDevice->Timeouts.ScsiCommandTimeout);
ASSERT(pDevice->Timeouts.UnitAttnRepeat);
// TODO: alloc additional disk instances and activate their interface...
//
// Activate the Streams Interface.
// This call invokes our DSK_Init.
//
pDevice->hStreamDevice = ActivateDevice(pDevice->ActivePath,
(DWORD)pDevice );
if ( !pDevice->hStreamDevice ) {
bRc = FALSE;
DEBUGMSG(ZONE_ERR, (TEXT("ActivateDevice ERROR:%d\n"), GetLastError() ));
TEST_TRAP();
break;
}
//
// Finally, if we discovered the device type and it has the removable media bit set
// (via the SCSI_INQUIRY command) then setup the media polling thread.
// Special case: CD-ROM must load UDFS, which has it's owm polling mechanism.
//
//
// We call need to ScsiInquiry() explicit because if a unit is not ready we do
// not know the DeviceType.
//
ScsiInquiry(pDevice, pDevice->Lun);
Sleep(500);
if ( SCSI_DEVICE_UNKNOWN != pDevice->DeviceType && pDevice->Flags.RMB &&
SCSI_DEVICE_CDROM != pDevice->DeviceType )
{
pDevice->hMediaChangedEvent = CreateEvent( NULL, AUTO_RESET_EVENT, FALSE, NULL);
if ( !pDevice->hMediaChangedEvent ) {
DEBUGMSG( ZONE_ERR, (TEXT("CreateEvent error:%d\n"), GetLastError() ));
bRc = FALSE;
break;
}
__try {
pDevice->hMediaPollThread = CreateThread( NULL, 0,
MediaChangeThread,
pDevice,
0, NULL );
if ( !pDevice->hMediaPollThread ) {
DEBUGMSG( ZONE_ERR, (TEXT("CreateThread error:%d\n"), GetLastError() ));
bRc = FALSE;
break;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode();
DEBUGMSG(ZONE_ERR,(TEXT("USBDISK6::UsbDiskAttach:EXCEPTION:0x%x\n"), dwErr));
TEST_TRAP();
}
}
} while (0);
if (!bRc) {
//
// If error then clean up
//
TEST_TRAP();
if (pDevice) {
ReleaseRemoveLock(&pDevice->RemoveLock,NULL);
RemoveDeviceContext( pDevice );
}
}
DEBUGMSG(ZONE_INIT, (TEXT("USBDISK6<DiskAttach:%d\n"), bRc));
return (bRc ? pDevice : NULL);
}
//
// The USB Mass Storage Class driver is removing this disk instance.
// Delete our context & streams interface.
//
BOOL
UsbDiskDetach(
PSCSI_DEVICE pDevice // Context
)
{
BOOL bRc = TRUE;
DWORD dwWait = 0;
DEBUGMSG(ZONE_INIT, (TEXT("USBDISK6>DiskDetach:%p\n"), pDevice));
if ( !VALID_CONTEXT( pDevice ) ) {
DEBUGMSG( ZONE_ERR, (TEXT("Invalid Context!\n")));
return FALSE;
}
//
// set Remove Pending state
//
EnterCriticalSection( &pDevice->Lock );
pDevice->Flags.DeviceRemoved = TRUE;
LeaveCriticalSection( &pDevice->Lock );
//
// wait for the polling thread to terminate
//
if (pDevice->hMediaChangedEvent && pDevice->hMediaPollThread) {
SetEvent(pDevice->hMediaChangedEvent);
WaitForSingleObject(pDevice->hMediaPollThread, INFINITE);
} else if ( pDevice->hStreamDevice ) {
//
// The device has no polling thread, so dismount the disk
//
DismountUpperDriver(pDevice);
} else {
TEST_TRAP();
}
//
// wait for the remove lock
//
DEBUGMSG(ZONE_INIT, (TEXT("ReleaseRemoveLockAndWait...\n")));
ReleaseRemoveLockAndWait( &pDevice->RemoveLock, NULL );
DEBUGMSG(ZONE_INIT, (TEXT("...ReleaseRemoveLockAndWait\n")));
//
// remove this device instance
//
RemoveDeviceContext( pDevice );
DEBUGMSG(ZONE_INIT, (TEXT("USBDISK6<DiskDetach:%d\n"), bRc));
return bRc;
}
//
// Mount the File System Driver named in the registry on top of our Device.
//
DWORD
MountUpperDriver(
IN PSCSI_DEVICE pDevice,
IN PPOST_INIT_BUF pInBuf
)
{
DWORD dwErr = ERROR_SUCCESS;
WCHAR sFsd[MAX_DLL_LEN] = DEFAULT_FSD_SZ;
REG_VALUE_DESCR RegVal[] = {
FSD_SZ, REG_SZ, MAX_DLL_LEN, (PUCHAR)(sFsd),
NULL, 0, 0, NULL
};
HANDLE h;
DEBUGMSG(ZONE_TRACE, (TEXT("USBDISK6>MountUpperDriver\n")));
if ( !VALID_CONTEXT( pDevice ) ) {
DEBUGMSG( ZONE_ERR, (TEXT("MountUpperDriver: Invalid Context!\n")));
return ERROR_INVALID_PARAMETER;
}
EnterCriticalSection(&pDevice->Lock);
do {
if (!pInBuf)
h = pDevice->hStreamDevice;
else
h = pInBuf->p_hDevice;
if ( !pDevice->ActivePath || !h ) {
dwErr = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERR, (TEXT("MountUpperDriver: ERROR_INVALID_PARAMETER\n")));
break;
}
if ( !GetSetKeyValues(pDevice->ActivePath,
RegVal,
GET,
FALSE ) ) {
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR, (TEXT("GetSetKeyValues ERRROR:%d\n"), dwErr));
TEST_TRAP();
break;
}
//
// Special case: CD-ROM must load UDFS
//
if (pDevice->DeviceType == SCSI_DEVICE_CDROM &&
wcscmp(sFsd, TEXT("UDFS.DLL")) != 0 )
{
DEBUGMSG(ZONE_WARN, (TEXT("LoadFSD:%s OVERRIDE to:%s\n"), sFsd, TEXT("UDFS.DLL")));
memset(sFsd, 0, MAX_DLL_LEN);
wcscpy(sFsd, TEXT("UDFS.DLL"));
}
//
// This will cause the named FSD to open our device, query via Ioctl,
// then close our device. We can not assume that the FSD is loaded until
// we successfully complete the IOCTL_DISK_GETINFO Ioctl.
//
__try {
if ( !LoadFSDEx(h, sFsd, LOADFSD_SYNCH) ) {
dwErr = GetLastError();
DEBUGMSG(ZONE_ERR, (TEXT("LoadFSD error:%d\n"), dwErr ));
TEST_TRAP();
break;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode();
DEBUGMSG(ZONE_ERR,(TEXT("USBDISK6::MountUpperDriver:EXCEPTION:0x%x\n"), dwErr));
}
// pDevice->Flags.FSDMounted = TRUE; // Set in IOCTL_DISK_GETINFO
} while(0);
LeaveCriticalSection(&pDevice->Lock);
DEBUGMSG(ZONE_TRACE, (TEXT("USBDISK6<MountUpperDriver:%d\n"), dwErr));
return dwErr;
}
/* ++
This function forces the FSD to dismount by unloading the streams interface.
This invokes our DSK_Deinit.
This deletes the active key in the registry, sends a WM_DEVICECHANGE
message, and triggers a NOTIFICATION_EVENT_DEVICE_CHANGE.
-- */
DWORD
DismountUpperDriver(
IN PSCSI_DEVICE pDevice
)
{
DWORD dwErr = ERROR_SUCCESS;
DEBUGMSG(ZONE_TRACE, (TEXT("USBDISK6>DismountUpperDriver\n")));
if ( !pDevice || !pDevice->hStreamDevice ) {
dwErr = ERROR_INVALID_PARAMETER;
} else {
EnterCriticalSection(&p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -