📄 usbhid.cpp
字号:
udr.bmRequestType |= USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_CLASS;
udr.bRequest = USB_REQUEST_HID_SET_REPORT;
udr.wValue = USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(type, bReportID);
udr.wLength = (USHORT) cbBuffer;
dwErr = IssueVendorTransfer(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
pfnNotify,
hEvent,
USB_OUT_TRANSFER,
&udr,
pbBuffer,
0,
&dwBytesTransferred,
dwTimeout,
&usbErr);
if (dwErr == ERROR_SUCCESS) {
if (usbErr == USB_STALL_ERROR) {
// SET_REPORT is not required according to the HID spec. If it is not
// present, the device may return a stall handshake.
dwErr = ERROR_NOT_SUPPORTED;
}
else if (usbErr != USB_NO_ERROR) {
dwErr = ERROR_GEN_FAILURE;
}
}
EXIT:
if (hEvent != NULL) CloseHandle(hEvent);
return dwErr;
}
// Retrieves the requested string descriptor and validates it.
static
DWORD
GetStringDescriptor(
PUSBHID_CONTEXT pUsbHid,
BYTE bIdx,
WORD wLangId,
PBYTE pbBuffer,
WORD cbBuffer,
PDWORD pbTransferred
)
{
SETFNAME(_T("GetStringDescriptor"));
PUSB_STRING_DESCRIPTOR pStringDesc = (PUSB_STRING_DESCRIPTOR) pbBuffer;
USB_ERROR usbErr;
USB_TRANSFER hTransfer;
DWORD dwErr;
PREFAST_DEBUGCHK(VALID_CONTEXT(pUsbHid));
ValidateUsbHidContext(pUsbHid);
PREFAST_DEBUGCHK(pbBuffer != NULL);
DEBUGCHK(cbBuffer >= sizeof(USB_STRING_DESCRIPTOR));
PREFAST_DEBUGCHK(pbTransferred != NULL);
hTransfer = pUsbHid->pUsbFuncs->lpGetDescriptor(pUsbHid->hUsbDevice, NULL, NULL,
USB_SHORT_TRANSFER_OK, USB_STRING_DESCRIPTOR_TYPE, bIdx,
wLangId, cbBuffer, pbBuffer);
if (hTransfer != NULL) {
GetTransferStatus(pUsbHid->pUsbFuncs, hTransfer,
pbTransferred, &usbErr);
CloseTransferHandle(pUsbHid->pUsbFuncs, hTransfer);
if (usbErr != USB_NO_ERROR) {
if (usbErr == USB_STALL_ERROR) {
dwErr = ERROR_NOT_SUPPORTED;
}
else {
dwErr = ERROR_GEN_FAILURE;
}
goto EXIT;
}
}
else {
dwErr = GetLastError();
goto EXIT;
}
// We've got a descriptor. Is it valid?
if ( (*pbTransferred < (sizeof(USB_STRING_DESCRIPTOR) - sizeof(pStringDesc->bString))) ||
(pStringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE) ) {
DEBUGCHK(FALSE); // The device returned something strange.
dwErr = ERROR_GEN_FAILURE;
goto EXIT;
}
dwErr = ERROR_SUCCESS;
EXIT:
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARNING, (_T("%s: Error getting string descriptor %u, %u. Err=%u\r\n"),
pszFname, bIdx, wLangId, dwErr));
}
return dwErr;
}
// Get a device string. For predefined types see hiddi.h.
// Call with pszBuffer == NULL to get the character count required
// (then add 1 for the NULL terminator).
DWORD
WINAPI
HidPdd_GetString(
HID_PDD_HANDLE hPddDevice,
HID_STRING_TYPE stringType,
DWORD dwIdx, // Only used with stringType == HID_STRING_INDEXED
LPWSTR pszBuffer, // Set to NULL to get character count
DWORD cchBuffer, // Count of chars that will fit into pszBuffer
// including the NULL terminator.
PDWORD pcchActual // Count of chars in the string NOT including
// the NULL terminator
)
{
SETFNAME(_T("HidPdd_GetString"));
const DWORD CB_STRING_DESCRIPTOR_MAX = 0xff;
PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hPddDevice;
union {
BYTE rgbBuffer[CB_STRING_DESCRIPTOR_MAX];
USB_STRING_DESCRIPTOR StringDesc;
} StringDescriptor;
PCUSB_DEVICE pDeviceInfo = NULL;
DWORD dwErr;
WORD wLangId;
// DWORD cchToCopy;
DWORD dwBytesTransferred;
BYTE bIdx;
PREFAST_DEBUGCHK(VALID_CONTEXT(pUsbHid));
ValidateUsbHidContext(pUsbHid);
// Mdd guarantees the following
DEBUGCHK(stringType < HID_STRING_MAX);
DEBUGCHK( ((stringType == HID_STRING_INDEXED) && (dwIdx != 0)) == FALSE );
PREFAST_DEBUGCHK(pcchActual != NULL);
if (stringType != HID_STRING_INDEXED) {
pDeviceInfo =
(*pUsbHid->pUsbFuncs->lpGetDeviceInfo)(pUsbHid->hUsbDevice);
if (pDeviceInfo == NULL) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Failure getting USB device info\r\n"),
pszFname));
dwErr = ERROR_GEN_FAILURE;
goto EXIT;
}
switch (stringType) {
case HID_STRING_ID_IMANUFACTURER:
bIdx = pDeviceInfo->Descriptor.iManufacturer;
break;
case HID_STRING_ID_IPRODUCT:
bIdx = pDeviceInfo->Descriptor.iProduct;
break;
case HID_STRING_ID_ISERIALNUMBER:
bIdx = pDeviceInfo->Descriptor.iSerialNumber;
break;
default:
bIdx = 0;
}
if (bIdx == 0) {
DEBUGMSG(ZONE_COMMENT, (_T("%s: String type %u does not exist\r\n"),
pszFname, stringType));
dwErr = ERROR_NOT_FOUND;
goto EXIT;
}
}
else {
// USB indexes strings with a byte. Make sure dwIdx can be represented
// in a byte.
if (dwIdx > UCHAR_MAX) {
DEBUGMSG(ZONE_ERROR, (_T("%s: String index 0x%x is too large\r\n"),
pszFname, dwIdx));
dwErr = ERROR_INVALID_PARAMETER;
goto EXIT;
}
bIdx = (BYTE) dwIdx;
}
// Get the Zero string descriptor to determine which LANGID to use.
// We just use the first LANGID listed.
dwErr = GetStringDescriptor(pUsbHid, 0, 0, (PBYTE) &StringDescriptor,
sizeof(StringDescriptor), &dwBytesTransferred);
if (dwErr != ERROR_SUCCESS) {
goto EXIT;
}
DEBUGCHK(StringDescriptor.StringDesc.bLength >= sizeof(USB_STRING_DESCRIPTOR));
DEBUGCHK(StringDescriptor.StringDesc.bDescriptorType == USB_STRING_DESCRIPTOR_TYPE);
wLangId = StringDescriptor.StringDesc.bString[0];
// Get the string descriptor for the first LANGID
dwErr = GetStringDescriptor(pUsbHid, bIdx, wLangId, (PBYTE) &StringDescriptor,
sizeof(StringDescriptor), &dwBytesTransferred);
if (dwErr != ERROR_SUCCESS) {
goto EXIT;
}
__try {
// Copy the character count and string into the user's buffer
*pcchActual = (StringDescriptor.StringDesc.bLength - 2) / sizeof(WCHAR); // Does not include NULL
if (pszBuffer != NULL) {
StringCchCopyN(pszBuffer, cchBuffer,
StringDescriptor.StringDesc.bString, *pcchActual);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Exception writing to user buffer\r\n"),
pszFname));
dwErr = ERROR_INVALID_PARAMETER;
}
EXIT:
return dwErr;
}
// Get the idle rate for a specific report.
DWORD
WINAPI
HidPdd_GetIdle(
HID_PDD_HANDLE hPddDevice,
PDWORD pdwIdle,
DWORD dwReportID
)
{
SETFNAME(_T("HidPdd_GetIdle"));
PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hPddDevice;
USB_DEVICE_REQUEST udr;
DWORD dwBytesTransferred;
DWORD dwErr;
BYTE bIdle;
USB_ERROR usbErr;
PREFAST_DEBUGCHK(VALID_CONTEXT(pUsbHid));
ValidateUsbHidContext(pUsbHid);
PREFAST_DEBUGCHK(pdwIdle != NULL);
if (dwReportID > UCHAR_MAX) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Report ID of %u is too large.\r\n"),
pszFname, dwReportID));
dwErr = ERROR_INVALID_PARAMETER;
goto EXIT;
}
// Do we send to the endpoint or interface?
DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);
udr.bmRequestType |= USB_REQUEST_DEVICE_TO_HOST | USB_REQUEST_CLASS;
udr.bRequest = USB_REQUEST_HID_GET_IDLE;
udr.wValue = USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(0, dwReportID);
udr.wLength = 1;
dwErr = IssueVendorTransfer(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
NULL,
NULL,
USB_IN_TRANSFER,
&udr,
&bIdle,
0,
&dwBytesTransferred,
INFINITE,
&usbErr);
if (dwErr == ERROR_SUCCESS) {
if (usbErr == USB_STALL_ERROR) {
// GET_IDLE is not required according to the HID spec. If it is not
// present, the device may return a stall handshake.
dwErr = ERROR_NOT_SUPPORTED;
}
else if (usbErr != USB_NO_ERROR) {
dwErr = ERROR_GEN_FAILURE;
}
}
else {
// Success. Write value to user buffer.
__try {
*pdwIdle = (DWORD) bIdle;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Exception writing to user buffer\r\n"),
pszFname));
dwErr = ERROR_INVALID_PARAMETER;
}
}
EXIT:
return dwErr;
}
// Set the idle rate for a specific report. The idle rate is expressed in
// 4 ms increments, so to set idle rate of 20 ms, bDuration should be 5.
// bDuration of 0 means infinite. bReportID of 0 means to apply to all
// reports.
DWORD
WINAPI
HidPdd_SetIdle(
HID_PDD_HANDLE hPddDevice,
DWORD dwDuration,
DWORD dwReportID
)
{
SETFNAME(_T("HidPdd_SetIdle"));
PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hPddDevice;
USB_DEVICE_REQUEST udr;
DWORD dwBytesTransferred;
DWORD dwErr;
USB_ERROR usbErr;
PREFAST_DEBUGCHK(VALID_CONTEXT(pUsbHid));
ValidateUsbHidContext(pUsbHid);
if (dwReportID > UCHAR_MAX) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Report ID of %u is too large.\r\n"),
pszFname, dwReportID));
dwErr = ERROR_INVALID_PARAMETER;
goto EXIT;
}
if (dwDuration > UCHAR_MAX) {
// Use the maximum possible value.
DEBUGMSG(ZONE_WARNING, (_T("%s: Reducing duration to max BYTE value\r\n"),
pszFname));
dwDuration = UCHAR_MAX;
}
// Do we send to the endpoint or interface?
DetermineDestination(pUsbHid, &udr.bmRequestType, &udr.wIndex);
udr.bmRequestType |= USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_CLASS;
udr.bRequest = USB_REQUEST_HID_SET_IDLE;
udr.wValue = USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(dwDuration, dwReportID);
udr.wLength = 0;
dwErr = IssueVendorTransfer(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
NULL,
NULL,
USB_OUT_TRANSFER,
&udr,
NULL,
0,
&dwBytesTransferred,
INFINITE,
&usbErr);
if (dwErr == ERROR_SUCCESS) {
if (usbErr == USB_STALL_ERROR) {
// SET_IDLE is not required according to the HID spec. If it is not
// present, the device may return a stall handshake.
dwErr = ERROR_NOT_SUPPORTED;
}
else if (usbErr != USB_NO_ERROR) {
dwErr = ERROR_GEN_FAILURE;
}
}
EXIT:
return dwErr;
}
// Enable remote wakeup if possible.
static
DWORD
EnableRemoteWakeup(
PUSBHID_CONTEXT pUsbHid,
BOOL fEnable
)
{
SETFNAME(_T("EnableRemotWakeup"));
DWORD dwErr;
PREFAST_DEBUGCHK(pUsbHid != NULL);
ValidateUsbHidContext(pUsbHid);
dwErr = ClearOrSetFeature(
pUsbHid->pUsbFuncs,
pUsbHid->hUsbDevice,
NULL,
NULL,
USB_SEND_TO_DEVICE,
USB_FEATURE_REMOTE_WAKEUP,
0,
0,
fEnable
);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s: Set Remote Wakeup Feature failure. Error: 0x%x\r\n"),
pszFname, dwErr));
}
return dwErr;
}
// Commands the PDD to initiate some activity or configuration.
DWORD
WINAPI
HidPdd_IssueCommand(
HID_PDD_HANDLE hPddDevice, // PDD function parameter
DWORD dwMsg, // Notification message
WPARAM wParam // Message parameter
)
{
SETFNAME(_T("HidPdd_IssueCommand"));
PUSBHID_CONTEXT pUsbHid = (PUSBHID_CONTEXT) hPddDevice;
DWORD dwErr = ERROR_SUCCESS;
ValidateUsbHidContext(pUsbHid);
if (dwMsg == HID_PDD_REMOTE_WAKEUP) {
dwErr = ERROR_SUCCESS;
if (pUsbHid->Flags.RemoteWakeup == TRUE) {
BOOL fEnable = wParam;
dwErr = EnableRemoteWakeup(pUsbHid, fEnable);
}
}
else {
DEBUGCHK(FALSE);
dwErr = ERROR_NOT_SUPPORTED;
}
return dwErr;
}
//
// ***** HID Stream Interface *****
//
// We do not expose any PDD IOCTLs, so these all pass through to the MDD.
extern "C"
DWORD
HID_Init(
LPCWSTR lpszDevKey
)
{
return HidMdd_Init(lpszDevKey);
}
extern "C"
BOOL
HID_Deinit(
DWORD dwContext
)
{
return HidMdd_Deinit(dwContext);
}
extern "C"
DWORD
HID_Open(
DWORD dwContext,
DWORD dwAccMode,
DWORD dwShrMode
)
{
return HidMdd_Open(dwContext, dwAccMode, dwShrMode);
}
extern "C"
BOOL
HID_Close(
DWORD dwContext
)
{
return HidMdd_Close(dwContext);
}
extern "C"
BOOL
HID_IOControl (
DWORD dwContext,
DWORD dwCode,
PBYTE pInpBuf,
DWORD dwInpLen,
PBYTE pOutBuf,
DWORD dwOutLen,
PDWORD pdwActualOutLen
)
{
// We do not have any PDD IOCTLs, so pass everything on to the MDD.
return HidMdd_IOControl(dwContext, dwCode, pInpBuf,
dwInpLen, pOutBuf, dwOutLen, pdwActualOutLen);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -