22 * \brief implement the beep evdev driver
33 * \author Copyright (C) 2000-2010 Johnathan Nightingale
44 * \author Copyright (C) 2010-2013 Gerfried Fuchs
5- * \author Copyright (C) 2019 Hans Ulrich Niedermann
5+ * \author Copyright (C) 2019-2020 Hans Ulrich Niedermann
6+ * \author Copyright (C) 2020 Bastian Krause
67 *
78 * This program is free software; you can redistribute it and/or modify
89 * it under the terms of the GNU General Public License as published by
2728 */
2829
2930
31+ #include <stdbool.h>
3032#include <stddef.h>
3133
3234#include <errno.h>
5052#define LOG_MODULE "evdev"
5153
5254
55+ enum snd_api_type {
56+ SND_API_TONE ,
57+ SND_API_BELL
58+ };
59+
60+
5361static
5462int open_checked_device (const char * const device_name )
5563{
@@ -77,25 +85,60 @@ bool driver_detect(beep_driver *driver, const char *console_device)
7785 LOG_VERBOSE ("driver_detect %p %p" ,
7886 (void * )driver , (const void * )console_device );
7987 }
88+
89+ bool device_open = false;
90+
8091 if (console_device ) {
8192 const int fd = open_checked_device (console_device );
8293 if (fd >= 0 ) {
8394 driver -> device_fd = fd ;
8495 driver -> device_name = console_device ;
85- return true;
96+ device_open = true;
8697 }
8798 } else {
99+ /* Make this a list of well-known device names when more
100+ * well-known.device names become known to us.
101+ */
88102 static
89103 const char * const default_name =
90104 "/dev/input/by-path/platform-pcspkr-event-spkr" ;
91105 const int fd = open_checked_device (default_name );
92106 if (fd >= 0 ) {
93107 driver -> device_fd = fd ;
94108 driver -> device_name = default_name ;
95- return true;
109+ device_open = true;
96110 }
97111 }
98- return false;
112+
113+ if (!device_open ) {
114+ return false;
115+ }
116+
117+ unsigned long evbit = 0 ;
118+ if (-1 == ioctl (driver -> device_fd ,
119+ EVIOCGBIT (EV_SND , sizeof (evbit )), & evbit )) {
120+ LOG_VERBOSE ("%d does not implement EVIOCGBIT" ,
121+ driver -> device_fd );
122+ return false;
123+ }
124+
125+ enum snd_api_type snd_api ;
126+ if (evbit & (1 << SND_TONE )) {
127+ snd_api = SND_API_TONE ;
128+ LOG_VERBOSE ("found SND_TONE support for fd=%d" ,
129+ driver -> device_fd );
130+ } else if (evbit & (1 << SND_BELL )) {
131+ snd_api = SND_API_BELL ;
132+ LOG_VERBOSE ("falling back to SND_BELL support for fd=%d" ,
133+ driver -> device_fd );
134+ } else {
135+ LOG_VERBOSE ("fd=%d supports neither SND_TONE nor SND_BELL" ,
136+ driver -> device_fd );
137+ return false;
138+ }
139+
140+ driver -> device_flags = snd_api ;
141+ return true;
99142}
100143
101144
@@ -124,8 +167,16 @@ void driver_begin_tone(beep_driver *driver, const uint16_t freq)
124167
125168 memset (& e , 0 , sizeof (e ));
126169 e .type = EV_SND ;
127- e .code = SND_TONE ;
128- e .value = freq ;
170+ switch ((enum snd_api_type )(driver -> device_flags )) {
171+ case SND_API_TONE :
172+ e .code = SND_TONE ;
173+ e .value = freq ;
174+ break ;
175+ case SND_API_BELL :
176+ e .code = SND_BELL ;
177+ e .value = (0 == 0 );
178+ break ;
179+ }
129180
130181 if (sizeof (e ) != write (driver -> device_fd , & e , sizeof (e ))) {
131182 /* If we cannot use the sound API, we cannot silence the sound either */
@@ -143,8 +194,16 @@ void driver_end_tone(beep_driver *driver)
143194
144195 memset (& e , 0 , sizeof (e ));
145196 e .type = EV_SND ;
146- e .code = SND_TONE ;
147- e .value = 0 ;
197+ switch ((enum snd_api_type )(driver -> device_flags )) {
198+ case SND_API_TONE :
199+ e .code = SND_TONE ;
200+ e .value = 0 ;
201+ break ;
202+ case SND_API_BELL :
203+ e .code = SND_BELL ;
204+ e .value = (0 != 0 );
205+ break ;
206+ }
148207
149208 if (sizeof (e ) != write (driver -> device_fd , & e , sizeof (e ))) {
150209 safe_error_exit ("write EV_SND" );
@@ -163,7 +222,8 @@ beep_driver driver_data =
163222 driver_begin_tone ,
164223 driver_end_tone ,
165224 0 ,
166- NULL
225+ NULL ,
226+ 0
167227 };
168228
169229
0 commit comments