1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci * ALSA server 3d5ac70f0Sopenharmony_ci * Copyright (c) by Abramo Bagnara <abramo@alsa-project.org> 4d5ac70f0Sopenharmony_ci * 5d5ac70f0Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 6d5ac70f0Sopenharmony_ci * it under the terms of the GNU General Public License as published by 7d5ac70f0Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 8d5ac70f0Sopenharmony_ci * (at your option) any later version. 9d5ac70f0Sopenharmony_ci * 10d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 11d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13d5ac70f0Sopenharmony_ci * GNU General Public License for more details. 14d5ac70f0Sopenharmony_ci * 15d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU General Public License 16d5ac70f0Sopenharmony_ci * along with this program; if not, write to the Free Software 17d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18d5ac70f0Sopenharmony_ci * 19d5ac70f0Sopenharmony_ci */ 20d5ac70f0Sopenharmony_ci 21d5ac70f0Sopenharmony_ci#include "aserver.h" 22d5ac70f0Sopenharmony_ci 23d5ac70f0Sopenharmony_ci#include <sys/shm.h> 24d5ac70f0Sopenharmony_ci#include <sys/socket.h> 25d5ac70f0Sopenharmony_ci#include <poll.h> 26d5ac70f0Sopenharmony_ci#include <sys/un.h> 27d5ac70f0Sopenharmony_ci#include <sys/uio.h> 28d5ac70f0Sopenharmony_ci#include <stdio.h> 29d5ac70f0Sopenharmony_ci#include <unistd.h> 30d5ac70f0Sopenharmony_ci#include <fcntl.h> 31d5ac70f0Sopenharmony_ci#include <stddef.h> 32d5ac70f0Sopenharmony_ci#include <getopt.h> 33d5ac70f0Sopenharmony_ci#include <netinet/in.h> 34d5ac70f0Sopenharmony_ci#include <netdb.h> 35d5ac70f0Sopenharmony_ci#include <limits.h> 36d5ac70f0Sopenharmony_ci#include <signal.h> 37d5ac70f0Sopenharmony_ci 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_cichar *command; 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_ci#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) 42d5ac70f0Sopenharmony_ci#define ERROR(...) do {\ 43d5ac70f0Sopenharmony_ci fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \ 44d5ac70f0Sopenharmony_ci fprintf(stderr, __VA_ARGS__); \ 45d5ac70f0Sopenharmony_ci putc('\n', stderr); \ 46d5ac70f0Sopenharmony_ci} while (0) 47d5ac70f0Sopenharmony_ci#else 48d5ac70f0Sopenharmony_ci#define ERROR(args...) do {\ 49d5ac70f0Sopenharmony_ci fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __func__); \ 50d5ac70f0Sopenharmony_ci fprintf(stderr, ##args); \ 51d5ac70f0Sopenharmony_ci putc('\n', stderr); \ 52d5ac70f0Sopenharmony_ci} while (0) 53d5ac70f0Sopenharmony_ci#endif 54d5ac70f0Sopenharmony_ci 55d5ac70f0Sopenharmony_ci#define SYSERROR(string) ERROR(string ": %s", strerror(errno)) 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_cistatic int make_local_socket(const char *filename) 58d5ac70f0Sopenharmony_ci{ 59d5ac70f0Sopenharmony_ci size_t l = strlen(filename); 60d5ac70f0Sopenharmony_ci size_t size = offsetof(struct sockaddr_un, sun_path) + l; 61d5ac70f0Sopenharmony_ci struct sockaddr_un *addr = alloca(size); 62d5ac70f0Sopenharmony_ci int sock; 63d5ac70f0Sopenharmony_ci 64d5ac70f0Sopenharmony_ci sock = socket(PF_LOCAL, SOCK_STREAM, 0); 65d5ac70f0Sopenharmony_ci if (sock < 0) { 66d5ac70f0Sopenharmony_ci int result = -errno; 67d5ac70f0Sopenharmony_ci SYSERROR("socket failed"); 68d5ac70f0Sopenharmony_ci return result; 69d5ac70f0Sopenharmony_ci } 70d5ac70f0Sopenharmony_ci 71d5ac70f0Sopenharmony_ci unlink(filename); 72d5ac70f0Sopenharmony_ci 73d5ac70f0Sopenharmony_ci addr->sun_family = AF_LOCAL; 74d5ac70f0Sopenharmony_ci memcpy(addr->sun_path, filename, l); 75d5ac70f0Sopenharmony_ci 76d5ac70f0Sopenharmony_ci if (bind(sock, (struct sockaddr *) addr, size) < 0) { 77d5ac70f0Sopenharmony_ci int result = -errno; 78d5ac70f0Sopenharmony_ci SYSERROR("bind failed"); 79d5ac70f0Sopenharmony_ci close(sock); 80d5ac70f0Sopenharmony_ci return result; 81d5ac70f0Sopenharmony_ci } 82d5ac70f0Sopenharmony_ci 83d5ac70f0Sopenharmony_ci return sock; 84d5ac70f0Sopenharmony_ci} 85d5ac70f0Sopenharmony_ci 86d5ac70f0Sopenharmony_cistatic int make_inet_socket(int port) 87d5ac70f0Sopenharmony_ci{ 88d5ac70f0Sopenharmony_ci struct sockaddr_in addr; 89d5ac70f0Sopenharmony_ci int sock; 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_ci sock = socket(PF_INET, SOCK_STREAM, 0); 92d5ac70f0Sopenharmony_ci if (sock < 0) { 93d5ac70f0Sopenharmony_ci int result = -errno; 94d5ac70f0Sopenharmony_ci SYSERROR("socket failed"); 95d5ac70f0Sopenharmony_ci return result; 96d5ac70f0Sopenharmony_ci } 97d5ac70f0Sopenharmony_ci 98d5ac70f0Sopenharmony_ci memset(&addr, 0, sizeof(addr)); 99d5ac70f0Sopenharmony_ci addr.sin_family = AF_INET; 100d5ac70f0Sopenharmony_ci addr.sin_port = htons(port); 101d5ac70f0Sopenharmony_ci addr.sin_addr.s_addr = INADDR_ANY; 102d5ac70f0Sopenharmony_ci 103d5ac70f0Sopenharmony_ci if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 104d5ac70f0Sopenharmony_ci int result = -errno; 105d5ac70f0Sopenharmony_ci SYSERROR("bind failed"); 106d5ac70f0Sopenharmony_ci close(sock); 107d5ac70f0Sopenharmony_ci return result; 108d5ac70f0Sopenharmony_ci } 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci return sock; 111d5ac70f0Sopenharmony_ci} 112d5ac70f0Sopenharmony_ci 113d5ac70f0Sopenharmony_cistruct pollfd *pollfds; 114d5ac70f0Sopenharmony_ciunsigned int pollfds_count = 0; 115d5ac70f0Sopenharmony_citypedef struct waiter waiter_t; 116d5ac70f0Sopenharmony_citypedef int (*waiter_handler_t)(waiter_t *waiter, unsigned short events); 117d5ac70f0Sopenharmony_cistruct waiter { 118d5ac70f0Sopenharmony_ci int fd; 119d5ac70f0Sopenharmony_ci void *private_data; 120d5ac70f0Sopenharmony_ci waiter_handler_t handler; 121d5ac70f0Sopenharmony_ci}; 122d5ac70f0Sopenharmony_ciwaiter_t *waiters; 123d5ac70f0Sopenharmony_ci 124d5ac70f0Sopenharmony_cistatic void add_waiter(int fd, unsigned short events, waiter_handler_t handler, 125d5ac70f0Sopenharmony_ci void *data) 126d5ac70f0Sopenharmony_ci{ 127d5ac70f0Sopenharmony_ci waiter_t *w = &waiters[fd]; 128d5ac70f0Sopenharmony_ci struct pollfd *pfd = &pollfds[pollfds_count]; 129d5ac70f0Sopenharmony_ci assert(!w->handler); 130d5ac70f0Sopenharmony_ci pfd->fd = fd; 131d5ac70f0Sopenharmony_ci pfd->events = events; 132d5ac70f0Sopenharmony_ci pfd->revents = 0; 133d5ac70f0Sopenharmony_ci w->fd = fd; 134d5ac70f0Sopenharmony_ci w->private_data = data; 135d5ac70f0Sopenharmony_ci w->handler = handler; 136d5ac70f0Sopenharmony_ci pollfds_count++; 137d5ac70f0Sopenharmony_ci} 138d5ac70f0Sopenharmony_ci 139d5ac70f0Sopenharmony_cistatic void del_waiter(int fd) 140d5ac70f0Sopenharmony_ci{ 141d5ac70f0Sopenharmony_ci waiter_t *w = &waiters[fd]; 142d5ac70f0Sopenharmony_ci unsigned int k; 143d5ac70f0Sopenharmony_ci assert(w->handler); 144d5ac70f0Sopenharmony_ci w->handler = 0; 145d5ac70f0Sopenharmony_ci for (k = 0; k < pollfds_count; ++k) { 146d5ac70f0Sopenharmony_ci if (pollfds[k].fd == fd) 147d5ac70f0Sopenharmony_ci break; 148d5ac70f0Sopenharmony_ci } 149d5ac70f0Sopenharmony_ci assert(k < pollfds_count); 150d5ac70f0Sopenharmony_ci pollfds_count--; 151d5ac70f0Sopenharmony_ci memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k); 152d5ac70f0Sopenharmony_ci} 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_citypedef struct client client_t; 155d5ac70f0Sopenharmony_ci 156d5ac70f0Sopenharmony_citypedef struct { 157d5ac70f0Sopenharmony_ci int (*open)(client_t *client, int *cookie); 158d5ac70f0Sopenharmony_ci int (*cmd)(client_t *client); 159d5ac70f0Sopenharmony_ci int (*close)(client_t *client); 160d5ac70f0Sopenharmony_ci} transport_ops_t; 161d5ac70f0Sopenharmony_ci 162d5ac70f0Sopenharmony_cistruct client { 163d5ac70f0Sopenharmony_ci struct list_head list; 164d5ac70f0Sopenharmony_ci int poll_fd; 165d5ac70f0Sopenharmony_ci int ctrl_fd; 166d5ac70f0Sopenharmony_ci int local; 167d5ac70f0Sopenharmony_ci int transport_type; 168d5ac70f0Sopenharmony_ci int dev_type; 169d5ac70f0Sopenharmony_ci char name[256]; 170d5ac70f0Sopenharmony_ci int stream; 171d5ac70f0Sopenharmony_ci int mode; 172d5ac70f0Sopenharmony_ci transport_ops_t *ops; 173d5ac70f0Sopenharmony_ci snd_async_handler_t *async_handler; 174d5ac70f0Sopenharmony_ci int async_sig; 175d5ac70f0Sopenharmony_ci pid_t async_pid; 176d5ac70f0Sopenharmony_ci union { 177d5ac70f0Sopenharmony_ci struct { 178d5ac70f0Sopenharmony_ci snd_pcm_t *handle; 179d5ac70f0Sopenharmony_ci int fd; 180d5ac70f0Sopenharmony_ci } pcm; 181d5ac70f0Sopenharmony_ci struct { 182d5ac70f0Sopenharmony_ci snd_ctl_t *handle; 183d5ac70f0Sopenharmony_ci int fd; 184d5ac70f0Sopenharmony_ci } ctl; 185d5ac70f0Sopenharmony_ci#if 0 186d5ac70f0Sopenharmony_ci struct { 187d5ac70f0Sopenharmony_ci snd_rawmidi_t *handle; 188d5ac70f0Sopenharmony_ci } rawmidi; 189d5ac70f0Sopenharmony_ci struct { 190d5ac70f0Sopenharmony_ci snd_timer_open_t *handle; 191d5ac70f0Sopenharmony_ci } timer; 192d5ac70f0Sopenharmony_ci struct { 193d5ac70f0Sopenharmony_ci snd_hwdep_t *handle; 194d5ac70f0Sopenharmony_ci } hwdep; 195d5ac70f0Sopenharmony_ci struct { 196d5ac70f0Sopenharmony_ci snd_seq_t *handle; 197d5ac70f0Sopenharmony_ci } seq; 198d5ac70f0Sopenharmony_ci#endif 199d5ac70f0Sopenharmony_ci } device; 200d5ac70f0Sopenharmony_ci int polling; 201d5ac70f0Sopenharmony_ci int open; 202d5ac70f0Sopenharmony_ci int cookie; 203d5ac70f0Sopenharmony_ci union { 204d5ac70f0Sopenharmony_ci struct { 205d5ac70f0Sopenharmony_ci int ctrl_id; 206d5ac70f0Sopenharmony_ci void *ctrl; 207d5ac70f0Sopenharmony_ci } shm; 208d5ac70f0Sopenharmony_ci } transport; 209d5ac70f0Sopenharmony_ci}; 210d5ac70f0Sopenharmony_ci 211d5ac70f0Sopenharmony_ciLIST_HEAD(clients); 212d5ac70f0Sopenharmony_ci 213d5ac70f0Sopenharmony_citypedef struct { 214d5ac70f0Sopenharmony_ci struct list_head list; 215d5ac70f0Sopenharmony_ci int fd; 216d5ac70f0Sopenharmony_ci uint32_t cookie; 217d5ac70f0Sopenharmony_ci} inet_pending_t; 218d5ac70f0Sopenharmony_ciLIST_HEAD(inet_pendings); 219d5ac70f0Sopenharmony_ci 220d5ac70f0Sopenharmony_ci#if 0 221d5ac70f0Sopenharmony_cistatic int pcm_handler(waiter_t *waiter, unsigned short events) 222d5ac70f0Sopenharmony_ci{ 223d5ac70f0Sopenharmony_ci client_t *client = waiter->private_data; 224d5ac70f0Sopenharmony_ci char buf[1]; 225d5ac70f0Sopenharmony_ci ssize_t n; 226d5ac70f0Sopenharmony_ci if (events & POLLIN) { 227d5ac70f0Sopenharmony_ci n = write(client->poll_fd, buf, 1); 228d5ac70f0Sopenharmony_ci if (n != 1) { 229d5ac70f0Sopenharmony_ci SYSERROR("write failed"); 230d5ac70f0Sopenharmony_ci return -errno; 231d5ac70f0Sopenharmony_ci } 232d5ac70f0Sopenharmony_ci } else if (events & POLLOUT) { 233d5ac70f0Sopenharmony_ci n = read(client->poll_fd, buf, 1); 234d5ac70f0Sopenharmony_ci if (n != 1) { 235d5ac70f0Sopenharmony_ci SYSERROR("read failed"); 236d5ac70f0Sopenharmony_ci return -errno; 237d5ac70f0Sopenharmony_ci } 238d5ac70f0Sopenharmony_ci } 239d5ac70f0Sopenharmony_ci del_waiter(waiter->fd); 240d5ac70f0Sopenharmony_ci client->polling = 0; 241d5ac70f0Sopenharmony_ci return 0; 242d5ac70f0Sopenharmony_ci} 243d5ac70f0Sopenharmony_ci#endif 244d5ac70f0Sopenharmony_ci 245d5ac70f0Sopenharmony_cistatic void pcm_shm_hw_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED) 246d5ac70f0Sopenharmony_ci{ 247d5ac70f0Sopenharmony_ci client_t *client = pcm->hw.private_data; 248d5ac70f0Sopenharmony_ci volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; 249d5ac70f0Sopenharmony_ci snd_pcm_t *loop; 250d5ac70f0Sopenharmony_ci 251d5ac70f0Sopenharmony_ci ctrl->hw.changed = 1; 252d5ac70f0Sopenharmony_ci if (pcm->hw.fd >= 0) { 253d5ac70f0Sopenharmony_ci ctrl->hw.use_mmap = 1; 254d5ac70f0Sopenharmony_ci ctrl->hw.offset = pcm->hw.offset; 255d5ac70f0Sopenharmony_ci return; 256d5ac70f0Sopenharmony_ci } 257d5ac70f0Sopenharmony_ci ctrl->hw.use_mmap = 0; 258d5ac70f0Sopenharmony_ci ctrl->hw.ptr = pcm->hw.ptr ? *pcm->hw.ptr : 0; 259d5ac70f0Sopenharmony_ci for (loop = pcm->hw.master; loop; loop = loop->hw.master) 260d5ac70f0Sopenharmony_ci loop->hw.ptr = &ctrl->hw.ptr; 261d5ac70f0Sopenharmony_ci pcm->hw.ptr = &ctrl->hw.ptr; 262d5ac70f0Sopenharmony_ci} 263d5ac70f0Sopenharmony_ci 264d5ac70f0Sopenharmony_cistatic void pcm_shm_appl_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED) 265d5ac70f0Sopenharmony_ci{ 266d5ac70f0Sopenharmony_ci client_t *client = pcm->appl.private_data; 267d5ac70f0Sopenharmony_ci volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; 268d5ac70f0Sopenharmony_ci snd_pcm_t *loop; 269d5ac70f0Sopenharmony_ci 270d5ac70f0Sopenharmony_ci ctrl->appl.changed = 1; 271d5ac70f0Sopenharmony_ci if (pcm->appl.fd >= 0) { 272d5ac70f0Sopenharmony_ci ctrl->appl.use_mmap = 1; 273d5ac70f0Sopenharmony_ci ctrl->appl.offset = pcm->appl.offset; 274d5ac70f0Sopenharmony_ci return; 275d5ac70f0Sopenharmony_ci } 276d5ac70f0Sopenharmony_ci ctrl->appl.use_mmap = 0; 277d5ac70f0Sopenharmony_ci ctrl->appl.ptr = pcm->appl.ptr ? *pcm->appl.ptr : 0; 278d5ac70f0Sopenharmony_ci for (loop = pcm->appl.master; loop; loop = loop->appl.master) 279d5ac70f0Sopenharmony_ci loop->appl.ptr = &ctrl->appl.ptr; 280d5ac70f0Sopenharmony_ci pcm->appl.ptr = &ctrl->appl.ptr; 281d5ac70f0Sopenharmony_ci} 282d5ac70f0Sopenharmony_ci 283d5ac70f0Sopenharmony_cistatic int pcm_shm_open(client_t *client, int *cookie) 284d5ac70f0Sopenharmony_ci{ 285d5ac70f0Sopenharmony_ci int shmid; 286d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 287d5ac70f0Sopenharmony_ci int err; 288d5ac70f0Sopenharmony_ci int result; 289d5ac70f0Sopenharmony_ci err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK); 290d5ac70f0Sopenharmony_ci if (err < 0) 291d5ac70f0Sopenharmony_ci return err; 292d5ac70f0Sopenharmony_ci client->device.pcm.handle = pcm; 293d5ac70f0Sopenharmony_ci client->device.pcm.fd = _snd_pcm_poll_descriptor(pcm); 294d5ac70f0Sopenharmony_ci pcm->hw.private_data = client; 295d5ac70f0Sopenharmony_ci pcm->hw.changed = pcm_shm_hw_ptr_changed; 296d5ac70f0Sopenharmony_ci pcm->appl.private_data = client; 297d5ac70f0Sopenharmony_ci pcm->appl.changed = pcm_shm_appl_ptr_changed; 298d5ac70f0Sopenharmony_ci 299d5ac70f0Sopenharmony_ci shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666); 300d5ac70f0Sopenharmony_ci if (shmid < 0) { 301d5ac70f0Sopenharmony_ci result = -errno; 302d5ac70f0Sopenharmony_ci SYSERROR("shmget failed"); 303d5ac70f0Sopenharmony_ci goto _err; 304d5ac70f0Sopenharmony_ci } 305d5ac70f0Sopenharmony_ci client->transport.shm.ctrl_id = shmid; 306d5ac70f0Sopenharmony_ci client->transport.shm.ctrl = shmat(shmid, 0, 0); 307d5ac70f0Sopenharmony_ci if (client->transport.shm.ctrl == (void*) -1) { 308d5ac70f0Sopenharmony_ci result = -errno; 309d5ac70f0Sopenharmony_ci shmctl(shmid, IPC_RMID, 0); 310d5ac70f0Sopenharmony_ci SYSERROR("shmat failed"); 311d5ac70f0Sopenharmony_ci goto _err; 312d5ac70f0Sopenharmony_ci } 313d5ac70f0Sopenharmony_ci *cookie = shmid; 314d5ac70f0Sopenharmony_ci return 0; 315d5ac70f0Sopenharmony_ci 316d5ac70f0Sopenharmony_ci _err: 317d5ac70f0Sopenharmony_ci snd_pcm_close(pcm); 318d5ac70f0Sopenharmony_ci return result; 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci} 321d5ac70f0Sopenharmony_ci 322d5ac70f0Sopenharmony_cistatic int pcm_shm_close(client_t *client) 323d5ac70f0Sopenharmony_ci{ 324d5ac70f0Sopenharmony_ci int err; 325d5ac70f0Sopenharmony_ci snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; 326d5ac70f0Sopenharmony_ci if (client->polling) { 327d5ac70f0Sopenharmony_ci del_waiter(client->device.pcm.fd); 328d5ac70f0Sopenharmony_ci client->polling = 0; 329d5ac70f0Sopenharmony_ci } 330d5ac70f0Sopenharmony_ci err = snd_pcm_close(client->device.pcm.handle); 331d5ac70f0Sopenharmony_ci ctrl->result = err; 332d5ac70f0Sopenharmony_ci if (err < 0) 333d5ac70f0Sopenharmony_ci ERROR("snd_pcm_close"); 334d5ac70f0Sopenharmony_ci if (client->transport.shm.ctrl) { 335d5ac70f0Sopenharmony_ci err = shmdt((void *)client->transport.shm.ctrl); 336d5ac70f0Sopenharmony_ci if (err < 0) 337d5ac70f0Sopenharmony_ci SYSERROR("shmdt failed"); 338d5ac70f0Sopenharmony_ci err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); 339d5ac70f0Sopenharmony_ci if (err < 0) 340d5ac70f0Sopenharmony_ci SYSERROR("shmctl IPC_RMID failed"); 341d5ac70f0Sopenharmony_ci client->transport.shm.ctrl = 0; 342d5ac70f0Sopenharmony_ci } 343d5ac70f0Sopenharmony_ci client->open = 0; 344d5ac70f0Sopenharmony_ci return 0; 345d5ac70f0Sopenharmony_ci} 346d5ac70f0Sopenharmony_ci 347d5ac70f0Sopenharmony_cistatic int shm_ack(client_t *client) 348d5ac70f0Sopenharmony_ci{ 349d5ac70f0Sopenharmony_ci struct pollfd pfd; 350d5ac70f0Sopenharmony_ci int err; 351d5ac70f0Sopenharmony_ci char buf[1]; 352d5ac70f0Sopenharmony_ci pfd.fd = client->ctrl_fd; 353d5ac70f0Sopenharmony_ci pfd.events = POLLHUP; 354d5ac70f0Sopenharmony_ci if (poll(&pfd, 1, 0) == 1) 355d5ac70f0Sopenharmony_ci return -EBADFD; 356d5ac70f0Sopenharmony_ci err = write(client->ctrl_fd, buf, 1); 357d5ac70f0Sopenharmony_ci if (err != 1) 358d5ac70f0Sopenharmony_ci return -EBADFD; 359d5ac70f0Sopenharmony_ci return 0; 360d5ac70f0Sopenharmony_ci} 361d5ac70f0Sopenharmony_ci 362d5ac70f0Sopenharmony_cistatic int shm_ack_fd(client_t *client, int fd) 363d5ac70f0Sopenharmony_ci{ 364d5ac70f0Sopenharmony_ci struct pollfd pfd; 365d5ac70f0Sopenharmony_ci int err; 366d5ac70f0Sopenharmony_ci char buf[1]; 367d5ac70f0Sopenharmony_ci pfd.fd = client->ctrl_fd; 368d5ac70f0Sopenharmony_ci pfd.events = POLLHUP; 369d5ac70f0Sopenharmony_ci if (poll(&pfd, 1, 0) == 1) 370d5ac70f0Sopenharmony_ci return -EBADFD; 371d5ac70f0Sopenharmony_ci err = snd_send_fd(client->ctrl_fd, buf, 1, fd); 372d5ac70f0Sopenharmony_ci if (err != 1) 373d5ac70f0Sopenharmony_ci return -EBADFD; 374d5ac70f0Sopenharmony_ci return 0; 375d5ac70f0Sopenharmony_ci} 376d5ac70f0Sopenharmony_ci 377d5ac70f0Sopenharmony_cistatic int shm_rbptr_fd(client_t *client, snd_pcm_rbptr_t *rbptr) 378d5ac70f0Sopenharmony_ci{ 379d5ac70f0Sopenharmony_ci if (rbptr->fd < 0) 380d5ac70f0Sopenharmony_ci return -EINVAL; 381d5ac70f0Sopenharmony_ci return shm_ack_fd(client, rbptr->fd); 382d5ac70f0Sopenharmony_ci} 383d5ac70f0Sopenharmony_ci 384d5ac70f0Sopenharmony_cistatic void async_handler(snd_async_handler_t *handler) 385d5ac70f0Sopenharmony_ci{ 386d5ac70f0Sopenharmony_ci client_t *client = snd_async_handler_get_callback_private(handler); 387d5ac70f0Sopenharmony_ci /* FIXME: use sigqueue */ 388d5ac70f0Sopenharmony_ci kill(client->async_pid, client->async_sig); 389d5ac70f0Sopenharmony_ci} 390d5ac70f0Sopenharmony_ci 391d5ac70f0Sopenharmony_cistatic int pcm_shm_cmd(client_t *client) 392d5ac70f0Sopenharmony_ci{ 393d5ac70f0Sopenharmony_ci volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl; 394d5ac70f0Sopenharmony_ci char buf[1]; 395d5ac70f0Sopenharmony_ci int err; 396d5ac70f0Sopenharmony_ci int cmd; 397d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 398d5ac70f0Sopenharmony_ci err = read(client->ctrl_fd, buf, 1); 399d5ac70f0Sopenharmony_ci if (err != 1) 400d5ac70f0Sopenharmony_ci return -EBADFD; 401d5ac70f0Sopenharmony_ci cmd = ctrl->cmd; 402d5ac70f0Sopenharmony_ci ctrl->cmd = 0; 403d5ac70f0Sopenharmony_ci pcm = client->device.pcm.handle; 404d5ac70f0Sopenharmony_ci switch (cmd) { 405d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_ASYNC: 406d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_async(pcm, ctrl->u.async.sig, ctrl->u.async.pid); 407d5ac70f0Sopenharmony_ci if (ctrl->result < 0) 408d5ac70f0Sopenharmony_ci break; 409d5ac70f0Sopenharmony_ci if (ctrl->u.async.sig >= 0) { 410d5ac70f0Sopenharmony_ci assert(client->async_sig < 0); 411d5ac70f0Sopenharmony_ci ctrl->result = snd_async_add_pcm_handler(&client->async_handler, pcm, async_handler, client); 412d5ac70f0Sopenharmony_ci if (ctrl->result < 0) 413d5ac70f0Sopenharmony_ci break; 414d5ac70f0Sopenharmony_ci } else { 415d5ac70f0Sopenharmony_ci assert(client->async_sig >= 0); 416d5ac70f0Sopenharmony_ci snd_async_del_handler(client->async_handler); 417d5ac70f0Sopenharmony_ci } 418d5ac70f0Sopenharmony_ci client->async_sig = ctrl->u.async.sig; 419d5ac70f0Sopenharmony_ci client->async_pid = ctrl->u.async.pid; 420d5ac70f0Sopenharmony_ci break; 421d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_INFO: 422d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info); 423d5ac70f0Sopenharmony_ci break; 424d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_HW_REFINE: 425d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_hw_refine(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_refine); 426d5ac70f0Sopenharmony_ci break; 427d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_HW_PARAMS: 428d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params); 429d5ac70f0Sopenharmony_ci break; 430d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_HW_FREE: 431d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_hw_free(pcm); 432d5ac70f0Sopenharmony_ci break; 433d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_SW_PARAMS: 434d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_sw_params(pcm, (snd_pcm_sw_params_t *) &ctrl->u.sw_params); 435d5ac70f0Sopenharmony_ci break; 436d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_STATUS: 437d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_status(pcm, (snd_pcm_status_t *) &ctrl->u.status); 438d5ac70f0Sopenharmony_ci break; 439d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_STATE: 440d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_state(pcm); 441d5ac70f0Sopenharmony_ci break; 442d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_HWSYNC: 443d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_hwsync(pcm); 444d5ac70f0Sopenharmony_ci break; 445d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_DELAY: 446d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_delay(pcm, (snd_pcm_sframes_t *) &ctrl->u.delay.frames); 447d5ac70f0Sopenharmony_ci break; 448d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_AVAIL_UPDATE: 449d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_avail_update(pcm); 450d5ac70f0Sopenharmony_ci break; 451d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_PREPARE: 452d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_prepare(pcm); 453d5ac70f0Sopenharmony_ci break; 454d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_RESET: 455d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_reset(pcm); 456d5ac70f0Sopenharmony_ci break; 457d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_START: 458d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_start(pcm); 459d5ac70f0Sopenharmony_ci break; 460d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_DRAIN: 461d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_drain(pcm); 462d5ac70f0Sopenharmony_ci break; 463d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_DROP: 464d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_drop(pcm); 465d5ac70f0Sopenharmony_ci break; 466d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_PAUSE: 467d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_pause(pcm, ctrl->u.pause.enable); 468d5ac70f0Sopenharmony_ci break; 469d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_CHANNEL_INFO: 470d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_channel_info(pcm, (snd_pcm_channel_info_t *) &ctrl->u.channel_info); 471d5ac70f0Sopenharmony_ci if (ctrl->result >= 0 && 472d5ac70f0Sopenharmony_ci ctrl->u.channel_info.type == SND_PCM_AREA_MMAP) 473d5ac70f0Sopenharmony_ci return shm_ack_fd(client, ctrl->u.channel_info.u.mmap.fd); 474d5ac70f0Sopenharmony_ci break; 475d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_REWIND: 476d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames); 477d5ac70f0Sopenharmony_ci break; 478d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_FORWARD: 479d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_forward(pcm, ctrl->u.forward.frames); 480d5ac70f0Sopenharmony_ci break; 481d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_LINK: 482d5ac70f0Sopenharmony_ci { 483d5ac70f0Sopenharmony_ci /* FIXME */ 484d5ac70f0Sopenharmony_ci ctrl->result = -ENOSYS; 485d5ac70f0Sopenharmony_ci break; 486d5ac70f0Sopenharmony_ci } 487d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_UNLINK: 488d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_unlink(pcm); 489d5ac70f0Sopenharmony_ci break; 490d5ac70f0Sopenharmony_ci case SNDRV_PCM_IOCTL_RESUME: 491d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_resume(pcm); 492d5ac70f0Sopenharmony_ci break; 493d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_MMAP: 494d5ac70f0Sopenharmony_ci { 495d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_mmap(pcm); 496d5ac70f0Sopenharmony_ci break; 497d5ac70f0Sopenharmony_ci } 498d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_MUNMAP: 499d5ac70f0Sopenharmony_ci { 500d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_munmap(pcm); 501d5ac70f0Sopenharmony_ci break; 502d5ac70f0Sopenharmony_ci } 503d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_MMAP_COMMIT: 504d5ac70f0Sopenharmony_ci ctrl->result = snd_pcm_mmap_commit(pcm, 505d5ac70f0Sopenharmony_ci ctrl->u.mmap_commit.offset, 506d5ac70f0Sopenharmony_ci ctrl->u.mmap_commit.frames); 507d5ac70f0Sopenharmony_ci break; 508d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_POLL_DESCRIPTOR: 509d5ac70f0Sopenharmony_ci ctrl->result = 0; 510d5ac70f0Sopenharmony_ci return shm_ack_fd(client, _snd_pcm_poll_descriptor(pcm)); 511d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_CLOSE: 512d5ac70f0Sopenharmony_ci client->ops->close(client); 513d5ac70f0Sopenharmony_ci break; 514d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_HW_PTR_FD: 515d5ac70f0Sopenharmony_ci return shm_rbptr_fd(client, &pcm->hw); 516d5ac70f0Sopenharmony_ci case SND_PCM_IOCTL_APPL_PTR_FD: 517d5ac70f0Sopenharmony_ci return shm_rbptr_fd(client, &pcm->appl); 518d5ac70f0Sopenharmony_ci default: 519d5ac70f0Sopenharmony_ci ERROR("Bogus cmd: %x", ctrl->cmd); 520d5ac70f0Sopenharmony_ci ctrl->result = -ENOSYS; 521d5ac70f0Sopenharmony_ci } 522d5ac70f0Sopenharmony_ci return shm_ack(client); 523d5ac70f0Sopenharmony_ci} 524d5ac70f0Sopenharmony_ci 525d5ac70f0Sopenharmony_citransport_ops_t pcm_shm_ops = { 526d5ac70f0Sopenharmony_ci .open = pcm_shm_open, 527d5ac70f0Sopenharmony_ci .cmd = pcm_shm_cmd, 528d5ac70f0Sopenharmony_ci .close = pcm_shm_close, 529d5ac70f0Sopenharmony_ci}; 530d5ac70f0Sopenharmony_ci 531d5ac70f0Sopenharmony_cistatic int ctl_handler(waiter_t *waiter, unsigned short events) 532d5ac70f0Sopenharmony_ci{ 533d5ac70f0Sopenharmony_ci client_t *client = waiter->private_data; 534d5ac70f0Sopenharmony_ci char buf[1] = ""; 535d5ac70f0Sopenharmony_ci ssize_t n; 536d5ac70f0Sopenharmony_ci if (events & POLLIN) { 537d5ac70f0Sopenharmony_ci n = write(client->poll_fd, buf, 1); 538d5ac70f0Sopenharmony_ci if (n != 1) { 539d5ac70f0Sopenharmony_ci SYSERROR("write failed"); 540d5ac70f0Sopenharmony_ci return -errno; 541d5ac70f0Sopenharmony_ci } 542d5ac70f0Sopenharmony_ci } 543d5ac70f0Sopenharmony_ci del_waiter(waiter->fd); 544d5ac70f0Sopenharmony_ci client->polling = 0; 545d5ac70f0Sopenharmony_ci return 0; 546d5ac70f0Sopenharmony_ci} 547d5ac70f0Sopenharmony_ci 548d5ac70f0Sopenharmony_cistatic int ctl_shm_open(client_t *client, int *cookie) 549d5ac70f0Sopenharmony_ci{ 550d5ac70f0Sopenharmony_ci int shmid; 551d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 552d5ac70f0Sopenharmony_ci int err; 553d5ac70f0Sopenharmony_ci int result; 554d5ac70f0Sopenharmony_ci err = snd_ctl_open(&ctl, client->name, SND_CTL_NONBLOCK); 555d5ac70f0Sopenharmony_ci if (err < 0) 556d5ac70f0Sopenharmony_ci return err; 557d5ac70f0Sopenharmony_ci client->device.ctl.handle = ctl; 558d5ac70f0Sopenharmony_ci client->device.ctl.fd = _snd_ctl_poll_descriptor(ctl); 559d5ac70f0Sopenharmony_ci 560d5ac70f0Sopenharmony_ci shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666); 561d5ac70f0Sopenharmony_ci if (shmid < 0) { 562d5ac70f0Sopenharmony_ci result = -errno; 563d5ac70f0Sopenharmony_ci SYSERROR("shmget failed"); 564d5ac70f0Sopenharmony_ci goto _err; 565d5ac70f0Sopenharmony_ci } 566d5ac70f0Sopenharmony_ci client->transport.shm.ctrl_id = shmid; 567d5ac70f0Sopenharmony_ci client->transport.shm.ctrl = shmat(shmid, 0, 0); 568d5ac70f0Sopenharmony_ci if (!client->transport.shm.ctrl) { 569d5ac70f0Sopenharmony_ci result = -errno; 570d5ac70f0Sopenharmony_ci shmctl(shmid, IPC_RMID, 0); 571d5ac70f0Sopenharmony_ci SYSERROR("shmat failed"); 572d5ac70f0Sopenharmony_ci goto _err; 573d5ac70f0Sopenharmony_ci } 574d5ac70f0Sopenharmony_ci *cookie = shmid; 575d5ac70f0Sopenharmony_ci add_waiter(client->device.ctl.fd, POLLIN, ctl_handler, client); 576d5ac70f0Sopenharmony_ci client->polling = 1; 577d5ac70f0Sopenharmony_ci return 0; 578d5ac70f0Sopenharmony_ci 579d5ac70f0Sopenharmony_ci _err: 580d5ac70f0Sopenharmony_ci snd_ctl_close(ctl); 581d5ac70f0Sopenharmony_ci return result; 582d5ac70f0Sopenharmony_ci 583d5ac70f0Sopenharmony_ci} 584d5ac70f0Sopenharmony_ci 585d5ac70f0Sopenharmony_cistatic int ctl_shm_close(client_t *client) 586d5ac70f0Sopenharmony_ci{ 587d5ac70f0Sopenharmony_ci int err; 588d5ac70f0Sopenharmony_ci snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; 589d5ac70f0Sopenharmony_ci if (client->polling) { 590d5ac70f0Sopenharmony_ci del_waiter(client->device.ctl.fd); 591d5ac70f0Sopenharmony_ci client->polling = 0; 592d5ac70f0Sopenharmony_ci } 593d5ac70f0Sopenharmony_ci err = snd_ctl_close(client->device.ctl.handle); 594d5ac70f0Sopenharmony_ci ctrl->result = err; 595d5ac70f0Sopenharmony_ci if (err < 0) 596d5ac70f0Sopenharmony_ci ERROR("snd_ctl_close"); 597d5ac70f0Sopenharmony_ci if (client->transport.shm.ctrl) { 598d5ac70f0Sopenharmony_ci err = shmdt((void *)client->transport.shm.ctrl); 599d5ac70f0Sopenharmony_ci if (err < 0) 600d5ac70f0Sopenharmony_ci SYSERROR("shmdt failed"); 601d5ac70f0Sopenharmony_ci err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0); 602d5ac70f0Sopenharmony_ci if (err < 0) 603d5ac70f0Sopenharmony_ci SYSERROR("shmctl failed"); 604d5ac70f0Sopenharmony_ci client->transport.shm.ctrl = 0; 605d5ac70f0Sopenharmony_ci } 606d5ac70f0Sopenharmony_ci client->open = 0; 607d5ac70f0Sopenharmony_ci return 0; 608d5ac70f0Sopenharmony_ci} 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_cistatic int ctl_shm_cmd(client_t *client) 611d5ac70f0Sopenharmony_ci{ 612d5ac70f0Sopenharmony_ci snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl; 613d5ac70f0Sopenharmony_ci char buf[1]; 614d5ac70f0Sopenharmony_ci int err; 615d5ac70f0Sopenharmony_ci int cmd; 616d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 617d5ac70f0Sopenharmony_ci err = read(client->ctrl_fd, buf, 1); 618d5ac70f0Sopenharmony_ci if (err != 1) 619d5ac70f0Sopenharmony_ci return -EBADFD; 620d5ac70f0Sopenharmony_ci cmd = ctrl->cmd; 621d5ac70f0Sopenharmony_ci ctrl->cmd = 0; 622d5ac70f0Sopenharmony_ci ctl = client->device.ctl.handle; 623d5ac70f0Sopenharmony_ci switch (cmd) { 624d5ac70f0Sopenharmony_ci case SND_CTL_IOCTL_ASYNC: 625d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_async(ctl, ctrl->u.async.sig, ctrl->u.async.pid); 626d5ac70f0Sopenharmony_ci if (ctrl->result < 0) 627d5ac70f0Sopenharmony_ci break; 628d5ac70f0Sopenharmony_ci if (ctrl->u.async.sig >= 0) { 629d5ac70f0Sopenharmony_ci assert(client->async_sig < 0); 630d5ac70f0Sopenharmony_ci ctrl->result = snd_async_add_ctl_handler(&client->async_handler, ctl, async_handler, client); 631d5ac70f0Sopenharmony_ci if (ctrl->result < 0) 632d5ac70f0Sopenharmony_ci break; 633d5ac70f0Sopenharmony_ci } else { 634d5ac70f0Sopenharmony_ci assert(client->async_sig >= 0); 635d5ac70f0Sopenharmony_ci snd_async_del_handler(client->async_handler); 636d5ac70f0Sopenharmony_ci } 637d5ac70f0Sopenharmony_ci client->async_sig = ctrl->u.async.sig; 638d5ac70f0Sopenharmony_ci client->async_pid = ctrl->u.async.pid; 639d5ac70f0Sopenharmony_ci break; 640d5ac70f0Sopenharmony_ci break; 641d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: 642d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_subscribe_events(ctl, ctrl->u.subscribe_events); 643d5ac70f0Sopenharmony_ci break; 644d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_CARD_INFO: 645d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_card_info(ctl, &ctrl->u.card_info); 646d5ac70f0Sopenharmony_ci break; 647d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_LIST: 648d5ac70f0Sopenharmony_ci { 649d5ac70f0Sopenharmony_ci size_t maxsize = CTL_SHM_DATA_MAXLEN; 650d5ac70f0Sopenharmony_ci if (ctrl->u.element_list.space * sizeof(*ctrl->u.element_list.pids) > maxsize) { 651d5ac70f0Sopenharmony_ci ctrl->result = -EFAULT; 652d5ac70f0Sopenharmony_ci break; 653d5ac70f0Sopenharmony_ci } 654d5ac70f0Sopenharmony_ci ctrl->u.element_list.pids = (snd_ctl_elem_id_t*) ctrl->data; 655d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_elem_list(ctl, &ctrl->u.element_list); 656d5ac70f0Sopenharmony_ci break; 657d5ac70f0Sopenharmony_ci } 658d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_INFO: 659d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_elem_info(ctl, &ctrl->u.element_info); 660d5ac70f0Sopenharmony_ci break; 661d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_READ: 662d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_elem_read(ctl, &ctrl->u.element_read); 663d5ac70f0Sopenharmony_ci break; 664d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_WRITE: 665d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_elem_write(ctl, &ctrl->u.element_write); 666d5ac70f0Sopenharmony_ci break; 667d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_LOCK: 668d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_elem_lock(ctl, &ctrl->u.element_lock); 669d5ac70f0Sopenharmony_ci break; 670d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_UNLOCK: 671d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_elem_unlock(ctl, &ctrl->u.element_unlock); 672d5ac70f0Sopenharmony_ci break; 673d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE: 674d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_hwdep_next_device(ctl, &ctrl->u.device); 675d5ac70f0Sopenharmony_ci break; 676d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_HWDEP_INFO: 677d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_hwdep_info(ctl, &ctrl->u.hwdep_info); 678d5ac70f0Sopenharmony_ci break; 679d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE: 680d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_pcm_next_device(ctl, &ctrl->u.device); 681d5ac70f0Sopenharmony_ci break; 682d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_PCM_INFO: 683d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_pcm_info(ctl, &ctrl->u.pcm_info); 684d5ac70f0Sopenharmony_ci break; 685d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE: 686d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_pcm_prefer_subdevice(ctl, ctrl->u.pcm_prefer_subdevice); 687d5ac70f0Sopenharmony_ci break; 688d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: 689d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_rawmidi_next_device(ctl, &ctrl->u.device); 690d5ac70f0Sopenharmony_ci break; 691d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_RAWMIDI_INFO: 692d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_rawmidi_info(ctl, &ctrl->u.rawmidi_info); 693d5ac70f0Sopenharmony_ci break; 694d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: 695d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_rawmidi_prefer_subdevice(ctl, ctrl->u.rawmidi_prefer_subdevice); 696d5ac70f0Sopenharmony_ci break; 697d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_POWER: 698d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_set_power_state(ctl, ctrl->u.power_state); 699d5ac70f0Sopenharmony_ci break; 700d5ac70f0Sopenharmony_ci case SNDRV_CTL_IOCTL_POWER_STATE: 701d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_get_power_state(ctl, &ctrl->u.power_state); 702d5ac70f0Sopenharmony_ci break; 703d5ac70f0Sopenharmony_ci case SND_CTL_IOCTL_READ: 704d5ac70f0Sopenharmony_ci ctrl->result = snd_ctl_read(ctl, &ctrl->u.read); 705d5ac70f0Sopenharmony_ci break; 706d5ac70f0Sopenharmony_ci case SND_CTL_IOCTL_CLOSE: 707d5ac70f0Sopenharmony_ci client->ops->close(client); 708d5ac70f0Sopenharmony_ci break; 709d5ac70f0Sopenharmony_ci case SND_CTL_IOCTL_POLL_DESCRIPTOR: 710d5ac70f0Sopenharmony_ci ctrl->result = 0; 711d5ac70f0Sopenharmony_ci return shm_ack_fd(client, _snd_ctl_poll_descriptor(ctl)); 712d5ac70f0Sopenharmony_ci default: 713d5ac70f0Sopenharmony_ci ERROR("Bogus cmd: %x", ctrl->cmd); 714d5ac70f0Sopenharmony_ci ctrl->result = -ENOSYS; 715d5ac70f0Sopenharmony_ci } 716d5ac70f0Sopenharmony_ci return shm_ack(client); 717d5ac70f0Sopenharmony_ci} 718d5ac70f0Sopenharmony_ci 719d5ac70f0Sopenharmony_citransport_ops_t ctl_shm_ops = { 720d5ac70f0Sopenharmony_ci .open = ctl_shm_open, 721d5ac70f0Sopenharmony_ci .cmd = ctl_shm_cmd, 722d5ac70f0Sopenharmony_ci .close = ctl_shm_close, 723d5ac70f0Sopenharmony_ci}; 724d5ac70f0Sopenharmony_ci 725d5ac70f0Sopenharmony_cistatic int snd_client_open(client_t *client) 726d5ac70f0Sopenharmony_ci{ 727d5ac70f0Sopenharmony_ci int err; 728d5ac70f0Sopenharmony_ci snd_client_open_request_t req; 729d5ac70f0Sopenharmony_ci snd_client_open_answer_t ans; 730d5ac70f0Sopenharmony_ci char *name; 731d5ac70f0Sopenharmony_ci memset(&ans, 0, sizeof(ans)); 732d5ac70f0Sopenharmony_ci err = read(client->ctrl_fd, &req, sizeof(req)); 733d5ac70f0Sopenharmony_ci if (err < 0) { 734d5ac70f0Sopenharmony_ci SYSERROR("read failed"); 735d5ac70f0Sopenharmony_ci exit(1); 736d5ac70f0Sopenharmony_ci } 737d5ac70f0Sopenharmony_ci if (err != sizeof(req)) { 738d5ac70f0Sopenharmony_ci ans.result = -EINVAL; 739d5ac70f0Sopenharmony_ci goto _answer; 740d5ac70f0Sopenharmony_ci } 741d5ac70f0Sopenharmony_ci name = alloca(req.namelen + 1); 742d5ac70f0Sopenharmony_ci err = read(client->ctrl_fd, name, req.namelen); 743d5ac70f0Sopenharmony_ci if (err < 0) { 744d5ac70f0Sopenharmony_ci SYSERROR("read failed"); 745d5ac70f0Sopenharmony_ci exit(1); 746d5ac70f0Sopenharmony_ci } 747d5ac70f0Sopenharmony_ci if (err != req.namelen) { 748d5ac70f0Sopenharmony_ci ans.result = -EINVAL; 749d5ac70f0Sopenharmony_ci goto _answer; 750d5ac70f0Sopenharmony_ci } 751d5ac70f0Sopenharmony_ci 752d5ac70f0Sopenharmony_ci switch (req.transport_type) { 753d5ac70f0Sopenharmony_ci case SND_TRANSPORT_TYPE_SHM: 754d5ac70f0Sopenharmony_ci if (!client->local) { 755d5ac70f0Sopenharmony_ci ans.result = -EINVAL; 756d5ac70f0Sopenharmony_ci goto _answer; 757d5ac70f0Sopenharmony_ci } 758d5ac70f0Sopenharmony_ci switch (req.dev_type) { 759d5ac70f0Sopenharmony_ci case SND_DEV_TYPE_PCM: 760d5ac70f0Sopenharmony_ci client->ops = &pcm_shm_ops; 761d5ac70f0Sopenharmony_ci break; 762d5ac70f0Sopenharmony_ci case SND_DEV_TYPE_CONTROL: 763d5ac70f0Sopenharmony_ci client->ops = &ctl_shm_ops; 764d5ac70f0Sopenharmony_ci break; 765d5ac70f0Sopenharmony_ci default: 766d5ac70f0Sopenharmony_ci ans.result = -EINVAL; 767d5ac70f0Sopenharmony_ci goto _answer; 768d5ac70f0Sopenharmony_ci } 769d5ac70f0Sopenharmony_ci break; 770d5ac70f0Sopenharmony_ci default: 771d5ac70f0Sopenharmony_ci ans.result = -EINVAL; 772d5ac70f0Sopenharmony_ci goto _answer; 773d5ac70f0Sopenharmony_ci } 774d5ac70f0Sopenharmony_ci 775d5ac70f0Sopenharmony_ci name[req.namelen] = '\0'; 776d5ac70f0Sopenharmony_ci 777d5ac70f0Sopenharmony_ci client->transport_type = req.transport_type; 778d5ac70f0Sopenharmony_ci if (sizeof(client->name) < (size_t)(req.namelen + 1)) { 779d5ac70f0Sopenharmony_ci ans.result = -ENOMEM; 780d5ac70f0Sopenharmony_ci goto _answer; 781d5ac70f0Sopenharmony_ci } 782d5ac70f0Sopenharmony_ci strcpy(client->name, name); 783d5ac70f0Sopenharmony_ci client->stream = req.stream; 784d5ac70f0Sopenharmony_ci client->mode = req.mode; 785d5ac70f0Sopenharmony_ci 786d5ac70f0Sopenharmony_ci err = client->ops->open(client, &ans.cookie); 787d5ac70f0Sopenharmony_ci if (err < 0) { 788d5ac70f0Sopenharmony_ci ans.result = err; 789d5ac70f0Sopenharmony_ci } else { 790d5ac70f0Sopenharmony_ci client->open = 1; 791d5ac70f0Sopenharmony_ci ans.result = 0; 792d5ac70f0Sopenharmony_ci } 793d5ac70f0Sopenharmony_ci 794d5ac70f0Sopenharmony_ci _answer: 795d5ac70f0Sopenharmony_ci err = write(client->ctrl_fd, &ans, sizeof(ans)); 796d5ac70f0Sopenharmony_ci if (err != sizeof(ans)) { 797d5ac70f0Sopenharmony_ci SYSERROR("write failed"); 798d5ac70f0Sopenharmony_ci exit(1); 799d5ac70f0Sopenharmony_ci } 800d5ac70f0Sopenharmony_ci return 0; 801d5ac70f0Sopenharmony_ci} 802d5ac70f0Sopenharmony_ci 803d5ac70f0Sopenharmony_cistatic int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) 804d5ac70f0Sopenharmony_ci{ 805d5ac70f0Sopenharmony_ci client_t *client = waiter->private_data; 806d5ac70f0Sopenharmony_ci if (client->open) 807d5ac70f0Sopenharmony_ci client->ops->close(client); 808d5ac70f0Sopenharmony_ci close(client->poll_fd); 809d5ac70f0Sopenharmony_ci close(client->ctrl_fd); 810d5ac70f0Sopenharmony_ci del_waiter(client->poll_fd); 811d5ac70f0Sopenharmony_ci del_waiter(client->ctrl_fd); 812d5ac70f0Sopenharmony_ci list_del(&client->list); 813d5ac70f0Sopenharmony_ci free(client); 814d5ac70f0Sopenharmony_ci return 0; 815d5ac70f0Sopenharmony_ci} 816d5ac70f0Sopenharmony_ci 817d5ac70f0Sopenharmony_cistatic int client_ctrl_handler(waiter_t *waiter, unsigned short events) 818d5ac70f0Sopenharmony_ci{ 819d5ac70f0Sopenharmony_ci client_t *client = waiter->private_data; 820d5ac70f0Sopenharmony_ci if (events & POLLHUP) { 821d5ac70f0Sopenharmony_ci if (client->open) 822d5ac70f0Sopenharmony_ci client->ops->close(client); 823d5ac70f0Sopenharmony_ci close(client->ctrl_fd); 824d5ac70f0Sopenharmony_ci del_waiter(client->ctrl_fd); 825d5ac70f0Sopenharmony_ci list_del(&client->list); 826d5ac70f0Sopenharmony_ci free(client); 827d5ac70f0Sopenharmony_ci return 0; 828d5ac70f0Sopenharmony_ci } 829d5ac70f0Sopenharmony_ci if (client->open) 830d5ac70f0Sopenharmony_ci return client->ops->cmd(client); 831d5ac70f0Sopenharmony_ci else 832d5ac70f0Sopenharmony_ci return snd_client_open(client); 833d5ac70f0Sopenharmony_ci} 834d5ac70f0Sopenharmony_ci 835d5ac70f0Sopenharmony_cistatic int inet_pending_handler(waiter_t *waiter, unsigned short events) 836d5ac70f0Sopenharmony_ci{ 837d5ac70f0Sopenharmony_ci inet_pending_t *pending = waiter->private_data; 838d5ac70f0Sopenharmony_ci inet_pending_t *pdata; 839d5ac70f0Sopenharmony_ci client_t *client; 840d5ac70f0Sopenharmony_ci uint32_t cookie; 841d5ac70f0Sopenharmony_ci struct list_head *item; 842d5ac70f0Sopenharmony_ci int remove = 0; 843d5ac70f0Sopenharmony_ci if (events & POLLHUP) 844d5ac70f0Sopenharmony_ci remove = 1; 845d5ac70f0Sopenharmony_ci else { 846d5ac70f0Sopenharmony_ci int err = read(waiter->fd, &cookie, sizeof(cookie)); 847d5ac70f0Sopenharmony_ci if (err != sizeof(cookie)) 848d5ac70f0Sopenharmony_ci remove = 1; 849d5ac70f0Sopenharmony_ci else { 850d5ac70f0Sopenharmony_ci err = write(waiter->fd, &cookie, sizeof(cookie)); 851d5ac70f0Sopenharmony_ci if (err != sizeof(cookie)) 852d5ac70f0Sopenharmony_ci remove = 1; 853d5ac70f0Sopenharmony_ci } 854d5ac70f0Sopenharmony_ci } 855d5ac70f0Sopenharmony_ci del_waiter(waiter->fd); 856d5ac70f0Sopenharmony_ci if (remove) { 857d5ac70f0Sopenharmony_ci close(waiter->fd); 858d5ac70f0Sopenharmony_ci list_del(&pending->list); 859d5ac70f0Sopenharmony_ci free(pending); 860d5ac70f0Sopenharmony_ci return 0; 861d5ac70f0Sopenharmony_ci } 862d5ac70f0Sopenharmony_ci 863d5ac70f0Sopenharmony_ci list_for_each(item, &inet_pendings) { 864d5ac70f0Sopenharmony_ci pdata = list_entry(item, inet_pending_t, list); 865d5ac70f0Sopenharmony_ci if (pdata->cookie == cookie) 866d5ac70f0Sopenharmony_ci goto found; 867d5ac70f0Sopenharmony_ci } 868d5ac70f0Sopenharmony_ci pending->cookie = cookie; 869d5ac70f0Sopenharmony_ci return 0; 870d5ac70f0Sopenharmony_ci 871d5ac70f0Sopenharmony_ci found: 872d5ac70f0Sopenharmony_ci client = calloc(1, sizeof(*client)); 873d5ac70f0Sopenharmony_ci client->local = 0; 874d5ac70f0Sopenharmony_ci client->poll_fd = pdata->fd; 875d5ac70f0Sopenharmony_ci client->ctrl_fd = waiter->fd; 876d5ac70f0Sopenharmony_ci add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client); 877d5ac70f0Sopenharmony_ci add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client); 878d5ac70f0Sopenharmony_ci client->open = 0; 879d5ac70f0Sopenharmony_ci list_add_tail(&client->list, &clients); 880d5ac70f0Sopenharmony_ci list_del(&pending->list); 881d5ac70f0Sopenharmony_ci list_del(&pdata->list); 882d5ac70f0Sopenharmony_ci free(pending); 883d5ac70f0Sopenharmony_ci free(pdata); 884d5ac70f0Sopenharmony_ci return 0; 885d5ac70f0Sopenharmony_ci} 886d5ac70f0Sopenharmony_ci 887d5ac70f0Sopenharmony_cistatic int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) 888d5ac70f0Sopenharmony_ci{ 889d5ac70f0Sopenharmony_ci int sock; 890d5ac70f0Sopenharmony_ci sock = accept(waiter->fd, 0, 0); 891d5ac70f0Sopenharmony_ci if (sock < 0) { 892d5ac70f0Sopenharmony_ci int result = -errno; 893d5ac70f0Sopenharmony_ci SYSERROR("accept failed"); 894d5ac70f0Sopenharmony_ci return result; 895d5ac70f0Sopenharmony_ci } else { 896d5ac70f0Sopenharmony_ci client_t *client = calloc(1, sizeof(*client)); 897d5ac70f0Sopenharmony_ci client->ctrl_fd = sock; 898d5ac70f0Sopenharmony_ci client->local = 1; 899d5ac70f0Sopenharmony_ci client->open = 0; 900d5ac70f0Sopenharmony_ci add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client); 901d5ac70f0Sopenharmony_ci list_add_tail(&client->list, &clients); 902d5ac70f0Sopenharmony_ci } 903d5ac70f0Sopenharmony_ci return 0; 904d5ac70f0Sopenharmony_ci} 905d5ac70f0Sopenharmony_ci 906d5ac70f0Sopenharmony_cistatic int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED) 907d5ac70f0Sopenharmony_ci{ 908d5ac70f0Sopenharmony_ci int sock; 909d5ac70f0Sopenharmony_ci sock = accept(waiter->fd, 0, 0); 910d5ac70f0Sopenharmony_ci if (sock < 0) { 911d5ac70f0Sopenharmony_ci int result = -errno; 912d5ac70f0Sopenharmony_ci SYSERROR("accept failed"); 913d5ac70f0Sopenharmony_ci return result; 914d5ac70f0Sopenharmony_ci } else { 915d5ac70f0Sopenharmony_ci inet_pending_t *pending = calloc(1, sizeof(*pending)); 916d5ac70f0Sopenharmony_ci pending->fd = sock; 917d5ac70f0Sopenharmony_ci pending->cookie = 0; 918d5ac70f0Sopenharmony_ci add_waiter(sock, POLLIN, inet_pending_handler, pending); 919d5ac70f0Sopenharmony_ci list_add_tail(&pending->list, &inet_pendings); 920d5ac70f0Sopenharmony_ci } 921d5ac70f0Sopenharmony_ci return 0; 922d5ac70f0Sopenharmony_ci} 923d5ac70f0Sopenharmony_ci 924d5ac70f0Sopenharmony_cistatic int server(const char *sockname, int port) 925d5ac70f0Sopenharmony_ci{ 926d5ac70f0Sopenharmony_ci int err, result, sockn = -1, socki = -1; 927d5ac70f0Sopenharmony_ci unsigned int k; 928d5ac70f0Sopenharmony_ci long open_max; 929d5ac70f0Sopenharmony_ci 930d5ac70f0Sopenharmony_ci if (!sockname && port < 0) 931d5ac70f0Sopenharmony_ci return -EINVAL; 932d5ac70f0Sopenharmony_ci open_max = sysconf(_SC_OPEN_MAX); 933d5ac70f0Sopenharmony_ci if (open_max < 0) { 934d5ac70f0Sopenharmony_ci result = -errno; 935d5ac70f0Sopenharmony_ci SYSERROR("sysconf failed"); 936d5ac70f0Sopenharmony_ci return result; 937d5ac70f0Sopenharmony_ci } 938d5ac70f0Sopenharmony_ci pollfds = calloc((size_t) open_max, sizeof(*pollfds)); 939d5ac70f0Sopenharmony_ci waiters = calloc((size_t) open_max, sizeof(*waiters)); 940d5ac70f0Sopenharmony_ci 941d5ac70f0Sopenharmony_ci if (sockname) { 942d5ac70f0Sopenharmony_ci sockn = make_local_socket(sockname); 943d5ac70f0Sopenharmony_ci if (sockn < 0) 944d5ac70f0Sopenharmony_ci return sockn; 945d5ac70f0Sopenharmony_ci if (fcntl(sockn, F_SETFL, O_NONBLOCK) < 0) { 946d5ac70f0Sopenharmony_ci result = -errno; 947d5ac70f0Sopenharmony_ci SYSERROR("fcntl O_NONBLOCK failed"); 948d5ac70f0Sopenharmony_ci goto _end; 949d5ac70f0Sopenharmony_ci } 950d5ac70f0Sopenharmony_ci if (listen(sockn, 4) < 0) { 951d5ac70f0Sopenharmony_ci result = -errno; 952d5ac70f0Sopenharmony_ci SYSERROR("listen failed"); 953d5ac70f0Sopenharmony_ci goto _end; 954d5ac70f0Sopenharmony_ci } 955d5ac70f0Sopenharmony_ci add_waiter(sockn, POLLIN, local_handler, NULL); 956d5ac70f0Sopenharmony_ci } 957d5ac70f0Sopenharmony_ci if (port >= 0) { 958d5ac70f0Sopenharmony_ci socki = make_inet_socket(port); 959d5ac70f0Sopenharmony_ci if (socki < 0) 960d5ac70f0Sopenharmony_ci return socki; 961d5ac70f0Sopenharmony_ci if (fcntl(socki, F_SETFL, O_NONBLOCK) < 0) { 962d5ac70f0Sopenharmony_ci result = -errno; 963d5ac70f0Sopenharmony_ci SYSERROR("fcntl failed"); 964d5ac70f0Sopenharmony_ci goto _end; 965d5ac70f0Sopenharmony_ci } 966d5ac70f0Sopenharmony_ci if (listen(socki, 4) < 0) { 967d5ac70f0Sopenharmony_ci result = -errno; 968d5ac70f0Sopenharmony_ci SYSERROR("listen failed"); 969d5ac70f0Sopenharmony_ci goto _end; 970d5ac70f0Sopenharmony_ci } 971d5ac70f0Sopenharmony_ci add_waiter(socki, POLLIN, inet_handler, NULL); 972d5ac70f0Sopenharmony_ci } 973d5ac70f0Sopenharmony_ci 974d5ac70f0Sopenharmony_ci while (1) { 975d5ac70f0Sopenharmony_ci struct pollfd pfds[open_max]; 976d5ac70f0Sopenharmony_ci size_t pfds_count; 977d5ac70f0Sopenharmony_ci do { 978d5ac70f0Sopenharmony_ci err = poll(pollfds, pollfds_count, -1); 979d5ac70f0Sopenharmony_ci } while (err == 0); 980d5ac70f0Sopenharmony_ci if (err < 0) { 981d5ac70f0Sopenharmony_ci SYSERROR("poll failed"); 982d5ac70f0Sopenharmony_ci continue; 983d5ac70f0Sopenharmony_ci } 984d5ac70f0Sopenharmony_ci 985d5ac70f0Sopenharmony_ci pfds_count = pollfds_count; 986d5ac70f0Sopenharmony_ci memcpy(pfds, pollfds, sizeof(*pfds) * pfds_count); 987d5ac70f0Sopenharmony_ci for (k = 0; k < pfds_count; k++) { 988d5ac70f0Sopenharmony_ci struct pollfd *pfd = &pfds[k]; 989d5ac70f0Sopenharmony_ci if (pfd->revents) { 990d5ac70f0Sopenharmony_ci waiter_t *w = &waiters[pfd->fd]; 991d5ac70f0Sopenharmony_ci if (!w->handler) 992d5ac70f0Sopenharmony_ci continue; 993d5ac70f0Sopenharmony_ci err = w->handler(w, pfd->revents); 994d5ac70f0Sopenharmony_ci if (err < 0) 995d5ac70f0Sopenharmony_ci ERROR("waiter handler failed"); 996d5ac70f0Sopenharmony_ci } 997d5ac70f0Sopenharmony_ci } 998d5ac70f0Sopenharmony_ci } 999d5ac70f0Sopenharmony_ci _end: 1000d5ac70f0Sopenharmony_ci if (sockn >= 0) 1001d5ac70f0Sopenharmony_ci close(sockn); 1002d5ac70f0Sopenharmony_ci if (socki >= 0) 1003d5ac70f0Sopenharmony_ci close(socki); 1004d5ac70f0Sopenharmony_ci free(pollfds); 1005d5ac70f0Sopenharmony_ci free(waiters); 1006d5ac70f0Sopenharmony_ci return result; 1007d5ac70f0Sopenharmony_ci} 1008d5ac70f0Sopenharmony_ci 1009d5ac70f0Sopenharmony_ci 1010d5ac70f0Sopenharmony_cistatic void usage(void) 1011d5ac70f0Sopenharmony_ci{ 1012d5ac70f0Sopenharmony_ci fprintf(stderr, 1013d5ac70f0Sopenharmony_ci "Usage: %s [OPTIONS] server\n" 1014d5ac70f0Sopenharmony_ci "--help help\n", 1015d5ac70f0Sopenharmony_ci command); 1016d5ac70f0Sopenharmony_ci} 1017d5ac70f0Sopenharmony_ci 1018d5ac70f0Sopenharmony_ciint main(int argc, char **argv) 1019d5ac70f0Sopenharmony_ci{ 1020d5ac70f0Sopenharmony_ci static const struct option long_options[] = { 1021d5ac70f0Sopenharmony_ci {"help", 0, 0, 'h'}, 1022d5ac70f0Sopenharmony_ci { 0 , 0 , 0, 0 } 1023d5ac70f0Sopenharmony_ci }; 1024d5ac70f0Sopenharmony_ci int c; 1025d5ac70f0Sopenharmony_ci snd_config_t *conf; 1026d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1027d5ac70f0Sopenharmony_ci const char *sockname = NULL; 1028d5ac70f0Sopenharmony_ci long port = -1; 1029d5ac70f0Sopenharmony_ci int err; 1030d5ac70f0Sopenharmony_ci char *srvname; 1031d5ac70f0Sopenharmony_ci 1032d5ac70f0Sopenharmony_ci command = argv[0]; 1033d5ac70f0Sopenharmony_ci while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) { 1034d5ac70f0Sopenharmony_ci switch (c) { 1035d5ac70f0Sopenharmony_ci case 'h': 1036d5ac70f0Sopenharmony_ci usage(); 1037d5ac70f0Sopenharmony_ci return 0; 1038d5ac70f0Sopenharmony_ci default: 1039d5ac70f0Sopenharmony_ci fprintf(stderr, "Try `%s --help' for more information\n", command); 1040d5ac70f0Sopenharmony_ci return 1; 1041d5ac70f0Sopenharmony_ci } 1042d5ac70f0Sopenharmony_ci } 1043d5ac70f0Sopenharmony_ci if (argc - optind != 1) { 1044d5ac70f0Sopenharmony_ci ERROR("you need to specify server name"); 1045d5ac70f0Sopenharmony_ci return 1; 1046d5ac70f0Sopenharmony_ci } 1047d5ac70f0Sopenharmony_ci err = snd_config_update(); 1048d5ac70f0Sopenharmony_ci if (err < 0) { 1049d5ac70f0Sopenharmony_ci ERROR("cannot read configuration file"); 1050d5ac70f0Sopenharmony_ci return 1; 1051d5ac70f0Sopenharmony_ci } 1052d5ac70f0Sopenharmony_ci srvname = argv[optind]; 1053d5ac70f0Sopenharmony_ci err = snd_config_search_definition(snd_config, "server", srvname, &conf); 1054d5ac70f0Sopenharmony_ci if (err < 0) { 1055d5ac70f0Sopenharmony_ci ERROR("Missing definition for server %s", srvname); 1056d5ac70f0Sopenharmony_ci return 1; 1057d5ac70f0Sopenharmony_ci } 1058d5ac70f0Sopenharmony_ci if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { 1059d5ac70f0Sopenharmony_ci SNDERR("Invalid type for server %s definition", srvname); 1060d5ac70f0Sopenharmony_ci return -EINVAL; 1061d5ac70f0Sopenharmony_ci } 1062d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 1063d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1064d5ac70f0Sopenharmony_ci const char *id; 1065d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1066d5ac70f0Sopenharmony_ci continue; 1067d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0) 1068d5ac70f0Sopenharmony_ci continue; 1069d5ac70f0Sopenharmony_ci if (strcmp(id, "host") == 0) 1070d5ac70f0Sopenharmony_ci continue; 1071d5ac70f0Sopenharmony_ci if (strcmp(id, "socket") == 0) { 1072d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &sockname); 1073d5ac70f0Sopenharmony_ci if (err < 0) { 1074d5ac70f0Sopenharmony_ci ERROR("Invalid type for %s", id); 1075d5ac70f0Sopenharmony_ci return 1; 1076d5ac70f0Sopenharmony_ci } 1077d5ac70f0Sopenharmony_ci continue; 1078d5ac70f0Sopenharmony_ci } 1079d5ac70f0Sopenharmony_ci if (strcmp(id, "port") == 0) { 1080d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &port); 1081d5ac70f0Sopenharmony_ci if (err < 0) { 1082d5ac70f0Sopenharmony_ci ERROR("Invalid type for %s", id); 1083d5ac70f0Sopenharmony_ci return 1; 1084d5ac70f0Sopenharmony_ci } 1085d5ac70f0Sopenharmony_ci continue; 1086d5ac70f0Sopenharmony_ci } 1087d5ac70f0Sopenharmony_ci ERROR("Unknown field %s", id); 1088d5ac70f0Sopenharmony_ci return 1; 1089d5ac70f0Sopenharmony_ci } 1090d5ac70f0Sopenharmony_ci if (!sockname && port < 0) { 1091d5ac70f0Sopenharmony_ci ERROR("either socket or port need to be defined"); 1092d5ac70f0Sopenharmony_ci return 1; 1093d5ac70f0Sopenharmony_ci } 1094d5ac70f0Sopenharmony_ci server(sockname, port); 1095d5ac70f0Sopenharmony_ci return 0; 1096d5ac70f0Sopenharmony_ci} 1097