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