OSDN Git Service

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