1 /*
2 * Control - SHM Client
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <sys/shm.h>
29 #include <sys/socket.h>
30 #include <poll.h>
31 #include <sys/un.h>
32 #include <sys/uio.h>
33 #include <sys/mman.h>
34 #include <netinet/in.h>
35 #include <netdb.h>
36 #include "aserver.h"
37
38 #ifndef PIC
39 /* entry for static linking */
40 const char *_snd_module_control_shm = "";
41 #endif
42
43 #ifndef DOC_HIDDEN
44 typedef struct {
45 int socket;
46 volatile snd_ctl_shm_ctrl_t *ctrl;
47 } snd_ctl_shm_t;
48 #endif
49
snd_ctl_shm_action(snd_ctl_t * ctl)50 static int snd_ctl_shm_action(snd_ctl_t *ctl)
51 {
52 snd_ctl_shm_t *shm = ctl->private_data;
53 int err;
54 char buf[1];
55 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
56 err = write(shm->socket, buf, 1);
57 if (err != 1)
58 return -EBADFD;
59 err = read(shm->socket, buf, 1);
60 if (err != 1)
61 return -EBADFD;
62 if (ctrl->cmd) {
63 SNDERR("Server has not done the cmd");
64 return -EBADFD;
65 }
66 return ctrl->result;
67 }
68
snd_ctl_shm_action_fd(snd_ctl_t * ctl,int * fd)69 static int snd_ctl_shm_action_fd(snd_ctl_t *ctl, int *fd)
70 {
71 snd_ctl_shm_t *shm = ctl->private_data;
72 int err;
73 char buf[1];
74 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
75 err = write(shm->socket, buf, 1);
76 if (err != 1)
77 return -EBADFD;
78 err = snd_receive_fd(shm->socket, buf, 1, fd);
79 if (err != 1)
80 return -EBADFD;
81 if (ctrl->cmd) {
82 SNDERR("Server has not done the cmd");
83 return -EBADFD;
84 }
85 return ctrl->result;
86 }
87
snd_ctl_shm_close(snd_ctl_t * ctl)88 static int snd_ctl_shm_close(snd_ctl_t *ctl)
89 {
90 snd_ctl_shm_t *shm = ctl->private_data;
91 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
92 int result;
93 ctrl->cmd = SND_CTL_IOCTL_CLOSE;
94 result = snd_ctl_shm_action(ctl);
95 shmdt((void *)ctrl);
96 close(shm->socket);
97 free(shm);
98 return result;
99 }
100
snd_ctl_shm_nonblock(snd_ctl_t * handle ATTRIBUTE_UNUSED,int nonblock ATTRIBUTE_UNUSED)101 static int snd_ctl_shm_nonblock(snd_ctl_t *handle ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
102 {
103 return 0;
104 }
105
snd_ctl_shm_async(snd_ctl_t * ctl,int sig,pid_t pid)106 static int snd_ctl_shm_async(snd_ctl_t *ctl, int sig, pid_t pid)
107 {
108 snd_ctl_shm_t *shm = ctl->private_data;
109 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
110 ctrl->cmd = SND_CTL_IOCTL_ASYNC;
111 ctrl->u.async.sig = sig;
112 if (pid == 0)
113 pid = getpid();
114 ctrl->u.async.pid = pid;
115 return snd_ctl_shm_action(ctl);
116 }
117
snd_ctl_shm_poll_descriptor(snd_ctl_t * ctl)118 static int snd_ctl_shm_poll_descriptor(snd_ctl_t *ctl)
119 {
120 snd_ctl_shm_t *shm = ctl->private_data;
121 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
122 int fd, err;
123 ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR;
124 err = snd_ctl_shm_action_fd(ctl, &fd);
125 if (err < 0)
126 return err;
127 return fd;
128 }
129
snd_ctl_shm_subscribe_events(snd_ctl_t * ctl,int subscribe)130 static int snd_ctl_shm_subscribe_events(snd_ctl_t *ctl, int subscribe)
131 {
132 snd_ctl_shm_t *shm = ctl->private_data;
133 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
134 ctrl->cmd = SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS;
135 ctrl->u.subscribe_events = subscribe;
136 return snd_ctl_shm_action(ctl);
137 }
138
snd_ctl_shm_card_info(snd_ctl_t * ctl,snd_ctl_card_info_t * info)139 static int snd_ctl_shm_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
140 {
141 snd_ctl_shm_t *shm = ctl->private_data;
142 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
143 int err;
144 // ctrl->u.card_info = *info;
145 ctrl->cmd = SNDRV_CTL_IOCTL_CARD_INFO;
146 err = snd_ctl_shm_action(ctl);
147 if (err < 0)
148 return err;
149 *info = ctrl->u.card_info;
150 return err;
151 }
152
snd_ctl_shm_elem_list(snd_ctl_t * ctl,snd_ctl_elem_list_t * list)153 static int snd_ctl_shm_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list)
154 {
155 snd_ctl_shm_t *shm = ctl->private_data;
156 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
157 size_t maxsize = CTL_SHM_DATA_MAXLEN;
158 size_t bytes = list->space * sizeof(*list->pids);
159 int err;
160 snd_ctl_elem_id_t *pids = list->pids;
161 if (bytes > maxsize)
162 return -EINVAL;
163 ctrl->u.element_list = *list;
164 ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_LIST;
165 err = snd_ctl_shm_action(ctl);
166 if (err < 0)
167 return err;
168 *list = ctrl->u.element_list;
169 list->pids = pids;
170 bytes = list->used * sizeof(*list->pids);
171 memcpy(pids, (void *)ctrl->data, bytes);
172 return err;
173 }
174
snd_ctl_shm_elem_info(snd_ctl_t * ctl,snd_ctl_elem_info_t * info)175 static int snd_ctl_shm_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)
176 {
177 snd_ctl_shm_t *shm = ctl->private_data;
178 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
179 int err;
180 ctrl->u.element_info = *info;
181 ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_INFO;
182 err = snd_ctl_shm_action(ctl);
183 if (err < 0)
184 return err;
185 *info = ctrl->u.element_info;
186 return err;
187 }
188
snd_ctl_shm_elem_read(snd_ctl_t * ctl,snd_ctl_elem_value_t * control)189 static int snd_ctl_shm_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
190 {
191 snd_ctl_shm_t *shm = ctl->private_data;
192 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
193 int err;
194 ctrl->u.element_read = *control;
195 ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_READ;
196 err = snd_ctl_shm_action(ctl);
197 if (err < 0)
198 return err;
199 *control = ctrl->u.element_read;
200 return err;
201 }
202
snd_ctl_shm_elem_write(snd_ctl_t * ctl,snd_ctl_elem_value_t * control)203 static int snd_ctl_shm_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
204 {
205 snd_ctl_shm_t *shm = ctl->private_data;
206 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
207 int err;
208 ctrl->u.element_write = *control;
209 ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_WRITE;
210 err = snd_ctl_shm_action(ctl);
211 if (err < 0)
212 return err;
213 *control = ctrl->u.element_write;
214 return err;
215 }
216
snd_ctl_shm_elem_lock(snd_ctl_t * ctl,snd_ctl_elem_id_t * id)217 static int snd_ctl_shm_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)
218 {
219 snd_ctl_shm_t *shm = ctl->private_data;
220 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
221 int err;
222 ctrl->u.element_lock = *id;
223 ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_LOCK;
224 err = snd_ctl_shm_action(ctl);
225 if (err < 0)
226 return err;
227 *id = ctrl->u.element_lock;
228 return err;
229 }
230
snd_ctl_shm_elem_unlock(snd_ctl_t * ctl,snd_ctl_elem_id_t * id)231 static int snd_ctl_shm_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)
232 {
233 snd_ctl_shm_t *shm = ctl->private_data;
234 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
235 int err;
236 ctrl->u.element_unlock = *id;
237 ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_UNLOCK;
238 err = snd_ctl_shm_action(ctl);
239 if (err < 0)
240 return err;
241 *id = ctrl->u.element_unlock;
242 return err;
243 }
244
snd_ctl_shm_hwdep_next_device(snd_ctl_t * ctl,int * device)245 static int snd_ctl_shm_hwdep_next_device(snd_ctl_t *ctl, int * device)
246 {
247 snd_ctl_shm_t *shm = ctl->private_data;
248 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
249 int err;
250 ctrl->u.device = *device;
251 ctrl->cmd = SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE;
252 err = snd_ctl_shm_action(ctl);
253 if (err < 0)
254 return err;
255 *device = ctrl->u.device;
256 return err;
257 }
258
snd_ctl_shm_hwdep_info(snd_ctl_t * ctl,snd_hwdep_info_t * info)259 static int snd_ctl_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)
260 {
261 snd_ctl_shm_t *shm = ctl->private_data;
262 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
263 int err;
264 ctrl->u.hwdep_info = *info;
265 ctrl->cmd = SNDRV_CTL_IOCTL_HWDEP_INFO;
266 err = snd_ctl_shm_action(ctl);
267 if (err < 0)
268 return err;
269 *info = ctrl->u.hwdep_info;
270 return err;
271 }
272
snd_ctl_shm_pcm_next_device(snd_ctl_t * ctl,int * device)273 static int snd_ctl_shm_pcm_next_device(snd_ctl_t *ctl, int * device)
274 {
275 snd_ctl_shm_t *shm = ctl->private_data;
276 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
277 int err;
278 ctrl->u.device = *device;
279 ctrl->cmd = SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE;
280 err = snd_ctl_shm_action(ctl);
281 if (err < 0)
282 return err;
283 *device = ctrl->u.device;
284 return err;
285 }
286
snd_ctl_shm_pcm_info(snd_ctl_t * ctl,snd_pcm_info_t * info)287 static int snd_ctl_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)
288 {
289 snd_ctl_shm_t *shm = ctl->private_data;
290 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
291 int err;
292 ctrl->u.pcm_info = *info;
293 ctrl->cmd = SNDRV_CTL_IOCTL_PCM_INFO;
294 err = snd_ctl_shm_action(ctl);
295 if (err < 0)
296 return err;
297 *info = ctrl->u.pcm_info;
298 return err;
299 }
300
snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t * ctl,int subdev)301 static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
302 {
303 snd_ctl_shm_t *shm = ctl->private_data;
304 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
305 ctrl->u.pcm_prefer_subdevice = subdev;
306 ctrl->cmd = SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE;
307 return snd_ctl_shm_action(ctl);
308 }
309
snd_ctl_shm_rawmidi_next_device(snd_ctl_t * ctl,int * device)310 static int snd_ctl_shm_rawmidi_next_device(snd_ctl_t *ctl, int * device)
311 {
312 snd_ctl_shm_t *shm = ctl->private_data;
313 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
314 int err;
315 ctrl->u.device = *device;
316 ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE;
317 err = snd_ctl_shm_action(ctl);
318 if (err < 0)
319 return err;
320 *device = ctrl->u.device;
321 return err;
322 }
323
snd_ctl_shm_rawmidi_info(snd_ctl_t * ctl,snd_rawmidi_info_t * info)324 static int snd_ctl_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)
325 {
326 snd_ctl_shm_t *shm = ctl->private_data;
327 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
328 int err;
329 ctrl->u.rawmidi_info = *info;
330 ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_INFO;
331 err = snd_ctl_shm_action(ctl);
332 if (err < 0)
333 return err;
334 *info = ctrl->u.rawmidi_info;
335 return err;
336 }
337
snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t * ctl,int subdev)338 static int snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)
339 {
340 snd_ctl_shm_t *shm = ctl->private_data;
341 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
342 ctrl->u.rawmidi_prefer_subdevice = subdev;
343 ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE;
344 return snd_ctl_shm_action(ctl);
345 }
346
snd_ctl_shm_set_power_state(snd_ctl_t * ctl,unsigned int state)347 static int snd_ctl_shm_set_power_state(snd_ctl_t *ctl, unsigned int state)
348 {
349 snd_ctl_shm_t *shm = ctl->private_data;
350 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
351 ctrl->u.power_state = state;
352 ctrl->cmd = SNDRV_CTL_IOCTL_POWER;
353 return snd_ctl_shm_action(ctl);
354 }
355
snd_ctl_shm_get_power_state(snd_ctl_t * ctl,unsigned int * state)356 static int snd_ctl_shm_get_power_state(snd_ctl_t *ctl, unsigned int *state)
357 {
358 snd_ctl_shm_t *shm = ctl->private_data;
359 volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
360 int err;
361 ctrl->cmd = SNDRV_CTL_IOCTL_POWER_STATE;
362 err = snd_ctl_shm_action(ctl);
363 if (err < 0)
364 return err;
365 *state = ctrl->u.power_state;
366 return err;
367 }
368
snd_ctl_shm_read(snd_ctl_t * ctl,snd_ctl_event_t * event)369 static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
370 {
371 snd_ctl_shm_t *shm;
372 volatile snd_ctl_shm_ctrl_t *ctrl;
373 int err;
374 err = snd_ctl_wait(ctl, -1);
375 if (err < 0)
376 return 0;
377 shm = ctl->private_data;
378 ctrl = shm->ctrl;
379 ctrl->u.read = *event;
380 ctrl->cmd = SND_CTL_IOCTL_READ;
381 err = snd_ctl_shm_action(ctl);
382 if (err < 0)
383 return err;
384 *event = ctrl->u.read;
385 return err;
386 }
387
388 static const snd_ctl_ops_t snd_ctl_shm_ops = {
389 .close = snd_ctl_shm_close,
390 .nonblock = snd_ctl_shm_nonblock,
391 .async = snd_ctl_shm_async,
392 .subscribe_events = snd_ctl_shm_subscribe_events,
393 .card_info = snd_ctl_shm_card_info,
394 .element_list = snd_ctl_shm_elem_list,
395 .element_info = snd_ctl_shm_elem_info,
396 .element_read = snd_ctl_shm_elem_read,
397 .element_write = snd_ctl_shm_elem_write,
398 .element_lock = snd_ctl_shm_elem_lock,
399 .element_unlock = snd_ctl_shm_elem_unlock,
400 .hwdep_next_device = snd_ctl_shm_hwdep_next_device,
401 .hwdep_info = snd_ctl_shm_hwdep_info,
402 .pcm_next_device = snd_ctl_shm_pcm_next_device,
403 .pcm_info = snd_ctl_shm_pcm_info,
404 .pcm_prefer_subdevice = snd_ctl_shm_pcm_prefer_subdevice,
405 .rawmidi_next_device = snd_ctl_shm_rawmidi_next_device,
406 .rawmidi_info = snd_ctl_shm_rawmidi_info,
407 .rawmidi_prefer_subdevice = snd_ctl_shm_rawmidi_prefer_subdevice,
408 .set_power_state = snd_ctl_shm_set_power_state,
409 .get_power_state = snd_ctl_shm_get_power_state,
410 .read = snd_ctl_shm_read,
411 };
412
make_local_socket(const char * filename)413 static int make_local_socket(const char *filename)
414 {
415 size_t l = strlen(filename);
416 size_t size = offsetof(struct sockaddr_un, sun_path) + l;
417 struct sockaddr_un *addr = alloca(size);
418 int sock;
419
420 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
421 if (sock < 0)
422 return -errno;
423
424 addr->sun_family = AF_LOCAL;
425 memcpy(addr->sun_path, filename, l);
426
427 if (connect(sock, (struct sockaddr *) addr, size) < 0) {
428 close(sock);
429 return -errno;
430 }
431 return sock;
432 }
433
snd_ctl_shm_open(snd_ctl_t ** handlep,const char * name,const char * sockname,const char * sname,int mode)434 int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode)
435 {
436 snd_ctl_t *ctl;
437 snd_ctl_shm_t *shm = NULL;
438 snd_client_open_request_t *req;
439 snd_client_open_answer_t ans;
440 size_t snamelen, reqlen;
441 int err;
442 int result;
443 int sock = -1;
444 snd_ctl_shm_ctrl_t *ctrl = NULL;
445 snamelen = strlen(sname);
446 if (snamelen > 255)
447 return -EINVAL;
448
449 result = make_local_socket(sockname);
450 if (result < 0) {
451 SNDERR("server for socket %s is not running", sockname);
452 goto _err;
453 }
454 sock = result;
455
456 reqlen = sizeof(*req) + snamelen;
457 req = alloca(reqlen);
458 memcpy(req->name, sname, snamelen);
459 req->dev_type = SND_DEV_TYPE_CONTROL;
460 req->transport_type = SND_TRANSPORT_TYPE_SHM;
461 req->stream = 0;
462 req->mode = mode;
463 req->namelen = snamelen;
464 err = write(sock, req, reqlen);
465 if (err < 0) {
466 SNDERR("write error");
467 result = -errno;
468 goto _err;
469 }
470 if ((size_t) err != reqlen) {
471 SNDERR("write size error");
472 result = -EINVAL;
473 goto _err;
474 }
475 err = read(sock, &ans, sizeof(ans));
476 if (err < 0) {
477 SNDERR("read error");
478 result = -errno;
479 goto _err;
480 }
481 if (err != sizeof(ans)) {
482 SNDERR("read size error");
483 result = -EINVAL;
484 goto _err;
485 }
486 result = ans.result;
487 if (result < 0)
488 goto _err;
489
490 ctrl = shmat(ans.cookie, 0, 0);
491 if (!ctrl) {
492 result = -errno;
493 goto _err;
494 }
495
496 shm = calloc(1, sizeof(snd_ctl_shm_t));
497 if (!shm) {
498 result = -ENOMEM;
499 goto _err;
500 }
501
502 shm->socket = sock;
503 shm->ctrl = ctrl;
504
505 err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name);
506 if (err < 0) {
507 result = err;
508 goto _err;
509 }
510 ctl->ops = &snd_ctl_shm_ops;
511 ctl->private_data = shm;
512 err = snd_ctl_shm_poll_descriptor(ctl);
513 if (err < 0) {
514 snd_ctl_close(ctl);
515 return err;
516 }
517 ctl->poll_fd = err;
518 *handlep = ctl;
519 return 0;
520
521 _err:
522 close(sock);
523 if (ctrl)
524 shmdt(ctrl);
525 free(shm);
526 return result;
527 }
528
_snd_ctl_shm_open(snd_ctl_t ** handlep,char * name,snd_config_t * root,snd_config_t * conf,int mode)529 int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_config_t *conf, int mode)
530 {
531 snd_config_iterator_t i, next;
532 const char *server = NULL;
533 const char *ctl_name = NULL;
534 snd_config_t *sconfig;
535 const char *sockname = NULL;
536 long port = -1;
537 int err;
538
539 snd_config_for_each(i, next, conf) {
540 snd_config_t *n = snd_config_iterator_entry(i);
541 const char *id;
542 if (snd_config_get_id(n, &id) < 0)
543 continue;
544 if (_snd_conf_generic_id(id))
545 continue;
546 if (strcmp(id, "server") == 0) {
547 err = snd_config_get_string(n, &server);
548 if (err < 0) {
549 SNDERR("Invalid type for %s", id);
550 return -EINVAL;
551 }
552 continue;
553 }
554 if (strcmp(id, "ctl") == 0) {
555 err = snd_config_get_string(n, &ctl_name);
556 if (err < 0) {
557 SNDERR("Invalid type for %s", id);
558 return -EINVAL;
559 }
560 continue;
561 }
562 SNDERR("Unknown field %s", id);
563 return -EINVAL;
564 }
565 if (!ctl_name) {
566 SNDERR("ctl is not defined");
567 return -EINVAL;
568 }
569 if (!server) {
570 SNDERR("server is not defined");
571 return -EINVAL;
572 }
573 err = snd_config_search_definition(root, "server", server, &sconfig);
574 if (err < 0) {
575 SNDERR("Unknown server %s", server);
576 return -EINVAL;
577 }
578 if (snd_config_get_type(sconfig) != SND_CONFIG_TYPE_COMPOUND) {
579 SNDERR("Invalid type for server %s definition", server);
580 err = -EINVAL;
581 goto _err;
582 }
583 snd_config_for_each(i, next, sconfig) {
584 snd_config_t *n = snd_config_iterator_entry(i);
585 const char *id;
586 if (snd_config_get_id(n, &id) < 0)
587 continue;
588 if (_snd_conf_generic_id(id))
589 continue;
590 if (strcmp(id, "host") == 0)
591 continue;
592 if (strcmp(id, "socket") == 0) {
593 err = snd_config_get_string(n, &sockname);
594 if (err < 0) {
595 SNDERR("Invalid type for %s", id);
596 goto _err;
597 }
598 continue;
599 }
600 if (strcmp(id, "port") == 0) {
601 err = snd_config_get_integer(n, &port);
602 if (err < 0) {
603 SNDERR("Invalid type for %s", id);
604 goto _err;
605 }
606 continue;
607 }
608 SNDERR("Unknown field %s", id);
609 err = -EINVAL;
610 goto _err;
611 }
612
613 if (!sockname) {
614 SNDERR("socket is not defined");
615 goto _err;
616 }
617 err = snd_ctl_shm_open(handlep, name, sockname, ctl_name, mode);
618 _err:
619 snd_config_delete(sconfig);
620 return err;
621 }
622 SND_DLSYM_BUILD_VERSION(_snd_ctl_shm_open, SND_CONTROL_DLSYM_VERSION);
623