mirror of https://github.com/tongzx/nt5src
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.
522 lines
15 KiB
522 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ioctl.c
|
|
|
|
Abstract: Contains routines to support HIDCLASS internal
|
|
ioctl queries for the pen tablet devices.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Author:
|
|
Michael Tsang (MikeTs) 13-Mar-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, GetDeviceDescriptor)
|
|
#pragma alloc_text(PAGE, GetReportDescriptor)
|
|
#pragma alloc_text(PAGE, GetString)
|
|
#pragma alloc_text(PAGE, GetAttributes)
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func NTSTATUS | HpenInternalIoctl |
|
|
* Process the Control IRPs sent to this device.
|
|
* <nl>This function cannot be pageable because reads/writes
|
|
* can be made at dispatch-level
|
|
*
|
|
* @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS EXTERNAL
|
|
HpenInternalIoctl(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("HpenInternalIoctl")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
PDEVICE_EXTENSION devext;
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(1, ("(DevObj=%p,Irp=%p,IrpSp=%p,Ioctl=%s)\n",
|
|
DevObj, Irp, irpsp,
|
|
LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
|
|
HidIoctlNames)));
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
|
|
status = IoAcquireRemoveLock(&devext->RemoveLock, Irp);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
ERRPRINT(("received PnP IRP after device was removed\n"));
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
else
|
|
{
|
|
BOOLEAN fNeedCompletion = TRUE;
|
|
|
|
ASSERT(devext->dwfHPen & HPENF_DEVICE_STARTED);
|
|
switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
|
|
status = GetDeviceDescriptor(DevObj, Irp);
|
|
break;
|
|
|
|
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
|
|
status = GetReportDescriptor(DevObj, Irp);
|
|
break;
|
|
|
|
case IOCTL_HID_READ_REPORT:
|
|
status = ReadReport(DevObj, Irp);
|
|
fNeedCompletion = FALSE;
|
|
break;
|
|
|
|
case IOCTL_HID_GET_FEATURE:
|
|
status = OemGetFeatures(DevObj, Irp);
|
|
break;
|
|
|
|
case IOCTL_HID_SET_FEATURE:
|
|
status = OemSetFeatures(DevObj, Irp);
|
|
break;
|
|
|
|
case IOCTL_HID_GET_STRING:
|
|
status = GetString(DevObj, Irp);
|
|
break;
|
|
|
|
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
|
|
status = GetAttributes(DevObj, Irp);
|
|
break;
|
|
|
|
case IOCTL_HID_ACTIVATE_DEVICE:
|
|
case IOCTL_HID_DEACTIVATE_DEVICE:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
WARNPRINT(("unsupported ioctl code (ioctl=%s)\n",
|
|
LookupName(irpsp->Parameters.DeviceIoControl.IoControlCode,
|
|
HidIoctlNames)));
|
|
status = Irp->IoStatus.Status;
|
|
break;
|
|
}
|
|
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
IoReleaseRemoveLock(&devext->RemoveLock, Irp);
|
|
if (fNeedCompletion)
|
|
{
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
}
|
|
|
|
EXIT(1, ("=%x\n", status));
|
|
return status;
|
|
} //HpenInternalIoctl
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | GetDeviceDescriptor |
|
|
* Respond to HIDCLASS IOCTL_HID_GET_DEVICE_DESCRIPTOR
|
|
* by returning a device descriptor.
|
|
*
|
|
* @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns STATUS_BUFFER_TOO_SMALL - need more memory
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
GetDeviceDescriptor(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("GetDeviceDescriptor")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
|
|
PAGED_CODE ();
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
|
|
|
|
if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(gHidDescriptor))
|
|
{
|
|
ERRPRINT(("output buffer too small (bufflen=%d)\n",
|
|
irpsp->Parameters.DeviceIoControl.OutputBufferLength));
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(Irp->UserBuffer,
|
|
&gHidDescriptor,
|
|
sizeof(gHidDescriptor));
|
|
|
|
Irp->IoStatus.Information = sizeof(gHidDescriptor);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //GetDeviceDescriptor
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | GetReportDescriptor |
|
|
* Respond to HIDCLASS IOCTL_HID_GET_REPORT_DESCRIPTOR
|
|
* by returning appropriate the report descriptor.
|
|
*
|
|
* @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
GetReportDescriptor(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("GetReportDescriptor")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
|
|
PAGED_CODE ();
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p\n", DevObj, Irp, irpsp));
|
|
|
|
if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(gReportDescriptor))
|
|
{
|
|
ERRPRINT(("output buffer too small (bufflen=%d)\n",
|
|
irpsp->Parameters.DeviceIoControl.OutputBufferLength));
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(Irp->UserBuffer,
|
|
gReportDescriptor,
|
|
sizeof(gReportDescriptor));
|
|
|
|
Irp->IoStatus.Information = sizeof(gReportDescriptor);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //GetReportDescriptor
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | ReadReport |
|
|
* Read input report.
|
|
*
|
|
* @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
ReadReport(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("ReadReport")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
PDEVICE_EXTENSION devext;
|
|
ULONG DataLen;
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
|
|
|
|
ASSERT(Irp->UserBuffer != NULL);
|
|
devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
|
|
DataLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
if (DataLen != sizeof(HID_INPUT_REPORT))
|
|
{
|
|
ERRPRINT(("invalid input report size (bufflen=%d)\n", DataLen));
|
|
status = STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
else if (!(devext->dwfHPen & HPENF_DEVICE_STARTED))
|
|
{
|
|
ERRPRINT(("device not started yet\n"));
|
|
status = STATUS_DEVICE_NOT_READY ;
|
|
}
|
|
else
|
|
{
|
|
PHID_INPUT_REPORT HidReport = (PHID_INPUT_REPORT)Irp->UserBuffer;
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&devext->SpinLock, &OldIrql);
|
|
status = OemProcessResyncBuffer(devext, Irp);
|
|
KeReleaseSpinLock(&devext->SpinLock, OldIrql);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// If we don't have enough bytes in the resync buffer or the packet
|
|
// in the resync buffer is invalid, send an IRP down to read some
|
|
// more.
|
|
//
|
|
status = SerialAsyncReadWritePort(TRUE,
|
|
devext,
|
|
Irp,
|
|
HidReport->Report.RawInput,
|
|
sizeof(OEM_INPUT_REPORT),
|
|
ReadReportCompletion,
|
|
HidReport);
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //ReadReport
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | GetString |
|
|
* Respond to IOCTL_HID_GET_STRING.
|
|
*
|
|
* @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
GetString(
|
|
PDEVICE_OBJECT DevObj,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("GetString")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
PWSTR pwstrID;
|
|
ULONG lenID;
|
|
|
|
PAGED_CODE();
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p,StringID=%x)\n",
|
|
DevObj, Irp, irpsp,
|
|
(ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer));
|
|
|
|
switch ((ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer &
|
|
0xffff)
|
|
{
|
|
case HID_STRING_ID_IMANUFACTURER:
|
|
pwstrID = gpwstrManufacturerID;
|
|
break;
|
|
|
|
case HID_STRING_ID_IPRODUCT:
|
|
pwstrID = gpwstrProductID;
|
|
break;
|
|
|
|
case HID_STRING_ID_ISERIALNUMBER:
|
|
pwstrID = gpwstrSerialNumber;
|
|
break;
|
|
|
|
default:
|
|
pwstrID = NULL;
|
|
break;
|
|
}
|
|
|
|
lenID = pwstrID? wcslen(pwstrID)*sizeof(WCHAR) + sizeof(UNICODE_NULL): 0;
|
|
if (pwstrID == NULL)
|
|
{
|
|
ERRPRINT(("invalid string ID (ID=%x)\n",
|
|
(ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < lenID)
|
|
{
|
|
ERRPRINT(("output buffer too small (bufflen=%d,need=%d)\n",
|
|
irpsp->Parameters.DeviceIoControl.OutputBufferLength, lenID));
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(Irp->UserBuffer, pwstrID, lenID);
|
|
|
|
Irp->IoStatus.Information = lenID;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
EXIT(2, ("=%x (string=%S)\n", status, pwstrID? pwstrID: L"Null"));
|
|
return status;
|
|
} //GetString
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | GetAttributes |
|
|
* Respond to IOCTL_HID_GET_ATTRIBUTES, by filling
|
|
* the HID_DEVICE_ATTRIBUTES struct.
|
|
*
|
|
* @parm IN PDRIVER_OBJECT | DevObj | Points to the driver object.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
GetAttributes(
|
|
PDEVICE_OBJECT DevObj,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PROCNAME("GetAttributes")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
|
|
PAGED_CODE();
|
|
|
|
irpsp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ENTER(2, ("(DevObj=%p,Irp=%p,IrpSp=%p)\n", DevObj, Irp, irpsp));
|
|
|
|
if (irpsp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(HID_DEVICE_ATTRIBUTES))
|
|
{
|
|
ERRPRINT(("output buffer too small (bufflen=%d)\n",
|
|
irpsp->Parameters.DeviceIoControl.OutputBufferLength));
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
else
|
|
{
|
|
PDEVICE_EXTENSION devext;
|
|
PHID_DEVICE_ATTRIBUTES DevAttrib;
|
|
|
|
devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
|
|
DevAttrib = (PHID_DEVICE_ATTRIBUTES)Irp->UserBuffer;
|
|
|
|
DevAttrib->Size = sizeof(HID_DEVICE_ATTRIBUTES);
|
|
DevAttrib->VendorID = OEM_VENDOR_ID;
|
|
DevAttrib->ProductID = devext->OemData.wProductID;
|
|
DevAttrib->VersionNumber = devext->OemData.wFirmwareRev;
|
|
|
|
Irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //GetAttributes
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | ReadReportCompletion | Completion routine for ReadReport.
|
|
*
|
|
* @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
|
|
* @parm IN PIRP | Irp | Points to an I/O request packet.
|
|
* @parm IN PHID_INPUT_REPORT | HidReport | Points to input data packet.
|
|
*
|
|
* @rvalue SUCCESS | Returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | Returns STATUS_MORE_PROCESSING_REQUIRED
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
ReadReportCompletion(
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PIRP Irp,
|
|
IN PHID_INPUT_REPORT HidReport
|
|
)
|
|
{
|
|
PROCNAME("ReadReportCompletion")
|
|
NTSTATUS status = Irp->IoStatus.Status;
|
|
PDEVICE_EXTENSION devext;
|
|
|
|
ENTER(2, ("(DevObj=%p,Irp=%p,HidReport=%p,Status=%x)\n",
|
|
DevObj, Irp, HidReport, status));
|
|
|
|
devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
|
|
if (status == STATUS_CANCELLED)
|
|
{
|
|
WARNPRINT(("ReadReport IRP was cancelled\n"));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else if (!NT_SUCCESS(status))
|
|
{
|
|
ERRPRINT(("failed to read input data packet (status=%x)\n", status));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = OemProcessInputData(devext, Irp, HidReport);
|
|
}
|
|
|
|
if (Irp->PendingReturned)
|
|
{
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
|
|
if (status != STATUS_MORE_PROCESSING_REQUIRED)
|
|
{
|
|
IoReleaseRemoveLock(&devext->RemoveLock, Irp);
|
|
}
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //ReadReportCompletion
|