230 lines
7.3 KiB
C
230 lines
7.3 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
oempen.c
|
|
|
|
Abstract: Contains OEM specific functions.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Author:
|
|
|
|
Michael Tsang (MikeTs) 13-Apr-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#endif //ifdef ALLOC_PRAGMA
|
|
|
|
UCHAR gReportDescriptor[32] = {
|
|
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
|
|
0x09, 0x01, // USAGE (Consumer Control)
|
|
0xa1, 0x01, // COLLECTION (Application)
|
|
0x09, 0x03, // USAGE (Programmable Buttons)
|
|
0xa1, 0x00, // COLLECTION (Physical)
|
|
0x05, 0x09, // USAGE_PAGE (Button)
|
|
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
|
0x29, 0x06, // USAGE_MAXIMUM (Button 6)
|
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
|
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
|
0x95, 0x06, // REPORT_COUNT (6)
|
|
0x75, 0x01, // REPORT_SIZE (1)
|
|
0x81, 0x00, // INPUT (Data,Ary,Abs)
|
|
0x95, 0x02, // REPORT_COUNT (2)
|
|
0x81, 0x03, // INPUT (Cnst,Var,Abs)
|
|
0xc0, // END_COLLECTION
|
|
0xc0 // END_COLLECTION
|
|
};
|
|
|
|
HID_DESCRIPTOR gHidDescriptor =
|
|
{
|
|
sizeof(HID_DESCRIPTOR), //bLength
|
|
HID_HID_DESCRIPTOR_TYPE, //bDescriptorType
|
|
HID_REVISION, //bcdHID
|
|
0, //bCountry - not localized
|
|
1, //bNumDescriptors
|
|
{ //DescriptorList[0]
|
|
HID_REPORT_DESCRIPTOR_TYPE, //bReportType
|
|
sizeof(gReportDescriptor) //wReportLength
|
|
}
|
|
};
|
|
|
|
PWSTR gpwstrManufacturerID = L"Microsoft";
|
|
PWSTR gpwstrProductID = L"Tablet PC Buttons";
|
|
PWSTR gpwstrSerialNumber = L"0";
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func BOOLEAN | OemInterruptServiceRoutine |
|
|
* Interrupt service routine for the button device.
|
|
*
|
|
* @parm IN PKINTERRUPT | Interrupt | Points to the interrupt object.
|
|
* @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
|
|
*
|
|
* @rvalue SUCCESS | returns TRUE - it's our interrupt.
|
|
* @rvalue FAILURE | returns FALSE - it's not our interrupt.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOLEAN EXTERNAL
|
|
OemInterruptServiceRoutine(
|
|
IN PKINTERRUPT Interrupt,
|
|
IN PDEVICE_EXTENSION DevExt
|
|
)
|
|
{
|
|
PROCNAME("OemInterruptServiceRoutine")
|
|
BOOLEAN rc = FALSE;
|
|
UCHAR ButtonState;
|
|
|
|
ENTER(1, ("(Interrupt=%p,DevExt=%p)\n", Interrupt, DevExt));
|
|
|
|
UNREFERENCED_PARAMETER(Interrupt);
|
|
|
|
//
|
|
// Note: the action of reading the button state will also clear
|
|
// the interrupt.
|
|
//
|
|
ButtonState = READBUTTONSTATE(DevExt);
|
|
if ((ButtonState & BUTTON_INTERRUPT_MASK) &&
|
|
((ButtonState & BUTTON_STATUS_MASK)!= DevExt->LastButtonState))
|
|
{
|
|
DBGPRINT(1, ("Button interrupt (Buttons=%x)\n", ButtonState));
|
|
DevExt->LastButtonState = ButtonState & BUTTON_STATUS_MASK;
|
|
DevExt->dwfHBut |= HBUTF_DEBOUNCE_TIMER_SET;
|
|
KeSetTimer(&DevExt->DebounceTimer,
|
|
DevExt->DebounceTime,
|
|
&DevExt->TimerDpc);
|
|
DBGPRINT(3, ("Button Interrupt (ButtonState=%x)\n", ButtonState));
|
|
rc = TRUE;
|
|
}
|
|
|
|
EXIT(1, ("=%x\n", rc));
|
|
return rc;
|
|
} //OemInterruptServiceRoutine
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func VOID | OemButtonDebounceDpc |
|
|
* Timer DPC routine to handle button debounce.
|
|
*
|
|
* @parm IN PKDPC | Dpc | Points to the DPC object.
|
|
* @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
|
|
* @parm IN PVOID | SysArg1 | System argument 1.
|
|
* @parm IN PVOID | SysArg2 | System arugment 2.
|
|
*
|
|
* @rvalue None.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
VOID EXTERNAL
|
|
OemButtonDebounceDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_EXTENSION DevExt,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2
|
|
)
|
|
{
|
|
PROCNAME("OemButtonDebounceDpc")
|
|
UCHAR ButtonState;
|
|
|
|
ENTER(2, ("(Dpc=%p,DevExt=%p,SysArg1=%p,SysArg2=%p)\n",
|
|
Dpc, DevExt, SysArg1, SysArg2));
|
|
|
|
UNREFERENCED_PARAMETER(Dpc);
|
|
UNREFERENCED_PARAMETER(SysArg1);
|
|
UNREFERENCED_PARAMETER(SysArg2);
|
|
|
|
ButtonState = READBUTTONSTATE(DevExt) & BUTTON_STATUS_MASK;
|
|
if (ButtonState == DevExt->LastButtonState)
|
|
{
|
|
PIRP irp = NULL;
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY plist;
|
|
PDRIVER_CANCEL OldCancelRoutine;
|
|
|
|
if (ButtonState & DevExt->StuckButtonsMask)
|
|
{
|
|
if (DevExt->bStuckCount >= MAX_STUCK_COUNT)
|
|
{
|
|
DBGPRINT(1, ("Clearing stuck buttons (Buttons=%x,StuckMask=%x)\n",
|
|
ButtonState, DevExt->StuckButtonsMask));
|
|
ButtonState &= ~DevExt->StuckButtonsMask;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(1, ("Detected stuck buttons (Buttons=%x,StuckMask=%x,Count=%d)\n",
|
|
ButtonState, DevExt->StuckButtonsMask,
|
|
DevExt->bStuckCount));
|
|
DevExt->bStuckCount++;
|
|
}
|
|
}
|
|
else if (DevExt->StuckButtonsMask != 0)
|
|
{
|
|
//
|
|
// The button has unstuck after all???
|
|
//
|
|
DBGPRINT(1, ("Button has unstuck (Buttons=%x,StuckMask=%x)\n",
|
|
ButtonState, DevExt->StuckButtonsMask));
|
|
DevExt->bStuckCount = 0;
|
|
}
|
|
|
|
DevExt->dwfHBut &= ~HBUTF_DEBOUNCE_TIMER_SET;
|
|
|
|
KeAcquireSpinLock(&DevExt->SpinLock, &OldIrql);
|
|
if (!IsListEmpty(&DevExt->PendingIrpList))
|
|
{
|
|
plist = RemoveHeadList(&DevExt->PendingIrpList);
|
|
irp = CONTAINING_RECORD(plist, IRP, Tail.Overlay.ListEntry);
|
|
OldCancelRoutine = IoSetCancelRoutine(irp, NULL);
|
|
ASSERT(OldCancelRoutine == ReadReportCanceled);
|
|
}
|
|
KeReleaseSpinLock(&DevExt->SpinLock, OldIrql);
|
|
|
|
if (irp != NULL)
|
|
{
|
|
POEM_INPUT_REPORT report = (POEM_INPUT_REPORT)irp->UserBuffer;
|
|
|
|
//
|
|
// Tell the system that we are not idling.
|
|
//
|
|
PoSetSystemState(ES_USER_PRESENT);
|
|
|
|
report->ButtonState = ButtonState;
|
|
irp->IoStatus.Information = sizeof(OEM_INPUT_REPORT);
|
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoReleaseRemoveLock(&DevExt->RemoveLock, irp);
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
DBGPRINT(3, ("Button Event (ButtonState=%x)\n", ButtonState));
|
|
}
|
|
else
|
|
{
|
|
WARNPRINT(("no pending ReadReport irp, must have been canceled\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(3, ("button state is unstable, try again (PrevState=%x,NewState=%x)\n",
|
|
DevExt->LastButtonState, ButtonState));
|
|
DevExt->LastButtonState = ButtonState;
|
|
KeSetTimer(&DevExt->DebounceTimer,
|
|
DevExt->DebounceTime,
|
|
&DevExt->TimerDpc);
|
|
}
|
|
|
|
EXIT(2, ("!\n"));
|
|
return;
|
|
} //OemButtonDebounceDpc
|