]> git.alsa-project.org Git - alsa-lib.git/blob - src/pcm/pcm_hw.c
833cad027507af20f8b2c5c3c5370a0b90fadc7e
[alsa-lib.git] / src / pcm / pcm_hw.c
1 /**
2  * \file pcm/pcm_hw.c
3  * \ingroup PCM_Plugins
4  * \brief PCM HW Plugin Interface
5  * \author Abramo Bagnara <abramo@alsa-project.org>
6  * \author Jaroslav Kysela <perex@perex.cz>
7  * \date 2000-2001
8  */
9 /*
10  *  PCM - Hardware
11  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
12  *
13  *
14  *   This library is free software; you can redistribute it and/or modify
15  *   it under the terms of the GNU Lesser General Public License as
16  *   published by the Free Software Foundation; either version 2.1 of
17  *   the License, or (at your option) any later version.
18  *
19  *   This program is distributed in the hope that it will be useful,
20  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *   GNU Lesser General Public License for more details.
23  *
24  *   You should have received a copy of the GNU Lesser General Public
25  *   License along with this library; if not, write to the Free Software
26  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27  *
28  */
29   
30 #include "pcm_local.h"
31 #include "../control/control_local.h"
32 #include "../timer/timer_local.h"
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36 #include <unistd.h>
37 #include <stdbool.h>
38 #include <signal.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <sys/ioctl.h>
42 #include <sys/mman.h>
43
44 //#define DEBUG_RW              /* use to debug readi/writei/readn/writen */
45 //#define DEBUG_MMAP            /* debug mmap_commit */
46
47 #ifndef PIC
48 /* entry for static linking */
49 const char *_snd_module_pcm_hw = "";
50 #endif
51
52 #ifndef DOC_HIDDEN
53
54 #ifndef F_SETSIG
55 #define F_SETSIG 10
56 #endif
57
58 /*
59  *  Compatibility
60  */
61
62 struct sndrv_pcm_hw_params_old {
63         unsigned int flags;
64         unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
65                            SNDRV_PCM_HW_PARAM_ACCESS + 1];
66         struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
67                                         SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
68         unsigned int rmask;
69         unsigned int cmask;
70         unsigned int info;
71         unsigned int msbits;
72         unsigned int rate_num;
73         unsigned int rate_den;
74         sndrv_pcm_uframes_t fifo_size;
75         unsigned char reserved[64];
76 };
77
78 #define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
79 #define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
80
81 static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
82 static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm);
83 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops;
84 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer;
85
86 /*
87  *
88  */
89
90 typedef struct {
91         int version;
92         int fd;
93         int card, device, subdevice;
94
95         volatile struct snd_pcm_mmap_status * mmap_status;
96         struct snd_pcm_mmap_control *mmap_control;
97         bool mmap_status_fallbacked;
98         bool mmap_control_fallbacked;
99         struct snd_pcm_sync_ptr *sync_ptr;
100
101         bool prepare_reset_sw_params;
102         bool perfect_drain;
103
104         int period_event;
105         snd_timer_t *period_timer;
106         struct pollfd period_timer_pfd;
107         int period_timer_need_poll;
108         /* restricted parameters */
109         snd_pcm_format_t format;
110         struct {
111                 int min;
112                 int max;
113         } rates;
114         int channels;
115         int drain_silence;
116         /* for chmap */
117         unsigned int chmap_caps;
118         snd_pcm_chmap_query_t **chmap_override;
119 } snd_pcm_hw_t;
120
121 #define SNDRV_FILE_PCM_STREAM_PLAYBACK          ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
122 #define SNDRV_FILE_PCM_STREAM_CAPTURE           ALSA_DEVICE_DIRECTORY "pcmC%iD%ic"
123 #define SNDRV_PCM_VERSION_MAX                   SNDRV_PROTOCOL_VERSION(2, 0, 9)
124
125 /* update appl_ptr with driver */
126 #define FAST_PCM_STATE(hw) \
127         ((snd_pcm_state_t) (hw)->mmap_status->state)
128 #define FAST_PCM_TSTAMP(hw) \
129         ((hw)->mmap_status->tstamp)
130
131 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm)
132 {
133         struct timespec res;
134         snd_pcm_hw_t *hw = pcm->private_data;
135         res = FAST_PCM_TSTAMP(hw);
136         if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version)
137                 res.tv_nsec *= 1000L;
138         return res;
139 }
140 #endif /* DOC_HIDDEN */
141
142 static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags)
143 {
144         int err;
145         hw->sync_ptr->flags = flags;
146         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) {
147                 err = -errno;
148                 SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err);
149                 return err;
150         }
151         return 0;
152 }
153
154 static int issue_avail_min(snd_pcm_hw_t *hw)
155 {
156         if (!hw->mmap_control_fallbacked)
157                 return 0;
158
159         /* Avoid unexpected change of applptr in kernel space. */
160         return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_APPL);
161 }
162
163 static int issue_applptr(snd_pcm_hw_t *hw)
164 {
165         if (!hw->mmap_control_fallbacked)
166                 return 0;
167
168         /* Avoid unexpected change of avail_min in kernel space. */
169         return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
170 }
171
172 static int request_hwsync(snd_pcm_hw_t *hw)
173 {
174         if (!hw->mmap_status_fallbacked)
175                 return 0;
176
177         /*
178          * Query both of control/status data to avoid unexpected change of
179          * control data in kernel space.
180          */
181         return sync_ptr1(hw,
182                          SNDRV_PCM_SYNC_PTR_HWSYNC |
183                          SNDRV_PCM_SYNC_PTR_APPL |
184                          SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
185 }
186
187 static int query_status_and_control_data(snd_pcm_hw_t *hw)
188 {
189         if (!hw->mmap_control_fallbacked)
190                 return 0;
191
192         /*
193          * Query both of control/status data to avoid unexpected change of
194          * control data in kernel space.
195          */
196         return sync_ptr1(hw,
197                          SNDRV_PCM_SYNC_PTR_APPL |
198                          SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
199 }
200
201 static int query_status_data(snd_pcm_hw_t *hw)
202 {
203         if (!hw->mmap_status_fallbacked)
204                 return 0;
205
206         /*
207          * Query both of control/status data to avoid unexpected change of
208          * control data in kernel space.
209          */
210         return sync_ptr1(hw,
211                          SNDRV_PCM_SYNC_PTR_APPL |
212                          SNDRV_PCM_SYNC_PTR_AVAIL_MIN);
213 }
214
215 static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw)
216 {
217         if (hw->period_timer_need_poll) {
218                 while (poll(&hw->period_timer_pfd, 1, 0) > 0) {
219                         snd_timer_tread_t rbuf[4];
220                         snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
221                 }
222         } else {
223                 snd_timer_tread_t rbuf[4];
224                 snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
225         }
226         return 0;
227 }
228
229 static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
230 {
231         return 2;
232 }
233
234 static int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
235 {
236         snd_pcm_hw_t *hw = pcm->private_data;
237
238         if (space < 2)
239                 return -ENOMEM;
240         pfds[0].fd = hw->fd;
241         pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL;
242         pfds[1].fd = hw->period_timer_pfd.fd;
243         pfds[1].events = POLLIN | POLLERR | POLLNVAL;
244         return 2;
245 }
246
247 static int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents)
248 {
249         snd_pcm_hw_t *hw = pcm->private_data;
250         unsigned int events;
251
252         if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd)
253                 return -EINVAL;
254         events = pfds[0].revents;
255         if (pfds[1].revents & POLLIN) {
256                 snd_pcm_hw_clear_timer_queue(hw);
257                 events |= pcm->poll_events & ~(POLLERR|POLLNVAL);
258         }
259         *revents = events;
260         return 0;
261 }
262
263 static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
264 {
265         long flags;
266         snd_pcm_hw_t *hw = pcm->private_data;
267         int fd = hw->fd, err;
268
269         if ((flags = fcntl(fd, F_GETFL)) < 0) {
270                 err = -errno;
271                 SYSMSG("F_GETFL failed (%i)", err);
272                 return err;
273         }
274         if (nonblock)
275                 flags |= O_NONBLOCK;
276         else
277                 flags &= ~O_NONBLOCK;
278         if (fcntl(fd, F_SETFL, flags) < 0) {
279                 err = -errno;
280                 SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err);
281                 return err;
282         }
283         return 0;
284 }
285
286 static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
287 {
288         long flags;
289         snd_pcm_hw_t *hw = pcm->private_data;
290         int fd = hw->fd, err;
291
292         if ((flags = fcntl(fd, F_GETFL)) < 0) {
293                 err = -errno;
294                 SYSMSG("F_GETFL failed (%i)", err);
295                 return err;
296         }
297         if (sig >= 0)
298                 flags |= O_ASYNC;
299         else
300                 flags &= ~O_ASYNC;
301         if (fcntl(fd, F_SETFL, flags) < 0) {
302                 err = -errno;
303                 SYSMSG("F_SETFL for O_ASYNC failed (%i)", err);
304                 return err;
305         }
306         if (sig < 0)
307                 return 0;
308         if (fcntl(fd, F_SETSIG, (long)sig) < 0) {
309                 err = -errno;
310                 SYSMSG("F_SETSIG failed (%i)", err);
311                 return err;
312         }
313         if (fcntl(fd, F_SETOWN, (long)pid) < 0) {
314                 err = -errno;
315                 SYSMSG("F_SETOWN failed (%i)", err);
316                 return err;
317         }
318         return 0;
319 }
320
321 static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
322 {
323         snd_pcm_hw_t *hw = pcm->private_data;
324         int fd = hw->fd, err;
325         if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) {
326                 err = -errno;
327                 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err);
328                 return err;
329         }
330         /* may be configurable (optional) */
331         if (__snd_pcm_info_eld_fixup_check(info))
332                 return __snd_pcm_info_eld_fixup(info);
333         return 0;
334 }
335
336 static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
337 {
338         /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
339         if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
340                 return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params);
341         return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params);
342 }
343
344 static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
345 {
346         snd_pcm_hw_t *hw = pcm->private_data;
347         int err;
348
349         if (hw->format != SND_PCM_FORMAT_UNKNOWN) {
350                 err = _snd_pcm_hw_params_set_format(params, hw->format);
351                 if (err < 0)
352                         return err;
353         }
354         if (hw->channels > 0) {
355                 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
356                                             hw->channels, 0);
357                 if (err < 0)
358                         return err;
359         }
360         if (hw->rates.min > 0) {
361                 err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE,
362                                                    hw->rates.min, 0, hw->rates.max + 1, -1);
363                 if (err < 0)
364                         return err;
365         }
366
367         if (hw_refine_call(hw, params) < 0) {
368                 err = -errno;
369                 // SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed");
370                 return err;
371         }
372
373         if (params->info != ~0U) {
374                 params->info &= ~0xf0000000;
375                 if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)
376                         params->info |= SND_PCM_INFO_MONOTONIC;
377         }
378         
379         return 0;
380 }
381
382 #define hw_param_mask(params,var) \
383         &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK])
384
385 static int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
386 {
387         int err;
388
389         /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
390         if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
391                 err = ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
392         else
393                 err = use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
394         if (err >= 0 && pcm_hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 17) && params->msbits > 0) {
395                 snd_mask_t *m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
396                 if (snd_mask_single(m)) {
397                         snd_pcm_format_t format = snd_mask_min(m);
398                         int width = snd_pcm_format_width(format);
399                         if (width > 0 && params->msbits > (unsigned int)width)
400                                 params->msbits = width;
401                 }
402         }
403         return err;
404 }
405
406 static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
407 {
408         snd_pcm_hw_t *hw = pcm->private_data;
409         int err;
410         if (hw_params_call(hw, params) < 0) {
411                 err = -errno;
412                 SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err);
413                 return err;
414         }
415         params->info &= ~0xf0000000;
416         if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)
417                 params->info |= SND_PCM_INFO_MONOTONIC;
418         hw->perfect_drain = !!(params->info & SND_PCM_INFO_PERFECT_DRAIN) ||
419                             !!(params->flags & SND_PCM_HW_PARAMS_NO_DRAIN_SILENCE);
420         return query_status_data(hw);
421 }
422
423 static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw)
424 {
425         if (hw->period_timer) {
426                 snd_timer_close(hw->period_timer);
427                 hw->period_timer = NULL;
428         }
429 }
430
431 static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable)
432 {
433         snd_pcm_hw_t *hw = pcm->private_data;
434         snd_timer_params_t params = {0};
435         unsigned int suspend, resume;
436         int err;
437         
438         if (enable) {
439                 err = snd_timer_hw_open(&hw->period_timer,
440                                 "hw-pcm-period-event",
441                                 SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE,
442                                 hw->card, hw->device,
443                                 (hw->subdevice << 1) | (pcm->stream & 1),
444                                 SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
445                 if (err < 0) {
446                         err = snd_timer_hw_open(&hw->period_timer,
447                                 "hw-pcm-period-event",
448                                 SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE,
449                                 hw->card, hw->device,
450                                 (hw->subdevice << 1) | (pcm->stream & 1),
451                                 SND_TIMER_OPEN_NONBLOCK);
452                         return err;
453                 }
454                 if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) {
455                         snd_pcm_hw_close_timer(hw);
456                         return -EINVAL;
457                 }
458                 hw->period_timer_pfd.events = POLLIN;
459                 hw->period_timer_pfd.revents = 0;
460                 snd_timer_poll_descriptors(hw->period_timer,
461                                            &hw->period_timer_pfd, 1);
462                 hw->period_timer_need_poll = 0;
463                 suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
464                 resume = 1<<SND_TIMER_EVENT_MRESUME;
465                 /*
466                  * hacks for older kernel drivers
467                  */
468                 {
469                         int ver = 0;
470                         ioctl(hw->period_timer_pfd.fd,
471                               SNDRV_TIMER_IOCTL_PVERSION, &ver);
472                         /*
473                          * In older versions, check via poll before read() is
474                          * needed because of the confliction between
475                          * TIMER_START and FIONBIO ioctls.
476                          */
477                         if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
478                                 hw->period_timer_need_poll = 1;
479                         /*
480                          * In older versions, timer uses pause events instead
481                          * suspend/resume events.
482                          */
483                         if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
484                                 suspend = 1<<SND_TIMER_EVENT_MPAUSE;
485                                 resume = 1<<SND_TIMER_EVENT_MCONTINUE;
486                         }
487                 }
488                 snd_timer_params_set_auto_start(&params, 1);
489                 snd_timer_params_set_ticks(&params, 1);
490                 INTERNAL(snd_timer_params_set_filter)(&params, (1<<SND_TIMER_EVENT_TICK) |
491                                             suspend | resume);
492                 err = snd_timer_params(hw->period_timer, &params);
493                 if (err < 0) {
494                         snd_pcm_hw_close_timer(hw);
495                         return err;
496                 }
497                 err = snd_timer_start(hw->period_timer);
498                 if (err < 0) {
499                         snd_pcm_hw_close_timer(hw);
500                         return err;
501                 }
502                 pcm->fast_ops = &snd_pcm_hw_fast_ops_timer;
503         } else {
504                 snd_pcm_hw_close_timer(hw);
505                 pcm->fast_ops = &snd_pcm_hw_fast_ops;
506                 hw->period_event = 0;
507         }
508         return 0;
509 }
510
511 static int snd_pcm_hw_hw_free(snd_pcm_t *pcm)
512 {
513         snd_pcm_hw_t *hw = pcm->private_data;
514         int fd = hw->fd, err;
515         snd_pcm_hw_change_timer(pcm, 0);
516         if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) {
517                 err = -errno;
518                 SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed (%i)", err);
519                 return err;
520         }
521         return 0;
522 }
523
524 static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
525 {
526         snd_pcm_hw_t *hw = pcm->private_data;
527         int fd = hw->fd, err = 0;
528         int old_period_event = sw_get_period_event(params);
529         sw_set_period_event(params, 0);
530         if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
531             (snd_pcm_tstamp_type_t) params->tstamp_type == pcm->tstamp_type &&
532             params->period_step == pcm->period_step &&
533             params->start_threshold == pcm->start_threshold &&
534             params->stop_threshold == pcm->stop_threshold &&
535             params->silence_threshold == pcm->silence_threshold &&
536             params->silence_size == pcm->silence_size &&
537             old_period_event == hw->period_event) {
538                 hw->mmap_control->avail_min = params->avail_min;
539                 err = issue_avail_min(hw);
540                 goto out;
541         }
542         if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW &&
543             hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) {
544                 SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW");
545                 err = -EINVAL;
546                 goto out;
547         }
548         if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC &&
549             hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
550                 SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC");
551                 err = -EINVAL;
552                 goto out;
553         }
554         if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) {
555                 err = -errno;
556                 SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
557                 goto out;
558         }
559         hw->prepare_reset_sw_params = false;
560         if ((snd_pcm_tstamp_type_t) params->tstamp_type != pcm->tstamp_type) {
561                 if (hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) {
562                         int on = (snd_pcm_tstamp_type_t) params->tstamp_type ==
563                                 SND_PCM_TSTAMP_TYPE_MONOTONIC;
564                         if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
565                                 err = -errno;
566                                 SNDMSG("TSTAMP failed");
567                                 goto out;
568                         }
569                 }
570                 pcm->tstamp_type = params->tstamp_type;
571         }
572         hw->mmap_control->avail_min = params->avail_min;
573         if (hw->period_event != old_period_event) {
574                 err = snd_pcm_hw_change_timer(pcm, old_period_event);
575                 if (err < 0)
576                         goto out;
577                 hw->period_event = old_period_event;
578         }
579  out:
580         sw_set_period_event(params, old_period_event);
581         return err;
582 }
583
584 static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
585 {
586         snd_pcm_hw_t *hw = pcm->private_data;
587         struct snd_pcm_channel_info i;
588         int fd = hw->fd, err;
589         i.channel = info->channel;
590         if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) {
591                 err = -errno;
592                 SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err);
593                 return err;
594         }
595         info->channel = i.channel;
596         info->addr = 0;
597         info->first = i.first;
598         info->step = i.step;
599         info->type = SND_PCM_AREA_MMAP;
600         info->u.mmap.fd = fd;
601         info->u.mmap.offset = i.offset;
602         return 0;
603 }
604
605 static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
606 {
607         snd_pcm_hw_t *hw = pcm->private_data;
608         int fd = hw->fd, err;
609         if (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) {
610                 if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
611                         err = -errno;
612                         SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
613                         return err;
614                 }
615         } else {
616                 if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) {
617                         err = -errno;
618                         SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT failed (%i)", err);
619                         return err;
620                 }
621         }
622         if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
623                 status->tstamp.tv_nsec *= 1000L;
624                 status->trigger_tstamp.tv_nsec *= 1000L;
625         }
626         return 0;
627 }
628
629 static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm)
630 {
631         snd_pcm_hw_t *hw = pcm->private_data;
632         /* the -ENODEV may come from the snd_disconnect_ioctl() or
633            snd_power_wait() in kernel */
634         if (query_status_data(hw) == -ENODEV)
635                 return SND_PCM_STATE_DISCONNECTED;
636         return (snd_pcm_state_t) hw->mmap_status->state;
637 }
638
639 static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
640 {
641         snd_pcm_hw_t *hw = pcm->private_data;
642         int fd = hw->fd, err;
643         if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
644                 err = -errno;
645                 SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err);
646                 return err;
647         }
648         return 0;
649 }
650
651 static int snd_pcm_hw_hwsync(snd_pcm_t *pcm)
652 {
653         snd_pcm_hw_t *hw = pcm->private_data;
654         int fd = hw->fd, err;
655         if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) {
656                 if (hw->mmap_status_fallbacked) {
657                         err = request_hwsync(hw);
658                         if (err < 0)
659                                 return err;
660                 } else {
661                         if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) {
662                                 err = -errno;
663                                 SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err);
664                                 return err;
665                         }
666                 }
667         } else {
668                 snd_pcm_sframes_t delay;
669                 int err = snd_pcm_hw_delay(pcm, &delay);
670                 if (err < 0) {
671                         switch (FAST_PCM_STATE(hw)) {
672                         case SND_PCM_STATE_PREPARED:
673                         case SND_PCM_STATE_SUSPENDED:
674                                 return 0;
675                         default:
676                                 return err;
677                         }
678                 }
679         }
680         return 0;
681 }
682
683 static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
684 {
685         snd_pcm_hw_t *hw = pcm->private_data;
686         snd_pcm_sw_params_t sw_params;
687         int fd = hw->fd, err;
688
689         if (hw->prepare_reset_sw_params) {
690                 snd_pcm_sw_params_current_no_lock(pcm, &sw_params);
691                 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sw_params) < 0) {
692                         err = -errno;
693                         SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
694                         return err;
695                 }
696                 hw->prepare_reset_sw_params = false;
697         }
698         if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
699                 err = -errno;
700                 SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err);
701                 return err;
702         }
703         return query_status_and_control_data(hw);
704 }
705
706 static int snd_pcm_hw_reset(snd_pcm_t *pcm)
707 {
708         snd_pcm_hw_t *hw = pcm->private_data;
709         int fd = hw->fd, err;
710         if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) {
711                 err = -errno;
712                 SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err);
713                 return err;
714         }
715         return query_status_and_control_data(hw);
716 }
717
718 static int snd_pcm_hw_start(snd_pcm_t *pcm)
719 {
720         snd_pcm_hw_t *hw = pcm->private_data;
721         int err;
722 #if 0
723         assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
724                snd_pcm_mmap_playback_hw_avail(pcm) > 0);
725 #endif
726         issue_applptr(hw);
727         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) {
728                 err = -errno;
729                 SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err);
730 #if 0
731                 if (err == -EBADFD)
732                         SNDERR("PCM state = %s", snd_pcm_state_name(snd_pcm_hw_state(pcm)));
733 #endif
734                 return err;
735         }
736         return 0;
737 }
738
739 static int snd_pcm_hw_drop(snd_pcm_t *pcm)
740 {
741         snd_pcm_hw_t *hw = pcm->private_data;
742         int err;
743         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) {
744                 err = -errno;
745                 SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err);
746                 return err;
747         } else {
748         }
749         return 0;
750 }
751
752 static int snd_pcm_hw_drain(snd_pcm_t *pcm)
753 {
754         snd_pcm_hw_t *hw = pcm->private_data;
755         snd_pcm_sw_params_t sw_params;
756         snd_pcm_uframes_t silence_size;
757         int err;
758
759         if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
760                 goto __skip_silence;
761         /* stream probably in SETUP, prevent divide by zero */
762         if (pcm->period_size == 0)
763                 goto __skip_silence;
764         if (hw->drain_silence == 0 || hw->perfect_drain)
765                 goto __skip_silence;
766         snd_pcm_sw_params_current_no_lock(pcm, &sw_params);
767         if (hw->drain_silence > 0) {
768                 silence_size = (pcm->rate * hw->drain_silence) / 1000;
769                 goto __manual_silence;
770         }
771         /* compute end silence size, align to period size + extra time */
772         if ((pcm->boundary % pcm->period_size) == 0) {
773                 silence_size = pcm->period_size - (*pcm->appl.ptr % pcm->period_size);
774                 if (silence_size == pcm->period_size)
775                         silence_size = 0;
776         } else {
777                 /* it not not easy to compute the period crossing point
778                  * in this case because the period is not aligned to the boundary
779                  * - use the full range (one period) in this case
780                  */
781                 silence_size = pcm->period_size;
782         }
783         silence_size += pcm->rate / 10; /* 1/10th of second */
784 __manual_silence:
785         if (sw_params.silence_size < silence_size) {
786                 /* fill the silence soon as possible (in the bellow ioctl
787                  * or the next period wake up)
788                  */
789                 sw_params.silence_threshold = pcm->buffer_size;
790                 if (silence_size > pcm->buffer_size)
791                         silence_size = pcm->buffer_size;
792                 sw_params.silence_size = silence_size;
793                 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sw_params) < 0) {
794                         err = -errno;
795                         SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
796                         return err;
797                 }
798                 hw->prepare_reset_sw_params = true;
799         }
800 __skip_silence:
801         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) {
802                 err = -errno;
803                 SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err);
804                 return err;
805         }
806         return 0;
807 }
808
809 static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
810 {
811         snd_pcm_hw_t *hw = pcm->private_data;
812         int err;
813         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) {
814                 err = -errno;
815                 SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err);
816                 return err;
817         }
818         return 0;
819 }
820
821 static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm)
822 {
823         return snd_pcm_mmap_hw_rewindable(pcm);
824 }
825
826 static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
827 {
828         snd_pcm_hw_t *hw = pcm->private_data;
829         int err;
830         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) {
831                 err = -errno;
832                 SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err);
833                 return err;
834         }
835         err = query_status_and_control_data(hw);
836         if (err < 0)
837                 return err;
838         return frames;
839 }
840
841 static snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm)
842 {
843         return snd_pcm_mmap_avail(pcm);
844 }
845
846 static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
847 {
848         snd_pcm_hw_t *hw = pcm->private_data;
849         int err;
850         if (SNDRV_PROTOCOL_VERSION(2, 0, 4) <= hw->version) {
851                 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_FORWARD, &frames) < 0) {
852                         err = -errno;
853                         SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err);
854                         return err;
855                 }
856                 err = query_status_and_control_data(hw);
857                 if (err < 0)
858                         return err;
859                 return frames;
860         } else {
861                 snd_pcm_sframes_t avail;
862
863                 switch (FAST_PCM_STATE(hw)) {
864                 case SNDRV_PCM_STATE_RUNNING:
865                 case SNDRV_PCM_STATE_DRAINING:
866                 case SNDRV_PCM_STATE_PAUSED:
867                 case SNDRV_PCM_STATE_PREPARED:
868                         break;
869                 case SNDRV_PCM_STATE_XRUN:
870                         return -EPIPE;
871                 default:
872                         return -EBADFD;
873                 }
874                 avail = snd_pcm_mmap_avail(pcm);
875                 if (avail < 0)
876                         return 0;
877                 if (frames > (snd_pcm_uframes_t)avail)
878                         frames = avail;
879                 snd_pcm_mmap_appl_forward(pcm, frames);
880                 return frames;
881         }
882 }
883
884 static int snd_pcm_hw_resume(snd_pcm_t *pcm)
885 {
886         snd_pcm_hw_t *hw = pcm->private_data;
887         int fd = hw->fd, err;
888         if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) {
889                 err = -errno;
890                 SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err);
891                 return err;
892         }
893         return 0;
894 }
895
896 static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
897 {
898         snd_pcm_hw_t *hw1 = pcm1->private_data;
899         snd_pcm_hw_t *hw2 = pcm2->private_data;
900         if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) {
901                 SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno);
902                 return -errno;
903         }
904         return 0;
905 }
906
907 static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
908 {
909         if (master->type != SND_PCM_TYPE_HW) {
910                 SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type);
911                 return -EINVAL;
912         }
913         return hw_link(master, pcm);
914 }
915
916 static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
917 {
918         if (pcm2->type != SND_PCM_TYPE_HW) {
919                 if (pcm2->fast_ops->link_slaves)
920                         return pcm2->fast_ops->link_slaves(pcm2->fast_op_arg, pcm1);
921                 return -ENOSYS;
922         }
923         return hw_link(pcm1, pcm2);
924  }
925
926 static int snd_pcm_hw_unlink(snd_pcm_t *pcm)
927 {
928         snd_pcm_hw_t *hw = pcm->private_data;
929
930         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_UNLINK) < 0) {
931                 SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno);
932                 return -errno;
933         }
934         return 0;
935 }
936
937 static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
938 {
939         int err;
940         snd_pcm_hw_t *hw = pcm->private_data;
941         int fd = hw->fd;
942         struct snd_xferi xferi;
943         xferi.buf = (char*) buffer;
944         xferi.frames = size;
945         xferi.result = 0; /* make valgrind happy */
946         if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi) < 0)
947                 err = -errno;
948         else
949                 err = query_status_and_control_data(hw);
950 #ifdef DEBUG_RW
951         fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err);
952 #endif
953         if (err < 0)
954                 return snd_pcm_check_error(pcm, err);
955         return xferi.result;
956 }
957
958 static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
959 {
960         int err;
961         snd_pcm_hw_t *hw = pcm->private_data;
962         int fd = hw->fd;
963         struct snd_xfern xfern;
964         memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
965         xfern.bufs = bufs;
966         xfern.frames = size;
967         if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern) < 0)
968                 err = -errno;
969         else
970                 err = query_status_and_control_data(hw);
971 #ifdef DEBUG_RW
972         fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
973 #endif
974         if (err < 0)
975                 return snd_pcm_check_error(pcm, err);
976         return xfern.result;
977 }
978
979 static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
980 {
981         int err;
982         snd_pcm_hw_t *hw = pcm->private_data;
983         int fd = hw->fd;
984         struct snd_xferi xferi;
985         xferi.buf = buffer;
986         xferi.frames = size;
987         xferi.result = 0; /* make valgrind happy */
988         if (ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi) < 0)
989                 err = -errno;
990         else
991                 err = query_status_and_control_data(hw);
992 #ifdef DEBUG_RW
993         fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err);
994 #endif
995         if (err < 0)
996                 return snd_pcm_check_error(pcm, err);
997         return xferi.result;
998 }
999
1000 static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
1001 {
1002         int err;
1003         snd_pcm_hw_t *hw = pcm->private_data;
1004         int fd = hw->fd;
1005         struct snd_xfern xfern;
1006         memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
1007         xfern.bufs = bufs;
1008         xfern.frames = size;
1009         if (ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern) < 0)
1010                 err = -errno;
1011         else
1012                 err = query_status_and_control_data(hw);
1013 #ifdef DEBUG_RW
1014         fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
1015 #endif
1016         if (err < 0)
1017                 return snd_pcm_check_error(pcm, err);
1018         return xfern.result;
1019 }
1020
1021 static bool map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr,
1022                             bool force_fallback)
1023 {
1024         struct snd_pcm_mmap_status *mmap_status;
1025         bool fallbacked;
1026
1027         mmap_status = MAP_FAILED;
1028         if (!force_fallback) {
1029                 mmap_status = mmap(NULL, page_align(sizeof(*mmap_status)),
1030                                    PROT_READ, MAP_FILE|MAP_SHARED,
1031                                    hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
1032         }
1033
1034         if (mmap_status == MAP_FAILED || mmap_status == NULL) {
1035                 mmap_status = &sync_ptr->s.status;
1036                 fallbacked = true;
1037         } else {
1038                 fallbacked = false;
1039         }
1040
1041         hw->mmap_status = mmap_status;
1042
1043         return fallbacked;
1044 }
1045
1046 static bool map_control_data(snd_pcm_hw_t *hw,
1047                              struct snd_pcm_sync_ptr *sync_ptr,
1048                              bool force_fallback)
1049 {
1050         struct snd_pcm_mmap_control *mmap_control;
1051         bool fallbacked;
1052
1053         mmap_control = MAP_FAILED;
1054         if (!force_fallback) {
1055                 mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)),
1056                                     PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
1057                                     hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
1058         }
1059
1060         if (mmap_control == MAP_FAILED || mmap_control == NULL) {
1061                 mmap_control = &sync_ptr->c.control;
1062                 fallbacked = true;
1063         } else {
1064                 fallbacked = false;
1065         }
1066
1067         hw->mmap_control = mmap_control;
1068
1069         return fallbacked;
1070 }
1071
1072 static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback)
1073 {
1074         snd_pcm_hw_t *hw = pcm->private_data;
1075         struct snd_pcm_sync_ptr *sync_ptr;
1076         int err;
1077
1078         /* Preparation for fallback to failure of mmap(2). */
1079         sync_ptr = malloc(sizeof(*sync_ptr));
1080         if (sync_ptr == NULL)
1081                 return -ENOMEM;
1082         memset(sync_ptr, 0, sizeof(*sync_ptr));
1083
1084         hw->mmap_status_fallbacked =
1085                         map_status_data(hw, sync_ptr, force_fallback);
1086         hw->mmap_control_fallbacked =
1087                         map_control_data(hw, sync_ptr, force_fallback);
1088
1089         /* Any fallback mode needs to keep the buffer. */
1090         if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) {
1091                 hw->sync_ptr = sync_ptr;
1092         } else {
1093                 free(sync_ptr);
1094                 hw->sync_ptr = NULL;
1095         }
1096
1097         /* do not initialize in case of append and keep the values from the
1098          * kernel
1099          */
1100         if (!(pcm->mode & SND_PCM_APPEND)) {
1101                 /* Initialize the data. */
1102                 hw->mmap_control->appl_ptr = 0;
1103                 hw->mmap_control->avail_min = 1;
1104         }
1105         snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd,
1106                            SNDRV_PCM_MMAP_OFFSET_STATUS +
1107                                 offsetof(struct snd_pcm_mmap_status, hw_ptr));
1108         snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd,
1109                              SNDRV_PCM_MMAP_OFFSET_CONTROL);
1110         if (hw->mmap_control_fallbacked) {
1111                 unsigned int flags = 0;
1112                 /* read appl_ptr and avail_min from kernel when device opened
1113                  * with SND_PCM_APPEND flag
1114                  */
1115                 if (pcm->mode & SND_PCM_APPEND)
1116                         flags = SNDRV_PCM_SYNC_PTR_APPL |
1117                                 SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
1118                 err = sync_ptr1(hw, flags);
1119                 if (err < 0)
1120                         return err;
1121         }
1122
1123         return 0;
1124 }
1125
1126 static void unmap_status_data(snd_pcm_hw_t *hw)
1127 {
1128         if (!hw->mmap_status_fallbacked) {
1129                 if (munmap((void *)hw->mmap_status,
1130                            page_align(sizeof(*hw->mmap_status))) < 0)
1131                         SYSMSG("status munmap failed (%u)", errno);
1132         }
1133 }
1134
1135 static void unmap_control_data(snd_pcm_hw_t *hw)
1136 {
1137         if (!hw->mmap_control_fallbacked) {
1138                 if (munmap((void *)hw->mmap_control,
1139                            page_align(sizeof(*hw->mmap_control))) < 0)
1140                         SYSMSG("control munmap failed (%u)", errno);
1141         }
1142 }
1143
1144 static void unmap_status_and_control_data(snd_pcm_hw_t *hw)
1145 {
1146         unmap_status_data(hw);
1147         unmap_control_data(hw);
1148
1149         if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked)
1150                 free(hw->sync_ptr);
1151
1152         hw->mmap_status = NULL;
1153         hw->mmap_control = NULL;
1154         hw->mmap_status_fallbacked = false;
1155         hw->mmap_control_fallbacked = false;
1156         hw->sync_ptr = NULL;
1157 }
1158
1159 static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1160 {
1161         return 0;
1162 }
1163
1164 static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
1165 {
1166         return 0;
1167 }
1168
1169 static int snd_pcm_hw_close(snd_pcm_t *pcm)
1170 {
1171         snd_pcm_hw_t *hw = pcm->private_data;
1172         int err = 0;
1173         if (close(hw->fd)) {
1174                 err = -errno;
1175                 SYSMSG("close failed (%i)", err);
1176         }
1177
1178         unmap_status_and_control_data(hw);
1179
1180         free(hw);
1181         return err;
1182 }
1183
1184 static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
1185                                                 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
1186                                                 snd_pcm_uframes_t size)
1187 {
1188         snd_pcm_hw_t *hw = pcm->private_data;
1189
1190         snd_pcm_mmap_appl_forward(pcm, size);
1191         issue_applptr(hw);
1192 #ifdef DEBUG_MMAP
1193         fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size);
1194 #endif
1195         return size;
1196 }
1197
1198 static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
1199 {
1200         snd_pcm_hw_t *hw = pcm->private_data;
1201         snd_pcm_uframes_t avail;
1202
1203         query_status_data(hw);
1204         avail = snd_pcm_mmap_avail(pcm);
1205         switch (FAST_PCM_STATE(hw)) {
1206         case SNDRV_PCM_STATE_RUNNING:
1207                 if (avail >= pcm->stop_threshold) {
1208                         /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */
1209                         if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) {
1210                                 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_XRUN) < 0)
1211                                         return -errno;
1212                         }
1213                         /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */
1214                         return -EPIPE;
1215                 }
1216                 break;
1217         case SNDRV_PCM_STATE_XRUN:
1218                 return -EPIPE;
1219         default:
1220                 break;
1221         }
1222         return avail;
1223 }
1224
1225 static int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
1226                                  snd_htimestamp_t *tstamp)
1227 {
1228         snd_pcm_sframes_t avail1;
1229         int ok = 0;
1230
1231         /* unfortunately, loop is necessary to ensure valid timestamp */
1232         while (1) {
1233                 avail1 = snd_pcm_hw_avail_update(pcm);
1234                 if (avail1 < 0)
1235                         return avail1;
1236                 if (ok && (snd_pcm_uframes_t)avail1 == *avail)
1237                         break;
1238                 *avail = avail1;
1239                 *tstamp = snd_pcm_hw_fast_tstamp(pcm);
1240                 ok = 1;
1241         }
1242         return 0;
1243 }
1244
1245 static void __fill_chmap_ctl_id(snd_ctl_elem_id_t *id, int dev, int subdev,
1246                                 int stream)
1247 {
1248         snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
1249         if (stream == SND_PCM_STREAM_PLAYBACK)
1250                 snd_ctl_elem_id_set_name(id, "Playback Channel Map");
1251         else
1252                 snd_ctl_elem_id_set_name(id, "Capture Channel Map");
1253         snd_ctl_elem_id_set_device(id, dev);
1254         snd_ctl_elem_id_set_index(id, subdev);
1255 }
1256
1257 static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id)
1258 {
1259         snd_pcm_hw_t *hw = pcm->private_data;
1260         __fill_chmap_ctl_id(id, hw->device, hw->subdevice, pcm->stream);
1261 }
1262
1263 static int is_chmap_type(int type)
1264 {
1265         return (type >= SND_CTL_TLVT_CHMAP_FIXED &&
1266                 type <= SND_CTL_TLVT_CHMAP_PAIRED);
1267 }
1268
1269 /**
1270  * \!brief Query the available channel maps
1271  * \param card the card number
1272  * \param dev the PCM device number
1273  * \param subdev the PCM substream index
1274  * \param stream the direction of PCM stream
1275  * \return the NULL-terminated array of integer pointers, or NULL at error.
1276  *
1277  * This function works like snd_pcm_query_chmaps() but it takes the card,
1278  * device, substream and stream numbers instead of the already opened
1279  * snd_pcm_t instance, so that you can query available channel maps of
1280  * a PCM before actually opening it.
1281  *
1282  * As the parameters stand, the query is performed only to the hw PCM
1283  * devices, not the abstracted PCM object in alsa-lib.
1284  */
1285 snd_pcm_chmap_query_t **
1286 snd_pcm_query_chmaps_from_hw(int card, int dev, int subdev,
1287                              snd_pcm_stream_t stream)
1288 {
1289         snd_ctl_t *ctl;
1290         snd_ctl_elem_id_t id = {0};
1291         unsigned int tlv[2048], *start;
1292         unsigned int type;
1293         snd_pcm_chmap_query_t **map;
1294         int i, ret, nums;
1295
1296         ret = snd_ctl_hw_open(&ctl, NULL, card, 0);
1297         if (ret < 0) {
1298                 SYSMSG("Cannot open the associated CTL");
1299                 return NULL;
1300         }
1301
1302         __fill_chmap_ctl_id(&id, dev, subdev, stream);
1303         ret = snd_ctl_elem_tlv_read(ctl, &id, tlv, sizeof(tlv));
1304         snd_ctl_close(ctl);
1305         if (ret < 0) {
1306                 SYSMSG("Cannot read Channel Map TLV");
1307                 return NULL;
1308         }
1309
1310 #if 0
1311         for (i = 0; i < 32; i++)
1312                 fprintf(stderr, "%02x: %08x\n", i, tlv[i]);
1313 #endif
1314         /* FIXME: the parser below assumes that the TLV only contains
1315          * chmap-related blocks
1316          */
1317         type = tlv[SNDRV_CTL_TLVO_TYPE];
1318         if (type != SND_CTL_TLVT_CONTAINER) {
1319                 if (!is_chmap_type(type)) {
1320                         SYSMSG("Invalid TLV type %d", type);
1321                         return NULL;
1322                 }
1323                 start = tlv;
1324                 nums = 1;
1325         } else {
1326                 unsigned int *p;
1327                 int size;
1328                 start = tlv + 2;
1329                 size = tlv[SNDRV_CTL_TLVO_LEN];
1330                 nums = 0;
1331                 for (p = start; size > 0; ) {
1332                         if (!is_chmap_type(p[0])) {
1333                                 SYSMSG("Invalid TLV type %d", p[0]);
1334                                 return NULL;
1335                         }
1336                         nums++;
1337                         size -= p[1] + 8;
1338                         p += p[1] / 4 + 2;
1339                 }
1340         }
1341         map = calloc(nums + 1, sizeof(int *));
1342         if (!map)
1343                 return NULL;
1344         for (i = 0; i < nums; i++) {
1345                 map[i] = malloc(start[1] + 8);
1346                 if (!map[i]) {
1347                         snd_pcm_free_chmaps(map);
1348                         return NULL;
1349                 }
1350                 map[i]->type = start[0] - 0x100;
1351                 map[i]->map.channels = start[1] / 4;
1352                 memcpy(map[i]->map.pos, start + 2, start[1]);
1353                 start += start[1] / 4 + 2;
1354         }
1355         return map;
1356 }
1357
1358 enum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET };
1359
1360 static int chmap_caps(snd_pcm_hw_t *hw, int type)
1361 {
1362         if (hw->chmap_caps & (1 << type))
1363                 return 1;
1364         if (hw->chmap_caps & (1 << (type + 8)))
1365                 return 0;
1366         return 1;
1367 }
1368
1369 static void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type)
1370 {
1371         hw->chmap_caps |= (1 << type);
1372 }
1373
1374 static void chmap_caps_set_error(snd_pcm_hw_t *hw, int type)
1375 {
1376         hw->chmap_caps |= (1 << (type + 8));
1377 }
1378
1379 static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
1380 {
1381         snd_pcm_hw_t *hw = pcm->private_data;
1382         snd_pcm_chmap_query_t **map;
1383
1384         if (hw->chmap_override)
1385                 return _snd_pcm_copy_chmap_query(hw->chmap_override);
1386
1387         if (!chmap_caps(hw, CHMAP_CTL_QUERY))
1388                 return NULL;
1389
1390         map = snd_pcm_query_chmaps_from_hw(hw->card, hw->device,
1391                                            hw->subdevice, pcm->stream);
1392         if (map)
1393                 chmap_caps_set_ok(hw, CHMAP_CTL_QUERY);
1394         else
1395                 chmap_caps_set_error(hw, CHMAP_CTL_QUERY);
1396         return map;
1397 }
1398
1399 static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
1400 {
1401         snd_pcm_hw_t *hw = pcm->private_data;
1402         snd_pcm_chmap_t *map;
1403         snd_ctl_t *ctl;
1404         snd_ctl_elem_id_t id = {0};
1405         snd_ctl_elem_value_t val = {0};
1406         unsigned int i;
1407         int ret;
1408
1409         if (hw->chmap_override)
1410                 return _snd_pcm_choose_fixed_chmap(pcm, hw->chmap_override);
1411
1412         if (!chmap_caps(hw, CHMAP_CTL_GET))
1413                 return NULL;
1414
1415         switch (FAST_PCM_STATE(hw)) {
1416         case SNDRV_PCM_STATE_PREPARED:
1417         case SNDRV_PCM_STATE_RUNNING:
1418         case SNDRV_PCM_STATE_XRUN:
1419         case SNDRV_PCM_STATE_DRAINING:
1420         case SNDRV_PCM_STATE_PAUSED:
1421         case SNDRV_PCM_STATE_SUSPENDED:
1422                 break;
1423         default:
1424                 SYSMSG("Invalid PCM state for chmap_get: %s",
1425                        snd_pcm_state_name(FAST_PCM_STATE(hw)));
1426                 return NULL;
1427         }
1428         map = malloc(pcm->channels * sizeof(map->pos[0]) + sizeof(*map));
1429         if (!map)
1430                 return NULL;
1431         map->channels = pcm->channels;
1432         ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
1433         if (ret < 0) {
1434                 free(map);
1435                 SYSMSG("Cannot open the associated CTL");
1436                 chmap_caps_set_error(hw, CHMAP_CTL_GET);
1437                 return NULL;
1438         }
1439         fill_chmap_ctl_id(pcm, &id);
1440         snd_ctl_elem_value_set_id(&val, &id);
1441         ret = snd_ctl_elem_read(ctl, &val);
1442         snd_ctl_close(ctl);
1443         if (ret < 0) {
1444                 free(map);
1445                 SYSMSG("Cannot read Channel Map ctl");
1446                 chmap_caps_set_error(hw, CHMAP_CTL_GET);
1447                 return NULL;
1448         }
1449         for (i = 0; i < pcm->channels; i++)
1450                 map->pos[i] = snd_ctl_elem_value_get_integer(&val, i);
1451         chmap_caps_set_ok(hw, CHMAP_CTL_GET);
1452         return map;
1453 }
1454
1455 static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
1456 {
1457         snd_pcm_hw_t *hw = pcm->private_data;
1458         snd_ctl_t *ctl;
1459         snd_ctl_elem_id_t id = {0};
1460         snd_ctl_elem_value_t val = {0};
1461         unsigned int i;
1462         int ret;
1463
1464         if (hw->chmap_override)
1465                 return -ENXIO;
1466
1467         if (!chmap_caps(hw, CHMAP_CTL_SET))
1468                 return -ENXIO;
1469
1470         if (map->channels > 128) {
1471                 SYSMSG("Invalid number of channels %d", map->channels);
1472                 return -EINVAL;
1473         }
1474         if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) {
1475                 SYSMSG("Invalid PCM state for chmap_set: %s",
1476                        snd_pcm_state_name(FAST_PCM_STATE(hw)));
1477                 return -EBADFD;
1478         }
1479         ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
1480         if (ret < 0) {
1481                 SYSMSG("Cannot open the associated CTL");
1482                 chmap_caps_set_error(hw, CHMAP_CTL_SET);
1483                 return ret;
1484         }
1485
1486         fill_chmap_ctl_id(pcm, &id);
1487         snd_ctl_elem_value_set_id(&val, &id);
1488         for (i = 0; i < map->channels; i++)
1489                 snd_ctl_elem_value_set_integer(&val, i, map->pos[i]);
1490         ret = snd_ctl_elem_write(ctl, &val);
1491         snd_ctl_close(ctl);
1492         if (ret >= 0)
1493                 chmap_caps_set_ok(hw, CHMAP_CTL_SET);
1494         else if (ret == -ENOENT || ret == -EPERM || ret == -ENXIO) {
1495                 chmap_caps_set_error(hw, CHMAP_CTL_SET);
1496                 ret = -ENXIO;
1497         }
1498         if (ret < 0)
1499                 SYSMSG("Cannot write Channel Map ctl");
1500         return ret;
1501 }
1502
1503 static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out)
1504 {
1505         snd_pcm_hw_t *hw = pcm->private_data;
1506         char *name;
1507         int err = snd_card_get_name(hw->card, &name);
1508         if (err < 0) {
1509                 SNDERR("cannot get card name");
1510                 return;
1511         }
1512         snd_output_printf(out, "Hardware PCM card %d '%s' device %d subdevice %d\n",
1513                           hw->card, name, hw->device, hw->subdevice);
1514         free(name);
1515         if (pcm->setup) {
1516                 snd_output_printf(out, "Its setup is:\n");
1517                 snd_pcm_dump_setup(pcm, out);
1518                 snd_output_printf(out, "  appl_ptr     : %li\n", hw->mmap_control->appl_ptr);
1519                 snd_output_printf(out, "  hw_ptr       : %li\n", hw->mmap_status->hw_ptr);
1520         }
1521 }
1522
1523 static const snd_pcm_ops_t snd_pcm_hw_ops = {
1524         .close = snd_pcm_hw_close,
1525         .info = snd_pcm_hw_info,
1526         .hw_refine = snd_pcm_hw_hw_refine,
1527         .hw_params = snd_pcm_hw_hw_params,
1528         .hw_free = snd_pcm_hw_hw_free,
1529         .sw_params = snd_pcm_hw_sw_params,
1530         .channel_info = snd_pcm_hw_channel_info,
1531         .dump = snd_pcm_hw_dump,
1532         .nonblock = snd_pcm_hw_nonblock,
1533         .async = snd_pcm_hw_async,
1534         .mmap = snd_pcm_hw_mmap,
1535         .munmap = snd_pcm_hw_munmap,
1536         .query_chmaps = snd_pcm_hw_query_chmaps,
1537         .get_chmap = snd_pcm_hw_get_chmap,
1538         .set_chmap = snd_pcm_hw_set_chmap,
1539 };
1540
1541 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
1542         .status = snd_pcm_hw_status,
1543         .state = snd_pcm_hw_state,
1544         .hwsync = snd_pcm_hw_hwsync,
1545         .delay = snd_pcm_hw_delay,
1546         .prepare = snd_pcm_hw_prepare,
1547         .reset = snd_pcm_hw_reset,
1548         .start = snd_pcm_hw_start,
1549         .drop = snd_pcm_hw_drop,
1550         .drain = snd_pcm_hw_drain,
1551         .pause = snd_pcm_hw_pause,
1552         .rewindable = snd_pcm_hw_rewindable,
1553         .rewind = snd_pcm_hw_rewind,
1554         .forwardable = snd_pcm_hw_forwardable,
1555         .forward = snd_pcm_hw_forward,
1556         .resume = snd_pcm_hw_resume,
1557         .link = snd_pcm_hw_link,
1558         .link_slaves = snd_pcm_hw_link_slaves,
1559         .unlink = snd_pcm_hw_unlink,
1560         .writei = snd_pcm_hw_writei,
1561         .writen = snd_pcm_hw_writen,
1562         .readi = snd_pcm_hw_readi,
1563         .readn = snd_pcm_hw_readn,
1564         .avail_update = snd_pcm_hw_avail_update,
1565         .mmap_commit = snd_pcm_hw_mmap_commit,
1566         .htimestamp = snd_pcm_hw_htimestamp,
1567         .poll_descriptors = NULL,
1568         .poll_descriptors_count = NULL,
1569         .poll_revents = NULL,
1570 };
1571
1572 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = {
1573         .status = snd_pcm_hw_status,
1574         .state = snd_pcm_hw_state,
1575         .hwsync = snd_pcm_hw_hwsync,
1576         .delay = snd_pcm_hw_delay,
1577         .prepare = snd_pcm_hw_prepare,
1578         .reset = snd_pcm_hw_reset,
1579         .start = snd_pcm_hw_start,
1580         .drop = snd_pcm_hw_drop,
1581         .drain = snd_pcm_hw_drain,
1582         .pause = snd_pcm_hw_pause,
1583         .rewindable = snd_pcm_hw_rewindable,
1584         .rewind = snd_pcm_hw_rewind,
1585         .forwardable = snd_pcm_hw_forwardable,
1586         .forward = snd_pcm_hw_forward,
1587         .resume = snd_pcm_hw_resume,
1588         .link = snd_pcm_hw_link,
1589         .link_slaves = snd_pcm_hw_link_slaves,
1590         .unlink = snd_pcm_hw_unlink,
1591         .writei = snd_pcm_hw_writei,
1592         .writen = snd_pcm_hw_writen,
1593         .readi = snd_pcm_hw_readi,
1594         .readn = snd_pcm_hw_readn,
1595         .avail_update = snd_pcm_hw_avail_update,
1596         .mmap_commit = snd_pcm_hw_mmap_commit,
1597         .htimestamp = snd_pcm_hw_htimestamp,
1598         .poll_descriptors = snd_pcm_hw_poll_descriptors,
1599         .poll_descriptors_count = snd_pcm_hw_poll_descriptors_count,
1600         .poll_revents = snd_pcm_hw_poll_revents,
1601 };
1602
1603 /**
1604  * \brief Creates a new hw PCM
1605  * \param pcmp Returns created PCM handle
1606  * \param name Name of PCM
1607  * \param fd File descriptor
1608  * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl
1609  * \retval zero on success otherwise a negative error code
1610  * \warning Using of this function might be dangerous in the sense
1611  *          of compatibility reasons. The prototype might be freely
1612  *          changed in future.
1613  */
1614 int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd,
1615                        int sync_ptr_ioctl)
1616 {
1617         int ver, mode;
1618         snd_pcm_tstamp_type_t tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
1619         long fmode;
1620         snd_pcm_t *pcm = NULL;
1621         snd_pcm_hw_t *hw = NULL;
1622         snd_pcm_info_t info;
1623         int ret;
1624
1625         assert(pcmp);
1626
1627         memset(&info, 0, sizeof(info));
1628         if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
1629                 ret = -errno;
1630                 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
1631                 close(fd);
1632                 return ret;
1633
1634         }
1635
1636         if ((fmode = fcntl(fd, F_GETFL)) < 0) {
1637                 ret = -errno;
1638                 close(fd);
1639                 return ret;
1640         }
1641         mode = 0;
1642         if (fmode & O_NONBLOCK)
1643                 mode |= SND_PCM_NONBLOCK;
1644         if (fmode & O_ASYNC)
1645                 mode |= SND_PCM_ASYNC;
1646         if (fmode & O_APPEND)
1647                 mode |= SND_PCM_APPEND;
1648
1649         if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) {
1650                 ret = -errno;
1651                 SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret);
1652                 close(fd);
1653                 return ret;
1654         }
1655         if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX))
1656                 return -SND_ERROR_INCOMPATIBLE_VERSION;
1657
1658         if (SNDRV_PROTOCOL_VERSION(2, 0, 14) <= ver) {
1659                 /* inform the protocol version we're supporting */
1660                 unsigned int user_ver = SNDRV_PCM_VERSION;
1661                 if (ioctl(fd, SNDRV_PCM_IOCTL_USER_PVERSION, &user_ver) < 0) {
1662                         ret = -errno;
1663                         SNDMSG("USER_PVERSION failed");
1664                         return ret;
1665                 }
1666         }
1667
1668 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1669         if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) {
1670                 struct timespec timespec;
1671                 if (clock_gettime(CLOCK_MONOTONIC, &timespec) == 0) {
1672                         if (!(mode & SND_PCM_APPEND)) {
1673                                 int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
1674                                 if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) {
1675                                         ret = -errno;
1676                                         SNDMSG("TTSTAMP failed");
1677                                         return ret;
1678                                 }
1679                         }
1680                         tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
1681                 }
1682         } else
1683 #endif
1684           if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver && !(mode & SND_PCM_APPEND)) {
1685                 int on = 1;
1686                 if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
1687                         ret = -errno;
1688                         SNDMSG("TSTAMP failed");
1689                         return ret;
1690                 }
1691         }
1692         
1693         hw = calloc(1, sizeof(snd_pcm_hw_t));
1694         if (!hw) {
1695                 close(fd);
1696                 return -ENOMEM;
1697         }
1698
1699         hw->version = ver;
1700         hw->card = info.card;
1701         hw->device = info.device;
1702         hw->subdevice = info.subdevice;
1703         hw->fd = fd;
1704         /* no restriction */
1705         hw->format = SND_PCM_FORMAT_UNKNOWN;
1706         hw->rates.min = hw->rates.max = 0;
1707         hw->channels = 0;
1708
1709         ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode);
1710         if (ret < 0) {
1711                 free(hw);
1712                 close(fd);
1713                 return ret;
1714         }
1715
1716         pcm->ops = &snd_pcm_hw_ops;
1717         pcm->fast_ops = &snd_pcm_hw_fast_ops;
1718         pcm->private_data = hw;
1719         pcm->poll_fd = fd;
1720         pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
1721         pcm->tstamp_type = tstamp_type;
1722 #ifdef THREAD_SAFE_API
1723         pcm->need_lock = 0;     /* hw plugin is thread-safe */
1724 #endif
1725         pcm->own_state_check = 1; /* skip the common state check */
1726
1727         ret = map_status_and_control_data(pcm, !!sync_ptr_ioctl);
1728         if (ret < 0) {
1729                 snd_pcm_close(pcm);
1730                 return ret;
1731         }
1732
1733         *pcmp = pcm;
1734         return 0;
1735 }
1736
1737 /**
1738  * \brief Creates a new hw PCM
1739  * \param pcmp Returns created PCM handle
1740  * \param name Name of PCM
1741  * \param card Number of card
1742  * \param device Number of device
1743  * \param subdevice Number of subdevice
1744  * \param stream PCM Stream
1745  * \param mode PCM Mode
1746  * \param mmap_emulation Obsoleted parameter
1747  * \param sync_ptr_ioctl Use SYNC_PTR ioctl rather than mmap for control structures
1748  * \retval zero on success otherwise a negative error code
1749  * \warning Using of this function might be dangerous in the sense
1750  *          of compatibility reasons. The prototype might be freely
1751  *          changed in future.
1752  */
1753 int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
1754                     int card, int device, int subdevice,
1755                     snd_pcm_stream_t stream, int mode,
1756                     int mmap_emulation ATTRIBUTE_UNUSED,
1757                     int sync_ptr_ioctl)
1758 {
1759         char filename[sizeof(SNDRV_FILE_PCM_STREAM_PLAYBACK) + 20];
1760         const char *filefmt;
1761         int ret = 0, fd = -1;
1762         int attempt = 0;
1763         snd_pcm_info_t info;
1764         int fmode;
1765         snd_ctl_t *ctl;
1766
1767         assert(pcmp);
1768
1769         if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0)
1770                 return ret;
1771
1772         switch (stream) {
1773         case SND_PCM_STREAM_PLAYBACK:
1774                 filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK;
1775                 break;
1776         case SND_PCM_STREAM_CAPTURE:
1777                 filefmt = SNDRV_FILE_PCM_STREAM_CAPTURE;
1778                 break;
1779         default:
1780                 SNDERR("invalid stream %d", stream);
1781                 return -EINVAL;
1782         }
1783         sprintf(filename, filefmt, card, device);
1784
1785       __again:
1786         if (attempt++ > 3) {
1787                 ret = -EBUSY;
1788                 goto _err;
1789         }
1790         ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
1791         if (ret < 0)
1792                 goto _err;
1793         fmode = O_RDWR;
1794         if (mode & SND_PCM_NONBLOCK)
1795                 fmode |= O_NONBLOCK;
1796         if (mode & SND_PCM_ASYNC)
1797                 fmode |= O_ASYNC;
1798         if (mode & SND_PCM_APPEND)
1799                 fmode |= O_APPEND;
1800         fd = snd_open_device(filename, fmode);
1801         if (fd < 0) {
1802                 ret = -errno;
1803                 SYSMSG("open '%s' failed (%i)", filename, ret);
1804                 goto _err;
1805         }
1806         if (subdevice >= 0) {
1807                 memset(&info, 0, sizeof(info));
1808                 if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
1809                         ret = -errno;
1810                         SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
1811                         goto _err;
1812                 }
1813                 if (info.subdevice != (unsigned int) subdevice) {
1814                         close(fd);
1815                         fd = -1;
1816                         goto __again;
1817                 }
1818         }
1819         snd_ctl_close(ctl);
1820         return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl);
1821        _err:
1822         if (fd >= 0)
1823                 close(fd);
1824         snd_ctl_close(ctl);
1825         return ret;
1826 }
1827
1828 /*! \page pcm_plugins
1829
1830 \section pcm_plugins_hw Plugin: hw
1831
1832 This plugin communicates directly with the ALSA kernel driver. It is a raw
1833 communication without any conversions. The emulation of mmap access can be
1834 optionally enabled, but expect worse latency in the case.
1835
1836 The nonblock option specifies whether the device is opened in a non-blocking
1837 manner.  Note that the blocking behavior for read/write access won't be
1838 changed by this option.  This influences only on the blocking behavior at
1839 opening the device.  If you would like to keep the compatibility with the
1840 older ALSA stuff, turn this option off.
1841
1842 \code
1843 pcm.name {
1844         type hw                 # Kernel PCM
1845         card INT/STR            # Card name (string) or number (integer)
1846         [device INT]            # Device number (default 0)
1847         [subdevice INT]         # Subdevice number (default -1: first available)
1848         [sync_ptr_ioctl BOOL]   # Use SYNC_PTR ioctl rather than the direct mmap access for control structures
1849         [nonblock BOOL]         # Force non-blocking open mode
1850         [format STR]            # Restrict only to the given format
1851         [channels INT]          # Restrict only to the given channels
1852         [rate INT]              # Restrict only to the given rate
1853           or [rate [INT INT]]   # Restrict only to the given rate range (min max)
1854         [chmap MAP]             # Override channel maps; MAP is a string array
1855         [drain_silence INT]     # Add silence in drain (-1 = auto /default/, 0 = off, > 0 milliseconds)
1856 }
1857 \endcode
1858
1859 \subsection pcm_plugins_hw_funcref Function reference
1860
1861 <UL>
1862   <LI>snd_pcm_hw_open()
1863   <LI>_snd_pcm_hw_open()
1864 </UL>
1865
1866 */
1867
1868 /**
1869  * \brief Creates a new hw PCM
1870  * \param pcmp Returns created PCM handle
1871  * \param name Name of PCM
1872  * \param root Root configuration node
1873  * \param conf Configuration node with hw PCM description
1874  * \param stream PCM Stream
1875  * \param mode PCM Mode
1876  * \warning Using of this function might be dangerous in the sense
1877  *          of compatibility reasons. The prototype might be freely
1878  *          changed in future.
1879  */
1880 int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
1881                      snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
1882                      snd_pcm_stream_t stream, int mode)
1883 {
1884         snd_config_iterator_t i, next;
1885         long card = -1, device = 0, subdevice = -1;
1886         const char *str;
1887         int err, sync_ptr_ioctl = 0;
1888         int min_rate = 0, max_rate = 0, channels = 0, drain_silence = -1;
1889         snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
1890         snd_config_t *n;
1891         int nonblock = 1; /* non-block per default */
1892         snd_pcm_chmap_query_t **chmap = NULL;
1893         snd_pcm_hw_t *hw;
1894
1895         /* look for defaults.pcm.nonblock definition */
1896         if (snd_config_search(root, "defaults.pcm.nonblock", &n) >= 0) {
1897                 err = snd_config_get_bool(n);
1898                 if (err >= 0)
1899                         nonblock = err;
1900         }
1901         snd_config_for_each(i, next, conf) {
1902                 const char *id;
1903                 n = snd_config_iterator_entry(i);
1904                 if (snd_config_get_id(n, &id) < 0)
1905                         continue;
1906                 if (snd_pcm_conf_generic_id(id))
1907                         continue;
1908                 if (strcmp(id, "card") == 0) {
1909                         err = snd_config_get_card(n);
1910                         if (err < 0)
1911                                 goto fail;
1912                         card = err;
1913                         continue;
1914                 }
1915                 if (strcmp(id, "device") == 0) {
1916                         err = snd_config_get_integer(n, &device);
1917                         if (err < 0) {
1918                                 SNDERR("Invalid type for %s", id);
1919                                 goto fail;
1920                         }
1921                         continue;
1922                 }
1923                 if (strcmp(id, "subdevice") == 0) {
1924                         err = snd_config_get_integer(n, &subdevice);
1925                         if (err < 0) {
1926                                 SNDERR("Invalid type for %s", id);
1927                                 goto fail;
1928                         }
1929                         continue;
1930                 }
1931                 if (strcmp(id, "sync_ptr_ioctl") == 0) {
1932                         err = snd_config_get_bool(n);
1933                         if (err < 0)
1934                                 continue;
1935                         sync_ptr_ioctl = err;
1936                         continue;
1937                 }
1938                 if (strcmp(id, "nonblock") == 0) {
1939                         err = snd_config_get_bool(n);
1940                         if (err < 0)
1941                                 continue;
1942                         nonblock = err;
1943                         continue;
1944                 }
1945                 if (strcmp(id, "rate") == 0) {
1946                         long val;
1947                         if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND &&
1948                             snd_config_is_array(n)) {
1949                                 snd_config_t *m;
1950                                 err = snd_config_search(n, "0", &m);
1951                                 if (err < 0) {
1952                                         SNDERR("array expected for rate compound");
1953                                         goto fail;
1954                                 }
1955                                 err = snd_config_get_integer(m, &val);
1956                                 if (err < 0) {
1957                                         SNDERR("Invalid type for rate.0");
1958                                         goto fail;
1959                                 }
1960                                 min_rate = max_rate = val;
1961                                 err = snd_config_search(n, "1", &m);
1962                                 if (err >= 0) {
1963                                         err = snd_config_get_integer(m, &val);
1964                                         if (err < 0) {
1965                                                 SNDERR("Invalid type for rate.0");
1966                                                 goto fail;
1967                                         }
1968                                         max_rate = val;
1969                                 }
1970                         } else {
1971                                 err = snd_config_get_integer(n, &val);
1972                                 if (err < 0) {
1973                                         SNDERR("Invalid type for %s", id);
1974                                         goto fail;
1975                                 }
1976                                 min_rate = max_rate = val;
1977                         }
1978                         continue;
1979                 }
1980                 if (strcmp(id, "min_rate") == 0) {
1981                         long val;
1982                         err = snd_config_get_integer(n, &val);
1983                         if (err < 0) {
1984                                 SNDERR("Invalid type for %s", id);
1985                                 goto fail;
1986                         }
1987                         min_rate = val;
1988                         continue;
1989                 }
1990                 if (strcmp(id, "max_rate") == 0) {
1991                         long val;
1992                         err = snd_config_get_integer(n, &val);
1993                         if (err < 0) {
1994                                 SNDERR("Invalid type for %s", id);
1995                                 goto fail;
1996                         }
1997                         max_rate = val;
1998                         continue;
1999                 }
2000                 if (strcmp(id, "format") == 0) {
2001                         err = snd_config_get_string(n, &str);
2002                         if (err < 0) {
2003                                 SNDERR("invalid type for %s", id);
2004                                 goto fail;
2005                         }
2006                         format = snd_pcm_format_value(str);
2007                         continue;
2008                 }
2009                 if (strcmp(id, "channels") == 0) {
2010                         long val;
2011                         err = snd_config_get_integer(n, &val);
2012                         if (err < 0) {
2013                                 SNDERR("Invalid type for %s", id);
2014                                 goto fail;
2015                         }
2016                         channels = val;
2017                         continue;
2018                 }
2019                 if (strcmp(id, "chmap") == 0) {
2020                         snd_pcm_free_chmaps(chmap);
2021                         chmap = _snd_pcm_parse_config_chmaps(n);
2022                         if (!chmap) {
2023                                 SNDERR("Invalid channel map for %s", id);
2024                                 err = -EINVAL;
2025                                 goto fail;
2026                         }
2027                         continue;
2028                 }
2029                 if (strcmp(id, "drain_silence") == 0) {
2030                         long val;
2031                         err = snd_config_get_integer(n, &val);
2032                         if (err < 0) {
2033                                 SNDERR("Invalid type for %s", id);
2034                                 goto fail;
2035                         }
2036                         drain_silence = val;
2037                         continue;
2038                 }
2039                 SNDERR("Unknown field %s", id);
2040                 err = -EINVAL;
2041                 goto fail;
2042         }
2043         if (card < 0) {
2044                 SNDERR("card is not defined");
2045                 err = -EINVAL;
2046                 goto fail;
2047         }
2048         if ((min_rate < 0) || (max_rate < min_rate)) {
2049                 SNDERR("min_rate - max_rate configuration invalid");
2050                 err = -EINVAL;
2051                 goto fail;
2052         }
2053         err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
2054                               mode | (nonblock ? SND_PCM_NONBLOCK : 0),
2055                               0, sync_ptr_ioctl);
2056         if (err < 0)
2057                 goto fail;
2058         if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
2059                 /* revert to blocking mode for read/write access */
2060                 snd_pcm_hw_nonblock(*pcmp, 0);
2061                 (*pcmp)->mode = mode;
2062         } else
2063                 /* make sure the SND_PCM_NO_xxx flags don't get lost on the
2064                  * way */
2065                 (*pcmp)->mode |= mode & (SND_PCM_NO_AUTO_RESAMPLE|
2066                                          SND_PCM_NO_AUTO_CHANNELS|
2067                                          SND_PCM_NO_AUTO_FORMAT|
2068                                          SND_PCM_NO_SOFTVOL);
2069
2070         hw = (*pcmp)->private_data;
2071         if (format != SND_PCM_FORMAT_UNKNOWN)
2072                 hw->format = format;
2073         if (channels > 0)
2074                 hw->channels = channels;
2075         if (min_rate > 0) {
2076                 hw->rates.min = min_rate;
2077                 hw->rates.max = max_rate;
2078         }
2079         if (chmap)
2080                 hw->chmap_override = chmap;
2081         hw->drain_silence = drain_silence;
2082
2083         return 0;
2084
2085 fail:
2086         snd_pcm_free_chmaps(chmap);
2087         return err;
2088 }
2089
2090 #ifndef DOC_HIDDEN
2091 SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION);
2092 #endif
2093
2094 /*
2095  *  To be removed helpers, but keep binary compatibility at the time
2096  */
2097
2098 #ifndef DOC_HIDDEN
2099 #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
2100 #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
2101 #endif
2102
2103 static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params,
2104                                                struct sndrv_pcm_hw_params_old *oparams)
2105 {
2106         unsigned int i;
2107
2108         memset(params, 0, sizeof(*params));
2109         params->flags = oparams->flags;
2110         for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
2111                 params->masks[i].bits[0] = oparams->masks[i];
2112         memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
2113         params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
2114         params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
2115         params->info = oparams->info;
2116         params->msbits = oparams->msbits;
2117         params->rate_num = oparams->rate_num;
2118         params->rate_den = oparams->rate_den;
2119         params->fifo_size = oparams->fifo_size;
2120 }
2121
2122 static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams,
2123                                              snd_pcm_hw_params_t *params,
2124                                              unsigned int *cmask)
2125 {
2126         unsigned int i, j;
2127
2128         memset(oparams, 0, sizeof(*oparams));
2129         oparams->flags = params->flags;
2130         for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) {
2131                 oparams->masks[i] = params->masks[i].bits[0];
2132                 for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++)
2133                         if (params->masks[i].bits[j]) {
2134                                 *cmask |= 1 << i;
2135                                 break;
2136                         }
2137         }
2138         memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
2139         oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
2140         oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
2141         oparams->info = params->info;
2142         oparams->msbits = params->msbits;
2143         oparams->rate_num = params->rate_num;
2144         oparams->rate_den = params->rate_den;
2145         oparams->fifo_size = params->fifo_size;
2146 }
2147
2148 static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params)
2149 {
2150         struct sndrv_pcm_hw_params_old oparams;
2151         unsigned int cmask = 0;
2152         int res;
2153         
2154         snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask);
2155         res = ioctl(fd, cmd, &oparams);
2156         snd_pcm_hw_convert_from_old_params(params, &oparams);
2157         params->cmask |= cmask;
2158         return res;
2159 }