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