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