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 */
49const 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
62struct 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
81static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
82static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm);
83static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops;
84static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer;
85
86/*
87 *
88 */
89
90typedef 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
120struct 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
131static 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
144static 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
149static 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
163static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
164{
165	return 2;
166}
167
168static 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
181static 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
197static 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
220static 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
255static 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
267static 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
275static 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
312static 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
320static 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
341static 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
349static 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
417static 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
430static 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
462static 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
483static 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
499static 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
508static 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
520static 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
552static 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
564static 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
576static 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
597static 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
610static 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
622static 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
634static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm)
635{
636	return snd_pcm_mmap_hw_avail(pcm);
637}
638
639static 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
654static snd_pcm_sframes_t snd_pcm_hw_forwardable(snd_pcm_t *pcm)
655{
656	return snd_pcm_mmap_avail(pcm);
657}
658
659static 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
703static 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
715static 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
726static 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
735static 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
745static 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
756static 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
775static 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
794static 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
813static 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
832static 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
866static 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
888static 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
905static 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
922static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
923{
924	return 0;
925}
926
927static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
928{
929	return 0;
930}
931
932static 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
946static 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
960static 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
987static 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
1007static 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
1027static 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
1042static 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
1073static 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 */
1116int 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 */
1243int 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
1319This plugin communicates directly with the ALSA kernel driver. It is a raw
1320communication without any conversions. The emulation of mmap access can be
1321optionally enabled, but expect worse latency in the case.
1322
1323The nonblock option specifies whether the device is opened in a non-blocking
1324manner.  Note that the blocking behavior for read/write access won't be
1325changed by this option.  This influences only on the blocking behavior at
1326opening the device.  If you would like to keep the compatibility with the
1327older ALSA stuff, turn this option off.
1328
1329\code
1330pcm.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 */
1364int _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
1502SND_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
1514static 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
1533static 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
1559static 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}
1571