You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
449 lines
16 KiB
449 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
name.c
|
|
|
|
Abstract
|
|
|
|
Get-friendly-name handling routines
|
|
|
|
Author:
|
|
|
|
Ervin P.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
|
|
/*
|
|
********************************************************************************
|
|
* HidpGetDeviceString
|
|
********************************************************************************
|
|
*
|
|
* Note: This function cannot be pageable because it is called
|
|
* from the IOCTL dispatch routine, which can get called
|
|
* at DISPATCH_LEVEL.
|
|
*
|
|
*/
|
|
NTSTATUS HidpGetDeviceString(IN FDO_EXTENSION *fdoExt,
|
|
IN OUT PIRP Irp,
|
|
IN ULONG stringId,
|
|
IN ULONG languageId)
|
|
{
|
|
BOOLEAN completeIrpHere = TRUE;
|
|
NTSTATUS status;
|
|
|
|
PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
|
|
|
|
currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
nextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|
|
|
/*
|
|
* The Irp we got uses buffering type METHOD_OUT_DIRECT,
|
|
* which passes the buffer in the MDL.
|
|
* IOCTL_HID_GET_STRING uses buffering type METHOD_NEITHER,
|
|
* which passes the buffer in Irp->UserBuffer.
|
|
* So we have to copy the pointer.
|
|
*/
|
|
Irp->UserBuffer = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
|
|
|
|
if (Irp->UserBuffer) {
|
|
|
|
/*
|
|
* Prepare the next (lower) IRP stack location.
|
|
* This will be the minidriver's (e.g. HIDUSB's) "current" stack location.
|
|
*/
|
|
nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_STRING;
|
|
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength =
|
|
currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
// Type3InputBuffer has string/lang IDs
|
|
nextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
|
|
ULongToPtr((ULONG)((stringId & 0xffff) + (languageId << 16)));
|
|
|
|
status = HidpCallDriver(fdoExt->fdo, Irp);
|
|
|
|
/*
|
|
* Irp will be completed by lower driver
|
|
*/
|
|
completeIrpHere = FALSE;
|
|
} else {
|
|
status = STATUS_INVALID_USER_BUFFER;
|
|
}
|
|
|
|
if (completeIrpHere) {
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
DBGSUCCESS(status, FALSE)
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
********************************************************************************
|
|
* HidpGetIndexedString
|
|
********************************************************************************
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
NTSTATUS HidpGetIndexedString( IN FDO_EXTENSION *fdoExt,
|
|
IN OUT PIRP Irp,
|
|
IN ULONG stringIndex,
|
|
IN ULONG languageId)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
|
|
|
|
currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
nextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|
|
|
/*
|
|
* The Irp we got uses buffering type METHOD_OUT_DIRECT,
|
|
* which passes the buffer in the MDL.
|
|
* The Irp we're sending down uses the same buffering method,
|
|
* so just let the lower driver derive the system address
|
|
* from the MDL.
|
|
*/
|
|
|
|
/*
|
|
* Prepare the next (lower) IRP stack location.
|
|
* This will be the minidriver's (e.g. HIDUSB's) "current" stack location.
|
|
*/
|
|
nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_INDEXED_STRING;
|
|
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
// Type3InputBuffer has string index/lang IDs
|
|
nextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
|
|
ULongToPtr((ULONG)(stringIndex + (languageId << 16)));
|
|
|
|
status = HidpCallDriver(fdoExt->fdo, Irp);
|
|
|
|
DBGSUCCESS(status, FALSE)
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
********************************************************************************
|
|
* HidpGetMsGenreDescriptor
|
|
********************************************************************************
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
NTSTATUS HidpGetMsGenreDescriptor(
|
|
IN FDO_EXTENSION *fdoExt,
|
|
IN OUT PIRP Irp)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
|
|
|
|
DBGOUT(("Received request for genre descriptor in hidclass"))
|
|
currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
nextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|
|
|
/*
|
|
* The Irp we got uses buffering type METHOD_OUT_DIRECT,
|
|
* which passes the buffer in the MDL.
|
|
* The Irp we're sending down uses the same buffering method,
|
|
* so just let the lower driver derive the system address
|
|
* from the MDL.
|
|
*/
|
|
|
|
/*
|
|
* Prepare the next (lower) IRP stack location.
|
|
* This will be the minidriver's (e.g. HIDUSB's) "current" stack location.
|
|
*/
|
|
nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_MS_GENRE_DESCRIPTOR;
|
|
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
status = HidpCallDriver(fdoExt->fdo, Irp);
|
|
|
|
DBGSUCCESS(status, FALSE)
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
********************************************************************************
|
|
* HidpGetSetReport
|
|
********************************************************************************
|
|
*
|
|
* There are not many differences between reading and writing a
|
|
* report at this level, whether it be an input, output or feature
|
|
* report, so we have one function do all six.
|
|
*
|
|
* controlCode is one of:
|
|
* IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_INPUT_REPORT
|
|
* IOCTL_HID_GET_OUTPUT_REPORT, IOCTL_HID_SET_OUTPUT_REPORT
|
|
* IOCTL_HID_GET_FEATURE, IOCTL_HID_SET_FEATURE
|
|
*
|
|
* Note: This function cannot be pageable because it is called
|
|
* from the IOCTL dispatch routine, which can get called
|
|
* at DISPATCH_LEVEL.
|
|
*
|
|
*/
|
|
NTSTATUS HidpGetSetReport ( IN PHIDCLASS_DEVICE_EXTENSION HidDeviceExtension,
|
|
IN OUT PIRP Irp,
|
|
IN ULONG controlCode,
|
|
OUT BOOLEAN *sentIrp)
|
|
{
|
|
FDO_EXTENSION *fdoExt;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION currentIrpSp, nextIrpSp;
|
|
PFILE_OBJECT fileObject;
|
|
PHIDCLASS_FILE_EXTENSION fileExtension;
|
|
PHIDP_COLLECTION_DESC collectionDesc;
|
|
|
|
DBG_COMMON_ENTRY()
|
|
|
|
ASSERT(HidDeviceExtension->isClientPdo);
|
|
fdoExt = &HidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
|
|
currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
nextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|
|
|
*sentIrp = FALSE;
|
|
|
|
/*
|
|
* Get the file extension.
|
|
*/
|
|
ASSERT(currentIrpSp->FileObject);
|
|
fileObject = currentIrpSp->FileObject;
|
|
|
|
if (!fileObject->FsContext) {
|
|
DBGWARN(("Attempted to get/set report with no file extension"))
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
|
|
ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
|
|
|
|
|
|
/*
|
|
* Get our collection description.
|
|
*/
|
|
collectionDesc = GetCollectionDesc(fdoExt, fileExtension->CollectionNumber);
|
|
if (collectionDesc) {
|
|
|
|
PUCHAR reportBuf;
|
|
ULONG reportBufLen;
|
|
BOOLEAN featureRequest = FALSE;
|
|
|
|
switch (controlCode) {
|
|
case IOCTL_HID_GET_INPUT_REPORT:
|
|
// Make sure that there is an input report on this collection.
|
|
if (collectionDesc->InputLength == 0) {
|
|
DBGWARN(("No input report on collection %x",
|
|
fileExtension->CollectionNumber))
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
break;
|
|
|
|
case IOCTL_HID_SET_OUTPUT_REPORT:
|
|
// Make sure that there is an output report on this collection.
|
|
if (collectionDesc->OutputLength == 0) {
|
|
DBGWARN(("No output report on collection %x",
|
|
fileExtension->CollectionNumber))
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
break;
|
|
|
|
case IOCTL_HID_GET_FEATURE:
|
|
case IOCTL_HID_SET_FEATURE:
|
|
featureRequest = TRUE;
|
|
// Make sure that there is a feature report on this collection.
|
|
if (collectionDesc->FeatureLength == 0) {
|
|
DBGWARN(("No feature report on collection %x",
|
|
fileExtension->CollectionNumber))
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TRAP;
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
switch (controlCode) {
|
|
case IOCTL_HID_GET_INPUT_REPORT:
|
|
case IOCTL_HID_GET_FEATURE:
|
|
reportBufLen = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
reportBuf = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
|
|
break;
|
|
|
|
case IOCTL_HID_SET_OUTPUT_REPORT:
|
|
case IOCTL_HID_SET_FEATURE:
|
|
reportBuf = Irp->AssociatedIrp.SystemBuffer;
|
|
reportBufLen = currentIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
break;
|
|
|
|
default:
|
|
TRAP;
|
|
status = STATUS_INVALID_PARAMETER;
|
|
reportBuf = NULL;
|
|
reportBufLen = 0;
|
|
}
|
|
|
|
if (reportBuf && reportBufLen && NT_SUCCESS(status)) {
|
|
PHIDP_REPORT_IDS reportIdent;
|
|
UCHAR reportId;
|
|
|
|
/*
|
|
* The client includes the report id as the first byte of the report.
|
|
* We send down the report byte only if the device has multiple
|
|
* report IDs (i.e. the report id is not implicit).
|
|
*/
|
|
reportId = reportBuf[0];
|
|
if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0) {
|
|
DBGASSERT((reportId == 0),
|
|
("Report Id should be zero, acutal id = %d", reportId),
|
|
FALSE)
|
|
reportBuf++;
|
|
reportBufLen--;
|
|
}
|
|
|
|
/*
|
|
* Find a matching report identifier.
|
|
*/
|
|
reportIdent = GetReportIdentifier(fdoExt, reportId);
|
|
|
|
/*
|
|
* Check the buffer length against the
|
|
* report length in the report identifier.
|
|
*/
|
|
if (reportIdent) {
|
|
switch (controlCode) {
|
|
case IOCTL_HID_GET_INPUT_REPORT:
|
|
/*
|
|
* The buffer must be big enough for the report.
|
|
*/
|
|
if (!reportIdent->InputLength ||
|
|
reportBufLen < reportIdent->InputLength) {
|
|
ASSERT(!(PVOID)"report buf must be at least report size for get-report.");
|
|
reportIdent = NULL;
|
|
}
|
|
break;
|
|
case IOCTL_HID_GET_FEATURE:
|
|
/*
|
|
* The buffer must be big enough for the report.
|
|
*/
|
|
if (!reportIdent->FeatureLength ||
|
|
reportBufLen < reportIdent->FeatureLength) {
|
|
ASSERT(!(PVOID)"report buf must be at least report size for get-report.");
|
|
reportIdent = NULL;
|
|
}
|
|
break;
|
|
case IOCTL_HID_SET_OUTPUT_REPORT:
|
|
/*
|
|
* The buffer must be big enough for the report.
|
|
* It CAN be larger, and it is up to us to use
|
|
* the correct report size from the report identifier.
|
|
*/
|
|
if (!reportIdent->OutputLength ||
|
|
reportBufLen < reportIdent->OutputLength) {
|
|
ASSERT(!(PVOID)"report buf must be exact size for set-report.");
|
|
reportIdent = NULL;
|
|
} else {
|
|
reportBufLen = reportIdent->OutputLength;
|
|
}
|
|
break;
|
|
case IOCTL_HID_SET_FEATURE:
|
|
if (!reportIdent->FeatureLength ||
|
|
reportBufLen < reportIdent->FeatureLength) {
|
|
ASSERT(!(PVOID)"report buf must be exact size for set-report.");
|
|
reportIdent = NULL;
|
|
} else {
|
|
reportBufLen = reportIdent->FeatureLength;
|
|
}
|
|
break;
|
|
default:
|
|
TRAP;
|
|
}
|
|
}
|
|
|
|
if (reportIdent) {
|
|
|
|
PHID_XFER_PACKET reportPacket = ALLOCATEPOOL(NonPagedPool, sizeof(HID_XFER_PACKET));
|
|
|
|
if (reportPacket) {
|
|
|
|
reportPacket->reportBuffer = reportBuf;
|
|
reportPacket->reportBufferLen = reportBufLen;
|
|
reportPacket->reportId = reportId;
|
|
|
|
Irp->UserBuffer = reportPacket;
|
|
|
|
/*
|
|
* Prepare the next (lower) IRP stack location.
|
|
* This will be HIDUSB's "current" stack location.
|
|
*/
|
|
nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextIrpSp->Parameters.DeviceIoControl.IoControlCode = controlCode;
|
|
|
|
/*
|
|
* Note - input/output is relative to IOCTL servicer
|
|
*/
|
|
switch (controlCode) {
|
|
case IOCTL_HID_GET_INPUT_REPORT:
|
|
case IOCTL_HID_GET_FEATURE:
|
|
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_XFER_PACKET);
|
|
break;
|
|
case IOCTL_HID_SET_OUTPUT_REPORT:
|
|
case IOCTL_HID_SET_FEATURE:
|
|
nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(HID_XFER_PACKET);
|
|
break;
|
|
default:
|
|
TRAP;
|
|
}
|
|
|
|
DBG_RECORD_REPORT(reportId, controlCode, FALSE)
|
|
|
|
status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
DBGWARN(("HidpGetSetFeature: usb returned status %xh.", status))
|
|
}
|
|
DBG_RECORD_REPORT(reportId, controlCode, TRUE)
|
|
ExFreePool(reportPacket);
|
|
*sentIrp = FALSE; // needs to be completed again
|
|
|
|
} else {
|
|
ASSERT(reportPacket);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} else {
|
|
DBGASSERT(reportIdent, ("Some yahoo sent invalid data in ioctl %x", controlCode), FALSE)
|
|
status = STATUS_DATA_ERROR;
|
|
}
|
|
} else if (NT_SUCCESS(status)) {
|
|
DBGASSERT(reportBuf, ("Feature buffer is invalid"), FALSE)
|
|
DBGASSERT(reportBufLen, ("Feature buffer length is invalid"), FALSE)
|
|
status = STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
} else {
|
|
ASSERT(collectionDesc);
|
|
status = STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
DBGSUCCESS(status, FALSE)
|
|
|
|
DBG_COMMON_EXIT()
|
|
|
|
return status;
|
|
}
|