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(¶ms, 1);
461 snd_timer_params_set_ticks(¶ms, 1);
462 INTERNAL(snd_timer_params_set_filter)(¶ms, (1<<SND_TIMER_EVENT_TICK) |
463 suspend | resume);
464 err = snd_timer_params(hw->period_timer, ¶ms);
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, ×pec) == 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