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