📄 cbit.c
字号:
dwErr = ERROR_GEN_FAILURE;
}
}
STOP_DT( TEXT("CBIT_CommandTransport"), 1000, pUsbDevice->Timeouts.CommandBlock );
DEBUGMSG( ZONE_TRACE, (TEXT("USBMSC<CBIT_CommandTransport:%d\n"), dwErr) );
return dwErr;
}
DWORD
CBIT_StatusTransport(
PUSBMSC_DEVICE pUsbDevice
)
{
DWORD dwBytesTransferred = 0;
DWORD dwErr = ERROR_SUCCESS;
DWORD dwUsbErr = USB_NO_ERROR;
UCHAR ucStatus[2];
DWORD dwStatusSize = sizeof(ucStatus);
BOOL bRc = FALSE;
if ( !ACCEPT_IO(pUsbDevice) ) {
dwErr = ERROR_ACCESS_DENIED;
DEBUGMSG( ZONE_ERR,(TEXT("CBIT_StatusTransport error:%d\n"), dwErr));
SetLastError(dwErr);
return dwErr;
}
if (pUsbDevice->Interrupt.hPipe && !pUsbDevice->Flags.IgnoreInterrupt) {
memset( ucStatus, 0, dwStatusSize );
START_DT;
dwErr = IssueInterruptTransfer(pUsbDevice->UsbFuncs,
pUsbDevice->Interrupt.hPipe,
DefaultTransferComplete,
pUsbDevice->Interrupt.hEvent,
USB_IN_TRANSFER|USB_NO_WAIT|USB_SHORT_TRANSFER_OK,
ucStatus, 0,
dwStatusSize,
&dwBytesTransferred,
pUsbDevice->Timeouts.CommandStatus,
&dwUsbErr );
STOP_DT( TEXT("StatusTransport"), 100, pUsbDevice->Timeouts.CommandStatus );
// check Status Transport bits
if ( ERROR_SUCCESS != dwErr || USB_NO_ERROR != dwUsbErr || dwBytesTransferred != dwStatusSize ) {
ResetPipe(pUsbDevice->UsbFuncs, pUsbDevice->Interrupt.hPipe, USB_NO_WAIT);
pUsbDevice->InterruptErrors++;
DEBUGMSG( ZONE_ERR, (TEXT("CBIT_Status Transport error(%d, 0x%x, %d, %d)\n"), dwErr, dwUsbErr, dwBytesTransferred, pUsbDevice->InterruptErrors ));
goto CBIT_StatusTransportDone;
} else {
pUsbDevice->InterruptErrors = 0;
}
//
// Check Command Status
//
switch (pUsbDevice->pUsbInterface->Descriptor.bInterfaceSubClass)
{
case USBMSC_SUBCLASS_UFI:
//
// The ASC & (optional) ASCQ are in the data block.
//
if ( ucStatus[0] ) {
DEBUGMSG(ZONE_ERR, (TEXT("CBIT_StatusTransport::UFI: ASC:0x%x ASCQ:0x%x\n"), ucStatus[0], ucStatus[1] ));
dwErr = ERROR_PERSISTANT;
}
break;
default:
{
if (CBIT_COMMAND_COMPLETION_INTERRUPT != ucStatus[0] ) {
DEBUGMSG(ZONE_ERR, (TEXT("Invalid Command Completion Interrupt: 0x%x\n"), ucStatus[0] ));
TEST_TRAP();
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_GEN_FAILURE;
goto CBIT_StatusTransportDone;
}
switch ( ucStatus[1] & 0x0F ) {
case CBIT_STATUS_SUCCESS:
break;
case CBIT_STATUS_FAIL:
DEBUGMSG(ZONE_ERR, (TEXT("CBIT_STATUS_FAIL\n")));
dwErr = ERROR_GEN_FAILURE;
break;
case CBIT_STATUS_PHASE_ERROR:
DEBUGMSG(ZONE_ERR, (TEXT("CBIT_STATUS_PHASE_ERROR\n")));
// TBD: send CommandBlockReset
dwErr = ERROR_GEN_FAILURE;
break;
case CBIT_STATUS_PERSISTENT_ERROR:
DEBUGMSG(ZONE_ERR, (TEXT("CBIT_STATUS_PERSISTENT_ERROR\n")));
//
// The CBIT spec states that a REQUEST_SENSE command block must be sent,
// which must be handled by the disk device.
//
dwErr = ERROR_PERSISTANT;
TEST_TRAP();
break;
default:
TEST_TRAP();
DEBUGMSG(ZONE_ERR, (TEXT("Invalid Command Completion Status: 0x%x\n"), ucStatus[1] ));
dwErr = ERROR_GEN_FAILURE;
break;
}
}
}
}
CBIT_StatusTransportDone:
//
// TODO: Some devices claim to use the interrupt endpoint but really do not.
// Currently, the only way to determine if the device really uses the
// interrupt endpoint is to try it a few times and see. Need to add registry work arounds.
// Exceptions:
// UFI Spec 2.1: Interrupt endpoint required
//
if (MAX_INT_RETRIES == pUsbDevice->InterruptErrors &&
!(USBMSC_SUBCLASS_UFI == pUsbDevice->pUsbInterface->Descriptor.bInterfaceSubClass &&
USBMSC_INTERFACE_PROTOCOL_CBIT == pUsbDevice->pUsbInterface->Descriptor.bInterfaceProtocol)
)
{
DEBUGMSG( ZONE_WARN, (TEXT("USBMSC:IgnoreInterrupt:ON\n"), dwErr) );
EnterCriticalSection(&pUsbDevice->Lock);
pUsbDevice->Flags.IgnoreInterrupt = TRUE;
LeaveCriticalSection(&pUsbDevice->Lock);
pUsbDevice->InterruptErrors++;
}
DEBUGMSG( ZONE_TRACE, (TEXT("USBMSC<CBIT_StatusTransport:%d\n"), dwErr) );
return dwErr;
}
//
// Command/Data/Status Transport
//
DWORD
CBIT_DataTransfer(
PUSBMSC_DEVICE pUsbDevice,
PTRANSPORT_COMMAND pCommand,
OPTIONAL PTRANSPORT_DATA pData, // OPTIONAL
BOOL Direction // TRUE = Data-In, else Data-Out
)
{
DWORD dwBytesTransferred = 0;
DWORD dwErr = ERROR_SUCCESS;
DWORD dwUsbErr = USB_NO_ERROR;
DWORD dwResetErr, dwStatusErr;
BOOL bRc = FALSE;
INIT_DT;
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>CBIT_DataTransfer\n")));
// parameter checks
if ( !pCommand || !pCommand->CommandBlock /*|| pCommand->Length > MAX_CBWCB_SIZE*/ ) {
dwErr = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERR,(TEXT("CBIT_DataTransfer error:%d\n"),dwErr));
SetLastError(dwErr);
return dwErr;
}
if ( !ACCEPT_IO(pUsbDevice) ) {
dwErr = ERROR_ACCESS_DENIED;
DEBUGMSG( ZONE_ERR,(TEXT("CBIT_DataTransfer error:%d\n"), dwErr));
SetLastError(dwErr);
return dwErr;
}
//
// We require exclusive entry into the transport.
// we could implement command queuing.
//
EnterCriticalSection(&pUsbDevice->Lock);
if ( !CBIT_ResetAllPipes(pUsbDevice) ) {
DEBUGMSG( ZONE_ERR, (TEXT("CBIT_ResetAllPipes failed!\n")));
dwErr = ERROR_GEN_FAILURE;
goto CBIT_SendCommandDone;
}
//
// Command Block Transport via ADSC
//
dwErr = CBIT_CommandTransport( pUsbDevice,
pCommand,
&dwBytesTransferred );
if (ERROR_SUCCESS != dwErr || dwBytesTransferred != pCommand->Length) {
// 2.3.2.1: if the device does STALL an ADSC, then the device shall not
// transport the status for the command block by interrupt pipe.
// Treat a timeout in the same manner.
goto CBIT_SendCommandDone;
}
//
// (optional) Data Transport
//
if (pData && pData->DataBlock && pData->RequestLength) {
UCHAR resets = 0; // consecutive resets
DEBUGMSG(ZONE_BOT,(TEXT("Data%s Transport - dwDataLength:%d, TimeOut:%d \n"), Direction ? TEXT("In") : TEXT("Out"), pData->RequestLength, pCommand->Timeout ));
while (resets < 3) {
PIPE pipeObj = Direction ? pUsbDevice->BulkIn : pUsbDevice->BulkOut;
DWORD dwFlags = Direction ? (USB_IN_TRANSFER|USB_NO_WAIT|USB_SHORT_TRANSFER_OK) : (USB_OUT_TRANSFER|USB_NO_WAIT|USB_SHORT_TRANSFER_OK);
BOOL fRet ;
DWORD dwTimeout = pCommand->Timeout;
DWORD dwStartTime=0;
DWORD dwUsbErr = USB_NOT_COMPLETE_ERROR;
DWORD dwTransferLength = 0 ;
ResetEvent(pipeObj.hEvent);
fRet = BulkTransferMgrTransfer(pipeObj.pAsyncContent, DefaultTransferComplete, pipeObj.hEvent,
dwFlags, pData->DataBlock, pData->RequestLength );
if (fRet ) {
if (!BulkTransferWait(pipeObj.pAsyncContent, dwTimeout)) {
fRet = BulkTransferMgrGetStatus(pipeObj.pAsyncContent, &dwTransferLength , &dwUsbErr);
dwUsbErr = USB_NOT_COMPLETE_ERROR;
}
else {
fRet = BulkTransferMgrGetStatus(pipeObj.pAsyncContent, &dwTransferLength , &dwUsbErr);
}
BulkTransferClose(pipeObj.pAsyncContent);
}
pData->TransferLength = dwTransferLength;
DEBUGMSG( ZONE_WARN && pData->RequestLength!= pData->TransferLength,
(TEXT("CBIT_DataTransfer warning(a, RequestLength:%d TransferLength:%d Err:%d UsbErr:0x%x)\n"), pData->RequestLength, pData->TransferLength, dwErr, dwUsbErr ));
if (USB_NO_ERROR != dwUsbErr) {
//
// reset the Bulk pipe
//
UCHAR bIndex = Direction ? pUsbDevice->BulkIn.bIndex : pUsbDevice->BulkOut.bIndex;
DEBUGMSG( ZONE_ERR, (TEXT("CBIT_DataTransfer error(b, dwErr:%d, dwUsbErr:0x%x, dwTimeout:%d)\n"), dwErr, dwUsbErr, dwTimeout));
resets++;
dwResetErr = ResetBulkEndpoint( pUsbDevice->UsbFuncs,
pUsbDevice->hUsbDevice,
Direction ? pUsbDevice->BulkIn.hPipe : pUsbDevice->BulkOut.hPipe,
DefaultTransferComplete,
Direction ? pUsbDevice->BulkIn.hEvent : pUsbDevice->BulkOut.hEvent,
bIndex,
pUsbDevice->Timeouts.Reset );
if (ERROR_SUCCESS != dwResetErr) {
DEBUGMSG( ZONE_ERR, (TEXT("ResetBulkEndpoint.1 ERROR:%d\n"), dwResetErr));
dwErr = ERROR_GEN_FAILURE;
break;
}
if (dwUsbErr == USB_NOT_COMPLETE_ERROR) { // Not be able complete. It is not stall.
dwErr = ERROR_GEN_FAILURE;
break;
}
}
else { // Success.
break;
}
}
}
CBIT_SendCommandDone:
//
// cleanup
//
if (ERROR_SUCCESS != dwErr) {
bRc = CBIT_ResetRecovery(pUsbDevice);
}
else {
//
// Status Transport
//
DEBUGMSG(ZONE_BOT,(TEXT("Status Transport\n")));
dwStatusErr = CBIT_StatusTransport( pUsbDevice );
if (ERROR_SUCCESS != dwStatusErr ) {
if (ERROR_SUCCESS == dwErr)
dwErr = dwStatusErr;
}
}
LeaveCriticalSection(&pUsbDevice->Lock);
DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<CBIT_DataTransfer:%d\n"), dwErr));
return dwErr;
}
// EOF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -