Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

318 lines
12 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
feature.c
Abstract
Feature handling routines
Author:
Ervin P.
Environment:
Kernel mode only
Revision History:
--*/
#include "pch.h"
#if 0
/*
********************************************************************************
* HidpGetSetFeatureComplete
********************************************************************************
*
*
*/
NTSTATUS HidpGetSetFeatureComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
PHIDCLASS_DEVICE_EXTENSION hidDeviceExtension = (PHIDCLASS_DEVICE_EXTENSION)Context;
PHID_XFER_PACKET featurePacket = Irp->UserBuffer;
NTSTATUS status = Irp->IoStatus.Status;
DBG_COMMON_ENTRY()
ASSERT(hidDeviceExtension->isClientPdo);
if (featurePacket){
DBG_RECORD_FEATURE(featurePacket->reportId, IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode, TRUE)
/*
* Free the feature packet.
*/
ExFreePool(featurePacket);
Irp->UserBuffer = NULL;
}
if (NT_SUCCESS(status)){
FDO_EXTENSION *fdoExt = &hidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0){
/*
* Since this collection only has one report,
* we deleted the report id (which is known implicitly)
* on the way down. We now have to bump the return
* value to indicate that one more byte was sent or received.
*/
(ULONG)Irp->IoStatus.Information++;
}
}
/*
* If the lower driver returned PENDING, mark our stack location as pending also.
*/
if (Irp->PendingReturned){
IoMarkIrpPending(Irp);
}
DBG_COMMON_EXIT()
return status;
}
/*
********************************************************************************
* HidpGetSetFeature
********************************************************************************
*
* There are not many differences between reading and writing a feature at this level,
* so we have one function do both.
*
* controlCode is either IOCTL_HID_GET_FEATURE or 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 HidpGetSetFeature( 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;
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 feature with no file extension"))
return STATUS_PRIVILEGE_NOT_HELD;
}
fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
/*
* Check security.
*/
if (fileExtension->SecurityCheck){
PHIDP_COLLECTION_DESC collectionDesc;
/*
* Get our collection description.
*/
collectionDesc = GetCollectionDesc(fdoExt, fileExtension->CollectionNumber);
if (collectionDesc){
/*
* Make sure that there is a feature report on this collection
* (or that we allow feature reads on a non-feature ctn for this device).
*/
if ((collectionDesc->FeatureLength > 0) ||
(fdoExt->deviceSpecificFlags & DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION)){
PUCHAR featureBuf;
ULONG featureBufLen;
switch (controlCode){
case IOCTL_HID_GET_FEATURE:
featureBufLen = currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
featureBuf = HidpGetSystemAddressForMdlSafe(Irp->MdlAddress);
break;
case IOCTL_HID_SET_FEATURE:
featureBuf = Irp->AssociatedIrp.SystemBuffer;
featureBufLen = currentIrpSp->Parameters.DeviceIoControl.InputBufferLength;
break;
default:
TRAP;
status = STATUS_INVALID_PARAMETER;
featureBuf = NULL;
featureBufLen = 0;
}
if (featureBuf && featureBufLen){
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 = featureBuf[0];
if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0){
DBGASSERT((reportId == 0),
("Report Id should be zero, acutal id = %d", reportId),
FALSE)
featureBuf++;
featureBufLen--;
}
/*
* Try to find a matching feature report for this device.
*/
reportIdent = GetReportIdentifier(fdoExt, reportId);
/*
* Check the buffer length against the
* feature length in the report identifier.
*/
if (reportIdent){
if (reportIdent->FeatureLength){
switch (controlCode){
case IOCTL_HID_GET_FEATURE:
/*
* The buffer must be big enough for the report.
*/
if (featureBufLen < reportIdent->FeatureLength){
ASSERT(!(PVOID)"feature buf must be at least feature size for get-feature.");
reportIdent = NULL;
}
break;
case IOCTL_HID_SET_FEATURE:
/*
* 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 (featureBufLen < reportIdent->FeatureLength){
ASSERT(!(PVOID)"feature buf must be exact size for set-feature.");
reportIdent = NULL;
}
else {
featureBufLen = reportIdent->FeatureLength;
}
break;
}
}
else {
/*
* This report id is not for a feature report.
*/
reportIdent = NULL;
}
}
if (reportIdent ||
(fdoExt->deviceSpecificFlags & DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION)){
PHID_XFER_PACKET featurePacket = ALLOCATEPOOL(NonPagedPool, sizeof(HID_XFER_PACKET));
if (featurePacket){
featurePacket->reportBuffer = featureBuf;
featurePacket->reportBufferLen = featureBufLen;
featurePacket->reportId = reportId;
Irp->UserBuffer = featurePacket;
/*
* 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_FEATURE:
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_XFER_PACKET);
break;
case IOCTL_HID_SET_FEATURE:
nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(HID_XFER_PACKET);
break;
default:
TRAP;
}
DBG_RECORD_FEATURE(reportId, controlCode, FALSE)
status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
if (!NT_SUCCESS(status)){
DBGWARN(("HidpGetSetFeature: usb returned status %xh.", status))
}
DBG_RECORD_FEATURE(reportId, controlCode, TRUE)
ExFreePool(featurePacket);
*sentIrp = FALSE; // needs to be completed again
}
else {
ASSERT(featurePacket);
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(featureBuf, ("Feature buffer is invalid"), FALSE)
DBGASSERT(featureBufLen, ("Feature buffer length is invalid"), FALSE)
status = STATUS_INVALID_BUFFER_SIZE;
}
}
else {
ASSERT(collectionDesc->FeatureLength);
status = STATUS_INVALID_DEVICE_REQUEST;
}
}
else {
ASSERT(collectionDesc);
status = STATUS_DEVICE_NOT_CONNECTED;
}
}
else {
ASSERT(fileExtension->SecurityCheck);
status = STATUS_PRIVILEGE_NOT_HELD;
}
DBGSUCCESS(status, FALSE)
DBG_COMMON_EXIT()
return status;
}
#endif