| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Digital Audio (PCM) abstract layer |
|---|
| 3 | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
|---|
| 4 | | - * |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, write to the Free Software |
|---|
| 18 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 19 | | - * |
|---|
| 20 | 5 | */ |
|---|
| 21 | 6 | |
|---|
| 22 | 7 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 178 | 163 | |
|---|
| 179 | 164 | #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v |
|---|
| 180 | 165 | |
|---|
| 181 | | -static char *snd_pcm_format_names[] = { |
|---|
| 166 | +static const char * const snd_pcm_format_names[] = { |
|---|
| 182 | 167 | FORMAT(S8), |
|---|
| 183 | 168 | FORMAT(U8), |
|---|
| 184 | 169 | FORMAT(S16_LE), |
|---|
| .. | .. |
|---|
| 252 | 237 | #define START(v) [SNDRV_PCM_START_##v] = #v |
|---|
| 253 | 238 | #define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v |
|---|
| 254 | 239 | |
|---|
| 255 | | -static char *snd_pcm_stream_names[] = { |
|---|
| 240 | +static const char * const snd_pcm_stream_names[] = { |
|---|
| 256 | 241 | STREAM(PLAYBACK), |
|---|
| 257 | 242 | STREAM(CAPTURE), |
|---|
| 258 | 243 | }; |
|---|
| 259 | 244 | |
|---|
| 260 | | -static char *snd_pcm_state_names[] = { |
|---|
| 245 | +static const char * const snd_pcm_state_names[] = { |
|---|
| 261 | 246 | STATE(OPEN), |
|---|
| 262 | 247 | STATE(SETUP), |
|---|
| 263 | 248 | STATE(PREPARED), |
|---|
| .. | .. |
|---|
| 268 | 253 | STATE(SUSPENDED), |
|---|
| 269 | 254 | }; |
|---|
| 270 | 255 | |
|---|
| 271 | | -static char *snd_pcm_access_names[] = { |
|---|
| 256 | +static const char * const snd_pcm_access_names[] = { |
|---|
| 272 | 257 | ACCESS(MMAP_INTERLEAVED), |
|---|
| 273 | 258 | ACCESS(MMAP_NONINTERLEAVED), |
|---|
| 274 | 259 | ACCESS(MMAP_COMPLEX), |
|---|
| .. | .. |
|---|
| 276 | 261 | ACCESS(RW_NONINTERLEAVED), |
|---|
| 277 | 262 | }; |
|---|
| 278 | 263 | |
|---|
| 279 | | -static char *snd_pcm_subformat_names[] = { |
|---|
| 264 | +static const char * const snd_pcm_subformat_names[] = { |
|---|
| 280 | 265 | SUBFORMAT(STD), |
|---|
| 281 | 266 | }; |
|---|
| 282 | 267 | |
|---|
| 283 | | -static char *snd_pcm_tstamp_mode_names[] = { |
|---|
| 268 | +static const char * const snd_pcm_tstamp_mode_names[] = { |
|---|
| 284 | 269 | TSTAMP(NONE), |
|---|
| 285 | 270 | TSTAMP(ENABLE), |
|---|
| 286 | 271 | }; |
|---|
| .. | .. |
|---|
| 458 | 443 | { |
|---|
| 459 | 444 | struct snd_pcm_substream *substream = entry->private_data; |
|---|
| 460 | 445 | struct snd_pcm_runtime *runtime; |
|---|
| 461 | | - struct snd_pcm_status status; |
|---|
| 446 | + struct snd_pcm_status64 status; |
|---|
| 462 | 447 | int err; |
|---|
| 463 | 448 | |
|---|
| 464 | 449 | mutex_lock(&substream->pcm->open_mutex); |
|---|
| .. | .. |
|---|
| 468 | 453 | goto unlock; |
|---|
| 469 | 454 | } |
|---|
| 470 | 455 | memset(&status, 0, sizeof(status)); |
|---|
| 471 | | - err = snd_pcm_status(substream, &status); |
|---|
| 456 | + err = snd_pcm_status64(substream, &status); |
|---|
| 472 | 457 | if (err < 0) { |
|---|
| 473 | 458 | snd_iprintf(buffer, "error %d\n", err); |
|---|
| 474 | 459 | goto unlock; |
|---|
| 475 | 460 | } |
|---|
| 476 | 461 | snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); |
|---|
| 477 | 462 | snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); |
|---|
| 478 | | - snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", |
|---|
| 479 | | - status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); |
|---|
| 480 | | - snd_iprintf(buffer, "tstamp : %ld.%09ld\n", |
|---|
| 481 | | - status.tstamp.tv_sec, status.tstamp.tv_nsec); |
|---|
| 463 | + snd_iprintf(buffer, "trigger_time: %lld.%09lld\n", |
|---|
| 464 | + status.trigger_tstamp_sec, status.trigger_tstamp_nsec); |
|---|
| 465 | + snd_iprintf(buffer, "tstamp : %lld.%09lld\n", |
|---|
| 466 | + status.tstamp_sec, status.tstamp_nsec); |
|---|
| 482 | 467 | snd_iprintf(buffer, "delay : %ld\n", status.delay); |
|---|
| 483 | 468 | snd_iprintf(buffer, "avail : %ld\n", status.avail); |
|---|
| 484 | 469 | snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max); |
|---|
| .. | .. |
|---|
| 528 | 513 | if (!entry) |
|---|
| 529 | 514 | return -ENOMEM; |
|---|
| 530 | 515 | entry->mode = S_IFDIR | 0555; |
|---|
| 531 | | - if (snd_info_register(entry) < 0) { |
|---|
| 532 | | - snd_info_free_entry(entry); |
|---|
| 533 | | - return -ENOMEM; |
|---|
| 534 | | - } |
|---|
| 535 | 516 | pstr->proc_root = entry; |
|---|
| 536 | 517 | entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root); |
|---|
| 537 | | - if (entry) { |
|---|
| 518 | + if (entry) |
|---|
| 538 | 519 | snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); |
|---|
| 539 | | - if (snd_info_register(entry) < 0) { |
|---|
| 540 | | - snd_info_free_entry(entry); |
|---|
| 541 | | - entry = NULL; |
|---|
| 542 | | - } |
|---|
| 543 | | - } |
|---|
| 544 | | - pstr->proc_info_entry = entry; |
|---|
| 545 | | - |
|---|
| 546 | 520 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
|---|
| 547 | 521 | entry = snd_info_create_card_entry(pcm->card, "xrun_debug", |
|---|
| 548 | 522 | pstr->proc_root); |
|---|
| 549 | 523 | if (entry) { |
|---|
| 550 | | - entry->c.text.read = snd_pcm_xrun_debug_read; |
|---|
| 524 | + snd_info_set_text_ops(entry, pstr, snd_pcm_xrun_debug_read); |
|---|
| 551 | 525 | entry->c.text.write = snd_pcm_xrun_debug_write; |
|---|
| 552 | 526 | entry->mode |= 0200; |
|---|
| 553 | | - entry->private_data = pstr; |
|---|
| 554 | | - if (snd_info_register(entry) < 0) { |
|---|
| 555 | | - snd_info_free_entry(entry); |
|---|
| 556 | | - entry = NULL; |
|---|
| 557 | | - } |
|---|
| 558 | 527 | } |
|---|
| 559 | | - pstr->proc_xrun_debug_entry = entry; |
|---|
| 560 | 528 | #endif |
|---|
| 561 | 529 | return 0; |
|---|
| 562 | 530 | } |
|---|
| 563 | 531 | |
|---|
| 564 | 532 | static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) |
|---|
| 565 | 533 | { |
|---|
| 566 | | -#ifdef CONFIG_SND_PCM_XRUN_DEBUG |
|---|
| 567 | | - snd_info_free_entry(pstr->proc_xrun_debug_entry); |
|---|
| 568 | | - pstr->proc_xrun_debug_entry = NULL; |
|---|
| 569 | | -#endif |
|---|
| 570 | | - snd_info_free_entry(pstr->proc_info_entry); |
|---|
| 571 | | - pstr->proc_info_entry = NULL; |
|---|
| 572 | 534 | snd_info_free_entry(pstr->proc_root); |
|---|
| 573 | 535 | pstr->proc_root = NULL; |
|---|
| 574 | 536 | return 0; |
|---|
| 537 | +} |
|---|
| 538 | + |
|---|
| 539 | +static struct snd_info_entry * |
|---|
| 540 | +create_substream_info_entry(struct snd_pcm_substream *substream, |
|---|
| 541 | + const char *name, |
|---|
| 542 | + void (*read)(struct snd_info_entry *, |
|---|
| 543 | + struct snd_info_buffer *)) |
|---|
| 544 | +{ |
|---|
| 545 | + struct snd_info_entry *entry; |
|---|
| 546 | + |
|---|
| 547 | + entry = snd_info_create_card_entry(substream->pcm->card, name, |
|---|
| 548 | + substream->proc_root); |
|---|
| 549 | + if (entry) |
|---|
| 550 | + snd_info_set_text_ops(entry, substream, read); |
|---|
| 551 | + return entry; |
|---|
| 575 | 552 | } |
|---|
| 576 | 553 | |
|---|
| 577 | 554 | static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) |
|---|
| .. | .. |
|---|
| 588 | 565 | if (!entry) |
|---|
| 589 | 566 | return -ENOMEM; |
|---|
| 590 | 567 | entry->mode = S_IFDIR | 0555; |
|---|
| 591 | | - if (snd_info_register(entry) < 0) { |
|---|
| 592 | | - snd_info_free_entry(entry); |
|---|
| 593 | | - return -ENOMEM; |
|---|
| 594 | | - } |
|---|
| 595 | 568 | substream->proc_root = entry; |
|---|
| 596 | | - entry = snd_info_create_card_entry(card, "info", substream->proc_root); |
|---|
| 597 | | - if (entry) { |
|---|
| 598 | | - snd_info_set_text_ops(entry, substream, |
|---|
| 599 | | - snd_pcm_substream_proc_info_read); |
|---|
| 600 | | - if (snd_info_register(entry) < 0) { |
|---|
| 601 | | - snd_info_free_entry(entry); |
|---|
| 602 | | - entry = NULL; |
|---|
| 603 | | - } |
|---|
| 604 | | - } |
|---|
| 605 | | - substream->proc_info_entry = entry; |
|---|
| 606 | | - entry = snd_info_create_card_entry(card, "hw_params", |
|---|
| 607 | | - substream->proc_root); |
|---|
| 608 | | - if (entry) { |
|---|
| 609 | | - snd_info_set_text_ops(entry, substream, |
|---|
| 610 | | - snd_pcm_substream_proc_hw_params_read); |
|---|
| 611 | | - if (snd_info_register(entry) < 0) { |
|---|
| 612 | | - snd_info_free_entry(entry); |
|---|
| 613 | | - entry = NULL; |
|---|
| 614 | | - } |
|---|
| 615 | | - } |
|---|
| 616 | | - substream->proc_hw_params_entry = entry; |
|---|
| 617 | | - entry = snd_info_create_card_entry(card, "sw_params", |
|---|
| 618 | | - substream->proc_root); |
|---|
| 619 | | - if (entry) { |
|---|
| 620 | | - snd_info_set_text_ops(entry, substream, |
|---|
| 621 | | - snd_pcm_substream_proc_sw_params_read); |
|---|
| 622 | | - if (snd_info_register(entry) < 0) { |
|---|
| 623 | | - snd_info_free_entry(entry); |
|---|
| 624 | | - entry = NULL; |
|---|
| 625 | | - } |
|---|
| 626 | | - } |
|---|
| 627 | | - substream->proc_sw_params_entry = entry; |
|---|
| 628 | | - entry = snd_info_create_card_entry(card, "status", |
|---|
| 629 | | - substream->proc_root); |
|---|
| 630 | | - if (entry) { |
|---|
| 631 | | - snd_info_set_text_ops(entry, substream, |
|---|
| 632 | | - snd_pcm_substream_proc_status_read); |
|---|
| 633 | | - if (snd_info_register(entry) < 0) { |
|---|
| 634 | | - snd_info_free_entry(entry); |
|---|
| 635 | | - entry = NULL; |
|---|
| 636 | | - } |
|---|
| 637 | | - } |
|---|
| 638 | | - substream->proc_status_entry = entry; |
|---|
| 569 | + |
|---|
| 570 | + create_substream_info_entry(substream, "info", |
|---|
| 571 | + snd_pcm_substream_proc_info_read); |
|---|
| 572 | + create_substream_info_entry(substream, "hw_params", |
|---|
| 573 | + snd_pcm_substream_proc_hw_params_read); |
|---|
| 574 | + create_substream_info_entry(substream, "sw_params", |
|---|
| 575 | + snd_pcm_substream_proc_sw_params_read); |
|---|
| 576 | + create_substream_info_entry(substream, "status", |
|---|
| 577 | + snd_pcm_substream_proc_status_read); |
|---|
| 639 | 578 | |
|---|
| 640 | 579 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
|---|
| 641 | | - entry = snd_info_create_card_entry(card, "xrun_injection", |
|---|
| 642 | | - substream->proc_root); |
|---|
| 580 | + entry = create_substream_info_entry(substream, "xrun_injection", NULL); |
|---|
| 643 | 581 | if (entry) { |
|---|
| 644 | | - entry->private_data = substream; |
|---|
| 645 | | - entry->c.text.read = NULL; |
|---|
| 646 | 582 | entry->c.text.write = snd_pcm_xrun_injection_write; |
|---|
| 647 | 583 | entry->mode = S_IFREG | 0200; |
|---|
| 648 | | - if (snd_info_register(entry) < 0) { |
|---|
| 649 | | - snd_info_free_entry(entry); |
|---|
| 650 | | - entry = NULL; |
|---|
| 651 | | - } |
|---|
| 652 | 584 | } |
|---|
| 653 | | - substream->proc_xrun_injection_entry = entry; |
|---|
| 654 | 585 | #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ |
|---|
| 655 | 586 | |
|---|
| 656 | 587 | return 0; |
|---|
| 657 | 588 | } |
|---|
| 658 | 589 | |
|---|
| 659 | | -static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) |
|---|
| 660 | | -{ |
|---|
| 661 | | - snd_info_free_entry(substream->proc_info_entry); |
|---|
| 662 | | - substream->proc_info_entry = NULL; |
|---|
| 663 | | - snd_info_free_entry(substream->proc_hw_params_entry); |
|---|
| 664 | | - substream->proc_hw_params_entry = NULL; |
|---|
| 665 | | - snd_info_free_entry(substream->proc_sw_params_entry); |
|---|
| 666 | | - substream->proc_sw_params_entry = NULL; |
|---|
| 667 | | - snd_info_free_entry(substream->proc_status_entry); |
|---|
| 668 | | - substream->proc_status_entry = NULL; |
|---|
| 669 | | -#ifdef CONFIG_SND_PCM_XRUN_DEBUG |
|---|
| 670 | | - snd_info_free_entry(substream->proc_xrun_injection_entry); |
|---|
| 671 | | - substream->proc_xrun_injection_entry = NULL; |
|---|
| 672 | | -#endif |
|---|
| 673 | | - snd_info_free_entry(substream->proc_root); |
|---|
| 674 | | - substream->proc_root = NULL; |
|---|
| 675 | | - return 0; |
|---|
| 676 | | -} |
|---|
| 677 | 590 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ |
|---|
| 678 | 591 | static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; } |
|---|
| 679 | 592 | static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; } |
|---|
| 680 | 593 | static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; } |
|---|
| 681 | | -static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; } |
|---|
| 682 | 594 | #endif /* CONFIG_SND_VERBOSE_PROCFS */ |
|---|
| 683 | 595 | |
|---|
| 684 | 596 | static const struct attribute_group *pcm_dev_attr_groups[]; |
|---|
| 597 | + |
|---|
| 598 | +/* |
|---|
| 599 | + * PM callbacks: we need to deal only with suspend here, as the resume is |
|---|
| 600 | + * triggered either from user-space or the driver's resume callback |
|---|
| 601 | + */ |
|---|
| 602 | +#ifdef CONFIG_PM_SLEEP |
|---|
| 603 | +static int do_pcm_suspend(struct device *dev) |
|---|
| 604 | +{ |
|---|
| 605 | + struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); |
|---|
| 606 | + |
|---|
| 607 | + if (!pstr->pcm->no_device_suspend) |
|---|
| 608 | + snd_pcm_suspend_all(pstr->pcm); |
|---|
| 609 | + return 0; |
|---|
| 610 | +} |
|---|
| 611 | +#endif |
|---|
| 612 | + |
|---|
| 613 | +static const struct dev_pm_ops pcm_dev_pm_ops = { |
|---|
| 614 | + SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL) |
|---|
| 615 | +}; |
|---|
| 616 | + |
|---|
| 617 | +/* device type for PCM -- basically only for passing PM callbacks */ |
|---|
| 618 | +static const struct device_type pcm_dev_type = { |
|---|
| 619 | + .name = "pcm", |
|---|
| 620 | + .pm = &pcm_dev_pm_ops, |
|---|
| 621 | +}; |
|---|
| 685 | 622 | |
|---|
| 686 | 623 | /** |
|---|
| 687 | 624 | * snd_pcm_new_stream - create a new PCM stream |
|---|
| .. | .. |
|---|
| 713 | 650 | |
|---|
| 714 | 651 | snd_device_initialize(&pstr->dev, pcm->card); |
|---|
| 715 | 652 | pstr->dev.groups = pcm_dev_attr_groups; |
|---|
| 653 | + pstr->dev.type = &pcm_dev_type; |
|---|
| 716 | 654 | dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, |
|---|
| 717 | 655 | stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); |
|---|
| 718 | 656 | |
|---|
| .. | .. |
|---|
| 753 | 691 | } |
|---|
| 754 | 692 | } |
|---|
| 755 | 693 | substream->group = &substream->self_group; |
|---|
| 756 | | - spin_lock_init(&substream->self_group.lock); |
|---|
| 757 | | - mutex_init(&substream->self_group.mutex); |
|---|
| 758 | | - INIT_LIST_HEAD(&substream->self_group.substreams); |
|---|
| 694 | + snd_pcm_group_init(&substream->self_group); |
|---|
| 759 | 695 | list_add_tail(&substream->link_list, &substream->self_group.substreams); |
|---|
| 760 | 696 | atomic_set(&substream->mmap_count, 0); |
|---|
| 761 | 697 | prev = substream; |
|---|
| .. | .. |
|---|
| 770 | 706 | { |
|---|
| 771 | 707 | struct snd_pcm *pcm; |
|---|
| 772 | 708 | int err; |
|---|
| 773 | | - static struct snd_device_ops ops = { |
|---|
| 709 | + static const struct snd_device_ops ops = { |
|---|
| 774 | 710 | .dev_free = snd_pcm_dev_free, |
|---|
| 775 | 711 | .dev_register = snd_pcm_dev_register, |
|---|
| 776 | 712 | .dev_disconnect = snd_pcm_dev_disconnect, |
|---|
| 777 | 713 | }; |
|---|
| 778 | | - static struct snd_device_ops internal_ops = { |
|---|
| 714 | + static const struct snd_device_ops internal_ops = { |
|---|
| 779 | 715 | .dev_free = snd_pcm_dev_free, |
|---|
| 780 | 716 | }; |
|---|
| 781 | 717 | |
|---|
| .. | .. |
|---|
| 881 | 817 | up_write(&card->controls_rwsem); |
|---|
| 882 | 818 | pstr->chmap_kctl = NULL; |
|---|
| 883 | 819 | } |
|---|
| 884 | | - if (pstr->vol_kctl) { |
|---|
| 885 | | - snd_ctl_remove(pstr->pcm->card, pstr->vol_kctl); |
|---|
| 886 | | - pstr->vol_kctl = NULL; |
|---|
| 887 | | - } |
|---|
| 888 | | - if (pstr->usr_kctl) { |
|---|
| 889 | | - snd_ctl_remove(pstr->pcm->card, pstr->usr_kctl); |
|---|
| 890 | | - pstr->usr_kctl = NULL; |
|---|
| 891 | | - } |
|---|
| 892 | 820 | } |
|---|
| 893 | 821 | |
|---|
| 894 | 822 | static void snd_pcm_free_stream(struct snd_pcm_str * pstr) |
|---|
| .. | .. |
|---|
| 897 | 825 | #if IS_ENABLED(CONFIG_SND_PCM_OSS) |
|---|
| 898 | 826 | struct snd_pcm_oss_setup *setup, *setupn; |
|---|
| 899 | 827 | #endif |
|---|
| 828 | + |
|---|
| 829 | + /* free all proc files under the stream */ |
|---|
| 830 | + snd_pcm_stream_proc_done(pstr); |
|---|
| 831 | + |
|---|
| 900 | 832 | substream = pstr->substream; |
|---|
| 901 | 833 | while (substream) { |
|---|
| 902 | 834 | substream_next = substream->next; |
|---|
| 903 | 835 | snd_pcm_timer_done(substream); |
|---|
| 904 | | - snd_pcm_substream_proc_done(substream); |
|---|
| 905 | 836 | kfree(substream); |
|---|
| 906 | 837 | substream = substream_next; |
|---|
| 907 | 838 | } |
|---|
| 908 | | - snd_pcm_stream_proc_done(pstr); |
|---|
| 909 | 839 | #if IS_ENABLED(CONFIG_SND_PCM_OSS) |
|---|
| 910 | 840 | for (setup = pstr->oss.setup_list; setup; setup = setupn) { |
|---|
| 911 | 841 | setupn = setup->next; |
|---|
| .. | .. |
|---|
| 1018 | 948 | return -ENOMEM; |
|---|
| 1019 | 949 | |
|---|
| 1020 | 950 | size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)); |
|---|
| 1021 | | - runtime->status = snd_malloc_pages(size, GFP_KERNEL); |
|---|
| 951 | + runtime->status = alloc_pages_exact(size, GFP_KERNEL); |
|---|
| 1022 | 952 | if (runtime->status == NULL) { |
|---|
| 1023 | 953 | kfree(runtime); |
|---|
| 1024 | 954 | return -ENOMEM; |
|---|
| 1025 | 955 | } |
|---|
| 1026 | | - memset((void*)runtime->status, 0, size); |
|---|
| 956 | + memset(runtime->status, 0, size); |
|---|
| 1027 | 957 | |
|---|
| 1028 | 958 | size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)); |
|---|
| 1029 | | - runtime->control = snd_malloc_pages(size, GFP_KERNEL); |
|---|
| 959 | + runtime->control = alloc_pages_exact(size, GFP_KERNEL); |
|---|
| 1030 | 960 | if (runtime->control == NULL) { |
|---|
| 1031 | | - snd_free_pages((void*)runtime->status, |
|---|
| 961 | + free_pages_exact(runtime->status, |
|---|
| 1032 | 962 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))); |
|---|
| 1033 | 963 | kfree(runtime); |
|---|
| 1034 | 964 | return -ENOMEM; |
|---|
| 1035 | 965 | } |
|---|
| 1036 | | - memset((void*)runtime->control, 0, size); |
|---|
| 966 | + memset(runtime->control, 0, size); |
|---|
| 1037 | 967 | |
|---|
| 1038 | 968 | init_waitqueue_head(&runtime->sleep); |
|---|
| 1039 | 969 | init_waitqueue_head(&runtime->tsleep); |
|---|
| 1040 | 970 | |
|---|
| 1041 | 971 | runtime->status->state = SNDRV_PCM_STATE_OPEN; |
|---|
| 972 | + mutex_init(&runtime->buffer_mutex); |
|---|
| 973 | + atomic_set(&runtime->buffer_accessing, 0); |
|---|
| 1042 | 974 | |
|---|
| 1043 | 975 | substream->runtime = runtime; |
|---|
| 1044 | 976 | substream->private_data = pcm->private_data; |
|---|
| .. | .. |
|---|
| 1059 | 991 | runtime = substream->runtime; |
|---|
| 1060 | 992 | if (runtime->private_free != NULL) |
|---|
| 1061 | 993 | runtime->private_free(runtime); |
|---|
| 1062 | | - snd_free_pages((void*)runtime->status, |
|---|
| 994 | + free_pages_exact(runtime->status, |
|---|
| 1063 | 995 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))); |
|---|
| 1064 | | - snd_free_pages((void*)runtime->control, |
|---|
| 996 | + free_pages_exact(runtime->control, |
|---|
| 1065 | 997 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); |
|---|
| 1066 | 998 | kfree(runtime->hw_constraints.rules); |
|---|
| 1067 | 999 | /* Avoid concurrent access to runtime via PCM timer interface */ |
|---|
| 1068 | | - if (substream->timer) |
|---|
| 1000 | + if (substream->timer) { |
|---|
| 1069 | 1001 | spin_lock_irq(&substream->timer->lock); |
|---|
| 1070 | | - substream->runtime = NULL; |
|---|
| 1071 | | - if (substream->timer) |
|---|
| 1002 | + substream->runtime = NULL; |
|---|
| 1072 | 1003 | spin_unlock_irq(&substream->timer->lock); |
|---|
| 1004 | + } else { |
|---|
| 1005 | + substream->runtime = NULL; |
|---|
| 1006 | + } |
|---|
| 1007 | + mutex_destroy(&runtime->buffer_mutex); |
|---|
| 1073 | 1008 | kfree(runtime); |
|---|
| 1074 | 1009 | put_pid(substream->pid); |
|---|
| 1075 | 1010 | substream->pid = NULL; |
|---|
| .. | .. |
|---|
| 1093 | 1028 | str = "none"; |
|---|
| 1094 | 1029 | else |
|---|
| 1095 | 1030 | str = strs[pcm->dev_class]; |
|---|
| 1096 | | - return snprintf(buf, PAGE_SIZE, "%s\n", str); |
|---|
| 1031 | + return sprintf(buf, "%s\n", str); |
|---|
| 1097 | 1032 | } |
|---|
| 1098 | 1033 | |
|---|
| 1099 | 1034 | static DEVICE_ATTR(pcm_class, 0444, show_pcm_class, NULL); |
|---|
| .. | .. |
|---|
| 1183 | 1118 | } |
|---|
| 1184 | 1119 | } |
|---|
| 1185 | 1120 | |
|---|
| 1121 | + for (cidx = 0; cidx < 2; cidx++) |
|---|
| 1122 | + for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
|---|
| 1123 | + snd_pcm_sync_stop(substream, false); |
|---|
| 1124 | + |
|---|
| 1186 | 1125 | pcm_call_notify(pcm, n_disconnect); |
|---|
| 1187 | 1126 | for (cidx = 0; cidx < 2; cidx++) { |
|---|
| 1188 | 1127 | snd_unregister_device(&pcm->streams[cidx].dev); |
|---|