OSDN Git Service

pcm: direct: check state before enter poll on timer
[android-x86/external-alsa-lib.git] / src / pcm / pcm_direct.c
1 /*
2  *  PCM - Direct Stream Mixing
3  *  Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  */
21   
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <grp.h>
31 #include <sys/ioctl.h>
32 #include <sys/mman.h>
33 #include <sys/poll.h>
34 #include <sys/shm.h>
35 #include <sys/sem.h>
36 #include <sys/wait.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <sys/un.h>
40 #include <sys/mman.h>
41 #include "pcm_direct.h"
42
43 /*
44  *
45  */
46  
47 union semun {
48         int              val;    /* Value for SETVAL */
49         struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
50         unsigned short  *array;  /* Array for GETALL, SETALL */
51         struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux specific) */
52 };
53  
54 /*
55  * FIXME:
56  *  add possibility to use futexes here
57  */
58
59 int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix)
60 {
61         union semun s;
62         struct semid_ds buf;
63         int i;
64
65         dmix->semid = semget(dmix->ipc_key, DIRECT_IPC_SEMS,
66                              IPC_CREAT | dmix->ipc_perm);
67         if (dmix->semid < 0)
68                 return -errno;
69         if (dmix->ipc_gid < 0)
70                 return 0;
71         for (i = 0; i < DIRECT_IPC_SEMS; i++) {
72                 s.buf = &buf;
73                 if (semctl(dmix->semid, i, IPC_STAT, s) < 0) {
74                         int err = -errno;
75                         snd_pcm_direct_semaphore_discard(dmix);
76                         return err;
77                 }
78                 buf.sem_perm.gid = dmix->ipc_gid;
79                 s.buf = &buf;
80                 semctl(dmix->semid, i, IPC_SET, s);
81         }
82         return 0;
83 }
84
85 #define SND_PCM_DIRECT_MAGIC    (0xa15ad300 + sizeof(snd_pcm_direct_share_t))
86
87 /*
88  *  global shared memory area 
89  */
90
91 int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix)
92 {
93         struct shmid_ds buf;
94         int tmpid, err, first_instance = 0;
95         
96 retryget:
97         dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t),
98                              dmix->ipc_perm);
99         if (dmix->shmid < 0 && errno == ENOENT) {
100                 if ((dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t),
101                                              IPC_CREAT | IPC_EXCL | dmix->ipc_perm)) != -1)
102                         first_instance = 1;
103                 else if (errno == EEXIST)
104                         goto retryget;
105         }
106         err = -errno;
107         if (dmix->shmid < 0) {
108                 if (errno == EINVAL)
109                 if ((tmpid = shmget(dmix->ipc_key, 0, dmix->ipc_perm)) != -1)
110                 if (!shmctl(tmpid, IPC_STAT, &buf))
111                 if (!buf.shm_nattch)
112                 /* no users so destroy the segment */
113                 if (!shmctl(tmpid, IPC_RMID, NULL))
114                     goto retryget;
115                 return err;
116         }
117         dmix->shmptr = shmat(dmix->shmid, 0, 0);
118         if (dmix->shmptr == (void *) -1) {
119                 err = -errno;
120                 snd_pcm_direct_shm_discard(dmix);
121                 return err;
122         }
123         mlock(dmix->shmptr, sizeof(snd_pcm_direct_share_t));
124         if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) {
125                 err = -errno;
126                 snd_pcm_direct_shm_discard(dmix);
127                 return err;
128         }
129         if (first_instance) {   /* we're the first user, clear the segment */
130                 memset(dmix->shmptr, 0, sizeof(snd_pcm_direct_share_t));
131                 if (dmix->ipc_gid >= 0) {
132                         buf.shm_perm.gid = dmix->ipc_gid;
133                         shmctl(dmix->shmid, IPC_SET, &buf);
134                 }
135                 dmix->shmptr->magic = SND_PCM_DIRECT_MAGIC;
136                 return 1;
137         } else {
138                 if (dmix->shmptr->magic != SND_PCM_DIRECT_MAGIC) {
139                         snd_pcm_direct_shm_discard(dmix);
140                         return -EINVAL;
141                 }
142         }
143         return 0;
144 }
145
146 /* discard shared memory */
147 /*
148  * Define snd_* functions to be used in server.
149  * Since objects referred in a plugin can be released dynamically, a forked
150  * server should have statically linked functions.
151  * (e.g. Novell bugzilla #105772)
152  */
153 static int _snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix)
154 {
155         struct shmid_ds buf;
156         int ret = 0;
157
158         if (dmix->shmid < 0)
159                 return -EINVAL;
160         if (dmix->shmptr != (void *) -1 && shmdt(dmix->shmptr) < 0)
161                 return -errno;
162         dmix->shmptr = (void *) -1;
163         if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0)
164                 return -errno;
165         if (buf.shm_nattch == 0) {      /* we're the last user, destroy the segment */
166                 if (shmctl(dmix->shmid, IPC_RMID, NULL) < 0)
167                         return -errno;
168                 ret = 1;
169         }
170         dmix->shmid = -1;
171         return ret;
172 }
173
174 /* ... and an exported version */
175 int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix)
176 {
177         return _snd_pcm_direct_shm_discard(dmix);
178 }
179
180 /*
181  *  server side
182  */
183
184 static int get_tmp_name(char *filename, size_t size)
185 {
186         struct timeval tv;
187
188         gettimeofday(&tv, NULL);
189         snprintf(filename, size, TMPDIR "/alsa-dmix-%i-%li-%li", (int)getpid(), (long)tv.tv_sec, (long)tv.tv_usec);
190         filename[size-1] = '\0';
191         return 0;
192 }
193
194 static int make_local_socket(const char *filename, int server, mode_t ipc_perm, int ipc_gid)
195 {
196         size_t l = strlen(filename);
197         size_t size = offsetof(struct sockaddr_un, sun_path) + l;
198         struct sockaddr_un *addr = alloca(size);
199         int sock;
200
201         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
202         if (sock < 0) {
203                 int result = -errno;
204                 SYSERR("socket failed");
205                 return result;
206         }
207
208         if (server)
209                 unlink(filename);
210         memset(addr, 0, size); /* make valgrind happy */
211         addr->sun_family = AF_LOCAL;
212         memcpy(addr->sun_path, filename, l);
213         
214         if (server) {
215                 if (bind(sock, (struct sockaddr *) addr, size) < 0) {
216                         int result = -errno;
217                         SYSERR("bind failed: %s", filename);
218                         close(sock);
219                         return result;
220                 } else {
221                         if (chmod(filename, ipc_perm) < 0) {
222                                 int result = -errno;
223                                 SYSERR("chmod failed: %s", filename);
224                                 close(sock);
225                                 unlink(filename);
226                                 return result;
227                         }
228                         if (chown(filename, -1, ipc_gid) < 0) {
229 #if 0 /* it's not fatal */
230                                 int result = -errno;
231                                 SYSERR("chown failed: %s", filename);
232                                 close(sock);
233                                 unlink(filename);
234                                 return result;
235 #endif
236                         }
237                 }
238         } else {
239                 if (connect(sock, (struct sockaddr *) addr, size) < 0) {
240                         int result = -errno;
241                         SYSERR("connect failed: %s", filename);
242                         close(sock);
243                         return result;
244                 }
245         }
246         return sock;
247 }
248
249 #if 0
250 #define SERVER_JOB_DEBUG
251 #define server_printf(fmt, args...) printf(fmt, ##args)
252 #else
253 #undef SERVER_JOB_DEBUG
254 #define server_printf(fmt, args...) /* nothing */
255 #endif
256
257 static snd_pcm_direct_t *server_job_dmix;
258
259 static void server_cleanup(snd_pcm_direct_t *dmix)
260 {
261         close(dmix->server_fd);
262         close(dmix->hw_fd);
263         if (dmix->server_free)
264                 dmix->server_free(dmix);
265         unlink(dmix->shmptr->socket_name);
266         _snd_pcm_direct_shm_discard(dmix);
267         snd_pcm_direct_semaphore_discard(dmix);
268 }
269
270 static void server_job_signal(int sig ATTRIBUTE_UNUSED)
271 {
272         snd_pcm_direct_semaphore_down(server_job_dmix, DIRECT_IPC_SEM_CLIENT);
273         server_cleanup(server_job_dmix);
274         server_printf("DIRECT SERVER EXIT - SIGNAL\n");
275         _exit(EXIT_SUCCESS);
276 }
277
278 /* This is a copy from ../socket.c, provided here only for a server job
279  * (see the comment above)
280  */
281 static int _snd_send_fd(int sock, void *data, size_t len, int fd)
282 {
283         int ret;
284         size_t cmsg_len = CMSG_LEN(sizeof(int));
285         struct cmsghdr *cmsg = alloca(cmsg_len);
286         int *fds = (int *) CMSG_DATA(cmsg);
287         struct msghdr msghdr;
288         struct iovec vec;
289
290         vec.iov_base = (void *)&data;
291         vec.iov_len = len;
292
293         cmsg->cmsg_len = cmsg_len;
294         cmsg->cmsg_level = SOL_SOCKET;
295         cmsg->cmsg_type = SCM_RIGHTS;
296         *fds = fd;
297
298         msghdr.msg_name = NULL;
299         msghdr.msg_namelen = 0;
300         msghdr.msg_iov = &vec;
301         msghdr.msg_iovlen = 1;
302         msghdr.msg_control = cmsg;
303         msghdr.msg_controllen = cmsg_len;
304         msghdr.msg_flags = 0;
305
306         ret = sendmsg(sock, &msghdr, 0 );
307         if (ret < 0)
308                 return -errno;
309         return ret;
310 }
311
312 static void server_job(snd_pcm_direct_t *dmix)
313 {
314         int ret, sck, i;
315         int max = 128, current = 0;
316         struct pollfd pfds[max + 1];
317
318         server_job_dmix = dmix;
319         /* don't allow to be killed */
320         signal(SIGHUP, server_job_signal);
321         signal(SIGQUIT, server_job_signal);
322         signal(SIGTERM, server_job_signal);
323         signal(SIGKILL, server_job_signal);
324         /* close all files to free resources */
325         i = sysconf(_SC_OPEN_MAX);
326 #ifdef SERVER_JOB_DEBUG
327         while (--i >= 3) {
328 #else
329         while (--i >= 0) {
330 #endif
331                 if (i != dmix->server_fd && i != dmix->hw_fd)
332                         close(i);
333         }
334         
335         /* detach from parent */
336         setsid();
337
338         pfds[0].fd = dmix->server_fd;
339         pfds[0].events = POLLIN | POLLERR | POLLHUP;
340
341         server_printf("DIRECT SERVER STARTED\n");
342         while (1) {
343                 ret = poll(pfds, current + 1, 500);
344                 server_printf("DIRECT SERVER: poll ret = %i, revents[0] = 0x%x, errno = %i\n", ret, pfds[0].revents, errno);
345                 if (ret < 0) {
346                         if (errno == EINTR)
347                                 continue;
348                         /* some error */
349                         break;
350                 }
351                 if (ret == 0 || (pfds[0].revents & (POLLERR | POLLHUP))) {      /* timeout or error? */
352                         struct shmid_ds buf;
353                         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
354                         if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) {
355                                 _snd_pcm_direct_shm_discard(dmix);
356                                 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
357                                 continue;
358                         }
359                         server_printf("DIRECT SERVER: nattch = %i\n", (int)buf.shm_nattch);
360                         if (buf.shm_nattch == 1)        /* server is the last user, exit */
361                                 break;
362                         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
363                         continue;
364                 }
365                 if (pfds[0].revents & POLLIN) {
366                         ret--;
367                         sck = accept(dmix->server_fd, 0, 0);
368                         if (sck >= 0) {
369                                 server_printf("DIRECT SERVER: new connection %i\n", sck);
370                                 if (current == max) {
371                                         close(sck);
372                                 } else {
373                                         unsigned char buf = 'A';
374                                         pfds[current+1].fd = sck;
375                                         pfds[current+1].events = POLLIN | POLLERR | POLLHUP;
376                                         _snd_send_fd(sck, &buf, 1, dmix->hw_fd);
377                                         server_printf("DIRECT SERVER: fd sent ok\n");
378                                         current++;
379                                 }
380                         }
381                 }
382                 for (i = 0; i < current && ret > 0; i++) {
383                         struct pollfd *pfd = &pfds[i+1];
384                         unsigned char cmd;
385                         server_printf("client %i revents = 0x%x\n", pfd->fd, pfd->revents);
386                         if (pfd->revents & (POLLERR | POLLHUP)) {
387                                 ret--;
388                                 close(pfd->fd);
389                                 pfd->fd = -1;
390                                 continue;
391                         }
392                         if (!(pfd->revents & POLLIN))
393                                 continue;
394                         ret--;
395                         if (read(pfd->fd, &cmd, 1) == 1)
396                                 cmd = 0 /*process command */;
397                 }
398                 for (i = 0; i < current; i++) {
399                         if (pfds[i+1].fd < 0) {
400                                 if (i + 1 != max)
401                                         memcpy(&pfds[i+1], &pfds[i+2], sizeof(struct pollfd) * (max - i - 1));
402                                 current--;
403                         }
404                 }
405         }
406         server_cleanup(dmix);
407         server_printf("DIRECT SERVER EXIT\n");
408 #ifdef SERVER_JOB_DEBUG
409         close(0); close(1); close(2);
410 #endif
411         _exit(EXIT_SUCCESS);
412 }
413
414 int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix)
415 {
416         int ret;
417
418         dmix->server_fd = -1;
419
420         ret = get_tmp_name(dmix->shmptr->socket_name, sizeof(dmix->shmptr->socket_name));
421         if (ret < 0)
422                 return ret;
423         
424         ret = make_local_socket(dmix->shmptr->socket_name, 1, dmix->ipc_perm, dmix->ipc_gid);
425         if (ret < 0)
426                 return ret;
427         dmix->server_fd = ret;
428
429         ret = listen(dmix->server_fd, 4);
430         if (ret < 0) {
431                 close(dmix->server_fd);
432                 return ret;
433         }
434         
435         ret = fork();
436         if (ret < 0) {
437                 close(dmix->server_fd);
438                 return ret;
439         } else if (ret == 0) {
440                 ret = fork();
441                 if (ret == 0)
442                         server_job(dmix);
443                 _exit(EXIT_SUCCESS);
444         } else {
445                 waitpid(ret, NULL, 0);
446         }
447         dmix->server_pid = ret;
448         dmix->server = 1;
449         return 0;
450 }
451
452 int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix)
453 {
454         if (dmix->server) {
455                 //kill(dmix->server_pid, SIGTERM);
456                 //waitpid(dmix->server_pid, NULL, 0);
457                 dmix->server_pid = (pid_t)-1;
458         }
459         if (dmix->server_fd > 0) {
460                 close(dmix->server_fd);
461                 dmix->server_fd = -1;
462         }
463         dmix->server = 0;
464         return 0;
465 }
466
467 /*
468  *  client side
469  */
470
471 int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix)
472 {
473         int ret;
474         unsigned char buf;
475
476         ret = make_local_socket(dmix->shmptr->socket_name, 0, -1, -1);
477         if (ret < 0)
478                 return ret;
479         dmix->comm_fd = ret;
480
481         ret = snd_receive_fd(dmix->comm_fd, &buf, 1, &dmix->hw_fd);
482         if (ret < 1 || buf != 'A') {
483                 close(dmix->comm_fd);
484                 dmix->comm_fd = -1;
485                 return ret;
486         }
487
488         dmix->client = 1;
489         return 0;
490 }
491
492 int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix)
493 {
494         if (dmix->client) {
495                 close(dmix->comm_fd);
496                 dmix->comm_fd = -1;
497         }
498         return 0;
499 }
500
501 /*
502  *  plugin helpers
503  */
504
505 int snd_pcm_direct_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
506 {
507         /* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */
508         return 0;
509 }
510
511 int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid)
512 {
513         snd_pcm_direct_t *dmix = pcm->private_data;
514         return snd_timer_async(dmix->timer, sig, pid);
515 }
516
517 /* empty the timer read queue */
518 void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
519 {
520         if (dmix->timer_need_poll) {
521                 while (poll(&dmix->timer_fd, 1, 0) > 0) {
522                         /* we don't need the value */
523                         if (dmix->tread) {
524                                 snd_timer_tread_t rbuf[4];
525                                 snd_timer_read(dmix->timer, rbuf, sizeof(rbuf));
526                         } else {
527                                 snd_timer_read_t rbuf;
528                                 snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf));
529                         }
530                 }
531         } else {
532                 if (dmix->tread) {
533                         snd_timer_tread_t rbuf[4];
534                         int len;
535                         while ((len = snd_timer_read(dmix->timer, rbuf,
536                                                      sizeof(rbuf))) > 0 &&
537                                len != sizeof(rbuf[0]))
538                                 ;
539                 } else {
540                         snd_timer_read_t rbuf;
541                         while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0)
542                                 ;
543                 }
544         }
545 }
546
547 int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix)
548 {
549         snd_timer_stop(dmix->timer);
550         return 0;
551 }
552
553 /*
554  * Recover slave on XRUN.
555  * Even if direct plugins disable xrun detection, there might be an xrun
556  * raised directly by some drivers.
557  * The first client recovers slave pcm.
558  * Each client needs to execute sw xrun handling afterwards
559  */
560 int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct)
561 {
562         int ret;
563         int semerr;
564
565         semerr = snd_pcm_direct_semaphore_down(direct,
566                                                    DIRECT_IPC_SEM_CLIENT);
567         if (semerr < 0) {
568                 SNDERR("SEMDOWN FAILED with err %d", semerr);
569                 return semerr;
570         }
571
572         if (snd_pcm_state(direct->spcm) != SND_PCM_STATE_XRUN) {
573                 /* ignore... someone else already did recovery */
574                 semerr = snd_pcm_direct_semaphore_up(direct,
575                                                      DIRECT_IPC_SEM_CLIENT);
576                 if (semerr < 0) {
577                         SNDERR("SEMUP FAILED with err %d", semerr);
578                         return semerr;
579                 }
580                 return 0;
581         }
582
583         ret = snd_pcm_prepare(direct->spcm);
584         if (ret < 0) {
585                 SNDERR("recover: unable to prepare slave");
586                 semerr = snd_pcm_direct_semaphore_up(direct,
587                                                      DIRECT_IPC_SEM_CLIENT);
588                 if (semerr < 0) {
589                         SNDERR("SEMUP FAILED with err %d", semerr);
590                         return semerr;
591                 }
592                 return ret;
593         }
594
595         if (direct->type == SND_PCM_TYPE_DSHARE) {
596                 const snd_pcm_channel_area_t *dst_areas;
597                 dst_areas = snd_pcm_mmap_areas(direct->spcm);
598                 snd_pcm_areas_silence(dst_areas, 0, direct->spcm->channels,
599                                       direct->spcm->buffer_size,
600                                       direct->spcm->format);
601         }
602
603         ret = snd_pcm_start(direct->spcm);
604         if (ret < 0) {
605                 SNDERR("recover: unable to start slave");
606                 semerr = snd_pcm_direct_semaphore_up(direct,
607                                                      DIRECT_IPC_SEM_CLIENT);
608                 if (semerr < 0) {
609                         SNDERR("SEMUP FAILED with err %d", semerr);
610                         return semerr;
611                 }
612                 return ret;
613         }
614         direct->shmptr->recoveries++;
615         semerr = snd_pcm_direct_semaphore_up(direct,
616                                                  DIRECT_IPC_SEM_CLIENT);
617         if (semerr < 0) {
618                 SNDERR("SEMUP FAILED with err %d", semerr);
619                 return semerr;
620         }
621         return 0;
622 }
623
624 /*
625  * enter xrun state, if slave xrun occurred
626  * @return: 0 - no xrun >0: xrun happened
627  */
628 int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm)
629 {
630         if (direct->shmptr->recoveries != direct->recoveries) {
631                 /* no matter how many xruns we missed -
632                  * so don't increment but just update to actual counter
633                  */
634                 direct->recoveries = direct->shmptr->recoveries;
635                 pcm->fast_ops->drop(pcm);
636                 /* trigger_tstamp update is missing in drop callbacks */
637                 gettimestamp(&direct->trigger_tstamp, pcm->tstamp_type);
638                 /* no timer clear:
639                  * if slave already entered xrun again the event is lost.
640                  * snd_pcm_direct_clear_timer_queue(direct);
641                  */
642                 direct->state = SND_PCM_STATE_XRUN;
643                 return 1;
644         }
645         return 0;
646 }
647
648 /*
649  * This is the only operation guaranteed to be called before entering poll().
650  * Direct plugins use fd of snd_timer to poll on, these timers do NOT check
651  * state of substream in kernel by intention.
652  * Only the enter to xrun might be notified once (SND_TIMER_EVENT_MSTOP).
653  * If xrun event was not correctly handled or was ignored it will never be
654  * evaluated again afterwards.
655  * This will result in snd_pcm_wait() always returning timeout.
656  * In contrast poll() on pcm hardware checks ALSA state and will immediately
657  * return POLLERR on XRUN.
658  *
659  * To prevent timeout and applications endlessly spinning without xrun
660  * detected we add a state check here which may trigger the xrun sequence.
661  *
662  * return count of filled descriptors or negative error code
663  */
664 int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
665                                     unsigned int space)
666 {
667         if (pcm->poll_fd < 0) {
668                 SNDMSG("poll_fd < 0");
669                 return -EIO;
670         }
671         if (space >= 1 && pfds) {
672                 pfds->fd = pcm->poll_fd;
673                 pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
674         } else {
675                 return 0;
676         }
677
678         /* this will also evaluate slave state and enter xrun if necessary */
679         switch (snd_pcm_state(pcm)) {
680         case SND_PCM_STATE_XRUN:
681                 return -EPIPE;
682         default:
683                 break;
684         }
685         return 1;
686 }
687
688 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
689 {
690         snd_pcm_direct_t *dmix = pcm->private_data;
691         unsigned short events;
692         int empty = 0;
693
694         assert(pfds && nfds == 1 && revents);
695         events = pfds[0].revents;
696         if (events & POLLIN) {
697                 snd_pcm_uframes_t avail;
698                 __snd_pcm_avail_update(pcm);
699                 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
700                         events |= POLLOUT;
701                         events &= ~POLLIN;
702                         avail = snd_pcm_mmap_playback_avail(pcm);
703                 } else {
704                         avail = snd_pcm_mmap_capture_avail(pcm);
705                 }
706                 empty = avail < pcm->avail_min;
707         }
708         switch (snd_pcm_state(dmix->spcm)) {
709         case SND_PCM_STATE_XRUN:
710                 /* recover slave and update client state to xrun
711                  * before returning POLLERR
712                  */
713                 snd_pcm_direct_slave_recover(dmix);
714                 snd_pcm_direct_client_chk_xrun(dmix, pcm);
715                 /* fallthrough */
716         case SND_PCM_STATE_SUSPENDED:
717         case SND_PCM_STATE_SETUP:
718                 events |= POLLERR;
719                 break;
720         default:
721                 if (empty) {
722                         snd_pcm_direct_clear_timer_queue(dmix);
723                         events &= ~(POLLOUT|POLLIN);
724                         /* additional check */
725                         switch (__snd_pcm_state(pcm)) {
726                         case SND_PCM_STATE_XRUN:
727                         case SND_PCM_STATE_SUSPENDED:
728                         case SND_PCM_STATE_SETUP:
729                                 events |= POLLERR;
730                                 break;
731                         default:
732                                 break;
733                         }
734                 }
735                 break;
736         }
737         *revents = events;
738         return 0;
739 }
740
741 int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
742 {
743         snd_pcm_direct_t *dmix = pcm->private_data;
744
745         if (dmix->spcm && !dmix->shmptr->use_server)
746                 return snd_pcm_info(dmix->spcm, info);
747
748         memset(info, 0, sizeof(*info));
749         info->stream = pcm->stream;
750         info->card = -1;
751         /* FIXME: fill this with something more useful: we know the hardware name */
752         if (pcm->name) {
753                 strncpy((char *)info->id, pcm->name, sizeof(info->id));
754                 strncpy((char *)info->name, pcm->name, sizeof(info->name));
755                 strncpy((char *)info->subname, pcm->name, sizeof(info->subname));
756         }
757         info->subdevices_count = 1;
758         return 0;
759 }
760
761 static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params,
762                                         snd_pcm_hw_param_t var)
763 {
764         return &params->masks[var - SND_PCM_HW_PARAM_FIRST_MASK];
765 }
766
767 static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params,
768                                                 snd_pcm_hw_param_t var)
769 {
770         return &params->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL];
771 }
772
773 static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params,
774                                         snd_pcm_hw_param_t var,
775                                         snd_interval_t *src)
776 {
777         snd_interval_t *i;
778
779         if (!(params->rmask & (1<<var)))        /* nothing to do? */
780                 return 0;
781         i = hw_param_interval(params, var);
782         if (snd_interval_empty(i)) {
783                 SNDERR("dshare interval %i empty?", (int)var);
784                 return -EINVAL;
785         }
786         if (snd_interval_refine(i, src))
787                 params->cmask |= 1<<var;
788         return 0;
789 }
790
791 static int hw_param_interval_refine_minmax(snd_pcm_hw_params_t *params,
792                                            snd_pcm_hw_param_t var,
793                                            unsigned int imin,
794                                            unsigned int imax)
795 {
796         snd_interval_t t;
797
798         memset(&t, 0, sizeof(t));
799         snd_interval_set_minmax(&t, imin, imax);
800         t.integer = 1;
801         return hw_param_interval_refine_one(params, var, &t);
802 }
803
804 /* this code is used 'as-is' from the alsa kernel code */
805 static int snd_interval_step(struct snd_interval *i, unsigned int min,
806                              unsigned int step)
807 {
808         unsigned int n;
809         int changed = 0;
810         n = (i->min - min) % step;
811         if (n != 0 || i->openmin) {
812                 i->min += step - n;
813                 changed = 1;
814         }
815         n = (i->max - min) % step;
816         if (n != 0 || i->openmax) {
817                 i->max -= n;
818                 changed = 1;
819         }
820         if (snd_interval_checkempty(i)) {
821                 i->empty = 1;
822                 return -EINVAL;
823         }
824         return changed;
825 }
826
827 #undef REFINE_DEBUG
828
829 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
830 {
831         snd_pcm_direct_t *dshare = pcm->private_data;
832         static const snd_mask_t access = { .bits = { 
833                                         (1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) |
834                                         (1<<SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) |
835                                         (1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
836                                         (1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED),
837                                         0, 0, 0 } };
838         int err;
839
840 #ifdef REFINE_DEBUG
841         snd_output_t *log;
842         snd_output_stdio_attach(&log, stderr, 0);
843         snd_output_puts(log, "DMIX REFINE (begin):\n");
844         snd_pcm_hw_params_dump(params, log);
845 #endif
846         if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) {
847                 if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) {
848                         SNDERR("dshare access mask empty?");
849                         return -EINVAL;
850                 }
851                 if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access))
852                         params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS;
853         }
854         if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) {
855                 if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) {
856                         SNDERR("dshare format mask empty?");
857                         return -EINVAL;
858                 }
859                 if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT),
860                                         dshare->shmptr->hw.format))
861                         params->cmask |= 1<<SND_PCM_HW_PARAM_FORMAT;
862         }
863         //snd_mask_none(hw_param_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
864         if (params->rmask & (1<<SND_PCM_HW_PARAM_CHANNELS)) {
865                 if (snd_interval_empty(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS))) {
866                         SNDERR("dshare channels mask empty?");
867                         return -EINVAL;
868                 }
869                 err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS), dshare->channels);
870                 if (err < 0)
871                         return err;
872         }
873         err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE,
874                                            &dshare->shmptr->hw.rate);
875         if (err < 0)
876                 return err;
877
878         if (dshare->max_periods < 0) {
879                 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE,
880                                                    &dshare->shmptr->hw.period_size);
881                 if (err < 0)
882                         return err;
883                 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME,
884                                                    &dshare->shmptr->hw.period_time);
885                 if (err < 0)
886                         return err;
887                 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE,
888                                                    &dshare->shmptr->hw.buffer_size);
889                 if (err < 0)
890                         return err;
891                 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME,
892                                                    &dshare->shmptr->hw.buffer_time);
893                 if (err < 0)
894                         return err;
895         } else if (params->rmask & ((1<<SND_PCM_HW_PARAM_PERIODS)|
896                                     (1<<SND_PCM_HW_PARAM_BUFFER_BYTES)|
897                                     (1<<SND_PCM_HW_PARAM_BUFFER_SIZE)|
898                                     (1<<SND_PCM_HW_PARAM_BUFFER_TIME)|
899                                     (1<<SND_PCM_HW_PARAM_PERIOD_TIME)|
900                                     (1<<SND_PCM_HW_PARAM_PERIOD_SIZE)|
901                                     (1<<SND_PCM_HW_PARAM_PERIOD_BYTES))) {
902                 snd_interval_t period_size = dshare->shmptr->hw.period_size;
903                 snd_interval_t period_time = dshare->shmptr->hw.period_time;
904                 int changed;
905                 unsigned int max_periods = dshare->max_periods;
906                 if (max_periods < 2)
907                         max_periods = dshare->slave_buffer_size / dshare->slave_period_size;
908
909                 /* make sure buffer size does not exceed slave buffer size */
910                 err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_BUFFER_SIZE,
911                                         2 * dshare->slave_period_size, dshare->slave_buffer_size);
912                 if (err < 0)
913                         return err;
914                 if (dshare->var_periodsize) {
915                         /* more tolerant settings... */
916                         if (dshare->shmptr->hw.buffer_size.max / 2 > period_size.max)
917                                 period_size.max = dshare->shmptr->hw.buffer_size.max / 2;
918                         if (dshare->shmptr->hw.buffer_time.max / 2 > period_time.max)
919                                 period_time.max = dshare->shmptr->hw.buffer_time.max / 2;
920                 }
921
922                 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE,
923                                                    &period_size);
924                 if (err < 0)
925                         return err;
926                 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME,
927                                                    &period_time);
928                 if (err < 0)
929                         return err;
930                 do {
931                         changed = 0;
932                         err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS,
933                                                               2, max_periods);
934                         if (err < 0)
935                                 return err;
936                         changed |= err;
937                         err = snd_pcm_hw_refine_soft(pcm, params);
938                         if (err < 0)
939                                 return err;
940                         changed |= err;
941                         err = snd_interval_step(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE),
942                                                                 0, dshare->slave_period_size);
943                         if (err < 0)
944                                 return err;
945                         changed |= err;
946                         if (err)
947                                 params->rmask |= (1 << SND_PCM_HW_PARAM_PERIOD_SIZE);
948                 } while (changed);
949         }
950         dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max / dshare->slave_period_size;
951         params->info = dshare->shmptr->s.info;
952 #ifdef REFINE_DEBUG
953         snd_output_puts(log, "DMIX REFINE (end):\n");
954         snd_pcm_hw_params_dump(params, log);
955         snd_output_close(log);
956 #endif
957         return 0;
958 }
959
960 int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
961 {
962         snd_pcm_direct_t *dmix = pcm->private_data;
963
964         params->info = dmix->shmptr->s.info;
965         params->rate_num = dmix->shmptr->s.rate;
966         params->rate_den = 1;
967         params->fifo_size = 0;
968         params->msbits = dmix->shmptr->s.msbits;
969         return 0;
970 }
971
972 int snd_pcm_direct_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
973 {
974         /* values are cached in the pcm structure */
975         return 0;
976 }
977
978 int snd_pcm_direct_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
979 {
980         /* values are cached in the pcm structure */
981         return 0;
982 }
983
984 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
985 {
986         return snd_pcm_channel_info_shm(pcm, info, -1);
987 }
988
989 int snd_pcm_direct_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
990 {
991         return 0;
992 }
993         
994 int snd_pcm_direct_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
995 {
996         return 0;
997 }
998
999 snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm)
1000 {
1001         snd_pcm_direct_t *dmix = pcm->private_data;
1002         return snd_pcm_query_chmaps(dmix->spcm);
1003 }
1004
1005 snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm)
1006 {
1007         snd_pcm_direct_t *dmix = pcm->private_data;
1008         return snd_pcm_get_chmap(dmix->spcm);
1009 }
1010
1011 int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
1012 {
1013         snd_pcm_direct_t *dmix = pcm->private_data;
1014         return snd_pcm_set_chmap(dmix->spcm, map);
1015 }
1016
1017 int snd_pcm_direct_prepare(snd_pcm_t *pcm)
1018 {
1019         snd_pcm_direct_t *dmix = pcm->private_data;
1020         int err;
1021
1022         switch (snd_pcm_state(dmix->spcm)) {
1023         case SND_PCM_STATE_SETUP:
1024         case SND_PCM_STATE_XRUN:
1025         case SND_PCM_STATE_SUSPENDED:
1026                 err = snd_pcm_prepare(dmix->spcm);
1027                 if (err < 0)
1028                         return err;
1029                 snd_pcm_start(dmix->spcm);
1030                 break;
1031         case SND_PCM_STATE_OPEN:
1032         case SND_PCM_STATE_DISCONNECTED:
1033                 return -EBADFD;
1034         default:
1035                 break;
1036         }
1037         snd_pcm_direct_check_interleave(dmix, pcm);
1038         dmix->state = SND_PCM_STATE_PREPARED;
1039         dmix->appl_ptr = dmix->last_appl_ptr = 0;
1040         dmix->hw_ptr = 0;
1041         return snd_pcm_direct_set_timer_params(dmix);
1042 }
1043
1044 int snd_pcm_direct_resume(snd_pcm_t *pcm)
1045 {
1046         snd_pcm_direct_t *dmix = pcm->private_data;
1047         snd_pcm_t *spcm = dmix->spcm;
1048
1049         snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1050         /* some buggy drivers require the device resumed before prepared;
1051          * when a device has RESUME flag and is in SUSPENDED state, resume
1052          * here but immediately drop to bring it to a sane active state.
1053          */
1054         if ((spcm->info & SND_PCM_INFO_RESUME) &&
1055             snd_pcm_state(spcm) == SND_PCM_STATE_SUSPENDED) {
1056                 snd_pcm_resume(spcm);
1057                 snd_pcm_drop(spcm);
1058                 snd_pcm_direct_timer_stop(dmix);
1059                 snd_pcm_direct_clear_timer_queue(dmix);
1060                 snd_pcm_areas_silence(snd_pcm_mmap_areas(spcm), 0,
1061                                       spcm->channels, spcm->buffer_size,
1062                                       spcm->format);
1063                 snd_pcm_prepare(spcm);
1064                 snd_pcm_start(spcm);
1065         }
1066         snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1067         return -ENOSYS;
1068 }
1069
1070 #define COPY_SLAVE(field) (dmix->shmptr->s.field = spcm->field)
1071
1072 /* copy the slave setting */
1073 static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
1074 {
1075         spcm->info &= ~SND_PCM_INFO_PAUSE;
1076
1077         COPY_SLAVE(access);
1078         COPY_SLAVE(format);
1079         COPY_SLAVE(subformat);
1080         COPY_SLAVE(channels);
1081         COPY_SLAVE(rate);
1082         COPY_SLAVE(period_size);
1083         COPY_SLAVE(period_time);
1084         COPY_SLAVE(periods);
1085         COPY_SLAVE(tstamp_mode);
1086         COPY_SLAVE(tstamp_type);
1087         COPY_SLAVE(period_step);
1088         COPY_SLAVE(avail_min);
1089         COPY_SLAVE(start_threshold);
1090         COPY_SLAVE(stop_threshold);
1091         COPY_SLAVE(silence_threshold);
1092         COPY_SLAVE(silence_size);
1093         COPY_SLAVE(boundary);
1094         COPY_SLAVE(info);
1095         COPY_SLAVE(msbits);
1096         COPY_SLAVE(rate_num);
1097         COPY_SLAVE(rate_den);
1098         COPY_SLAVE(hw_flags);
1099         COPY_SLAVE(fifo_size);
1100         COPY_SLAVE(buffer_size);
1101         COPY_SLAVE(buffer_time);
1102         COPY_SLAVE(sample_bits);
1103         COPY_SLAVE(frame_bits);
1104
1105         dmix->shmptr->s.info &= ~SND_PCM_INFO_RESUME;
1106 }
1107
1108 #undef COPY_SLAVE
1109
1110 /*
1111  * this function initializes hardware and starts playback operation with
1112  * no stop threshold (it operates all time without xrun checking)
1113  * also, the driver silences the unused ring buffer areas for us
1114  */
1115 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params)
1116 {
1117         snd_pcm_hw_params_t hw_params = {0};
1118         snd_pcm_sw_params_t sw_params = {0};
1119         int ret, buffer_is_not_initialized;
1120         snd_pcm_uframes_t boundary;
1121         struct pollfd fd;
1122         int loops = 10;
1123
1124       __again:
1125         if (loops-- <= 0) {
1126                 SNDERR("unable to find a valid configuration for slave");
1127                 return -EINVAL;
1128         }
1129         ret = snd_pcm_hw_params_any(spcm, &hw_params);
1130         if (ret < 0) {
1131                 SNDERR("snd_pcm_hw_params_any failed");
1132                 return ret;
1133         }
1134         ret = snd_pcm_hw_params_set_access(spcm, &hw_params,
1135                                            SND_PCM_ACCESS_MMAP_INTERLEAVED);
1136         if (ret < 0) {
1137                 ret = snd_pcm_hw_params_set_access(spcm, &hw_params,
1138                                         SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
1139                 if (ret < 0) {
1140                         SNDERR("slave plugin does not support mmap interleaved or mmap noninterleaved access");
1141                         return ret;
1142                 }
1143         }
1144         if (params->format == SND_PCM_FORMAT_UNKNOWN)
1145                 ret = -EINVAL;
1146         else
1147                 ret = snd_pcm_hw_params_set_format(spcm, &hw_params,
1148                                                    params->format);
1149         if (ret < 0) {
1150                 static const snd_pcm_format_t dmix_formats[] = {
1151                         SND_PCM_FORMAT_S32,
1152                         SND_PCM_FORMAT_S32 ^ SND_PCM_FORMAT_S32_LE ^
1153                                                         SND_PCM_FORMAT_S32_BE,
1154                         SND_PCM_FORMAT_S16,
1155                         SND_PCM_FORMAT_S16 ^ SND_PCM_FORMAT_S16_LE ^
1156                                                         SND_PCM_FORMAT_S16_BE,
1157                         SND_PCM_FORMAT_S24_LE,
1158                         SND_PCM_FORMAT_S24_3LE,
1159                         SND_PCM_FORMAT_U8,
1160                 };
1161                 snd_pcm_format_t format;
1162                 unsigned int i;
1163
1164                 for (i = 0; i < ARRAY_SIZE(dmix_formats); ++i) {
1165                         format = dmix_formats[i];
1166                         ret = snd_pcm_hw_params_set_format(spcm, &hw_params,
1167                                                            format);
1168                         if (ret >= 0)
1169                                 break;
1170                 }
1171                 if (ret < 0 && dmix->type != SND_PCM_TYPE_DMIX) {
1172                         /* TODO: try to choose a good format */
1173                         ret = INTERNAL(snd_pcm_hw_params_set_format_first)(spcm,
1174                                                         &hw_params, &format);
1175                 }
1176                 if (ret < 0) {
1177                         SNDERR("requested or auto-format is not available");
1178                         return ret;
1179                 }
1180                 params->format = format;
1181         }
1182         ret = INTERNAL(snd_pcm_hw_params_set_channels_near)(spcm, &hw_params,
1183                                         (unsigned int *)&params->channels);
1184         if (ret < 0) {
1185                 SNDERR("requested count of channels is not available");
1186                 return ret;
1187         }
1188         ret = INTERNAL(snd_pcm_hw_params_set_rate_near)(spcm, &hw_params,
1189                                         (unsigned int *)&params->rate, 0);
1190         if (ret < 0) {
1191                 SNDERR("requested rate is not available");
1192                 return ret;
1193         }
1194
1195         buffer_is_not_initialized = 0;
1196         if (params->buffer_time > 0) {
1197                 ret = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(spcm,
1198                         &hw_params, (unsigned int *)&params->buffer_time, 0);
1199                 if (ret < 0) {
1200                         SNDERR("unable to set buffer time");
1201                         return ret;
1202                 }
1203         } else if (params->buffer_size > 0) {
1204                 ret = INTERNAL(snd_pcm_hw_params_set_buffer_size_near)(spcm,
1205                         &hw_params, (snd_pcm_uframes_t *)&params->buffer_size);
1206                 if (ret < 0) {
1207                         SNDERR("unable to set buffer size");
1208                         return ret;
1209                 }
1210         } else {
1211                 buffer_is_not_initialized = 1;
1212         }
1213
1214         if (params->period_time > 0) {
1215                 ret = INTERNAL(snd_pcm_hw_params_set_period_time_near)(spcm,
1216                         &hw_params, (unsigned int *)&params->period_time, 0);
1217                 if (ret < 0) {
1218                         SNDERR("unable to set period_time");
1219                         return ret;
1220                 }
1221         } else if (params->period_size > 0) {
1222                 ret = INTERNAL(snd_pcm_hw_params_set_period_size_near)(spcm,
1223                         &hw_params, (snd_pcm_uframes_t *)&params->period_size,
1224                         0);
1225                 if (ret < 0) {
1226                         SNDERR("unable to set period_size");
1227                         return ret;
1228                 }
1229         }               
1230         
1231         if (buffer_is_not_initialized && params->periods > 0) {
1232                 unsigned int periods = params->periods;
1233                 ret = INTERNAL(snd_pcm_hw_params_set_periods_near)(spcm,
1234                                         &hw_params, &params->periods, 0);
1235                 if (ret < 0) {
1236                         SNDERR("unable to set requested periods");
1237                         return ret;
1238                 }
1239                 if (params->periods == 1) {
1240                         params->periods = periods;
1241                         if (params->period_time > 0) {
1242                                 params->period_time /= 2;
1243                                 goto __again;
1244                         } else if (params->period_size > 0) {
1245                                 params->period_size /= 2;
1246                                 goto __again;
1247                         }
1248                         SNDERR("unable to use stream with periods == 1");
1249                         return ret;
1250                 }
1251         }
1252         
1253         ret = snd_pcm_hw_params(spcm, &hw_params);
1254         if (ret < 0) {
1255                 SNDERR("unable to install hw params");
1256                 return ret;
1257         }
1258
1259         /* store some hw_params values to shared info */
1260         dmix->shmptr->hw.format =
1261                 snd_mask_value(hw_param_mask(&hw_params,
1262                                              SND_PCM_HW_PARAM_FORMAT));
1263         dmix->shmptr->hw.rate =
1264                 *hw_param_interval(&hw_params, SND_PCM_HW_PARAM_RATE);
1265         dmix->shmptr->hw.buffer_size =
1266                 *hw_param_interval(&hw_params, SND_PCM_HW_PARAM_BUFFER_SIZE);
1267         dmix->shmptr->hw.buffer_time =
1268                 *hw_param_interval(&hw_params, SND_PCM_HW_PARAM_BUFFER_TIME);
1269         dmix->shmptr->hw.period_size =
1270                 *hw_param_interval(&hw_params, SND_PCM_HW_PARAM_PERIOD_SIZE);
1271         dmix->shmptr->hw.period_time =
1272                 *hw_param_interval(&hw_params, SND_PCM_HW_PARAM_PERIOD_TIME);
1273         dmix->shmptr->hw.periods =
1274                 *hw_param_interval(&hw_params, SND_PCM_HW_PARAM_PERIODS);
1275
1276
1277         ret = snd_pcm_sw_params_current(spcm, &sw_params);
1278         if (ret < 0) {
1279                 SNDERR("unable to get current sw_params");
1280                 return ret;
1281         }
1282
1283         ret = snd_pcm_sw_params_get_boundary(&sw_params, &boundary);
1284         if (ret < 0) {
1285                 SNDERR("unable to get boundary");
1286                 return ret;
1287         }
1288         ret = snd_pcm_sw_params_set_stop_threshold(spcm, &sw_params, boundary);
1289         if (ret < 0) {
1290                 SNDERR("unable to set stop threshold");
1291                 return ret;
1292         }
1293
1294         /* set timestamp mode to MMAP
1295          * the slave timestamp is copied appropriately in dsnoop/dmix/dshare
1296          * based on the tstamp_mode of each client
1297          */
1298         ret = snd_pcm_sw_params_set_tstamp_mode(spcm, &sw_params,
1299                                                 SND_PCM_TSTAMP_ENABLE);
1300         if (ret < 0) {
1301                 SNDERR("unable to tstamp mode MMAP");
1302                 return ret;
1303         }
1304
1305         if (dmix->type != SND_PCM_TYPE_DMIX &&
1306             dmix->type != SND_PCM_TYPE_DSHARE)
1307                 goto __skip_silencing;
1308
1309         ret = snd_pcm_sw_params_set_silence_threshold(spcm, &sw_params, 0);
1310         if (ret < 0) {
1311                 SNDERR("unable to set silence threshold");
1312                 return ret;
1313         }
1314         ret = snd_pcm_sw_params_set_silence_size(spcm, &sw_params, boundary);
1315         if (ret < 0) {
1316                 SNDERR("unable to set silence threshold (please upgrade to 0.9.0rc8+ driver)");
1317                 return ret;
1318         }
1319
1320       __skip_silencing:
1321
1322         ret = snd_pcm_sw_params(spcm, &sw_params);
1323         if (ret < 0) {
1324                 SNDERR("unable to install sw params (please upgrade to 0.9.0rc8+ driver)");
1325                 return ret;
1326         }
1327
1328         if (dmix->type == SND_PCM_TYPE_DSHARE) {
1329                 const snd_pcm_channel_area_t *dst_areas;
1330                 dst_areas = snd_pcm_mmap_areas(spcm);
1331                 snd_pcm_areas_silence(dst_areas, 0, spcm->channels,
1332                                       spcm->buffer_size, spcm->format);
1333         }
1334         
1335         ret = snd_pcm_start(spcm);
1336         if (ret < 0) {
1337                 SNDERR("unable to start PCM stream");
1338                 return ret;
1339         }
1340
1341         if (snd_pcm_poll_descriptors_count(spcm) != 1) {
1342                 SNDERR("unable to use hardware pcm with fd more than one!!!");
1343                 return ret;
1344         }
1345         snd_pcm_poll_descriptors(spcm, &fd, 1);
1346         dmix->hw_fd = fd.fd;
1347         
1348         save_slave_setting(dmix, spcm);
1349
1350         /* Currently, we assume that each dmix client has the same
1351          * hw_params setting.
1352          * If the arbitrary hw_parmas is supported in future,
1353          * boundary has to be taken from the slave config but
1354          * recalculated for the native boundary size (for 32bit
1355          * emulation on 64bit arch).
1356          */
1357         dmix->slave_buffer_size = spcm->buffer_size;
1358         dmix->slave_period_size = spcm->period_size;
1359         dmix->slave_boundary = spcm->boundary;
1360
1361         spcm->donot_close = 1;
1362
1363         {
1364                 int ver = 0;
1365                 ioctl(spcm->poll_fd, SNDRV_PCM_IOCTL_PVERSION, &ver);
1366                 if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 8))
1367                         dmix->shmptr->use_server = 1;
1368         }
1369
1370         return 0;
1371 }
1372
1373 /*
1374  * the trick is used here; we cannot use effectively the hardware handle because
1375  * we cannot drive multiple accesses to appl_ptr; so we use slave timer of given
1376  * PCM hardware handle; it's not this easy and cheap?
1377  */
1378 int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
1379 {
1380         int ret;
1381         snd_pcm_info_t info = {0};
1382         char name[128];
1383         int capture = dmix->type == SND_PCM_TYPE_DSNOOP ? 1 : 0;
1384
1385         dmix->tread = 1;
1386         dmix->timer_need_poll = 0;
1387         dmix->timer_ticks = 1;
1388         ret = snd_pcm_info(dmix->spcm, &info);
1389         if (ret < 0) {
1390                 SNDERR("unable to info for slave pcm");
1391                 return ret;
1392         }
1393         sprintf(name, "hw:CLASS=%i,SCLASS=0,CARD=%i,DEV=%i,SUBDEV=%i",
1394                 (int)SND_TIMER_CLASS_PCM,
1395                 snd_pcm_info_get_card(&info),
1396                 snd_pcm_info_get_device(&info),
1397                 snd_pcm_info_get_subdevice(&info) * 2 + capture);
1398         ret = snd_timer_open(&dmix->timer, name,
1399                              SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
1400         if (ret < 0) {
1401                 dmix->tread = 0;
1402                 ret = snd_timer_open(&dmix->timer, name,
1403                                      SND_TIMER_OPEN_NONBLOCK);
1404                 if (ret < 0) {
1405                         SNDERR("unable to open timer '%s'", name);
1406                         return ret;
1407                 }
1408         }
1409
1410         if (snd_timer_poll_descriptors_count(dmix->timer) != 1) {
1411                 SNDERR("unable to use timer '%s' with more than one fd!", name);
1412                 return ret;
1413         }
1414         snd_timer_poll_descriptors(dmix->timer, &dmix->timer_fd, 1);
1415         dmix->poll_fd = dmix->timer_fd.fd;
1416
1417         dmix->timer_events = (1<<SND_TIMER_EVENT_MSUSPEND) |
1418                              (1<<SND_TIMER_EVENT_MRESUME) |
1419                              (1<<SND_TIMER_EVENT_MSTOP) |
1420                              (1<<SND_TIMER_EVENT_STOP);
1421
1422         /*
1423          * Some hacks for older kernel drivers
1424          */
1425         {
1426                 int ver = 0;
1427                 ioctl(dmix->poll_fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
1428                 /* In older versions, check via poll before read() is needed
1429                  * because of the confliction between TIMER_START and
1430                  * FIONBIO ioctls.
1431                  */
1432                 if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
1433                         dmix->timer_need_poll = 1;
1434                 /*
1435                  * In older versions, timer uses pause events instead
1436                  * suspend/resume events.
1437                  */
1438                 if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
1439                         dmix->timer_events &= ~((1<<SND_TIMER_EVENT_MSUSPEND) |
1440                                                 (1<<SND_TIMER_EVENT_MRESUME));
1441                         dmix->timer_events |= (1<<SND_TIMER_EVENT_MPAUSE) |
1442                                               (1<<SND_TIMER_EVENT_MCONTINUE);
1443                 }
1444                 /* In older versions, use SND_TIMER_EVENT_START too.
1445                  */
1446                 if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 6))
1447                         dmix->timer_events |= 1<<SND_TIMER_EVENT_START;
1448         }
1449         return 0;
1450 }
1451
1452 static snd_pcm_uframes_t recalc_boundary_size(unsigned long long bsize, snd_pcm_uframes_t buffer_size)
1453 {
1454         if (bsize > LONG_MAX) {
1455                 bsize = buffer_size;
1456                 while (bsize * 2 <= LONG_MAX - buffer_size)
1457                         bsize *= 2;
1458         }
1459         return (snd_pcm_uframes_t)bsize;
1460 }
1461
1462 #define COPY_SLAVE(field) (spcm->field = dmix->shmptr->s.field)
1463
1464 /* copy the slave setting */
1465 static void copy_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
1466 {
1467         COPY_SLAVE(access);
1468         COPY_SLAVE(format);
1469         COPY_SLAVE(subformat);
1470         COPY_SLAVE(channels);
1471         COPY_SLAVE(rate);
1472         COPY_SLAVE(period_size);
1473         COPY_SLAVE(period_time);
1474         COPY_SLAVE(periods);
1475         COPY_SLAVE(tstamp_mode);
1476         COPY_SLAVE(tstamp_type);
1477         COPY_SLAVE(period_step);
1478         COPY_SLAVE(avail_min);
1479         COPY_SLAVE(start_threshold);
1480         COPY_SLAVE(stop_threshold);
1481         COPY_SLAVE(silence_threshold);
1482         COPY_SLAVE(silence_size);
1483         COPY_SLAVE(boundary);
1484         COPY_SLAVE(info);
1485         COPY_SLAVE(msbits);
1486         COPY_SLAVE(rate_num);
1487         COPY_SLAVE(rate_den);
1488         COPY_SLAVE(hw_flags);
1489         COPY_SLAVE(fifo_size);
1490         COPY_SLAVE(buffer_size);
1491         COPY_SLAVE(buffer_time);
1492         COPY_SLAVE(sample_bits);
1493         COPY_SLAVE(frame_bits);
1494
1495         spcm->info &= ~SND_PCM_INFO_PAUSE;
1496         spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size);
1497 }
1498
1499 #undef COPY_SLAVE
1500
1501
1502 /*
1503  * open a slave PCM as secondary client (dup'ed fd)
1504  */
1505 int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name)
1506 {
1507         int ret;
1508         snd_pcm_t *spcm;
1509
1510         ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0, 0);
1511         if (ret < 0) {
1512                 SNDERR("unable to open hardware");
1513                 return ret;
1514         }
1515                 
1516         spcm = *spcmp;
1517         spcm->donot_close = 1;
1518         spcm->setup = 1;
1519
1520         copy_slave_setting(dmix, spcm);
1521
1522         /* Use the slave setting as SPCM, so far */
1523         dmix->slave_buffer_size = spcm->buffer_size;
1524         dmix->slave_period_size = dmix->shmptr->s.period_size;
1525         dmix->slave_boundary = spcm->boundary;
1526         dmix->recoveries = dmix->shmptr->recoveries;
1527
1528         ret = snd_pcm_mmap(spcm);
1529         if (ret < 0) {
1530                 SNDERR("unable to mmap channels");
1531                 return ret;
1532         }
1533         return 0;
1534 }
1535
1536 /*
1537  * open a slave PCM as secondary client (dup'ed fd)
1538  */
1539 int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix,
1540                                               snd_pcm_t *spcm,
1541                                               struct slave_params *params ATTRIBUTE_UNUSED)
1542 {
1543         int ret;
1544
1545         spcm->donot_close = 1;
1546         spcm->setup = 1;
1547
1548         copy_slave_setting(dmix, spcm);
1549
1550         /* Use the slave setting as SPCM, so far */
1551         dmix->slave_buffer_size = spcm->buffer_size;
1552         dmix->slave_period_size = dmix->shmptr->s.period_size;
1553         dmix->slave_boundary = spcm->boundary;
1554
1555         ret = snd_pcm_mmap(spcm);
1556         if (ret < 0) {
1557                 SNDERR("unable to mmap channels");
1558                 return ret;
1559         }
1560         return 0;
1561 }
1562
1563 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
1564 {
1565         snd_timer_params_t params = {0};
1566         unsigned int filter;
1567         int ret;
1568
1569         snd_timer_params_set_auto_start(&params, 1);
1570         if (dmix->type != SND_PCM_TYPE_DSNOOP)
1571                 snd_timer_params_set_early_event(&params, 1);
1572         snd_timer_params_set_ticks(&params, dmix->timer_ticks);
1573         if (dmix->tread) {
1574                 filter = (1<<SND_TIMER_EVENT_TICK) |
1575                          dmix->timer_events;
1576                 snd_timer_params_set_filter(&params, filter);
1577         }
1578         ret = snd_timer_params(dmix->timer, &params);
1579         if (ret < 0) {
1580                 SNDERR("unable to set timer parameters");
1581                 return ret;
1582         }
1583         return 0;
1584 }
1585
1586 /*
1587  *  ring buffer operation
1588  */
1589 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm)
1590 {
1591         unsigned int chn, channels;
1592         int bits, interleaved = 1;
1593         const snd_pcm_channel_area_t *dst_areas;
1594         const snd_pcm_channel_area_t *src_areas;
1595
1596         bits = snd_pcm_format_physical_width(pcm->format);
1597         if ((bits % 8) != 0)
1598                 interleaved = 0;
1599         channels = dmix->channels;
1600         dst_areas = snd_pcm_mmap_areas(dmix->spcm);
1601         src_areas = snd_pcm_mmap_areas(pcm);
1602         for (chn = 1; chn < channels; chn++) {
1603                 if (dst_areas[chn-1].addr != dst_areas[chn].addr) {
1604                         interleaved = 0;
1605                         break;
1606                 }
1607                 if (src_areas[chn-1].addr != src_areas[chn].addr) {
1608                         interleaved = 0;
1609                         break;
1610                 }
1611         }
1612         for (chn = 0; chn < channels; chn++) {
1613                 if (dmix->bindings && dmix->bindings[chn] != chn) {
1614                         interleaved = 0;
1615                         break;
1616                 }
1617                 if (dst_areas[chn].first != chn * bits ||
1618                     dst_areas[chn].step != channels * bits) {
1619                         interleaved = 0;
1620                         break;
1621                 }
1622                 if (src_areas[chn].first != chn * bits ||
1623                     src_areas[chn].step != channels * bits) {
1624                         interleaved = 0;
1625                         break;
1626                 }
1627         }
1628         return dmix->interleaved = interleaved;
1629 }
1630
1631 /*
1632  * parse the channel map
1633  * id == client channel
1634  * value == slave's channel
1635  */
1636 int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
1637                                   struct slave_params *params,
1638                                   snd_config_t *cfg)
1639 {
1640         snd_config_iterator_t i, next;
1641         unsigned int chn, chn1, count = 0;
1642         unsigned int *bindings;
1643         int err;
1644
1645         dmix->channels = UINT_MAX;
1646         if (cfg == NULL)
1647                 return 0;
1648         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1649                 SNDERR("invalid type for bindings");
1650                 return -EINVAL;
1651         }
1652         snd_config_for_each(i, next, cfg) {
1653                 snd_config_t *n = snd_config_iterator_entry(i);
1654                 const char *id;
1655                 long cchannel;
1656                 if (snd_config_get_id(n, &id) < 0)
1657                         continue;
1658                 err = safe_strtol(id, &cchannel);
1659                 if (err < 0 || cchannel < 0) {
1660                         SNDERR("invalid client channel in binding: %s\n", id);
1661                         return -EINVAL;
1662                 }
1663                 if ((unsigned)cchannel >= count)
1664                         count = cchannel + 1;
1665         }
1666         if (count == 0)
1667                 return 0;
1668         if (count > 1024) {
1669                 SNDERR("client channel out of range");
1670                 return -EINVAL;
1671         }
1672         bindings = malloc(count * sizeof(unsigned int));
1673         if (bindings == NULL)
1674                 return -ENOMEM;
1675         for (chn = 0; chn < count; chn++)
1676                 bindings[chn] = UINT_MAX;               /* don't route */
1677         snd_config_for_each(i, next, cfg) {
1678                 snd_config_t *n = snd_config_iterator_entry(i);
1679                 const char *id;
1680                 long cchannel, schannel;
1681                 if (snd_config_get_id(n, &id) < 0)
1682                         continue;
1683                 safe_strtol(id, &cchannel);
1684                 if (snd_config_get_integer(n, &schannel) < 0) {
1685                         SNDERR("unable to get slave channel (should be integer type) in binding: %s\n", id);
1686                         free(bindings);
1687                         return -EINVAL;
1688                 }
1689                 if (schannel < 0 || schannel >= params->channels) {
1690                         SNDERR("invalid slave channel number %ld in binding to %ld",
1691                                schannel, cchannel);
1692                         free(bindings);
1693                         return -EINVAL;
1694                 }
1695                 bindings[cchannel] = schannel;
1696         }
1697         if (dmix->type == SND_PCM_TYPE_DSNOOP ||
1698             ! dmix->bindings)
1699                 goto __skip_same_dst;
1700         for (chn = 0; chn < count; chn++) {
1701                 for (chn1 = 0; chn1 < count; chn1++) {
1702                         if (chn == chn1)
1703                                 continue;
1704                         if (bindings[chn] == dmix->bindings[chn1]) {
1705                                 SNDERR("unable to route channels %d,%d to same destination %d", chn, chn1, bindings[chn]);
1706                                 free(bindings);
1707                                 return -EINVAL;
1708                         }
1709                 }
1710         }
1711       __skip_same_dst:
1712         dmix->bindings = bindings;
1713         dmix->channels = count;
1714         return 0;
1715 }
1716
1717 /*
1718  * parse slave config and calculate the ipc_key offset
1719  */
1720
1721 static int _snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
1722                                                 snd_config_t *sconf,
1723                                                 int direction,
1724                                                 int hop)
1725 {
1726         snd_config_iterator_t i, next;
1727         snd_config_t *pcm_conf, *pcm_conf2;
1728         int err;
1729         long card = 0, device = 0, subdevice = 0;
1730         const char *str;
1731
1732         if (snd_config_get_string(sconf, &str) >= 0) {
1733                 if (hop > SND_CONF_MAX_HOPS) {
1734                         SNDERR("Too many definition levels (looped?)");
1735                         return -EINVAL;
1736                 }
1737                 err = snd_config_search_definition(root, "pcm", str, &pcm_conf);
1738                 if (err < 0) {
1739                         SNDERR("Unknown slave PCM %s", str);
1740                         return err;
1741                 }
1742                 err = _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf,
1743                                                            direction,
1744                                                            hop + 1);
1745                 snd_config_delete(pcm_conf);
1746                 return err;
1747         }
1748
1749 #if 0   /* for debug purposes */
1750         {
1751                 snd_output_t *out;
1752                 snd_output_stdio_attach(&out, stderr, 0);
1753                 snd_config_save(sconf, out);
1754                 snd_output_close(out);
1755         }
1756 #endif
1757
1758         if (snd_config_search(sconf, "slave", &pcm_conf) >= 0) {
1759                 if (snd_config_search(pcm_conf, "pcm", &pcm_conf) >= 0) {
1760                         return _snd_pcm_direct_get_slave_ipc_offset(root,
1761                                                                    pcm_conf,
1762                                                                    direction,
1763                                                                    hop + 1);
1764                 } else {
1765                         if (snd_config_get_string(pcm_conf, &str) >= 0 &&
1766                             snd_config_search_definition(root, "pcm_slave",
1767                                                     str, &pcm_conf) >= 0) {
1768                                 if (snd_config_search(pcm_conf, "pcm",
1769                                                         &pcm_conf2) >= 0) {
1770                                         err =
1771                                          _snd_pcm_direct_get_slave_ipc_offset(
1772                                              root, pcm_conf2, direction, hop + 1);
1773                                         snd_config_delete(pcm_conf);
1774                                         return err;
1775                                 }
1776                                 snd_config_delete(pcm_conf);
1777                         }
1778                 }
1779         }
1780
1781         snd_config_for_each(i, next, sconf) {
1782                 snd_config_t *n = snd_config_iterator_entry(i);
1783                 const char *id, *str;
1784                 if (snd_config_get_id(n, &id) < 0)
1785                         continue;
1786                 if (strcmp(id, "type") == 0) {
1787                         err = snd_config_get_string(n, &str);
1788                         if (err < 0) {
1789                                 SNDERR("Invalid value for PCM type definition\n");
1790                                 return -EINVAL;
1791                         }
1792                         if (strcmp(str, "hw")) {
1793                                 SNDERR("Invalid type '%s' for slave PCM\n", str);
1794                                 return -EINVAL;
1795                         }
1796                         continue;
1797                 }
1798                 if (strcmp(id, "card") == 0) {
1799                         err = snd_config_get_integer(n, &card);
1800                         if (err < 0) {
1801                                 err = snd_config_get_string(n, &str);
1802                                 if (err < 0) {
1803                                         SNDERR("Invalid type for %s", id);
1804                                         return -EINVAL;
1805                                 }
1806                                 card = snd_card_get_index(str);
1807                                 if (card < 0) {
1808                                         SNDERR("Invalid value for %s", id);
1809                                         return card;
1810                                 }
1811                         }
1812                         continue;
1813                 }
1814                 if (strcmp(id, "device") == 0) {
1815                         err = snd_config_get_integer(n, &device);
1816                         if (err < 0) {
1817                                 SNDERR("Invalid type for %s", id);
1818                                 return err;
1819                         }
1820                         continue;
1821                 }
1822                 if (strcmp(id, "subdevice") == 0) {
1823                         err = snd_config_get_integer(n, &subdevice);
1824                         if (err < 0) {
1825                                 SNDERR("Invalid type for %s", id);
1826                                 return err;
1827                         }
1828                         continue;
1829                 }
1830         }
1831         if (card < 0)
1832                 card = 0;
1833         if (device < 0)
1834                 device = 0;
1835         if (subdevice < 0)
1836                 subdevice = 0;
1837         return (direction << 1) + (device << 2) + (subdevice << 8) + (card << 12);
1838 }
1839
1840 static int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
1841                                         snd_config_t *sconf,
1842                                         int direction)
1843 {
1844         return _snd_pcm_direct_get_slave_ipc_offset(root, sconf, direction, 0);
1845 }
1846
1847 int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf,
1848                                    int stream, struct snd_pcm_direct_open_conf *rec)
1849 {
1850         snd_config_iterator_t i, next;
1851         int ipc_key_add_uid = 0;
1852         snd_config_t *n;
1853         int err;
1854
1855         rec->slave = NULL;
1856         rec->bindings = NULL;
1857         rec->ipc_key = 0;
1858         rec->ipc_perm = 0600;
1859         rec->ipc_gid = -1;
1860         rec->slowptr = 1;
1861         rec->max_periods = 0;
1862         rec->var_periodsize = 1;
1863
1864         /* read defaults */
1865         if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) {
1866                 long val;
1867                 err = snd_config_get_integer(n, &val);
1868                 if (err >= 0)
1869                         rec->max_periods = val;
1870         }
1871
1872         snd_config_for_each(i, next, conf) {
1873                 const char *id;
1874                 n = snd_config_iterator_entry(i);
1875                 if (snd_config_get_id(n, &id) < 0)
1876                         continue;
1877                 if (snd_pcm_conf_generic_id(id))
1878                         continue;
1879                 if (strcmp(id, "ipc_key") == 0) {
1880                         long key;
1881                         err = snd_config_get_integer(n, &key);
1882                         if (err < 0) {
1883                                 SNDERR("The field ipc_key must be an integer type");
1884
1885                                 return err;
1886                         }
1887                         rec->ipc_key = key;
1888                         continue;
1889                 }
1890                 if (strcmp(id, "ipc_perm") == 0) {
1891                         long perm;
1892                         err = snd_config_get_integer(n, &perm);
1893                         if (err < 0) {
1894                                 SNDERR("Invalid type for %s", id);
1895                                 return err;
1896                         }
1897                         if ((perm & ~0777) != 0) {
1898                                 SNDERR("The field ipc_perm must be a valid file permission");
1899                                 return -EINVAL;
1900                         }
1901                         rec->ipc_perm = perm;
1902                         continue;
1903                 }
1904                 if (strcmp(id, "ipc_gid") == 0) {
1905                         char *group;
1906                         char *endp;
1907                         err = snd_config_get_ascii(n, &group);
1908                         if (err < 0) {
1909                                 SNDERR("The field ipc_gid must be a valid group");
1910                                 return err;
1911                         }
1912                         if (! *group) {
1913                                 rec->ipc_gid = -1;
1914                                 free(group);
1915                                 continue;
1916                         }
1917                         if (isdigit(*group) == 0) {
1918                                 long clen = sysconf(_SC_GETGR_R_SIZE_MAX);
1919                                 size_t len = (clen == -1) ? 1024 : (size_t)clen;
1920                                 struct group grp, *pgrp;
1921                                 char *buffer = (char *)malloc(len);
1922                                 if (buffer == NULL)
1923                                         return -ENOMEM;
1924                                 int st = getgrnam_r(group, &grp, buffer, len, &pgrp);
1925                                 if (st != 0 || !pgrp) {
1926                                         SNDERR("The field ipc_gid must be a valid group (create group %s)", group);
1927                                         free(buffer);
1928                                         return -EINVAL;
1929                                 }
1930                                 rec->ipc_gid = pgrp->gr_gid;
1931                                 free(buffer);
1932                         } else {
1933                                 rec->ipc_gid = strtol(group, &endp, 10);
1934                         }
1935                         free(group);
1936                         continue;
1937                 }
1938                 if (strcmp(id, "ipc_key_add_uid") == 0) {
1939                         if ((err = snd_config_get_bool(n)) < 0) {
1940                                 SNDERR("The field ipc_key_add_uid must be a boolean type");
1941                                 return err;
1942                         }
1943                         ipc_key_add_uid = err;
1944                         continue;
1945                 }
1946                 if (strcmp(id, "slave") == 0) {
1947                         rec->slave = n;
1948                         continue;
1949                 }
1950                 if (strcmp(id, "bindings") == 0) {
1951                         rec->bindings = n;
1952                         continue;
1953                 }
1954                 if (strcmp(id, "slowptr") == 0) {
1955                         err = snd_config_get_bool(n);
1956                         if (err < 0)
1957                                 return err;
1958                         rec->slowptr = err;
1959                         continue;
1960                 }
1961                 if (strcmp(id, "max_periods") == 0) {
1962                         long val;
1963                         err = snd_config_get_integer(n, &val);
1964                         if (err < 0)
1965                                 return err;
1966                         rec->max_periods = val;
1967                         continue;
1968                 }
1969                 if (strcmp(id, "var_periodsize") == 0) {
1970                         err = snd_config_get_bool(n);
1971                         if (err < 0)
1972                                 return err;
1973                         rec->var_periodsize = err;
1974                         continue;
1975                 }
1976                 SNDERR("Unknown field %s", id);
1977                 return -EINVAL;
1978         }
1979         if (!rec->slave) {
1980                 SNDERR("slave is not defined");
1981                 return -EINVAL;
1982         }
1983         if (!rec->ipc_key) {
1984                 SNDERR("Unique IPC key is not defined");
1985                 return -EINVAL;
1986         }
1987         if (ipc_key_add_uid)
1988                 rec->ipc_key += getuid();
1989         err = snd_pcm_direct_get_slave_ipc_offset(root, conf, stream);
1990         if (err < 0)
1991                 return err;
1992         rec->ipc_key += err;
1993
1994         return 0;
1995 }