//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
usbclient.c
Abstract:
Common USB Client Driver Interface
Issues:
No isoch support yet
--*/
#include "usbclient.h"
#if 0
#ifdef DEBUG
DBGPARAM dpCurSettings = {
TEXT("USBCLIENT"), {
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined")
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined")
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined")
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined")
},
0x0003 // ZONE_WRN|ZONE_ERR
};
#endif // DEBUG
BOOL
DllEntry(
HANDLE hDllHandle,
DWORD dwReason,
LPVOID lpreserved
)
{
UNREFERENCED_PARAMETER(lpreserved);
switch (dwReason) {
case DLL_PROCESS_ATTACH:
DEBUGREGISTER((HINSTANCE)hDllHandle);
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}
#endif 0
__inline
DWORD
_ResetEvent(
HANDLE hEvent
)
{
DWORD dwErr = ERROR_SUCCESS;
if ( !ResetEvent(hEvent) ) {
dwErr = GetLastError();
DEBUGMSG(ZONE_USBCLIENT, (TEXT("*** ResetEvent ERROR:%d ***\n"), dwErr));
// ASSERT(0);
return dwErr;
}
return TRUE;
}
BOOL
AbortTransfer(
LPCUSB_FUNCS pUsbFuncs,
USB_TRANSFER hTransfer,
DWORD dwFlags
)
{
BOOL bRc = TRUE;
// AbortTransfer checks if the transfer has already completed
if ( !pUsbFuncs->lpAbortTransfer(hTransfer, dwFlags) ) {
DEBUGMSG( ZONE_USBCLIENT, (TEXT("*** AbortTransfer ERROR:%d ***\n"), GetLastError()));
bRc = FALSE;
}
return bRc;
}
BOOL
CloseTransferHandle(
LPCUSB_FUNCS pUsbFuncs,
USB_TRANSFER hTransfer
)
{
BOOL bRc = TRUE;
// This assert may fail on suprise remove,
// but should pass during normal I/O.
// ASSERT( pUsbFuncs->lpIsTransferComplete(hTransfer) );
// CloseTransfer aborts any pending transfers
if ( !pUsbFuncs->lpCloseTransfer(hTransfer) ) {
DEBUGMSG( ZONE_USBCLIENT, (TEXT("*** CloseTransfer ERROR:%d ***\n"), GetLastError()));
bRc = FALSE;
}
return bRc;
}
//
// Returns:
// Win32 error
//
// Note:
// a synchronous ClearOrSetFeature call can take quite some time.
//
DWORD
ClearOrSetFeature(
LPCUSB_FUNCS pUsbFuncs,
HANDLE hUsbDevice,
LPTRANSFER_NOTIFY_ROUTINE NotifyRoutine, // CallbackRoutine: signals a completion event.
PVOID NotifyContext, // CallbackContext: handle to a BulkXxx Completion Event
DWORD dwFlags, // see ClearOrSetFeature doc
WORD wFeature, // one of USB_FEATURE_*
UCHAR bIndex,
DWORD dwTimeout, // Timeout in msec
BOOL bSet // TRUE to Set, FALSE to Clear
)
{
DWORD dwErr = ERROR_SUCCESS;
DWORD dwUsbErr = USB_NO_ERROR;
DWORD dwWaitReturn;
USB_TRANSFER hTransfer;
if (NotifyContext && NotifyRoutine && dwTimeout) {
_ResetEvent(NotifyContext); // NotifyContext *must* be an EVENT
}
//
// reset endpoint on device
//
if (bSet)
hTransfer = pUsbFuncs->lpSetFeature( hUsbDevice,
NotifyRoutine,
NotifyContext,
dwFlags,
wFeature,
bIndex );
else
hTransfer = pUsbFuncs->lpClearFeature( hUsbDevice,
NotifyRoutine,
NotifyContext,
dwFlags,
wFeature,
bIndex );
if ( hTransfer ) {
//
// Asynch call completed.
// Get transfer status & number of bytes transferred
//
if (NotifyContext && NotifyRoutine) {
if (!dwTimeout) {
return (DWORD)hTransfer;
}
//
// sync the transfer completion / timer
//
dwWaitReturn = WaitForSingleObject( NotifyContext,
dwTimeout );
switch (dwWaitReturn) {
case WAIT_OBJECT_0:
//
// The completion event was signalled by the callback.
// determine if it was actually cleared on the device
//
// ASSERT( pUsbFuncs->lpIsTransferComplete(hTransfer) );
GetTransferStatus(pUsbFuncs, hTransfer, NULL, &dwUsbErr);
if ( USB_NO_ERROR != dwUsbErr)
dwErr = ERROR_GEN_FAILURE;
break;
case WAIT_TIMEOUT:
//
// The transfer reqest timed out.
//
DEBUGMSG( ZONE_USBCLIENT, (TEXT("ClearOrSetFeature:WAIT_TIMEOUT on bIndex:0x%x\n"), bIndex ));
GetTransferStatus(pUsbFuncs, hTransfer, NULL, &dwUsbErr);
//
// let caller know it timed out
//
dwErr = ERROR_TIMEOUT;
break;
default:
dwErr = ERROR_GEN_FAILURE;
DEBUGMSG( ZONE_USBCLIENT, (TEXT("*** Unhandled WaitReason:%d ***\n"), dwWaitReturn ));
break;
}
} else {
//
// Synch call completed.
// determine if it was actually cleared on the device
//
// ASSERT( pUsbFuncs->lpIsTransferComplete(hTransfer) );
GetTransferStatus(pUsbFuncs, hTransfer, NULL, &dwUsbErr);
if ( USB_NO_ERROR != dwUsbErr)
dwErr = ERROR_GEN_FAILURE;
}
CloseTransferHandle(pUsbFuncs, hTransfer);
} else {
dwErr = GetLastError();
DEBUGMSG( ZONE_USBCLIENT, (TEXT("*** ClearOrSetFeature on endpoint:0x%x ERROR:%d ***\n"), bIndex, dwErr ));
}
return dwErr;
}
//
// Generic DefaultTransferComplete callback routine.
// Simply signals the hEvent passed in when USB signals a transfer is done.
// If you prematurely close/abort a transfer then this routine will still run.
//
DWORD
DefaultTransferComplete(
PVOID Context
)
{
HANDLE hEvent = (HANDLE)Context;
DWORD dwErr = ERROR_SUCCESS;
if ( hEvent ) {
//
// The current operation completed, signal the event
//
if ( !SetEvent( hEve