.. | .. |
---|
| 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); |
---|