├── .gitattributes ├── crostouchscreen2 ├── stdint.h ├── resource.h ├── crostouchscreen2.rc ├── trace.h ├── spb.h ├── hidcommon.h ├── crostouchscreen2.vcxproj.filters ├── crostouchscreen2.inf ├── registers.h ├── crostouchscreen2.vcxproj ├── raydium_i2c.h ├── spb.cpp └── rayd.cpp ├── README.md ├── crostouchscreen2.sln ├── LICENSE.txt ├── .gitignore └── crostouchscreen2 Package └── crostouchscreen2 Package.vcxproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /crostouchscreen2/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 BIT(nr) (1UL << (nr)) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crostouchscreen2-raydium 2 | Raydium Touch Screen Driver for Skylake/Apollo Lake and newer chromebooks. 3 | 4 | Tested on Acer Chromebook Spin 15 CP315. Works with up to 10 touches. 5 | 6 | # Credits 7 | 8 | Huge thanks to the vmulti and DragonFlyBSD projects, which I used for references. Also, thanks to Microsoft for open sourcing the Synaptics RMI I2C driver, which I also used as a reference. 9 | -------------------------------------------------------------------------------- /crostouchscreen2/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by crostouchscreen2.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /crostouchscreen2/crostouchscreen2.rc: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Microsoft Corporation All Rights Reserved 4 | 5 | Module Name: 6 | 7 | crostouchscreen2.rc 8 | 9 | Abstract: 10 | 11 | --*/ 12 | 13 | #include 14 | 15 | #define VER_FILETYPE VFT_DRV 16 | #define VER_FILESUBTYPE VFT2_UNKNOWN 17 | #define VER_FILEDESCRIPTION_STR "Chromebook Raydium Touch Screen" 18 | #define VER_INTERNALNAME_STR "crostouchscreen2.sys" 19 | #define VER_ORIGINALFILENAME_STR "crostouchscreen2.sys" 20 | 21 | #define VER_LEGALCOPYRIGHT_YEARS "2023" 22 | #define VER_LEGALCOPYRIGHT_STR "Copyright (C) " VER_LEGALCOPYRIGHT_YEARS " CoolStar." 23 | 24 | #define VER_FILEVERSION 2,9,4,0 25 | #define VER_PRODUCTVERSION_STR "2.9.4.0" 26 | #define VER_PRODUCTVERSION 2,9,4,0 27 | #define LVER_PRODUCTVERSION_STR L"2.9.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 Raydium Touch Screen" 40 | 41 | #include "common.ver" -------------------------------------------------------------------------------- /crostouchscreen2/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 | -------------------------------------------------------------------------------- /crostouchscreen2/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 | SpbXferDataSynchronously( 44 | _In_ SPB_CONTEXT* SpbContext, 45 | _In_ PVOID SendData, 46 | _In_ ULONG SendLength, 47 | _In_reads_bytes_(Length) PVOID Data, 48 | _In_ ULONG Length 49 | ); 50 | 51 | VOID 52 | SpbTargetDeinitialize( 53 | IN WDFDEVICE FxDevice, 54 | IN SPB_CONTEXT *SpbContext 55 | ); 56 | 57 | NTSTATUS 58 | SpbTargetInitialize( 59 | IN WDFDEVICE FxDevice, 60 | IN SPB_CONTEXT *SpbContext 61 | ); 62 | 63 | NTSTATUS 64 | SpbWriteDataSynchronously( 65 | IN SPB_CONTEXT *SpbContext, 66 | IN PVOID Data, 67 | IN ULONG Length 68 | ); 69 | 70 | NTSTATUS 71 | SpbLockController( 72 | IN SPB_CONTEXT* SpbContext 73 | ); 74 | 75 | NTSTATUS 76 | SpbUnlockController( 77 | IN SPB_CONTEXT* SpbContext 78 | ); -------------------------------------------------------------------------------- /crostouchscreen2/hidcommon.h: -------------------------------------------------------------------------------- 1 | #if !defined(_RAYD_COMMON_H_) 2 | #define _RAYD_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 RAYD_PID 0xBACC 10 | #define RAYD_VID 0x00FF 11 | #define RAYD_VERSION 0x0001 12 | 13 | // 14 | // These are the report ids 15 | // 16 | 17 | #define REPORTID_MTOUCH 0x01 18 | #define REPORTID_FEATURE 0x02 19 | 20 | // 21 | // Multitouch specific report information 22 | // 23 | 24 | #define MULTI_TIPSWITCH_BIT 1 25 | #define MULTI_CONFIDENCE_BIT 2 26 | 27 | #define MULTI_MIN_COORDINATE 0x0000 28 | #define MULTI_MAX_COORDINATE 0x7FFF 29 | 30 | #define MULTI_MAX_COUNT 10 31 | 32 | #pragma pack(1) 33 | typedef struct 34 | { 35 | 36 | BYTE Status; 37 | 38 | BYTE ContactID; 39 | 40 | USHORT XValue; 41 | 42 | USHORT YValue; 43 | 44 | USHORT Width; 45 | 46 | USHORT Height; 47 | 48 | } 49 | TOUCH, *PTOUCH; 50 | 51 | typedef struct _RAYD_MULTITOUCH_REPORT 52 | { 53 | 54 | BYTE ReportID; 55 | 56 | TOUCH Touch[10]; 57 | 58 | BYTE ActualCount; 59 | 60 | } RaydMultiTouchReport; 61 | #pragma pack() 62 | 63 | // 64 | // Feature report infomation 65 | // 66 | 67 | #define DEVICE_MODE_MOUSE 0x00 68 | #define DEVICE_MODE_SINGLE_INPUT 0x01 69 | #define DEVICE_MODE_MULTI_INPUT 0x02 70 | 71 | #pragma pack(1) 72 | typedef struct _RAYD_FEATURE_REPORT 73 | { 74 | 75 | BYTE ReportID; 76 | 77 | BYTE DeviceMode; 78 | 79 | BYTE DeviceIdentifier; 80 | 81 | } RaydFeatureReport; 82 | 83 | typedef struct _RAYD_MAXCOUNT_REPORT 84 | { 85 | 86 | BYTE ReportID; 87 | 88 | BYTE MaximumCount; 89 | 90 | } RaydMaxCountReport; 91 | #pragma pack() 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /crostouchscreen2/crostouchscreen2.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 | Driver Files 24 | 25 | 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | 58 | 59 | Resource Files 60 | 61 | 62 | -------------------------------------------------------------------------------- /crostouchscreen2/crostouchscreen2.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 Raydium Touch Screen 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 = 10/8/2022,2.9.3 20 | CatalogFile = crostouchscreen2.cat 21 | PnpLockdown=1 22 | 23 | [DestinationDirs] 24 | DefaultDestDir = 12 25 | 26 | ; ================= Class section ===================== 27 | 28 | [SourceDisksNames] 29 | 1 = %DiskId1%,,,"" 30 | 31 | [SourceDisksFiles] 32 | crostouchscreen2.sys = 1,, 33 | 34 | ;***************************************** 35 | ; CrosTouchScreen Install Section 36 | ;***************************************** 37 | 38 | [Manufacturer] 39 | %StdMfg%=Standard,NTAMD64 40 | 41 | ; Decorated model section take precedence over undecorated 42 | ; ones on XP and later. 43 | [Standard.NTAMD64] 44 | %CrosTouchScreen.DeviceDesc%=CrosTouchScreen_Device, ACPI\RAYD0001 45 | 46 | [CrosTouchScreen_Device.NT] 47 | CopyFiles=Drivers_Dir 48 | 49 | [CrosTouchScreen_Device.NT.HW] 50 | AddReg=CrosTouchScreen_AddReg 51 | 52 | [Drivers_Dir] 53 | crostouchscreen2.sys 54 | 55 | [CrosTouchScreen_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 | [CrosTouchScreen_Device.NT.Services] 62 | AddService = CrosTouchScreen,%SPSVCINST_ASSOCSERVICE%, CrosTouchScreen_Service_Inst 63 | 64 | ; -------------- CrosTouchScreen driver install sections 65 | [CrosTouchScreen_Service_Inst] 66 | DisplayName = %CrosTouchScreen.SVCDESC% 67 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 68 | StartType = 3 ; SERVICE_DEMAND_START 69 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 70 | ServiceBinary = %12%\crostouchscreen2.sys 71 | LoadOrderGroup = Base 72 | 73 | [Strings] 74 | SPSVCINST_ASSOCSERVICE= 0x00000002 75 | StdMfg = "CoolStar" 76 | DiskId1 = "CrosTouchScreen Installation Disk #1" 77 | CrosTouchScreen.DeviceDesc = "Chromebook Raydium Touch Screen" 78 | CrosTouchScreen.SVCDESC = "CrosTouchScreen Service" 79 | -------------------------------------------------------------------------------- /crostouchscreen2/registers.h: -------------------------------------------------------------------------------- 1 | #include "stdint.h" 2 | 3 | /* Slave I2C mode */ 4 | #define RM_BOOT_BLDR 0x02 5 | #define RM_BOOT_MAIN 0x03 6 | 7 | /* I2C bootoloader commands */ 8 | #define RM_CMD_BOOT_PAGE_WRT 0x0B /* send bl page write */ 9 | #define RM_CMD_BOOT_WRT 0x11 /* send bl write */ 10 | #define RM_CMD_BOOT_ACK 0x22 /* send ack*/ 11 | #define RM_CMD_BOOT_CHK 0x33 /* send data check */ 12 | #define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/ 13 | 14 | #define RM_BOOT_RDY 0xFF /* bl data ready */ 15 | #define RM_BOOT_CMD_READHWID 0x0E /* read hwid */ 16 | 17 | /* I2C main commands */ 18 | #define RM_CMD_QUERY_BANK 0x2B 19 | #define RM_CMD_DATA_BANK 0x4D 20 | #define RM_CMD_ENTER_SLEEP 0x4E 21 | #define RM_CMD_BANK_SWITCH 0xAA 22 | 23 | #define RM_RESET_MSG_ADDR 0x40000004 24 | 25 | #define RM_MAX_READ_SIZE 56 26 | #define RM_PACKET_CRC_SIZE 2 27 | 28 | /* Touch relative info */ 29 | #define RM_MAX_RETRIES 3 30 | #define RM_RETRY_DELAY_MS 20 31 | #define RM_MAX_TOUCH_NUM 10 32 | #define RM_BOOT_DELAY_MS 100 33 | 34 | /* Offsets in contact data */ 35 | #define RM_CONTACT_STATE_POS 0 36 | #define RM_CONTACT_X_POS 1 37 | #define RM_CONTACT_Y_POS 3 38 | #define RM_CONTACT_PRESSURE_POS 5 39 | #define RM_CONTACT_WIDTH_X_POS 6 40 | #define RM_CONTACT_WIDTH_Y_POS 7 41 | 42 | /* Bootloader relative info */ 43 | #define RM_BL_WRT_CMD_SIZE 3 /* bl flash wrt cmd size */ 44 | #define RM_BL_WRT_PKG_SIZE 32 /* bl wrt pkg size */ 45 | #define RM_BL_WRT_LEN (RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE) 46 | #define RM_FW_PAGE_SIZE 128 47 | #define RM_MAX_FW_RETRIES 30 48 | #define RM_MAX_FW_SIZE 0xD000 49 | 50 | #define RM_POWERON_DELAY_USEC 500 51 | #define RM_RESET_DELAY_MSEC 50 52 | 53 | enum raydium_bl_cmd { 54 | BL_HEADER = 0, 55 | BL_PAGE_STR, 56 | BL_PKG_IDX, 57 | BL_DATA_STR, 58 | }; 59 | 60 | enum raydium_bl_ack { 61 | RAYDIUM_ACK_NULL = 0, 62 | RAYDIUM_WAIT_READY, 63 | RAYDIUM_PATH_READY, 64 | }; 65 | 66 | enum raydium_boot_mode { 67 | RAYDIUM_TS_MAIN = 0, 68 | RAYDIUM_TS_BLDR, 69 | }; 70 | 71 | /* Response to RM_CMD_DATA_BANK request */ 72 | struct raydium_data_info { 73 | UINT32 data_bank_addr; 74 | UINT8 pkg_size; 75 | UINT8 tp_info_size; 76 | }; 77 | 78 | struct raydium_info { 79 | UINT32 hw_ver; /*device version */ 80 | UINT8 main_ver; 81 | UINT8 sub_ver; 82 | UINT16 ft_ver; /* test version */ 83 | UINT8 x_num; 84 | UINT8 y_num; 85 | UINT16 x_max; 86 | UINT16 y_max; 87 | UINT8 x_res; /* units/mm */ 88 | UINT8 y_res; /* units/mm */ 89 | }; 90 | -------------------------------------------------------------------------------- /crostouchscreen2.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crostouchscreen2", "crostouchscreen2\crostouchscreen2.vcxproj", "{36580C07-EDC3-4C2B-B45F-6AB017E01A5D}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crostouchscreen2 Package", "crostouchscreen2 Package\crostouchscreen2 Package.vcxproj", "{3DAE7ED3-003A-4495-8352-3D7B5B5D846F}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D} = {36580C07-EDC3-4C2B-B45F-6AB017E01A5D} 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 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Debug|Win32.Build.0 = Debug|Win32 23 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Debug|Win32.Deploy.0 = Debug|Win32 24 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Debug|x64.ActiveCfg = Debug|x64 25 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Debug|x64.Build.0 = Debug|x64 26 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Debug|x64.Deploy.0 = Debug|x64 27 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Release|Win32.ActiveCfg = Release|Win32 28 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Release|Win32.Build.0 = Release|Win32 29 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Release|Win32.Deploy.0 = Release|Win32 30 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Release|x64.ActiveCfg = Release|x64 31 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Release|x64.Build.0 = Release|x64 32 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D}.Release|x64.Deploy.0 = Release|x64 33 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Debug|Win32.ActiveCfg = Debug|Win32 34 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Debug|Win32.Build.0 = Debug|Win32 35 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Debug|Win32.Deploy.0 = Debug|Win32 36 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Debug|x64.ActiveCfg = Debug|x64 37 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Debug|x64.Build.0 = Debug|x64 38 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Debug|x64.Deploy.0 = Debug|x64 39 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Release|Win32.ActiveCfg = Release|Win32 40 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Release|Win32.Build.0 = Release|Win32 41 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Release|Win32.Deploy.0 = Release|Win32 42 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Release|x64.ActiveCfg = Release|x64 43 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Release|x64.Build.0 = Release|x64 44 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F}.Release|x64.Deploy.0 = Release|x64 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | GlobalSection(ExtensibilityGlobals) = postSolution 50 | SolutionGuid = {5BB5003A-DF11-421F-AB70-72368340F27C} 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2022 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. 14 | 15 | 16 | ====================== Windows Driver Samples License ====================== 17 | 18 | The Microsoft Public License (MS-PL) 19 | Copyright (c) 2015 Microsoft 20 | 21 | This license governs use of the accompanying software. If you use the software, you 22 | accept this license. If you do not accept the license, do not use the software. 23 | 24 | 1. Definitions 25 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the 26 | same meaning here as under U.S. copyright law. 27 | A "contribution" is the original software, or any additions or changes to the software. 28 | A "contributor" is any person that distributes its contribution under this license. 29 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 30 | 31 | 2. Grant of Rights 32 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 33 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 34 | 35 | 3. Conditions and Limitations 36 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 37 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 38 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 39 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 40 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. -------------------------------------------------------------------------------- /crostouchscreen2/crostouchscreen2.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 | {36580C07-EDC3-4C2B-B45F-6AB017E01A5D} 23 | {1bc93793-694f-48fe-9372-81e2b05556fd} 24 | v4.5 25 | 11.0 26 | Win8.1 Debug 27 | Win32 28 | crostouchscreen2 29 | $(LatestTargetPlatformVersion) 30 | 31 | 32 | 33 | Windows10 34 | true 35 | WindowsKernelModeDriver10.0 36 | Driver 37 | KMDF 38 | 39 | 40 | Windows10 41 | false 42 | WindowsKernelModeDriver10.0 43 | Driver 44 | KMDF 45 | 46 | 47 | Windows10 48 | true 49 | WindowsKernelModeDriver10.0 50 | Driver 51 | KMDF 52 | 53 | 54 | Windows10 55 | false 56 | WindowsKernelModeDriver10.0 57 | Driver 58 | KMDF 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | DbgengKernelDebugger 70 | 71 | 72 | DbgengKernelDebugger 73 | 74 | 75 | DbgengKernelDebugger 76 | 77 | 78 | DbgengKernelDebugger 79 | 80 | 81 | 82 | true 83 | trace.h 84 | true 85 | 86 | 87 | 2.9.4 88 | 89 | 90 | 91 | 92 | true 93 | trace.h 94 | true 95 | 96 | 97 | 2.9.4 98 | 99 | 100 | 101 | 102 | true 103 | trace.h 104 | true 105 | 106 | 107 | 2.9.4 108 | 109 | 110 | 111 | 112 | true 113 | trace.h 114 | true 115 | 116 | 117 | 2.9.4 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /crostouchscreen2 Package/crostouchscreen2 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 | {3DAE7ED3-003A-4495-8352-3D7B5B5D846F} 23 | {4605da2c-74a5-4865-98e1-152ef136825f} 24 | v4.5 25 | 11.0 26 | Win8.1 Debug 27 | Win32 28 | crostouchscreen2_Package 29 | $(LatestTargetPlatformVersion) 30 | 31 | 32 | 33 | Windows10 34 | true 35 | WindowsKernelModeDriver10.0 36 | Utility 37 | Package 38 | true 39 | 40 | 41 | Windows10 42 | false 43 | WindowsKernelModeDriver10.0 44 | Utility 45 | Package 46 | true 47 | 48 | 49 | Windows10 50 | true 51 | WindowsKernelModeDriver10.0 52 | Utility 53 | Package 54 | true 55 | 56 | 57 | Windows10 58 | false 59 | WindowsKernelModeDriver10.0 60 | Utility 61 | Package 62 | true 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | DbgengKernelDebugger 74 | False 75 | True 76 | 77 | 78 | 79 | False 80 | False 81 | True 82 | 83 | 133563 84 | 85 | 86 | DbgengKernelDebugger 87 | False 88 | True 89 | 90 | 91 | 92 | False 93 | False 94 | True 95 | 96 | 133563 97 | 98 | 99 | DbgengKernelDebugger 100 | False 101 | True 102 | 103 | 104 | 105 | False 106 | False 107 | True 108 | 109 | 133563 110 | 111 | 112 | DbgengKernelDebugger 113 | False 114 | True 115 | 116 | 117 | 118 | False 119 | False 120 | True 121 | 122 | 133563 123 | 124 | 125 | 126 | SHA256 127 | 128 | 129 | 130 | 131 | SHA256 132 | 133 | 134 | 135 | 136 | SHA256 137 | 138 | 139 | 140 | 141 | SHA256 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | {36580c07-edc3-4c2b-b45f-6ab017e01a5d} 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /crostouchscreen2/raydium_i2c.h: -------------------------------------------------------------------------------- 1 | #if !defined(_RAYD_H_) 2 | #define _RAYD_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 | 22 | #include "registers.h" 23 | 24 | // 25 | // String definitions 26 | // 27 | 28 | #define DRIVERNAME "crostouchscreen2.sys: " 29 | 30 | #define RAYD_POOL_TAG (ULONG) 'dyaR' 31 | 32 | #define NTDEVICE_NAME_STRING L"\\Device\\RAYD0001" 33 | #define SYMBOLIC_NAME_STRING L"\\DosDevices\\RAYD0001" 34 | 35 | #define MT_TOUCH_COLLECTION0 \ 36 | 0xa1, 0x02, /* COLLECTION (Logical) */ \ 37 | 0x09, 0x42, /* USAGE (Tip Switch) */ \ 38 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ 39 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ \ 40 | 0x75, 0x01, /* REPORT_SIZE (1) */ \ 41 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 42 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 43 | 0x09, 0x47, /* USAGE (Confidence) */ \ 44 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 45 | 0x95, 0x06, /* REPORT_COUNT (6) */ \ 46 | 0x81, 0x03, /* INPUT (Cnst,Ary,Abs) */ \ 47 | 0x75, 0x08, /* REPORT_SIZE (8) */ \ 48 | 0x09, 0x51, /* USAGE (Contact Identifier) */ \ 49 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 50 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 51 | 0x05, 0x01, /* USAGE_PAGE (Generic Desk.. */ \ 52 | 0x75, 0x10, /* REPORT_SIZE (16) */ \ 53 | 0x55, 0x00, /* UNIT_EXPONENT (0) */ \ 54 | 0x65, 0x00, /* UNIT (None) */ \ 55 | 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ \ 56 | 0x46, 0x00, 0x00, /* PHYSICAL_MAXIMUM (0) */ 57 | 58 | 59 | //0x26, 0x56, 0x05, /* LOGICAL_MAXIMUM (1366) */ 60 | 61 | #define MT_TOUCH_COLLECTION1 \ 62 | 0x09, 0x30, /* USAGE (X) */ \ 63 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 64 | 65 | //0x26, 0x00, 0x03, /* LOGICAL_MAXIMUM (768) */ 66 | 67 | #define MT_TOUCH_COLLECTION2 \ 68 | 0x09, 0x31, /* USAGE (Y) */ \ 69 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 70 | 0x05, 0x0d, /* USAGE PAGE (Digitizers) */ \ 71 | 0x09, 0x48, /* USAGE (Width) */ \ 72 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 73 | 0x09, 0x49, /* USAGE (Height) */ \ 74 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 75 | 0xc0, /* END_COLLECTION */ 76 | 77 | #if 0 78 | 0x26, 0x56, 0x05, /* LOGICAL_MAXIMUM (1366) */ 79 | 0x26, 0x00, 0x03, /* LOGICAL_MAXIMUM (768) */ 80 | #endif 81 | 82 | #define MT_REF_TOUCH_COLLECTION \ 83 | MT_TOUCH_COLLECTION0 \ 84 | 0x26, 0x00, 0x00, /* LOGICAL_MAXIMUM (1366) */ \ 85 | MT_TOUCH_COLLECTION1 \ 86 | 0x26, 0x00, 0x00, /* LOGICAL_MAXIMUM (768) */ \ 87 | MT_TOUCH_COLLECTION2 \ 88 | 89 | #define USAGE_PAGE \ 90 | 0x05, 0x0d, /* USAGE_PAGE (Digitizers) */ \ 91 | 0x09, 0x54, /* USAGE (Contact Count) */ \ 92 | 0x95, 0x01, /* REPORT_COUNT (1) */ \ 93 | 0x75, 0x08, /* REPORT_SIZE (8) */ \ 94 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ \ 95 | 0x25, 0x08, /* LOGICAL_MAXIMUM (8) */ \ 96 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ \ 97 | 0x09, 0x55, /* USAGE(Contact Count Maximum) */ \ 98 | 0xb1, 0x02, /* FEATURE (Data,Var,Abs) */ \ 99 | 100 | // 101 | // This is the default report descriptor for the Hid device provided 102 | // by the mini driver in response to IOCTL_HID_GET_REPORT_DESCRIPTOR. 103 | // 104 | 105 | typedef UCHAR HID_REPORT_DESCRIPTOR, *PHID_REPORT_DESCRIPTOR; 106 | 107 | #ifdef DESCRIPTOR_DEF 108 | HID_REPORT_DESCRIPTOR DefaultReportDescriptor[] = { 109 | // 110 | // Multitouch report starts here 111 | // 112 | 0x05, 0x0d, // USAGE_PAGE (Digitizers) 113 | 0x09, 0x04, // USAGE (Touch Screen) 114 | 0xa1, 0x01, // COLLECTION (Application) 115 | 0x85, REPORTID_MTOUCH, // REPORT_ID (Touch) 116 | 0x09, 0x22, // USAGE (Finger) 117 | MT_REF_TOUCH_COLLECTION 118 | MT_REF_TOUCH_COLLECTION 119 | MT_REF_TOUCH_COLLECTION 120 | MT_REF_TOUCH_COLLECTION 121 | MT_REF_TOUCH_COLLECTION 122 | MT_REF_TOUCH_COLLECTION 123 | MT_REF_TOUCH_COLLECTION 124 | MT_REF_TOUCH_COLLECTION 125 | MT_REF_TOUCH_COLLECTION 126 | MT_REF_TOUCH_COLLECTION 127 | USAGE_PAGE 128 | 0xc0, // END_COLLECTION 129 | }; 130 | 131 | 132 | // 133 | // This is the default HID descriptor returned by the mini driver 134 | // in response to IOCTL_HID_GET_DEVICE_DESCRIPTOR. The size 135 | // of report descriptor is currently the size of DefaultReportDescriptor. 136 | // 137 | 138 | CONST HID_DESCRIPTOR DefaultHidDescriptor = { 139 | 0x09, // length of HID descriptor 140 | 0x21, // descriptor type == HID 0x21 141 | 0x0100, // hid spec release 142 | 0x00, // country code == Not Specified 143 | 0x01, // number of HID class descriptors 144 | { 0x22, // descriptor type 145 | sizeof(DefaultReportDescriptor) } // total length of report descriptor 146 | }; 147 | #endif 148 | 149 | #define true 1 150 | #define false 0 151 | 152 | #define MXT_T9_RELEASE (1 << 5) 153 | #define MXT_T9_PRESS (1 << 6) 154 | #define MXT_T9_DETECT (1 << 7) 155 | 156 | typedef struct _RAYD_CONTEXT 157 | { 158 | 159 | WDFDEVICE FxDevice; 160 | 161 | WDFQUEUE ReportQueue; 162 | 163 | BYTE DeviceMode; 164 | 165 | SPB_CONTEXT I2CContext; 166 | 167 | WDFINTERRUPT Interrupt; 168 | 169 | BOOLEAN ConnectInterrupt; 170 | 171 | BOOLEAN TouchScreenBooted; 172 | 173 | BOOLEAN RegsSet; 174 | 175 | UINT32 TouchCount; 176 | 177 | uint8_t Flags[20]; 178 | 179 | USHORT XValue[20]; 180 | 181 | USHORT YValue[20]; 182 | 183 | USHORT AREA[20]; 184 | 185 | uint8_t max_x_hid[2]; 186 | uint8_t max_y_hid[2]; 187 | 188 | struct raydium_info info; 189 | 190 | UINT32 dataBankAddr; 191 | UINT8 reportSize; 192 | UINT8 contactSize; 193 | UINT8 packageSize; 194 | 195 | enum raydium_boot_mode bootMode; 196 | 197 | UINT8* reportData; 198 | 199 | } RAYD_CONTEXT, *PRAYD_CONTEXT; 200 | 201 | WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RAYD_CONTEXT, GetDeviceContext) 202 | 203 | // 204 | // Function definitions 205 | // 206 | 207 | extern "C" { 208 | DRIVER_INITIALIZE DriverEntry; 209 | } 210 | 211 | EVT_WDF_DRIVER_UNLOAD RaydDriverUnload; 212 | 213 | EVT_WDF_DRIVER_DEVICE_ADD RaydEvtDeviceAdd; 214 | 215 | EVT_WDFDEVICE_WDM_IRP_PREPROCESS RaydEvtWdmPreprocessMnQueryId; 216 | 217 | EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL RaydEvtInternalDeviceControl; 218 | 219 | NTSTATUS 220 | RaydGetHidDescriptor( 221 | IN WDFDEVICE Device, 222 | IN WDFREQUEST Request 223 | ); 224 | 225 | NTSTATUS 226 | RaydGetReportDescriptor( 227 | IN WDFDEVICE Device, 228 | IN WDFREQUEST Request 229 | ); 230 | 231 | NTSTATUS 232 | RaydGetDeviceAttributes( 233 | IN WDFREQUEST Request 234 | ); 235 | 236 | NTSTATUS 237 | RaydGetString( 238 | IN WDFREQUEST Request 239 | ); 240 | 241 | NTSTATUS 242 | RaydWriteReport( 243 | IN PRAYD_CONTEXT DevContext, 244 | IN WDFREQUEST Request 245 | ); 246 | 247 | NTSTATUS 248 | RaydProcessVendorReport( 249 | IN PRAYD_CONTEXT DevContext, 250 | IN PVOID ReportBuffer, 251 | IN ULONG ReportBufferLen, 252 | OUT size_t* BytesWritten 253 | ); 254 | 255 | NTSTATUS 256 | RaydReadReport( 257 | IN PRAYD_CONTEXT DevContext, 258 | IN WDFREQUEST Request, 259 | OUT BOOLEAN* CompleteRequest 260 | ); 261 | 262 | NTSTATUS 263 | RaydSetFeature( 264 | IN PRAYD_CONTEXT DevContext, 265 | IN WDFREQUEST Request, 266 | OUT BOOLEAN* CompleteRequest 267 | ); 268 | 269 | NTSTATUS 270 | RaydGetFeature( 271 | IN PRAYD_CONTEXT DevContext, 272 | IN WDFREQUEST Request, 273 | OUT BOOLEAN* CompleteRequest 274 | ); 275 | 276 | PCHAR 277 | DbgHidInternalIoctlString( 278 | IN ULONG IoControlCode 279 | ); 280 | 281 | // 282 | // Helper macros 283 | // 284 | 285 | #define DEBUG_LEVEL_ERROR 1 286 | #define DEBUG_LEVEL_INFO 2 287 | #define DEBUG_LEVEL_VERBOSE 3 288 | 289 | #define DBG_INIT 1 290 | #define DBG_PNP 2 291 | #define DBG_IOCTL 4 292 | 293 | #if 0 294 | #define RaydPrint(dbglevel, dbgcatagory, fmt, ...) { \ 295 | if (RaydDebugLevel >= dbglevel && \ 296 | (RaydDebugCatagories && dbgcatagory)) \ 297 | { \ 298 | DbgPrint(DRIVERNAME); \ 299 | DbgPrint(fmt, __VA_ARGS__); \ 300 | } \ 301 | } 302 | #else 303 | #define RaydPrint(dbglevel, fmt, ...) { \ 304 | } 305 | #endif 306 | 307 | #endif -------------------------------------------------------------------------------- /crostouchscreen2/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 "raydium_i2c.h" 22 | #include "spb.h" 23 | #include 24 | #include 25 | 26 | static ULONG RaydDebugLevel = 100; 27 | static ULONG RaydDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 28 | 29 | NTSTATUS 30 | SpbDoWriteDataSynchronously( 31 | IN SPB_CONTEXT *SpbContext, 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 | length = Length; 62 | memory = NULL; 63 | 64 | if (length > DEFAULT_SPB_BUFFER_SIZE) 65 | { 66 | status = WdfMemoryCreate( 67 | WDF_NO_OBJECT_ATTRIBUTES, 68 | NonPagedPool, 69 | RAYD_POOL_TAG, 70 | length, 71 | &memory, 72 | (PVOID *)&buffer); 73 | 74 | if (!NT_SUCCESS(status)) 75 | { 76 | RaydPrint( 77 | DEBUG_LEVEL_ERROR, 78 | DBG_IOCTL, 79 | "Error allocating memory for Spb write - 0x%x\n", 80 | status); 81 | goto exit; 82 | } 83 | 84 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 85 | &memoryDescriptor, 86 | memory, 87 | NULL); 88 | } 89 | else 90 | { 91 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL); 92 | 93 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 94 | &memoryDescriptor, 95 | (PVOID)buffer, 96 | length); 97 | } 98 | 99 | RtlCopyMemory(buffer, Data, length); 100 | 101 | status = WdfIoTargetSendWriteSynchronously( 102 | SpbContext->SpbIoTarget, 103 | NULL, 104 | &memoryDescriptor, 105 | NULL, 106 | NULL, 107 | NULL); 108 | 109 | if (!NT_SUCCESS(status)) 110 | { 111 | RaydPrint( 112 | DEBUG_LEVEL_ERROR, 113 | DBG_IOCTL, 114 | "Error writing to Spb - 0x%x\n", 115 | status); 116 | goto exit; 117 | } 118 | 119 | exit: 120 | 121 | if (NULL != memory) 122 | { 123 | WdfObjectDelete(memory); 124 | } 125 | 126 | return status; 127 | } 128 | 129 | NTSTATUS 130 | SpbWriteDataSynchronously( 131 | IN SPB_CONTEXT *SpbContext, 132 | IN PVOID Data, 133 | IN ULONG Length 134 | ) 135 | /*++ 136 | 137 | Routine Description: 138 | 139 | This routine abstracts creating and sending an I/O 140 | request (I2C Write) to the Spb I/O target and utilizes 141 | a helper routine to do work inside of locked code. 142 | 143 | Arguments: 144 | 145 | SpbContext - Pointer to the current device context 146 | Address - The I2C register address to write to 147 | Data - A buffer to receive the data at at the above address 148 | Length - The amount of data to be read from the above address 149 | 150 | Return Value: 151 | 152 | NTSTATUS Status indicating success or failure 153 | 154 | --*/ 155 | { 156 | NTSTATUS status; 157 | 158 | status = SpbDoWriteDataSynchronously( 159 | SpbContext, 160 | Data, 161 | Length); 162 | 163 | return status; 164 | } 165 | 166 | NTSTATUS 167 | SpbXferDataSynchronously( 168 | _In_ SPB_CONTEXT* SpbContext, 169 | _In_ PVOID SendData, 170 | _In_ ULONG SendLength, 171 | _In_reads_bytes_(Length) PVOID Data, 172 | _In_ ULONG Length 173 | ) 174 | /*++ 175 | Routine Description: 176 | This helper routine abstracts creating and sending an I/O 177 | request (I2C Read) to the Spb I/O target. 178 | Arguments: 179 | SpbContext - Pointer to the current device context 180 | Address - The I2C register address to read from 181 | Data - A buffer to receive the data at at the above address 182 | Length - The amount of data to be read from the above address 183 | Return Value: 184 | NTSTATUS Status indicating success or failure 185 | --*/ 186 | { 187 | PUCHAR buffer; 188 | WDFMEMORY memory; 189 | WDF_MEMORY_DESCRIPTOR memoryDescriptor; 190 | NTSTATUS status; 191 | ULONG_PTR bytesRead; 192 | 193 | memory = NULL; 194 | status = STATUS_INVALID_PARAMETER; 195 | bytesRead = 0; 196 | 197 | // 198 | // Xfer transactions start by writing an address pointer 199 | // 200 | status = SpbDoWriteDataSynchronously( 201 | SpbContext, 202 | SendData, 203 | SendLength); 204 | 205 | if (!NT_SUCCESS(status)) 206 | { 207 | RaydPrint( 208 | DEBUG_LEVEL_ERROR, 209 | DBG_IOCTL, 210 | "Error doing initial write for Spb xfer 0x%x\n", 211 | status); 212 | goto exit; 213 | } 214 | 215 | if (Length > DEFAULT_SPB_BUFFER_SIZE) 216 | { 217 | status = WdfMemoryCreate( 218 | WDF_NO_OBJECT_ATTRIBUTES, 219 | NonPagedPool, 220 | RAYD_POOL_TAG, 221 | Length, 222 | &memory, 223 | (PVOID*)&buffer); 224 | 225 | if (!NT_SUCCESS(status)) 226 | { 227 | RaydPrint( 228 | DEBUG_LEVEL_ERROR, 229 | DBG_IOCTL, 230 | "Error allocating memory for Spb read - 0x%x\n", 231 | status); 232 | goto exit; 233 | } 234 | 235 | WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( 236 | &memoryDescriptor, 237 | memory, 238 | NULL); 239 | } 240 | else 241 | { 242 | buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL); 243 | 244 | WDF_MEMORY_DESCRIPTOR_INIT_BUFFER( 245 | &memoryDescriptor, 246 | (PVOID)buffer, 247 | Length); 248 | } 249 | 250 | 251 | status = WdfIoTargetSendReadSynchronously( 252 | SpbContext->SpbIoTarget, 253 | NULL, 254 | &memoryDescriptor, 255 | NULL, 256 | NULL, 257 | &bytesRead); 258 | 259 | if (!NT_SUCCESS(status) || 260 | bytesRead != Length) 261 | { 262 | RaydPrint( 263 | DEBUG_LEVEL_ERROR, 264 | DBG_IOCTL, 265 | "Error reading from Spb - 0x%x\n", 266 | status); 267 | goto exit; 268 | } 269 | 270 | // 271 | // Copy back to the caller's buffer 272 | // 273 | RtlCopyMemory(Data, buffer, Length); 274 | 275 | exit: 276 | if (NULL != memory) 277 | { 278 | WdfObjectDelete(memory); 279 | } 280 | 281 | return status; 282 | } 283 | 284 | NTSTATUS 285 | SpbLockController( 286 | IN SPB_CONTEXT* SpbContext 287 | ) 288 | /*++ 289 | 290 | Routine Description: 291 | 292 | This routine sends a lock command to the SPB controller. 293 | 294 | Arguments: 295 | 296 | pDevice - a pointer to the device context 297 | FxRequest - the framework request object 298 | 299 | Return Value: 300 | 301 | None 302 | 303 | --*/ 304 | { 305 | NTSTATUS status; 306 | 307 | // 308 | // Initialize the SPB request for lock and send. 309 | // 310 | 311 | status = WdfIoTargetSendIoctlSynchronously( 312 | SpbContext->SpbIoTarget, 313 | nullptr, 314 | IOCTL_SPB_LOCK_CONTROLLER, 315 | nullptr, 316 | nullptr, 317 | nullptr, 318 | nullptr); 319 | 320 | if (!NT_SUCCESS(status)) 321 | { 322 | RaydPrint( 323 | DEBUG_LEVEL_ERROR, 324 | DBG_IOCTL, 325 | "Failed to send SPB request for " 326 | "IOCTL_SPB_LOCK_CONTROLLER - %!STATUS!", 327 | status); 328 | } 329 | return status; 330 | } 331 | 332 | NTSTATUS 333 | SpbUnlockController( 334 | IN SPB_CONTEXT* SpbContext 335 | ) 336 | /*++ 337 | 338 | Routine Description: 339 | 340 | This routine sends a lock command to the SPB controller. 341 | 342 | Arguments: 343 | 344 | pDevice - a pointer to the device context 345 | FxRequest - the framework request object 346 | 347 | Return Value: 348 | 349 | None 350 | 351 | --*/ 352 | { 353 | NTSTATUS status; 354 | 355 | // 356 | // Initialize the SPB request for lock and send. 357 | // 358 | 359 | status = WdfIoTargetSendIoctlSynchronously( 360 | SpbContext->SpbIoTarget, 361 | nullptr, 362 | IOCTL_SPB_UNLOCK_CONTROLLER, 363 | nullptr, 364 | nullptr, 365 | nullptr, 366 | nullptr); 367 | 368 | if (!NT_SUCCESS(status)) 369 | { 370 | RaydPrint( 371 | DEBUG_LEVEL_ERROR, 372 | DBG_IOCTL, 373 | "Failed to send SPB request for " 374 | "IOCTL_SPB_UNLOCK_CONTROLLER - %!STATUS!", 375 | status); 376 | } 377 | return status; 378 | } 379 | 380 | VOID 381 | SpbTargetDeinitialize( 382 | IN WDFDEVICE FxDevice, 383 | IN SPB_CONTEXT *SpbContext 384 | ) 385 | /*++ 386 | 387 | Routine Description: 388 | 389 | This helper routine is used to free any members added to the SPB_CONTEXT, 390 | note the SPB I/O target is parented to the device and will be 391 | closed and free'd when the device is removed. 392 | 393 | Arguments: 394 | 395 | FxDevice - Handle to the framework device object 396 | SpbContext - Pointer to the current device context 397 | 398 | Return Value: 399 | 400 | NTSTATUS Status indicating success or failure 401 | 402 | --*/ 403 | { 404 | UNREFERENCED_PARAMETER(FxDevice); 405 | UNREFERENCED_PARAMETER(SpbContext); 406 | 407 | // 408 | // Free any SPB_CONTEXT allocations here 409 | // 410 | if (SpbContext->SpbLock != NULL) 411 | { 412 | WdfObjectDelete(SpbContext->SpbLock); 413 | } 414 | 415 | if (SpbContext->ReadMemory != NULL) 416 | { 417 | WdfObjectDelete(SpbContext->ReadMemory); 418 | } 419 | 420 | if (SpbContext->WriteMemory != NULL) 421 | { 422 | WdfObjectDelete(SpbContext->WriteMemory); 423 | } 424 | } 425 | 426 | NTSTATUS 427 | SpbTargetInitialize( 428 | IN WDFDEVICE FxDevice, 429 | IN SPB_CONTEXT *SpbContext 430 | ) 431 | /*++ 432 | 433 | Routine Description: 434 | 435 | This helper routine opens the Spb I/O target and 436 | initializes a request object used for the lifetime 437 | of communication between this driver and Spb. 438 | 439 | Arguments: 440 | 441 | FxDevice - Handle to the framework device object 442 | SpbContext - Pointer to the current device context 443 | 444 | Return Value: 445 | 446 | NTSTATUS Status indicating success or failure 447 | 448 | --*/ 449 | { 450 | WDF_OBJECT_ATTRIBUTES objectAttributes; 451 | WDF_IO_TARGET_OPEN_PARAMS openParams; 452 | UNICODE_STRING spbDeviceName; 453 | WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE]; 454 | NTSTATUS status; 455 | 456 | WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); 457 | objectAttributes.ParentObject = FxDevice; 458 | 459 | status = WdfIoTargetCreate( 460 | FxDevice, 461 | &objectAttributes, 462 | &SpbContext->SpbIoTarget); 463 | 464 | if (!NT_SUCCESS(status)) 465 | { 466 | RaydPrint( 467 | DEBUG_LEVEL_ERROR, 468 | DBG_IOCTL, 469 | "Error creating IoTarget object - %!STATUS!", 470 | status); 471 | 472 | WdfObjectDelete(SpbContext->SpbIoTarget); 473 | goto exit; 474 | } 475 | 476 | RtlInitEmptyUnicodeString( 477 | &spbDeviceName, 478 | spbDeviceNameBuffer, 479 | sizeof(spbDeviceNameBuffer)); 480 | 481 | status = RESOURCE_HUB_CREATE_PATH_FROM_ID( 482 | &spbDeviceName, 483 | SpbContext->I2cResHubId.LowPart, 484 | SpbContext->I2cResHubId.HighPart); 485 | 486 | if (!NT_SUCCESS(status)) 487 | { 488 | RaydPrint( 489 | DEBUG_LEVEL_ERROR, 490 | DBG_IOCTL, 491 | "Error creating Spb resource hub path string - %!STATUS!", 492 | status); 493 | goto exit; 494 | } 495 | 496 | WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( 497 | &openParams, 498 | &spbDeviceName, 499 | (GENERIC_READ | GENERIC_WRITE)); 500 | 501 | openParams.ShareAccess = 0; 502 | openParams.CreateDisposition = FILE_OPEN; 503 | openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; 504 | 505 | status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams); 506 | 507 | if (!NT_SUCCESS(status)) 508 | { 509 | RaydPrint( 510 | DEBUG_LEVEL_ERROR, 511 | DBG_IOCTL, 512 | "Error opening Spb target for communication - %!STATUS!", 513 | status); 514 | goto exit; 515 | } 516 | 517 | // 518 | // Allocate some fixed-size buffers from NonPagedPool for typical 519 | // Spb transaction sizes to avoid pool fragmentation in most cases 520 | // 521 | status = WdfMemoryCreate( 522 | WDF_NO_OBJECT_ATTRIBUTES, 523 | NonPagedPool, 524 | RAYD_POOL_TAG, 525 | DEFAULT_SPB_BUFFER_SIZE, 526 | &SpbContext->WriteMemory, 527 | NULL); 528 | 529 | if (!NT_SUCCESS(status)) 530 | { 531 | RaydPrint( 532 | DEBUG_LEVEL_ERROR, 533 | DBG_IOCTL, 534 | "Error allocating default memory for Spb write - %!STATUS!", 535 | status); 536 | goto exit; 537 | } 538 | 539 | status = WdfMemoryCreate( 540 | WDF_NO_OBJECT_ATTRIBUTES, 541 | NonPagedPool, 542 | RAYD_POOL_TAG, 543 | DEFAULT_SPB_BUFFER_SIZE, 544 | &SpbContext->ReadMemory, 545 | NULL); 546 | 547 | if (!NT_SUCCESS(status)) 548 | { 549 | RaydPrint( 550 | DEBUG_LEVEL_ERROR, 551 | DBG_IOCTL, 552 | "Error allocating default memory for Spb read - %!STATUS!", 553 | status); 554 | goto exit; 555 | } 556 | 557 | // 558 | // Allocate a waitlock to guard access to the default buffers 559 | // 560 | status = WdfWaitLockCreate( 561 | WDF_NO_OBJECT_ATTRIBUTES, 562 | &SpbContext->SpbLock); 563 | 564 | if (!NT_SUCCESS(status)) 565 | { 566 | RaydPrint( 567 | DEBUG_LEVEL_ERROR, 568 | DBG_IOCTL, 569 | "Error creating Spb Waitlock - %!STATUS!", 570 | status); 571 | goto exit; 572 | } 573 | 574 | exit: 575 | 576 | if (!NT_SUCCESS(status)) 577 | { 578 | SpbTargetDeinitialize(FxDevice, SpbContext); 579 | } 580 | 581 | return status; 582 | } -------------------------------------------------------------------------------- /crostouchscreen2/rayd.cpp: -------------------------------------------------------------------------------- 1 | #define DESCRIPTOR_DEF 2 | #include "raydium_i2c.h" 3 | 4 | static ULONG RaydDebugLevel = 100; 5 | static ULONG RaydDebugCatagories = DBG_INIT || DBG_PNP || DBG_IOCTL; 6 | 7 | NTSTATUS 8 | DriverEntry( 9 | __in PDRIVER_OBJECT DriverObject, 10 | __in PUNICODE_STRING RegistryPath 11 | ) 12 | { 13 | NTSTATUS status = STATUS_SUCCESS; 14 | WDF_DRIVER_CONFIG config; 15 | WDF_OBJECT_ATTRIBUTES attributes; 16 | 17 | RaydPrint(DEBUG_LEVEL_INFO, DBG_INIT, 18 | "Driver Entry\n"); 19 | 20 | WDF_DRIVER_CONFIG_INIT(&config, RaydEvtDeviceAdd); 21 | 22 | WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 23 | 24 | // 25 | // Create a framework driver object to represent our driver. 26 | // 27 | 28 | status = WdfDriverCreate(DriverObject, 29 | RegistryPath, 30 | &attributes, 31 | &config, 32 | WDF_NO_HANDLE 33 | ); 34 | 35 | if (!NT_SUCCESS(status)) 36 | { 37 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_INIT, 38 | "WdfDriverCreate failed with status 0x%x\n", status); 39 | } 40 | 41 | return status; 42 | } 43 | 44 | #include 45 | struct raydium_bank_switch_header { 46 | UINT8 cmd; 47 | UINT32 be_addr; 48 | }; 49 | #include 50 | 51 | static NTSTATUS raydium_i2c_send(PRAYD_CONTEXT pDevice, UINT32 addr, const UINT8* data, UINT32 len) { 52 | NTSTATUS status; 53 | 54 | UINT8 regAddr = addr & 0xFF; 55 | UINT8 *txBuf = (UINT8 *)ExAllocatePool2(POOL_FLAG_NON_PAGED, len + 1, RAYD_POOL_TAG); 56 | if (!txBuf) { 57 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 58 | "Failed to allocate txBuf\n"); 59 | return STATUS_NO_MEMORY; 60 | } 61 | 62 | LONGLONG Timeout; 63 | Timeout = -10 * 1000; 64 | status = WdfWaitLockAcquire(pDevice->I2CContext.SpbLock, &Timeout); 65 | if (status == STATUS_TIMEOUT) { 66 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 67 | "Timed out trying to acquire lock for write\n"); 68 | return STATUS_IO_TIMEOUT; 69 | } 70 | 71 | txBuf[0] = regAddr; 72 | RtlCopyMemory(txBuf + 1, data, len); 73 | 74 | status = SpbLockController(&pDevice->I2CContext); //Perform as a single i2c transfer transaction 75 | if (!NT_SUCCESS(status)) 76 | { 77 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 78 | "Failed to lock controller with status 0x%x\n", status); 79 | goto exit; 80 | } 81 | 82 | int tries = 0; 83 | do { 84 | struct raydium_bank_switch_header header; 85 | header.cmd = RM_CMD_BANK_SWITCH, 86 | header.be_addr = RtlUlongByteSwap(addr); 87 | 88 | if (addr > 0xFF) { //need to send RM_CMD_BANK_SWITCH first 89 | status = SpbWriteDataSynchronously(&pDevice->I2CContext, &header, sizeof(header)); 90 | if (!NT_SUCCESS(status)) { 91 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 92 | "Failed to send RM_CMD_BANK_SWITCH 0x%x\n", status); 93 | goto retry; 94 | } 95 | } 96 | 97 | status = SpbWriteDataSynchronously(&pDevice->I2CContext, txBuf, len + 1); 98 | if (!NT_SUCCESS(status)) { 99 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 100 | "Failed to send data 0x%x\n", status); 101 | goto retry; 102 | } 103 | break; 104 | retry: 105 | LARGE_INTEGER Interval; 106 | Interval.QuadPart = -10 * 1000 * RM_RETRY_DELAY_MS; 107 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 108 | } while (++tries < RM_MAX_RETRIES); 109 | 110 | exit: 111 | SpbUnlockController(&pDevice->I2CContext); 112 | 113 | ExFreePoolWithTag(txBuf, RAYD_POOL_TAG); 114 | 115 | WdfWaitLockRelease(pDevice->I2CContext.SpbLock); 116 | 117 | return status; 118 | } 119 | 120 | static NTSTATUS raydium_i2c_readSubset(PRAYD_CONTEXT pDevice, UINT32 addr, UINT8* data, UINT32 len) { 121 | NTSTATUS status; 122 | 123 | UINT8 regAddr = addr & 0xFF; 124 | 125 | LONGLONG Timeout; 126 | Timeout = -10 * 1000; 127 | status = WdfWaitLockAcquire(pDevice->I2CContext.SpbLock, &Timeout); 128 | if (status == STATUS_TIMEOUT) { 129 | return STATUS_IO_TIMEOUT; 130 | } 131 | 132 | status = SpbLockController(&pDevice->I2CContext); //Perform as a single i2c transfer transaction 133 | if (!NT_SUCCESS(status)) 134 | { 135 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 136 | "Failed to lock controller with status 0x%x\n", status); 137 | goto exit; 138 | } 139 | 140 | struct raydium_bank_switch_header header; 141 | header.cmd = RM_CMD_BANK_SWITCH, 142 | header.be_addr = RtlUlongByteSwap(addr); 143 | 144 | if (addr > 0xFF) { //need to send RM_CMD_BANK_SWITCH first 145 | status = SpbWriteDataSynchronously(&pDevice->I2CContext, &header, sizeof(header)); 146 | if (!NT_SUCCESS(status)) { 147 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 148 | "Failed to send RM_CMD_BANK_SWITCH 0x%x\n", status); 149 | goto exit; 150 | } 151 | } 152 | 153 | status = SpbXferDataSynchronously(&pDevice->I2CContext, ®Addr, 1, (PVOID)data, len); 154 | if (!NT_SUCCESS(status)) { 155 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 156 | "Failed to xfer data 0x%x\n", status); 157 | goto exit; 158 | } 159 | 160 | exit: 161 | SpbUnlockController(&pDevice->I2CContext); 162 | 163 | WdfWaitLockRelease(pDevice->I2CContext.SpbLock); 164 | 165 | return status; 166 | } 167 | 168 | static NTSTATUS raydium_i2c_read(PRAYD_CONTEXT pDevice, UINT32 addr, UINT8* data, UINT32 len) { 169 | NTSTATUS status = STATUS_SUCCESS; 170 | 171 | while (len) { 172 | UINT32 xfer_len = min(len, RM_MAX_READ_SIZE); 173 | 174 | status = raydium_i2c_readSubset(pDevice, addr, data, xfer_len); 175 | if (!NT_SUCCESS(status)) { 176 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 177 | "subset read failed! (read %d of %d)\n", total_len - len, total_len); 178 | return status; 179 | } 180 | 181 | len -= xfer_len; 182 | data += xfer_len; 183 | addr += xfer_len; 184 | } 185 | return status; 186 | } 187 | 188 | static NTSTATUS raydium_i2c_sw_reset(_In_ PRAYD_CONTEXT pDevice) 189 | { 190 | const UINT8 soft_rst_cmd = 0x01; 191 | NTSTATUS status; 192 | 193 | status = raydium_i2c_send(pDevice, RM_RESET_MSG_ADDR, &soft_rst_cmd, 194 | sizeof(soft_rst_cmd)); 195 | if (!NT_SUCCESS(status)) { 196 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 197 | "software reset failed: %d\n", status); 198 | return status; 199 | } 200 | 201 | LARGE_INTEGER Interval; 202 | Interval.QuadPart = -10 * 1000 * RM_RESET_DELAY_MSEC; 203 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 204 | 205 | return 0; 206 | } 207 | 208 | static NTSTATUS raydium_i2c_query_ts_info(_In_ PRAYD_CONTEXT pDevice) { 209 | struct raydium_data_info data_info; 210 | UINT32 queryBankAddr; 211 | 212 | NTSTATUS status; 213 | int retry_cnt; 214 | 215 | for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { 216 | status = raydium_i2c_read(pDevice, RM_CMD_DATA_BANK, (UINT8 *)&data_info, sizeof(data_info)); 217 | if (!NT_SUCCESS(status)) 218 | continue; 219 | 220 | pDevice->packageSize = data_info.pkg_size; 221 | pDevice->reportSize = pDevice->packageSize - RM_PACKET_CRC_SIZE; 222 | pDevice->contactSize = data_info.tp_info_size; 223 | pDevice->dataBankAddr = data_info.data_bank_addr; 224 | 225 | status = raydium_i2c_read(pDevice, RM_CMD_QUERY_BANK, (UINT8*)&queryBankAddr, sizeof(queryBankAddr)); 226 | if (!NT_SUCCESS(status)) 227 | continue; 228 | 229 | status = raydium_i2c_read(pDevice, queryBankAddr, (UINT8*)&pDevice->info, sizeof(pDevice->info)); 230 | if (!NT_SUCCESS(status)) 231 | continue; 232 | 233 | DbgPrint("Raydium Touch Screen Initialized (%d x %d)\n", pDevice->info.x_max, pDevice->info.y_max); 234 | 235 | pDevice->max_x_hid[0] = pDevice->info.x_max & 0xFF; 236 | pDevice->max_x_hid[1] = pDevice->info.x_max >> 8; 237 | 238 | pDevice->max_y_hid[0] = pDevice->info.y_max & 0xFF; 239 | pDevice->max_y_hid[1] = pDevice->info.y_max >> 8; 240 | break; 241 | } 242 | return status; 243 | } 244 | 245 | static NTSTATUS raydium_i2c_check_fw_status(PRAYD_CONTEXT pDevice) { 246 | static const UINT8 bl_ack = 0x62; 247 | static const UINT8 main_ack = 0x66; 248 | UINT8 buf[4]; 249 | NTSTATUS status; 250 | 251 | status = raydium_i2c_read(pDevice, RM_CMD_BOOT_READ, buf, sizeof(buf)); 252 | if (NT_SUCCESS(status)) { 253 | if (buf[0] == bl_ack) 254 | pDevice->bootMode = RAYDIUM_TS_BLDR; 255 | else if (buf[0] == main_ack) 256 | pDevice->bootMode = RAYDIUM_TS_MAIN; 257 | return status; 258 | } 259 | return status; 260 | } 261 | 262 | NTSTATUS BOOTTOUCHSCREEN( 263 | _In_ PRAYD_CONTEXT devContext 264 | ) 265 | { 266 | NTSTATUS status; 267 | 268 | if (devContext->TouchScreenBooted) 269 | return STATUS_SUCCESS; 270 | 271 | int retryCount; 272 | for (retryCount = 0; retryCount < RM_MAX_RETRIES; retryCount++) { 273 | /* Wait for Hello packet */ 274 | LARGE_INTEGER Interval; 275 | Interval.QuadPart = -10 * 1000 * RM_BOOT_DELAY_MS; 276 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 277 | 278 | status = raydium_i2c_check_fw_status(devContext); 279 | if (!NT_SUCCESS(status)) { 280 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "failed to read 'hello' packet: 0x%x\n", status); 281 | continue; 282 | } 283 | 284 | if (devContext->bootMode == RAYDIUM_TS_BLDR || 285 | devContext->bootMode == RAYDIUM_TS_MAIN) { 286 | break; 287 | } 288 | } 289 | 290 | if (!NT_SUCCESS(status)) 291 | devContext->bootMode = RAYDIUM_TS_BLDR; 292 | 293 | if (devContext->bootMode == RAYDIUM_TS_MAIN) { 294 | status = raydium_i2c_query_ts_info(devContext); 295 | if (!NT_SUCCESS(status)) { 296 | return status; 297 | } 298 | devContext->reportData = (UINT8 *)ExAllocatePool2(POOL_FLAG_NON_PAGED, devContext->packageSize, RAYD_POOL_TAG); 299 | if (!devContext->reportData) 300 | return STATUS_NO_MEMORY; 301 | 302 | devContext->TouchScreenBooted = true; 303 | return status; 304 | } 305 | else { 306 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Bootloader state not supported\n"); 307 | return STATUS_INVALID_DEVICE_STATE; 308 | } 309 | } 310 | 311 | NTSTATUS 312 | OnPrepareHardware( 313 | _In_ WDFDEVICE FxDevice, 314 | _In_ WDFCMRESLIST FxResourcesRaw, 315 | _In_ WDFCMRESLIST FxResourcesTranslated 316 | ) 317 | /*++ 318 | 319 | Routine Description: 320 | 321 | This routine caches the SPB resource connection ID. 322 | 323 | Arguments: 324 | 325 | FxDevice - a handle to the framework device object 326 | FxResourcesRaw - list of translated hardware resources that 327 | the PnP manager has assigned to the device 328 | FxResourcesTranslated - list of raw hardware resources that 329 | the PnP manager has assigned to the device 330 | 331 | Return Value: 332 | 333 | Status 334 | 335 | --*/ 336 | { 337 | PRAYD_CONTEXT pDevice = GetDeviceContext(FxDevice); 338 | BOOLEAN fSpbResourceFound = FALSE; 339 | NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; 340 | 341 | UNREFERENCED_PARAMETER(FxResourcesRaw); 342 | 343 | // 344 | // Parse the peripheral's resources. 345 | // 346 | 347 | ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); 348 | 349 | for (ULONG i = 0; i < resourceCount; i++) 350 | { 351 | PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; 352 | UCHAR Class; 353 | UCHAR Type; 354 | 355 | pDescriptor = WdfCmResourceListGetDescriptor( 356 | FxResourcesTranslated, i); 357 | 358 | switch (pDescriptor->Type) 359 | { 360 | case CmResourceTypeConnection: 361 | // 362 | // Look for I2C or SPI resource and save connection ID. 363 | // 364 | Class = pDescriptor->u.Connection.Class; 365 | Type = pDescriptor->u.Connection.Type; 366 | if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && 367 | Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) 368 | { 369 | if (fSpbResourceFound == FALSE) 370 | { 371 | status = STATUS_SUCCESS; 372 | pDevice->I2CContext.I2cResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; 373 | pDevice->I2CContext.I2cResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; 374 | fSpbResourceFound = TRUE; 375 | } 376 | else 377 | { 378 | } 379 | } 380 | break; 381 | default: 382 | // 383 | // Ignoring all other resource types. 384 | // 385 | break; 386 | } 387 | } 388 | 389 | // 390 | // An SPB resource is required. 391 | // 392 | 393 | if (fSpbResourceFound == FALSE) 394 | { 395 | status = STATUS_NOT_FOUND; 396 | } 397 | 398 | status = SpbTargetInitialize(FxDevice, &pDevice->I2CContext); 399 | 400 | if (!NT_SUCCESS(status)) 401 | { 402 | return status; 403 | } 404 | 405 | return status; 406 | } 407 | 408 | NTSTATUS 409 | OnReleaseHardware( 410 | _In_ WDFDEVICE FxDevice, 411 | _In_ WDFCMRESLIST FxResourcesTranslated 412 | ) 413 | /*++ 414 | 415 | Routine Description: 416 | 417 | Arguments: 418 | 419 | FxDevice - a handle to the framework device object 420 | FxResourcesTranslated - list of raw hardware resources that 421 | the PnP manager has assigned to the device 422 | 423 | Return Value: 424 | 425 | Status 426 | 427 | --*/ 428 | { 429 | PRAYD_CONTEXT pDevice = GetDeviceContext(FxDevice); 430 | NTSTATUS status = STATUS_SUCCESS; 431 | 432 | UNREFERENCED_PARAMETER(FxResourcesTranslated); 433 | 434 | if (pDevice->reportData) { 435 | ExFreePoolWithTag(pDevice->reportData, RAYD_POOL_TAG); 436 | } 437 | 438 | SpbTargetDeinitialize(FxDevice, &pDevice->I2CContext); 439 | 440 | return status; 441 | } 442 | 443 | NTSTATUS 444 | OnD0Entry( 445 | _In_ WDFDEVICE FxDevice, 446 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 447 | ) 448 | /*++ 449 | 450 | Routine Description: 451 | 452 | This routine allocates objects needed by the driver. 453 | 454 | Arguments: 455 | 456 | FxDevice - a handle to the framework device object 457 | FxPreviousState - previous power state 458 | 459 | Return Value: 460 | 461 | Status 462 | 463 | --*/ 464 | { 465 | UNREFERENCED_PARAMETER(FxPreviousState); 466 | 467 | PRAYD_CONTEXT pDevice = GetDeviceContext(FxDevice); 468 | NTSTATUS status = STATUS_SUCCESS; 469 | 470 | status = raydium_i2c_sw_reset(pDevice); 471 | if (!NT_SUCCESS(status)) { 472 | return status; 473 | } 474 | 475 | for (int i = 0; i < 20; i++) { 476 | pDevice->Flags[i] = 0; 477 | } 478 | 479 | pDevice->RegsSet = false; 480 | pDevice->ConnectInterrupt = true; 481 | 482 | status = BOOTTOUCHSCREEN(pDevice); 483 | if (!NT_SUCCESS(status)) { 484 | return status; 485 | } 486 | 487 | return status; 488 | } 489 | 490 | NTSTATUS 491 | OnD0Exit( 492 | _In_ WDFDEVICE FxDevice, 493 | _In_ WDF_POWER_DEVICE_STATE FxPreviousState 494 | ) 495 | /*++ 496 | 497 | Routine Description: 498 | 499 | This routine destroys objects needed by the driver. 500 | 501 | Arguments: 502 | 503 | FxDevice - a handle to the framework device object 504 | FxPreviousState - previous power state 505 | 506 | Return Value: 507 | 508 | Status 509 | 510 | --*/ 511 | { 512 | UNREFERENCED_PARAMETER(FxPreviousState); 513 | 514 | PRAYD_CONTEXT pDevice = GetDeviceContext(FxDevice); 515 | 516 | pDevice->ConnectInterrupt = false; 517 | 518 | return STATUS_SUCCESS; 519 | } 520 | 521 | void RaydProcessInput(PRAYD_CONTEXT pDevice) { 522 | struct _RAYD_MULTITOUCH_REPORT report; 523 | report.ReportID = REPORTID_MTOUCH; 524 | 525 | int count = 0, i = 0; 526 | while (count < 10 && i < 20) { 527 | if (pDevice->Flags[i] != 0) { 528 | report.Touch[count].ContactID = (BYTE)i; 529 | report.Touch[count].Height = pDevice->AREA[i]; 530 | report.Touch[count].Width = pDevice->AREA[i]; 531 | 532 | report.Touch[count].XValue = pDevice->XValue[i]; 533 | report.Touch[count].YValue = pDevice->YValue[i]; 534 | 535 | uint8_t flags = pDevice->Flags[i]; 536 | if (flags & MXT_T9_DETECT) { 537 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT | MULTI_TIPSWITCH_BIT; 538 | } 539 | else if (flags & MXT_T9_PRESS) { 540 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT | MULTI_TIPSWITCH_BIT; 541 | } 542 | else if (flags & MXT_T9_RELEASE) { 543 | report.Touch[count].Status = MULTI_CONFIDENCE_BIT; 544 | pDevice->Flags[i] = 0; 545 | } 546 | else 547 | report.Touch[count].Status = 0; 548 | 549 | count++; 550 | } 551 | i++; 552 | } 553 | 554 | report.ActualCount = (BYTE)count; 555 | 556 | if (count > 0) { 557 | size_t bytesWritten; 558 | RaydProcessVendorReport(pDevice, &report, sizeof(report), &bytesWritten); 559 | } 560 | } 561 | 562 | static UINT16 raydium_calc_chksum(const UINT8* buf, UINT16 len) 563 | { 564 | UINT16 checksum = 0; 565 | UINT16 i; 566 | 567 | for (i = 0; i < len; i++) 568 | checksum += buf[i]; 569 | 570 | return checksum; 571 | } 572 | 573 | BOOLEAN OnInterruptIsr( 574 | WDFINTERRUPT Interrupt, 575 | ULONG MessageID) { 576 | UNREFERENCED_PARAMETER(MessageID); 577 | 578 | WDFDEVICE Device = WdfInterruptGetDevice(Interrupt); 579 | PRAYD_CONTEXT pDevice = GetDeviceContext(Device); 580 | 581 | UNREFERENCED_PARAMETER(pDevice); 582 | NTSTATUS status; 583 | 584 | if (!pDevice->ConnectInterrupt) { 585 | return false; 586 | } 587 | 588 | 589 | if (!pDevice->TouchScreenBooted) { 590 | return false; 591 | } 592 | 593 | status = raydium_i2c_read(pDevice, pDevice->dataBankAddr, pDevice->reportData, pDevice->packageSize); 594 | if (!NT_SUCCESS(status)) { 595 | return true; 596 | } 597 | 598 | UINT16 fw_crc = *((UINT16 *)&pDevice->reportData[pDevice->reportSize]); 599 | UINT16 calc_crc = raydium_calc_chksum(pDevice->reportData, pDevice->reportSize); 600 | if (fw_crc != calc_crc) { 601 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_INIT, "Invalid raydium crc %#04x vs %#04x\n", calc_crc, fw_crc); 602 | return true; 603 | } 604 | 605 | for (int i = 0; i < pDevice->reportSize / pDevice->contactSize; i++) { 606 | UINT8* contact = &pDevice->reportData[pDevice->contactSize * i]; 607 | bool state = contact[RM_CONTACT_STATE_POS]; 608 | UINT8 wx, wy; 609 | 610 | if (!state && pDevice->Flags[i] == MXT_T9_DETECT) { 611 | pDevice->Flags[i] = MXT_T9_RELEASE; 612 | } else if (state) { 613 | pDevice->Flags[i] = MXT_T9_DETECT; 614 | } else { 615 | pDevice->Flags[i] = 0; 616 | } 617 | 618 | if (!state) 619 | continue; 620 | 621 | wx = contact[RM_CONTACT_WIDTH_X_POS]; 622 | wy = contact[RM_CONTACT_WIDTH_Y_POS]; 623 | 624 | pDevice->XValue[i] = *((UINT16*)&contact[RM_CONTACT_X_POS]); 625 | pDevice->YValue[i] = *((UINT16*)&contact[RM_CONTACT_Y_POS]); 626 | 627 | pDevice->AREA[i] = max(wx, wy); 628 | } 629 | 630 | RaydProcessInput(pDevice); 631 | 632 | return true; 633 | } 634 | 635 | NTSTATUS 636 | RaydEvtDeviceAdd( 637 | IN WDFDRIVER Driver, 638 | IN PWDFDEVICE_INIT DeviceInit 639 | ) 640 | { 641 | NTSTATUS status = STATUS_SUCCESS; 642 | WDF_IO_QUEUE_CONFIG queueConfig; 643 | WDF_OBJECT_ATTRIBUTES attributes; 644 | WDFDEVICE device; 645 | WDF_INTERRUPT_CONFIG interruptConfig; 646 | WDFQUEUE queue; 647 | PRAYD_CONTEXT devContext; 648 | 649 | UNREFERENCED_PARAMETER(Driver); 650 | 651 | PAGED_CODE(); 652 | 653 | RaydPrint(DEBUG_LEVEL_INFO, DBG_PNP, 654 | "RaydEvtDeviceAdd called\n"); 655 | 656 | // 657 | // Tell framework this is a filter driver. Filter drivers by default are 658 | // not power policy owners. This works well for this driver because 659 | // HIDclass driver is the power policy owner for HID minidrivers. 660 | // 661 | 662 | WdfFdoInitSetFilter(DeviceInit); 663 | 664 | { 665 | WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; 666 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); 667 | 668 | pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; 669 | pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; 670 | pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; 671 | pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; 672 | 673 | WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); 674 | } 675 | 676 | // 677 | // Setup the device context 678 | // 679 | 680 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, RAYD_CONTEXT); 681 | 682 | // 683 | // Create a framework device object.This call will in turn create 684 | // a WDM device object, attach to the lower stack, and set the 685 | // appropriate flags and attributes. 686 | // 687 | 688 | status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 689 | 690 | if (!NT_SUCCESS(status)) 691 | { 692 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 693 | "WdfDeviceCreate failed with status code 0x%x\n", status); 694 | 695 | return status; 696 | } 697 | 698 | WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); 699 | 700 | queueConfig.EvtIoInternalDeviceControl = RaydEvtInternalDeviceControl; 701 | 702 | status = WdfIoQueueCreate(device, 703 | &queueConfig, 704 | WDF_NO_OBJECT_ATTRIBUTES, 705 | &queue 706 | ); 707 | 708 | if (!NT_SUCCESS(status)) 709 | { 710 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 711 | "WdfIoQueueCreate failed 0x%x\n", status); 712 | 713 | return status; 714 | } 715 | 716 | // 717 | // Create manual I/O queue to take care of hid report read requests 718 | // 719 | 720 | devContext = GetDeviceContext(device); 721 | 722 | devContext->TouchScreenBooted = false; 723 | 724 | devContext->FxDevice = device; 725 | 726 | WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 727 | 728 | queueConfig.PowerManaged = WdfFalse; 729 | 730 | status = WdfIoQueueCreate(device, 731 | &queueConfig, 732 | WDF_NO_OBJECT_ATTRIBUTES, 733 | &devContext->ReportQueue 734 | ); 735 | 736 | if (!NT_SUCCESS(status)) 737 | { 738 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 739 | "WdfIoQueueCreate failed 0x%x\n", status); 740 | 741 | return status; 742 | } 743 | 744 | // 745 | // Create an interrupt object for hardware notifications 746 | // 747 | WDF_INTERRUPT_CONFIG_INIT( 748 | &interruptConfig, 749 | OnInterruptIsr, 750 | NULL); 751 | interruptConfig.PassiveHandling = TRUE; 752 | 753 | status = WdfInterruptCreate( 754 | device, 755 | &interruptConfig, 756 | WDF_NO_OBJECT_ATTRIBUTES, 757 | &devContext->Interrupt); 758 | 759 | if (!NT_SUCCESS(status)) 760 | { 761 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_PNP, 762 | "Error creating WDF interrupt object - %!STATUS!", 763 | status); 764 | 765 | return status; 766 | } 767 | 768 | // 769 | // Initialize DeviceMode 770 | // 771 | 772 | devContext->DeviceMode = DEVICE_MODE_MOUSE; 773 | 774 | return status; 775 | } 776 | 777 | VOID 778 | RaydEvtInternalDeviceControl( 779 | IN WDFQUEUE Queue, 780 | IN WDFREQUEST Request, 781 | IN size_t OutputBufferLength, 782 | IN size_t InputBufferLength, 783 | IN ULONG IoControlCode 784 | ) 785 | { 786 | NTSTATUS status = STATUS_SUCCESS; 787 | WDFDEVICE device; 788 | PRAYD_CONTEXT devContext; 789 | BOOLEAN completeRequest = TRUE; 790 | 791 | UNREFERENCED_PARAMETER(OutputBufferLength); 792 | UNREFERENCED_PARAMETER(InputBufferLength); 793 | 794 | device = WdfIoQueueGetDevice(Queue); 795 | devContext = GetDeviceContext(device); 796 | 797 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 798 | "%s, Queue:0x%p, Request:0x%p\n", 799 | DbgHidInternalIoctlString(IoControlCode), 800 | Queue, 801 | Request 802 | ); 803 | 804 | // 805 | // Please note that HIDCLASS provides the buffer in the Irp->UserBuffer 806 | // field irrespective of the ioctl buffer type. However, framework is very 807 | // strict about type checking. You cannot get Irp->UserBuffer by using 808 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 809 | // internal ioctl. So depending on the ioctl code, we will either 810 | // use retreive function or escape to WDM to get the UserBuffer. 811 | // 812 | 813 | switch (IoControlCode) 814 | { 815 | 816 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 817 | // 818 | // Retrieves the device's HID descriptor. 819 | // 820 | status = RaydGetHidDescriptor(device, Request); 821 | break; 822 | 823 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 824 | // 825 | //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. 826 | // 827 | status = RaydGetDeviceAttributes(Request); 828 | break; 829 | 830 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 831 | // 832 | //Obtains the report descriptor for the HID device. 833 | // 834 | status = RaydGetReportDescriptor(device, Request); 835 | break; 836 | 837 | case IOCTL_HID_GET_STRING: 838 | // 839 | // Requests that the HID minidriver retrieve a human-readable string 840 | // for either the manufacturer ID, the product ID, or the serial number 841 | // from the string descriptor of the device. The minidriver must send 842 | // a Get String Descriptor request to the device, in order to retrieve 843 | // the string descriptor, then it must extract the string at the 844 | // appropriate index from the string descriptor and return it in the 845 | // output buffer indicated by the IRP. Before sending the Get String 846 | // Descriptor request, the minidriver must retrieve the appropriate 847 | // index for the manufacturer ID, the product ID or the serial number 848 | // from the device extension of a top level collection associated with 849 | // the device. 850 | // 851 | status = RaydGetString(Request); 852 | break; 853 | 854 | case IOCTL_HID_WRITE_REPORT: 855 | case IOCTL_HID_SET_OUTPUT_REPORT: 856 | // 857 | //Transmits a class driver-supplied report to the device. 858 | // 859 | status = RaydWriteReport(devContext, Request); 860 | break; 861 | 862 | case IOCTL_HID_READ_REPORT: 863 | case IOCTL_HID_GET_INPUT_REPORT: 864 | // 865 | // Returns a report from the device into a class driver-supplied buffer. 866 | // 867 | status = RaydReadReport(devContext, Request, &completeRequest); 868 | break; 869 | 870 | case IOCTL_HID_SET_FEATURE: 871 | // 872 | // This sends a HID class feature report to a top-level collection of 873 | // a HID class device. 874 | // 875 | status = RaydSetFeature(devContext, Request, &completeRequest); 876 | break; 877 | 878 | case IOCTL_HID_GET_FEATURE: 879 | // 880 | // returns a feature report associated with a top-level collection 881 | // 882 | status = RaydGetFeature(devContext, Request, &completeRequest); 883 | break; 884 | 885 | case IOCTL_HID_ACTIVATE_DEVICE: 886 | // 887 | // Makes the device ready for I/O operations. 888 | // 889 | case IOCTL_HID_DEACTIVATE_DEVICE: 890 | // 891 | // Causes the device to cease operations and terminate all outstanding 892 | // I/O requests. 893 | // 894 | default: 895 | status = STATUS_NOT_SUPPORTED; 896 | break; 897 | } 898 | 899 | if (completeRequest) 900 | { 901 | WdfRequestComplete(Request, status); 902 | 903 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 904 | "%s completed, Queue:0x%p, Request:0x%p\n", 905 | DbgHidInternalIoctlString(IoControlCode), 906 | Queue, 907 | Request 908 | ); 909 | } 910 | else 911 | { 912 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 913 | "%s deferred, Queue:0x%p, Request:0x%p\n", 914 | DbgHidInternalIoctlString(IoControlCode), 915 | Queue, 916 | Request 917 | ); 918 | } 919 | 920 | return; 921 | } 922 | 923 | NTSTATUS 924 | RaydGetHidDescriptor( 925 | IN WDFDEVICE Device, 926 | IN WDFREQUEST Request 927 | ) 928 | { 929 | NTSTATUS status = STATUS_SUCCESS; 930 | size_t bytesToCopy = 0; 931 | WDFMEMORY memory; 932 | 933 | UNREFERENCED_PARAMETER(Device); 934 | 935 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 936 | "RaydGetHidDescriptor Entry\n"); 937 | 938 | // 939 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 940 | // will correctly retrieve buffer from Irp->UserBuffer. 941 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 942 | // field irrespective of the ioctl buffer type. However, framework is very 943 | // strict about type checking. You cannot get Irp->UserBuffer by using 944 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 945 | // internal ioctl. 946 | // 947 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 948 | 949 | if (!NT_SUCCESS(status)) 950 | { 951 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 952 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 953 | 954 | return status; 955 | } 956 | 957 | // 958 | // Use hardcoded "HID Descriptor" 959 | // 960 | bytesToCopy = DefaultHidDescriptor.bLength; 961 | 962 | if (bytesToCopy == 0) 963 | { 964 | status = STATUS_INVALID_DEVICE_STATE; 965 | 966 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 967 | "DefaultHidDescriptor is zero, 0x%x\n", status); 968 | 969 | return status; 970 | } 971 | 972 | status = WdfMemoryCopyFromBuffer(memory, 973 | 0, // Offset 974 | (PVOID)&DefaultHidDescriptor, 975 | bytesToCopy); 976 | 977 | if (!NT_SUCCESS(status)) 978 | { 979 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 980 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 981 | 982 | return status; 983 | } 984 | 985 | // 986 | // Report how many bytes were copied 987 | // 988 | WdfRequestSetInformation(Request, bytesToCopy); 989 | 990 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 991 | "RaydGetHidDescriptor Exit = 0x%x\n", status); 992 | 993 | return status; 994 | } 995 | 996 | NTSTATUS 997 | RaydGetReportDescriptor( 998 | IN WDFDEVICE Device, 999 | IN WDFREQUEST Request 1000 | ) 1001 | { 1002 | NTSTATUS status = STATUS_SUCCESS; 1003 | ULONG_PTR bytesToCopy; 1004 | WDFMEMORY memory; 1005 | 1006 | PRAYD_CONTEXT devContext = GetDeviceContext(Device); 1007 | 1008 | UNREFERENCED_PARAMETER(Device); 1009 | 1010 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1011 | "RaydGetReportDescriptor Entry\n"); 1012 | 1013 | #define MT_TOUCH_COLLECTION \ 1014 | MT_TOUCH_COLLECTION0 \ 1015 | 0x26, devContext->max_x_hid[0], devContext->max_x_hid[1], /* LOGICAL_MAXIMUM (WIDTH) */ \ 1016 | MT_TOUCH_COLLECTION1 \ 1017 | 0x26, devContext->max_y_hid[0], devContext->max_y_hid[1], /* LOGICAL_MAXIMUM (HEIGHT) */ \ 1018 | MT_TOUCH_COLLECTION2 \ 1019 | 1020 | HID_REPORT_DESCRIPTOR ReportDescriptor[] = { 1021 | // 1022 | // Multitouch report starts here 1023 | // 1024 | 0x05, 0x0d, // USAGE_PAGE (Digitizers) 1025 | 0x09, 0x04, // USAGE (Touch Screen) 1026 | 0xa1, 0x01, // COLLECTION (Application) 1027 | 0x85, REPORTID_MTOUCH, // REPORT_ID (Touch) 1028 | 0x09, 0x22, // USAGE (Finger) 1029 | MT_TOUCH_COLLECTION 1030 | MT_TOUCH_COLLECTION 1031 | MT_TOUCH_COLLECTION 1032 | MT_TOUCH_COLLECTION 1033 | MT_TOUCH_COLLECTION 1034 | MT_TOUCH_COLLECTION 1035 | MT_TOUCH_COLLECTION 1036 | MT_TOUCH_COLLECTION 1037 | MT_TOUCH_COLLECTION 1038 | MT_TOUCH_COLLECTION 1039 | USAGE_PAGE 1040 | 0xc0, // END_COLLECTION 1041 | }; 1042 | 1043 | // 1044 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 1045 | // will correctly retrieve buffer from Irp->UserBuffer. 1046 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 1047 | // field irrespective of the ioctl buffer type. However, framework is very 1048 | // strict about type checking. You cannot get Irp->UserBuffer by using 1049 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 1050 | // internal ioctl. 1051 | // 1052 | status = WdfRequestRetrieveOutputMemory(Request, &memory); 1053 | if (!NT_SUCCESS(status)) 1054 | { 1055 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1056 | "WdfRequestRetrieveOutputMemory failed 0x%x\n", status); 1057 | 1058 | return status; 1059 | } 1060 | 1061 | // 1062 | // Use hardcoded Report descriptor 1063 | // 1064 | bytesToCopy = DefaultHidDescriptor.DescriptorList[0].wReportLength; 1065 | 1066 | if (bytesToCopy == 0) 1067 | { 1068 | status = STATUS_INVALID_DEVICE_STATE; 1069 | 1070 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1071 | "DefaultHidDescriptor's reportLength is zero, 0x%x\n", status); 1072 | 1073 | return status; 1074 | } 1075 | 1076 | status = WdfMemoryCopyFromBuffer(memory, 1077 | 0, 1078 | (PVOID)ReportDescriptor, 1079 | bytesToCopy); 1080 | if (!NT_SUCCESS(status)) 1081 | { 1082 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1083 | "WdfMemoryCopyFromBuffer failed 0x%x\n", status); 1084 | 1085 | return status; 1086 | } 1087 | 1088 | // 1089 | // Report how many bytes were copied 1090 | // 1091 | WdfRequestSetInformation(Request, bytesToCopy); 1092 | 1093 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1094 | "RaydGetReportDescriptor Exit = 0x%x\n", status); 1095 | 1096 | return status; 1097 | } 1098 | 1099 | 1100 | NTSTATUS 1101 | RaydGetDeviceAttributes( 1102 | IN WDFREQUEST Request 1103 | ) 1104 | { 1105 | NTSTATUS status = STATUS_SUCCESS; 1106 | PHID_DEVICE_ATTRIBUTES deviceAttributes = NULL; 1107 | 1108 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1109 | "RaydGetDeviceAttributes Entry\n"); 1110 | 1111 | // 1112 | // This IOCTL is METHOD_NEITHER so WdfRequestRetrieveOutputMemory 1113 | // will correctly retrieve buffer from Irp->UserBuffer. 1114 | // Remember that HIDCLASS provides the buffer in the Irp->UserBuffer 1115 | // field irrespective of the ioctl buffer type. However, framework is very 1116 | // strict about type checking. You cannot get Irp->UserBuffer by using 1117 | // WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER 1118 | // internal ioctl. 1119 | // 1120 | status = WdfRequestRetrieveOutputBuffer(Request, 1121 | sizeof(HID_DEVICE_ATTRIBUTES), 1122 | (PVOID *)&deviceAttributes, 1123 | NULL); 1124 | if (!NT_SUCCESS(status)) 1125 | { 1126 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1127 | "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); 1128 | 1129 | return status; 1130 | } 1131 | 1132 | // 1133 | // Set USB device descriptor 1134 | // 1135 | 1136 | deviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES); 1137 | deviceAttributes->VendorID = RAYD_VID; 1138 | deviceAttributes->ProductID = RAYD_PID; 1139 | deviceAttributes->VersionNumber = RAYD_VERSION; 1140 | 1141 | // 1142 | // Report how many bytes were copied 1143 | // 1144 | WdfRequestSetInformation(Request, sizeof(HID_DEVICE_ATTRIBUTES)); 1145 | 1146 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1147 | "RaydGetDeviceAttributes Exit = 0x%x\n", status); 1148 | 1149 | return status; 1150 | } 1151 | 1152 | NTSTATUS 1153 | RaydGetString( 1154 | IN WDFREQUEST Request 1155 | ) 1156 | { 1157 | 1158 | NTSTATUS status = STATUS_SUCCESS; 1159 | PWSTR pwstrID; 1160 | size_t lenID; 1161 | WDF_REQUEST_PARAMETERS params; 1162 | void *pStringBuffer = NULL; 1163 | 1164 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1165 | "RaydGetString Entry\n"); 1166 | 1167 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1168 | WdfRequestGetParameters(Request, ¶ms); 1169 | 1170 | switch ((ULONG_PTR)params.Parameters.DeviceIoControl.Type3InputBuffer & 0xFFFF) 1171 | { 1172 | case HID_STRING_ID_IMANUFACTURER: 1173 | pwstrID = L"Rayd.\0"; 1174 | break; 1175 | 1176 | case HID_STRING_ID_IPRODUCT: 1177 | pwstrID = L"Touch Screen\0"; 1178 | break; 1179 | 1180 | case HID_STRING_ID_ISERIALNUMBER: 1181 | pwstrID = L"123123123\0"; 1182 | break; 1183 | 1184 | default: 1185 | pwstrID = NULL; 1186 | break; 1187 | } 1188 | 1189 | lenID = pwstrID ? wcslen(pwstrID) * sizeof(WCHAR) + sizeof(UNICODE_NULL) : 0; 1190 | 1191 | if (pwstrID == NULL) 1192 | { 1193 | 1194 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1195 | "RaydGetString Invalid request type\n"); 1196 | 1197 | status = STATUS_INVALID_PARAMETER; 1198 | 1199 | return status; 1200 | } 1201 | 1202 | status = WdfRequestRetrieveOutputBuffer(Request, 1203 | lenID, 1204 | &pStringBuffer, 1205 | &lenID); 1206 | 1207 | if (!NT_SUCCESS(status)) 1208 | { 1209 | 1210 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1211 | "RaydGetString WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1212 | 1213 | return status; 1214 | } 1215 | 1216 | RtlCopyMemory(pStringBuffer, pwstrID, lenID); 1217 | 1218 | WdfRequestSetInformation(Request, lenID); 1219 | 1220 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1221 | "RaydGetString Exit = 0x%x\n", status); 1222 | 1223 | return status; 1224 | } 1225 | 1226 | NTSTATUS 1227 | RaydWriteReport( 1228 | IN PRAYD_CONTEXT DevContext, 1229 | IN WDFREQUEST Request 1230 | ) 1231 | { 1232 | UNREFERENCED_PARAMETER(DevContext); 1233 | 1234 | NTSTATUS status = STATUS_SUCCESS; 1235 | WDF_REQUEST_PARAMETERS params; 1236 | PHID_XFER_PACKET transferPacket = NULL; 1237 | 1238 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1239 | "RaydWriteReport Entry\n"); 1240 | 1241 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1242 | WdfRequestGetParameters(Request, ¶ms); 1243 | 1244 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1245 | { 1246 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1247 | "RaydWriteReport Xfer packet too small\n"); 1248 | 1249 | status = STATUS_BUFFER_TOO_SMALL; 1250 | } 1251 | else 1252 | { 1253 | 1254 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1255 | 1256 | if (transferPacket == NULL) 1257 | { 1258 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1259 | "RaydWriteReport No xfer packet\n"); 1260 | 1261 | status = STATUS_INVALID_DEVICE_REQUEST; 1262 | } 1263 | else 1264 | { 1265 | // 1266 | // switch on the report id 1267 | // 1268 | 1269 | //switch (transferPacket->reportId) 1270 | //{ 1271 | //default: 1272 | 1273 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1274 | "RaydWriteReport Unhandled report type %d\n", transferPacket->reportId); 1275 | 1276 | status = STATUS_INVALID_PARAMETER; 1277 | 1278 | //break; 1279 | //} 1280 | } 1281 | } 1282 | 1283 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1284 | "RaydWriteReport Exit = 0x%x\n", status); 1285 | 1286 | return status; 1287 | 1288 | } 1289 | 1290 | NTSTATUS 1291 | RaydProcessVendorReport( 1292 | IN PRAYD_CONTEXT DevContext, 1293 | IN PVOID ReportBuffer, 1294 | IN ULONG ReportBufferLen, 1295 | OUT size_t* BytesWritten 1296 | ) 1297 | { 1298 | NTSTATUS status = STATUS_SUCCESS; 1299 | WDFREQUEST reqRead; 1300 | PVOID pReadReport = NULL; 1301 | size_t bytesReturned = 0; 1302 | 1303 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1304 | "RaydProcessVendorReport Entry\n"); 1305 | 1306 | status = WdfIoQueueRetrieveNextRequest(DevContext->ReportQueue, 1307 | &reqRead); 1308 | 1309 | if (NT_SUCCESS(status)) 1310 | { 1311 | status = WdfRequestRetrieveOutputBuffer(reqRead, 1312 | ReportBufferLen, 1313 | &pReadReport, 1314 | &bytesReturned); 1315 | 1316 | if (NT_SUCCESS(status)) 1317 | { 1318 | // 1319 | // Copy ReportBuffer into read request 1320 | // 1321 | 1322 | if (bytesReturned > ReportBufferLen) 1323 | { 1324 | bytesReturned = ReportBufferLen; 1325 | } 1326 | 1327 | RtlCopyMemory(pReadReport, 1328 | ReportBuffer, 1329 | bytesReturned); 1330 | 1331 | // 1332 | // Complete read with the number of bytes returned as info 1333 | // 1334 | 1335 | WdfRequestCompleteWithInformation(reqRead, 1336 | status, 1337 | bytesReturned); 1338 | 1339 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1340 | "RaydProcessVendorReport %d bytes returned\n", bytesReturned); 1341 | 1342 | // 1343 | // Return the number of bytes written for the write request completion 1344 | // 1345 | 1346 | *BytesWritten = bytesReturned; 1347 | 1348 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1349 | "%s completed, Queue:0x%p, Request:0x%p\n", 1350 | DbgHidInternalIoctlString(IOCTL_HID_READ_REPORT), 1351 | DevContext->ReportQueue, 1352 | reqRead); 1353 | } 1354 | else 1355 | { 1356 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1357 | "WdfRequestRetrieveOutputBuffer failed Status 0x%x\n", status); 1358 | } 1359 | } 1360 | else 1361 | { 1362 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1363 | "WdfIoQueueRetrieveNextRequest failed Status 0x%x\n", status); 1364 | } 1365 | 1366 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1367 | "RaydProcessVendorReport Exit = 0x%x\n", status); 1368 | 1369 | return status; 1370 | } 1371 | 1372 | NTSTATUS 1373 | RaydReadReport( 1374 | IN PRAYD_CONTEXT DevContext, 1375 | IN WDFREQUEST Request, 1376 | OUT BOOLEAN* CompleteRequest 1377 | ) 1378 | { 1379 | NTSTATUS status = STATUS_SUCCESS; 1380 | 1381 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1382 | "RaydReadReport Entry\n"); 1383 | 1384 | // 1385 | // Forward this read request to our manual queue 1386 | // (in other words, we are going to defer this request 1387 | // until we have a corresponding write request to 1388 | // match it with) 1389 | // 1390 | 1391 | status = WdfRequestForwardToIoQueue(Request, DevContext->ReportQueue); 1392 | 1393 | if (!NT_SUCCESS(status)) 1394 | { 1395 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1396 | "WdfRequestForwardToIoQueue failed Status 0x%x\n", status); 1397 | } 1398 | else 1399 | { 1400 | *CompleteRequest = FALSE; 1401 | } 1402 | 1403 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1404 | "RaydReadReport Exit = 0x%x\n", status); 1405 | 1406 | return status; 1407 | } 1408 | 1409 | NTSTATUS 1410 | RaydSetFeature( 1411 | IN PRAYD_CONTEXT DevContext, 1412 | IN WDFREQUEST Request, 1413 | OUT BOOLEAN* CompleteRequest 1414 | ) 1415 | { 1416 | UNREFERENCED_PARAMETER(CompleteRequest); 1417 | 1418 | NTSTATUS status = STATUS_SUCCESS; 1419 | WDF_REQUEST_PARAMETERS params; 1420 | PHID_XFER_PACKET transferPacket = NULL; 1421 | RaydFeatureReport* pReport = NULL; 1422 | 1423 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1424 | "RaydSetFeature Entry\n"); 1425 | 1426 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1427 | WdfRequestGetParameters(Request, ¶ms); 1428 | 1429 | if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) 1430 | { 1431 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1432 | "RaydSetFeature Xfer packet too small\n"); 1433 | 1434 | status = STATUS_BUFFER_TOO_SMALL; 1435 | } 1436 | else 1437 | { 1438 | 1439 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1440 | 1441 | if (transferPacket == NULL) 1442 | { 1443 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1444 | "RaydWriteReport No xfer packet\n"); 1445 | 1446 | status = STATUS_INVALID_DEVICE_REQUEST; 1447 | } 1448 | else 1449 | { 1450 | // 1451 | // switch on the report id 1452 | // 1453 | 1454 | switch (transferPacket->reportId) 1455 | { 1456 | case REPORTID_FEATURE: 1457 | 1458 | if (transferPacket->reportBufferLen == sizeof(RaydFeatureReport)) 1459 | { 1460 | pReport = (RaydFeatureReport*)transferPacket->reportBuffer; 1461 | 1462 | DevContext->DeviceMode = pReport->DeviceMode; 1463 | 1464 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1465 | "RaydSetFeature DeviceMode = 0x%x\n", DevContext->DeviceMode); 1466 | } 1467 | else 1468 | { 1469 | status = STATUS_INVALID_PARAMETER; 1470 | 1471 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1472 | "RaydSetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(RaydFeatureReport) (%d)\n", 1473 | transferPacket->reportBufferLen, 1474 | sizeof(RaydFeatureReport)); 1475 | } 1476 | 1477 | break; 1478 | 1479 | default: 1480 | 1481 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1482 | "RaydSetFeature Unhandled report type %d\n", transferPacket->reportId); 1483 | 1484 | status = STATUS_INVALID_PARAMETER; 1485 | 1486 | break; 1487 | } 1488 | } 1489 | } 1490 | 1491 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1492 | "RaydSetFeature Exit = 0x%x\n", status); 1493 | 1494 | return status; 1495 | } 1496 | 1497 | NTSTATUS 1498 | RaydGetFeature( 1499 | IN PRAYD_CONTEXT DevContext, 1500 | IN WDFREQUEST Request, 1501 | OUT BOOLEAN* CompleteRequest 1502 | ) 1503 | { 1504 | UNREFERENCED_PARAMETER(CompleteRequest); 1505 | 1506 | NTSTATUS status = STATUS_SUCCESS; 1507 | WDF_REQUEST_PARAMETERS params; 1508 | PHID_XFER_PACKET transferPacket = NULL; 1509 | 1510 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1511 | "RaydGetFeature Entry\n"); 1512 | 1513 | WDF_REQUEST_PARAMETERS_INIT(¶ms); 1514 | WdfRequestGetParameters(Request, ¶ms); 1515 | 1516 | if (params.Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) 1517 | { 1518 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1519 | "RaydGetFeature Xfer packet too small\n"); 1520 | 1521 | status = STATUS_BUFFER_TOO_SMALL; 1522 | } 1523 | else 1524 | { 1525 | 1526 | transferPacket = (PHID_XFER_PACKET)WdfRequestWdmGetIrp(Request)->UserBuffer; 1527 | 1528 | if (transferPacket == NULL) 1529 | { 1530 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1531 | "RaydGetFeature No xfer packet\n"); 1532 | 1533 | status = STATUS_INVALID_DEVICE_REQUEST; 1534 | } 1535 | else 1536 | { 1537 | // 1538 | // switch on the report id 1539 | // 1540 | 1541 | switch (transferPacket->reportId) 1542 | { 1543 | case REPORTID_MTOUCH: 1544 | { 1545 | 1546 | RaydMaxCountReport* pReport = NULL; 1547 | 1548 | if (transferPacket->reportBufferLen == sizeof(RaydMaxCountReport)) 1549 | { 1550 | pReport = (RaydMaxCountReport*)transferPacket->reportBuffer; 1551 | 1552 | pReport->MaximumCount = MULTI_MAX_COUNT; 1553 | 1554 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1555 | "RaydGetFeature MaximumCount = 0x%x\n", MULTI_MAX_COUNT); 1556 | } 1557 | else 1558 | { 1559 | status = STATUS_INVALID_PARAMETER; 1560 | 1561 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1562 | "RaydGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(RaydMaxCountReport) (%d)\n", 1563 | transferPacket->reportBufferLen, 1564 | sizeof(RaydMaxCountReport)); 1565 | } 1566 | 1567 | break; 1568 | } 1569 | 1570 | case REPORTID_FEATURE: 1571 | { 1572 | 1573 | RaydFeatureReport* pReport = NULL; 1574 | 1575 | if (transferPacket->reportBufferLen == sizeof(RaydFeatureReport)) 1576 | { 1577 | pReport = (RaydFeatureReport*)transferPacket->reportBuffer; 1578 | 1579 | pReport->DeviceMode = DevContext->DeviceMode; 1580 | 1581 | pReport->DeviceIdentifier = 0; 1582 | 1583 | RaydPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, 1584 | "RaydGetFeature DeviceMode = 0x%x\n", DevContext->DeviceMode); 1585 | } 1586 | else 1587 | { 1588 | status = STATUS_INVALID_PARAMETER; 1589 | 1590 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1591 | "RaydGetFeature Error transferPacket->reportBufferLen (%d) is different from sizeof(RaydFeatureReport) (%d)\n", 1592 | transferPacket->reportBufferLen, 1593 | sizeof(RaydFeatureReport)); 1594 | } 1595 | 1596 | break; 1597 | } 1598 | 1599 | default: 1600 | 1601 | RaydPrint(DEBUG_LEVEL_ERROR, DBG_IOCTL, 1602 | "RaydGetFeature Unhandled report type %d\n", transferPacket->reportId); 1603 | 1604 | status = STATUS_INVALID_PARAMETER; 1605 | 1606 | break; 1607 | } 1608 | } 1609 | } 1610 | 1611 | RaydPrint(DEBUG_LEVEL_VERBOSE, DBG_IOCTL, 1612 | "RaydGetFeature Exit = 0x%x\n", status); 1613 | 1614 | return status; 1615 | } 1616 | 1617 | PCHAR 1618 | DbgHidInternalIoctlString( 1619 | IN ULONG IoControlCode 1620 | ) 1621 | { 1622 | switch (IoControlCode) 1623 | { 1624 | case IOCTL_HID_GET_DEVICE_DESCRIPTOR: 1625 | return "IOCTL_HID_GET_DEVICE_DESCRIPTOR"; 1626 | case IOCTL_HID_GET_REPORT_DESCRIPTOR: 1627 | return "IOCTL_HID_GET_REPORT_DESCRIPTOR"; 1628 | case IOCTL_HID_READ_REPORT: 1629 | return "IOCTL_HID_READ_REPORT"; 1630 | case IOCTL_HID_GET_DEVICE_ATTRIBUTES: 1631 | return "IOCTL_HID_GET_DEVICE_ATTRIBUTES"; 1632 | case IOCTL_HID_WRITE_REPORT: 1633 | return "IOCTL_HID_WRITE_REPORT"; 1634 | case IOCTL_HID_SET_FEATURE: 1635 | return "IOCTL_HID_SET_FEATURE"; 1636 | case IOCTL_HID_GET_FEATURE: 1637 | return "IOCTL_HID_GET_FEATURE"; 1638 | case IOCTL_HID_GET_STRING: 1639 | return "IOCTL_HID_GET_STRING"; 1640 | case IOCTL_HID_ACTIVATE_DEVICE: 1641 | return "IOCTL_HID_ACTIVATE_DEVICE"; 1642 | case IOCTL_HID_DEACTIVATE_DEVICE: 1643 | return "IOCTL_HID_DEACTIVATE_DEVICE"; 1644 | case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: 1645 | return "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST"; 1646 | case IOCTL_HID_SET_OUTPUT_REPORT: 1647 | return "IOCTL_HID_SET_OUTPUT_REPORT"; 1648 | case IOCTL_HID_GET_INPUT_REPORT: 1649 | return "IOCTL_HID_GET_INPUT_REPORT"; 1650 | default: 1651 | return "Unknown IOCTL"; 1652 | } 1653 | } --------------------------------------------------------------------------------