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