1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file async.c 3d5ac70f0Sopenharmony_ci * \brief Async notification helpers 4d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 5d5ac70f0Sopenharmony_ci * \date 2001 6d5ac70f0Sopenharmony_ci */ 7d5ac70f0Sopenharmony_ci/* 8d5ac70f0Sopenharmony_ci * Async notification helpers 9d5ac70f0Sopenharmony_ci * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org> 10d5ac70f0Sopenharmony_ci * 11d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 12d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 13d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 14d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 15d5ac70f0Sopenharmony_ci * 16d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 17d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 18d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 20d5ac70f0Sopenharmony_ci * 21d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 22d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 23d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 24d5ac70f0Sopenharmony_ci * 25d5ac70f0Sopenharmony_ci */ 26d5ac70f0Sopenharmony_ci 27d5ac70f0Sopenharmony_ci#include "pcm/pcm_local.h" 28d5ac70f0Sopenharmony_ci#include "control/control_local.h" 29d5ac70f0Sopenharmony_ci#include <signal.h> 30d5ac70f0Sopenharmony_ci 31d5ac70f0Sopenharmony_cistatic struct sigaction previous_action; 32d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 33d5ac70f0Sopenharmony_ci#define MAX_SIG_FUNCTION_CODE 10 /* i.e. SIG_DFL SIG_IGN SIG_HOLD et al */ 34d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 35d5ac70f0Sopenharmony_ci 36d5ac70f0Sopenharmony_ci#ifdef SND_ASYNC_RT_SIGNAL 37d5ac70f0Sopenharmony_ci/** async signal number */ 38d5ac70f0Sopenharmony_cistatic int snd_async_signo; 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_civoid snd_async_init(void) __attribute__ ((constructor)); 41d5ac70f0Sopenharmony_ci 42d5ac70f0Sopenharmony_civoid snd_async_init(void) 43d5ac70f0Sopenharmony_ci{ 44d5ac70f0Sopenharmony_ci snd_async_signo = __libc_allocate_rtsig(0); 45d5ac70f0Sopenharmony_ci if (snd_async_signo < 0) { 46d5ac70f0Sopenharmony_ci SNDERR("Unable to find a RT signal to use for snd_async"); 47d5ac70f0Sopenharmony_ci exit(1); 48d5ac70f0Sopenharmony_ci } 49d5ac70f0Sopenharmony_ci} 50d5ac70f0Sopenharmony_ci#else 51d5ac70f0Sopenharmony_ci/** async signal number */ 52d5ac70f0Sopenharmony_cistatic const int snd_async_signo = SIGIO; 53d5ac70f0Sopenharmony_ci#endif 54d5ac70f0Sopenharmony_ci 55d5ac70f0Sopenharmony_cistatic LIST_HEAD(snd_async_handlers); 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_cistatic void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED) 58d5ac70f0Sopenharmony_ci{ 59d5ac70f0Sopenharmony_ci#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 60d5ac70f0Sopenharmony_ci /* siginfo_t does not have si_fd */ 61d5ac70f0Sopenharmony_ci struct list_head *i; 62d5ac70f0Sopenharmony_ci list_for_each(i, &snd_async_handlers) { 63d5ac70f0Sopenharmony_ci snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); 64d5ac70f0Sopenharmony_ci if (h->callback) 65d5ac70f0Sopenharmony_ci h->callback(h); 66d5ac70f0Sopenharmony_ci } 67d5ac70f0Sopenharmony_ci#else 68d5ac70f0Sopenharmony_ci int fd; 69d5ac70f0Sopenharmony_ci struct list_head *i; 70d5ac70f0Sopenharmony_ci //assert(siginfo->si_code == SI_SIGIO); 71d5ac70f0Sopenharmony_ci if (signo == SIGIO 72d5ac70f0Sopenharmony_ci && (unsigned long)(previous_action.sa_sigaction) > MAX_SIG_FUNCTION_CODE) 73d5ac70f0Sopenharmony_ci previous_action.sa_sigaction(signo, siginfo, context); 74d5ac70f0Sopenharmony_ci fd = siginfo->si_fd; 75d5ac70f0Sopenharmony_ci list_for_each(i, &snd_async_handlers) { 76d5ac70f0Sopenharmony_ci snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist); 77d5ac70f0Sopenharmony_ci if (h->fd == fd && h->callback) 78d5ac70f0Sopenharmony_ci h->callback(h); 79d5ac70f0Sopenharmony_ci } 80d5ac70f0Sopenharmony_ci#endif 81d5ac70f0Sopenharmony_ci} 82d5ac70f0Sopenharmony_ci 83d5ac70f0Sopenharmony_ci/** 84d5ac70f0Sopenharmony_ci * \brief Registers an async handler. 85d5ac70f0Sopenharmony_ci * \param handler The function puts the pointer to the new async handler 86d5ac70f0Sopenharmony_ci * object at the address specified by \p handler. 87d5ac70f0Sopenharmony_ci * \param fd The file descriptor to be associated with the callback. 88d5ac70f0Sopenharmony_ci * \param callback The async callback function. 89d5ac70f0Sopenharmony_ci * \param private_data Private data for the async callback function. 90d5ac70f0Sopenharmony_ci * \result Zero if successful, otherwise a negative error code. 91d5ac70f0Sopenharmony_ci * 92d5ac70f0Sopenharmony_ci * This function associates the callback function with the given file, 93d5ac70f0Sopenharmony_ci * and saves this association in a \c snd_async_handler_t object. 94d5ac70f0Sopenharmony_ci * 95d5ac70f0Sopenharmony_ci * Whenever the \c SIGIO signal is raised for the file \p fd, the callback 96d5ac70f0Sopenharmony_ci * function will be called with its parameter pointing to the async handler 97d5ac70f0Sopenharmony_ci * object returned by this function. 98d5ac70f0Sopenharmony_ci * 99d5ac70f0Sopenharmony_ci * The ALSA \c sigaction handler for the \c SIGIO signal automatically 100d5ac70f0Sopenharmony_ci * multiplexes the notifications to the registered async callbacks. 101d5ac70f0Sopenharmony_ci * However, the application is responsible for instructing the device driver 102d5ac70f0Sopenharmony_ci * to generate the \c SIGIO signal. 103d5ac70f0Sopenharmony_ci * 104d5ac70f0Sopenharmony_ci * The \c SIGIO signal may have been replaced with another signal, 105d5ac70f0Sopenharmony_ci * see #snd_async_handler_get_signo. 106d5ac70f0Sopenharmony_ci * 107d5ac70f0Sopenharmony_ci * When the async handler isn't needed anymore, you must delete it with 108d5ac70f0Sopenharmony_ci * #snd_async_del_handler. 109d5ac70f0Sopenharmony_ci * 110d5ac70f0Sopenharmony_ci * \see snd_async_add_pcm_handler, snd_async_add_ctl_handler 111d5ac70f0Sopenharmony_ci */ 112d5ac70f0Sopenharmony_ciint snd_async_add_handler(snd_async_handler_t **handler, int fd, 113d5ac70f0Sopenharmony_ci snd_async_callback_t callback, void *private_data) 114d5ac70f0Sopenharmony_ci{ 115d5ac70f0Sopenharmony_ci snd_async_handler_t *h; 116d5ac70f0Sopenharmony_ci int was_empty; 117d5ac70f0Sopenharmony_ci assert(handler); 118d5ac70f0Sopenharmony_ci h = malloc(sizeof(*h)); 119d5ac70f0Sopenharmony_ci if (!h) 120d5ac70f0Sopenharmony_ci return -ENOMEM; 121d5ac70f0Sopenharmony_ci h->fd = fd; 122d5ac70f0Sopenharmony_ci h->callback = callback; 123d5ac70f0Sopenharmony_ci h->private_data = private_data; 124d5ac70f0Sopenharmony_ci was_empty = list_empty(&snd_async_handlers); 125d5ac70f0Sopenharmony_ci list_add_tail(&h->glist, &snd_async_handlers); 126d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&h->hlist); 127d5ac70f0Sopenharmony_ci *handler = h; 128d5ac70f0Sopenharmony_ci if (was_empty) { 129d5ac70f0Sopenharmony_ci int err; 130d5ac70f0Sopenharmony_ci struct sigaction act; 131d5ac70f0Sopenharmony_ci memset(&act, 0, sizeof(act)); 132d5ac70f0Sopenharmony_ci act.sa_flags = SA_RESTART | SA_SIGINFO; 133d5ac70f0Sopenharmony_ci act.sa_sigaction = snd_async_handler; 134d5ac70f0Sopenharmony_ci sigemptyset(&act.sa_mask); 135d5ac70f0Sopenharmony_ci assert(!previous_action.sa_sigaction); 136d5ac70f0Sopenharmony_ci err = sigaction(snd_async_signo, &act, &previous_action); 137d5ac70f0Sopenharmony_ci if (err < 0) { 138d5ac70f0Sopenharmony_ci SYSERR("sigaction"); 139d5ac70f0Sopenharmony_ci return -errno; 140d5ac70f0Sopenharmony_ci } 141d5ac70f0Sopenharmony_ci } 142d5ac70f0Sopenharmony_ci return 0; 143d5ac70f0Sopenharmony_ci} 144d5ac70f0Sopenharmony_ci 145d5ac70f0Sopenharmony_ci/** 146d5ac70f0Sopenharmony_ci * \brief Deletes an async handler. 147d5ac70f0Sopenharmony_ci * \param handler Handle of the async handler to delete. 148d5ac70f0Sopenharmony_ci * \result Zero if successful, otherwise a negative error code. 149d5ac70f0Sopenharmony_ci */ 150d5ac70f0Sopenharmony_ciint snd_async_del_handler(snd_async_handler_t *handler) 151d5ac70f0Sopenharmony_ci{ 152d5ac70f0Sopenharmony_ci int err = 0; 153d5ac70f0Sopenharmony_ci int was_empty = list_empty(&snd_async_handlers); 154d5ac70f0Sopenharmony_ci assert(handler); 155d5ac70f0Sopenharmony_ci list_del(&handler->glist); 156d5ac70f0Sopenharmony_ci if (!was_empty 157d5ac70f0Sopenharmony_ci && list_empty(&snd_async_handlers)) { 158d5ac70f0Sopenharmony_ci err = sigaction(snd_async_signo, &previous_action, NULL); 159d5ac70f0Sopenharmony_ci if (err < 0) { 160d5ac70f0Sopenharmony_ci SYSERR("sigaction"); 161d5ac70f0Sopenharmony_ci return -errno; 162d5ac70f0Sopenharmony_ci } 163d5ac70f0Sopenharmony_ci memset(&previous_action, 0, sizeof(previous_action)); 164d5ac70f0Sopenharmony_ci } 165d5ac70f0Sopenharmony_ci if (handler->type == SND_ASYNC_HANDLER_GENERIC) 166d5ac70f0Sopenharmony_ci goto _end; 167d5ac70f0Sopenharmony_ci if (!list_empty(&handler->hlist)) 168d5ac70f0Sopenharmony_ci list_del(&handler->hlist); 169d5ac70f0Sopenharmony_ci if (!list_empty(&handler->hlist)) 170d5ac70f0Sopenharmony_ci goto _end; 171d5ac70f0Sopenharmony_ci switch (handler->type) { 172d5ac70f0Sopenharmony_ci#ifdef BUILD_PCM 173d5ac70f0Sopenharmony_ci case SND_ASYNC_HANDLER_PCM: 174d5ac70f0Sopenharmony_ci err = snd_pcm_async(handler->u.pcm, -1, 1); 175d5ac70f0Sopenharmony_ci break; 176d5ac70f0Sopenharmony_ci#endif 177d5ac70f0Sopenharmony_ci case SND_ASYNC_HANDLER_CTL: 178d5ac70f0Sopenharmony_ci err = snd_ctl_async(handler->u.ctl, -1, 1); 179d5ac70f0Sopenharmony_ci break; 180d5ac70f0Sopenharmony_ci default: 181d5ac70f0Sopenharmony_ci assert(0); 182d5ac70f0Sopenharmony_ci } 183d5ac70f0Sopenharmony_ci _end: 184d5ac70f0Sopenharmony_ci free(handler); 185d5ac70f0Sopenharmony_ci return err; 186d5ac70f0Sopenharmony_ci} 187d5ac70f0Sopenharmony_ci 188d5ac70f0Sopenharmony_ci/** 189d5ac70f0Sopenharmony_ci * \brief Returns the signal number assigned to an async handler. 190d5ac70f0Sopenharmony_ci * \param handler Handle to an async handler. 191d5ac70f0Sopenharmony_ci * \result The signal number if successful, otherwise a negative error code. 192d5ac70f0Sopenharmony_ci * 193d5ac70f0Sopenharmony_ci * The signal number for async handlers usually is \c SIGIO, 194d5ac70f0Sopenharmony_ci * but wizards can redefine it to a realtime signal 195d5ac70f0Sopenharmony_ci * when compiling the ALSA library. 196d5ac70f0Sopenharmony_ci */ 197d5ac70f0Sopenharmony_ciint snd_async_handler_get_signo(snd_async_handler_t *handler) 198d5ac70f0Sopenharmony_ci{ 199d5ac70f0Sopenharmony_ci assert(handler); 200d5ac70f0Sopenharmony_ci return snd_async_signo; 201d5ac70f0Sopenharmony_ci} 202d5ac70f0Sopenharmony_ci 203d5ac70f0Sopenharmony_ci/** 204d5ac70f0Sopenharmony_ci * \brief Returns the file descriptor assigned to an async handler. 205d5ac70f0Sopenharmony_ci * \param handler Handle to an async handler. 206d5ac70f0Sopenharmony_ci * \result The file descriptor if successful, otherwise a negative error code. 207d5ac70f0Sopenharmony_ci */ 208d5ac70f0Sopenharmony_ciint snd_async_handler_get_fd(snd_async_handler_t *handler) 209d5ac70f0Sopenharmony_ci{ 210d5ac70f0Sopenharmony_ci assert(handler); 211d5ac70f0Sopenharmony_ci return handler->fd; 212d5ac70f0Sopenharmony_ci} 213d5ac70f0Sopenharmony_ci 214d5ac70f0Sopenharmony_ci/** 215d5ac70f0Sopenharmony_ci * \brief Returns the private data assigned to an async handler. 216d5ac70f0Sopenharmony_ci * \param handler Handle to an async handler. 217d5ac70f0Sopenharmony_ci * \result The \c private_data value registered with the async handler. 218d5ac70f0Sopenharmony_ci */ 219d5ac70f0Sopenharmony_civoid *snd_async_handler_get_callback_private(snd_async_handler_t *handler) 220d5ac70f0Sopenharmony_ci{ 221d5ac70f0Sopenharmony_ci assert(handler); 222d5ac70f0Sopenharmony_ci return handler->private_data; 223d5ac70f0Sopenharmony_ci} 224d5ac70f0Sopenharmony_ci 225