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