• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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