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.
 
 
 
 
 
 

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