From 3a6dbd077959ea255ac298beae890d5aebd9ea27 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. --- beep-driver-console.c | 3 +- beep-driver-evdev.c | 78 ++++++++++++++++++++++++++++++++++++++----- beep-driver-noop.c | 3 +- beep-driver.h | 3 ++ beep-main.c | 5 +-- 5 files changed, 79 insertions(+), 13 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.