📄 cbit.c
字号:
)
{
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)
{
const USHORT wMaxPacketSize = Direction ? pUsbDevice->BulkIn.wMaxPacketSize : pUsbDevice->BulkOut.wMaxPacketSize;
// we don't provide our own phys buffer so are limited by USBD's max buffer size
const DWORD dwMaxBlock = (MAX_USB_BULK_LENGTH / wMaxPacketSize) * wMaxPacketSize;
PVOID pDataBlock = pData->DataBlock;
DWORD dwTransferLength = 0;
DWORD dwRequestLength = 0;
DWORD dwDataLength = pData->RequestLength;
DWORD dwTimeout = pCommand->Timeout;
DWORD dwStartTime=0;
UCHAR resets = 0; // consecutive resets
DEBUGMSG(ZONE_BOT,(TEXT("Data%s Transport - dwDataLength:%d, TimeOut:%d \n"), Direction ? TEXT("In") : TEXT("Out"), dwDataLength, dwTimeout ));
while (dwDataLength && ((signed)dwTimeout > 0) && resets < 3)
{
dwRequestLength = min(dwMaxBlock, dwDataLength);
dwTransferLength = 0;
DEBUGMSG(ZONE_BOT,(TEXT("Data%s Transport - dwRequestLength:%d, TimeOut:%d \n"), Direction ? TEXT("In") : TEXT("Out"), dwRequestLength, dwTimeout ));
ASSERT( dwRequestLength <= MAX_USB_BULK_LENGTH );
dwStartTime = GetTickCount();
dwErr = IssueBulkTransfer( pUsbDevice->UsbFuncs,
Direction ? pUsbDevice->BulkIn.hPipe : pUsbDevice->BulkOut.hPipe,
DefaultTransferComplete,
Direction ? pUsbDevice->BulkIn.hEvent : pUsbDevice->BulkOut.hEvent,
Direction ? (USB_IN_TRANSFER|USB_NO_WAIT|USB_SHORT_TRANSFER_OK) : (USB_OUT_TRANSFER|USB_NO_WAIT|USB_SHORT_TRANSFER_OK),
pDataBlock, 0,
dwRequestLength,
&dwTransferLength,
dwTimeout,
&dwUsbErr );
// accept any data received
if ( (ERROR_SUCCESS == dwErr || ERROR_TIMEOUT == dwErr) &&
(USB_NO_ERROR == dwUsbErr || USB_STALL_ERROR == dwUsbErr) )
{
#if DEBUG
if ( dwTransferLength != dwRequestLength ) {
DEBUGMSG( ZONE_WARN, (TEXT("CBIT_DataTransfer warning(a, RequestLength:%d TransferLength:%d Err:%d UsbErr:0x%x)\n"), dwRequestLength, dwTransferLength, dwErr, dwUsbErr ));
}
#endif
// adjust transfer length & buffer
ASSERT(dwTransferLength <= dwRequestLength);
pData->TransferLength += dwTransferLength;
dwDataLength -= dwTransferLength;
pDataBlock = (PVOID)((PBYTE)pDataBlock + dwTransferLength);
}
if ((ERROR_SUCCESS != dwErr) || (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));
dwDataLength = 0;
}
// protocol says its done
if (USB_NO_ERROR != dwUsbErr) {
dwDataLength = 0;
}
} else {
resets = 0;
}
dwTimeout -= (GetTickCount() - dwStartTime);
}
}
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 + -