1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Advanced Linux Sound Architecture Control Program 3c72fcc34Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4c72fcc34Sopenharmony_ci * 5c72fcc34Sopenharmony_ci * 6c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 7c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 8c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 9c72fcc34Sopenharmony_ci * (at your option) any later version. 10c72fcc34Sopenharmony_ci * 11c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 12c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14c72fcc34Sopenharmony_ci * GNU General Public License for more details. 15c72fcc34Sopenharmony_ci * 16c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 17c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 18c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19c72fcc34Sopenharmony_ci * 20c72fcc34Sopenharmony_ci */ 21c72fcc34Sopenharmony_ci 22c72fcc34Sopenharmony_ci#include "aconfig.h" 23c72fcc34Sopenharmony_ci#include "version.h" 24c72fcc34Sopenharmony_ci#include <getopt.h> 25c72fcc34Sopenharmony_ci#include <stdarg.h> 26c72fcc34Sopenharmony_ci#include <stdio.h> 27c72fcc34Sopenharmony_ci#include <assert.h> 28c72fcc34Sopenharmony_ci#include <errno.h> 29c72fcc34Sopenharmony_ci#include <signal.h> 30c72fcc34Sopenharmony_ci#include <time.h> 31c72fcc34Sopenharmony_ci#include <poll.h> 32c72fcc34Sopenharmony_ci#include "alsactl.h" 33c72fcc34Sopenharmony_ci 34c72fcc34Sopenharmony_cistruct id_list { 35c72fcc34Sopenharmony_ci snd_ctl_elem_id_t **list; 36c72fcc34Sopenharmony_ci int size; 37c72fcc34Sopenharmony_ci}; 38c72fcc34Sopenharmony_ci 39c72fcc34Sopenharmony_cistruct card { 40c72fcc34Sopenharmony_ci int index; 41c72fcc34Sopenharmony_ci int pfds; 42c72fcc34Sopenharmony_ci snd_ctl_t *handle; 43c72fcc34Sopenharmony_ci struct id_list whitelist; 44c72fcc34Sopenharmony_ci struct id_list blacklist; 45c72fcc34Sopenharmony_ci}; 46c72fcc34Sopenharmony_ci 47c72fcc34Sopenharmony_cistatic int quit = 0; 48c72fcc34Sopenharmony_cistatic int rescan = 0; 49c72fcc34Sopenharmony_cistatic int save_now = 0; 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_cistatic void signal_handler_quit(int sig) 52c72fcc34Sopenharmony_ci{ 53c72fcc34Sopenharmony_ci quit = 1; 54c72fcc34Sopenharmony_ci signal(sig, signal_handler_quit); 55c72fcc34Sopenharmony_ci} 56c72fcc34Sopenharmony_ci 57c72fcc34Sopenharmony_cistatic void signal_handler_save_and_quit(int sig) 58c72fcc34Sopenharmony_ci{ 59c72fcc34Sopenharmony_ci quit = save_now = 1; 60c72fcc34Sopenharmony_ci signal(sig, signal_handler_quit); 61c72fcc34Sopenharmony_ci} 62c72fcc34Sopenharmony_ci 63c72fcc34Sopenharmony_cistatic void signal_handler_rescan(int sig) 64c72fcc34Sopenharmony_ci{ 65c72fcc34Sopenharmony_ci rescan = 1; 66c72fcc34Sopenharmony_ci signal(sig, signal_handler_rescan); 67c72fcc34Sopenharmony_ci} 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_cistatic void free_list(struct id_list *list) 70c72fcc34Sopenharmony_ci{ 71c72fcc34Sopenharmony_ci int i; 72c72fcc34Sopenharmony_ci 73c72fcc34Sopenharmony_ci for (i = 0; i < list->size; i++) 74c72fcc34Sopenharmony_ci free(list->list[i]); 75c72fcc34Sopenharmony_ci free(list->list); 76c72fcc34Sopenharmony_ci} 77c72fcc34Sopenharmony_ci 78c72fcc34Sopenharmony_cistatic void card_free(struct card **card) 79c72fcc34Sopenharmony_ci{ 80c72fcc34Sopenharmony_ci struct card *c = *card; 81c72fcc34Sopenharmony_ci 82c72fcc34Sopenharmony_ci free_list(&c->blacklist); 83c72fcc34Sopenharmony_ci free_list(&c->whitelist); 84c72fcc34Sopenharmony_ci if (c->handle) 85c72fcc34Sopenharmony_ci snd_ctl_close(c->handle); 86c72fcc34Sopenharmony_ci free(c); 87c72fcc34Sopenharmony_ci *card = NULL; 88c72fcc34Sopenharmony_ci} 89c72fcc34Sopenharmony_ci 90c72fcc34Sopenharmony_cistatic void add_card(struct card ***cards, int *count, const char *cardname) 91c72fcc34Sopenharmony_ci{ 92c72fcc34Sopenharmony_ci struct card *card, **cc; 93c72fcc34Sopenharmony_ci int i, index, findex; 94c72fcc34Sopenharmony_ci char device[16]; 95c72fcc34Sopenharmony_ci 96c72fcc34Sopenharmony_ci index = snd_card_get_index(cardname); 97c72fcc34Sopenharmony_ci if (index < 0) 98c72fcc34Sopenharmony_ci return; 99c72fcc34Sopenharmony_ci for (i = 0, findex = -1; i < *count; i++) { 100c72fcc34Sopenharmony_ci if ((*cards)[i] == NULL) { 101c72fcc34Sopenharmony_ci findex = i; 102c72fcc34Sopenharmony_ci } else { 103c72fcc34Sopenharmony_ci if ((*cards)[i]->index == index) 104c72fcc34Sopenharmony_ci return; 105c72fcc34Sopenharmony_ci } 106c72fcc34Sopenharmony_ci } 107c72fcc34Sopenharmony_ci card = calloc(1, sizeof(*card)); 108c72fcc34Sopenharmony_ci if (card == NULL) 109c72fcc34Sopenharmony_ci return; 110c72fcc34Sopenharmony_ci card->index = index; 111c72fcc34Sopenharmony_ci sprintf(device, "hw:%i", index); 112c72fcc34Sopenharmony_ci if (snd_ctl_open(&card->handle, device, SND_CTL_READONLY|SND_CTL_NONBLOCK) < 0) { 113c72fcc34Sopenharmony_ci card_free(&card); 114c72fcc34Sopenharmony_ci return; 115c72fcc34Sopenharmony_ci } 116c72fcc34Sopenharmony_ci card->pfds = snd_ctl_poll_descriptors_count(card->handle); 117c72fcc34Sopenharmony_ci if (card->pfds < 0) { 118c72fcc34Sopenharmony_ci card_free(&card); 119c72fcc34Sopenharmony_ci return; 120c72fcc34Sopenharmony_ci } 121c72fcc34Sopenharmony_ci if (snd_ctl_subscribe_events(card->handle, 1) < 0) { 122c72fcc34Sopenharmony_ci card_free(&card); 123c72fcc34Sopenharmony_ci return; 124c72fcc34Sopenharmony_ci } 125c72fcc34Sopenharmony_ci if (findex >= 0) { 126c72fcc34Sopenharmony_ci (*cards)[findex] = card; 127c72fcc34Sopenharmony_ci } else { 128c72fcc34Sopenharmony_ci cc = realloc(*cards, sizeof(void *) * (*count + 1)); 129c72fcc34Sopenharmony_ci if (cc == NULL) { 130c72fcc34Sopenharmony_ci card_free(&card); 131c72fcc34Sopenharmony_ci return; 132c72fcc34Sopenharmony_ci } 133c72fcc34Sopenharmony_ci cc[*count] = card; 134c72fcc34Sopenharmony_ci *count = *count + 1; 135c72fcc34Sopenharmony_ci *cards = cc; 136c72fcc34Sopenharmony_ci } 137c72fcc34Sopenharmony_ci} 138c72fcc34Sopenharmony_ci 139c72fcc34Sopenharmony_cistatic void add_cards(struct card ***cards, int *count) 140c72fcc34Sopenharmony_ci{ 141c72fcc34Sopenharmony_ci int card = -1; 142c72fcc34Sopenharmony_ci char cardname[16]; 143c72fcc34Sopenharmony_ci 144c72fcc34Sopenharmony_ci while (1) { 145c72fcc34Sopenharmony_ci if (snd_card_next(&card) < 0) 146c72fcc34Sopenharmony_ci break; 147c72fcc34Sopenharmony_ci if (card < 0) 148c72fcc34Sopenharmony_ci break; 149c72fcc34Sopenharmony_ci if (card >= 0) { 150c72fcc34Sopenharmony_ci sprintf(cardname, "%i", card); 151c72fcc34Sopenharmony_ci add_card(cards, count, cardname); 152c72fcc34Sopenharmony_ci } 153c72fcc34Sopenharmony_ci } 154c72fcc34Sopenharmony_ci} 155c72fcc34Sopenharmony_ci 156c72fcc34Sopenharmony_cistatic int compare_ids(snd_ctl_elem_id_t *id1, snd_ctl_elem_id_t *id2) 157c72fcc34Sopenharmony_ci{ 158c72fcc34Sopenharmony_ci if (id1 == NULL || id2 == NULL) 159c72fcc34Sopenharmony_ci return 0; 160c72fcc34Sopenharmony_ci return snd_ctl_elem_id_get_interface(id1) == snd_ctl_elem_id_get_interface(id2) && 161c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_index(id1) == snd_ctl_elem_id_get_index(id2) && 162c72fcc34Sopenharmony_ci strcmp(snd_ctl_elem_id_get_name(id1), snd_ctl_elem_id_get_name(id2)) == 0 && 163c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_device(id1) == snd_ctl_elem_id_get_device(id2) && 164c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_subdevice(id1) == snd_ctl_elem_id_get_subdevice(id2); 165c72fcc34Sopenharmony_ci} 166c72fcc34Sopenharmony_ci 167c72fcc34Sopenharmony_cistatic int in_list(struct id_list *list, snd_ctl_elem_id_t *id) 168c72fcc34Sopenharmony_ci{ 169c72fcc34Sopenharmony_ci int i; 170c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id1; 171c72fcc34Sopenharmony_ci 172c72fcc34Sopenharmony_ci for (i = 0; i < list->size; i++) { 173c72fcc34Sopenharmony_ci id1 = list->list[i]; 174c72fcc34Sopenharmony_ci if (id1 == NULL) 175c72fcc34Sopenharmony_ci continue; 176c72fcc34Sopenharmony_ci if (compare_ids(id, id1)) 177c72fcc34Sopenharmony_ci return 1; 178c72fcc34Sopenharmony_ci } 179c72fcc34Sopenharmony_ci return 0; 180c72fcc34Sopenharmony_ci} 181c72fcc34Sopenharmony_ci 182c72fcc34Sopenharmony_cistatic void remove_from_list(struct id_list *list, snd_ctl_elem_id_t *id) 183c72fcc34Sopenharmony_ci{ 184c72fcc34Sopenharmony_ci int i; 185c72fcc34Sopenharmony_ci 186c72fcc34Sopenharmony_ci for (i = 0; i < list->size; i++) { 187c72fcc34Sopenharmony_ci if (compare_ids(id, list->list[i])) { 188c72fcc34Sopenharmony_ci free(list->list[i]); 189c72fcc34Sopenharmony_ci list->list[i] = NULL; 190c72fcc34Sopenharmony_ci } 191c72fcc34Sopenharmony_ci } 192c72fcc34Sopenharmony_ci} 193c72fcc34Sopenharmony_ci 194c72fcc34Sopenharmony_cistatic void add_to_list(struct id_list *list, snd_ctl_elem_id_t *id) 195c72fcc34Sopenharmony_ci{ 196c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id1; 197c72fcc34Sopenharmony_ci snd_ctl_elem_id_t **n; 198c72fcc34Sopenharmony_ci int i; 199c72fcc34Sopenharmony_ci 200c72fcc34Sopenharmony_ci if (snd_ctl_elem_id_malloc(&id1)) 201c72fcc34Sopenharmony_ci return; 202c72fcc34Sopenharmony_ci snd_ctl_elem_id_copy(id1, id); 203c72fcc34Sopenharmony_ci for (i = 0; i < list->size; i++) { 204c72fcc34Sopenharmony_ci if (list->list[i] == NULL) { 205c72fcc34Sopenharmony_ci list->list[i] = id1; 206c72fcc34Sopenharmony_ci return; 207c72fcc34Sopenharmony_ci } 208c72fcc34Sopenharmony_ci } 209c72fcc34Sopenharmony_ci n = realloc(list->list, sizeof(void *) * (list->size + 1)); 210c72fcc34Sopenharmony_ci if (n == NULL) 211c72fcc34Sopenharmony_ci return; 212c72fcc34Sopenharmony_ci n[list->size] = id1; 213c72fcc34Sopenharmony_ci list->size++; 214c72fcc34Sopenharmony_ci list->list = n; 215c72fcc34Sopenharmony_ci} 216c72fcc34Sopenharmony_ci 217c72fcc34Sopenharmony_cistatic int check_lists(struct card *card, snd_ctl_elem_id_t *id) 218c72fcc34Sopenharmony_ci{ 219c72fcc34Sopenharmony_ci snd_ctl_elem_info_t *info; 220c72fcc34Sopenharmony_ci snd_ctl_elem_info_alloca(&info); 221c72fcc34Sopenharmony_ci 222c72fcc34Sopenharmony_ci if (in_list(&card->blacklist, id)) 223c72fcc34Sopenharmony_ci return 0; 224c72fcc34Sopenharmony_ci if (in_list(&card->whitelist, id)) 225c72fcc34Sopenharmony_ci return 1; 226c72fcc34Sopenharmony_ci snd_ctl_elem_info_set_id(info, id); 227c72fcc34Sopenharmony_ci if (snd_ctl_elem_info(card->handle, info) < 0) 228c72fcc34Sopenharmony_ci return 0; 229c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_writable(info) || 230c72fcc34Sopenharmony_ci snd_ctl_elem_info_is_tlv_writable(info)) { 231c72fcc34Sopenharmony_ci add_to_list(&card->whitelist, id); 232c72fcc34Sopenharmony_ci return 1; 233c72fcc34Sopenharmony_ci } else { 234c72fcc34Sopenharmony_ci add_to_list(&card->blacklist, id); 235c72fcc34Sopenharmony_ci return 0; 236c72fcc34Sopenharmony_ci } 237c72fcc34Sopenharmony_ci} 238c72fcc34Sopenharmony_ci 239c72fcc34Sopenharmony_cistatic int card_events(struct card *card) 240c72fcc34Sopenharmony_ci{ 241c72fcc34Sopenharmony_ci int res = 0; 242c72fcc34Sopenharmony_ci snd_ctl_event_t *ev; 243c72fcc34Sopenharmony_ci snd_ctl_event_type_t type; 244c72fcc34Sopenharmony_ci unsigned int mask; 245c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 246c72fcc34Sopenharmony_ci snd_ctl_event_alloca(&ev); 247c72fcc34Sopenharmony_ci snd_ctl_elem_id_alloca(&id); 248c72fcc34Sopenharmony_ci 249c72fcc34Sopenharmony_ci while (snd_ctl_read(card->handle, ev) == 1) { 250c72fcc34Sopenharmony_ci type = snd_ctl_event_get_type(ev); 251c72fcc34Sopenharmony_ci if (type != SND_CTL_EVENT_ELEM) 252c72fcc34Sopenharmony_ci continue; 253c72fcc34Sopenharmony_ci mask = snd_ctl_event_elem_get_mask(ev); 254c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_id(ev, id); 255c72fcc34Sopenharmony_ci if (mask == SND_CTL_EVENT_MASK_REMOVE) { 256c72fcc34Sopenharmony_ci remove_from_list(&card->whitelist, id); 257c72fcc34Sopenharmony_ci remove_from_list(&card->blacklist, id); 258c72fcc34Sopenharmony_ci continue; 259c72fcc34Sopenharmony_ci } 260c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_INFO) { 261c72fcc34Sopenharmony_ci remove_from_list(&card->whitelist, id); 262c72fcc34Sopenharmony_ci remove_from_list(&card->blacklist, id); 263c72fcc34Sopenharmony_ci } 264c72fcc34Sopenharmony_ci if (mask & (SND_CTL_EVENT_MASK_VALUE| 265c72fcc34Sopenharmony_ci SND_CTL_EVENT_MASK_ADD| 266c72fcc34Sopenharmony_ci SND_CTL_EVENT_MASK_TLV)) { 267c72fcc34Sopenharmony_ci if (check_lists(card, id)) 268c72fcc34Sopenharmony_ci res = 1; 269c72fcc34Sopenharmony_ci } 270c72fcc34Sopenharmony_ci } 271c72fcc34Sopenharmony_ci return res; 272c72fcc34Sopenharmony_ci} 273c72fcc34Sopenharmony_ci 274c72fcc34Sopenharmony_cistatic long read_pid_file(const char *pidfile) 275c72fcc34Sopenharmony_ci{ 276c72fcc34Sopenharmony_ci int fd, err; 277c72fcc34Sopenharmony_ci char pid_txt[12]; 278c72fcc34Sopenharmony_ci 279c72fcc34Sopenharmony_ci fd = open(pidfile, O_RDONLY); 280c72fcc34Sopenharmony_ci if (fd >= 0) { 281c72fcc34Sopenharmony_ci err = read(fd, pid_txt, 11); 282c72fcc34Sopenharmony_ci if (err != 11) 283c72fcc34Sopenharmony_ci err = err < 0 ? -errno : -EIO; 284c72fcc34Sopenharmony_ci close(fd); 285c72fcc34Sopenharmony_ci pid_txt[11] = '\0'; 286c72fcc34Sopenharmony_ci return err < 0 ? err : atol(pid_txt); 287c72fcc34Sopenharmony_ci } else { 288c72fcc34Sopenharmony_ci return -errno; 289c72fcc34Sopenharmony_ci } 290c72fcc34Sopenharmony_ci} 291c72fcc34Sopenharmony_ci 292c72fcc34Sopenharmony_cistatic int write_pid_file(const char *pidfile) 293c72fcc34Sopenharmony_ci{ 294c72fcc34Sopenharmony_ci int fd, err; 295c72fcc34Sopenharmony_ci char pid_txt[14]; 296c72fcc34Sopenharmony_ci 297c72fcc34Sopenharmony_ci sprintf(pid_txt, "%10li\n", (long)getpid()); 298c72fcc34Sopenharmony_ci fd = open(pidfile, O_WRONLY|O_CREAT|O_EXCL, 0600); 299c72fcc34Sopenharmony_ci if (fd >= 0) { 300c72fcc34Sopenharmony_ci err = write(fd, pid_txt, 11); 301c72fcc34Sopenharmony_ci if (err != 11) { 302c72fcc34Sopenharmony_ci err = err < 0 ? -errno : -EIO; 303c72fcc34Sopenharmony_ci unlink(pidfile); 304c72fcc34Sopenharmony_ci } else { 305c72fcc34Sopenharmony_ci err = 0; 306c72fcc34Sopenharmony_ci } 307c72fcc34Sopenharmony_ci close(fd); 308c72fcc34Sopenharmony_ci } else { 309c72fcc34Sopenharmony_ci err = -errno; 310c72fcc34Sopenharmony_ci } 311c72fcc34Sopenharmony_ci return err; 312c72fcc34Sopenharmony_ci} 313c72fcc34Sopenharmony_ci 314c72fcc34Sopenharmony_ciint state_daemon_kill(const char *pidfile, const char *cmd) 315c72fcc34Sopenharmony_ci{ 316c72fcc34Sopenharmony_ci long pid; 317c72fcc34Sopenharmony_ci int sig = SIGHUP; 318c72fcc34Sopenharmony_ci 319c72fcc34Sopenharmony_ci if (cmd == NULL) { 320c72fcc34Sopenharmony_ci error("Specify kill command (quit, rescan or save_and_quit)"); 321c72fcc34Sopenharmony_ci return -EINVAL; 322c72fcc34Sopenharmony_ci } 323c72fcc34Sopenharmony_ci if (strcmp(cmd, "rescan") == 0) 324c72fcc34Sopenharmony_ci sig = SIGUSR1; 325c72fcc34Sopenharmony_ci else if (strcmp(cmd, "save_and_quit") == 0) 326c72fcc34Sopenharmony_ci sig = SIGUSR2; 327c72fcc34Sopenharmony_ci else if (strcmp(cmd, "quit") == 0) 328c72fcc34Sopenharmony_ci sig = SIGTERM; 329c72fcc34Sopenharmony_ci if (sig == SIGHUP) { 330c72fcc34Sopenharmony_ci error("Unknown kill command '%s'", cmd); 331c72fcc34Sopenharmony_ci return -EINVAL; 332c72fcc34Sopenharmony_ci } 333c72fcc34Sopenharmony_ci pid = read_pid_file(pidfile); 334c72fcc34Sopenharmony_ci if (pid > 0) { 335c72fcc34Sopenharmony_ci if (kill(pid, sig) >= 0) 336c72fcc34Sopenharmony_ci return 0; 337c72fcc34Sopenharmony_ci return -errno; 338c72fcc34Sopenharmony_ci } 339c72fcc34Sopenharmony_ci return 0; 340c72fcc34Sopenharmony_ci} 341c72fcc34Sopenharmony_ci 342c72fcc34Sopenharmony_cistatic int check_another_instance(const char *pidfile) 343c72fcc34Sopenharmony_ci{ 344c72fcc34Sopenharmony_ci long pid; 345c72fcc34Sopenharmony_ci 346c72fcc34Sopenharmony_ci pid = read_pid_file(pidfile); 347c72fcc34Sopenharmony_ci if (pid >= 0) { 348c72fcc34Sopenharmony_ci /* invoke new card rescan */ 349c72fcc34Sopenharmony_ci if (kill(pid, SIGUSR1) >= 0) { 350c72fcc34Sopenharmony_ci usleep(1000); 351c72fcc34Sopenharmony_ci pid = read_pid_file(pidfile); 352c72fcc34Sopenharmony_ci if (pid >= 0) 353c72fcc34Sopenharmony_ci return 1; 354c72fcc34Sopenharmony_ci } 355c72fcc34Sopenharmony_ci } 356c72fcc34Sopenharmony_ci return 0; 357c72fcc34Sopenharmony_ci} 358c72fcc34Sopenharmony_ci 359c72fcc34Sopenharmony_ciint state_daemon(const char *file, const char *cardname, int period, 360c72fcc34Sopenharmony_ci const char *pidfile) 361c72fcc34Sopenharmony_ci{ 362c72fcc34Sopenharmony_ci int count = 0, pcount, psize = 0, i, j, k, changed = 0; 363c72fcc34Sopenharmony_ci time_t last_write, now; 364c72fcc34Sopenharmony_ci unsigned short revents; 365c72fcc34Sopenharmony_ci struct card **cards = NULL; 366c72fcc34Sopenharmony_ci struct pollfd *pfd = NULL, *pfdn; 367c72fcc34Sopenharmony_ci 368c72fcc34Sopenharmony_ci if (check_another_instance(pidfile)) 369c72fcc34Sopenharmony_ci return 0; 370c72fcc34Sopenharmony_ci rescan = 1; 371c72fcc34Sopenharmony_ci signal(SIGABRT, signal_handler_quit); 372c72fcc34Sopenharmony_ci signal(SIGTERM, signal_handler_quit); 373c72fcc34Sopenharmony_ci signal(SIGINT, signal_handler_quit); 374c72fcc34Sopenharmony_ci signal(SIGUSR1, signal_handler_rescan); 375c72fcc34Sopenharmony_ci signal(SIGUSR2, signal_handler_save_and_quit); 376c72fcc34Sopenharmony_ci write_pid_file(pidfile); 377c72fcc34Sopenharmony_ci time(&last_write); 378c72fcc34Sopenharmony_ci while (!quit || save_now) { 379c72fcc34Sopenharmony_ci if (save_now) 380c72fcc34Sopenharmony_ci goto save; 381c72fcc34Sopenharmony_ci if (rescan) { 382c72fcc34Sopenharmony_ci if (cardname) { 383c72fcc34Sopenharmony_ci add_card(&cards, &count, cardname); 384c72fcc34Sopenharmony_ci } else { 385c72fcc34Sopenharmony_ci add_cards(&cards, &count); 386c72fcc34Sopenharmony_ci } 387c72fcc34Sopenharmony_ci snd_config_update_free_global(); 388c72fcc34Sopenharmony_ci rescan = 0; 389c72fcc34Sopenharmony_ci } 390c72fcc34Sopenharmony_ci for (i = pcount = 0; i < count; i++) { 391c72fcc34Sopenharmony_ci if (cards[i] == NULL) 392c72fcc34Sopenharmony_ci continue; 393c72fcc34Sopenharmony_ci pcount += cards[i]->pfds; 394c72fcc34Sopenharmony_ci } 395c72fcc34Sopenharmony_ci if (pcount > psize) { 396c72fcc34Sopenharmony_ci pfdn = realloc(pfd, sizeof(struct pollfd) * pcount); 397c72fcc34Sopenharmony_ci if (pfdn) { 398c72fcc34Sopenharmony_ci psize = pcount; 399c72fcc34Sopenharmony_ci pfd = pfdn; 400c72fcc34Sopenharmony_ci } else { 401c72fcc34Sopenharmony_ci error("No enough memory..."); 402c72fcc34Sopenharmony_ci goto out; 403c72fcc34Sopenharmony_ci } 404c72fcc34Sopenharmony_ci } 405c72fcc34Sopenharmony_ci for (i = j = 0; i < count; i++) { 406c72fcc34Sopenharmony_ci if (cards[i] == NULL) 407c72fcc34Sopenharmony_ci continue; 408c72fcc34Sopenharmony_ci k = snd_ctl_poll_descriptors(cards[i]->handle, pfd + j, pcount - j); 409c72fcc34Sopenharmony_ci if (k != cards[i]->pfds) { 410c72fcc34Sopenharmony_ci error("poll prepare failed: %i", k); 411c72fcc34Sopenharmony_ci goto out; 412c72fcc34Sopenharmony_ci } 413c72fcc34Sopenharmony_ci j += k; 414c72fcc34Sopenharmony_ci } 415c72fcc34Sopenharmony_ci i = poll(pfd, j, (period / 2) * 1000); 416c72fcc34Sopenharmony_ci if (i < 0 && errno == EINTR) 417c72fcc34Sopenharmony_ci continue; 418c72fcc34Sopenharmony_ci if (i < 0) { 419c72fcc34Sopenharmony_ci error("poll failed: %s", strerror(errno)); 420c72fcc34Sopenharmony_ci break; 421c72fcc34Sopenharmony_ci } 422c72fcc34Sopenharmony_ci time(&now); 423c72fcc34Sopenharmony_ci for (i = j = 0; i < count; i++) { 424c72fcc34Sopenharmony_ci if (cards[i] == NULL) 425c72fcc34Sopenharmony_ci continue; 426c72fcc34Sopenharmony_ci k = snd_ctl_poll_descriptors_revents(cards[i]->handle, 427c72fcc34Sopenharmony_ci pfd + j, cards[i]->pfds, &revents); 428c72fcc34Sopenharmony_ci if (k < 0) { 429c72fcc34Sopenharmony_ci error("poll post failed: %i\n", k); 430c72fcc34Sopenharmony_ci goto out; 431c72fcc34Sopenharmony_ci } 432c72fcc34Sopenharmony_ci j += cards[i]->pfds; 433c72fcc34Sopenharmony_ci if (revents & (POLLERR|POLLNVAL)) { 434c72fcc34Sopenharmony_ci card_free(&cards[i]); 435c72fcc34Sopenharmony_ci } else if (revents & POLLIN) { 436c72fcc34Sopenharmony_ci if (card_events(cards[i])) { 437c72fcc34Sopenharmony_ci /* delay the write */ 438c72fcc34Sopenharmony_ci if (!changed) 439c72fcc34Sopenharmony_ci last_write = now; 440c72fcc34Sopenharmony_ci changed = 1; 441c72fcc34Sopenharmony_ci } 442c72fcc34Sopenharmony_ci } 443c72fcc34Sopenharmony_ci } 444c72fcc34Sopenharmony_ci if ((now - last_write >= period && changed) || save_now) { 445c72fcc34Sopenharmony_cisave: 446c72fcc34Sopenharmony_ci changed = save_now = 0; 447c72fcc34Sopenharmony_ci save_state(file, cardname); 448c72fcc34Sopenharmony_ci } 449c72fcc34Sopenharmony_ci } 450c72fcc34Sopenharmony_ciout: 451c72fcc34Sopenharmony_ci free(pfd); 452c72fcc34Sopenharmony_ci remove(pidfile); 453c72fcc34Sopenharmony_ci if (cards) { 454c72fcc34Sopenharmony_ci for (i = 0; i < count; i++) 455c72fcc34Sopenharmony_ci card_free(&cards[i]); 456c72fcc34Sopenharmony_ci free(cards); 457c72fcc34Sopenharmony_ci } 458c72fcc34Sopenharmony_ci return 0; 459c72fcc34Sopenharmony_ci} 460