|
|
/*++
Copyright (c) 1998 - 1999 Microsoft Corporation
Module Name:
ioctl.c
Abstract: Contains routines to support HIDCLASS internal ioctl queries for game devices.
Environment:
Kernel mode
@@BEGIN_DDKSPLIT Author: Eliyas Yakub (Mar, 10, 1997)
Revision History:
Updated by Eliyas on Feb 5 1998 MarcAnd 02-Jul-98 Quick tidy for DDK
@@END_DDKSPLIT
--*/
#include "hidgame.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, HGM_GetDeviceDescriptor)
#pragma alloc_text (PAGE, HGM_GetReportDescriptor)
#pragma alloc_text (PAGE, HGM_GetAttributes )
#endif
/*****************************************************************************
* * @doc EXTERNAL * * @func NTSTATUS | HGM_InternalIoctl | * * 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 | DeviceObject | * * Pointer to the driver object * * @parm IN PIRP | Irp | * * Pointer to an I/O Request Packet. * * @rvalue STATUS_SUCCESS | success * @rvalue STATUS_NOT_SUPPORT | Irp function not supported * @rvalue ??? | ??? * *****************************************************************************/ NTSTATUS EXTERNAL HGM_InternalIoctl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack;
HGM_DBGPRINT(FILE_IOCTL | HGM_FENTRY, \ ("HGM_InternalIoctl(DeviceObject=0x%x,Irp=0x%x)", \ DeviceObject, Irp));
/*
* Get a pointer to the current location in the Irp */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
/*
* Get a pointer to the device extension */
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
ntStatus = HGM_IncRequestCount( DeviceExtension ); if (!NT_SUCCESS (ntStatus)) { /*
* Someone sent us another plug and play IRP after removed */
HGM_DBGPRINT(FILE_PNP | HGM_ERROR,\ ("HGM_InternalIoctl: PnP IRP after device was removed\n")); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = ntStatus; } else { switch(IrpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: HGM_DBGPRINT(FILE_IOCTL | HGM_BABBLE, \ ("IOCTL_HID_GET_DEVICE_DESCRIPTOR")); ntStatus = HGM_GetDeviceDescriptor(DeviceObject, Irp); break;
case IOCTL_HID_GET_REPORT_DESCRIPTOR: HGM_DBGPRINT(FILE_IOCTL | HGM_BABBLE, \ ("IOCTL_HID_GET_REPORT_DESCRIPTOR")); ntStatus = HGM_GetReportDescriptor(DeviceObject, Irp); break;
case IOCTL_HID_READ_REPORT: HGM_DBGPRINT(FILE_IOCTL | HGM_BABBLE,\ ("IOCTL_HID_READ_REPORT")); ntStatus = HGM_ReadReport(DeviceObject, Irp); break;
case IOCTL_HID_GET_DEVICE_ATTRIBUTES: HGM_DBGPRINT(FILE_IOCTL | HGM_BABBLE,\ ("IOCTL_HID_GET_DEVICE_ATTRIBUTES")); ntStatus = HGM_GetAttributes(DeviceObject, Irp); break;
default: HGM_DBGPRINT(FILE_IOCTL | HGM_WARN,\ ("Unknown or unsupported IOCTL (%x)", IrpStack->Parameters.DeviceIoControl.IoControlCode)); ntStatus = STATUS_NOT_SUPPORTED; break; }
/*
* Set real return status in Irp */ Irp->IoStatus.Status = ntStatus;
HGM_DecRequestCount( DeviceExtension ); }
if(ntStatus != STATUS_PENDING) { IoCompleteRequest(Irp, IO_NO_INCREMENT); /*
* NOTE: Real return status set in Irp->IoStatus.Status */ ntStatus = STATUS_SUCCESS; } else { /*
* No reason why there should be a status pending */ HGM_DBGPRINT(FILE_IOCTL | HGM_ERROR, \ ("HGM_InternalIoctl: Pending Status !")); IoMarkIrpPending( Irp ); }
HGM_EXITPROC(FILE_IOCTL | HGM_FEXIT_STATUSOK, "HGM_InternalIoctl", ntStatus);
return ntStatus; } /* HGM_InternalIoctl */
/*****************************************************************************
* * @doc EXTERNAL * * @func NTSTATUS | HGM_GetDeviceDescriptor | * * Respond to HIDCLASS IOCTL_HID_GET_DEVICE_DESCRIPTOR * by returning a device descriptor * * @parm IN PDRIVER_OBJECT | DeviceObject | * * Pointer to the driver object * * @parm IN PIRP | Irp | * * Pointer to an I/O Request Packet. * * @rvalue STATUS_SUCCESS | success * @rvalue STATUS_BUFFER_TOO_SMALL | need more memory * *****************************************************************************/ NTSTATUS INTERNAL HGM_GetDeviceDescriptor ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PHID_DESCRIPTOR pHidDescriptor; /* Hid descriptor for this device */ USHORT cbReport; UCHAR rgGameReport[MAXBYTES_GAME_REPORT] ; NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack;
PAGED_CODE ();
HGM_DBGPRINT(FILE_IOCTL | HGM_FENTRY,\ ("HGM_GetDeviceDescriptor(DeviceObject=0x%x,Irp=0x%x)", DeviceObject, Irp));
/*
* Get a pointer to the current location in the Irp */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
/*
* Get a pointer to the device extension */
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
/*
* Get a pointer to the HID_DESCRIPTOR */ pHidDescriptor = (PHID_DESCRIPTOR) Irp->UserBuffer;
if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(*pHidDescriptor) ) {
HGM_DBGPRINT(FILE_IOCTL | HGM_ERROR,\ ("HGM_GetDeviceDescriptor: OutBufferLength(0x%x) < sizeof(HID_DESCRIPTOR)(0x%x)", \ IrpStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(*pHidDescriptor)));
ntStatus = STATUS_BUFFER_TOO_SMALL; } else { /*
* Generate the report */ ntStatus = HGM_GenerateReport(DeviceObject, rgGameReport, &cbReport);
if( NT_SUCCESS(ntStatus) ) { RtlZeroMemory( pHidDescriptor, sizeof(*pHidDescriptor) ); /*
* Copy device descriptor to HIDCLASS buffer */ pHidDescriptor->bLength = sizeof(*pHidDescriptor); pHidDescriptor->bDescriptorType = HID_HID_DESCRIPTOR_TYPE; pHidDescriptor->bcdHID = HID_REVISION; pHidDescriptor->bCountry = 0; /*not localized*/ pHidDescriptor->bNumDescriptors = HGM_NUMBER_DESCRIPTORS; pHidDescriptor->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE ; pHidDescriptor->DescriptorList[0].wReportLength = cbReport;
/*
* Report how many bytes were copied */ Irp->IoStatus.Information = sizeof(*pHidDescriptor); } else { Irp->IoStatus.Information = 0x0; } }
HGM_EXITPROC(FILE_IOCTL |HGM_FEXIT_STATUSOK, "HGM_GetDeviceDescriptor", ntStatus);
return ntStatus; } /* HGM_GetDeviceDescriptor */
/*****************************************************************************
* * @doc EXTERNAL * * @func NTSTATUS | HGM_GetReportDescriptor | * * Respond to HIDCLASS IOCTL_HID_GET_REPORT_DESCRIPTOR * by returning appropriate the report descriptor * * @parm IN PDRIVER_OBJECT | DeviceObject | * * Pointer to the driver object * * @parm IN PIRP | Irp | * * Pointer to an I/O Request Packet. * * @rvalue STATUS_SUCCESS | success * @rvalue ??? | ??? * *****************************************************************************/ NTSTATUS INTERNAL HGM_GetReportDescriptor ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack; NTSTATUS ntStatus; UCHAR rgGameReport[MAXBYTES_GAME_REPORT] ; USHORT cbReport;
PAGED_CODE ();
HGM_DBGPRINT(FILE_IOCTL | HGM_FENTRY,\ ("HGM_GetReportDescriptor(DeviceObject=0x%x,Irp=0x%x)",\ DeviceObject, Irp));
/*
* Get a pointer to the current location in the Irp */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
/*
* Get a pointer to the device extension */
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
/*
* Generate the report */ ntStatus = HGM_GenerateReport(DeviceObject, rgGameReport, &cbReport);
if( NT_SUCCESS(ntStatus) ) { if( cbReport > (USHORT) IrpStack->Parameters.DeviceIoControl.OutputBufferLength ) { ntStatus = STATUS_BUFFER_TOO_SMALL;
HGM_DBGPRINT(FILE_IOCTL | HGM_ERROR,\ ("HGM_GetReportDescriptor: cbReport(0x%x) OutputBufferLength(0x%x)",\ cbReport, IrpStack->Parameters.DeviceIoControl.OutputBufferLength));
} else { RtlCopyMemory( Irp->UserBuffer, rgGameReport, cbReport ); /*
* Report how many bytes were copied */ Irp->IoStatus.Information = cbReport; ntStatus = STATUS_SUCCESS; } }
HGM_EXITPROC(FILE_IOCTL |HGM_FEXIT_STATUSOK, "HGM_GetReportDescriptor", ntStatus);
return ntStatus; } /* HGM_GetReportDescriptor */
/*****************************************************************************
* * @doc EXTERNAL * * @func NTSTATUS | HGM_ReadReport | * * Poll the gameport, remap the axis and button data and package * into the defined HID report field. * <nl>This routine cannot be pageable as HID can make reads at * dispatch-level. * * @parm IN PDRIVER_OBJECT | DeviceObject | * * Pointer to the driver object * * @parm IN PIRP | Irp | * * Pointer to an I/O Request Packet. * * @rvalue STATUS_SUCCESS | success * @rvalue STATUS_DEVICE_NOT_CONNECTED | Device Failed to Quiesce * ( not connected ) * @rvalue STATUS_TIMEOUT | Could not determine exact transition time for * one or more axis but not a failure. * *****************************************************************************/ NTSTATUS INTERNAL HGM_ReadReport ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IrpStack;
HGM_DBGPRINT(FILE_IOCTL | HGM_FENTRY,\ ("HGM_ReadReport(DeviceObject=0x%x,Irp=0x%x)", \ DeviceObject, Irp));
/*
* Get a pointer to the device extension. */
DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
/*
* Get Stack location. */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
/*
* First check the size of the output buffer (there is no input buffer) */
if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HIDGAME_INPUT_DATA) ) { HGM_DBGPRINT(FILE_IOCTL | HGM_WARN,\ ("HGM_ReadReport: Buffer too small, output=0x%x need=0x%x", \ IrpStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(HIDGAME_INPUT_DATA) ) );
ntStatus = STATUS_BUFFER_TOO_SMALL; }
if( DeviceExtension->fStarted == FALSE ) { ntStatus = STATUS_DEVICE_NOT_READY ; }
/*
* All the checking done so do device specific polling */ if( NT_SUCCESS(ntStatus) ) { ntStatus = HGM_UpdateLatestPollData( DeviceExtension ); }
/*
* If all's well, translate device specific data to HID report */ if( NT_SUCCESS(ntStatus) ) { HGM_Game2HID( DeviceExtension, (PHIDGAME_INPUT_DATA)Irp->UserBuffer ); Irp->IoStatus.Information = sizeof(HIDGAME_INPUT_DATA); } else { Irp->IoStatus.Information = 0x0; }
Irp->IoStatus.Status = ntStatus;
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT, "HGM_ReadReport", ntStatus);
return ntStatus; } /* HGM_ReadReport */
/*****************************************************************************
* * @doc EXTERNAL * * @func NTSTATUS | HGM_GetAttributes | * * Respond to IOCTL_HID_GET_ATTRIBUTES, by filling * the HID_DEVICE_ATTRIBUTES struct * * @parm IN PDRIVER_OBJECT | DeviceObject | * * Pointer to the driver object * * @parm IN PIRP | Irp | * * Pointer to an I/O Request Packet. * * @rvalue STATUS_SUCCESS | success * @rvalue ??? | ??? * *****************************************************************************/ NTSTATUS INTERNAL HGM_GetAttributes ( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS ntStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack;
PAGED_CODE();
HGM_DBGPRINT(FILE_IOCTL | HGM_FENTRY,\ ("HGM_GetAttributes(DeviceObject=0x%x,Irp=0x%x)",\ DeviceObject, Irp));
/*
* Get a pointer to the current location in the Irp */
IrpStack = IoGetCurrentIrpStackLocation(Irp);
if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof (HID_DEVICE_ATTRIBUTES) ) { ntStatus = STATUS_BUFFER_TOO_SMALL;
HGM_DBGPRINT(FILE_IOCTL | HGM_ERROR,\ ("HGM_GetAttributes: cbReport(0x%x) OutputBufferLength(0x%x)",\ sizeof (HID_DEVICE_ATTRIBUTES), IrpStack->Parameters.DeviceIoControl.OutputBufferLength)); } else { PDEVICE_EXTENSION DeviceExtension; PHID_DEVICE_ATTRIBUTES DeviceAttributes; POEMDATA OemData;
/*
* Get a pointer to the device extension */ DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject); DeviceAttributes = (PHID_DEVICE_ATTRIBUTES) Irp->UserBuffer;
OemData = &DeviceExtension->HidGameOemData.OemData[0]; if( DeviceExtension->fSiblingFound) { OemData = &DeviceExtension->HidGameOemData.OemData[1]; }
RtlZeroMemory( DeviceAttributes, sizeof(*DeviceAttributes));
/*
* Report how many bytes were copied */
Irp->IoStatus.Information = sizeof(*DeviceAttributes);
DeviceAttributes->Size = sizeof (*DeviceAttributes); DeviceAttributes->VendorID = OemData->VID; DeviceAttributes->ProductID = OemData->PID; DeviceAttributes->VersionNumber = HIDGAME_VERSION_NUMBER;
}
HGM_EXITPROC(FILE_IOCTL|HGM_FEXIT_STATUSOK, "HGM_GetAttributes", ntStatus);
return ntStatus; } /* HGM_GetAttributes */
|