|
|
/*++
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-Apr-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 | HbutInternalIoctl | * 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 HbutInternalIoctl( IN PDEVICE_OBJECT DevObj, IN PIRP Irp ) { PROCNAME("HbutInternalIoctl") 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 { ASSERT(devext->dwfHBut & HBUTF_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); 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); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { IoMarkIrpPending(Irp); } }
EXIT(1, ("=%x\n", status)); return status; } //HbutInternalIoctl
/*****************************************************************************
* * @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;
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);
if (irpsp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(OEM_INPUT_REPORT)) { ERRPRINT(("invalid input report size (bufflen=%d)\n", irpsp->Parameters.DeviceIoControl.OutputBufferLength)); status = STATUS_INVALID_BUFFER_SIZE; } else if (!(devext->dwfHBut & HBUTF_DEVICE_STARTED)) { ERRPRINT(("device not started yet\n")); status = STATUS_DEVICE_NOT_READY ; } else { KIRQL OldIrql; PDRIVER_CANCEL OldCancelRoutine;
KeAcquireSpinLock(&devext->SpinLock, &OldIrql); OldCancelRoutine = IoSetCancelRoutine(Irp, ReadReportCanceled); ASSERT(OldCancelRoutine == NULL);
if (Irp->Cancel) { //
// This IRP was canceled. Do not queue it.
//
OldCancelRoutine = IoSetCancelRoutine(Irp, NULL); if (OldCancelRoutine != NULL) { //
// Cancel routine was not called.
//
ASSERT(OldCancelRoutine == ReadReportCanceled); status = STATUS_CANCELLED; } else { //
// Cancel routine was called and it will complete this IRP
// as soon as we drop the spinlock. Return PENDING so the
// caller doesn't touch this IRP.
//
InitializeListHead(&Irp->Tail.Overlay.ListEntry); IoMarkIrpPending(Irp); status = STATUS_PENDING; } } else { InsertTailList(&devext->PendingIrpList, &Irp->Tail.Overlay.ListEntry); IoMarkIrpPending(Irp); status = STATUS_PENDING; }
KeReleaseSpinLock(&devext->SpinLock, OldIrql); }
EXIT(2, ("=%x\n", status)); return status; } //ReadReport
/*****************************************************************************
* * @doc EXTERNAL * * @func VOID | ReadReportCanceled | * ReadReport IRP has been canceled, so do the clean up. * * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object. * @parm IN PIRP | Irp | Points to an I/O Request Packet. * * @rvalue None. * *****************************************************************************/
VOID EXTERNAL ReadReportCanceled( IN PDEVICE_OBJECT DevObj, IN PIRP Irp ) { PROCNAME("ReadReportCanceled") PDEVICE_EXTENSION devext; KIRQL OldIrql;
ENTER(2, ("(DevObj=%p,Irp=%p)\n", DevObj, Irp));
ASSERT(Irp->Cancel); ASSERT(Irp->CancelRoutine == NULL); devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj); KeAcquireSpinLock(&devext->SpinLock, &OldIrql); RemoveEntryList(&Irp->Tail.Overlay.ListEntry); KeReleaseSpinLock(&devext->SpinLock, OldIrql); IoReleaseCancelSpinLock(Irp->CancelIrql);
Irp->IoStatus.Status = STATUS_CANCELLED; IoReleaseRemoveLock(&devext->RemoveLock, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); WARNPRINT(("ReadReport IRP was canceled\n"));
EXIT(2, ("!\n")); return; } //ReadReportCanceled
/*****************************************************************************
* * @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 = OEM_PRODUCT_ID; DevAttrib->VersionNumber = OEM_VERSION_NUM;
Irp->IoStatus.Information = sizeof(HID_DEVICE_ATTRIBUTES); status = STATUS_SUCCESS; }
EXIT(2, ("=%x\n", status)); return status; } //GetAttributes
|