diff options
| author | a1xd <[email protected]> | 2021-09-06 19:11:47 -0400 |
|---|---|---|
| committer | a1xd <[email protected]> | 2021-09-23 22:28:44 -0400 |
| commit | 8680805b267bf5280b8f446ed33ef07981ea5475 (patch) | |
| tree | ccf8f2cd368a5f6d1d87fb23934218946ff6e388 | |
| parent | change lookup impl to use binary search (diff) | |
| download | rawaccel-8680805b267bf5280b8f446ed33ef07981ea5475.tar.xz rawaccel-8680805b267bf5280b8f446ed33ef07981ea5475.zip | |
make profile count dynamic (unlimited)
| -rw-r--r-- | common/rawaccel-io.hpp | 50 | ||||
| -rw-r--r-- | common/rawaccel.hpp | 13 | ||||
| -rw-r--r-- | driver/driver.cpp | 173 | ||||
| -rw-r--r-- | driver/driver.h | 4 | ||||
| -rw-r--r-- | wrapper/wrapper.cpp | 101 |
5 files changed, 206 insertions, 135 deletions
diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index 57bf707..f368896 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -5,6 +5,8 @@ #include "rawaccel-error.hpp" #include "rawaccel.hpp" +#include <memory> + namespace rawaccel { inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) @@ -37,14 +39,54 @@ namespace rawaccel { } } - inline void read(io_t& args) + inline std::unique_ptr<std::byte[]> read() { - io_control(READ, NULL, 0, &args, sizeof(io_t)); + io_base base_data; + + io_control(READ, NULL, 0, &base_data, sizeof(io_base)); + + size_t size = sizeof(base_data); + + if (base_data.driver_data_size == 0) { + // driver has no data, but it's more useful to return something, + // so return a default driver_settings object along with base data + + size += sizeof(driver_settings); + base_data.driver_data_size = 1; + auto bytes = std::make_unique<std::byte[]>(size); + *reinterpret_cast<io_base*>(bytes.get()) = base_data; + *reinterpret_cast<driver_settings*>(bytes.get() + sizeof(io_base)) = {}; + return bytes; + } + else { + size += sizeof(driver_settings) * base_data.driver_data_size; + size += sizeof(device_settings) * base_data.device_data_size; + auto bytes = std::make_unique<std::byte[]>(size); + io_control(READ, NULL, 0, bytes.get(), DWORD(size)); + return bytes; + } + } + + // buffer must point to at least sizeof(io_base) bytes + inline void write(const void* buffer) + { + if (buffer == nullptr) throw io_error("write buffer is null"); + + auto* base_ptr = static_cast<const io_base*>(buffer); + auto size = sizeof(io_base); + size += base_ptr->driver_data_size * sizeof(driver_settings); + size += base_ptr->device_data_size * sizeof(device_settings); + + if (size > DWORD(-1)) throw io_error("write buffer is too large"); + + io_control(WRITE, const_cast<void*>(buffer), DWORD(size), NULL, 0); } - inline void write(const io_t& args) + inline void reset() { - io_control(WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0); + io_base base_data{}; + // all driver/device data is cleared when a default io_base is passed + io_control(WRITE, &base_data, sizeof(io_base), NULL, 0); } inline version_t get_version() diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index b7e632b..c7bf33d 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -48,17 +48,14 @@ namespace rawaccel { settings.data.rot_direction = direction(settings.prof.degrees_rotation); } - inline constexpr unsigned DRIVER_CAPACITY = POOL_SIZE / sizeof(driver_settings); - inline constexpr unsigned DEVICE_CAPACITY = POOL_SIZE / sizeof(device_settings); - - struct io_t { + struct io_base { device_config default_dev_cfg; - unsigned driver_data_size; - unsigned device_data_size; - driver_settings driver_data[DRIVER_CAPACITY]; - device_settings device_data[DEVICE_CAPACITY]; + unsigned driver_data_size = 0; + unsigned device_data_size = 0; }; + static_assert(alignof(io_base) == alignof(driver_settings) && alignof(driver_settings) == alignof(device_settings)); + class modifier { public: #ifdef _KERNEL_MODE diff --git a/driver/driver.cpp b/driver/driver.cpp index 3096de8..2a4f460 100644 --- a/driver/driver.cpp +++ b/driver/driver.cpp @@ -20,24 +20,17 @@ using milliseconds = double; struct { + bool initialized; WDFCOLLECTION device_collection; WDFWAITLOCK collection_lock; - ra::device_config default_dev_cfg; - unsigned device_data_size; - unsigned driver_data_size; - ra::device_settings* device_data; + ra::io_base base_data; ra::driver_settings* driver_data; + ra::device_settings* device_data; milliseconds tick_interval; - ra::modifier modifier_data[ra::DRIVER_CAPACITY]; } global = {}; extern "C" PULONG InitSafeBootMode; -bool init_failed() -{ - return global.driver_data_size == 0; -}; - __declspec(guard(ignore)) VOID RawaccelCallback( @@ -105,7 +98,7 @@ Arguments: static_cast<double>(it->LastY) }; - devExt->mod_ptr->modify(input, *devExt->drv_ptr, devExt->dpi_factor, time); + devExt->mod.modify(input, devExt->drv_settings, devExt->dpi_factor, time); double carried_result_x = input.x + devExt->carry.x; double carried_result_y = input.y + devExt->carry.y; @@ -167,7 +160,7 @@ Return Value: { NTSTATUS status; void* buffer; - + size_t buffer_length; size_t bytes_out = 0; UNREFERENCED_PARAMETER(Queue); @@ -177,42 +170,50 @@ Return Value: DebugPrint(("Ioctl received into filter control object.\n")); - if (init_failed()) { + if (!global.initialized) { WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0); return; } + const auto SIZEOF_BASE = sizeof(ra::io_base); + switch (IoControlCode) { case ra::READ: status = WdfRequestRetrieveOutputBuffer( Request, - sizeof(ra::io_t), + SIZEOF_BASE, &buffer, - NULL + &buffer_length ); if (!NT_SUCCESS(status)) { DebugPrint(("RetrieveOutputBuffer failed: 0x%x\n", status)); } else { - ra::io_t& output = *static_cast<ra::io_t*>(buffer); + *static_cast<ra::io_base*>(buffer) = global.base_data; - output.default_dev_cfg = global.default_dev_cfg; + size_t driver_bytes = global.base_data.driver_data_size * sizeof(ra::driver_settings); + size_t device_bytes = global.base_data.device_data_size * sizeof(ra::device_settings); + size_t total_bytes = SIZEOF_BASE + driver_bytes + device_bytes; - output.device_data_size = global.device_data_size; - output.driver_data_size = global.driver_data_size; - - RtlCopyMemory(output.device_data, global.device_data, sizeof(output.device_data)); - RtlCopyMemory(output.driver_data, global.driver_data, sizeof(output.driver_data)); + if (buffer_length < total_bytes) { + bytes_out = SIZEOF_BASE; + } + else { + BYTE* output_ptr = static_cast<BYTE*>(buffer) + SIZEOF_BASE; - bytes_out = sizeof(ra::io_t); + if (global.driver_data) RtlCopyMemory(output_ptr, global.driver_data, driver_bytes); + output_ptr += driver_bytes; + if (global.device_data) RtlCopyMemory(output_ptr, global.device_data, device_bytes); + bytes_out = total_bytes; + } } break; case ra::WRITE: status = WdfRequestRetrieveInputBuffer( Request, - sizeof(ra::io_t), + SIZEOF_BASE, &buffer, - NULL + &buffer_length ); if (!NT_SUCCESS(status)) { DebugPrint(("RetrieveInputBuffer failed: 0x%x\n", status)); @@ -220,36 +221,73 @@ Return Value: else { WriteDelay(); - ra::io_t& input = *static_cast<ra::io_t*>(buffer); + ra::io_base& input = *static_cast<ra::io_base*>(buffer); - if (input.driver_data_size == 0) { + auto driver_bytes = size_t(input.driver_data_size) * sizeof(ra::driver_settings); + auto device_bytes = size_t(input.device_data_size) * sizeof(ra::device_settings); + auto alloc_size = driver_bytes + device_bytes; + auto total_size = alloc_size + SIZEOF_BASE; + + auto max_u32 = unsigned(-1); + if (driver_bytes > max_u32 || device_bytes > max_u32 || total_size > max_u32) { status = STATUS_CANCELLED; break; } - WdfWaitLockAcquire(global.collection_lock, NULL); + if (input.driver_data_size == 0) { + // clear data and disable all devices + WdfWaitLockAcquire(global.collection_lock, NULL); + + global.base_data = {}; - global.default_dev_cfg = input.default_dev_cfg; + if (global.driver_data) { + ExFreePoolWithTag(global.driver_data, 'g'); + global.driver_data = NULL; + global.device_data = NULL; + } - global.device_data_size = ra::min(input.device_data_size, ra::DEVICE_CAPACITY); - global.driver_data_size = ra::min(input.driver_data_size, ra::DRIVER_CAPACITY); + auto count = WdfCollectionGetCount(global.device_collection); - RtlCopyMemory(global.device_data, input.device_data, sizeof(input.device_data)); - RtlCopyMemory(global.driver_data, input.driver_data, sizeof(input.driver_data)); + for (auto i = 0u; i < count; i++) { + DeviceSetup(WdfCollectionGetItem(global.device_collection, i)); + } - for (auto i = 0u; i < global.driver_data_size; i++) { - global.modifier_data[i] = { global.driver_data[i] }; + WdfWaitLockRelease(global.collection_lock); } + else if (buffer_length == total_size) { + void* pool = ExAllocatePoolWithTag(PagedPool, alloc_size, 'g'); + if (!pool) { + DebugPrint(("ExAllocatePoolWithTag (PagedPool) failed")); + status = STATUS_UNSUCCESSFUL; + break; + } + RtlCopyMemory(pool, static_cast<BYTE*>(buffer) + SIZEOF_BASE, alloc_size); - auto count = WdfCollectionGetCount(global.device_collection); + WdfWaitLockAcquire(global.collection_lock, NULL); - for (auto i = 0u; i < count; i++) { - DeviceSetup(WdfCollectionGetItem(global.device_collection, i)); - } + if (global.driver_data) { + ExFreePoolWithTag(global.driver_data, 'g'); + } - WdfWaitLockRelease(global.collection_lock); - } + void* dev_data = static_cast<BYTE*>(pool) + driver_bytes; + global.device_data = input.device_data_size > 0 ? + static_cast<ra::device_settings*>(dev_data) : + NULL; + global.driver_data = static_cast<ra::driver_settings*>(pool); + global.base_data = input; + auto count = WdfCollectionGetCount(global.device_collection); + + for (auto i = 0u; i < count; i++) { + DeviceSetup(WdfCollectionGetItem(global.device_collection, i)); + } + + WdfWaitLockRelease(global.collection_lock); + } + else { + status = STATUS_CANCELLED; + } + } break; case ra::GET_VERSION: status = WdfRequestRetrieveOutputBuffer( @@ -310,34 +348,11 @@ RawaccelInit(WDFDRIVER driver) return; } - void* paged_p = ExAllocatePoolWithTag(PagedPool, ra::POOL_SIZE, 'g'); - if (paged_p) { - RtlZeroMemory(paged_p, ra::POOL_SIZE); - global.device_data = static_cast<ra::device_settings*>(paged_p); - } - else { - DebugPrint(("ExAllocatePoolWithTag (PagedPool) failed")); - return; - } - - void* nonpaged_p = ExAllocatePoolWithTag(NonPagedPool, ra::POOL_SIZE, 'g'); - if (nonpaged_p) { - RtlZeroMemory(nonpaged_p, ra::POOL_SIZE); - global.driver_data = static_cast<ra::driver_settings*>(nonpaged_p); - global.driver_data->prof.domain_weights = { 1, 1 }; - global.driver_data->prof.range_weights = { 1, 1 }; - global.driver_data->prof.sensitivity = 1; - global.driver_data->prof.yx_sens_ratio = 1; - global.driver_data_size = 1; - } - else { - DebugPrint(("ExAllocatePoolWithTag (NonPagedPool) failed")); - return; - } - LARGE_INTEGER freq; KeQueryPerformanceCounter(&freq); global.tick_interval = 1e3 / freq.QuadPart; + + global.initialized = true; } VOID @@ -360,25 +375,29 @@ DeviceSetup(WDFOBJECT hDevice) } }; - set_ext_from_cfg(global.default_dev_cfg); - devExt->counter = 0; - devExt->carry = {}; - devExt->drv_ptr = global.driver_data; - devExt->mod_ptr = global.modifier_data; - - for (auto i = 0u; i < global.device_data_size; i++) { + if (!global.driver_data) { + devExt->enable = false; + devExt->mod = {}; + return; + } + + set_ext_from_cfg(global.base_data.default_dev_cfg); + devExt->drv_settings = *global.driver_data; + devExt->mod = { devExt->drv_settings }; + + for (auto i = 0u; i < global.base_data.device_data_size; i++) { auto& dev_settings = global.device_data[i]; if (wcsncmp(devExt->dev_id, dev_settings.id, ra::MAX_DEV_ID_LEN) == 0) { set_ext_from_cfg(dev_settings.config); if (dev_settings.profile[0] != L'\0') { - for (auto j = 0u; j < global.driver_data_size; j++) { + for (auto j = 0u; j < global.base_data.driver_data_size; j++) { auto& profile = global.driver_data[j].prof; if (wcsncmp(dev_settings.profile, profile.name, ra::MAX_NAME_LEN) == 0) { - devExt->drv_ptr = &global.driver_data[j]; - devExt->mod_ptr = &global.modifier_data[j]; + devExt->drv_settings = global.driver_data[j]; + devExt->mod = { devExt->drv_settings }; return; } } @@ -624,7 +643,7 @@ Return Value: DebugPrint(("Enter FilterEvtDeviceAdd \n")); - if (init_failed()) { + if (!global.initialized) { return STATUS_SUCCESS; } diff --git a/driver/driver.h b/driver/driver.h index 4818367..d8b3162 100644 --- a/driver/driver.h +++ b/driver/driver.h @@ -25,10 +25,10 @@ typedef struct _DEVICE_EXTENSION { double dpi_factor; counter_t counter; ra::time_clamp clamp; - ra::driver_settings* drv_ptr; - ra::modifier* mod_ptr; + ra::modifier mod; vec2d carry; CONNECT_DATA UpperConnectData; + ra::driver_settings drv_settings; WCHAR dev_id[ra::MAX_DEV_ID_LEN]; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index fba66fa..83804a2 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -462,7 +462,7 @@ public: } - ra::driver_settings GetSettings() + ra::driver_settings NativeSettings() { return instance->settings; } @@ -474,8 +474,6 @@ public: public ref class DriverConfig { public: literal double WriteDelayMs = ra::WRITE_DELAY; - literal int MaxProfiles = ra::DRIVER_CAPACITY; - literal int MaxDevices = ra::DEVICE_CAPACITY; literal String^ Key = "Driver settings"; String^ version = RA_VER_STRING; @@ -491,36 +489,56 @@ public: void Activate() { - ra::io_t* data = static_cast<ra::io_t*>(malloc(sizeof(ra::io_t))); + if (accels->Count != profiles->Count) { + throw gcnew Exception("Profile count does not match ManagedAccel"); + } - if (!data) throw gcnew Exception("bad alloc"); - - data->default_dev_cfg.disable = defaultDeviceConfig.disable; - data->default_dev_cfg.set_extra_info = defaultDeviceConfig.setExtraInfo; - data->default_dev_cfg.dpi = defaultDeviceConfig.dpi; - data->default_dev_cfg.polling_rate = defaultDeviceConfig.pollingRate; - data->default_dev_cfg.clamp.min = defaultDeviceConfig.minimumTime; - data->default_dev_cfg.clamp.max = defaultDeviceConfig.maximumTime; + std::byte* buffer; - data->driver_data_size = profiles->Count; - data->device_data_size = devices->Count; + auto driver_data_bytes = accels->Count * sizeof(ra::driver_settings); + auto device_data_bytes = devices->Count * sizeof(ra::device_settings); - for (auto i = 0; i < profiles->Count; i++) { - auto& drv_settings = data->driver_data[i]; - drv_settings = accels[i]->GetSettings(); + try { + buffer = new std::byte[sizeof(ra::io_base) + driver_data_bytes + device_data_bytes]; + } + catch (const std::exception& e) { + throw gcnew InteropException(e); } + auto* byte_ptr = buffer; + + auto* base_data = reinterpret_cast<ra::io_base*>(byte_ptr); + base_data->default_dev_cfg.disable = defaultDeviceConfig.disable; + base_data->default_dev_cfg.set_extra_info = defaultDeviceConfig.setExtraInfo; + base_data->default_dev_cfg.dpi = defaultDeviceConfig.dpi; + base_data->default_dev_cfg.polling_rate = defaultDeviceConfig.pollingRate; + base_data->default_dev_cfg.clamp.min = defaultDeviceConfig.minimumTime; + base_data->default_dev_cfg.clamp.max = defaultDeviceConfig.maximumTime; + base_data->driver_data_size = accels->Count; + base_data->device_data_size = devices->Count; + + byte_ptr += sizeof(ra::io_base); + + auto* driver_data = reinterpret_cast<ra::driver_settings*>(byte_ptr); + for (auto i = 0; i < accels->Count; i++) { + auto& drv_settings = driver_data[i]; + drv_settings = accels[i]->NativeSettings(); + } + + byte_ptr += driver_data_bytes; + + auto* device_data = reinterpret_cast<ra::device_settings*>(byte_ptr); for (auto i = 0; i < devices->Count; i++) { - auto& dev_settings = data->device_data[i]; + auto& dev_settings = device_data[i]; Marshal::StructureToPtr(devices[i], IntPtr(&dev_settings), false); } try { - ra::write(*data); - free(data); + ra::write(buffer); + delete[] buffer; } - catch (const ra::error& e) { - free(data); + catch (const std::exception& e) { + delete[] buffer; throw gcnew InteropException(e); } } @@ -530,14 +548,6 @@ public: { Text::StringBuilder^ sb = gcnew Text::StringBuilder(); - if (profiles->Count > MaxProfiles) { - sb->AppendFormat("Number of profiles ({0}) exceeds max ({1})\n", profiles->Count, MaxProfiles); - } - - if (devices->Count > MaxDevices) { - sb->AppendFormat("Number of devices ({0}) exceeds max ({1})\n", devices->Count, MaxDevices); - } - ProfileErrors^ profErrors = gcnew ProfileErrors(profiles); if (!profErrors->Empty()) { sb->Append(profErrors->ToString()); @@ -648,15 +658,11 @@ public: static DriverConfig^ GetActive() { - ra::io_t* data = static_cast<ra::io_t*>(malloc(sizeof(ra::io_t))); - - if (!data) throw gcnew Exception("io_t alloc failed"); - + std::unique_ptr<std::byte[]> bytes; try { - ra::read(*data); + bytes = ra::read(); } - catch (const ra::error& e) { - free(data); + catch (const std::exception& e) { throw gcnew InteropException(e); } @@ -665,20 +671,27 @@ public: cfg->accels = gcnew List<ManagedAccel^>(); cfg->devices = gcnew List<DeviceSettings^>(); - for (auto i = 0u; i < data->driver_data_size; i++) { - auto& drv_settings = data->driver_data[i]; + auto* byte_ptr = bytes.get(); + ra::io_base* base_data = reinterpret_cast<ra::io_base*>(byte_ptr); + cfg->defaultDeviceConfig.Init(base_data->default_dev_cfg); + + byte_ptr += sizeof(ra::io_base); + + ra::driver_settings* driver_data = reinterpret_cast<ra::driver_settings*>(byte_ptr); + for (auto i = 0u; i < base_data->driver_data_size; i++) { + auto& drv_settings = driver_data[i]; cfg->profiles->Add(gcnew Profile(drv_settings.prof)); cfg->accels->Add(gcnew ManagedAccel(drv_settings)); } - for (auto i = 0u; i < data->device_data_size; i++) { - auto& dev_settings = data->device_data[i]; + byte_ptr += base_data->driver_data_size * sizeof(ra::driver_settings); + + ra::device_settings* device_data = reinterpret_cast<ra::device_settings*>(byte_ptr); + for (auto i = 0u; i < base_data->device_data_size; i++) { + auto& dev_settings = device_data[i]; cfg->devices->Add(gcnew DeviceSettings(dev_settings)); } - cfg->defaultDeviceConfig.Init(data->default_dev_cfg); - - free(data); return cfg; } |