1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Advanced Linux Sound Architecture Control Program 3c72fcc34Sopenharmony_ci * Copyright (c) by Takashi Iwai <tiwai@suse.de> 4c72fcc34Sopenharmony_ci * 5c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 6c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 7c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 8c72fcc34Sopenharmony_ci * (at your option) any later version. 9c72fcc34Sopenharmony_ci * 10c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 11c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c72fcc34Sopenharmony_ci * GNU General Public License for more details. 14c72fcc34Sopenharmony_ci * 15c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 16c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 17c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18c72fcc34Sopenharmony_ci */ 19c72fcc34Sopenharmony_ci 20c72fcc34Sopenharmony_ci#include "aconfig.h" 21c72fcc34Sopenharmony_ci#include "version.h" 22c72fcc34Sopenharmony_ci#include <stdio.h> 23c72fcc34Sopenharmony_ci#include <stdbool.h> 24c72fcc34Sopenharmony_ci#include <string.h> 25c72fcc34Sopenharmony_ci#include <sys/epoll.h> 26c72fcc34Sopenharmony_ci#include <sys/inotify.h> 27c72fcc34Sopenharmony_ci#include <limits.h> 28c72fcc34Sopenharmony_ci#include <time.h> 29c72fcc34Sopenharmony_ci#include <signal.h> 30c72fcc34Sopenharmony_ci#include <sys/signalfd.h> 31c72fcc34Sopenharmony_ci 32c72fcc34Sopenharmony_ci#include <stddef.h> 33c72fcc34Sopenharmony_ci#include "list.h" 34c72fcc34Sopenharmony_ci 35c72fcc34Sopenharmony_ci#include "alsactl.h" 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_cistruct src_entry { 38c72fcc34Sopenharmony_ci snd_ctl_t *handle; 39c72fcc34Sopenharmony_ci char *name; 40c72fcc34Sopenharmony_ci unsigned int pfd_count; 41c72fcc34Sopenharmony_ci struct list_head list; 42c72fcc34Sopenharmony_ci}; 43c72fcc34Sopenharmony_ci 44c72fcc34Sopenharmony_cistatic void remove_source_entry(struct src_entry *entry) 45c72fcc34Sopenharmony_ci{ 46c72fcc34Sopenharmony_ci list_del(&entry->list); 47c72fcc34Sopenharmony_ci if (entry->handle) 48c72fcc34Sopenharmony_ci snd_ctl_close(entry->handle); 49c72fcc34Sopenharmony_ci free(entry->name); 50c72fcc34Sopenharmony_ci free(entry); 51c72fcc34Sopenharmony_ci} 52c72fcc34Sopenharmony_ci 53c72fcc34Sopenharmony_cistatic void clear_source_list(struct list_head *srcs) 54c72fcc34Sopenharmony_ci{ 55c72fcc34Sopenharmony_ci struct src_entry *entry, *tmp; 56c72fcc34Sopenharmony_ci 57c72fcc34Sopenharmony_ci list_for_each_entry_safe(entry, tmp, srcs, list) 58c72fcc34Sopenharmony_ci remove_source_entry(entry); 59c72fcc34Sopenharmony_ci} 60c72fcc34Sopenharmony_ci 61c72fcc34Sopenharmony_cistatic int insert_source_entry(struct list_head *srcs, snd_ctl_t *handle, 62c72fcc34Sopenharmony_ci const char *name) 63c72fcc34Sopenharmony_ci{ 64c72fcc34Sopenharmony_ci struct src_entry *entry; 65c72fcc34Sopenharmony_ci int count; 66c72fcc34Sopenharmony_ci int err; 67c72fcc34Sopenharmony_ci 68c72fcc34Sopenharmony_ci entry = calloc(1, sizeof(*entry)); 69c72fcc34Sopenharmony_ci if (!entry) 70c72fcc34Sopenharmony_ci return -ENOMEM; 71c72fcc34Sopenharmony_ci INIT_LIST_HEAD(&entry->list); 72c72fcc34Sopenharmony_ci entry->handle = handle; 73c72fcc34Sopenharmony_ci 74c72fcc34Sopenharmony_ci entry->name = strdup(name); 75c72fcc34Sopenharmony_ci if (!entry->name) { 76c72fcc34Sopenharmony_ci err = -ENOMEM; 77c72fcc34Sopenharmony_ci goto error; 78c72fcc34Sopenharmony_ci } 79c72fcc34Sopenharmony_ci 80c72fcc34Sopenharmony_ci count = snd_ctl_poll_descriptors_count(handle); 81c72fcc34Sopenharmony_ci if (count < 0) { 82c72fcc34Sopenharmony_ci err = count; 83c72fcc34Sopenharmony_ci goto error; 84c72fcc34Sopenharmony_ci } 85c72fcc34Sopenharmony_ci if (count == 0) { 86c72fcc34Sopenharmony_ci err = -ENXIO; 87c72fcc34Sopenharmony_ci goto error; 88c72fcc34Sopenharmony_ci } 89c72fcc34Sopenharmony_ci entry->pfd_count = count; 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_ci list_add_tail(&entry->list, srcs); 92c72fcc34Sopenharmony_ci 93c72fcc34Sopenharmony_ci return 0; 94c72fcc34Sopenharmony_cierror: 95c72fcc34Sopenharmony_ci remove_source_entry(entry); 96c72fcc34Sopenharmony_ci return err; 97c72fcc34Sopenharmony_ci} 98c72fcc34Sopenharmony_ci 99c72fcc34Sopenharmony_cistatic int open_ctl(const char *name, snd_ctl_t **ctlp) 100c72fcc34Sopenharmony_ci{ 101c72fcc34Sopenharmony_ci snd_ctl_t *ctl; 102c72fcc34Sopenharmony_ci int err; 103c72fcc34Sopenharmony_ci 104c72fcc34Sopenharmony_ci err = snd_ctl_open(&ctl, name, SND_CTL_READONLY); 105c72fcc34Sopenharmony_ci if (err < 0) { 106c72fcc34Sopenharmony_ci fprintf(stderr, "Cannot open ctl %s\n", name); 107c72fcc34Sopenharmony_ci return err; 108c72fcc34Sopenharmony_ci } 109c72fcc34Sopenharmony_ci err = snd_ctl_subscribe_events(ctl, 1); 110c72fcc34Sopenharmony_ci if (err < 0) { 111c72fcc34Sopenharmony_ci fprintf(stderr, "Cannot open subscribe events to ctl %s\n", name); 112c72fcc34Sopenharmony_ci snd_ctl_close(ctl); 113c72fcc34Sopenharmony_ci return err; 114c72fcc34Sopenharmony_ci } 115c72fcc34Sopenharmony_ci *ctlp = ctl; 116c72fcc34Sopenharmony_ci return 0; 117c72fcc34Sopenharmony_ci} 118c72fcc34Sopenharmony_ci 119c72fcc34Sopenharmony_cistatic inline bool seek_entry_by_name(struct list_head *srcs, const char *name) 120c72fcc34Sopenharmony_ci{ 121c72fcc34Sopenharmony_ci struct src_entry *entry; 122c72fcc34Sopenharmony_ci 123c72fcc34Sopenharmony_ci list_for_each_entry(entry, srcs, list) { 124c72fcc34Sopenharmony_ci if (!strcmp(entry->name, name)) 125c72fcc34Sopenharmony_ci return true; 126c72fcc34Sopenharmony_ci } 127c72fcc34Sopenharmony_ci 128c72fcc34Sopenharmony_ci return false; 129c72fcc34Sopenharmony_ci} 130c72fcc34Sopenharmony_ci 131c72fcc34Sopenharmony_cistatic int prepare_source_entry(struct list_head *srcs, const char *name) 132c72fcc34Sopenharmony_ci{ 133c72fcc34Sopenharmony_ci snd_ctl_t *handle; 134c72fcc34Sopenharmony_ci int err; 135c72fcc34Sopenharmony_ci 136c72fcc34Sopenharmony_ci if (!name) { 137c72fcc34Sopenharmony_ci struct snd_card_iterator iter; 138c72fcc34Sopenharmony_ci const char *cardname; 139c72fcc34Sopenharmony_ci 140c72fcc34Sopenharmony_ci snd_card_iterator_init(&iter, -1); 141c72fcc34Sopenharmony_ci while ((cardname = snd_card_iterator_next(&iter))) { 142c72fcc34Sopenharmony_ci if (seek_entry_by_name(srcs, cardname)) 143c72fcc34Sopenharmony_ci continue; 144c72fcc34Sopenharmony_ci err = open_ctl(cardname, &handle); 145c72fcc34Sopenharmony_ci if (err < 0) 146c72fcc34Sopenharmony_ci return err; 147c72fcc34Sopenharmony_ci err = insert_source_entry(srcs, handle, cardname); 148c72fcc34Sopenharmony_ci if (err < 0) 149c72fcc34Sopenharmony_ci return err; 150c72fcc34Sopenharmony_ci } 151c72fcc34Sopenharmony_ci } else { 152c72fcc34Sopenharmony_ci if (seek_entry_by_name(srcs, name)) 153c72fcc34Sopenharmony_ci return 0; 154c72fcc34Sopenharmony_ci err = open_ctl(name, &handle); 155c72fcc34Sopenharmony_ci if (err < 0) 156c72fcc34Sopenharmony_ci return err; 157c72fcc34Sopenharmony_ci err = insert_source_entry(srcs, handle, name); 158c72fcc34Sopenharmony_ci if (err < 0) 159c72fcc34Sopenharmony_ci return err; 160c72fcc34Sopenharmony_ci } 161c72fcc34Sopenharmony_ci 162c72fcc34Sopenharmony_ci return 0; 163c72fcc34Sopenharmony_ci} 164c72fcc34Sopenharmony_ci 165c72fcc34Sopenharmony_cistatic int check_control_cdev(int infd, bool *retry) 166c72fcc34Sopenharmony_ci{ 167c72fcc34Sopenharmony_ci struct inotify_event *ev; 168c72fcc34Sopenharmony_ci char *buf; 169c72fcc34Sopenharmony_ci int err = 0; 170c72fcc34Sopenharmony_ci 171c72fcc34Sopenharmony_ci buf = calloc(1, sizeof(*ev) + NAME_MAX); 172c72fcc34Sopenharmony_ci if (!buf) 173c72fcc34Sopenharmony_ci return -ENOMEM; 174c72fcc34Sopenharmony_ci 175c72fcc34Sopenharmony_ci while (1) { 176c72fcc34Sopenharmony_ci ssize_t len = read(infd, buf, sizeof(*ev) + NAME_MAX); 177c72fcc34Sopenharmony_ci if (len < 0) { 178c72fcc34Sopenharmony_ci if (errno != EAGAIN) 179c72fcc34Sopenharmony_ci err = errno; 180c72fcc34Sopenharmony_ci break; 181c72fcc34Sopenharmony_ci } else if (len == 0) { 182c72fcc34Sopenharmony_ci break; 183c72fcc34Sopenharmony_ci } 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ci size_t pos = 0; 186c72fcc34Sopenharmony_ci while (pos < (size_t)len) { 187c72fcc34Sopenharmony_ci ev = (struct inotify_event *)(buf + pos); 188c72fcc34Sopenharmony_ci if ((ev->mask & IN_CREATE) && 189c72fcc34Sopenharmony_ci strstr(ev->name, "controlC") == ev->name) 190c72fcc34Sopenharmony_ci *retry = true; 191c72fcc34Sopenharmony_ci pos += sizeof(*ev) + ev->len; 192c72fcc34Sopenharmony_ci } 193c72fcc34Sopenharmony_ci } 194c72fcc34Sopenharmony_ci 195c72fcc34Sopenharmony_ci free(buf); 196c72fcc34Sopenharmony_ci 197c72fcc34Sopenharmony_ci return err; 198c72fcc34Sopenharmony_ci} 199c72fcc34Sopenharmony_ci 200c72fcc34Sopenharmony_cistatic int print_event(snd_ctl_t *ctl, const char *name) 201c72fcc34Sopenharmony_ci{ 202c72fcc34Sopenharmony_ci snd_ctl_event_t *event; 203c72fcc34Sopenharmony_ci unsigned int mask; 204c72fcc34Sopenharmony_ci int err; 205c72fcc34Sopenharmony_ci 206c72fcc34Sopenharmony_ci snd_ctl_event_alloca(&event); 207c72fcc34Sopenharmony_ci err = snd_ctl_read(ctl, event); 208c72fcc34Sopenharmony_ci if (err < 0) 209c72fcc34Sopenharmony_ci return err; 210c72fcc34Sopenharmony_ci 211c72fcc34Sopenharmony_ci if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) 212c72fcc34Sopenharmony_ci return 0; 213c72fcc34Sopenharmony_ci 214c72fcc34Sopenharmony_ci printf("node %s, #%d (%i,%i,%i,%s,%i)", 215c72fcc34Sopenharmony_ci name, 216c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_numid(event), 217c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_interface(event), 218c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_device(event), 219c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_subdevice(event), 220c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_name(event), 221c72fcc34Sopenharmony_ci snd_ctl_event_elem_get_index(event)); 222c72fcc34Sopenharmony_ci 223c72fcc34Sopenharmony_ci mask = snd_ctl_event_elem_get_mask(event); 224c72fcc34Sopenharmony_ci if (mask == SND_CTL_EVENT_MASK_REMOVE) { 225c72fcc34Sopenharmony_ci printf(" REMOVE\n"); 226c72fcc34Sopenharmony_ci return 0; 227c72fcc34Sopenharmony_ci } 228c72fcc34Sopenharmony_ci 229c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_VALUE) 230c72fcc34Sopenharmony_ci printf(" VALUE"); 231c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_INFO) 232c72fcc34Sopenharmony_ci printf(" INFO"); 233c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_ADD) 234c72fcc34Sopenharmony_ci printf(" ADD"); 235c72fcc34Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_TLV) 236c72fcc34Sopenharmony_ci printf(" TLV"); 237c72fcc34Sopenharmony_ci printf("\n"); 238c72fcc34Sopenharmony_ci fflush(stdout); 239c72fcc34Sopenharmony_ci return 0; 240c72fcc34Sopenharmony_ci} 241c72fcc34Sopenharmony_ci 242c72fcc34Sopenharmony_cistatic int operate_dispatcher(int epfd, uint32_t op, struct epoll_event *epev, 243c72fcc34Sopenharmony_ci struct src_entry *entry) 244c72fcc34Sopenharmony_ci{ 245c72fcc34Sopenharmony_ci struct pollfd *pfds; 246c72fcc34Sopenharmony_ci int count; 247c72fcc34Sopenharmony_ci int i; 248c72fcc34Sopenharmony_ci int err = 0; 249c72fcc34Sopenharmony_ci 250c72fcc34Sopenharmony_ci pfds = calloc(entry->pfd_count, sizeof(*pfds)); 251c72fcc34Sopenharmony_ci if (!pfds) 252c72fcc34Sopenharmony_ci return -ENOMEM; 253c72fcc34Sopenharmony_ci 254c72fcc34Sopenharmony_ci count = snd_ctl_poll_descriptors(entry->handle, pfds, entry->pfd_count); 255c72fcc34Sopenharmony_ci if (count < 0) { 256c72fcc34Sopenharmony_ci err = count; 257c72fcc34Sopenharmony_ci goto end; 258c72fcc34Sopenharmony_ci } 259c72fcc34Sopenharmony_ci if (count != (int)entry->pfd_count) { 260c72fcc34Sopenharmony_ci err = -EIO; 261c72fcc34Sopenharmony_ci goto end; 262c72fcc34Sopenharmony_ci } 263c72fcc34Sopenharmony_ci 264c72fcc34Sopenharmony_ci for (i = 0; i < (int)entry->pfd_count; ++i) { 265c72fcc34Sopenharmony_ci err = epoll_ctl(epfd, op, pfds[i].fd, epev); 266c72fcc34Sopenharmony_ci if (err < 0) 267c72fcc34Sopenharmony_ci break; 268c72fcc34Sopenharmony_ci } 269c72fcc34Sopenharmony_ciend: 270c72fcc34Sopenharmony_ci free(pfds); 271c72fcc34Sopenharmony_ci return err; 272c72fcc34Sopenharmony_ci} 273c72fcc34Sopenharmony_ci 274c72fcc34Sopenharmony_cistatic int prepare_dispatcher(int epfd, int sigfd, int infd, 275c72fcc34Sopenharmony_ci struct list_head *srcs) 276c72fcc34Sopenharmony_ci{ 277c72fcc34Sopenharmony_ci struct epoll_event ev = {0}; 278c72fcc34Sopenharmony_ci struct src_entry *entry; 279c72fcc34Sopenharmony_ci int err = 0; 280c72fcc34Sopenharmony_ci 281c72fcc34Sopenharmony_ci ev.events = EPOLLIN; 282c72fcc34Sopenharmony_ci ev.data.fd = sigfd; 283c72fcc34Sopenharmony_ci if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &ev) < 0) 284c72fcc34Sopenharmony_ci return -errno; 285c72fcc34Sopenharmony_ci 286c72fcc34Sopenharmony_ci ev.events = EPOLLIN; 287c72fcc34Sopenharmony_ci ev.data.fd = infd; 288c72fcc34Sopenharmony_ci if (epoll_ctl(epfd, EPOLL_CTL_ADD, infd, &ev) < 0) 289c72fcc34Sopenharmony_ci return -errno; 290c72fcc34Sopenharmony_ci 291c72fcc34Sopenharmony_ci list_for_each_entry(entry, srcs, list) { 292c72fcc34Sopenharmony_ci ev.events = EPOLLIN; 293c72fcc34Sopenharmony_ci ev.data.ptr = (void *)entry; 294c72fcc34Sopenharmony_ci err = operate_dispatcher(epfd, EPOLL_CTL_ADD, &ev, entry); 295c72fcc34Sopenharmony_ci if (err < 0) 296c72fcc34Sopenharmony_ci break; 297c72fcc34Sopenharmony_ci } 298c72fcc34Sopenharmony_ci 299c72fcc34Sopenharmony_ci return err; 300c72fcc34Sopenharmony_ci} 301c72fcc34Sopenharmony_ci 302c72fcc34Sopenharmony_cistatic int run_dispatcher(int epfd, int sigfd, int infd, struct list_head *srcs, 303c72fcc34Sopenharmony_ci bool *retry) 304c72fcc34Sopenharmony_ci{ 305c72fcc34Sopenharmony_ci struct src_entry *entry; 306c72fcc34Sopenharmony_ci unsigned int max_ev_count; 307c72fcc34Sopenharmony_ci struct epoll_event *epev; 308c72fcc34Sopenharmony_ci int err = 0; 309c72fcc34Sopenharmony_ci 310c72fcc34Sopenharmony_ci max_ev_count = 0; 311c72fcc34Sopenharmony_ci list_for_each_entry(entry, srcs, list) 312c72fcc34Sopenharmony_ci max_ev_count += entry->pfd_count; 313c72fcc34Sopenharmony_ci 314c72fcc34Sopenharmony_ci epev = calloc(max_ev_count, sizeof(*epev)); 315c72fcc34Sopenharmony_ci if (!epev) 316c72fcc34Sopenharmony_ci return -ENOMEM; 317c72fcc34Sopenharmony_ci 318c72fcc34Sopenharmony_ci while (true) { 319c72fcc34Sopenharmony_ci int count; 320c72fcc34Sopenharmony_ci int i; 321c72fcc34Sopenharmony_ci 322c72fcc34Sopenharmony_ci count = epoll_wait(epfd, epev, max_ev_count, -1); 323c72fcc34Sopenharmony_ci if (count < 0) { 324c72fcc34Sopenharmony_ci if (errno == EINTR) 325c72fcc34Sopenharmony_ci continue; 326c72fcc34Sopenharmony_ci err = count; 327c72fcc34Sopenharmony_ci break; 328c72fcc34Sopenharmony_ci } 329c72fcc34Sopenharmony_ci if (count == 0) 330c72fcc34Sopenharmony_ci continue; 331c72fcc34Sopenharmony_ci 332c72fcc34Sopenharmony_ci for (i = 0; i < count; ++i) { 333c72fcc34Sopenharmony_ci struct epoll_event *ev = epev + i; 334c72fcc34Sopenharmony_ci 335c72fcc34Sopenharmony_ci if (ev->data.fd == sigfd) 336c72fcc34Sopenharmony_ci goto end; 337c72fcc34Sopenharmony_ci 338c72fcc34Sopenharmony_ci if (ev->data.fd == infd) { 339c72fcc34Sopenharmony_ci err = check_control_cdev(infd, retry); 340c72fcc34Sopenharmony_ci if (err < 0 || *retry) 341c72fcc34Sopenharmony_ci goto end; 342c72fcc34Sopenharmony_ci continue; 343c72fcc34Sopenharmony_ci } 344c72fcc34Sopenharmony_ci 345c72fcc34Sopenharmony_ci entry = ev->data.ptr; 346c72fcc34Sopenharmony_ci if (ev->events & EPOLLIN) 347c72fcc34Sopenharmony_ci print_event(entry->handle, entry->name); 348c72fcc34Sopenharmony_ci if (ev->events & EPOLLERR) { 349c72fcc34Sopenharmony_ci operate_dispatcher(epfd, EPOLL_CTL_DEL, NULL, entry); 350c72fcc34Sopenharmony_ci remove_source_entry(entry); 351c72fcc34Sopenharmony_ci } 352c72fcc34Sopenharmony_ci } 353c72fcc34Sopenharmony_ci } 354c72fcc34Sopenharmony_ciend: 355c72fcc34Sopenharmony_ci free(epev); 356c72fcc34Sopenharmony_ci return err; 357c72fcc34Sopenharmony_ci} 358c72fcc34Sopenharmony_ci 359c72fcc34Sopenharmony_cistatic void clear_dispatcher(int epfd, int sigfd, int infd, 360c72fcc34Sopenharmony_ci struct list_head *srcs) 361c72fcc34Sopenharmony_ci{ 362c72fcc34Sopenharmony_ci struct src_entry *entry; 363c72fcc34Sopenharmony_ci 364c72fcc34Sopenharmony_ci list_for_each_entry(entry, srcs, list) 365c72fcc34Sopenharmony_ci operate_dispatcher(epfd, EPOLL_CTL_DEL, NULL, entry); 366c72fcc34Sopenharmony_ci 367c72fcc34Sopenharmony_ci epoll_ctl(epfd, EPOLL_CTL_DEL, infd, NULL); 368c72fcc34Sopenharmony_ci 369c72fcc34Sopenharmony_ci epoll_ctl(epfd, EPOLL_CTL_DEL, sigfd, NULL); 370c72fcc34Sopenharmony_ci} 371c72fcc34Sopenharmony_ci 372c72fcc34Sopenharmony_cistatic int prepare_signalfd(int *sigfd) 373c72fcc34Sopenharmony_ci{ 374c72fcc34Sopenharmony_ci sigset_t mask; 375c72fcc34Sopenharmony_ci int fd; 376c72fcc34Sopenharmony_ci 377c72fcc34Sopenharmony_ci sigemptyset(&mask); 378c72fcc34Sopenharmony_ci sigaddset(&mask, SIGINT); 379c72fcc34Sopenharmony_ci sigaddset(&mask, SIGTERM); 380c72fcc34Sopenharmony_ci 381c72fcc34Sopenharmony_ci if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) 382c72fcc34Sopenharmony_ci return -errno; 383c72fcc34Sopenharmony_ci 384c72fcc34Sopenharmony_ci fd = signalfd(-1, &mask, 0); 385c72fcc34Sopenharmony_ci if (fd < 0) 386c72fcc34Sopenharmony_ci return -errno; 387c72fcc34Sopenharmony_ci *sigfd = fd; 388c72fcc34Sopenharmony_ci 389c72fcc34Sopenharmony_ci return 0; 390c72fcc34Sopenharmony_ci} 391c72fcc34Sopenharmony_ci 392c72fcc34Sopenharmony_ciint monitor(const char *name) 393c72fcc34Sopenharmony_ci{ 394c72fcc34Sopenharmony_ci LIST_HEAD(srcs); 395c72fcc34Sopenharmony_ci int sigfd = 0; 396c72fcc34Sopenharmony_ci int epfd; 397c72fcc34Sopenharmony_ci int infd; 398c72fcc34Sopenharmony_ci int wd = 0; 399c72fcc34Sopenharmony_ci bool retry; 400c72fcc34Sopenharmony_ci int err = 0; 401c72fcc34Sopenharmony_ci 402c72fcc34Sopenharmony_ci err = prepare_signalfd(&sigfd); 403c72fcc34Sopenharmony_ci if (err < 0) 404c72fcc34Sopenharmony_ci return err; 405c72fcc34Sopenharmony_ci 406c72fcc34Sopenharmony_ci epfd = epoll_create(1); 407c72fcc34Sopenharmony_ci if (epfd < 0) { 408c72fcc34Sopenharmony_ci close(sigfd); 409c72fcc34Sopenharmony_ci return -errno; 410c72fcc34Sopenharmony_ci } 411c72fcc34Sopenharmony_ci 412c72fcc34Sopenharmony_ci infd = inotify_init1(IN_NONBLOCK); 413c72fcc34Sopenharmony_ci if (infd < 0) { 414c72fcc34Sopenharmony_ci err = -errno; 415c72fcc34Sopenharmony_ci goto error; 416c72fcc34Sopenharmony_ci } 417c72fcc34Sopenharmony_ci wd = inotify_add_watch(infd, "/dev/snd/", IN_CREATE); 418c72fcc34Sopenharmony_ci if (wd < 0) { 419c72fcc34Sopenharmony_ci err = -errno; 420c72fcc34Sopenharmony_ci goto error; 421c72fcc34Sopenharmony_ci } 422c72fcc34Sopenharmony_ciretry: 423c72fcc34Sopenharmony_ci retry = false; 424c72fcc34Sopenharmony_ci err = prepare_source_entry(&srcs, name); 425c72fcc34Sopenharmony_ci if (err < 0) 426c72fcc34Sopenharmony_ci goto error; 427c72fcc34Sopenharmony_ci 428c72fcc34Sopenharmony_ci err = prepare_dispatcher(epfd, sigfd, infd, &srcs); 429c72fcc34Sopenharmony_ci if (err >= 0) 430c72fcc34Sopenharmony_ci err = run_dispatcher(epfd, sigfd, infd, &srcs, &retry); 431c72fcc34Sopenharmony_ci clear_dispatcher(epfd, sigfd, infd, &srcs); 432c72fcc34Sopenharmony_ci 433c72fcc34Sopenharmony_ci if (retry) { 434c72fcc34Sopenharmony_ci // A simple makeshift for timing gap between creation of nodes 435c72fcc34Sopenharmony_ci // by devtmpfs and chmod() by udevd. 436c72fcc34Sopenharmony_ci struct timespec req = { .tv_sec = 1 }; 437c72fcc34Sopenharmony_ci nanosleep(&req, NULL); 438c72fcc34Sopenharmony_ci goto retry; 439c72fcc34Sopenharmony_ci } 440c72fcc34Sopenharmony_cierror: 441c72fcc34Sopenharmony_ci clear_source_list(&srcs); 442c72fcc34Sopenharmony_ci 443c72fcc34Sopenharmony_ci if (wd > 0) 444c72fcc34Sopenharmony_ci inotify_rm_watch(infd, wd); 445c72fcc34Sopenharmony_ci close(infd); 446c72fcc34Sopenharmony_ci 447c72fcc34Sopenharmony_ci close(epfd); 448c72fcc34Sopenharmony_ci 449c72fcc34Sopenharmony_ci close(sigfd); 450c72fcc34Sopenharmony_ci 451c72fcc34Sopenharmony_ci return err; 452c72fcc34Sopenharmony_ci} 453