diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-05 15:34:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-05 15:34:44 -0500 |
commit | ea5a273c76f8ba3569705362b00c7d94fb92468e (patch) | |
tree | bee0d42010f66a2deb9d7a724cf8f9f8207731c0 | |
parent | ed1741b77c162ad7087949fda39af4ec8c33e663 (diff) | |
parent | 094fd3be87b0f102589e2d5c3fa5d06b7e20496d (diff) |
Merge tag 'sound-4.5-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai:
"This was a busy week and I had to prepare a pile of duct tapes for the
bugs reported by syzkaller fuzzer in wide range of ALSA core APIs:
timer, rawmidi, sequencer, and PCM OSS emulation. Let's see how many
other holes we need to plug.
Besides that, a few usual boring stuff, HD- and USB-audio quirks, have
been added"
* tag 'sound-4.5-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
ALSA: timer: Fix leftover link at closing
ALSA: seq: Fix lockdep warnings due to double mutex locks
ALSA: rawmidi: Fix race at copying & updating the position
ALSA: rawmidi: Make snd_rawmidi_transmit() race-free
ALSA: hda - Add fixup for Mac Mini 7,1 model
ALSA: hda/realtek - Support headset mode for ALC225
ALSA: hda/realtek - Support Dell headset mode for ALC225
ALSA: hda/realtek - New codec support of ALC225
ALSA: timer: Sync timer deletion at closing the system timer
ALSA: timer: Fix link corruption due to double start or stop
ALSA: seq: Fix yet another races among ALSA timer accesses
ALSA: pcm: Fix potential deadlock in OSS emulation
ALSA: rawmidi: Remove kernel WARNING for NULL user-space buffer check
ALSA: seq: Fix race at closing in virmidi driver
ALSA: emu10k1: correctly handling failed thread creation
ALSA: usb-audio: Add quirk for Microsoft LifeCam HD-6000
ALSA: usb-audio: Add native DSD support for PS Audio NuWave DAC
ALSA: usb-audio: Fix OPPO HA-1 vendor ID
-rw-r--r-- | include/sound/rawmidi.h | 4 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 21 | ||||
-rw-r--r-- | sound/core/rawmidi.c | 134 | ||||
-rw-r--r-- | sound/core/seq/seq_clientmgr.c | 3 | ||||
-rw-r--r-- | sound/core/seq/seq_ports.c | 233 | ||||
-rw-r--r-- | sound/core/seq/seq_timer.c | 87 | ||||
-rw-r--r-- | sound/core/seq/seq_virmidi.c | 23 | ||||
-rw-r--r-- | sound/core/timer.c | 44 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_main.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 27 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 74 | ||||
-rw-r--r-- | sound/usb/quirks.c | 4 |
12 files changed, 483 insertions, 179 deletions
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index fdabbb4ddba9..f730b91e472f 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h | |||
@@ -167,6 +167,10 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, | |||
167 | int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); | 167 | int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); |
168 | int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, | 168 | int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, |
169 | unsigned char *buffer, int count); | 169 | unsigned char *buffer, int count); |
170 | int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, | ||
171 | unsigned char *buffer, int count); | ||
172 | int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, | ||
173 | int count); | ||
170 | 174 | ||
171 | /* main midi functions */ | 175 | /* main midi functions */ |
172 | 176 | ||
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 0e73d03b30e3..ebc9fdfe64df 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -835,7 +835,8 @@ static int choose_rate(struct snd_pcm_substream *substream, | |||
835 | return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); | 835 | return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); |
836 | } | 836 | } |
837 | 837 | ||
838 | static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | 838 | static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, |
839 | bool trylock) | ||
839 | { | 840 | { |
840 | struct snd_pcm_runtime *runtime = substream->runtime; | 841 | struct snd_pcm_runtime *runtime = substream->runtime; |
841 | struct snd_pcm_hw_params *params, *sparams; | 842 | struct snd_pcm_hw_params *params, *sparams; |
@@ -849,7 +850,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
849 | struct snd_mask sformat_mask; | 850 | struct snd_mask sformat_mask; |
850 | struct snd_mask mask; | 851 | struct snd_mask mask; |
851 | 852 | ||
852 | if (mutex_lock_interruptible(&runtime->oss.params_lock)) | 853 | if (trylock) { |
854 | if (!(mutex_trylock(&runtime->oss.params_lock))) | ||
855 | return -EAGAIN; | ||
856 | } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) | ||
853 | return -EINTR; | 857 | return -EINTR; |
854 | sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); | 858 | sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); |
855 | params = kmalloc(sizeof(*params), GFP_KERNEL); | 859 | params = kmalloc(sizeof(*params), GFP_KERNEL); |
@@ -1092,7 +1096,7 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil | |||
1092 | if (asubstream == NULL) | 1096 | if (asubstream == NULL) |
1093 | asubstream = substream; | 1097 | asubstream = substream; |
1094 | if (substream->runtime->oss.params) { | 1098 | if (substream->runtime->oss.params) { |
1095 | err = snd_pcm_oss_change_params(substream); | 1099 | err = snd_pcm_oss_change_params(substream, false); |
1096 | if (err < 0) | 1100 | if (err < 0) |
1097 | return err; | 1101 | return err; |
1098 | } | 1102 | } |
@@ -1132,7 +1136,7 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream) | |||
1132 | return 0; | 1136 | return 0; |
1133 | runtime = substream->runtime; | 1137 | runtime = substream->runtime; |
1134 | if (runtime->oss.params) { | 1138 | if (runtime->oss.params) { |
1135 | err = snd_pcm_oss_change_params(substream); | 1139 | err = snd_pcm_oss_change_params(substream, false); |
1136 | if (err < 0) | 1140 | if (err < 0) |
1137 | return err; | 1141 | return err; |
1138 | } | 1142 | } |
@@ -2163,7 +2167,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre | |||
2163 | runtime = substream->runtime; | 2167 | runtime = substream->runtime; |
2164 | 2168 | ||
2165 | if (runtime->oss.params && | 2169 | if (runtime->oss.params && |
2166 | (err = snd_pcm_oss_change_params(substream)) < 0) | 2170 | (err = snd_pcm_oss_change_params(substream, false)) < 0) |
2167 | return err; | 2171 | return err; |
2168 | 2172 | ||
2169 | info.fragsize = runtime->oss.period_bytes; | 2173 | info.fragsize = runtime->oss.period_bytes; |
@@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) | |||
2804 | return -EIO; | 2808 | return -EIO; |
2805 | 2809 | ||
2806 | if (runtime->oss.params) { | 2810 | if (runtime->oss.params) { |
2807 | if ((err = snd_pcm_oss_change_params(substream)) < 0) | 2811 | /* use mutex_trylock() for params_lock for avoiding a deadlock |
2812 | * between mmap_sem and params_lock taken by | ||
2813 | * copy_from/to_user() in snd_pcm_oss_write/read() | ||
2814 | */ | ||
2815 | err = snd_pcm_oss_change_params(substream, true); | ||
2816 | if (err < 0) | ||
2808 | return err; | 2817 | return err; |
2809 | } | 2818 | } |
2810 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS | 2819 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index a7759846fbaa..795437b10082 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, | |||
942 | unsigned long flags; | 942 | unsigned long flags; |
943 | long result = 0, count1; | 943 | long result = 0, count1; |
944 | struct snd_rawmidi_runtime *runtime = substream->runtime; | 944 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
945 | unsigned long appl_ptr; | ||
945 | 946 | ||
947 | spin_lock_irqsave(&runtime->lock, flags); | ||
946 | while (count > 0 && runtime->avail) { | 948 | while (count > 0 && runtime->avail) { |
947 | count1 = runtime->buffer_size - runtime->appl_ptr; | 949 | count1 = runtime->buffer_size - runtime->appl_ptr; |
948 | if (count1 > count) | 950 | if (count1 > count) |
949 | count1 = count; | 951 | count1 = count; |
950 | spin_lock_irqsave(&runtime->lock, flags); | ||
951 | if (count1 > (int)runtime->avail) | 952 | if (count1 > (int)runtime->avail) |
952 | count1 = runtime->avail; | 953 | count1 = runtime->avail; |
954 | |||
955 | /* update runtime->appl_ptr before unlocking for userbuf */ | ||
956 | appl_ptr = runtime->appl_ptr; | ||
957 | runtime->appl_ptr += count1; | ||
958 | runtime->appl_ptr %= runtime->buffer_size; | ||
959 | runtime->avail -= count1; | ||
960 | |||
953 | if (kernelbuf) | 961 | if (kernelbuf) |
954 | memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); | 962 | memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); |
955 | if (userbuf) { | 963 | if (userbuf) { |
956 | spin_unlock_irqrestore(&runtime->lock, flags); | 964 | spin_unlock_irqrestore(&runtime->lock, flags); |
957 | if (copy_to_user(userbuf + result, | 965 | if (copy_to_user(userbuf + result, |
958 | runtime->buffer + runtime->appl_ptr, count1)) { | 966 | runtime->buffer + appl_ptr, count1)) { |
959 | return result > 0 ? result : -EFAULT; | 967 | return result > 0 ? result : -EFAULT; |
960 | } | 968 | } |
961 | spin_lock_irqsave(&runtime->lock, flags); | 969 | spin_lock_irqsave(&runtime->lock, flags); |
962 | } | 970 | } |
963 | runtime->appl_ptr += count1; | ||
964 | runtime->appl_ptr %= runtime->buffer_size; | ||
965 | runtime->avail -= count1; | ||
966 | spin_unlock_irqrestore(&runtime->lock, flags); | ||
967 | result += count1; | 971 | result += count1; |
968 | count -= count1; | 972 | count -= count1; |
969 | } | 973 | } |
974 | spin_unlock_irqrestore(&runtime->lock, flags); | ||
970 | return result; | 975 | return result; |
971 | } | 976 | } |
972 | 977 | ||
@@ -1055,23 +1060,16 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) | |||
1055 | EXPORT_SYMBOL(snd_rawmidi_transmit_empty); | 1060 | EXPORT_SYMBOL(snd_rawmidi_transmit_empty); |
1056 | 1061 | ||
1057 | /** | 1062 | /** |
1058 | * snd_rawmidi_transmit_peek - copy data from the internal buffer | 1063 | * __snd_rawmidi_transmit_peek - copy data from the internal buffer |
1059 | * @substream: the rawmidi substream | 1064 | * @substream: the rawmidi substream |
1060 | * @buffer: the buffer pointer | 1065 | * @buffer: the buffer pointer |
1061 | * @count: data size to transfer | 1066 | * @count: data size to transfer |
1062 | * | 1067 | * |
1063 | * Copies data from the internal output buffer to the given buffer. | 1068 | * This is a variant of snd_rawmidi_transmit_peek() without spinlock. |
1064 | * | ||
1065 | * Call this in the interrupt handler when the midi output is ready, | ||
1066 | * and call snd_rawmidi_transmit_ack() after the transmission is | ||
1067 | * finished. | ||
1068 | * | ||
1069 | * Return: The size of copied data, or a negative error code on failure. | ||
1070 | */ | 1069 | */ |
1071 | int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, | 1070 | int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, |
1072 | unsigned char *buffer, int count) | 1071 | unsigned char *buffer, int count) |
1073 | { | 1072 | { |
1074 | unsigned long flags; | ||
1075 | int result, count1; | 1073 | int result, count1; |
1076 | struct snd_rawmidi_runtime *runtime = substream->runtime; | 1074 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
1077 | 1075 | ||
@@ -1081,7 +1079,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, | |||
1081 | return -EINVAL; | 1079 | return -EINVAL; |
1082 | } | 1080 | } |
1083 | result = 0; | 1081 | result = 0; |
1084 | spin_lock_irqsave(&runtime->lock, flags); | ||
1085 | if (runtime->avail >= runtime->buffer_size) { | 1082 | if (runtime->avail >= runtime->buffer_size) { |
1086 | /* warning: lowlevel layer MUST trigger down the hardware */ | 1083 | /* warning: lowlevel layer MUST trigger down the hardware */ |
1087 | goto __skip; | 1084 | goto __skip; |
@@ -1106,25 +1103,47 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, | |||
1106 | } | 1103 | } |
1107 | } | 1104 | } |
1108 | __skip: | 1105 | __skip: |
1106 | return result; | ||
1107 | } | ||
1108 | EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); | ||
1109 | |||
1110 | /** | ||
1111 | * snd_rawmidi_transmit_peek - copy data from the internal buffer | ||
1112 | * @substream: the rawmidi substream | ||
1113 | * @buffer: the buffer pointer | ||
1114 | * @count: data size to transfer | ||
1115 | * | ||
1116 | * Copies data from the internal output buffer to the given buffer. | ||
1117 | * | ||
1118 | * Call this in the interrupt handler when the midi output is ready, | ||
1119 | * and call snd_rawmidi_transmit_ack() after the transmission is | ||
1120 | * finished. | ||
1121 | * | ||
1122 | * Return: The size of copied data, or a negative error code on failure. | ||
1123 | */ | ||
1124 | int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, | ||
1125 | unsigned char *buffer, int count) | ||
1126 | { | ||
1127 | struct snd_rawmidi_runtime *runtime = substream->runtime; | ||
1128 | int result; | ||
1129 | unsigned long flags; | ||
1130 | |||
1131 | spin_lock_irqsave(&runtime->lock, flags); | ||
1132 | result = __snd_rawmidi_transmit_peek(substream, buffer, count); | ||
1109 | spin_unlock_irqrestore(&runtime->lock, flags); | 1133 | spin_unlock_irqrestore(&runtime->lock, flags); |
1110 | return result; | 1134 | return result; |
1111 | } | 1135 | } |
1112 | EXPORT_SYMBOL(snd_rawmidi_transmit_peek); | 1136 | EXPORT_SYMBOL(snd_rawmidi_transmit_peek); |
1113 | 1137 | ||
1114 | /** | 1138 | /** |
1115 | * snd_rawmidi_transmit_ack - acknowledge the transmission | 1139 | * __snd_rawmidi_transmit_ack - acknowledge the transmission |
1116 | * @substream: the rawmidi substream | 1140 | * @substream: the rawmidi substream |
1117 | * @count: the transferred count | 1141 | * @count: the transferred count |
1118 | * | 1142 | * |
1119 | * Advances the hardware pointer for the internal output buffer with | 1143 | * This is a variant of __snd_rawmidi_transmit_ack() without spinlock. |
1120 | * the given size and updates the condition. | ||
1121 | * Call after the transmission is finished. | ||
1122 | * | ||
1123 | * Return: The advanced size if successful, or a negative error code on failure. | ||
1124 | */ | 1144 | */ |
1125 | int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) | 1145 | int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) |
1126 | { | 1146 | { |
1127 | unsigned long flags; | ||
1128 | struct snd_rawmidi_runtime *runtime = substream->runtime; | 1147 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
1129 | 1148 | ||
1130 | if (runtime->buffer == NULL) { | 1149 | if (runtime->buffer == NULL) { |
@@ -1132,7 +1151,6 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) | |||
1132 | "snd_rawmidi_transmit_ack: output is not active!!!\n"); | 1151 | "snd_rawmidi_transmit_ack: output is not active!!!\n"); |
1133 | return -EINVAL; | 1152 | return -EINVAL; |
1134 | } | 1153 | } |
1135 | spin_lock_irqsave(&runtime->lock, flags); | ||
1136 | snd_BUG_ON(runtime->avail + count > runtime->buffer_size); | 1154 | snd_BUG_ON(runtime->avail + count > runtime->buffer_size); |
1137 | runtime->hw_ptr += count; | 1155 | runtime->hw_ptr += count; |
1138 | runtime->hw_ptr %= runtime->buffer_size; | 1156 | runtime->hw_ptr %= runtime->buffer_size; |
@@ -1142,9 +1160,32 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) | |||
1142 | if (runtime->drain || snd_rawmidi_ready(substream)) | 1160 | if (runtime->drain || snd_rawmidi_ready(substream)) |
1143 | wake_up(&runtime->sleep); | 1161 | wake_up(&runtime->sleep); |
1144 | } | 1162 | } |
1145 | spin_unlock_irqrestore(&runtime->lock, flags); | ||
1146 | return count; | 1163 | return count; |
1147 | } | 1164 | } |
1165 | EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); | ||
1166 | |||
1167 | /** | ||
1168 | * snd_rawmidi_transmit_ack - acknowledge the transmission | ||
1169 | * @substream: the rawmidi substream | ||
1170 | * @count: the transferred count | ||
1171 | * | ||
1172 | * Advances the hardware pointer for the internal output buffer with | ||
1173 | * the given size and updates the condition. | ||
1174 | * Call after the transmission is finished. | ||
1175 | * | ||
1176 | * Return: The advanced size if successful, or a negative error code on failure. | ||
1177 | */ | ||
1178 | int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) | ||
1179 | { | ||
1180 | struct snd_rawmidi_runtime *runtime = substream->runtime; | ||
1181 | int result; | ||
1182 | unsigned long flags; | ||
1183 | |||
1184 | spin_lock_irqsave(&runtime->lock, flags); | ||
1185 | result = __snd_rawmidi_transmit_ack(substream, count); | ||
1186 | spin_unlock_irqrestore(&runtime->lock, flags); | ||
1187 | return result; | ||
1188 | } | ||
1148 | EXPORT_SYMBOL(snd_rawmidi_transmit_ack); | 1189 | EXPORT_SYMBOL(snd_rawmidi_transmit_ack); |
1149 | 1190 | ||
1150 | /** | 1191 | /** |
@@ -1160,12 +1201,22 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); | |||
1160 | int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, | 1201 | int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, |
1161 | unsigned char *buffer, int count) | 1202 | unsigned char *buffer, int count) |
1162 | { | 1203 | { |
1204 | struct snd_rawmidi_runtime *runtime = substream->runtime; | ||
1205 | int result; | ||
1206 | unsigned long flags; | ||
1207 | |||
1208 | spin_lock_irqsave(&runtime->lock, flags); | ||
1163 | if (!substream->opened) | 1209 | if (!substream->opened) |
1164 | return -EBADFD; | 1210 | result = -EBADFD; |
1165 | count = snd_rawmidi_transmit_peek(substream, buffer, count); | 1211 | else { |
1166 | if (count < 0) | 1212 | count = __snd_rawmidi_transmit_peek(substream, buffer, count); |
1167 | return count; | 1213 | if (count <= 0) |
1168 | return snd_rawmidi_transmit_ack(substream, count); | 1214 | result = count; |
1215 | else | ||
1216 | result = __snd_rawmidi_transmit_ack(substream, count); | ||
1217 | } | ||
1218 | spin_unlock_irqrestore(&runtime->lock, flags); | ||
1219 | return result; | ||
1169 | } | 1220 | } |
1170 | EXPORT_SYMBOL(snd_rawmidi_transmit); | 1221 | EXPORT_SYMBOL(snd_rawmidi_transmit); |
1171 | 1222 | ||
@@ -1177,8 +1228,9 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | |||
1177 | unsigned long flags; | 1228 | unsigned long flags; |
1178 | long count1, result; | 1229 | long count1, result; |
1179 | struct snd_rawmidi_runtime *runtime = substream->runtime; | 1230 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
1231 | unsigned long appl_ptr; | ||
1180 | 1232 | ||
1181 | if (snd_BUG_ON(!kernelbuf && !userbuf)) | 1233 | if (!kernelbuf && !userbuf) |
1182 | return -EINVAL; | 1234 | return -EINVAL; |
1183 | if (snd_BUG_ON(!runtime->buffer)) | 1235 | if (snd_BUG_ON(!runtime->buffer)) |
1184 | return -EINVAL; | 1236 | return -EINVAL; |
@@ -1197,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | |||
1197 | count1 = count; | 1249 | count1 = count; |
1198 | if (count1 > (long)runtime->avail) | 1250 | if (count1 > (long)runtime->avail) |
1199 | count1 = runtime->avail; | 1251 | count1 = runtime->avail; |
1252 | |||
1253 | /* update runtime->appl_ptr before unlocking for userbuf */ | ||
1254 | appl_ptr = runtime->appl_ptr; | ||
1255 | runtime->appl_ptr += count1; | ||
1256 | runtime->appl_ptr %= runtime->buffer_size; | ||
1257 | runtime->avail -= count1; | ||
1258 | |||
1200 | if (kernelbuf) | 1259 | if (kernelbuf) |
1201 | memcpy(runtime->buffer + runtime->appl_ptr, | 1260 | memcpy(runtime->buffer + appl_ptr, |
1202 | kernelbuf + result, count1); | 1261 | kernelbuf + result, count1); |
1203 | else if (userbuf) { | 1262 | else if (userbuf) { |
1204 | spin_unlock_irqrestore(&runtime->lock, flags); | 1263 | spin_unlock_irqrestore(&runtime->lock, flags); |
1205 | if (copy_from_user(runtime->buffer + runtime->appl_ptr, | 1264 | if (copy_from_user(runtime->buffer + appl_ptr, |
1206 | userbuf + result, count1)) { | 1265 | userbuf + result, count1)) { |
1207 | spin_lock_irqsave(&runtime->lock, flags); | 1266 | spin_lock_irqsave(&runtime->lock, flags); |
1208 | result = result > 0 ? result : -EFAULT; | 1267 | result = result > 0 ? result : -EFAULT; |
@@ -1210,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | |||
1210 | } | 1269 | } |
1211 | spin_lock_irqsave(&runtime->lock, flags); | 1270 | spin_lock_irqsave(&runtime->lock, flags); |
1212 | } | 1271 | } |
1213 | runtime->appl_ptr += count1; | ||
1214 | runtime->appl_ptr %= runtime->buffer_size; | ||
1215 | runtime->avail -= count1; | ||
1216 | result += count1; | 1272 | result += count1; |
1217 | count -= count1; | 1273 | count -= count1; |
1218 | } | 1274 | } |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 13cfa815732d..58e79e02f217 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client, | |||
678 | else | 678 | else |
679 | down_read(&grp->list_mutex); | 679 | down_read(&grp->list_mutex); |
680 | list_for_each_entry(subs, &grp->list_head, src_list) { | 680 | list_for_each_entry(subs, &grp->list_head, src_list) { |
681 | /* both ports ready? */ | ||
682 | if (atomic_read(&subs->ref_count) != 2) | ||
683 | continue; | ||
681 | event->dest = subs->info.dest; | 684 | event->dest = subs->info.dest; |
682 | if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) | 685 | if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) |
683 | /* convert time according to flag with subscription */ | 686 | /* convert time according to flag with subscription */ |
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 55170a20ae72..921fb2bd8fad 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
@@ -173,10 +173,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, | |||
173 | } | 173 | } |
174 | 174 | ||
175 | /* */ | 175 | /* */ |
176 | enum group_type { | ||
177 | SRC_LIST, DEST_LIST | ||
178 | }; | ||
179 | |||
180 | static int subscribe_port(struct snd_seq_client *client, | 176 | static int subscribe_port(struct snd_seq_client *client, |
181 | struct snd_seq_client_port *port, | 177 | struct snd_seq_client_port *port, |
182 | struct snd_seq_port_subs_info *grp, | 178 | struct snd_seq_port_subs_info *grp, |
@@ -203,6 +199,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, | |||
203 | return NULL; | 199 | return NULL; |
204 | } | 200 | } |
205 | 201 | ||
202 | static void delete_and_unsubscribe_port(struct snd_seq_client *client, | ||
203 | struct snd_seq_client_port *port, | ||
204 | struct snd_seq_subscribers *subs, | ||
205 | bool is_src, bool ack); | ||
206 | |||
207 | static inline struct snd_seq_subscribers * | ||
208 | get_subscriber(struct list_head *p, bool is_src) | ||
209 | { | ||
210 | if (is_src) | ||
211 | return list_entry(p, struct snd_seq_subscribers, src_list); | ||
212 | else | ||
213 | return list_entry(p, struct snd_seq_subscribers, dest_list); | ||
214 | } | ||
215 | |||
206 | /* | 216 | /* |
207 | * remove all subscribers on the list | 217 | * remove all subscribers on the list |
208 | * this is called from port_delete, for each src and dest list. | 218 | * this is called from port_delete, for each src and dest list. |
@@ -210,7 +220,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, | |||
210 | static void clear_subscriber_list(struct snd_seq_client *client, | 220 | static void clear_subscriber_list(struct snd_seq_client *client, |
211 | struct snd_seq_client_port *port, | 221 | struct snd_seq_client_port *port, |
212 | struct snd_seq_port_subs_info *grp, | 222 | struct snd_seq_port_subs_info *grp, |
213 | int grptype) | 223 | int is_src) |
214 | { | 224 | { |
215 | struct list_head *p, *n; | 225 | struct list_head *p, *n; |
216 | 226 | ||
@@ -219,15 +229,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, | |||
219 | struct snd_seq_client *c; | 229 | struct snd_seq_client *c; |
220 | struct snd_seq_client_port *aport; | 230 | struct snd_seq_client_port *aport; |
221 | 231 | ||
222 | if (grptype == SRC_LIST) { | 232 | subs = get_subscriber(p, is_src); |
223 | subs = list_entry(p, struct snd_seq_subscribers, src_list); | 233 | if (is_src) |
224 | aport = get_client_port(&subs->info.dest, &c); | 234 | aport = get_client_port(&subs->info.dest, &c); |
225 | } else { | 235 | else |
226 | subs = list_entry(p, struct snd_seq_subscribers, dest_list); | ||
227 | aport = get_client_port(&subs->info.sender, &c); | 236 | aport = get_client_port(&subs->info.sender, &c); |
228 | } | 237 | delete_and_unsubscribe_port(client, port, subs, is_src, false); |
229 | list_del(p); | 238 | |
230 | unsubscribe_port(client, port, grp, &subs->info, 0); | ||
231 | if (!aport) { | 239 | if (!aport) { |
232 | /* looks like the connected port is being deleted. | 240 | /* looks like the connected port is being deleted. |
233 | * we decrease the counter, and when both ports are deleted | 241 | * we decrease the counter, and when both ports are deleted |
@@ -235,21 +243,14 @@ static void clear_subscriber_list(struct snd_seq_client *client, | |||
235 | */ | 243 | */ |
236 | if (atomic_dec_and_test(&subs->ref_count)) | 244 | if (atomic_dec_and_test(&subs->ref_count)) |
237 | kfree(subs); | 245 | kfree(subs); |
238 | } else { | 246 | continue; |
239 | /* ok we got the connected port */ | ||
240 | struct snd_seq_port_subs_info *agrp; | ||
241 | agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src; | ||
242 | down_write(&agrp->list_mutex); | ||
243 | if (grptype == SRC_LIST) | ||
244 | list_del(&subs->dest_list); | ||
245 | else | ||
246 | list_del(&subs->src_list); | ||
247 | up_write(&agrp->list_mutex); | ||
248 | unsubscribe_port(c, aport, agrp, &subs->info, 1); | ||
249 | kfree(subs); | ||
250 | snd_seq_port_unlock(aport); | ||
251 | snd_seq_client_unlock(c); | ||
252 | } | 247 | } |
248 | |||
249 | /* ok we got the connected port */ | ||
250 | delete_and_unsubscribe_port(c, aport, subs, !is_src, true); | ||
251 | kfree(subs); | ||
252 | snd_seq_port_unlock(aport); | ||
253 | snd_seq_client_unlock(c); | ||
253 | } | 254 | } |
254 | } | 255 | } |
255 | 256 | ||
@@ -262,8 +263,8 @@ static int port_delete(struct snd_seq_client *client, | |||
262 | snd_use_lock_sync(&port->use_lock); | 263 | snd_use_lock_sync(&port->use_lock); |
263 | 264 | ||
264 | /* clear subscribers info */ | 265 | /* clear subscribers info */ |
265 | clear_subscriber_list(client, port, &port->c_src, SRC_LIST); | 266 | clear_subscriber_list(client, port, &port->c_src, true); |
266 | clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); | 267 | clear_subscriber_list(client, port, &port->c_dest, false); |
267 | 268 | ||
268 | if (port->private_free) | 269 | if (port->private_free) |
269 | port->private_free(port->private_data); | 270 | port->private_free(port->private_data); |
@@ -479,85 +480,120 @@ static int match_subs_info(struct snd_seq_port_subscribe *r, | |||
479 | return 0; | 480 | return 0; |
480 | } | 481 | } |
481 | 482 | ||
482 | 483 | static int check_and_subscribe_port(struct snd_seq_client *client, | |
483 | /* connect two ports */ | 484 | struct snd_seq_client_port *port, |
484 | int snd_seq_port_connect(struct snd_seq_client *connector, | 485 | struct snd_seq_subscribers *subs, |
485 | struct snd_seq_client *src_client, | 486 | bool is_src, bool exclusive, bool ack) |
486 | struct snd_seq_client_port *src_port, | ||
487 | struct snd_seq_client *dest_client, | ||
488 | struct snd_seq_client_port *dest_port, | ||
489 | struct snd_seq_port_subscribe *info) | ||
490 | { | 487 | { |
491 | struct snd_seq_port_subs_info *src = &src_port->c_src; | 488 | struct snd_seq_port_subs_info *grp; |
492 | struct snd_seq_port_subs_info *dest = &dest_port->c_dest; | 489 | struct list_head *p; |
493 | struct snd_seq_subscribers *subs, *s; | 490 | struct snd_seq_subscribers *s; |
494 | int err, src_called = 0; | 491 | int err; |
495 | unsigned long flags; | ||
496 | int exclusive; | ||
497 | 492 | ||
498 | subs = kzalloc(sizeof(*subs), GFP_KERNEL); | 493 | grp = is_src ? &port->c_src : &port->c_dest; |
499 | if (! subs) | ||
500 | return -ENOMEM; | ||
501 | |||
502 | subs->info = *info; | ||
503 | atomic_set(&subs->ref_count, 2); | ||
504 | |||
505 | down_write(&src->list_mutex); | ||
506 | down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); | ||
507 | |||
508 | exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; | ||
509 | err = -EBUSY; | 494 | err = -EBUSY; |
495 | down_write(&grp->list_mutex); | ||
510 | if (exclusive) { | 496 | if (exclusive) { |
511 | if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) | 497 | if (!list_empty(&grp->list_head)) |
512 | goto __error; | 498 | goto __error; |
513 | } else { | 499 | } else { |
514 | if (src->exclusive || dest->exclusive) | 500 | if (grp->exclusive) |
515 | goto __error; | 501 | goto __error; |
516 | /* check whether already exists */ | 502 | /* check whether already exists */ |
517 | list_for_each_entry(s, &src->list_head, src_list) { | 503 | list_for_each(p, &grp->list_head) { |
518 | if (match_subs_info(info, &s->info)) | 504 | s = get_subscriber(p, is_src); |
519 | goto __error; | 505 | if (match_subs_info(&subs->info, &s->info)) |
520 | } | ||
521 | list_for_each_entry(s, &dest->list_head, dest_list) { | ||
522 | if (match_subs_info(info, &s->info)) | ||
523 | goto __error; | 506 | goto __error; |
524 | } | 507 | } |
525 | } | 508 | } |
526 | 509 | ||
527 | if ((err = subscribe_port(src_client, src_port, src, info, | 510 | err = subscribe_port(client, port, grp, &subs->info, ack); |
528 | connector->number != src_client->number)) < 0) | 511 | if (err < 0) { |
529 | goto __error; | 512 | grp->exclusive = 0; |
530 | src_called = 1; | ||
531 | |||
532 | if ((err = subscribe_port(dest_client, dest_port, dest, info, | ||
533 | connector->number != dest_client->number)) < 0) | ||
534 | goto __error; | 513 | goto __error; |
514 | } | ||
535 | 515 | ||
536 | /* add to list */ | 516 | /* add to list */ |
537 | write_lock_irqsave(&src->list_lock, flags); | 517 | write_lock_irq(&grp->list_lock); |
538 | // write_lock(&dest->list_lock); // no other lock yet | 518 | if (is_src) |
539 | list_add_tail(&subs->src_list, &src->list_head); | 519 | list_add_tail(&subs->src_list, &grp->list_head); |
540 | list_add_tail(&subs->dest_list, &dest->list_head); | 520 | else |
541 | // write_unlock(&dest->list_lock); // no other lock yet | 521 | list_add_tail(&subs->dest_list, &grp->list_head); |
542 | write_unlock_irqrestore(&src->list_lock, flags); | 522 | grp->exclusive = exclusive; |
523 | atomic_inc(&subs->ref_count); | ||
524 | write_unlock_irq(&grp->list_lock); | ||
525 | err = 0; | ||
526 | |||
527 | __error: | ||
528 | up_write(&grp->list_mutex); | ||
529 | return err; | ||
530 | } | ||
543 | 531 | ||
544 | src->exclusive = dest->exclusive = exclusive; | 532 | static void delete_and_unsubscribe_port(struct snd_seq_client *client, |
533 | struct snd_seq_client_port *port, | ||
534 | struct snd_seq_subscribers *subs, | ||
535 | bool is_src, bool ack) | ||
536 | { | ||
537 | struct snd_seq_port_subs_info *grp; | ||
538 | |||
539 | grp = is_src ? &port->c_src : &port->c_dest; | ||
540 | down_write(&grp->list_mutex); | ||
541 | write_lock_irq(&grp->list_lock); | ||
542 | if (is_src) | ||
543 | list_del(&subs->src_list); | ||
544 | else | ||
545 | list_del(&subs->dest_list); | ||
546 | grp->exclusive = 0; | ||
547 | write_unlock_irq(&grp->list_lock); | ||
548 | up_write(&grp->list_mutex); | ||
549 | |||
550 | unsubscribe_port(client, port, grp, &subs->info, ack); | ||
551 | } | ||
552 | |||
553 | /* connect two ports */ | ||
554 | int snd_seq_port_connect(struct snd_seq_client *connector, | ||
555 | struct snd_seq_client *src_client, | ||
556 | struct snd_seq_client_port *src_port, | ||
557 | struct snd_seq_client *dest_client, | ||
558 | struct snd_seq_client_port *dest_port, | ||
559 | struct snd_seq_port_subscribe *info) | ||
560 | { | ||
561 | struct snd_seq_subscribers *subs; | ||
562 | bool exclusive; | ||
563 | int err; | ||
564 | |||
565 | subs = kzalloc(sizeof(*subs), GFP_KERNEL); | ||
566 | if (!subs) | ||
567 | return -ENOMEM; | ||
568 | |||
569 | subs->info = *info; | ||
570 | atomic_set(&subs->ref_count, 0); | ||
571 | INIT_LIST_HEAD(&subs->src_list); | ||
572 | INIT_LIST_HEAD(&subs->dest_list); | ||
573 | |||
574 | exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); | ||
575 | |||
576 | err = check_and_subscribe_port(src_client, src_port, subs, true, | ||
577 | exclusive, | ||
578 | connector->number != src_client->number); | ||
579 | if (err < 0) | ||
580 | goto error; | ||
581 | err = check_and_subscribe_port(dest_client, dest_port, subs, false, | ||
582 | exclusive, | ||
583 | connector->number != dest_client->number); | ||
584 | if (err < 0) | ||
585 | goto error_dest; | ||
545 | 586 | ||
546 | up_write(&dest->list_mutex); | ||
547 | up_write(&src->list_mutex); | ||
548 | return 0; | 587 | return 0; |
549 | 588 | ||
550 | __error: | 589 | error_dest: |
551 | if (src_called) | 590 | delete_and_unsubscribe_port(src_client, src_port, subs, true, |
552 | unsubscribe_port(src_client, src_port, src, info, | 591 | connector->number != src_client->number); |
553 | connector->number != src_client->number); | 592 | error: |
554 | kfree(subs); | 593 | kfree(subs); |
555 | up_write(&dest->list_mutex); | ||
556 | up_write(&src->list_mutex); | ||
557 | return err; | 594 | return err; |
558 | } | 595 | } |
559 | 596 | ||
560 | |||
561 | /* remove the connection */ | 597 | /* remove the connection */ |
562 | int snd_seq_port_disconnect(struct snd_seq_client *connector, | 598 | int snd_seq_port_disconnect(struct snd_seq_client *connector, |
563 | struct snd_seq_client *src_client, | 599 | struct snd_seq_client *src_client, |
@@ -567,37 +603,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, | |||
567 | struct snd_seq_port_subscribe *info) | 603 | struct snd_seq_port_subscribe *info) |
568 | { | 604 | { |
569 | struct snd_seq_port_subs_info *src = &src_port->c_src; | 605 | struct snd_seq_port_subs_info *src = &src_port->c_src; |
570 | struct snd_seq_port_subs_info *dest = &dest_port->c_dest; | ||
571 | struct snd_seq_subscribers *subs; | 606 | struct snd_seq_subscribers *subs; |
572 | int err = -ENOENT; | 607 | int err = -ENOENT; |
573 | unsigned long flags; | ||
574 | 608 | ||
575 | down_write(&src->list_mutex); | 609 | down_write(&src->list_mutex); |
576 | down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); | ||
577 | |||
578 | /* look for the connection */ | 610 | /* look for the connection */ |
579 | list_for_each_entry(subs, &src->list_head, src_list) { | 611 | list_for_each_entry(subs, &src->list_head, src_list) { |
580 | if (match_subs_info(info, &subs->info)) { | 612 | if (match_subs_info(info, &subs->info)) { |
581 | write_lock_irqsave(&src->list_lock, flags); | 613 | atomic_dec(&subs->ref_count); /* mark as not ready */ |
582 | // write_lock(&dest->list_lock); // no lock yet | ||
583 | list_del(&subs->src_list); | ||
584 | list_del(&subs->dest_list); | ||
585 | // write_unlock(&dest->list_lock); | ||
586 | write_unlock_irqrestore(&src->list_lock, flags); | ||
587 | src->exclusive = dest->exclusive = 0; | ||
588 | unsubscribe_port(src_client, src_port, src, info, | ||
589 | connector->number != src_client->number); | ||
590 | unsubscribe_port(dest_client, dest_port, dest, info, | ||
591 | connector->number != dest_client->number); | ||
592 | kfree(subs); | ||
593 | err = 0; | 614 | err = 0; |
594 | break; | 615 | break; |
595 | } | 616 | } |
596 | } | 617 | } |
597 | |||
598 | up_write(&dest->list_mutex); | ||
599 | up_write(&src->list_mutex); | 618 | up_write(&src->list_mutex); |
600 | return err; | 619 | if (err < 0) |
620 | return err; | ||
621 | |||
622 | delete_and_unsubscribe_port(src_client, src_port, subs, true, | ||
623 | connector->number != src_client->number); | ||
624 | delete_and_unsubscribe_port(dest_client, dest_port, subs, false, | ||
625 | connector->number != dest_client->number); | ||
626 | kfree(subs); | ||
627 | return 0; | ||
601 | } | 628 | } |
602 | 629 | ||
603 | 630 | ||
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 82b220c769c1..293104926098 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
@@ -90,6 +90,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr) | |||
90 | 90 | ||
91 | void snd_seq_timer_defaults(struct snd_seq_timer * tmr) | 91 | void snd_seq_timer_defaults(struct snd_seq_timer * tmr) |
92 | { | 92 | { |
93 | unsigned long flags; | ||
94 | |||
95 | spin_lock_irqsave(&tmr->lock, flags); | ||
93 | /* setup defaults */ | 96 | /* setup defaults */ |
94 | tmr->ppq = 96; /* 96 PPQ */ | 97 | tmr->ppq = 96; /* 96 PPQ */ |
95 | tmr->tempo = 500000; /* 120 BPM */ | 98 | tmr->tempo = 500000; /* 120 BPM */ |
@@ -105,21 +108,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) | |||
105 | tmr->preferred_resolution = seq_default_timer_resolution; | 108 | tmr->preferred_resolution = seq_default_timer_resolution; |
106 | 109 | ||
107 | tmr->skew = tmr->skew_base = SKEW_BASE; | 110 | tmr->skew = tmr->skew_base = SKEW_BASE; |
111 | spin_unlock_irqrestore(&tmr->lock, flags); | ||
108 | } | 112 | } |
109 | 113 | ||
110 | void snd_seq_timer_reset(struct snd_seq_timer * tmr) | 114 | static void seq_timer_reset(struct snd_seq_timer *tmr) |
111 | { | 115 | { |
112 | unsigned long flags; | ||
113 | |||
114 | spin_lock_irqsave(&tmr->lock, flags); | ||
115 | |||
116 | /* reset time & songposition */ | 116 | /* reset time & songposition */ |
117 | tmr->cur_time.tv_sec = 0; | 117 | tmr->cur_time.tv_sec = 0; |
118 | tmr->cur_time.tv_nsec = 0; | 118 | tmr->cur_time.tv_nsec = 0; |
119 | 119 | ||
120 | tmr->tick.cur_tick = 0; | 120 | tmr->tick.cur_tick = 0; |
121 | tmr->tick.fraction = 0; | 121 | tmr->tick.fraction = 0; |
122 | } | ||
123 | |||
124 | void snd_seq_timer_reset(struct snd_seq_timer *tmr) | ||
125 | { | ||
126 | unsigned long flags; | ||
122 | 127 | ||
128 | spin_lock_irqsave(&tmr->lock, flags); | ||
129 | seq_timer_reset(tmr); | ||
123 | spin_unlock_irqrestore(&tmr->lock, flags); | 130 | spin_unlock_irqrestore(&tmr->lock, flags); |
124 | } | 131 | } |
125 | 132 | ||
@@ -138,8 +145,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, | |||
138 | tmr = q->timer; | 145 | tmr = q->timer; |
139 | if (tmr == NULL) | 146 | if (tmr == NULL) |
140 | return; | 147 | return; |
141 | if (!tmr->running) | 148 | spin_lock_irqsave(&tmr->lock, flags); |
149 | if (!tmr->running) { | ||
150 | spin_unlock_irqrestore(&tmr->lock, flags); | ||
142 | return; | 151 | return; |
152 | } | ||
143 | 153 | ||
144 | resolution *= ticks; | 154 | resolution *= ticks; |
145 | if (tmr->skew != tmr->skew_base) { | 155 | if (tmr->skew != tmr->skew_base) { |
@@ -148,8 +158,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, | |||
148 | (((resolution & 0xffff) * tmr->skew) >> 16); | 158 | (((resolution & 0xffff) * tmr->skew) >> 16); |
149 | } | 159 | } |
150 | 160 | ||
151 | spin_lock_irqsave(&tmr->lock, flags); | ||
152 | |||
153 | /* update timer */ | 161 | /* update timer */ |
154 | snd_seq_inc_time_nsec(&tmr->cur_time, resolution); | 162 | snd_seq_inc_time_nsec(&tmr->cur_time, resolution); |
155 | 163 | ||
@@ -296,26 +304,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q) | |||
296 | t->callback = snd_seq_timer_interrupt; | 304 | t->callback = snd_seq_timer_interrupt; |
297 | t->callback_data = q; | 305 | t->callback_data = q; |
298 | t->flags |= SNDRV_TIMER_IFLG_AUTO; | 306 | t->flags |= SNDRV_TIMER_IFLG_AUTO; |
307 | spin_lock_irq(&tmr->lock); | ||
299 | tmr->timeri = t; | 308 | tmr->timeri = t; |
309 | spin_unlock_irq(&tmr->lock); | ||
300 | return 0; | 310 | return 0; |
301 | } | 311 | } |
302 | 312 | ||
303 | int snd_seq_timer_close(struct snd_seq_queue *q) | 313 | int snd_seq_timer_close(struct snd_seq_queue *q) |
304 | { | 314 | { |
305 | struct snd_seq_timer *tmr; | 315 | struct snd_seq_timer *tmr; |
316 | struct snd_timer_instance *t; | ||
306 | 317 | ||
307 | tmr = q->timer; | 318 | tmr = q->timer; |
308 | if (snd_BUG_ON(!tmr)) | 319 | if (snd_BUG_ON(!tmr)) |
309 | return -EINVAL; | 320 | return -EINVAL; |
310 | if (tmr->timeri) { | 321 | spin_lock_irq(&tmr->lock); |
311 | snd_timer_stop(tmr->timeri); | 322 | t = tmr->timeri; |
312 | snd_timer_close(tmr->timeri); | 323 | tmr->timeri = NULL; |
313 | tmr->timeri = NULL; | 324 | spin_unlock_irq(&tmr->lock); |
314 | } | 325 | if (t) |
326 | snd_timer_close(t); | ||
315 | return 0; | 327 | return 0; |
316 | } | 328 | } |
317 | 329 | ||
318 | int snd_seq_timer_stop(struct snd_seq_timer * tmr) | 330 | static int seq_timer_stop(struct snd_seq_timer *tmr) |
319 | { | 331 | { |
320 | if (! tmr->timeri) | 332 | if (! tmr->timeri) |
321 | return -EINVAL; | 333 | return -EINVAL; |
@@ -326,6 +338,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr) | |||
326 | return 0; | 338 | return 0; |
327 | } | 339 | } |
328 | 340 | ||
341 | int snd_seq_timer_stop(struct snd_seq_timer *tmr) | ||
342 | { | ||
343 | unsigned long flags; | ||
344 | int err; | ||
345 | |||
346 | spin_lock_irqsave(&tmr->lock, flags); | ||
347 | err = seq_timer_stop(tmr); | ||
348 | spin_unlock_irqrestore(&tmr->lock, flags); | ||
349 | return err; | ||
350 | } | ||
351 | |||
329 | static int initialize_timer(struct snd_seq_timer *tmr) | 352 | static int initialize_timer(struct snd_seq_timer *tmr) |
330 | { | 353 | { |
331 | struct snd_timer *t; | 354 | struct snd_timer *t; |
@@ -358,13 +381,13 @@ static int initialize_timer(struct snd_seq_timer *tmr) | |||
358 | return 0; | 381 | return 0; |
359 | } | 382 | } |
360 | 383 | ||
361 | int snd_seq_timer_start(struct snd_seq_timer * tmr) | 384 | static int seq_timer_start(struct snd_seq_timer *tmr) |
362 | { | 385 | { |
363 | if (! tmr->timeri) | 386 | if (! tmr->timeri) |
364 | return -EINVAL; | 387 | return -EINVAL; |
365 | if (tmr->running) | 388 | if (tmr->running) |
366 | snd_seq_timer_stop(tmr); | 389 | seq_timer_stop(tmr); |
367 | snd_seq_timer_reset(tmr); | 390 | seq_timer_reset(tmr); |
368 | if (initialize_timer(tmr) < 0) | 391 | if (initialize_timer(tmr) < 0) |
369 | return -EINVAL; | 392 | return -EINVAL; |
370 | snd_timer_start(tmr->timeri, tmr->ticks); | 393 | snd_timer_start(tmr->timeri, tmr->ticks); |
@@ -373,14 +396,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr) | |||
373 | return 0; | 396 | return 0; |
374 | } | 397 | } |
375 | 398 | ||
376 | int snd_seq_timer_continue(struct snd_seq_timer * tmr) | 399 | int snd_seq_timer_start(struct snd_seq_timer *tmr) |
400 | { | ||
401 | unsigned long flags; | ||
402 | int err; | ||
403 | |||
404 | spin_lock_irqsave(&tmr->lock, flags); | ||
405 | err = seq_timer_start(tmr); | ||
406 | spin_unlock_irqrestore(&tmr->lock, flags); | ||
407 | return err; | ||
408 | } | ||
409 | |||
410 | static int seq_timer_continue(struct snd_seq_timer *tmr) | ||
377 | { | 411 | { |
378 | if (! tmr->timeri) | 412 | if (! tmr->timeri) |
379 | return -EINVAL; | 413 | return -EINVAL; |
380 | if (tmr->running) | 414 | if (tmr->running) |
381 | return -EBUSY; | 415 | return -EBUSY; |
382 | if (! tmr->initialized) { | 416 | if (! tmr->initialized) { |
383 | snd_seq_timer_reset(tmr); | 417 | seq_timer_reset(tmr); |
384 | if (initialize_timer(tmr) < 0) | 418 | if (initialize_timer(tmr) < 0) |
385 | return -EINVAL; | 419 | return -EINVAL; |
386 | } | 420 | } |
@@ -390,11 +424,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr) | |||
390 | return 0; | 424 | return 0; |
391 | } | 425 | } |
392 | 426 | ||
427 | int snd_seq_timer_continue(struct snd_seq_timer *tmr) | ||
428 | { | ||
429 | unsigned long flags; | ||
430 | int err; | ||
431 | |||
432 | spin_lock_irqsave(&tmr->lock, flags); | ||
433 | err = seq_timer_continue(tmr); | ||
434 | spin_unlock_irqrestore(&tmr->lock, flags); | ||
435 | return err; | ||
436 | } | ||
437 | |||
393 | /* return current 'real' time. use timeofday() to get better granularity. */ | 438 | /* return current 'real' time. use timeofday() to get better granularity. */ |
394 | snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) | 439 | snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) |
395 | { | 440 | { |
396 | snd_seq_real_time_t cur_time; | 441 | snd_seq_real_time_t cur_time; |
442 | unsigned long flags; | ||
397 | 443 | ||
444 | spin_lock_irqsave(&tmr->lock, flags); | ||
398 | cur_time = tmr->cur_time; | 445 | cur_time = tmr->cur_time; |
399 | if (tmr->running) { | 446 | if (tmr->running) { |
400 | struct timeval tm; | 447 | struct timeval tm; |
@@ -410,7 +457,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) | |||
410 | } | 457 | } |
411 | snd_seq_sanity_real_time(&cur_time); | 458 | snd_seq_sanity_real_time(&cur_time); |
412 | } | 459 | } |
413 | 460 | spin_unlock_irqrestore(&tmr->lock, flags); | |
414 | return cur_time; | 461 | return cur_time; |
415 | } | 462 | } |
416 | 463 | ||
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 3da2d48610b3..c82ed3e70506 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c | |||
@@ -155,21 +155,26 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, | |||
155 | struct snd_virmidi *vmidi = substream->runtime->private_data; | 155 | struct snd_virmidi *vmidi = substream->runtime->private_data; |
156 | int count, res; | 156 | int count, res; |
157 | unsigned char buf[32], *pbuf; | 157 | unsigned char buf[32], *pbuf; |
158 | unsigned long flags; | ||
158 | 159 | ||
159 | if (up) { | 160 | if (up) { |
160 | vmidi->trigger = 1; | 161 | vmidi->trigger = 1; |
161 | if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && | 162 | if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && |
162 | !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { | 163 | !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { |
163 | snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail); | 164 | while (snd_rawmidi_transmit(substream, buf, |
164 | return; /* ignored */ | 165 | sizeof(buf)) > 0) { |
166 | /* ignored */ | ||
167 | } | ||
168 | return; | ||
165 | } | 169 | } |
166 | if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { | 170 | if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { |
167 | if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) | 171 | if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) |
168 | return; | 172 | return; |
169 | vmidi->event.type = SNDRV_SEQ_EVENT_NONE; | 173 | vmidi->event.type = SNDRV_SEQ_EVENT_NONE; |
170 | } | 174 | } |
175 | spin_lock_irqsave(&substream->runtime->lock, flags); | ||
171 | while (1) { | 176 | while (1) { |
172 | count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); | 177 | count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); |
173 | if (count <= 0) | 178 | if (count <= 0) |
174 | break; | 179 | break; |
175 | pbuf = buf; | 180 | pbuf = buf; |
@@ -179,16 +184,18 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, | |||
179 | snd_midi_event_reset_encode(vmidi->parser); | 184 | snd_midi_event_reset_encode(vmidi->parser); |
180 | continue; | 185 | continue; |
181 | } | 186 | } |
182 | snd_rawmidi_transmit_ack(substream, res); | 187 | __snd_rawmidi_transmit_ack(substream, res); |
183 | pbuf += res; | 188 | pbuf += res; |
184 | count -= res; | 189 | count -= res; |
185 | if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { | 190 | if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { |
186 | if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) | 191 | if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) |
187 | return; | 192 | goto out; |
188 | vmidi->event.type = SNDRV_SEQ_EVENT_NONE; | 193 | vmidi->event.type = SNDRV_SEQ_EVENT_NONE; |
189 | } | 194 | } |
190 | } | 195 | } |
191 | } | 196 | } |
197 | out: | ||
198 | spin_unlock_irqrestore(&substream->runtime->lock, flags); | ||
192 | } else { | 199 | } else { |
193 | vmidi->trigger = 0; | 200 | vmidi->trigger = 0; |
194 | } | 201 | } |
@@ -254,9 +261,13 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) | |||
254 | */ | 261 | */ |
255 | static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) | 262 | static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) |
256 | { | 263 | { |
264 | struct snd_virmidi_dev *rdev = substream->rmidi->private_data; | ||
257 | struct snd_virmidi *vmidi = substream->runtime->private_data; | 265 | struct snd_virmidi *vmidi = substream->runtime->private_data; |
258 | snd_midi_event_free(vmidi->parser); | 266 | |
267 | write_lock_irq(&rdev->filelist_lock); | ||
259 | list_del(&vmidi->list); | 268 | list_del(&vmidi->list); |
269 | write_unlock_irq(&rdev->filelist_lock); | ||
270 | snd_midi_event_free(vmidi->parser); | ||
260 | substream->runtime->private_data = NULL; | 271 | substream->runtime->private_data = NULL; |
261 | kfree(vmidi); | 272 | kfree(vmidi); |
262 | return 0; | 273 | return 0; |
diff --git a/sound/core/timer.c b/sound/core/timer.c index af1f68f7e315..9b513a05765a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -451,6 +451,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) | |||
451 | unsigned long flags; | 451 | unsigned long flags; |
452 | 452 | ||
453 | spin_lock_irqsave(&slave_active_lock, flags); | 453 | spin_lock_irqsave(&slave_active_lock, flags); |
454 | if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { | ||
455 | spin_unlock_irqrestore(&slave_active_lock, flags); | ||
456 | return -EBUSY; | ||
457 | } | ||
454 | timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; | 458 | timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; |
455 | if (timeri->master && timeri->timer) { | 459 | if (timeri->master && timeri->timer) { |
456 | spin_lock(&timeri->timer->lock); | 460 | spin_lock(&timeri->timer->lock); |
@@ -475,7 +479,8 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) | |||
475 | return -EINVAL; | 479 | return -EINVAL; |
476 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { | 480 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { |
477 | result = snd_timer_start_slave(timeri); | 481 | result = snd_timer_start_slave(timeri); |
478 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | 482 | if (result >= 0) |
483 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | ||
479 | return result; | 484 | return result; |
480 | } | 485 | } |
481 | timer = timeri->timer; | 486 | timer = timeri->timer; |
@@ -484,11 +489,18 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) | |||
484 | if (timer->card && timer->card->shutdown) | 489 | if (timer->card && timer->card->shutdown) |
485 | return -ENODEV; | 490 | return -ENODEV; |
486 | spin_lock_irqsave(&timer->lock, flags); | 491 | spin_lock_irqsave(&timer->lock, flags); |
492 | if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | | ||
493 | SNDRV_TIMER_IFLG_START)) { | ||
494 | result = -EBUSY; | ||
495 | goto unlock; | ||
496 | } | ||
487 | timeri->ticks = timeri->cticks = ticks; | 497 | timeri->ticks = timeri->cticks = ticks; |
488 | timeri->pticks = 0; | 498 | timeri->pticks = 0; |
489 | result = snd_timer_start1(timer, timeri, ticks); | 499 | result = snd_timer_start1(timer, timeri, ticks); |
500 | unlock: | ||
490 | spin_unlock_irqrestore(&timer->lock, flags); | 501 | spin_unlock_irqrestore(&timer->lock, flags); |
491 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | 502 | if (result >= 0) |
503 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | ||
492 | return result; | 504 | return result; |
493 | } | 505 | } |
494 | 506 | ||
@@ -502,6 +514,10 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) | |||
502 | 514 | ||
503 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { | 515 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { |
504 | spin_lock_irqsave(&slave_active_lock, flags); | 516 | spin_lock_irqsave(&slave_active_lock, flags); |
517 | if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { | ||
518 | spin_unlock_irqrestore(&slave_active_lock, flags); | ||
519 | return -EBUSY; | ||
520 | } | ||
505 | timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | 521 | timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; |
506 | list_del_init(&timeri->ack_list); | 522 | list_del_init(&timeri->ack_list); |
507 | list_del_init(&timeri->active_list); | 523 | list_del_init(&timeri->active_list); |
@@ -512,6 +528,11 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) | |||
512 | if (!timer) | 528 | if (!timer) |
513 | return -EINVAL; | 529 | return -EINVAL; |
514 | spin_lock_irqsave(&timer->lock, flags); | 530 | spin_lock_irqsave(&timer->lock, flags); |
531 | if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | | ||
532 | SNDRV_TIMER_IFLG_START))) { | ||
533 | spin_unlock_irqrestore(&timer->lock, flags); | ||
534 | return -EBUSY; | ||
535 | } | ||
515 | list_del_init(&timeri->ack_list); | 536 | list_del_init(&timeri->ack_list); |
516 | list_del_init(&timeri->active_list); | 537 | list_del_init(&timeri->active_list); |
517 | if (timer->card && timer->card->shutdown) { | 538 | if (timer->card && timer->card->shutdown) { |
@@ -581,10 +602,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri) | |||
581 | if (timer->card && timer->card->shutdown) | 602 | if (timer->card && timer->card->shutdown) |
582 | return -ENODEV; | 603 | return -ENODEV; |
583 | spin_lock_irqsave(&timer->lock, flags); | 604 | spin_lock_irqsave(&timer->lock, flags); |
605 | if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { | ||
606 | result = -EBUSY; | ||
607 | goto unlock; | ||
608 | } | ||
584 | if (!timeri->cticks) | 609 | if (!timeri->cticks) |
585 | timeri->cticks = 1; | 610 | timeri->cticks = 1; |
586 | timeri->pticks = 0; | 611 | timeri->pticks = 0; |
587 | result = snd_timer_start1(timer, timeri, timer->sticks); | 612 | result = snd_timer_start1(timer, timeri, timer->sticks); |
613 | unlock: | ||
588 | spin_unlock_irqrestore(&timer->lock, flags); | 614 | spin_unlock_irqrestore(&timer->lock, flags); |
589 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); | 615 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); |
590 | return result; | 616 | return result; |
@@ -718,8 +744,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
718 | ti->cticks = ti->ticks; | 744 | ti->cticks = ti->ticks; |
719 | } else { | 745 | } else { |
720 | ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | 746 | ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; |
721 | if (--timer->running) | 747 | --timer->running; |
722 | list_del_init(&ti->active_list); | 748 | list_del_init(&ti->active_list); |
723 | } | 749 | } |
724 | if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || | 750 | if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || |
725 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) | 751 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) |
@@ -1032,11 +1058,21 @@ static int snd_timer_s_stop(struct snd_timer * timer) | |||
1032 | return 0; | 1058 | return 0; |
1033 | } | 1059 | } |
1034 | 1060 | ||
1061 | static int snd_timer_s_close(struct snd_timer *timer) | ||
1062 | { | ||
1063 | struct snd_timer_system_private *priv; | ||
1064 | |||
1065 | priv = (struct snd_timer_system_private *)timer->private_data; | ||
1066 | del_timer_sync(&priv->tlist); | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1035 | static struct snd_timer_hardware snd_timer_system = | 1070 | static struct snd_timer_hardware snd_timer_system = |
1036 | { | 1071 | { |
1037 | .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, | 1072 | .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, |
1038 | .resolution = 1000000000L / HZ, | 1073 | .resolution = 1000000000L / HZ, |
1039 | .ticks = 10000000L, | 1074 | .ticks = 10000000L, |
1075 | .close = snd_timer_s_close, | ||
1040 | .start = snd_timer_s_start, | 1076 | .start = snd_timer_s_start, |
1041 | .stop = snd_timer_s_stop | 1077 | .stop = snd_timer_s_stop |
1042 | }; | 1078 | }; |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 28e2f8b42f5e..891453451543 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -1141,6 +1141,14 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) | |||
1141 | emu->emu1010.firmware_thread = | 1141 | emu->emu1010.firmware_thread = |
1142 | kthread_create(emu1010_firmware_thread, emu, | 1142 | kthread_create(emu1010_firmware_thread, emu, |
1143 | "emu1010_firmware"); | 1143 | "emu1010_firmware"); |
1144 | if (IS_ERR(emu->emu1010.firmware_thread)) { | ||
1145 | err = PTR_ERR(emu->emu1010.firmware_thread); | ||
1146 | emu->emu1010.firmware_thread = NULL; | ||
1147 | dev_info(emu->card->dev, | ||
1148 | "emu1010: Creating thread failed\n"); | ||
1149 | return err; | ||
1150 | } | ||
1151 | |||
1144 | wake_up_process(emu->emu1010.firmware_thread); | 1152 | wake_up_process(emu->emu1010.firmware_thread); |
1145 | } | 1153 | } |
1146 | 1154 | ||
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a12ae8ac0914..c1c855a6c0af 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -614,6 +614,7 @@ enum { | |||
614 | CS4208_MAC_AUTO, | 614 | CS4208_MAC_AUTO, |
615 | CS4208_MBA6, | 615 | CS4208_MBA6, |
616 | CS4208_MBP11, | 616 | CS4208_MBP11, |
617 | CS4208_MACMINI, | ||
617 | CS4208_GPIO0, | 618 | CS4208_GPIO0, |
618 | }; | 619 | }; |
619 | 620 | ||
@@ -621,6 +622,7 @@ static const struct hda_model_fixup cs4208_models[] = { | |||
621 | { .id = CS4208_GPIO0, .name = "gpio0" }, | 622 | { .id = CS4208_GPIO0, .name = "gpio0" }, |
622 | { .id = CS4208_MBA6, .name = "mba6" }, | 623 | { .id = CS4208_MBA6, .name = "mba6" }, |
623 | { .id = CS4208_MBP11, .name = "mbp11" }, | 624 | { .id = CS4208_MBP11, .name = "mbp11" }, |
625 | { .id = CS4208_MACMINI, .name = "macmini" }, | ||
624 | {} | 626 | {} |
625 | }; | 627 | }; |
626 | 628 | ||
@@ -632,6 +634,7 @@ static const struct snd_pci_quirk cs4208_fixup_tbl[] = { | |||
632 | /* codec SSID matching */ | 634 | /* codec SSID matching */ |
633 | static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { | 635 | static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { |
634 | SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), | 636 | SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), |
637 | SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), | ||
635 | SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), | 638 | SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), |
636 | SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6), | 639 | SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6), |
637 | SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11), | 640 | SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11), |
@@ -666,6 +669,24 @@ static void cs4208_fixup_mac(struct hda_codec *codec, | |||
666 | snd_hda_apply_fixup(codec, action); | 669 | snd_hda_apply_fixup(codec, action); |
667 | } | 670 | } |
668 | 671 | ||
672 | /* MacMini 7,1 has the inverted jack detection */ | ||
673 | static void cs4208_fixup_macmini(struct hda_codec *codec, | ||
674 | const struct hda_fixup *fix, int action) | ||
675 | { | ||
676 | static const struct hda_pintbl pincfgs[] = { | ||
677 | { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */ | ||
678 | { 0x21, 0x004be140 }, /* SPDIF: disable detect */ | ||
679 | { } | ||
680 | }; | ||
681 | |||
682 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
683 | /* HP pin (0x10) has an inverted detection */ | ||
684 | codec->inv_jack_detect = 1; | ||
685 | /* disable the bogus Mic and SPDIF jack detections */ | ||
686 | snd_hda_apply_pincfgs(codec, pincfgs); | ||
687 | } | ||
688 | } | ||
689 | |||
669 | static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol, | 690 | static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol, |
670 | struct snd_ctl_elem_value *ucontrol) | 691 | struct snd_ctl_elem_value *ucontrol) |
671 | { | 692 | { |
@@ -709,6 +730,12 @@ static const struct hda_fixup cs4208_fixups[] = { | |||
709 | .chained = true, | 730 | .chained = true, |
710 | .chain_id = CS4208_GPIO0, | 731 | .chain_id = CS4208_GPIO0, |
711 | }, | 732 | }, |
733 | [CS4208_MACMINI] = { | ||
734 | .type = HDA_FIXUP_FUNC, | ||
735 | .v.func = cs4208_fixup_macmini, | ||
736 | .chained = true, | ||
737 | .chain_id = CS4208_GPIO0, | ||
738 | }, | ||
712 | [CS4208_GPIO0] = { | 739 | [CS4208_GPIO0] = { |
713 | .type = HDA_FIXUP_FUNC, | 740 | .type = HDA_FIXUP_FUNC, |
714 | .v.func = cs4208_fixup_gpio0, | 741 | .v.func = cs4208_fixup_gpio0, |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 33753244f48f..21992fb7035d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -327,6 +327,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) | |||
327 | case 0x10ec0292: | 327 | case 0x10ec0292: |
328 | alc_update_coef_idx(codec, 0x4, 1<<15, 0); | 328 | alc_update_coef_idx(codec, 0x4, 1<<15, 0); |
329 | break; | 329 | break; |
330 | case 0x10ec0225: | ||
330 | case 0x10ec0233: | 331 | case 0x10ec0233: |
331 | case 0x10ec0255: | 332 | case 0x10ec0255: |
332 | case 0x10ec0256: | 333 | case 0x10ec0256: |
@@ -900,6 +901,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { | |||
900 | { 0x10ec0899, 0x1028, 0, "ALC3861" }, | 901 | { 0x10ec0899, 0x1028, 0, "ALC3861" }, |
901 | { 0x10ec0298, 0x1028, 0, "ALC3266" }, | 902 | { 0x10ec0298, 0x1028, 0, "ALC3266" }, |
902 | { 0x10ec0256, 0x1028, 0, "ALC3246" }, | 903 | { 0x10ec0256, 0x1028, 0, "ALC3246" }, |
904 | { 0x10ec0225, 0x1028, 0, "ALC3253" }, | ||
903 | { 0x10ec0670, 0x1025, 0, "ALC669X" }, | 905 | { 0x10ec0670, 0x1025, 0, "ALC669X" }, |
904 | { 0x10ec0676, 0x1025, 0, "ALC679X" }, | 906 | { 0x10ec0676, 0x1025, 0, "ALC679X" }, |
905 | { 0x10ec0282, 0x1043, 0, "ALC3229" }, | 907 | { 0x10ec0282, 0x1043, 0, "ALC3229" }, |
@@ -2651,6 +2653,7 @@ enum { | |||
2651 | ALC269_TYPE_ALC298, | 2653 | ALC269_TYPE_ALC298, |
2652 | ALC269_TYPE_ALC255, | 2654 | ALC269_TYPE_ALC255, |
2653 | ALC269_TYPE_ALC256, | 2655 | ALC269_TYPE_ALC256, |
2656 | ALC269_TYPE_ALC225, | ||
2654 | }; | 2657 | }; |
2655 | 2658 | ||
2656 | /* | 2659 | /* |
@@ -2680,6 +2683,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
2680 | case ALC269_TYPE_ALC298: | 2683 | case ALC269_TYPE_ALC298: |
2681 | case ALC269_TYPE_ALC255: | 2684 | case ALC269_TYPE_ALC255: |
2682 | case ALC269_TYPE_ALC256: | 2685 | case ALC269_TYPE_ALC256: |
2686 | case ALC269_TYPE_ALC225: | ||
2683 | ssids = alc269_ssids; | 2687 | ssids = alc269_ssids; |
2684 | break; | 2688 | break; |
2685 | default: | 2689 | default: |
@@ -3658,6 +3662,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) | |||
3658 | WRITE_COEF(0xb7, 0x802b), | 3662 | WRITE_COEF(0xb7, 0x802b), |
3659 | {} | 3663 | {} |
3660 | }; | 3664 | }; |
3665 | static struct coef_fw coef0225[] = { | ||
3666 | UPDATE_COEF(0x4a, 1<<8, 0), | ||
3667 | UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), | ||
3668 | UPDATE_COEF(0x63, 3<<14, 3<<14), | ||
3669 | UPDATE_COEF(0x4a, 3<<4, 2<<4), | ||
3670 | UPDATE_COEF(0x4a, 3<<10, 3<<10), | ||
3671 | UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), | ||
3672 | UPDATE_COEF(0x4a, 3<<10, 0), | ||
3673 | {} | ||
3674 | }; | ||
3661 | 3675 | ||
3662 | switch (codec->core.vendor_id) { | 3676 | switch (codec->core.vendor_id) { |
3663 | case 0x10ec0255: | 3677 | case 0x10ec0255: |
@@ -3682,6 +3696,9 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) | |||
3682 | case 0x10ec0668: | 3696 | case 0x10ec0668: |
3683 | alc_process_coef_fw(codec, coef0668); | 3697 | alc_process_coef_fw(codec, coef0668); |
3684 | break; | 3698 | break; |
3699 | case 0x10ec0225: | ||
3700 | alc_process_coef_fw(codec, coef0225); | ||
3701 | break; | ||
3685 | } | 3702 | } |
3686 | codec_dbg(codec, "Headset jack set to unplugged mode.\n"); | 3703 | codec_dbg(codec, "Headset jack set to unplugged mode.\n"); |
3687 | } | 3704 | } |
@@ -3727,6 +3744,13 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, | |||
3727 | UPDATE_COEF(0xc3, 0, 1<<12), | 3744 | UPDATE_COEF(0xc3, 0, 1<<12), |
3728 | {} | 3745 | {} |
3729 | }; | 3746 | }; |
3747 | static struct coef_fw coef0225[] = { | ||
3748 | UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), | ||
3749 | UPDATE_COEF(0x4a, 3<<4, 2<<4), | ||
3750 | UPDATE_COEF(0x63, 3<<14, 0), | ||
3751 | {} | ||
3752 | }; | ||
3753 | |||
3730 | 3754 | ||
3731 | switch (codec->core.vendor_id) { | 3755 | switch (codec->core.vendor_id) { |
3732 | case 0x10ec0255: | 3756 | case 0x10ec0255: |
@@ -3772,6 +3796,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, | |||
3772 | alc_process_coef_fw(codec, coef0688); | 3796 | alc_process_coef_fw(codec, coef0688); |
3773 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | 3797 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); |
3774 | break; | 3798 | break; |
3799 | case 0x10ec0225: | ||
3800 | alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); | ||
3801 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); | ||
3802 | alc_process_coef_fw(codec, coef0225); | ||
3803 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | ||
3804 | break; | ||
3775 | } | 3805 | } |
3776 | codec_dbg(codec, "Headset jack set to mic-in mode.\n"); | 3806 | codec_dbg(codec, "Headset jack set to mic-in mode.\n"); |
3777 | } | 3807 | } |
@@ -3884,6 +3914,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) | |||
3884 | WRITE_COEF(0xc3, 0x0000), | 3914 | WRITE_COEF(0xc3, 0x0000), |
3885 | {} | 3915 | {} |
3886 | }; | 3916 | }; |
3917 | static struct coef_fw coef0225[] = { | ||
3918 | UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), | ||
3919 | UPDATE_COEF(0x49, 1<<8, 1<<8), | ||
3920 | UPDATE_COEF(0x4a, 7<<6, 7<<6), | ||
3921 | UPDATE_COEF(0x4a, 3<<4, 3<<4), | ||
3922 | {} | ||
3923 | }; | ||
3887 | 3924 | ||
3888 | switch (codec->core.vendor_id) { | 3925 | switch (codec->core.vendor_id) { |
3889 | case 0x10ec0255: | 3926 | case 0x10ec0255: |
@@ -3912,6 +3949,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) | |||
3912 | case 0x10ec0668: | 3949 | case 0x10ec0668: |
3913 | alc_process_coef_fw(codec, coef0688); | 3950 | alc_process_coef_fw(codec, coef0688); |
3914 | break; | 3951 | break; |
3952 | case 0x10ec0225: | ||
3953 | alc_process_coef_fw(codec, coef0225); | ||
3954 | break; | ||
3915 | } | 3955 | } |
3916 | codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); | 3956 | codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); |
3917 | } | 3957 | } |
@@ -3955,6 +3995,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) | |||
3955 | WRITE_COEF(0xc3, 0x0000), | 3995 | WRITE_COEF(0xc3, 0x0000), |
3956 | {} | 3996 | {} |
3957 | }; | 3997 | }; |
3998 | static struct coef_fw coef0225[] = { | ||
3999 | UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10), | ||
4000 | UPDATE_COEF(0x49, 1<<8, 1<<8), | ||
4001 | UPDATE_COEF(0x4a, 7<<6, 7<<6), | ||
4002 | UPDATE_COEF(0x4a, 3<<4, 3<<4), | ||
4003 | {} | ||
4004 | }; | ||
3958 | 4005 | ||
3959 | switch (codec->core.vendor_id) { | 4006 | switch (codec->core.vendor_id) { |
3960 | case 0x10ec0255: | 4007 | case 0x10ec0255: |
@@ -3983,6 +4030,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) | |||
3983 | case 0x10ec0668: | 4030 | case 0x10ec0668: |
3984 | alc_process_coef_fw(codec, coef0688); | 4031 | alc_process_coef_fw(codec, coef0688); |
3985 | break; | 4032 | break; |
4033 | case 0x10ec0225: | ||
4034 | alc_process_coef_fw(codec, coef0225); | ||
4035 | break; | ||
3986 | } | 4036 | } |
3987 | codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); | 4037 | codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); |
3988 | } | 4038 | } |
@@ -4014,6 +4064,11 @@ static void alc_determine_headset_type(struct hda_codec *codec) | |||
4014 | WRITE_COEF(0xc3, 0x0c00), | 4064 | WRITE_COEF(0xc3, 0x0c00), |
4015 | {} | 4065 | {} |
4016 | }; | 4066 | }; |
4067 | static struct coef_fw coef0225[] = { | ||
4068 | UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), | ||
4069 | UPDATE_COEF(0x49, 1<<8, 1<<8), | ||
4070 | {} | ||
4071 | }; | ||
4017 | 4072 | ||
4018 | switch (codec->core.vendor_id) { | 4073 | switch (codec->core.vendor_id) { |
4019 | case 0x10ec0255: | 4074 | case 0x10ec0255: |
@@ -4058,6 +4113,12 @@ static void alc_determine_headset_type(struct hda_codec *codec) | |||
4058 | val = alc_read_coef_idx(codec, 0xbe); | 4113 | val = alc_read_coef_idx(codec, 0xbe); |
4059 | is_ctia = (val & 0x1c02) == 0x1c02; | 4114 | is_ctia = (val & 0x1c02) == 0x1c02; |
4060 | break; | 4115 | break; |
4116 | case 0x10ec0225: | ||
4117 | alc_process_coef_fw(codec, coef0225); | ||
4118 | msleep(800); | ||
4119 | val = alc_read_coef_idx(codec, 0x46); | ||
4120 | is_ctia = (val & 0x00f0) == 0x00f0; | ||
4121 | break; | ||
4061 | } | 4122 | } |
4062 | 4123 | ||
4063 | codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", | 4124 | codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", |
@@ -5560,6 +5621,9 @@ static const struct hda_model_fixup alc269_fixup_models[] = { | |||
5560 | {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, | 5621 | {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, |
5561 | {} | 5622 | {} |
5562 | }; | 5623 | }; |
5624 | #define ALC225_STANDARD_PINS \ | ||
5625 | {0x12, 0xb7a60130}, \ | ||
5626 | {0x21, 0x04211020} | ||
5563 | 5627 | ||
5564 | #define ALC256_STANDARD_PINS \ | 5628 | #define ALC256_STANDARD_PINS \ |
5565 | {0x12, 0x90a60140}, \ | 5629 | {0x12, 0x90a60140}, \ |
@@ -5581,6 +5645,12 @@ static const struct hda_model_fixup alc269_fixup_models[] = { | |||
5581 | {0x21, 0x03211020} | 5645 | {0x21, 0x03211020} |
5582 | 5646 | ||
5583 | static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | 5647 | static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { |
5648 | SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5649 | ALC225_STANDARD_PINS, | ||
5650 | {0x14, 0x901701a0}), | ||
5651 | SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5652 | ALC225_STANDARD_PINS, | ||
5653 | {0x14, 0x901701b0}), | ||
5584 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, | 5654 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, |
5585 | {0x14, 0x90170110}, | 5655 | {0x14, 0x90170110}, |
5586 | {0x21, 0x02211020}), | 5656 | {0x21, 0x02211020}), |
@@ -5906,6 +5976,9 @@ static int patch_alc269(struct hda_codec *codec) | |||
5906 | spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ | 5976 | spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ |
5907 | alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ | 5977 | alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ |
5908 | break; | 5978 | break; |
5979 | case 0x10ec0225: | ||
5980 | spec->codec_variant = ALC269_TYPE_ALC225; | ||
5981 | break; | ||
5909 | } | 5982 | } |
5910 | 5983 | ||
5911 | if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) { | 5984 | if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) { |
@@ -6796,6 +6869,7 @@ static int patch_alc680(struct hda_codec *codec) | |||
6796 | */ | 6869 | */ |
6797 | static const struct hda_device_id snd_hda_id_realtek[] = { | 6870 | static const struct hda_device_id snd_hda_id_realtek[] = { |
6798 | HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), | 6871 | HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), |
6872 | HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269), | ||
6799 | HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), | 6873 | HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), |
6800 | HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), | 6874 | HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), |
6801 | HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), | 6875 | HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a75d9ce7d77a..4f6ce1cac8e2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -1121,6 +1121,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) | |||
1121 | switch (chip->usb_id) { | 1121 | switch (chip->usb_id) { |
1122 | case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ | 1122 | case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ |
1123 | case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ | 1123 | case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ |
1124 | case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ | ||
1124 | case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ | 1125 | case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ |
1125 | case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ | 1126 | case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ |
1126 | case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ | 1127 | case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ |
@@ -1281,7 +1282,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, | |||
1281 | case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ | 1282 | case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ |
1282 | case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ | 1283 | case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ |
1283 | case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ | 1284 | case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ |
1284 | case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/ | 1285 | case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ |
1285 | if (fp->altsetting == 2) | 1286 | if (fp->altsetting == 2) |
1286 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; | 1287 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1287 | break; | 1288 | break; |
@@ -1290,6 +1291,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, | |||
1290 | case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ | 1291 | case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ |
1291 | case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ | 1292 | case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ |
1292 | case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ | 1293 | case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ |
1294 | case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ | ||
1293 | if (fp->altsetting == 3) | 1295 | if (fp->altsetting == 3) |
1294 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; | 1296 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1295 | break; | 1297 | break; |