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(¶ms, 1);
489 snd_timer_params_set_ticks(¶ms, 1);
490 INTERNAL(snd_timer_params_set_filter)(¶ms, (1<<SND_TIMER_EVENT_TICK) |
491 suspend | resume);
492 err = snd_timer_params(hw->period_timer, ¶ms);
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, ×pec) == 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