├── 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 |
--------------------------------------------------------------------------------