📄 hid.cpp
字号:
)
{
SETFNAME(_T("GetReportDescriptor"));
BOOL fRet = FALSE;
USB_DEVICE_REQUEST udr;
BYTE *pRawReportDescriptor = NULL;
NTSTATUS status;
DWORD dwBytesTransferred;
DWORD dwUsbErr;
DWORD dwErr;
DEBUGCHK(pUsbHid != NULL);
DEBUGCHK(uReportDescriptorLength > 0);
pRawReportDescriptor = (BYTE*) HidAlloc(uReportDescriptorLength);
if (pRawReportDescriptor == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: LocalAlloc error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
// Do we send this to the endpoint or the interface?
DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);
udr.bmRequestType |= USB_REQUEST_DEVICE_TO_HOST;
udr.bRequest = USB_REQUEST_GET_DESCRIPTOR;
udr.wValue = USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(HID_REPORT_DESCRIPTOR_TYPE, 0);
udr.wLength = uReportDescriptorLength;
dwErr = IssueVendorTransfer(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
DefaultTransferComplete,
pUsbHid->hEP0Event,
(USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK),
&udr,
pRawReportDescriptor,
0,
&dwBytesTransferred,
GET_HID_DESCRIPTOR_TIMEOUT,
&dwUsbErr);
if ( (ERROR_SUCCESS != dwErr) || (USB_NO_ERROR != dwUsbErr) ||
(dwBytesTransferred != uReportDescriptorLength) )
{
DEBUGMSG(ZONE_ERROR, (_T("%s: IssueVendorTransfer ERROR:%d 0x%x\n"), pszFname, dwErr, dwUsbErr));
goto EXIT;
}
pUsbHid->phidpDeviceDesc = (PHIDP_DEVICE_DESC) HidAlloc(sizeof(HIDP_DEVICE_DESC));
if (pUsbHid->phidpDeviceDesc == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: LocalAlloc error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
ZeroMemory(pUsbHid->phidpDeviceDesc, sizeof(PHIDP_DEVICE_DESC));
// Good. We've got our report descriptor. Let's parse it.
status = HidP_GetCollectionDescription(
pRawReportDescriptor,
uReportDescriptorLength,
0,
pUsbHid->phidpDeviceDesc
);
if (NT_SUCCESS(status) == FALSE) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Problem parsing report descriptor Error: 0x%x\r\n"),
pszFname, status));
goto EXIT;
}
DumpHIDDeviceDescription(pUsbHid->phidpDeviceDesc);
fRet = TRUE;
EXIT:
if (pRawReportDescriptor != NULL) HidFree(pRawReportDescriptor);
NKDbgPrintfW(TEXT("Hid GetReportDescriptor:%d\r\n"),GetLastError());
return fRet;
}
// Setup the pipes for this interface
static
BOOL
SetUsbInterface(
PUSBHID_CONTEXT pUsbHid
)
{
SETFNAME(_T("SetUsbInterface"));
BOOL fRet = FALSE;
DWORD dwIndex;
BYTE bNumEndpoints;
DEBUGCHK(pUsbHid != NULL);
DEBUGCHK(pUsbHid->pUsbInterface != NULL);
// Parse the endpoints
bNumEndpoints = pUsbHid->pUsbInterface->Descriptor.bNumEndpoints;
for (dwIndex = 0; dwIndex < bNumEndpoints; ++dwIndex)
{
LPCUSB_ENDPOINT pEndpoint;
pEndpoint = pUsbHid->pUsbInterface->lpEndpoints + dwIndex;
DEBUGCHK(pEndpoint != NULL);
DUMP_USB_ENDPOINT_DESCRIPTOR(pEndpoint->Descriptor);
//
// HID Class supports 1 mandatory Interrupt IN, and 1 optional Interrupt OUT
//
if (USB_ENDPOINT_DIRECTION_IN(pEndpoint->Descriptor.bEndpointAddress))
{
if ( (NULL == pUsbHid->InterruptIn.hPipe) &&
( (pEndpoint->Descriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT) )
{
// create the Interrupt In pipe
pUsbHid->InterruptIn.hPipe = pUsbHid->pUsbFuncs->lpOpenPipe(pUsbHid->hUsbDevice,
&pEndpoint->Descriptor);
if (pUsbHid->InterruptIn.hPipe == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("%s: OpenPipe error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
// setup any endpoint specific timers, buffers, context, etc.
pUsbHid->InterruptIn.hEvent = CreateEvent(NULL, MANUAL_RESET_EVENT, FALSE, NULL);
if (pUsbHid->InterruptIn.hEvent == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("%s: CreateEvent error:%d\r\n"), pszFname, GetLastError()));
goto EXIT;
}
pUsbHid->InterruptIn.bIndex = pEndpoint->Descriptor.bEndpointAddress;
pUsbHid->InterruptIn.wMaxPacketSize = pEndpoint->Descriptor.wMaxPacketSize;
}
else {
DEBUGCHK(FALSE); // The HID spec does not allow for this condition. You should not get here!
}
}
else if (USB_ENDPOINT_DIRECTION_OUT(pEndpoint->Descriptor.bEndpointAddress))
{
DEBUGMSG(ZONE_WARNING, (_T("%s: Driver does not support optional Iterrupt Out\r\n"),
pszFname));
}
else {
DEBUGCHK(FALSE); // The HID spec does not allow for this condition. You should not get here!
}
}
// Did we find our endpoint?
if (pUsbHid->InterruptIn.hPipe == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: No Interrupt In endpoint\r\n"), pszFname));
goto EXIT;
}
// If we failed to find all of our endpoints then cleanup will occur later
fRet = TRUE;
EXIT:
NKDbgPrintfW(TEXT("Hid SetUsbInterface Fail:%d\r\n"),GetLastError());
return fRet;
}
// Enable remote wakeup if possible.
static
BOOL
EnableRemoteWakeup(
PUSBHID_CONTEXT pUsbHid
)
{
SETFNAME(_T("EnableRemotWakeup"));
DWORD dwErr;
DEBUGCHK(pUsbHid != NULL);
dwErr = ClearOrSetFeature(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
DefaultTransferComplete,
pUsbHid->hEP0Event,
USB_SEND_TO_DEVICE,
USB_FEATURE_REMOTE_WAKEUP,
0,
1000,
TRUE
);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Set Feature failure Error: 0x%x\r\n"),
pszFname, dwErr));
}
return dwErr == ERROR_SUCCESS;
}
// Set the device protocol to report (not boot)
static
BOOL
SetReportProtocol(
PUSBHID_CONTEXT pUsbHid
)
{
SETFNAME(_T("SetReportProtocol"));
DWORD dwErr, dwBytesTransferred;
USB_ERROR usbErr;
USB_DEVICE_REQUEST udr;
DEBUGCHK(pUsbHid != NULL);
ValidateHidContext(pUsbHid);
DEBUGCHK(pUsbHid->pUsbInterface->Descriptor.bInterfaceSubClass == HID_INTERFACE_BOOT_SUBCLASS);
// Do we send this to the endpoint or the interface?
DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);
udr.bmRequestType |= USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_CLASS;
udr.bRequest = USB_REQUEST_HID_SET_PROTOCOL;
udr.wValue = HID_REPORT_PROTOCOL;
udr.wLength = 0;
dwErr = IssueVendorTransfer(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
NULL,
NULL,
USB_OUT_TRANSFER,
&udr,
NULL,
0,
&dwBytesTransferred,
0,
&usbErr);
if ((dwErr != ERROR_SUCCESS) || (usbErr != USB_NO_ERROR) ) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Set report protocol error: 0x%x 0x%x\r\n"),
pszFname, dwErr, usbErr));
}
return (dwErr == ERROR_SUCCESS);
}
// Set the idle rate for the device.
// Returns the error values from IssueVendorTransfer.
static
DWORD
SetIdle(
PUSBHID_CONTEXT pUsbHid,
USB_ERROR *pUsbErr
)
{
SETFNAME(_T("HidSetIdle"));
USB_DEVICE_REQUEST udr;
DWORD dwBytesTransferred;
DWORD dwErr;
USB_ERROR UsbErr;
DEBUGCHK(pUsbHid != NULL);
//NKDbgPrintfW(TEXT("LINE-%d\r\n"), __LINE__);
ValidateHidContext(pUsbHid);
//NKDbgPrintfW(TEXT("LINE-%d\r\n"), __LINE__);
// Do we send to the endpoint or interface?
DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);
//NKDbgPrintfW(TEXT("LINE-%d\r\n"), __LINE__);
udr.bmRequestType |= USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_CLASS;
udr.bRequest = USB_REQUEST_HID_SET_IDLE;
udr.wValue = 0; // Set infinite idle for all reports.
udr.wLength = 0;
dwErr = IssueVendorTransfer(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
NULL,
NULL,
USB_OUT_TRANSFER,
&udr,
NULL,
0,
&dwBytesTransferred,
INFINITE,
&UsbErr);
//NKDbgPrintfW(TEXT("LINE-%d\r\n"), __LINE__);
if (pUsbErr != NULL) {
*pUsbErr = UsbErr;
}
// SET_IDLE is not required according to the HID spec. If it is not
// present, we might stall endpoint 0. If so, clear the stall feature.
if (UsbErr == USB_STALL_ERROR) {
ClearEndpointZeroStall(pUsbHid);
}
//NKDbgPrintfW(TEXT("LINE-%d\r\n"), __LINE__);
return dwErr;
}
// Generic routine to return the subkey of the form
// pdwVals[0]_pdwVals[1]_...pdwVals[cdwVals-1].
static
HKEY
OpenSpecificClientRegKey(
HKEY hKeyRoot,
const DWORD *pdwVals,
DWORD cdwVals
)
{
HKEY hKeyRet = NULL;
TCHAR szBuf[40];
TCHAR *pszCur = szBuf;
const TCHAR *pszKey;
DWORD dwIdx;
int ichWritten;
DEBUGCHK(cdwVals * 11 + 1 < dim(szBuf));
if (cdwVals == 0) {
// Try default
pszKey = DEFAULT_SZ;
}
else
{
// Build key string
for (dwIdx = 0; dwIdx < cdwVals; ++dwIdx) {
ichWritten = _stprintf(pszCur, _T("%u_"), pdwVals[dwIdx]);
pszCur += ichWritten;
}
*(pszCur - 1) = 0; // Remove the last _
pszKey = szBuf;
}
RegOpenKey(hKeyRoot, pszKey, &hKeyRet);
return hKeyRet;
}
// Contains most of the logic to find and open the proper HID client key.
// The algorithm searches for the most specific vendor key of the form
// idVendor_idProduct_bcdDevice. Then its subkeys are searched for the most
// specific interface key of the form bInterface_bCollection. Then its
// subkeys are searched for the most specific top level collection key
// of the form UsagePage_Usage.
//
// The order of vendor precedence is described below.
//
// idVendor_idProduct_bcdDevice
// idVendor_idProduct
// idVendor
// Default
//
// The order of interface precedence is described below.
//
// bInterface_bCollection
// bInterface
// Default
//
// The order of TLC precedence is
//
// UsagePage_Usage
// UsagePage
// Default
//
// So the order of checking would be
// 1. idVendor_idProduct_bcdDevice\bInterface_bCollection\UsagePage_Usage
// 2. idVendor_idProduct_bcdDevice\bInterface_bCollection\UsagePage
// 3. idVendor_idProduct_bcdDevice\bInterface_bCollection\Default
// 4. idVendor_idProduct_bcdDevice\bInterface\UsagePage_Usage
// ...
// 7. idVendor_idProduct_bcdDevice\Default\UsagePage_Usage
// ...
// 10. idVendor_idProduct\bInterface_bCollection\UsagePage_Usage
// ...
// 42. Default\bInterface_bCollection\Default
// 43. Default\bInterface\UsagePage_Usage
// 44. Default\bInterface\UsagePage
// 45. Default\bInterface\Default
// 46. Default\Default\UsagePage_Usage
// 47. Default\Default\UsagePage
// 48. Default\Default\Default
//
static
HKEY
OpenClientRegKey(
HKEY hKeyRoot,
const DWORD *pdwVendorVals,
DWORD cdwVendorVals,
const DWORD *pdwInterfaceVals,
DWORD cdwInterfaceVals,
const DWORD *pdwTLCVals,
DWORD cdwTLCVals,
PHID_DRIVER_SETTINGS pDriverSettingsUsed
)
{
SETFNAME(_T("OpenClientRegKey"));
HKEY hKeyRet = NULL;
HKEY hKeyVendor;
HKEY hKeyInterface;
INT cCurrVendor = -1;
INT cCurrInterface = -1;
INT cCurrTLC = -1;
INT iIdx;
DEBUGCHK(pdwVendorVals != NULL);
DEBUGCHK(pdwInterfaceVals != NULL);
DEBUGCHK(pdwTLCVals != NULL);
for (cCurrVendor = (INT) cdwVendorVals; cCurrVendor >= 0; --cCurrVendor)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -