From f951454ba4fe012d1316f405306063446d832dd1 Mon Sep 17 00:00:00 2001 From: Hans Ulrich Niedermann Date: Sun, 8 Mar 2020 14:13:04 +0100 Subject: [PATCH] evdev: fall back to SND_BELL if SND_TONE is unsupported The gpio-beeper driver does not support SND_TONE, but SND_BELL. So we send SND_BELL instead when SND_TONE is not supported. Adapted the pull request from Bastian Krause from https://github.com/johnath/beep/pull/17 for spkr-beep. No well-known devices names for those devices are known, so we cannot try them by default. Closes: https://github.com/spkr-beep/beep/issues/12 --- beep-driver-console.c | 3 +- beep-driver-evdev.c | 78 +++++++++++++++++++++++---- beep-driver-noop.c | 3 +- beep-driver.h | 3 ++ beep-main.c | 5 +- tests/11-beep-default-logs.expected.0 | 3 +- tests/11-beep-default-logs.expected.1 | 3 +- 7 files changed, 83 insertions(+), 15 deletions(-) diff --git a/beep-driver-console.c b/beep-driver-console.c index b92853c..864b12a 100644 --- a/beep-driver-console.c +++ b/beep-driver-console.c @@ -164,7 +164,8 @@ beep_driver driver_data = driver_begin_tone, driver_end_tone, 0, - NULL + NULL, + 0 }; diff --git a/beep-driver-evdev.c b/beep-driver-evdev.c index ca2d8c5..668c57d 100644 --- a/beep-driver-evdev.c +++ b/beep-driver-evdev.c @@ -2,7 +2,8 @@ * \brief implement the beep evdev driver * \author Copyright (C) 2000-2010 Johnathan Nightingale * \author Copyright (C) 2010-2013 Gerfried Fuchs - * \author Copyright (C) 2019 Hans Ulrich Niedermann + * \author Copyright (C) 2019-2020 Hans Ulrich Niedermann + * \author Copyright (C) 2020 Bastian Krause * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +28,7 @@ */ +#include #include #include @@ -50,6 +52,12 @@ #define LOG_MODULE "evdev" +enum snd_api_type { + SND_API_TONE, + SND_API_BELL +}; + + static int open_checked_device(const char *const device_name) { @@ -77,14 +85,20 @@ bool driver_detect(beep_driver *driver, const char *console_device) LOG_VERBOSE("driver_detect %p %p", (void *)driver, (const void *)console_device); } + + bool device_open = false; + if (console_device) { const int fd = open_checked_device(console_device); if (fd >= 0) { driver->device_fd = fd; driver->device_name = console_device; - return true; + device_open = true; } } else { + /* Make this a list of well-known device names when more + * well-known.device names become known to us. + */ static const char *const default_name = "/dev/input/by-path/platform-pcspkr-event-spkr"; @@ -92,10 +106,39 @@ bool driver_detect(beep_driver *driver, const char *console_device) if (fd >= 0) { driver->device_fd = fd; driver->device_name = default_name; - return true; + device_open = true; } } - return false; + + if (!device_open) { + return false; + } + + unsigned long evbit = 0; + if (-1 == ioctl(driver->device_fd, + EVIOCGBIT(EV_SND, sizeof(evbit)), &evbit)) { + LOG_VERBOSE("%d does not implement EVIOCGBIT", + driver->device_fd); + return false; + } + + enum snd_api_type snd_api; + if (evbit & (1 << SND_TONE)) { + snd_api = SND_API_TONE; + LOG_VERBOSE("found SND_TONE support for fd=%d", + driver->device_fd); + } else if (evbit & (1 << SND_BELL)) { + snd_api = SND_API_BELL; + LOG_VERBOSE("falling back to SND_BELL support for fd=%d", + driver->device_fd); + } else { + LOG_VERBOSE("fd=%d supports neither SND_TONE nor SND_BELL", + driver->device_fd); + return false; + } + + driver->device_flags = snd_api; + return true; } @@ -124,8 +167,16 @@ void driver_begin_tone(beep_driver *driver, const uint16_t freq) memset(&e, 0, sizeof(e)); e.type = EV_SND; - e.code = SND_TONE; - e.value = freq; + switch ((enum snd_api_type)(driver->device_flags)) { + case SND_API_TONE: + e.code = SND_TONE; + e.value = freq; + break; + case SND_API_BELL: + e.code = SND_BELL; + e.value = (0 == 0); + break; + } if (sizeof(e) != write(driver->device_fd, &e, sizeof(e))) { /* If we cannot use the sound API, we cannot silence the sound either */ @@ -143,8 +194,16 @@ void driver_end_tone(beep_driver *driver) memset(&e, 0, sizeof(e)); e.type = EV_SND; - e.code = SND_TONE; - e.value = 0; + switch ((enum snd_api_type)(driver->device_flags)) { + case SND_API_TONE: + e.code = SND_TONE; + e.value = 0; + break; + case SND_API_BELL: + e.code = SND_BELL; + e.value = (0 != 0); + break; + } if (sizeof(e) != write(driver->device_fd, &e, sizeof(e))) { safe_error_exit("write EV_SND"); @@ -163,7 +222,8 @@ beep_driver driver_data = driver_begin_tone, driver_end_tone, 0, - NULL + NULL, + 0 }; diff --git a/beep-driver-noop.c b/beep-driver-noop.c index 601055b..770f35c 100644 --- a/beep-driver-noop.c +++ b/beep-driver-noop.c @@ -89,7 +89,8 @@ beep_driver driver_data = driver_begin_tone, driver_end_tone, 0, - NULL + NULL, + 0 }; diff --git a/beep-driver.h b/beep-driver.h index 142cb80..e834fd7 100644 --- a/beep-driver.h +++ b/beep-driver.h @@ -104,6 +104,9 @@ struct _beep_driver { /** device file name for this driver */ const char *device_name; + + /** driver specific set of flags */ + unsigned int device_flags; }; diff --git a/beep-main.c b/beep-main.c index 0297779..fcd0f99 100644 --- a/beep-main.c +++ b/beep-main.c @@ -529,9 +529,10 @@ int main(const int argc, char *const argv[]) } } - LOG_VERBOSE("using %s driver (fd=%d, dev=%s)", + LOG_VERBOSE("using %s driver (fd=%d, dev=%s, flags=0x%x)", driver->name, - driver->device_fd, driver->device_name); + driver->device_fd, driver->device_name, + driver->device_flags); /* At this time, we know what API to use on which device, and we do * not have to fall back onto printing '\a' any more. diff --git a/tests/11-beep-default-logs.expected.0 b/tests/11-beep-default-logs.expected.0 index 32e891a..4618b8f 100644 --- a/tests/11-beep-default-logs.expected.0 +++ b/tests/11-beep-default-logs.expected.0 @@ -8,7 +8,8 @@ beep-log: Verbose: drivers: beep_drivers_register (noop) BEEP_EXECUTABLE: Verbose: noop: driver_detect (nil) BEEP_EXECUTABLE: Verbose: evdev: driver_detect (nil) BEEP_EXECUTABLE: Verbose: lib: opened /dev/input/by-path/platform-pcspkr-event-spkr as fd= -BEEP_EXECUTABLE: Verbose: main: using evdev driver (fd=, dev=/dev/input/by-path/platform-pcspkr-event-spkr) +BEEP_EXECUTABLE: Verbose: evdev: found SND_TONE support for fd= +BEEP_EXECUTABLE: Verbose: main: using evdev driver (fd=, dev=/dev/input/by-path/platform-pcspkr-event-spkr, flags=0x0) BEEP_EXECUTABLE: Verbose: main: 1 times 200 ms beeps (100 ms delay between, 0 ms delay after) @ 440 Hz BEEP_EXECUTABLE: Verbose: evdev: driver_begin_tone 440 BEEP_EXECUTABLE: Verbose: evdev: driver_end_tone diff --git a/tests/11-beep-default-logs.expected.1 b/tests/11-beep-default-logs.expected.1 index d978196..2d2063c 100644 --- a/tests/11-beep-default-logs.expected.1 +++ b/tests/11-beep-default-logs.expected.1 @@ -5,7 +5,8 @@ beep-log: Verbose: evdev: beep_driver_evdev_constructor beep-log: Verbose: drivers: beep_drivers_register (evdev) BEEP_EXECUTABLE: Verbose: evdev: driver_detect (nil) BEEP_EXECUTABLE: Verbose: lib: opened /dev/input/by-path/platform-pcspkr-event-spkr as fd= -BEEP_EXECUTABLE: Verbose: main: using evdev driver (fd=, dev=/dev/input/by-path/platform-pcspkr-event-spkr) +BEEP_EXECUTABLE: Verbose: evdev: found SND_TONE support for fd= +BEEP_EXECUTABLE: Verbose: main: using evdev driver (fd=, dev=/dev/input/by-path/platform-pcspkr-event-spkr, flags=0x0) BEEP_EXECUTABLE: Verbose: main: 1 times 200 ms beeps (100 ms delay between, 0 ms delay after) @ 440 Hz BEEP_EXECUTABLE: Verbose: evdev: driver_begin_tone 440 BEEP_EXECUTABLE: Verbose: evdev: driver_end_tone