|
|
/*++
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; }
|