From 9011bc5fbb514377059d3505204f2284aa46794a Mon Sep 17 00:00:00 2001 From: Denis Arnst Date: Thu, 13 May 2021 13:01:42 +0200 Subject: [PATCH] Auto-generate udev-rules Also fix cmake version warning --- CMakeLists.txt | 14 ++++++- README.md | 6 ++- src/device_registry.c | 10 +++++ src/device_registry.h | 10 +++++ src/main.c | 35 +++++++++++++++-- udev/70-headsets.rules | 87 ------------------------------------------ 6 files changed, 67 insertions(+), 95 deletions(-) delete mode 100644 udev/70-headsets.rules diff --git a/CMakeLists.txt b/CMakeLists.txt index cf63d01..ed3167a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6.2) +cmake_minimum_required(VERSION 2.8...3.19) project(headsetcontrol) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/") @@ -115,7 +115,17 @@ install(TARGETS headsetcontrol DESTINATION bin) # install udev files on linux if(UNIX AND NOT APPLE) - install(DIRECTORY udev/ DESTINATION /etc/udev/rules.d) + set (program_cmd headsetcontrol) + set (program_arg "-u") + set (program_output "/etc/udev/rules.d/70-headsets.rules") + install( CODE + " + execute_process(COMMAND ${program_cmd} ${program_arg} + OUTPUT_FILE ${program_output}) + + message(STATUS \"Installed udev rules to ${program_output}\") + " + ) endif() diff --git a/README.md b/README.md index aed69cf..05cdc34 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ This will copy the binary to a folder globally accessible via path. ### Access without root -Also in Linux, you need udev rules if you don't want to start the application with root. Those rules reside in the udev folder of this repository. Typing `make install` on Linux copies them automatically to /etc/udev/rules.d/. +Also in Linux, you need udev rules if you don't want to start the application with root. Those rules are generated via `headsetcontrol -u`. Typing `make install` on Linux generates and writes them automatically to /etc/udev/rules.d/. You can reload udev configuration without reboot via `sudo udevadm control --reload-rules && sudo udevadm trigger` @@ -123,7 +123,7 @@ You can reload udev configuration without reboot via `sudo udevadm control --rel Type `headsetcontrol -h` to get all available options.\ (Don't forget to prefix it with `./` when the application resides in the current folder) -Type `headsetcontrol -?` to get a list of supported capabilities for the currently detected headset +Type `headsetcontrol -?` to get a list of supported capabilities for the currently detected headset. `headsetcontrol -s 128` sets the sidetone to 128 (REAL loud). You can silence it with `0`. I recommend a loudness of 16. @@ -141,6 +141,8 @@ Following options don't work on all devices yet: `headsetcontrol -m` retrieves the current chat-mix-dial level setting. +`headsetcontrol -u` Generates and outputs udev-rules for Linux. + ### Third Party The following additional software can be used to enable control via a GUI diff --git a/src/device_registry.c b/src/device_registry.c index 51f21f1..ded0bc6 100644 --- a/src/device_registry.c +++ b/src/device_registry.c @@ -57,3 +57,13 @@ int get_device(struct device* device_found, uint16_t idVendor, uint16_t idProduc } return 1; } + +int iterate_devices(int index, struct device** device_found) +{ + if (index < NUMDEVICES) { + *device_found = devicelist[index]; + return 0; + } else { + return -1; + } +} diff --git a/src/device_registry.h b/src/device_registry.h index af6d543..93812ee 100644 --- a/src/device_registry.h +++ b/src/device_registry.h @@ -17,3 +17,13 @@ void init_devices(); * @return 0 when a device was found, 1 otherwise */ int get_device(struct device* device_found, uint16_t idVendor, uint16_t idProduct); + +/** @brief Gives back an device at the given index + * + * Caller must iterate from index 0 upwards until returned -1 to get all devices + * + * @param index Current index + * @param device_found output parameter, pointer to device pointer + * @return 0 when a device exists at the given index, -1 if not + */ +int iterate_devices(int index, struct device** device_found); diff --git a/src/main.c b/src/main.c index 38bed54..1ebf830 100644 --- a/src/main.c +++ b/src/main.c @@ -186,6 +186,27 @@ static void print_capability(enum capabilities cap, char shortName, const char* } } +static void print_udevrules() +{ + int i = 0; + struct device* device_found; + + printf("ACTION!=\"add|change\", GOTO=\"headset_end\"\n"); + printf("\n"); + + while (iterate_devices(i++, &device_found) == 0) { + printf("# %s\n", device_found->device_name); + + for (int i = 0; i < device_found->numIdProducts; i++) + printf("KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", TAG+=\"uaccess\"\n", + (unsigned int)device_found->idVendor, (unsigned int)device_found->idProductsSupported[i]); + + printf("\n"); + } + + printf("LABEL=\"headset_end\"\n"); +} + int main(int argc, char* argv[]) { int c; @@ -200,7 +221,10 @@ int main(int argc, char* argv[]) long rotate_to_mute = -1; long print_capabilities = -1; - while ((c = getopt(argc, argv, "bchs:n:l:i:mv:r:?")) != -1) { + // Init all information of supported devices + init_devices(); + + while ((c = getopt(argc, argv, "bchs:n:l:i:mv:r:u?")) != -1) { switch (c) { case 'b': request_battery = 1; @@ -256,6 +280,10 @@ int main(int argc, char* argv[]) return 1; } break; + case 'u': + fprintf(stderr, "Outputting udev rules to stdout/console...\n\n"); + print_udevrules(); + return 0; case '?': print_capabilities = 1; break; @@ -271,6 +299,8 @@ int main(int argc, char* argv[]) printf(" -m\t\tRetrieves the current chat-mix-dial level setting\n"); printf(" -v 0|1\tTurn voice prompts on or off (0 = off, 1 = on)\n"); printf(" -r 0|1\tTurn rotate to mute feature on or off (0 = off, 1 = on)\n"); + printf("\n"); + printf(" -u\t\tOutputs udev rules to stdout/console\n"); printf("\n"); return 0; @@ -285,9 +315,6 @@ int main(int argc, char* argv[]) printf("Non-option argument %s\n", argv[index]); } - // Init all information of supported devices - init_devices(); - // Look for a supported device int headset_available = find_device(); if (headset_available != 0) { diff --git a/udev/70-headsets.rules b/udev/70-headsets.rules deleted file mode 100644 index 3eafc3b..0000000 --- a/udev/70-headsets.rules +++ /dev/null @@ -1,87 +0,0 @@ -ACTION!="add|change", GOTO="headset_end" - -# Corsair VOID Wireless -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a2b", TAG+="uaccess" - -# Corsair VOID ELITE -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a55", TAG+="uaccess" - -# Corsair VOID PRO -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a14", TAG+="uaccess" - -# Corsair VOID PRO Wireless -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a1a", TAG+="uaccess" - -# Corsair VOID PRO USB -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a17", TAG+="uaccess" - -# Corsair VOID RGB USB -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="1b2a", TAG+="uaccess" - -# Corsair VOID RGB ELITE -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a51", TAG+="uaccess" - -# Corsair VOID ELITE USB -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a52", TAG+="uaccess" - -# Corsair VOID -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="1b27", TAG+="uaccess" - -# Corsair HS70 Wireless -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a38", TAG+="uaccess" - -# Corsair HS70 Pro -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1b1c", ATTRS{idProduct}=="0a4f", TAG+="uaccess" - -# Logitech G430 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a4d", TAG+="uaccess" - -# Logitech G432 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a9c", TAG+="uaccess" - -# Logitech G533 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a66", TAG+="uaccess" - -# logitech G633 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a5c", TAG+="uaccess" - -# logitech G635 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a89", TAG+="uaccess" - -# logitech G930 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a1f", TAG+="uaccess" - -# logitech G933 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a5b", TAG+="uaccess" - -# logitech G935 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0a87", TAG+="uaccess" - -# logitech G733 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0ab5", TAG+="uaccess" - -# logitech G PRO -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0aa7", TAG+="uaccess" - -# logitech Zone Wired -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0aad", TAG+="uaccess" - -# SteelSeries ARCTIS 1 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1038", ATTRS{idProduct}=="12b3", TAG+="uaccess" - -# SteelSeries ACTIS 7 (2019) -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1038", ATTRS{idProduct}=="12ad", TAG+="uaccess" - -# SteelSeries ARCTIS 7 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1260", TAG+="uaccess" - -# SteelSeries ARCTIS PRO (2019) -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1252", TAG+="uaccess" - -# SteelSeries ARCTIS 9 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1038", ATTRS{idProduct}=="12c2", TAG+="uaccess" - -# ROCCAT Elo 7.1 Air -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e7d", ATTRS{idProduct}=="3a37", TAG+="uaccess" - -LABEL="headset_end"