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