Initial Import
[profile/ivi/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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
27  *
28  */
29   
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <sys/ioctl.h>
38 #include <sys/mman.h>
39 #include <sys/shm.h>
40 #include "pcm_local.h"
41 #include "../control/control_local.h"
42 #include "../timer/timer_local.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 sndrv_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         int sync_ptr_ioctl;
95         volatile struct sndrv_pcm_mmap_status * mmap_status;
96         struct sndrv_pcm_mmap_control *mmap_control;
97         struct sndrv_pcm_sync_ptr *sync_ptr;
98         snd_pcm_uframes_t hw_ptr;
99         snd_pcm_uframes_t appl_ptr;
100         int period_event;
101         snd_timer_t *period_timer;
102         struct pollfd period_timer_pfd;
103         int period_timer_need_poll;
104         /* restricted parameters */
105         snd_pcm_format_t format;
106         int rate;
107         int channels;
108 } snd_pcm_hw_t;
109
110 #define SNDRV_FILE_PCM_STREAM_PLAYBACK          ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
111 #define SNDRV_FILE_PCM_STREAM_CAPTURE           ALSA_DEVICE_DIRECTORY "pcmC%iD%ic"
112 #define SNDRV_PCM_VERSION_MAX                   SNDRV_PROTOCOL_VERSION(2, 0, 9)
113
114 /* update appl_ptr with driver */
115 #define FAST_PCM_STATE(hw) \
116         ((enum sndrv_pcm_state) (hw)->mmap_status->state)
117 #define FAST_PCM_TSTAMP(hw) \
118         ((hw)->mmap_status->tstamp)
119
120 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm)
121 {
122         struct timespec res;
123         snd_pcm_hw_t *hw = pcm->private_data;
124         res = FAST_PCM_TSTAMP(hw);
125         if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version)
126                 res.tv_nsec *= 1000L;
127         return res;
128 }
129 #endif /* DOC_HIDDEN */
130
131 static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags)
132 {
133         int err;
134         hw->sync_ptr->flags = flags;
135         err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr);
136         if (err < 0) {
137                 err = -errno;
138                 SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err);
139                 return err;
140         }
141         return 0;
142 }
143
144 static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags)
145 {
146         return hw->sync_ptr ? sync_ptr1(hw, flags) : 0;
147 }
148
149 static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw)
150 {
151         if (hw->period_timer_need_poll) {
152                 while (poll(&hw->period_timer_pfd, 1, 0) > 0) {
153                         snd_timer_tread_t rbuf[4];
154                         snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
155                 }
156         } else {
157                 snd_timer_tread_t rbuf[4];
158                 snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
159         }
160         return 0;
161 }
162
163 static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
164 {
165         return 2;
166 }
167
168 static int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
169 {
170         snd_pcm_hw_t *hw = pcm->private_data;
171
172         if (space < 2)
173                 return -ENOMEM;
174         pfds[0].fd = hw->fd;
175         pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL;
176         pfds[1].fd = hw->period_timer_pfd.fd;
177         pfds[1].events = POLLIN | POLLERR | POLLNVAL;
178         return 2;
179 }
180
181 static int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents)
182 {
183         snd_pcm_hw_t *hw = pcm->private_data;
184         unsigned int events;
185
186         if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd)
187                 return -EINVAL;
188         events = pfds[0].revents;
189         if (pfds[1].revents & POLLIN) {
190                 snd_pcm_hw_clear_timer_queue(hw);
191                 events |= pcm->poll_events & ~(POLLERR|POLLNVAL);
192         }
193         *revents = events;
194         return 0;
195 }
196
197 static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
198 {
199         long flags;
200         snd_pcm_hw_t *hw = pcm->private_data;
201         int fd = hw->fd, err;
202
203         if ((flags = fcntl(fd, F_GETFL)) < 0) {
204                 err = -errno;
205                 SYSMSG("F_GETFL failed (%i)", err);
206                 return err;
207         }
208         if (nonblock)
209                 flags |= O_NONBLOCK;
210         else
211                 flags &= ~O_NONBLOCK;
212         if (fcntl(fd, F_SETFL, flags) < 0) {
213                 err = -errno;
214                 SYSMSG("F_SETFL for O_NONBLOCK failed (%i)", err);
215                 return err;
216         }
217         return 0;
218 }
219
220 static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
221 {
222         long flags;
223         snd_pcm_hw_t *hw = pcm->private_data;
224         int fd = hw->fd, err;
225
226         if ((flags = fcntl(fd, F_GETFL)) < 0) {
227                 err = -errno;
228                 SYSMSG("F_GETFL failed (%i)", err);
229                 return err;
230         }
231         if (sig >= 0)
232                 flags |= O_ASYNC;
233         else
234                 flags &= ~O_ASYNC;
235         if (fcntl(fd, F_SETFL, flags) < 0) {
236                 err = -errno;
237                 SYSMSG("F_SETFL for O_ASYNC failed (%i)", err);
238                 return err;
239         }
240         if (sig < 0)
241                 return 0;
242         if (fcntl(fd, F_SETSIG, (long)sig) < 0) {
243                 err = -errno;
244                 SYSMSG("F_SETSIG failed (%i)", err);
245                 return err;
246         }
247         if (fcntl(fd, F_SETOWN, (long)pid) < 0) {
248                 err = -errno;
249                 SYSMSG("F_SETOWN failed (%i)", err);
250                 return err;
251         }
252         return 0;
253 }
254
255 static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
256 {
257         snd_pcm_hw_t *hw = pcm->private_data;
258         int fd = hw->fd, err;
259         if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, info) < 0) {
260                 err = -errno;
261                 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", err);
262                 return err;
263         }
264         return 0;
265 }
266
267 static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
268 {
269         /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
270         if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
271                 return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params);
272         return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params);
273 }
274
275 static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
276 {
277         snd_pcm_hw_t *hw = pcm->private_data;
278         int err;
279
280         if (hw->format != SND_PCM_FORMAT_UNKNOWN) {
281                 err = _snd_pcm_hw_params_set_format(params, hw->format);
282                 if (err < 0)
283                         return err;
284         }
285         if (hw->channels > 0) {
286                 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
287                                             hw->channels, 0);
288                 if (err < 0)
289                         return err;
290         }
291         if (hw->rate > 0) {
292                 err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE,
293                                                    hw->rate, 0, hw->rate + 1, -1);
294                 if (err < 0)
295                         return err;
296         }
297
298         if (hw_refine_call(hw, params) < 0) {
299                 err = -errno;
300                 // SYSMSG("SNDRV_PCM_IOCTL_HW_REFINE failed");
301                 return err;
302         }
303
304         if (params->info != ~0U) {
305                 params->info &= ~0xf0000000;
306                 params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
307         }
308         
309         return 0;
310 }
311
312 static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
313 {
314         /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
315         if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
316                 return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
317         return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
318 }
319
320 static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
321 {
322         snd_pcm_hw_t *hw = pcm->private_data;
323         int err;
324         if (hw_params_call(hw, params) < 0) {
325                 err = -errno;
326                 SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err);
327                 return err;
328         }
329         params->info &= ~0xf0000000;
330         params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
331         err = sync_ptr(hw, 0);
332         if (err < 0)
333                 return err;
334         if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
335                 snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd,
336                                      SNDRV_PCM_MMAP_OFFSET_CONTROL);
337         }
338         return 0;
339 }
340
341 static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw)
342 {
343         if (hw->period_timer) {
344                 snd_timer_close(hw->period_timer);
345                 hw->period_timer = NULL;
346         }
347 }
348
349 static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable)
350 {
351         snd_pcm_hw_t *hw = pcm->private_data;
352         snd_timer_params_t *params;
353         unsigned int suspend, resume;
354         int err;
355         
356         if (enable) {
357                 snd_timer_params_alloca(&params);
358                 err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, (hw->subdevice << 1) | (pcm->stream & 1), SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
359                 if (err < 0) {
360                         err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, (hw->subdevice << 1) | (pcm->stream & 1), SND_TIMER_OPEN_NONBLOCK);
361                         return err;
362                 }
363                 if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) {
364                         snd_pcm_hw_close_timer(hw);
365                         return -EINVAL;
366                 }
367                 hw->period_timer_pfd.events = POLLIN;
368                 hw->period_timer_pfd.revents = 0;
369                 snd_timer_poll_descriptors(hw->period_timer, &hw->period_timer_pfd, 1);
370                 hw->period_timer_need_poll = 0;
371                 suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
372                 resume = 1<<SND_TIMER_EVENT_MRESUME;
373                 /*
374                  * hacks for older kernel drivers
375                  */
376                 {
377                         int ver = 0;
378                         ioctl(hw->period_timer_pfd.fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
379                         /* In older versions, check via poll before read() is needed
380                          * because of the confliction between TIMER_START and
381                          * FIONBIO ioctls.
382                          */
383                         if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
384                                 hw->period_timer_need_poll = 1;
385                         /*
386                          * In older versions, timer uses pause events instead
387                          * suspend/resume events.
388                          */
389                         if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
390                                 suspend = 1<<SND_TIMER_EVENT_MPAUSE;
391                                 resume = 1<<SND_TIMER_EVENT_MCONTINUE;
392                         }
393                 }
394                 snd_timer_params_set_auto_start(params, 1);
395                 snd_timer_params_set_ticks(params, 1);
396                 snd_timer_params_set_filter(params, (1<<SND_TIMER_EVENT_TICK) |
397                                             suspend | resume);
398                 err = snd_timer_params(hw->period_timer, params);
399                 if (err < 0) {
400                         snd_pcm_hw_close_timer(hw);
401                         return err;
402                 }
403                 err = snd_timer_start(hw->period_timer);
404                 if (err < 0) {
405                         snd_pcm_hw_close_timer(hw);
406                         return err;
407                 }
408                 pcm->fast_ops = &snd_pcm_hw_fast_ops_timer;
409         } else {
410                 snd_pcm_hw_close_timer(hw);
411                 pcm->fast_ops = &snd_pcm_hw_fast_ops;
412                 hw->period_event = 0;
413         }
414         return 0;
415 }
416
417 static int snd_pcm_hw_hw_free(snd_pcm_t *pcm)
418 {
419         snd_pcm_hw_t *hw = pcm->private_data;
420         int fd = hw->fd, err;
421         snd_pcm_hw_change_timer(pcm, 0);
422         if (ioctl(fd, SNDRV_PCM_IOCTL_HW_FREE) < 0) {
423                 err = -errno;
424                 SYSMSG("SNDRV_PCM_IOCTL_HW_FREE failed (%i)", err);
425                 return err;
426         }
427         return 0;
428 }
429
430 static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
431 {
432         snd_pcm_hw_t *hw = pcm->private_data;
433         int fd = hw->fd, err;
434         int old_period_event = params->period_event;
435         params->period_event = 0;
436         if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
437             params->period_step == pcm->period_step &&
438             params->start_threshold == pcm->start_threshold &&
439             params->stop_threshold == pcm->stop_threshold &&
440             params->silence_threshold == pcm->silence_threshold &&
441             params->silence_size == pcm->silence_size &&
442             old_period_event == hw->period_event) {
443                 hw->mmap_control->avail_min = params->avail_min;
444                 return sync_ptr(hw, 0);
445         }
446         if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) {
447                 err = -errno;
448                 SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
449                 return err;
450         }
451         params->period_event = old_period_event;
452         hw->mmap_control->avail_min = params->avail_min;
453         if (hw->period_event != old_period_event) {
454                 err = snd_pcm_hw_change_timer(pcm, old_period_event);
455                 if (err < 0)
456                         return err;
457                 hw->period_event = old_period_event;
458         }
459         return 0;
460 }
461
462 static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
463 {
464         snd_pcm_hw_t *hw = pcm->private_data;
465         struct sndrv_pcm_channel_info i;
466         int fd = hw->fd, err;
467         i.channel = info->channel;
468         if (ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i) < 0) {
469                 err = -errno;
470                 SYSMSG("SNDRV_PCM_IOCTL_CHANNEL_INFO failed (%i)", err);
471                 return err;
472         }
473         info->channel = i.channel;
474         info->addr = 0;
475         info->first = i.first;
476         info->step = i.step;
477         info->type = SND_PCM_AREA_MMAP;
478         info->u.mmap.fd = fd;
479         info->u.mmap.offset = i.offset;
480         return 0;
481 }
482
483 static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
484 {
485         snd_pcm_hw_t *hw = pcm->private_data;
486         int fd = hw->fd, err;
487         if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
488                 err = -errno;
489                 SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
490                 return err;
491         }
492         if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
493                 status->tstamp.tv_nsec *= 1000L;
494                 status->trigger_tstamp.tv_nsec *= 1000L;
495         }
496         return 0;
497 }
498
499 static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm)
500 {
501         snd_pcm_hw_t *hw = pcm->private_data;
502         int err = sync_ptr(hw, 0);
503         if (err < 0)
504                 return err;
505         return (snd_pcm_state_t) hw->mmap_status->state;
506 }
507
508 static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
509 {
510         snd_pcm_hw_t *hw = pcm->private_data;
511         int fd = hw->fd, err;
512         if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
513                 err = -errno;
514                 SYSMSG("SNDRV_PCM_IOCTL_DELAY failed (%i)", err);
515                 return err;
516         }
517         return 0;
518 }
519
520 static int snd_pcm_hw_hwsync(snd_pcm_t *pcm)
521 {
522         snd_pcm_hw_t *hw = pcm->private_data;
523         int fd = hw->fd, err;
524         if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) {
525                 if (hw->sync_ptr) {
526                         err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC);
527                         if (err < 0)
528                                 return err;
529                 } else {
530                         if (ioctl(fd, SNDRV_PCM_IOCTL_HWSYNC) < 0) {
531                                 err = -errno;
532                                 SYSMSG("SNDRV_PCM_IOCTL_HWSYNC failed (%i)", err);
533                                 return err;
534                         }
535                 }
536         } else {
537                 snd_pcm_sframes_t delay;
538                 int err = snd_pcm_hw_delay(pcm, &delay);
539                 if (err < 0) {
540                         switch (FAST_PCM_STATE(hw)) {
541                         case SND_PCM_STATE_PREPARED:
542                         case SND_PCM_STATE_SUSPENDED:
543                                 return 0;
544                         default:
545                                 return err;
546                         }
547                 }
548         }
549         return 0;
550 }
551
552 static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
553 {
554         snd_pcm_hw_t *hw = pcm->private_data;
555         int fd = hw->fd, err;
556         if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
557                 err = -errno;
558                 SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err);
559                 return err;
560         }
561         return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
562 }
563
564 static int snd_pcm_hw_reset(snd_pcm_t *pcm)
565 {
566         snd_pcm_hw_t *hw = pcm->private_data;
567         int fd = hw->fd, err;
568         if (ioctl(fd, SNDRV_PCM_IOCTL_RESET) < 0) {
569                 err = -errno;
570                 SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err);
571                 return err;
572         }
573         return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
574 }
575
576 static int snd_pcm_hw_start(snd_pcm_t *pcm)
577 {
578         snd_pcm_hw_t *hw = pcm->private_data;
579         int err;
580 #if 0
581         assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
582                snd_pcm_mmap_playback_hw_avail(pcm) > 0);
583 #endif
584         sync_ptr(hw, 0);
585         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) {
586                 err = -errno;
587                 SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err);
588 #if 0
589                 if (err == -EBADFD)
590                         SNDERR("PCM state = %s", snd_pcm_state_name(snd_pcm_hw_state(pcm)));
591 #endif
592                 return err;
593         }
594         return 0;
595 }
596
597 static int snd_pcm_hw_drop(snd_pcm_t *pcm)
598 {
599         snd_pcm_hw_t *hw = pcm->private_data;
600         int err;
601         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DROP) < 0) {
602                 err = -errno;
603                 SYSMSG("SNDRV_PCM_IOCTL_DROP failed (%i)", err);
604                 return err;
605         } else {
606         }
607         return 0;
608 }
609
610 static int snd_pcm_hw_drain(snd_pcm_t *pcm)
611 {
612         snd_pcm_hw_t *hw = pcm->private_data;
613         int err;
614         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_DRAIN) < 0) {
615                 err = -errno;
616                 SYSMSG("SNDRV_PCM_IOCTL_DRAIN failed (%i)", err);
617                 return err;
618         }
619         return 0;
620 }
621
622 static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
623 {
624         snd_pcm_hw_t *hw = pcm->private_data;
625         int err;
626         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_PAUSE, enable) < 0) {
627                 err = -errno;
628                 SYSMSG("SNDRV_PCM_IOCTL_PAUSE failed (%i)", err);
629                 return err;
630         }
631         return 0;
632 }
633
634 static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm)
635 {
636         return snd_pcm_mmap_hw_avail(pcm);
637 }
638
639 static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
640 {
641         snd_pcm_hw_t *hw = pcm->private_data;
642         int err;
643         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_REWIND, &frames) < 0) {
644                 err = -errno;
645                 SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err);
646                 return err;
647         }
648         err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
649         if (err < 0)
650                 return err;
651         return frames;
652 }
653
654 static snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm)
655 {
656         return snd_pcm_mmap_avail(pcm);
657 }
658
659 static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
660 {
661         snd_pcm_hw_t *hw = pcm->private_data;
662         int err;
663         if (SNDRV_PROTOCOL_VERSION(2, 0, 4) <= hw->version) {
664                 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_FORWARD, &frames) < 0) {
665                         err = -errno;
666                         SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err);
667                         return err;
668                 }
669                 err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL);
670                 if (err < 0)
671                         return err;
672                 return frames;
673         } else {
674                 snd_pcm_sframes_t avail;
675
676                 err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_HWSYNC);
677                 if (err < 0)
678                         return err;
679                 switch (FAST_PCM_STATE(hw)) {
680                 case SNDRV_PCM_STATE_RUNNING:
681                 case SNDRV_PCM_STATE_DRAINING:
682                 case SNDRV_PCM_STATE_PAUSED:
683                 case SNDRV_PCM_STATE_PREPARED:
684                         break;
685                 case SNDRV_PCM_STATE_XRUN:
686                         return -EPIPE;
687                 default:
688                         return -EBADFD;
689                 }
690                 avail = snd_pcm_mmap_avail(pcm);
691                 if (avail < 0)
692                         return 0;
693                 if (frames > (snd_pcm_uframes_t)avail)
694                         frames = avail;
695                 snd_pcm_mmap_appl_forward(pcm, frames);
696                 err = sync_ptr(hw, 0);
697                 if (err < 0)
698                         return err;
699                 return frames;
700         }
701 }
702
703 static int snd_pcm_hw_resume(snd_pcm_t *pcm)
704 {
705         snd_pcm_hw_t *hw = pcm->private_data;
706         int fd = hw->fd, err;
707         if (ioctl(fd, SNDRV_PCM_IOCTL_RESUME) < 0) {
708                 err = -errno;
709                 SYSMSG("SNDRV_PCM_IOCTL_RESUME failed (%i)", err);
710                 return err;
711         }
712         return 0;
713 }
714
715 static int hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
716 {
717         snd_pcm_hw_t *hw1 = pcm1->private_data;
718         snd_pcm_hw_t *hw2 = pcm2->private_data;
719         if (ioctl(hw1->fd, SNDRV_PCM_IOCTL_LINK, hw2->fd) < 0) {
720                 SYSMSG("SNDRV_PCM_IOCTL_LINK failed (%i)", -errno);
721                 return -errno;
722         }
723         return 0;
724 }
725
726 static int snd_pcm_hw_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
727 {
728         if (master->type != SND_PCM_TYPE_HW) {
729                 SYSMSG("Invalid type for SNDRV_PCM_IOCTL_LINK (%i)", master->type);
730                 return -EINVAL;
731         }
732         return hw_link(master, pcm);
733 }
734
735 static int snd_pcm_hw_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
736 {
737         if (pcm2->type != SND_PCM_TYPE_HW) {
738                 if (pcm2->fast_ops->link_slaves)
739                         return pcm2->fast_ops->link_slaves(pcm2, pcm1);
740                 return -ENOSYS;
741         }
742         return hw_link(pcm1, pcm2);
743  }
744
745 static int snd_pcm_hw_unlink(snd_pcm_t *pcm)
746 {
747         snd_pcm_hw_t *hw = pcm->private_data;
748
749         if (ioctl(hw->fd, SNDRV_PCM_IOCTL_UNLINK) < 0) {
750                 SYSMSG("SNDRV_PCM_IOCTL_UNLINK failed (%i)", -errno);
751                 return -errno;
752         }
753         return 0;
754 }
755
756 static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
757 {
758         int err;
759         snd_pcm_hw_t *hw = pcm->private_data;
760         int fd = hw->fd;
761         struct sndrv_xferi xferi;
762         xferi.buf = (char*) buffer;
763         xferi.frames = size;
764         xferi.result = 0; /* make valgrind happy */
765         err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi);
766         err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
767 #ifdef DEBUG_RW
768         fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err);
769 #endif
770         if (err < 0)
771                 return snd_pcm_check_error(pcm, err);
772         return xferi.result;
773 }
774
775 static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
776 {
777         int err;
778         snd_pcm_hw_t *hw = pcm->private_data;
779         int fd = hw->fd;
780         struct sndrv_xfern xfern;
781         memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
782         xfern.bufs = bufs;
783         xfern.frames = size;
784         err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern);
785         err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
786 #ifdef DEBUG_RW
787         fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
788 #endif
789         if (err < 0)
790                 return snd_pcm_check_error(pcm, err);
791         return xfern.result;
792 }
793
794 static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
795 {
796         int err;
797         snd_pcm_hw_t *hw = pcm->private_data;
798         int fd = hw->fd;
799         struct sndrv_xferi xferi;
800         xferi.buf = buffer;
801         xferi.frames = size;
802         xferi.result = 0; /* make valgrind happy */
803         err = ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi);
804         err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
805 #ifdef DEBUG_RW
806         fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err);
807 #endif
808         if (err < 0)
809                 return snd_pcm_check_error(pcm, err);
810         return xferi.result;
811 }
812
813 static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
814 {
815         int err;
816         snd_pcm_hw_t *hw = pcm->private_data;
817         int fd = hw->fd;
818         struct sndrv_xfern xfern;
819         memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */
820         xfern.bufs = bufs;
821         xfern.frames = size;
822         err = ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern);
823         err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno;
824 #ifdef DEBUG_RW
825         fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err);
826 #endif
827         if (err < 0)
828                 return snd_pcm_check_error(pcm, err);
829         return xfern.result;
830 }
831
832 static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
833 {
834         snd_pcm_hw_t *hw = pcm->private_data;
835         struct sndrv_pcm_sync_ptr sync_ptr;
836         void *ptr;
837         int err;
838         ptr = MAP_FAILED;
839         if (hw->sync_ptr_ioctl == 0)
840                 ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_status)),
841                            PROT_READ, MAP_FILE|MAP_SHARED, 
842                            hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
843         if (ptr == MAP_FAILED || ptr == NULL) {
844                 memset(&sync_ptr, 0, sizeof(sync_ptr));
845                 sync_ptr.c.control.appl_ptr = 0;
846                 sync_ptr.c.control.avail_min = 1;
847                 err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, &sync_ptr);
848                 if (err < 0) {
849                         err = -errno;
850                         SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err);
851                         return err;
852                 }
853                 hw->sync_ptr = calloc(1, sizeof(struct sndrv_pcm_sync_ptr));
854                 if (hw->sync_ptr == NULL)
855                         return -ENOMEM;
856                 hw->mmap_status = &hw->sync_ptr->s.status;
857                 hw->mmap_control = &hw->sync_ptr->c.control;
858                 hw->sync_ptr_ioctl = 1;
859         } else {
860                 hw->mmap_status = ptr;
861         }
862         snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct sndrv_pcm_mmap_status, hw_ptr));
863         return 0;
864 }
865
866 static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
867 {
868         snd_pcm_hw_t *hw = pcm->private_data;
869         void *ptr;
870         int err;
871         if (hw->sync_ptr == NULL) {
872                 ptr = mmap(NULL, page_align(sizeof(struct sndrv_pcm_mmap_control)),
873                            PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 
874                            hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
875                 if (ptr == MAP_FAILED || ptr == NULL) {
876                         err = -errno;
877                         SYSMSG("control mmap failed (%i)", err);
878                         return err;
879                 }
880                 hw->mmap_control = ptr;
881         } else {
882                 hw->mmap_control->avail_min = 1;
883         }
884         snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
885         return 0;
886 }
887
888 static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
889 {
890         snd_pcm_hw_t *hw = pcm->private_data;
891         int err;
892         if (hw->sync_ptr_ioctl) {
893                 free(hw->sync_ptr);
894                 hw->sync_ptr = NULL;
895         } else {
896                 if (munmap((void*)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) {
897                         err = -errno;
898                         SYSMSG("status munmap failed (%i)", err);
899                         return err;
900                 }
901         }
902         return 0;
903 }
904
905 static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
906 {
907         snd_pcm_hw_t *hw = pcm->private_data;
908         int err;
909         if (hw->sync_ptr_ioctl) {
910                 free(hw->sync_ptr);
911                 hw->sync_ptr = NULL;
912         } else {
913                 if (munmap(hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) {
914                         err = -errno;
915                         SYSMSG("control munmap failed (%i)", err);
916                         return err;
917                 }
918         }
919         return 0;
920 }
921
922 static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
923 {
924         return 0;
925 }
926
927 static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
928 {
929         return 0;
930 }
931
932 static int snd_pcm_hw_close(snd_pcm_t *pcm)
933 {
934         snd_pcm_hw_t *hw = pcm->private_data;
935         int err = 0;
936         if (close(hw->fd)) {
937                 err = -errno;
938                 SYSMSG("close failed (%i)\n", err);
939         }
940         snd_pcm_hw_munmap_status(pcm);
941         snd_pcm_hw_munmap_control(pcm);
942         free(hw);
943         return err;
944 }
945
946 static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
947                                                 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
948                                                 snd_pcm_uframes_t size)
949 {
950         snd_pcm_hw_t *hw = pcm->private_data;
951
952         snd_pcm_mmap_appl_forward(pcm, size);
953         sync_ptr(hw, 0);
954 #ifdef DEBUG_MMAP
955         fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size);
956 #endif
957         return size;
958 }
959
960 static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
961 {
962         snd_pcm_hw_t *hw = pcm->private_data;
963         snd_pcm_uframes_t avail;
964
965         sync_ptr(hw, 0);
966         avail = snd_pcm_mmap_avail(pcm);
967         switch (FAST_PCM_STATE(hw)) {
968         case SNDRV_PCM_STATE_RUNNING:
969                 if (avail >= pcm->stop_threshold) {
970                         /* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */
971                         if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) {
972                                 if (ioctl(hw->fd, SNDRV_PCM_IOCTL_XRUN) < 0)
973                                         return -errno;
974                         }
975                         /* everything is ok, state == SND_PCM_STATE_XRUN at the moment */
976                         return -EPIPE;
977                 }
978                 break;
979         case SNDRV_PCM_STATE_XRUN:
980                 return -EPIPE;
981         default:
982                 break;
983         }
984         return avail;
985 }
986
987 static int snd_pcm_hw_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
988                                  snd_htimestamp_t *tstamp)
989 {
990         snd_pcm_sframes_t avail1;
991         int ok = 0;
992
993         /* unfortunately, loop is necessary to ensure valid timestamp */
994         while (1) {
995                 avail1 = snd_pcm_hw_avail_update(pcm);
996                 if (avail1 < 0)
997                         return avail1;
998                 if (ok && (snd_pcm_uframes_t)avail1 == *avail)
999                         break;
1000                 *avail = avail1;
1001                 *tstamp = snd_pcm_hw_fast_tstamp(pcm);
1002                 ok = 1;
1003         }
1004         return 0;
1005 }
1006
1007 static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out)
1008 {
1009         snd_pcm_hw_t *hw = pcm->private_data;
1010         char *name;
1011         int err = snd_card_get_name(hw->card, &name);
1012         if (err < 0) {
1013                 SNDERR("cannot get card name");
1014                 return;
1015         }
1016         snd_output_printf(out, "Hardware PCM card %d '%s' device %d subdevice %d\n",
1017                           hw->card, name, hw->device, hw->subdevice);
1018         free(name);
1019         if (pcm->setup) {
1020                 snd_output_printf(out, "Its setup is:\n");
1021                 snd_pcm_dump_setup(pcm, out);
1022                 snd_output_printf(out, "  appl_ptr     : %li\n", hw->mmap_control->appl_ptr);
1023                 snd_output_printf(out, "  hw_ptr       : %li\n", hw->mmap_status->hw_ptr);
1024         }
1025 }
1026
1027 static const snd_pcm_ops_t snd_pcm_hw_ops = {
1028         .close = snd_pcm_hw_close,
1029         .info = snd_pcm_hw_info,
1030         .hw_refine = snd_pcm_hw_hw_refine,
1031         .hw_params = snd_pcm_hw_hw_params,
1032         .hw_free = snd_pcm_hw_hw_free,
1033         .sw_params = snd_pcm_hw_sw_params,
1034         .channel_info = snd_pcm_hw_channel_info,
1035         .dump = snd_pcm_hw_dump,
1036         .nonblock = snd_pcm_hw_nonblock,
1037         .async = snd_pcm_hw_async,
1038         .mmap = snd_pcm_hw_mmap,
1039         .munmap = snd_pcm_hw_munmap,
1040 };
1041
1042 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
1043         .status = snd_pcm_hw_status,
1044         .state = snd_pcm_hw_state,
1045         .hwsync = snd_pcm_hw_hwsync,
1046         .delay = snd_pcm_hw_delay,
1047         .prepare = snd_pcm_hw_prepare,
1048         .reset = snd_pcm_hw_reset,
1049         .start = snd_pcm_hw_start,
1050         .drop = snd_pcm_hw_drop,
1051         .drain = snd_pcm_hw_drain,
1052         .pause = snd_pcm_hw_pause,
1053         .rewindable = snd_pcm_hw_rewindable,
1054         .rewind = snd_pcm_hw_rewind,
1055         .forwardable = snd_pcm_hw_forwardable,
1056         .forward = snd_pcm_hw_forward,
1057         .resume = snd_pcm_hw_resume,
1058         .link = snd_pcm_hw_link,
1059         .link_slaves = snd_pcm_hw_link_slaves,
1060         .unlink = snd_pcm_hw_unlink,
1061         .writei = snd_pcm_hw_writei,
1062         .writen = snd_pcm_hw_writen,
1063         .readi = snd_pcm_hw_readi,
1064         .readn = snd_pcm_hw_readn,
1065         .avail_update = snd_pcm_hw_avail_update,
1066         .mmap_commit = snd_pcm_hw_mmap_commit,
1067         .htimestamp = snd_pcm_hw_htimestamp,
1068         .poll_descriptors = NULL,
1069         .poll_descriptors_count = NULL,
1070         .poll_revents = NULL,
1071 };
1072
1073 static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = {
1074         .status = snd_pcm_hw_status,
1075         .state = snd_pcm_hw_state,
1076         .hwsync = snd_pcm_hw_hwsync,
1077         .delay = snd_pcm_hw_delay,
1078         .prepare = snd_pcm_hw_prepare,
1079         .reset = snd_pcm_hw_reset,
1080         .start = snd_pcm_hw_start,
1081         .drop = snd_pcm_hw_drop,
1082         .drain = snd_pcm_hw_drain,
1083         .pause = snd_pcm_hw_pause,
1084         .rewindable = snd_pcm_hw_rewindable,
1085         .rewind = snd_pcm_hw_rewind,
1086         .forwardable = snd_pcm_hw_forwardable,
1087         .forward = snd_pcm_hw_forward,
1088         .resume = snd_pcm_hw_resume,
1089         .link = snd_pcm_hw_link,
1090         .link_slaves = snd_pcm_hw_link_slaves,
1091         .unlink = snd_pcm_hw_unlink,
1092         .writei = snd_pcm_hw_writei,
1093         .writen = snd_pcm_hw_writen,
1094         .readi = snd_pcm_hw_readi,
1095         .readn = snd_pcm_hw_readn,
1096         .avail_update = snd_pcm_hw_avail_update,
1097         .mmap_commit = snd_pcm_hw_mmap_commit,
1098         .htimestamp = snd_pcm_hw_htimestamp,
1099         .poll_descriptors = snd_pcm_hw_poll_descriptors,
1100         .poll_descriptors_count = snd_pcm_hw_poll_descriptors_count,
1101         .poll_revents = snd_pcm_hw_poll_revents,
1102 };
1103
1104 /**
1105  * \brief Creates a new hw PCM
1106  * \param pcmp Returns created PCM handle
1107  * \param name Name of PCM
1108  * \param fd File descriptor
1109  * \param mmap_emulation Obsoleted parameter
1110  * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl
1111  * \retval zero on success otherwise a negative error code
1112  * \warning Using of this function might be dangerous in the sense
1113  *          of compatibility reasons. The prototype might be freely
1114  *          changed in future.
1115  */
1116 int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name,
1117                        int fd, int mmap_emulation ATTRIBUTE_UNUSED,
1118                        int sync_ptr_ioctl)
1119 {
1120         int ver, mode, monotonic = 0;
1121         long fmode;
1122         snd_pcm_t *pcm = NULL;
1123         snd_pcm_hw_t *hw = NULL;
1124         snd_pcm_info_t info;
1125         int ret;
1126
1127         assert(pcmp);
1128
1129         memset(&info, 0, sizeof(info));
1130         if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
1131                 ret = -errno;
1132                 SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
1133                 close(fd);
1134                 return ret;
1135
1136         }
1137
1138         if ((fmode = fcntl(fd, F_GETFL)) < 0) {
1139                 ret = -errno;
1140                 close(fd);
1141                 return ret;
1142         }
1143         mode = 0;
1144         if (fmode & O_NONBLOCK)
1145                 mode |= SND_PCM_NONBLOCK;
1146         if (fmode & O_ASYNC)
1147                 mode |= SND_PCM_ASYNC;
1148
1149         if (ioctl(fd, SNDRV_PCM_IOCTL_PVERSION, &ver) < 0) {
1150                 ret = -errno;
1151                 SYSMSG("SNDRV_PCM_IOCTL_PVERSION failed (%i)", ret);
1152                 close(fd);
1153                 return ret;
1154         }
1155         if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX))
1156                 return -SND_ERROR_INCOMPATIBLE_VERSION;
1157
1158 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
1159         if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) {
1160                 struct timespec timespec;
1161                 if (clock_gettime(CLOCK_MONOTONIC, &timespec) == 0) {
1162                         int on = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
1163                         if (ioctl(fd, SNDRV_PCM_IOCTL_TTSTAMP, &on) < 0) {
1164                                 ret = -errno;
1165                                 SNDMSG("TTSTAMP failed\n");
1166                                 return ret;
1167                         }
1168                         monotonic = 1;
1169                 }
1170         } else
1171 #endif
1172           if (SNDRV_PROTOCOL_VERSION(2, 0, 5) <= ver) {
1173                 int on = 1;
1174                 if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
1175                         ret = -errno;
1176                         SNDMSG("TSTAMP failed\n");
1177                         return ret;
1178                 }
1179         }
1180         
1181         hw = calloc(1, sizeof(snd_pcm_hw_t));
1182         if (!hw) {
1183                 close(fd);
1184                 return -ENOMEM;
1185         }
1186
1187         hw->version = ver;
1188         hw->card = info.card;
1189         hw->device = info.device;
1190         hw->subdevice = info.subdevice;
1191         hw->fd = fd;
1192         hw->sync_ptr_ioctl = sync_ptr_ioctl;
1193         /* no restriction */
1194         hw->format = SND_PCM_FORMAT_UNKNOWN;
1195         hw->rate = 0;
1196         hw->channels = 0;
1197
1198         ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode);
1199         if (ret < 0) {
1200                 free(hw);
1201                 close(fd);
1202                 return ret;
1203         }
1204
1205         pcm->ops = &snd_pcm_hw_ops;
1206         pcm->fast_ops = &snd_pcm_hw_fast_ops;
1207         pcm->private_data = hw;
1208         pcm->poll_fd = fd;
1209         pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
1210         pcm->monotonic = monotonic;
1211
1212         ret = snd_pcm_hw_mmap_status(pcm);
1213         if (ret < 0) {
1214                 snd_pcm_close(pcm);
1215                 return ret;
1216         }
1217         ret = snd_pcm_hw_mmap_control(pcm);
1218         if (ret < 0) {
1219                 snd_pcm_close(pcm);
1220                 return ret;
1221         }
1222
1223         *pcmp = pcm;
1224         return 0;
1225 }
1226
1227 /**
1228  * \brief Creates a new hw PCM
1229  * \param pcmp Returns created PCM handle
1230  * \param name Name of PCM
1231  * \param card Number of card
1232  * \param device Number of device
1233  * \param subdevice Number of subdevice
1234  * \param stream PCM Stream
1235  * \param mode PCM Mode
1236  * \param mmap_emulation Obsoleted parameter
1237  * \param sync_ptr_ioctl Use SYNC_PTR ioctl rather than mmap for control structures
1238  * \retval zero on success otherwise a negative error code
1239  * \warning Using of this function might be dangerous in the sense
1240  *          of compatibility reasons. The prototype might be freely
1241  *          changed in future.
1242  */
1243 int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
1244                     int card, int device, int subdevice,
1245                     snd_pcm_stream_t stream, int mode,
1246                     int mmap_emulation ATTRIBUTE_UNUSED,
1247                     int sync_ptr_ioctl)
1248 {
1249         char filename[sizeof(SNDRV_FILE_PCM_STREAM_PLAYBACK) + 20];
1250         const char *filefmt;
1251         int ret = 0, fd = -1;
1252         int attempt = 0;
1253         snd_pcm_info_t info;
1254         int fmode;
1255         snd_ctl_t *ctl;
1256
1257         assert(pcmp);
1258
1259         if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0)
1260                 return ret;
1261
1262         switch (stream) {
1263         case SND_PCM_STREAM_PLAYBACK:
1264                 filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK;
1265                 break;
1266         case SND_PCM_STREAM_CAPTURE:
1267                 filefmt = SNDRV_FILE_PCM_STREAM_CAPTURE;
1268                 break;
1269         default:
1270                 SNDERR("invalid stream %d", stream);
1271                 return -EINVAL;
1272         }
1273         sprintf(filename, filefmt, card, device);
1274
1275       __again:
1276         if (attempt++ > 3) {
1277                 ret = -EBUSY;
1278                 goto _err;
1279         }
1280         ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
1281         if (ret < 0)
1282                 goto _err;
1283         fmode = O_RDWR;
1284         if (mode & SND_PCM_NONBLOCK)
1285                 fmode |= O_NONBLOCK;
1286         if (mode & SND_PCM_ASYNC)
1287                 fmode |= O_ASYNC;
1288         if (mode & SND_PCM_APPEND)
1289                 fmode |= O_APPEND;
1290         fd = snd_open_device(filename, fmode);
1291         if (fd < 0) {
1292                 ret = -errno;
1293                 SYSMSG("open '%s' failed (%i)", filename, ret);
1294                 goto _err;
1295         }
1296         if (subdevice >= 0) {
1297                 memset(&info, 0, sizeof(info));
1298                 if (ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) < 0) {
1299                         ret = -errno;
1300                         SYSMSG("SNDRV_PCM_IOCTL_INFO failed (%i)", ret);
1301                         goto _err;
1302                 }
1303                 if (info.subdevice != (unsigned int) subdevice) {
1304                         close(fd);
1305                         goto __again;
1306                 }
1307         }
1308         snd_ctl_close(ctl);
1309         return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl);
1310        _err:
1311         snd_ctl_close(ctl);
1312         return ret;
1313 }
1314
1315 /*! \page pcm_plugins
1316
1317 \section pcm_plugins_hw Plugin: hw
1318
1319 This plugin communicates directly with the ALSA kernel driver. It is a raw
1320 communication without any conversions. The emulation of mmap access can be
1321 optionally enabled, but expect worse latency in the case.
1322
1323 The nonblock option specifies whether the device is opened in a non-blocking
1324 manner.  Note that the blocking behavior for read/write access won't be
1325 changed by this option.  This influences only on the blocking behavior at
1326 opening the device.  If you would like to keep the compatibility with the
1327 older ALSA stuff, turn this option off.
1328
1329 \code
1330 pcm.name {
1331         type hw                 # Kernel PCM
1332         card INT/STR            # Card name (string) or number (integer)
1333         [device INT]            # Device number (default 0)
1334         [subdevice INT]         # Subdevice number (default -1: first available)
1335         [sync_ptr_ioctl BOOL]   # Use SYNC_PTR ioctl rather than the direct mmap access for control structures
1336         [nonblock BOOL]         # Force non-blocking open mode
1337         [format STR]            # Restrict only to the given format
1338         [channels INT]          # Restrict only to the given channels
1339         [rate INT]              # Restrict only to the given rate
1340 }
1341 \endcode
1342
1343 \subsection pcm_plugins_hw_funcref Function reference
1344
1345 <UL>
1346   <LI>snd_pcm_hw_open()
1347   <LI>_snd_pcm_hw_open()
1348 </UL>
1349
1350 */
1351
1352 /**
1353  * \brief Creates a new hw PCM
1354  * \param pcmp Returns created PCM handle
1355  * \param name Name of PCM
1356  * \param root Root configuration node
1357  * \param conf Configuration node with hw PCM description
1358  * \param stream PCM Stream
1359  * \param mode PCM Mode
1360  * \warning Using of this function might be dangerous in the sense
1361  *          of compatibility reasons. The prototype might be freely
1362  *          changed in future.
1363  */
1364 int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
1365                      snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
1366                      snd_pcm_stream_t stream, int mode)
1367 {
1368         snd_config_iterator_t i, next;
1369         long card = -1, device = 0, subdevice = -1;
1370         const char *str;
1371         int err, sync_ptr_ioctl = 0;
1372         int rate = 0, channels = 0;
1373         snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
1374         snd_config_t *n;
1375         int nonblock = 1; /* non-block per default */
1376         snd_pcm_hw_t *hw;
1377
1378         /* look for defaults.pcm.nonblock definition */
1379         if (snd_config_search(root, "defaults.pcm.nonblock", &n) >= 0) {
1380                 err = snd_config_get_bool(n);
1381                 if (err >= 0)
1382                         nonblock = err;
1383         }
1384         snd_config_for_each(i, next, conf) {
1385                 const char *id;
1386                 n = snd_config_iterator_entry(i);
1387                 if (snd_config_get_id(n, &id) < 0)
1388                         continue;
1389                 if (snd_pcm_conf_generic_id(id))
1390                         continue;
1391                 if (strcmp(id, "card") == 0) {
1392                         err = snd_config_get_integer(n, &card);
1393                         if (err < 0) {
1394                                 err = snd_config_get_string(n, &str);
1395                                 if (err < 0) {
1396                                         SNDERR("Invalid type for %s", id);
1397                                         return -EINVAL;
1398                                 }
1399                                 card = snd_card_get_index(str);
1400                                 if (card < 0) {
1401                                         SNDERR("Invalid value for %s", id);
1402                                         return card;
1403                                 }
1404                         }
1405                         continue;
1406                 }
1407                 if (strcmp(id, "device") == 0) {
1408                         err = snd_config_get_integer(n, &device);
1409                         if (err < 0) {
1410                                 SNDERR("Invalid type for %s", id);
1411                                 return err;
1412                         }
1413                         continue;
1414                 }
1415                 if (strcmp(id, "subdevice") == 0) {
1416                         err = snd_config_get_integer(n, &subdevice);
1417                         if (err < 0) {
1418                                 SNDERR("Invalid type for %s", id);
1419                                 return err;
1420                         }
1421                         continue;
1422                 }
1423                 if (strcmp(id, "sync_ptr_ioctl") == 0) {
1424                         err = snd_config_get_bool(n);
1425                         if (err < 0)
1426                                 continue;
1427                         sync_ptr_ioctl = err;
1428                         continue;
1429                 }
1430                 if (strcmp(id, "nonblock") == 0) {
1431                         err = snd_config_get_bool(n);
1432                         if (err < 0)
1433                                 continue;
1434                         nonblock = err;
1435                         continue;
1436                 }
1437                 if (strcmp(id, "rate") == 0) {
1438                         long val;
1439                         err = snd_config_get_integer(n, &val);
1440                         if (err < 0) {
1441                                 SNDERR("Invalid type for %s", id);
1442                                 return err;
1443                         }
1444                         rate = val;
1445                         continue;
1446                 }
1447                 if (strcmp(id, "format") == 0) {
1448                         err = snd_config_get_string(n, &str);
1449                         if (err < 0) {
1450                                 SNDERR("invalid type for %s", id);
1451                                 return err;
1452                         }
1453                         format = snd_pcm_format_value(str);
1454                         continue;
1455                 }
1456                 if (strcmp(id, "channels") == 0) {
1457                         long val;
1458                         err = snd_config_get_integer(n, &val);
1459                         if (err < 0) {
1460                                 SNDERR("Invalid type for %s", id);
1461                                 return err;
1462                         }
1463                         channels = val;
1464                         continue;
1465                 }
1466                 SNDERR("Unknown field %s", id);
1467                 return -EINVAL;
1468         }
1469         if (card < 0) {
1470                 SNDERR("card is not defined");
1471                 return -EINVAL;
1472         }
1473         err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
1474                               mode | (nonblock ? SND_PCM_NONBLOCK : 0),
1475                               0, sync_ptr_ioctl);
1476         if (err < 0)
1477                 return err;
1478         if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
1479                 /* revert to blocking mode for read/write access */
1480                 snd_pcm_hw_nonblock(*pcmp, 0);
1481                 (*pcmp)->mode = mode;
1482         } else
1483                 /* make sure the SND_PCM_NO_xxx flags don't get lost on the
1484                  * way */
1485                 (*pcmp)->mode |= mode & (SND_PCM_NO_AUTO_RESAMPLE|
1486                                          SND_PCM_NO_AUTO_CHANNELS|
1487                                          SND_PCM_NO_AUTO_FORMAT|
1488                                          SND_PCM_NO_SOFTVOL);
1489
1490         hw = (*pcmp)->private_data;
1491         if (format != SND_PCM_FORMAT_UNKNOWN)
1492                 hw->format = format;
1493         if (channels > 0)
1494                 hw->channels = channels;
1495         if (rate > 0)
1496                 hw->rate = rate;
1497
1498         return 0;
1499 }
1500
1501 #ifndef DOC_HIDDEN
1502 SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION);
1503 #endif
1504
1505 /*
1506  *  To be removed helpers, but keep binary compatibility at the time
1507  */
1508
1509 #ifndef DOC_HIDDEN
1510 #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
1511 #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
1512 #endif
1513
1514 static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params,
1515                                                struct sndrv_pcm_hw_params_old *oparams)
1516 {
1517         unsigned int i;
1518
1519         memset(params, 0, sizeof(*params));
1520         params->flags = oparams->flags;
1521         for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
1522                 params->masks[i].bits[0] = oparams->masks[i];
1523         memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
1524         params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
1525         params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
1526         params->info = oparams->info;
1527         params->msbits = oparams->msbits;
1528         params->rate_num = oparams->rate_num;
1529         params->rate_den = oparams->rate_den;
1530         params->fifo_size = oparams->fifo_size;
1531 }
1532
1533 static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams,
1534                                              snd_pcm_hw_params_t *params,
1535                                              unsigned int *cmask)
1536 {
1537         unsigned int i, j;
1538
1539         memset(oparams, 0, sizeof(*oparams));
1540         oparams->flags = params->flags;
1541         for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) {
1542                 oparams->masks[i] = params->masks[i].bits[0];
1543                 for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++)
1544                         if (params->masks[i].bits[j]) {
1545                                 *cmask |= 1 << i;
1546                                 break;
1547                         }
1548         }
1549         memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
1550         oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
1551         oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
1552         oparams->info = params->info;
1553         oparams->msbits = params->msbits;
1554         oparams->rate_num = params->rate_num;
1555         oparams->rate_den = params->rate_den;
1556         oparams->fifo_size = params->fifo_size;
1557 }
1558
1559 static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params)
1560 {
1561         struct sndrv_pcm_hw_params_old oparams;
1562         unsigned int cmask = 0;
1563         int res;
1564         
1565         snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask);
1566         res = ioctl(fd, cmd, &oparams);
1567         snd_pcm_hw_convert_from_old_params(params, &oparams);
1568         params->cmask |= cmask;
1569         return res;
1570 }