diff options
Diffstat (limited to 'sound/core')
42 files changed, 1311 insertions, 1272 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 9749f9e8b45c..6e937a8146a1 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
@@ -18,8 +18,12 @@ config SND_DMAENGINE_PCM | |||
18 | config SND_HWDEP | 18 | config SND_HWDEP |
19 | tristate | 19 | tristate |
20 | 20 | ||
21 | config SND_SEQ_DEVICE | ||
22 | tristate | ||
23 | |||
21 | config SND_RAWMIDI | 24 | config SND_RAWMIDI |
22 | tristate | 25 | tristate |
26 | select SND_SEQ_DEVICE if SND_SEQUENCER != n | ||
23 | 27 | ||
24 | config SND_COMPRESS_OFFLOAD | 28 | config SND_COMPRESS_OFFLOAD |
25 | tristate | 29 | tristate |
@@ -33,38 +37,15 @@ config SND_JACK_INPUT_DEV | |||
33 | depends on SND_JACK | 37 | depends on SND_JACK |
34 | default y if INPUT=y || INPUT=SND | 38 | default y if INPUT=y || INPUT=SND |
35 | 39 | ||
36 | config SND_SEQUENCER | ||
37 | tristate "Sequencer support" | ||
38 | select SND_TIMER | ||
39 | help | ||
40 | Say Y or M to enable MIDI sequencer and router support. This | ||
41 | feature allows routing and enqueueing of MIDI events. Events | ||
42 | can be processed at a given time. | ||
43 | |||
44 | Many programs require this feature, so you should enable it | ||
45 | unless you know what you're doing. | ||
46 | |||
47 | config SND_SEQ_DUMMY | ||
48 | tristate "Sequencer dummy client" | ||
49 | depends on SND_SEQUENCER | ||
50 | help | ||
51 | Say Y here to enable the dummy sequencer client. This client | ||
52 | is a simple MIDI-through client: all normal input events are | ||
53 | redirected to the output port immediately. | ||
54 | |||
55 | You don't need this unless you want to connect many MIDI | ||
56 | devices or applications together. | ||
57 | |||
58 | To compile this driver as a module, choose M here: the module | ||
59 | will be called snd-seq-dummy. | ||
60 | |||
61 | config SND_OSSEMUL | 40 | config SND_OSSEMUL |
41 | bool "Enable OSS Emulation" | ||
62 | select SOUND_OSS_CORE | 42 | select SOUND_OSS_CORE |
63 | bool | 43 | help |
44 | This option enables the build of OSS emulation layer. | ||
64 | 45 | ||
65 | config SND_MIXER_OSS | 46 | config SND_MIXER_OSS |
66 | tristate "OSS Mixer API" | 47 | tristate "OSS Mixer API" |
67 | select SND_OSSEMUL | 48 | depends on SND_OSSEMUL |
68 | help | 49 | help |
69 | To enable OSS mixer API emulation (/dev/mixer*), say Y here | 50 | To enable OSS mixer API emulation (/dev/mixer*), say Y here |
70 | and read <file:Documentation/sound/alsa/OSS-Emulation.txt>. | 51 | and read <file:Documentation/sound/alsa/OSS-Emulation.txt>. |
@@ -76,7 +57,7 @@ config SND_MIXER_OSS | |||
76 | 57 | ||
77 | config SND_PCM_OSS | 58 | config SND_PCM_OSS |
78 | tristate "OSS PCM (digital audio) API" | 59 | tristate "OSS PCM (digital audio) API" |
79 | select SND_OSSEMUL | 60 | depends on SND_OSSEMUL |
80 | select SND_PCM | 61 | select SND_PCM |
81 | help | 62 | help |
82 | To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y | 63 | To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y |
@@ -107,20 +88,6 @@ config SND_PCM_TIMER | |||
107 | For some embedded devices, we may disable it to reduce memory | 88 | For some embedded devices, we may disable it to reduce memory |
108 | footprint, about 20KB on x86_64 platform. | 89 | footprint, about 20KB on x86_64 platform. |
109 | 90 | ||
110 | config SND_SEQUENCER_OSS | ||
111 | bool "OSS Sequencer API" | ||
112 | depends on SND_SEQUENCER | ||
113 | select SND_OSSEMUL | ||
114 | help | ||
115 | Say Y here to enable OSS sequencer emulation (both | ||
116 | /dev/sequencer and /dev/music interfaces). | ||
117 | |||
118 | Many programs still use the OSS API, so say Y. | ||
119 | |||
120 | If you choose M in "Sequencer support" (SND_SEQUENCER), | ||
121 | this will be compiled as a module. The module will be called | ||
122 | snd-seq-oss. | ||
123 | |||
124 | config SND_HRTIMER | 91 | config SND_HRTIMER |
125 | tristate "HR-timer backend support" | 92 | tristate "HR-timer backend support" |
126 | depends on HIGH_RES_TIMERS | 93 | depends on HIGH_RES_TIMERS |
@@ -133,14 +100,6 @@ config SND_HRTIMER | |||
133 | To compile this driver as a module, choose M here: the module | 100 | To compile this driver as a module, choose M here: the module |
134 | will be called snd-hrtimer. | 101 | will be called snd-hrtimer. |
135 | 102 | ||
136 | config SND_SEQ_HRTIMER_DEFAULT | ||
137 | bool "Use HR-timer as default sequencer timer" | ||
138 | depends on SND_HRTIMER && SND_SEQUENCER | ||
139 | default y | ||
140 | help | ||
141 | Say Y here to use the HR-timer backend as the default sequencer | ||
142 | timer. | ||
143 | |||
144 | config SND_DYNAMIC_MINORS | 103 | config SND_DYNAMIC_MINORS |
145 | bool "Dynamic device file minor numbers" | 104 | bool "Dynamic device file minor numbers" |
146 | help | 105 | help |
diff --git a/sound/core/Makefile b/sound/core/Makefile index e85d9dd12c2d..e2066e2ef9f8 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile | |||
@@ -22,6 +22,7 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o | |||
22 | 22 | ||
23 | # for trace-points | 23 | # for trace-points |
24 | CFLAGS_pcm_lib.o := -I$(src) | 24 | CFLAGS_pcm_lib.o := -I$(src) |
25 | CFLAGS_pcm_native.o := -I$(src) | ||
25 | 26 | ||
26 | snd-pcm-dmaengine-objs := pcm_dmaengine.o | 27 | snd-pcm-dmaengine-objs := pcm_dmaengine.o |
27 | 28 | ||
@@ -30,6 +31,7 @@ snd-timer-objs := timer.o | |||
30 | snd-hrtimer-objs := hrtimer.o | 31 | snd-hrtimer-objs := hrtimer.o |
31 | snd-rtctimer-objs := rtctimer.o | 32 | snd-rtctimer-objs := rtctimer.o |
32 | snd-hwdep-objs := hwdep.o | 33 | snd-hwdep-objs := hwdep.o |
34 | snd-seq-device-objs := seq_device.o | ||
33 | 35 | ||
34 | snd-compress-objs := compress_offload.o | 36 | snd-compress-objs := compress_offload.o |
35 | 37 | ||
@@ -39,6 +41,7 @@ obj-$(CONFIG_SND_TIMER) += snd-timer.o | |||
39 | obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o | 41 | obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o |
40 | obj-$(CONFIG_SND_PCM) += snd-pcm.o | 42 | obj-$(CONFIG_SND_PCM) += snd-pcm.o |
41 | obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o | 43 | obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o |
44 | obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o | ||
42 | obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o | 45 | obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o |
43 | 46 | ||
44 | obj-$(CONFIG_SND_OSSEMUL) += oss/ | 47 | obj-$(CONFIG_SND_OSSEMUL) += oss/ |
diff --git a/sound/core/control.c b/sound/core/control.c index 6362da17ac3f..3c6be1452e35 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -747,65 +747,45 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, | |||
747 | static int snd_ctl_elem_list(struct snd_card *card, | 747 | static int snd_ctl_elem_list(struct snd_card *card, |
748 | struct snd_ctl_elem_list __user *_list) | 748 | struct snd_ctl_elem_list __user *_list) |
749 | { | 749 | { |
750 | struct list_head *plist; | ||
751 | struct snd_ctl_elem_list list; | 750 | struct snd_ctl_elem_list list; |
752 | struct snd_kcontrol *kctl; | 751 | struct snd_kcontrol *kctl; |
753 | struct snd_ctl_elem_id *dst, *id; | 752 | struct snd_ctl_elem_id id; |
754 | unsigned int offset, space, jidx; | 753 | unsigned int offset, space, jidx; |
754 | int err = 0; | ||
755 | 755 | ||
756 | if (copy_from_user(&list, _list, sizeof(list))) | 756 | if (copy_from_user(&list, _list, sizeof(list))) |
757 | return -EFAULT; | 757 | return -EFAULT; |
758 | offset = list.offset; | 758 | offset = list.offset; |
759 | space = list.space; | 759 | space = list.space; |
760 | /* try limit maximum space */ | 760 | |
761 | if (space > 16384) | 761 | down_read(&card->controls_rwsem); |
762 | return -ENOMEM; | 762 | list.count = card->controls_count; |
763 | list.used = 0; | ||
763 | if (space > 0) { | 764 | if (space > 0) { |
764 | /* allocate temporary buffer for atomic operation */ | 765 | list_for_each_entry(kctl, &card->controls, list) { |
765 | dst = vmalloc(space * sizeof(struct snd_ctl_elem_id)); | 766 | if (offset >= kctl->count) { |
766 | if (dst == NULL) | 767 | offset -= kctl->count; |
767 | return -ENOMEM; | 768 | continue; |
768 | down_read(&card->controls_rwsem); | 769 | } |
769 | list.count = card->controls_count; | 770 | for (jidx = offset; jidx < kctl->count; jidx++) { |
770 | plist = card->controls.next; | 771 | snd_ctl_build_ioff(&id, kctl, jidx); |
771 | while (plist != &card->controls) { | 772 | if (copy_to_user(list.pids + list.used, &id, |
772 | if (offset == 0) | 773 | sizeof(id))) { |
773 | break; | 774 | err = -EFAULT; |
774 | kctl = snd_kcontrol(plist); | 775 | goto out; |
775 | if (offset < kctl->count) | 776 | } |
776 | break; | ||
777 | offset -= kctl->count; | ||
778 | plist = plist->next; | ||
779 | } | ||
780 | list.used = 0; | ||
781 | id = dst; | ||
782 | while (space > 0 && plist != &card->controls) { | ||
783 | kctl = snd_kcontrol(plist); | ||
784 | for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) { | ||
785 | snd_ctl_build_ioff(id, kctl, jidx); | ||
786 | id++; | ||
787 | space--; | ||
788 | list.used++; | 777 | list.used++; |
778 | if (!--space) | ||
779 | goto out; | ||
789 | } | 780 | } |
790 | plist = plist->next; | ||
791 | offset = 0; | 781 | offset = 0; |
792 | } | 782 | } |
793 | up_read(&card->controls_rwsem); | ||
794 | if (list.used > 0 && | ||
795 | copy_to_user(list.pids, dst, | ||
796 | list.used * sizeof(struct snd_ctl_elem_id))) { | ||
797 | vfree(dst); | ||
798 | return -EFAULT; | ||
799 | } | ||
800 | vfree(dst); | ||
801 | } else { | ||
802 | down_read(&card->controls_rwsem); | ||
803 | list.count = card->controls_count; | ||
804 | up_read(&card->controls_rwsem); | ||
805 | } | 783 | } |
806 | if (copy_to_user(_list, &list, sizeof(list))) | 784 | out: |
807 | return -EFAULT; | 785 | up_read(&card->controls_rwsem); |
808 | return 0; | 786 | if (!err && copy_to_user(_list, &list, sizeof(list))) |
787 | err = -EFAULT; | ||
788 | return err; | ||
809 | } | 789 | } |
810 | 790 | ||
811 | static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) | 791 | static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) |
diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c index 84a3cd683068..0249d5e6ac23 100644 --- a/sound/core/ctljack.c +++ b/sound/core/ctljack.c | |||
@@ -23,7 +23,7 @@ static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol, | |||
23 | return 0; | 23 | return 0; |
24 | } | 24 | } |
25 | 25 | ||
26 | static struct snd_kcontrol_new jack_detect_kctl = { | 26 | static const struct snd_kcontrol_new jack_detect_kctl = { |
27 | /* name is filled later */ | 27 | /* name is filled later */ |
28 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 28 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
29 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 29 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
diff --git a/sound/core/info.c b/sound/core/info.c index 8ab72e0f5932..bcf6a48cc70d 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -344,12 +344,12 @@ static ssize_t snd_info_text_entry_write(struct file *file, | |||
344 | } | 344 | } |
345 | } | 345 | } |
346 | if (next > buf->len) { | 346 | if (next > buf->len) { |
347 | char *nbuf = krealloc(buf->buffer, PAGE_ALIGN(next), | 347 | char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); |
348 | GFP_KERNEL | __GFP_ZERO); | ||
349 | if (!nbuf) { | 348 | if (!nbuf) { |
350 | err = -ENOMEM; | 349 | err = -ENOMEM; |
351 | goto error; | 350 | goto error; |
352 | } | 351 | } |
352 | kvfree(buf->buffer); | ||
353 | buf->buffer = nbuf; | 353 | buf->buffer = nbuf; |
354 | buf->len = PAGE_ALIGN(next); | 354 | buf->len = PAGE_ALIGN(next); |
355 | } | 355 | } |
@@ -427,7 +427,7 @@ static int snd_info_text_entry_release(struct inode *inode, struct file *file) | |||
427 | single_release(inode, file); | 427 | single_release(inode, file); |
428 | kfree(data->rbuffer); | 428 | kfree(data->rbuffer); |
429 | if (data->wbuffer) { | 429 | if (data->wbuffer) { |
430 | kfree(data->wbuffer->buffer); | 430 | kvfree(data->wbuffer->buffer); |
431 | kfree(data->wbuffer); | 431 | kfree(data->wbuffer); |
432 | } | 432 | } |
433 | 433 | ||
@@ -652,7 +652,6 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) | |||
652 | *line = '\0'; | 652 | *line = '\0'; |
653 | return 0; | 653 | return 0; |
654 | } | 654 | } |
655 | |||
656 | EXPORT_SYMBOL(snd_info_get_line); | 655 | EXPORT_SYMBOL(snd_info_get_line); |
657 | 656 | ||
658 | /** | 657 | /** |
@@ -690,7 +689,6 @@ const char *snd_info_get_str(char *dest, const char *src, int len) | |||
690 | src++; | 689 | src++; |
691 | return src; | 690 | return src; |
692 | } | 691 | } |
693 | |||
694 | EXPORT_SYMBOL(snd_info_get_str); | 692 | EXPORT_SYMBOL(snd_info_get_str); |
695 | 693 | ||
696 | /* | 694 | /* |
@@ -748,7 +746,6 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, | |||
748 | entry->module = module; | 746 | entry->module = module; |
749 | return entry; | 747 | return entry; |
750 | } | 748 | } |
751 | |||
752 | EXPORT_SYMBOL(snd_info_create_module_entry); | 749 | EXPORT_SYMBOL(snd_info_create_module_entry); |
753 | 750 | ||
754 | /** | 751 | /** |
@@ -772,7 +769,6 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, | |||
772 | } | 769 | } |
773 | return entry; | 770 | return entry; |
774 | } | 771 | } |
775 | |||
776 | EXPORT_SYMBOL(snd_info_create_card_entry); | 772 | EXPORT_SYMBOL(snd_info_create_card_entry); |
777 | 773 | ||
778 | static void snd_info_disconnect(struct snd_info_entry *entry) | 774 | static void snd_info_disconnect(struct snd_info_entry *entry) |
@@ -815,7 +811,6 @@ void snd_info_free_entry(struct snd_info_entry * entry) | |||
815 | entry->private_free(entry); | 811 | entry->private_free(entry); |
816 | kfree(entry); | 812 | kfree(entry); |
817 | } | 813 | } |
818 | |||
819 | EXPORT_SYMBOL(snd_info_free_entry); | 814 | EXPORT_SYMBOL(snd_info_free_entry); |
820 | 815 | ||
821 | /** | 816 | /** |
@@ -858,7 +853,6 @@ int snd_info_register(struct snd_info_entry * entry) | |||
858 | mutex_unlock(&info_mutex); | 853 | mutex_unlock(&info_mutex); |
859 | return 0; | 854 | return 0; |
860 | } | 855 | } |
861 | |||
862 | EXPORT_SYMBOL(snd_info_register); | 856 | EXPORT_SYMBOL(snd_info_register); |
863 | 857 | ||
864 | /* | 858 | /* |
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 1478c8dfd473..f479374b6bd8 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c | |||
@@ -61,7 +61,6 @@ int snd_oss_info_register(int dev, int num, char *string) | |||
61 | mutex_unlock(&strings); | 61 | mutex_unlock(&strings); |
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | |||
65 | EXPORT_SYMBOL(snd_oss_info_register); | 64 | EXPORT_SYMBOL(snd_oss_info_register); |
66 | 65 | ||
67 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) | 66 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) |
diff --git a/sound/core/init.c b/sound/core/init.c index d61d2b3cd521..b4365bcf28a7 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -452,7 +452,6 @@ int snd_card_disconnect(struct snd_card *card) | |||
452 | #endif | 452 | #endif |
453 | return 0; | 453 | return 0; |
454 | } | 454 | } |
455 | |||
456 | EXPORT_SYMBOL(snd_card_disconnect); | 455 | EXPORT_SYMBOL(snd_card_disconnect); |
457 | 456 | ||
458 | static int snd_card_do_free(struct snd_card *card) | 457 | static int snd_card_do_free(struct snd_card *card) |
@@ -718,7 +717,7 @@ int snd_card_add_dev_attr(struct snd_card *card, | |||
718 | 717 | ||
719 | dev_err(card->dev, "Too many groups assigned\n"); | 718 | dev_err(card->dev, "Too many groups assigned\n"); |
720 | return -ENOSPC; | 719 | return -ENOSPC; |
721 | }; | 720 | } |
722 | EXPORT_SYMBOL_GPL(snd_card_add_dev_attr); | 721 | EXPORT_SYMBOL_GPL(snd_card_add_dev_attr); |
723 | 722 | ||
724 | /** | 723 | /** |
@@ -775,7 +774,6 @@ int snd_card_register(struct snd_card *card) | |||
775 | #endif | 774 | #endif |
776 | return 0; | 775 | return 0; |
777 | } | 776 | } |
778 | |||
779 | EXPORT_SYMBOL(snd_card_register); | 777 | EXPORT_SYMBOL(snd_card_register); |
780 | 778 | ||
781 | #ifdef CONFIG_SND_PROC_FS | 779 | #ifdef CONFIG_SND_PROC_FS |
@@ -895,7 +893,6 @@ int snd_component_add(struct snd_card *card, const char *component) | |||
895 | strcat(card->components, component); | 893 | strcat(card->components, component); |
896 | return 0; | 894 | return 0; |
897 | } | 895 | } |
898 | |||
899 | EXPORT_SYMBOL(snd_component_add); | 896 | EXPORT_SYMBOL(snd_component_add); |
900 | 897 | ||
901 | /** | 898 | /** |
@@ -930,7 +927,6 @@ int snd_card_file_add(struct snd_card *card, struct file *file) | |||
930 | spin_unlock(&card->files_lock); | 927 | spin_unlock(&card->files_lock); |
931 | return 0; | 928 | return 0; |
932 | } | 929 | } |
933 | |||
934 | EXPORT_SYMBOL(snd_card_file_add); | 930 | EXPORT_SYMBOL(snd_card_file_add); |
935 | 931 | ||
936 | /** | 932 | /** |
@@ -972,7 +968,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
972 | put_device(&card->card_dev); | 968 | put_device(&card->card_dev); |
973 | return 0; | 969 | return 0; |
974 | } | 970 | } |
975 | |||
976 | EXPORT_SYMBOL(snd_card_file_remove); | 971 | EXPORT_SYMBOL(snd_card_file_remove); |
977 | 972 | ||
978 | #ifdef CONFIG_PM | 973 | #ifdef CONFIG_PM |
@@ -1012,6 +1007,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) | |||
1012 | remove_wait_queue(&card->power_sleep, &wait); | 1007 | remove_wait_queue(&card->power_sleep, &wait); |
1013 | return result; | 1008 | return result; |
1014 | } | 1009 | } |
1015 | |||
1016 | EXPORT_SYMBOL(snd_power_wait); | 1010 | EXPORT_SYMBOL(snd_power_wait); |
1017 | #endif /* CONFIG_PM */ | 1011 | #endif /* CONFIG_PM */ |
diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 31e8544d7f2d..7a8515abb5f9 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c | |||
@@ -55,7 +55,6 @@ void snd_dma_program(unsigned long dma, | |||
55 | enable_dma(dma); | 55 | enable_dma(dma); |
56 | release_dma_lock(flags); | 56 | release_dma_lock(flags); |
57 | } | 57 | } |
58 | |||
59 | EXPORT_SYMBOL(snd_dma_program); | 58 | EXPORT_SYMBOL(snd_dma_program); |
60 | 59 | ||
61 | /** | 60 | /** |
@@ -73,7 +72,6 @@ void snd_dma_disable(unsigned long dma) | |||
73 | disable_dma(dma); | 72 | disable_dma(dma); |
74 | release_dma_lock(flags); | 73 | release_dma_lock(flags); |
75 | } | 74 | } |
76 | |||
77 | EXPORT_SYMBOL(snd_dma_disable); | 75 | EXPORT_SYMBOL(snd_dma_disable); |
78 | 76 | ||
79 | /** | 77 | /** |
@@ -113,5 +111,4 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) | |||
113 | else | 111 | else |
114 | return size - result; | 112 | return size - result; |
115 | } | 113 | } |
116 | |||
117 | EXPORT_SYMBOL(snd_dma_pointer); | 114 | EXPORT_SYMBOL(snd_dma_pointer); |
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index f05cb6a8cbe0..7f89d3c79a4b 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
@@ -54,6 +54,7 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags) | |||
54 | pg = get_order(size); | 54 | pg = get_order(size); |
55 | return (void *) __get_free_pages(gfp_flags, pg); | 55 | return (void *) __get_free_pages(gfp_flags, pg); |
56 | } | 56 | } |
57 | EXPORT_SYMBOL(snd_malloc_pages); | ||
57 | 58 | ||
58 | /** | 59 | /** |
59 | * snd_free_pages - release the pages | 60 | * snd_free_pages - release the pages |
@@ -71,6 +72,7 @@ void snd_free_pages(void *ptr, size_t size) | |||
71 | pg = get_order(size); | 72 | pg = get_order(size); |
72 | free_pages((unsigned long) ptr, pg); | 73 | free_pages((unsigned long) ptr, pg); |
73 | } | 74 | } |
75 | EXPORT_SYMBOL(snd_free_pages); | ||
74 | 76 | ||
75 | /* | 77 | /* |
76 | * | 78 | * |
@@ -217,6 +219,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, | |||
217 | dmab->bytes = size; | 219 | dmab->bytes = size; |
218 | return 0; | 220 | return 0; |
219 | } | 221 | } |
222 | EXPORT_SYMBOL(snd_dma_alloc_pages); | ||
220 | 223 | ||
221 | /** | 224 | /** |
222 | * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback | 225 | * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback |
@@ -254,6 +257,7 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, | |||
254 | return -ENOMEM; | 257 | return -ENOMEM; |
255 | return 0; | 258 | return 0; |
256 | } | 259 | } |
260 | EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); | ||
257 | 261 | ||
258 | 262 | ||
259 | /** | 263 | /** |
@@ -287,13 +291,4 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) | |||
287 | pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); | 291 | pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); |
288 | } | 292 | } |
289 | } | 293 | } |
290 | |||
291 | /* | ||
292 | * exports | ||
293 | */ | ||
294 | EXPORT_SYMBOL(snd_dma_alloc_pages); | ||
295 | EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); | ||
296 | EXPORT_SYMBOL(snd_dma_free_pages); | 294 | EXPORT_SYMBOL(snd_dma_free_pages); |
297 | |||
298 | EXPORT_SYMBOL(snd_malloc_pages); | ||
299 | EXPORT_SYMBOL(snd_free_pages); | ||
diff --git a/sound/core/memory.c b/sound/core/memory.c index 4cd664efad77..19c9ea90d9bf 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c | |||
@@ -55,7 +55,6 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size | |||
55 | return 0; | 55 | return 0; |
56 | #endif | 56 | #endif |
57 | } | 57 | } |
58 | |||
59 | EXPORT_SYMBOL(copy_to_user_fromio); | 58 | EXPORT_SYMBOL(copy_to_user_fromio); |
60 | 59 | ||
61 | /** | 60 | /** |
@@ -88,5 +87,4 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size | |||
88 | return 0; | 87 | return 0; |
89 | #endif | 88 | #endif |
90 | } | 89 | } |
91 | |||
92 | EXPORT_SYMBOL(copy_from_user_toio); | 90 | EXPORT_SYMBOL(copy_from_user_toio); |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 21b228046e88..0f818d593c9e 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
@@ -48,7 +48,6 @@ void release_and_free_resource(struct resource *res) | |||
48 | kfree(res); | 48 | kfree(res); |
49 | } | 49 | } |
50 | } | 50 | } |
51 | |||
52 | EXPORT_SYMBOL(release_and_free_resource); | 51 | EXPORT_SYMBOL(release_and_free_resource); |
53 | 52 | ||
54 | #ifdef CONFIG_SND_VERBOSE_PRINTK | 53 | #ifdef CONFIG_SND_VERBOSE_PRINTK |
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index 6faa1d719206..d870b2d93135 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c | |||
@@ -26,9 +26,9 @@ | |||
26 | #include "pcm_plugin.h" | 26 | #include "pcm_plugin.h" |
27 | 27 | ||
28 | #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) | 28 | #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) |
29 | #define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1) | 29 | #define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count) |
30 | #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) | 30 | #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) |
31 | #define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1) | 31 | #define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count) |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Basic io plugin | 34 | * Basic io plugin |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 2ff9c12d664a..379bf486ccc7 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -395,6 +395,7 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l | |||
395 | fmixer.mixer = card->mixer_oss; | 395 | fmixer.mixer = card->mixer_oss; |
396 | return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); | 396 | return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); |
397 | } | 397 | } |
398 | EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); | ||
398 | 399 | ||
399 | #ifdef CONFIG_COMPAT | 400 | #ifdef CONFIG_COMPAT |
400 | /* all compatible */ | 401 | /* all compatible */ |
@@ -1425,5 +1426,3 @@ static void __exit alsa_mixer_oss_exit(void) | |||
1425 | 1426 | ||
1426 | module_init(alsa_mixer_oss_init) | 1427 | module_init(alsa_mixer_oss_init) |
1427 | module_exit(alsa_mixer_oss_exit) | 1428 | module_exit(alsa_mixer_oss_exit) |
1428 | |||
1429 | EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); | ||
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index cd8b7bef8d06..e49f448ee04f 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -67,18 +67,6 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file); | |||
67 | static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file); | 67 | static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file); |
68 | static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file); | 68 | static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file); |
69 | 69 | ||
70 | static inline mm_segment_t snd_enter_user(void) | ||
71 | { | ||
72 | mm_segment_t fs = get_fs(); | ||
73 | set_fs(get_ds()); | ||
74 | return fs; | ||
75 | } | ||
76 | |||
77 | static inline void snd_leave_user(mm_segment_t fs) | ||
78 | { | ||
79 | set_fs(fs); | ||
80 | } | ||
81 | |||
82 | /* | 70 | /* |
83 | * helper functions to process hw_params | 71 | * helper functions to process hw_params |
84 | */ | 72 | */ |
@@ -799,7 +787,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, | |||
799 | static int choose_rate(struct snd_pcm_substream *substream, | 787 | static int choose_rate(struct snd_pcm_substream *substream, |
800 | struct snd_pcm_hw_params *params, unsigned int best_rate) | 788 | struct snd_pcm_hw_params *params, unsigned int best_rate) |
801 | { | 789 | { |
802 | struct snd_interval *it; | 790 | const struct snd_interval *it; |
803 | struct snd_pcm_hw_params *save; | 791 | struct snd_pcm_hw_params *save; |
804 | unsigned int rate, prev; | 792 | unsigned int rate, prev; |
805 | 793 | ||
@@ -807,7 +795,7 @@ static int choose_rate(struct snd_pcm_substream *substream, | |||
807 | if (save == NULL) | 795 | if (save == NULL) |
808 | return -ENOMEM; | 796 | return -ENOMEM; |
809 | *save = *params; | 797 | *save = *params; |
810 | it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE); | 798 | it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE); |
811 | 799 | ||
812 | /* try multiples of the best rate */ | 800 | /* try multiples of the best rate */ |
813 | rate = best_rate; | 801 | rate = best_rate; |
@@ -848,7 +836,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, | |||
848 | int direct; | 836 | int direct; |
849 | snd_pcm_format_t format, sformat; | 837 | snd_pcm_format_t format, sformat; |
850 | int n; | 838 | int n; |
851 | struct snd_mask sformat_mask; | 839 | const struct snd_mask *sformat_mask; |
852 | struct snd_mask mask; | 840 | struct snd_mask mask; |
853 | 841 | ||
854 | if (trylock) { | 842 | if (trylock) { |
@@ -891,18 +879,18 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, | |||
891 | 879 | ||
892 | format = snd_pcm_oss_format_from(runtime->oss.format); | 880 | format = snd_pcm_oss_format_from(runtime->oss.format); |
893 | 881 | ||
894 | sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT); | 882 | sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT); |
895 | if (direct) | 883 | if (direct) |
896 | sformat = format; | 884 | sformat = format; |
897 | else | 885 | else |
898 | sformat = snd_pcm_plug_slave_format(format, &sformat_mask); | 886 | sformat = snd_pcm_plug_slave_format(format, sformat_mask); |
899 | 887 | ||
900 | if ((__force int)sformat < 0 || | 888 | if ((__force int)sformat < 0 || |
901 | !snd_mask_test(&sformat_mask, (__force int)sformat)) { | 889 | !snd_mask_test(sformat_mask, (__force int)sformat)) { |
902 | for (sformat = (__force snd_pcm_format_t)0; | 890 | for (sformat = (__force snd_pcm_format_t)0; |
903 | (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST; | 891 | (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST; |
904 | sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { | 892 | sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { |
905 | if (snd_mask_test(&sformat_mask, (__force int)sformat) && | 893 | if (snd_mask_test(sformat_mask, (__force int)sformat) && |
906 | snd_pcm_oss_format_to(sformat) >= 0) | 894 | snd_pcm_oss_format_to(sformat) >= 0) |
907 | break; | 895 | break; |
908 | } | 896 | } |
@@ -1191,14 +1179,8 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const | |||
1191 | if (ret < 0) | 1179 | if (ret < 0) |
1192 | break; | 1180 | break; |
1193 | } | 1181 | } |
1194 | if (in_kernel) { | 1182 | ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, |
1195 | mm_segment_t fs; | 1183 | frames, in_kernel); |
1196 | fs = snd_enter_user(); | ||
1197 | ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); | ||
1198 | snd_leave_user(fs); | ||
1199 | } else { | ||
1200 | ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); | ||
1201 | } | ||
1202 | if (ret != -EPIPE && ret != -ESTRPIPE) | 1184 | if (ret != -EPIPE && ret != -ESTRPIPE) |
1203 | break; | 1185 | break; |
1204 | /* test, if we can't store new data, because the stream */ | 1186 | /* test, if we can't store new data, because the stream */ |
@@ -1234,14 +1216,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p | |||
1234 | ret = snd_pcm_oss_capture_position_fixup(substream, &delay); | 1216 | ret = snd_pcm_oss_capture_position_fixup(substream, &delay); |
1235 | if (ret < 0) | 1217 | if (ret < 0) |
1236 | break; | 1218 | break; |
1237 | if (in_kernel) { | 1219 | ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, |
1238 | mm_segment_t fs; | 1220 | frames, in_kernel); |
1239 | fs = snd_enter_user(); | ||
1240 | ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); | ||
1241 | snd_leave_user(fs); | ||
1242 | } else { | ||
1243 | ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); | ||
1244 | } | ||
1245 | if (ret == -EPIPE) { | 1221 | if (ret == -EPIPE) { |
1246 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { | 1222 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { |
1247 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); | 1223 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); |
@@ -1256,7 +1232,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p | |||
1256 | return ret; | 1232 | return ret; |
1257 | } | 1233 | } |
1258 | 1234 | ||
1259 | snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) | 1235 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS |
1236 | snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames) | ||
1260 | { | 1237 | { |
1261 | struct snd_pcm_runtime *runtime = substream->runtime; | 1238 | struct snd_pcm_runtime *runtime = substream->runtime; |
1262 | int ret; | 1239 | int ret; |
@@ -1273,14 +1250,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void | |||
1273 | if (ret < 0) | 1250 | if (ret < 0) |
1274 | break; | 1251 | break; |
1275 | } | 1252 | } |
1276 | if (in_kernel) { | 1253 | ret = snd_pcm_kernel_writev(substream, bufs, frames); |
1277 | mm_segment_t fs; | ||
1278 | fs = snd_enter_user(); | ||
1279 | ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); | ||
1280 | snd_leave_user(fs); | ||
1281 | } else { | ||
1282 | ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); | ||
1283 | } | ||
1284 | if (ret != -EPIPE && ret != -ESTRPIPE) | 1254 | if (ret != -EPIPE && ret != -ESTRPIPE) |
1285 | break; | 1255 | break; |
1286 | 1256 | ||
@@ -1292,7 +1262,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void | |||
1292 | return ret; | 1262 | return ret; |
1293 | } | 1263 | } |
1294 | 1264 | ||
1295 | snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) | 1265 | snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames) |
1296 | { | 1266 | { |
1297 | struct snd_pcm_runtime *runtime = substream->runtime; | 1267 | struct snd_pcm_runtime *runtime = substream->runtime; |
1298 | int ret; | 1268 | int ret; |
@@ -1313,19 +1283,13 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void * | |||
1313 | if (ret < 0) | 1283 | if (ret < 0) |
1314 | break; | 1284 | break; |
1315 | } | 1285 | } |
1316 | if (in_kernel) { | 1286 | ret = snd_pcm_kernel_readv(substream, bufs, frames); |
1317 | mm_segment_t fs; | ||
1318 | fs = snd_enter_user(); | ||
1319 | ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); | ||
1320 | snd_leave_user(fs); | ||
1321 | } else { | ||
1322 | ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); | ||
1323 | } | ||
1324 | if (ret != -EPIPE && ret != -ESTRPIPE) | 1287 | if (ret != -EPIPE && ret != -ESTRPIPE) |
1325 | break; | 1288 | break; |
1326 | } | 1289 | } |
1327 | return ret; | 1290 | return ret; |
1328 | } | 1291 | } |
1292 | #endif /* CONFIG_SND_PCM_OSS_PLUGINS */ | ||
1329 | 1293 | ||
1330 | static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel) | 1294 | static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel) |
1331 | { | 1295 | { |
@@ -1650,27 +1614,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) | |||
1650 | size = runtime->control->appl_ptr % runtime->period_size; | 1614 | size = runtime->control->appl_ptr % runtime->period_size; |
1651 | if (size > 0) { | 1615 | if (size > 0) { |
1652 | size = runtime->period_size - size; | 1616 | size = runtime->period_size - size; |
1653 | if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { | 1617 | if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
1654 | size = (runtime->frame_bits * size) / 8; | 1618 | snd_pcm_lib_write(substream, NULL, size); |
1655 | while (size > 0) { | 1619 | else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) |
1656 | mm_segment_t fs; | 1620 | snd_pcm_lib_writev(substream, NULL, size); |
1657 | size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; | ||
1658 | size -= size1; | ||
1659 | size1 *= 8; | ||
1660 | size1 /= runtime->sample_bits; | ||
1661 | snd_pcm_format_set_silence(runtime->format, | ||
1662 | runtime->oss.buffer, | ||
1663 | size1); | ||
1664 | size1 /= runtime->channels; /* frames */ | ||
1665 | fs = snd_enter_user(); | ||
1666 | snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); | ||
1667 | snd_leave_user(fs); | ||
1668 | } | ||
1669 | } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { | ||
1670 | void __user *buffers[runtime->channels]; | ||
1671 | memset(buffers, 0, runtime->channels * sizeof(void *)); | ||
1672 | snd_pcm_lib_writev(substream, buffers, size); | ||
1673 | } | ||
1674 | } | 1621 | } |
1675 | mutex_unlock(&runtime->oss.params_lock); | 1622 | mutex_unlock(&runtime->oss.params_lock); |
1676 | /* | 1623 | /* |
@@ -1780,7 +1727,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) | |||
1780 | int direct; | 1727 | int direct; |
1781 | struct snd_pcm_hw_params *params; | 1728 | struct snd_pcm_hw_params *params; |
1782 | unsigned int formats = 0; | 1729 | unsigned int formats = 0; |
1783 | struct snd_mask format_mask; | 1730 | const struct snd_mask *format_mask; |
1784 | int fmt; | 1731 | int fmt; |
1785 | 1732 | ||
1786 | if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) | 1733 | if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) |
@@ -1802,12 +1749,12 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) | |||
1802 | return -ENOMEM; | 1749 | return -ENOMEM; |
1803 | _snd_pcm_hw_params_any(params); | 1750 | _snd_pcm_hw_params_any(params); |
1804 | err = snd_pcm_hw_refine(substream, params); | 1751 | err = snd_pcm_hw_refine(substream, params); |
1805 | format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 1752 | format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); |
1806 | kfree(params); | 1753 | kfree(params); |
1807 | if (err < 0) | 1754 | if (err < 0) |
1808 | return err; | 1755 | return err; |
1809 | for (fmt = 0; fmt < 32; ++fmt) { | 1756 | for (fmt = 0; fmt < 32; ++fmt) { |
1810 | if (snd_mask_test(&format_mask, fmt)) { | 1757 | if (snd_mask_test(format_mask, fmt)) { |
1811 | int f = snd_pcm_oss_format_to(fmt); | 1758 | int f = snd_pcm_oss_format_to(fmt); |
1812 | if (f >= 0) | 1759 | if (f >= 0) |
1813 | formats |= f; | 1760 | formats |= f; |
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 727ac44d39f4..cadc93792868 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c | |||
@@ -266,7 +266,8 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc | |||
266 | return frames; | 266 | return frames; |
267 | } | 267 | } |
268 | 268 | ||
269 | static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format) | 269 | static int snd_pcm_plug_formats(const struct snd_mask *mask, |
270 | snd_pcm_format_t format) | ||
270 | { | 271 | { |
271 | struct snd_mask formats = *mask; | 272 | struct snd_mask formats = *mask; |
272 | u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | | 273 | u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | |
@@ -309,7 +310,7 @@ static snd_pcm_format_t preferred_formats[] = { | |||
309 | }; | 310 | }; |
310 | 311 | ||
311 | snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, | 312 | snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, |
312 | struct snd_mask *format_mask) | 313 | const struct snd_mask *format_mask) |
313 | { | 314 | { |
314 | int i; | 315 | int i; |
315 | 316 | ||
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index a5035c2369a6..c9cd29d86efd 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h | |||
@@ -126,7 +126,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream, | |||
126 | struct snd_pcm_hw_params *slave_params); | 126 | struct snd_pcm_hw_params *slave_params); |
127 | 127 | ||
128 | snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, | 128 | snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, |
129 | struct snd_mask *format_mask); | 129 | const struct snd_mask *format_mask); |
130 | 130 | ||
131 | int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin); | 131 | int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin); |
132 | 132 | ||
@@ -162,17 +162,15 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, | |||
162 | snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, | 162 | snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, |
163 | char *ptr, snd_pcm_uframes_t size, int in_kernel); | 163 | char *ptr, snd_pcm_uframes_t size, int in_kernel); |
164 | snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, | 164 | snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, |
165 | void **bufs, snd_pcm_uframes_t frames, | 165 | void **bufs, snd_pcm_uframes_t frames); |
166 | int in_kernel); | ||
167 | snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, | 166 | snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, |
168 | void **bufs, snd_pcm_uframes_t frames, | 167 | void **bufs, snd_pcm_uframes_t frames); |
169 | int in_kernel); | ||
170 | 168 | ||
171 | #else | 169 | #else |
172 | 170 | ||
173 | static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; } | 171 | static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; } |
174 | static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; } | 172 | static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; } |
175 | static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; } | 173 | static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; } |
176 | 174 | ||
177 | #endif | 175 | #endif |
178 | 176 | ||
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e980aa678d0..89c7485519cb 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -31,13 +31,17 @@ | |||
31 | #include <sound/control.h> | 31 | #include <sound/control.h> |
32 | #include <sound/info.h> | 32 | #include <sound/info.h> |
33 | 33 | ||
34 | #include "pcm_local.h" | ||
35 | |||
34 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); | 36 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); |
35 | MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); | 37 | MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); |
36 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
37 | 39 | ||
38 | static LIST_HEAD(snd_pcm_devices); | 40 | static LIST_HEAD(snd_pcm_devices); |
39 | static LIST_HEAD(snd_pcm_notify_list); | ||
40 | static DEFINE_MUTEX(register_mutex); | 41 | static DEFINE_MUTEX(register_mutex); |
42 | #if IS_ENABLED(CONFIG_SND_PCM_OSS) | ||
43 | static LIST_HEAD(snd_pcm_notify_list); | ||
44 | #endif | ||
41 | 45 | ||
42 | static int snd_pcm_free(struct snd_pcm *pcm); | 46 | static int snd_pcm_free(struct snd_pcm *pcm); |
43 | static int snd_pcm_dev_free(struct snd_device *device); | 47 | static int snd_pcm_dev_free(struct snd_device *device); |
@@ -884,16 +888,23 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
884 | put_device(&pstr->dev); | 888 | put_device(&pstr->dev); |
885 | } | 889 | } |
886 | 890 | ||
891 | #if IS_ENABLED(CONFIG_SND_PCM_OSS) | ||
892 | #define pcm_call_notify(pcm, call) \ | ||
893 | do { \ | ||
894 | struct snd_pcm_notify *_notify; \ | ||
895 | list_for_each_entry(_notify, &snd_pcm_notify_list, list) \ | ||
896 | _notify->call(pcm); \ | ||
897 | } while (0) | ||
898 | #else | ||
899 | #define pcm_call_notify(pcm, call) do {} while (0) | ||
900 | #endif | ||
901 | |||
887 | static int snd_pcm_free(struct snd_pcm *pcm) | 902 | static int snd_pcm_free(struct snd_pcm *pcm) |
888 | { | 903 | { |
889 | struct snd_pcm_notify *notify; | ||
890 | |||
891 | if (!pcm) | 904 | if (!pcm) |
892 | return 0; | 905 | return 0; |
893 | if (!pcm->internal) { | 906 | if (!pcm->internal) |
894 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | 907 | pcm_call_notify(pcm, n_unregister); |
895 | notify->n_unregister(pcm); | ||
896 | } | ||
897 | if (pcm->private_free) | 908 | if (pcm->private_free) |
898 | pcm->private_free(pcm); | 909 | pcm->private_free(pcm); |
899 | snd_pcm_lib_preallocate_free_for_all(pcm); | 910 | snd_pcm_lib_preallocate_free_for_all(pcm); |
@@ -1056,7 +1067,7 @@ static struct attribute *pcm_dev_attrs[] = { | |||
1056 | NULL | 1067 | NULL |
1057 | }; | 1068 | }; |
1058 | 1069 | ||
1059 | static struct attribute_group pcm_dev_attr_group = { | 1070 | static const struct attribute_group pcm_dev_attr_group = { |
1060 | .attrs = pcm_dev_attrs, | 1071 | .attrs = pcm_dev_attrs, |
1061 | }; | 1072 | }; |
1062 | 1073 | ||
@@ -1069,7 +1080,6 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
1069 | { | 1080 | { |
1070 | int cidx, err; | 1081 | int cidx, err; |
1071 | struct snd_pcm_substream *substream; | 1082 | struct snd_pcm_substream *substream; |
1072 | struct snd_pcm_notify *notify; | ||
1073 | struct snd_pcm *pcm; | 1083 | struct snd_pcm *pcm; |
1074 | 1084 | ||
1075 | if (snd_BUG_ON(!device || !device->device_data)) | 1085 | if (snd_BUG_ON(!device || !device->device_data)) |
@@ -1107,8 +1117,7 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
1107 | snd_pcm_timer_init(substream); | 1117 | snd_pcm_timer_init(substream); |
1108 | } | 1118 | } |
1109 | 1119 | ||
1110 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | 1120 | pcm_call_notify(pcm, n_register); |
1111 | notify->n_register(pcm); | ||
1112 | 1121 | ||
1113 | unlock: | 1122 | unlock: |
1114 | mutex_unlock(®ister_mutex); | 1123 | mutex_unlock(®ister_mutex); |
@@ -1118,7 +1127,6 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
1118 | static int snd_pcm_dev_disconnect(struct snd_device *device) | 1127 | static int snd_pcm_dev_disconnect(struct snd_device *device) |
1119 | { | 1128 | { |
1120 | struct snd_pcm *pcm = device->device_data; | 1129 | struct snd_pcm *pcm = device->device_data; |
1121 | struct snd_pcm_notify *notify; | ||
1122 | struct snd_pcm_substream *substream; | 1130 | struct snd_pcm_substream *substream; |
1123 | int cidx; | 1131 | int cidx; |
1124 | 1132 | ||
@@ -1138,8 +1146,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
1138 | } | 1146 | } |
1139 | } | 1147 | } |
1140 | if (!pcm->internal) { | 1148 | if (!pcm->internal) { |
1141 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | 1149 | pcm_call_notify(pcm, n_disconnect); |
1142 | notify->n_disconnect(pcm); | ||
1143 | } | 1150 | } |
1144 | for (cidx = 0; cidx < 2; cidx++) { | 1151 | for (cidx = 0; cidx < 2; cidx++) { |
1145 | if (!pcm->internal) | 1152 | if (!pcm->internal) |
@@ -1151,6 +1158,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
1151 | return 0; | 1158 | return 0; |
1152 | } | 1159 | } |
1153 | 1160 | ||
1161 | #if IS_ENABLED(CONFIG_SND_PCM_OSS) | ||
1154 | /** | 1162 | /** |
1155 | * snd_pcm_notify - Add/remove the notify list | 1163 | * snd_pcm_notify - Add/remove the notify list |
1156 | * @notify: PCM notify list | 1164 | * @notify: PCM notify list |
@@ -1183,6 +1191,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | |||
1183 | return 0; | 1191 | return 0; |
1184 | } | 1192 | } |
1185 | EXPORT_SYMBOL(snd_pcm_notify); | 1193 | EXPORT_SYMBOL(snd_pcm_notify); |
1194 | #endif /* CONFIG_SND_PCM_OSS */ | ||
1186 | 1195 | ||
1187 | #ifdef CONFIG_SND_PROC_FS | 1196 | #ifdef CONFIG_SND_PROC_FS |
1188 | /* | 1197 | /* |
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 1f64ab0c2a95..10f537f4d735 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -27,17 +27,13 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, | |||
27 | s32 __user *src) | 27 | s32 __user *src) |
28 | { | 28 | { |
29 | snd_pcm_sframes_t delay; | 29 | snd_pcm_sframes_t delay; |
30 | mm_segment_t fs; | ||
31 | int err; | ||
32 | 30 | ||
33 | fs = snd_enter_user(); | 31 | delay = snd_pcm_delay(substream); |
34 | err = snd_pcm_delay(substream, &delay); | 32 | if (delay < 0) |
35 | snd_leave_user(fs); | 33 | return delay; |
36 | if (err < 0) | ||
37 | return err; | ||
38 | if (put_user(delay, src)) | 34 | if (put_user(delay, src)) |
39 | return -EFAULT; | 35 | return -EFAULT; |
40 | return err; | 36 | return 0; |
41 | } | 37 | } |
42 | 38 | ||
43 | static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, | 39 | static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, |
@@ -680,6 +676,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l | |||
680 | case SNDRV_PCM_IOCTL_INFO: | 676 | case SNDRV_PCM_IOCTL_INFO: |
681 | case SNDRV_PCM_IOCTL_TSTAMP: | 677 | case SNDRV_PCM_IOCTL_TSTAMP: |
682 | case SNDRV_PCM_IOCTL_TTSTAMP: | 678 | case SNDRV_PCM_IOCTL_TTSTAMP: |
679 | case SNDRV_PCM_IOCTL_USER_PVERSION: | ||
683 | case SNDRV_PCM_IOCTL_HWSYNC: | 680 | case SNDRV_PCM_IOCTL_HWSYNC: |
684 | case SNDRV_PCM_IOCTL_PREPARE: | 681 | case SNDRV_PCM_IOCTL_PREPARE: |
685 | case SNDRV_PCM_IOCTL_RESET: | 682 | case SNDRV_PCM_IOCTL_RESET: |
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index e70379fb63d0..9881d087756f 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c | |||
@@ -29,13 +29,13 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params, | |||
29 | struct snd_pcm_hw_rule *rule) | 29 | struct snd_pcm_hw_rule *rule) |
30 | { | 30 | { |
31 | struct snd_interval *r = hw_param_interval(params, rule->var); | 31 | struct snd_interval *r = hw_param_interval(params, rule->var); |
32 | struct snd_interval *c; | 32 | const struct snd_interval *c; |
33 | unsigned int rate_mask = 7, i; | 33 | unsigned int rate_mask = 7, i; |
34 | const u8 *sad, *eld = rule->private; | 34 | const u8 *sad, *eld = rule->private; |
35 | 35 | ||
36 | sad = drm_eld_sad(eld); | 36 | sad = drm_eld_sad(eld); |
37 | if (sad) { | 37 | if (sad) { |
38 | c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | 38 | c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
39 | 39 | ||
40 | for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) { | 40 | for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) { |
41 | unsigned max_channels = sad_max_channels(sad); | 41 | unsigned max_channels = sad_max_channels(sad); |
@@ -57,7 +57,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params, | |||
57 | struct snd_pcm_hw_rule *rule) | 57 | struct snd_pcm_hw_rule *rule) |
58 | { | 58 | { |
59 | struct snd_interval *c = hw_param_interval(params, rule->var); | 59 | struct snd_interval *c = hw_param_interval(params, rule->var); |
60 | struct snd_interval *r; | 60 | const struct snd_interval *r; |
61 | struct snd_interval t = { .min = 1, .max = 2, .integer = 1, }; | 61 | struct snd_interval t = { .min = 1, .max = 2, .integer = 1, }; |
62 | unsigned int i; | 62 | unsigned int i; |
63 | const u8 *sad, *eld = rule->private; | 63 | const u8 *sad, *eld = rule->private; |
@@ -67,7 +67,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params, | |||
67 | unsigned int rate_mask = 0; | 67 | unsigned int rate_mask = 0; |
68 | 68 | ||
69 | /* Convert the rate interval to a mask */ | 69 | /* Convert the rate interval to a mask */ |
70 | r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | 70 | r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); |
71 | for (i = 0; i < ARRAY_SIZE(eld_rates); i++) | 71 | for (i = 0; i < ARRAY_SIZE(eld_rates); i++) |
72 | if (r->min <= eld_rates[i] && r->max >= eld_rates[i]) | 72 | if (r->min <= eld_rates[i] && r->max >= eld_rates[i]) |
73 | rate_mask |= BIT(i); | 73 | rate_mask |= BIT(i); |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 877176067072..a93a4235a332 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
34 | #include <sound/timer.h> | 34 | #include <sound/timer.h> |
35 | 35 | ||
36 | #include "pcm_local.h" | ||
37 | |||
36 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 38 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
37 | #define CREATE_TRACE_POINTS | 39 | #define CREATE_TRACE_POINTS |
38 | #include "pcm_trace.h" | 40 | #include "pcm_trace.h" |
@@ -40,8 +42,12 @@ | |||
40 | #define trace_hwptr(substream, pos, in_interrupt) | 42 | #define trace_hwptr(substream, pos, in_interrupt) |
41 | #define trace_xrun(substream) | 43 | #define trace_xrun(substream) |
42 | #define trace_hw_ptr_error(substream, reason) | 44 | #define trace_hw_ptr_error(substream, reason) |
45 | #define trace_applptr(substream, prev, curr) | ||
43 | #endif | 46 | #endif |
44 | 47 | ||
48 | static int fill_silence_frames(struct snd_pcm_substream *substream, | ||
49 | snd_pcm_uframes_t off, snd_pcm_uframes_t frames); | ||
50 | |||
45 | /* | 51 | /* |
46 | * fill ring buffer with silence | 52 | * fill ring buffer with silence |
47 | * runtime->silence_start: starting pointer to silence area | 53 | * runtime->silence_start: starting pointer to silence area |
@@ -55,18 +61,20 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
55 | { | 61 | { |
56 | struct snd_pcm_runtime *runtime = substream->runtime; | 62 | struct snd_pcm_runtime *runtime = substream->runtime; |
57 | snd_pcm_uframes_t frames, ofs, transfer; | 63 | snd_pcm_uframes_t frames, ofs, transfer; |
64 | int err; | ||
58 | 65 | ||
59 | if (runtime->silence_size < runtime->boundary) { | 66 | if (runtime->silence_size < runtime->boundary) { |
60 | snd_pcm_sframes_t noise_dist, n; | 67 | snd_pcm_sframes_t noise_dist, n; |
61 | if (runtime->silence_start != runtime->control->appl_ptr) { | 68 | snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); |
62 | n = runtime->control->appl_ptr - runtime->silence_start; | 69 | if (runtime->silence_start != appl_ptr) { |
70 | n = appl_ptr - runtime->silence_start; | ||
63 | if (n < 0) | 71 | if (n < 0) |
64 | n += runtime->boundary; | 72 | n += runtime->boundary; |
65 | if ((snd_pcm_uframes_t)n < runtime->silence_filled) | 73 | if ((snd_pcm_uframes_t)n < runtime->silence_filled) |
66 | runtime->silence_filled -= n; | 74 | runtime->silence_filled -= n; |
67 | else | 75 | else |
68 | runtime->silence_filled = 0; | 76 | runtime->silence_filled = 0; |
69 | runtime->silence_start = runtime->control->appl_ptr; | 77 | runtime->silence_start = appl_ptr; |
70 | } | 78 | } |
71 | if (runtime->silence_filled >= runtime->buffer_size) | 79 | if (runtime->silence_filled >= runtime->buffer_size) |
72 | return; | 80 | return; |
@@ -107,33 +115,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
107 | ofs = runtime->silence_start % runtime->buffer_size; | 115 | ofs = runtime->silence_start % runtime->buffer_size; |
108 | while (frames > 0) { | 116 | while (frames > 0) { |
109 | transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; | 117 | transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; |
110 | if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || | 118 | err = fill_silence_frames(substream, ofs, transfer); |
111 | runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { | 119 | snd_BUG_ON(err < 0); |
112 | if (substream->ops->silence) { | ||
113 | int err; | ||
114 | err = substream->ops->silence(substream, -1, ofs, transfer); | ||
115 | snd_BUG_ON(err < 0); | ||
116 | } else { | ||
117 | char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); | ||
118 | snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); | ||
119 | } | ||
120 | } else { | ||
121 | unsigned int c; | ||
122 | unsigned int channels = runtime->channels; | ||
123 | if (substream->ops->silence) { | ||
124 | for (c = 0; c < channels; ++c) { | ||
125 | int err; | ||
126 | err = substream->ops->silence(substream, c, ofs, transfer); | ||
127 | snd_BUG_ON(err < 0); | ||
128 | } | ||
129 | } else { | ||
130 | size_t dma_csize = runtime->dma_bytes / channels; | ||
131 | for (c = 0; c < channels; ++c) { | ||
132 | char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); | ||
133 | snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | runtime->silence_filled += transfer; | 120 | runtime->silence_filled += transfer; |
138 | frames -= transfer; | 121 | frames -= transfer; |
139 | ofs = 0; | 122 | ofs = 0; |
@@ -508,7 +491,6 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, | |||
508 | for (substream = stream->substream; substream != NULL; substream = substream->next) | 491 | for (substream = stream->substream; substream != NULL; substream = substream->next) |
509 | substream->ops = ops; | 492 | substream->ops = ops; |
510 | } | 493 | } |
511 | |||
512 | EXPORT_SYMBOL(snd_pcm_set_ops); | 494 | EXPORT_SYMBOL(snd_pcm_set_ops); |
513 | 495 | ||
514 | /** | 496 | /** |
@@ -526,7 +508,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) | |||
526 | runtime->sync.id32[2] = -1; | 508 | runtime->sync.id32[2] = -1; |
527 | runtime->sync.id32[3] = -1; | 509 | runtime->sync.id32[3] = -1; |
528 | } | 510 | } |
529 | |||
530 | EXPORT_SYMBOL(snd_pcm_set_sync); | 511 | EXPORT_SYMBOL(snd_pcm_set_sync); |
531 | 512 | ||
532 | /* | 513 | /* |
@@ -643,7 +624,6 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) | |||
643 | } | 624 | } |
644 | return changed; | 625 | return changed; |
645 | } | 626 | } |
646 | |||
647 | EXPORT_SYMBOL(snd_interval_refine); | 627 | EXPORT_SYMBOL(snd_interval_refine); |
648 | 628 | ||
649 | static int snd_interval_refine_first(struct snd_interval *i) | 629 | static int snd_interval_refine_first(struct snd_interval *i) |
@@ -906,7 +886,6 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
906 | } | 886 | } |
907 | return err; | 887 | return err; |
908 | } | 888 | } |
909 | |||
910 | EXPORT_SYMBOL(snd_interval_ratnum); | 889 | EXPORT_SYMBOL(snd_interval_ratnum); |
911 | 890 | ||
912 | /** | 891 | /** |
@@ -1044,7 +1023,6 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, | |||
1044 | } | 1023 | } |
1045 | return snd_interval_refine(i, &list_range); | 1024 | return snd_interval_refine(i, &list_range); |
1046 | } | 1025 | } |
1047 | |||
1048 | EXPORT_SYMBOL(snd_interval_list); | 1026 | EXPORT_SYMBOL(snd_interval_list); |
1049 | 1027 | ||
1050 | /** | 1028 | /** |
@@ -1183,7 +1161,6 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, | |||
1183 | va_end(args); | 1161 | va_end(args); |
1184 | return 0; | 1162 | return 0; |
1185 | } | 1163 | } |
1186 | |||
1187 | EXPORT_SYMBOL(snd_pcm_hw_rule_add); | 1164 | EXPORT_SYMBOL(snd_pcm_hw_rule_add); |
1188 | 1165 | ||
1189 | /** | 1166 | /** |
@@ -1247,7 +1224,6 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa | |||
1247 | struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; | 1224 | struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; |
1248 | return snd_interval_setinteger(constrs_interval(constrs, var)); | 1225 | return snd_interval_setinteger(constrs_interval(constrs, var)); |
1249 | } | 1226 | } |
1250 | |||
1251 | EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); | 1227 | EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); |
1252 | 1228 | ||
1253 | /** | 1229 | /** |
@@ -1273,7 +1249,6 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par | |||
1273 | t.integer = 0; | 1249 | t.integer = 0; |
1274 | return snd_interval_refine(constrs_interval(constrs, var), &t); | 1250 | return snd_interval_refine(constrs_interval(constrs, var), &t); |
1275 | } | 1251 | } |
1276 | |||
1277 | EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); | 1252 | EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); |
1278 | 1253 | ||
1279 | static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, | 1254 | static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, |
@@ -1304,7 +1279,6 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, | |||
1304 | snd_pcm_hw_rule_list, (void *)l, | 1279 | snd_pcm_hw_rule_list, (void *)l, |
1305 | var, -1); | 1280 | var, -1); |
1306 | } | 1281 | } |
1307 | |||
1308 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); | 1282 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); |
1309 | 1283 | ||
1310 | static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, | 1284 | static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, |
@@ -1371,7 +1345,6 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, | |||
1371 | snd_pcm_hw_rule_ratnums, (void *)r, | 1345 | snd_pcm_hw_rule_ratnums, (void *)r, |
1372 | var, -1); | 1346 | var, -1); |
1373 | } | 1347 | } |
1374 | |||
1375 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); | 1348 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); |
1376 | 1349 | ||
1377 | static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, | 1350 | static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, |
@@ -1406,7 +1379,6 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, | |||
1406 | snd_pcm_hw_rule_ratdens, (void *)r, | 1379 | snd_pcm_hw_rule_ratdens, (void *)r, |
1407 | var, -1); | 1380 | var, -1); |
1408 | } | 1381 | } |
1409 | |||
1410 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); | 1382 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); |
1411 | 1383 | ||
1412 | static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, | 1384 | static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, |
@@ -1415,7 +1387,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, | |||
1415 | unsigned int l = (unsigned long) rule->private; | 1387 | unsigned int l = (unsigned long) rule->private; |
1416 | int width = l & 0xffff; | 1388 | int width = l & 0xffff; |
1417 | unsigned int msbits = l >> 16; | 1389 | unsigned int msbits = l >> 16; |
1418 | struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | 1390 | const struct snd_interval *i = |
1391 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | ||
1419 | 1392 | ||
1420 | if (!snd_interval_single(i)) | 1393 | if (!snd_interval_single(i)) |
1421 | return 0; | 1394 | return 0; |
@@ -1452,7 +1425,6 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, | |||
1452 | (void*) l, | 1425 | (void*) l, |
1453 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); | 1426 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); |
1454 | } | 1427 | } |
1455 | |||
1456 | EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); | 1428 | EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); |
1457 | 1429 | ||
1458 | static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, | 1430 | static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, |
@@ -1480,7 +1452,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, | |||
1480 | snd_pcm_hw_rule_step, (void *) step, | 1452 | snd_pcm_hw_rule_step, (void *) step, |
1481 | var, -1); | 1453 | var, -1); |
1482 | } | 1454 | } |
1483 | |||
1484 | EXPORT_SYMBOL(snd_pcm_hw_constraint_step); | 1455 | EXPORT_SYMBOL(snd_pcm_hw_constraint_step); |
1485 | 1456 | ||
1486 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | 1457 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) |
@@ -1511,7 +1482,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, | |||
1511 | snd_pcm_hw_rule_pow2, NULL, | 1482 | snd_pcm_hw_rule_pow2, NULL, |
1512 | var, -1); | 1483 | var, -1); |
1513 | } | 1484 | } |
1514 | |||
1515 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); | 1485 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); |
1516 | 1486 | ||
1517 | static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, | 1487 | static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, |
@@ -1570,7 +1540,6 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) | |||
1570 | _snd_pcm_hw_param_any(params, k); | 1540 | _snd_pcm_hw_param_any(params, k); |
1571 | params->info = ~0U; | 1541 | params->info = ~0U; |
1572 | } | 1542 | } |
1573 | |||
1574 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); | 1543 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); |
1575 | 1544 | ||
1576 | /** | 1545 | /** |
@@ -1603,7 +1572,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, | |||
1603 | } | 1572 | } |
1604 | return -EINVAL; | 1573 | return -EINVAL; |
1605 | } | 1574 | } |
1606 | |||
1607 | EXPORT_SYMBOL(snd_pcm_hw_param_value); | 1575 | EXPORT_SYMBOL(snd_pcm_hw_param_value); |
1608 | 1576 | ||
1609 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, | 1577 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, |
@@ -1621,7 +1589,6 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, | |||
1621 | snd_BUG(); | 1589 | snd_BUG(); |
1622 | } | 1590 | } |
1623 | } | 1591 | } |
1624 | |||
1625 | EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); | 1592 | EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); |
1626 | 1593 | ||
1627 | static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, | 1594 | static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, |
@@ -1668,7 +1635,6 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, | |||
1668 | } | 1635 | } |
1669 | return snd_pcm_hw_param_value(params, var, dir); | 1636 | return snd_pcm_hw_param_value(params, var, dir); |
1670 | } | 1637 | } |
1671 | |||
1672 | EXPORT_SYMBOL(snd_pcm_hw_param_first); | 1638 | EXPORT_SYMBOL(snd_pcm_hw_param_first); |
1673 | 1639 | ||
1674 | static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, | 1640 | static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, |
@@ -1715,48 +1681,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, | |||
1715 | } | 1681 | } |
1716 | return snd_pcm_hw_param_value(params, var, dir); | 1682 | return snd_pcm_hw_param_value(params, var, dir); |
1717 | } | 1683 | } |
1718 | |||
1719 | EXPORT_SYMBOL(snd_pcm_hw_param_last); | 1684 | EXPORT_SYMBOL(snd_pcm_hw_param_last); |
1720 | 1685 | ||
1721 | /** | ||
1722 | * snd_pcm_hw_param_choose - choose a configuration defined by @params | ||
1723 | * @pcm: PCM instance | ||
1724 | * @params: the hw_params instance | ||
1725 | * | ||
1726 | * Choose one configuration from configuration space defined by @params. | ||
1727 | * The configuration chosen is that obtained fixing in this order: | ||
1728 | * first access, first format, first subformat, min channels, | ||
1729 | * min rate, min period time, max buffer size, min tick time | ||
1730 | * | ||
1731 | * Return: Zero if successful, or a negative error code on failure. | ||
1732 | */ | ||
1733 | int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, | ||
1734 | struct snd_pcm_hw_params *params) | ||
1735 | { | ||
1736 | static int vars[] = { | ||
1737 | SNDRV_PCM_HW_PARAM_ACCESS, | ||
1738 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1739 | SNDRV_PCM_HW_PARAM_SUBFORMAT, | ||
1740 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1741 | SNDRV_PCM_HW_PARAM_RATE, | ||
1742 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
1743 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1744 | SNDRV_PCM_HW_PARAM_TICK_TIME, | ||
1745 | -1 | ||
1746 | }; | ||
1747 | int err, *v; | ||
1748 | |||
1749 | for (v = vars; *v != -1; v++) { | ||
1750 | if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) | ||
1751 | err = snd_pcm_hw_param_first(pcm, params, *v, NULL); | ||
1752 | else | ||
1753 | err = snd_pcm_hw_param_last(pcm, params, *v, NULL); | ||
1754 | if (snd_BUG_ON(err < 0)) | ||
1755 | return err; | ||
1756 | } | ||
1757 | return 0; | ||
1758 | } | ||
1759 | |||
1760 | static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, | 1686 | static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, |
1761 | void *arg) | 1687 | void *arg) |
1762 | { | 1688 | { |
@@ -1843,8 +1769,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |||
1843 | unsigned int cmd, void *arg) | 1769 | unsigned int cmd, void *arg) |
1844 | { | 1770 | { |
1845 | switch (cmd) { | 1771 | switch (cmd) { |
1846 | case SNDRV_PCM_IOCTL1_INFO: | ||
1847 | return 0; | ||
1848 | case SNDRV_PCM_IOCTL1_RESET: | 1772 | case SNDRV_PCM_IOCTL1_RESET: |
1849 | return snd_pcm_lib_ioctl_reset(substream, arg); | 1773 | return snd_pcm_lib_ioctl_reset(substream, arg); |
1850 | case SNDRV_PCM_IOCTL1_CHANNEL_INFO: | 1774 | case SNDRV_PCM_IOCTL1_CHANNEL_INFO: |
@@ -1854,7 +1778,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |||
1854 | } | 1778 | } |
1855 | return -ENXIO; | 1779 | return -ENXIO; |
1856 | } | 1780 | } |
1857 | |||
1858 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); | 1781 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); |
1859 | 1782 | ||
1860 | /** | 1783 | /** |
@@ -1890,7 +1813,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
1890 | kill_fasync(&runtime->fasync, SIGIO, POLL_IN); | 1813 | kill_fasync(&runtime->fasync, SIGIO, POLL_IN); |
1891 | snd_pcm_stream_unlock_irqrestore(substream, flags); | 1814 | snd_pcm_stream_unlock_irqrestore(substream, flags); |
1892 | } | 1815 | } |
1893 | |||
1894 | EXPORT_SYMBOL(snd_pcm_period_elapsed); | 1816 | EXPORT_SYMBOL(snd_pcm_period_elapsed); |
1895 | 1817 | ||
1896 | /* | 1818 | /* |
@@ -1985,129 +1907,147 @@ static int wait_for_avail(struct snd_pcm_substream *substream, | |||
1985 | return err; | 1907 | return err; |
1986 | } | 1908 | } |
1987 | 1909 | ||
1988 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, | 1910 | typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream, |
1989 | unsigned int hwoff, | 1911 | int channel, unsigned long hwoff, |
1990 | unsigned long data, unsigned int off, | 1912 | void *buf, unsigned long bytes); |
1991 | snd_pcm_uframes_t frames) | 1913 | |
1914 | typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *, | ||
1915 | snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f); | ||
1916 | |||
1917 | /* calculate the target DMA-buffer position to be written/read */ | ||
1918 | static void *get_dma_ptr(struct snd_pcm_runtime *runtime, | ||
1919 | int channel, unsigned long hwoff) | ||
1992 | { | 1920 | { |
1993 | struct snd_pcm_runtime *runtime = substream->runtime; | 1921 | return runtime->dma_area + hwoff + |
1994 | int err; | 1922 | channel * (runtime->dma_bytes / runtime->channels); |
1995 | char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); | 1923 | } |
1996 | if (substream->ops->copy) { | 1924 | |
1997 | if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) | 1925 | /* default copy_user ops for write; used for both interleaved and non- modes */ |
1998 | return err; | 1926 | static int default_write_copy(struct snd_pcm_substream *substream, |
1999 | } else { | 1927 | int channel, unsigned long hwoff, |
2000 | char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); | 1928 | void *buf, unsigned long bytes) |
2001 | if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) | 1929 | { |
2002 | return -EFAULT; | 1930 | if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), |
2003 | } | 1931 | (void __user *)buf, bytes)) |
1932 | return -EFAULT; | ||
2004 | return 0; | 1933 | return 0; |
2005 | } | 1934 | } |
2006 | |||
2007 | typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, | ||
2008 | unsigned long data, unsigned int off, | ||
2009 | snd_pcm_uframes_t size); | ||
2010 | 1935 | ||
2011 | static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | 1936 | /* default copy_kernel ops for write */ |
2012 | unsigned long data, | 1937 | static int default_write_copy_kernel(struct snd_pcm_substream *substream, |
2013 | snd_pcm_uframes_t size, | 1938 | int channel, unsigned long hwoff, |
2014 | int nonblock, | 1939 | void *buf, unsigned long bytes) |
2015 | transfer_f transfer) | 1940 | { |
1941 | memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes); | ||
1942 | return 0; | ||
1943 | } | ||
1944 | |||
1945 | /* fill silence instead of copy data; called as a transfer helper | ||
1946 | * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when | ||
1947 | * a NULL buffer is passed | ||
1948 | */ | ||
1949 | static int fill_silence(struct snd_pcm_substream *substream, int channel, | ||
1950 | unsigned long hwoff, void *buf, unsigned long bytes) | ||
2016 | { | 1951 | { |
2017 | struct snd_pcm_runtime *runtime = substream->runtime; | 1952 | struct snd_pcm_runtime *runtime = substream->runtime; |
2018 | snd_pcm_uframes_t xfer = 0; | ||
2019 | snd_pcm_uframes_t offset = 0; | ||
2020 | snd_pcm_uframes_t avail; | ||
2021 | int err = 0; | ||
2022 | 1953 | ||
2023 | if (size == 0) | 1954 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) |
2024 | return 0; | 1955 | return 0; |
1956 | if (substream->ops->fill_silence) | ||
1957 | return substream->ops->fill_silence(substream, channel, | ||
1958 | hwoff, bytes); | ||
2025 | 1959 | ||
2026 | snd_pcm_stream_lock_irq(substream); | 1960 | snd_pcm_format_set_silence(runtime->format, |
2027 | switch (runtime->status->state) { | 1961 | get_dma_ptr(runtime, channel, hwoff), |
2028 | case SNDRV_PCM_STATE_PREPARED: | 1962 | bytes_to_samples(runtime, bytes)); |
2029 | case SNDRV_PCM_STATE_RUNNING: | 1963 | return 0; |
2030 | case SNDRV_PCM_STATE_PAUSED: | 1964 | } |
2031 | break; | ||
2032 | case SNDRV_PCM_STATE_XRUN: | ||
2033 | err = -EPIPE; | ||
2034 | goto _end_unlock; | ||
2035 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2036 | err = -ESTRPIPE; | ||
2037 | goto _end_unlock; | ||
2038 | default: | ||
2039 | err = -EBADFD; | ||
2040 | goto _end_unlock; | ||
2041 | } | ||
2042 | 1965 | ||
2043 | runtime->twake = runtime->control->avail_min ? : 1; | 1966 | /* default copy_user ops for read; used for both interleaved and non- modes */ |
2044 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 1967 | static int default_read_copy(struct snd_pcm_substream *substream, |
2045 | snd_pcm_update_hw_ptr(substream); | 1968 | int channel, unsigned long hwoff, |
2046 | avail = snd_pcm_playback_avail(runtime); | 1969 | void *buf, unsigned long bytes) |
2047 | while (size > 0) { | 1970 | { |
2048 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1971 | if (copy_to_user((void __user *)buf, |
2049 | snd_pcm_uframes_t cont; | 1972 | get_dma_ptr(substream->runtime, channel, hwoff), |
2050 | if (!avail) { | 1973 | bytes)) |
2051 | if (nonblock) { | 1974 | return -EFAULT; |
2052 | err = -EAGAIN; | 1975 | return 0; |
2053 | goto _end_unlock; | 1976 | } |
2054 | } | ||
2055 | runtime->twake = min_t(snd_pcm_uframes_t, size, | ||
2056 | runtime->control->avail_min ? : 1); | ||
2057 | err = wait_for_avail(substream, &avail); | ||
2058 | if (err < 0) | ||
2059 | goto _end_unlock; | ||
2060 | } | ||
2061 | frames = size > avail ? avail : size; | ||
2062 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | ||
2063 | if (frames > cont) | ||
2064 | frames = cont; | ||
2065 | if (snd_BUG_ON(!frames)) { | ||
2066 | runtime->twake = 0; | ||
2067 | snd_pcm_stream_unlock_irq(substream); | ||
2068 | return -EINVAL; | ||
2069 | } | ||
2070 | appl_ptr = runtime->control->appl_ptr; | ||
2071 | appl_ofs = appl_ptr % runtime->buffer_size; | ||
2072 | snd_pcm_stream_unlock_irq(substream); | ||
2073 | err = transfer(substream, appl_ofs, data, offset, frames); | ||
2074 | snd_pcm_stream_lock_irq(substream); | ||
2075 | if (err < 0) | ||
2076 | goto _end_unlock; | ||
2077 | switch (runtime->status->state) { | ||
2078 | case SNDRV_PCM_STATE_XRUN: | ||
2079 | err = -EPIPE; | ||
2080 | goto _end_unlock; | ||
2081 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2082 | err = -ESTRPIPE; | ||
2083 | goto _end_unlock; | ||
2084 | default: | ||
2085 | break; | ||
2086 | } | ||
2087 | appl_ptr += frames; | ||
2088 | if (appl_ptr >= runtime->boundary) | ||
2089 | appl_ptr -= runtime->boundary; | ||
2090 | runtime->control->appl_ptr = appl_ptr; | ||
2091 | if (substream->ops->ack) | ||
2092 | substream->ops->ack(substream); | ||
2093 | 1977 | ||
2094 | offset += frames; | 1978 | /* default copy_kernel ops for read */ |
2095 | size -= frames; | 1979 | static int default_read_copy_kernel(struct snd_pcm_substream *substream, |
2096 | xfer += frames; | 1980 | int channel, unsigned long hwoff, |
2097 | avail -= frames; | 1981 | void *buf, unsigned long bytes) |
2098 | if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && | 1982 | { |
2099 | snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { | 1983 | memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes); |
2100 | err = snd_pcm_start(substream); | 1984 | return 0; |
2101 | if (err < 0) | 1985 | } |
2102 | goto _end_unlock; | 1986 | |
2103 | } | 1987 | /* call transfer function with the converted pointers and sizes; |
1988 | * for interleaved mode, it's one shot for all samples | ||
1989 | */ | ||
1990 | static int interleaved_copy(struct snd_pcm_substream *substream, | ||
1991 | snd_pcm_uframes_t hwoff, void *data, | ||
1992 | snd_pcm_uframes_t off, | ||
1993 | snd_pcm_uframes_t frames, | ||
1994 | pcm_transfer_f transfer) | ||
1995 | { | ||
1996 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1997 | |||
1998 | /* convert to bytes */ | ||
1999 | hwoff = frames_to_bytes(runtime, hwoff); | ||
2000 | off = frames_to_bytes(runtime, off); | ||
2001 | frames = frames_to_bytes(runtime, frames); | ||
2002 | return transfer(substream, 0, hwoff, data + off, frames); | ||
2003 | } | ||
2004 | |||
2005 | /* call transfer function with the converted pointers and sizes for each | ||
2006 | * non-interleaved channel; when buffer is NULL, silencing instead of copying | ||
2007 | */ | ||
2008 | static int noninterleaved_copy(struct snd_pcm_substream *substream, | ||
2009 | snd_pcm_uframes_t hwoff, void *data, | ||
2010 | snd_pcm_uframes_t off, | ||
2011 | snd_pcm_uframes_t frames, | ||
2012 | pcm_transfer_f transfer) | ||
2013 | { | ||
2014 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2015 | int channels = runtime->channels; | ||
2016 | void **bufs = data; | ||
2017 | int c, err; | ||
2018 | |||
2019 | /* convert to bytes; note that it's not frames_to_bytes() here. | ||
2020 | * in non-interleaved mode, we copy for each channel, thus | ||
2021 | * each copy is n_samples bytes x channels = whole frames. | ||
2022 | */ | ||
2023 | off = samples_to_bytes(runtime, off); | ||
2024 | frames = samples_to_bytes(runtime, frames); | ||
2025 | hwoff = samples_to_bytes(runtime, hwoff); | ||
2026 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2027 | if (!data || !*bufs) | ||
2028 | err = fill_silence(substream, c, hwoff, NULL, frames); | ||
2029 | else | ||
2030 | err = transfer(substream, c, hwoff, *bufs + off, | ||
2031 | frames); | ||
2032 | if (err < 0) | ||
2033 | return err; | ||
2104 | } | 2034 | } |
2105 | _end_unlock: | 2035 | return 0; |
2106 | runtime->twake = 0; | 2036 | } |
2107 | if (xfer > 0 && err >= 0) | 2037 | |
2108 | snd_pcm_update_state(substream, runtime); | 2038 | /* fill silence on the given buffer position; |
2109 | snd_pcm_stream_unlock_irq(substream); | 2039 | * called from snd_pcm_playback_silence() |
2110 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2040 | */ |
2041 | static int fill_silence_frames(struct snd_pcm_substream *substream, | ||
2042 | snd_pcm_uframes_t off, snd_pcm_uframes_t frames) | ||
2043 | { | ||
2044 | if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || | ||
2045 | substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | ||
2046 | return interleaved_copy(substream, off, NULL, 0, frames, | ||
2047 | fill_silence); | ||
2048 | else | ||
2049 | return noninterleaved_copy(substream, off, NULL, 0, frames, | ||
2050 | fill_silence); | ||
2111 | } | 2051 | } |
2112 | 2052 | ||
2113 | /* sanity-check for read/write methods */ | 2053 | /* sanity-check for read/write methods */ |
@@ -2117,164 +2057,137 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) | |||
2117 | if (PCM_RUNTIME_CHECK(substream)) | 2057 | if (PCM_RUNTIME_CHECK(substream)) |
2118 | return -ENXIO; | 2058 | return -ENXIO; |
2119 | runtime = substream->runtime; | 2059 | runtime = substream->runtime; |
2120 | if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) | 2060 | if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) |
2121 | return -EINVAL; | 2061 | return -EINVAL; |
2122 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 2062 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
2123 | return -EBADFD; | 2063 | return -EBADFD; |
2124 | return 0; | 2064 | return 0; |
2125 | } | 2065 | } |
2126 | 2066 | ||
2127 | snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size) | 2067 | static int pcm_accessible_state(struct snd_pcm_runtime *runtime) |
2128 | { | 2068 | { |
2129 | struct snd_pcm_runtime *runtime; | 2069 | switch (runtime->status->state) { |
2130 | int nonblock; | 2070 | case SNDRV_PCM_STATE_PREPARED: |
2131 | int err; | 2071 | case SNDRV_PCM_STATE_RUNNING: |
2132 | 2072 | case SNDRV_PCM_STATE_PAUSED: | |
2133 | err = pcm_sanity_check(substream); | 2073 | return 0; |
2134 | if (err < 0) | 2074 | case SNDRV_PCM_STATE_XRUN: |
2135 | return err; | 2075 | return -EPIPE; |
2136 | runtime = substream->runtime; | 2076 | case SNDRV_PCM_STATE_SUSPENDED: |
2137 | nonblock = !!(substream->f_flags & O_NONBLOCK); | 2077 | return -ESTRPIPE; |
2138 | 2078 | default: | |
2139 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && | 2079 | return -EBADFD; |
2140 | runtime->channels > 1) | 2080 | } |
2141 | return -EINVAL; | ||
2142 | return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, | ||
2143 | snd_pcm_lib_write_transfer); | ||
2144 | } | 2081 | } |
2145 | 2082 | ||
2146 | EXPORT_SYMBOL(snd_pcm_lib_write); | 2083 | /* update to the given appl_ptr and call ack callback if needed; |
2147 | 2084 | * when an error is returned, take back to the original value | |
2148 | static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, | 2085 | */ |
2149 | unsigned int hwoff, | 2086 | int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, |
2150 | unsigned long data, unsigned int off, | 2087 | snd_pcm_uframes_t appl_ptr) |
2151 | snd_pcm_uframes_t frames) | ||
2152 | { | 2088 | { |
2153 | struct snd_pcm_runtime *runtime = substream->runtime; | 2089 | struct snd_pcm_runtime *runtime = substream->runtime; |
2154 | int err; | 2090 | snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; |
2155 | void __user **bufs = (void __user **)data; | 2091 | int ret; |
2156 | int channels = runtime->channels; | 2092 | |
2157 | int c; | 2093 | if (old_appl_ptr == appl_ptr) |
2158 | if (substream->ops->copy) { | 2094 | return 0; |
2159 | if (snd_BUG_ON(!substream->ops->silence)) | 2095 | |
2160 | return -EINVAL; | 2096 | runtime->control->appl_ptr = appl_ptr; |
2161 | for (c = 0; c < channels; ++c, ++bufs) { | 2097 | if (substream->ops->ack) { |
2162 | if (*bufs == NULL) { | 2098 | ret = substream->ops->ack(substream); |
2163 | if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0) | 2099 | if (ret < 0) { |
2164 | return err; | 2100 | runtime->control->appl_ptr = old_appl_ptr; |
2165 | } else { | 2101 | return ret; |
2166 | char __user *buf = *bufs + samples_to_bytes(runtime, off); | ||
2167 | if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) | ||
2168 | return err; | ||
2169 | } | ||
2170 | } | ||
2171 | } else { | ||
2172 | /* default transfer behaviour */ | ||
2173 | size_t dma_csize = runtime->dma_bytes / channels; | ||
2174 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2175 | char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); | ||
2176 | if (*bufs == NULL) { | ||
2177 | snd_pcm_format_set_silence(runtime->format, hwbuf, frames); | ||
2178 | } else { | ||
2179 | char __user *buf = *bufs + samples_to_bytes(runtime, off); | ||
2180 | if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) | ||
2181 | return -EFAULT; | ||
2182 | } | ||
2183 | } | 2102 | } |
2184 | } | 2103 | } |
2104 | |||
2105 | trace_applptr(substream, old_appl_ptr, appl_ptr); | ||
2106 | |||
2185 | return 0; | 2107 | return 0; |
2186 | } | 2108 | } |
2187 | 2109 | ||
2188 | snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, | 2110 | /* the common loop for read/write data */ |
2189 | void __user **bufs, | 2111 | snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, |
2190 | snd_pcm_uframes_t frames) | 2112 | void *data, bool interleaved, |
2113 | snd_pcm_uframes_t size, bool in_kernel) | ||
2191 | { | 2114 | { |
2192 | struct snd_pcm_runtime *runtime; | 2115 | struct snd_pcm_runtime *runtime = substream->runtime; |
2193 | int nonblock; | 2116 | snd_pcm_uframes_t xfer = 0; |
2117 | snd_pcm_uframes_t offset = 0; | ||
2118 | snd_pcm_uframes_t avail; | ||
2119 | pcm_copy_f writer; | ||
2120 | pcm_transfer_f transfer; | ||
2121 | bool nonblock; | ||
2122 | bool is_playback; | ||
2194 | int err; | 2123 | int err; |
2195 | 2124 | ||
2196 | err = pcm_sanity_check(substream); | 2125 | err = pcm_sanity_check(substream); |
2197 | if (err < 0) | 2126 | if (err < 0) |
2198 | return err; | 2127 | return err; |
2199 | runtime = substream->runtime; | ||
2200 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2201 | |||
2202 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | ||
2203 | return -EINVAL; | ||
2204 | return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, | ||
2205 | nonblock, snd_pcm_lib_writev_transfer); | ||
2206 | } | ||
2207 | |||
2208 | EXPORT_SYMBOL(snd_pcm_lib_writev); | ||
2209 | 2128 | ||
2210 | static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, | 2129 | is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
2211 | unsigned int hwoff, | 2130 | if (interleaved) { |
2212 | unsigned long data, unsigned int off, | 2131 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && |
2213 | snd_pcm_uframes_t frames) | 2132 | runtime->channels > 1) |
2214 | { | 2133 | return -EINVAL; |
2215 | struct snd_pcm_runtime *runtime = substream->runtime; | 2134 | writer = interleaved_copy; |
2216 | int err; | ||
2217 | char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); | ||
2218 | if (substream->ops->copy) { | ||
2219 | if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) | ||
2220 | return err; | ||
2221 | } else { | 2135 | } else { |
2222 | char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); | 2136 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) |
2223 | if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) | 2137 | return -EINVAL; |
2224 | return -EFAULT; | 2138 | writer = noninterleaved_copy; |
2225 | } | 2139 | } |
2226 | return 0; | ||
2227 | } | ||
2228 | 2140 | ||
2229 | static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | 2141 | if (!data) { |
2230 | unsigned long data, | 2142 | if (is_playback) |
2231 | snd_pcm_uframes_t size, | 2143 | transfer = fill_silence; |
2232 | int nonblock, | 2144 | else |
2233 | transfer_f transfer) | 2145 | return -EINVAL; |
2234 | { | 2146 | } else if (in_kernel) { |
2235 | struct snd_pcm_runtime *runtime = substream->runtime; | 2147 | if (substream->ops->copy_kernel) |
2236 | snd_pcm_uframes_t xfer = 0; | 2148 | transfer = substream->ops->copy_kernel; |
2237 | snd_pcm_uframes_t offset = 0; | 2149 | else |
2238 | snd_pcm_uframes_t avail; | 2150 | transfer = is_playback ? |
2239 | int err = 0; | 2151 | default_write_copy_kernel : default_read_copy_kernel; |
2152 | } else { | ||
2153 | if (substream->ops->copy_user) | ||
2154 | transfer = (pcm_transfer_f)substream->ops->copy_user; | ||
2155 | else | ||
2156 | transfer = is_playback ? | ||
2157 | default_write_copy : default_read_copy; | ||
2158 | } | ||
2240 | 2159 | ||
2241 | if (size == 0) | 2160 | if (size == 0) |
2242 | return 0; | 2161 | return 0; |
2243 | 2162 | ||
2163 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2164 | |||
2244 | snd_pcm_stream_lock_irq(substream); | 2165 | snd_pcm_stream_lock_irq(substream); |
2245 | switch (runtime->status->state) { | 2166 | err = pcm_accessible_state(runtime); |
2246 | case SNDRV_PCM_STATE_PREPARED: | 2167 | if (err < 0) |
2247 | if (size >= runtime->start_threshold) { | ||
2248 | err = snd_pcm_start(substream); | ||
2249 | if (err < 0) | ||
2250 | goto _end_unlock; | ||
2251 | } | ||
2252 | break; | ||
2253 | case SNDRV_PCM_STATE_DRAINING: | ||
2254 | case SNDRV_PCM_STATE_RUNNING: | ||
2255 | case SNDRV_PCM_STATE_PAUSED: | ||
2256 | break; | ||
2257 | case SNDRV_PCM_STATE_XRUN: | ||
2258 | err = -EPIPE; | ||
2259 | goto _end_unlock; | ||
2260 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2261 | err = -ESTRPIPE; | ||
2262 | goto _end_unlock; | ||
2263 | default: | ||
2264 | err = -EBADFD; | ||
2265 | goto _end_unlock; | 2168 | goto _end_unlock; |
2169 | |||
2170 | if (!is_playback && | ||
2171 | runtime->status->state == SNDRV_PCM_STATE_PREPARED && | ||
2172 | size >= runtime->start_threshold) { | ||
2173 | err = snd_pcm_start(substream); | ||
2174 | if (err < 0) | ||
2175 | goto _end_unlock; | ||
2266 | } | 2176 | } |
2267 | 2177 | ||
2268 | runtime->twake = runtime->control->avail_min ? : 1; | 2178 | runtime->twake = runtime->control->avail_min ? : 1; |
2269 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 2179 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
2270 | snd_pcm_update_hw_ptr(substream); | 2180 | snd_pcm_update_hw_ptr(substream); |
2271 | avail = snd_pcm_capture_avail(runtime); | 2181 | if (is_playback) |
2182 | avail = snd_pcm_playback_avail(runtime); | ||
2183 | else | ||
2184 | avail = snd_pcm_capture_avail(runtime); | ||
2272 | while (size > 0) { | 2185 | while (size > 0) { |
2273 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2186 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
2274 | snd_pcm_uframes_t cont; | 2187 | snd_pcm_uframes_t cont; |
2275 | if (!avail) { | 2188 | if (!avail) { |
2276 | if (runtime->status->state == | 2189 | if (!is_playback && |
2277 | SNDRV_PCM_STATE_DRAINING) { | 2190 | runtime->status->state == SNDRV_PCM_STATE_DRAINING) { |
2278 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | 2191 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); |
2279 | goto _end_unlock; | 2192 | goto _end_unlock; |
2280 | } | 2193 | } |
@@ -2291,7 +2204,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2291 | continue; /* draining */ | 2204 | continue; /* draining */ |
2292 | } | 2205 | } |
2293 | frames = size > avail ? avail : size; | 2206 | frames = size > avail ? avail : size; |
2294 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | 2207 | appl_ptr = READ_ONCE(runtime->control->appl_ptr); |
2208 | appl_ofs = appl_ptr % runtime->buffer_size; | ||
2209 | cont = runtime->buffer_size - appl_ofs; | ||
2295 | if (frames > cont) | 2210 | if (frames > cont) |
2296 | frames = cont; | 2211 | frames = cont; |
2297 | if (snd_BUG_ON(!frames)) { | 2212 | if (snd_BUG_ON(!frames)) { |
@@ -2299,34 +2214,33 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2299 | snd_pcm_stream_unlock_irq(substream); | 2214 | snd_pcm_stream_unlock_irq(substream); |
2300 | return -EINVAL; | 2215 | return -EINVAL; |
2301 | } | 2216 | } |
2302 | appl_ptr = runtime->control->appl_ptr; | ||
2303 | appl_ofs = appl_ptr % runtime->buffer_size; | ||
2304 | snd_pcm_stream_unlock_irq(substream); | 2217 | snd_pcm_stream_unlock_irq(substream); |
2305 | err = transfer(substream, appl_ofs, data, offset, frames); | 2218 | err = writer(substream, appl_ofs, data, offset, frames, |
2219 | transfer); | ||
2306 | snd_pcm_stream_lock_irq(substream); | 2220 | snd_pcm_stream_lock_irq(substream); |
2307 | if (err < 0) | 2221 | if (err < 0) |
2308 | goto _end_unlock; | 2222 | goto _end_unlock; |
2309 | switch (runtime->status->state) { | 2223 | err = pcm_accessible_state(runtime); |
2310 | case SNDRV_PCM_STATE_XRUN: | 2224 | if (err < 0) |
2311 | err = -EPIPE; | ||
2312 | goto _end_unlock; | ||
2313 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2314 | err = -ESTRPIPE; | ||
2315 | goto _end_unlock; | 2225 | goto _end_unlock; |
2316 | default: | ||
2317 | break; | ||
2318 | } | ||
2319 | appl_ptr += frames; | 2226 | appl_ptr += frames; |
2320 | if (appl_ptr >= runtime->boundary) | 2227 | if (appl_ptr >= runtime->boundary) |
2321 | appl_ptr -= runtime->boundary; | 2228 | appl_ptr -= runtime->boundary; |
2322 | runtime->control->appl_ptr = appl_ptr; | 2229 | err = pcm_lib_apply_appl_ptr(substream, appl_ptr); |
2323 | if (substream->ops->ack) | 2230 | if (err < 0) |
2324 | substream->ops->ack(substream); | 2231 | goto _end_unlock; |
2325 | 2232 | ||
2326 | offset += frames; | 2233 | offset += frames; |
2327 | size -= frames; | 2234 | size -= frames; |
2328 | xfer += frames; | 2235 | xfer += frames; |
2329 | avail -= frames; | 2236 | avail -= frames; |
2237 | if (is_playback && | ||
2238 | runtime->status->state == SNDRV_PCM_STATE_PREPARED && | ||
2239 | snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { | ||
2240 | err = snd_pcm_start(substream); | ||
2241 | if (err < 0) | ||
2242 | goto _end_unlock; | ||
2243 | } | ||
2330 | } | 2244 | } |
2331 | _end_unlock: | 2245 | _end_unlock: |
2332 | runtime->twake = 0; | 2246 | runtime->twake = 0; |
@@ -2335,83 +2249,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2335 | snd_pcm_stream_unlock_irq(substream); | 2249 | snd_pcm_stream_unlock_irq(substream); |
2336 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2250 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
2337 | } | 2251 | } |
2338 | 2252 | EXPORT_SYMBOL(__snd_pcm_lib_xfer); | |
2339 | snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size) | ||
2340 | { | ||
2341 | struct snd_pcm_runtime *runtime; | ||
2342 | int nonblock; | ||
2343 | int err; | ||
2344 | |||
2345 | err = pcm_sanity_check(substream); | ||
2346 | if (err < 0) | ||
2347 | return err; | ||
2348 | runtime = substream->runtime; | ||
2349 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2350 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) | ||
2351 | return -EINVAL; | ||
2352 | return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); | ||
2353 | } | ||
2354 | |||
2355 | EXPORT_SYMBOL(snd_pcm_lib_read); | ||
2356 | |||
2357 | static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, | ||
2358 | unsigned int hwoff, | ||
2359 | unsigned long data, unsigned int off, | ||
2360 | snd_pcm_uframes_t frames) | ||
2361 | { | ||
2362 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2363 | int err; | ||
2364 | void __user **bufs = (void __user **)data; | ||
2365 | int channels = runtime->channels; | ||
2366 | int c; | ||
2367 | if (substream->ops->copy) { | ||
2368 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2369 | char __user *buf; | ||
2370 | if (*bufs == NULL) | ||
2371 | continue; | ||
2372 | buf = *bufs + samples_to_bytes(runtime, off); | ||
2373 | if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) | ||
2374 | return err; | ||
2375 | } | ||
2376 | } else { | ||
2377 | snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; | ||
2378 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2379 | char *hwbuf; | ||
2380 | char __user *buf; | ||
2381 | if (*bufs == NULL) | ||
2382 | continue; | ||
2383 | |||
2384 | hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); | ||
2385 | buf = *bufs + samples_to_bytes(runtime, off); | ||
2386 | if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) | ||
2387 | return -EFAULT; | ||
2388 | } | ||
2389 | } | ||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, | ||
2394 | void __user **bufs, | ||
2395 | snd_pcm_uframes_t frames) | ||
2396 | { | ||
2397 | struct snd_pcm_runtime *runtime; | ||
2398 | int nonblock; | ||
2399 | int err; | ||
2400 | |||
2401 | err = pcm_sanity_check(substream); | ||
2402 | if (err < 0) | ||
2403 | return err; | ||
2404 | runtime = substream->runtime; | ||
2405 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2406 | return -EBADFD; | ||
2407 | |||
2408 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2409 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | ||
2410 | return -EINVAL; | ||
2411 | return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); | ||
2412 | } | ||
2413 | |||
2414 | EXPORT_SYMBOL(snd_pcm_lib_readv); | ||
2415 | 2253 | ||
2416 | /* | 2254 | /* |
2417 | * standard channel mapping helpers | 2255 | * standard channel mapping helpers |
diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h new file mode 100644 index 000000000000..16f254732b2a --- /dev/null +++ b/sound/core/pcm_local.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * pcm_local.h - a local header file for snd-pcm module. | ||
3 | * | ||
4 | * Copyright (c) Takashi Sakamoto <o-takashi@sakamocchi.jp> | ||
5 | * | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #ifndef __SOUND_CORE_PCM_LOCAL_H | ||
10 | #define __SOUND_CORE_PCM_LOCAL_H | ||
11 | |||
12 | extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; | ||
13 | |||
14 | void snd_interval_mul(const struct snd_interval *a, | ||
15 | const struct snd_interval *b, struct snd_interval *c); | ||
16 | void snd_interval_div(const struct snd_interval *a, | ||
17 | const struct snd_interval *b, struct snd_interval *c); | ||
18 | void snd_interval_muldivk(const struct snd_interval *a, | ||
19 | const struct snd_interval *b, | ||
20 | unsigned int k, struct snd_interval *c); | ||
21 | void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, | ||
22 | const struct snd_interval *b, struct snd_interval *c); | ||
23 | |||
24 | int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); | ||
25 | int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); | ||
26 | |||
27 | int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, | ||
28 | snd_pcm_hw_param_t var, u_int32_t mask); | ||
29 | |||
30 | int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, | ||
31 | snd_pcm_uframes_t appl_ptr); | ||
32 | int snd_pcm_update_state(struct snd_pcm_substream *substream, | ||
33 | struct snd_pcm_runtime *runtime); | ||
34 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); | ||
35 | |||
36 | void snd_pcm_playback_silence(struct snd_pcm_substream *substream, | ||
37 | snd_pcm_uframes_t new_hw_ptr); | ||
38 | |||
39 | #ifdef CONFIG_SND_PCM_TIMER | ||
40 | void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); | ||
41 | void snd_pcm_timer_init(struct snd_pcm_substream *substream); | ||
42 | void snd_pcm_timer_done(struct snd_pcm_substream *substream); | ||
43 | #else | ||
44 | static inline void | ||
45 | snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {} | ||
46 | static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {} | ||
47 | static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} | ||
48 | #endif | ||
49 | |||
50 | #endif /* __SOUND_CORE_PCM_LOCAL_H */ | ||
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index b45f6aa32264..ae33e456708c 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -120,7 +120,6 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) | |||
120 | snd_pcm_lib_preallocate_free(substream); | 120 | snd_pcm_lib_preallocate_free(substream); |
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
123 | |||
124 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); | 123 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); |
125 | 124 | ||
126 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 125 | #ifdef CONFIG_SND_VERBOSE_PROCFS |
@@ -263,7 +262,6 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, | |||
263 | substream->dma_buffer.dev.dev = data; | 262 | substream->dma_buffer.dev.dev = data; |
264 | return snd_pcm_lib_preallocate_pages1(substream, size, max); | 263 | return snd_pcm_lib_preallocate_pages1(substream, size, max); |
265 | } | 264 | } |
266 | |||
267 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); | 265 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); |
268 | 266 | ||
269 | /** | 267 | /** |
@@ -292,7 +290,6 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, | |||
292 | return err; | 290 | return err; |
293 | return 0; | 291 | return 0; |
294 | } | 292 | } |
295 | |||
296 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); | 293 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); |
297 | 294 | ||
298 | #ifdef CONFIG_SND_DMA_SGBUF | 295 | #ifdef CONFIG_SND_DMA_SGBUF |
@@ -314,7 +311,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne | |||
314 | return NULL; | 311 | return NULL; |
315 | return sgbuf->page_table[idx]; | 312 | return sgbuf->page_table[idx]; |
316 | } | 313 | } |
317 | |||
318 | EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); | 314 | EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); |
319 | #endif /* CONFIG_SND_DMA_SGBUF */ | 315 | #endif /* CONFIG_SND_DMA_SGBUF */ |
320 | 316 | ||
@@ -370,7 +366,6 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) | |||
370 | runtime->dma_bytes = size; | 366 | runtime->dma_bytes = size; |
371 | return 1; /* area was changed */ | 367 | return 1; /* area was changed */ |
372 | } | 368 | } |
373 | |||
374 | EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); | 369 | EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); |
375 | 370 | ||
376 | /** | 371 | /** |
@@ -398,7 +393,6 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) | |||
398 | snd_pcm_set_runtime_buffer(substream, NULL); | 393 | snd_pcm_set_runtime_buffer(substream, NULL); |
399 | return 0; | 394 | return 0; |
400 | } | 395 | } |
401 | |||
402 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); | 396 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); |
403 | 397 | ||
404 | int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, | 398 | int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 53dc37357bca..9be81025372f 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <linux/export.h> | 23 | #include <linux/export.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
26 | |||
27 | #include "pcm_local.h" | ||
28 | |||
26 | #define SND_PCM_FORMAT_UNKNOWN (-1) | 29 | #define SND_PCM_FORMAT_UNKNOWN (-1) |
27 | 30 | ||
28 | /* NOTE: "signed" prefix must be given below since the default char is | 31 | /* NOTE: "signed" prefix must be given below since the default char is |
@@ -245,7 +248,6 @@ int snd_pcm_format_signed(snd_pcm_format_t format) | |||
245 | return -EINVAL; | 248 | return -EINVAL; |
246 | return val; | 249 | return val; |
247 | } | 250 | } |
248 | |||
249 | EXPORT_SYMBOL(snd_pcm_format_signed); | 251 | EXPORT_SYMBOL(snd_pcm_format_signed); |
250 | 252 | ||
251 | /** | 253 | /** |
@@ -264,7 +266,6 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format) | |||
264 | return val; | 266 | return val; |
265 | return !val; | 267 | return !val; |
266 | } | 268 | } |
267 | |||
268 | EXPORT_SYMBOL(snd_pcm_format_unsigned); | 269 | EXPORT_SYMBOL(snd_pcm_format_unsigned); |
269 | 270 | ||
270 | /** | 271 | /** |
@@ -277,7 +278,6 @@ int snd_pcm_format_linear(snd_pcm_format_t format) | |||
277 | { | 278 | { |
278 | return snd_pcm_format_signed(format) >= 0; | 279 | return snd_pcm_format_signed(format) >= 0; |
279 | } | 280 | } |
280 | |||
281 | EXPORT_SYMBOL(snd_pcm_format_linear); | 281 | EXPORT_SYMBOL(snd_pcm_format_linear); |
282 | 282 | ||
283 | /** | 283 | /** |
@@ -296,7 +296,6 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) | |||
296 | return -EINVAL; | 296 | return -EINVAL; |
297 | return val; | 297 | return val; |
298 | } | 298 | } |
299 | |||
300 | EXPORT_SYMBOL(snd_pcm_format_little_endian); | 299 | EXPORT_SYMBOL(snd_pcm_format_little_endian); |
301 | 300 | ||
302 | /** | 301 | /** |
@@ -315,7 +314,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) | |||
315 | return val; | 314 | return val; |
316 | return !val; | 315 | return !val; |
317 | } | 316 | } |
318 | |||
319 | EXPORT_SYMBOL(snd_pcm_format_big_endian); | 317 | EXPORT_SYMBOL(snd_pcm_format_big_endian); |
320 | 318 | ||
321 | /** | 319 | /** |
@@ -334,7 +332,6 @@ int snd_pcm_format_width(snd_pcm_format_t format) | |||
334 | return -EINVAL; | 332 | return -EINVAL; |
335 | return val; | 333 | return val; |
336 | } | 334 | } |
337 | |||
338 | EXPORT_SYMBOL(snd_pcm_format_width); | 335 | EXPORT_SYMBOL(snd_pcm_format_width); |
339 | 336 | ||
340 | /** | 337 | /** |
@@ -353,7 +350,6 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) | |||
353 | return -EINVAL; | 350 | return -EINVAL; |
354 | return val; | 351 | return val; |
355 | } | 352 | } |
356 | |||
357 | EXPORT_SYMBOL(snd_pcm_format_physical_width); | 353 | EXPORT_SYMBOL(snd_pcm_format_physical_width); |
358 | 354 | ||
359 | /** | 355 | /** |
@@ -371,7 +367,6 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) | |||
371 | return -EINVAL; | 367 | return -EINVAL; |
372 | return samples * phys_width / 8; | 368 | return samples * phys_width / 8; |
373 | } | 369 | } |
374 | |||
375 | EXPORT_SYMBOL(snd_pcm_format_size); | 370 | EXPORT_SYMBOL(snd_pcm_format_size); |
376 | 371 | ||
377 | /** | 372 | /** |
@@ -388,7 +383,6 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) | |||
388 | return NULL; | 383 | return NULL; |
389 | return pcm_formats[(INT)format].silence; | 384 | return pcm_formats[(INT)format].silence; |
390 | } | 385 | } |
391 | |||
392 | EXPORT_SYMBOL(snd_pcm_format_silence_64); | 386 | EXPORT_SYMBOL(snd_pcm_format_silence_64); |
393 | 387 | ||
394 | /** | 388 | /** |
@@ -459,7 +453,6 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int | |||
459 | #endif | 453 | #endif |
460 | return 0; | 454 | return 0; |
461 | } | 455 | } |
462 | |||
463 | EXPORT_SYMBOL(snd_pcm_format_set_silence); | 456 | EXPORT_SYMBOL(snd_pcm_format_set_silence); |
464 | 457 | ||
465 | /** | 458 | /** |
@@ -488,7 +481,6 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) | |||
488 | } | 481 | } |
489 | return 0; | 482 | return 0; |
490 | } | 483 | } |
491 | |||
492 | EXPORT_SYMBOL(snd_pcm_limit_hw_rates); | 484 | EXPORT_SYMBOL(snd_pcm_limit_hw_rates); |
493 | 485 | ||
494 | /** | 486 | /** |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index faa2e2be6f2e..b3d5bed75029 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -37,6 +37,18 @@ | |||
37 | #include <sound/minors.h> | 37 | #include <sound/minors.h> |
38 | #include <linux/uio.h> | 38 | #include <linux/uio.h> |
39 | 39 | ||
40 | #include "pcm_local.h" | ||
41 | |||
42 | #ifdef CONFIG_SND_DEBUG | ||
43 | #define CREATE_TRACE_POINTS | ||
44 | #include "pcm_param_trace.h" | ||
45 | #else | ||
46 | #define trace_hw_mask_param_enabled() 0 | ||
47 | #define trace_hw_interval_param_enabled() 0 | ||
48 | #define trace_hw_mask_param(substream, type, index, prev, curr) | ||
49 | #define trace_hw_interval_param(substream, type, index, prev, curr) | ||
50 | #endif | ||
51 | |||
40 | /* | 52 | /* |
41 | * Compatibility | 53 | * Compatibility |
42 | */ | 54 | */ |
@@ -181,20 +193,6 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, | |||
181 | } | 193 | } |
182 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); | 194 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); |
183 | 195 | ||
184 | static inline mm_segment_t snd_enter_user(void) | ||
185 | { | ||
186 | mm_segment_t fs = get_fs(); | ||
187 | set_fs(get_ds()); | ||
188 | return fs; | ||
189 | } | ||
190 | |||
191 | static inline void snd_leave_user(mm_segment_t fs) | ||
192 | { | ||
193 | set_fs(fs); | ||
194 | } | ||
195 | |||
196 | |||
197 | |||
198 | int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) | 196 | int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) |
199 | { | 197 | { |
200 | struct snd_pcm_runtime *runtime; | 198 | struct snd_pcm_runtime *runtime; |
@@ -214,11 +212,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) | |||
214 | info->subdevices_avail = pstr->substream_count - pstr->substream_opened; | 212 | info->subdevices_avail = pstr->substream_count - pstr->substream_opened; |
215 | strlcpy(info->subname, substream->name, sizeof(info->subname)); | 213 | strlcpy(info->subname, substream->name, sizeof(info->subname)); |
216 | runtime = substream->runtime; | 214 | runtime = substream->runtime; |
217 | /* AB: FIXME!!! This is definitely nonsense */ | 215 | |
218 | if (runtime) { | ||
219 | info->sync = runtime->sync; | ||
220 | substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); | ||
221 | } | ||
222 | return 0; | 216 | return 0; |
223 | } | 217 | } |
224 | 218 | ||
@@ -255,205 +249,268 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) | |||
255 | return true; | 249 | return true; |
256 | } | 250 | } |
257 | 251 | ||
258 | #undef RULES_DEBUG | 252 | static int constrain_mask_params(struct snd_pcm_substream *substream, |
259 | 253 | struct snd_pcm_hw_params *params) | |
260 | #ifdef RULES_DEBUG | ||
261 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v | ||
262 | static const char * const snd_pcm_hw_param_names[] = { | ||
263 | HW_PARAM(ACCESS), | ||
264 | HW_PARAM(FORMAT), | ||
265 | HW_PARAM(SUBFORMAT), | ||
266 | HW_PARAM(SAMPLE_BITS), | ||
267 | HW_PARAM(FRAME_BITS), | ||
268 | HW_PARAM(CHANNELS), | ||
269 | HW_PARAM(RATE), | ||
270 | HW_PARAM(PERIOD_TIME), | ||
271 | HW_PARAM(PERIOD_SIZE), | ||
272 | HW_PARAM(PERIOD_BYTES), | ||
273 | HW_PARAM(PERIODS), | ||
274 | HW_PARAM(BUFFER_TIME), | ||
275 | HW_PARAM(BUFFER_SIZE), | ||
276 | HW_PARAM(BUFFER_BYTES), | ||
277 | HW_PARAM(TICK_TIME), | ||
278 | }; | ||
279 | #endif | ||
280 | |||
281 | int snd_pcm_hw_refine(struct snd_pcm_substream *substream, | ||
282 | struct snd_pcm_hw_params *params) | ||
283 | { | 254 | { |
255 | struct snd_pcm_hw_constraints *constrs = | ||
256 | &substream->runtime->hw_constraints; | ||
257 | struct snd_mask *m; | ||
284 | unsigned int k; | 258 | unsigned int k; |
285 | struct snd_pcm_hardware *hw; | 259 | struct snd_mask old_mask; |
286 | struct snd_interval *i = NULL; | 260 | int changed; |
287 | struct snd_mask *m = NULL; | ||
288 | struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; | ||
289 | unsigned int rstamps[constrs->rules_num]; | ||
290 | unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; | ||
291 | unsigned int stamp = 2; | ||
292 | int changed, again; | ||
293 | |||
294 | params->info = 0; | ||
295 | params->fifo_size = 0; | ||
296 | if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) | ||
297 | params->msbits = 0; | ||
298 | if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { | ||
299 | params->rate_num = 0; | ||
300 | params->rate_den = 0; | ||
301 | } | ||
302 | 261 | ||
303 | for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { | 262 | for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { |
304 | m = hw_param_mask(params, k); | 263 | m = hw_param_mask(params, k); |
305 | if (snd_mask_empty(m)) | 264 | if (snd_mask_empty(m)) |
306 | return -EINVAL; | 265 | return -EINVAL; |
266 | |||
267 | /* This parameter is not requested to change by a caller. */ | ||
307 | if (!(params->rmask & (1 << k))) | 268 | if (!(params->rmask & (1 << k))) |
308 | continue; | 269 | continue; |
309 | #ifdef RULES_DEBUG | 270 | |
310 | pr_debug("%s = ", snd_pcm_hw_param_names[k]); | 271 | if (trace_hw_mask_param_enabled()) |
311 | pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); | 272 | old_mask = *m; |
312 | #endif | 273 | |
313 | changed = snd_mask_refine(m, constrs_mask(constrs, k)); | 274 | changed = snd_mask_refine(m, constrs_mask(constrs, k)); |
314 | #ifdef RULES_DEBUG | ||
315 | pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); | ||
316 | #endif | ||
317 | if (changed) | ||
318 | params->cmask |= 1 << k; | ||
319 | if (changed < 0) | 275 | if (changed < 0) |
320 | return changed; | 276 | return changed; |
277 | if (changed == 0) | ||
278 | continue; | ||
279 | |||
280 | /* Set corresponding flag so that the caller gets it. */ | ||
281 | trace_hw_mask_param(substream, k, 0, &old_mask, m); | ||
282 | params->cmask |= 1 << k; | ||
321 | } | 283 | } |
322 | 284 | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int constrain_interval_params(struct snd_pcm_substream *substream, | ||
289 | struct snd_pcm_hw_params *params) | ||
290 | { | ||
291 | struct snd_pcm_hw_constraints *constrs = | ||
292 | &substream->runtime->hw_constraints; | ||
293 | struct snd_interval *i; | ||
294 | unsigned int k; | ||
295 | struct snd_interval old_interval; | ||
296 | int changed; | ||
297 | |||
323 | for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { | 298 | for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { |
324 | i = hw_param_interval(params, k); | 299 | i = hw_param_interval(params, k); |
325 | if (snd_interval_empty(i)) | 300 | if (snd_interval_empty(i)) |
326 | return -EINVAL; | 301 | return -EINVAL; |
302 | |||
303 | /* This parameter is not requested to change by a caller. */ | ||
327 | if (!(params->rmask & (1 << k))) | 304 | if (!(params->rmask & (1 << k))) |
328 | continue; | 305 | continue; |
329 | #ifdef RULES_DEBUG | 306 | |
330 | pr_debug("%s = ", snd_pcm_hw_param_names[k]); | 307 | if (trace_hw_interval_param_enabled()) |
331 | if (i->empty) | 308 | old_interval = *i; |
332 | pr_cont("empty"); | 309 | |
333 | else | ||
334 | pr_cont("%c%u %u%c", | ||
335 | i->openmin ? '(' : '[', i->min, | ||
336 | i->max, i->openmax ? ')' : ']'); | ||
337 | pr_cont(" -> "); | ||
338 | #endif | ||
339 | changed = snd_interval_refine(i, constrs_interval(constrs, k)); | 310 | changed = snd_interval_refine(i, constrs_interval(constrs, k)); |
340 | #ifdef RULES_DEBUG | ||
341 | if (i->empty) | ||
342 | pr_cont("empty\n"); | ||
343 | else | ||
344 | pr_cont("%c%u %u%c\n", | ||
345 | i->openmin ? '(' : '[', i->min, | ||
346 | i->max, i->openmax ? ')' : ']'); | ||
347 | #endif | ||
348 | if (changed) | ||
349 | params->cmask |= 1 << k; | ||
350 | if (changed < 0) | 311 | if (changed < 0) |
351 | return changed; | 312 | return changed; |
313 | if (changed == 0) | ||
314 | continue; | ||
315 | |||
316 | /* Set corresponding flag so that the caller gets it. */ | ||
317 | trace_hw_interval_param(substream, k, 0, &old_interval, i); | ||
318 | params->cmask |= 1 << k; | ||
352 | } | 319 | } |
353 | 320 | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int constrain_params_by_rules(struct snd_pcm_substream *substream, | ||
325 | struct snd_pcm_hw_params *params) | ||
326 | { | ||
327 | struct snd_pcm_hw_constraints *constrs = | ||
328 | &substream->runtime->hw_constraints; | ||
329 | unsigned int k; | ||
330 | unsigned int rstamps[constrs->rules_num]; | ||
331 | unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; | ||
332 | unsigned int stamp; | ||
333 | struct snd_pcm_hw_rule *r; | ||
334 | unsigned int d; | ||
335 | struct snd_mask old_mask; | ||
336 | struct snd_interval old_interval; | ||
337 | bool again; | ||
338 | int changed; | ||
339 | |||
340 | /* | ||
341 | * Each application of rule has own sequence number. | ||
342 | * | ||
343 | * Each member of 'rstamps' array represents the sequence number of | ||
344 | * recent application of corresponding rule. | ||
345 | */ | ||
354 | for (k = 0; k < constrs->rules_num; k++) | 346 | for (k = 0; k < constrs->rules_num; k++) |
355 | rstamps[k] = 0; | 347 | rstamps[k] = 0; |
356 | for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) | 348 | |
349 | /* | ||
350 | * Each member of 'vstamps' array represents the sequence number of | ||
351 | * recent application of rule in which corresponding parameters were | ||
352 | * changed. | ||
353 | * | ||
354 | * In initial state, elements corresponding to parameters requested by | ||
355 | * a caller is 1. For unrequested parameters, corresponding members | ||
356 | * have 0 so that the parameters are never changed anymore. | ||
357 | */ | ||
358 | for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) | ||
357 | vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; | 359 | vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; |
358 | do { | 360 | |
359 | again = 0; | 361 | /* Due to the above design, actual sequence number starts at 2. */ |
360 | for (k = 0; k < constrs->rules_num; k++) { | 362 | stamp = 2; |
361 | struct snd_pcm_hw_rule *r = &constrs->rules[k]; | 363 | retry: |
362 | unsigned int d; | 364 | /* Apply all rules in order. */ |
363 | int doit = 0; | 365 | again = false; |
364 | if (r->cond && !(r->cond & params->flags)) | 366 | for (k = 0; k < constrs->rules_num; k++) { |
365 | continue; | 367 | r = &constrs->rules[k]; |
366 | for (d = 0; r->deps[d] >= 0; d++) { | 368 | |
367 | if (vstamps[r->deps[d]] > rstamps[k]) { | 369 | /* |
368 | doit = 1; | 370 | * Check condition bits of this rule. When the rule has |
369 | break; | 371 | * some condition bits, parameter without the bits is |
370 | } | 372 | * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP |
371 | } | 373 | * is an example of the condition bits. |
372 | if (!doit) | 374 | */ |
373 | continue; | 375 | if (r->cond && !(r->cond & params->flags)) |
374 | #ifdef RULES_DEBUG | 376 | continue; |
375 | pr_debug("Rule %d [%p]: ", k, r->func); | 377 | |
376 | if (r->var >= 0) { | 378 | /* |
377 | pr_cont("%s = ", snd_pcm_hw_param_names[r->var]); | 379 | * The 'deps' array includes maximum three dependencies |
378 | if (hw_is_mask(r->var)) { | 380 | * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth |
379 | m = hw_param_mask(params, r->var); | 381 | * member of this array is a sentinel and should be |
380 | pr_cont("%x", *m->bits); | 382 | * negative value. |
381 | } else { | 383 | * |
382 | i = hw_param_interval(params, r->var); | 384 | * This rule should be processed in this time when dependent |
383 | if (i->empty) | 385 | * parameters were changed at former applications of the other |
384 | pr_cont("empty"); | 386 | * rules. |
385 | else | 387 | */ |
386 | pr_cont("%c%u %u%c", | 388 | for (d = 0; r->deps[d] >= 0; d++) { |
387 | i->openmin ? '(' : '[', i->min, | 389 | if (vstamps[r->deps[d]] > rstamps[k]) |
388 | i->max, i->openmax ? ')' : ']'); | 390 | break; |
389 | } | 391 | } |
390 | } | 392 | if (r->deps[d] < 0) |
391 | #endif | 393 | continue; |
392 | changed = r->func(params, r); | 394 | |
393 | #ifdef RULES_DEBUG | 395 | if (trace_hw_mask_param_enabled()) { |
394 | if (r->var >= 0) { | 396 | if (hw_is_mask(r->var)) |
395 | pr_cont(" -> "); | 397 | old_mask = *hw_param_mask(params, r->var); |
396 | if (hw_is_mask(r->var)) | 398 | } |
397 | pr_cont("%x", *m->bits); | 399 | if (trace_hw_interval_param_enabled()) { |
398 | else { | 400 | if (hw_is_interval(r->var)) |
399 | if (i->empty) | 401 | old_interval = *hw_param_interval(params, r->var); |
400 | pr_cont("empty"); | 402 | } |
401 | else | 403 | |
402 | pr_cont("%c%u %u%c", | 404 | changed = r->func(params, r); |
403 | i->openmin ? '(' : '[', i->min, | 405 | if (changed < 0) |
404 | i->max, i->openmax ? ')' : ']'); | 406 | return changed; |
405 | } | 407 | |
408 | /* | ||
409 | * When the parameter is changed, notify it to the caller | ||
410 | * by corresponding returned bit, then preparing for next | ||
411 | * iteration. | ||
412 | */ | ||
413 | if (changed && r->var >= 0) { | ||
414 | if (hw_is_mask(r->var)) { | ||
415 | trace_hw_mask_param(substream, r->var, | ||
416 | k + 1, &old_mask, | ||
417 | hw_param_mask(params, r->var)); | ||
406 | } | 418 | } |
407 | pr_cont("\n"); | 419 | if (hw_is_interval(r->var)) { |
408 | #endif | 420 | trace_hw_interval_param(substream, r->var, |
409 | rstamps[k] = stamp; | 421 | k + 1, &old_interval, |
410 | if (changed && r->var >= 0) { | 422 | hw_param_interval(params, r->var)); |
411 | params->cmask |= (1 << r->var); | ||
412 | vstamps[r->var] = stamp; | ||
413 | again = 1; | ||
414 | } | 423 | } |
415 | if (changed < 0) | 424 | |
416 | return changed; | 425 | params->cmask |= (1 << r->var); |
417 | stamp++; | 426 | vstamps[r->var] = stamp; |
427 | again = true; | ||
418 | } | 428 | } |
419 | } while (again); | 429 | |
430 | rstamps[k] = stamp++; | ||
431 | } | ||
432 | |||
433 | /* Iterate to evaluate all rules till no parameters are changed. */ | ||
434 | if (again) | ||
435 | goto retry; | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int fixup_unreferenced_params(struct snd_pcm_substream *substream, | ||
441 | struct snd_pcm_hw_params *params) | ||
442 | { | ||
443 | const struct snd_interval *i; | ||
444 | const struct snd_mask *m; | ||
445 | int err; | ||
446 | |||
420 | if (!params->msbits) { | 447 | if (!params->msbits) { |
421 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | 448 | i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); |
422 | if (snd_interval_single(i)) | 449 | if (snd_interval_single(i)) |
423 | params->msbits = snd_interval_value(i); | 450 | params->msbits = snd_interval_value(i); |
424 | } | 451 | } |
425 | 452 | ||
426 | if (!params->rate_den) { | 453 | if (!params->rate_den) { |
427 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | 454 | i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); |
428 | if (snd_interval_single(i)) { | 455 | if (snd_interval_single(i)) { |
429 | params->rate_num = snd_interval_value(i); | 456 | params->rate_num = snd_interval_value(i); |
430 | params->rate_den = 1; | 457 | params->rate_den = 1; |
431 | } | 458 | } |
432 | } | 459 | } |
433 | 460 | ||
434 | hw = &substream->runtime->hw; | 461 | if (!params->fifo_size) { |
462 | m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
463 | i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
464 | if (snd_mask_single(m) && snd_interval_single(i)) { | ||
465 | err = substream->ops->ioctl(substream, | ||
466 | SNDRV_PCM_IOCTL1_FIFO_SIZE, params); | ||
467 | if (err < 0) | ||
468 | return err; | ||
469 | } | ||
470 | } | ||
471 | |||
435 | if (!params->info) { | 472 | if (!params->info) { |
436 | params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | | 473 | params->info = substream->runtime->hw.info; |
437 | SNDRV_PCM_INFO_DRAIN_TRIGGER); | 474 | params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | |
475 | SNDRV_PCM_INFO_DRAIN_TRIGGER); | ||
438 | if (!hw_support_mmap(substream)) | 476 | if (!hw_support_mmap(substream)) |
439 | params->info &= ~(SNDRV_PCM_INFO_MMAP | | 477 | params->info &= ~(SNDRV_PCM_INFO_MMAP | |
440 | SNDRV_PCM_INFO_MMAP_VALID); | 478 | SNDRV_PCM_INFO_MMAP_VALID); |
441 | } | 479 | } |
442 | if (!params->fifo_size) { | 480 | |
443 | m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 481 | return 0; |
444 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | 482 | } |
445 | if (snd_mask_min(m) == snd_mask_max(m) && | 483 | |
446 | snd_interval_min(i) == snd_interval_max(i)) { | 484 | int snd_pcm_hw_refine(struct snd_pcm_substream *substream, |
447 | changed = substream->ops->ioctl(substream, | 485 | struct snd_pcm_hw_params *params) |
448 | SNDRV_PCM_IOCTL1_FIFO_SIZE, params); | 486 | { |
449 | if (changed < 0) | 487 | int err; |
450 | return changed; | 488 | |
451 | } | 489 | params->info = 0; |
490 | params->fifo_size = 0; | ||
491 | if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) | ||
492 | params->msbits = 0; | ||
493 | if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { | ||
494 | params->rate_num = 0; | ||
495 | params->rate_den = 0; | ||
452 | } | 496 | } |
497 | |||
498 | err = constrain_mask_params(substream, params); | ||
499 | if (err < 0) | ||
500 | return err; | ||
501 | |||
502 | err = constrain_interval_params(substream, params); | ||
503 | if (err < 0) | ||
504 | return err; | ||
505 | |||
506 | err = constrain_params_by_rules(substream, params); | ||
507 | if (err < 0) | ||
508 | return err; | ||
509 | |||
453 | params->rmask = 0; | 510 | params->rmask = 0; |
511 | |||
454 | return 0; | 512 | return 0; |
455 | } | 513 | } |
456 | |||
457 | EXPORT_SYMBOL(snd_pcm_hw_refine); | 514 | EXPORT_SYMBOL(snd_pcm_hw_refine); |
458 | 515 | ||
459 | static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, | 516 | static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, |
@@ -467,11 +524,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, | |||
467 | return PTR_ERR(params); | 524 | return PTR_ERR(params); |
468 | 525 | ||
469 | err = snd_pcm_hw_refine(substream, params); | 526 | err = snd_pcm_hw_refine(substream, params); |
470 | if (copy_to_user(_params, params, sizeof(*params))) { | 527 | if (err < 0) |
471 | if (!err) | 528 | goto end; |
472 | err = -EFAULT; | 529 | |
473 | } | 530 | err = fixup_unreferenced_params(substream, params); |
531 | if (err < 0) | ||
532 | goto end; | ||
474 | 533 | ||
534 | if (copy_to_user(_params, params, sizeof(*params))) | ||
535 | err = -EFAULT; | ||
536 | end: | ||
475 | kfree(params); | 537 | kfree(params); |
476 | return err; | 538 | return err; |
477 | } | 539 | } |
@@ -509,6 +571,70 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, | |||
509 | #endif | 571 | #endif |
510 | } | 572 | } |
511 | 573 | ||
574 | /** | ||
575 | * snd_pcm_hw_param_choose - choose a configuration defined by @params | ||
576 | * @pcm: PCM instance | ||
577 | * @params: the hw_params instance | ||
578 | * | ||
579 | * Choose one configuration from configuration space defined by @params. | ||
580 | * The configuration chosen is that obtained fixing in this order: | ||
581 | * first access, first format, first subformat, min channels, | ||
582 | * min rate, min period time, max buffer size, min tick time | ||
583 | * | ||
584 | * Return: Zero if successful, or a negative error code on failure. | ||
585 | */ | ||
586 | static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, | ||
587 | struct snd_pcm_hw_params *params) | ||
588 | { | ||
589 | static const int vars[] = { | ||
590 | SNDRV_PCM_HW_PARAM_ACCESS, | ||
591 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
592 | SNDRV_PCM_HW_PARAM_SUBFORMAT, | ||
593 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
594 | SNDRV_PCM_HW_PARAM_RATE, | ||
595 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
596 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
597 | SNDRV_PCM_HW_PARAM_TICK_TIME, | ||
598 | -1 | ||
599 | }; | ||
600 | const int *v; | ||
601 | struct snd_mask old_mask; | ||
602 | struct snd_interval old_interval; | ||
603 | int changed; | ||
604 | |||
605 | for (v = vars; *v != -1; v++) { | ||
606 | /* Keep old parameter to trace. */ | ||
607 | if (trace_hw_mask_param_enabled()) { | ||
608 | if (hw_is_mask(*v)) | ||
609 | old_mask = *hw_param_mask(params, *v); | ||
610 | } | ||
611 | if (trace_hw_interval_param_enabled()) { | ||
612 | if (hw_is_interval(*v)) | ||
613 | old_interval = *hw_param_interval(params, *v); | ||
614 | } | ||
615 | if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) | ||
616 | changed = snd_pcm_hw_param_first(pcm, params, *v, NULL); | ||
617 | else | ||
618 | changed = snd_pcm_hw_param_last(pcm, params, *v, NULL); | ||
619 | if (snd_BUG_ON(changed < 0)) | ||
620 | return changed; | ||
621 | if (changed == 0) | ||
622 | continue; | ||
623 | |||
624 | /* Trace the changed parameter. */ | ||
625 | if (hw_is_mask(*v)) { | ||
626 | trace_hw_mask_param(pcm, *v, 0, &old_mask, | ||
627 | hw_param_mask(params, *v)); | ||
628 | } | ||
629 | if (hw_is_interval(*v)) { | ||
630 | trace_hw_interval_param(pcm, *v, 0, &old_interval, | ||
631 | hw_param_interval(params, *v)); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
512 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | 638 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, |
513 | struct snd_pcm_hw_params *params) | 639 | struct snd_pcm_hw_params *params) |
514 | { | 640 | { |
@@ -546,6 +672,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
546 | if (err < 0) | 672 | if (err < 0) |
547 | goto _error; | 673 | goto _error; |
548 | 674 | ||
675 | err = fixup_unreferenced_params(substream, params); | ||
676 | if (err < 0) | ||
677 | goto _error; | ||
678 | |||
549 | if (substream->ops->hw_params != NULL) { | 679 | if (substream->ops->hw_params != NULL) { |
550 | err = substream->ops->hw_params(substream, params); | 680 | err = substream->ops->hw_params(substream, params); |
551 | if (err < 0) | 681 | if (err < 0) |
@@ -621,11 +751,12 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, | |||
621 | return PTR_ERR(params); | 751 | return PTR_ERR(params); |
622 | 752 | ||
623 | err = snd_pcm_hw_params(substream, params); | 753 | err = snd_pcm_hw_params(substream, params); |
624 | if (copy_to_user(_params, params, sizeof(*params))) { | 754 | if (err < 0) |
625 | if (!err) | 755 | goto end; |
626 | err = -EFAULT; | ||
627 | } | ||
628 | 756 | ||
757 | if (copy_to_user(_params, params, sizeof(*params))) | ||
758 | err = -EFAULT; | ||
759 | end: | ||
629 | kfree(params); | 760 | kfree(params); |
630 | return err; | 761 | return err; |
631 | } | 762 | } |
@@ -1081,6 +1212,7 @@ static const struct action_ops snd_pcm_action_start = { | |||
1081 | * @substream: the PCM substream instance | 1212 | * @substream: the PCM substream instance |
1082 | * | 1213 | * |
1083 | * Return: Zero if successful, or a negative error code. | 1214 | * Return: Zero if successful, or a negative error code. |
1215 | * The stream lock must be acquired before calling this function. | ||
1084 | */ | 1216 | */ |
1085 | int snd_pcm_start(struct snd_pcm_substream *substream) | 1217 | int snd_pcm_start(struct snd_pcm_substream *substream) |
1086 | { | 1218 | { |
@@ -1088,6 +1220,13 @@ int snd_pcm_start(struct snd_pcm_substream *substream) | |||
1088 | SNDRV_PCM_STATE_RUNNING); | 1220 | SNDRV_PCM_STATE_RUNNING); |
1089 | } | 1221 | } |
1090 | 1222 | ||
1223 | /* take the stream lock and start the streams */ | ||
1224 | static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream) | ||
1225 | { | ||
1226 | return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, | ||
1227 | SNDRV_PCM_STATE_RUNNING); | ||
1228 | } | ||
1229 | |||
1091 | /* | 1230 | /* |
1092 | * stop callbacks | 1231 | * stop callbacks |
1093 | */ | 1232 | */ |
@@ -1139,7 +1278,6 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) | |||
1139 | { | 1278 | { |
1140 | return snd_pcm_action(&snd_pcm_action_stop, substream, state); | 1279 | return snd_pcm_action(&snd_pcm_action_stop, substream, state); |
1141 | } | 1280 | } |
1142 | |||
1143 | EXPORT_SYMBOL(snd_pcm_stop); | 1281 | EXPORT_SYMBOL(snd_pcm_stop); |
1144 | 1282 | ||
1145 | /** | 1283 | /** |
@@ -1314,7 +1452,6 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream) | |||
1314 | snd_pcm_stream_unlock_irqrestore(substream, flags); | 1452 | snd_pcm_stream_unlock_irqrestore(substream, flags); |
1315 | return err; | 1453 | return err; |
1316 | } | 1454 | } |
1317 | |||
1318 | EXPORT_SYMBOL(snd_pcm_suspend); | 1455 | EXPORT_SYMBOL(snd_pcm_suspend); |
1319 | 1456 | ||
1320 | /** | 1457 | /** |
@@ -1346,7 +1483,6 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) | |||
1346 | } | 1483 | } |
1347 | return 0; | 1484 | return 0; |
1348 | } | 1485 | } |
1349 | |||
1350 | EXPORT_SYMBOL(snd_pcm_suspend_all); | 1486 | EXPORT_SYMBOL(snd_pcm_suspend_all); |
1351 | 1487 | ||
1352 | /* resume */ | 1488 | /* resume */ |
@@ -1397,14 +1533,7 @@ static const struct action_ops snd_pcm_action_resume = { | |||
1397 | 1533 | ||
1398 | static int snd_pcm_resume(struct snd_pcm_substream *substream) | 1534 | static int snd_pcm_resume(struct snd_pcm_substream *substream) |
1399 | { | 1535 | { |
1400 | struct snd_card *card = substream->pcm->card; | 1536 | return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); |
1401 | int res; | ||
1402 | |||
1403 | snd_power_lock(card); | ||
1404 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) | ||
1405 | res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); | ||
1406 | snd_power_unlock(card); | ||
1407 | return res; | ||
1408 | } | 1537 | } |
1409 | 1538 | ||
1410 | #else | 1539 | #else |
@@ -1423,17 +1552,9 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream) | |||
1423 | */ | 1552 | */ |
1424 | static int snd_pcm_xrun(struct snd_pcm_substream *substream) | 1553 | static int snd_pcm_xrun(struct snd_pcm_substream *substream) |
1425 | { | 1554 | { |
1426 | struct snd_card *card = substream->pcm->card; | ||
1427 | struct snd_pcm_runtime *runtime = substream->runtime; | 1555 | struct snd_pcm_runtime *runtime = substream->runtime; |
1428 | int result; | 1556 | int result; |
1429 | 1557 | ||
1430 | snd_power_lock(card); | ||
1431 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | ||
1432 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0); | ||
1433 | if (result < 0) | ||
1434 | goto _unlock; | ||
1435 | } | ||
1436 | |||
1437 | snd_pcm_stream_lock_irq(substream); | 1558 | snd_pcm_stream_lock_irq(substream); |
1438 | switch (runtime->status->state) { | 1559 | switch (runtime->status->state) { |
1439 | case SNDRV_PCM_STATE_XRUN: | 1560 | case SNDRV_PCM_STATE_XRUN: |
@@ -1446,8 +1567,6 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream) | |||
1446 | result = -EBADFD; | 1567 | result = -EBADFD; |
1447 | } | 1568 | } |
1448 | snd_pcm_stream_unlock_irq(substream); | 1569 | snd_pcm_stream_unlock_irq(substream); |
1449 | _unlock: | ||
1450 | snd_power_unlock(card); | ||
1451 | return result; | 1570 | return result; |
1452 | } | 1571 | } |
1453 | 1572 | ||
@@ -1551,8 +1670,6 @@ static const struct action_ops snd_pcm_action_prepare = { | |||
1551 | static int snd_pcm_prepare(struct snd_pcm_substream *substream, | 1670 | static int snd_pcm_prepare(struct snd_pcm_substream *substream, |
1552 | struct file *file) | 1671 | struct file *file) |
1553 | { | 1672 | { |
1554 | int res; | ||
1555 | struct snd_card *card = substream->pcm->card; | ||
1556 | int f_flags; | 1673 | int f_flags; |
1557 | 1674 | ||
1558 | if (file) | 1675 | if (file) |
@@ -1560,12 +1677,19 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, | |||
1560 | else | 1677 | else |
1561 | f_flags = substream->f_flags; | 1678 | f_flags = substream->f_flags; |
1562 | 1679 | ||
1563 | snd_power_lock(card); | 1680 | snd_pcm_stream_lock_irq(substream); |
1564 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) | 1681 | switch (substream->runtime->status->state) { |
1565 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, | 1682 | case SNDRV_PCM_STATE_PAUSED: |
1566 | substream, f_flags); | 1683 | snd_pcm_pause(substream, 0); |
1567 | snd_power_unlock(card); | 1684 | /* fallthru */ |
1568 | return res; | 1685 | case SNDRV_PCM_STATE_SUSPENDED: |
1686 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | ||
1687 | break; | ||
1688 | } | ||
1689 | snd_pcm_stream_unlock_irq(substream); | ||
1690 | |||
1691 | return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, | ||
1692 | substream, f_flags); | ||
1569 | } | 1693 | } |
1570 | 1694 | ||
1571 | /* | 1695 | /* |
@@ -1662,15 +1786,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, | |||
1662 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 1786 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
1663 | return -EBADFD; | 1787 | return -EBADFD; |
1664 | 1788 | ||
1665 | snd_power_lock(card); | ||
1666 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | ||
1667 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0); | ||
1668 | if (result < 0) { | ||
1669 | snd_power_unlock(card); | ||
1670 | return result; | ||
1671 | } | ||
1672 | } | ||
1673 | |||
1674 | if (file) { | 1789 | if (file) { |
1675 | if (file->f_flags & O_NONBLOCK) | 1790 | if (file->f_flags & O_NONBLOCK) |
1676 | nonblock = 1; | 1791 | nonblock = 1; |
@@ -1753,7 +1868,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, | |||
1753 | unlock: | 1868 | unlock: |
1754 | snd_pcm_stream_unlock_irq(substream); | 1869 | snd_pcm_stream_unlock_irq(substream); |
1755 | up_read(&snd_pcm_link_rwsem); | 1870 | up_read(&snd_pcm_link_rwsem); |
1756 | snd_power_unlock(card); | ||
1757 | 1871 | ||
1758 | return result; | 1872 | return result; |
1759 | } | 1873 | } |
@@ -1773,8 +1887,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) | |||
1773 | runtime = substream->runtime; | 1887 | runtime = substream->runtime; |
1774 | 1888 | ||
1775 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN || | 1889 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN || |
1776 | runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || | 1890 | runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) |
1777 | runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) | ||
1778 | return -EBADFD; | 1891 | return -EBADFD; |
1779 | 1892 | ||
1780 | snd_pcm_stream_lock_irq(substream); | 1893 | snd_pcm_stream_lock_irq(substream); |
@@ -1940,7 +2053,8 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, | |||
1940 | struct snd_pcm_hw_rule *rule) | 2053 | struct snd_pcm_hw_rule *rule) |
1941 | { | 2054 | { |
1942 | unsigned int k; | 2055 | unsigned int k; |
1943 | struct snd_interval *i = hw_param_interval(params, rule->deps[0]); | 2056 | const struct snd_interval *i = |
2057 | hw_param_interval_c(params, rule->deps[0]); | ||
1944 | struct snd_mask m; | 2058 | struct snd_mask m; |
1945 | struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 2059 | struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); |
1946 | snd_mask_any(&m); | 2060 | snd_mask_any(&m); |
@@ -1986,8 +2100,10 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, | |||
1986 | #error "Change this table" | 2100 | #error "Change this table" |
1987 | #endif | 2101 | #endif |
1988 | 2102 | ||
1989 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 2103 | static const unsigned int rates[] = { |
1990 | 48000, 64000, 88200, 96000, 176400, 192000 }; | 2104 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, |
2105 | 48000, 64000, 88200, 96000, 176400, 192000 | ||
2106 | }; | ||
1991 | 2107 | ||
1992 | const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { | 2108 | const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { |
1993 | .count = ARRAY_SIZE(rates), | 2109 | .count = ARRAY_SIZE(rates), |
@@ -2250,7 +2366,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) | |||
2250 | } | 2366 | } |
2251 | snd_pcm_detach_substream(substream); | 2367 | snd_pcm_detach_substream(substream); |
2252 | } | 2368 | } |
2253 | |||
2254 | EXPORT_SYMBOL(snd_pcm_release_substream); | 2369 | EXPORT_SYMBOL(snd_pcm_release_substream); |
2255 | 2370 | ||
2256 | int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | 2371 | int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, |
@@ -2292,7 +2407,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | |||
2292 | snd_pcm_release_substream(substream); | 2407 | snd_pcm_release_substream(substream); |
2293 | return err; | 2408 | return err; |
2294 | } | 2409 | } |
2295 | |||
2296 | EXPORT_SYMBOL(snd_pcm_open_substream); | 2410 | EXPORT_SYMBOL(snd_pcm_open_substream); |
2297 | 2411 | ||
2298 | static int snd_pcm_open_file(struct file *file, | 2412 | static int snd_pcm_open_file(struct file *file, |
@@ -2428,50 +2542,84 @@ static int snd_pcm_release(struct inode *inode, struct file *file) | |||
2428 | return 0; | 2542 | return 0; |
2429 | } | 2543 | } |
2430 | 2544 | ||
2431 | static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, | 2545 | /* check and update PCM state; return 0 or a negative error |
2432 | snd_pcm_uframes_t frames) | 2546 | * call this inside PCM lock |
2547 | */ | ||
2548 | static int do_pcm_hwsync(struct snd_pcm_substream *substream) | ||
2433 | { | 2549 | { |
2434 | struct snd_pcm_runtime *runtime = substream->runtime; | 2550 | switch (substream->runtime->status->state) { |
2435 | snd_pcm_sframes_t appl_ptr; | ||
2436 | snd_pcm_sframes_t ret; | ||
2437 | snd_pcm_sframes_t hw_avail; | ||
2438 | |||
2439 | if (frames == 0) | ||
2440 | return 0; | ||
2441 | |||
2442 | snd_pcm_stream_lock_irq(substream); | ||
2443 | switch (runtime->status->state) { | ||
2444 | case SNDRV_PCM_STATE_PREPARED: | ||
2445 | break; | ||
2446 | case SNDRV_PCM_STATE_DRAINING: | 2551 | case SNDRV_PCM_STATE_DRAINING: |
2447 | case SNDRV_PCM_STATE_RUNNING: | 2552 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
2448 | if (snd_pcm_update_hw_ptr(substream) >= 0) | 2553 | return -EBADFD; |
2449 | break; | ||
2450 | /* Fall through */ | 2554 | /* Fall through */ |
2451 | case SNDRV_PCM_STATE_XRUN: | 2555 | case SNDRV_PCM_STATE_RUNNING: |
2452 | ret = -EPIPE; | 2556 | return snd_pcm_update_hw_ptr(substream); |
2453 | goto __end; | 2557 | case SNDRV_PCM_STATE_PREPARED: |
2558 | case SNDRV_PCM_STATE_PAUSED: | ||
2559 | return 0; | ||
2454 | case SNDRV_PCM_STATE_SUSPENDED: | 2560 | case SNDRV_PCM_STATE_SUSPENDED: |
2455 | ret = -ESTRPIPE; | 2561 | return -ESTRPIPE; |
2456 | goto __end; | 2562 | case SNDRV_PCM_STATE_XRUN: |
2563 | return -EPIPE; | ||
2457 | default: | 2564 | default: |
2458 | ret = -EBADFD; | 2565 | return -EBADFD; |
2459 | goto __end; | ||
2460 | } | 2566 | } |
2567 | } | ||
2461 | 2568 | ||
2462 | hw_avail = snd_pcm_playback_hw_avail(runtime); | 2569 | /* increase the appl_ptr; returns the processed frames or a negative error */ |
2463 | if (hw_avail <= 0) { | 2570 | static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, |
2464 | ret = 0; | 2571 | snd_pcm_uframes_t frames, |
2465 | goto __end; | 2572 | snd_pcm_sframes_t avail) |
2466 | } | 2573 | { |
2467 | if (frames > (snd_pcm_uframes_t)hw_avail) | 2574 | struct snd_pcm_runtime *runtime = substream->runtime; |
2468 | frames = hw_avail; | 2575 | snd_pcm_sframes_t appl_ptr; |
2576 | int ret; | ||
2577 | |||
2578 | if (avail <= 0) | ||
2579 | return 0; | ||
2580 | if (frames > (snd_pcm_uframes_t)avail) | ||
2581 | frames = avail; | ||
2582 | appl_ptr = runtime->control->appl_ptr + frames; | ||
2583 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | ||
2584 | appl_ptr -= runtime->boundary; | ||
2585 | ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); | ||
2586 | return ret < 0 ? ret : frames; | ||
2587 | } | ||
2588 | |||
2589 | /* decrease the appl_ptr; returns the processed frames or a negative error */ | ||
2590 | static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, | ||
2591 | snd_pcm_uframes_t frames, | ||
2592 | snd_pcm_sframes_t avail) | ||
2593 | { | ||
2594 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2595 | snd_pcm_sframes_t appl_ptr; | ||
2596 | int ret; | ||
2597 | |||
2598 | if (avail <= 0) | ||
2599 | return 0; | ||
2600 | if (frames > (snd_pcm_uframes_t)avail) | ||
2601 | frames = avail; | ||
2469 | appl_ptr = runtime->control->appl_ptr - frames; | 2602 | appl_ptr = runtime->control->appl_ptr - frames; |
2470 | if (appl_ptr < 0) | 2603 | if (appl_ptr < 0) |
2471 | appl_ptr += runtime->boundary; | 2604 | appl_ptr += runtime->boundary; |
2472 | runtime->control->appl_ptr = appl_ptr; | 2605 | ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); |
2473 | ret = frames; | 2606 | return ret < 0 ? ret : frames; |
2474 | __end: | 2607 | } |
2608 | |||
2609 | static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, | ||
2610 | snd_pcm_uframes_t frames) | ||
2611 | { | ||
2612 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2613 | snd_pcm_sframes_t ret; | ||
2614 | |||
2615 | if (frames == 0) | ||
2616 | return 0; | ||
2617 | |||
2618 | snd_pcm_stream_lock_irq(substream); | ||
2619 | ret = do_pcm_hwsync(substream); | ||
2620 | if (!ret) | ||
2621 | ret = rewind_appl_ptr(substream, frames, | ||
2622 | snd_pcm_playback_hw_avail(runtime)); | ||
2475 | snd_pcm_stream_unlock_irq(substream); | 2623 | snd_pcm_stream_unlock_irq(substream); |
2476 | return ret; | 2624 | return ret; |
2477 | } | 2625 | } |
@@ -2480,46 +2628,16 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr | |||
2480 | snd_pcm_uframes_t frames) | 2628 | snd_pcm_uframes_t frames) |
2481 | { | 2629 | { |
2482 | struct snd_pcm_runtime *runtime = substream->runtime; | 2630 | struct snd_pcm_runtime *runtime = substream->runtime; |
2483 | snd_pcm_sframes_t appl_ptr; | ||
2484 | snd_pcm_sframes_t ret; | 2631 | snd_pcm_sframes_t ret; |
2485 | snd_pcm_sframes_t hw_avail; | ||
2486 | 2632 | ||
2487 | if (frames == 0) | 2633 | if (frames == 0) |
2488 | return 0; | 2634 | return 0; |
2489 | 2635 | ||
2490 | snd_pcm_stream_lock_irq(substream); | 2636 | snd_pcm_stream_lock_irq(substream); |
2491 | switch (runtime->status->state) { | 2637 | ret = do_pcm_hwsync(substream); |
2492 | case SNDRV_PCM_STATE_PREPARED: | 2638 | if (!ret) |
2493 | case SNDRV_PCM_STATE_DRAINING: | 2639 | ret = rewind_appl_ptr(substream, frames, |
2494 | break; | 2640 | snd_pcm_capture_hw_avail(runtime)); |
2495 | case SNDRV_PCM_STATE_RUNNING: | ||
2496 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2497 | break; | ||
2498 | /* Fall through */ | ||
2499 | case SNDRV_PCM_STATE_XRUN: | ||
2500 | ret = -EPIPE; | ||
2501 | goto __end; | ||
2502 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2503 | ret = -ESTRPIPE; | ||
2504 | goto __end; | ||
2505 | default: | ||
2506 | ret = -EBADFD; | ||
2507 | goto __end; | ||
2508 | } | ||
2509 | |||
2510 | hw_avail = snd_pcm_capture_hw_avail(runtime); | ||
2511 | if (hw_avail <= 0) { | ||
2512 | ret = 0; | ||
2513 | goto __end; | ||
2514 | } | ||
2515 | if (frames > (snd_pcm_uframes_t)hw_avail) | ||
2516 | frames = hw_avail; | ||
2517 | appl_ptr = runtime->control->appl_ptr - frames; | ||
2518 | if (appl_ptr < 0) | ||
2519 | appl_ptr += runtime->boundary; | ||
2520 | runtime->control->appl_ptr = appl_ptr; | ||
2521 | ret = frames; | ||
2522 | __end: | ||
2523 | snd_pcm_stream_unlock_irq(substream); | 2641 | snd_pcm_stream_unlock_irq(substream); |
2524 | return ret; | 2642 | return ret; |
2525 | } | 2643 | } |
@@ -2528,47 +2646,16 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs | |||
2528 | snd_pcm_uframes_t frames) | 2646 | snd_pcm_uframes_t frames) |
2529 | { | 2647 | { |
2530 | struct snd_pcm_runtime *runtime = substream->runtime; | 2648 | struct snd_pcm_runtime *runtime = substream->runtime; |
2531 | snd_pcm_sframes_t appl_ptr; | ||
2532 | snd_pcm_sframes_t ret; | 2649 | snd_pcm_sframes_t ret; |
2533 | snd_pcm_sframes_t avail; | ||
2534 | 2650 | ||
2535 | if (frames == 0) | 2651 | if (frames == 0) |
2536 | return 0; | 2652 | return 0; |
2537 | 2653 | ||
2538 | snd_pcm_stream_lock_irq(substream); | 2654 | snd_pcm_stream_lock_irq(substream); |
2539 | switch (runtime->status->state) { | 2655 | ret = do_pcm_hwsync(substream); |
2540 | case SNDRV_PCM_STATE_PREPARED: | 2656 | if (!ret) |
2541 | case SNDRV_PCM_STATE_PAUSED: | 2657 | ret = forward_appl_ptr(substream, frames, |
2542 | break; | 2658 | snd_pcm_playback_avail(runtime)); |
2543 | case SNDRV_PCM_STATE_DRAINING: | ||
2544 | case SNDRV_PCM_STATE_RUNNING: | ||
2545 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2546 | break; | ||
2547 | /* Fall through */ | ||
2548 | case SNDRV_PCM_STATE_XRUN: | ||
2549 | ret = -EPIPE; | ||
2550 | goto __end; | ||
2551 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2552 | ret = -ESTRPIPE; | ||
2553 | goto __end; | ||
2554 | default: | ||
2555 | ret = -EBADFD; | ||
2556 | goto __end; | ||
2557 | } | ||
2558 | |||
2559 | avail = snd_pcm_playback_avail(runtime); | ||
2560 | if (avail <= 0) { | ||
2561 | ret = 0; | ||
2562 | goto __end; | ||
2563 | } | ||
2564 | if (frames > (snd_pcm_uframes_t)avail) | ||
2565 | frames = avail; | ||
2566 | appl_ptr = runtime->control->appl_ptr + frames; | ||
2567 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | ||
2568 | appl_ptr -= runtime->boundary; | ||
2569 | runtime->control->appl_ptr = appl_ptr; | ||
2570 | ret = frames; | ||
2571 | __end: | ||
2572 | snd_pcm_stream_unlock_irq(substream); | 2659 | snd_pcm_stream_unlock_irq(substream); |
2573 | return ret; | 2660 | return ret; |
2574 | } | 2661 | } |
@@ -2577,123 +2664,47 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst | |||
2577 | snd_pcm_uframes_t frames) | 2664 | snd_pcm_uframes_t frames) |
2578 | { | 2665 | { |
2579 | struct snd_pcm_runtime *runtime = substream->runtime; | 2666 | struct snd_pcm_runtime *runtime = substream->runtime; |
2580 | snd_pcm_sframes_t appl_ptr; | ||
2581 | snd_pcm_sframes_t ret; | 2667 | snd_pcm_sframes_t ret; |
2582 | snd_pcm_sframes_t avail; | ||
2583 | 2668 | ||
2584 | if (frames == 0) | 2669 | if (frames == 0) |
2585 | return 0; | 2670 | return 0; |
2586 | 2671 | ||
2587 | snd_pcm_stream_lock_irq(substream); | 2672 | snd_pcm_stream_lock_irq(substream); |
2588 | switch (runtime->status->state) { | 2673 | ret = do_pcm_hwsync(substream); |
2589 | case SNDRV_PCM_STATE_PREPARED: | 2674 | if (!ret) |
2590 | case SNDRV_PCM_STATE_DRAINING: | 2675 | ret = forward_appl_ptr(substream, frames, |
2591 | case SNDRV_PCM_STATE_PAUSED: | 2676 | snd_pcm_capture_avail(runtime)); |
2592 | break; | ||
2593 | case SNDRV_PCM_STATE_RUNNING: | ||
2594 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2595 | break; | ||
2596 | /* Fall through */ | ||
2597 | case SNDRV_PCM_STATE_XRUN: | ||
2598 | ret = -EPIPE; | ||
2599 | goto __end; | ||
2600 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2601 | ret = -ESTRPIPE; | ||
2602 | goto __end; | ||
2603 | default: | ||
2604 | ret = -EBADFD; | ||
2605 | goto __end; | ||
2606 | } | ||
2607 | |||
2608 | avail = snd_pcm_capture_avail(runtime); | ||
2609 | if (avail <= 0) { | ||
2610 | ret = 0; | ||
2611 | goto __end; | ||
2612 | } | ||
2613 | if (frames > (snd_pcm_uframes_t)avail) | ||
2614 | frames = avail; | ||
2615 | appl_ptr = runtime->control->appl_ptr + frames; | ||
2616 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | ||
2617 | appl_ptr -= runtime->boundary; | ||
2618 | runtime->control->appl_ptr = appl_ptr; | ||
2619 | ret = frames; | ||
2620 | __end: | ||
2621 | snd_pcm_stream_unlock_irq(substream); | 2677 | snd_pcm_stream_unlock_irq(substream); |
2622 | return ret; | 2678 | return ret; |
2623 | } | 2679 | } |
2624 | 2680 | ||
2625 | static int snd_pcm_hwsync(struct snd_pcm_substream *substream) | 2681 | static int snd_pcm_hwsync(struct snd_pcm_substream *substream) |
2626 | { | 2682 | { |
2627 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2628 | int err; | 2683 | int err; |
2629 | 2684 | ||
2630 | snd_pcm_stream_lock_irq(substream); | 2685 | snd_pcm_stream_lock_irq(substream); |
2631 | switch (runtime->status->state) { | 2686 | err = do_pcm_hwsync(substream); |
2632 | case SNDRV_PCM_STATE_DRAINING: | ||
2633 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
2634 | goto __badfd; | ||
2635 | /* Fall through */ | ||
2636 | case SNDRV_PCM_STATE_RUNNING: | ||
2637 | if ((err = snd_pcm_update_hw_ptr(substream)) < 0) | ||
2638 | break; | ||
2639 | /* Fall through */ | ||
2640 | case SNDRV_PCM_STATE_PREPARED: | ||
2641 | err = 0; | ||
2642 | break; | ||
2643 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2644 | err = -ESTRPIPE; | ||
2645 | break; | ||
2646 | case SNDRV_PCM_STATE_XRUN: | ||
2647 | err = -EPIPE; | ||
2648 | break; | ||
2649 | default: | ||
2650 | __badfd: | ||
2651 | err = -EBADFD; | ||
2652 | break; | ||
2653 | } | ||
2654 | snd_pcm_stream_unlock_irq(substream); | 2687 | snd_pcm_stream_unlock_irq(substream); |
2655 | return err; | 2688 | return err; |
2656 | } | 2689 | } |
2657 | 2690 | ||
2658 | static int snd_pcm_delay(struct snd_pcm_substream *substream, | 2691 | static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream) |
2659 | snd_pcm_sframes_t __user *res) | ||
2660 | { | 2692 | { |
2661 | struct snd_pcm_runtime *runtime = substream->runtime; | 2693 | struct snd_pcm_runtime *runtime = substream->runtime; |
2662 | int err; | 2694 | int err; |
2663 | snd_pcm_sframes_t n = 0; | 2695 | snd_pcm_sframes_t n = 0; |
2664 | 2696 | ||
2665 | snd_pcm_stream_lock_irq(substream); | 2697 | snd_pcm_stream_lock_irq(substream); |
2666 | switch (runtime->status->state) { | 2698 | err = do_pcm_hwsync(substream); |
2667 | case SNDRV_PCM_STATE_DRAINING: | 2699 | if (!err) { |
2668 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
2669 | goto __badfd; | ||
2670 | /* Fall through */ | ||
2671 | case SNDRV_PCM_STATE_RUNNING: | ||
2672 | if ((err = snd_pcm_update_hw_ptr(substream)) < 0) | ||
2673 | break; | ||
2674 | /* Fall through */ | ||
2675 | case SNDRV_PCM_STATE_PREPARED: | ||
2676 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2677 | err = 0; | ||
2678 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 2700 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
2679 | n = snd_pcm_playback_hw_avail(runtime); | 2701 | n = snd_pcm_playback_hw_avail(runtime); |
2680 | else | 2702 | else |
2681 | n = snd_pcm_capture_avail(runtime); | 2703 | n = snd_pcm_capture_avail(runtime); |
2682 | n += runtime->delay; | 2704 | n += runtime->delay; |
2683 | break; | ||
2684 | case SNDRV_PCM_STATE_XRUN: | ||
2685 | err = -EPIPE; | ||
2686 | break; | ||
2687 | default: | ||
2688 | __badfd: | ||
2689 | err = -EBADFD; | ||
2690 | break; | ||
2691 | } | 2705 | } |
2692 | snd_pcm_stream_unlock_irq(substream); | 2706 | snd_pcm_stream_unlock_irq(substream); |
2693 | if (!err) | 2707 | return err < 0 ? err : n; |
2694 | if (put_user(n, res)) | ||
2695 | err = -EFAULT; | ||
2696 | return err; | ||
2697 | } | 2708 | } |
2698 | 2709 | ||
2699 | static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | 2710 | static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, |
@@ -2718,10 +2729,16 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | |||
2718 | return err; | 2729 | return err; |
2719 | } | 2730 | } |
2720 | snd_pcm_stream_lock_irq(substream); | 2731 | snd_pcm_stream_lock_irq(substream); |
2721 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) | 2732 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { |
2722 | control->appl_ptr = sync_ptr.c.control.appl_ptr; | 2733 | err = pcm_lib_apply_appl_ptr(substream, |
2723 | else | 2734 | sync_ptr.c.control.appl_ptr); |
2735 | if (err < 0) { | ||
2736 | snd_pcm_stream_unlock_irq(substream); | ||
2737 | return err; | ||
2738 | } | ||
2739 | } else { | ||
2724 | sync_ptr.c.control.appl_ptr = control->appl_ptr; | 2740 | sync_ptr.c.control.appl_ptr = control->appl_ptr; |
2741 | } | ||
2725 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) | 2742 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) |
2726 | control->avail_min = sync_ptr.c.control.avail_min; | 2743 | control->avail_min = sync_ptr.c.control.avail_min; |
2727 | else | 2744 | else |
@@ -2749,10 +2766,12 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) | |||
2749 | return 0; | 2766 | return 0; |
2750 | } | 2767 | } |
2751 | 2768 | ||
2752 | static int snd_pcm_common_ioctl1(struct file *file, | 2769 | static int snd_pcm_common_ioctl(struct file *file, |
2753 | struct snd_pcm_substream *substream, | 2770 | struct snd_pcm_substream *substream, |
2754 | unsigned int cmd, void __user *arg) | 2771 | unsigned int cmd, void __user *arg) |
2755 | { | 2772 | { |
2773 | struct snd_pcm_file *pcm_file = file->private_data; | ||
2774 | |||
2756 | switch (cmd) { | 2775 | switch (cmd) { |
2757 | case SNDRV_PCM_IOCTL_PVERSION: | 2776 | case SNDRV_PCM_IOCTL_PVERSION: |
2758 | return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; | 2777 | return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; |
@@ -2762,6 +2781,11 @@ static int snd_pcm_common_ioctl1(struct file *file, | |||
2762 | return 0; | 2781 | return 0; |
2763 | case SNDRV_PCM_IOCTL_TTSTAMP: | 2782 | case SNDRV_PCM_IOCTL_TTSTAMP: |
2764 | return snd_pcm_tstamp(substream, arg); | 2783 | return snd_pcm_tstamp(substream, arg); |
2784 | case SNDRV_PCM_IOCTL_USER_PVERSION: | ||
2785 | if (get_user(pcm_file->user_pversion, | ||
2786 | (unsigned int __user *)arg)) | ||
2787 | return -EFAULT; | ||
2788 | return 0; | ||
2765 | case SNDRV_PCM_IOCTL_HW_REFINE: | 2789 | case SNDRV_PCM_IOCTL_HW_REFINE: |
2766 | return snd_pcm_hw_refine_user(substream, arg); | 2790 | return snd_pcm_hw_refine_user(substream, arg); |
2767 | case SNDRV_PCM_IOCTL_HW_PARAMS: | 2791 | case SNDRV_PCM_IOCTL_HW_PARAMS: |
@@ -2781,7 +2805,7 @@ static int snd_pcm_common_ioctl1(struct file *file, | |||
2781 | case SNDRV_PCM_IOCTL_RESET: | 2805 | case SNDRV_PCM_IOCTL_RESET: |
2782 | return snd_pcm_reset(substream); | 2806 | return snd_pcm_reset(substream); |
2783 | case SNDRV_PCM_IOCTL_START: | 2807 | case SNDRV_PCM_IOCTL_START: |
2784 | return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); | 2808 | return snd_pcm_start_lock_irq(substream); |
2785 | case SNDRV_PCM_IOCTL_LINK: | 2809 | case SNDRV_PCM_IOCTL_LINK: |
2786 | return snd_pcm_link(substream, (int)(unsigned long) arg); | 2810 | return snd_pcm_link(substream, (int)(unsigned long) arg); |
2787 | case SNDRV_PCM_IOCTL_UNLINK: | 2811 | case SNDRV_PCM_IOCTL_UNLINK: |
@@ -2793,7 +2817,16 @@ static int snd_pcm_common_ioctl1(struct file *file, | |||
2793 | case SNDRV_PCM_IOCTL_HWSYNC: | 2817 | case SNDRV_PCM_IOCTL_HWSYNC: |
2794 | return snd_pcm_hwsync(substream); | 2818 | return snd_pcm_hwsync(substream); |
2795 | case SNDRV_PCM_IOCTL_DELAY: | 2819 | case SNDRV_PCM_IOCTL_DELAY: |
2796 | return snd_pcm_delay(substream, arg); | 2820 | { |
2821 | snd_pcm_sframes_t delay = snd_pcm_delay(substream); | ||
2822 | snd_pcm_sframes_t __user *res = arg; | ||
2823 | |||
2824 | if (delay < 0) | ||
2825 | return delay; | ||
2826 | if (put_user(delay, res)) | ||
2827 | return -EFAULT; | ||
2828 | return 0; | ||
2829 | } | ||
2797 | case SNDRV_PCM_IOCTL_SYNC_PTR: | 2830 | case SNDRV_PCM_IOCTL_SYNC_PTR: |
2798 | return snd_pcm_sync_ptr(substream, arg); | 2831 | return snd_pcm_sync_ptr(substream, arg); |
2799 | #ifdef CONFIG_SND_SUPPORT_OLD_API | 2832 | #ifdef CONFIG_SND_SUPPORT_OLD_API |
@@ -2807,23 +2840,34 @@ static int snd_pcm_common_ioctl1(struct file *file, | |||
2807 | case SNDRV_PCM_IOCTL_DROP: | 2840 | case SNDRV_PCM_IOCTL_DROP: |
2808 | return snd_pcm_drop(substream); | 2841 | return snd_pcm_drop(substream); |
2809 | case SNDRV_PCM_IOCTL_PAUSE: | 2842 | case SNDRV_PCM_IOCTL_PAUSE: |
2810 | { | 2843 | return snd_pcm_action_lock_irq(&snd_pcm_action_pause, |
2811 | int res; | 2844 | substream, |
2812 | snd_pcm_stream_lock_irq(substream); | 2845 | (int)(unsigned long)arg); |
2813 | res = snd_pcm_pause(substream, (int)(unsigned long)arg); | ||
2814 | snd_pcm_stream_unlock_irq(substream); | ||
2815 | return res; | ||
2816 | } | ||
2817 | } | 2846 | } |
2818 | pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd); | 2847 | pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd); |
2819 | return -ENOTTY; | 2848 | return -ENOTTY; |
2820 | } | 2849 | } |
2821 | 2850 | ||
2851 | static int snd_pcm_common_ioctl1(struct file *file, | ||
2852 | struct snd_pcm_substream *substream, | ||
2853 | unsigned int cmd, void __user *arg) | ||
2854 | { | ||
2855 | struct snd_card *card = substream->pcm->card; | ||
2856 | int res; | ||
2857 | |||
2858 | snd_power_lock(card); | ||
2859 | res = snd_power_wait(card, SNDRV_CTL_POWER_D0); | ||
2860 | if (res >= 0) | ||
2861 | res = snd_pcm_common_ioctl(file, substream, cmd, arg); | ||
2862 | snd_power_unlock(card); | ||
2863 | return res; | ||
2864 | } | ||
2865 | |||
2822 | static int snd_pcm_playback_ioctl1(struct file *file, | 2866 | static int snd_pcm_playback_ioctl1(struct file *file, |
2823 | struct snd_pcm_substream *substream, | 2867 | struct snd_pcm_substream *substream, |
2824 | unsigned int cmd, void __user *arg) | 2868 | unsigned int cmd, void __user *arg) |
2825 | { | 2869 | { |
2826 | if (snd_BUG_ON(!substream)) | 2870 | if (PCM_RUNTIME_CHECK(substream)) |
2827 | return -ENXIO; | 2871 | return -ENXIO; |
2828 | if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) | 2872 | if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) |
2829 | return -EINVAL; | 2873 | return -EINVAL; |
@@ -2903,7 +2947,7 @@ static int snd_pcm_capture_ioctl1(struct file *file, | |||
2903 | struct snd_pcm_substream *substream, | 2947 | struct snd_pcm_substream *substream, |
2904 | unsigned int cmd, void __user *arg) | 2948 | unsigned int cmd, void __user *arg) |
2905 | { | 2949 | { |
2906 | if (snd_BUG_ON(!substream)) | 2950 | if (PCM_RUNTIME_CHECK(substream)) |
2907 | return -ENXIO; | 2951 | return -ENXIO; |
2908 | if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE)) | 2952 | if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE)) |
2909 | return -EINVAL; | 2953 | return -EINVAL; |
@@ -3007,30 +3051,55 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, | |||
3007 | (void __user *)arg); | 3051 | (void __user *)arg); |
3008 | } | 3052 | } |
3009 | 3053 | ||
3054 | /** | ||
3055 | * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space | ||
3056 | * @substream: PCM substream | ||
3057 | * @cmd: IOCTL cmd | ||
3058 | * @arg: IOCTL argument | ||
3059 | * | ||
3060 | * The function is provided primarily for OSS layer and USB gadget drivers, | ||
3061 | * and it allows only the limited set of ioctls (hw_params, sw_params, | ||
3062 | * prepare, start, drain, drop, forward). | ||
3063 | */ | ||
3010 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | 3064 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, |
3011 | unsigned int cmd, void *arg) | 3065 | unsigned int cmd, void *arg) |
3012 | { | 3066 | { |
3013 | mm_segment_t fs; | 3067 | snd_pcm_uframes_t *frames = arg; |
3014 | int result; | 3068 | snd_pcm_sframes_t result; |
3015 | 3069 | ||
3016 | fs = snd_enter_user(); | 3070 | switch (cmd) { |
3017 | switch (substream->stream) { | 3071 | case SNDRV_PCM_IOCTL_FORWARD: |
3018 | case SNDRV_PCM_STREAM_PLAYBACK: | 3072 | { |
3019 | result = snd_pcm_playback_ioctl1(NULL, substream, cmd, | 3073 | /* provided only for OSS; capture-only and no value returned */ |
3020 | (void __user *)arg); | 3074 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) |
3021 | break; | 3075 | return -EINVAL; |
3022 | case SNDRV_PCM_STREAM_CAPTURE: | 3076 | result = snd_pcm_capture_forward(substream, *frames); |
3023 | result = snd_pcm_capture_ioctl1(NULL, substream, cmd, | 3077 | return result < 0 ? result : 0; |
3024 | (void __user *)arg); | 3078 | } |
3025 | break; | 3079 | case SNDRV_PCM_IOCTL_HW_PARAMS: |
3080 | return snd_pcm_hw_params(substream, arg); | ||
3081 | case SNDRV_PCM_IOCTL_SW_PARAMS: | ||
3082 | return snd_pcm_sw_params(substream, arg); | ||
3083 | case SNDRV_PCM_IOCTL_PREPARE: | ||
3084 | return snd_pcm_prepare(substream, NULL); | ||
3085 | case SNDRV_PCM_IOCTL_START: | ||
3086 | return snd_pcm_start_lock_irq(substream); | ||
3087 | case SNDRV_PCM_IOCTL_DRAIN: | ||
3088 | return snd_pcm_drain(substream, NULL); | ||
3089 | case SNDRV_PCM_IOCTL_DROP: | ||
3090 | return snd_pcm_drop(substream); | ||
3091 | case SNDRV_PCM_IOCTL_DELAY: | ||
3092 | { | ||
3093 | result = snd_pcm_delay(substream); | ||
3094 | if (result < 0) | ||
3095 | return result; | ||
3096 | *frames = result; | ||
3097 | return 0; | ||
3098 | } | ||
3026 | default: | 3099 | default: |
3027 | result = -EINVAL; | 3100 | return -EINVAL; |
3028 | break; | ||
3029 | } | 3101 | } |
3030 | snd_leave_user(fs); | ||
3031 | return result; | ||
3032 | } | 3102 | } |
3033 | |||
3034 | EXPORT_SYMBOL(snd_pcm_kernel_ioctl); | 3103 | EXPORT_SYMBOL(snd_pcm_kernel_ioctl); |
3035 | 3104 | ||
3036 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, | 3105 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, |
@@ -3314,10 +3383,41 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file | |||
3314 | area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; | 3383 | area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; |
3315 | return 0; | 3384 | return 0; |
3316 | } | 3385 | } |
3386 | |||
3387 | static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) | ||
3388 | { | ||
3389 | if (pcm_file->no_compat_mmap) | ||
3390 | return false; | ||
3391 | /* See pcm_control_mmap_allowed() below. | ||
3392 | * Since older alsa-lib requires both status and control mmaps to be | ||
3393 | * coupled, we have to disable the status mmap for old alsa-lib, too. | ||
3394 | */ | ||
3395 | if (pcm_file->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 14) && | ||
3396 | (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)) | ||
3397 | return false; | ||
3398 | return true; | ||
3399 | } | ||
3400 | |||
3401 | static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file) | ||
3402 | { | ||
3403 | if (pcm_file->no_compat_mmap) | ||
3404 | return false; | ||
3405 | /* Disallow the control mmap when SYNC_APPLPTR flag is set; | ||
3406 | * it enforces the user-space to fall back to snd_pcm_sync_ptr(), | ||
3407 | * thus it effectively assures the manual update of appl_ptr. | ||
3408 | */ | ||
3409 | if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR) | ||
3410 | return false; | ||
3411 | return true; | ||
3412 | } | ||
3413 | |||
3317 | #else /* ! coherent mmap */ | 3414 | #else /* ! coherent mmap */ |
3318 | /* | 3415 | /* |
3319 | * don't support mmap for status and control records. | 3416 | * don't support mmap for status and control records. |
3320 | */ | 3417 | */ |
3418 | #define pcm_status_mmap_allowed(pcm_file) false | ||
3419 | #define pcm_control_mmap_allowed(pcm_file) false | ||
3420 | |||
3321 | static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, | 3421 | static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, |
3322 | struct vm_area_struct *area) | 3422 | struct vm_area_struct *area) |
3323 | { | 3423 | { |
@@ -3437,7 +3537,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
3437 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | 3537 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); |
3438 | return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes); | 3538 | return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes); |
3439 | } | 3539 | } |
3440 | |||
3441 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | 3540 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); |
3442 | #endif /* SNDRV_PCM_INFO_MMAP */ | 3541 | #endif /* SNDRV_PCM_INFO_MMAP */ |
3443 | 3542 | ||
@@ -3486,7 +3585,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, | |||
3486 | atomic_inc(&substream->mmap_count); | 3585 | atomic_inc(&substream->mmap_count); |
3487 | return err; | 3586 | return err; |
3488 | } | 3587 | } |
3489 | |||
3490 | EXPORT_SYMBOL(snd_pcm_mmap_data); | 3588 | EXPORT_SYMBOL(snd_pcm_mmap_data); |
3491 | 3589 | ||
3492 | static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) | 3590 | static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) |
@@ -3503,11 +3601,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) | |||
3503 | offset = area->vm_pgoff << PAGE_SHIFT; | 3601 | offset = area->vm_pgoff << PAGE_SHIFT; |
3504 | switch (offset) { | 3602 | switch (offset) { |
3505 | case SNDRV_PCM_MMAP_OFFSET_STATUS: | 3603 | case SNDRV_PCM_MMAP_OFFSET_STATUS: |
3506 | if (pcm_file->no_compat_mmap) | 3604 | if (!pcm_status_mmap_allowed(pcm_file)) |
3507 | return -ENXIO; | 3605 | return -ENXIO; |
3508 | return snd_pcm_mmap_status(substream, file, area); | 3606 | return snd_pcm_mmap_status(substream, file, area); |
3509 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: | 3607 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: |
3510 | if (pcm_file->no_compat_mmap) | 3608 | if (!pcm_control_mmap_allowed(pcm_file)) |
3511 | return -ENXIO; | 3609 | return -ENXIO; |
3512 | return snd_pcm_mmap_control(substream, file, area); | 3610 | return snd_pcm_mmap_control(substream, file, area); |
3513 | default: | 3611 | default: |
@@ -3603,12 +3701,17 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, | |||
3603 | } | 3701 | } |
3604 | snd_pcm_hw_convert_from_old_params(params, oparams); | 3702 | snd_pcm_hw_convert_from_old_params(params, oparams); |
3605 | err = snd_pcm_hw_refine(substream, params); | 3703 | err = snd_pcm_hw_refine(substream, params); |
3606 | snd_pcm_hw_convert_to_old_params(oparams, params); | 3704 | if (err < 0) |
3607 | if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { | 3705 | goto out_old; |
3608 | if (!err) | ||
3609 | err = -EFAULT; | ||
3610 | } | ||
3611 | 3706 | ||
3707 | err = fixup_unreferenced_params(substream, params); | ||
3708 | if (err < 0) | ||
3709 | goto out_old; | ||
3710 | |||
3711 | snd_pcm_hw_convert_to_old_params(oparams, params); | ||
3712 | if (copy_to_user(_oparams, oparams, sizeof(*oparams))) | ||
3713 | err = -EFAULT; | ||
3714 | out_old: | ||
3612 | kfree(oparams); | 3715 | kfree(oparams); |
3613 | out: | 3716 | out: |
3614 | kfree(params); | 3717 | kfree(params); |
@@ -3631,14 +3734,16 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, | |||
3631 | err = PTR_ERR(oparams); | 3734 | err = PTR_ERR(oparams); |
3632 | goto out; | 3735 | goto out; |
3633 | } | 3736 | } |
3737 | |||
3634 | snd_pcm_hw_convert_from_old_params(params, oparams); | 3738 | snd_pcm_hw_convert_from_old_params(params, oparams); |
3635 | err = snd_pcm_hw_params(substream, params); | 3739 | err = snd_pcm_hw_params(substream, params); |
3636 | snd_pcm_hw_convert_to_old_params(oparams, params); | 3740 | if (err < 0) |
3637 | if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { | 3741 | goto out_old; |
3638 | if (!err) | ||
3639 | err = -EFAULT; | ||
3640 | } | ||
3641 | 3742 | ||
3743 | snd_pcm_hw_convert_to_old_params(oparams, params); | ||
3744 | if (copy_to_user(_oparams, oparams, sizeof(*oparams))) | ||
3745 | err = -EFAULT; | ||
3746 | out_old: | ||
3642 | kfree(oparams); | 3747 | kfree(oparams); |
3643 | out: | 3748 | out: |
3644 | kfree(params); | 3749 | kfree(params); |
diff --git a/sound/core/pcm_param_trace.h b/sound/core/pcm_param_trace.h new file mode 100644 index 000000000000..86c8d658a25c --- /dev/null +++ b/sound/core/pcm_param_trace.h | |||
@@ -0,0 +1,142 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM snd_pcm | ||
3 | |||
4 | #if !defined(_PCM_PARAMS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _PCM_PARAMS_TRACE_H | ||
6 | |||
7 | #include <linux/tracepoint.h> | ||
8 | |||
9 | #define HW_PARAM_ENTRY(param) {SNDRV_PCM_HW_PARAM_##param, #param} | ||
10 | #define hw_param_labels \ | ||
11 | HW_PARAM_ENTRY(ACCESS), \ | ||
12 | HW_PARAM_ENTRY(FORMAT), \ | ||
13 | HW_PARAM_ENTRY(SUBFORMAT), \ | ||
14 | HW_PARAM_ENTRY(SAMPLE_BITS), \ | ||
15 | HW_PARAM_ENTRY(FRAME_BITS), \ | ||
16 | HW_PARAM_ENTRY(CHANNELS), \ | ||
17 | HW_PARAM_ENTRY(RATE), \ | ||
18 | HW_PARAM_ENTRY(PERIOD_TIME), \ | ||
19 | HW_PARAM_ENTRY(PERIOD_SIZE), \ | ||
20 | HW_PARAM_ENTRY(PERIOD_BYTES), \ | ||
21 | HW_PARAM_ENTRY(PERIODS), \ | ||
22 | HW_PARAM_ENTRY(BUFFER_TIME), \ | ||
23 | HW_PARAM_ENTRY(BUFFER_SIZE), \ | ||
24 | HW_PARAM_ENTRY(BUFFER_BYTES), \ | ||
25 | HW_PARAM_ENTRY(TICK_TIME) | ||
26 | |||
27 | TRACE_EVENT(hw_mask_param, | ||
28 | TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_mask *prev, const struct snd_mask *curr), | ||
29 | TP_ARGS(substream, type, index, prev, curr), | ||
30 | TP_STRUCT__entry( | ||
31 | __field(int, card) | ||
32 | __field(int, device) | ||
33 | __field(int, subdevice) | ||
34 | __field(int, direction) | ||
35 | __field(snd_pcm_hw_param_t, type) | ||
36 | __field(int, index) | ||
37 | __field(int, total) | ||
38 | __array(__u32, prev_bits, 8) | ||
39 | __array(__u32, curr_bits, 8) | ||
40 | ), | ||
41 | TP_fast_assign( | ||
42 | __entry->card = substream->pcm->card->number; | ||
43 | __entry->device = substream->pcm->device; | ||
44 | __entry->subdevice = substream->number; | ||
45 | __entry->direction = substream->stream; | ||
46 | __entry->type = type; | ||
47 | __entry->index = index; | ||
48 | __entry->total = substream->runtime->hw_constraints.rules_num; | ||
49 | memcpy(__entry->prev_bits, prev->bits, sizeof(__u32) * 8); | ||
50 | memcpy(__entry->curr_bits, curr->bits, sizeof(__u32) * 8); | ||
51 | ), | ||
52 | TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x", | ||
53 | __entry->card, | ||
54 | __entry->device, | ||
55 | __entry->direction ? "c" : "p", | ||
56 | __entry->subdevice, | ||
57 | __entry->index, | ||
58 | __entry->total, | ||
59 | __print_symbolic(__entry->type, hw_param_labels), | ||
60 | __entry->prev_bits[3], __entry->prev_bits[2], | ||
61 | __entry->prev_bits[1], __entry->prev_bits[0], | ||
62 | __entry->curr_bits[3], __entry->curr_bits[2], | ||
63 | __entry->curr_bits[1], __entry->curr_bits[0] | ||
64 | ) | ||
65 | ); | ||
66 | |||
67 | TRACE_EVENT(hw_interval_param, | ||
68 | TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_interval *prev, const struct snd_interval *curr), | ||
69 | TP_ARGS(substream, type, index, prev, curr), | ||
70 | TP_STRUCT__entry( | ||
71 | __field(int, card) | ||
72 | __field(int, device) | ||
73 | __field(int, subdevice) | ||
74 | __field(int, direction) | ||
75 | __field(snd_pcm_hw_param_t, type) | ||
76 | __field(int, index) | ||
77 | __field(int, total) | ||
78 | __field(unsigned int, prev_min) | ||
79 | __field(unsigned int, prev_max) | ||
80 | __field(unsigned int, prev_openmin) | ||
81 | __field(unsigned int, prev_openmax) | ||
82 | __field(unsigned int, prev_integer) | ||
83 | __field(unsigned int, prev_empty) | ||
84 | __field(unsigned int, curr_min) | ||
85 | __field(unsigned int, curr_max) | ||
86 | __field(unsigned int, curr_openmin) | ||
87 | __field(unsigned int, curr_openmax) | ||
88 | __field(unsigned int, curr_integer) | ||
89 | __field(unsigned int, curr_empty) | ||
90 | ), | ||
91 | TP_fast_assign( | ||
92 | __entry->card = substream->pcm->card->number; | ||
93 | __entry->device = substream->pcm->device; | ||
94 | __entry->subdevice = substream->number; | ||
95 | __entry->direction = substream->stream; | ||
96 | __entry->type = type; | ||
97 | __entry->index = index; | ||
98 | __entry->total = substream->runtime->hw_constraints.rules_num; | ||
99 | __entry->prev_min = prev->min; | ||
100 | __entry->prev_max = prev->max; | ||
101 | __entry->prev_openmin = prev->openmin; | ||
102 | __entry->prev_openmax = prev->openmax; | ||
103 | __entry->prev_integer = prev->integer; | ||
104 | __entry->prev_empty = prev->empty; | ||
105 | __entry->curr_min = curr->min; | ||
106 | __entry->curr_max = curr->max; | ||
107 | __entry->curr_openmin = curr->openmin; | ||
108 | __entry->curr_openmax = curr->openmax; | ||
109 | __entry->curr_integer = curr->integer; | ||
110 | __entry->curr_empty = curr->empty; | ||
111 | ), | ||
112 | TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s", | ||
113 | __entry->card, | ||
114 | __entry->device, | ||
115 | __entry->direction ? "c" : "p", | ||
116 | __entry->subdevice, | ||
117 | __entry->index, | ||
118 | __entry->total, | ||
119 | __print_symbolic(__entry->type, hw_param_labels), | ||
120 | __entry->prev_empty, | ||
121 | __entry->prev_integer, | ||
122 | __entry->prev_openmin ? "(" : "[", | ||
123 | __entry->prev_min, | ||
124 | __entry->prev_max, | ||
125 | __entry->prev_openmax ? ")" : "]", | ||
126 | __entry->curr_empty, | ||
127 | __entry->curr_integer, | ||
128 | __entry->curr_openmin ? "(" : "[", | ||
129 | __entry->curr_min, | ||
130 | __entry->curr_max, | ||
131 | __entry->curr_openmax ? ")" : "]" | ||
132 | ) | ||
133 | ); | ||
134 | |||
135 | #endif /* _PCM_PARAMS_TRACE_H */ | ||
136 | |||
137 | /* This part must be outside protection */ | ||
138 | #undef TRACE_INCLUDE_PATH | ||
139 | #define TRACE_INCLUDE_PATH . | ||
140 | #undef TRACE_INCLUDE_FILE | ||
141 | #define TRACE_INCLUDE_FILE pcm_param_trace | ||
142 | #include <trace/define_trace.h> | ||
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index 20ecd8f18080..11389f13de73 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
26 | #include <sound/timer.h> | 26 | #include <sound/timer.h> |
27 | 27 | ||
28 | #include "pcm_local.h" | ||
29 | |||
28 | /* | 30 | /* |
29 | * Timer functions | 31 | * Timer functions |
30 | */ | 32 | */ |
@@ -33,8 +35,8 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) | |||
33 | { | 35 | { |
34 | unsigned long rate, mult, fsize, l, post; | 36 | unsigned long rate, mult, fsize, l, post; |
35 | struct snd_pcm_runtime *runtime = substream->runtime; | 37 | struct snd_pcm_runtime *runtime = substream->runtime; |
36 | 38 | ||
37 | mult = 1000000000; | 39 | mult = 1000000000; |
38 | rate = runtime->rate; | 40 | rate = runtime->rate; |
39 | if (snd_BUG_ON(!rate)) | 41 | if (snd_BUG_ON(!rate)) |
40 | return; | 42 | return; |
@@ -65,7 +67,7 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) | |||
65 | static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) | 67 | static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) |
66 | { | 68 | { |
67 | struct snd_pcm_substream *substream; | 69 | struct snd_pcm_substream *substream; |
68 | 70 | ||
69 | substream = timer->private_data; | 71 | substream = timer->private_data; |
70 | return substream->runtime ? substream->runtime->timer_resolution : 0; | 72 | return substream->runtime ? substream->runtime->timer_resolution : 0; |
71 | } | 73 | } |
@@ -73,7 +75,7 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) | |||
73 | static int snd_pcm_timer_start(struct snd_timer * timer) | 75 | static int snd_pcm_timer_start(struct snd_timer * timer) |
74 | { | 76 | { |
75 | struct snd_pcm_substream *substream; | 77 | struct snd_pcm_substream *substream; |
76 | 78 | ||
77 | substream = snd_timer_chip(timer); | 79 | substream = snd_timer_chip(timer); |
78 | substream->timer_running = 1; | 80 | substream->timer_running = 1; |
79 | return 0; | 81 | return 0; |
@@ -82,7 +84,7 @@ static int snd_pcm_timer_start(struct snd_timer * timer) | |||
82 | static int snd_pcm_timer_stop(struct snd_timer * timer) | 84 | static int snd_pcm_timer_stop(struct snd_timer * timer) |
83 | { | 85 | { |
84 | struct snd_pcm_substream *substream; | 86 | struct snd_pcm_substream *substream; |
85 | 87 | ||
86 | substream = snd_timer_chip(timer); | 88 | substream = snd_timer_chip(timer); |
87 | substream->timer_running = 0; | 89 | substream->timer_running = 0; |
88 | return 0; | 90 | return 0; |
@@ -112,7 +114,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream) | |||
112 | { | 114 | { |
113 | struct snd_timer_id tid; | 115 | struct snd_timer_id tid; |
114 | struct snd_timer *timer; | 116 | struct snd_timer *timer; |
115 | 117 | ||
116 | tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; | 118 | tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; |
117 | tid.dev_class = SNDRV_TIMER_CLASS_PCM; | 119 | tid.dev_class = SNDRV_TIMER_CLASS_PCM; |
118 | tid.card = substream->pcm->card->number; | 120 | tid.card = substream->pcm->card->number; |
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h index b63b654da5ff..3ddec1b8ae46 100644 --- a/sound/core/pcm_trace.h +++ b/sound/core/pcm_trace.h | |||
@@ -34,9 +34,9 @@ TRACE_EVENT(hwptr, | |||
34 | __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; | 34 | __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; |
35 | __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; | 35 | __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; |
36 | ), | 36 | ), |
37 | TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", | 37 | TP_printk("pcmC%dD%d%s/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", |
38 | __entry->card, __entry->device, | 38 | __entry->card, __entry->device, |
39 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', | 39 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", |
40 | __entry->number, | 40 | __entry->number, |
41 | __entry->in_interrupt ? "IRQ" : "POS", | 41 | __entry->in_interrupt ? "IRQ" : "POS", |
42 | (unsigned long)__entry->pos, | 42 | (unsigned long)__entry->pos, |
@@ -69,9 +69,9 @@ TRACE_EVENT(xrun, | |||
69 | __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; | 69 | __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; |
70 | __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; | 70 | __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; |
71 | ), | 71 | ), |
72 | TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", | 72 | TP_printk("pcmC%dD%d%s/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", |
73 | __entry->card, __entry->device, | 73 | __entry->card, __entry->device, |
74 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', | 74 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", |
75 | __entry->number, | 75 | __entry->number, |
76 | (unsigned long)__entry->old_hw_ptr, | 76 | (unsigned long)__entry->old_hw_ptr, |
77 | (unsigned long)__entry->hw_ptr_base, | 77 | (unsigned long)__entry->hw_ptr_base, |
@@ -96,12 +96,50 @@ TRACE_EVENT(hw_ptr_error, | |||
96 | __entry->stream = (substream)->stream; | 96 | __entry->stream = (substream)->stream; |
97 | __entry->reason = (why); | 97 | __entry->reason = (why); |
98 | ), | 98 | ), |
99 | TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", | 99 | TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s", |
100 | __entry->card, __entry->device, | 100 | __entry->card, __entry->device, |
101 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', | 101 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", |
102 | __entry->number, __entry->reason) | 102 | __entry->number, __entry->reason) |
103 | ); | 103 | ); |
104 | 104 | ||
105 | TRACE_EVENT(applptr, | ||
106 | TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t prev, snd_pcm_uframes_t curr), | ||
107 | TP_ARGS(substream, prev, curr), | ||
108 | TP_STRUCT__entry( | ||
109 | __field( unsigned int, card ) | ||
110 | __field( unsigned int, device ) | ||
111 | __field( unsigned int, number ) | ||
112 | __field( unsigned int, stream ) | ||
113 | __field( snd_pcm_uframes_t, prev ) | ||
114 | __field( snd_pcm_uframes_t, curr ) | ||
115 | __field( snd_pcm_uframes_t, avail ) | ||
116 | __field( snd_pcm_uframes_t, period_size ) | ||
117 | __field( snd_pcm_uframes_t, buffer_size ) | ||
118 | ), | ||
119 | TP_fast_assign( | ||
120 | __entry->card = (substream)->pcm->card->number; | ||
121 | __entry->device = (substream)->pcm->device; | ||
122 | __entry->number = (substream)->number; | ||
123 | __entry->stream = (substream)->stream; | ||
124 | __entry->prev = (prev); | ||
125 | __entry->curr = (curr); | ||
126 | __entry->avail = (substream)->stream ? snd_pcm_capture_avail(substream->runtime) : snd_pcm_playback_avail(substream->runtime); | ||
127 | __entry->period_size = (substream)->runtime->period_size; | ||
128 | __entry->buffer_size = (substream)->runtime->buffer_size; | ||
129 | ), | ||
130 | TP_printk("pcmC%dD%d%s/sub%d: prev=%lu, curr=%lu, avail=%lu, period=%lu, buf=%lu", | ||
131 | __entry->card, | ||
132 | __entry->device, | ||
133 | __entry->stream ? "c" : "p", | ||
134 | __entry->number, | ||
135 | __entry->prev, | ||
136 | __entry->curr, | ||
137 | __entry->avail, | ||
138 | __entry->period_size, | ||
139 | __entry->buffer_size | ||
140 | ) | ||
141 | ); | ||
142 | |||
105 | #endif /* _PCM_TRACE_H */ | 143 | #endif /* _PCM_TRACE_H */ |
106 | 144 | ||
107 | /* This part must be outside protection */ | 145 | /* This part must be outside protection */ |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 32588ad05653..b3b353d72527 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -1610,7 +1610,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device) | |||
1610 | return snd_rawmidi_free(rmidi); | 1610 | return snd_rawmidi_free(rmidi); |
1611 | } | 1611 | } |
1612 | 1612 | ||
1613 | #if IS_REACHABLE(CONFIG_SND_SEQUENCER) | 1613 | #if IS_ENABLED(CONFIG_SND_SEQUENCER) |
1614 | static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device) | 1614 | static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device) |
1615 | { | 1615 | { |
1616 | struct snd_rawmidi *rmidi = device->private_data; | 1616 | struct snd_rawmidi *rmidi = device->private_data; |
@@ -1691,7 +1691,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) | |||
1691 | } | 1691 | } |
1692 | } | 1692 | } |
1693 | rmidi->proc_entry = entry; | 1693 | rmidi->proc_entry = entry; |
1694 | #if IS_REACHABLE(CONFIG_SND_SEQUENCER) | 1694 | #if IS_ENABLED(CONFIG_SND_SEQUENCER) |
1695 | if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ | 1695 | if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ |
1696 | if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { | 1696 | if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { |
1697 | rmidi->seq_dev->private_data = rmidi; | 1697 | rmidi->seq_dev->private_data = rmidi; |
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index b851fd890a89..a536760a94c2 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig | |||
@@ -1,16 +1,62 @@ | |||
1 | # define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) | 1 | config SND_SEQUENCER |
2 | tristate "Sequencer support" | ||
3 | select SND_TIMER | ||
4 | select SND_SEQ_DEVICE | ||
5 | help | ||
6 | Say Y or M to enable MIDI sequencer and router support. This | ||
7 | feature allows routing and enqueueing of MIDI events. Events | ||
8 | can be processed at a given time. | ||
2 | 9 | ||
3 | config SND_RAWMIDI_SEQ | 10 | Many programs require this feature, so you should enable it |
4 | def_tristate SND_SEQUENCER && SND_RAWMIDI | 11 | unless you know what you're doing. |
5 | 12 | ||
6 | config SND_OPL3_LIB_SEQ | 13 | if SND_SEQUENCER |
7 | def_tristate SND_SEQUENCER && SND_OPL3_LIB | ||
8 | 14 | ||
9 | config SND_OPL4_LIB_SEQ | 15 | config SND_SEQ_DUMMY |
10 | def_tristate SND_SEQUENCER && SND_OPL4_LIB | 16 | tristate "Sequencer dummy client" |
17 | help | ||
18 | Say Y here to enable the dummy sequencer client. This client | ||
19 | is a simple MIDI-through client: all normal input events are | ||
20 | redirected to the output port immediately. | ||
11 | 21 | ||
12 | config SND_SBAWE_SEQ | 22 | You don't need this unless you want to connect many MIDI |
13 | def_tristate SND_SEQUENCER && SND_SBAWE | 23 | devices or applications together. |
14 | 24 | ||
15 | config SND_EMU10K1_SEQ | 25 | To compile this driver as a module, choose M here: the module |
16 | def_tristate SND_SEQUENCER && SND_EMU10K1 | 26 | will be called snd-seq-dummy. |
27 | |||
28 | config SND_SEQUENCER_OSS | ||
29 | tristate "OSS Sequencer API" | ||
30 | depends on SND_OSSEMUL | ||
31 | select SND_SEQ_MIDI_EVENT | ||
32 | help | ||
33 | Say Y here to enable OSS sequencer emulation (both | ||
34 | /dev/sequencer and /dev/music interfaces). | ||
35 | |||
36 | Many programs still use the OSS API, so say Y. | ||
37 | |||
38 | To compile this driver as a module, choose M here: the module | ||
39 | will be called snd-seq-oss. | ||
40 | |||
41 | config SND_SEQ_HRTIMER_DEFAULT | ||
42 | bool "Use HR-timer as default sequencer timer" | ||
43 | depends on SND_HRTIMER | ||
44 | default y | ||
45 | help | ||
46 | Say Y here to use the HR-timer backend as the default sequencer | ||
47 | timer. | ||
48 | |||
49 | config SND_SEQ_MIDI_EVENT | ||
50 | def_tristate SND_RAWMIDI | ||
51 | |||
52 | config SND_SEQ_MIDI | ||
53 | tristate | ||
54 | select SND_SEQ_MIDI_EVENT | ||
55 | |||
56 | config SND_SEQ_MIDI_EMUL | ||
57 | tristate | ||
58 | |||
59 | config SND_SEQ_VIRMIDI | ||
60 | tristate | ||
61 | |||
62 | endif # SND_SEQUENCER | ||
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index b65fa5a1943b..68fd367ac39c 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | 3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> |
4 | # | 4 | # |
5 | 5 | ||
6 | snd-seq-device-objs := seq_device.o | ||
7 | snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ | 6 | snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ |
8 | seq_fifo.o seq_prioq.o seq_timer.o \ | 7 | seq_fifo.o seq_prioq.o seq_timer.o \ |
9 | seq_system.o seq_ports.o | 8 | seq_system.o seq_ports.o |
@@ -14,17 +13,11 @@ snd-seq-midi-event-objs := seq_midi_event.o | |||
14 | snd-seq-dummy-objs := seq_dummy.o | 13 | snd-seq-dummy-objs := seq_dummy.o |
15 | snd-seq-virmidi-objs := seq_virmidi.o | 14 | snd-seq-virmidi-objs := seq_virmidi.o |
16 | 15 | ||
17 | obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o | 16 | obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o |
18 | ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) | 17 | obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ |
19 | obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o | ||
20 | obj-$(CONFIG_SND_SEQUENCER) += oss/ | ||
21 | endif | ||
22 | obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o | ||
23 | 18 | ||
24 | # Toplevel Module Dependency | 19 | obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o |
25 | obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o | 20 | obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o |
26 | obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o | 21 | obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o |
27 | obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o | 22 | obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o |
28 | obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o | 23 | obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o |
29 | obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o | ||
30 | obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o | ||
diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile index b38406b8463c..4ea4e3eea6b7 100644 --- a/sound/core/seq/oss/Makefile +++ b/sound/core/seq/oss/Makefile | |||
@@ -7,4 +7,4 @@ snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \ | |||
7 | seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \ | 7 | seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \ |
8 | seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o | 8 | seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o |
9 | 9 | ||
10 | obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o | 10 | obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-oss.o |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index f3b1d7f50b81..272c55fe17c8 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -1668,7 +1668,6 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo) | |||
1668 | return -EPERM; | 1668 | return -EPERM; |
1669 | return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); | 1669 | return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); |
1670 | } | 1670 | } |
1671 | |||
1672 | EXPORT_SYMBOL(snd_seq_set_queue_tempo); | 1671 | EXPORT_SYMBOL(snd_seq_set_queue_tempo); |
1673 | 1672 | ||
1674 | static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, | 1673 | static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, |
@@ -2200,7 +2199,6 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, | |||
2200 | /* return client number to caller */ | 2199 | /* return client number to caller */ |
2201 | return client->number; | 2200 | return client->number; |
2202 | } | 2201 | } |
2203 | |||
2204 | EXPORT_SYMBOL(snd_seq_create_kernel_client); | 2202 | EXPORT_SYMBOL(snd_seq_create_kernel_client); |
2205 | 2203 | ||
2206 | /* exported to kernel modules */ | 2204 | /* exported to kernel modules */ |
@@ -2219,7 +2217,6 @@ int snd_seq_delete_kernel_client(int client) | |||
2219 | kfree(ptr); | 2217 | kfree(ptr); |
2220 | return 0; | 2218 | return 0; |
2221 | } | 2219 | } |
2222 | |||
2223 | EXPORT_SYMBOL(snd_seq_delete_kernel_client); | 2220 | EXPORT_SYMBOL(snd_seq_delete_kernel_client); |
2224 | 2221 | ||
2225 | /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue | 2222 | /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue |
@@ -2269,7 +2266,6 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev, | |||
2269 | { | 2266 | { |
2270 | return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); | 2267 | return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); |
2271 | } | 2268 | } |
2272 | |||
2273 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); | 2269 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); |
2274 | 2270 | ||
2275 | /* | 2271 | /* |
@@ -2283,7 +2279,6 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev | |||
2283 | { | 2279 | { |
2284 | return kernel_client_enqueue(client, ev, file, 1, atomic, hop); | 2280 | return kernel_client_enqueue(client, ev, file, 1, atomic, hop); |
2285 | } | 2281 | } |
2286 | |||
2287 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); | 2282 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); |
2288 | 2283 | ||
2289 | /* | 2284 | /* |
@@ -2321,7 +2316,6 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, | |||
2321 | snd_seq_client_unlock(cptr); | 2316 | snd_seq_client_unlock(cptr); |
2322 | return result; | 2317 | return result; |
2323 | } | 2318 | } |
2324 | |||
2325 | EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); | 2319 | EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); |
2326 | 2320 | ||
2327 | /** | 2321 | /** |
@@ -2354,7 +2348,6 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) | |||
2354 | cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); | 2348 | cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); |
2355 | return -ENOTTY; | 2349 | return -ENOTTY; |
2356 | } | 2350 | } |
2357 | |||
2358 | EXPORT_SYMBOL(snd_seq_kernel_client_ctl); | 2351 | EXPORT_SYMBOL(snd_seq_kernel_client_ctl); |
2359 | 2352 | ||
2360 | /* exported (for OSS emulator) */ | 2353 | /* exported (for OSS emulator) */ |
@@ -2372,7 +2365,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table | |||
2372 | return 1; | 2365 | return 1; |
2373 | return 0; | 2366 | return 0; |
2374 | } | 2367 | } |
2375 | |||
2376 | EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); | 2368 | EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); |
2377 | 2369 | ||
2378 | /*---------------------------------------------------------------------------*/ | 2370 | /*---------------------------------------------------------------------------*/ |
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index 12ba83367b1b..0ff7926a5a69 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c | |||
@@ -40,7 +40,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) | |||
40 | schedule_timeout_uninterruptible(1); | 40 | schedule_timeout_uninterruptible(1); |
41 | } | 41 | } |
42 | } | 42 | } |
43 | |||
44 | EXPORT_SYMBOL(snd_use_lock_sync_helper); | 43 | EXPORT_SYMBOL(snd_use_lock_sync_helper); |
45 | 44 | ||
46 | #endif | 45 | #endif |
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index d6e9aacdc36b..f763682584a8 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c | |||
@@ -118,7 +118,6 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, | |||
118 | } | 118 | } |
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | |||
122 | EXPORT_SYMBOL(snd_seq_dump_var_event); | 121 | EXPORT_SYMBOL(snd_seq_dump_var_event); |
123 | 122 | ||
124 | 123 | ||
@@ -169,7 +168,6 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char | |||
169 | &buf); | 168 | &buf); |
170 | return err < 0 ? err : newlen; | 169 | return err < 0 ? err : newlen; |
171 | } | 170 | } |
172 | |||
173 | EXPORT_SYMBOL(snd_seq_expand_var_event); | 171 | EXPORT_SYMBOL(snd_seq_expand_var_event); |
174 | 172 | ||
175 | /* | 173 | /* |
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index 7ba937399ac7..9e2912e3e80f 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c | |||
@@ -236,6 +236,7 @@ snd_midi_process_event(struct snd_midi_op *ops, | |||
236 | break; | 236 | break; |
237 | } | 237 | } |
238 | } | 238 | } |
239 | EXPORT_SYMBOL(snd_midi_process_event); | ||
239 | 240 | ||
240 | 241 | ||
241 | /* | 242 | /* |
@@ -409,6 +410,7 @@ snd_midi_channel_set_clear(struct snd_midi_channel_set *chset) | |||
409 | chan->drum_channel = 0; | 410 | chan->drum_channel = 0; |
410 | } | 411 | } |
411 | } | 412 | } |
413 | EXPORT_SYMBOL(snd_midi_channel_set_clear); | ||
412 | 414 | ||
413 | /* | 415 | /* |
414 | * Process a rpn message. | 416 | * Process a rpn message. |
@@ -701,6 +703,7 @@ struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n) | |||
701 | } | 703 | } |
702 | return chset; | 704 | return chset; |
703 | } | 705 | } |
706 | EXPORT_SYMBOL(snd_midi_channel_alloc_set); | ||
704 | 707 | ||
705 | /* | 708 | /* |
706 | * Reset the midi controllers on a particular channel to default values. | 709 | * Reset the midi controllers on a particular channel to default values. |
@@ -724,6 +727,7 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset) | |||
724 | kfree(chset->channels); | 727 | kfree(chset->channels); |
725 | kfree(chset); | 728 | kfree(chset); |
726 | } | 729 | } |
730 | EXPORT_SYMBOL(snd_midi_channel_free_set); | ||
727 | 731 | ||
728 | static int __init alsa_seq_midi_emul_init(void) | 732 | static int __init alsa_seq_midi_emul_init(void) |
729 | { | 733 | { |
@@ -736,8 +740,3 @@ static void __exit alsa_seq_midi_emul_exit(void) | |||
736 | 740 | ||
737 | module_init(alsa_seq_midi_emul_init) | 741 | module_init(alsa_seq_midi_emul_init) |
738 | module_exit(alsa_seq_midi_emul_exit) | 742 | module_exit(alsa_seq_midi_emul_exit) |
739 | |||
740 | EXPORT_SYMBOL(snd_midi_process_event); | ||
741 | EXPORT_SYMBOL(snd_midi_channel_set_clear); | ||
742 | EXPORT_SYMBOL(snd_midi_channel_alloc_set); | ||
743 | EXPORT_SYMBOL(snd_midi_channel_free_set); | ||
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 37db7ba492a6..90bbbdbeba03 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c | |||
@@ -134,6 +134,7 @@ int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) | |||
134 | *rdev = dev; | 134 | *rdev = dev; |
135 | return 0; | 135 | return 0; |
136 | } | 136 | } |
137 | EXPORT_SYMBOL(snd_midi_event_new); | ||
137 | 138 | ||
138 | void snd_midi_event_free(struct snd_midi_event *dev) | 139 | void snd_midi_event_free(struct snd_midi_event *dev) |
139 | { | 140 | { |
@@ -142,6 +143,7 @@ void snd_midi_event_free(struct snd_midi_event *dev) | |||
142 | kfree(dev); | 143 | kfree(dev); |
143 | } | 144 | } |
144 | } | 145 | } |
146 | EXPORT_SYMBOL(snd_midi_event_free); | ||
145 | 147 | ||
146 | /* | 148 | /* |
147 | * initialize record | 149 | * initialize record |
@@ -161,6 +163,7 @@ void snd_midi_event_reset_encode(struct snd_midi_event *dev) | |||
161 | reset_encode(dev); | 163 | reset_encode(dev); |
162 | spin_unlock_irqrestore(&dev->lock, flags); | 164 | spin_unlock_irqrestore(&dev->lock, flags); |
163 | } | 165 | } |
166 | EXPORT_SYMBOL(snd_midi_event_reset_encode); | ||
164 | 167 | ||
165 | void snd_midi_event_reset_decode(struct snd_midi_event *dev) | 168 | void snd_midi_event_reset_decode(struct snd_midi_event *dev) |
166 | { | 169 | { |
@@ -170,6 +173,7 @@ void snd_midi_event_reset_decode(struct snd_midi_event *dev) | |||
170 | dev->lastcmd = 0xff; | 173 | dev->lastcmd = 0xff; |
171 | spin_unlock_irqrestore(&dev->lock, flags); | 174 | spin_unlock_irqrestore(&dev->lock, flags); |
172 | } | 175 | } |
176 | EXPORT_SYMBOL(snd_midi_event_reset_decode); | ||
173 | 177 | ||
174 | #if 0 | 178 | #if 0 |
175 | void snd_midi_event_init(struct snd_midi_event *dev) | 179 | void snd_midi_event_init(struct snd_midi_event *dev) |
@@ -183,6 +187,7 @@ void snd_midi_event_no_status(struct snd_midi_event *dev, int on) | |||
183 | { | 187 | { |
184 | dev->nostat = on ? 1 : 0; | 188 | dev->nostat = on ? 1 : 0; |
185 | } | 189 | } |
190 | EXPORT_SYMBOL(snd_midi_event_no_status); | ||
186 | 191 | ||
187 | /* | 192 | /* |
188 | * resize buffer | 193 | * resize buffer |
@@ -232,6 +237,7 @@ long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long | |||
232 | 237 | ||
233 | return result; | 238 | return result; |
234 | } | 239 | } |
240 | EXPORT_SYMBOL(snd_midi_event_encode); | ||
235 | 241 | ||
236 | /* | 242 | /* |
237 | * read one byte and encode to sequencer event: | 243 | * read one byte and encode to sequencer event: |
@@ -307,6 +313,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, | |||
307 | spin_unlock_irqrestore(&dev->lock, flags); | 313 | spin_unlock_irqrestore(&dev->lock, flags); |
308 | return rc; | 314 | return rc; |
309 | } | 315 | } |
316 | EXPORT_SYMBOL(snd_midi_event_encode_byte); | ||
310 | 317 | ||
311 | /* encode note event */ | 318 | /* encode note event */ |
312 | static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) | 319 | static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) |
@@ -408,6 +415,7 @@ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long | |||
408 | return qlen; | 415 | return qlen; |
409 | } | 416 | } |
410 | } | 417 | } |
418 | EXPORT_SYMBOL(snd_midi_event_decode); | ||
411 | 419 | ||
412 | 420 | ||
413 | /* decode note event */ | 421 | /* decode note event */ |
@@ -524,19 +532,6 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, | |||
524 | return idx; | 532 | return idx; |
525 | } | 533 | } |
526 | 534 | ||
527 | /* | ||
528 | * exports | ||
529 | */ | ||
530 | |||
531 | EXPORT_SYMBOL(snd_midi_event_new); | ||
532 | EXPORT_SYMBOL(snd_midi_event_free); | ||
533 | EXPORT_SYMBOL(snd_midi_event_reset_encode); | ||
534 | EXPORT_SYMBOL(snd_midi_event_reset_decode); | ||
535 | EXPORT_SYMBOL(snd_midi_event_no_status); | ||
536 | EXPORT_SYMBOL(snd_midi_event_encode); | ||
537 | EXPORT_SYMBOL(snd_midi_event_encode_byte); | ||
538 | EXPORT_SYMBOL(snd_midi_event_decode); | ||
539 | |||
540 | static int __init alsa_seq_midi_event_init(void) | 535 | static int __init alsa_seq_midi_event_init(void) |
541 | { | 536 | { |
542 | return 0; | 537 | return 0; |
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index fe686ee41c6d..0a7020c82bfc 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
@@ -685,7 +685,6 @@ int snd_seq_event_port_attach(int client, | |||
685 | 685 | ||
686 | return ret; | 686 | return ret; |
687 | } | 687 | } |
688 | |||
689 | EXPORT_SYMBOL(snd_seq_event_port_attach); | 688 | EXPORT_SYMBOL(snd_seq_event_port_attach); |
690 | 689 | ||
691 | /* | 690 | /* |
@@ -706,5 +705,4 @@ int snd_seq_event_port_detach(int client, int port) | |||
706 | 705 | ||
707 | return err; | 706 | return err; |
708 | } | 707 | } |
709 | |||
710 | EXPORT_SYMBOL(snd_seq_event_port_detach); | 708 | EXPORT_SYMBOL(snd_seq_event_port_detach); |
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 52f31f1498f9..8d93a4021c78 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c | |||
@@ -534,6 +534,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi | |||
534 | *rrmidi = rmidi; | 534 | *rrmidi = rmidi; |
535 | return 0; | 535 | return 0; |
536 | } | 536 | } |
537 | EXPORT_SYMBOL(snd_virmidi_new); | ||
537 | 538 | ||
538 | /* | 539 | /* |
539 | * ENTRY functions | 540 | * ENTRY functions |
@@ -550,5 +551,3 @@ static void __exit alsa_virmidi_exit(void) | |||
550 | 551 | ||
551 | module_init(alsa_virmidi_init) | 552 | module_init(alsa_virmidi_init) |
552 | module_exit(alsa_virmidi_exit) | 553 | module_exit(alsa_virmidi_exit) |
553 | |||
554 | EXPORT_SYMBOL(snd_virmidi_new); | ||
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq_device.c index c4acf17e9f5e..c4acf17e9f5e 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq_device.c | |||
diff --git a/sound/core/sound.c b/sound/core/sound.c index 175f9e4e01c8..b30f027eb0fe 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -74,7 +74,6 @@ void snd_request_card(int card) | |||
74 | return; | 74 | return; |
75 | request_module("snd-card-%i", card); | 75 | request_module("snd-card-%i", card); |
76 | } | 76 | } |
77 | |||
78 | EXPORT_SYMBOL(snd_request_card); | 77 | EXPORT_SYMBOL(snd_request_card); |
79 | 78 | ||
80 | static void snd_request_other(int minor) | 79 | static void snd_request_other(int minor) |
@@ -124,7 +123,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type) | |||
124 | mutex_unlock(&sound_mutex); | 123 | mutex_unlock(&sound_mutex); |
125 | return private_data; | 124 | return private_data; |
126 | } | 125 | } |
127 | |||
128 | EXPORT_SYMBOL(snd_lookup_minor_data); | 126 | EXPORT_SYMBOL(snd_lookup_minor_data); |
129 | 127 | ||
130 | #ifdef CONFIG_MODULES | 128 | #ifdef CONFIG_MODULES |
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 0ca9d72b2273..0a5c66229a22 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c | |||
@@ -55,7 +55,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) | |||
55 | mutex_unlock(&sound_oss_mutex); | 55 | mutex_unlock(&sound_oss_mutex); |
56 | return private_data; | 56 | return private_data; |
57 | } | 57 | } |
58 | |||
59 | EXPORT_SYMBOL(snd_lookup_oss_minor_data); | 58 | EXPORT_SYMBOL(snd_lookup_oss_minor_data); |
60 | 59 | ||
61 | static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) | 60 | static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) |
@@ -159,7 +158,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, | |||
159 | kfree(preg); | 158 | kfree(preg); |
160 | return -EBUSY; | 159 | return -EBUSY; |
161 | } | 160 | } |
162 | |||
163 | EXPORT_SYMBOL(snd_register_oss_device); | 161 | EXPORT_SYMBOL(snd_register_oss_device); |
164 | 162 | ||
165 | int snd_unregister_oss_device(int type, struct snd_card *card, int dev) | 163 | int snd_unregister_oss_device(int type, struct snd_card *card, int dev) |
@@ -200,7 +198,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) | |||
200 | kfree(mptr); | 198 | kfree(mptr); |
201 | return 0; | 199 | return 0; |
202 | } | 200 | } |
203 | |||
204 | EXPORT_SYMBOL(snd_unregister_oss_device); | 201 | EXPORT_SYMBOL(snd_unregister_oss_device); |
205 | 202 | ||
206 | /* | 203 | /* |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 884c3066b028..a9b9a277e00c 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -319,6 +319,7 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
319 | *ti = timeri; | 319 | *ti = timeri; |
320 | return 0; | 320 | return 0; |
321 | } | 321 | } |
322 | EXPORT_SYMBOL(snd_timer_open); | ||
322 | 323 | ||
323 | /* | 324 | /* |
324 | * close a timer instance | 325 | * close a timer instance |
@@ -384,6 +385,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
384 | mutex_unlock(®ister_mutex); | 385 | mutex_unlock(®ister_mutex); |
385 | return 0; | 386 | return 0; |
386 | } | 387 | } |
388 | EXPORT_SYMBOL(snd_timer_close); | ||
387 | 389 | ||
388 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) | 390 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) |
389 | { | 391 | { |
@@ -398,6 +400,7 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) | |||
398 | } | 400 | } |
399 | return 0; | 401 | return 0; |
400 | } | 402 | } |
403 | EXPORT_SYMBOL(snd_timer_resolution); | ||
401 | 404 | ||
402 | static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | 405 | static void snd_timer_notify1(struct snd_timer_instance *ti, int event) |
403 | { | 406 | { |
@@ -589,6 +592,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) | |||
589 | else | 592 | else |
590 | return snd_timer_start1(timeri, true, ticks); | 593 | return snd_timer_start1(timeri, true, ticks); |
591 | } | 594 | } |
595 | EXPORT_SYMBOL(snd_timer_start); | ||
592 | 596 | ||
593 | /* | 597 | /* |
594 | * stop the timer instance. | 598 | * stop the timer instance. |
@@ -602,6 +606,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) | |||
602 | else | 606 | else |
603 | return snd_timer_stop1(timeri, true); | 607 | return snd_timer_stop1(timeri, true); |
604 | } | 608 | } |
609 | EXPORT_SYMBOL(snd_timer_stop); | ||
605 | 610 | ||
606 | /* | 611 | /* |
607 | * start again.. the tick is kept. | 612 | * start again.. the tick is kept. |
@@ -617,6 +622,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) | |||
617 | else | 622 | else |
618 | return snd_timer_start1(timeri, false, 0); | 623 | return snd_timer_start1(timeri, false, 0); |
619 | } | 624 | } |
625 | EXPORT_SYMBOL(snd_timer_continue); | ||
620 | 626 | ||
621 | /* | 627 | /* |
622 | * pause.. remember the ticks left | 628 | * pause.. remember the ticks left |
@@ -628,6 +634,7 @@ int snd_timer_pause(struct snd_timer_instance * timeri) | |||
628 | else | 634 | else |
629 | return snd_timer_stop1(timeri, false); | 635 | return snd_timer_stop1(timeri, false); |
630 | } | 636 | } |
637 | EXPORT_SYMBOL(snd_timer_pause); | ||
631 | 638 | ||
632 | /* | 639 | /* |
633 | * reschedule the timer | 640 | * reschedule the timer |
@@ -809,6 +816,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
809 | if (use_tasklet) | 816 | if (use_tasklet) |
810 | tasklet_schedule(&timer->task_queue); | 817 | tasklet_schedule(&timer->task_queue); |
811 | } | 818 | } |
819 | EXPORT_SYMBOL(snd_timer_interrupt); | ||
812 | 820 | ||
813 | /* | 821 | /* |
814 | 822 | ||
@@ -859,6 +867,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
859 | *rtimer = timer; | 867 | *rtimer = timer; |
860 | return 0; | 868 | return 0; |
861 | } | 869 | } |
870 | EXPORT_SYMBOL(snd_timer_new); | ||
862 | 871 | ||
863 | static int snd_timer_free(struct snd_timer *timer) | 872 | static int snd_timer_free(struct snd_timer *timer) |
864 | { | 873 | { |
@@ -978,6 +987,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam | |||
978 | } | 987 | } |
979 | spin_unlock_irqrestore(&timer->lock, flags); | 988 | spin_unlock_irqrestore(&timer->lock, flags); |
980 | } | 989 | } |
990 | EXPORT_SYMBOL(snd_timer_notify); | ||
981 | 991 | ||
982 | /* | 992 | /* |
983 | * exported functions for global timers | 993 | * exported functions for global timers |
@@ -993,11 +1003,13 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) | |||
993 | tid.subdevice = 0; | 1003 | tid.subdevice = 0; |
994 | return snd_timer_new(NULL, id, &tid, rtimer); | 1004 | return snd_timer_new(NULL, id, &tid, rtimer); |
995 | } | 1005 | } |
1006 | EXPORT_SYMBOL(snd_timer_global_new); | ||
996 | 1007 | ||
997 | int snd_timer_global_free(struct snd_timer *timer) | 1008 | int snd_timer_global_free(struct snd_timer *timer) |
998 | { | 1009 | { |
999 | return snd_timer_free(timer); | 1010 | return snd_timer_free(timer); |
1000 | } | 1011 | } |
1012 | EXPORT_SYMBOL(snd_timer_global_free); | ||
1001 | 1013 | ||
1002 | int snd_timer_global_register(struct snd_timer *timer) | 1014 | int snd_timer_global_register(struct snd_timer *timer) |
1003 | { | 1015 | { |
@@ -1007,6 +1019,7 @@ int snd_timer_global_register(struct snd_timer *timer) | |||
1007 | dev.device_data = timer; | 1019 | dev.device_data = timer; |
1008 | return snd_timer_dev_register(&dev); | 1020 | return snd_timer_dev_register(&dev); |
1009 | } | 1021 | } |
1022 | EXPORT_SYMBOL(snd_timer_global_register); | ||
1010 | 1023 | ||
1011 | /* | 1024 | /* |
1012 | * System timer | 1025 | * System timer |
@@ -1327,6 +1340,33 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, | |||
1327 | wake_up(&tu->qchange_sleep); | 1340 | wake_up(&tu->qchange_sleep); |
1328 | } | 1341 | } |
1329 | 1342 | ||
1343 | static int realloc_user_queue(struct snd_timer_user *tu, int size) | ||
1344 | { | ||
1345 | struct snd_timer_read *queue = NULL; | ||
1346 | struct snd_timer_tread *tqueue = NULL; | ||
1347 | |||
1348 | if (tu->tread) { | ||
1349 | tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); | ||
1350 | if (!tqueue) | ||
1351 | return -ENOMEM; | ||
1352 | } else { | ||
1353 | queue = kcalloc(size, sizeof(*queue), GFP_KERNEL); | ||
1354 | if (!queue) | ||
1355 | return -ENOMEM; | ||
1356 | } | ||
1357 | |||
1358 | spin_lock_irq(&tu->qlock); | ||
1359 | kfree(tu->queue); | ||
1360 | kfree(tu->tqueue); | ||
1361 | tu->queue_size = size; | ||
1362 | tu->queue = queue; | ||
1363 | tu->tqueue = tqueue; | ||
1364 | tu->qhead = tu->qtail = tu->qused = 0; | ||
1365 | spin_unlock_irq(&tu->qlock); | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1330 | static int snd_timer_user_open(struct inode *inode, struct file *file) | 1370 | static int snd_timer_user_open(struct inode *inode, struct file *file) |
1331 | { | 1371 | { |
1332 | struct snd_timer_user *tu; | 1372 | struct snd_timer_user *tu; |
@@ -1343,10 +1383,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) | |||
1343 | init_waitqueue_head(&tu->qchange_sleep); | 1383 | init_waitqueue_head(&tu->qchange_sleep); |
1344 | mutex_init(&tu->ioctl_lock); | 1384 | mutex_init(&tu->ioctl_lock); |
1345 | tu->ticks = 1; | 1385 | tu->ticks = 1; |
1346 | tu->queue_size = 128; | 1386 | if (realloc_user_queue(tu, 128) < 0) { |
1347 | tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), | ||
1348 | GFP_KERNEL); | ||
1349 | if (tu->queue == NULL) { | ||
1350 | kfree(tu); | 1387 | kfree(tu); |
1351 | return -ENOMEM; | 1388 | return -ENOMEM; |
1352 | } | 1389 | } |
@@ -1618,34 +1655,12 @@ static int snd_timer_user_tselect(struct file *file, | |||
1618 | if (err < 0) | 1655 | if (err < 0) |
1619 | goto __err; | 1656 | goto __err; |
1620 | 1657 | ||
1621 | tu->qhead = tu->qtail = tu->qused = 0; | 1658 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; |
1622 | kfree(tu->queue); | 1659 | tu->timeri->callback = tu->tread |
1623 | tu->queue = NULL; | ||
1624 | kfree(tu->tqueue); | ||
1625 | tu->tqueue = NULL; | ||
1626 | if (tu->tread) { | ||
1627 | tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), | ||
1628 | GFP_KERNEL); | ||
1629 | if (tu->tqueue == NULL) | ||
1630 | err = -ENOMEM; | ||
1631 | } else { | ||
1632 | tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), | ||
1633 | GFP_KERNEL); | ||
1634 | if (tu->queue == NULL) | ||
1635 | err = -ENOMEM; | ||
1636 | } | ||
1637 | |||
1638 | if (err < 0) { | ||
1639 | snd_timer_close(tu->timeri); | ||
1640 | tu->timeri = NULL; | ||
1641 | } else { | ||
1642 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; | ||
1643 | tu->timeri->callback = tu->tread | ||
1644 | ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; | 1660 | ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; |
1645 | tu->timeri->ccallback = snd_timer_user_ccallback; | 1661 | tu->timeri->ccallback = snd_timer_user_ccallback; |
1646 | tu->timeri->callback_data = (void *)tu; | 1662 | tu->timeri->callback_data = (void *)tu; |
1647 | tu->timeri->disconnect = snd_timer_user_disconnect; | 1663 | tu->timeri->disconnect = snd_timer_user_disconnect; |
1648 | } | ||
1649 | 1664 | ||
1650 | __err: | 1665 | __err: |
1651 | return err; | 1666 | return err; |
@@ -1687,8 +1702,6 @@ static int snd_timer_user_params(struct file *file, | |||
1687 | struct snd_timer_user *tu; | 1702 | struct snd_timer_user *tu; |
1688 | struct snd_timer_params params; | 1703 | struct snd_timer_params params; |
1689 | struct snd_timer *t; | 1704 | struct snd_timer *t; |
1690 | struct snd_timer_read *tr; | ||
1691 | struct snd_timer_tread *ttr; | ||
1692 | int err; | 1705 | int err; |
1693 | 1706 | ||
1694 | tu = file->private_data; | 1707 | tu = file->private_data; |
@@ -1751,24 +1764,11 @@ static int snd_timer_user_params(struct file *file, | |||
1751 | spin_unlock_irq(&t->lock); | 1764 | spin_unlock_irq(&t->lock); |
1752 | if (params.queue_size > 0 && | 1765 | if (params.queue_size > 0 && |
1753 | (unsigned int)tu->queue_size != params.queue_size) { | 1766 | (unsigned int)tu->queue_size != params.queue_size) { |
1754 | if (tu->tread) { | 1767 | err = realloc_user_queue(tu, params.queue_size); |
1755 | ttr = kmalloc(params.queue_size * sizeof(*ttr), | 1768 | if (err < 0) |
1756 | GFP_KERNEL); | 1769 | goto _end; |
1757 | if (ttr) { | ||
1758 | kfree(tu->tqueue); | ||
1759 | tu->queue_size = params.queue_size; | ||
1760 | tu->tqueue = ttr; | ||
1761 | } | ||
1762 | } else { | ||
1763 | tr = kmalloc(params.queue_size * sizeof(*tr), | ||
1764 | GFP_KERNEL); | ||
1765 | if (tr) { | ||
1766 | kfree(tu->queue); | ||
1767 | tu->queue_size = params.queue_size; | ||
1768 | tu->queue = tr; | ||
1769 | } | ||
1770 | } | ||
1771 | } | 1770 | } |
1771 | spin_lock_irq(&tu->qlock); | ||
1772 | tu->qhead = tu->qtail = tu->qused = 0; | 1772 | tu->qhead = tu->qtail = tu->qused = 0; |
1773 | if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { | 1773 | if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { |
1774 | if (tu->tread) { | 1774 | if (tu->tread) { |
@@ -1789,6 +1789,7 @@ static int snd_timer_user_params(struct file *file, | |||
1789 | } | 1789 | } |
1790 | tu->filter = params.filter; | 1790 | tu->filter = params.filter; |
1791 | tu->ticks = params.ticks; | 1791 | tu->ticks = params.ticks; |
1792 | spin_unlock_irq(&tu->qlock); | ||
1792 | err = 0; | 1793 | err = 0; |
1793 | _end: | 1794 | _end: |
1794 | if (copy_to_user(_params, ¶ms, sizeof(params))) | 1795 | if (copy_to_user(_params, ¶ms, sizeof(params))) |
@@ -1891,13 +1892,19 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |||
1891 | return snd_timer_user_next_device(argp); | 1892 | return snd_timer_user_next_device(argp); |
1892 | case SNDRV_TIMER_IOCTL_TREAD: | 1893 | case SNDRV_TIMER_IOCTL_TREAD: |
1893 | { | 1894 | { |
1894 | int xarg; | 1895 | int xarg, old_tread; |
1895 | 1896 | ||
1896 | if (tu->timeri) /* too late */ | 1897 | if (tu->timeri) /* too late */ |
1897 | return -EBUSY; | 1898 | return -EBUSY; |
1898 | if (get_user(xarg, p)) | 1899 | if (get_user(xarg, p)) |
1899 | return -EFAULT; | 1900 | return -EFAULT; |
1901 | old_tread = tu->tread; | ||
1900 | tu->tread = xarg ? 1 : 0; | 1902 | tu->tread = xarg ? 1 : 0; |
1903 | if (tu->tread != old_tread && | ||
1904 | realloc_user_queue(tu, tu->queue_size) < 0) { | ||
1905 | tu->tread = old_tread; | ||
1906 | return -ENOMEM; | ||
1907 | } | ||
1901 | return 0; | 1908 | return 0; |
1902 | } | 1909 | } |
1903 | case SNDRV_TIMER_IOCTL_GINFO: | 1910 | case SNDRV_TIMER_IOCTL_GINFO: |
@@ -2030,10 +2037,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) | |||
2030 | poll_wait(file, &tu->qchange_sleep, wait); | 2037 | poll_wait(file, &tu->qchange_sleep, wait); |
2031 | 2038 | ||
2032 | mask = 0; | 2039 | mask = 0; |
2040 | spin_lock_irq(&tu->qlock); | ||
2033 | if (tu->qused) | 2041 | if (tu->qused) |
2034 | mask |= POLLIN | POLLRDNORM; | 2042 | mask |= POLLIN | POLLRDNORM; |
2035 | if (tu->disconnected) | 2043 | if (tu->disconnected) |
2036 | mask |= POLLERR; | 2044 | mask |= POLLERR; |
2045 | spin_unlock_irq(&tu->qlock); | ||
2037 | 2046 | ||
2038 | return mask; | 2047 | return mask; |
2039 | } | 2048 | } |
@@ -2117,17 +2126,3 @@ static void __exit alsa_timer_exit(void) | |||
2117 | 2126 | ||
2118 | module_init(alsa_timer_init) | 2127 | module_init(alsa_timer_init) |
2119 | module_exit(alsa_timer_exit) | 2128 | module_exit(alsa_timer_exit) |
2120 | |||
2121 | EXPORT_SYMBOL(snd_timer_open); | ||
2122 | EXPORT_SYMBOL(snd_timer_close); | ||
2123 | EXPORT_SYMBOL(snd_timer_resolution); | ||
2124 | EXPORT_SYMBOL(snd_timer_start); | ||
2125 | EXPORT_SYMBOL(snd_timer_stop); | ||
2126 | EXPORT_SYMBOL(snd_timer_continue); | ||
2127 | EXPORT_SYMBOL(snd_timer_pause); | ||
2128 | EXPORT_SYMBOL(snd_timer_new); | ||
2129 | EXPORT_SYMBOL(snd_timer_notify); | ||
2130 | EXPORT_SYMBOL(snd_timer_global_new); | ||
2131 | EXPORT_SYMBOL(snd_timer_global_free); | ||
2132 | EXPORT_SYMBOL(snd_timer_global_register); | ||
2133 | EXPORT_SYMBOL(snd_timer_interrupt); | ||