├── src ├── Resource.rc ├── SynapticsTouch.inf ├── hweight.c ├── bitops.c ├── queue.c ├── power.c ├── driver.c ├── idle.c ├── device.c ├── spb.c ├── resolutions.c ├── hid.c └── report.c ├── include ├── compat.h ├── hweight.h ├── resource.h ├── queue.h ├── driver.h ├── device.h ├── idle.h ├── spb.h ├── bitops.h ├── internal.h ├── HidCommon.h ├── resolutions.h ├── trace.h ├── controller.h ├── hid.h └── rmiinternal.h ├── README.md ├── contrib ├── SynapticsTouch.sln ├── SynapticsTouch.vcxproj.Filters ├── SynapticsTouch.vcxproj.filters └── SynapticsTouch.vcxproj ├── .gitattributes └── .gitignore /src/Resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imbushuo/SynapticsTouch/HEAD/src/Resource.rc -------------------------------------------------------------------------------- /src/SynapticsTouch.inf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imbushuo/SynapticsTouch/HEAD/src/SynapticsTouch.inf -------------------------------------------------------------------------------- /include/compat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef __COMPAT_H__ 4 | #define __COMPAT_H__ 5 | 6 | 7 | #endif -------------------------------------------------------------------------------- /include/hweight.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __HEWEIGHT_H__ 3 | #define __HEWEIGHT_H__ 4 | 5 | unsigned int hweight32(unsigned int w); 6 | ULONGLONG hweight64(ULONGLONG w); 7 | 8 | static inline unsigned long hweight_long(unsigned long w) 9 | { 10 | return sizeof(w) == 4 ? hweight32(w) : hweight64(w); 11 | } 12 | 13 | #endif -------------------------------------------------------------------------------- /include/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Resource.rc 4 | 5 | #define IDS_APP_TITLE 103 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 101 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Synaptics Touch Controller Driver for Lumia 950 XL 2 | ====================== 3 | 4 | [![Build Status (Visual Studio Team Services)](https://ligstd.visualstudio.com/Apple%20PTP%20Trackpad/_apis/build/status/SynapticsTouch%20CI%20Build)](https://ligstd.visualstudio.com/Apple%20PTP%20Trackpad/_build/latest?definitionId=41) 5 | 6 | This Synaptics Touch (KMDF) driver is modified from the deleted one in Windows Driver Samples. 7 | 8 | It demonstrates how to write a HID miniport driver for the Synaptics 3400 touch controller. 9 | 10 | -------------------------------------------------------------------------------- /include/queue.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | queue.h 8 | 9 | Abstract: 10 | 11 | Contains WDF queue related function declarations 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #pragma once 22 | 23 | EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OnDeviceControl; 24 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL OnInternalDeviceControl; 25 | -------------------------------------------------------------------------------- /include/driver.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | driver.h 8 | 9 | Abstract: 10 | 11 | Contains WDF driver-specific function declarations 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #pragma once 22 | 23 | 24 | DRIVER_INITIALIZE DriverEntry; 25 | 26 | EVT_WDF_DEVICE_CONTEXT_CLEANUP OnContextCleanup; 27 | 28 | EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; 29 | -------------------------------------------------------------------------------- /include/device.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | device.h 8 | 9 | Abstract: 10 | 11 | Declarations of WDF device specific entry points 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #pragma once 22 | 23 | 24 | EVT_WDF_DEVICE_D0_ENTRY OnD0Entry; 25 | 26 | EVT_WDF_DEVICE_D0_EXIT OnD0Exit; 27 | 28 | EVT_WDF_INTERRUPT_ISR OnInterruptIsr; 29 | 30 | EVT_WDF_DEVICE_PREPARE_HARDWARE OnPrepareHardware; 31 | 32 | EVT_WDF_DEVICE_RELEASE_HARDWARE OnReleaseHardware; -------------------------------------------------------------------------------- /src/hweight.c: -------------------------------------------------------------------------------- 1 | /* HWeight Linux Port */ 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | unsigned int hweight32(unsigned int w) 8 | { 9 | unsigned int res = w - ((w >> 1) & 0x55555555); 10 | res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 11 | res = (res + (res >> 4)) & 0x0F0F0F0F; 12 | res = res + (res >> 8); 13 | return (res + (res >> 16)) & 0x000000FF; 14 | } 15 | 16 | ULONGLONG hweight64(ULONGLONG w) 17 | { 18 | #if ARM || X86 19 | return hweight32((unsigned int)(w >> 32)) + 20 | hweight32((unsigned int)w); 21 | #else 22 | ULONGLONG res = w - ((w >> 1) & 0x5555555555555555ul); 23 | res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); 24 | res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; 25 | res = res + (res >> 8); 26 | res = res + (res >> 16); 27 | return (res + (res >> 32)) & 0x00000000000000FFul; 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /include/idle.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | idle.c 8 | 9 | Abstract: 10 | 11 | This file contains the declarations for Power Idle specific callbacks 12 | and function declarations 13 | 14 | Environment: 15 | 16 | Kernel mode 17 | 18 | Revision History: 19 | 20 | --*/ 21 | 22 | #pragma once 23 | 24 | 25 | // 26 | // Power Idle Workitem context 27 | // 28 | typedef struct _IDLE_WORKITEM_CONTEXT 29 | { 30 | // Handle to a WDF device object 31 | WDFDEVICE FxDevice; 32 | 33 | // Handle to a WDF request object 34 | WDFREQUEST FxRequest; 35 | 36 | } IDLE_WORKITEM_CONTEXT, *PIDLE_WORKITEM_CONTEXT; 37 | 38 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(IDLE_WORKITEM_CONTEXT, GetWorkItemContext) 39 | 40 | NTSTATUS 41 | TchProcessIdleRequest( 42 | IN WDFDEVICE Device, 43 | IN WDFREQUEST Request, 44 | OUT BOOLEAN *Pending 45 | ); 46 | 47 | VOID 48 | TchCompleteIdleIrp( 49 | IN PDEVICE_EXTENSION FxDeviceContext 50 | ); 51 | 52 | EVT_WDF_WORKITEM TchIdleIrpWorkitem; 53 | 54 | 55 | -------------------------------------------------------------------------------- /include/spb.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | spb.h 8 | 9 | Abstract: 10 | 11 | This module contains the touch driver I2C helper definitions. 12 | 13 | Environment: 14 | 15 | Kernel Mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | 26 | #define DEFAULT_SPB_BUFFER_SIZE 64 27 | 28 | // 29 | // SPB (I2C) context 30 | // 31 | 32 | typedef struct _SPB_CONTEXT 33 | { 34 | WDFIOTARGET SpbIoTarget; 35 | LARGE_INTEGER I2cResHubId; 36 | WDFMEMORY WriteMemory; 37 | WDFMEMORY ReadMemory; 38 | WDFWAITLOCK SpbLock; 39 | } SPB_CONTEXT; 40 | 41 | NTSTATUS 42 | SpbReadDataSynchronously( 43 | _In_ SPB_CONTEXT *SpbContext, 44 | _In_ UCHAR Address, 45 | _In_reads_bytes_(Length) PVOID Data, 46 | _In_ ULONG Length 47 | ); 48 | 49 | VOID 50 | SpbTargetDeinitialize( 51 | IN WDFDEVICE FxDevice, 52 | IN SPB_CONTEXT *SpbContext 53 | ); 54 | 55 | NTSTATUS 56 | SpbTargetInitialize( 57 | IN WDFDEVICE FxDevice, 58 | IN SPB_CONTEXT *SpbContext 59 | ); 60 | 61 | NTSTATUS 62 | SpbWriteDataSynchronously( 63 | IN SPB_CONTEXT *SpbContext, 64 | IN UCHAR Address, 65 | IN PVOID Data, 66 | IN ULONG Length 67 | ); 68 | -------------------------------------------------------------------------------- /include/bitops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "compat.h" 3 | 4 | #ifndef __BITOPS_H__ 5 | #define __BITOPS_H__ 6 | 7 | #ifndef __SIZEOF_LONG__ 8 | #define __SIZEOF_LONG__ sizeof(long) 9 | #endif 10 | 11 | #ifndef __WORDSIZE 12 | #define __WORDSIZE (__SIZEOF_LONG__ * 8) 13 | #endif 14 | 15 | #ifndef BITS_PER_LONG 16 | # define BITS_PER_LONG __WORDSIZE 17 | #endif 18 | #define BITS_PER_BYTE 8 19 | 20 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 21 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 22 | 23 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) 24 | 25 | #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) 26 | #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) 27 | 28 | #define __round_mask_ul(x, y) ((unsigned long) ((y)-1)) 29 | #define round_down_ul(x, y) ((x) & ~__round_mask_ul(x, y)) 30 | 31 | #define BIT(nr) (1UL << (nr)) 32 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) 33 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) 34 | #define BITS_TO_TYPE(nr, t) (((nr)+(t)-1)/(t)) 35 | 36 | void bitmap_set(unsigned long *map, unsigned int start, int len); 37 | int bitmap_weight(const unsigned long *bitmap, unsigned int bits); 38 | unsigned long find_first_bit(const unsigned long *addr, unsigned long size); 39 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/internal.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #pragma once 5 | 6 | #include "controller.h" 7 | 8 | // 9 | // Device context 10 | // 11 | 12 | typedef struct _DEVICE_EXTENSION 13 | { 14 | // 15 | // HID Touch input mode (touch vs. mouse) 16 | // 17 | UCHAR InputMode; 18 | 19 | // 20 | // Device related 21 | // 22 | WDFDEVICE FxDevice; 23 | WDFQUEUE DefaultQueue; 24 | WDFQUEUE PingPongQueue; 25 | 26 | // 27 | // Interrupt servicing 28 | // 29 | WDFINTERRUPT InterruptObject; 30 | BOOLEAN ServiceInterruptsAfterD0Entry; 31 | 32 | // 33 | // Spb (I2C) related members used for the lifetime of the device 34 | // 35 | SPB_CONTEXT I2CContext; 36 | 37 | // 38 | // Test related 39 | // 40 | WDFQUEUE TestQueue; 41 | volatile LONG TestSessionRefCnt; 42 | BOOLEAN DiagnosticMode; 43 | 44 | // 45 | // Power related 46 | // 47 | WDFQUEUE IdleQueue; 48 | 49 | // 50 | // Touch related members used for the lifetime of the device 51 | // 52 | VOID *TouchContext; 53 | 54 | // 55 | // PTP New 56 | // 57 | BOOLEAN PtpInputOn; 58 | BOOLEAN PtpReportButton; 59 | BOOLEAN PtpReportTouch; 60 | } DEVICE_EXTENSION, *PDEVICE_EXTENSION; 61 | 62 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, GetDeviceContext) 63 | -------------------------------------------------------------------------------- /include/HidCommon.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #pragma once 5 | 6 | #ifndef __HID_COMMON_H__ 7 | #define __HID_COMMON_H__ 8 | 9 | #define PTP_MAX_CONTACT_POINTS 10 10 | #define PTP_BUTTON_TYPE_CLICK_PAD 0 11 | #define PTP_BUTTON_TYPE_PRESSURE_PAD 1 12 | 13 | #define PTP_COLLECTION_MOUSE 0 14 | #define PTP_COLLECTION_WINDOWS 3 15 | 16 | #define PTP_CONTACT_CONFIDENCE_BIT 1 17 | #define PTP_CONTACT_TIPSWITCH_BIT 2 18 | 19 | #define REPORTID_STANDARDMOUSE 0x02 20 | #define REPORTID_MULTITOUCH 0x05 21 | #define REPORTID_REPORTMODE 0x04 22 | #define REPORTID_PTPHQA 0x08 23 | #define REPORTID_FUNCSWITCH 0x06 24 | #define REPORTID_DEVICE_CAPS 0x07 25 | #define REPORTID_UMAPP_CONF 0x09 26 | 27 | #define BUTTON_SWITCH 0x57 28 | #define SURFACE_SWITCH 0x58 29 | 30 | #define USAGE_PAGE 0x05 31 | #define USAGE_PAGE_1 0x06 32 | #define USAGE 0x09 33 | #define USAGE_MINIMUM 0x19 34 | #define USAGE_MAXIMUM 0x29 35 | #define LOGICAL_MINIMUM 0x15 36 | #define LOGICAL_MAXIMUM 0x25 37 | #define LOGICAL_MAXIMUM_2 0x26 38 | #define LOGICAL_MAXIMUM_3 0x27 39 | #define PHYSICAL_MINIMUM 0x35 40 | #define PHYSICAL_MAXIMUM 0x45 41 | #define PHYSICAL_MAXIMUM_2 0x46 42 | #define PHYSICAL_MAXIMUM_3 0x47 43 | #define UNIT_EXPONENT 0x55 44 | #define UNIT 0x65 45 | #define UNIT_2 0x66 46 | 47 | #define REPORT_ID 0x85 48 | #define REPORT_COUNT 0x95 49 | #define REPORT_COUNT_2 0x96 50 | #define REPORT_SIZE 0x75 51 | #define INPUT 0x81 52 | #define FEATURE 0xb1 53 | 54 | #define BEGIN_COLLECTION 0xa1 55 | #define END_COLLECTION 0xc0 56 | 57 | #define REPORT_BUFFER_SIZE 1024 58 | #define DEVICE_VERSION 0x01 59 | #define MAX_FINGERS 16 60 | 61 | #endif -------------------------------------------------------------------------------- /include/resolutions.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | resolutions.h 8 | 9 | Abstract: 10 | 11 | Contains resolution translation defines and types 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #pragma once 22 | 23 | #define TOUCH_SCREEN_PROPERTIES_REG_KEY L"\\Registry\\Machine\\System\\TOUCH\\SCREENPROPERTIES" 24 | #define TOUCH_DEFAULT_RESOLUTION_X 1440 25 | #define TOUCH_DEFAULT_RESOLUTION_Y 2560 26 | #define TOUCH_DEVICE_RESOLUTION_X 1440 27 | #define TOUCH_DEVICE_RESOLUTION_Y 2560 28 | 29 | typedef struct _TOUCH_SCREEN_PROPERTIES 30 | { 31 | ULONG TouchSwapAxes; 32 | ULONG TouchInvertXAxis; 33 | ULONG TouchInvertYAxis; 34 | ULONG TouchPhysicalWidth; 35 | ULONG TouchPhysicalHeight; 36 | ULONG TouchPhysicalButtonHeight; 37 | ULONG TouchPillarBoxWidthLeft; 38 | ULONG TouchPillarBoxWidthRight; 39 | ULONG TouchLetterBoxHeightTop; 40 | ULONG TouchLetterBoxHeightBottom; 41 | ULONG TouchAdjustedWidth; 42 | ULONG TouchAdjustedHeight; 43 | ULONG DisplayPhysicalWidth; 44 | ULONG DisplayPhysicalHeight; 45 | ULONG DisplayAdjustedButtonHeight; 46 | ULONG DisplayPillarBoxWidthLeft; 47 | ULONG DisplayPillarBoxWidthRight; 48 | ULONG DisplayLetterBoxHeightTop; 49 | ULONG DisplayLetterBoxHeightBottom; 50 | ULONG DisplayAdjustedWidth; 51 | ULONG DisplayAdjustedHeight; 52 | ULONG DisplayViewableWidth; 53 | ULONG DisplayViewableHeight; 54 | } TOUCH_SCREEN_PROPERTIES, *PTOUCH_SCREEN_PROPERTIES; 55 | 56 | VOID 57 | TchGetScreenProperties( 58 | IN PTOUCH_SCREEN_PROPERTIES Props 59 | ); 60 | 61 | VOID 62 | TchTranslateToDisplayCoordinates( 63 | IN PUSHORT X, 64 | IN PUSHORT Y, 65 | IN PTOUCH_SCREEN_PROPERTIES Props 66 | ); 67 | -------------------------------------------------------------------------------- /include/trace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #pragma once 5 | 6 | // 7 | // Control GUID: 8 | // {64BAF936-E94C-4747-91E3-BB4CB8328E5F} 9 | // 10 | 11 | #define WPP_CONTROL_GUIDS \ 12 | WPP_DEFINE_CONTROL_GUID( \ 13 | TouchDriverTraceGuid, (64BAF936,E94C,4747,91E3,BB4CB8328E5F), \ 14 | \ 15 | WPP_DEFINE_BIT(TRACE_INIT) \ 16 | WPP_DEFINE_BIT(TRACE_REGISTRY) \ 17 | WPP_DEFINE_BIT(TRACE_HID) \ 18 | WPP_DEFINE_BIT(TRACE_PNP) \ 19 | WPP_DEFINE_BIT(TRACE_POWER) \ 20 | WPP_DEFINE_BIT(TRACE_SPB) \ 21 | WPP_DEFINE_BIT(TRACE_CONFIG) \ 22 | WPP_DEFINE_BIT(TRACE_REPORTING) \ 23 | WPP_DEFINE_BIT(TRACE_INTERRUPT) \ 24 | WPP_DEFINE_BIT(TRACE_SAMPLES) \ 25 | WPP_DEFINE_BIT(TRACE_OTHER) \ 26 | WPP_DEFINE_BIT(TRACE_IDLE) \ 27 | WPP_DEFINE_BIT(TRACE_DRIVER) \ 28 | ) 29 | 30 | #define WPP_FLAG_LEVEL_LOGGER(flag, level) \ 31 | WPP_LEVEL_LOGGER(flag) 32 | 33 | #define WPP_FLAG_LEVEL_ENABLED(flag, level) \ 34 | (WPP_LEVEL_ENABLED(flag) && \ 35 | WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) 36 | 37 | #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ 38 | WPP_LEVEL_LOGGER(flags) 39 | 40 | #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ 41 | (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) 42 | 43 | // 44 | // WPP orders static parameters before dynamic parameters. To support the Trace function 45 | // defined below which sets FLAGS=MYDRIVER_ALL_INFO, a custom macro must be defined to 46 | // reorder the arguments to what the .tpl configuration file expects. 47 | // 48 | #define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags) 49 | #define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags) 50 | 51 | // 52 | // This comment block is scanned by the trace preprocessor to define our 53 | // Trace function. 54 | // 55 | // begin_wpp config 56 | // FUNC Trace(LEVEL, FLAGS, MSG, ...); 57 | // end_wpp 58 | // 59 | -------------------------------------------------------------------------------- /include/controller.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #define RESHUB_USE_HELPER_ROUTINES 10 | #include 11 | #include "trace.h" 12 | #include "spb.h" 13 | 14 | // 15 | // Memory tags 16 | // 17 | #define TOUCH_POOL_TAG (ULONG)'cuoT' 18 | #define TOUCH_POOL_TAG_F12 (ULONG)'21oT' 19 | 20 | // 21 | // Constants 22 | // 23 | #define MODE_MULTI_TOUCH 0x02 24 | #define MAX_TOUCH_COORD 0x0FFF 25 | #define FINGER_STATUS 0x01 // finger down 26 | 27 | // 28 | // Types for PTP 29 | // 30 | #pragma pack(push) 31 | #pragma pack(1) 32 | typedef struct _PTP_CONTACT { 33 | UCHAR Confidence : 1; 34 | UCHAR TipSwitch : 1; 35 | UCHAR ContactID : 3; 36 | UCHAR Padding : 3; 37 | USHORT X; 38 | USHORT Y; 39 | } PTP_CONTACT, *PPTP_CONTACT; 40 | #pragma pack(pop) 41 | 42 | enum CONTACT_STATE { 43 | CONTACT_NEW = 0, 44 | CONTACT_CONTINUED = 1, 45 | CONTACT_CONFIDENCE_CANCELLED = 2, 46 | CONTACT_INVALID = 3 47 | }; 48 | 49 | typedef struct _PTP_REPORT { 50 | UCHAR ReportID; 51 | PTP_CONTACT Contacts[5]; 52 | USHORT ScanTime; 53 | UCHAR ContactCount; 54 | UCHAR IsButtonClicked; 55 | } PTP_REPORT, *PPTP_REPORT; 56 | 57 | NTSTATUS 58 | TchAllocateContext( 59 | OUT VOID **ControllerContext, 60 | IN WDFDEVICE FxDevice 61 | ); 62 | 63 | NTSTATUS 64 | TchFreeContext( 65 | IN VOID *ControllerContext 66 | ); 67 | 68 | NTSTATUS 69 | TchStartDevice( 70 | IN VOID *ControllerContext, 71 | IN SPB_CONTEXT *SpbContext 72 | ); 73 | 74 | NTSTATUS 75 | TchStopDevice( 76 | IN VOID *ControllerContext, 77 | IN SPB_CONTEXT *SpbContext 78 | ); 79 | 80 | NTSTATUS 81 | TchStandbyDevice( 82 | IN VOID *ControllerContext, 83 | IN SPB_CONTEXT *SpbContext 84 | ); 85 | 86 | NTSTATUS 87 | TchWakeDevice( 88 | IN VOID *ControllerContext, 89 | IN SPB_CONTEXT *SpbContext 90 | ); 91 | 92 | NTSTATUS 93 | TchRegistryGetControllerSettings( 94 | IN VOID *ControllerContext, 95 | IN WDFDEVICE FxDevice 96 | ); 97 | 98 | NTSTATUS 99 | TchServiceInterrupts( 100 | IN VOID *ControllerContext, 101 | IN SPB_CONTEXT *SpbContext, 102 | IN PPTP_REPORT HidReport, 103 | IN UCHAR InputMode, 104 | OUT BOOLEAN *ServicingComplete 105 | ); 106 | 107 | -------------------------------------------------------------------------------- /contrib/SynapticsTouch.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2024 5 | MinimumVisualStudioVersion = 12.0 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SynapticsTouch", "SynapticsTouch.vcxproj", "{1E12CAAD-D041-4C21-B673-6FF831FC3D70}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|Win32 = Release|Win32 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|ARM.Build.0 = Debug|ARM 22 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|ARM.Deploy.0 = Debug|ARM 23 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|Win32.Build.0 = Debug|Win32 28 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|x64.ActiveCfg = Debug|x64 29 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Debug|x64.Build.0 = Debug|x64 30 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|ARM.ActiveCfg = Release|ARM 31 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|ARM.Build.0 = Release|ARM 32 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|ARM.Deploy.0 = Release|ARM 33 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|ARM64.ActiveCfg = Release|ARM64 34 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|ARM64.Build.0 = Release|ARM64 35 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|ARM64.Deploy.0 = Release|ARM64 36 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|Win32.ActiveCfg = Release|Win32 37 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|Win32.Build.0 = Release|Win32 38 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|x64.ActiveCfg = Release|x64 39 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70}.Release|x64.Build.0 = Release|x64 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | GlobalSection(ExtensibilityGlobals) = postSolution 45 | SolutionGuid = {740AA028-CDAA-4AC0-95C6-3561ECF2000A} 46 | EndGlobalSection 47 | EndGlobal 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/bitops.c: -------------------------------------------------------------------------------- 1 | /* BitOps Linux Port */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void bitmap_set(unsigned long *map, unsigned int start, int len) 8 | { 9 | unsigned long *p = map + BIT_WORD(start); 10 | const unsigned int size = start + len; 11 | int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); 12 | unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); 13 | 14 | while (len - bits_to_set >= 0) 15 | { 16 | *p |= mask_to_set; 17 | len -= bits_to_set; 18 | bits_to_set = BITS_PER_LONG; 19 | mask_to_set = ~0UL; 20 | p++; 21 | } 22 | 23 | if (len) 24 | { 25 | mask_to_set &= BITMAP_LAST_WORD_MASK(size); 26 | *p |= mask_to_set; 27 | } 28 | } 29 | 30 | int bitmap_weight(const unsigned long *bitmap, unsigned int bits) 31 | { 32 | unsigned int k, lim = bits / BITS_PER_LONG; 33 | int w = 0; 34 | 35 | for (k = 0; k < lim; k++) 36 | w += hweight_long(bitmap[k]); 37 | 38 | if (bits % BITS_PER_LONG) 39 | w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); 40 | 41 | return w; 42 | } 43 | 44 | static inline unsigned long __ffs(unsigned long word) 45 | { 46 | int num = 0; 47 | 48 | #if defined(ARM64) || defined(AMD64) 49 | if ((word & 0xffffffff) == 0) { 50 | num += 32; 51 | word >>= 32; 52 | } 53 | #endif 54 | if ((word & 0xffff) == 0) { 55 | num += 16; 56 | word >>= 16; 57 | } 58 | if ((word & 0xff) == 0) { 59 | num += 8; 60 | word >>= 8; 61 | } 62 | if ((word & 0xf) == 0) { 63 | num += 4; 64 | word >>= 4; 65 | } 66 | if ((word & 0x3) == 0) { 67 | num += 2; 68 | word >>= 2; 69 | } 70 | if ((word & 0x1) == 0) 71 | num += 1; 72 | return num; 73 | } 74 | 75 | unsigned long find_first_bit(const unsigned long *addr, unsigned long size) 76 | { 77 | unsigned long idx; 78 | 79 | for (idx = 0; idx * BITS_PER_LONG < size; idx++) { 80 | if (addr[idx]) 81 | return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); 82 | } 83 | 84 | return size; 85 | } 86 | 87 | /* 88 | * This is a common helper function for find_next_bit, find_next_zero_bit, and 89 | * find_next_and_bit. The differences are: 90 | * - The "invert" argument, which is XORed with each fetched word before 91 | * searching it for one bits. 92 | * - The optional "addr2", which is anded with "addr1" if present. 93 | */ 94 | static inline unsigned long _find_next_bit(const unsigned long *addr1, 95 | const unsigned long *addr2, unsigned long nbits, 96 | unsigned long start, unsigned long invert) 97 | { 98 | unsigned long tmp; 99 | 100 | if (start >= nbits) return nbits; 101 | 102 | tmp = addr1[start / BITS_PER_LONG]; 103 | if (addr2) 104 | tmp &= addr2[start / BITS_PER_LONG]; 105 | tmp ^= invert; 106 | 107 | /* Handle 1st word. */ 108 | tmp &= BITMAP_FIRST_WORD_MASK(start); 109 | start = round_down_ul(start, BITS_PER_LONG); 110 | 111 | while (!tmp) { 112 | start += BITS_PER_LONG; 113 | if (start >= nbits) 114 | return nbits; 115 | 116 | tmp = addr1[start / BITS_PER_LONG]; 117 | if (addr2) 118 | tmp &= addr2[start / BITS_PER_LONG]; 119 | tmp ^= invert; 120 | } 121 | 122 | return min(start + __ffs(tmp), nbits); 123 | } 124 | 125 | unsigned long find_next_bit(const unsigned long *addr, unsigned long size, 126 | unsigned long offset) 127 | { 128 | return _find_next_bit(addr, NULL, size, offset, 0UL); 129 | } 130 | -------------------------------------------------------------------------------- /contrib/SynapticsTouch.vcxproj.Filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {f2fa0c72-647d-400d-b18f-95a63aa5eeca} 6 | 7 | 8 | {5ba863f3-b147-473e-90cd-c58282854fbe} 9 | 10 | 11 | {22e35757-3564-41d1-919f-a3331bc1b341} 12 | 13 | 14 | {25cea26e-6fe9-489d-9f3f-494d76c39c07} 15 | 16 | 17 | {fb139949-95da-4a79-9f64-ff14ea801e7b} 18 | 19 | 20 | {9686f0d4-e35c-4f82-a1bb-f9e1b58bf934} 21 | 22 | 23 | 24 | 25 | Source Files\Cross Platform Shim 26 | 27 | 28 | Source Files\Cross Platform Shim 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | 65 | 66 | Resources 67 | 68 | 69 | 70 | 71 | Driver Files 72 | 73 | 74 | 75 | 76 | Header Files 77 | 78 | 79 | Header Files 80 | 81 | 82 | Header Files 83 | 84 | 85 | Header Files 86 | 87 | 88 | Header Files 89 | 90 | 91 | Header Files 92 | 93 | 94 | Header Files 95 | 96 | 97 | Header Files 98 | 99 | 100 | Header Files 101 | 102 | 103 | Header Files 104 | 105 | 106 | Header Files 107 | 108 | 109 | Header Files 110 | 111 | 112 | Header Files\Cross Platform Shim 113 | 114 | 115 | Header Files\Cross Platform Shim 116 | 117 | 118 | Header Files\Cross Platform Shim 119 | 120 | 121 | Header Files 122 | 123 | 124 | -------------------------------------------------------------------------------- /contrib/SynapticsTouch.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {f2fa0c72-647d-400d-b18f-95a63aa5eeca} 6 | 7 | 8 | {5ba863f3-b147-473e-90cd-c58282854fbe} 9 | 10 | 11 | {22e35757-3564-41d1-919f-a3331bc1b341} 12 | 13 | 14 | {25cea26e-6fe9-489d-9f3f-494d76c39c07} 15 | 16 | 17 | {fb139949-95da-4a79-9f64-ff14ea801e7b} 18 | 19 | 20 | {9686f0d4-e35c-4f82-a1bb-f9e1b58bf934} 21 | 22 | 23 | 24 | 25 | Source Files\Cross Platform Shim 26 | 27 | 28 | Source Files\Cross Platform Shim 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | 65 | 66 | Resources 67 | 68 | 69 | 70 | 71 | Driver Files 72 | 73 | 74 | 75 | 76 | Header Files 77 | 78 | 79 | Header Files 80 | 81 | 82 | Header Files 83 | 84 | 85 | Header Files 86 | 87 | 88 | Header Files 89 | 90 | 91 | Header Files 92 | 93 | 94 | Header Files 95 | 96 | 97 | Header Files 98 | 99 | 100 | Header Files 101 | 102 | 103 | Header Files 104 | 105 | 106 | Header Files 107 | 108 | 109 | Header Files 110 | 111 | 112 | Header Files\Cross Platform Shim 113 | 114 | 115 | Header Files\Cross Platform Shim 116 | 117 | 118 | Header Files\Cross Platform Shim 119 | 120 | 121 | Header Files 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | queue.c 8 | 9 | Abstract: 10 | 11 | Contains WDF queue related code, namely the top-level queue 12 | handler for all device IOCTL requests. 13 | 14 | Environment: 15 | 16 | Kernel mode 17 | 18 | Revision History: 19 | 20 | --*/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | VOID 31 | OnDeviceControl( 32 | _In_ WDFQUEUE Queue, 33 | _In_ WDFREQUEST Request, 34 | _In_ size_t OutputBufferLength, 35 | _In_ size_t InputBufferLength, 36 | _In_ ULONG IoControlCode 37 | ) 38 | { 39 | OnInternalDeviceControl(Queue, Request, OutputBufferLength, InputBufferLength, IoControlCode); 40 | } 41 | 42 | VOID 43 | OnInternalDeviceControl( 44 | IN WDFQUEUE Queue, 45 | IN WDFREQUEST Request, 46 | IN size_t OutputBufferLength, 47 | IN size_t InputBufferLength, 48 | IN ULONG IoControlCode 49 | ) 50 | /*++ 51 | 52 | Routine Description: 53 | 54 | This event is called when the framework receives 55 | IRP_MJ_INTERNAL DEVICE_CONTROL requests from the system. 56 | 57 | Arguments: 58 | 59 | Queue - Handle to the framework queue object that is associated 60 | with the I/O request. 61 | 62 | Request - Handle to a framework request object. 63 | 64 | OutputBufferLength - length of the request's output buffer, 65 | if an output buffer is available. 66 | 67 | InputBufferLength - length of the request's input buffer, 68 | if an input buffer is available. 69 | 70 | IoControlCode - the driver-defined or system-defined I/O control code 71 | (IOCTL) that is associated with the request. 72 | 73 | Return Value: 74 | 75 | None, status is indicated when completing the request 76 | 77 | --*/ 78 | { 79 | NTSTATUS status; 80 | PDEVICE_EXTENSION devContext; 81 | WDFDEVICE device; 82 | BOOLEAN requestPending; 83 | 84 | UNREFERENCED_PARAMETER(OutputBufferLength); 85 | UNREFERENCED_PARAMETER(InputBufferLength); 86 | 87 | device = WdfIoQueueGetDevice(Queue); 88 | devContext = GetDeviceContext(device); 89 | requestPending = FALSE; 90 | 91 | // 92 | // Please note that HIDCLASS provides the buffer in the Irp->UserBuffer 93 | // field irrespective of the ioctl buffer type. However, framework is very 94 | // strict about type checking. You cannot get Irp->UserBuffer by using 95 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 96 | // internal ioctl. So depending on the ioctl code, we will either 97 | // use retreive function or escape to WDM to get the UserBuffer. 98 | // 99 | 100 | switch(IoControlCode) { 101 | 102 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 103 | // 104 | // Retrieves master HID descriptor 105 | // 106 | status = TchGetHidDescriptor(device, Request); 107 | break; 108 | 109 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 110 | // 111 | // Retrieves device attributes in a HID_DEVICE_ATTRIBUTES structure 112 | // 113 | status = TchGetDeviceAttributes(Request); 114 | break; 115 | 116 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 117 | // 118 | // Obtains the report descriptor for the HID device 119 | // 120 | status = TchGetReportDescriptor(device, Request); 121 | break; 122 | 123 | case IOCTL_HID_GET_STRING: 124 | // 125 | // Obtains strings associated with the HID device 126 | // 127 | status = TchGetString(device, Request); 128 | break; 129 | 130 | case IOCTL_HID_READ_REPORT: 131 | // 132 | // Dangling read requests for passing up touch data 133 | // 134 | status = TchReadReport(device, Request, &requestPending); 135 | break; 136 | 137 | case IOCTL_HID_SET_FEATURE: 138 | // 139 | // This sends a HID class feature report to a top-level collection of 140 | // a HID class device. 141 | // 142 | status = TchSetFeatureReport(device, Request); 143 | break; 144 | 145 | case IOCTL_HID_GET_FEATURE: 146 | // 147 | // Returns a feature report associated with a top-level collection 148 | // 149 | status = TchGetFeatureReport(device, Request); 150 | break; 151 | 152 | case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: 153 | // 154 | // Hidclass sends this IOCTL to notify miniports that it wants 155 | // them to go into idle 156 | // 157 | status = TchProcessIdleRequest(device, Request, &requestPending); 158 | break; 159 | 160 | case IOCTL_HID_WRITE_REPORT: 161 | // 162 | // Transmits a class driver-supplied report to the device. 163 | // 164 | case IOCTL_HID_ACTIVATE_DEVICE: 165 | // 166 | // Makes the device ready for I/O operations. 167 | // 168 | case IOCTL_HID_DEACTIVATE_DEVICE: 169 | // 170 | // Causes the device to cease operations and terminate all outstanding 171 | // I/O requests. 172 | // 173 | 174 | default: 175 | status = STATUS_NOT_SUPPORTED; 176 | break; 177 | } 178 | 179 | if (!requestPending) 180 | { 181 | WdfRequestComplete(Request, status); 182 | } 183 | 184 | return; 185 | } 186 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | .vscode/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | project.fragment.lock.json 47 | artifacts/ 48 | 49 | *_i.c 50 | *_p.c 51 | *_i.h 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.tmp_proj 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | *.pidb 71 | *.svclog 72 | *.scc 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # NCrunch 115 | _NCrunch_* 116 | .*crunch*.local.xml 117 | nCrunchTemp_* 118 | 119 | # MightyMoose 120 | *.mm.* 121 | AutoTest.Net/ 122 | 123 | # Web workbench (sass) 124 | .sass-cache/ 125 | 126 | # Installshield output folder 127 | [Ee]xpress/ 128 | 129 | # DocProject is a documentation generator add-in 130 | DocProject/buildhelp/ 131 | DocProject/Help/*.HxT 132 | DocProject/Help/*.HxC 133 | DocProject/Help/*.hhc 134 | DocProject/Help/*.hhk 135 | DocProject/Help/*.hhp 136 | DocProject/Help/Html2 137 | DocProject/Help/html 138 | 139 | # Click-Once directory 140 | publish/ 141 | 142 | # Publish Web Output 143 | *.[Pp]ublish.xml 144 | *.azurePubxml 145 | # TODO: Comment the next line if you want to checkin your web deploy settings 146 | # but database connection strings (with potential passwords) will be unencrypted 147 | #*.pubxml 148 | *.publishproj 149 | 150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 151 | # checkin your Azure Web App publish settings, but sensitive information contained 152 | # in these scripts will be unencrypted 153 | PublishScripts/ 154 | 155 | # NuGet Packages 156 | *.nupkg 157 | # The packages folder can be ignored because of Package Restore 158 | **/packages/* 159 | # except build/, which is used as an MSBuild target. 160 | !**/packages/build/ 161 | # Uncomment if necessary however generally it will be regenerated when needed 162 | #!**/packages/repositories.config 163 | # NuGet v3's project.json files produces more ignoreable files 164 | *.nuget.props 165 | *.nuget.targets 166 | 167 | # Microsoft Azure Build Output 168 | csx/ 169 | *.build.csdef 170 | 171 | # Microsoft Azure Emulator 172 | ecf/ 173 | rcf/ 174 | 175 | # Windows Store app package directories and files 176 | AppPackages/ 177 | BundleArtifacts/ 178 | Package.StoreAssociation.xml 179 | _pkginfo.txt 180 | 181 | # Visual Studio cache files 182 | # files ending in .cache can be ignored 183 | *.[Cc]ache 184 | # but keep track of directories ending in .cache 185 | !*.[Cc]ache/ 186 | 187 | # Others 188 | ClientBin/ 189 | ~$* 190 | *~ 191 | *.dbmdl 192 | *.dbproj.schemaview 193 | *.jfm 194 | *.pfx 195 | *.publishsettings 196 | node_modules/ 197 | orleans.codegen.cs 198 | 199 | # Since there are multiple workflows, uncomment next line to ignore bower_components 200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 201 | #bower_components/ 202 | 203 | # RIA/Silverlight projects 204 | Generated_Code/ 205 | 206 | # Backup & report files from converting an old project file 207 | # to a newer Visual Studio version. Backup files are not needed, 208 | # because we have git ;-) 209 | _UpgradeReport_Files/ 210 | Backup*/ 211 | UpgradeLog*.XML 212 | UpgradeLog*.htm 213 | 214 | # SQL Server files 215 | *.mdf 216 | *.ldf 217 | 218 | # Business Intelligence projects 219 | *.rdl.data 220 | *.bim.layout 221 | *.bim_*.settings 222 | 223 | # Microsoft Fakes 224 | FakesAssemblies/ 225 | 226 | # GhostDoc plugin setting file 227 | *.GhostDoc.xml 228 | 229 | # Node.js Tools for Visual Studio 230 | .ntvs_analysis.dat 231 | 232 | # Visual Studio 6 build log 233 | *.plg 234 | 235 | # Visual Studio 6 workspace options file 236 | *.opt 237 | 238 | # Visual Studio LightSwitch build output 239 | **/*.HTMLClient/GeneratedArtifacts 240 | **/*.DesktopClient/GeneratedArtifacts 241 | **/*.DesktopClient/ModelManifest.xml 242 | **/*.Server/GeneratedArtifacts 243 | **/*.Server/ModelManifest.xml 244 | _Pvt_Extensions 245 | 246 | # Paket dependency manager 247 | .paket/paket.exe 248 | paket-files/ 249 | 250 | # FAKE - F# Make 251 | .fake/ 252 | 253 | # JetBrains Rider 254 | .idea/ 255 | *.sln.iml 256 | 257 | # CodeRush 258 | .cr/ 259 | 260 | # Python Tools for Visual Studio (PTVS) 261 | __pycache__/ 262 | *.pyc 263 | RCa* 264 | -------------------------------------------------------------------------------- /src/power.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | power.c 8 | 9 | Abstract: 10 | 11 | Contains Synaptics power-on and power-off functionality 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | NTSTATUS 28 | RmiChangeSleepState( 29 | IN RMI4_CONTROLLER_CONTEXT* ControllerContext, 30 | IN SPB_CONTEXT *SpbContext, 31 | IN UCHAR SleepState 32 | ) 33 | /*++ 34 | 35 | Routine Description: 36 | 37 | Changes the SleepMode bits on the controller as specified 38 | 39 | Arguments: 40 | 41 | ControllerContext - Touch controller context 42 | 43 | SpbContext - A pointer to the current i2c context 44 | 45 | SleepState - Either RMI4_F11_DEVICE_CONTROL_SLEEP_MODE_OPERATING 46 | or RMI4_F11_DEVICE_CONTROL_SLEEP_MODE_SLEEPING 47 | 48 | Return Value: 49 | 50 | NTSTATUS indicating success or failure 51 | 52 | --*/ 53 | { 54 | RMI4_F01_CTRL_REGISTERS* controlF01; 55 | UCHAR deviceControl; 56 | int index; 57 | NTSTATUS status; 58 | 59 | controlF01 = (RMI4_F01_CTRL_REGISTERS*) &deviceControl; 60 | 61 | // 62 | // Find RMI device control function housing sleep settings 63 | // 64 | index = RmiGetFunctionIndex( 65 | ControllerContext->Descriptors, 66 | ControllerContext->FunctionCount, 67 | RMI4_F01_RMI_DEVICE_CONTROL); 68 | 69 | if (index == ControllerContext->FunctionCount) 70 | { 71 | Trace( 72 | TRACE_LEVEL_ERROR, 73 | TRACE_POWER, 74 | "Power change failure - RMI Function 01 missing"); 75 | 76 | status = STATUS_INVALID_DEVICE_STATE; 77 | goto exit; 78 | } 79 | 80 | status = RmiChangePage( 81 | ControllerContext, 82 | SpbContext, 83 | ControllerContext->FunctionOnPage[index]); 84 | 85 | if (!NT_SUCCESS(status)) 86 | { 87 | Trace( 88 | TRACE_LEVEL_ERROR, 89 | TRACE_POWER, 90 | "Could not change register page"); 91 | 92 | goto exit; 93 | } 94 | 95 | // 96 | // Read Device Control register 97 | // 98 | status = SpbReadDataSynchronously( 99 | SpbContext, 100 | ControllerContext->Descriptors[index].ControlBase, 101 | &deviceControl, 102 | sizeof(deviceControl) 103 | ); 104 | 105 | if (!NT_SUCCESS(status)) 106 | { 107 | Trace( 108 | TRACE_LEVEL_ERROR, 109 | TRACE_POWER, 110 | "Could not read sleep register - %!STATUS!", 111 | status); 112 | 113 | goto exit; 114 | } 115 | 116 | // 117 | // Assign new sleep state 118 | // 119 | controlF01->DeviceControl.SleepMode = SleepState; 120 | 121 | // 122 | // Write setting back to the controller 123 | // 124 | status = SpbWriteDataSynchronously( 125 | SpbContext, 126 | ControllerContext->Descriptors[index].ControlBase, 127 | &deviceControl, 128 | sizeof(deviceControl) 129 | ); 130 | 131 | if (!NT_SUCCESS(status)) 132 | { 133 | Trace( 134 | TRACE_LEVEL_ERROR, 135 | TRACE_POWER, 136 | "Could not write sleep register - %X", 137 | status); 138 | 139 | goto exit; 140 | } 141 | 142 | exit: 143 | 144 | return status; 145 | } 146 | 147 | NTSTATUS 148 | TchWakeDevice( 149 | IN VOID *ControllerContext, 150 | IN SPB_CONTEXT *SpbContext 151 | ) 152 | /*++ 153 | 154 | Routine Description: 155 | 156 | Enables multi-touch scanning 157 | 158 | Arguments: 159 | 160 | ControllerContext - Touch controller context 161 | 162 | SpbContext - A pointer to the current i2c context 163 | 164 | Return Value: 165 | 166 | NTSTATUS indicating success or failure 167 | 168 | --*/ 169 | { 170 | RMI4_CONTROLLER_CONTEXT* controller; 171 | NTSTATUS status; 172 | 173 | controller = (RMI4_CONTROLLER_CONTEXT*) ControllerContext; 174 | 175 | // 176 | // Check if we were already on 177 | // 178 | if (controller->DevicePowerState == PowerDeviceD0) 179 | { 180 | goto exit; 181 | } 182 | 183 | controller->DevicePowerState = PowerDeviceD0; 184 | 185 | // 186 | // Attempt to put the controller into operating mode 187 | // 188 | status = RmiChangeSleepState( 189 | controller, 190 | SpbContext, 191 | RMI4_F01_DEVICE_CONTROL_SLEEP_MODE_OPERATING); 192 | 193 | if (!NT_SUCCESS(status)) 194 | { 195 | Trace( 196 | TRACE_LEVEL_ERROR, 197 | TRACE_POWER, 198 | "Error waking touch controller - %!STATUS!", 199 | status); 200 | } 201 | 202 | exit: 203 | 204 | return STATUS_SUCCESS; 205 | } 206 | 207 | NTSTATUS 208 | TchStandbyDevice( 209 | IN VOID *ControllerContext, 210 | IN SPB_CONTEXT *SpbContext 211 | ) 212 | /*++ 213 | 214 | Routine Description: 215 | 216 | Disables multi-touch scanning to conserve power 217 | 218 | Arguments: 219 | 220 | ControllerContext - Touch controller context 221 | 222 | SpbContext - A pointer to the current i2c context 223 | 224 | Return Value: 225 | 226 | NTSTATUS indicating success or failure 227 | 228 | --*/ 229 | { 230 | RMI4_CONTROLLER_CONTEXT* controller; 231 | NTSTATUS status; 232 | 233 | controller = (RMI4_CONTROLLER_CONTEXT*) ControllerContext; 234 | 235 | // 236 | // Interrupts are now disabled but the ISR may still be 237 | // executing, so grab the controller lock to ensure ISR 238 | // is finished touching HW and controller state. 239 | // 240 | WdfWaitLockAcquire(controller->ControllerLock, NULL); 241 | 242 | // 243 | // Put the chip in sleep mode 244 | // 245 | status = RmiChangeSleepState( 246 | ControllerContext, 247 | SpbContext, 248 | RMI4_F01_DEVICE_CONTROL_SLEEP_MODE_SLEEPING); 249 | 250 | if (!NT_SUCCESS(status)) 251 | { 252 | Trace( 253 | TRACE_LEVEL_ERROR, 254 | TRACE_POWER, 255 | "Error sleeping touch controller - %!STATUS!", 256 | status); 257 | } 258 | 259 | controller->DevicePowerState = PowerDeviceD3; 260 | 261 | // 262 | // Invalidate state 263 | // 264 | controller->TouchesReported = 0; 265 | controller->TouchesTotal = 0; 266 | controller->Cache.FingerSlotValid = 0; 267 | controller->Cache.FingerSlotDirty = 0; 268 | controller->Cache.FingerDownCount = 0; 269 | 270 | WdfWaitLockRelease(controller->ControllerLock); 271 | 272 | return STATUS_SUCCESS; 273 | } -------------------------------------------------------------------------------- /src/driver.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | driver.c 8 | 9 | Abstract: 10 | 11 | Contains driver-specific WDF functions 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef ALLOC_PRAGMA 31 | #pragma alloc_text(PAGE, OnDeviceAdd) 32 | #pragma alloc_text(PAGE, OnContextCleanup) 33 | #endif 34 | 35 | NTSTATUS 36 | DriverEntry ( 37 | IN PDRIVER_OBJECT DriverObject, 38 | IN PUNICODE_STRING RegistryPath 39 | ) 40 | /*++ 41 | 42 | Routine Description: 43 | 44 | Installable driver initialization entry point. 45 | This entry point is called directly by the I/O system. 46 | 47 | Arguments: 48 | 49 | DriverObject - pointer to the driver object 50 | RegistryPath - pointer to a unicode string representing the path, 51 | to driver-specific key in the registry. 52 | 53 | Return Value: 54 | 55 | STATUS_SUCCESS if successful, error code otherwise. 56 | 57 | --*/ 58 | { 59 | WDF_OBJECT_ATTRIBUTES attributes; 60 | WDF_DRIVER_CONFIG config; 61 | NTSTATUS status; 62 | 63 | // 64 | // Initialize tracing via WPP 65 | // 66 | WPP_INIT_TRACING(DriverObject, RegistryPath); 67 | 68 | // 69 | // Create a framework driver object 70 | // 71 | WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); 72 | config.DriverPoolTag = TOUCH_POOL_TAG; 73 | 74 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 75 | attributes.EvtCleanupCallback = OnContextCleanup; 76 | 77 | status = WdfDriverCreate( 78 | DriverObject, 79 | RegistryPath, 80 | &attributes, 81 | &config, 82 | WDF_NO_HANDLE 83 | ); 84 | 85 | if (!NT_SUCCESS(status)) 86 | { 87 | Trace( 88 | TRACE_LEVEL_ERROR, 89 | TRACE_INIT, 90 | "Error creating WDF driver object - %!STATUS!", 91 | status); 92 | 93 | WPP_CLEANUP(DriverObject); 94 | 95 | goto exit; 96 | } 97 | 98 | exit: 99 | 100 | return status; 101 | } 102 | 103 | NTSTATUS 104 | OnDeviceAdd( 105 | IN WDFDRIVER Driver, 106 | IN PWDFDEVICE_INIT DeviceInit 107 | ) 108 | /*++ 109 | 110 | Routine Description: 111 | 112 | OnDeviceAdd is called by the framework in response to AddDevice 113 | call from the PnP manager when a device is found. We create and 114 | initialize a WDF device object to represent the new instance of 115 | an touch device. Per-device objects are also instantiated. 116 | 117 | Arguments: 118 | 119 | Driver - Handle to a framework driver object created in DriverEntry 120 | DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. 121 | 122 | Return Value: 123 | 124 | NTSTATUS indicating success or failure 125 | 126 | --*/ 127 | { 128 | WDF_OBJECT_ATTRIBUTES attributes; 129 | PDEVICE_EXTENSION devContext; 130 | WDFDEVICE fxDevice; 131 | WDF_INTERRUPT_CONFIG interruptConfig; 132 | WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; 133 | WDF_IO_QUEUE_CONFIG queueConfig; 134 | NTSTATUS status; 135 | 136 | UNREFERENCED_PARAMETER(Driver); 137 | PAGED_CODE(); 138 | 139 | // 140 | // Relinquish power policy ownership because HIDCLASS acts a power 141 | // policy owner for ther HID stack. 142 | // 143 | WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE); 144 | 145 | // 146 | // This driver handles D0 Entry and Exit to power on and off the 147 | // controller. It also handles prepare/release hardware so that it 148 | // can acquire and free SPB resources needed to communicate with the 149 | // touch controller. 150 | // 151 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); 152 | 153 | pnpPowerCallbacks.EvtDeviceD0Entry = OnD0Entry; 154 | pnpPowerCallbacks.EvtDeviceD0Exit = OnD0Exit; 155 | pnpPowerCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; 156 | pnpPowerCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; 157 | 158 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); 159 | 160 | // 161 | // Create a framework device object. This call will in turn create 162 | // a WDM device object, attach to the lower stack, and set the 163 | // appropriate flags and attributes. 164 | // 165 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION); 166 | 167 | status = WdfDeviceCreate(&DeviceInit, &attributes, &fxDevice); 168 | 169 | if (!NT_SUCCESS(status)) 170 | { 171 | Trace( 172 | TRACE_LEVEL_ERROR, 173 | TRACE_INIT, 174 | "WdfDeviceCreate failed - %!STATUS!", 175 | status); 176 | 177 | goto exit; 178 | } 179 | 180 | devContext = GetDeviceContext(fxDevice); 181 | devContext->FxDevice = fxDevice; 182 | devContext->InputMode = MODE_MULTI_TOUCH; 183 | 184 | // 185 | // Create a parallel dispatch queue to handle requests from HID Class 186 | // 187 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( 188 | &queueConfig, 189 | WdfIoQueueDispatchParallel); 190 | 191 | queueConfig.EvtIoInternalDeviceControl = OnInternalDeviceControl; 192 | queueConfig.EvtIoDeviceControl = OnDeviceControl; 193 | queueConfig.PowerManaged = WdfFalse; 194 | 195 | status = WdfIoQueueCreate( 196 | fxDevice, 197 | &queueConfig, 198 | WDF_NO_OBJECT_ATTRIBUTES, 199 | &devContext->DefaultQueue); 200 | 201 | if (!NT_SUCCESS (status)) 202 | { 203 | Trace( 204 | TRACE_LEVEL_ERROR, 205 | TRACE_INIT, 206 | "Error creating WDF default queue - %!STATUS!", 207 | status); 208 | 209 | goto exit; 210 | } 211 | 212 | // 213 | // Register a manual I/O queue for Read Requests. This queue will be used 214 | // for storing HID read requests until touch data is available to 215 | // complete them. 216 | // 217 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 218 | 219 | queueConfig.PowerManaged = WdfFalse; 220 | 221 | status = WdfIoQueueCreate( 222 | fxDevice, 223 | &queueConfig, 224 | WDF_NO_OBJECT_ATTRIBUTES, 225 | &devContext->PingPongQueue); 226 | 227 | if (!NT_SUCCESS(status)) 228 | { 229 | Trace( 230 | TRACE_LEVEL_ERROR, 231 | TRACE_INIT, 232 | "Error creating WDF read request queue - %!STATUS!", 233 | status); 234 | 235 | goto exit; 236 | } 237 | 238 | // 239 | // Register one last manual I/O queue for parking HIDClass's idle power 240 | // requests. This queue stores idle requests until they're cancelled, 241 | // and could be used to complete a wait/wake request. 242 | // 243 | 244 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 245 | 246 | queueConfig.PowerManaged = WdfFalse; 247 | 248 | status = WdfIoQueueCreate( 249 | fxDevice, 250 | &queueConfig, 251 | WDF_NO_OBJECT_ATTRIBUTES, 252 | &devContext->IdleQueue 253 | ); 254 | 255 | if (!NT_SUCCESS(status)) 256 | { 257 | Trace( 258 | TRACE_LEVEL_ERROR, 259 | TRACE_INIT, 260 | "Error creating WDF idle request queue - %!STATUS!", 261 | status); 262 | 263 | goto exit; 264 | } 265 | 266 | // 267 | // Create an interrupt object for hardware notifications 268 | // 269 | WDF_INTERRUPT_CONFIG_INIT( 270 | &interruptConfig, 271 | OnInterruptIsr, 272 | NULL); 273 | interruptConfig.PassiveHandling = TRUE; 274 | 275 | status = WdfInterruptCreate( 276 | fxDevice, 277 | &interruptConfig, 278 | WDF_NO_OBJECT_ATTRIBUTES, 279 | &devContext->InterruptObject); 280 | 281 | if (!NT_SUCCESS(status)) 282 | { 283 | Trace( 284 | TRACE_LEVEL_ERROR, 285 | TRACE_INIT, 286 | "Error creating WDF interrupt object - %!STATUS!", 287 | status); 288 | 289 | goto exit; 290 | } 291 | 292 | exit: 293 | 294 | return status; 295 | } 296 | 297 | VOID 298 | OnContextCleanup( 299 | IN WDFOBJECT Driver 300 | ) 301 | /*++ 302 | Routine Description: 303 | 304 | Free resources allocated in DriverEntry that are not automatically 305 | cleaned up framework. 306 | 307 | Arguments: 308 | 309 | Driver - handle to a WDF Driver object. 310 | 311 | Return Value: 312 | 313 | VOID. 314 | 315 | --*/ 316 | { 317 | PAGED_CODE(); 318 | 319 | WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver)); 320 | } 321 | -------------------------------------------------------------------------------- /src/idle.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | idle.c 8 | 9 | Abstract: 10 | 11 | This file contains the declarations for Power Idle specific callbacks 12 | and function definitions 13 | 14 | Environment: 15 | 16 | Kernel mode 17 | 18 | Revision History: 19 | 20 | --*/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | NTSTATUS 29 | TchProcessIdleRequest( 30 | IN WDFDEVICE Device, 31 | IN WDFREQUEST Request, 32 | OUT BOOLEAN *Pending 33 | ) 34 | /*++ 35 | 36 | Routine Description: 37 | 38 | Handles HIDClass's idle notification request. 39 | 40 | This request is provided to a HID miniport, and provides a callback 41 | routine typically used by HID miniports to self-manage power. 42 | 43 | The callback routine is invoked by the miniport to indicate that all 44 | peripherals are idle, and in response the HID class driver will: 45 | 1) Queue a wait/wake IRP to the device, and 46 | 2) Set the device to D3 47 | 48 | In the case of this touch miniport, we are using the HID class driver's 49 | enhanced power management functionality, whereby invoking the callback 50 | results in an immediate exit from D0, powering off touch. 51 | 52 | The Request will be completed when either HIDCLASS cancels it or 53 | there is a device wake signal that will cause us to complete it. 54 | 55 | Arguments: 56 | 57 | Device - Handle to WDF Device Object 58 | 59 | Request - Handle to request object 60 | 61 | Pending - flag to monitor if the request was sent down the stack 62 | 63 | Return Value: 64 | 65 | On success, the function returns STATUS_SUCCESS 66 | On failure it passes the relevant error code to the caller. 67 | 68 | --*/ 69 | { 70 | PDEVICE_EXTENSION devContext; 71 | PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO idleCallbackInfo; 72 | PIRP irp; 73 | PIO_STACK_LOCATION irpSp; 74 | NTSTATUS status; 75 | 76 | devContext = GetDeviceContext(Device); 77 | 78 | NT_ASSERT(Pending != NULL); 79 | *Pending = FALSE; 80 | 81 | // 82 | // Retrieve request parameters and validate 83 | // 84 | irp = WdfRequestWdmGetIrp(Request); 85 | irpSp = IoGetCurrentIrpStackLocation(irp); 86 | 87 | if (irpSp->Parameters.DeviceIoControl.InputBufferLength < 88 | sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)) 89 | { 90 | status = STATUS_INVALID_BUFFER_SIZE; 91 | 92 | Trace( 93 | TRACE_LEVEL_ERROR, 94 | TRACE_HID, 95 | "Error: Input buffer is too small to process idle request - %!STATUS!", 96 | status); 97 | 98 | goto exit; 99 | } 100 | 101 | // 102 | // Grab the callback 103 | // 104 | idleCallbackInfo = (PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) 105 | irpSp->Parameters.DeviceIoControl.Type3InputBuffer; 106 | 107 | NT_ASSERT(idleCallbackInfo != NULL); 108 | 109 | if (idleCallbackInfo == NULL || idleCallbackInfo->IdleCallback == NULL) 110 | { 111 | status = STATUS_NO_CALLBACK_ACTIVE; 112 | Trace( 113 | TRACE_LEVEL_ERROR, 114 | TRACE_HID, 115 | "Error: Idle Notification request %p has no idle callback info - %!STATUS!", 116 | Request, 117 | status); 118 | goto exit; 119 | } 120 | 121 | { 122 | // 123 | // Create a workitem for the idle callback 124 | // 125 | WDF_OBJECT_ATTRIBUTES workItemAttributes; 126 | WDF_WORKITEM_CONFIG workitemConfig; 127 | WDFWORKITEM idleWorkItem; 128 | PIDLE_WORKITEM_CONTEXT idleWorkItemContext; 129 | 130 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workItemAttributes, IDLE_WORKITEM_CONTEXT); 131 | workItemAttributes.ParentObject = devContext->FxDevice; 132 | 133 | WDF_WORKITEM_CONFIG_INIT(&workitemConfig, TchIdleIrpWorkitem); 134 | 135 | status = WdfWorkItemCreate( 136 | &workitemConfig, 137 | &workItemAttributes, 138 | &idleWorkItem 139 | ); 140 | 141 | if (!NT_SUCCESS(status)) { 142 | Trace( 143 | TRACE_LEVEL_ERROR, 144 | TRACE_HID, 145 | "Error creating creating idle work item - %!STATUS!", 146 | status); 147 | goto exit; 148 | } 149 | 150 | // 151 | // Set the workitem context 152 | // 153 | idleWorkItemContext = GetWorkItemContext(idleWorkItem); 154 | idleWorkItemContext->FxDevice = devContext->FxDevice; 155 | idleWorkItemContext->FxRequest = Request; 156 | 157 | // 158 | // Enqueue a workitem for the idle callback 159 | // 160 | WdfWorkItemEnqueue(idleWorkItem); 161 | 162 | // 163 | // Mark the request as pending so that 164 | // we can complete it when we come out of idle 165 | // 166 | *Pending = TRUE; 167 | } 168 | 169 | exit: 170 | 171 | return status; 172 | } 173 | 174 | VOID 175 | TchIdleIrpWorkitem( 176 | IN WDFWORKITEM IdleWorkItem 177 | ) 178 | /*++ 179 | 180 | Routine Description: 181 | 182 | This is a workitem routine that TchProcessIdleRequest queues when 183 | handling the HIDClass's idle notification IRP, so the idle callback can be made in 184 | a different thread context, instead of the Idle Irp's dispatch call. 185 | 186 | Arguments: 187 | 188 | IdleWorkItem - Handle to a WDF workitem object 189 | 190 | Return Value: 191 | 192 | VOID 193 | 194 | --*/ 195 | { 196 | NTSTATUS status; 197 | PIDLE_WORKITEM_CONTEXT idleWorkItemContext; 198 | PDEVICE_EXTENSION deviceContext; 199 | PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO idleCallbackInfo; 200 | 201 | idleWorkItemContext = GetWorkItemContext(IdleWorkItem); 202 | NT_ASSERT(idleWorkItemContext != NULL); 203 | 204 | deviceContext = GetDeviceContext(idleWorkItemContext->FxDevice); 205 | NT_ASSERT(deviceContext != NULL); 206 | 207 | // 208 | // Get the idle callback info from the workitem context 209 | // 210 | idleCallbackInfo = (PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) 211 | IoGetCurrentIrpStackLocation(WdfRequestWdmGetIrp(idleWorkItemContext->FxRequest))->\ 212 | Parameters.DeviceIoControl.Type3InputBuffer; 213 | 214 | // 215 | // idleCallbackInfo is validated already, so invoke idle callback 216 | // 217 | idleCallbackInfo->IdleCallback(idleCallbackInfo->IdleContext); 218 | 219 | // 220 | // Park this request in our IdleQueue and mark it as pending 221 | // This way if the IRP was cancelled, WDF will cancel it for us 222 | // 223 | status = WdfRequestForwardToIoQueue( 224 | idleWorkItemContext->FxRequest, 225 | deviceContext->IdleQueue); 226 | 227 | if (!NT_SUCCESS(status)) 228 | { 229 | // 230 | // IdleQueue is a manual-dispatch, non-power-managed queue. This should 231 | // *never* fail. 232 | // 233 | 234 | NT_ASSERTMSG("WdfRequestForwardToIoQueue to IdleQueue failed!", FALSE); 235 | 236 | Trace( 237 | TRACE_LEVEL_ERROR, 238 | TRACE_IDLE, 239 | "Error forwarding idle notification Request:0x%p to IdleQueue:0x%p - %!STATUS!", 240 | idleWorkItemContext->FxRequest, 241 | deviceContext->IdleQueue, 242 | status); 243 | 244 | // 245 | // Complete the request if we couldnt forward to the Idle Queue 246 | // 247 | WdfRequestComplete(idleWorkItemContext->FxRequest, status); 248 | } 249 | else 250 | { 251 | Trace( 252 | TRACE_LEVEL_INFORMATION, 253 | TRACE_IDLE, 254 | "Forwarded idle notification Request:0x%p to IdleQueue:0x%p - %!STATUS!", 255 | idleWorkItemContext->FxRequest, 256 | deviceContext->IdleQueue, 257 | status); 258 | } 259 | 260 | // 261 | // Delete the workitem since we're done with it 262 | // 263 | WdfObjectDelete(IdleWorkItem); 264 | 265 | return; 266 | } 267 | 268 | 269 | VOID 270 | TchCompleteIdleIrp( 271 | IN PDEVICE_EXTENSION FxDeviceContext 272 | ) 273 | /*++ 274 | 275 | Routine Description: 276 | 277 | This is invoked when we enter D0. 278 | We simply complete the Idle Irp if it hasn't been cancelled already. 279 | 280 | Arguments: 281 | 282 | FxDeviceContext - Pointer to Device Context for the device 283 | 284 | Return Value: 285 | 286 | 287 | 288 | --*/ 289 | { 290 | NTSTATUS status; 291 | WDFREQUEST request = NULL; 292 | 293 | // 294 | // Lets try to retrieve the Idle IRP from the Idle queue 295 | // 296 | status = WdfIoQueueRetrieveNextRequest( 297 | FxDeviceContext->IdleQueue, 298 | &request); 299 | 300 | // 301 | // We did not find the Idle IRP, maybe it was cancelled 302 | // 303 | if (!NT_SUCCESS(status) || (request == NULL)) 304 | { 305 | Trace( 306 | TRACE_LEVEL_WARNING, 307 | TRACE_IDLE, 308 | "Error finding idle notification request in IdleQueue:0x%p - %!STATUS!", 309 | FxDeviceContext->IdleQueue, 310 | status); 311 | } 312 | else 313 | { 314 | // 315 | // Complete the Idle IRP 316 | // 317 | WdfRequestComplete(request, status); 318 | 319 | Trace( 320 | TRACE_LEVEL_INFORMATION, 321 | TRACE_IDLE, 322 | "Completed idle notification Request:0x%p from IdleQueue:0x%p - %!STATUS!", 323 | request, 324 | FxDeviceContext->IdleQueue, 325 | status); 326 | } 327 | 328 | return; 329 | } -------------------------------------------------------------------------------- /src/device.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef ALLOC_PRAGMA 13 | #pragma alloc_text(PAGE, OnD0Exit) 14 | #endif 15 | 16 | BOOLEAN 17 | OnInterruptIsr( 18 | IN WDFINTERRUPT Interrupt, 19 | IN ULONG MessageID 20 | ) 21 | /*++ 22 | 23 | Routine Description: 24 | 25 | This routine responds to interrupts generated by the 26 | controller. If one is recognized, it queues a DPC for 27 | processing. 28 | 29 | This is a PASSIVE_LEVEL ISR. ACPI should specify 30 | level-triggered interrupts when using Synaptics 3202. 31 | 32 | Arguments: 33 | 34 | Interrupt - a handle to a framework interrupt object 35 | MessageID - message number identifying the device's 36 | hardware interrupt message (if using MSI) 37 | 38 | Return Value: 39 | 40 | TRUE if interrupt recognized. 41 | 42 | --*/ 43 | { 44 | PDEVICE_EXTENSION devContext; 45 | NTSTATUS status; 46 | WDFREQUEST request; 47 | BOOLEAN servicingComplete; 48 | PTP_REPORT hidReportFromDriver; 49 | PPTP_REPORT hidReportRequestBuffer; 50 | size_t hidReportRequestBufferLength; 51 | 52 | UNREFERENCED_PARAMETER(MessageID); 53 | 54 | status = STATUS_SUCCESS; 55 | servicingComplete = FALSE; 56 | devContext = GetDeviceContext(WdfInterruptGetDevice(Interrupt)); 57 | request = NULL; 58 | 59 | 60 | // 61 | // If we're in diagnostic mode, let the diagnostic application handle 62 | // interrupt servicing 63 | // 64 | if (devContext->DiagnosticMode != FALSE) 65 | { 66 | goto exit; 67 | } 68 | 69 | 70 | // 71 | // Service the device interrupt 72 | // 73 | while (servicingComplete == FALSE) 74 | { 75 | // 76 | // Service touch interrupts. Success indicates we have a report 77 | // to complete to Hid. ServicingComplete indicates another report 78 | // is required to continue servicing this interrupt. 79 | // 80 | if (!NT_SUCCESS(TchServiceInterrupts( 81 | devContext->TouchContext, 82 | &devContext->I2CContext, 83 | &hidReportFromDriver, 84 | devContext->InputMode, 85 | &servicingComplete))) 86 | { 87 | // 88 | // hidReportFromDriver was not filled 89 | // 90 | continue; 91 | } 92 | 93 | // 94 | // Complete a HIDClass request if one is available 95 | // 96 | status = WdfIoQueueRetrieveNextRequest( 97 | devContext->PingPongQueue, 98 | &request); 99 | 100 | if (!NT_SUCCESS(status)) 101 | { 102 | Trace( 103 | TRACE_LEVEL_ERROR, 104 | TRACE_REPORTING, 105 | "No request pending from HIDClass, ignoring report - %!STATUS!", 106 | status); 107 | 108 | 109 | 110 | continue; 111 | } 112 | 113 | // 114 | // Validate an output buffer was provided 115 | // 116 | status = WdfRequestRetrieveOutputBuffer( 117 | request, 118 | sizeof(PTP_REPORT), 119 | &hidReportRequestBuffer, 120 | &hidReportRequestBufferLength); 121 | 122 | if (!NT_SUCCESS(status)) 123 | { 124 | Trace( 125 | TRACE_LEVEL_VERBOSE, 126 | TRACE_SAMPLES, 127 | "Error retrieving HID read request output buffer - %!STATUS!", 128 | status); 129 | } 130 | else 131 | { 132 | // 133 | // Validate the size of the output buffer 134 | // 135 | if (hidReportRequestBufferLength < sizeof(PTP_REPORT)) 136 | { 137 | status = STATUS_BUFFER_TOO_SMALL; 138 | 139 | Trace( 140 | TRACE_LEVEL_VERBOSE, 141 | TRACE_SAMPLES, 142 | "Error HID read request buffer is too small (%I64x bytes) - %!STATUS!", 143 | hidReportRequestBufferLength, 144 | status); 145 | } 146 | else 147 | { 148 | RtlCopyMemory( 149 | hidReportRequestBuffer, 150 | &hidReportFromDriver, 151 | sizeof(PTP_REPORT)); 152 | 153 | WdfRequestSetInformation(request, sizeof(PTP_REPORT)); 154 | } 155 | } 156 | 157 | WdfRequestComplete(request, status); 158 | } 159 | 160 | exit: 161 | return TRUE; 162 | } 163 | 164 | NTSTATUS 165 | OnD0Entry( 166 | IN WDFDEVICE Device, 167 | IN WDF_POWER_DEVICE_STATE PreviousState 168 | ) 169 | /*++ 170 | 171 | Routine Description: 172 | 173 | This routine will power on the hardware 174 | 175 | Arguments: 176 | 177 | Device - WDF device to power on 178 | PreviousState - Prior power state 179 | 180 | Return Value: 181 | 182 | NTSTATUS indicating success or failure 183 | 184 | */ 185 | { 186 | NTSTATUS status; 187 | PDEVICE_EXTENSION devContext; 188 | 189 | devContext = GetDeviceContext(Device); 190 | 191 | UNREFERENCED_PARAMETER(PreviousState); 192 | 193 | status = TchWakeDevice(devContext->TouchContext, &devContext->I2CContext); 194 | 195 | if (!NT_SUCCESS(status)) 196 | { 197 | Trace( 198 | TRACE_LEVEL_ERROR, 199 | TRACE_POWER, 200 | "Error setting device to D0 - %!STATUS!", 201 | status); 202 | } 203 | 204 | // 205 | // N.B. This RMI chip's IRQ is level-triggered, but cannot be enabled in 206 | // ACPI until passive-level interrupt handling is added to the driver. 207 | // Service chip in case we missed an edge during D3 or boot-up. 208 | // 209 | devContext->ServiceInterruptsAfterD0Entry = TRUE; 210 | 211 | // 212 | // Complete any pending Idle IRPs 213 | // 214 | TchCompleteIdleIrp(devContext); 215 | 216 | return status; 217 | } 218 | 219 | NTSTATUS 220 | OnD0Exit( 221 | IN WDFDEVICE Device, 222 | IN WDF_POWER_DEVICE_STATE TargetState 223 | ) 224 | /*++ 225 | 226 | Routine Description: 227 | 228 | This routine will power down the hardware 229 | 230 | Arguments: 231 | 232 | Device - WDF device to power off 233 | 234 | PreviousState - Prior power state 235 | 236 | Return Value: 237 | 238 | NTSTATUS indicating success or failure 239 | 240 | */ 241 | { 242 | NTSTATUS status; 243 | PDEVICE_EXTENSION devContext; 244 | 245 | PAGED_CODE(); 246 | 247 | devContext = GetDeviceContext(Device); 248 | 249 | UNREFERENCED_PARAMETER(TargetState); 250 | 251 | status = TchStandbyDevice(devContext->TouchContext, &devContext->I2CContext); 252 | 253 | if (!NT_SUCCESS(status)) 254 | { 255 | Trace( 256 | TRACE_LEVEL_ERROR, 257 | TRACE_POWER, 258 | "Error exiting D0 - %!STATUS!", 259 | status); 260 | } 261 | 262 | return status; 263 | } 264 | 265 | NTSTATUS 266 | OnPrepareHardware( 267 | IN WDFDEVICE FxDevice, 268 | IN WDFCMRESLIST FxResourcesRaw, 269 | IN WDFCMRESLIST FxResourcesTranslated 270 | ) 271 | /*++ 272 | 273 | Routine Description: 274 | 275 | This routine is called by the PnP manager and supplies thie device instance 276 | with it's SPB resources (CmResourceTypeConnection) needed to find the I2C 277 | driver. 278 | 279 | Arguments: 280 | 281 | FxDevice - a handle to the framework device object 282 | FxResourcesRaw - list of translated hardware resources that 283 | the PnP manager has assigned to the device 284 | FxResourcesTranslated - list of raw hardware resources that 285 | the PnP manager has assigned to the device 286 | 287 | Return Value: 288 | 289 | NTSTATUS indicating sucess or failure 290 | 291 | --*/ 292 | { 293 | NTSTATUS status; 294 | PCM_PARTIAL_RESOURCE_DESCRIPTOR res; 295 | PDEVICE_EXTENSION devContext; 296 | ULONG resourceCount; 297 | ULONG i; 298 | 299 | UNREFERENCED_PARAMETER(FxResourcesRaw); 300 | 301 | status = STATUS_INSUFFICIENT_RESOURCES; 302 | devContext = GetDeviceContext(FxDevice); 303 | 304 | // 305 | // Get the resouce hub connection ID for our I2C driver 306 | // 307 | resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); 308 | 309 | for (i=0; i < resourceCount; i++) 310 | { 311 | res = WdfCmResourceListGetDescriptor(FxResourcesTranslated, i); 312 | 313 | if (res->Type == CmResourceTypeConnection && 314 | res->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && 315 | res->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) 316 | { 317 | devContext->I2CContext.I2cResHubId.LowPart = 318 | res->u.Connection.IdLowPart; 319 | devContext->I2CContext.I2cResHubId.HighPart = 320 | res->u.Connection.IdHighPart; 321 | 322 | status = STATUS_SUCCESS; 323 | } 324 | } 325 | 326 | if (!NT_SUCCESS(status)) 327 | { 328 | Trace( 329 | TRACE_LEVEL_ERROR, 330 | TRACE_INIT, 331 | "Error finding CmResourceTypeConnection resource - %!STATUS!", 332 | status); 333 | 334 | goto exit; 335 | } 336 | 337 | // 338 | // Initialize Spb so the driver can issue reads/writes 339 | // 340 | status = SpbTargetInitialize(FxDevice, &devContext->I2CContext); 341 | 342 | if (!NT_SUCCESS(status)) 343 | { 344 | Trace( 345 | TRACE_LEVEL_ERROR, 346 | TRACE_INIT, 347 | "Error in Spb initialization - %!STATUS!", 348 | status); 349 | 350 | goto exit; 351 | } 352 | 353 | // 354 | // Prepare the hardware for touch scanning 355 | // 356 | status = TchAllocateContext(&devContext->TouchContext, FxDevice); 357 | 358 | if (!NT_SUCCESS(status)) 359 | { 360 | Trace( 361 | TRACE_LEVEL_ERROR, 362 | TRACE_INIT, 363 | "Error allocating touch context - %!STATUS!", 364 | status); 365 | 366 | goto exit; 367 | } 368 | 369 | // 370 | // Fetch controller settings from registry 371 | // 372 | status = TchRegistryGetControllerSettings( 373 | devContext->TouchContext, 374 | devContext->FxDevice); 375 | 376 | if (!NT_SUCCESS(status)) 377 | { 378 | Trace( 379 | TRACE_LEVEL_ERROR, 380 | TRACE_INIT, 381 | "Error retrieving controller settings from registry - %!STATUS!", 382 | status); 383 | 384 | goto exit; 385 | } 386 | 387 | // 388 | // Start the controller 389 | // 390 | status = TchStartDevice(devContext->TouchContext, &devContext->I2CContext); 391 | 392 | if (!NT_SUCCESS(status)) 393 | { 394 | Trace( 395 | TRACE_LEVEL_ERROR, 396 | TRACE_INIT, 397 | "Error starting touch device - %!STATUS!", 398 | status); 399 | 400 | goto exit; 401 | } 402 | 403 | exit: 404 | 405 | return status; 406 | } 407 | 408 | NTSTATUS 409 | OnReleaseHardware( 410 | IN WDFDEVICE FxDevice, 411 | IN WDFCMRESLIST FxResourcesTranslated 412 | ) 413 | /*++ 414 | 415 | Routine Description: 416 | 417 | This routine cleans up any resources provided. 418 | 419 | Arguments: 420 | 421 | FxDevice - a handle to the framework device object 422 | FxResourcesRaw - list of translated hardware resources that 423 | the PnP manager has assigned to the device 424 | FxResourcesTranslated - list of raw hardware resources that 425 | the PnP manager has assigned to the device 426 | 427 | Return Value: 428 | 429 | NTSTATUS indicating sucesss or failure 430 | 431 | --*/ 432 | { 433 | NTSTATUS status; 434 | PDEVICE_EXTENSION devContext; 435 | 436 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 437 | 438 | devContext = GetDeviceContext(FxDevice); 439 | 440 | status = TchStopDevice(devContext->TouchContext, &devContext->I2CContext); 441 | 442 | if (!NT_SUCCESS(status)) 443 | { 444 | Trace( 445 | TRACE_LEVEL_ERROR, 446 | TRACE_PNP, 447 | "Error stopping device - %!STATUS!", 448 | status); 449 | } 450 | 451 | status = TchFreeContext(devContext->TouchContext); 452 | 453 | if (!NT_SUCCESS(status)) 454 | { 455 | Trace( 456 | TRACE_LEVEL_ERROR, 457 | TRACE_PNP, 458 | "Error freeing touch context - %!STATUS!", 459 | status); 460 | } 461 | 462 | SpbTargetDeinitialize(FxDevice, &GetDeviceContext(FxDevice)->I2CContext); 463 | 464 | return status; 465 | } 466 | 467 | -------------------------------------------------------------------------------- /src/spb.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | spb.c 8 | 9 | Abstract: 10 | 11 | Contains all I2C-specific functionality 12 | 13 | Environment: 14 | 15 | Kernel mode 16 | 17 | Revision History: 18 | 19 | --*/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | NTSTATUS 27 | SpbDoWriteDataSynchronously( 28 | IN SPB_CONTEXT *SpbContext, 29 | IN UCHAR Address, 30 | IN PVOID Data, 31 | IN ULONG Length 32 | ) 33 | /*++ 34 | 35 | Routine Description: 36 | 37 | This helper routine abstracts creating and sending an I/O 38 | request (I2C Write) to the Spb I/O target. 39 | 40 | Arguments: 41 | 42 | SpbContext - Pointer to the current device context 43 | Address - The I2C register address to write to 44 | Data - A buffer to receive the data at at the above address 45 | Length - The amount of data to be read from the above address 46 | 47 | Return Value: 48 | 49 | NTSTATUS Status indicating success or failure 50 | 51 | --*/ 52 | { 53 | PUCHAR buffer; 54 | ULONG length; 55 | WDFMEMORY memory; 56 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 57 | NTSTATUS status; 58 | 59 | // 60 | // The address pointer and data buffer must be combined 61 | // into one contiguous buffer representing the write transaction. 62 | // 63 | length = Length + 1; 64 | memory = NULL; 65 | 66 | if (length > DEFAULT_SPB_BUFFER_SIZE) 67 | { 68 | status = WdfMemoryCreate( 69 | WDF_NO_OBJECT_ATTRIBUTES, 70 | NonPagedPoolNx, 71 | TOUCH_POOL_TAG, 72 | length, 73 | &memory, 74 | &buffer); 75 | 76 | if (!NT_SUCCESS(status)) 77 | { 78 | Trace( 79 | TRACE_LEVEL_ERROR, 80 | TRACE_SPB, 81 | "Error allocating memory for Spb write - %!STATUS!", 82 | status); 83 | goto exit; 84 | } 85 | 86 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 87 | &memoryDescriptor, 88 | memory, 89 | NULL); 90 | } 91 | else 92 | { 93 | buffer = (PUCHAR) WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 94 | 95 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 96 | &memoryDescriptor, 97 | (PVOID) buffer, 98 | length); 99 | } 100 | 101 | // 102 | // Transaction starts by specifying the address bytes 103 | // 104 | RtlCopyMemory(buffer, &Address, sizeof(Address)); 105 | 106 | // 107 | // Address is followed by the data payload 108 | // 109 | RtlCopyMemory((buffer+sizeof(Address)), Data, length-sizeof(Address)); 110 | 111 | status = WdfIoTargetSendWriteSynchronously( 112 | SpbContext->SpbIoTarget, 113 | NULL, 114 | &memoryDescriptor, 115 | NULL, 116 | NULL, 117 | NULL); 118 | 119 | if (!NT_SUCCESS(status)) 120 | { 121 | Trace( 122 | TRACE_LEVEL_ERROR, 123 | TRACE_SPB, 124 | "Error writing to Spb - %!STATUS!", 125 | status); 126 | goto exit; 127 | } 128 | 129 | exit: 130 | 131 | if (NULL != memory) 132 | { 133 | WdfObjectDelete(memory); 134 | } 135 | 136 | return status; 137 | } 138 | 139 | NTSTATUS 140 | SpbWriteDataSynchronously( 141 | IN SPB_CONTEXT *SpbContext, 142 | IN UCHAR Address, 143 | IN PVOID Data, 144 | IN ULONG Length 145 | ) 146 | /*++ 147 | 148 | Routine Description: 149 | 150 | This routine abstracts creating and sending an I/O 151 | request (I2C Write) to the Spb I/O target and utilizes 152 | a helper routine to do work inside of locked code. 153 | 154 | Arguments: 155 | 156 | SpbContext - Pointer to the current device context 157 | Address - The I2C register address to write to 158 | Data - A buffer to receive the data at at the above address 159 | Length - The amount of data to be read from the above address 160 | 161 | Return Value: 162 | 163 | NTSTATUS Status indicating success or failure 164 | 165 | --*/ 166 | { 167 | NTSTATUS status; 168 | 169 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 170 | 171 | status = SpbDoWriteDataSynchronously( 172 | SpbContext, 173 | Address, 174 | Data, 175 | Length); 176 | 177 | WdfWaitLockRelease(SpbContext->SpbLock); 178 | 179 | return status; 180 | } 181 | 182 | NTSTATUS 183 | SpbReadDataSynchronously( 184 | _In_ SPB_CONTEXT *SpbContext, 185 | _In_ UCHAR Address, 186 | _In_reads_bytes_(Length) PVOID Data, 187 | _In_ ULONG Length 188 | ) 189 | /*++ 190 | 191 | Routine Description: 192 | 193 | This helper routine abstracts creating and sending an I/O 194 | request (I2C Read) to the Spb I/O target. 195 | 196 | Arguments: 197 | 198 | SpbContext - Pointer to the current device context 199 | Address - The I2C register address to read from 200 | Data - A buffer to receive the data at at the above address 201 | Length - The amount of data to be read from the above address 202 | 203 | Return Value: 204 | 205 | NTSTATUS Status indicating success or failure 206 | 207 | --*/ 208 | { 209 | PUCHAR buffer; 210 | WDFMEMORY memory; 211 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 212 | NTSTATUS status; 213 | ULONG_PTR bytesRead; 214 | 215 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 216 | 217 | memory = NULL; 218 | status = STATUS_INVALID_PARAMETER; 219 | bytesRead = 0; 220 | 221 | // 222 | // Read transactions start by writing an address pointer 223 | // 224 | status = SpbDoWriteDataSynchronously( 225 | SpbContext, 226 | Address, 227 | NULL, 228 | 0); 229 | 230 | if (!NT_SUCCESS(status)) 231 | { 232 | Trace( 233 | TRACE_LEVEL_ERROR, 234 | TRACE_SPB, 235 | "Error setting address pointer for Spb read - %!STATUS!", 236 | status); 237 | goto exit; 238 | } 239 | 240 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 241 | { 242 | status = WdfMemoryCreate( 243 | WDF_NO_OBJECT_ATTRIBUTES, 244 | NonPagedPoolNx, 245 | TOUCH_POOL_TAG, 246 | Length, 247 | &memory, 248 | &buffer); 249 | 250 | if (!NT_SUCCESS(status)) 251 | { 252 | Trace( 253 | TRACE_LEVEL_ERROR, 254 | TRACE_SPB, 255 | "Error allocating memory for Spb read - %!STATUS!", 256 | status); 257 | goto exit; 258 | } 259 | 260 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 261 | &memoryDescriptor, 262 | memory, 263 | NULL); 264 | } 265 | else 266 | { 267 | buffer = (PUCHAR) WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 268 | 269 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 270 | &memoryDescriptor, 271 | (PVOID) buffer, 272 | Length); 273 | } 274 | 275 | 276 | status = WdfIoTargetSendReadSynchronously( 277 | SpbContext->SpbIoTarget, 278 | NULL, 279 | &memoryDescriptor, 280 | NULL, 281 | NULL, 282 | &bytesRead); 283 | 284 | if (!NT_SUCCESS(status) || 285 | bytesRead != Length) 286 | { 287 | Trace( 288 | TRACE_LEVEL_ERROR, 289 | TRACE_SPB, 290 | "Error reading from Spb - %!STATUS!", 291 | status); 292 | goto exit; 293 | } 294 | 295 | // 296 | // Copy back to the caller's buffer 297 | // 298 | RtlCopyMemory(Data, buffer, Length); 299 | 300 | exit: 301 | if (NULL != memory) 302 | { 303 | WdfObjectDelete(memory); 304 | } 305 | 306 | WdfWaitLockRelease(SpbContext->SpbLock); 307 | 308 | return status; 309 | } 310 | 311 | VOID 312 | SpbTargetDeinitialize( 313 | IN WDFDEVICE FxDevice, 314 | IN SPB_CONTEXT *SpbContext 315 | ) 316 | /*++ 317 | 318 | Routine Description: 319 | 320 | This helper routine is used to free any members added to the SPB_CONTEXT, 321 | note the SPB I/O target is parented to the device and will be 322 | closed and free'd when the device is removed. 323 | 324 | Arguments: 325 | 326 | FxDevice - Handle to the framework device object 327 | SpbContext - Pointer to the current device context 328 | 329 | Return Value: 330 | 331 | NTSTATUS Status indicating success or failure 332 | 333 | --*/ 334 | { 335 | UNREFERENCED_PARAMETER(FxDevice); 336 | UNREFERENCED_PARAMETER(SpbContext); 337 | 338 | // 339 | // Free any SPB_CONTEXT allocations here 340 | // 341 | if (SpbContext->SpbLock != NULL) 342 | { 343 | WdfObjectDelete(SpbContext->SpbLock); 344 | } 345 | 346 | if (SpbContext->ReadMemory != NULL) 347 | { 348 | WdfObjectDelete(SpbContext->ReadMemory); 349 | } 350 | 351 | if (SpbContext->WriteMemory != NULL) 352 | { 353 | WdfObjectDelete(SpbContext->WriteMemory); 354 | } 355 | } 356 | 357 | NTSTATUS 358 | SpbTargetInitialize( 359 | IN WDFDEVICE FxDevice, 360 | IN SPB_CONTEXT *SpbContext 361 | ) 362 | /*++ 363 | 364 | Routine Description: 365 | 366 | This helper routine opens the Spb I/O target and 367 | initializes a request object used for the lifetime 368 | of communication between this driver and Spb. 369 | 370 | Arguments: 371 | 372 | FxDevice - Handle to the framework device object 373 | SpbContext - Pointer to the current device context 374 | 375 | Return Value: 376 | 377 | NTSTATUS Status indicating success or failure 378 | 379 | --*/ 380 | { 381 | WDF_OBJECT_ATTRIBUTES objectAttributes; 382 | WDF_IO_TARGET_OPEN_PARAMS openParams; 383 | UNICODE_STRING spbDeviceName; 384 | WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 385 | NTSTATUS status; 386 | 387 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 388 | objectAttributes.ParentObject = FxDevice; 389 | 390 | status = WdfIoTargetCreate( 391 | FxDevice, 392 | &objectAttributes, 393 | &SpbContext->SpbIoTarget); 394 | 395 | if (!NT_SUCCESS(status)) 396 | { 397 | Trace( 398 | TRACE_LEVEL_ERROR, 399 | TRACE_SPB, 400 | "Error creating IoTarget object - %!STATUS!", 401 | status); 402 | 403 | WdfObjectDelete(SpbContext->SpbIoTarget); 404 | goto exit; 405 | } 406 | 407 | RtlInitEmptyUnicodeString( 408 | &spbDeviceName, 409 | spbDeviceNameBuffer, 410 | sizeof(spbDeviceNameBuffer)); 411 | 412 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 413 | &spbDeviceName, 414 | SpbContext->I2cResHubId.LowPart, 415 | SpbContext->I2cResHubId.HighPart); 416 | 417 | if (!NT_SUCCESS(status)) 418 | { 419 | Trace( 420 | TRACE_LEVEL_ERROR, 421 | TRACE_SPB, 422 | "Error creating Spb resource hub path string - %!STATUS!", 423 | status); 424 | goto exit; 425 | } 426 | 427 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 428 | &openParams, 429 | &spbDeviceName, 430 | (GENERIC_READ | GENERIC_WRITE)); 431 | 432 | openParams.ShareAccess = 0; 433 | openParams.CreateDisposition = FILE_OPEN; 434 | openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; 435 | 436 | status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); 437 | 438 | if (!NT_SUCCESS(status)) 439 | { 440 | Trace( 441 | TRACE_LEVEL_ERROR, 442 | TRACE_SPB, 443 | "Error opening Spb target for communication - %!STATUS!", 444 | status); 445 | goto exit; 446 | } 447 | 448 | // 449 | // Allocate some fixed-size buffers from NonPagedPoolNx for typical 450 | // Spb transaction sizes to avoid pool fragmentation in most cases 451 | // 452 | status = WdfMemoryCreate( 453 | WDF_NO_OBJECT_ATTRIBUTES, 454 | NonPagedPoolNx, 455 | TOUCH_POOL_TAG, 456 | DEFAULT_SPB_BUFFER_SIZE, 457 | &SpbContext->WriteMemory, 458 | NULL); 459 | 460 | if (!NT_SUCCESS(status)) 461 | { 462 | Trace( 463 | TRACE_LEVEL_ERROR, 464 | TRACE_SPB, 465 | "Error allocating default memory for Spb write - %!STATUS!", 466 | status); 467 | goto exit; 468 | } 469 | 470 | status = WdfMemoryCreate( 471 | WDF_NO_OBJECT_ATTRIBUTES, 472 | NonPagedPoolNx, 473 | TOUCH_POOL_TAG, 474 | DEFAULT_SPB_BUFFER_SIZE, 475 | &SpbContext->ReadMemory, 476 | NULL); 477 | 478 | if (!NT_SUCCESS(status)) 479 | { 480 | Trace( 481 | TRACE_LEVEL_ERROR, 482 | TRACE_SPB, 483 | "Error allocating default memory for Spb read - %!STATUS!", 484 | status); 485 | goto exit; 486 | } 487 | 488 | // 489 | // Allocate a waitlock to guard access to the default buffers 490 | // 491 | status = WdfWaitLockCreate( 492 | WDF_NO_OBJECT_ATTRIBUTES, 493 | &SpbContext->SpbLock); 494 | 495 | if (!NT_SUCCESS(status)) 496 | { 497 | Trace( 498 | TRACE_LEVEL_ERROR, 499 | TRACE_SPB, 500 | "Error creating Spb Waitlock - %!STATUS!", 501 | status); 502 | goto exit; 503 | } 504 | 505 | exit: 506 | 507 | if (!NT_SUCCESS(status)) 508 | { 509 | SpbTargetDeinitialize(FxDevice, SpbContext); 510 | } 511 | 512 | return status; 513 | } 514 | -------------------------------------------------------------------------------- /include/hid.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #pragma once 5 | 6 | // 7 | // Global Data Declarations 8 | // 9 | extern const PWSTR gpwstrManufacturerID; 10 | extern const PWSTR gpwstrProductID; 11 | extern const PWSTR gpwstrSerialNumber; 12 | extern const USHORT gOEMVendorID; 13 | extern const USHORT gOEMProductID; 14 | extern const USHORT gOEMVersionID; 15 | 16 | // 17 | // Function prototypes 18 | // 19 | 20 | NTSTATUS 21 | TchGetDeviceAttributes( 22 | IN WDFREQUEST Request 23 | ); 24 | 25 | NTSTATUS 26 | TchGetFeatureReport( 27 | IN WDFDEVICE Device, 28 | IN WDFREQUEST Request 29 | ); 30 | 31 | NTSTATUS 32 | TchGetHidDescriptor( 33 | IN WDFDEVICE Device, 34 | IN WDFREQUEST Request 35 | ); 36 | 37 | NTSTATUS 38 | TchGetReportDescriptor( 39 | IN WDFDEVICE Device, 40 | IN WDFREQUEST Request 41 | ); 42 | 43 | NTSTATUS 44 | TchGetString( 45 | IN WDFDEVICE Device, 46 | IN WDFREQUEST Request 47 | ); 48 | 49 | NTSTATUS 50 | TchProcessIdleRequest( 51 | IN WDFDEVICE Device, 52 | IN WDFREQUEST Request, 53 | OUT BOOLEAN *Pending 54 | ); 55 | 56 | NTSTATUS 57 | TchSetFeatureReport( 58 | IN WDFDEVICE Device, 59 | IN WDFREQUEST Request 60 | ); 61 | 62 | NTSTATUS 63 | TchReadReport( 64 | IN WDFDEVICE Device, 65 | IN WDFREQUEST Request, 66 | OUT BOOLEAN *Pending 67 | ); 68 | 69 | // 70 | // HID collections 71 | // 72 | #include "HidCommon.h" 73 | 74 | #define SYNAPTICS_PTP_FINGER_COLLECTION_1 \ 75 | BEGIN_COLLECTION, 0x02, /* Begin Collection: Logical */ \ 76 | /* Begin a byte */ \ 77 | LOGICAL_MAXIMUM, 0x01, /* Logical Maximum: 1 */ \ 78 | USAGE, 0x47, /* Usage: Confidence */ \ 79 | USAGE, 0x42, /* Usage: Tip switch */ \ 80 | REPORT_COUNT, 0x02, /* Report Count: 2 */ \ 81 | REPORT_SIZE, 0x01, /* Report Size: 1 */ \ 82 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 83 | REPORT_COUNT, 0x01, /* Report Count: 1 */ \ 84 | REPORT_SIZE, 0x03, /* Report Size: 3 */ \ 85 | LOGICAL_MAXIMUM, 0x03, /* Logical Maximum: 3 */ \ 86 | USAGE, 0x51, /* Usage: Contract Identifier */ \ 87 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 88 | REPORT_SIZE, 0x01, /* Report Size: 1 */ \ 89 | REPORT_COUNT, 0x03, /* Report Count: 3 */ \ 90 | INPUT, 0x03, /* Input: (Const, Var, Abs) */ \ 91 | /* End of a byte */ \ 92 | /* Begin of 4 bytes */ \ 93 | /* Size is hard-coded at this moment */ \ 94 | /* This hard-coded size is designed for Lumia 950 XL */ \ 95 | USAGE_PAGE, 0x01, /* Usage Page: Generic Desktop */ \ 96 | LOGICAL_MAXIMUM_2, 0xA0, 0x05, /* Logical Maximum: 1440 (See defintion) */ \ 97 | REPORT_SIZE, 0x10, /* Report Size: 0x10 (2 bytes) */ \ 98 | UNIT_EXPONENT, 0x0e, /* Unit exponent: -2 */ \ 99 | UNIT, 0x11, /* Unit: SI Length (cm) */ \ 100 | USAGE, 0x30, /* Usage: X */ \ 101 | PHYSICAL_MAXIMUM_2, 0xce, 0x02, /* Physical Maximum: 7.18 */ \ 102 | REPORT_COUNT, 0x01, /* Report count: 1 */ \ 103 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 104 | PHYSICAL_MAXIMUM_2, 0xeb, 0x04, /* Physical Maximum: 12.59 */ \ 105 | LOGICAL_MAXIMUM_2, 0x00, 0x0a, /* Logical Maximum: 2560 (See definition) */ \ 106 | USAGE, 0x31, /* Usage: Y */ \ 107 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 108 | PHYSICAL_MAXIMUM, 0x00, /* Physical Maximum: 0 */ \ 109 | UNIT_EXPONENT, 0x00, /* Unit exponent: 0 */ \ 110 | UNIT, 0x00, /* Unit: None */ \ 111 | /* End of 4 bytes */ \ 112 | END_COLLECTION /* End Collection */ \ 113 | 114 | #define SYNAPTICS_PTP_FINGER_COLLECTION_2 \ 115 | BEGIN_COLLECTION, 0x02, /* Begin Collection: Logical */ \ 116 | /* Begin a byte */ \ 117 | LOGICAL_MAXIMUM, 0x01, /* Logical Maximum: 1 */ \ 118 | USAGE, 0x47, /* Usage: Confidence */ \ 119 | USAGE, 0x42, /* Usage: Tip switch */ \ 120 | REPORT_COUNT, 0x02, /* Report Count: 2 */ \ 121 | REPORT_SIZE, 0x01, /* Report Size: 1 */ \ 122 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 123 | REPORT_COUNT, 0x01, /* Report Count: 1 */ \ 124 | REPORT_SIZE, 0x03, /* Report Size: 3 */ \ 125 | LOGICAL_MAXIMUM, 0x03, /* Logical Maximum: 3 */ \ 126 | USAGE, 0x51, /* Usage: Contract Identifier */ \ 127 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 128 | REPORT_SIZE, 0x01, /* Report Size: 1 */ \ 129 | REPORT_COUNT, 0x03, /* Report Count: 3 */ \ 130 | INPUT, 0x03, /* Input: (Const, Var, Abs) */ \ 131 | /* End of a byte */ \ 132 | /* Begin of 4 bytes */ \ 133 | /* This hard-coded size is designed for Lumia 950 XL */ \ 134 | USAGE_PAGE, 0x01, /* Usage Page: Generic Desktop */ \ 135 | LOGICAL_MAXIMUM_2, 0xA0, 0x05, /* Logical Maximum: 1440 (See defintion) */ \ 136 | REPORT_SIZE, 0x10, /* Report Size: 0x10 (2 bytes) */ \ 137 | UNIT_EXPONENT, 0x0e, /* Unit exponent: -2 */ \ 138 | UNIT, 0x11, /* Unit: SI Length (cm) */ \ 139 | USAGE, 0x30, /* Usage: X */ \ 140 | PHYSICAL_MAXIMUM_2, 0xce, 0x02, /* Physical Maximum: 7.18 */ \ 141 | REPORT_COUNT, 0x01, /* Report count: 1 */ \ 142 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 143 | PHYSICAL_MAXIMUM_2, 0xeb, 0x04, /* Physical Maximum: 12.59 */ \ 144 | LOGICAL_MAXIMUM_2, 0x00, 0x0a, /* Logical Maximum: 2560 (See definition) */ \ 145 | USAGE, 0x31, /* Usage: Y */ \ 146 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 147 | /* End of 4 bytes */ \ 148 | END_COLLECTION /* End Collection */ \ 149 | 150 | #define SYNAPTICS_PTP_TLC \ 151 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 152 | USAGE, 0x05, /* Usage: Touch Pad */ \ 153 | BEGIN_COLLECTION, 0x01, /* Begin Collection: Application */ \ 154 | REPORT_ID, REPORTID_MULTITOUCH, /* Report ID: Multi-touch */ \ 155 | USAGE, 0x22, /* Usage: Finger */ \ 156 | SYNAPTICS_PTP_FINGER_COLLECTION_1, /* 1 */ \ 157 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 158 | USAGE, 0x22, /* Usage: Finger */ \ 159 | SYNAPTICS_PTP_FINGER_COLLECTION_1, /* 2 */ \ 160 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 161 | USAGE, 0x22, /* Usage: Finger */ \ 162 | SYNAPTICS_PTP_FINGER_COLLECTION_2, /* 3 */ \ 163 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 164 | USAGE, 0x22, /* Usage: Finger */ \ 165 | SYNAPTICS_PTP_FINGER_COLLECTION_1, /* 4 */ \ 166 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 167 | USAGE, 0x22, /* Usage: Finger */ \ 168 | SYNAPTICS_PTP_FINGER_COLLECTION_2, /* 5 */ \ 169 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 170 | UNIT_EXPONENT, 0x0c, /* Unit exponent: -4 */ \ 171 | UNIT_2, 0x01, 0x10, /* Time: Second */ \ 172 | PHYSICAL_MAXIMUM_3, 0xff, 0xff, 0x00, 0x00, \ 173 | LOGICAL_MAXIMUM_3, 0xff, 0xff, 0x00, 0x00, \ 174 | USAGE, 0x56, /* Usage: Scan Time */ \ 175 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 176 | USAGE, 0x54, /* Usage: Contact Count */ \ 177 | LOGICAL_MAXIMUM, 0x7f, \ 178 | REPORT_SIZE, 0x08, \ 179 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 180 | USAGE_PAGE, 0x09, /* Usage Page: Button */ \ 181 | USAGE, 0x01, /* Button 1 */ \ 182 | LOGICAL_MAXIMUM, 0x01, \ 183 | REPORT_SIZE, 0x01, \ 184 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 185 | REPORT_COUNT, 0x07, \ 186 | INPUT, 0x03, /* Input: (Const, Var, Abs) */ \ 187 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 188 | REPORT_ID, REPORTID_DEVICE_CAPS, \ 189 | USAGE, 0x55, /* Usage: Maximum Contacts */ \ 190 | USAGE, 0x59, /* Usage: Touchpad Button Type*/ \ 191 | LOGICAL_MINIMUM, 0x00, \ 192 | LOGICAL_MAXIMUM_2, 0xff, 0x00, \ 193 | REPORT_SIZE, 0x08, \ 194 | REPORT_COUNT, 0x02, \ 195 | FEATURE, 0x02, \ 196 | USAGE_PAGE_1, 0x00, 0xff, \ 197 | REPORT_ID, REPORTID_PTPHQA, \ 198 | USAGE, 0xc5, \ 199 | LOGICAL_MINIMUM, 0x00, \ 200 | LOGICAL_MAXIMUM_2, 0xff, 0x00, \ 201 | REPORT_SIZE, 0x08, \ 202 | REPORT_COUNT_2, 0x00, 0x01, \ 203 | FEATURE, 0x02, \ 204 | END_COLLECTION /* End Collection */ 205 | 206 | #define SYNAPTICS_TOUCHSCREEN_TLC \ 207 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 208 | USAGE, 0x04, /* Usage: Touch Screen */ \ 209 | BEGIN_COLLECTION, 0x01, /* Begin Collection: Application */ \ 210 | REPORT_ID, REPORTID_MULTITOUCH, /* Report ID: Multi-touch */ \ 211 | USAGE, 0x22, /* Usage: Finger */ \ 212 | SYNAPTICS_PTP_FINGER_COLLECTION_1, /* 1 */ \ 213 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 214 | USAGE, 0x22, /* Usage: Finger */ \ 215 | SYNAPTICS_PTP_FINGER_COLLECTION_1, /* 2 */ \ 216 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 217 | USAGE, 0x22, /* Usage: Finger */ \ 218 | SYNAPTICS_PTP_FINGER_COLLECTION_2, /* 3 */ \ 219 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 220 | USAGE, 0x22, /* Usage: Finger */ \ 221 | SYNAPTICS_PTP_FINGER_COLLECTION_1, /* 4 */ \ 222 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 223 | USAGE, 0x22, /* Usage: Finger */ \ 224 | SYNAPTICS_PTP_FINGER_COLLECTION_2, /* 5 */ \ 225 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 226 | UNIT_EXPONENT, 0x0c, /* Unit exponent: -4 */ \ 227 | UNIT_2, 0x01, 0x10, /* Time: Second */ \ 228 | PHYSICAL_MAXIMUM_3, 0xff, 0xff, 0x00, 0x00, \ 229 | LOGICAL_MAXIMUM_3, 0xff, 0xff, 0x00, 0x00, \ 230 | USAGE, 0x56, /* Usage: Scan Time */ \ 231 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 232 | USAGE, 0x54, /* Usage: Contact Count */ \ 233 | LOGICAL_MAXIMUM, 0x7f, \ 234 | REPORT_SIZE, 0x08, \ 235 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 236 | USAGE_PAGE, 0x09, /* Usage Page: Button */ \ 237 | USAGE, 0x01, /* Button 1 */ \ 238 | LOGICAL_MAXIMUM, 0x01, \ 239 | REPORT_SIZE, 0x01, \ 240 | INPUT, 0x02, /* Input: (Data, Var, Abs) */ \ 241 | REPORT_COUNT, 0x07, \ 242 | INPUT, 0x03, /* Input: (Const, Var, Abs) */ \ 243 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 244 | REPORT_ID, REPORTID_DEVICE_CAPS, \ 245 | USAGE, 0x55, /* Usage: Maximum Contacts */ \ 246 | USAGE, 0x59, /* Usage: Touchpad Button Type*/ \ 247 | LOGICAL_MINIMUM, 0x00, \ 248 | LOGICAL_MAXIMUM_2, 0xff, 0x00, \ 249 | REPORT_SIZE, 0x08, \ 250 | REPORT_COUNT, 0x02, \ 251 | FEATURE, 0x02, \ 252 | USAGE_PAGE_1, 0x00, 0xff, \ 253 | REPORT_ID, REPORTID_PTPHQA, \ 254 | USAGE, 0xc5, \ 255 | LOGICAL_MINIMUM, 0x00, \ 256 | LOGICAL_MAXIMUM_2, 0xff, 0x00, \ 257 | REPORT_SIZE, 0x08, \ 258 | REPORT_COUNT_2, 0x00, 0x01, \ 259 | FEATURE, 0x02, \ 260 | END_COLLECTION /* End Collection */ 261 | 262 | #define SYNAPTICS_CONFIGURATION_TLC \ 263 | USAGE_PAGE, 0x0d, /* Usage Page: Digitizer */ \ 264 | USAGE, 0x0e, /* Usage: Configuration */ \ 265 | BEGIN_COLLECTION, 0x01, /* Begin Collection: Application */ \ 266 | REPORT_ID, REPORTID_REPORTMODE, /* Report ID: Mode Selection */ \ 267 | USAGE, 0x22, /* Usage: Finger */ \ 268 | BEGIN_COLLECTION, 0x02, /* Begin Collection: Logical */ \ 269 | USAGE, 0x52, /* Usage: Input Mode */ \ 270 | LOGICAL_MINIMUM, 0x00, /* Logical Minumum: 0 finger */ \ 271 | LOGICAL_MAXIMUM, MAX_FINGERS, /* Logical Maximum: MAX_TOUCH_COUNT fingers */ \ 272 | REPORT_SIZE, 0x08, /* Report Size: 0x08 */ \ 273 | REPORT_COUNT, 0x01, /* Report Count: 0x01 */ \ 274 | FEATURE, 0x02, /* Feature: (Data, Var, Abs) */ \ 275 | END_COLLECTION, /* End Collection */ \ 276 | BEGIN_COLLECTION, 0x00, /* Begin Collection: Physical */ \ 277 | REPORT_ID, REPORTID_FUNCSWITCH, /* Report ID: Function Switch */ \ 278 | USAGE, BUTTON_SWITCH, /* Usage: Button Switch */ \ 279 | USAGE, SURFACE_SWITCH, /* Usage: Surface Switch */ \ 280 | REPORT_SIZE, 0x01, /* Report Size: 0x01 */ \ 281 | REPORT_COUNT, 0x02, /* Report Count: 0x02 */ \ 282 | LOGICAL_MAXIMUM, 0x01, /* Logical Maximum: 0x01 */ \ 283 | FEATURE, 0x02, /* Feature: (Data, Var, Abs) */ \ 284 | REPORT_COUNT, 0x06, /* Report Count: 0x06 */ \ 285 | FEATURE, 0x03, /* Feature: (Const, Var, Abs) */ \ 286 | END_COLLECTION, /* End Collection */ \ 287 | END_COLLECTION /* End Collection */ 288 | 289 | #define DEFAULT_PTP_HQA_BLOB \ 290 | 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87, \ 291 | 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88, \ 292 | 0x07, 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6, \ 293 | 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2, \ 294 | 0x2e, 0x84, 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43, \ 295 | 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc, \ 296 | 0x47, 0x70, 0x1b, 0x59, 0x6f, 0x74, 0x43, 0xc4, \ 297 | 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71, \ 298 | 0xc7, 0x95, 0x0e, 0x31, 0x55, 0x21, 0xd3, 0xb5, \ 299 | 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19, \ 300 | 0x3e, 0xb3, 0xaf, 0x75, 0x81, 0x9d, 0x53, 0xb9, \ 301 | 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c, \ 302 | 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d, 0xa7, 0x26, \ 303 | 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b, \ 304 | 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0, 0x2a, \ 305 | 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8, \ 306 | 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1, \ 307 | 0x0b, 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7, \ 308 | 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b, \ 309 | 0xe8, 0x8a, 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35, \ 310 | 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc, \ 311 | 0x2b, 0x53, 0x5c, 0x69, 0x52, 0xd5, 0xc8, 0x73, \ 312 | 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff, \ 313 | 0x05, 0xd8, 0x2b, 0x79, 0x9a, 0xe2, 0x34, 0x60, \ 314 | 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc, \ 315 | 0x80, 0xe3, 0x0f, 0xbd, 0x65, 0x20, 0x08, 0x13, \ 316 | 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7, \ 317 | 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe, 0x31, 0x48, \ 318 | 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89, \ 319 | 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a, 0xe4, \ 320 | 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08, \ 321 | 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2 322 | 323 | typedef struct _PTP_DEVICE_CAPS_FEATURE_REPORT { 324 | UCHAR ReportID; 325 | UCHAR MaximumContactPoints; 326 | UCHAR ButtonType; 327 | } PTP_DEVICE_CAPS_FEATURE_REPORT, *PPTP_DEVICE_CAPS_FEATURE_REPORT; 328 | 329 | typedef struct _PTP_DEVICE_HQA_CERTIFICATION_REPORT { 330 | UCHAR ReportID; 331 | UCHAR CertificationBlob[256]; 332 | } PTP_DEVICE_HQA_CERTIFICATION_REPORT, *PPTP_DEVICE_HQA_CERTIFICATION_REPORT; 333 | 334 | typedef struct _PTP_DEVICE_INPUT_MODE_REPORT { 335 | UCHAR ReportID; 336 | UCHAR Mode; 337 | } PTP_DEVICE_INPUT_MODE_REPORT, *PPTP_DEVICE_INPUT_MODE_REPORT; 338 | 339 | #pragma pack(push) 340 | #pragma pack(1) 341 | typedef struct _PTP_DEVICE_SELECTIVE_REPORT_MODE_REPORT { 342 | UCHAR ReportID; 343 | UCHAR DeviceMode; 344 | UCHAR ButtonReport : 1; 345 | UCHAR SurfaceReport : 1; 346 | UCHAR Padding : 6; 347 | } PTP_DEVICE_SELECTIVE_REPORT_MODE_REPORT, *PPTP_DEVICE_SELECTIVE_REPORT_MODE_REPORT; 348 | #pragma pack(pop) 349 | -------------------------------------------------------------------------------- /src/resolutions.c: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | resolutions.c 8 | 9 | Abstract: 10 | 11 | This module retrieves platform-specific configuration 12 | parameters from the registry, and translates touch 13 | controller pixel units to display pixel units. 14 | 15 | Environment: 16 | 17 | Kernel Mode 18 | 19 | Revision History: 20 | 21 | --*/ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | // 28 | // Registry values explaining the relationship of the touch 29 | // controller coordinates to the physical LCD, as well as 30 | // any differences between the physical LCD dimensons and 31 | // viewable LCD area, are required. If not provided for whatever 32 | // reason, we will assume everything is 480x800 and perfectly 33 | // aligned. 34 | // 35 | 36 | TOUCH_SCREEN_PROPERTIES gDefaultProperties = 37 | { 38 | 0, 39 | 0, 40 | 0, 41 | TOUCH_DEFAULT_RESOLUTION_X, 42 | TOUCH_DEFAULT_RESOLUTION_Y, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | TOUCH_DEFAULT_RESOLUTION_X, 51 | TOUCH_DEFAULT_RESOLUTION_Y, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 0, 57 | 0, 58 | 0, 59 | TOUCH_DEFAULT_RESOLUTION_X, 60 | TOUCH_DEFAULT_RESOLUTION_Y 61 | }; 62 | 63 | 64 | RTL_QUERY_REGISTRY_TABLE gResParamsRegTable[] = 65 | { 66 | { 67 | NULL, RTL_QUERY_REGISTRY_DIRECT, 68 | L"TouchSwapAxes", 69 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchSwapAxes), 70 | REG_DWORD, 71 | &gDefaultProperties.TouchSwapAxes, 72 | sizeof(ULONG) 73 | }, 74 | { 75 | NULL, RTL_QUERY_REGISTRY_DIRECT, 76 | L"TouchInvertXAxis", 77 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchInvertXAxis), 78 | REG_DWORD, 79 | &gDefaultProperties.TouchInvertXAxis, 80 | sizeof(ULONG) 81 | }, 82 | { 83 | NULL, RTL_QUERY_REGISTRY_DIRECT, 84 | L"TouchInvertYAxis", 85 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchInvertYAxis), 86 | REG_DWORD, 87 | &gDefaultProperties.TouchInvertYAxis, 88 | sizeof(ULONG) 89 | }, 90 | { 91 | NULL, RTL_QUERY_REGISTRY_DIRECT, 92 | L"TouchPhysicalWidth", 93 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchPhysicalWidth), 94 | REG_DWORD, 95 | &gDefaultProperties.TouchPhysicalWidth, 96 | sizeof(ULONG) 97 | }, 98 | { 99 | NULL, RTL_QUERY_REGISTRY_DIRECT, 100 | L"TouchPhysicalHeight", 101 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchPhysicalHeight), 102 | REG_DWORD, 103 | &gDefaultProperties.TouchPhysicalHeight, 104 | sizeof(ULONG) 105 | }, 106 | { 107 | NULL, RTL_QUERY_REGISTRY_DIRECT, 108 | L"TouchPhysicalButtonHeight", 109 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchPhysicalButtonHeight), 110 | REG_DWORD, 111 | &gDefaultProperties.TouchPhysicalButtonHeight, 112 | sizeof(ULONG) 113 | }, 114 | { 115 | NULL, RTL_QUERY_REGISTRY_DIRECT, 116 | L"TouchPillarBoxWidthLeft", 117 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchPillarBoxWidthLeft), 118 | REG_DWORD, 119 | &gDefaultProperties.TouchPillarBoxWidthLeft, 120 | sizeof(ULONG) 121 | }, 122 | { 123 | NULL, RTL_QUERY_REGISTRY_DIRECT, 124 | L"TouchPillarBoxWidthRight", 125 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchPillarBoxWidthRight), 126 | REG_DWORD, 127 | &gDefaultProperties.TouchPillarBoxWidthRight, 128 | sizeof(ULONG) 129 | }, 130 | { 131 | NULL, RTL_QUERY_REGISTRY_DIRECT, 132 | L"TouchLetterBoxHeightTop", 133 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchLetterBoxHeightTop), 134 | REG_DWORD, 135 | &gDefaultProperties.TouchLetterBoxHeightTop, 136 | sizeof(ULONG) 137 | }, 138 | { 139 | NULL, RTL_QUERY_REGISTRY_DIRECT, 140 | L"TouchLetterBoxHeightBottom", 141 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, TouchLetterBoxHeightBottom), 142 | REG_DWORD, 143 | &gDefaultProperties.TouchLetterBoxHeightBottom, 144 | sizeof(ULONG) 145 | }, 146 | { 147 | NULL, RTL_QUERY_REGISTRY_DIRECT, 148 | L"DisplayPhysicalWidth", 149 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayPhysicalWidth), 150 | REG_DWORD, 151 | &gDefaultProperties.DisplayPhysicalWidth, 152 | sizeof(ULONG) 153 | }, 154 | { 155 | NULL, RTL_QUERY_REGISTRY_DIRECT, 156 | L"DisplayPhysicalHeight", 157 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayPhysicalHeight), 158 | REG_DWORD, 159 | &gDefaultProperties.DisplayPhysicalHeight, 160 | sizeof(ULONG) 161 | }, 162 | { 163 | NULL, RTL_QUERY_REGISTRY_DIRECT, 164 | L"DisplayViewableWidth", 165 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayViewableWidth), 166 | REG_DWORD, 167 | &gDefaultProperties.DisplayViewableWidth, 168 | sizeof(ULONG) 169 | }, 170 | { 171 | NULL, RTL_QUERY_REGISTRY_DIRECT, 172 | L"DisplayViewableHeight", 173 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayViewableHeight), 174 | REG_DWORD, 175 | &gDefaultProperties.DisplayViewableHeight, 176 | sizeof(ULONG) 177 | }, 178 | { 179 | NULL, RTL_QUERY_REGISTRY_DIRECT, 180 | L"DisplayPillarBoxWidthLeft", 181 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayPillarBoxWidthLeft), 182 | REG_DWORD, 183 | &gDefaultProperties.DisplayPillarBoxWidthLeft, 184 | sizeof(ULONG) 185 | }, 186 | { 187 | NULL, RTL_QUERY_REGISTRY_DIRECT, 188 | L"DisplayPillarBoxWidthRight", 189 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayPillarBoxWidthRight), 190 | REG_DWORD, 191 | &gDefaultProperties.DisplayPillarBoxWidthRight, 192 | sizeof(ULONG) 193 | }, 194 | { 195 | NULL, RTL_QUERY_REGISTRY_DIRECT, 196 | L"DisplayLetterBoxHeightTop", 197 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayLetterBoxHeightTop), 198 | REG_DWORD, 199 | &gDefaultProperties.DisplayLetterBoxHeightTop, 200 | sizeof(ULONG) 201 | }, 202 | { 203 | NULL, RTL_QUERY_REGISTRY_DIRECT, 204 | L"DisplayLetterBoxHeightBottom", 205 | (PVOID) FIELD_OFFSET(TOUCH_SCREEN_PROPERTIES, DisplayLetterBoxHeightBottom), 206 | REG_DWORD, 207 | &gDefaultProperties.DisplayLetterBoxHeightBottom, 208 | sizeof(ULONG) 209 | }, 210 | // 211 | // List Terminator - set to NULL to indicate end of table 212 | // 213 | { 214 | NULL, 0, 215 | NULL, 216 | 0, 217 | REG_DWORD, 218 | NULL, 219 | 0 220 | } 221 | }; 222 | 223 | static const ULONG gcbRegistryTable = sizeof(gResParamsRegTable); 224 | static const ULONG gcRegistryTable = 225 | sizeof(gResParamsRegTable) / sizeof(gResParamsRegTable[0]); 226 | 227 | 228 | VOID 229 | TchTranslateToDisplayCoordinates( 230 | IN PUSHORT PX, 231 | IN PUSHORT PY, 232 | IN PTOUCH_SCREEN_PROPERTIES Props 233 | ) 234 | /*++ 235 | 236 | Routine Description: 237 | 238 | This routine performs translations on touch coordinates 239 | to ensure points reported to the OS match pixels on the 240 | display. 241 | 242 | Arguments: 243 | 244 | X - pointer to the pre-processed X coordinate 245 | Y - pointer the pre-processed Y coordinate 246 | Props - pointer to screen information 247 | 248 | Return Value: 249 | 250 | None. The X/Y values will be modified by this function. 251 | 252 | --*/ 253 | { 254 | ULONG X; 255 | ULONG Y; 256 | 257 | // 258 | // Avoid overflow 259 | // 260 | X = (ULONG) *PX; 261 | Y = (ULONG) *PY; 262 | 263 | // 264 | // Swap the axes reported by the touch controller if requested 265 | // 266 | if (Props->TouchSwapAxes) 267 | { 268 | ULONG temp = Y; 269 | Y = X; 270 | X = temp; 271 | } 272 | 273 | // 274 | // Invert the coordinates as requested 275 | // 276 | if (Props->TouchInvertXAxis) 277 | { 278 | if (X >= Props->TouchPhysicalWidth) 279 | { 280 | X = Props->TouchPhysicalWidth - 1u; 281 | } 282 | 283 | X = Props->TouchPhysicalWidth - X - 1u; 284 | } 285 | if (Props->TouchInvertYAxis) 286 | { 287 | if (Y >= Props->TouchPhysicalHeight) 288 | { 289 | Y = Props->TouchPhysicalHeight - 1u; 290 | } 291 | 292 | Y = Props->TouchPhysicalHeight - Y - 1u; 293 | } 294 | 295 | // 296 | // Handle touch clipping boundaries so touch matches 297 | // the physical display 298 | // 299 | if (X <= Props->TouchPillarBoxWidthLeft) 300 | { 301 | X = 0; 302 | } 303 | else 304 | { 305 | X -= Props->TouchPillarBoxWidthLeft; 306 | } 307 | if (Y <= Props->TouchLetterBoxHeightTop) 308 | { 309 | Y = 0; 310 | } 311 | else 312 | { 313 | Y -= Props->TouchLetterBoxHeightTop; 314 | } 315 | if (X >= Props->TouchAdjustedWidth) 316 | { 317 | X = Props->TouchAdjustedWidth - 1u; 318 | } 319 | if (Y >= Props->TouchAdjustedHeight) 320 | { 321 | Y = Props->TouchAdjustedHeight - 1u; 322 | } 323 | 324 | // 325 | // Scale the raw touch pixel units into physical display pixels, 326 | // leaving off the capacitive button region. 327 | // 328 | X = X * Props->DisplayPhysicalWidth / Props->TouchAdjustedWidth; 329 | Y = Y * Props->DisplayPhysicalHeight / 330 | (Props->TouchAdjustedHeight - Props->TouchPhysicalButtonHeight); 331 | 332 | // 333 | // If the display is additionally being letterboxed or pillarboxed, make 334 | // further adjustments to the touch coordinates. 335 | // 336 | if (X <= Props->DisplayPillarBoxWidthLeft) 337 | { 338 | X = 0; 339 | } 340 | else 341 | { 342 | X -= Props->DisplayPillarBoxWidthLeft; 343 | } 344 | if (Y <= Props->DisplayLetterBoxHeightTop) 345 | { 346 | Y = 0; 347 | } 348 | else 349 | { 350 | Y -= Props->DisplayLetterBoxHeightTop; 351 | } 352 | if (X >= Props->DisplayAdjustedWidth) 353 | { 354 | X = Props->DisplayAdjustedWidth - 1u; 355 | } 356 | if (Y >= Props->DisplayAdjustedHeight) 357 | { 358 | Y = Props->DisplayAdjustedHeight - 1u; 359 | } 360 | 361 | X = X * Props->DisplayViewableWidth / Props->DisplayAdjustedWidth; 362 | Y = Y * Props->DisplayViewableHeight / 363 | (Props->DisplayAdjustedHeight - Props->DisplayAdjustedButtonHeight); 364 | 365 | Trace( 366 | TRACE_LEVEL_INFORMATION, 367 | TRACE_REPORTING, 368 | "In (%d,%d), Out (%d,%d)", 369 | *PX, *PY, X, Y); 370 | 371 | *PX = (USHORT) X; 372 | *PY = (USHORT) Y; 373 | } 374 | 375 | VOID 376 | TchGetScreenProperties( 377 | IN PTOUCH_SCREEN_PROPERTIES Props 378 | ) 379 | /*++ 380 | 381 | Routine Description: 382 | 383 | This routine retrieves coordinate translation settings 384 | from the registry. 385 | 386 | Arguments: 387 | 388 | Props - receives the Props 389 | 390 | Return Value: 391 | 392 | None. On failure, defaults are returned. 393 | 394 | --*/ 395 | { 396 | ULONG i; 397 | PRTL_QUERY_REGISTRY_TABLE regTable; 398 | NTSTATUS status; 399 | 400 | regTable = NULL; 401 | 402 | // 403 | // Table passed to RtlQueryRegistryValues must be allocated 404 | // from NonPagedPoolNx 405 | // 406 | regTable = ExAllocatePoolWithTag( 407 | NonPagedPoolNx, 408 | gcbRegistryTable, 409 | TOUCH_POOL_TAG); 410 | 411 | RtlCopyMemory( 412 | regTable, 413 | gResParamsRegTable, 414 | gcbRegistryTable); 415 | 416 | // 417 | // Update offset values with base pointer 418 | // 419 | for (i=0; i < gcRegistryTable-1; i++) 420 | { 421 | regTable[i].EntryContext = (PVOID) ( 422 | ((SIZE_T) regTable[i].EntryContext) + 423 | ((ULONG_PTR) Props)); 424 | } 425 | 426 | // 427 | // Start with default values 428 | // 429 | RtlCopyMemory( 430 | Props, 431 | &gDefaultProperties, 432 | sizeof(TOUCH_SCREEN_PROPERTIES)); 433 | 434 | // 435 | // Populate device context with registry overrides (or defaults) 436 | // 437 | status = RtlQueryRegistryValues( 438 | RTL_REGISTRY_ABSOLUTE, 439 | TOUCH_SCREEN_PROPERTIES_REG_KEY, 440 | regTable, 441 | NULL, 442 | NULL); 443 | 444 | if (!NT_SUCCESS(status)) 445 | { 446 | Trace( 447 | TRACE_LEVEL_WARNING, 448 | TRACE_REGISTRY, 449 | "Error retrieving registry configuration - %!STATUS!", 450 | status); 451 | } 452 | 453 | // 454 | // Sanity check values provided from the registry 455 | // 456 | 457 | if (Props->TouchPillarBoxWidthLeft + 458 | Props->TouchPillarBoxWidthRight >= 459 | Props->TouchPhysicalWidth) 460 | { 461 | Trace( 462 | TRACE_LEVEL_ERROR, 463 | TRACE_REGISTRY, 464 | "Invalid pillar box widths provided (%d,%d for %d)", 465 | Props->TouchPillarBoxWidthLeft, 466 | Props->TouchPillarBoxWidthRight, 467 | Props->TouchPhysicalWidth); 468 | 469 | Props->TouchPillarBoxWidthLeft = 470 | gDefaultProperties.TouchPillarBoxWidthLeft; 471 | Props->TouchPillarBoxWidthRight = 472 | gDefaultProperties.TouchPillarBoxWidthRight; 473 | 474 | } 475 | 476 | if (Props->TouchLetterBoxHeightTop + 477 | Props->TouchLetterBoxHeightBottom >= 478 | Props->TouchPhysicalHeight) 479 | { 480 | Trace( 481 | TRACE_LEVEL_ERROR, 482 | TRACE_REGISTRY, 483 | "Invalid letter box heights provided (%d,%d for %d)", 484 | Props->TouchLetterBoxHeightTop, 485 | Props->TouchLetterBoxHeightBottom, 486 | Props->TouchPhysicalHeight); 487 | 488 | Props->TouchLetterBoxHeightTop = 489 | gDefaultProperties.TouchLetterBoxHeightTop; 490 | Props->TouchLetterBoxHeightBottom = 491 | gDefaultProperties.TouchLetterBoxHeightBottom; 492 | } 493 | 494 | // 495 | // Calculate a few parameters for later use 496 | // 497 | Props->TouchAdjustedWidth = 498 | Props->TouchPhysicalWidth - 499 | Props->TouchPillarBoxWidthLeft - 500 | Props->TouchPillarBoxWidthRight; 501 | 502 | Props->TouchAdjustedHeight = 503 | Props->TouchPhysicalHeight - 504 | Props->TouchLetterBoxHeightTop - 505 | Props->TouchLetterBoxHeightBottom; 506 | 507 | Props->DisplayAdjustedWidth = 508 | Props->DisplayPhysicalWidth - 509 | Props->DisplayPillarBoxWidthLeft - 510 | Props->DisplayPillarBoxWidthRight; 511 | 512 | Props->DisplayAdjustedButtonHeight = 513 | Props->TouchPhysicalButtonHeight * 514 | Props->DisplayPhysicalHeight / 515 | (Props->TouchAdjustedHeight - Props->TouchPhysicalButtonHeight); 516 | 517 | Props->DisplayAdjustedHeight = 518 | Props->DisplayPhysicalHeight - 519 | Props->DisplayLetterBoxHeightTop - 520 | Props->DisplayLetterBoxHeightBottom + 521 | Props->DisplayAdjustedButtonHeight; 522 | 523 | if (regTable != NULL) 524 | { 525 | ExFreePoolWithTag(regTable, TOUCH_POOL_TAG); 526 | } 527 | } -------------------------------------------------------------------------------- /include/rmiinternal.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All Rights Reserved. 3 | Sample code. Dealpoint ID #843729. 4 | 5 | Module Name: 6 | 7 | rmiinternal.h 8 | 9 | Abstract: 10 | 11 | Contains common types and defintions used internally 12 | by the multi touch screen driver. 13 | 14 | Environment: 15 | 16 | Kernel mode 17 | 18 | Revision History: 19 | 20 | --*/ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include "controller.h" 27 | #include "resolutions.h" 28 | #include "bitops.h" 29 | #include "hweight.h" 30 | 31 | // Ignore warning C4152: nonstandard extension, function/data pointer conversion in expression 32 | #pragma warning (disable : 4152) 33 | 34 | // Ignore warning C4201: nonstandard extension used : nameless struct/union 35 | #pragma warning (disable : 4201) 36 | 37 | // Ignore warning C4201: nonstandard extension used : bit field types other than in 38 | #pragma warning (disable : 4214) 39 | 40 | // Ignore warning C4324: 'xxx' : structure was padded due to __declspec(align()) 41 | #pragma warning (disable : 4324) 42 | 43 | 44 | // 45 | // Defines from Synaptics RMI4 Data Sheet, please refer to 46 | // the spec for details about the fields and values. 47 | // 48 | 49 | #define RMI4_FIRST_FUNCTION_ADDRESS 0xE9 50 | #define RMI4_PAGE_SELECT_ADDRESS 0xFF 51 | 52 | #define RMI4_F01_RMI_DEVICE_CONTROL 0x01 53 | #define RMI4_F12_2D_TOUCHPAD_SENSOR 0x12 54 | #define RMI4_F1A_0D_CAP_BUTTON_SENSOR 0x1A 55 | #define RMI4_F34_FLASH_MEMORY_MANAGEMENT 0x34 56 | #define RMI4_F54_TEST_REPORTING 0x54 57 | 58 | #define RMI4_MAX_FUNCTIONS 10 59 | #define RMI4_MAX_TOUCHES 32 60 | 61 | typedef struct _RMI4_FUNCTION_DESCRIPTOR 62 | { 63 | BYTE QueryBase; 64 | BYTE CommandBase; 65 | BYTE ControlBase; 66 | BYTE DataBase; 67 | union 68 | { 69 | BYTE All; 70 | struct 71 | { 72 | BYTE IrqCount : 3; 73 | BYTE Reserved0 : 2; 74 | BYTE FuncVer : 2; 75 | BYTE Reserved1 : 1; 76 | }; 77 | } VersionIrq; 78 | BYTE Number; 79 | } RMI4_FUNCTION_DESCRIPTOR; 80 | 81 | // 82 | // Function $01 - RMI Device Control 83 | // 84 | 85 | typedef struct _RMI4_F01_QUERY_REGISTERS 86 | { 87 | BYTE ManufacturerID; 88 | union 89 | { 90 | BYTE All; 91 | struct 92 | { 93 | BYTE CustomMap : 1; 94 | BYTE NonCompliant : 1; 95 | BYTE Reserved0 : 1; 96 | BYTE HasSensorID : 1; 97 | BYTE Reserved1 : 1; 98 | BYTE HasAdjDoze : 1; 99 | BYTE HasAdJDozeHold : 1; 100 | BYTE Reserved2 : 1; 101 | }; 102 | } ProductProperties; 103 | BYTE ProductInfo0; 104 | BYTE ProductInfo1; 105 | BYTE Date0; 106 | BYTE Date1; 107 | BYTE WaferLotId0Lo; 108 | BYTE WaferLotId0Hi; 109 | BYTE WaferLotId1Lo; 110 | BYTE WaferLotId1Hi; 111 | BYTE WaferLotId2Lo; 112 | BYTE ProductID1; 113 | BYTE ProductID2; 114 | BYTE ProductID3; 115 | BYTE ProductID4; 116 | BYTE ProductID5; 117 | BYTE ProductID6; 118 | BYTE ProductID7; 119 | BYTE ProductID8; 120 | BYTE ProductID9; 121 | BYTE ProductID10; 122 | BYTE Reserved21; 123 | BYTE SendorID; 124 | BYTE Reserved23; 125 | BYTE Reserved24; 126 | BYTE Reserved25; 127 | BYTE Reserved26; 128 | BYTE Reserved27; 129 | BYTE Reserved28; 130 | BYTE Reserved29; 131 | BYTE Reserved30; 132 | BYTE Reserved31; 133 | } RMI4_F01_QUERY_REGISTERS; 134 | 135 | typedef struct _RMI4_F01_CTRL_REGISTERS 136 | { 137 | union 138 | { 139 | BYTE All; 140 | struct 141 | { 142 | BYTE SleepMode :2; 143 | BYTE NoSleep :1; 144 | BYTE Reserved0 :3; 145 | BYTE ReportRate :1; 146 | BYTE Configured :1; 147 | }; 148 | } DeviceControl; 149 | BYTE InterruptEnable; 150 | BYTE DozeInterval; 151 | BYTE DozeThreshold; 152 | BYTE DozeHoldoff; 153 | } RMI4_F01_CTRL_REGISTERS; 154 | 155 | #define RMI4_F01_DEVICE_CONTROL_SLEEP_MODE_OPERATING 0 156 | #define RMI4_F01_DEVICE_CONTROL_SLEEP_MODE_SLEEPING 1 157 | 158 | // 159 | // Logical structure for getting registry config settings 160 | // 161 | typedef struct _RM4_F01_CTRL_REGISTERS_LOGICAL 162 | { 163 | UINT32 SleepMode; 164 | UINT32 NoSleep; 165 | UINT32 ReportRate; 166 | UINT32 Configured; 167 | UINT32 InterruptEnable; 168 | UINT32 DozeInterval; 169 | UINT32 DozeThreshold; 170 | UINT32 DozeHoldoff; 171 | } RMI4_F01_CTRL_REGISTERS_LOGICAL; 172 | 173 | #define RMI4_MILLISECONDS_TO_TENTH_MILLISECONDS(n) n/10 174 | #define RMI4_SECONDS_TO_HALF_SECONDS(n) 2*n 175 | 176 | typedef struct _RMI4_F01_DATA_REGISTERS 177 | { 178 | union { 179 | BYTE All; 180 | struct 181 | { 182 | BYTE Status : 4; 183 | BYTE Reserved0 : 2; 184 | BYTE FlashProg : 1; 185 | BYTE Unconfigured : 1; 186 | }; 187 | } DeviceStatus; 188 | BYTE InterruptStatus[1]; 189 | } RMI4_F01_DATA_REGISTERS; 190 | 191 | #define RMI4_INTERRUPT_BIT_2D_TOUCH 0x04 192 | #define RMI4_INTERRUPT_BIT_0D_CAP_BUTTON 0x20 193 | 194 | #define RMI4_F01_DATA_STATUS_NO_ERROR 0 195 | #define RMI4_F01_DATA_STATUS_RESET_OCCURRED 1 196 | #define RMI4_F01_DATA_STATUS_INVALID_CONFIG 2 197 | #define RMI4_F01_DATA_STATUS_DEVICE_FAILURE 3 198 | #define RMI4_F01_DATA_STATUS_CONFIG_CRC_FAILURE 4 199 | #define RMI4_F01_DATA_STATUS_FW_CRC_FAILURE 5 200 | #define RMI4_F01_DATA_STATUS_CRC_IN_PROGRESS 6 201 | 202 | typedef struct _RMI4_F01_COMMAND_REGISTERS 203 | { 204 | BYTE Reset; 205 | } RMI4_F01_COMMAND_REGISTERS; 206 | 207 | // 208 | // Function $11 - 2-D Touch Sensor 209 | // 210 | 211 | // 212 | // Logical structure for getting registry config settings 213 | // 214 | typedef struct _RMI4_F11_CTRL_REGISTERS_LOGICAL 215 | { 216 | UINT32 ReportingMode; 217 | UINT32 AbsPosFilt; 218 | UINT32 RelPosFilt; 219 | UINT32 RelBallistics; 220 | UINT32 Dribble; 221 | UINT32 PalmDetectThreshold; 222 | UINT32 MotionSensitivity; 223 | UINT32 ManTrackEn; 224 | UINT32 ManTrackedFinger; 225 | UINT32 DeltaXPosThreshold; 226 | UINT32 DeltaYPosThreshold; 227 | UINT32 Velocity; 228 | UINT32 Acceleration; 229 | UINT32 SensorMaxXPos; 230 | UINT32 SensorMaxYPos; 231 | UINT32 ZTouchThreshold; 232 | UINT32 ZHysteresis; 233 | UINT32 SmallZThreshold; 234 | UINT32 SmallZScaleFactor; 235 | UINT32 LargeZScaleFactor; 236 | UINT32 AlgorithmSelection; 237 | UINT32 WxScaleFactor; 238 | UINT32 WxOffset; 239 | UINT32 WyScaleFactor; 240 | UINT32 WyOffset; 241 | UINT32 XPitch; 242 | UINT32 YPitch; 243 | UINT32 FingerWidthX; 244 | UINT32 FingerWidthY; 245 | UINT32 ReportMeasuredSize; 246 | UINT32 SegmentationSensitivity; 247 | UINT32 XClipLo; 248 | UINT32 XClipHi; 249 | UINT32 YClipLo; 250 | UINT32 YClipHi; 251 | UINT32 MinFingerSeparation; 252 | UINT32 MaxFingerMovement; 253 | } RMI4_F11_CTRL_REGISTERS_LOGICAL; 254 | 255 | typedef struct _RMI4_F11_DATA_POSITION 256 | { 257 | int X; 258 | int Y; 259 | } RMI4_F11_DATA_POSITION; 260 | 261 | typedef struct _RMI4_F11_DATA_REGISTERS_STATUS_BLOCK 262 | { 263 | struct 264 | { 265 | BYTE FingerState0 : 2; 266 | BYTE FingerState1 : 2; 267 | BYTE FingerState2 : 2; 268 | BYTE FingerState3 : 2; 269 | }; 270 | struct 271 | { 272 | BYTE FingerState4 : 2; 273 | BYTE FingerState5 : 2; 274 | BYTE FingerState6 : 2; 275 | BYTE FingerState7 : 2; 276 | }; 277 | struct 278 | { 279 | BYTE FingerState8 : 2; 280 | BYTE FingerState9 : 2; 281 | BYTE Reserved0 : 4; 282 | }; 283 | } RMI4_F11_DATA_REGISTERS_STATUS_BLOCK; 284 | 285 | typedef struct _RMI4_F11_DATA_REGISTERS 286 | { 287 | RMI4_F11_DATA_REGISTERS_STATUS_BLOCK Status; 288 | RMI4_F11_DATA_POSITION Finger[RMI4_MAX_TOUCHES]; 289 | } RMI4_F11_DATA_REGISTERS; 290 | 291 | #define RMI4_FINGER_STATE_NOT_PRESENT 0 292 | #define RMI4_FINGER_STATE_PRESENT_WITH_ACCURATE_POS 1 293 | #define RMI4_FINGER_STATE_PRESENT_WITH_INACCURATE_POS 2 294 | #define RMI4_FINGER_STATE_RESERVED 3 295 | 296 | // 297 | // Function $12 - 2-D Touch Sensor 298 | // 299 | 300 | typedef enum _RMI4_F12_OBJECT_TYPE { 301 | RMI_F12_OBJECT_NONE = 0x00, 302 | RMI_F12_OBJECT_FINGER = 0x01, 303 | RMI_F12_OBJECT_STYLUS = 0x02, 304 | RMI_F12_OBJECT_PALM = 0x03, 305 | RMI_F12_OBJECT_UNCLASSIFIED = 0x04, 306 | RMI_F12_OBJECT_GLOVED_FINGER = 0x06, 307 | RMI_F12_OBJECT_NARROW_OBJECT = 0x07, 308 | RMI_F12_OBJECT_HAND_EDGE = 0x08, 309 | RMI_F12_OBJECT_COVER = 0x0A, 310 | RMI_F12_OBJECT_STYLUS_2 = 0x0B, 311 | RMI_F12_OBJECT_ERASER = 0x0C, 312 | RMI_F12_OBJECT_SMALL_OBJECT = 0x0D, 313 | } RMI4_F12_OBJECT_TYPE; 314 | 315 | #define F12_DATA1_BYTES_PER_OBJ 8 316 | #define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE) 317 | #define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE) 318 | 319 | #define RMI_F12_REPORTING_MODE_CONTINUOUS 0 320 | #define RMI_F12_REPORTING_MODE_REDUCED 1 321 | #define RMI_F12_REPORTING_MODE_MASK 7 322 | 323 | #define F12_2D_CTRL20 20 324 | 325 | /* describes a single packet register */ 326 | typedef struct _RMI_REGISTER_DESC_ITEM { 327 | USHORT Register; 328 | ULONG RegisterSize; 329 | BYTE NumSubPackets; 330 | ULONG SubPacketMap[BITS_TO_LONGS(RMI_REG_DESC_SUBPACKET_BITS)]; 331 | } RMI_REGISTER_DESC_ITEM, *PRMI_REGISTER_DESC_ITEM; 332 | 333 | /* 334 | * describes the packet registers for a particular type 335 | * (ie query, control, data) 336 | */ 337 | typedef struct _RMI_REGISTER_DESCRIPTOR { 338 | ULONG StructSize; 339 | ULONG PresenceMap[BITS_TO_LONGS(RMI_REG_DESC_PRESENSE_BITS)]; 340 | UINT8 NumRegisters; 341 | RMI_REGISTER_DESC_ITEM *Registers; 342 | } RMI_REGISTER_DESCRIPTOR, *PRMI_REGISTER_DESCRIPTOR; 343 | 344 | typedef enum _RMI_2D_SENSOR_OBJECT_TYPE { 345 | RMI_2D_OBJECT_NONE, 346 | RMI_2D_OBJECT_FINGER, 347 | RMI_2D_OBJECT_STYLUS, 348 | RMI_2D_OBJECT_PALM, 349 | RMI_2D_OBJECT_UNCLASSIFIED, 350 | } RMI_2D_SENSOR_OBJECT_TYPE; 351 | 352 | typedef struct _RMI_2D_SENSOR_ABS_OBJECT { 353 | RMI_2D_SENSOR_OBJECT_TYPE Type; 354 | int MtTool; 355 | USHORT X; 356 | USHORT Y; 357 | BYTE Z; 358 | BYTE wX; 359 | BYTE wY; 360 | } RMI_2D_SENSOR_ABS_OBJECT, *PRMI_2D_SENSOR_ABS_OBJECT; 361 | 362 | // 363 | // Function $1A - 0-D Capacitive Button Sensors 364 | // 365 | 366 | typedef struct _RMI4_F1A_QUERY_REGISTERS 367 | { 368 | struct 369 | { 370 | BYTE MaxButtonCount : 2; 371 | BYTE Reserved0 : 5; 372 | }; 373 | struct 374 | { 375 | BYTE HasGenControl : 1; 376 | BYTE HasIntEnable : 1; 377 | BYTE HasMultiButSel : 1; 378 | BYTE HasTxRxMapping : 1; 379 | BYTE HasPerButThresh : 1; 380 | BYTE HasRelThresh : 1; 381 | BYTE HasStrongButHyst: 1; 382 | BYTE HasFiltStrength : 1; 383 | }; 384 | } RMI4_F1A_QUERY_REGISTERS; 385 | 386 | typedef struct _RMI4_F1A_CTRL_REGISTERS 387 | { 388 | struct 389 | { 390 | BYTE MultiButtonRpt : 2; 391 | BYTE FilterMode : 2; 392 | BYTE Reserved0 : 4; 393 | }; 394 | struct 395 | { 396 | BYTE IntEnBtn0 : 1; 397 | BYTE IntEnBtn1 : 1; 398 | BYTE IntEnBtn2 : 1; 399 | BYTE IntEnBtn3 : 1; 400 | BYTE Reserved1 : 4; 401 | }; 402 | struct 403 | { 404 | BYTE MultiBtn0 : 1; 405 | BYTE MultiBtn1 : 1; 406 | BYTE MultiBtn2 : 1; 407 | BYTE MultiBtn3 : 1; 408 | BYTE Reserved2 : 4; 409 | }; 410 | BYTE PhysicalTx0; 411 | BYTE PhysicalRx0; 412 | BYTE PhysicalTx1; 413 | BYTE PhysicalRx1; 414 | BYTE PhysicalTx2; 415 | BYTE PhysicalRx2; 416 | BYTE PhysicalTx3; 417 | BYTE PhysicalRx3; 418 | BYTE Threshold0; 419 | BYTE Threshold1; 420 | BYTE Threshold2; 421 | BYTE Threshold3; 422 | BYTE ReleaseThreshold; 423 | BYTE StrongButtonHyst; 424 | BYTE FilterStrength; 425 | } RMI4_F1A_CTRL_REGISTERS; 426 | 427 | typedef struct _RMI4_F1A_DATA_REGISTERS 428 | { 429 | struct 430 | { 431 | BYTE Button0 : 1; 432 | BYTE Button1 : 1; 433 | BYTE Button2 : 1; 434 | BYTE Button3 : 1; 435 | BYTE Reserved0 : 4; 436 | }; 437 | } RMI4_F1A_DATA_REGISTERS; 438 | 439 | // 440 | // Function $XX - Add new support functions here 441 | // 442 | 443 | 444 | // 445 | // Driver structures 446 | // 447 | 448 | typedef struct _RMI4_CONFIGURATION 449 | { 450 | RMI4_F01_CTRL_REGISTERS_LOGICAL DeviceSettings; 451 | RMI4_F11_CTRL_REGISTERS_LOGICAL TouchSettings; 452 | UINT32 PepRemovesVoltageInD3; 453 | } RMI4_CONFIGURATION; 454 | 455 | typedef struct _RMI4_FINGER_INFO 456 | { 457 | int x; 458 | int y; 459 | UCHAR fingerStatus; 460 | } RMI4_FINGER_INFO; 461 | 462 | typedef struct _RMI4_FINGER_CACHE 463 | { 464 | RMI4_FINGER_INFO FingerSlot[RMI4_MAX_TOUCHES]; 465 | UINT32 FingerSlotValid; 466 | UINT32 FingerSlotDirty; 467 | int FingerDownOrder[RMI4_MAX_TOUCHES]; 468 | int FingerDownCount; 469 | ULONG64 ScanTime; 470 | } RMI4_FINGER_CACHE; 471 | 472 | typedef struct _RMI4_CONTROLLER_CONTEXT 473 | { 474 | WDFDEVICE FxDevice; 475 | WDFWAITLOCK ControllerLock; 476 | 477 | // 478 | // Controller state 479 | // 480 | int FunctionCount; 481 | RMI4_FUNCTION_DESCRIPTOR Descriptors[RMI4_MAX_FUNCTIONS]; 482 | int FunctionOnPage[RMI4_MAX_FUNCTIONS]; 483 | int CurrentPage; 484 | 485 | ULONG InterruptStatus; 486 | BOOLEAN HasButtons; 487 | BOOLEAN ResetOccurred; 488 | BOOLEAN InvalidConfiguration; 489 | BOOLEAN DeviceFailure; 490 | BOOLEAN UnknownStatus; 491 | BYTE UnknownStatusMessage; 492 | RMI4_F01_QUERY_REGISTERS F01QueryRegisters; 493 | 494 | // 495 | // Power state 496 | // 497 | DEVICE_POWER_STATE DevicePowerState; 498 | 499 | // 500 | // Register configuration programmed to chip 501 | // 502 | TOUCH_SCREEN_PROPERTIES Props; 503 | RMI4_CONFIGURATION Config; 504 | 505 | // 506 | // Current touch state 507 | // 508 | int TouchesReported; 509 | int TouchesTotal; 510 | RMI4_FINGER_CACHE Cache; 511 | 512 | // 513 | // RMI4 F12 state 514 | // 515 | 516 | BOOLEAN HasDribble; 517 | RMI_REGISTER_DESCRIPTOR QueryRegDesc; 518 | RMI_REGISTER_DESCRIPTOR ControlRegDesc; 519 | RMI_REGISTER_DESCRIPTOR DataRegDesc; 520 | size_t PacketSize; 521 | 522 | USHORT Data1Offset; 523 | BYTE MaxFingers; 524 | BYTE MaxFingerObjects; 525 | 526 | } RMI4_CONTROLLER_CONTEXT; 527 | 528 | NTSTATUS 529 | RmiCheckInterrupts( 530 | IN RMI4_CONTROLLER_CONTEXT *ControllerContext, 531 | IN SPB_CONTEXT *SpbContext, 532 | IN ULONG* InterruptStatus 533 | ); 534 | 535 | NTSTATUS 536 | RmiSetReportingMode( 537 | IN RMI4_CONTROLLER_CONTEXT* ControllerContext, 538 | IN SPB_CONTEXT *SpbContext, 539 | IN UCHAR ReportingMode, 540 | OUT OPTIONAL UCHAR *OldMode 541 | ); 542 | 543 | int 544 | RmiGetFunctionIndex( 545 | IN RMI4_FUNCTION_DESCRIPTOR* FunctionDescriptors, 546 | IN int FunctionCount, 547 | IN int FunctionDesired 548 | ); 549 | 550 | NTSTATUS 551 | RmiChangePage( 552 | IN RMI4_CONTROLLER_CONTEXT* ControllerContext, 553 | IN SPB_CONTEXT* SpbContext, 554 | IN int DesiredPage 555 | ); 556 | 557 | NTSTATUS 558 | RmiReadRegisterDescriptor( 559 | IN SPB_CONTEXT *Context, 560 | IN UCHAR Address, 561 | IN PRMI_REGISTER_DESCRIPTOR Rdesc 562 | ); 563 | 564 | size_t 565 | RmiRegisterDescriptorCalcSize( 566 | IN PRMI_REGISTER_DESCRIPTOR Rdesc 567 | ); 568 | 569 | const PRMI_REGISTER_DESC_ITEM RmiGetRegisterDescItem( 570 | PRMI_REGISTER_DESCRIPTOR Rdesc, 571 | USHORT reg 572 | ); 573 | 574 | UINT8 RmiGetRegisterIndex( 575 | PRMI_REGISTER_DESCRIPTOR Rdesc, 576 | USHORT reg 577 | ); -------------------------------------------------------------------------------- /src/hid.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // 11 | // HID Report Descriptor for a touch device 12 | // 13 | 14 | const UCHAR gReportDescriptor[] = { 15 | SYNAPTICS_TOUCHSCREEN_TLC, 16 | SYNAPTICS_CONFIGURATION_TLC 17 | }; 18 | const ULONG gdwcbReportDescriptor = sizeof(gReportDescriptor); 19 | 20 | // 21 | // HID Descriptor for a touch device 22 | // 23 | const HID_DESCRIPTOR gHidDescriptor = 24 | { 25 | sizeof(HID_DESCRIPTOR), //bLength 26 | HID_HID_DESCRIPTOR_TYPE, //bDescriptorType 27 | HID_REVISION, //bcdHID 28 | 0, //bCountry - not localized 29 | 1, //bNumDescriptors 30 | { //DescriptorList[0] 31 | HID_REPORT_DESCRIPTOR_TYPE, //bReportType 32 | sizeof(gReportDescriptor) //wReportLength 33 | } 34 | }; 35 | 36 | NTSTATUS 37 | TchReadReport( 38 | IN WDFDEVICE Device, 39 | IN WDFREQUEST Request, 40 | OUT BOOLEAN *Pending 41 | ) 42 | /*++ 43 | 44 | Routine Description: 45 | 46 | Handles read requests from HIDCLASS, by forwarding the request. 47 | 48 | Arguments: 49 | 50 | Device - Handle to WDF Device Object 51 | 52 | Request - Handle to request object 53 | 54 | Pending - flag to monitor if the request was sent down the stack 55 | 56 | Return Value: 57 | 58 | On success, the function returns STATUS_SUCCESS 59 | On failure it passes the relevant error code to the caller. 60 | 61 | --*/ 62 | { 63 | PDEVICE_EXTENSION devContext; 64 | NTSTATUS status; 65 | 66 | devContext = GetDeviceContext(Device); 67 | 68 | status = WdfRequestForwardToIoQueue( 69 | Request, 70 | devContext->PingPongQueue); 71 | 72 | if (!NT_SUCCESS(status)) 73 | { 74 | Trace( 75 | TRACE_LEVEL_ERROR, 76 | TRACE_HID, 77 | "Failed to forward HID request to I/O queue - %!STATUS!", 78 | status); 79 | 80 | goto exit; 81 | } 82 | 83 | if (NULL != Pending) 84 | { 85 | *Pending = TRUE; 86 | } 87 | 88 | // 89 | // Service any interrupt that may have asserted while the framework had 90 | // interrupts disabled, or occurred before a read request was queued. 91 | // 92 | if (devContext->ServiceInterruptsAfterD0Entry == TRUE) 93 | { 94 | PTP_REPORT ptpReport; 95 | BOOLEAN servicingComplete = FALSE; 96 | 97 | while (servicingComplete == FALSE) 98 | { 99 | TchServiceInterrupts( 100 | devContext->TouchContext, 101 | &devContext->I2CContext, 102 | &ptpReport, 103 | devContext->InputMode, 104 | &servicingComplete); 105 | } 106 | 107 | devContext->ServiceInterruptsAfterD0Entry = FALSE; 108 | } 109 | 110 | exit: 111 | 112 | return status; 113 | } 114 | 115 | NTSTATUS 116 | TchGetString( 117 | IN WDFDEVICE Device, 118 | IN WDFREQUEST Request 119 | ) 120 | /*++ 121 | 122 | Routine Description: 123 | 124 | Returns string requested by the HIDCLASS driver 125 | 126 | Arguments: 127 | 128 | Device - Handle to WDF Device Object 129 | 130 | Request - Handle to request object 131 | 132 | Return Value: 133 | 134 | NTSTATUS indicating success or failure 135 | 136 | --*/ 137 | { 138 | PIRP irp; 139 | PIO_STACK_LOCATION irpSp; 140 | ULONG_PTR lenId; 141 | NTSTATUS status; 142 | PWSTR strId; 143 | 144 | UNREFERENCED_PARAMETER(Device); 145 | 146 | status = STATUS_SUCCESS; 147 | 148 | irp = WdfRequestWdmGetIrp(Request); 149 | irpSp = IoGetCurrentIrpStackLocation(irp); 150 | switch ((ULONG_PTR)irpSp->Parameters.DeviceIoControl.Type3InputBuffer & 151 | 0xffff) 152 | { 153 | case HID_STRING_ID_IMANUFACTURER: 154 | strId = gpwstrManufacturerID; 155 | break; 156 | 157 | case HID_STRING_ID_IPRODUCT: 158 | strId = gpwstrProductID; 159 | break; 160 | 161 | case HID_STRING_ID_ISERIALNUMBER: 162 | strId = gpwstrSerialNumber; 163 | break; 164 | 165 | default: 166 | strId = NULL; 167 | break; 168 | } 169 | 170 | lenId = strId ? (wcslen(strId)*sizeof(WCHAR) + sizeof(UNICODE_NULL)) : 0; 171 | if (strId == NULL) 172 | { 173 | status = STATUS_INVALID_PARAMETER; 174 | } 175 | else if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < lenId) 176 | { 177 | status = STATUS_BUFFER_TOO_SMALL; 178 | } 179 | else 180 | { 181 | RtlCopyMemory(irp->UserBuffer, strId, lenId); 182 | irp->IoStatus.Information = lenId; 183 | } 184 | 185 | if (!NT_SUCCESS(status)) 186 | { 187 | Trace( 188 | TRACE_LEVEL_ERROR, 189 | TRACE_HID, 190 | "Error getting device string - %!STATUS!", 191 | status); 192 | } 193 | 194 | return status; 195 | } 196 | 197 | NTSTATUS 198 | TchGetHidDescriptor( 199 | IN WDFDEVICE Device, 200 | IN WDFREQUEST Request 201 | ) 202 | /*++ 203 | 204 | Routine Description: 205 | 206 | Finds the HID descriptor and copies it into the buffer provided by the 207 | Request. 208 | 209 | Arguments: 210 | 211 | Device - Handle to WDF Device Object 212 | 213 | Request - Handle to request object 214 | 215 | Return Value: 216 | 217 | NTSTATUS indicating success or failure 218 | 219 | --*/ 220 | { 221 | WDFMEMORY memory; 222 | NTSTATUS status; 223 | 224 | UNREFERENCED_PARAMETER(Device); 225 | 226 | // 227 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 228 | // will correctly retrieve buffer from Irp->UserBuffer. 229 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 230 | // field irrespective of the ioctl buffer type. However, framework is very 231 | // strict about type checking. You cannot get Irp->UserBuffer by using 232 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 233 | // internal ioctl. 234 | // 235 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 236 | 237 | if (!NT_SUCCESS(status)) 238 | { 239 | Trace( 240 | TRACE_LEVEL_ERROR, 241 | TRACE_HID, 242 | "Error getting HID descriptor request memory - %!STATUS!", 243 | status); 244 | goto exit; 245 | } 246 | 247 | // 248 | // Use hardcoded global HID Descriptor 249 | // 250 | status = WdfMemoryCopyFromBuffer( 251 | memory, 252 | 0, 253 | (PUCHAR) &gHidDescriptor, 254 | sizeof(gHidDescriptor)); 255 | 256 | if (!NT_SUCCESS(status)) 257 | { 258 | Trace( 259 | TRACE_LEVEL_ERROR, 260 | TRACE_HID, 261 | "Error copying HID descriptor to request memory - %!STATUS!", 262 | status); 263 | goto exit; 264 | } 265 | 266 | // 267 | // Report how many bytes were copied 268 | // 269 | WdfRequestSetInformation(Request, sizeof(gHidDescriptor)); 270 | 271 | exit: 272 | 273 | return status; 274 | } 275 | 276 | NTSTATUS 277 | TchGetReportDescriptor( 278 | IN WDFDEVICE Device, 279 | IN WDFREQUEST Request 280 | ) 281 | /*++ 282 | 283 | Routine Description: 284 | 285 | Finds the report descriptor and copies it into the buffer provided by the 286 | Request. 287 | 288 | Arguments: 289 | 290 | Device - Handle to WDF Device Object 291 | 292 | Request - Handle to request object 293 | 294 | Return Value: 295 | 296 | NT status code. 297 | success - STATUS_SUCCESS 298 | failure: 299 | STATUS_INVALID_PARAMETER - An invalid parameter was detected. 300 | 301 | --*/ 302 | { 303 | WDFMEMORY memory; 304 | NTSTATUS status; 305 | 306 | UNREFERENCED_PARAMETER(Device); 307 | 308 | // 309 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 310 | // will correctly retrieve buffer from Irp->UserBuffer. 311 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 312 | // field irrespective of the ioctl buffer type. However, framework is very 313 | // strict about type checking. You cannot get Irp->UserBuffer by using 314 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 315 | // internal ioctl. 316 | // 317 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 318 | 319 | if (!NT_SUCCESS(status)) 320 | { 321 | Trace( 322 | TRACE_LEVEL_ERROR, 323 | TRACE_HID, 324 | "Error getting HID report descriptor request memory - %!STATUS!", 325 | status); 326 | goto exit; 327 | } 328 | 329 | // 330 | // Use hardcoded Report descriptor 331 | // 332 | status = WdfMemoryCopyFromBuffer( 333 | memory, 334 | 0, 335 | (PUCHAR) gReportDescriptor, 336 | gdwcbReportDescriptor); 337 | 338 | if (!NT_SUCCESS(status)) 339 | { 340 | Trace( 341 | TRACE_LEVEL_ERROR, 342 | TRACE_HID, 343 | "Error copying HID report descriptor to request memory - %!STATUS!", 344 | status); 345 | goto exit; 346 | } 347 | 348 | // 349 | // Report how many bytes were copied 350 | // 351 | WdfRequestSetInformation(Request, gdwcbReportDescriptor); 352 | 353 | exit: 354 | 355 | return status; 356 | } 357 | 358 | NTSTATUS 359 | TchGetDeviceAttributes( 360 | IN WDFREQUEST Request 361 | ) 362 | /*++ 363 | 364 | Routine Description: 365 | 366 | Fill in the given struct _HID_DEVICE_ATTRIBUTES 367 | 368 | Arguments: 369 | 370 | Request - Pointer to Request object. 371 | 372 | Return Value: 373 | 374 | NTSTATUS indicating success or failure 375 | 376 | --*/ 377 | { 378 | PHID_DEVICE_ATTRIBUTES deviceAttributes; 379 | NTSTATUS status; 380 | 381 | // 382 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 383 | // will correctly retrieve buffer from Irp->UserBuffer. 384 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 385 | // field irrespective of the ioctl buffer type. However, framework is very 386 | // strict about type checking. You cannot get Irp->UserBuffer by using 387 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 388 | // internal ioctl. 389 | // 390 | status = WdfRequestRetrieveOutputBuffer( 391 | Request, 392 | sizeof (HID_DEVICE_ATTRIBUTES), 393 | &deviceAttributes, 394 | NULL); 395 | 396 | if (!NT_SUCCESS(status)) 397 | { 398 | Trace( 399 | TRACE_LEVEL_ERROR, 400 | TRACE_HID, 401 | "Error retrieving device attribute output buffer - %!STATUS!", 402 | status); 403 | goto exit; 404 | } 405 | 406 | deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES); 407 | deviceAttributes->VendorID = gOEMVendorID; 408 | deviceAttributes->ProductID = gOEMProductID; 409 | deviceAttributes->VersionNumber = gOEMVersionID; 410 | 411 | // 412 | // Report how many bytes were copied 413 | // 414 | WdfRequestSetInformation(Request, sizeof (HID_DEVICE_ATTRIBUTES)); 415 | 416 | exit: 417 | 418 | return status; 419 | } 420 | 421 | NTSTATUS 422 | TchSetFeatureReport( 423 | IN WDFDEVICE Device, 424 | IN WDFREQUEST Request 425 | ) 426 | /*++ 427 | 428 | Routine Description: 429 | 430 | Emulates setting a HID Feature report 431 | 432 | Arguments: 433 | 434 | Device - Framework device object 435 | Request - Framework request object 436 | 437 | Return Value: 438 | 439 | NTSTATUS indicating success or failure 440 | 441 | --*/ 442 | { 443 | PDEVICE_EXTENSION devContext; 444 | PHID_XFER_PACKET featurePacket; 445 | WDF_REQUEST_PARAMETERS params; 446 | NTSTATUS status; 447 | 448 | devContext = GetDeviceContext(Device); 449 | status = STATUS_SUCCESS; 450 | 451 | // 452 | // Validate Request Parameters 453 | // 454 | 455 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 456 | WdfRequestGetParameters(Request, ¶ms); 457 | 458 | if (params.Parameters.DeviceIoControl.InputBufferLength < 459 | sizeof(HID_XFER_PACKET)) 460 | { 461 | status = STATUS_BUFFER_TOO_SMALL; 462 | goto exit; 463 | } 464 | 465 | featurePacket = 466 | (PHID_XFER_PACKET) WdfRequestWdmGetIrp(Request)->UserBuffer; 467 | 468 | if (featurePacket == NULL) 469 | { 470 | status = STATUS_INVALID_DEVICE_REQUEST; 471 | goto exit; 472 | } 473 | 474 | // 475 | // Process Request 476 | // 477 | 478 | switch (*(PUCHAR)featurePacket->reportBuffer) 479 | { 480 | case REPORTID_REPORTMODE: 481 | { 482 | Trace( 483 | TRACE_LEVEL_INFORMATION, 484 | TRACE_DRIVER, 485 | "%!FUNC! Report REPORTID_REPORTMODE is requested" 486 | ); 487 | 488 | PPTP_DEVICE_INPUT_MODE_REPORT DeviceInputMode = (PPTP_DEVICE_INPUT_MODE_REPORT) featurePacket->reportBuffer; 489 | switch (DeviceInputMode->Mode) 490 | { 491 | case PTP_COLLECTION_MOUSE: 492 | { 493 | Trace( 494 | TRACE_LEVEL_INFORMATION, 495 | TRACE_DRIVER, 496 | "%!FUNC! Report REPORTID_REPORTMODE requested Mouse Input" 497 | ); 498 | 499 | devContext->PtpInputOn = FALSE; 500 | break; 501 | } 502 | case PTP_COLLECTION_WINDOWS: 503 | { 504 | 505 | Trace( 506 | TRACE_LEVEL_INFORMATION, 507 | TRACE_DRIVER, 508 | "%!FUNC! Report REPORTID_REPORTMODE requested Windows PTP Input" 509 | ); 510 | 511 | devContext->PtpInputOn = TRUE; 512 | break; 513 | } 514 | } 515 | 516 | Trace( 517 | TRACE_LEVEL_INFORMATION, 518 | TRACE_DRIVER, 519 | "%!FUNC! Report REPORTID_REPORTMODE is fulfilled" 520 | ); 521 | break; 522 | } 523 | case REPORTID_FUNCSWITCH: 524 | { 525 | Trace( 526 | TRACE_LEVEL_INFORMATION, 527 | TRACE_DRIVER, 528 | "%!FUNC! Report REPORTID_FUNCSWITCH is requested" 529 | ); 530 | 531 | PPTP_DEVICE_SELECTIVE_REPORT_MODE_REPORT InputSelection = (PPTP_DEVICE_SELECTIVE_REPORT_MODE_REPORT) featurePacket->reportBuffer; 532 | devContext->PtpReportButton = InputSelection->ButtonReport; 533 | devContext->PtpReportTouch = InputSelection->SurfaceReport; 534 | 535 | Trace( 536 | TRACE_LEVEL_INFORMATION, 537 | TRACE_DRIVER, 538 | "%!FUNC! Report REPORTID_FUNCSWITCH requested Button = %d, Surface = %d", 539 | InputSelection->ButtonReport, 540 | InputSelection->SurfaceReport 541 | ); 542 | 543 | Trace( 544 | TRACE_LEVEL_INFORMATION, 545 | TRACE_DRIVER, 546 | "%!FUNC! Report REPORTID_FUNCSWITCH is fulfilled" 547 | ); 548 | 549 | break; 550 | } 551 | default: 552 | { 553 | Trace( 554 | TRACE_LEVEL_INFORMATION, 555 | TRACE_DRIVER, 556 | "%!FUNC! Unsupported type %d is requested", 557 | featurePacket->reportId 558 | ); 559 | 560 | status = STATUS_NOT_SUPPORTED; 561 | goto exit; 562 | } 563 | } 564 | 565 | exit: 566 | 567 | return status; 568 | } 569 | 570 | NTSTATUS 571 | TchGetFeatureReport( 572 | IN WDFDEVICE Device, 573 | IN WDFREQUEST Request 574 | ) 575 | /*++ 576 | 577 | Routine Description: 578 | 579 | Emulates retrieval of a HID Feature report 580 | 581 | Arguments: 582 | 583 | Device - Framework device object 584 | Request - Framework request object 585 | 586 | Return Value: 587 | 588 | NTSTATUS indicating success or failure 589 | 590 | --*/ 591 | { 592 | PDEVICE_EXTENSION devContext; 593 | PHID_XFER_PACKET featurePacket; 594 | WDF_REQUEST_PARAMETERS params; 595 | NTSTATUS status; 596 | size_t ReportSize; 597 | 598 | devContext = GetDeviceContext(Device); 599 | status = STATUS_SUCCESS; 600 | 601 | // 602 | // Validate Request Parameters 603 | // 604 | 605 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 606 | WdfRequestGetParameters(Request, ¶ms); 607 | 608 | if (params.Parameters.DeviceIoControl.OutputBufferLength < 609 | sizeof(HID_XFER_PACKET)) 610 | { 611 | status = STATUS_BUFFER_TOO_SMALL; 612 | goto exit; 613 | } 614 | 615 | featurePacket = 616 | (PHID_XFER_PACKET) WdfRequestWdmGetIrp(Request)->UserBuffer; 617 | 618 | if (featurePacket == NULL) 619 | { 620 | status = STATUS_INVALID_DEVICE_REQUEST; 621 | goto exit; 622 | } 623 | 624 | // 625 | // Process Request 626 | // 627 | 628 | switch (*(PUCHAR)featurePacket->reportBuffer) 629 | { 630 | case REPORTID_DEVICE_CAPS: 631 | { 632 | Trace( 633 | TRACE_LEVEL_INFORMATION, 634 | TRACE_DRIVER, 635 | "%!FUNC! Report REPORTID_DEVICE_CAPS is requested" 636 | ); 637 | 638 | // Size sanity check 639 | ReportSize = sizeof(PTP_DEVICE_CAPS_FEATURE_REPORT); 640 | if (featurePacket->reportBufferLen < ReportSize) { 641 | status = STATUS_INVALID_BUFFER_SIZE; 642 | Trace( 643 | TRACE_LEVEL_ERROR, 644 | TRACE_DRIVER, 645 | "%!FUNC! Report buffer is too small" 646 | ); 647 | goto exit; 648 | } 649 | 650 | PPTP_DEVICE_CAPS_FEATURE_REPORT capsReport = (PPTP_DEVICE_CAPS_FEATURE_REPORT) featurePacket->reportBuffer; 651 | 652 | capsReport->MaximumContactPoints = PTP_MAX_CONTACT_POINTS; 653 | capsReport->ButtonType = PTP_BUTTON_TYPE_CLICK_PAD; 654 | capsReport->ReportID = REPORTID_DEVICE_CAPS; 655 | 656 | Trace( 657 | TRACE_LEVEL_INFORMATION, 658 | TRACE_DRIVER, 659 | "%!FUNC! Report REPORTID_DEVICE_CAPS has maximum contact points of %d", 660 | capsReport->MaximumContactPoints 661 | ); 662 | Trace( 663 | TRACE_LEVEL_INFORMATION, 664 | TRACE_DRIVER, 665 | "%!FUNC! Report REPORTID_DEVICE_CAPS has touchpad type %d", 666 | capsReport->ButtonType 667 | ); 668 | Trace( 669 | TRACE_LEVEL_INFORMATION, 670 | TRACE_DRIVER, 671 | "%!FUNC! Report REPORTID_DEVICE_CAPS is fulfilled" 672 | ); 673 | 674 | break; 675 | } 676 | case REPORTID_PTPHQA: 677 | { 678 | Trace( 679 | TRACE_LEVEL_INFORMATION, 680 | TRACE_DRIVER, 681 | "%!FUNC! Report REPORTID_PTPHQA is requested" 682 | ); 683 | 684 | // Size sanity check 685 | ReportSize = sizeof(PTP_DEVICE_HQA_CERTIFICATION_REPORT); 686 | if (featurePacket->reportBufferLen < ReportSize) 687 | { 688 | status = STATUS_INVALID_BUFFER_SIZE; 689 | Trace( 690 | TRACE_LEVEL_ERROR, 691 | TRACE_DRIVER, 692 | "%!FUNC! Report buffer is too small." 693 | ); 694 | goto exit; 695 | } 696 | 697 | PPTP_DEVICE_HQA_CERTIFICATION_REPORT certReport = (PPTP_DEVICE_HQA_CERTIFICATION_REPORT) featurePacket->reportBuffer; 698 | 699 | *certReport->CertificationBlob = DEFAULT_PTP_HQA_BLOB; 700 | certReport->ReportID = REPORTID_PTPHQA; 701 | 702 | Trace( 703 | TRACE_LEVEL_INFORMATION, 704 | TRACE_DRIVER, 705 | "%!FUNC! Report REPORTID_PTPHQA is fulfilled" 706 | ); 707 | 708 | break; 709 | } 710 | default: 711 | { 712 | Trace( 713 | TRACE_LEVEL_INFORMATION, 714 | TRACE_DRIVER, 715 | "%!FUNC! Unsupported type %d is requested", 716 | featurePacket->reportId 717 | ); 718 | 719 | status = STATUS_NOT_SUPPORTED; 720 | goto exit; 721 | } 722 | } 723 | 724 | exit: 725 | 726 | return status; 727 | } 728 | -------------------------------------------------------------------------------- /src/report.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All Rights Reserved. 2 | // Copyright (c) Bingxing Wang. All Rights Reserved. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | const USHORT gOEMVendorID = 0x7379; // "sy" 12 | const USHORT gOEMProductID = 0x726D; // "rm" 13 | const USHORT gOEMVersionID = 3400; 14 | 15 | const PWSTR gpwstrManufacturerID = L"Synaptics"; 16 | const PWSTR gpwstrProductID = L"3400"; 17 | const PWSTR gpwstrSerialNumber = L"4"; 18 | 19 | NTSTATUS 20 | RmiGetTouchesFromController( 21 | IN VOID *ControllerContext, 22 | IN SPB_CONTEXT *SpbContext, 23 | IN RMI4_F11_DATA_REGISTERS *Data 24 | ) 25 | /*++ 26 | 27 | Routine Description: 28 | 29 | This routine reads raw touch messages from hardware. If there is 30 | no touch data available (if a non-touch interrupt fired), the 31 | function will not return success and no touch data was transferred. 32 | 33 | Arguments: 34 | 35 | ControllerContext - Touch controller context 36 | SpbContext - A pointer to the current i2c context 37 | Data - A pointer to any returned F11 touch data 38 | 39 | Return Value: 40 | 41 | NTSTATUS, where only success indicates data was returned 42 | 43 | --*/ 44 | { 45 | NTSTATUS status; 46 | RMI4_CONTROLLER_CONTEXT* controller; 47 | 48 | int index, i, x, y, fingers; 49 | 50 | BYTE fingerStatus[RMI4_MAX_TOUCHES] = { 0 }; 51 | BYTE* data1; 52 | BYTE* controllerData; 53 | 54 | controller = (RMI4_CONTROLLER_CONTEXT*) ControllerContext; 55 | 56 | // 57 | // Locate RMI data base address of 2D touch function 58 | // 59 | index = RmiGetFunctionIndex( 60 | controller->Descriptors, 61 | controller->FunctionCount, 62 | RMI4_F12_2D_TOUCHPAD_SENSOR); 63 | 64 | if (index == controller->FunctionCount) 65 | { 66 | Trace( 67 | TRACE_LEVEL_ERROR, 68 | TRACE_INIT, 69 | "Unexpected - RMI Function 12 missing"); 70 | 71 | status = STATUS_INVALID_DEVICE_STATE; 72 | goto exit; 73 | } 74 | 75 | status = RmiChangePage( 76 | ControllerContext, 77 | SpbContext, 78 | controller->FunctionOnPage[index]); 79 | 80 | if (!NT_SUCCESS(status)) 81 | { 82 | Trace( 83 | TRACE_LEVEL_ERROR, 84 | TRACE_INIT, 85 | "Could not change register page"); 86 | 87 | goto exit; 88 | } 89 | 90 | controllerData = ExAllocatePoolWithTag( 91 | NonPagedPoolNx, 92 | controller->PacketSize, 93 | TOUCH_POOL_TAG_F12 94 | ); 95 | 96 | if (controllerData == NULL) 97 | { 98 | status = STATUS_INSUFFICIENT_RESOURCES; 99 | goto exit; 100 | } 101 | 102 | // 103 | // Packets we need is determined by context 104 | // 105 | status = SpbReadDataSynchronously( 106 | SpbContext, 107 | controller->Descriptors[index].DataBase, 108 | controllerData, 109 | (ULONG) controller->PacketSize 110 | ); 111 | 112 | if (!NT_SUCCESS(status)) 113 | { 114 | Trace( 115 | TRACE_LEVEL_ERROR, 116 | TRACE_INTERRUPT, 117 | "Error reading finger status data - %!STATUS!", 118 | status); 119 | 120 | goto free_buffer; 121 | } 122 | 123 | data1 = &controllerData[controller->Data1Offset]; 124 | fingers = 0; 125 | 126 | if (data1 != NULL) 127 | { 128 | for (i = 0; i < controller->MaxFingers; i++) 129 | { 130 | switch (data1[0]) 131 | { 132 | case RMI_F12_OBJECT_FINGER: 133 | case RMI_F12_OBJECT_STYLUS: 134 | fingerStatus[i] = RMI4_FINGER_STATE_PRESENT_WITH_ACCURATE_POS; 135 | fingers++; 136 | break; 137 | default: 138 | fingerStatus[i] = RMI4_FINGER_STATE_NOT_PRESENT; 139 | break; 140 | } 141 | 142 | x = (data1[2] << 8) | data1[1]; 143 | y = (data1[4] << 8) | data1[3]; 144 | 145 | Data->Finger[i].X = x; 146 | Data->Finger[i].Y = y; 147 | 148 | data1 += F12_DATA1_BYTES_PER_OBJ; 149 | } 150 | } 151 | else 152 | { 153 | Trace( 154 | TRACE_LEVEL_ERROR, 155 | TRACE_INTERRUPT, 156 | "Error reading finger status data - empty buffer" 157 | ); 158 | 159 | goto free_buffer; 160 | } 161 | 162 | // Synchronize status back 163 | Data->Status.FingerState0 = fingerStatus[0]; 164 | Data->Status.FingerState1 = fingerStatus[1]; 165 | Data->Status.FingerState2 = fingerStatus[2]; 166 | Data->Status.FingerState3 = fingerStatus[3]; 167 | Data->Status.FingerState4 = fingerStatus[4]; 168 | Data->Status.FingerState5 = fingerStatus[5]; 169 | Data->Status.FingerState6 = fingerStatus[6]; 170 | Data->Status.FingerState7 = fingerStatus[7]; 171 | Data->Status.FingerState8 = fingerStatus[8]; 172 | Data->Status.FingerState9 = fingerStatus[9]; 173 | 174 | free_buffer: 175 | ExFreePoolWithTag( 176 | controllerData, 177 | TOUCH_POOL_TAG_F12 178 | ); 179 | 180 | exit: 181 | return status; 182 | } 183 | 184 | VOID 185 | RmiUpdateLocalFingerCache( 186 | IN RMI4_F11_DATA_REGISTERS *Data, 187 | IN RMI4_FINGER_CACHE *Cache 188 | ) 189 | /*++ 190 | 191 | Routine Description: 192 | 193 | This routine takes raw data reported by the Synaptics hardware and 194 | parses it to update a local cache of finger states. This routine manages 195 | removing lifted touches from the cache, and manages a map between the 196 | order of reported touches in hardware, and the order the driver should 197 | use in reporting. 198 | 199 | Arguments: 200 | 201 | Data - A pointer to the new data returned from hardware 202 | Cache - A data structure holding various current finger state info 203 | 204 | Return Value: 205 | 206 | None. 207 | 208 | --*/ 209 | { 210 | int fingerStatus[RMI4_MAX_TOUCHES] = {0}; 211 | int i, j; 212 | 213 | // 214 | // Unpack the finger statuses into an array to ease dealing with each 215 | // finger uniformly in loops 216 | // 217 | fingerStatus[0] = Data->Status.FingerState0; 218 | fingerStatus[1] = Data->Status.FingerState1; 219 | fingerStatus[2] = Data->Status.FingerState2; 220 | fingerStatus[3] = Data->Status.FingerState3; 221 | fingerStatus[4] = Data->Status.FingerState4; 222 | fingerStatus[5] = Data->Status.FingerState5; 223 | fingerStatus[6] = Data->Status.FingerState6; 224 | fingerStatus[7] = Data->Status.FingerState7; 225 | fingerStatus[8] = Data->Status.FingerState8; 226 | fingerStatus[9] = Data->Status.FingerState9; 227 | 228 | // 229 | // When hardware was last read, if any slots reported as lifted, we 230 | // must clean out the slot and old touch info. There may be new 231 | // finger data using the slot. 232 | // 233 | for (i=0; iFingerSlotDirty & (1 << i))) 239 | { 240 | continue; 241 | } 242 | 243 | NT_ASSERT(Cache->FingerDownCount > 0); 244 | 245 | // 246 | // Find the slot in the reporting list 247 | // 248 | for (j=0; jFingerDownOrder[j] == i) 251 | { 252 | break; 253 | } 254 | } 255 | 256 | NT_ASSERT(j != RMI4_MAX_TOUCHES); 257 | 258 | // 259 | // Remove the slot. If the finger lifted was the last in the list, 260 | // we just decrement the list total by one. If it was not last, we 261 | // shift the trailing list items up by one. 262 | // 263 | for (; (jFingerDownCount-1) && (jFingerDownOrder[j] = Cache->FingerDownOrder[j+1]; 266 | } 267 | Cache->FingerDownCount--; 268 | 269 | // 270 | // Finished, clobber the dirty bit 271 | // 272 | Cache->FingerSlotDirty &= ~(1 << i); 273 | } 274 | 275 | // 276 | // Cache the new set of finger data reported by hardware 277 | // 278 | for (i=0; iFingerSlotValid & (1 << i)) == 0) && 285 | (Cache->FingerDownCount < RMI4_MAX_TOUCHES)) 286 | { 287 | Cache->FingerSlotValid |= (1 << i); 288 | Cache->FingerDownOrder[Cache->FingerDownCount++] = i; 289 | } 290 | 291 | // 292 | // Ignore slots with no new information 293 | // 294 | if (!(Cache->FingerSlotValid & (1 << i))) 295 | { 296 | continue; 297 | } 298 | 299 | // 300 | // When finger is down, update local cache with new information from 301 | // the controller. When finger is up, we'll use last cached value 302 | // 303 | Cache->FingerSlot[i].fingerStatus = (UCHAR) fingerStatus[i]; 304 | if (Cache->FingerSlot[i].fingerStatus) 305 | { 306 | Cache->FingerSlot[i].x = Data->Finger[i].X; 307 | Cache->FingerSlot[i].y = Data->Finger[i].Y; 308 | } 309 | 310 | // 311 | // If a finger lifted, note the slot is now inactive so that any 312 | // cached data is cleaned out before we read hardware again. 313 | // 314 | if (Cache->FingerSlot[i].fingerStatus == RMI4_FINGER_STATE_NOT_PRESENT) 315 | { 316 | Cache->FingerSlotDirty |= (1 << i); 317 | Cache->FingerSlotValid &= ~(1 << i); 318 | } 319 | } 320 | 321 | // 322 | // Get current scan time (in 100us units) 323 | // 324 | ULONG64 QpcTimeStamp; 325 | Cache->ScanTime = KeQueryInterruptTimePrecise(&QpcTimeStamp) / 1000; 326 | } 327 | 328 | VOID 329 | RmiFillNextHidReportFromCache( 330 | IN PPTP_REPORT HidReport, 331 | IN RMI4_FINGER_CACHE *Cache, 332 | IN PTOUCH_SCREEN_PROPERTIES Props, 333 | IN int *TouchesReported, 334 | IN int TouchesTotal 335 | ) 336 | /*++ 337 | 338 | Routine Description: 339 | 340 | This routine fills a HID report with the next touch entries in 341 | the local device finger cache. 342 | 343 | The routine also adjusts X/Y coordinates to match the desired display 344 | coordinates. 345 | 346 | Arguments: 347 | 348 | HidReport - pointer to the HID report structure to fill 349 | Cache - pointer to the local device finger cache 350 | Props - information on how to adjust X/Y coordinates to match the display 351 | TouchesReported - On entry, the number of touches (against total) that 352 | have already been reported. As touches are transferred from the local 353 | device cache to a HID report, this number is incremented. 354 | TouchesTotal - total number of touches in the touch cache 355 | 356 | Return Value: 357 | 358 | None. 359 | 360 | --*/ 361 | { 362 | int currentFingerIndex; 363 | int fingersToReport = min(TouchesTotal - *TouchesReported, 5); 364 | USHORT SctatchX = 0, ScratchY = 0; 365 | 366 | HidReport->ReportID = REPORTID_MULTITOUCH; 367 | 368 | // 369 | // There are only 16-bits for ScanTime, truncate it 370 | // 371 | HidReport->ScanTime = Cache->ScanTime & 0xFFFF; 372 | 373 | // 374 | // No button in our context 375 | // 376 | HidReport->IsButtonClicked = FALSE; 377 | 378 | // 379 | // Report the count 380 | // We're sending touches using hybrid mode with 5 fingers in our 381 | // report descriptor. The first report must indicate the 382 | // total count of touch fingers detected by the digitizer. 383 | // The remaining reports must indicate 0 for the count. 384 | // The first report will have the TouchesReported integer set to 0 385 | // The others will have it set to something else. 386 | // 387 | if (*TouchesReported == 0) 388 | { 389 | HidReport->ContactCount = (UCHAR)TouchesTotal; 390 | } 391 | else 392 | { 393 | HidReport->ContactCount = 0; 394 | } 395 | 396 | // 397 | // Only five fingers supported yet 398 | // 399 | for (currentFingerIndex = 0; currentFingerIndex < fingersToReport; currentFingerIndex++) 400 | { 401 | int currentlyReporting = Cache->FingerDownOrder[*TouchesReported]; 402 | 403 | HidReport->Contacts[currentFingerIndex].ContactID = (UCHAR)currentlyReporting; 404 | SctatchX = (USHORT)Cache->FingerSlot[currentlyReporting].x; 405 | ScratchY = (USHORT)Cache->FingerSlot[currentlyReporting].y; 406 | HidReport->Contacts[currentFingerIndex].Confidence = 1; 407 | 408 | // 409 | // Perform per-platform x/y adjustments to controller coordinates 410 | // 411 | TchTranslateToDisplayCoordinates( 412 | &SctatchX, 413 | &ScratchY, 414 | Props); 415 | 416 | HidReport->Contacts[currentFingerIndex].X = SctatchX; 417 | HidReport->Contacts[currentFingerIndex].Y = ScratchY; 418 | 419 | if (Cache->FingerSlot[currentlyReporting].fingerStatus) 420 | { 421 | HidReport->Contacts[currentFingerIndex].TipSwitch = FINGER_STATUS; 422 | } 423 | 424 | (*TouchesReported)++; 425 | } 426 | } 427 | 428 | NTSTATUS 429 | RmiServiceTouchDataInterrupt( 430 | IN RMI4_CONTROLLER_CONTEXT* ControllerContext, 431 | IN SPB_CONTEXT* SpbContext, 432 | IN PPTP_REPORT HidReport, 433 | IN UCHAR InputMode, 434 | OUT BOOLEAN* PendingTouches 435 | ) 436 | /*++ 437 | 438 | Routine Description: 439 | 440 | Called when a touch interrupt needs service. 441 | 442 | Arguments: 443 | 444 | ControllerContext - Touch controller context 445 | SpbContext - A pointer to the current SPB context (I2C, etc) 446 | HidReport- Buffer to fill with a hid report if touch data is available 447 | InputMode - Specifies mouse, single-touch, or multi-touch reporting modes 448 | PendingTouches - Notifies caller if there are more touches to report, to 449 | complete reporting the full state of fingers on the screen 450 | 451 | Return Value: 452 | 453 | NTSTATUS indicating whether or not the current hid report buffer was filled 454 | 455 | PendingTouches also indicates whether the caller should expect more than 456 | one request to be completed to indicate the full state of fingers on 457 | the screen 458 | --*/ 459 | { 460 | RMI4_F11_DATA_REGISTERS data; 461 | NTSTATUS status; 462 | 463 | UNREFERENCED_PARAMETER(InputMode); 464 | 465 | status = STATUS_SUCCESS; 466 | RtlZeroMemory(&data, sizeof(data)); 467 | NT_ASSERT(PendingTouches != NULL); 468 | *PendingTouches = FALSE; 469 | 470 | // 471 | // If no touches are unreported in our cache, read the next set of touches 472 | // from hardware. 473 | // 474 | if (ControllerContext->TouchesReported == ControllerContext->TouchesTotal) 475 | { 476 | // 477 | // See if new touch data is available 478 | // 479 | status = RmiGetTouchesFromController( 480 | ControllerContext, 481 | SpbContext, 482 | &data 483 | ); 484 | 485 | if (!NT_SUCCESS(status)) 486 | { 487 | Trace( 488 | TRACE_LEVEL_VERBOSE, 489 | TRACE_SAMPLES, 490 | "No touch data to report - %!STATUS!", 491 | status); 492 | 493 | goto exit; 494 | } 495 | 496 | // 497 | // Process the new touch data by updating our cached state 498 | // 499 | // 500 | RmiUpdateLocalFingerCache( 501 | &data, 502 | &ControllerContext->Cache); 503 | 504 | // 505 | // Prepare to report touches via HID reports 506 | // 507 | ControllerContext->TouchesReported = 0; 508 | ControllerContext->TouchesTotal = 509 | ControllerContext->Cache.FingerDownCount; 510 | 511 | // 512 | // If no touches are present return that no data needed to be reported 513 | // 514 | if (ControllerContext->TouchesTotal == 0) 515 | { 516 | status = STATUS_NO_DATA_DETECTED; 517 | goto exit; 518 | } 519 | } 520 | 521 | RtlZeroMemory(HidReport, sizeof(PTP_REPORT)); 522 | 523 | // 524 | // Fill report with the next cached touches 525 | // 526 | RmiFillNextHidReportFromCache( 527 | HidReport, 528 | &ControllerContext->Cache, 529 | &ControllerContext->Props, 530 | &ControllerContext->TouchesReported, 531 | ControllerContext->TouchesTotal); 532 | 533 | // 534 | // Update the caller if we still have outstanding touches to report 535 | // 536 | if (ControllerContext->TouchesReported < ControllerContext->TouchesTotal) 537 | { 538 | *PendingTouches = TRUE; 539 | } 540 | else 541 | { 542 | *PendingTouches = FALSE; 543 | } 544 | 545 | exit: 546 | 547 | return status; 548 | } 549 | 550 | 551 | NTSTATUS 552 | TchServiceInterrupts( 553 | IN VOID *ControllerContext, 554 | IN SPB_CONTEXT *SpbContext, 555 | IN PPTP_REPORT HidReport, 556 | IN UCHAR InputMode, 557 | IN BOOLEAN *ServicingComplete 558 | ) 559 | /*++ 560 | 561 | Routine Description: 562 | 563 | This routine is called in response to an interrupt. The driver will 564 | service chip interrupts, and if data is available to report to HID, 565 | fill the Request object buffer with a HID report. 566 | 567 | Arguments: 568 | 569 | ControllerContext - Touch controller context 570 | SpbContext - A pointer to the current i2c context 571 | HidReport - Pointer to a HID_INPUT_REPORT structure to report to the OS 572 | InputMode - Specifies mouse, single-touch, or multi-touch reporting modes 573 | ServicingComplete - Notifies caller if there are more reports needed to 574 | complete servicing interrupts coming from the hardware. 575 | 576 | Return Value: 577 | 578 | NTSTATUS indicating whether or not the current HidReport has been filled 579 | 580 | ServicingComplete indicates whether or not a new report buffer is required 581 | to complete interrupt processing. 582 | --*/ 583 | { 584 | NTSTATUS status = STATUS_NO_DATA_DETECTED; 585 | RMI4_CONTROLLER_CONTEXT* controller; 586 | 587 | controller = (RMI4_CONTROLLER_CONTEXT*) ControllerContext; 588 | 589 | NT_ASSERT(ServicingComplete != NULL); 590 | 591 | // 592 | // Grab a waitlock to ensure the ISR executes serially and is 593 | // protected against power state transitions 594 | // 595 | WdfWaitLockAcquire(controller->ControllerLock, NULL); 596 | 597 | // 598 | // Check the interrupt source if no interrupts are pending processing 599 | // 600 | if (controller->InterruptStatus == 0) 601 | { 602 | status = RmiCheckInterrupts( 603 | controller, 604 | SpbContext, 605 | &controller->InterruptStatus); 606 | 607 | if (!NT_SUCCESS(status)) 608 | { 609 | Trace( 610 | TRACE_LEVEL_ERROR, 611 | TRACE_INTERRUPT, 612 | "Error servicing interrupts - %!STATUS!", 613 | status); 614 | 615 | *ServicingComplete = FALSE; 616 | goto exit; 617 | } 618 | } 619 | 620 | // 621 | // Driver only services 0D cap button and 2D touch messages currently 622 | // 623 | if (controller->InterruptStatus & 624 | ~(RMI4_INTERRUPT_BIT_0D_CAP_BUTTON | RMI4_INTERRUPT_BIT_2D_TOUCH)) 625 | { 626 | Trace( 627 | TRACE_LEVEL_WARNING, 628 | TRACE_INTERRUPT, 629 | "Ignoring following interrupt flags - %!STATUS!", 630 | controller->InterruptStatus & 631 | ~(RMI4_INTERRUPT_BIT_0D_CAP_BUTTON | 632 | RMI4_INTERRUPT_BIT_2D_TOUCH)); 633 | 634 | // 635 | // Mask away flags we don't service 636 | // 637 | controller->InterruptStatus &= 638 | (RMI4_INTERRUPT_BIT_0D_CAP_BUTTON | 639 | RMI4_INTERRUPT_BIT_2D_TOUCH); 640 | } 641 | 642 | // 643 | // RmiServiceXXX routine will change status to STATUS_SUCCESS if there 644 | // is a HID report to process. 645 | // 646 | status = STATUS_UNSUCCESSFUL; 647 | 648 | // 649 | // Service a touch data event if indicated by hardware 650 | // 651 | if (controller->InterruptStatus & RMI4_INTERRUPT_BIT_2D_TOUCH) 652 | { 653 | BOOLEAN pendingTouches = FALSE; 654 | 655 | status = RmiServiceTouchDataInterrupt( 656 | ControllerContext, 657 | SpbContext, 658 | HidReport, 659 | InputMode, 660 | &pendingTouches); 661 | 662 | // 663 | // If there are more touches to report, servicing is incomplete 664 | // 665 | if (pendingTouches == FALSE) 666 | { 667 | controller->InterruptStatus &= ~RMI4_INTERRUPT_BIT_2D_TOUCH; 668 | } 669 | 670 | // 671 | // Success indicates the report is ready to be sent, otherwise, 672 | // continue to service interrupts. 673 | // 674 | if (NT_SUCCESS(status)) 675 | { 676 | goto exit; 677 | } 678 | else 679 | { 680 | Trace( 681 | TRACE_LEVEL_ERROR, 682 | TRACE_INTERRUPT, 683 | "Error processing touch event - %!STATUS!", 684 | status); 685 | } 686 | } 687 | 688 | // 689 | // Add servicing for additional touch interrupts here 690 | // 691 | 692 | exit: 693 | 694 | // 695 | // Indicate whether or not we're done servicing interrupts 696 | // 697 | if (controller->InterruptStatus == 0) 698 | { 699 | *ServicingComplete = TRUE; 700 | } 701 | else 702 | { 703 | *ServicingComplete = FALSE; 704 | } 705 | 706 | WdfWaitLockRelease(controller->ControllerLock); 707 | 708 | return status; 709 | } 710 | -------------------------------------------------------------------------------- /contrib/SynapticsTouch.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | ARM64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | {1E12CAAD-D041-4C21-B673-6FF831FC3D70} 39 | $(MSBuildProjectName) 40 | 1 41 | Debug 42 | Win32 43 | {25B3301B-A9D9-4EE3-8EA5-B1F1FBB3A18C} 44 | 10.0.17134.0 45 | 46 | 47 | 48 | 49 | 50 | False 51 | Universal 52 | KMDF 53 | WindowsKernelModeDriver10.0 54 | Driver 55 | 56 | 57 | 58 | 59 | 60 | 61 | True 62 | Universal 63 | KMDF 64 | WindowsKernelModeDriver10.0 65 | Driver 66 | 67 | 68 | 69 | 70 | 71 | 72 | False 73 | Universal 74 | KMDF 75 | WindowsKernelModeDriver10.0 76 | Driver 77 | 78 | 79 | 80 | 81 | 82 | 83 | False 84 | Universal 85 | KMDF 86 | WindowsKernelModeDriver10.0 87 | Driver 88 | 89 | 90 | 91 | 92 | 93 | 94 | False 95 | Universal 96 | KMDF 97 | WindowsKernelModeDriver10.0 98 | Driver 99 | 100 | 101 | 102 | 103 | 104 | 105 | True 106 | Universal 107 | KMDF 108 | WindowsKernelModeDriver10.0 109 | Driver 110 | 111 | 112 | 113 | 114 | 115 | 116 | True 117 | Universal 118 | KMDF 119 | WindowsKernelModeDriver10.0 120 | Driver 121 | 122 | 123 | 124 | 125 | 126 | 127 | True 128 | Universal 129 | KMDF 130 | WindowsKernelModeDriver10.0 131 | Driver 132 | 133 | 134 | 135 | 136 | 137 | ..\build\$(Platform)\$(ConfigurationName)\ 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | SynapticsTouch 165 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 166 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 167 | 168 | 169 | SynapticsTouch 170 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 171 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 172 | 173 | 174 | SynapticsTouch 175 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 176 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 177 | 178 | 179 | SynapticsTouch 180 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 181 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 182 | 183 | 184 | SynapticsTouch 185 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 186 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 187 | 188 | 189 | SynapticsTouch 190 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 191 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 192 | 193 | 194 | SynapticsTouch 195 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 196 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 197 | 198 | 199 | SynapticsTouch 200 | $(IntDir);$(SolutionDir)..\include;$(IncludePath) 201 | ..\intermediate\$(Platform)\$(ConfigurationName)\ 202 | 203 | 204 | 205 | true 206 | Level4 207 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 208 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 209 | 210 | 211 | 4146;4214;%(DisableSpecificWarnings) 212 | true 213 | true 214 | $(SolutionDir)..\include\trace.h 215 | 216 | 217 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 218 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 219 | 220 | 221 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 222 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 223 | 224 | 225 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 226 | 227 | 228 | 229 | 230 | true 231 | Level4 232 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 233 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 234 | 235 | 236 | 4146;4214;%(DisableSpecificWarnings) 237 | true 238 | true 239 | $(SolutionDir)..\include\trace.h 240 | 241 | 242 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 243 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 244 | 245 | 246 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 247 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 248 | 249 | 250 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 251 | 252 | 253 | 254 | 255 | true 256 | Level4 257 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 258 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 259 | 260 | 261 | 4146;4214;%(DisableSpecificWarnings) 262 | true 263 | true 264 | $(SolutionDir)..\include\trace.h 265 | 266 | 267 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 268 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 269 | 270 | 271 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 272 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 273 | 274 | 275 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 276 | 277 | 278 | 279 | 280 | true 281 | Level4 282 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 283 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 284 | 285 | 286 | 4146;4214;%(DisableSpecificWarnings) 287 | true 288 | true 289 | $(SolutionDir)..\include\trace.h 290 | 291 | 292 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 293 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 294 | 295 | 296 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 297 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 298 | 299 | 300 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 301 | 302 | 303 | 304 | 305 | true 306 | Level4 307 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 308 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 309 | 310 | 311 | 4146;4214;%(DisableSpecificWarnings) 312 | true 313 | true 314 | $(SolutionDir)..\include\trace.h 315 | 316 | 317 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 318 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 319 | 320 | 321 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 322 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 323 | 324 | 325 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 326 | 327 | 328 | 329 | 330 | false 331 | Level4 332 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 333 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 334 | 335 | 336 | 4146;4214;%(DisableSpecificWarnings) 337 | true 338 | true 339 | $(SolutionDir)..\include\trace.h 340 | 341 | 342 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 343 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 344 | 345 | 346 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 347 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 348 | 349 | 350 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 351 | 352 | 353 | 354 | 355 | false 356 | Level4 357 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 358 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 359 | 360 | 361 | 4146;4214;%(DisableSpecificWarnings) 362 | true 363 | true 364 | $(SolutionDir)..\include\trace.h 365 | 366 | 367 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 368 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 369 | 370 | 371 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 372 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 373 | 374 | 375 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 376 | 377 | 378 | 379 | 380 | true 381 | Level4 382 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 383 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 384 | 385 | 386 | 4146;4214;%(DisableSpecificWarnings) 387 | true 388 | true 389 | $(SolutionDir)..\include\trace.h 390 | 391 | 392 | %(PreprocessorDefinitions);DRIVER;_WIN32_WINNT=0x602;_WINNT_;_SAMPLE_DESCRIPTOR_ 393 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 394 | 395 | 396 | %(PreprocessorDefinitions);DRIVER;_WINNT_;_SAMPLE_DESCRIPTOR_ 397 | %(AdditionalIncludeDirectories);.;$(DDK_INC_PATH);$(DDK_INC_PATH)\wdm\ 398 | 399 | 400 | %(AdditionalDependencies);$(DDK_LIB_PATH)\HidClass.lib 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | --------------------------------------------------------------------------------