├── crostouchpad ├── stdint.h ├── crostouchpad4.rc ├── trace.h ├── linuxmacros.h ├── spb.h ├── hidcommon.h ├── crostouchpad.vcxproj.filters ├── crostouchpad.inf ├── rmi.h ├── crostouchpad.vcxproj ├── driver.h ├── spb.cpp ├── spb.c ├── rmi.c └── synaptics.c ├── crostouchpad Package ├── crostouchpad Package.vcxproj.filters └── crostouchpad Package.vcxproj ├── LICENSE.txt ├── crostouchpad4.sln └── .gitignore /crostouchpad/stdint.h: -------------------------------------------------------------------------------- 1 | typedef signed char int8_t; 2 | typedef signed short int16_t; 3 | typedef signed int int32_t; 4 | typedef unsigned char uint8_t; 5 | typedef unsigned short uint16_t; 6 | typedef unsigned int uint32_t; 7 | 8 | #define bool uint8_t -------------------------------------------------------------------------------- /crostouchpad Package/crostouchpad Package.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {8E41214B-6785-4CFE-B992-037D68949A14} 6 | inf;inv;inx;mof;mc; 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 CoolStar 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /crostouchpad/crostouchpad4.rc: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation All Rights Reserved 4 | 5 | Module Name: 6 | 7 | crostouchpad4.rc 8 | 9 | Abstract: 10 | 11 | --*/ 12 | 13 | #include 14 | 15 | #define VER_FILETYPE VFT_DRV 16 | #define VER_FILESUBTYPE VFT2_DRV_MOUSE 17 | #define VER_FILEDESCRIPTION_STR "Chromebook Synaptics RMI Touchpad" 18 | #define VER_INTERNALNAME_STR "crostouchpad4.sys" 19 | #define VER_ORIGINALFILENAME_STR "crostouchpad4.sys" 20 | 21 | #define VER_LEGALCOPYRIGHT_YEARS "2023" 22 | #define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." 23 | 24 | #define VER_FILEVERSION 4,1,4,0 25 | #define VER_PRODUCTVERSION_STR "4.1.4.0" 26 | #define VER_PRODUCTVERSION 4,1,4,0 27 | #define LVER_PRODUCTVERSION_STR L"4.1.4.0" 28 | 29 | #define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) 30 | #ifdef DEBUG 31 | #define VER_FILEFLAGS (VS_FF_DEBUG) 32 | #else 33 | #define VER_FILEFLAGS (0) 34 | #endif 35 | 36 | #define VER_FILEOS VOS_NT_WINDOWS32 37 | 38 | #define VER_COMPANYNAME_STR "CoolStar" 39 | #define VER_PRODUCTNAME_STR "Chromebook Synaptics RMI Touchpad" 40 | 41 | #include "common.ver" -------------------------------------------------------------------------------- /crostouchpad/trace.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef _TRACE_H_ 4 | #define _TRACE_H_ 5 | 6 | extern "C" 7 | { 8 | // 9 | // Tracing Definitions: 10 | // 11 | // Control GUID: 12 | // {73e3b785-f5fb-423e-94a9-56627fea9053} 13 | // 14 | 15 | #define WPP_CONTROL_GUIDS \ 16 | WPP_DEFINE_CONTROL_GUID( \ 17 | SpbTestToolTraceGuid, \ 18 | (73e3b785,f5fb,423e,94a9,56627fea9053), \ 19 | WPP_DEFINE_BIT(TRACE_FLAG_WDFLOADING) \ 20 | WPP_DEFINE_BIT(TRACE_FLAG_SPBAPI) \ 21 | WPP_DEFINE_BIT(TRACE_FLAG_OTHER) \ 22 | ) 23 | } 24 | 25 | #define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags) 26 | #define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level) 27 | 28 | #define Trace CyapaPrint 29 | #define FuncEntry 30 | #define FuncExit 31 | #define WPP_INIT_TRACING 32 | #define WPP_CLEANUP 33 | #define TRACE_FLAG_SPBAPI 0 34 | #define TRACE_FLAG_WDFLOADING 0 35 | 36 | // begin_wpp config 37 | // FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 38 | // FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); 39 | // USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> entry"); 40 | // USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <--"); 41 | // end_wpp 42 | 43 | #endif _TRACE_H_ 44 | -------------------------------------------------------------------------------- /crostouchpad/linuxmacros.h: -------------------------------------------------------------------------------- 1 | #include "stdint.h" 2 | 3 | #define BITS_PER_LONG 64 4 | #define GENMASK(h, l) \ 5 | (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) 6 | #define BIT(nr) (1UL << (nr)) 7 | #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) 8 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) 9 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 10 | 11 | // Error codes 12 | #define EPERM 1 13 | #define ENOENT 2 14 | #define ESRCH 3 15 | #define EINTR 4 16 | #define EIO 5 17 | #define ENXIO 6 18 | #define E2BIG 7 19 | #define ENOEXEC 8 20 | #define EBADF 9 21 | #define ECHILD 10 22 | #define EAGAIN 11 23 | #define ENOMEM 12 24 | #define EACCES 13 25 | #define EFAULT 14 26 | #define EBUSY 16 27 | #define EEXIST 17 28 | #define EXDEV 18 29 | #define ENODEV 19 30 | #define ENOTDIR 20 31 | #define EISDIR 21 32 | #define ENFILE 23 33 | #define EMFILE 24 34 | #define ENOTTY 25 35 | #define EFBIG 27 36 | #define ENOSPC 28 37 | #define ESPIPE 29 38 | #define EROFS 30 39 | #define EMLINK 31 40 | #define EPIPE 32 41 | #define EDOM 33 42 | #define EDEADLK 36 43 | #define ENAMETOOLONG 38 44 | #define ENOLCK 39 45 | #define ENOSYS 40 46 | #define ENOTEMPTY 41 -------------------------------------------------------------------------------- /crostouchpad/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 | #define RESHUB_USE_HELPER_ROUTINES 28 | 29 | // 30 | // SPB (I2C) context 31 | // 32 | 33 | typedef struct _SPB_CONTEXT 34 | { 35 | WDFIOTARGET SpbIoTarget; 36 | LARGE_INTEGER I2cResHubId; 37 | WDFMEMORY WriteMemory; 38 | WDFMEMORY ReadMemory; 39 | WDFWAITLOCK SpbLock; 40 | } SPB_CONTEXT; 41 | 42 | NTSTATUS 43 | SpbOnlyReadDataSynchronously( 44 | _In_ SPB_CONTEXT *SpbContext, 45 | _In_reads_bytes_(Length) PVOID Data, 46 | _In_ ULONG Length 47 | ); 48 | 49 | NTSTATUS 50 | SpbReadDataSynchronously( 51 | _In_ SPB_CONTEXT *SpbContext, 52 | _In_ UCHAR Address, 53 | _In_reads_bytes_(Length) PVOID Data, 54 | _In_ ULONG Length 55 | ); 56 | 57 | NTSTATUS 58 | SpbReadDataSynchronously16( 59 | _In_ SPB_CONTEXT *SpbContext, 60 | _In_ UINT16 Address, 61 | _In_reads_bytes_(Length) PVOID Data, 62 | _In_ ULONG Length 63 | ); 64 | 65 | VOID 66 | SpbTargetDeinitialize( 67 | IN WDFDEVICE FxDevice, 68 | IN SPB_CONTEXT *SpbContext 69 | ); 70 | 71 | NTSTATUS 72 | SpbTargetInitialize( 73 | IN WDFDEVICE FxDevice, 74 | IN SPB_CONTEXT *SpbContext 75 | ); 76 | 77 | NTSTATUS 78 | SpbWriteDataSynchronously( 79 | IN SPB_CONTEXT *SpbContext, 80 | IN UCHAR Address, 81 | IN PVOID Data, 82 | IN ULONG Length 83 | ); 84 | 85 | NTSTATUS 86 | SpbWriteDataSynchronously16( 87 | IN SPB_CONTEXT *SpbContext, 88 | IN UINT16 Address, 89 | IN PVOID Data, 90 | IN ULONG Length 91 | ); -------------------------------------------------------------------------------- /crostouchpad/hidcommon.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SYNA_COMMON_H_) 2 | #define _SYNA_COMMON_H_ 3 | 4 | // 5 | //These are the device attributes returned by vmulti in response 6 | // to IOCTL_HID_GET_DEVICE_ATTRIBUTES. 7 | // 8 | 9 | #define SYNA_PID 0xBACC 10 | #define SYNA_VID 0x00FF 11 | #define SYNA_VERSION 0x0001 12 | 13 | // 14 | // These are the report ids 15 | // 16 | 17 | #define REPORTID_MTOUCH 0x01 18 | #define REPORTID_FEATURE 0x02 19 | #define REPORTID_MOUSE 0x03 20 | #define REPORTID_PTPHQA 0x04 21 | 22 | // 23 | // Multitouch specific report information 24 | // 25 | 26 | #define MULTI_CONFIDENCE_BIT 1 27 | #define MULTI_TIPSWITCH_BIT 2 28 | 29 | #define MULTI_MIN_COORDINATE 0x0000 30 | #define MULTI_MAX_COORDINATE 0x7FFF 31 | 32 | #define MULTI_MAX_COUNT 5 33 | 34 | #pragma pack(1) 35 | typedef struct 36 | { 37 | 38 | BYTE Status; 39 | 40 | BYTE ContactID; 41 | 42 | USHORT XValue; 43 | 44 | USHORT YValue; 45 | 46 | USHORT Pressure; 47 | } 48 | TOUCH, *PTOUCH; 49 | 50 | typedef struct _SYNA_MULTITOUCH_REPORT 51 | { 52 | 53 | BYTE ReportID; 54 | 55 | TOUCH Touch[5]; 56 | 57 | USHORT ScanTime; 58 | 59 | BYTE ContactCount; 60 | 61 | BYTE IsDepressed; 62 | } SynaMultiTouchReport; 63 | #pragma pack() 64 | 65 | // 66 | // Feature report infomation 67 | // 68 | 69 | #define DEVICE_MODE_MOUSE 0x00 70 | #define DEVICE_MODE_SINGLE_INPUT 0x01 71 | #define DEVICE_MODE_MULTI_INPUT 0x02 72 | 73 | #pragma pack(1) 74 | typedef struct _SYNA_FEATURE_REPORT 75 | { 76 | 77 | BYTE ReportID; 78 | 79 | BYTE DeviceMode; 80 | 81 | BYTE DeviceIdentifier; 82 | 83 | } SynaFeatureReport; 84 | 85 | typedef struct _SYNA_MAXCOUNT_REPORT 86 | { 87 | 88 | BYTE ReportID; 89 | 90 | BYTE MaximumCount; 91 | 92 | BYTE PadType; 93 | 94 | } SynaMaxCountReport; 95 | #pragma pack() 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /crostouchpad/crostouchpad.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Header Files 24 | 25 | 26 | Header Files 27 | 28 | 29 | Header Files 30 | 31 | 32 | Header Files 33 | 34 | 35 | Header Files 36 | 37 | 38 | Header Files 39 | 40 | 41 | Header Files 42 | 43 | 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | 56 | 57 | Driver Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /crostouchpad/crostouchpad.inf: -------------------------------------------------------------------------------- 1 | ;/*++ 2 | ; 3 | ;Copyright (c) CoolStar. All rights reserved. 4 | ; 5 | ;Module Name: 6 | ; coolstar.inf 7 | ; 8 | ;Abstract: 9 | ; INF file for installing the Synaptics RMI Touchpad Driver 10 | ; 11 | ; 12 | ;--*/ 13 | 14 | [Version] 15 | Signature = "$WINDOWS NT$" 16 | Class = HIDClass 17 | ClassGuid = {745a17a0-74d3-11d0-b6fe-00a0c90f57da} 18 | Provider = CoolStar 19 | DriverVer = 2/15/2022, 4.1.2 20 | CatalogFile = crostouchpad.cat 21 | PnpLockdown = 1 22 | 23 | [DestinationDirs] 24 | DefaultDestDir = 12 25 | 26 | ; ================= Class section ===================== 27 | 28 | [SourceDisksNames] 29 | 1 = %DiskId1%,,,"" 30 | 31 | [SourceDisksFiles] 32 | crostouchpad.sys = 1,, 33 | 34 | ;***************************************** 35 | ; CrosTouchpad Install Section 36 | ;***************************************** 37 | 38 | [Manufacturer] 39 | %StdMfg%=Standard,NT$ARCH$ 40 | 41 | ; Decorated model section take precedence over undecorated 42 | ; ones on XP and later. 43 | [Standard.NT$ARCH$] 44 | %CrosTouchpad.DeviceDesc%=CrosTouchpad_Device, ACPI\SYNA0000 45 | 46 | [CrosTouchpad_Device.NT] 47 | CopyFiles=Drivers_Dir 48 | 49 | [CrosTouchpad_Device.NT.HW] 50 | AddReg=CrosTouchpad_AddReg 51 | 52 | [Drivers_Dir] 53 | crostouchpad.sys 54 | 55 | [CrosTouchpad_AddReg] 56 | ; Set to 1 to connect the first interrupt resource found, 0 to leave disconnected 57 | HKR,Settings,"ConnectInterrupt",0x00010001,0 58 | HKR,,"UpperFilters",0x00010000,"mshidkmdf" 59 | 60 | ;-------------- Service installation 61 | [CrosTouchpad_Device.NT.Services] 62 | AddService = CrosTouchpad,%SPSVCINST_ASSOCSERVICE%, CrosTouchpad_Service_Inst 63 | 64 | ; -------------- CrosTouchpad driver install sections 65 | [CrosTouchpad_Service_Inst] 66 | DisplayName = %CrosTouchpad.SVCDESC% 67 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 68 | StartType = 3 ; SERVICE_DEMAND_START 69 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 70 | ServiceBinary = %12%\crostouchpad.sys 71 | LoadOrderGroup = Base 72 | 73 | [Strings] 74 | SPSVCINST_ASSOCSERVICE= 0x00000002 75 | StdMfg = "CoolStar" 76 | DiskId1 = "CrosTouchpad Installation Disk #1" 77 | CrosTouchpad.DeviceDesc = "Chromebook Synaptics RMI Touchpad" 78 | CrosTouchpad.SVCDESC = "CrosTouchpad Service" 79 | -------------------------------------------------------------------------------- /crostouchpad/rmi.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "linuxmacros.h" 3 | 4 | #ifndef __packed 5 | #define __packed( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) 6 | #endif 7 | 8 | #define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */ 9 | #define RMI_WRITE_REPORT_ID 0x09 /* Output Report */ 10 | #define RMI_READ_ADDR_REPORT_ID 0x0a /* Output Report */ 11 | #define RMI_READ_DATA_REPORT_ID 0x0b /* Input Report */ 12 | #define RMI_ATTN_REPORT_ID 0x0c /* Input Report */ 13 | #define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */ 14 | 15 | /* flags */ 16 | #define RMI_READ_REQUEST_PENDING 0 17 | #define RMI_READ_DATA_PENDING 1 18 | #define RMI_STARTED 2 19 | 20 | #define RMI_SLEEP_NORMAL 0x0 21 | #define RMI_SLEEP_DEEP_SLEEP 0x1 22 | 23 | /* device flags */ 24 | #define RMI_DEVICE BIT(0) 25 | #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) 26 | 27 | /* 28 | * retrieve the ctrl registers 29 | * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, 30 | * and there is no way to know if the first 20 bytes are here or not. 31 | * We use only the first 12 bytes, so get only them. 32 | */ 33 | #define RMI_F11_CTRL_REG_COUNT 12 34 | 35 | enum rmi_mode_type { 36 | RMI_MODE_OFF = 0, 37 | RMI_MODE_ATTN_REPORTS = 1, 38 | RMI_MODE_NO_PACKED_ATTN_REPORTS = 2, 39 | }; 40 | 41 | struct rmi_function { 42 | unsigned page; /* page of the function */ 43 | uint16_t query_base_addr; /* base address for queries */ 44 | uint16_t command_base_addr; /* base address for commands */ 45 | uint16_t control_base_addr; /* base address for controls */ 46 | uint16_t data_base_addr; /* base address for datas */ 47 | unsigned int interrupt_base; /* cross-function interrupt number 48 | * (uniq in the device)*/ 49 | unsigned int interrupt_count; /* number of interrupts */ 50 | unsigned int report_size; /* size of a report */ 51 | unsigned long irq_mask; /* mask of the interrupts 52 | * (to be applied against ATTN IRQ) */ 53 | }; 54 | 55 | #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) 56 | 57 | #define RMI4_MAX_PAGE 0xff 58 | #define RMI4_PAGE_SIZE 0x0100 59 | 60 | #define PDT_START_SCAN_LOCATION 0x00e9 61 | #define PDT_END_SCAN_LOCATION 0x0005 62 | #define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff) 63 | 64 | __packed(struct pdt_entry { 65 | uint8_t query_base_addr : 8; 66 | uint8_t command_base_addr : 8; 67 | uint8_t control_base_addr : 8; 68 | uint8_t data_base_addr : 8; 69 | uint8_t interrupt_source_count : 3; 70 | uint8_t bits3and4 : 2; 71 | uint8_t function_version : 2; 72 | uint8_t bit7 : 1; 73 | uint8_t function_number : 8; 74 | }); 75 | 76 | #define RMI_DEVICE_F01_BASIC_QUERY_LEN 11 77 | 78 | #define MXT_T9_RELEASE (1 << 5) 79 | #define MXT_T9_PRESS (1 << 6) 80 | #define MXT_T9_DETECT (1 << 7) 81 | 82 | struct touch_softc { 83 | int *x; 84 | int *y; 85 | int *p; 86 | int *palm; 87 | }; -------------------------------------------------------------------------------- /crostouchpad4.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33516.290 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crostouchpad", "crostouchpad\crostouchpad.vcxproj", "{B3E71397-9BE4-492B-AAED-4D056E59CB1F}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crostouchpad Package", "crostouchpad Package\crostouchpad Package.vcxproj", "{EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F} = {B3E71397-9BE4-492B-AAED-4D056E59CB1F} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Debug|x64 = Debug|x64 17 | Release|Win32 = Release|Win32 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|Win32.Build.0 = Debug|Win32 23 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|Win32.Deploy.0 = Debug|Win32 24 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|x64.ActiveCfg = Debug|x64 25 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|x64.Build.0 = Debug|x64 26 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Debug|x64.Deploy.0 = Debug|x64 27 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|Win32.ActiveCfg = Release|Win32 28 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|Win32.Build.0 = Release|Win32 29 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|Win32.Deploy.0 = Release|Win32 30 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|x64.ActiveCfg = Release|x64 31 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|x64.Build.0 = Release|x64 32 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F}.Release|x64.Deploy.0 = Release|x64 33 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|Win32.ActiveCfg = Debug|Win32 34 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|Win32.Build.0 = Debug|Win32 35 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|Win32.Deploy.0 = Debug|Win32 36 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|x64.ActiveCfg = Debug|x64 37 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|x64.Build.0 = Debug|x64 38 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Debug|x64.Deploy.0 = Debug|x64 39 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|Win32.ActiveCfg = Release|Win32 40 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|Win32.Build.0 = Release|Win32 41 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|Win32.Deploy.0 = Release|Win32 42 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|x64.ActiveCfg = Release|x64 43 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|x64.Build.0 = Release|x64 44 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B}.Release|x64.Deploy.0 = Release|x64 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | GlobalSection(ExtensibilityGlobals) = postSolution 50 | SolutionGuid = {174C1C30-71EF-4032-96F8-2432991151AB} 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_h.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *_wpftmp.csproj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush personal settings 296 | .cr/personal 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | 333 | # Local History for Visual Studio 334 | .localhistory/ 335 | -------------------------------------------------------------------------------- /crostouchpad Package/crostouchpad Package.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {EA676041-89D8-4ACF-A48B-F11CA9F5DD8B} 23 | {4605da2c-74a5-4865-98e1-152ef136825f} 24 | v4.5 25 | 11.0 26 | Win8.1 Debug 27 | Win32 28 | crostouchpad_Package 29 | $(LatestTargetPlatformVersion) 30 | crostouchpad Package 31 | 32 | 33 | 34 | Windows10 35 | true 36 | WindowsKernelModeDriver10.0 37 | Utility 38 | Package 39 | true 40 | 41 | 42 | Windows10 43 | false 44 | WindowsKernelModeDriver10.0 45 | Utility 46 | Package 47 | true 48 | 49 | 50 | Windows10 51 | true 52 | WindowsKernelModeDriver10.0 53 | Utility 54 | Package 55 | true 56 | 57 | 58 | Windows10 59 | false 60 | WindowsKernelModeDriver10.0 61 | Utility 62 | Package 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | DbgengKernelDebugger 75 | False 76 | True 77 | 78 | 79 | 80 | False 81 | False 82 | True 83 | 84 | 133563 85 | 86 | 87 | DbgengKernelDebugger 88 | False 89 | True 90 | 91 | 92 | 93 | False 94 | False 95 | True 96 | 97 | 133563 98 | 99 | 100 | DbgengKernelDebugger 101 | False 102 | True 103 | 104 | 105 | 106 | False 107 | False 108 | True 109 | 110 | 133563 111 | 112 | 113 | DbgengKernelDebugger 114 | False 115 | True 116 | 117 | 118 | 119 | False 120 | False 121 | True 122 | 123 | 133563 124 | 125 | 126 | 127 | SHA256 128 | 129 | 130 | 131 | 132 | SHA256 133 | 134 | 135 | 136 | 137 | SHA256 138 | 139 | 140 | 141 | 142 | SHA256 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | {b3e71397-9be4-492b-aaed-4d056e59cb1f} 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /crostouchpad/crostouchpad.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {B3E71397-9BE4-492B-AAED-4D056E59CB1F} 23 | {1bc93793-694f-48fe-9372-81e2b05556fd} 24 | v4.5 25 | 11.0 26 | Win8.1 Debug 27 | Win32 28 | crostouchpad 29 | $(LatestTargetPlatformVersion) 30 | crostouchpad 31 | 32 | 33 | 34 | Windows10 35 | true 36 | WindowsKernelModeDriver10.0 37 | Driver 38 | KMDF 39 | 40 | 41 | Windows10 42 | false 43 | WindowsKernelModeDriver10.0 44 | Driver 45 | KMDF 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | KMDF 53 | 54 | 55 | Windows10 56 | false 57 | WindowsKernelModeDriver10.0 58 | Driver 59 | KMDF 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | DbgengKernelDebugger 71 | 72 | 73 | DbgengKernelDebugger 74 | 75 | 76 | DbgengKernelDebugger 77 | 78 | 79 | DbgengKernelDebugger 80 | 81 | 82 | 83 | true 84 | trace.h 85 | true 86 | false 87 | 88 | 89 | 4.1.4 90 | 91 | 92 | SHA256 93 | 94 | 95 | 96 | 97 | true 98 | trace.h 99 | true 100 | false 101 | 102 | 103 | 4.1.4 104 | 105 | 106 | SHA256 107 | 108 | 109 | 110 | 111 | true 112 | trace.h 113 | true 114 | false 115 | 116 | 117 | 4.1.4 118 | 119 | 120 | SHA256 121 | 122 | 123 | 124 | 125 | true 126 | trace.h 127 | true 128 | false 129 | 130 | 131 | 4.1.4 132 | 133 | 134 | SHA256 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /crostouchpad/driver.h: -------------------------------------------------------------------------------- 1 | #if !defined(_SYNA_H_) 2 | #define _SYNA_H_ 3 | 4 | #pragma warning(disable:4200) // suppress nameless struct/union warning 5 | #pragma warning(disable:4201) // suppress nameless struct/union warning 6 | #pragma warning(disable:4214) // suppress bit field types other than int warning 7 | #include 8 | #include 9 | 10 | #pragma warning(default:4200) 11 | #pragma warning(default:4201) 12 | #pragma warning(default:4214) 13 | #include 14 | 15 | #pragma warning(disable:4201) // suppress nameless struct/union warning 16 | #pragma warning(disable:4214) // suppress bit field types other than int warning 17 | #include 18 | 19 | #include "hidcommon.h" 20 | #include "spb.h" 21 | #include "rmi.h" 22 | 23 | // 24 | // String definitions 25 | // 26 | 27 | #define DRIVERNAME "crostouchpad4.sys: " 28 | 29 | #define SYNA_POOL_TAG (ULONG) 'anyS' 30 | 31 | #define NTDEVICE_NAME_STRING L"\\Device\\SYNA0000" 32 | #define SYMBOLIC_NAME_STRING L"\\DosDevices\\SYNA0000" 33 | 34 | #define MT_TOUCH_COLLECTION0 \ 35 | 0xa1, 0x02, /* COLLECTION (Logical) */ \ 36 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ 37 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ 38 | 0x09, 0x47, /* USAGE (Confidence) */ \ 39 | 0x09, 0x42, /* USAGE (Tip switch) */ \ 40 | 0x95, 0x02, /* REPORT_COUNT (2) */ \ 41 | 0x75, 0x01, /* REPORT_SIZE (1) */ \ 42 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 43 | 0x95, 0x06, /* REPORT_COUNT (6) */ \ 44 | 0x81, 0x03, /* INPUT (Cnst,Ary,Abs) */ \ 45 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 46 | 0x75, 0x04, /* REPORT_SIZE (4) */ \ 47 | 0x25, 0x10, /* LOGICAL_MAXIMUM (16) */ \ 48 | 0x09, 0x51, /* USAGE (Contact Identifier)*/ \ 49 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 50 | 0x75, 0x01, /* REPORT_SIZE (1) */ \ 51 | 0x95, 0x04, /* REPORT_COUNT (4) */ \ 52 | 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ 53 | 0x05, 0x01, /* USAGE_PAGE (Generic Desk..*/ \ 54 | 0x75, 0x10, /* REPORT_SIZE (16) */ \ 55 | 0x55, 0x0e, /* UNIT_EXPONENT (-2) */ \ 56 | /*0x65, 0x13, /* UNIT(Inch,EngLinear) */ \ 57 | 0x65, 0x11, /* UNIT(Cm,SiLinear) */ \ 58 | 0x09, 0x30, /* USAGE (X) */ \ 59 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ 60 | 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ \ 61 | 62 | #define MT_TOUCH_COLLECTION1 \ 63 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 64 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 65 | 66 | #define MT_TOUCH_COLLECTION2 \ 67 | 0x09, 0x31, /* USAGE (Y) */ \ 68 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 69 | 0x05, 0x0d, /* USAGE PAGE (Digitizers) */ \ 70 | 0x25, 0x28, /* LOGICAL_MAXIMUM (40) */ \ 71 | 0x09, 0x30, /* USAGE (Tip Pressure) */ \ 72 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 73 | 0xc0, /* END_COLLECTION */ 74 | 75 | #define MT_REF_TOUCH_COLLECTION \ 76 | MT_TOUCH_COLLECTION0 \ 77 | 0x26, 0x66, 0x03, /* LOGICAL_MAXIMUM (870) */ \ 78 | 0x46, 0x8E, 0x03, /* PHYSICAL_MAXIMUM (910) */ \ 79 | MT_TOUCH_COLLECTION1 \ 80 | 0x26, 0xE0, 0x01, /* LOGICAL_MAXIMUM (480) */ \ 81 | 0x46, 0xFE, 0x01, /* PHYSICAL_MAXIMUM (550) */ \ 82 | MT_TOUCH_COLLECTION2 83 | 84 | #define USAGE_PAGES \ 85 | 0x55, 0x0C, /* UNIT_EXPONENT (-4) */ \ 86 | 0x66, 0x01, 0x10, /* UNIT (Seconds) */ \ 87 | 0x47, 0xff, 0xff, 0x00, 0x00, /* PHYSICAL_MAXIMUM (65535) */ \ 88 | 0x27, 0xff, 0xff, 0x00, 0x00, /* LOGICAL_MAXIMUM (65535) */ \ 89 | 0x75, 0x10, /* REPORT_SIZE (16) */ \ 90 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 91 | 0x05, 0x0d, /* USAGE_PAGE (Digitizers) */ \ 92 | 0x09, 0x56, /* USAGE (Scan Time) */ \ 93 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 94 | 0x09, 0x54, /* USAGE (Contact count) */ \ 95 | 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ \ 96 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 97 | 0x75, 0x08, /* REPORT_SIZE (8) */ \ 98 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 99 | 0x05, 0x09, /* USAGE_PAGE (Button) */ \ 100 | 0x09, 0x01, /* USAGE_(Button 1) */ \ 101 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ 102 | 0x75, 0x01, /* REPORT_SIZE (1) */ \ 103 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 104 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 105 | 0x95, 0x07, /* REPORT_COUNT (7) */ \ 106 | 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ 107 | 0x05, 0x0d, /* USAGE_PAGE (Digitizer) */ \ 108 | 0x85, REPORTID_MTOUCH, /* REPORT_ID (Feature) */ \ 109 | 0x09, 0x55, /* USAGE (Contact Count Maximum) */ \ 110 | 0x09, 0x59, /* USAGE (Pad TYpe) */ \ 111 | 0x75, 0x08, /* REPORT_SIZE (8) */ \ 112 | 0x95, 0x02, /* REPORT_COUNT (2) */ \ 113 | 0x25, 0x0f, /* LOGICAL_MAXIMUM (15) */ \ 114 | 0xb1, 0x02, /* FEATURE (Data,Var,Abs) */ \ 115 | 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */ \ 116 | 0x85, REPORTID_PTPHQA, /* Report ID (Certification) */ \ 117 | 0x09, 0xC5, /* Usage (0xC5) */ \ 118 | 0x15, 0x00, /* Logical Minimum (0) */ \ 119 | 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ \ 120 | 0x75, 0x08, /* Report Size (8) */ \ 121 | 0x96, 0x00, 0x01, /* Report Count (256) */ \ 122 | 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */ \ 123 | 0xc0, /* END_COLLECTION */ \ 124 | \ 125 | /*MOUSE TLC */ \ 126 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ 127 | 0x09, 0x02, /* USAGE (Mouse) */ \ 128 | 0xa1, 0x01, /* COLLECTION (Application) */ \ 129 | 0x85, REPORTID_MOUSE, /* REPORT_ID (Mouse) */ \ 130 | 0x09, 0x01, /* USAGE (Pointer) */ \ 131 | 0xa1, 0x00, /* COLLECTION (Physical) */ \ 132 | 0x05, 0x09, /* USAGE_PAGE (Button) */ \ 133 | 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ \ 134 | 0x29, 0x02, /* USAGE_MAXIMUM (Button 2) */ \ 135 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ 136 | 0x75, 0x01, /* REPORT_SIZE (1) */ \ 137 | 0x95, 0x02, /* REPORT_COUNT (2) */ \ 138 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 139 | 0x95, 0x06, /* REPORT_COUNT (6) */ \ 140 | 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ \ 141 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ \ 142 | 0x09, 0x30, /* USAGE (X) */ \ 143 | 0x09, 0x31, /* USAGE (Y) */ \ 144 | 0x75, 0x10, /* REPORT_SIZE (16) */ \ 145 | 0x95, 0x02, /* REPORT_COUNT (2) */ \ 146 | 0x25, 0x0a, /* LOGICAL_MAXIMUM (10) */ \ 147 | 0x81, 0x06, /* INPUT (Data,Var,Rel) */ \ 148 | 0xc0, /* END_COLLECTION */ \ 149 | 0xc0, /*END_COLLECTION */ 150 | // 151 | // This is the default report descriptor for the Hid device provided 152 | // by the mini driver in response to IOCTL_HID_GET_REPORT_DESCRIPTOR. 153 | // 154 | 155 | typedef UCHAR HID_REPORT_DESCRIPTOR, *PHID_REPORT_DESCRIPTOR; 156 | 157 | #ifdef DESCRIPTOR_DEF 158 | HID_REPORT_DESCRIPTOR DefaultReportDescriptor[] = { 159 | // 160 | // Multitouch report starts here 161 | // 162 | //TOUCH PAD input TLC 163 | 0x05, 0x0d, // USAGE_PAGE (Digitizers) 164 | 0x09, 0x05, // USAGE (Touch Pad) 165 | 0xa1, 0x01, // COLLECTION (Application) 166 | 0x85, REPORTID_MTOUCH, // REPORT_ID (Touch pad) 167 | 0x09, 0x22, // USAGE (Finger) 168 | MT_REF_TOUCH_COLLECTION 169 | MT_REF_TOUCH_COLLECTION 170 | MT_REF_TOUCH_COLLECTION 171 | MT_REF_TOUCH_COLLECTION 172 | MT_REF_TOUCH_COLLECTION 173 | USAGE_PAGES 174 | }; 175 | 176 | 177 | // 178 | // This is the default HID descriptor returned by the mini driver 179 | // in response to IOCTL_HID_GET_DEVICE_DESCRIPTOR. The size 180 | // of report descriptor is currently the size of DefaultReportDescriptor. 181 | // 182 | 183 | CONST HID_DESCRIPTOR DefaultHidDescriptor = { 184 | 0x09, // length of HID descriptor 185 | 0x21, // descriptor type == HID 0x21 186 | 0x0100, // hid spec release 187 | 0x00, // country code == Not Specified 188 | 0x01, // number of HID class descriptors 189 | { 0x22, // descriptor type 190 | sizeof(DefaultReportDescriptor) } // total length of report descriptor 191 | }; 192 | #endif 193 | 194 | #define true 1 195 | #define false 0 196 | 197 | typedef struct _SYNA_CONTEXT 198 | { 199 | 200 | // 201 | // Handle back to the WDFDEVICE 202 | // 203 | 204 | WDFDEVICE FxDevice; 205 | 206 | WDFQUEUE ReportQueue; 207 | 208 | BYTE DeviceMode; 209 | 210 | SPB_CONTEXT I2CContext; 211 | 212 | WDFINTERRUPT Interrupt; 213 | 214 | BOOLEAN ConnectInterrupt; 215 | 216 | BOOLEAN RegsSet; 217 | 218 | uint8_t Flags[5]; 219 | 220 | USHORT XValue[5]; 221 | 222 | USHORT YValue[5]; 223 | 224 | USHORT PValue[5]; 225 | 226 | USHORT Palm[5]; 227 | 228 | BOOLEAN BUTTONPRESSED; 229 | 230 | USHORT TIMEINT; 231 | 232 | LARGE_INTEGER LastTime; 233 | 234 | uint16_t max_x; 235 | uint16_t max_y; 236 | 237 | uint8_t max_x_hid[2]; 238 | uint8_t max_y_hid[2]; 239 | 240 | uint16_t phy_x; 241 | uint16_t phy_y; 242 | 243 | uint8_t phy_x_hid[2]; 244 | uint8_t phy_y_hid[2]; 245 | 246 | int page; 247 | 248 | unsigned long flags; 249 | 250 | struct rmi_function f01; 251 | struct rmi_function f11; 252 | struct rmi_function f30; 253 | 254 | unsigned int max_fingers; 255 | uint16_t x_size_mm; 256 | uint16_t y_size_mm; 257 | bool read_f11_ctrl_regs; 258 | uint8_t f11_ctrl_regs[RMI_F11_CTRL_REG_COUNT]; 259 | 260 | unsigned int gpio_led_count; 261 | unsigned int button_count; 262 | unsigned long button_mask; 263 | unsigned long button_state_mask; 264 | 265 | unsigned long device_flags; 266 | unsigned long firmware_id; 267 | 268 | uint8_t f01_ctrl0; 269 | uint8_t interrupt_enable_mask; 270 | bool restore_interrupt_mask; 271 | 272 | } SYNA_CONTEXT, *PSYNA_CONTEXT; 273 | 274 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SYNA_CONTEXT, GetDeviceContext) 275 | 276 | // 277 | // Function definitions 278 | // 279 | 280 | DRIVER_INITIALIZE DriverEntry; 281 | 282 | EVT_WDF_DRIVER_UNLOAD SynaDriverUnload; 283 | 284 | EVT_WDF_DRIVER_DEVICE_ADD SynaEvtDeviceAdd; 285 | 286 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL SynaEvtInternalDeviceControl; 287 | 288 | NTSTATUS 289 | SynaGetHidDescriptor( 290 | IN WDFDEVICE Device, 291 | IN WDFREQUEST Request 292 | ); 293 | 294 | NTSTATUS 295 | SynaGetReportDescriptor( 296 | IN WDFDEVICE Device, 297 | IN WDFREQUEST Request 298 | ); 299 | 300 | NTSTATUS 301 | SynaGetDeviceAttributes( 302 | IN WDFREQUEST Request 303 | ); 304 | 305 | NTSTATUS 306 | SynaGetString( 307 | IN WDFREQUEST Request 308 | ); 309 | 310 | NTSTATUS 311 | SynaWriteReport( 312 | IN PSYNA_CONTEXT DevContext, 313 | IN WDFREQUEST Request 314 | ); 315 | 316 | NTSTATUS 317 | SynaProcessVendorReport( 318 | IN PSYNA_CONTEXT DevContext, 319 | IN PVOID ReportBuffer, 320 | IN ULONG ReportBufferLen, 321 | OUT size_t* BytesWritten 322 | ); 323 | 324 | NTSTATUS 325 | SynaReadReport( 326 | IN PSYNA_CONTEXT DevContext, 327 | IN WDFREQUEST Request, 328 | OUT BOOLEAN* CompleteRequest 329 | ); 330 | 331 | NTSTATUS 332 | SynaSetFeature( 333 | IN PSYNA_CONTEXT DevContext, 334 | IN WDFREQUEST Request, 335 | OUT BOOLEAN* CompleteRequest 336 | ); 337 | 338 | NTSTATUS 339 | SynaGetFeature( 340 | IN PSYNA_CONTEXT DevContext, 341 | IN WDFREQUEST Request, 342 | OUT BOOLEAN* CompleteRequest 343 | ); 344 | 345 | PCHAR 346 | DbgHidInternalIoctlString( 347 | IN ULONG IoControlCode 348 | ); 349 | 350 | // 351 | // Helper macros 352 | // 353 | 354 | #define DEBUG_LEVEL_ERROR 1 355 | #define DEBUG_LEVEL_INFO 2 356 | #define DEBUG_LEVEL_VERBOSE 3 357 | 358 | #define DBG_INIT 1 359 | #define DBG_PNP 2 360 | #define DBG_IOCTL 4 361 | 362 | #if 0 363 | #define SynaPrint(dbglevel, dbgcatagory, fmt, ...) { \ 364 | if (SynaDebugLevel >= dbglevel && \ 365 | (SynaDebugCatagories && dbgcatagory)) \ 366 | { \ 367 | DbgPrint(DRIVERNAME); \ 368 | DbgPrint(fmt, __VA_ARGS__); \ 369 | } \ 370 | } 371 | #else 372 | #define SynaPrint(dbglevel, fmt, ...) { \ 373 | } 374 | #endif 375 | 376 | #endif 377 | -------------------------------------------------------------------------------- /crostouchpad/spb.cpp: -------------------------------------------------------------------------------- 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 "internal.h" 22 | #include "hiddevice.h" 23 | #include "spb.h" 24 | 25 | static ULONG ElanPrintDebugLevel = 100; 26 | static ULONG ElanPrintDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 27 | 28 | NTSTATUS 29 | SpbDoWriteDataSynchronously16( 30 | IN SPB_CONTEXT *SpbContext, 31 | IN UINT16 Address, 32 | IN PVOID Data, 33 | IN ULONG Length 34 | ) 35 | /*++ 36 | 37 | Routine Description: 38 | 39 | This helper routine abstracts creating and sending an I/O 40 | request (I2C Write) to the Spb I/O target. 41 | 42 | Arguments: 43 | 44 | SpbContext - Pointer to the current device context 45 | Address - The I2C register address to write to 46 | Data - A buffer to receive the data at at the above address 47 | Length - The amount of data to be read from the above address 48 | 49 | Return Value: 50 | 51 | NTSTATUS Status indicating success or failure 52 | 53 | --*/ 54 | { 55 | PUCHAR buffer; 56 | ULONG length; 57 | WDFMEMORY memory; 58 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 59 | NTSTATUS status; 60 | 61 | // 62 | // The address pointer and data buffer must be combined 63 | // into one contiguous buffer representing the write transaction. 64 | // 65 | length = Length + 2; 66 | memory = NULL; 67 | 68 | if (length > DEFAULT_SPB_BUFFER_SIZE) 69 | { 70 | status = WdfMemoryCreate( 71 | WDF_NO_OBJECT_ATTRIBUTES, 72 | NonPagedPool, 73 | CYAPA_POOL_TAG, 74 | length, 75 | &memory, 76 | (PVOID *)&buffer); 77 | 78 | if (!NT_SUCCESS(status)) 79 | { 80 | ElanPrint( 81 | DEBUG_LEVEL_ERROR, 82 | DBG_IOCTL, 83 | "Error allocating memory for Spb write - %!STATUS!", 84 | status); 85 | goto exit; 86 | } 87 | 88 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 89 | &memoryDescriptor, 90 | memory, 91 | NULL); 92 | } 93 | else 94 | { 95 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 96 | 97 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 98 | &memoryDescriptor, 99 | (PVOID)buffer, 100 | length); 101 | } 102 | 103 | UINT16 AddressBuffer[] = { 104 | Address 105 | }; 106 | 107 | // 108 | // Transaction starts by specifying the address bytes 109 | // 110 | RtlCopyMemory(buffer, (UCHAR *)&AddressBuffer, sizeof(AddressBuffer)); 111 | 112 | // 113 | // Address is followed by the data payload 114 | // 115 | RtlCopyMemory((buffer + sizeof(AddressBuffer)), Data, length - sizeof(AddressBuffer)); 116 | 117 | status = WdfIoTargetSendWriteSynchronously( 118 | SpbContext->SpbIoTarget, 119 | NULL, 120 | &memoryDescriptor, 121 | NULL, 122 | NULL, 123 | NULL); 124 | 125 | if (!NT_SUCCESS(status)) 126 | { 127 | ElanPrint( 128 | DEBUG_LEVEL_ERROR, 129 | DBG_IOCTL, 130 | "Error writing to Spb - %!STATUS!", 131 | status); 132 | goto exit; 133 | } 134 | 135 | exit: 136 | 137 | if (NULL != memory) 138 | { 139 | WdfObjectDelete(memory); 140 | } 141 | 142 | return status; 143 | } 144 | 145 | NTSTATUS 146 | SpbDoWriteDataSynchronously( 147 | IN SPB_CONTEXT *SpbContext, 148 | IN UCHAR Address, 149 | IN PVOID Data, 150 | IN ULONG Length 151 | ) 152 | /*++ 153 | 154 | Routine Description: 155 | 156 | This helper routine abstracts creating and sending an I/O 157 | request (I2C Write) to the Spb I/O target. 158 | 159 | Arguments: 160 | 161 | SpbContext - Pointer to the current device context 162 | Address - The I2C register address to write to 163 | Data - A buffer to receive the data at at the above address 164 | Length - The amount of data to be read from the above address 165 | 166 | Return Value: 167 | 168 | NTSTATUS Status indicating success or failure 169 | 170 | --*/ 171 | { 172 | PUCHAR buffer; 173 | ULONG length; 174 | WDFMEMORY memory; 175 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 176 | NTSTATUS status; 177 | 178 | // 179 | // The address pointer and data buffer must be combined 180 | // into one contiguous buffer representing the write transaction. 181 | // 182 | length = Length + 1; 183 | memory = NULL; 184 | 185 | if (length > DEFAULT_SPB_BUFFER_SIZE) 186 | { 187 | status = WdfMemoryCreate( 188 | WDF_NO_OBJECT_ATTRIBUTES, 189 | NonPagedPool, 190 | CYAPA_POOL_TAG, 191 | length, 192 | &memory, 193 | (PVOID *)&buffer); 194 | 195 | if (!NT_SUCCESS(status)) 196 | { 197 | ElanPrint( 198 | DEBUG_LEVEL_ERROR, 199 | DBG_IOCTL, 200 | "Error allocating memory for Spb write - %!STATUS!", 201 | status); 202 | goto exit; 203 | } 204 | 205 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 206 | &memoryDescriptor, 207 | memory, 208 | NULL); 209 | } 210 | else 211 | { 212 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 213 | 214 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 215 | &memoryDescriptor, 216 | (PVOID)buffer, 217 | length); 218 | } 219 | 220 | // 221 | // Transaction starts by specifying the address bytes 222 | // 223 | RtlCopyMemory(buffer, &Address, sizeof(Address)); 224 | 225 | // 226 | // Address is followed by the data payload 227 | // 228 | RtlCopyMemory((buffer + sizeof(Address)), Data, length - sizeof(Address)); 229 | 230 | status = WdfIoTargetSendWriteSynchronously( 231 | SpbContext->SpbIoTarget, 232 | NULL, 233 | &memoryDescriptor, 234 | NULL, 235 | NULL, 236 | NULL); 237 | 238 | if (!NT_SUCCESS(status)) 239 | { 240 | ElanPrint( 241 | DEBUG_LEVEL_ERROR, 242 | DBG_IOCTL, 243 | "Error writing to Spb - %!STATUS!", 244 | status); 245 | goto exit; 246 | } 247 | 248 | exit: 249 | 250 | if (NULL != memory) 251 | { 252 | WdfObjectDelete(memory); 253 | } 254 | 255 | return status; 256 | } 257 | 258 | NTSTATUS 259 | SpbWriteDataSynchronously( 260 | IN SPB_CONTEXT *SpbContext, 261 | IN UCHAR Address, 262 | IN PVOID Data, 263 | IN ULONG Length 264 | ) 265 | /*++ 266 | 267 | Routine Description: 268 | 269 | This routine abstracts creating and sending an I/O 270 | request (I2C Write) to the Spb I/O target and utilizes 271 | a helper routine to do work inside of locked code. 272 | 273 | Arguments: 274 | 275 | SpbContext - Pointer to the current device context 276 | Address - The I2C register address to write to 277 | Data - A buffer to receive the data at at the above address 278 | Length - The amount of data to be read from the above address 279 | 280 | Return Value: 281 | 282 | NTSTATUS Status indicating success or failure 283 | 284 | --*/ 285 | { 286 | NTSTATUS status; 287 | 288 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 289 | 290 | status = SpbDoWriteDataSynchronously( 291 | SpbContext, 292 | Address, 293 | Data, 294 | Length); 295 | 296 | WdfWaitLockRelease(SpbContext->SpbLock); 297 | 298 | return status; 299 | } 300 | 301 | NTSTATUS 302 | SpbWriteDataSynchronously16( 303 | IN SPB_CONTEXT *SpbContext, 304 | IN UINT16 Address, 305 | IN PVOID Data, 306 | IN ULONG Length 307 | ) 308 | /*++ 309 | 310 | Routine Description: 311 | 312 | This routine abstracts creating and sending an I/O 313 | request (I2C Write) to the Spb I/O target and utilizes 314 | a helper routine to do work inside of locked code. 315 | 316 | Arguments: 317 | 318 | SpbContext - Pointer to the current device context 319 | Address - The I2C register address to write to 320 | Data - A buffer to receive the data at at the above address 321 | Length - The amount of data to be read from the above address 322 | 323 | Return Value: 324 | 325 | NTSTATUS Status indicating success or failure 326 | 327 | --*/ 328 | { 329 | NTSTATUS status; 330 | 331 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 332 | 333 | status = SpbDoWriteDataSynchronously16( 334 | SpbContext, 335 | Address, 336 | Data, 337 | Length); 338 | 339 | WdfWaitLockRelease(SpbContext->SpbLock); 340 | 341 | return status; 342 | } 343 | 344 | NTSTATUS 345 | SpbReadDataSynchronously( 346 | _In_ SPB_CONTEXT *SpbContext, 347 | _In_ UCHAR Address, 348 | _In_reads_bytes_(Length) PVOID Data, 349 | _In_ ULONG Length 350 | ) 351 | /*++ 352 | 353 | Routine Description: 354 | 355 | This helper routine abstracts creating and sending an I/O 356 | request (I2C Read) to the Spb I/O target. 357 | 358 | Arguments: 359 | 360 | SpbContext - Pointer to the current device context 361 | Address - The I2C register address to read from 362 | Data - A buffer to receive the data at at the above address 363 | Length - The amount of data to be read from the above address 364 | 365 | Return Value: 366 | 367 | NTSTATUS Status indicating success or failure 368 | 369 | --*/ 370 | { 371 | PUCHAR buffer; 372 | WDFMEMORY memory; 373 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 374 | NTSTATUS status; 375 | ULONG_PTR bytesRead; 376 | 377 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 378 | 379 | memory = NULL; 380 | status = STATUS_INVALID_PARAMETER; 381 | bytesRead = 0; 382 | 383 | // 384 | // Read transactions start by writing an address pointer 385 | // 386 | status = SpbDoWriteDataSynchronously( 387 | SpbContext, 388 | Address, 389 | NULL, 390 | 0); 391 | 392 | if (!NT_SUCCESS(status)) 393 | { 394 | ElanPrint( 395 | DEBUG_LEVEL_ERROR, 396 | DBG_IOCTL, 397 | "Error setting address pointer for Spb read - %!STATUS!", 398 | status); 399 | goto exit; 400 | } 401 | 402 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 403 | { 404 | status = WdfMemoryCreate( 405 | WDF_NO_OBJECT_ATTRIBUTES, 406 | NonPagedPool, 407 | CYAPA_POOL_TAG, 408 | Length, 409 | &memory, 410 | (PVOID *)&buffer); 411 | 412 | if (!NT_SUCCESS(status)) 413 | { 414 | ElanPrint( 415 | DEBUG_LEVEL_ERROR, 416 | DBG_IOCTL, 417 | "Error allocating memory for Spb read - %!STATUS!", 418 | status); 419 | goto exit; 420 | } 421 | 422 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 423 | &memoryDescriptor, 424 | memory, 425 | NULL); 426 | } 427 | else 428 | { 429 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 430 | 431 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 432 | &memoryDescriptor, 433 | (PVOID)buffer, 434 | Length); 435 | } 436 | 437 | 438 | status = WdfIoTargetSendReadSynchronously( 439 | SpbContext->SpbIoTarget, 440 | NULL, 441 | &memoryDescriptor, 442 | NULL, 443 | NULL, 444 | &bytesRead); 445 | 446 | if (!NT_SUCCESS(status) || 447 | bytesRead != Length) 448 | { 449 | ElanPrint( 450 | DEBUG_LEVEL_ERROR, 451 | DBG_IOCTL, 452 | "Error reading from Spb - %!STATUS!", 453 | status); 454 | goto exit; 455 | } 456 | 457 | // 458 | // Copy back to the caller's buffer 459 | // 460 | RtlCopyMemory(Data, buffer, Length); 461 | 462 | exit: 463 | if (NULL != memory) 464 | { 465 | WdfObjectDelete(memory); 466 | } 467 | 468 | WdfWaitLockRelease(SpbContext->SpbLock); 469 | 470 | return status; 471 | } 472 | 473 | NTSTATUS 474 | SpbReadDataSynchronously16( 475 | _In_ SPB_CONTEXT *SpbContext, 476 | _In_ UINT16 Address, 477 | _In_reads_bytes_(Length) PVOID Data, 478 | _In_ ULONG Length 479 | ) 480 | /*++ 481 | 482 | Routine Description: 483 | 484 | This helper routine abstracts creating and sending an I/O 485 | request (I2C Read) to the Spb I/O target. 486 | 487 | Arguments: 488 | 489 | SpbContext - Pointer to the current device context 490 | Address - The I2C register address to read from 491 | Data - A buffer to receive the data at at the above address 492 | Length - The amount of data to be read from the above address 493 | 494 | Return Value: 495 | 496 | NTSTATUS Status indicating success or failure 497 | 498 | --*/ 499 | { 500 | PUCHAR buffer; 501 | WDFMEMORY memory; 502 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 503 | NTSTATUS status; 504 | ULONG_PTR bytesRead; 505 | 506 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 507 | 508 | memory = NULL; 509 | status = STATUS_INVALID_PARAMETER; 510 | bytesRead = 0; 511 | 512 | // 513 | // Read transactions start by writing an address pointer 514 | // 515 | status = SpbDoWriteDataSynchronously16( 516 | SpbContext, 517 | Address, 518 | NULL, 519 | 0); 520 | 521 | if (!NT_SUCCESS(status)) 522 | { 523 | ElanPrint( 524 | DEBUG_LEVEL_ERROR, 525 | DBG_IOCTL, 526 | "Error setting address pointer for Spb read - %!STATUS!", 527 | status); 528 | goto exit; 529 | } 530 | 531 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 532 | { 533 | status = WdfMemoryCreate( 534 | WDF_NO_OBJECT_ATTRIBUTES, 535 | NonPagedPool, 536 | CYAPA_POOL_TAG, 537 | Length, 538 | &memory, 539 | (PVOID *)&buffer); 540 | 541 | if (!NT_SUCCESS(status)) 542 | { 543 | ElanPrint( 544 | DEBUG_LEVEL_ERROR, 545 | DBG_IOCTL, 546 | "Error allocating memory for Spb read - %!STATUS!", 547 | status); 548 | goto exit; 549 | } 550 | 551 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 552 | &memoryDescriptor, 553 | memory, 554 | NULL); 555 | } 556 | else 557 | { 558 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 559 | 560 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 561 | &memoryDescriptor, 562 | (PVOID)buffer, 563 | Length); 564 | } 565 | 566 | 567 | status = WdfIoTargetSendReadSynchronously( 568 | SpbContext->SpbIoTarget, 569 | NULL, 570 | &memoryDescriptor, 571 | NULL, 572 | NULL, 573 | &bytesRead); 574 | 575 | if (!NT_SUCCESS(status) || 576 | bytesRead != Length) 577 | { 578 | ElanPrint( 579 | DEBUG_LEVEL_ERROR, 580 | DBG_IOCTL, 581 | "Error reading from Spb - %!STATUS!", 582 | status); 583 | goto exit; 584 | } 585 | 586 | // 587 | // Copy back to the caller's buffer 588 | // 589 | RtlCopyMemory(Data, buffer, Length); 590 | 591 | exit: 592 | if (NULL != memory) 593 | { 594 | WdfObjectDelete(memory); 595 | } 596 | 597 | WdfWaitLockRelease(SpbContext->SpbLock); 598 | 599 | return status; 600 | } 601 | 602 | VOID 603 | SpbTargetDeinitialize( 604 | IN WDFDEVICE FxDevice, 605 | IN SPB_CONTEXT *SpbContext 606 | ) 607 | /*++ 608 | 609 | Routine Description: 610 | 611 | This helper routine is used to free any members added to the SPB_CONTEXT, 612 | note the SPB I/O target is parented to the device and will be 613 | closed and free'd when the device is removed. 614 | 615 | Arguments: 616 | 617 | FxDevice - Handle to the framework device object 618 | SpbContext - Pointer to the current device context 619 | 620 | Return Value: 621 | 622 | NTSTATUS Status indicating success or failure 623 | 624 | --*/ 625 | { 626 | UNREFERENCED_PARAMETER(FxDevice); 627 | UNREFERENCED_PARAMETER(SpbContext); 628 | 629 | // 630 | // Free any SPB_CONTEXT allocations here 631 | // 632 | if (SpbContext->SpbLock != NULL) 633 | { 634 | WdfObjectDelete(SpbContext->SpbLock); 635 | } 636 | 637 | if (SpbContext->ReadMemory != NULL) 638 | { 639 | WdfObjectDelete(SpbContext->ReadMemory); 640 | } 641 | 642 | if (SpbContext->WriteMemory != NULL) 643 | { 644 | WdfObjectDelete(SpbContext->WriteMemory); 645 | } 646 | } 647 | 648 | NTSTATUS 649 | SpbTargetInitialize( 650 | IN WDFDEVICE FxDevice, 651 | IN SPB_CONTEXT *SpbContext 652 | ) 653 | /*++ 654 | 655 | Routine Description: 656 | 657 | This helper routine opens the Spb I/O target and 658 | initializes a request object used for the lifetime 659 | of communication between this driver and Spb. 660 | 661 | Arguments: 662 | 663 | FxDevice - Handle to the framework device object 664 | SpbContext - Pointer to the current device context 665 | 666 | Return Value: 667 | 668 | NTSTATUS Status indicating success or failure 669 | 670 | --*/ 671 | { 672 | WDF_OBJECT_ATTRIBUTES objectAttributes; 673 | WDF_IO_TARGET_OPEN_PARAMS openParams; 674 | UNICODE_STRING spbDeviceName; 675 | WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 676 | NTSTATUS status; 677 | 678 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 679 | objectAttributes.ParentObject = FxDevice; 680 | 681 | status = WdfIoTargetCreate( 682 | FxDevice, 683 | &objectAttributes, 684 | &SpbContext->SpbIoTarget); 685 | 686 | if (!NT_SUCCESS(status)) 687 | { 688 | ElanPrint( 689 | DEBUG_LEVEL_ERROR, 690 | DBG_IOCTL, 691 | "Error creating IoTarget object - %!STATUS!", 692 | status); 693 | 694 | WdfObjectDelete(SpbContext->SpbIoTarget); 695 | goto exit; 696 | } 697 | 698 | RtlInitEmptyUnicodeString( 699 | &spbDeviceName, 700 | spbDeviceNameBuffer, 701 | sizeof(spbDeviceNameBuffer)); 702 | 703 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 704 | &spbDeviceName, 705 | SpbContext->I2cResHubId.LowPart, 706 | SpbContext->I2cResHubId.HighPart); 707 | 708 | if (!NT_SUCCESS(status)) 709 | { 710 | ElanPrint( 711 | DEBUG_LEVEL_ERROR, 712 | DBG_IOCTL, 713 | "Error creating Spb resource hub path string - %!STATUS!", 714 | status); 715 | goto exit; 716 | } 717 | 718 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 719 | &openParams, 720 | &spbDeviceName, 721 | (GENERIC_READ | GENERIC_WRITE)); 722 | 723 | openParams.ShareAccess = 0; 724 | openParams.CreateDisposition = FILE_OPEN; 725 | openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; 726 | 727 | status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); 728 | 729 | if (!NT_SUCCESS(status)) 730 | { 731 | ElanPrint( 732 | DEBUG_LEVEL_ERROR, 733 | DBG_IOCTL, 734 | "Error opening Spb target for communication - %!STATUS!", 735 | status); 736 | goto exit; 737 | } 738 | 739 | // 740 | // Allocate some fixed-size buffers from NonPagedPool for typical 741 | // Spb transaction sizes to avoid pool fragmentation in most cases 742 | // 743 | status = WdfMemoryCreate( 744 | WDF_NO_OBJECT_ATTRIBUTES, 745 | NonPagedPool, 746 | CYAPA_POOL_TAG, 747 | DEFAULT_SPB_BUFFER_SIZE, 748 | &SpbContext->WriteMemory, 749 | NULL); 750 | 751 | if (!NT_SUCCESS(status)) 752 | { 753 | ElanPrint( 754 | DEBUG_LEVEL_ERROR, 755 | DBG_IOCTL, 756 | "Error allocating default memory for Spb write - %!STATUS!", 757 | status); 758 | goto exit; 759 | } 760 | 761 | status = WdfMemoryCreate( 762 | WDF_NO_OBJECT_ATTRIBUTES, 763 | NonPagedPool, 764 | CYAPA_POOL_TAG, 765 | DEFAULT_SPB_BUFFER_SIZE, 766 | &SpbContext->ReadMemory, 767 | NULL); 768 | 769 | if (!NT_SUCCESS(status)) 770 | { 771 | ElanPrint( 772 | DEBUG_LEVEL_ERROR, 773 | DBG_IOCTL, 774 | "Error allocating default memory for Spb read - %!STATUS!", 775 | status); 776 | goto exit; 777 | } 778 | 779 | // 780 | // Allocate a waitlock to guard access to the default buffers 781 | // 782 | status = WdfWaitLockCreate( 783 | WDF_NO_OBJECT_ATTRIBUTES, 784 | &SpbContext->SpbLock); 785 | 786 | if (!NT_SUCCESS(status)) 787 | { 788 | ElanPrint( 789 | DEBUG_LEVEL_ERROR, 790 | DBG_IOCTL, 791 | "Error creating Spb Waitlock - %!STATUS!", 792 | status); 793 | goto exit; 794 | } 795 | 796 | exit: 797 | 798 | if (!NT_SUCCESS(status)) 799 | { 800 | SpbTargetDeinitialize(FxDevice, SpbContext); 801 | } 802 | 803 | return status; 804 | } -------------------------------------------------------------------------------- /crostouchpad/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 "driver.h" 22 | #include "spb.h" 23 | #include 24 | 25 | static ULONG SynaDebugLevel = 100; 26 | static ULONG SynaDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 27 | 28 | NTSTATUS 29 | SpbDoWriteDataSynchronously16( 30 | IN SPB_CONTEXT *SpbContext, 31 | IN UINT16 Address, 32 | IN PVOID Data, 33 | IN ULONG Length 34 | ) 35 | /*++ 36 | 37 | Routine Description: 38 | 39 | This helper routine abstracts creating and sending an I/O 40 | request (I2C Write) to the Spb I/O target. 41 | 42 | Arguments: 43 | 44 | SpbContext - Pointer to the current device context 45 | Address - The I2C register address to write to 46 | Data - A buffer to receive the data at at the above address 47 | Length - The amount of data to be read from the above address 48 | 49 | Return Value: 50 | 51 | NTSTATUS Status indicating success or failure 52 | 53 | --*/ 54 | { 55 | PUCHAR buffer; 56 | ULONG length; 57 | WDFMEMORY memory; 58 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 59 | NTSTATUS status; 60 | 61 | // 62 | // The address pointer and data buffer must be combined 63 | // into one contiguous buffer representing the write transaction. 64 | // 65 | length = Length + 2; 66 | memory = NULL; 67 | 68 | if (length > DEFAULT_SPB_BUFFER_SIZE) 69 | { 70 | status = WdfMemoryCreate( 71 | WDF_NO_OBJECT_ATTRIBUTES, 72 | NonPagedPool, 73 | SYNA_POOL_TAG, 74 | length, 75 | &memory, 76 | (PVOID *)&buffer); 77 | 78 | if (!NT_SUCCESS(status)) 79 | { 80 | SynaPrint( 81 | DEBUG_LEVEL_ERROR, 82 | DBG_IOCTL, 83 | "Error allocating memory for Spb write - %!STATUS!", 84 | status); 85 | goto exit; 86 | } 87 | 88 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 89 | &memoryDescriptor, 90 | memory, 91 | NULL); 92 | } 93 | else 94 | { 95 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 96 | 97 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 98 | &memoryDescriptor, 99 | (PVOID)buffer, 100 | length); 101 | } 102 | 103 | UINT16 AddressBuffer[] = { 104 | Address 105 | }; 106 | 107 | // 108 | // Transaction starts by specifying the address bytes 109 | // 110 | RtlCopyMemory(buffer, (UCHAR *)&AddressBuffer, sizeof(AddressBuffer)); 111 | 112 | // 113 | // Address is followed by the data payload 114 | // 115 | RtlCopyMemory((buffer + sizeof(AddressBuffer)), Data, length - sizeof(AddressBuffer)); 116 | 117 | status = WdfIoTargetSendWriteSynchronously( 118 | SpbContext->SpbIoTarget, 119 | NULL, 120 | &memoryDescriptor, 121 | NULL, 122 | NULL, 123 | NULL); 124 | 125 | if (!NT_SUCCESS(status)) 126 | { 127 | SynaPrint( 128 | DEBUG_LEVEL_ERROR, 129 | DBG_IOCTL, 130 | "Error writing to Spb - %!STATUS!", 131 | status); 132 | goto exit; 133 | } 134 | 135 | exit: 136 | 137 | if (NULL != memory) 138 | { 139 | WdfObjectDelete(memory); 140 | } 141 | 142 | return status; 143 | } 144 | 145 | NTSTATUS 146 | SpbDoWriteDataSynchronously( 147 | IN SPB_CONTEXT *SpbContext, 148 | IN UCHAR Address, 149 | IN PVOID Data, 150 | IN ULONG Length 151 | ) 152 | /*++ 153 | 154 | Routine Description: 155 | 156 | This helper routine abstracts creating and sending an I/O 157 | request (I2C Write) to the Spb I/O target. 158 | 159 | Arguments: 160 | 161 | SpbContext - Pointer to the current device context 162 | Address - The I2C register address to write to 163 | Data - A buffer to receive the data at at the above address 164 | Length - The amount of data to be read from the above address 165 | 166 | Return Value: 167 | 168 | NTSTATUS Status indicating success or failure 169 | 170 | --*/ 171 | { 172 | PUCHAR buffer; 173 | ULONG length; 174 | WDFMEMORY memory; 175 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 176 | NTSTATUS status; 177 | 178 | // 179 | // The address pointer and data buffer must be combined 180 | // into one contiguous buffer representing the write transaction. 181 | // 182 | length = Length + 1; 183 | memory = NULL; 184 | 185 | if (length > DEFAULT_SPB_BUFFER_SIZE) 186 | { 187 | status = WdfMemoryCreate( 188 | WDF_NO_OBJECT_ATTRIBUTES, 189 | NonPagedPool, 190 | SYNA_POOL_TAG, 191 | length, 192 | &memory, 193 | (PVOID *)&buffer); 194 | 195 | if (!NT_SUCCESS(status)) 196 | { 197 | SynaPrint( 198 | DEBUG_LEVEL_ERROR, 199 | DBG_IOCTL, 200 | "Error allocating memory for Spb write - %!STATUS!", 201 | status); 202 | goto exit; 203 | } 204 | 205 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 206 | &memoryDescriptor, 207 | memory, 208 | NULL); 209 | } 210 | else 211 | { 212 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 213 | 214 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 215 | &memoryDescriptor, 216 | (PVOID)buffer, 217 | length); 218 | } 219 | 220 | // 221 | // Transaction starts by specifying the address bytes 222 | // 223 | RtlCopyMemory(buffer, &Address, sizeof(Address)); 224 | 225 | // 226 | // Address is followed by the data payload 227 | // 228 | RtlCopyMemory((buffer + sizeof(Address)), Data, length - sizeof(Address)); 229 | 230 | status = WdfIoTargetSendWriteSynchronously( 231 | SpbContext->SpbIoTarget, 232 | NULL, 233 | &memoryDescriptor, 234 | NULL, 235 | NULL, 236 | NULL); 237 | 238 | if (!NT_SUCCESS(status)) 239 | { 240 | SynaPrint( 241 | DEBUG_LEVEL_ERROR, 242 | DBG_IOCTL, 243 | "Error writing to Spb - %!STATUS!", 244 | status); 245 | goto exit; 246 | } 247 | 248 | exit: 249 | 250 | if (NULL != memory) 251 | { 252 | WdfObjectDelete(memory); 253 | } 254 | 255 | return status; 256 | } 257 | 258 | NTSTATUS 259 | SpbWriteDataSynchronously( 260 | IN SPB_CONTEXT *SpbContext, 261 | IN UCHAR Address, 262 | IN PVOID Data, 263 | IN ULONG Length 264 | ) 265 | /*++ 266 | 267 | Routine Description: 268 | 269 | This routine abstracts creating and sending an I/O 270 | request (I2C Write) to the Spb I/O target and utilizes 271 | a helper routine to do work inside of locked code. 272 | 273 | Arguments: 274 | 275 | SpbContext - Pointer to the current device context 276 | Address - The I2C register address to write to 277 | Data - A buffer to receive the data at at the above address 278 | Length - The amount of data to be read from the above address 279 | 280 | Return Value: 281 | 282 | NTSTATUS Status indicating success or failure 283 | 284 | --*/ 285 | { 286 | NTSTATUS status; 287 | 288 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 289 | 290 | status = SpbDoWriteDataSynchronously( 291 | SpbContext, 292 | Address, 293 | Data, 294 | Length); 295 | 296 | WdfWaitLockRelease(SpbContext->SpbLock); 297 | 298 | return status; 299 | } 300 | 301 | NTSTATUS 302 | SpbWriteDataSynchronously16( 303 | IN SPB_CONTEXT *SpbContext, 304 | IN UINT16 Address, 305 | IN PVOID Data, 306 | IN ULONG Length 307 | ) 308 | /*++ 309 | 310 | Routine Description: 311 | 312 | This routine abstracts creating and sending an I/O 313 | request (I2C Write) to the Spb I/O target and utilizes 314 | a helper routine to do work inside of locked code. 315 | 316 | Arguments: 317 | 318 | SpbContext - Pointer to the current device context 319 | Address - The I2C register address to write to 320 | Data - A buffer to receive the data at at the above address 321 | Length - The amount of data to be read from the above address 322 | 323 | Return Value: 324 | 325 | NTSTATUS Status indicating success or failure 326 | 327 | --*/ 328 | { 329 | NTSTATUS status; 330 | 331 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 332 | 333 | status = SpbDoWriteDataSynchronously16( 334 | SpbContext, 335 | Address, 336 | Data, 337 | Length); 338 | 339 | WdfWaitLockRelease(SpbContext->SpbLock); 340 | 341 | return status; 342 | } 343 | 344 | NTSTATUS 345 | SpbOnlyReadDataSynchronously( 346 | _In_ SPB_CONTEXT *SpbContext, 347 | _In_reads_bytes_(Length) PVOID Data, 348 | _In_ ULONG Length 349 | ) 350 | /*++ 351 | Routine Description: 352 | This helper routine abstracts creating and sending an I/O 353 | request (I2C Read) to the Spb I/O target. 354 | Arguments: 355 | SpbContext - Pointer to the current device context 356 | Address - The I2C register address to read from 357 | Data - A buffer to receive the data at at the above address 358 | Length - The amount of data to be read from the above address 359 | Return Value: 360 | NTSTATUS Status indicating success or failure 361 | --*/ 362 | { 363 | PUCHAR buffer; 364 | WDFMEMORY memory; 365 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 366 | NTSTATUS status; 367 | ULONG_PTR bytesRead; 368 | 369 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 370 | 371 | memory = NULL; 372 | status = STATUS_INVALID_PARAMETER; 373 | bytesRead = 0; 374 | 375 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 376 | { 377 | status = WdfMemoryCreate( 378 | WDF_NO_OBJECT_ATTRIBUTES, 379 | NonPagedPool, 380 | SYNA_POOL_TAG, 381 | Length, 382 | &memory, 383 | (PVOID *)&buffer); 384 | 385 | if (!NT_SUCCESS(status)) 386 | { 387 | SynaPrint( 388 | DEBUG_LEVEL_ERROR, 389 | DBG_IOCTL, 390 | "Error allocating memory for Spb read - %!STATUS!", 391 | status); 392 | goto exit; 393 | } 394 | 395 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 396 | &memoryDescriptor, 397 | memory, 398 | NULL); 399 | } 400 | else 401 | { 402 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 403 | 404 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 405 | &memoryDescriptor, 406 | (PVOID)buffer, 407 | Length); 408 | } 409 | 410 | 411 | status = WdfIoTargetSendReadSynchronously( 412 | SpbContext->SpbIoTarget, 413 | NULL, 414 | &memoryDescriptor, 415 | NULL, 416 | NULL, 417 | &bytesRead); 418 | 419 | if (!NT_SUCCESS(status) || 420 | bytesRead != Length) 421 | { 422 | SynaPrint( 423 | DEBUG_LEVEL_ERROR, 424 | DBG_IOCTL, 425 | "Error reading from Spb - %!STATUS!", 426 | status); 427 | goto exit; 428 | } 429 | 430 | // 431 | // Copy back to the caller's buffer 432 | // 433 | RtlCopyMemory(Data, buffer, Length); 434 | 435 | exit: 436 | if (NULL != memory) 437 | { 438 | WdfObjectDelete(memory); 439 | } 440 | 441 | WdfWaitLockRelease(SpbContext->SpbLock); 442 | 443 | return status; 444 | } 445 | 446 | NTSTATUS 447 | SpbReadDataSynchronously( 448 | _In_ SPB_CONTEXT *SpbContext, 449 | _In_ UCHAR Address, 450 | _In_reads_bytes_(Length) PVOID Data, 451 | _In_ ULONG Length 452 | ) 453 | /*++ 454 | 455 | Routine Description: 456 | 457 | This helper routine abstracts creating and sending an I/O 458 | request (I2C Read) to the Spb I/O target. 459 | 460 | Arguments: 461 | 462 | SpbContext - Pointer to the current device context 463 | Address - The I2C register address to read from 464 | Data - A buffer to receive the data at at the above address 465 | Length - The amount of data to be read from the above address 466 | 467 | Return Value: 468 | 469 | NTSTATUS Status indicating success or failure 470 | 471 | --*/ 472 | { 473 | PUCHAR buffer; 474 | WDFMEMORY memory; 475 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 476 | NTSTATUS status; 477 | ULONG_PTR bytesRead; 478 | 479 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 480 | 481 | memory = NULL; 482 | status = STATUS_INVALID_PARAMETER; 483 | bytesRead = 0; 484 | 485 | // 486 | // Read transactions start by writing an address pointer 487 | // 488 | status = SpbDoWriteDataSynchronously( 489 | SpbContext, 490 | Address, 491 | NULL, 492 | 0); 493 | 494 | if (!NT_SUCCESS(status)) 495 | { 496 | SynaPrint( 497 | DEBUG_LEVEL_ERROR, 498 | DBG_IOCTL, 499 | "Error setting address pointer for Spb read - %!STATUS!", 500 | status); 501 | goto exit; 502 | } 503 | 504 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 505 | { 506 | status = WdfMemoryCreate( 507 | WDF_NO_OBJECT_ATTRIBUTES, 508 | NonPagedPool, 509 | SYNA_POOL_TAG, 510 | Length, 511 | &memory, 512 | (PVOID *)&buffer); 513 | 514 | if (!NT_SUCCESS(status)) 515 | { 516 | SynaPrint( 517 | DEBUG_LEVEL_ERROR, 518 | DBG_IOCTL, 519 | "Error allocating memory for Spb read - %!STATUS!", 520 | status); 521 | goto exit; 522 | } 523 | 524 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 525 | &memoryDescriptor, 526 | memory, 527 | NULL); 528 | } 529 | else 530 | { 531 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 532 | 533 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 534 | &memoryDescriptor, 535 | (PVOID)buffer, 536 | Length); 537 | } 538 | 539 | 540 | status = WdfIoTargetSendReadSynchronously( 541 | SpbContext->SpbIoTarget, 542 | NULL, 543 | &memoryDescriptor, 544 | NULL, 545 | NULL, 546 | &bytesRead); 547 | 548 | if (!NT_SUCCESS(status) || 549 | bytesRead != Length) 550 | { 551 | SynaPrint( 552 | DEBUG_LEVEL_ERROR, 553 | DBG_IOCTL, 554 | "Error reading from Spb - %!STATUS!", 555 | status); 556 | goto exit; 557 | } 558 | 559 | // 560 | // Copy back to the caller's buffer 561 | // 562 | RtlCopyMemory(Data, buffer, Length); 563 | 564 | exit: 565 | if (NULL != memory) 566 | { 567 | WdfObjectDelete(memory); 568 | } 569 | 570 | WdfWaitLockRelease(SpbContext->SpbLock); 571 | 572 | return status; 573 | } 574 | 575 | NTSTATUS 576 | SpbReadDataSynchronously16( 577 | _In_ SPB_CONTEXT *SpbContext, 578 | _In_ UINT16 Address, 579 | _In_reads_bytes_(Length) PVOID Data, 580 | _In_ ULONG Length 581 | ) 582 | /*++ 583 | 584 | Routine Description: 585 | 586 | This helper routine abstracts creating and sending an I/O 587 | request (I2C Read) to the Spb I/O target. 588 | 589 | Arguments: 590 | 591 | SpbContext - Pointer to the current device context 592 | Address - The I2C register address to read from 593 | Data - A buffer to receive the data at at the above address 594 | Length - The amount of data to be read from the above address 595 | 596 | Return Value: 597 | 598 | NTSTATUS Status indicating success or failure 599 | 600 | --*/ 601 | { 602 | PUCHAR buffer; 603 | WDFMEMORY memory; 604 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 605 | NTSTATUS status; 606 | ULONG_PTR bytesRead; 607 | 608 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 609 | 610 | memory = NULL; 611 | status = STATUS_INVALID_PARAMETER; 612 | bytesRead = 0; 613 | 614 | // 615 | // Read transactions start by writing an address pointer 616 | // 617 | status = SpbDoWriteDataSynchronously16( 618 | SpbContext, 619 | Address, 620 | NULL, 621 | 0); 622 | 623 | if (!NT_SUCCESS(status)) 624 | { 625 | SynaPrint( 626 | DEBUG_LEVEL_ERROR, 627 | DBG_IOCTL, 628 | "Error setting address pointer for Spb read - %!STATUS!", 629 | status); 630 | goto exit; 631 | } 632 | 633 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 634 | { 635 | status = WdfMemoryCreate( 636 | WDF_NO_OBJECT_ATTRIBUTES, 637 | NonPagedPool, 638 | SYNA_POOL_TAG, 639 | Length, 640 | &memory, 641 | (PVOID *)&buffer); 642 | 643 | if (!NT_SUCCESS(status)) 644 | { 645 | SynaPrint( 646 | DEBUG_LEVEL_ERROR, 647 | DBG_IOCTL, 648 | "Error allocating memory for Spb read - %!STATUS!", 649 | status); 650 | goto exit; 651 | } 652 | 653 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 654 | &memoryDescriptor, 655 | memory, 656 | NULL); 657 | } 658 | else 659 | { 660 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 661 | 662 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 663 | &memoryDescriptor, 664 | (PVOID)buffer, 665 | Length); 666 | } 667 | 668 | 669 | status = WdfIoTargetSendReadSynchronously( 670 | SpbContext->SpbIoTarget, 671 | NULL, 672 | &memoryDescriptor, 673 | NULL, 674 | NULL, 675 | &bytesRead); 676 | 677 | if (!NT_SUCCESS(status) || 678 | bytesRead != Length) 679 | { 680 | SynaPrint( 681 | DEBUG_LEVEL_ERROR, 682 | DBG_IOCTL, 683 | "Error reading from Spb - %!STATUS!", 684 | status); 685 | goto exit; 686 | } 687 | 688 | // 689 | // Copy back to the caller's buffer 690 | // 691 | RtlCopyMemory(Data, buffer, Length); 692 | 693 | exit: 694 | if (NULL != memory) 695 | { 696 | WdfObjectDelete(memory); 697 | } 698 | 699 | WdfWaitLockRelease(SpbContext->SpbLock); 700 | 701 | return status; 702 | } 703 | 704 | VOID 705 | SpbTargetDeinitialize( 706 | IN WDFDEVICE FxDevice, 707 | IN SPB_CONTEXT *SpbContext 708 | ) 709 | /*++ 710 | 711 | Routine Description: 712 | 713 | This helper routine is used to free any members added to the SPB_CONTEXT, 714 | note the SPB I/O target is parented to the device and will be 715 | closed and free'd when the device is removed. 716 | 717 | Arguments: 718 | 719 | FxDevice - Handle to the framework device object 720 | SpbContext - Pointer to the current device context 721 | 722 | Return Value: 723 | 724 | NTSTATUS Status indicating success or failure 725 | 726 | --*/ 727 | { 728 | UNREFERENCED_PARAMETER(FxDevice); 729 | UNREFERENCED_PARAMETER(SpbContext); 730 | 731 | // 732 | // Free any SPB_CONTEXT allocations here 733 | // 734 | if (SpbContext->SpbLock != NULL) 735 | { 736 | WdfObjectDelete(SpbContext->SpbLock); 737 | } 738 | 739 | if (SpbContext->ReadMemory != NULL) 740 | { 741 | WdfObjectDelete(SpbContext->ReadMemory); 742 | } 743 | 744 | if (SpbContext->WriteMemory != NULL) 745 | { 746 | WdfObjectDelete(SpbContext->WriteMemory); 747 | } 748 | } 749 | 750 | NTSTATUS 751 | SpbTargetInitialize( 752 | IN WDFDEVICE FxDevice, 753 | IN SPB_CONTEXT *SpbContext 754 | ) 755 | /*++ 756 | 757 | Routine Description: 758 | 759 | This helper routine opens the Spb I/O target and 760 | initializes a request object used for the lifetime 761 | of communication between this driver and Spb. 762 | 763 | Arguments: 764 | 765 | FxDevice - Handle to the framework device object 766 | SpbContext - Pointer to the current device context 767 | 768 | Return Value: 769 | 770 | NTSTATUS Status indicating success or failure 771 | 772 | --*/ 773 | { 774 | WDF_OBJECT_ATTRIBUTES objectAttributes; 775 | WDF_IO_TARGET_OPEN_PARAMS openParams; 776 | UNICODE_STRING spbDeviceName; 777 | WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 778 | NTSTATUS status; 779 | 780 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 781 | objectAttributes.ParentObject = FxDevice; 782 | 783 | status = WdfIoTargetCreate( 784 | FxDevice, 785 | &objectAttributes, 786 | &SpbContext->SpbIoTarget); 787 | 788 | if (!NT_SUCCESS(status)) 789 | { 790 | SynaPrint( 791 | DEBUG_LEVEL_ERROR, 792 | DBG_IOCTL, 793 | "Error creating IoTarget object - %!STATUS!", 794 | status); 795 | 796 | WdfObjectDelete(SpbContext->SpbIoTarget); 797 | goto exit; 798 | } 799 | 800 | RtlInitEmptyUnicodeString( 801 | &spbDeviceName, 802 | spbDeviceNameBuffer, 803 | sizeof(spbDeviceNameBuffer)); 804 | 805 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 806 | &spbDeviceName, 807 | SpbContext->I2cResHubId.LowPart, 808 | SpbContext->I2cResHubId.HighPart); 809 | 810 | if (!NT_SUCCESS(status)) 811 | { 812 | SynaPrint( 813 | DEBUG_LEVEL_ERROR, 814 | DBG_IOCTL, 815 | "Error creating Spb resource hub path string - %!STATUS!", 816 | status); 817 | goto exit; 818 | } 819 | 820 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 821 | &openParams, 822 | &spbDeviceName, 823 | (GENERIC_READ | GENERIC_WRITE)); 824 | 825 | openParams.ShareAccess = 0; 826 | openParams.CreateDisposition = FILE_OPEN; 827 | openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; 828 | 829 | status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); 830 | 831 | if (!NT_SUCCESS(status)) 832 | { 833 | SynaPrint( 834 | DEBUG_LEVEL_ERROR, 835 | DBG_IOCTL, 836 | "Error opening Spb target for communication - %!STATUS!", 837 | status); 838 | goto exit; 839 | } 840 | 841 | // 842 | // Allocate some fixed-size buffers from NonPagedPool for typical 843 | // Spb transaction sizes to avoid pool fragmentation in most cases 844 | // 845 | status = WdfMemoryCreate( 846 | WDF_NO_OBJECT_ATTRIBUTES, 847 | NonPagedPool, 848 | SYNA_POOL_TAG, 849 | DEFAULT_SPB_BUFFER_SIZE, 850 | &SpbContext->WriteMemory, 851 | NULL); 852 | 853 | if (!NT_SUCCESS(status)) 854 | { 855 | SynaPrint( 856 | DEBUG_LEVEL_ERROR, 857 | DBG_IOCTL, 858 | "Error allocating default memory for Spb write - %!STATUS!", 859 | status); 860 | goto exit; 861 | } 862 | 863 | status = WdfMemoryCreate( 864 | WDF_NO_OBJECT_ATTRIBUTES, 865 | NonPagedPool, 866 | SYNA_POOL_TAG, 867 | DEFAULT_SPB_BUFFER_SIZE, 868 | &SpbContext->ReadMemory, 869 | NULL); 870 | 871 | if (!NT_SUCCESS(status)) 872 | { 873 | SynaPrint( 874 | DEBUG_LEVEL_ERROR, 875 | DBG_IOCTL, 876 | "Error allocating default memory for Spb read - %!STATUS!", 877 | status); 878 | goto exit; 879 | } 880 | 881 | // 882 | // Allocate a waitlock to guard access to the default buffers 883 | // 884 | status = WdfWaitLockCreate( 885 | WDF_NO_OBJECT_ATTRIBUTES, 886 | &SpbContext->SpbLock); 887 | 888 | if (!NT_SUCCESS(status)) 889 | { 890 | SynaPrint( 891 | DEBUG_LEVEL_ERROR, 892 | DBG_IOCTL, 893 | "Error creating Spb Waitlock - %!STATUS!", 894 | status); 895 | goto exit; 896 | } 897 | 898 | exit: 899 | 900 | if (!NT_SUCCESS(status)) 901 | { 902 | SpbTargetDeinitialize(FxDevice, SpbContext); 903 | } 904 | 905 | return status; 906 | } -------------------------------------------------------------------------------- /crostouchpad/rmi.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | static ULONG SynaDebugLevel = 100; 4 | static ULONG SynaDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 5 | 6 | static NTSTATUS rmi_set_mode(PSYNA_CONTEXT pDevice, uint8_t mode) { 7 | uint8_t command[] = { 0x00, 0x3f, 0x03, 0x0f, 0x23, 0x00, 0x04, 0x00, RMI_SET_RMI_MODE_REPORT_ID, mode }; //magic bytes from Linux 8 | return SpbWriteDataSynchronously(&pDevice->I2CContext, 0x22, command, sizeof(command)); 9 | } 10 | 11 | static NTSTATUS rmi_write_report(PSYNA_CONTEXT pDevice, uint8_t *report, size_t report_size) { 12 | uint8_t command[24]; 13 | command[0] = 0x00; 14 | command[1] = 0x17; 15 | command[2] = 0x00; 16 | //SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "RMI Write Report: "); 17 | for (int i = 0; i < report_size; i++) { 18 | //SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "0x%x ", report[i]); 19 | command[i + 3] = report[i]; 20 | } 21 | //SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "\n"); 22 | return SpbWriteDataSynchronously(&pDevice->I2CContext, 0x25, command, sizeof(command)); 23 | } 24 | 25 | static NTSTATUS rmi_set_page(PSYNA_CONTEXT pDevice, uint8_t page) 26 | { 27 | uint8_t writeReport[21]; 28 | NTSTATUS retval; 29 | 30 | writeReport[0] = RMI_WRITE_REPORT_ID; 31 | writeReport[1] = 1; 32 | writeReport[2] = 0xFF; 33 | writeReport[4] = page; 34 | 35 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Set Page\n"); 36 | 37 | retval = rmi_write_report(pDevice, writeReport, 38 | sizeof(writeReport)); 39 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Report Written\n"); 40 | 41 | pDevice->page = page; 42 | return retval; 43 | } 44 | 45 | static NTSTATUS rmi_read_block(PSYNA_CONTEXT pDevice, uint16_t addr, uint8_t *buf, 46 | const int len) 47 | { 48 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Read Block: 0x%x\n", addr); 49 | NTSTATUS status = 0; 50 | 51 | if (RMI_PAGE(addr) != pDevice->page) { 52 | status = rmi_set_page(pDevice, RMI_PAGE(addr)); 53 | if (!NT_SUCCESS(status)) 54 | goto exit; 55 | } 56 | 57 | uint8_t writeReport[21]; 58 | for (int i = 0; i < 21; i++) { 59 | writeReport[i] = 0; 60 | } 61 | writeReport[0] = RMI_READ_ADDR_REPORT_ID; 62 | writeReport[1] = 0; 63 | writeReport[2] = addr & 0xFF; 64 | writeReport[3] = (addr >> 8) & 0xFF; 65 | writeReport[4] = len & 0xFF; 66 | writeReport[5] = (len >> 8) & 0xFF; 67 | status = rmi_write_report(pDevice, writeReport, sizeof(writeReport)); 68 | if (!NT_SUCCESS(status)) 69 | goto exit; 70 | 71 | uint8_t i2cInput[42]; 72 | status = SpbOnlyReadDataSynchronously(&pDevice->I2CContext, &i2cInput, sizeof(i2cInput)); 73 | if (!NT_SUCCESS(status)) 74 | goto exit; 75 | 76 | uint8_t rmiInput[40]; 77 | for (int i = 0; i < 40; i++) { 78 | rmiInput[i] = i2cInput[i + 2]; 79 | } 80 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "RMI Input ID: 0x%x\n", rmiInput[0]); 81 | if (rmiInput[0] == RMI_READ_DATA_REPORT_ID) { 82 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "RMI Read: "); 83 | for (int i = 0; i < len; i++) { 84 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "0x%x ", rmiInput[i + 2]); 85 | buf[i] = rmiInput[i + 2]; 86 | } 87 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "\n"); 88 | } 89 | exit: 90 | return status; 91 | } 92 | 93 | static NTSTATUS rmi_read(PSYNA_CONTEXT pDevice, uint16_t addr, uint8_t *buf) { 94 | return rmi_read_block(pDevice, addr, buf, 1); 95 | } 96 | 97 | static NTSTATUS rmi_write_block(PSYNA_CONTEXT pDevice, uint16_t addr, uint8_t *buf, const uint8_t len) 98 | { 99 | NTSTATUS status = STATUS_SUCCESS; 100 | 101 | uint8_t writeReport[21]; 102 | for (int i = 0; i < 21; i++) { 103 | writeReport[i] = 0; 104 | } 105 | 106 | if (RMI_PAGE(addr) != pDevice->page) { 107 | status = rmi_set_page(pDevice, RMI_PAGE(addr)); 108 | if (!NT_SUCCESS(status)) 109 | goto exit; 110 | } 111 | 112 | writeReport[0] = RMI_WRITE_REPORT_ID; 113 | writeReport[1] = len; 114 | writeReport[2] = addr & 0xFF; 115 | writeReport[3] = (addr >> 8) & 0xFF; 116 | for (int i = 0; i < len; i++) { 117 | writeReport[i + 4] = buf[i]; 118 | } 119 | 120 | status = rmi_write_report(pDevice, writeReport, sizeof(writeReport)); 121 | if (!NT_SUCCESS(status)) { 122 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "failed to write request output report (%d)\n", 123 | status); 124 | goto exit; 125 | } 126 | 127 | exit: 128 | return status; 129 | } 130 | 131 | static NTSTATUS rmi_write(PSYNA_CONTEXT pDevice, uint16_t addr, uint8_t *buf) 132 | { 133 | return rmi_write_block(pDevice, addr, buf, 1); 134 | } 135 | 136 | static unsigned long rmi_gen_mask(unsigned irq_base, unsigned irq_count) 137 | { 138 | return GENMASK(irq_count + irq_base - 1, irq_base); 139 | } 140 | 141 | static void rmi_register_function(PSYNA_CONTEXT pDevice, struct pdt_entry *pdt_entry, uint16_t page, unsigned interrupt_count) 142 | { 143 | struct rmi_function *f = NULL; 144 | uint16_t page_base = page << 8; 145 | 146 | switch (pdt_entry->function_number) { 147 | case 0x01: 148 | f = &pDevice->f01; 149 | break; 150 | case 0x11: 151 | f = &pDevice->f11; 152 | break; 153 | case 0x30: 154 | f = &pDevice->f30; 155 | break; 156 | } 157 | 158 | if (f) { 159 | f->page = page; 160 | f->query_base_addr = page_base | pdt_entry->query_base_addr; 161 | f->command_base_addr = page_base | pdt_entry->command_base_addr; 162 | f->control_base_addr = page_base | pdt_entry->control_base_addr; 163 | f->data_base_addr = page_base | pdt_entry->data_base_addr; 164 | f->interrupt_base = interrupt_count; 165 | f->interrupt_count = pdt_entry->interrupt_source_count; 166 | f->irq_mask = rmi_gen_mask(f->interrupt_base, 167 | f->interrupt_count); 168 | pDevice->interrupt_enable_mask |= f->irq_mask; 169 | } 170 | } 171 | 172 | int rmi_scan_pdt(PSYNA_CONTEXT pDevice) 173 | { 174 | struct pdt_entry entry; 175 | uint16_t page; 176 | bool page_has_function; 177 | uint16_t i; 178 | int retval; 179 | int interrupt = 0; 180 | uint16_t page_start, pdt_start, pdt_end; 181 | 182 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Scanning PDT...\n"); 183 | 184 | for (page = 0; (page <= RMI4_MAX_PAGE); page++) { 185 | page_start = RMI4_PAGE_SIZE * page; 186 | pdt_start = page_start + PDT_START_SCAN_LOCATION; 187 | pdt_end = page_start + PDT_END_SCAN_LOCATION; 188 | 189 | page_has_function = false; 190 | for (i = pdt_start; i >= pdt_end; i -= sizeof(entry)) { 191 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Read PDT Entry...\n"); 192 | retval = rmi_read_block(pDevice, i, (uint8_t *)&entry, sizeof(entry)); 193 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Read PDT Entry done\n"); 194 | if (retval) { 195 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Read of PDT entry at %#06x failed.\n", 196 | i); 197 | goto error_exit; 198 | } 199 | 200 | if (RMI4_END_OF_PDT(entry.function_number)) 201 | break; 202 | 203 | page_has_function = true; 204 | 205 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Found F%02X on page %#04x\n", 206 | entry.function_number, page); 207 | 208 | rmi_register_function(pDevice, &entry, page, interrupt); 209 | interrupt += entry.interrupt_source_count; 210 | } 211 | 212 | if (!page_has_function) 213 | break; 214 | } 215 | 216 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Done with PDT scan.\n"); 217 | retval = 0; 218 | 219 | error_exit: 220 | return retval; 221 | } 222 | 223 | static NTSTATUS rmi_populate_f01(PSYNA_CONTEXT pDevice) 224 | { 225 | uint8_t basic_queries[RMI_DEVICE_F01_BASIC_QUERY_LEN]; 226 | uint8_t info[3]; 227 | NTSTATUS status; 228 | bool has_query42; 229 | bool has_lts; 230 | bool has_sensor_id; 231 | bool has_ds4_queries = false; 232 | bool has_build_id_query = false; 233 | bool has_package_id_query = false; 234 | uint16_t query_offset = pDevice->f01.query_base_addr; 235 | uint16_t prod_info_addr; 236 | uint8_t ds4_query_len; 237 | 238 | status = rmi_read_block(pDevice, query_offset, basic_queries, 239 | RMI_DEVICE_F01_BASIC_QUERY_LEN); 240 | if (!NT_SUCCESS(status)) { 241 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Can not read basic queries from Function 0x1.\n"); 242 | return status; 243 | } 244 | 245 | has_lts = !!(basic_queries[0] & BIT(2)); 246 | has_sensor_id = !!(basic_queries[1] & BIT(3)); 247 | has_query42 = !!(basic_queries[1] & BIT(7)); 248 | 249 | query_offset += 11; 250 | prod_info_addr = query_offset + 6; 251 | query_offset += 10; 252 | 253 | if (has_lts) 254 | query_offset += 20; 255 | 256 | if (has_sensor_id) 257 | query_offset++; 258 | 259 | if (has_query42) { 260 | status = rmi_read(pDevice, query_offset, info); 261 | if (!NT_SUCCESS(status)) { 262 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Can not read query42.\n"); 263 | return status; 264 | } 265 | has_ds4_queries = !!(info[0] & BIT(0)); 266 | query_offset++; 267 | } 268 | 269 | if (has_ds4_queries) { 270 | status = rmi_read(pDevice, query_offset, &ds4_query_len); 271 | if (!NT_SUCCESS(status)) { 272 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Can not read DS4 Query length.\n"); 273 | return status; 274 | } 275 | query_offset++; 276 | 277 | if (ds4_query_len > 0) { 278 | status = rmi_read(pDevice, query_offset, info); 279 | if (!NT_SUCCESS(status)) { 280 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Can not read DS4 query.\n"); 281 | return status; 282 | } 283 | 284 | has_package_id_query = !!(info[0] & BIT(0)); 285 | has_build_id_query = !!(info[0] & BIT(1)); 286 | } 287 | } 288 | 289 | if (has_package_id_query) 290 | prod_info_addr++; 291 | 292 | if (has_build_id_query) { 293 | status = rmi_read_block(pDevice, prod_info_addr, info, 3); 294 | if (!NT_SUCCESS(status)) { 295 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Can not read product info.\n"); 296 | return status; 297 | } 298 | 299 | pDevice->firmware_id = info[1] << 8 | info[0]; 300 | pDevice->firmware_id += info[2] * 65536; 301 | } 302 | 303 | status = rmi_read_block(pDevice, pDevice->f01.control_base_addr, info, 304 | 2); 305 | 306 | if (!NT_SUCCESS(status)) { 307 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not read f01 ctrl registers\n"); 308 | return status; 309 | } 310 | 311 | pDevice->f01_ctrl0 = info[0]; 312 | 313 | if (!info[1]) { 314 | /* 315 | * Do to a firmware bug in some touchpads the F01 interrupt 316 | * enable control register will be cleared on reset. 317 | * This will stop the touchpad from reporting data, so 318 | * if F01 CTRL1 is 0 then we need to explicitly enable 319 | * interrupts for the functions we want data for. 320 | */ 321 | pDevice->restore_interrupt_mask = true; 322 | 323 | status = rmi_write(pDevice, pDevice->f01.control_base_addr + 1, 324 | &pDevice->interrupt_enable_mask); 325 | if (!NT_SUCCESS(status)) { 326 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not write to control reg 1: %d.\n", status); 327 | return status; 328 | } 329 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Firmware bug fix needed!!! :/\n"); 330 | } 331 | 332 | return status; 333 | } 334 | 335 | static NTSTATUS rmi_populate_f11(PSYNA_CONTEXT pDevice) 336 | { 337 | uint8_t buf[20]; 338 | NTSTATUS status; 339 | bool has_query9; 340 | bool has_query10 = false; 341 | bool has_query11; 342 | bool has_query12; 343 | bool has_query27; 344 | bool has_query28; 345 | bool has_query36 = false; 346 | bool has_physical_props; 347 | bool has_gestures; 348 | bool has_rel; 349 | bool has_data40 = false; 350 | bool has_dribble = false; 351 | bool has_palm_detect = false; 352 | uint16_t x_size, y_size; 353 | uint16_t query_offset; 354 | 355 | if (!pDevice->f11.query_base_addr) { 356 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "No 2D sensor found, giving up.\n"); 357 | return STATUS_NO_SUCH_DEVICE; 358 | } 359 | 360 | /* query 0 contains some useful information */ 361 | status = rmi_read(pDevice, pDevice->f11.query_base_addr, buf); 362 | if (!NT_SUCCESS(status)) { 363 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get query 0: %d.\n", status); 364 | return status; 365 | } 366 | has_query9 = !!(buf[0] & BIT(3)); 367 | has_query11 = !!(buf[0] & BIT(4)); 368 | has_query12 = !!(buf[0] & BIT(5)); 369 | has_query27 = !!(buf[0] & BIT(6)); 370 | has_query28 = !!(buf[0] & BIT(7)); 371 | 372 | /* query 1 to get the max number of fingers */ 373 | status = rmi_read(pDevice, pDevice->f11.query_base_addr + 1, buf); 374 | if (!NT_SUCCESS(status)) { 375 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get NumberOfFingers: %d.\n", status); 376 | return status; 377 | } 378 | pDevice->max_fingers = (buf[0] & 0x07) + 1; 379 | if (pDevice->max_fingers > 5) 380 | pDevice->max_fingers = 10; 381 | 382 | pDevice->f11.report_size = pDevice->max_fingers * 5 + 383 | DIV_ROUND_UP(pDevice->max_fingers, 4); 384 | 385 | if (!(buf[0] & BIT(4))) { 386 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "No absolute events, giving up.\n"); 387 | return STATUS_INVALID_DEVICE_REQUEST; 388 | } 389 | 390 | has_rel = !!(buf[0] & BIT(3)); 391 | has_gestures = !!(buf[0] & BIT(5)); 392 | 393 | status = rmi_read(pDevice, pDevice->f11.query_base_addr + 5, buf); 394 | if (!NT_SUCCESS(status)) { 395 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get absolute data sources: %d.\n", status); 396 | return status; 397 | } 398 | 399 | has_dribble = !!(buf[0] & BIT(4)); 400 | 401 | /* 402 | * At least 4 queries are guaranteed to be present in F11 403 | * +1 for query 5 which is present since absolute events are 404 | * reported and +1 for query 12. 405 | */ 406 | query_offset = 6; 407 | 408 | if (has_rel) 409 | ++query_offset; /* query 6 is present */ 410 | 411 | if (has_gestures) { 412 | /* query 8 to find out if query 10 exists */ 413 | status = rmi_read(pDevice, pDevice->f11.query_base_addr + query_offset + 1, buf); 414 | if (!NT_SUCCESS(status)) { 415 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not read gesture information: %d.\n", 416 | status); 417 | return status; 418 | } 419 | has_palm_detect = !!(buf[0] & BIT(0)); 420 | has_query10 = !!(buf[0] & BIT(2)); 421 | 422 | query_offset += 2; /* query 7 and 8 are present */ 423 | } 424 | 425 | if (has_query9) 426 | ++query_offset; 427 | 428 | if (has_query10) 429 | ++query_offset; 430 | 431 | if (has_query11) 432 | ++query_offset; 433 | 434 | /* query 12 to know if the physical properties are reported */ 435 | if (has_query12) { 436 | status = rmi_read(pDevice, pDevice->f11.query_base_addr 437 | + query_offset, buf); 438 | if (!NT_SUCCESS(status)) { 439 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get query 12: %d.\n", status); 440 | return status; 441 | } 442 | has_physical_props = !!(buf[0] & BIT(5)); 443 | 444 | if (has_physical_props) { 445 | query_offset += 1; 446 | status = rmi_read_block(pDevice, pDevice->f11.query_base_addr 447 | + query_offset, buf, 4); 448 | if (status) { 449 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not read query 15-18: %d.\n", 450 | status); 451 | return status; 452 | } 453 | 454 | x_size = buf[0] | (buf[1] << 8); 455 | y_size = buf[2] | (buf[3] << 8); 456 | 457 | pDevice->x_size_mm = x_size / 10; 458 | pDevice->y_size_mm = y_size / 10; 459 | 460 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "size in mm: %d x %d\n", 461 | pDevice->x_size_mm, pDevice->y_size_mm); 462 | 463 | /* 464 | * query 15 - 18 contain the size of the sensor 465 | * and query 19 - 26 contain bezel dimensions 466 | */ 467 | query_offset += 12; 468 | } 469 | } 470 | 471 | if (has_query27) 472 | ++query_offset; 473 | 474 | if (has_query28) { 475 | status = rmi_read(pDevice, pDevice->f11.query_base_addr 476 | + query_offset, buf); 477 | if (!NT_SUCCESS(status)) { 478 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get query 28: %d.\n", status); 479 | return status; 480 | } 481 | 482 | has_query36 = !!(buf[0] & BIT(6)); 483 | } 484 | 485 | if (has_query36) { 486 | query_offset += 2; 487 | status = rmi_read(pDevice, pDevice->f11.query_base_addr 488 | + query_offset, buf); 489 | if (!NT_SUCCESS(status)) { 490 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get query 36: %d.\n", status); 491 | return status; 492 | } 493 | 494 | has_data40 = !!(buf[0] & BIT(5)); 495 | } 496 | 497 | 498 | if (has_data40) 499 | pDevice->f11.report_size += pDevice->max_fingers * 2; 500 | 501 | status = rmi_read_block(pDevice, pDevice->f11.control_base_addr, 502 | pDevice->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); 503 | if (!NT_SUCCESS(status)) { 504 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not read ctrl block of size 11: %d.\n", status); 505 | return status; 506 | } 507 | 508 | /* data->f11_ctrl_regs now contains valid register data */ 509 | pDevice->read_f11_ctrl_regs = true; 510 | 511 | pDevice->max_x = pDevice->f11_ctrl_regs[6] | (pDevice->f11_ctrl_regs[7] << 8); 512 | pDevice->max_y = pDevice->f11_ctrl_regs[8] | (pDevice->f11_ctrl_regs[9] << 8); 513 | 514 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Trackpad Resolution: %d x %d\n", pDevice->max_x, pDevice->max_y); 515 | 516 | if (has_dribble) { 517 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Has Dribble\n"); 518 | pDevice->f11_ctrl_regs[0] = pDevice->f11_ctrl_regs[0] & ~BIT(6); 519 | status = rmi_write(pDevice, pDevice->f11.control_base_addr, 520 | pDevice->f11_ctrl_regs); 521 | if (!NT_SUCCESS(status)) { 522 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not write to control reg 0: %d.\n", 523 | status); 524 | return status; 525 | } 526 | } 527 | 528 | if (has_palm_detect) { 529 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Has Palm Detect\n"); 530 | pDevice->f11_ctrl_regs[11] = pDevice->f11_ctrl_regs[11] & ~BIT(0); 531 | status = rmi_write(pDevice, pDevice->f11.control_base_addr + 11, 532 | &pDevice->f11_ctrl_regs[11]); 533 | if (!NT_SUCCESS(status)) { 534 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not write to control reg 11: %d.\n", 535 | status); 536 | return status; 537 | } 538 | } 539 | 540 | return status; 541 | } 542 | 543 | /* Defs for Query 0 */ 544 | #define RMI_F30_EXTENDED_PATTERNS 0x01 545 | #define RMI_F30_HAS_MAPPABLE_BUTTONS BIT(1) 546 | #define RMI_F30_HAS_LED BIT(2) 547 | #define RMI_F30_HAS_GPIO BIT(3) 548 | #define RMI_F30_HAS_HAPTIC BIT(4) 549 | #define RMI_F30_HAS_GPIO_DRV_CTL BIT(5) 550 | #define RMI_F30_HAS_MECH_MOUSE_BTNS BIT(6) 551 | 552 | /* Defs for Query 1 */ 553 | #define RMI_F30_GPIO_LED_COUNT 0x1F 554 | 555 | /* Defs for Control Registers */ 556 | #define RMI_F30_CTRL_1_GPIO_DEBOUNCE 0x01 557 | #define RMI_F30_CTRL_1_HALT BIT(4) 558 | #define RMI_F30_CTRL_1_HALTED BIT(5) 559 | #define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS 0x03 560 | 561 | #define RMI_F30_CTRL_MAX_REGS 32 562 | #define RMI_F30_CTRL_MAX_BYTES DIV_ROUND_UP(RMI_F30_CTRL_MAX_REGS, 8) 563 | #define RMI_F30_CTRL_MAX_REG_BLOCKS 11 564 | 565 | #define TRACKSTICK_RANGE_START 3 566 | #define TRACKSTICK_RANGE_END 6 567 | 568 | static NTSTATUS rmi_populate_f30(PSYNA_CONTEXT pDevice) 569 | { 570 | uint8_t buf[20]; 571 | NTSTATUS status; 572 | bool has_gpio, has_led; 573 | uint8_t bytes_per_ctrl; 574 | uint8_t ctrl2_addr; 575 | int ctrl2_3_length; 576 | uint32_t i; 577 | 578 | /* function F30 is for physical buttons */ 579 | if (!pDevice->f30.query_base_addr) { 580 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "No GPIO/LEDs found, giving up.\n"); 581 | return STATUS_NO_SUCH_DEVICE; 582 | } 583 | 584 | status = rmi_read_block(pDevice, pDevice->f30.query_base_addr, buf, 2); 585 | if (!NT_SUCCESS(status)) { 586 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not get F30 query registers: %d.\n", status); 587 | return status; 588 | } 589 | 590 | has_gpio = buf[0] & RMI_F30_HAS_GPIO; 591 | has_led = buf[0] & RMI_F30_HAS_LED; 592 | pDevice->gpio_led_count = buf[1] & RMI_F30_GPIO_LED_COUNT; 593 | 594 | /* retrieve ctrl 2 & 3 registers */ 595 | bytes_per_ctrl = (UINT8)DIV_ROUND_UP(pDevice->gpio_led_count, 8); 596 | /* Ctrl0 is present only if both has_gpio and has_led are set*/ 597 | ctrl2_addr = (has_gpio && has_led) ? bytes_per_ctrl : 0; 598 | /* Ctrl1 is always be present, but is only length 1 for some reason? */ 599 | ctrl2_addr += sizeof(UINT8); 600 | ctrl2_3_length = 2 * bytes_per_ctrl; 601 | 602 | pDevice->f30.report_size = bytes_per_ctrl; 603 | 604 | RtlZeroMemory(buf, sizeof(buf)); 605 | status = rmi_read_block(pDevice, pDevice->f30.control_base_addr + ctrl2_addr, 606 | buf, ctrl2_3_length); 607 | if (!NT_SUCCESS(status)) { 608 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "can not read ctrl 2&3 block of size %d: %d.\n", 609 | ctrl2_3_length, status); 610 | return status; 611 | } 612 | 613 | pDevice->button_count = 0; 614 | pDevice->button_mask = 0; 615 | pDevice->button_state_mask = 0; 616 | 617 | for (i = 0; i < min(pDevice->gpio_led_count, TRACKSTICK_RANGE_END); i++) { 618 | int byte_position = i >> 3; 619 | int bit_position = i & 0x07; 620 | uint8_t dir_byte = buf[byte_position]; 621 | uint8_t data_byte = buf[byte_position + bytes_per_ctrl]; 622 | bool dir = (dir_byte >> bit_position) & BIT(0); 623 | bool dat = (data_byte >> bit_position) & BIT(0); 624 | 625 | if (dir == 0) { 626 | /* input mode */ 627 | if (dat) { 628 | /* actual buttons have pull up resistor */ 629 | pDevice->button_count++; 630 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Button found at Bit %d\n", i); 631 | 632 | pDevice->button_mask |= BIT(i); 633 | pDevice->button_state_mask |= BIT(i); 634 | } 635 | } 636 | 637 | } 638 | 639 | return status; 640 | } 641 | 642 | NTSTATUS rmi_populate(PSYNA_CONTEXT pDevice) { 643 | NTSTATUS status; 644 | 645 | status = rmi_set_mode(pDevice, 0); 646 | if (!NT_SUCCESS(status)) { 647 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "PDT set mode failed with code %d\n", status); 648 | return status; 649 | } 650 | 651 | status = rmi_scan_pdt(pDevice); 652 | if (!NT_SUCCESS(status)) { 653 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "PDT scan failed with code %d\n", status); 654 | return status; 655 | } 656 | 657 | status = rmi_populate_f01(pDevice); 658 | if (!NT_SUCCESS(status)) { 659 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Error while initializing F01 (%d)\n", status); 660 | return status; 661 | } 662 | 663 | status = rmi_populate_f11(pDevice); 664 | if (!NT_SUCCESS(status)) { 665 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Error while initializing F11 (%d)\n", status); 666 | return status; 667 | } 668 | 669 | status = rmi_populate_f30(pDevice); 670 | if (!NT_SUCCESS(status)) { 671 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, "Error while initializing F30 (%d)\n", status); 672 | return status; 673 | } 674 | return status; 675 | } 676 | 677 | NTSTATUS rmi_set_sleep_mode(PSYNA_CONTEXT pDevice, uint8_t sleep) { 678 | uint8_t f01ctrl0 = (pDevice->f01_ctrl0 & ~0x3) | sleep; 679 | 680 | return rmi_write(pDevice, pDevice->f01.control_base_addr, &f01ctrl0); 681 | } 682 | -------------------------------------------------------------------------------- /crostouchpad/synaptics.c: -------------------------------------------------------------------------------- 1 | #define DESCRIPTOR_DEF 2 | #include "driver.h" 3 | 4 | NTSTATUS rmi_populate(PSYNA_CONTEXT pDevice); 5 | NTSTATUS rmi_set_sleep_mode(PSYNA_CONTEXT pDevice, int sleep); 6 | 7 | static ULONG SynaDebugLevel = 100; 8 | static ULONG SynaDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 9 | 10 | static bool deviceLoaded = false; 11 | 12 | NTSTATUS 13 | DriverEntry( 14 | __in PDRIVER_OBJECT DriverObject, 15 | __in PUNICODE_STRING RegistryPath 16 | ) 17 | { 18 | NTSTATUS status = STATUS_SUCCESS; 19 | WDF_DRIVER_CONFIG config; 20 | WDF_OBJECT_ATTRIBUTES attributes; 21 | 22 | SynaPrint(DEBUG_LEVEL_INFO, DBG_INIT, 23 | "Driver Entry\n"); 24 | 25 | WDF_DRIVER_CONFIG_INIT(&config, SynaEvtDeviceAdd); 26 | 27 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 28 | 29 | // 30 | // Create a framework driver object to represent our driver. 31 | // 32 | 33 | status = WdfDriverCreate(DriverObject, 34 | RegistryPath, 35 | &attributes, 36 | &config, 37 | WDF_NO_HANDLE 38 | ); 39 | 40 | if (!NT_SUCCESS(status)) 41 | { 42 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 43 | "WdfDriverCreate failed with status 0x%x\n", status); 44 | } 45 | 46 | return status; 47 | } 48 | 49 | NTSTATUS BOOTTRACKPAD( 50 | _In_ PSYNA_CONTEXT pDevice 51 | ) 52 | { 53 | NTSTATUS status = 0; 54 | 55 | status = rmi_populate(pDevice); 56 | if (!NT_SUCCESS(status)) { 57 | return status; 58 | } 59 | 60 | //pDevice->max_x set by rmi_populate 61 | //pDevice->max_y set by rmi_populate 62 | 63 | pDevice->phy_x = pDevice->x_size_mm * 10; 64 | pDevice->phy_y = pDevice->y_size_mm * 10; 65 | 66 | uint16_t max_x[] = { pDevice->max_x }; 67 | uint16_t max_y[] = { pDevice->max_y }; 68 | 69 | uint8_t *max_x8bit = (uint8_t *)max_x; 70 | uint8_t *max_y8bit = (uint8_t *)max_y; 71 | 72 | pDevice->max_x_hid[0] = max_x8bit[0]; 73 | pDevice->max_x_hid[1] = max_x8bit[1]; 74 | 75 | pDevice->max_y_hid[0] = max_y8bit[0]; 76 | pDevice->max_y_hid[1] = max_y8bit[1]; 77 | 78 | uint16_t phy_x[] = { pDevice->phy_x }; 79 | uint16_t phy_y[] = { pDevice->phy_y }; 80 | 81 | uint8_t *phy_x8bit = (uint8_t *)phy_x; 82 | uint8_t *phy_y8bit = (uint8_t *)phy_y; 83 | 84 | pDevice->phy_x_hid[0] = phy_x8bit[0]; 85 | pDevice->phy_x_hid[1] = phy_x8bit[1]; 86 | 87 | pDevice->phy_y_hid[0] = phy_y8bit[0]; 88 | pDevice->phy_y_hid[1] = phy_y8bit[1]; 89 | 90 | pDevice->ConnectInterrupt = true; 91 | 92 | return status; 93 | } 94 | 95 | NTSTATUS 96 | OnPrepareHardware( 97 | _In_ WDFDEVICE FxDevice, 98 | _In_ WDFCMRESLIST FxResourcesRaw, 99 | _In_ WDFCMRESLIST FxResourcesTranslated 100 | ) 101 | /*++ 102 | 103 | Routine Description: 104 | 105 | This routine caches the SPB resource connection ID. 106 | 107 | Arguments: 108 | 109 | FxDevice - a handle to the framework device object 110 | FxResourcesRaw - list of translated hardware resources that 111 | the PnP manager has assigned to the device 112 | FxResourcesTranslated - list of raw hardware resources that 113 | the PnP manager has assigned to the device 114 | 115 | Return Value: 116 | 117 | Status 118 | 119 | --*/ 120 | { 121 | PSYNA_CONTEXT pDevice = GetDeviceContext(FxDevice); 122 | BOOLEAN fSpbResourceFound = FALSE; 123 | NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; 124 | 125 | UNREFERENCED_PARAMETER(FxResourcesRaw); 126 | 127 | // 128 | // Parse the peripheral's resources. 129 | // 130 | 131 | ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); 132 | 133 | for (ULONG i = 0; i < resourceCount; i++) 134 | { 135 | PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 136 | UCHAR Class; 137 | UCHAR Type; 138 | 139 | pDescriptor = WdfCmResourceListGetDescriptor( 140 | FxResourcesTranslated, i); 141 | 142 | switch (pDescriptor->Type) 143 | { 144 | case CmResourceTypeConnection: 145 | // 146 | // Look for I2C or SPI resource and save connection ID. 147 | // 148 | Class = pDescriptor->u.Connection.Class; 149 | Type = pDescriptor->u.Connection.Type; 150 | if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && 151 | Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) 152 | { 153 | if (fSpbResourceFound == FALSE) 154 | { 155 | status = STATUS_SUCCESS; 156 | pDevice->I2CContext.I2cResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; 157 | pDevice->I2CContext.I2cResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; 158 | fSpbResourceFound = TRUE; 159 | } 160 | else 161 | { 162 | } 163 | } 164 | break; 165 | default: 166 | // 167 | // Ignoring all other resource types. 168 | // 169 | break; 170 | } 171 | } 172 | 173 | // 174 | // An SPB resource is required. 175 | // 176 | 177 | if (fSpbResourceFound == FALSE) 178 | { 179 | status = STATUS_NOT_FOUND; 180 | } 181 | 182 | status = SpbTargetInitialize(FxDevice, &pDevice->I2CContext); 183 | if (!NT_SUCCESS(status)) 184 | { 185 | return status; 186 | } 187 | 188 | return status; 189 | } 190 | 191 | NTSTATUS 192 | OnReleaseHardware( 193 | _In_ WDFDEVICE FxDevice, 194 | _In_ WDFCMRESLIST FxResourcesTranslated 195 | ) 196 | /*++ 197 | 198 | Routine Description: 199 | 200 | Arguments: 201 | 202 | FxDevice - a handle to the framework device object 203 | FxResourcesTranslated - list of raw hardware resources that 204 | the PnP manager has assigned to the device 205 | 206 | Return Value: 207 | 208 | Status 209 | 210 | --*/ 211 | { 212 | PSYNA_CONTEXT pDevice = GetDeviceContext(FxDevice); 213 | NTSTATUS status = STATUS_SUCCESS; 214 | 215 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 216 | 217 | SpbTargetDeinitialize(FxDevice, &pDevice->I2CContext); 218 | 219 | return status; 220 | } 221 | 222 | NTSTATUS 223 | OnD0Entry( 224 | _In_ WDFDEVICE FxDevice, 225 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 226 | ) 227 | /*++ 228 | 229 | Routine Description: 230 | 231 | This routine allocates objects needed by the driver. 232 | 233 | Arguments: 234 | 235 | FxDevice - a handle to the framework device object 236 | FxPreviousState - previous power state 237 | 238 | Return Value: 239 | 240 | Status 241 | 242 | --*/ 243 | { 244 | UNREFERENCED_PARAMETER(FxPreviousState); 245 | 246 | PSYNA_CONTEXT pDevice = GetDeviceContext(FxDevice); 247 | NTSTATUS status = STATUS_SUCCESS; 248 | 249 | for (int i = 0; i < 5; i++){ 250 | pDevice->Flags[i] = 0; 251 | } 252 | 253 | status = BOOTTRACKPAD(pDevice); 254 | if (!NT_SUCCESS(status)) 255 | { 256 | return status; 257 | } 258 | 259 | status = rmi_set_sleep_mode(pDevice, RMI_SLEEP_NORMAL); 260 | if (!NT_SUCCESS(status)) { 261 | return status; 262 | } 263 | 264 | pDevice->ConnectInterrupt = true; 265 | pDevice->RegsSet = false; 266 | 267 | return status; 268 | } 269 | 270 | NTSTATUS 271 | OnD0Exit( 272 | _In_ WDFDEVICE FxDevice, 273 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 274 | ) 275 | /*++ 276 | 277 | Routine Description: 278 | 279 | This routine destroys objects needed by the driver. 280 | 281 | Arguments: 282 | 283 | FxDevice - a handle to the framework device object 284 | FxPreviousState - previous power state 285 | 286 | Return Value: 287 | 288 | Status 289 | 290 | --*/ 291 | { 292 | UNREFERENCED_PARAMETER(FxPreviousState); 293 | 294 | PSYNA_CONTEXT pDevice = GetDeviceContext(FxDevice); 295 | 296 | NTSTATUS status = rmi_set_sleep_mode(pDevice, RMI_SLEEP_DEEP_SLEEP); 297 | 298 | pDevice->ConnectInterrupt = false; 299 | 300 | return status; 301 | } 302 | 303 | static void rmi_f11_process_touch(PSYNA_CONTEXT pDevice, struct touch_softc *sc, int slot, 304 | uint8_t finger_state, uint8_t *touch_data) 305 | { 306 | int x, y, wx, wy; 307 | int wide, major, minor; 308 | int z; 309 | 310 | if (finger_state == 0x01) { 311 | x = (touch_data[0] << 4) | (touch_data[2] & 0x0F); 312 | y = (touch_data[1] << 4) | (touch_data[2] >> 4); 313 | wx = touch_data[3] & 0x0F; 314 | wy = touch_data[3] >> 4; 315 | wide = (wx > wy); 316 | major = max(wx, wy); 317 | minor = min(wx, wy); 318 | z = touch_data[4]; 319 | 320 | if (minor > 10) { 321 | sc->palm[slot] = 1; 322 | } 323 | 324 | y = pDevice->max_y - y; 325 | 326 | sc->x[slot] = x; 327 | sc->y[slot] = y; 328 | sc->p[slot] = z; 329 | } 330 | } 331 | 332 | int rmi_f11_input(PSYNA_CONTEXT pDevice, struct touch_softc *sc, uint8_t *rmiInput) { 333 | //begin rmi parse 334 | int offset; 335 | int i; 336 | 337 | int max_fingers = pDevice->max_fingers; 338 | 339 | offset = (max_fingers >> 2) + 1; 340 | for (i = 0; i < max_fingers; i++) { 341 | int fs_byte_position = i >> 2; 342 | int fs_bit_position = (i & 0x3) << 1; 343 | uint8_t finger_state = (rmiInput[fs_byte_position] >> fs_bit_position) & 344 | 0x03; 345 | int position = offset + 5 * i; 346 | rmi_f11_process_touch(pDevice, sc, i, finger_state, &rmiInput[position]); 347 | } 348 | return pDevice->f11.report_size; 349 | } 350 | 351 | static int rmi_f30_input(PSYNA_CONTEXT pDevice, uint8_t irq, uint8_t *rmiInput, int size) 352 | { 353 | uint32_t i; 354 | bool value; 355 | 356 | if (!(irq & pDevice->f30.irq_mask)) 357 | return 0; 358 | 359 | if (size < (int)pDevice->f30.report_size) { 360 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Click Button pressed, but the click data is missing\n"); 361 | return 0; 362 | } 363 | 364 | for (i = 0; i < pDevice->gpio_led_count; i++) { 365 | if (pDevice->button_mask & BIT(i)) { 366 | value = (rmiInput[i / 8] >> (i & 0x07)) & BIT(0); 367 | if (pDevice->button_state_mask & BIT(i)) 368 | value = !value; 369 | pDevice->BUTTONPRESSED = value; 370 | } 371 | } 372 | return pDevice->f30.report_size; 373 | } 374 | 375 | BOOLEAN OnInterruptIsr( 376 | WDFINTERRUPT Interrupt, 377 | ULONG MessageID){ 378 | UNREFERENCED_PARAMETER(MessageID); 379 | 380 | WDFDEVICE Device = WdfInterruptGetDevice(Interrupt); 381 | PSYNA_CONTEXT pDevice = GetDeviceContext(Device); 382 | 383 | if (!pDevice->ConnectInterrupt) 384 | return false; 385 | 386 | LARGE_INTEGER CurrentTime; 387 | 388 | KeQuerySystemTime(&CurrentTime); 389 | 390 | LARGE_INTEGER DIFF; 391 | 392 | DIFF.QuadPart = 0; 393 | 394 | if (pDevice->LastTime.QuadPart != 0) 395 | DIFF.QuadPart = (CurrentTime.QuadPart - pDevice->LastTime.QuadPart) / 1000; 396 | 397 | uint8_t i2cInput[42]; 398 | NTSTATUS status = SpbOnlyReadDataSynchronously(&pDevice->I2CContext, &i2cInput, sizeof(i2cInput)); 399 | if (!NT_SUCCESS(status)) { 400 | return false; 401 | } 402 | 403 | uint8_t rmiInput[40]; 404 | for (int i = 0; i < 40; i++) { 405 | rmiInput[i] = i2cInput[i + 2]; 406 | } 407 | 408 | if (rmiInput[0] == 0x00) 409 | return false; 410 | 411 | if (rmiInput[0] != RMI_ATTN_REPORT_ID) { 412 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Unknown Report ID: 0x%x\n", rmiInput[0]); 413 | return false; 414 | } 415 | 416 | struct _SYNA_MULTITOUCH_REPORT report; 417 | report.ReportID = REPORTID_MTOUCH; 418 | 419 | int x[5]; 420 | int y[5]; 421 | int p[5]; 422 | int palm[5]; 423 | for (int i = 0; i < 5; i++) { 424 | x[i] = -1; 425 | y[i] = -1; 426 | p[i] = -1; 427 | palm[i] = 0; 428 | } 429 | 430 | int index = 2; 431 | 432 | int reportSize = 40; 433 | 434 | struct touch_softc softc; 435 | softc.x = x; 436 | softc.y = y; 437 | softc.p = p; 438 | softc.palm = palm; 439 | 440 | if (pDevice->f11.interrupt_base < pDevice->f30.interrupt_base) { 441 | index += rmi_f11_input(pDevice, &softc, &rmiInput[index]); 442 | index += rmi_f30_input(pDevice, rmiInput[1], &rmiInput[index], reportSize - index); 443 | } 444 | else { 445 | index += rmi_f30_input(pDevice, rmiInput[1], &rmiInput[index], reportSize - index); 446 | index += rmi_f11_input(pDevice, &softc, &rmiInput[index]); 447 | } 448 | 449 | for (int i = 0; i < 5; i++) { 450 | if (pDevice->Flags[i] == MXT_T9_DETECT && softc.x[i] == -1) { 451 | pDevice->Flags[i] = MXT_T9_RELEASE; 452 | } 453 | if (softc.x[i] != -1) { 454 | pDevice->Flags[i] = MXT_T9_DETECT; 455 | 456 | pDevice->XValue[i] = (USHORT)softc.x[i]; 457 | pDevice->YValue[i] = (USHORT)softc.y[i]; 458 | pDevice->PValue[i] = (USHORT)softc.p[i]; 459 | pDevice->Palm[i] = (USHORT)palm[i]; 460 | } 461 | } 462 | 463 | pDevice->TIMEINT += (USHORT)DIFF.QuadPart; 464 | 465 | pDevice->LastTime = CurrentTime; 466 | 467 | BYTE count = 0, i = 0; 468 | while (count < 5 && i < 5) { 469 | if (pDevice->Flags[i] != 0) { 470 | report.Touch[count].ContactID = i; 471 | 472 | report.Touch[count].XValue = pDevice->XValue[i]; 473 | report.Touch[count].YValue = pDevice->YValue[i]; 474 | report.Touch[count].Pressure = pDevice->PValue[i]; 475 | 476 | uint8_t flags = pDevice->Flags[i]; 477 | if (flags & MXT_T9_DETECT) { 478 | if (pDevice->Palm[i]) 479 | report.Touch[count].Status = MULTI_TIPSWITCH_BIT; 480 | else 481 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT | MULTI_TIPSWITCH_BIT; 482 | } 483 | else if (flags & MXT_T9_PRESS) { 484 | if (pDevice->Palm[i]) 485 | report.Touch[count].Status = MULTI_TIPSWITCH_BIT; 486 | else 487 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT | MULTI_TIPSWITCH_BIT; 488 | } 489 | else if (flags & MXT_T9_RELEASE) { 490 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT; 491 | pDevice->Flags[i] = 0; 492 | } 493 | else 494 | report.Touch[count].Status = 0; 495 | 496 | count++; 497 | } 498 | i++; 499 | } 500 | 501 | report.ScanTime = pDevice->TIMEINT; 502 | report.IsDepressed = pDevice->BUTTONPRESSED; 503 | 504 | report.ContactCount = count; 505 | 506 | size_t bytesWritten; 507 | SynaProcessVendorReport(pDevice, &report, sizeof(report), &bytesWritten); 508 | 509 | pDevice->RegsSet = true; 510 | return true; 511 | } 512 | 513 | NTSTATUS 514 | SynaEvtDeviceAdd( 515 | IN WDFDRIVER Driver, 516 | IN PWDFDEVICE_INIT DeviceInit 517 | ) 518 | { 519 | NTSTATUS status = STATUS_SUCCESS; 520 | WDF_IO_QUEUE_CONFIG queueConfig; 521 | WDF_OBJECT_ATTRIBUTES attributes; 522 | WDFDEVICE device; 523 | WDF_INTERRUPT_CONFIG interruptConfig; 524 | WDFQUEUE queue; 525 | PSYNA_CONTEXT devContext; 526 | 527 | UNREFERENCED_PARAMETER(Driver); 528 | 529 | PAGED_CODE(); 530 | 531 | SynaPrint(DEBUG_LEVEL_INFO, DBG_PNP, 532 | "SynaEvtDeviceAdd called\n"); 533 | 534 | // 535 | // Tell framework this is a filter driver. Filter drivers by default are 536 | // not power policy owners. This works well for this driver because 537 | // HIDclass driver is the power policy owner for HID minidrivers. 538 | // 539 | 540 | WdfFdoInitSetFilter(DeviceInit); 541 | 542 | { 543 | WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; 544 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); 545 | 546 | pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; 547 | pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; 548 | pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; 549 | pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; 550 | 551 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); 552 | } 553 | 554 | // 555 | // Setup the device context 556 | // 557 | 558 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, SYNA_CONTEXT); 559 | 560 | // 561 | // Create a framework device object.This call will in turn create 562 | // a WDM device object, attach to the lower stack, and set the 563 | // appropriate flags and attributes. 564 | // 565 | 566 | status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 567 | 568 | if (!NT_SUCCESS(status)) 569 | { 570 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 571 | "WdfDeviceCreate failed with status code 0x%x\n", status); 572 | 573 | return status; 574 | } 575 | 576 | { 577 | WDF_DEVICE_STATE deviceState; 578 | WDF_DEVICE_STATE_INIT(&deviceState); 579 | 580 | deviceState.NotDisableable = WdfFalse; 581 | WdfDeviceSetDeviceState(device, &deviceState); 582 | } 583 | 584 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); 585 | 586 | queueConfig.EvtIoInternalDeviceControl = SynaEvtInternalDeviceControl; 587 | 588 | status = WdfIoQueueCreate(device, 589 | &queueConfig, 590 | WDF_NO_OBJECT_ATTRIBUTES, 591 | &queue 592 | ); 593 | 594 | if (!NT_SUCCESS(status)) 595 | { 596 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 597 | "WdfIoQueueCreate failed 0x%x\n", status); 598 | 599 | return status; 600 | } 601 | 602 | // 603 | // Create manual I/O queue to take care of hid report read requests 604 | // 605 | 606 | devContext = GetDeviceContext(device); 607 | 608 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 609 | 610 | queueConfig.PowerManaged = WdfFalse; 611 | 612 | status = WdfIoQueueCreate(device, 613 | &queueConfig, 614 | WDF_NO_OBJECT_ATTRIBUTES, 615 | &devContext->ReportQueue 616 | ); 617 | 618 | if (!NT_SUCCESS(status)) 619 | { 620 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 621 | "WdfIoQueueCreate failed 0x%x\n", status); 622 | 623 | return status; 624 | } 625 | 626 | // 627 | // Create an interrupt object for hardware notifications 628 | // 629 | WDF_INTERRUPT_CONFIG_INIT( 630 | &interruptConfig, 631 | OnInterruptIsr, 632 | NULL); 633 | interruptConfig.PassiveHandling = TRUE; 634 | 635 | status = WdfInterruptCreate( 636 | device, 637 | &interruptConfig, 638 | WDF_NO_OBJECT_ATTRIBUTES, 639 | &devContext->Interrupt); 640 | 641 | if (!NT_SUCCESS(status)) 642 | { 643 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 644 | "Error creating WDF interrupt object - %!STATUS!", 645 | status); 646 | 647 | return status; 648 | } 649 | 650 | // 651 | // Initialize DeviceMode 652 | // 653 | 654 | devContext->DeviceMode = DEVICE_MODE_MOUSE; 655 | devContext->FxDevice = device; 656 | 657 | return status; 658 | } 659 | 660 | VOID 661 | SynaEvtInternalDeviceControl( 662 | IN WDFQUEUE Queue, 663 | IN WDFREQUEST Request, 664 | IN size_t OutputBufferLength, 665 | IN size_t InputBufferLength, 666 | IN ULONG IoControlCode 667 | ) 668 | { 669 | NTSTATUS status = STATUS_SUCCESS; 670 | WDFDEVICE device; 671 | PSYNA_CONTEXT devContext; 672 | BOOLEAN completeRequest = TRUE; 673 | 674 | UNREFERENCED_PARAMETER(OutputBufferLength); 675 | UNREFERENCED_PARAMETER(InputBufferLength); 676 | 677 | device = WdfIoQueueGetDevice(Queue); 678 | devContext = GetDeviceContext(device); 679 | 680 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 681 | "%s, Queue:0x%p, Request:0x%p\n", 682 | DbgHidInternalIoctlString(IoControlCode), 683 | Queue, 684 | Request 685 | ); 686 | 687 | // 688 | // Please note that HIDCLASS provides the buffer in the Irp->UserBuffer 689 | // field irrespective of the ioctl buffer type. However, framework is very 690 | // strict about type checking. You cannot get Irp->UserBuffer by using 691 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 692 | // internal ioctl. So depending on the ioctl code, we will either 693 | // use retreive function or escape to WDM to get the UserBuffer. 694 | // 695 | 696 | switch (IoControlCode) 697 | { 698 | 699 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 700 | // 701 | // Retrieves the device's HID descriptor. 702 | // 703 | status = SynaGetHidDescriptor(device, Request); 704 | break; 705 | 706 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 707 | // 708 | //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. 709 | // 710 | status = SynaGetDeviceAttributes(Request); 711 | break; 712 | 713 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 714 | // 715 | //Obtains the report descriptor for the HID device. 716 | // 717 | status = SynaGetReportDescriptor(device, Request); 718 | break; 719 | 720 | case IOCTL_HID_GET_STRING: 721 | // 722 | // Requests that the HID minidriver retrieve a human-readable string 723 | // for either the manufacturer ID, the product ID, or the serial number 724 | // from the string descriptor of the device. The minidriver must send 725 | // a Get String Descriptor request to the device, in order to retrieve 726 | // the string descriptor, then it must extract the string at the 727 | // appropriate index from the string descriptor and return it in the 728 | // output buffer indicated by the IRP. Before sending the Get String 729 | // Descriptor request, the minidriver must retrieve the appropriate 730 | // index for the manufacturer ID, the product ID or the serial number 731 | // from the device extension of a top level collection associated with 732 | // the device. 733 | // 734 | status = SynaGetString(Request); 735 | break; 736 | 737 | case IOCTL_HID_WRITE_REPORT: 738 | case IOCTL_HID_SET_OUTPUT_REPORT: 739 | // 740 | //Transmits a class driver-supplied report to the device. 741 | // 742 | status = SynaWriteReport(devContext, Request); 743 | break; 744 | 745 | case IOCTL_HID_READ_REPORT: 746 | case IOCTL_HID_GET_INPUT_REPORT: 747 | // 748 | // Returns a report from the device into a class driver-supplied buffer. 749 | // 750 | status = SynaReadReport(devContext, Request, &completeRequest); 751 | break; 752 | 753 | case IOCTL_HID_SET_FEATURE: 754 | // 755 | // This sends a HID class feature report to a top-level collection of 756 | // a HID class device. 757 | // 758 | status = SynaSetFeature(devContext, Request, &completeRequest); 759 | break; 760 | 761 | case IOCTL_HID_GET_FEATURE: 762 | // 763 | // returns a feature report associated with a top-level collection 764 | // 765 | status = SynaGetFeature(devContext, Request, &completeRequest); 766 | break; 767 | 768 | case IOCTL_HID_ACTIVATE_DEVICE: 769 | // 770 | // Makes the device ready for I/O operations. 771 | // 772 | case IOCTL_HID_DEACTIVATE_DEVICE: 773 | // 774 | // Causes the device to cease operations and terminate all outstanding 775 | // I/O requests. 776 | // 777 | default: 778 | status = STATUS_NOT_SUPPORTED; 779 | break; 780 | } 781 | 782 | if (completeRequest) 783 | { 784 | WdfRequestComplete(Request, status); 785 | 786 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 787 | "%s completed, Queue:0x%p, Request:0x%p\n", 788 | DbgHidInternalIoctlString(IoControlCode), 789 | Queue, 790 | Request 791 | ); 792 | } 793 | else 794 | { 795 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 796 | "%s deferred, Queue:0x%p, Request:0x%p\n", 797 | DbgHidInternalIoctlString(IoControlCode), 798 | Queue, 799 | Request 800 | ); 801 | } 802 | 803 | return; 804 | } 805 | 806 | NTSTATUS 807 | SynaGetHidDescriptor( 808 | IN WDFDEVICE Device, 809 | IN WDFREQUEST Request 810 | ) 811 | { 812 | NTSTATUS status = STATUS_SUCCESS; 813 | size_t bytesToCopy = 0; 814 | WDFMEMORY memory; 815 | 816 | UNREFERENCED_PARAMETER(Device); 817 | 818 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 819 | "SynaGetHidDescriptor Entry\n"); 820 | 821 | // 822 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 823 | // will correctly retrieve buffer from Irp->UserBuffer. 824 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 825 | // field irrespective of the ioctl buffer type. However, framework is very 826 | // strict about type checking. You cannot get Irp->UserBuffer by using 827 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 828 | // internal ioctl. 829 | // 830 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 831 | 832 | if (!NT_SUCCESS(status)) 833 | { 834 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 835 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 836 | 837 | return status; 838 | } 839 | 840 | // 841 | // Use hardcoded "HID Descriptor" 842 | // 843 | bytesToCopy = DefaultHidDescriptor.bLength; 844 | 845 | if (bytesToCopy == 0) 846 | { 847 | status = STATUS_INVALID_DEVICE_STATE; 848 | 849 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 850 | "DefaultHidDescriptor is zero, 0x%x\n", status); 851 | 852 | return status; 853 | } 854 | 855 | status = WdfMemoryCopyFromBuffer(memory, 856 | 0, // Offset 857 | (PVOID)&DefaultHidDescriptor, 858 | bytesToCopy); 859 | 860 | if (!NT_SUCCESS(status)) 861 | { 862 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 863 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 864 | 865 | return status; 866 | } 867 | 868 | // 869 | // Report how many bytes were copied 870 | // 871 | WdfRequestSetInformation(Request, bytesToCopy); 872 | 873 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 874 | "SynaGetHidDescriptor Exit = 0x%x\n", status); 875 | 876 | return status; 877 | } 878 | 879 | NTSTATUS 880 | SynaGetReportDescriptor( 881 | IN WDFDEVICE Device, 882 | IN WDFREQUEST Request 883 | ) 884 | { 885 | NTSTATUS status = STATUS_SUCCESS; 886 | ULONG_PTR bytesToCopy; 887 | WDFMEMORY memory; 888 | 889 | UNREFERENCED_PARAMETER(Device); 890 | 891 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 892 | "SynaGetReportDescriptor Entry\n"); 893 | 894 | PSYNA_CONTEXT devContext = GetDeviceContext(Device); 895 | 896 | #define MT_TOUCH_COLLECTION \ 897 | MT_TOUCH_COLLECTION0 \ 898 | 0x26, devContext->max_x_hid[0], devContext->max_x_hid[1], /* LOGICAL_MAXIMUM (WIDTH) */ \ 899 | 0x46, devContext->phy_x_hid[0], devContext->phy_x_hid[1], /* PHYSICAL_MAXIMUM (WIDTH) */ \ 900 | MT_TOUCH_COLLECTION1 \ 901 | 0x26, devContext->max_y_hid[0], devContext->max_y_hid[1], /* LOGICAL_MAXIMUM (HEIGHT) */ \ 902 | 0x46, devContext->phy_y_hid[0], devContext->phy_y_hid[1], /* PHYSICAL_MAXIMUM (HEIGHT) */ \ 903 | MT_TOUCH_COLLECTION2 904 | 905 | HID_REPORT_DESCRIPTOR ReportDescriptor[] = { 906 | // 907 | // Multitouch report starts here 908 | // 909 | //TOUCH PAD input TLC 910 | 0x05, 0x0d, // USAGE_PAGE (Digitizers) 911 | 0x09, 0x05, // USAGE (Touch Pad) 912 | 0xa1, 0x01, // COLLECTION (Application) 913 | 0x85, REPORTID_MTOUCH, // REPORT_ID (Touch pad) 914 | 0x09, 0x22, // USAGE (Finger) 915 | MT_TOUCH_COLLECTION 916 | MT_TOUCH_COLLECTION 917 | MT_TOUCH_COLLECTION 918 | MT_TOUCH_COLLECTION 919 | MT_TOUCH_COLLECTION 920 | USAGE_PAGES 921 | }; 922 | 923 | // 924 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 925 | // will correctly retrieve buffer from Irp->UserBuffer. 926 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 927 | // field irrespective of the ioctl buffer type. However, framework is very 928 | // strict about type checking. You cannot get Irp->UserBuffer by using 929 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 930 | // internal ioctl. 931 | // 932 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 933 | if (!NT_SUCCESS(status)) 934 | { 935 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 936 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 937 | 938 | return status; 939 | } 940 | 941 | // 942 | // Use hardcoded Report descriptor 943 | // 944 | bytesToCopy = DefaultHidDescriptor.DescriptorList[0].wReportLength; 945 | 946 | if (bytesToCopy == 0) 947 | { 948 | status = STATUS_INVALID_DEVICE_STATE; 949 | 950 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 951 | "DefaultHidDescriptor's reportLength is zero, 0x%x\n", status); 952 | 953 | return status; 954 | } 955 | 956 | status = WdfMemoryCopyFromBuffer(memory, 957 | 0, 958 | (PVOID)ReportDescriptor, 959 | bytesToCopy); 960 | if (!NT_SUCCESS(status)) 961 | { 962 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 963 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 964 | 965 | return status; 966 | } 967 | 968 | // 969 | // Report how many bytes were copied 970 | // 971 | WdfRequestSetInformation(Request, bytesToCopy); 972 | 973 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 974 | "SynaGetReportDescriptor Exit = 0x%x\n", status); 975 | 976 | return status; 977 | } 978 | 979 | 980 | NTSTATUS 981 | SynaGetDeviceAttributes( 982 | IN WDFREQUEST Request 983 | ) 984 | { 985 | NTSTATUS status = STATUS_SUCCESS; 986 | PHID_DEVICE_ATTRIBUTES deviceAttributes = NULL; 987 | 988 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 989 | "SynaGetDeviceAttributes Entry\n"); 990 | 991 | // 992 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 993 | // will correctly retrieve buffer from Irp->UserBuffer. 994 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 995 | // field irrespective of the ioctl buffer type. However, framework is very 996 | // strict about type checking. You cannot get Irp->UserBuffer by using 997 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 998 | // internal ioctl. 999 | // 1000 | status = WdfRequestRetrieveOutputBuffer(Request, 1001 | sizeof(HID_DEVICE_ATTRIBUTES), 1002 | &deviceAttributes, 1003 | NULL); 1004 | if (!NT_SUCCESS(status)) 1005 | { 1006 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1007 | "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); 1008 | 1009 | return status; 1010 | } 1011 | 1012 | // 1013 | // Set USB device descriptor 1014 | // 1015 | 1016 | deviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES); 1017 | deviceAttributes->VendorID = SYNA_VID; 1018 | deviceAttributes->ProductID = SYNA_PID; 1019 | deviceAttributes->VersionNumber = SYNA_VERSION; 1020 | 1021 | // 1022 | // Report how many bytes were copied 1023 | // 1024 | WdfRequestSetInformation(Request, sizeof(HID_DEVICE_ATTRIBUTES)); 1025 | 1026 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1027 | "SynaGetDeviceAttributes Exit = 0x%x\n", status); 1028 | 1029 | return status; 1030 | } 1031 | 1032 | NTSTATUS 1033 | SynaGetString( 1034 | IN WDFREQUEST Request 1035 | ) 1036 | { 1037 | 1038 | NTSTATUS status = STATUS_SUCCESS; 1039 | PWSTR pwstrID; 1040 | size_t lenID; 1041 | WDF_REQUEST_PARAMETERS params; 1042 | void *pStringBuffer = NULL; 1043 | 1044 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1045 | "SynaGetString Entry\n"); 1046 | 1047 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1048 | WdfRequestGetParameters(Request, ¶ms); 1049 | 1050 | switch ((ULONG_PTR)params.Parameters.DeviceIoControl.Type3InputBuffer & 0xFFFF) 1051 | { 1052 | case HID_STRING_ID_IMANUFACTURER: 1053 | pwstrID = L"Syna.\0"; 1054 | break; 1055 | 1056 | case HID_STRING_ID_IPRODUCT: 1057 | pwstrID = L"MaxTouch Touch Screen\0"; 1058 | break; 1059 | 1060 | case HID_STRING_ID_ISERIALNUMBER: 1061 | pwstrID = L"123123123\0"; 1062 | break; 1063 | 1064 | default: 1065 | pwstrID = NULL; 1066 | break; 1067 | } 1068 | 1069 | lenID = pwstrID ? wcslen(pwstrID)*sizeof(WCHAR) + sizeof(UNICODE_NULL) : 0; 1070 | 1071 | if (pwstrID == NULL) 1072 | { 1073 | 1074 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1075 | "SynaGetString Invalid request type\n"); 1076 | 1077 | status = STATUS_INVALID_PARAMETER; 1078 | 1079 | return status; 1080 | } 1081 | 1082 | status = WdfRequestRetrieveOutputBuffer(Request, 1083 | lenID, 1084 | &pStringBuffer, 1085 | &lenID); 1086 | 1087 | if (!NT_SUCCESS(status)) 1088 | { 1089 | 1090 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1091 | "SynaGetString WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1092 | 1093 | return status; 1094 | } 1095 | 1096 | RtlCopyMemory(pStringBuffer, pwstrID, lenID); 1097 | 1098 | WdfRequestSetInformation(Request, lenID); 1099 | 1100 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1101 | "SynaGetString Exit = 0x%x\n", status); 1102 | 1103 | return status; 1104 | } 1105 | 1106 | NTSTATUS 1107 | SynaWriteReport( 1108 | IN PSYNA_CONTEXT DevContext, 1109 | IN WDFREQUEST Request 1110 | ) 1111 | { 1112 | UNREFERENCED_PARAMETER(DevContext); 1113 | 1114 | NTSTATUS status = STATUS_SUCCESS; 1115 | WDF_REQUEST_PARAMETERS params; 1116 | PHID_XFER_PACKET transferPacket = NULL; 1117 | 1118 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1119 | "SynaWriteReport Entry\n"); 1120 | 1121 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1122 | WdfRequestGetParameters(Request, ¶ms); 1123 | 1124 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1125 | { 1126 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1127 | "SynaWriteReport Xfer packet too small\n"); 1128 | 1129 | status = STATUS_BUFFER_TOO_SMALL; 1130 | } 1131 | else 1132 | { 1133 | 1134 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1135 | 1136 | if (transferPacket == NULL) 1137 | { 1138 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1139 | "SynaWriteReport No xfer packet\n"); 1140 | 1141 | status = STATUS_INVALID_DEVICE_REQUEST; 1142 | } 1143 | else 1144 | { 1145 | // 1146 | // switch on the report id 1147 | // 1148 | 1149 | switch (transferPacket->reportId) 1150 | { 1151 | default: 1152 | 1153 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1154 | "SynaWriteReport Unhandled report type %d\n", transferPacket->reportId); 1155 | 1156 | status = STATUS_INVALID_PARAMETER; 1157 | 1158 | break; 1159 | } 1160 | } 1161 | } 1162 | 1163 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1164 | "SynaWriteReport Exit = 0x%x\n", status); 1165 | 1166 | return status; 1167 | 1168 | } 1169 | 1170 | NTSTATUS 1171 | SynaProcessVendorReport( 1172 | IN PSYNA_CONTEXT DevContext, 1173 | IN PVOID ReportBuffer, 1174 | IN ULONG ReportBufferLen, 1175 | OUT size_t* BytesWritten 1176 | ) 1177 | { 1178 | NTSTATUS status = STATUS_SUCCESS; 1179 | WDFREQUEST reqRead; 1180 | PVOID pReadReport = NULL; 1181 | size_t bytesReturned = 0; 1182 | 1183 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1184 | "SynaProcessVendorReport Entry\n"); 1185 | 1186 | status = WdfIoQueueRetrieveNextRequest(DevContext->ReportQueue, 1187 | &reqRead); 1188 | 1189 | if (NT_SUCCESS(status)) 1190 | { 1191 | status = WdfRequestRetrieveOutputBuffer(reqRead, 1192 | ReportBufferLen, 1193 | &pReadReport, 1194 | &bytesReturned); 1195 | 1196 | if (NT_SUCCESS(status)) 1197 | { 1198 | // 1199 | // Copy ReportBuffer into read request 1200 | // 1201 | 1202 | if (bytesReturned > ReportBufferLen) 1203 | { 1204 | bytesReturned = ReportBufferLen; 1205 | } 1206 | 1207 | RtlCopyMemory(pReadReport, 1208 | ReportBuffer, 1209 | bytesReturned); 1210 | 1211 | // 1212 | // Complete read with the number of bytes returned as info 1213 | // 1214 | 1215 | WdfRequestCompleteWithInformation(reqRead, 1216 | status, 1217 | bytesReturned); 1218 | 1219 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1220 | "SynaProcessVendorReport %d bytes returned\n", bytesReturned); 1221 | 1222 | // 1223 | // Return the number of bytes written for the write request completion 1224 | // 1225 | 1226 | *BytesWritten = bytesReturned; 1227 | 1228 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1229 | "%s completed, Queue:0x%p, Request:0x%p\n", 1230 | DbgHidInternalIoctlString(IOCTL_HID_READ_REPORT), 1231 | DevContext->ReportQueue, 1232 | reqRead); 1233 | } 1234 | else 1235 | { 1236 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1237 | "WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1238 | } 1239 | } 1240 | else 1241 | { 1242 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1243 | "WdfIoQueueRetrieveNextRequest failed Status 0x%x\n", status); 1244 | } 1245 | 1246 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1247 | "SynaProcessVendorReport Exit = 0x%x\n", status); 1248 | 1249 | return status; 1250 | } 1251 | 1252 | NTSTATUS 1253 | SynaReadReport( 1254 | IN PSYNA_CONTEXT DevContext, 1255 | IN WDFREQUEST Request, 1256 | OUT BOOLEAN* CompleteRequest 1257 | ) 1258 | { 1259 | NTSTATUS status = STATUS_SUCCESS; 1260 | 1261 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1262 | "SynaReadReport Entry\n"); 1263 | 1264 | // 1265 | // Forward this read request to our manual queue 1266 | // (in other words, we are going to defer this request 1267 | // until we have a corresponding write request to 1268 | // match it with) 1269 | // 1270 | 1271 | status = WdfRequestForwardToIoQueue(Request, DevContext->ReportQueue); 1272 | 1273 | if (!NT_SUCCESS(status)) 1274 | { 1275 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1276 | "WdfRequestForwardToIoQueue failed Status 0x%x\n", status); 1277 | } 1278 | else 1279 | { 1280 | *CompleteRequest = FALSE; 1281 | } 1282 | 1283 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1284 | "SynaReadReport Exit = 0x%x\n", status); 1285 | 1286 | return status; 1287 | } 1288 | 1289 | NTSTATUS 1290 | SynaSetFeature( 1291 | IN PSYNA_CONTEXT DevContext, 1292 | IN WDFREQUEST Request, 1293 | OUT BOOLEAN* CompleteRequest 1294 | ) 1295 | { 1296 | UNREFERENCED_PARAMETER(CompleteRequest); 1297 | 1298 | NTSTATUS status = STATUS_SUCCESS; 1299 | WDF_REQUEST_PARAMETERS params; 1300 | PHID_XFER_PACKET transferPacket = NULL; 1301 | SynaFeatureReport* pReport = NULL; 1302 | 1303 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1304 | "SynaSetFeature Entry\n"); 1305 | 1306 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1307 | WdfRequestGetParameters(Request, ¶ms); 1308 | 1309 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1310 | { 1311 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1312 | "SynaSetFeature Xfer packet too small\n"); 1313 | 1314 | status = STATUS_BUFFER_TOO_SMALL; 1315 | } 1316 | else 1317 | { 1318 | 1319 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1320 | 1321 | if (transferPacket == NULL) 1322 | { 1323 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1324 | "SynaWriteReport No xfer packet\n"); 1325 | 1326 | status = STATUS_INVALID_DEVICE_REQUEST; 1327 | } 1328 | else 1329 | { 1330 | // 1331 | // switch on the report id 1332 | // 1333 | 1334 | switch (transferPacket->reportId) 1335 | { 1336 | case REPORTID_FEATURE: 1337 | 1338 | if (transferPacket->reportBufferLen == sizeof(SynaFeatureReport)) 1339 | { 1340 | pReport = (SynaFeatureReport*)transferPacket->reportBuffer; 1341 | 1342 | DevContext->DeviceMode = pReport->DeviceMode; 1343 | 1344 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1345 | "SynaSetFeature DeviceMode = 0x%x\n", DevContext->DeviceMode); 1346 | } 1347 | else 1348 | { 1349 | status = STATUS_INVALID_PARAMETER; 1350 | 1351 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1352 | "SynaSetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(SynaFeatureReport) (%d)\n", 1353 | transferPacket->reportBufferLen, 1354 | sizeof(SynaFeatureReport)); 1355 | } 1356 | 1357 | break; 1358 | 1359 | default: 1360 | 1361 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1362 | "SynaSetFeature Unhandled report type %d\n", transferPacket->reportId); 1363 | 1364 | status = STATUS_INVALID_PARAMETER; 1365 | 1366 | break; 1367 | } 1368 | } 1369 | } 1370 | 1371 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1372 | "SynaSetFeature Exit = 0x%x\n", status); 1373 | 1374 | return status; 1375 | } 1376 | 1377 | NTSTATUS 1378 | SynaGetFeature( 1379 | IN PSYNA_CONTEXT DevContext, 1380 | IN WDFREQUEST Request, 1381 | OUT BOOLEAN* CompleteRequest 1382 | ) 1383 | { 1384 | UNREFERENCED_PARAMETER(CompleteRequest); 1385 | 1386 | NTSTATUS status = STATUS_SUCCESS; 1387 | WDF_REQUEST_PARAMETERS params; 1388 | PHID_XFER_PACKET transferPacket = NULL; 1389 | 1390 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1391 | "SynaGetFeature Entry\n"); 1392 | 1393 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1394 | WdfRequestGetParameters(Request, ¶ms); 1395 | 1396 | if (params.Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) 1397 | { 1398 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1399 | "SynaGetFeature Xfer packet too small\n"); 1400 | 1401 | status = STATUS_BUFFER_TOO_SMALL; 1402 | } 1403 | else 1404 | { 1405 | 1406 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1407 | 1408 | if (transferPacket == NULL) 1409 | { 1410 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1411 | "SynaGetFeature No xfer packet\n"); 1412 | 1413 | status = STATUS_INVALID_DEVICE_REQUEST; 1414 | } 1415 | else 1416 | { 1417 | // 1418 | // switch on the report id 1419 | // 1420 | 1421 | switch (transferPacket->reportId) 1422 | { 1423 | case REPORTID_MTOUCH: 1424 | { 1425 | 1426 | SynaMaxCountReport* pReport = NULL; 1427 | 1428 | if (transferPacket->reportBufferLen >= sizeof(SynaMaxCountReport)) 1429 | { 1430 | pReport = (SynaMaxCountReport*)transferPacket->reportBuffer; 1431 | 1432 | pReport->MaximumCount = MULTI_MAX_COUNT; 1433 | 1434 | pReport->PadType = 0; 1435 | 1436 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1437 | "SynaGetFeature MaximumCount = 0x%x\n", MULTI_MAX_COUNT); 1438 | } 1439 | else 1440 | { 1441 | status = STATUS_INVALID_PARAMETER; 1442 | 1443 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1444 | "SynaGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(SynaMaxCountReport) (%d)\n", 1445 | transferPacket->reportBufferLen, 1446 | sizeof(SynaMaxCountReport)); 1447 | } 1448 | 1449 | break; 1450 | } 1451 | 1452 | case REPORTID_FEATURE: 1453 | { 1454 | 1455 | SynaFeatureReport* pReport = NULL; 1456 | 1457 | if (transferPacket->reportBufferLen >= sizeof(SynaFeatureReport)) 1458 | { 1459 | pReport = (SynaFeatureReport*)transferPacket->reportBuffer; 1460 | 1461 | pReport->DeviceMode = DevContext->DeviceMode; 1462 | 1463 | pReport->DeviceIdentifier = 0; 1464 | 1465 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1466 | "SynaGetFeature DeviceMode = 0x%x\n", DevContext->DeviceMode); 1467 | } 1468 | else 1469 | { 1470 | status = STATUS_INVALID_PARAMETER; 1471 | 1472 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1473 | "SynaGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(SynaFeatureReport) (%d)\n", 1474 | transferPacket->reportBufferLen, 1475 | sizeof(SynaFeatureReport)); 1476 | } 1477 | 1478 | break; 1479 | } 1480 | 1481 | case REPORTID_PTPHQA: 1482 | { 1483 | uint8_t PTPHQA_BLOB[] = { REPORTID_PTPHQA, 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87, 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88, 0x07,\ 1484 | 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6, 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2, 0x2e, 0x84,\ 1485 | 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43, 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc, 0x47, 0x70, 0x1b,\ 1486 | 0x59, 0x6f, 0x74, 0x43, 0xc4, 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71, 0xc7, 0x95, 0x0e, 0x31,\ 1487 | 0x55, 0x21, 0xd3, 0xb5, 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19, 0x3e, 0xb3, 0xaf, 0x75, 0x81,\ 1488 | 0x9d, 0x53, 0xb9, 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c, 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d,\ 1489 | 0xa7, 0x26, 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b, 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0,\ 1490 | 0x2a, 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8, 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1, 0x0b,\ 1491 | 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7, 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b, 0xe8, 0x8a,\ 1492 | 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35, 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc, 0x2b, 0x53, 0x5c,\ 1493 | 0x69, 0x52, 0xd5, 0xc8, 0x73, 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff, 0x05, 0xd8, 0x2b, 0x79,\ 1494 | 0x9a, 0xe2, 0x34, 0x60, 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc, 0x80, 0xe3, 0x0f, 0xbd, 0x65,\ 1495 | 0x20, 0x08, 0x13, 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7, 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe,\ 1496 | 0x31, 0x48, 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89, 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a,\ 1497 | 0xe4, 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08, 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2 }; 1498 | if (transferPacket->reportBufferLen >= sizeof(PTPHQA_BLOB)) 1499 | { 1500 | uint8_t* blobBuffer = (uint8_t*)transferPacket->reportBuffer; 1501 | for (int i = 0; i < sizeof(PTPHQA_BLOB); i++) { 1502 | blobBuffer[i] = PTPHQA_BLOB[i]; 1503 | } 1504 | SynaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1505 | "SynaGetFeature PHPHQA\n"); 1506 | } 1507 | else 1508 | { 1509 | status = STATUS_INVALID_PARAMETER; 1510 | 1511 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1512 | "SynaGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(PTPHEQ_BLOB) (%d)\n", 1513 | transferPacket->reportBufferLen, 1514 | sizeof(SynaFeatureReport)); 1515 | } 1516 | break; 1517 | } 1518 | 1519 | default: 1520 | 1521 | SynaPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1522 | "SynaGetFeature Unhandled report type %d\n", transferPacket->reportId); 1523 | 1524 | status = STATUS_INVALID_PARAMETER; 1525 | 1526 | break; 1527 | } 1528 | } 1529 | } 1530 | 1531 | SynaPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1532 | "SynaGetFeature Exit = 0x%x\n", status); 1533 | 1534 | return status; 1535 | } 1536 | 1537 | PCHAR 1538 | DbgHidInternalIoctlString( 1539 | IN ULONG IoControlCode 1540 | ) 1541 | { 1542 | switch (IoControlCode) 1543 | { 1544 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 1545 | return "IOCTL_HID_GET_DEVICE_DESCRIPTOR"; 1546 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 1547 | return "IOCTL_HID_GET_REPORT_DESCRIPTOR"; 1548 | case IOCTL_HID_READ_REPORT: 1549 | return "IOCTL_HID_READ_REPORT"; 1550 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 1551 | return "IOCTL_HID_GET_DEVICE_ATTRIBUTES"; 1552 | case IOCTL_HID_WRITE_REPORT: 1553 | return "IOCTL_HID_WRITE_REPORT"; 1554 | case IOCTL_HID_SET_FEATURE: 1555 | return "IOCTL_HID_SET_FEATURE"; 1556 | case IOCTL_HID_GET_FEATURE: 1557 | return "IOCTL_HID_GET_FEATURE"; 1558 | case IOCTL_HID_GET_STRING: 1559 | return "IOCTL_HID_GET_STRING"; 1560 | case IOCTL_HID_ACTIVATE_DEVICE: 1561 | return "IOCTL_HID_ACTIVATE_DEVICE"; 1562 | case IOCTL_HID_DEACTIVATE_DEVICE: 1563 | return "IOCTL_HID_DEACTIVATE_DEVICE"; 1564 | case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: 1565 | return "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST"; 1566 | case IOCTL_HID_SET_OUTPUT_REPORT: 1567 | return "IOCTL_HID_SET_OUTPUT_REPORT"; 1568 | case IOCTL_HID_GET_INPUT_REPORT: 1569 | return "IOCTL_HID_GET_INPUT_REPORT"; 1570 | default: 1571 | return "Unknown IOCTL"; 1572 | } 1573 | } 1574 | --------------------------------------------------------------------------------