📄 wdu_lib.cpp
字号:
////////////////////////////////////////////////////////////////
// File - wdu_lib.c
//
// WinDriver USB API Declarations & Implementations
//
// Copyright (c) 2003 - 2006 Jungo Ltd. http://www.jungo.com
////////////////////////////////////////////////////////////////
#include "stdafx.h"
#ifdef __KERNEL_DRIVER__
#include "kd.h"
#elif defined(_KERNEL_)
#include "kpstdlib.h"
#endif
#include "wdu_lib.h"
#include "windrvr_events.h"
#include "status_strings.h"
#include "utils.h"
#include <stdarg.h>
#include <stdio.h>
#include "StdAfx.h"
// Print Functions
#if defined(__KERNEL__) && defined(WIN32)
#pragma warning( disable :4013 4100)
#endif
#if !defined(TRACE)
int __cdecl TRACE(const char *fmt, ...)
{
#if defined(DEBUG)
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
#endif
return 0;
}
#endif
#if !defined(ERR)
int __cdecl ERR(const char *fmt, ...)
{
#if defined(DEBUG)
va_list argp;
va_start(argp, fmt);
fprintf(stderr, "WDERROR: ");
vfprintf(stderr, fmt, argp);
va_end(argp);
#endif
return 0;
}
#endif
// Structures
#define WDU_DEVLIST_TIMEOUT 30 // in seconds
#define WDU_TRANSFER_TIMEOUT 30000 // in msecs
typedef struct
{
HANDLE hWD;
WDU_EVENT_TABLE EventTable;
HANDLE hEvents;
} DRIVER_CTX;
typedef struct
{
DRIVER_CTX *pDriverCtx;
WDU_DEVICE *pDevice; // not fixed size => ptr
DWORD dwUniqueID;
} DEVICE_CTX;
typedef struct _WDU_DEVICE_LIST_ITEM
{
struct _WDU_DEVICE_LIST_ITEM *next;
DEVICE_CTX *pDeviceCtx;
} WDU_DEVICE_LIST_ITEM;
typedef struct
{
WDU_DEVICE_LIST_ITEM *pHead;
HANDLE hEvent;
int iRefCount;
} WDU_DEVICE_LIST;
WDU_DEVICE_LIST DevList; // global devices list
// Private Functions Prototypes
static DWORD AddDeviceToDevList(DEVICE_CTX *pDeviceCtx);
static DWORD RemoveDeviceFromDevList(DRIVER_CTX *pDriverCtx, DWORD dwUniqueID, DEVICE_CTX **ppDeviceCtx);
static DWORD RemoveAllDevicesFromDevList(DRIVER_CTX *pDriverCtx);
static DWORD FindDeviceByUniqueID(DRIVER_CTX *pDriverCtx, DWORD dwUniqueID, DEVICE_CTX **ppDeviceCtx);
static DWORD FindDeviceByCtx(DEVICE_CTX *pDeviceCtx);
// Translate WD_functions into IOCTLs
#define PARAMS_SET(param) Params.param = param
#define GET_HWD(h) (((DEVICE_CTX *)(h))->pDriverCtx->hWD)
// unique ID is passed in IOCTLs to identify the device/interface instead of
// hDevice like in the old API
#define PARAMS_INIT(T) \
T Params; \
BZERO(Params); \
if (!hDevice || FindDeviceByCtx((DEVICE_CTX *)hDevice) != WD_STATUS_SUCCESS) \
return WD_DEVICE_NOT_FOUND; \
Params.dwUniqueID = ((DEVICE_CTX *)hDevice)->dwUniqueID;
DWORD DLLCALLCONV WDU_SetInterface(WDU_DEVICE_HANDLE hDevice, DWORD dwInterfaceNum,
DWORD dwAlternateSetting)
{
DWORD dwStatus;
DWORD ifc_index;
DEVICE_CTX *pDevCtx = (DEVICE_CTX*)hDevice;
WDU_DEVICE *pDevice = pDevCtx->pDevice;
PARAMS_INIT(WDU_SET_INTERFACE);
PARAMS_SET(dwInterfaceNum);
PARAMS_SET(dwAlternateSetting);
dwStatus = WD_USetInterface(GET_HWD(hDevice), &Params);
if (dwStatus)
{
ERR("WDU_SetInterface: Set interface (interface: %ld, alternate setting: %ld) failed:\n"
"Error: 0x%lx (%s)\n", dwInterfaceNum, dwAlternateSetting, dwStatus, Stat2Str(dwStatus));
return dwStatus;
}
for (ifc_index = 0; ifc_index < pDevice->pConfigs->dwNumInterfaces; ifc_index++)
{
if (pDevice->pActiveInterface[ifc_index]->pAlternateSettings[dwAlternateSetting].Descriptor.bInterfaceNumber == dwInterfaceNum)
break;
}
// Update the active alternate setting
pDevice->pActiveInterface[ifc_index]->pActiveAltSetting =
&pDevice->pActiveInterface[ifc_index]->pAlternateSettings[dwAlternateSetting];
return WD_STATUS_SUCCESS;
}
// currently not implemented
DWORD DLLCALLCONV WDU_SetConfig(WDU_DEVICE_HANDLE hDevice, DWORD dwConfigNum);
DWORD DLLCALLCONV WDU_ResetPipe(WDU_DEVICE_HANDLE hDevice, DWORD dwPipeNum)
{
PARAMS_INIT(WDU_RESET_PIPE);
PARAMS_SET(dwPipeNum);
return WD_UResetPipe(GET_HWD(hDevice), &Params);
}
// currently not implemented on WinCE and Linux
DWORD DLLCALLCONV WDU_ResetDevice(WDU_DEVICE_HANDLE hDevice, DWORD dwOptions)
{
PARAMS_INIT(WDU_RESET_DEVICE);
PARAMS_SET(dwOptions);
return WD_UResetDevice(GET_HWD(hDevice), &Params);
}
// currently not implemented on WinCE and Linux
DWORD DLLCALLCONV WDU_Wakeup(WDU_DEVICE_HANDLE hDevice, DWORD dwOptions)
{
PARAMS_INIT(WDU_WAKEUP);
PARAMS_SET(dwOptions);
return WD_UWakeup(GET_HWD(hDevice), &Params);
}
DWORD DLLCALLCONV WDU_Transfer(WDU_DEVICE_HANDLE hDevice, DWORD dwPipeNum, DWORD fRead,
DWORD dwOptions, PVOID pBuffer, DWORD dwBufferSize, PDWORD pdwBytesTransferred,
PBYTE pSetupPacket, DWORD dwTimeout)
{
DWORD dwStatus;
PARAMS_INIT(WDU_TRANSFER);
PARAMS_SET(dwPipeNum);
PARAMS_SET(fRead);
PARAMS_SET(dwOptions);
PARAMS_SET(pBuffer);
PARAMS_SET(dwBufferSize);
if (pSetupPacket)
memcpy(&Params.SetupPacket, pSetupPacket, 8);
PARAMS_SET(dwTimeout);
dwStatus = WD_UTransfer(GET_HWD(hDevice), &Params);
*pdwBytesTransferred = Params.dwBytesTransferred;
return dwStatus;
}
DWORD DLLCALLCONV WDU_HaltTransfer(WDU_DEVICE_HANDLE hDevice, DWORD dwPipeNum)
{
PARAMS_INIT(WDU_HALT_TRANSFER);
PARAMS_SET(dwPipeNum);
return WD_UHaltTransfer(GET_HWD(hDevice), &Params);
}
// User-mode wrappers for kernel functions
static void EventHandler(WD_EVENT *pEvent, void *pDriverContext);
DWORD DLLCALLCONV WDU_Init(WDU_DRIVER_HANDLE *phDriver,
WDU_MATCH_TABLE *pMatchTables, DWORD dwNumMatchTables,
WDU_EVENT_TABLE *pEventTable, const char *sLicense, DWORD dwOptions)
{
DWORD dwStatus;
DRIVER_CTX *pDriverCtx = NULL;
WD_VERSION ver;
WD_EVENT *event = NULL;
WD_LICENSE lic;
*phDriver = INVALID_HANDLE_VALUE;
pDriverCtx = (DRIVER_CTX *) calloc(1, sizeof(DRIVER_CTX));
if (!pDriverCtx)
{
ERR("WDU_Init: cannot malloc memory\n");
dwStatus = WD_INSUFFICIENT_RESOURCES;
goto Error;
}
#if !defined(__KERNEL__)
// init the device list event
if (DevList.iRefCount == 0)
{
dwStatus = OsEventCreate(&DevList.hEvent);
if (dwStatus)
{
ERR("WDU_Init: cannot create event: dwStatus (0x%lx) - %s\n",
dwStatus, Stat2Str(dwStatus));
goto Error;
}
dwStatus = OsEventSignal(DevList.hEvent);
if (dwStatus)
{
ERR("WDU_Init: error signaling device list event: dwStatus (0x%lx) - %s\n",
dwStatus, Stat2Str(dwStatus));
OsEventClose(DevList.hEvent);
goto Error;
}
}
DevList.iRefCount++;
#endif
pDriverCtx->hWD = INVALID_HANDLE_VALUE;
pDriverCtx->hWD = WD_Open();
// Check whether handle is valid and version OK
if (pDriverCtx->hWD==INVALID_HANDLE_VALUE)
{
ERR("WDU_Init: cannot open " WD_PROD_NAME " device\n");
dwStatus = WD_SYSTEM_INTERNAL_ERROR;
goto Error;
}
strcpy(lic.cLicense, sLicense);
WD_License(pDriverCtx->hWD, &lic);
BZERO(ver);
dwStatus = WD_Version(pDriverCtx->hWD, &ver);
if ((dwStatus != WD_STATUS_SUCCESS) || (ver.dwVer<WD_VER))
{
ERR("WDU_Init: incorrect " WD_PROD_NAME " version\n");
if (!dwStatus)
dwStatus = WD_INCORRECT_VERSION;
goto Error;
}
pDriverCtx->EventTable = *pEventTable;
if (pEventTable->pfDeviceAttach)
{
DWORD dwAction;
dwAction = WD_INSERT |
(pEventTable->pfDeviceDetach ? WD_REMOVE : 0) |
(pEventTable->pfPowerChange ? WD_POWER_CHANGED_D0 |
WD_POWER_CHANGED_D1 |
WD_POWER_CHANGED_D2 |
WD_POWER_CHANGED_D3 |
WD_POWER_SYSTEM_WORKING |
WD_POWER_SYSTEM_SLEEPING1 |
WD_POWER_SYSTEM_SLEEPING2 |
WD_POWER_SYSTEM_SLEEPING3 |
WD_POWER_SYSTEM_HIBERNATE |
WD_POWER_SYSTEM_SHUTDOWN : 0);
event = UsbEventCreate(pMatchTables, dwNumMatchTables, dwOptions,
dwAction);
if (!event)
{
ERR("WDU_Init: cannot malloc memory\n");
dwStatus = WD_INSUFFICIENT_RESOURCES;
goto Error;
}
dwStatus = EventRegister(&pDriverCtx->hEvents, pDriverCtx->hWD, event,
EventHandler, pDriverCtx);
if (dwStatus)
{
ERR("WDU_Init: EventRegister failed with dwStatus (0x%lx) - %s\n",
dwStatus, Stat2Str(dwStatus));
goto Error;
}
}
*phDriver = pDriverCtx;
goto Exit;
Error:
if (pDriverCtx)
WDU_Uninit(pDriverCtx);
Exit:
if (event)
EventFree(event);
return dwStatus;
}
void DLLCALLCONV WDU_Uninit(WDU_DRIVER_HANDLE hDriver)
{
DRIVER_CTX *pDriverCtx = (DRIVER_CTX *)hDriver;
if (pDriverCtx && hDriver != INVALID_HANDLE_VALUE)
{
if (pDriverCtx->hWD)
{
if (pDriverCtx->hEvents)
EventUnregister(pDriverCtx->hEvents);
WD_Close(pDriverCtx->hWD);
}
RemoveAllDevicesFromDevList(pDriverCtx);
free (pDriverCtx);
}
#if !defined(__KERNEL__)
DevList.iRefCount--;
if (DevList.iRefCount == 0)
OsEventClose(DevList.hEvent);
#endif
}
static void EventHandler(WD_EVENT *pEvent, void *pDriverContext)
{
DRIVER_CTX *pDriverCtx = (DRIVER_CTX *)pDriverContext;
DEVICE_CTX *pDeviceCtx, *pDummyDeviceCtx;
WDU_DEVICE_HANDLE hDevice;
BOOL bControlDevice = FALSE, bChangePower;
DWORD dwStatus;
TRACE("EventHandler: got event 0x%lx handle %p\n", pEvent->dwAction, pEvent->handle);
switch (pEvent->dwAction)
{
case WD_INSERT:
// create device context
pDeviceCtx = (DEVICE_CTX *)calloc(1, sizeof(DEVICE_CTX));
if (!pDeviceCtx)
{
ERR("EventHandler: cannot alloc memory\n");
return;
}
// DEVICE_CTX * is used as WDU_DEVICE_HANDLE
hDevice = pDeviceCtx;
pDeviceCtx->dwUniqueID = pEvent->u.Usb.dwUniqueID;
pDeviceCtx->pDriverCtx = pDriverCtx;
// add the device handle to the device list for future IOCTLs
dwStatus = AddDeviceToDevList(pDeviceCtx);
if (dwStatus)
{
free(pDeviceCtx);
return;
}
// get device info
dwStatus = WDU_GetDeviceInfo(hDevice, &pDeviceCtx->pDevice);
if (dwStatus)
{
ERR("EventHandler: unable to get device info for device"
" handle %p dwUniqueID 0x%lx\n",
hDevice, pDeviceCtx->dwUniqueID);
RemoveDeviceFromDevList(pDriverCtx, pEvent->u.Usb.dwUniqueID, &pDummyDeviceCtx);
free(pDeviceCtx);
return;
}
bControlDevice = pDriverCtx->EventTable.pfDeviceAttach(hDevice,
pDeviceCtx->pDevice, pDriverCtx->EventTable.pUserData);
if (!bControlDevice)
{
TRACE("EventHandler: bControlDevice==FALSE; pDriverCtx %p\n", pDriverCtx);
RemoveDeviceFromDevList(pDriverCtx, pEvent->u.Usb.dwUniqueID, &pDummyDeviceCtx);
WDU_PutDeviceInfo(pDeviceCtx->pDevice);
free(pDeviceCtx);
}
pEvent->dwOptions |= bControlDevice ? WD_ACCEPT_CONTROL : 0;
break;
case WD_REMOVE:
dwStatus = RemoveDeviceFromDevList(pDriverCtx, pEvent->u.Usb.dwUniqueID, &pDeviceCtx);
if (dwStatus)
// device is not mine or may has been closed by WDU_Uninit
break;
// DEVICE_CTX * is used as WDU_DEVICE_HANDLE
pDriverCtx->EventTable.pfDeviceDetach((WDU_DEVICE_HANDLE) pDeviceCtx, pDriverCtx->EventTable.pUserData);
WDU_PutDeviceInfo(pDeviceCtx->pDevice);
free(pDeviceCtx);
break;
case WD_POWER_CHANGED_D0:
case WD_POWER_CHANGED_D1:
case WD_POWER_CHANGED_D2:
case WD_POWER_CHANGED_D3:
case WD_POWER_SYSTEM_WORKING:
case WD_POWER_SYSTEM_SLEEPING1:
case WD_POWER_SYSTEM_SLEEPING2:
case WD_POWER_SYSTEM_SLEEPING3:
case WD_POWER_SYSTEM_HIBERNATE:
case WD_POWER_SYSTEM_SHUTDOWN:
dwStatus = FindDeviceByUniqueID(pDriverCtx, pEvent->u.Usb.dwUniqueID, &pDeviceCtx);
if (dwStatus)
{
// device is not mine or may have been closed by WDU_Uninit
break;
}
bChangePower = pDriverCtx->EventTable.pfPowerChange((WDU_DEVICE_HANDLE) pDeviceCtx, pEvent->dwAction,
pDriverCtx->EventTable.pUserData);
// XXX return in the event structure if the user says it's ok to change power
// (not implemented yet)
break;
}
}
// ppDeviceInfo is set to point to an allocated buffer containing the info.
// The caller should free the buffer after the use by calling
// WDU_PutDeviceInfo()
DWORD DLLCALLCONV WDU_GetDeviceInfo(WDU_DEVICE_HANDLE hDevice, WDU_DEVICE **ppDeviceInfo)
{
DWORD dwStatus;
PARAMS_INIT(WDU_GET_DEVICE_DATA);
// first call with pBuf NULL, return dwBytes
dwStatus = WD_UGetDeviceData(GET_HWD(hDevice), &Params);
if (dwStatus != WD_STATUS_SUCCESS)
return dwStatus;
*ppDeviceInfo = (WDU_DEVICE *) malloc(Params.dwBytes);
if (!ppDeviceInfo)
{
ERR("WDU_GetDeviceInfo: cannot alloc memory\n");
return WD_INSUFFICIENT_RESOURCES;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -