├── crostouchpad Package ├── crostouchpad Package.vcxproj.user ├── crostouchpad Package.vcxproj.filters └── crostouchpad Package.vcxproj ├── crostouchpad ├── stdint.h ├── crostouchpad.vcxproj.user ├── crostouchpad4.rc ├── trace.h ├── spb.h ├── hidcommon.h ├── crostouchpad.vcxproj.filters ├── crostouchpad.inf ├── elantp.h ├── crostouchpad.vcxproj ├── spb.c ├── driver.h └── elan.c ├── LICENSE.txt ├── crostouchpad4.sln └── .gitignore /crostouchpad Package/crostouchpad Package.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /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; -------------------------------------------------------------------------------- /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/crostouchpad.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /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 Elan 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 Elan 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/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 | SpbReadDataSynchronously( 44 | _In_ SPB_CONTEXT *SpbContext, 45 | _In_reads_bytes_(Length) PVOID Data, 46 | _In_ ULONG Length 47 | ); 48 | 49 | NTSTATUS 50 | SpbXferDataSynchronously( 51 | _In_ SPB_CONTEXT* SpbContext, 52 | _In_ PVOID SendData, 53 | _In_ ULONG SendLength, 54 | _In_reads_bytes_(Length) PVOID Data, 55 | _In_ ULONG Length 56 | ); 57 | 58 | 59 | VOID 60 | SpbTargetDeinitialize( 61 | IN WDFDEVICE FxDevice, 62 | IN SPB_CONTEXT *SpbContext 63 | ); 64 | 65 | NTSTATUS 66 | SpbTargetInitialize( 67 | IN WDFDEVICE FxDevice, 68 | IN SPB_CONTEXT *SpbContext 69 | ); 70 | 71 | NTSTATUS 72 | SpbWriteDataSynchronously( 73 | IN SPB_CONTEXT *SpbContext, 74 | IN PVOID Data, 75 | IN ULONG Length 76 | ); -------------------------------------------------------------------------------- /crostouchpad/hidcommon.h: -------------------------------------------------------------------------------- 1 | #if !defined(_ELAN_COMMON_H_) 2 | #define _ELAN_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 ELAN_PID 0xBACC 10 | #define ELAN_VID 0x00FF 11 | #define ELAN_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 _ELAN_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 | } ElanMultiTouchReport; 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 _ELAN_FEATURE_REPORT 75 | { 76 | 77 | BYTE ReportID; 78 | 79 | BYTE DeviceMode; 80 | 81 | BYTE DeviceIdentifier; 82 | 83 | } ElanFeatureReport; 84 | 85 | typedef struct _ELAN_MAXCOUNT_REPORT 86 | { 87 | 88 | BYTE ReportID; 89 | 90 | BYTE MaximumCount; 91 | 92 | BYTE PadType; 93 | 94 | } ElanMaxCountReport; 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 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | 50 | 51 | Driver Files 52 | 53 | 54 | 55 | 56 | Resource Files 57 | 58 | 59 | -------------------------------------------------------------------------------- /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 Cypress v3 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.4 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\ELAN0000 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 Elan Touchpad" 78 | CrosTouchpad.SVCDESC = "CrosTouchpad Service" 79 | -------------------------------------------------------------------------------- /crostouchpad/elantp.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef __packed 4 | #define __packed( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) 5 | #endif 6 | 7 | /* Elan i2c commands */ 8 | #define ETP_I2C_RESET 0x0100 9 | #define ETP_I2C_WAKE_UP 0x0800 10 | #define ETP_I2C_SLEEP 0x0801 11 | #define ETP_I2C_DESC_CMD 0x0001 12 | #define ETP_I2C_REPORT_DESC_CMD 0x0002 13 | #define ETP_I2C_STAND_CMD 0x0005 14 | #define ETP_I2C_UNIQUEID_CMD 0x0101 15 | #define ETP_I2C_FW_VERSION_CMD 0x0102 16 | #define ETP_I2C_SM_VERSION_CMD 0x0103 17 | #define ETP_I2C_XY_TRACENUM_CMD 0x0105 18 | #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 19 | #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 20 | #define ETP_I2C_RESOLUTION_CMD 0x0108 21 | #define ETP_I2C_PRESSURE_CMD 0x010A 22 | #define ETP_I2C_IAP_VERSION_CMD 0x0110 23 | #define ETP_I2C_SET_CMD 0x0300 24 | #define ETP_I2C_POWER_CMD 0x0307 25 | #define ETP_I2C_FW_CHECKSUM_CMD 0x030F 26 | #define ETP_I2C_IAP_CTRL_CMD 0x0310 27 | #define ETP_I2C_IAP_CMD 0x0311 28 | #define ETP_I2C_IAP_RESET_CMD 0x0314 29 | #define ETP_I2C_IAP_CHECKSUM_CMD 0x0315 30 | #define ETP_I2C_CALIBRATE_CMD 0x0316 31 | #define ETP_I2C_MAX_BASELINE_CMD 0x0317 32 | #define ETP_I2C_MIN_BASELINE_CMD 0x0318 33 | 34 | #define ETP_I2C_REPORT_LEN 34 35 | #define ETP_I2C_DESC_LENGTH 30 36 | #define ETP_I2C_REPORT_DESC_LENGTH 158 37 | #define ETP_I2C_INF_LENGTH 2 38 | #define ETP_I2C_IAP_PASSWORD 0x1EA5 39 | #define ETP_I2C_IAP_RESET 0xF0F0 40 | #define ETP_I2C_MAIN_MODE_ON (1 << 9) 41 | #define ETP_I2C_IAP_REG_L 0x01 42 | #define ETP_I2C_IAP_REG_H 0x06 43 | 44 | #define ETP_ENABLE_ABS 0x0001 45 | #define ETP_ENABLE_CALIBRATE 0x0002 46 | #define ETP_DISABLE_CALIBRATE 0x0000 47 | #define ETP_DISABLE_POWER 0x0001 48 | #define ETP_PRESSURE_OFFSET 25 49 | 50 | #define ETP_MAX_PRESSURE 255 51 | #define ETP_FWIDTH_REDUCE 90 52 | #define ETP_FINGER_WIDTH 15 53 | #define ETP_RETRY_COUNT 3 54 | 55 | #define ETP_MAX_FINGERS 5 56 | #define ETP_FINGER_DATA_LEN 5 57 | #define ETP_REPORT_ID 0x5D 58 | #define ETP_REPORT_ID_OFFSET 2 59 | #define ETP_TOUCH_INFO_OFFSET 3 60 | #define ETP_FINGER_DATA_OFFSET 4 61 | #define ETP_HOVER_INFO_OFFSET 30 62 | #define ETP_MAX_REPORT_LEN 34 63 | 64 | enum tp_mode { 65 | IAP_MODE = 1, 66 | MAIN_MODE 67 | }; 68 | 69 | #define MXT_T9_RELEASE (1 << 5) 70 | #define MXT_T9_PRESS (1 << 6) 71 | #define MXT_T9_DETECT (1 << 7) -------------------------------------------------------------------------------- /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 = {02C4EB4E-E672-40E9-8645-D0E4B2EEEAA0} 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/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 | crostouchpad 30 | $(LatestTargetPlatformVersion) 31 | 32 | 33 | 34 | Windows10 35 | true 36 | WindowsKernelModeDriver10.0 37 | Driver 38 | KMDF 39 | 40 | 41 | 42 | 43 | Windows10 44 | false 45 | WindowsKernelModeDriver10.0 46 | Driver 47 | KMDF 48 | 49 | 50 | 51 | 52 | Windows10 53 | true 54 | WindowsKernelModeDriver10.0 55 | Driver 56 | KMDF 57 | 58 | 59 | 60 | 61 | Windows10 62 | false 63 | WindowsKernelModeDriver10.0 64 | Driver 65 | KMDF 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | DbgengKernelDebugger 79 | 80 | 81 | DbgengKernelDebugger 82 | 83 | 84 | DbgengKernelDebugger 85 | 86 | 87 | DbgengKernelDebugger 88 | 89 | 90 | 91 | true 92 | trace.h 93 | true 94 | false 95 | 96 | 97 | 4.1.4 98 | 99 | 100 | 101 | 102 | true 103 | trace.h 104 | true 105 | false 106 | 107 | 108 | 4.1.4 109 | 110 | 111 | 112 | 113 | true 114 | trace.h 115 | true 116 | false 117 | 118 | 119 | 4.1.4 120 | 121 | 122 | 123 | 124 | true 125 | trace.h 126 | true 127 | false 128 | 129 | 130 | 4.1.4 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /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/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 ElanDebugLevel = 100; 26 | static ULONG ElanDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 27 | 28 | NTSTATUS 29 | SpbDoWriteDataSynchronously( 30 | IN SPB_CONTEXT *SpbContext, 31 | IN PVOID Data, 32 | IN ULONG Length 33 | ) 34 | /*++ 35 | 36 | Routine Description: 37 | 38 | This helper routine abstracts creating and sending an I/O 39 | request (I2C Write) to the Spb I/O target. 40 | 41 | Arguments: 42 | 43 | SpbContext - Pointer to the current device context 44 | Address - The I2C register address to write to 45 | Data - A buffer to receive the data at at the above address 46 | Length - The amount of data to be read from the above address 47 | 48 | Return Value: 49 | 50 | NTSTATUS Status indicating success or failure 51 | 52 | --*/ 53 | { 54 | PUCHAR buffer; 55 | ULONG length; 56 | WDFMEMORY memory; 57 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 58 | NTSTATUS status; 59 | 60 | // 61 | // The address pointer and data buffer must be combined 62 | // into one contiguous buffer representing the write transaction. 63 | // 64 | length = Length; 65 | memory = NULL; 66 | 67 | if (length > DEFAULT_SPB_BUFFER_SIZE) 68 | { 69 | status = WdfMemoryCreate( 70 | WDF_NO_OBJECT_ATTRIBUTES, 71 | NonPagedPool, 72 | ELAN_POOL_TAG, 73 | length, 74 | &memory, 75 | (PVOID *)&buffer); 76 | 77 | if (!NT_SUCCESS(status)) 78 | { 79 | ElanPrint( 80 | DEBUG_LEVEL_ERROR, 81 | DBG_IOCTL, 82 | "Error allocating memory for Spb write - %!STATUS!", 83 | status); 84 | goto exit; 85 | } 86 | 87 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 88 | &memoryDescriptor, 89 | memory, 90 | NULL); 91 | } 92 | else 93 | { 94 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 95 | 96 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 97 | &memoryDescriptor, 98 | (PVOID)buffer, 99 | length); 100 | } 101 | 102 | // 103 | // Address is followed by the data payload 104 | // 105 | RtlCopyMemory(buffer, Data, length); 106 | 107 | status = WdfIoTargetSendWriteSynchronously( 108 | SpbContext->SpbIoTarget, 109 | NULL, 110 | &memoryDescriptor, 111 | NULL, 112 | NULL, 113 | NULL); 114 | 115 | if (!NT_SUCCESS(status)) 116 | { 117 | ElanPrint( 118 | DEBUG_LEVEL_ERROR, 119 | DBG_IOCTL, 120 | "Error writing to Spb - %!STATUS!", 121 | status); 122 | goto exit; 123 | } 124 | 125 | exit: 126 | 127 | if (NULL != memory) 128 | { 129 | WdfObjectDelete(memory); 130 | } 131 | 132 | return status; 133 | } 134 | 135 | NTSTATUS 136 | SpbWriteDataSynchronously( 137 | IN SPB_CONTEXT *SpbContext, 138 | IN PVOID Data, 139 | IN ULONG Length 140 | ) 141 | /*++ 142 | 143 | Routine Description: 144 | 145 | This routine abstracts creating and sending an I/O 146 | request (I2C Write) to the Spb I/O target and utilizes 147 | a helper routine to do work inside of locked code. 148 | 149 | Arguments: 150 | 151 | SpbContext - Pointer to the current device context 152 | Address - The I2C register address to write to 153 | Data - A buffer to receive the data at at the above address 154 | Length - The amount of data to be read from the above address 155 | 156 | Return Value: 157 | 158 | NTSTATUS Status indicating success or failure 159 | 160 | --*/ 161 | { 162 | NTSTATUS status; 163 | 164 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 165 | 166 | status = SpbDoWriteDataSynchronously( 167 | SpbContext, 168 | Data, 169 | Length); 170 | 171 | WdfWaitLockRelease(SpbContext->SpbLock); 172 | 173 | return status; 174 | } 175 | 176 | NTSTATUS 177 | SpbXferDataSynchronously( 178 | _In_ SPB_CONTEXT* SpbContext, 179 | _In_ PVOID SendData, 180 | _In_ ULONG SendLength, 181 | _In_reads_bytes_(Length) PVOID Data, 182 | _In_ ULONG Length 183 | ) 184 | /*++ 185 | Routine Description: 186 | This helper routine abstracts creating and sending an I/O 187 | request (I2C Read) to the Spb I/O target. 188 | Arguments: 189 | SpbContext - Pointer to the current device context 190 | Address - The I2C register address to read from 191 | Data - A buffer to receive the data at at the above address 192 | Length - The amount of data to be read from the above address 193 | Return Value: 194 | NTSTATUS Status indicating success or failure 195 | --*/ 196 | { 197 | PUCHAR buffer; 198 | WDFMEMORY memory; 199 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 200 | NTSTATUS status; 201 | ULONG_PTR bytesRead; 202 | 203 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 204 | 205 | memory = NULL; 206 | status = STATUS_INVALID_PARAMETER; 207 | bytesRead = 0; 208 | 209 | // 210 | // Xfer transactions start by writing an address pointer 211 | // 212 | status = SpbDoWriteDataSynchronously( 213 | SpbContext, 214 | SendData, 215 | SendLength); 216 | 217 | if (!NT_SUCCESS(status)) 218 | { 219 | ElanPrint( 220 | DEBUG_LEVEL_ERROR, 221 | DBG_IOCTL, 222 | "Error setting address pointer for Spb read - %!STATUS!", 223 | status); 224 | goto exit; 225 | } 226 | 227 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 228 | { 229 | status = WdfMemoryCreate( 230 | WDF_NO_OBJECT_ATTRIBUTES, 231 | NonPagedPool, 232 | ELAN_POOL_TAG, 233 | Length, 234 | &memory, 235 | (PVOID*)&buffer); 236 | 237 | if (!NT_SUCCESS(status)) 238 | { 239 | ElanPrint( 240 | DEBUG_LEVEL_ERROR, 241 | DBG_IOCTL, 242 | "Error allocating memory for Spb read - %!STATUS!", 243 | status); 244 | goto exit; 245 | } 246 | 247 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 248 | &memoryDescriptor, 249 | memory, 250 | NULL); 251 | } 252 | else 253 | { 254 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 255 | 256 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 257 | &memoryDescriptor, 258 | (PVOID)buffer, 259 | Length); 260 | } 261 | 262 | 263 | status = WdfIoTargetSendReadSynchronously( 264 | SpbContext->SpbIoTarget, 265 | NULL, 266 | &memoryDescriptor, 267 | NULL, 268 | NULL, 269 | &bytesRead); 270 | 271 | if (!NT_SUCCESS(status) || 272 | bytesRead != Length) 273 | { 274 | ElanPrint( 275 | DEBUG_LEVEL_ERROR, 276 | DBG_IOCTL, 277 | "Error reading from Spb - %!STATUS!", 278 | status); 279 | goto exit; 280 | } 281 | 282 | // 283 | // Copy back to the caller's buffer 284 | // 285 | RtlCopyMemory(Data, buffer, Length); 286 | 287 | exit: 288 | if (NULL != memory) 289 | { 290 | WdfObjectDelete(memory); 291 | } 292 | 293 | WdfWaitLockRelease(SpbContext->SpbLock); 294 | 295 | return status; 296 | } 297 | 298 | NTSTATUS 299 | SpbReadDataSynchronously( 300 | _In_ SPB_CONTEXT *SpbContext, 301 | _In_reads_bytes_(Length) PVOID Data, 302 | _In_ ULONG Length 303 | ) 304 | /*++ 305 | 306 | Routine Description: 307 | 308 | This helper routine abstracts creating and sending an I/O 309 | request (I2C Read) to the Spb I/O target. 310 | 311 | Arguments: 312 | 313 | SpbContext - Pointer to the current device context 314 | Address - The I2C register address to read from 315 | Data - A buffer to receive the data at at the above address 316 | Length - The amount of data to be read from the above address 317 | 318 | Return Value: 319 | 320 | NTSTATUS Status indicating success or failure 321 | 322 | --*/ 323 | { 324 | PUCHAR buffer; 325 | WDFMEMORY memory; 326 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 327 | NTSTATUS status; 328 | ULONG_PTR bytesRead; 329 | 330 | WdfWaitLockAcquire(SpbContext->SpbLock, NULL); 331 | 332 | memory = NULL; 333 | status = STATUS_INVALID_PARAMETER; 334 | bytesRead = 0; 335 | 336 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 337 | { 338 | status = WdfMemoryCreate( 339 | WDF_NO_OBJECT_ATTRIBUTES, 340 | NonPagedPool, 341 | ELAN_POOL_TAG, 342 | Length, 343 | &memory, 344 | (PVOID *)&buffer); 345 | 346 | if (!NT_SUCCESS(status)) 347 | { 348 | ElanPrint( 349 | DEBUG_LEVEL_ERROR, 350 | DBG_IOCTL, 351 | "Error allocating memory for Spb read - %!STATUS!", 352 | status); 353 | goto exit; 354 | } 355 | 356 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 357 | &memoryDescriptor, 358 | memory, 359 | NULL); 360 | } 361 | else 362 | { 363 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 364 | 365 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 366 | &memoryDescriptor, 367 | (PVOID)buffer, 368 | Length); 369 | } 370 | 371 | 372 | status = WdfIoTargetSendReadSynchronously( 373 | SpbContext->SpbIoTarget, 374 | NULL, 375 | &memoryDescriptor, 376 | NULL, 377 | NULL, 378 | &bytesRead); 379 | 380 | if (!NT_SUCCESS(status) || 381 | bytesRead != Length) 382 | { 383 | ElanPrint( 384 | DEBUG_LEVEL_ERROR, 385 | DBG_IOCTL, 386 | "Error reading from Spb - %!STATUS!", 387 | status); 388 | goto exit; 389 | } 390 | 391 | // 392 | // Copy back to the caller's buffer 393 | // 394 | RtlCopyMemory(Data, buffer, Length); 395 | 396 | exit: 397 | if (NULL != memory) 398 | { 399 | WdfObjectDelete(memory); 400 | } 401 | 402 | WdfWaitLockRelease(SpbContext->SpbLock); 403 | 404 | return status; 405 | } 406 | 407 | VOID 408 | SpbTargetDeinitialize( 409 | IN WDFDEVICE FxDevice, 410 | IN SPB_CONTEXT *SpbContext 411 | ) 412 | /*++ 413 | 414 | Routine Description: 415 | 416 | This helper routine is used to free any members added to the SPB_CONTEXT, 417 | note the SPB I/O target is parented to the device and will be 418 | closed and free'd when the device is removed. 419 | 420 | Arguments: 421 | 422 | FxDevice - Handle to the framework device object 423 | SpbContext - Pointer to the current device context 424 | 425 | Return Value: 426 | 427 | NTSTATUS Status indicating success or failure 428 | 429 | --*/ 430 | { 431 | UNREFERENCED_PARAMETER(FxDevice); 432 | UNREFERENCED_PARAMETER(SpbContext); 433 | 434 | // 435 | // Free any SPB_CONTEXT allocations here 436 | // 437 | if (SpbContext->SpbLock != NULL) 438 | { 439 | WdfObjectDelete(SpbContext->SpbLock); 440 | } 441 | 442 | if (SpbContext->ReadMemory != NULL) 443 | { 444 | WdfObjectDelete(SpbContext->ReadMemory); 445 | } 446 | 447 | if (SpbContext->WriteMemory != NULL) 448 | { 449 | WdfObjectDelete(SpbContext->WriteMemory); 450 | } 451 | } 452 | 453 | NTSTATUS 454 | SpbTargetInitialize( 455 | IN WDFDEVICE FxDevice, 456 | IN SPB_CONTEXT *SpbContext 457 | ) 458 | /*++ 459 | 460 | Routine Description: 461 | 462 | This helper routine opens the Spb I/O target and 463 | initializes a request object used for the lifetime 464 | of communication between this driver and Spb. 465 | 466 | Arguments: 467 | 468 | FxDevice - Handle to the framework device object 469 | SpbContext - Pointer to the current device context 470 | 471 | Return Value: 472 | 473 | NTSTATUS Status indicating success or failure 474 | 475 | --*/ 476 | { 477 | WDF_OBJECT_ATTRIBUTES objectAttributes; 478 | WDF_IO_TARGET_OPEN_PARAMS openParams; 479 | UNICODE_STRING spbDeviceName; 480 | WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 481 | NTSTATUS status; 482 | 483 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 484 | objectAttributes.ParentObject = FxDevice; 485 | 486 | status = WdfIoTargetCreate( 487 | FxDevice, 488 | &objectAttributes, 489 | &SpbContext->SpbIoTarget); 490 | 491 | if (!NT_SUCCESS(status)) 492 | { 493 | ElanPrint( 494 | DEBUG_LEVEL_ERROR, 495 | DBG_IOCTL, 496 | "Error creating IoTarget object - %!STATUS!", 497 | status); 498 | 499 | WdfObjectDelete(SpbContext->SpbIoTarget); 500 | goto exit; 501 | } 502 | 503 | RtlInitEmptyUnicodeString( 504 | &spbDeviceName, 505 | spbDeviceNameBuffer, 506 | sizeof(spbDeviceNameBuffer)); 507 | 508 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 509 | &spbDeviceName, 510 | SpbContext->I2cResHubId.LowPart, 511 | SpbContext->I2cResHubId.HighPart); 512 | 513 | if (!NT_SUCCESS(status)) 514 | { 515 | ElanPrint( 516 | DEBUG_LEVEL_ERROR, 517 | DBG_IOCTL, 518 | "Error creating Spb resource hub path string - %!STATUS!", 519 | status); 520 | goto exit; 521 | } 522 | 523 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 524 | &openParams, 525 | &spbDeviceName, 526 | (GENERIC_READ | GENERIC_WRITE)); 527 | 528 | openParams.ShareAccess = 0; 529 | openParams.CreateDisposition = FILE_OPEN; 530 | openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; 531 | 532 | status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); 533 | 534 | if (!NT_SUCCESS(status)) 535 | { 536 | ElanPrint( 537 | DEBUG_LEVEL_ERROR, 538 | DBG_IOCTL, 539 | "Error opening Spb target for communication - %!STATUS!", 540 | status); 541 | goto exit; 542 | } 543 | 544 | // 545 | // Allocate some fixed-size buffers from NonPagedPool for typical 546 | // Spb transaction sizes to avoid pool fragmentation in most cases 547 | // 548 | status = WdfMemoryCreate( 549 | WDF_NO_OBJECT_ATTRIBUTES, 550 | NonPagedPool, 551 | ELAN_POOL_TAG, 552 | DEFAULT_SPB_BUFFER_SIZE, 553 | &SpbContext->WriteMemory, 554 | NULL); 555 | 556 | if (!NT_SUCCESS(status)) 557 | { 558 | ElanPrint( 559 | DEBUG_LEVEL_ERROR, 560 | DBG_IOCTL, 561 | "Error allocating default memory for Spb write - %!STATUS!", 562 | status); 563 | goto exit; 564 | } 565 | 566 | status = WdfMemoryCreate( 567 | WDF_NO_OBJECT_ATTRIBUTES, 568 | NonPagedPool, 569 | ELAN_POOL_TAG, 570 | DEFAULT_SPB_BUFFER_SIZE, 571 | &SpbContext->ReadMemory, 572 | NULL); 573 | 574 | if (!NT_SUCCESS(status)) 575 | { 576 | ElanPrint( 577 | DEBUG_LEVEL_ERROR, 578 | DBG_IOCTL, 579 | "Error allocating default memory for Spb read - %!STATUS!", 580 | status); 581 | goto exit; 582 | } 583 | 584 | // 585 | // Allocate a waitlock to guard access to the default buffers 586 | // 587 | status = WdfWaitLockCreate( 588 | WDF_NO_OBJECT_ATTRIBUTES, 589 | &SpbContext->SpbLock); 590 | 591 | if (!NT_SUCCESS(status)) 592 | { 593 | ElanPrint( 594 | DEBUG_LEVEL_ERROR, 595 | DBG_IOCTL, 596 | "Error creating Spb Waitlock - %!STATUS!", 597 | status); 598 | goto exit; 599 | } 600 | 601 | exit: 602 | 603 | if (!NT_SUCCESS(status)) 604 | { 605 | SpbTargetDeinitialize(FxDevice, SpbContext); 606 | } 607 | 608 | return status; 609 | } -------------------------------------------------------------------------------- /crostouchpad/driver.h: -------------------------------------------------------------------------------- 1 | #if !defined(_ELAN_H_) 2 | #define _ELAN_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 "elantp.h" 22 | 23 | // 24 | // String definitions 25 | // 26 | 27 | #define DRIVERNAME "crostouchpad4.sys: " 28 | 29 | #define ELAN_POOL_TAG (ULONG) 'nalE' 30 | 31 | #define NTDEVICE_NAME_STRING L"\\Device\\ELAN0000" 32 | #define SYMBOLIC_NAME_STRING L"\\DosDevices\\ELAN0000" 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 _ELAN_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 | BOOLEAN TrackpadBooted; 219 | 220 | uint8_t Flags[5]; 221 | 222 | USHORT XValue[5]; 223 | 224 | USHORT YValue[5]; 225 | 226 | USHORT PValue[5]; 227 | 228 | USHORT Palm[5]; 229 | 230 | BOOLEAN BUTTONPRESSED; 231 | 232 | USHORT TIMEINT; 233 | 234 | LARGE_INTEGER LastTime; 235 | 236 | uint16_t max_x; 237 | uint16_t max_y; 238 | 239 | uint8_t max_x_hid[2]; 240 | uint8_t max_y_hid[2]; 241 | 242 | uint16_t phy_x; 243 | uint16_t phy_y; 244 | 245 | uint8_t phy_x_hid[2]; 246 | uint8_t phy_y_hid[2]; 247 | 248 | } ELAN_CONTEXT, *PELAN_CONTEXT; 249 | 250 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ELAN_CONTEXT, GetDeviceContext) 251 | 252 | // 253 | // Function definitions 254 | // 255 | 256 | DRIVER_INITIALIZE DriverEntry; 257 | 258 | EVT_WDF_DRIVER_UNLOAD ElanDriverUnload; 259 | 260 | EVT_WDF_DRIVER_DEVICE_ADD ElanEvtDeviceAdd; 261 | 262 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL ElanEvtInternalDeviceControl; 263 | 264 | NTSTATUS 265 | ElanGetHidDescriptor( 266 | IN WDFDEVICE Device, 267 | IN WDFREQUEST Request 268 | ); 269 | 270 | NTSTATUS 271 | ElanGetReportDescriptor( 272 | IN WDFDEVICE Device, 273 | IN WDFREQUEST Request 274 | ); 275 | 276 | NTSTATUS 277 | ElanGetDeviceAttributes( 278 | IN WDFREQUEST Request 279 | ); 280 | 281 | NTSTATUS 282 | ElanGetString( 283 | IN WDFREQUEST Request 284 | ); 285 | 286 | NTSTATUS 287 | ElanWriteReport( 288 | IN PELAN_CONTEXT DevContext, 289 | IN WDFREQUEST Request 290 | ); 291 | 292 | NTSTATUS 293 | ElanProcessVendorReport( 294 | IN PELAN_CONTEXT DevContext, 295 | IN PVOID ReportBuffer, 296 | IN ULONG ReportBufferLen, 297 | OUT size_t* BytesWritten 298 | ); 299 | 300 | NTSTATUS 301 | ElanReadReport( 302 | IN PELAN_CONTEXT DevContext, 303 | IN WDFREQUEST Request, 304 | OUT BOOLEAN* CompleteRequest 305 | ); 306 | 307 | NTSTATUS 308 | ElanSetFeature( 309 | IN PELAN_CONTEXT DevContext, 310 | IN WDFREQUEST Request, 311 | OUT BOOLEAN* CompleteRequest 312 | ); 313 | 314 | NTSTATUS 315 | ElanGetFeature( 316 | IN PELAN_CONTEXT DevContext, 317 | IN WDFREQUEST Request, 318 | OUT BOOLEAN* CompleteRequest 319 | ); 320 | 321 | PCHAR 322 | DbgHidInternalIoctlString( 323 | IN ULONG IoControlCode 324 | ); 325 | 326 | // 327 | // Helper macros 328 | // 329 | 330 | #define DEBUG_LEVEL_ERROR 1 331 | #define DEBUG_LEVEL_INFO 2 332 | #define DEBUG_LEVEL_VERBOSE 3 333 | 334 | #define DBG_INIT 1 335 | #define DBG_PNP 2 336 | #define DBG_IOCTL 4 337 | 338 | #if 0 339 | #define ElanPrint(dbglevel, dbgcatagory, fmt, ...) { \ 340 | if (ElanDebugLevel >= dbglevel && \ 341 | (ElanDebugCatagories && dbgcatagory)) \ 342 | { \ 343 | DbgPrint(DRIVERNAME); \ 344 | DbgPrint(fmt, __VA_ARGS__); \ 345 | } \ 346 | } 347 | #else 348 | #define ElanPrint(dbglevel, fmt, ...) { \ 349 | } 350 | #endif 351 | 352 | #endif 353 | -------------------------------------------------------------------------------- /crostouchpad/elan.c: -------------------------------------------------------------------------------- 1 | #define DESCRIPTOR_DEF 2 | #include "driver.h" 3 | 4 | #define bool int 5 | 6 | static ULONG ElanDebugLevel = 100; 7 | static ULONG ElanDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 8 | 9 | static bool deviceLoaded = false; 10 | 11 | NTSTATUS 12 | DriverEntry( 13 | __in PDRIVER_OBJECT DriverObject, 14 | __in PUNICODE_STRING RegistryPath 15 | ) 16 | { 17 | NTSTATUS status = STATUS_SUCCESS; 18 | WDF_DRIVER_CONFIG config; 19 | WDF_OBJECT_ATTRIBUTES attributes; 20 | 21 | ElanPrint(DEBUG_LEVEL_INFO, DBG_INIT, 22 | "Driver Entry\n"); 23 | 24 | WDF_DRIVER_CONFIG_INIT(&config, ElanEvtDeviceAdd); 25 | 26 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 27 | 28 | // 29 | // Create a framework driver object to represent our driver. 30 | // 31 | 32 | status = WdfDriverCreate(DriverObject, 33 | RegistryPath, 34 | &attributes, 35 | &config, 36 | WDF_NO_HANDLE 37 | ); 38 | 39 | if (!NT_SUCCESS(status)) 40 | { 41 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 42 | "WdfDriverCreate failed with status 0x%x\n", status); 43 | } 44 | 45 | return status; 46 | } 47 | 48 | NTSTATUS elan_i2c_read_cmd(PELAN_CONTEXT pDevice, UINT16 reg, uint8_t* val) { 49 | return SpbXferDataSynchronously(&pDevice->I2CContext, ®, sizeof(UINT16), val, ETP_I2C_INF_LENGTH); 50 | } 51 | 52 | NTSTATUS elan_i2c_read_block(PELAN_CONTEXT pDevice, UINT16 reg, PVOID val, ULONG len) { 53 | return SpbXferDataSynchronously(&pDevice->I2CContext, ®, sizeof(UINT16), val, len); 54 | } 55 | 56 | NTSTATUS elan_i2c_write_cmd(PELAN_CONTEXT pDevice, UINT16 reg, UINT16 cmd) { 57 | uint16_t buffer[] = { reg, cmd }; 58 | return SpbWriteDataSynchronously(&pDevice->I2CContext, buffer, sizeof(buffer)); 59 | } 60 | 61 | NTSTATUS elan_i2c_power_control(PELAN_CONTEXT pDevice, bool enable) 62 | { 63 | uint8_t val[2]; 64 | uint16_t reg; 65 | NTSTATUS status; 66 | 67 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_POWER_CMD, val); 68 | if (!NT_SUCCESS(status)) { 69 | return status; 70 | } 71 | 72 | reg = *((uint16_t *)val); 73 | if (enable) 74 | reg &= ~ETP_DISABLE_POWER; 75 | else 76 | reg |= ETP_DISABLE_POWER; 77 | 78 | return elan_i2c_write_cmd(pDevice, ETP_I2C_POWER_CMD, reg); 79 | } 80 | 81 | static bool elan_check_ASUS_special_fw(uint8_t prodid, uint8_t ic_type) 82 | { 83 | if (ic_type == 0x08 && prodid == 0x26) 84 | return true; 85 | if (ic_type != 0x0E) 86 | return false; 87 | 88 | switch (prodid) { 89 | case 0x05: 90 | case 0x06: 91 | case 0x07: 92 | case 0x09: 93 | case 0x13: 94 | return true; 95 | default: 96 | return false; 97 | } 98 | } 99 | 100 | NTSTATUS BOOTTRACKPAD( 101 | _In_ PELAN_CONTEXT pDevice 102 | ) 103 | { 104 | NTSTATUS status; 105 | 106 | status = elan_i2c_write_cmd(pDevice, ETP_I2C_STAND_CMD, ETP_I2C_RESET); 107 | if (!NT_SUCCESS(status)) { 108 | return status; 109 | } 110 | 111 | /* Wait for device to reset */ 112 | LARGE_INTEGER delay; 113 | delay.QuadPart = -100 * 10; 114 | KeDelayExecutionThread(KernelMode, FALSE, &delay); 115 | 116 | /* get reset achknowledgement 000 */ 117 | uint8_t val[256]; 118 | status = SpbReadDataSynchronously(&pDevice->I2CContext, val, ETP_I2C_INF_LENGTH); 119 | if (!NT_SUCCESS(status)) { 120 | return status; 121 | } 122 | 123 | status = elan_i2c_read_block(pDevice, ETP_I2C_DESC_CMD, val, ETP_I2C_DESC_LENGTH); 124 | if (!NT_SUCCESS(status)) { 125 | return status; 126 | } 127 | 128 | status = elan_i2c_read_block(pDevice, ETP_I2C_REPORT_DESC_CMD, val, ETP_I2C_REPORT_DESC_LENGTH); 129 | if (!NT_SUCCESS(status)) { 130 | return status; 131 | } 132 | 133 | 134 | status = elan_i2c_power_control(pDevice, 1); 135 | if (!NT_SUCCESS(status)) { 136 | return status; 137 | } 138 | 139 | uint8_t val2[3]; 140 | 141 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_UNIQUEID_CMD, val2); 142 | if (!NT_SUCCESS(status)) { 143 | return status; 144 | } 145 | uint8_t prodid = val2[0]; 146 | 147 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_SM_VERSION_CMD, val2); 148 | if (!NT_SUCCESS(status)) { 149 | return status; 150 | } 151 | //uint8_t smvers = val2[0]; 152 | uint8_t ictype = val2[1]; 153 | 154 | if (elan_check_ASUS_special_fw(prodid, ictype)) { //some Elan trackpads on certain ASUS laptops are buggy (linux commit 2de4fcc64685def3e586856a2dc636df44532395) 155 | status = elan_i2c_write_cmd(pDevice, ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP); 156 | if (!NT_SUCCESS(status)) { 157 | return status; 158 | } 159 | 160 | delay.QuadPart = -200 * 10; 161 | KeDelayExecutionThread(KernelMode, FALSE, &delay); //Wait for touchpad to wake up 162 | 163 | status = elan_i2c_write_cmd(pDevice, ETP_I2C_SET_CMD, ETP_ENABLE_ABS); 164 | if (!NT_SUCCESS(status)) { 165 | return status; 166 | } 167 | } 168 | else { 169 | status = elan_i2c_write_cmd(pDevice, ETP_I2C_SET_CMD, ETP_ENABLE_ABS); 170 | if (!NT_SUCCESS(status)) { 171 | return status; 172 | } 173 | 174 | status = elan_i2c_write_cmd(pDevice, ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP); 175 | if (!NT_SUCCESS(status)) { 176 | return status; 177 | } 178 | } 179 | 180 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_FW_VERSION_CMD, val2); 181 | if (!NT_SUCCESS(status)) { 182 | return status; 183 | } 184 | //uint8_t version = val2[0]; 185 | 186 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_FW_CHECKSUM_CMD, val2); 187 | if (!NT_SUCCESS(status)) { 188 | return status; 189 | } 190 | //uint16_t csum = *((uint16_t *)val2); 191 | 192 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_IAP_VERSION_CMD, val2); 193 | if (!NT_SUCCESS(status)) { 194 | return status; 195 | } 196 | //uint8_t iapversion = val2[0]; 197 | 198 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_PRESSURE_CMD, val2); 199 | if (!NT_SUCCESS(status)) { 200 | return status; 201 | } 202 | 203 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_MAX_X_AXIS_CMD, val2); 204 | if (!NT_SUCCESS(status)) { 205 | return status; 206 | } 207 | pDevice->max_x = (*((uint16_t *)val2)) & 0x0fff; 208 | 209 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_MAX_Y_AXIS_CMD, val2); 210 | if (!NT_SUCCESS(status)) { 211 | return status; 212 | } 213 | pDevice->max_y = (*((uint16_t *)val2)) & 0x0fff; 214 | 215 | status = elan_i2c_read_cmd(pDevice, ETP_I2C_RESOLUTION_CMD, val2); 216 | if (!NT_SUCCESS(status)) { 217 | return status; 218 | } 219 | 220 | uint8_t hw_res_x = val2[0]; 221 | uint8_t hw_res_y = val2[1]; 222 | 223 | uint16_t dots_per_mm_x = (hw_res_x * 10 + 790) * 10 / 254; 224 | uint16_t dots_per_mm_y = (hw_res_y * 10 + 790) * 10 / 254; 225 | 226 | pDevice->phy_x = pDevice->max_x / dots_per_mm_x; 227 | pDevice->phy_y = pDevice->max_y / dots_per_mm_y; 228 | 229 | uint16_t rmax_x = pDevice->max_x * 1; 230 | rmax_x /= 1; 231 | 232 | uint16_t rmax_y = pDevice->max_y * 1; 233 | rmax_y /= 1; 234 | 235 | uint16_t max_x[] = { rmax_x }; 236 | uint16_t max_y[] = { rmax_y }; 237 | 238 | uint8_t *max_x8bit = (uint8_t *)max_x; 239 | uint8_t *max_y8bit = (uint8_t *)max_y; 240 | 241 | pDevice->max_x_hid[0] = max_x8bit[0]; 242 | pDevice->max_x_hid[1] = max_x8bit[1]; 243 | 244 | pDevice->max_y_hid[0] = max_y8bit[0]; 245 | pDevice->max_y_hid[1] = max_y8bit[1]; 246 | 247 | //DbgPrint("[elantp] Max: %d x %d; X: 0x%x 0x%x Y: 0x%x 0x%x\n", rmax_x, rmax_y, max_x8bit[0], max_x8bit[1], max_y8bit[0], max_y8bit[1]); 248 | 249 | 250 | uint16_t phy_x[] = { pDevice->phy_x * 10 }; 251 | uint16_t phy_y[] = { pDevice->phy_y * 10 }; 252 | 253 | uint8_t *phy_x8bit = (uint8_t *)phy_x; 254 | uint8_t *phy_y8bit = (uint8_t *)phy_y; 255 | 256 | pDevice->phy_x_hid[0] = phy_x8bit[0]; 257 | pDevice->phy_x_hid[1] = phy_x8bit[1]; 258 | 259 | pDevice->phy_y_hid[0] = phy_y8bit[0]; 260 | pDevice->phy_y_hid[1] = phy_y8bit[1]; 261 | 262 | pDevice->TrackpadBooted = true; 263 | 264 | return status; 265 | } 266 | 267 | NTSTATUS 268 | OnPrepareHardware( 269 | _In_ WDFDEVICE FxDevice, 270 | _In_ WDFCMRESLIST FxResourcesRaw, 271 | _In_ WDFCMRESLIST FxResourcesTranslated 272 | ) 273 | /*++ 274 | 275 | Routine Description: 276 | 277 | This routine caches the SPB resource connection ID. 278 | 279 | Arguments: 280 | 281 | FxDevice - a handle to the framework device object 282 | FxResourcesRaw - list of translated hardware resources that 283 | the PnP manager has assigned to the device 284 | FxResourcesTranslated - list of raw hardware resources that 285 | the PnP manager has assigned to the device 286 | 287 | Return Value: 288 | 289 | Status 290 | 291 | --*/ 292 | { 293 | PELAN_CONTEXT pDevice = GetDeviceContext(FxDevice); 294 | BOOLEAN fSpbResourceFound = FALSE; 295 | NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; 296 | 297 | UNREFERENCED_PARAMETER(FxResourcesRaw); 298 | 299 | // 300 | // Parse the peripheral's resources. 301 | // 302 | 303 | ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); 304 | 305 | for (ULONG i = 0; i < resourceCount; i++) 306 | { 307 | PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 308 | UCHAR Class; 309 | UCHAR Type; 310 | 311 | pDescriptor = WdfCmResourceListGetDescriptor( 312 | FxResourcesTranslated, i); 313 | 314 | switch (pDescriptor->Type) 315 | { 316 | case CmResourceTypeConnection: 317 | // 318 | // Look for I2C or SPI resource and save connection ID. 319 | // 320 | Class = pDescriptor->u.Connection.Class; 321 | Type = pDescriptor->u.Connection.Type; 322 | if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && 323 | Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) 324 | { 325 | if (fSpbResourceFound == FALSE) 326 | { 327 | status = STATUS_SUCCESS; 328 | pDevice->I2CContext.I2cResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; 329 | pDevice->I2CContext.I2cResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; 330 | fSpbResourceFound = TRUE; 331 | } 332 | else 333 | { 334 | } 335 | } 336 | break; 337 | default: 338 | // 339 | // Ignoring all other resource types. 340 | // 341 | break; 342 | } 343 | } 344 | 345 | // 346 | // An SPB resource is required. 347 | // 348 | 349 | if (fSpbResourceFound == FALSE) 350 | { 351 | status = STATUS_NOT_FOUND; 352 | } 353 | 354 | status = SpbTargetInitialize(FxDevice, &pDevice->I2CContext); 355 | if (!NT_SUCCESS(status)) 356 | { 357 | return status; 358 | } 359 | 360 | return status; 361 | } 362 | 363 | NTSTATUS 364 | OnReleaseHardware( 365 | _In_ WDFDEVICE FxDevice, 366 | _In_ WDFCMRESLIST FxResourcesTranslated 367 | ) 368 | /*++ 369 | 370 | Routine Description: 371 | 372 | Arguments: 373 | 374 | FxDevice - a handle to the framework device object 375 | FxResourcesTranslated - list of raw hardware resources that 376 | the PnP manager has assigned to the device 377 | 378 | Return Value: 379 | 380 | Status 381 | 382 | --*/ 383 | { 384 | PELAN_CONTEXT pDevice = GetDeviceContext(FxDevice); 385 | NTSTATUS status = STATUS_SUCCESS; 386 | 387 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 388 | 389 | SpbTargetDeinitialize(FxDevice, &pDevice->I2CContext); 390 | 391 | return status; 392 | } 393 | 394 | NTSTATUS 395 | OnD0Entry( 396 | _In_ WDFDEVICE FxDevice, 397 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 398 | ) 399 | /*++ 400 | 401 | Routine Description: 402 | 403 | This routine allocates objects needed by the driver. 404 | 405 | Arguments: 406 | 407 | FxDevice - a handle to the framework device object 408 | FxPreviousState - previous power state 409 | 410 | Return Value: 411 | 412 | Status 413 | 414 | --*/ 415 | { 416 | UNREFERENCED_PARAMETER(FxPreviousState); 417 | 418 | PELAN_CONTEXT pDevice = GetDeviceContext(FxDevice); 419 | NTSTATUS status; 420 | 421 | for (int i = 0; i < 5; i++){ 422 | pDevice->Flags[i] = 0; 423 | } 424 | 425 | status = BOOTTRACKPAD(pDevice); 426 | if (!NT_SUCCESS(status)) 427 | { 428 | return status; 429 | } 430 | 431 | pDevice->ConnectInterrupt = true; 432 | pDevice->RegsSet = false; 433 | 434 | return status; 435 | } 436 | 437 | NTSTATUS 438 | OnD0Exit( 439 | _In_ WDFDEVICE FxDevice, 440 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 441 | ) 442 | /*++ 443 | 444 | Routine Description: 445 | 446 | This routine destroys objects needed by the driver. 447 | 448 | Arguments: 449 | 450 | FxDevice - a handle to the framework device object 451 | FxPreviousState - previous power state 452 | 453 | Return Value: 454 | 455 | Status 456 | 457 | --*/ 458 | { 459 | UNREFERENCED_PARAMETER(FxPreviousState); 460 | 461 | NTSTATUS status; 462 | 463 | PELAN_CONTEXT pDevice = GetDeviceContext(FxDevice); 464 | 465 | status = elan_i2c_power_control(pDevice, 0); 466 | 467 | pDevice->ConnectInterrupt = false; 468 | 469 | return status; 470 | } 471 | 472 | BOOLEAN OnInterruptIsr( 473 | WDFINTERRUPT Interrupt, 474 | ULONG MessageID){ 475 | UNREFERENCED_PARAMETER(MessageID); 476 | 477 | WDFDEVICE Device = WdfInterruptGetDevice(Interrupt); 478 | PELAN_CONTEXT pDevice = GetDeviceContext(Device); 479 | 480 | if (!pDevice->ConnectInterrupt) 481 | return false; 482 | if (!pDevice->TrackpadBooted) 483 | return false; 484 | 485 | LARGE_INTEGER CurrentTime; 486 | 487 | KeQuerySystemTime(&CurrentTime); 488 | 489 | LARGE_INTEGER DIFF; 490 | 491 | DIFF.QuadPart = 0; 492 | 493 | if (pDevice->LastTime.QuadPart != 0) 494 | DIFF.QuadPart = (CurrentTime.QuadPart - pDevice->LastTime.QuadPart) / 1000; 495 | 496 | uint8_t touchpadReport[ETP_MAX_REPORT_LEN]; 497 | if (!NT_SUCCESS(SpbReadDataSynchronously(&pDevice->I2CContext, &touchpadReport, sizeof(touchpadReport)))) { 498 | return false; 499 | } 500 | 501 | if (touchpadReport[0] == 0xff) { 502 | return false; 503 | } 504 | 505 | struct _ELAN_MULTITOUCH_REPORT report; 506 | report.ReportID = REPORTID_MTOUCH; 507 | 508 | int x[5]; 509 | int y[5]; 510 | int p[5]; 511 | int palm[5]; 512 | for (int i = 0; i < 5; i++) { 513 | x[i] = -1; 514 | y[i] = -1; 515 | p[i] = -1; 516 | palm[i] = 0; 517 | } 518 | uint8_t *finger_data = &touchpadReport[ETP_FINGER_DATA_OFFSET]; 519 | uint8_t tp_info = touchpadReport[ETP_TOUCH_INFO_OFFSET]; 520 | uint8_t hover_info = touchpadReport[ETP_HOVER_INFO_OFFSET]; 521 | bool contact_valid, hover_event; 522 | 523 | hover_event = hover_info & 0x40; 524 | for (int i = 0; i < ETP_MAX_FINGERS; i++) { 525 | contact_valid = tp_info & (1U << (3 + i)); 526 | unsigned int pos_x, pos_y; 527 | unsigned int pressure, mk_x, mk_y; 528 | unsigned int area_x, area_y, major, minor; 529 | unsigned int scaled_pressure; 530 | 531 | if (contact_valid) { 532 | pos_x = ((finger_data[0] & 0xf0) << 4) | 533 | finger_data[1]; 534 | pos_y = ((finger_data[0] & 0x0f) << 8) | 535 | finger_data[2]; 536 | 537 | mk_x = (finger_data[3] & 0x0f); 538 | mk_y = (finger_data[3] >> 4); 539 | pressure = finger_data[4]; 540 | 541 | pos_y = pDevice->max_y - pos_y; 542 | 543 | pos_x *= 1; 544 | pos_x /= 1; 545 | 546 | pos_y *= 1; 547 | pos_y /= 1; 548 | 549 | /* 550 | * To avoid treating large finger as palm, let's reduce the 551 | * width x and y per trace. 552 | */ 553 | area_x = mk_x; 554 | area_y = mk_y; 555 | 556 | major = max(area_x, area_y); 557 | minor = min(area_x, area_y); 558 | 559 | if (minor >= 7) { 560 | palm[i] = 1; 561 | } 562 | 563 | scaled_pressure = pressure; 564 | 565 | if (scaled_pressure > ETP_MAX_PRESSURE) 566 | scaled_pressure = ETP_MAX_PRESSURE; 567 | x[i] = pos_x; 568 | y[i] = pos_y; 569 | p[i] = scaled_pressure; 570 | } 571 | else { 572 | } 573 | 574 | if (contact_valid) { 575 | finger_data += ETP_FINGER_DATA_LEN; 576 | } 577 | } 578 | 579 | for (int i = 0; i < 5; i++) { 580 | if (pDevice->Flags[i] == MXT_T9_DETECT && x[i] == -1) { 581 | pDevice->Flags[i] = MXT_T9_RELEASE; 582 | } 583 | if (x[i] != -1) { 584 | pDevice->Flags[i] = MXT_T9_DETECT; 585 | 586 | pDevice->XValue[i] = (USHORT)x[i]; 587 | pDevice->YValue[i] = (USHORT)y[i]; 588 | pDevice->Palm[i] = (USHORT)palm[i]; 589 | pDevice->PValue[i] = (USHORT)p[i]; 590 | 591 | //DbgPrint("[elantp] %d: %dx%d", i, x[i], y[i]); 592 | } 593 | } 594 | 595 | pDevice->BUTTONPRESSED = (tp_info & 0x01); 596 | 597 | pDevice->TIMEINT += (USHORT)DIFF.QuadPart; 598 | 599 | pDevice->LastTime = CurrentTime; 600 | 601 | BYTE count = 0, i = 0; 602 | while (count < 5 && i < 5) { 603 | if (pDevice->Flags[i] != 0) { 604 | report.Touch[count].ContactID = i; 605 | 606 | report.Touch[count].XValue = pDevice->XValue[i]; 607 | report.Touch[count].YValue = pDevice->YValue[i]; 608 | report.Touch[count].Pressure = pDevice->PValue[i]; 609 | 610 | //DbgPrint("[elantp] %d 2: %dx%d", i, report.Touch[count].XValue, report.Touch[count].YValue); 611 | 612 | uint8_t flags = pDevice->Flags[i]; 613 | if (flags & MXT_T9_DETECT) { 614 | if (pDevice->Palm[i]) 615 | report.Touch[count].Status = MULTI_TIPSWITCH_BIT; 616 | else 617 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT | MULTI_TIPSWITCH_BIT; 618 | } 619 | else if (flags & MXT_T9_PRESS) { 620 | if (pDevice->Palm[i]) 621 | report.Touch[count].Status = MULTI_TIPSWITCH_BIT; 622 | else 623 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT | MULTI_TIPSWITCH_BIT; 624 | } 625 | else if (flags & MXT_T9_RELEASE) { 626 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT; 627 | pDevice->Flags[i] = 0; 628 | } 629 | else 630 | report.Touch[count].Status = 0; 631 | 632 | count++; 633 | } 634 | i++; 635 | } 636 | 637 | report.ScanTime = pDevice->TIMEINT; 638 | report.IsDepressed = pDevice->BUTTONPRESSED; 639 | 640 | report.ContactCount = count; 641 | 642 | size_t bytesWritten; 643 | ElanProcessVendorReport(pDevice, &report, sizeof(report), &bytesWritten); 644 | 645 | pDevice->RegsSet = true; 646 | return true; 647 | } 648 | 649 | NTSTATUS 650 | ElanEvtDeviceAdd( 651 | IN WDFDRIVER Driver, 652 | IN PWDFDEVICE_INIT DeviceInit 653 | ) 654 | { 655 | NTSTATUS status = STATUS_SUCCESS; 656 | WDF_IO_QUEUE_CONFIG queueConfig; 657 | WDF_OBJECT_ATTRIBUTES attributes; 658 | WDFDEVICE device; 659 | WDF_INTERRUPT_CONFIG interruptConfig; 660 | WDFQUEUE queue; 661 | PELAN_CONTEXT devContext; 662 | 663 | UNREFERENCED_PARAMETER(Driver); 664 | 665 | PAGED_CODE(); 666 | 667 | ElanPrint(DEBUG_LEVEL_INFO, DBG_PNP, 668 | "ElanEvtDeviceAdd called\n"); 669 | 670 | // 671 | // Tell framework this is a filter driver. Filter drivers by default are 672 | // not power policy owners. This works well for this driver because 673 | // HIDclass driver is the power policy owner for HID minidrivers. 674 | // 675 | 676 | WdfFdoInitSetFilter(DeviceInit); 677 | 678 | { 679 | WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; 680 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); 681 | 682 | pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; 683 | pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; 684 | pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; 685 | pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; 686 | 687 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); 688 | } 689 | 690 | // 691 | // Setup the device context 692 | // 693 | 694 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, ELAN_CONTEXT); 695 | 696 | // 697 | // Create a framework device object.This call will in turn create 698 | // a WDM device object, attach to the lower stack, and set the 699 | // appropriate flags and attributes. 700 | // 701 | 702 | status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 703 | 704 | if (!NT_SUCCESS(status)) 705 | { 706 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 707 | "WdfDeviceCreate failed with status code 0x%x\n", status); 708 | 709 | return status; 710 | } 711 | 712 | { 713 | WDF_DEVICE_STATE deviceState; 714 | WDF_DEVICE_STATE_INIT(&deviceState); 715 | 716 | deviceState.NotDisableable = WdfFalse; 717 | WdfDeviceSetDeviceState(device, &deviceState); 718 | } 719 | 720 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); 721 | 722 | queueConfig.EvtIoInternalDeviceControl = ElanEvtInternalDeviceControl; 723 | 724 | status = WdfIoQueueCreate(device, 725 | &queueConfig, 726 | WDF_NO_OBJECT_ATTRIBUTES, 727 | &queue 728 | ); 729 | 730 | if (!NT_SUCCESS(status)) 731 | { 732 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 733 | "WdfIoQueueCreate failed 0x%x\n", status); 734 | 735 | return status; 736 | } 737 | 738 | // 739 | // Create manual I/O queue to take care of hid report read requests 740 | // 741 | 742 | devContext = GetDeviceContext(device); 743 | 744 | devContext->FxDevice = device; 745 | devContext->TrackpadBooted = false; 746 | 747 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 748 | 749 | queueConfig.PowerManaged = WdfFalse; 750 | 751 | status = WdfIoQueueCreate(device, 752 | &queueConfig, 753 | WDF_NO_OBJECT_ATTRIBUTES, 754 | &devContext->ReportQueue 755 | ); 756 | 757 | if (!NT_SUCCESS(status)) 758 | { 759 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 760 | "WdfIoQueueCreate failed 0x%x\n", status); 761 | 762 | return status; 763 | } 764 | 765 | // 766 | // Create an interrupt object for hardware notifications 767 | // 768 | WDF_INTERRUPT_CONFIG_INIT( 769 | &interruptConfig, 770 | OnInterruptIsr, 771 | NULL); 772 | interruptConfig.PassiveHandling = TRUE; 773 | 774 | status = WdfInterruptCreate( 775 | device, 776 | &interruptConfig, 777 | WDF_NO_OBJECT_ATTRIBUTES, 778 | &devContext->Interrupt); 779 | 780 | if (!NT_SUCCESS(status)) 781 | { 782 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 783 | "Error creating WDF interrupt object - %!STATUS!", 784 | status); 785 | 786 | return status; 787 | } 788 | 789 | // 790 | // Initialize DeviceMode 791 | // 792 | 793 | devContext->DeviceMode = DEVICE_MODE_MOUSE; 794 | 795 | return status; 796 | } 797 | 798 | VOID 799 | ElanEvtInternalDeviceControl( 800 | IN WDFQUEUE Queue, 801 | IN WDFREQUEST Request, 802 | IN size_t OutputBufferLength, 803 | IN size_t InputBufferLength, 804 | IN ULONG IoControlCode 805 | ) 806 | { 807 | NTSTATUS status = STATUS_SUCCESS; 808 | WDFDEVICE device; 809 | PELAN_CONTEXT devContext; 810 | BOOLEAN completeRequest = TRUE; 811 | 812 | UNREFERENCED_PARAMETER(OutputBufferLength); 813 | UNREFERENCED_PARAMETER(InputBufferLength); 814 | 815 | device = WdfIoQueueGetDevice(Queue); 816 | devContext = GetDeviceContext(device); 817 | 818 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 819 | "%s, Queue:0x%p, Request:0x%p\n", 820 | DbgHidInternalIoctlString(IoControlCode), 821 | Queue, 822 | Request 823 | ); 824 | 825 | // 826 | // Please note that HIDCLASS provides the buffer in the Irp->UserBuffer 827 | // field irrespective of the ioctl buffer type. However, framework is very 828 | // strict about type checking. You cannot get Irp->UserBuffer by using 829 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 830 | // internal ioctl. So depending on the ioctl code, we will either 831 | // use retreive function or escape to WDM to get the UserBuffer. 832 | // 833 | 834 | switch (IoControlCode) 835 | { 836 | 837 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 838 | // 839 | // Retrieves the device's HID descriptor. 840 | // 841 | status = ElanGetHidDescriptor(device, Request); 842 | break; 843 | 844 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 845 | // 846 | //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. 847 | // 848 | status = ElanGetDeviceAttributes(Request); 849 | break; 850 | 851 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 852 | // 853 | //Obtains the report descriptor for the HID device. 854 | // 855 | status = ElanGetReportDescriptor(device, Request); 856 | break; 857 | 858 | case IOCTL_HID_GET_STRING: 859 | // 860 | // Requests that the HID minidriver retrieve a human-readable string 861 | // for either the manufacturer ID, the product ID, or the serial number 862 | // from the string descriptor of the device. The minidriver must send 863 | // a Get String Descriptor request to the device, in order to retrieve 864 | // the string descriptor, then it must extract the string at the 865 | // appropriate index from the string descriptor and return it in the 866 | // output buffer indicated by the IRP. Before sending the Get String 867 | // Descriptor request, the minidriver must retrieve the appropriate 868 | // index for the manufacturer ID, the product ID or the serial number 869 | // from the device extension of a top level collection associated with 870 | // the device. 871 | // 872 | status = ElanGetString(Request); 873 | break; 874 | 875 | case IOCTL_HID_WRITE_REPORT: 876 | case IOCTL_HID_SET_OUTPUT_REPORT: 877 | // 878 | //Transmits a class driver-supplied report to the device. 879 | // 880 | status = ElanWriteReport(devContext, Request); 881 | break; 882 | 883 | case IOCTL_HID_READ_REPORT: 884 | case IOCTL_HID_GET_INPUT_REPORT: 885 | // 886 | // Returns a report from the device into a class driver-supplied buffer. 887 | // 888 | status = ElanReadReport(devContext, Request, &completeRequest); 889 | break; 890 | 891 | case IOCTL_HID_SET_FEATURE: 892 | // 893 | // This sends a HID class feature report to a top-level collection of 894 | // a HID class device. 895 | // 896 | status = ElanSetFeature(devContext, Request, &completeRequest); 897 | break; 898 | 899 | case IOCTL_HID_GET_FEATURE: 900 | // 901 | // returns a feature report associated with a top-level collection 902 | // 903 | status = ElanGetFeature(devContext, Request, &completeRequest); 904 | break; 905 | 906 | case IOCTL_HID_ACTIVATE_DEVICE: 907 | // 908 | // Makes the device ready for I/O operations. 909 | // 910 | case IOCTL_HID_DEACTIVATE_DEVICE: 911 | // 912 | // Causes the device to cease operations and terminate all outstanding 913 | // I/O requests. 914 | // 915 | default: 916 | status = STATUS_NOT_SUPPORTED; 917 | break; 918 | } 919 | 920 | if (completeRequest) 921 | { 922 | WdfRequestComplete(Request, status); 923 | 924 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 925 | "%s completed, Queue:0x%p, Request:0x%p\n", 926 | DbgHidInternalIoctlString(IoControlCode), 927 | Queue, 928 | Request 929 | ); 930 | } 931 | else 932 | { 933 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 934 | "%s deferred, Queue:0x%p, Request:0x%p\n", 935 | DbgHidInternalIoctlString(IoControlCode), 936 | Queue, 937 | Request 938 | ); 939 | } 940 | 941 | return; 942 | } 943 | 944 | NTSTATUS 945 | ElanGetHidDescriptor( 946 | IN WDFDEVICE Device, 947 | IN WDFREQUEST Request 948 | ) 949 | { 950 | NTSTATUS status = STATUS_SUCCESS; 951 | size_t bytesToCopy = 0; 952 | WDFMEMORY memory; 953 | 954 | UNREFERENCED_PARAMETER(Device); 955 | 956 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 957 | "ElanGetHidDescriptor Entry\n"); 958 | 959 | // 960 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 961 | // will correctly retrieve buffer from Irp->UserBuffer. 962 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 963 | // field irrespective of the ioctl buffer type. However, framework is very 964 | // strict about type checking. You cannot get Irp->UserBuffer by using 965 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 966 | // internal ioctl. 967 | // 968 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 969 | 970 | if (!NT_SUCCESS(status)) 971 | { 972 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 973 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 974 | 975 | return status; 976 | } 977 | 978 | // 979 | // Use hardcoded "HID Descriptor" 980 | // 981 | bytesToCopy = DefaultHidDescriptor.bLength; 982 | 983 | if (bytesToCopy == 0) 984 | { 985 | status = STATUS_INVALID_DEVICE_STATE; 986 | 987 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 988 | "DefaultHidDescriptor is zero, 0x%x\n", status); 989 | 990 | return status; 991 | } 992 | 993 | status = WdfMemoryCopyFromBuffer(memory, 994 | 0, // Offset 995 | (PVOID)&DefaultHidDescriptor, 996 | bytesToCopy); 997 | 998 | if (!NT_SUCCESS(status)) 999 | { 1000 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1001 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 1002 | 1003 | return status; 1004 | } 1005 | 1006 | // 1007 | // Report how many bytes were copied 1008 | // 1009 | WdfRequestSetInformation(Request, bytesToCopy); 1010 | 1011 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1012 | "ElanGetHidDescriptor Exit = 0x%x\n", status); 1013 | 1014 | return status; 1015 | } 1016 | 1017 | NTSTATUS 1018 | ElanGetReportDescriptor( 1019 | IN WDFDEVICE Device, 1020 | IN WDFREQUEST Request 1021 | ) 1022 | { 1023 | NTSTATUS status = STATUS_SUCCESS; 1024 | ULONG_PTR bytesToCopy; 1025 | WDFMEMORY memory; 1026 | 1027 | UNREFERENCED_PARAMETER(Device); 1028 | 1029 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1030 | "ElanGetReportDescriptor Entry\n"); 1031 | 1032 | PELAN_CONTEXT devContext = GetDeviceContext(Device); 1033 | 1034 | #define MT_TOUCH_COLLECTION \ 1035 | MT_TOUCH_COLLECTION0 \ 1036 | 0x26, devContext->max_x_hid[0], devContext->max_x_hid[1], /* LOGICAL_MAXIMUM (WIDTH) */ \ 1037 | 0x46, devContext->phy_x_hid[0], devContext->phy_x_hid[1], /* PHYSICAL_MAXIMUM (WIDTH) */ \ 1038 | MT_TOUCH_COLLECTION1 \ 1039 | 0x26, devContext->max_y_hid[0], devContext->max_y_hid[1], /* LOGICAL_MAXIMUM (HEIGHT) */ \ 1040 | 0x46, devContext->phy_y_hid[0], devContext->phy_y_hid[1], /* PHYSICAL_MAXIMUM (HEIGHT) */ \ 1041 | MT_TOUCH_COLLECTION2 1042 | 1043 | HID_REPORT_DESCRIPTOR ReportDescriptor[] = { 1044 | // 1045 | // Multitouch report starts here 1046 | // 1047 | //TOUCH PAD input TLC 1048 | 0x05, 0x0d, // USAGE_PAGE (Digitizers) 1049 | 0x09, 0x05, // USAGE (Touch Pad) 1050 | 0xa1, 0x01, // COLLECTION (Application) 1051 | 0x85, REPORTID_MTOUCH, // REPORT_ID (Touch pad) 1052 | 0x09, 0x22, // USAGE (Finger) 1053 | MT_TOUCH_COLLECTION 1054 | MT_TOUCH_COLLECTION 1055 | MT_TOUCH_COLLECTION 1056 | MT_TOUCH_COLLECTION 1057 | MT_TOUCH_COLLECTION 1058 | USAGE_PAGES 1059 | }; 1060 | 1061 | // 1062 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 1063 | // will correctly retrieve buffer from Irp->UserBuffer. 1064 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 1065 | // field irrespective of the ioctl buffer type. However, framework is very 1066 | // strict about type checking. You cannot get Irp->UserBuffer by using 1067 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 1068 | // internal ioctl. 1069 | // 1070 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 1071 | if (!NT_SUCCESS(status)) 1072 | { 1073 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1074 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 1075 | 1076 | return status; 1077 | } 1078 | 1079 | // 1080 | // Use hardcoded Report descriptor 1081 | // 1082 | bytesToCopy = DefaultHidDescriptor.DescriptorList[0].wReportLength; 1083 | 1084 | if (bytesToCopy == 0) 1085 | { 1086 | status = STATUS_INVALID_DEVICE_STATE; 1087 | 1088 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1089 | "DefaultHidDescriptor's reportLength is zero, 0x%x\n", status); 1090 | 1091 | return status; 1092 | } 1093 | 1094 | status = WdfMemoryCopyFromBuffer(memory, 1095 | 0, 1096 | (PVOID)ReportDescriptor, 1097 | bytesToCopy); 1098 | if (!NT_SUCCESS(status)) 1099 | { 1100 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1101 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 1102 | 1103 | return status; 1104 | } 1105 | 1106 | // 1107 | // Report how many bytes were copied 1108 | // 1109 | WdfRequestSetInformation(Request, bytesToCopy); 1110 | 1111 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1112 | "ElanGetReportDescriptor Exit = 0x%x\n", status); 1113 | 1114 | return status; 1115 | } 1116 | 1117 | 1118 | NTSTATUS 1119 | ElanGetDeviceAttributes( 1120 | IN WDFREQUEST Request 1121 | ) 1122 | { 1123 | NTSTATUS status = STATUS_SUCCESS; 1124 | PHID_DEVICE_ATTRIBUTES deviceAttributes = NULL; 1125 | 1126 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1127 | "ElanGetDeviceAttributes Entry\n"); 1128 | 1129 | // 1130 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 1131 | // will correctly retrieve buffer from Irp->UserBuffer. 1132 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 1133 | // field irrespective of the ioctl buffer type. However, framework is very 1134 | // strict about type checking. You cannot get Irp->UserBuffer by using 1135 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 1136 | // internal ioctl. 1137 | // 1138 | status = WdfRequestRetrieveOutputBuffer(Request, 1139 | sizeof(HID_DEVICE_ATTRIBUTES), 1140 | &deviceAttributes, 1141 | NULL); 1142 | if (!NT_SUCCESS(status)) 1143 | { 1144 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1145 | "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); 1146 | 1147 | return status; 1148 | } 1149 | 1150 | // 1151 | // Set USB device descriptor 1152 | // 1153 | 1154 | deviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES); 1155 | deviceAttributes->VendorID = ELAN_VID; 1156 | deviceAttributes->ProductID = ELAN_PID; 1157 | deviceAttributes->VersionNumber = ELAN_VERSION; 1158 | 1159 | // 1160 | // Report how many bytes were copied 1161 | // 1162 | WdfRequestSetInformation(Request, sizeof(HID_DEVICE_ATTRIBUTES)); 1163 | 1164 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1165 | "ElanGetDeviceAttributes Exit = 0x%x\n", status); 1166 | 1167 | return status; 1168 | } 1169 | 1170 | NTSTATUS 1171 | ElanGetString( 1172 | IN WDFREQUEST Request 1173 | ) 1174 | { 1175 | 1176 | NTSTATUS status = STATUS_SUCCESS; 1177 | PWSTR pwstrID; 1178 | size_t lenID; 1179 | WDF_REQUEST_PARAMETERS params; 1180 | void *pStringBuffer = NULL; 1181 | 1182 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1183 | "ElanGetString Entry\n"); 1184 | 1185 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1186 | WdfRequestGetParameters(Request, ¶ms); 1187 | 1188 | switch ((ULONG_PTR)params.Parameters.DeviceIoControl.Type3InputBuffer & 0xFFFF) 1189 | { 1190 | case HID_STRING_ID_IMANUFACTURER: 1191 | pwstrID = L"Elan.\0"; 1192 | break; 1193 | 1194 | case HID_STRING_ID_IPRODUCT: 1195 | pwstrID = L"MaxTouch Touch Screen\0"; 1196 | break; 1197 | 1198 | case HID_STRING_ID_ISERIALNUMBER: 1199 | pwstrID = L"123123123\0"; 1200 | break; 1201 | 1202 | default: 1203 | pwstrID = NULL; 1204 | break; 1205 | } 1206 | 1207 | lenID = pwstrID ? wcslen(pwstrID)*sizeof(WCHAR) + sizeof(UNICODE_NULL) : 0; 1208 | 1209 | if (pwstrID == NULL) 1210 | { 1211 | 1212 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1213 | "ElanGetString Invalid request type\n"); 1214 | 1215 | status = STATUS_INVALID_PARAMETER; 1216 | 1217 | return status; 1218 | } 1219 | 1220 | status = WdfRequestRetrieveOutputBuffer(Request, 1221 | lenID, 1222 | &pStringBuffer, 1223 | &lenID); 1224 | 1225 | if (!NT_SUCCESS(status)) 1226 | { 1227 | 1228 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1229 | "ElanGetString WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1230 | 1231 | return status; 1232 | } 1233 | 1234 | RtlCopyMemory(pStringBuffer, pwstrID, lenID); 1235 | 1236 | WdfRequestSetInformation(Request, lenID); 1237 | 1238 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1239 | "ElanGetString Exit = 0x%x\n", status); 1240 | 1241 | return status; 1242 | } 1243 | 1244 | NTSTATUS 1245 | ElanWriteReport( 1246 | IN PELAN_CONTEXT DevContext, 1247 | IN WDFREQUEST Request 1248 | ) 1249 | { 1250 | UNREFERENCED_PARAMETER(DevContext); 1251 | 1252 | NTSTATUS status = STATUS_SUCCESS; 1253 | WDF_REQUEST_PARAMETERS params; 1254 | PHID_XFER_PACKET transferPacket = NULL; 1255 | 1256 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1257 | "ElanWriteReport Entry\n"); 1258 | 1259 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1260 | WdfRequestGetParameters(Request, ¶ms); 1261 | 1262 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1263 | { 1264 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1265 | "ElanWriteReport Xfer packet too small\n"); 1266 | 1267 | status = STATUS_BUFFER_TOO_SMALL; 1268 | } 1269 | else 1270 | { 1271 | 1272 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1273 | 1274 | if (transferPacket == NULL) 1275 | { 1276 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1277 | "ElanWriteReport No xfer packet\n"); 1278 | 1279 | status = STATUS_INVALID_DEVICE_REQUEST; 1280 | } 1281 | else 1282 | { 1283 | // 1284 | // switch on the report id 1285 | // 1286 | 1287 | switch (transferPacket->reportId) 1288 | { 1289 | default: 1290 | 1291 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1292 | "ElanWriteReport Unhandled report type %d\n", transferPacket->reportId); 1293 | 1294 | status = STATUS_INVALID_PARAMETER; 1295 | 1296 | break; 1297 | } 1298 | } 1299 | } 1300 | 1301 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1302 | "ElanWriteReport Exit = 0x%x\n", status); 1303 | 1304 | return status; 1305 | 1306 | } 1307 | 1308 | NTSTATUS 1309 | ElanProcessVendorReport( 1310 | IN PELAN_CONTEXT DevContext, 1311 | IN PVOID ReportBuffer, 1312 | IN ULONG ReportBufferLen, 1313 | OUT size_t* BytesWritten 1314 | ) 1315 | { 1316 | NTSTATUS status = STATUS_SUCCESS; 1317 | WDFREQUEST reqRead; 1318 | PVOID pReadReport = NULL; 1319 | size_t bytesReturned = 0; 1320 | 1321 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1322 | "ElanProcessVendorReport Entry\n"); 1323 | 1324 | status = WdfIoQueueRetrieveNextRequest(DevContext->ReportQueue, 1325 | &reqRead); 1326 | 1327 | if (NT_SUCCESS(status)) 1328 | { 1329 | status = WdfRequestRetrieveOutputBuffer(reqRead, 1330 | ReportBufferLen, 1331 | &pReadReport, 1332 | &bytesReturned); 1333 | 1334 | if (NT_SUCCESS(status)) 1335 | { 1336 | // 1337 | // Copy ReportBuffer into read request 1338 | // 1339 | 1340 | if (bytesReturned > ReportBufferLen) 1341 | { 1342 | bytesReturned = ReportBufferLen; 1343 | } 1344 | 1345 | RtlCopyMemory(pReadReport, 1346 | ReportBuffer, 1347 | bytesReturned); 1348 | 1349 | // 1350 | // Complete read with the number of bytes returned as info 1351 | // 1352 | 1353 | WdfRequestCompleteWithInformation(reqRead, 1354 | status, 1355 | bytesReturned); 1356 | 1357 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1358 | "ElanProcessVendorReport %d bytes returned\n", bytesReturned); 1359 | 1360 | // 1361 | // Return the number of bytes written for the write request completion 1362 | // 1363 | 1364 | *BytesWritten = bytesReturned; 1365 | 1366 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1367 | "%s completed, Queue:0x%p, Request:0x%p\n", 1368 | DbgHidInternalIoctlString(IOCTL_HID_READ_REPORT), 1369 | DevContext->ReportQueue, 1370 | reqRead); 1371 | } 1372 | else 1373 | { 1374 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1375 | "WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1376 | } 1377 | } 1378 | else 1379 | { 1380 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1381 | "WdfIoQueueRetrieveNextRequest failed Status 0x%x\n", status); 1382 | } 1383 | 1384 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1385 | "ElanProcessVendorReport Exit = 0x%x\n", status); 1386 | 1387 | return status; 1388 | } 1389 | 1390 | NTSTATUS 1391 | ElanReadReport( 1392 | IN PELAN_CONTEXT DevContext, 1393 | IN WDFREQUEST Request, 1394 | OUT BOOLEAN* CompleteRequest 1395 | ) 1396 | { 1397 | NTSTATUS status = STATUS_SUCCESS; 1398 | 1399 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1400 | "ElanReadReport Entry\n"); 1401 | 1402 | // 1403 | // Forward this read request to our manual queue 1404 | // (in other words, we are going to defer this request 1405 | // until we have a corresponding write request to 1406 | // match it with) 1407 | // 1408 | 1409 | status = WdfRequestForwardToIoQueue(Request, DevContext->ReportQueue); 1410 | 1411 | if (!NT_SUCCESS(status)) 1412 | { 1413 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1414 | "WdfRequestForwardToIoQueue failed Status 0x%x\n", status); 1415 | } 1416 | else 1417 | { 1418 | *CompleteRequest = FALSE; 1419 | } 1420 | 1421 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1422 | "ElanReadReport Exit = 0x%x\n", status); 1423 | 1424 | return status; 1425 | } 1426 | 1427 | NTSTATUS 1428 | ElanSetFeature( 1429 | IN PELAN_CONTEXT DevContext, 1430 | IN WDFREQUEST Request, 1431 | OUT BOOLEAN* CompleteRequest 1432 | ) 1433 | { 1434 | UNREFERENCED_PARAMETER(CompleteRequest); 1435 | 1436 | NTSTATUS status = STATUS_SUCCESS; 1437 | WDF_REQUEST_PARAMETERS params; 1438 | PHID_XFER_PACKET transferPacket = NULL; 1439 | ElanFeatureReport* pReport = NULL; 1440 | 1441 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1442 | "ElanSetFeature Entry\n"); 1443 | 1444 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1445 | WdfRequestGetParameters(Request, ¶ms); 1446 | 1447 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1448 | { 1449 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1450 | "ElanSetFeature Xfer packet too small\n"); 1451 | 1452 | status = STATUS_BUFFER_TOO_SMALL; 1453 | } 1454 | else 1455 | { 1456 | 1457 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1458 | 1459 | if (transferPacket == NULL) 1460 | { 1461 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1462 | "ElanWriteReport No xfer packet\n"); 1463 | 1464 | status = STATUS_INVALID_DEVICE_REQUEST; 1465 | } 1466 | else 1467 | { 1468 | // 1469 | // switch on the report id 1470 | // 1471 | 1472 | switch (transferPacket->reportId) 1473 | { 1474 | case REPORTID_FEATURE: 1475 | 1476 | if (transferPacket->reportBufferLen == sizeof(ElanFeatureReport)) 1477 | { 1478 | pReport = (ElanFeatureReport*)transferPacket->reportBuffer; 1479 | 1480 | DevContext->DeviceMode = pReport->DeviceMode; 1481 | 1482 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1483 | "ElanSetFeature DeviceMode = 0x%x\n", DevContext->DeviceMode); 1484 | } 1485 | else 1486 | { 1487 | status = STATUS_INVALID_PARAMETER; 1488 | 1489 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1490 | "ElanSetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(ElanFeatureReport) (%d)\n", 1491 | transferPacket->reportBufferLen, 1492 | sizeof(ElanFeatureReport)); 1493 | } 1494 | 1495 | break; 1496 | 1497 | default: 1498 | 1499 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1500 | "ElanSetFeature Unhandled report type %d\n", transferPacket->reportId); 1501 | 1502 | status = STATUS_INVALID_PARAMETER; 1503 | 1504 | break; 1505 | } 1506 | } 1507 | } 1508 | 1509 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1510 | "ElanSetFeature Exit = 0x%x\n", status); 1511 | 1512 | return status; 1513 | } 1514 | 1515 | NTSTATUS 1516 | ElanGetFeature( 1517 | IN PELAN_CONTEXT DevContext, 1518 | IN WDFREQUEST Request, 1519 | OUT BOOLEAN* CompleteRequest 1520 | ) 1521 | { 1522 | UNREFERENCED_PARAMETER(CompleteRequest); 1523 | 1524 | NTSTATUS status = STATUS_SUCCESS; 1525 | WDF_REQUEST_PARAMETERS params; 1526 | PHID_XFER_PACKET transferPacket = NULL; 1527 | 1528 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1529 | "ElanGetFeature Entry\n"); 1530 | 1531 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1532 | WdfRequestGetParameters(Request, ¶ms); 1533 | 1534 | if (params.Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) 1535 | { 1536 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1537 | "ElanGetFeature Xfer packet too small\n"); 1538 | 1539 | status = STATUS_BUFFER_TOO_SMALL; 1540 | } 1541 | else 1542 | { 1543 | 1544 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1545 | 1546 | if (transferPacket == NULL) 1547 | { 1548 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1549 | "ElanGetFeature No xfer packet\n"); 1550 | 1551 | status = STATUS_INVALID_DEVICE_REQUEST; 1552 | } 1553 | else 1554 | { 1555 | // 1556 | // switch on the report id 1557 | // 1558 | 1559 | switch (transferPacket->reportId) 1560 | { 1561 | case REPORTID_MTOUCH: 1562 | { 1563 | 1564 | ElanMaxCountReport* pReport = NULL; 1565 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1566 | "ElanGetFeature MaximumCount = 0x%x\n", MULTI_MAX_COUNT); 1567 | if (transferPacket->reportBufferLen >= sizeof(ElanMaxCountReport)) 1568 | { 1569 | pReport = (ElanMaxCountReport*)transferPacket->reportBuffer; 1570 | 1571 | pReport->MaximumCount = MULTI_MAX_COUNT; 1572 | 1573 | pReport->PadType = 0; 1574 | 1575 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1576 | "ElanGetFeature MaximumCount = 0x%x\n", MULTI_MAX_COUNT); 1577 | } 1578 | else 1579 | { 1580 | status = STATUS_INVALID_PARAMETER; 1581 | 1582 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1583 | "ElanGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(ElanMaxCountReport) (%d)\n", 1584 | transferPacket->reportBufferLen, 1585 | sizeof(ElanMaxCountReport)); 1586 | } 1587 | 1588 | break; 1589 | } 1590 | 1591 | case REPORTID_FEATURE: 1592 | { 1593 | 1594 | ElanFeatureReport* pReport = NULL; 1595 | 1596 | if (transferPacket->reportBufferLen >= sizeof(ElanFeatureReport)) 1597 | { 1598 | pReport = (ElanFeatureReport*)transferPacket->reportBuffer; 1599 | 1600 | pReport->DeviceMode = DevContext->DeviceMode; 1601 | 1602 | pReport->DeviceIdentifier = 0; 1603 | 1604 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1605 | "ElanGetFeature DeviceMode = 0x%x\n", DevContext->DeviceMode); 1606 | } 1607 | else 1608 | { 1609 | status = STATUS_INVALID_PARAMETER; 1610 | 1611 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1612 | "ElanGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(ElanFeatureReport) (%d)\n", 1613 | transferPacket->reportBufferLen, 1614 | sizeof(ElanFeatureReport)); 1615 | } 1616 | 1617 | break; 1618 | } 1619 | 1620 | case REPORTID_PTPHQA: 1621 | { 1622 | uint8_t PTPHQA_BLOB[] = { REPORTID_PTPHQA, 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87, 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88, 0x07,\ 1623 | 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6, 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2, 0x2e, 0x84,\ 1624 | 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43, 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc, 0x47, 0x70, 0x1b,\ 1625 | 0x59, 0x6f, 0x74, 0x43, 0xc4, 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71, 0xc7, 0x95, 0x0e, 0x31,\ 1626 | 0x55, 0x21, 0xd3, 0xb5, 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19, 0x3e, 0xb3, 0xaf, 0x75, 0x81,\ 1627 | 0x9d, 0x53, 0xb9, 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c, 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d,\ 1628 | 0xa7, 0x26, 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b, 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0,\ 1629 | 0x2a, 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8, 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1, 0x0b,\ 1630 | 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7, 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b, 0xe8, 0x8a,\ 1631 | 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35, 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc, 0x2b, 0x53, 0x5c,\ 1632 | 0x69, 0x52, 0xd5, 0xc8, 0x73, 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff, 0x05, 0xd8, 0x2b, 0x79,\ 1633 | 0x9a, 0xe2, 0x34, 0x60, 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc, 0x80, 0xe3, 0x0f, 0xbd, 0x65,\ 1634 | 0x20, 0x08, 0x13, 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7, 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe,\ 1635 | 0x31, 0x48, 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89, 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a,\ 1636 | 0xe4, 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08, 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2 }; 1637 | if (transferPacket->reportBufferLen >= sizeof(PTPHQA_BLOB)) 1638 | { 1639 | uint8_t *blobBuffer = (uint8_t*)transferPacket->reportBuffer; 1640 | for (int i = 0; i < sizeof(PTPHQA_BLOB); i++) { 1641 | blobBuffer[i] = PTPHQA_BLOB[i]; 1642 | } 1643 | ElanPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1644 | "ElanGetFeature PHPHQA\n"); 1645 | } 1646 | else 1647 | { 1648 | status = STATUS_INVALID_PARAMETER; 1649 | 1650 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1651 | "ElanGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(PTPHEQ_BLOB) (%d)\n", 1652 | transferPacket->reportBufferLen, 1653 | sizeof(ElanFeatureReport)); 1654 | } 1655 | break; 1656 | } 1657 | 1658 | default: 1659 | 1660 | ElanPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1661 | "ElanGetFeature Unhandled report type %d\n", transferPacket->reportId); 1662 | 1663 | status = STATUS_INVALID_PARAMETER; 1664 | 1665 | break; 1666 | } 1667 | } 1668 | } 1669 | 1670 | ElanPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1671 | "ElanGetFeature Exit = 0x%x\n", status); 1672 | 1673 | return status; 1674 | } 1675 | 1676 | PCHAR 1677 | DbgHidInternalIoctlString( 1678 | IN ULONG IoControlCode 1679 | ) 1680 | { 1681 | switch (IoControlCode) 1682 | { 1683 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 1684 | return "IOCTL_HID_GET_DEVICE_DESCRIPTOR"; 1685 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 1686 | return "IOCTL_HID_GET_REPORT_DESCRIPTOR"; 1687 | case IOCTL_HID_READ_REPORT: 1688 | return "IOCTL_HID_READ_REPORT"; 1689 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 1690 | return "IOCTL_HID_GET_DEVICE_ATTRIBUTES"; 1691 | case IOCTL_HID_WRITE_REPORT: 1692 | return "IOCTL_HID_WRITE_REPORT"; 1693 | case IOCTL_HID_SET_FEATURE: 1694 | return "IOCTL_HID_SET_FEATURE"; 1695 | case IOCTL_HID_GET_FEATURE: 1696 | return "IOCTL_HID_GET_FEATURE"; 1697 | case IOCTL_HID_GET_STRING: 1698 | return "IOCTL_HID_GET_STRING"; 1699 | case IOCTL_HID_ACTIVATE_DEVICE: 1700 | return "IOCTL_HID_ACTIVATE_DEVICE"; 1701 | case IOCTL_HID_DEACTIVATE_DEVICE: 1702 | return "IOCTL_HID_DEACTIVATE_DEVICE"; 1703 | case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: 1704 | return "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST"; 1705 | case IOCTL_HID_SET_OUTPUT_REPORT: 1706 | return "IOCTL_HID_SET_OUTPUT_REPORT"; 1707 | case IOCTL_HID_GET_INPUT_REPORT: 1708 | return "IOCTL_HID_GET_INPUT_REPORT"; 1709 | default: 1710 | return "Unknown IOCTL"; 1711 | } 1712 | } 1713 | --------------------------------------------------------------------------------