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