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