.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | | - * This program is free software; you can redistribute it and/or modify |
---|
3 | | - * it under the terms of the GNU General Public License as published by |
---|
4 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
5 | | - * (at your option) any later version. |
---|
6 | | - * |
---|
7 | | - * This program is distributed in the hope that it will be useful, |
---|
8 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
10 | | - * GNU General Public License for more details. |
---|
11 | | - * |
---|
12 | | - * You should have received a copy of the GNU General Public License |
---|
13 | | - * along with this program; if not, write to the Free Software |
---|
14 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
15 | 3 | */ |
---|
16 | 4 | |
---|
17 | 5 | |
---|
.. | .. |
---|
38 | 26 | #include "clock.h" |
---|
39 | 27 | #include "stream.h" |
---|
40 | 28 | #include "power.h" |
---|
| 29 | +#include "media.h" |
---|
| 30 | + |
---|
| 31 | +static void audioformat_free(struct audioformat *fp) |
---|
| 32 | +{ |
---|
| 33 | + list_del(&fp->list); /* unlink for avoiding double-free */ |
---|
| 34 | + kfree(fp->rate_table); |
---|
| 35 | + kfree(fp->chmap); |
---|
| 36 | + kfree(fp); |
---|
| 37 | +} |
---|
41 | 38 | |
---|
42 | 39 | /* |
---|
43 | 40 | * free a substream |
---|
.. | .. |
---|
48 | 45 | |
---|
49 | 46 | if (!subs->num_formats) |
---|
50 | 47 | return; /* not initialized */ |
---|
51 | | - list_for_each_entry_safe(fp, n, &subs->fmt_list, list) { |
---|
52 | | - kfree(fp->rate_table); |
---|
53 | | - kfree(fp->chmap); |
---|
54 | | - kfree(fp); |
---|
55 | | - } |
---|
| 48 | + list_for_each_entry_safe(fp, n, &subs->fmt_list, list) |
---|
| 49 | + audioformat_free(fp); |
---|
56 | 50 | kfree(subs->rate_list.list); |
---|
57 | 51 | kfree(subs->str_pd); |
---|
| 52 | + snd_media_stream_delete(subs); |
---|
58 | 53 | } |
---|
59 | 54 | |
---|
60 | 55 | |
---|
.. | .. |
---|
73 | 68 | { |
---|
74 | 69 | struct snd_usb_stream *stream = pcm->private_data; |
---|
75 | 70 | struct snd_usb_audio *chip; |
---|
76 | | - |
---|
77 | 71 | if (stream) { |
---|
78 | 72 | mutex_lock(&stream->chip->dev_lock); |
---|
79 | 73 | chip = stream->chip; |
---|
.. | .. |
---|
104 | 98 | subs->tx_length_quirk = as->chip->tx_length_quirk; |
---|
105 | 99 | subs->speed = snd_usb_get_speed(subs->dev); |
---|
106 | 100 | subs->pkt_offset_adj = 0; |
---|
| 101 | + subs->stream_offset_adj = 0; |
---|
107 | 102 | |
---|
108 | 103 | snd_usb_set_pcm_ops(as->pcm, stream); |
---|
109 | 104 | |
---|
.. | .. |
---|
505 | 500 | return 0; |
---|
506 | 501 | } |
---|
507 | 502 | } |
---|
| 503 | + |
---|
| 504 | + if (chip->card->registered) |
---|
| 505 | + chip->need_delayed_register = true; |
---|
| 506 | + |
---|
508 | 507 | /* look for an empty stream */ |
---|
509 | 508 | list_for_each_entry(as, &chip->pcm_list, list) { |
---|
510 | 509 | if (as->fmt_type != fp->fmt_type) |
---|
.. | .. |
---|
847 | 846 | /* ok, let's parse further... */ |
---|
848 | 847 | if (snd_usb_parse_audio_format(chip, fp, format, |
---|
849 | 848 | fmt, stream) < 0) { |
---|
850 | | - kfree(fp->rate_table); |
---|
851 | | - kfree(fp); |
---|
| 849 | + audioformat_free(fp); |
---|
852 | 850 | return NULL; |
---|
853 | 851 | } |
---|
854 | 852 | |
---|
.. | .. |
---|
1059 | 1057 | |
---|
1060 | 1058 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); |
---|
1061 | 1059 | if (!pd) { |
---|
1062 | | - kfree(fp->chmap); |
---|
1063 | | - kfree(fp->rate_table); |
---|
1064 | | - kfree(fp); |
---|
| 1060 | + audioformat_free(fp); |
---|
1065 | 1061 | return NULL; |
---|
1066 | 1062 | } |
---|
1067 | 1063 | pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
---|
.. | .. |
---|
1080 | 1076 | /* ok, let's parse further... */ |
---|
1081 | 1077 | if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { |
---|
1082 | 1078 | kfree(pd); |
---|
1083 | | - kfree(fp->chmap); |
---|
1084 | | - kfree(fp->rate_table); |
---|
1085 | | - kfree(fp); |
---|
| 1079 | + audioformat_free(fp); |
---|
1086 | 1080 | return NULL; |
---|
1087 | 1081 | } |
---|
1088 | 1082 | } |
---|
.. | .. |
---|
1093 | 1087 | return fp; |
---|
1094 | 1088 | } |
---|
1095 | 1089 | |
---|
1096 | | -int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) |
---|
| 1090 | +static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, |
---|
| 1091 | + int iface_no, |
---|
| 1092 | + bool *has_non_pcm, bool non_pcm) |
---|
1097 | 1093 | { |
---|
1098 | 1094 | struct usb_device *dev; |
---|
1099 | 1095 | struct usb_interface *iface; |
---|
.. | .. |
---|
1115 | 1111 | * Dallas DS4201 workaround: It presents 5 altsettings, but the last |
---|
1116 | 1112 | * one misses syncpipe, and does not produce any sound. |
---|
1117 | 1113 | */ |
---|
1118 | | - if (chip->usb_id == USB_ID(0x04fa, 0x4201)) |
---|
| 1114 | + if (chip->usb_id == USB_ID(0x04fa, 0x4201) && num >= 4) |
---|
1119 | 1115 | num = 4; |
---|
1120 | 1116 | |
---|
1121 | 1117 | for (i = 0; i < num; i++) { |
---|
.. | .. |
---|
1156 | 1152 | dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n", |
---|
1157 | 1153 | iface_no, altno, protocol); |
---|
1158 | 1154 | protocol = UAC_VERSION_1; |
---|
1159 | | - /* fall through */ |
---|
| 1155 | + fallthrough; |
---|
1160 | 1156 | case UAC_VERSION_1: |
---|
1161 | | - /* fall through */ |
---|
1162 | 1157 | case UAC_VERSION_2: { |
---|
1163 | 1158 | int bm_quirk = 0; |
---|
1164 | 1159 | |
---|
.. | .. |
---|
1194 | 1189 | else if (IS_ERR(fp)) |
---|
1195 | 1190 | return PTR_ERR(fp); |
---|
1196 | 1191 | |
---|
| 1192 | + if (fp->fmt_type != UAC_FORMAT_TYPE_I) |
---|
| 1193 | + *has_non_pcm = true; |
---|
| 1194 | + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { |
---|
| 1195 | + audioformat_free(fp); |
---|
| 1196 | + kfree(pd); |
---|
| 1197 | + fp = NULL; |
---|
| 1198 | + pd = NULL; |
---|
| 1199 | + continue; |
---|
| 1200 | + } |
---|
| 1201 | + |
---|
1197 | 1202 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); |
---|
1198 | 1203 | if (protocol == UAC_VERSION_3) |
---|
1199 | 1204 | err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); |
---|
.. | .. |
---|
1201 | 1206 | err = snd_usb_add_audio_stream(chip, stream, fp); |
---|
1202 | 1207 | |
---|
1203 | 1208 | if (err < 0) { |
---|
1204 | | - list_del(&fp->list); /* unlink for avoiding double-free */ |
---|
| 1209 | + audioformat_free(fp); |
---|
1205 | 1210 | kfree(pd); |
---|
1206 | | - kfree(fp->rate_table); |
---|
1207 | | - kfree(fp->chmap); |
---|
1208 | | - kfree(fp); |
---|
1209 | 1211 | return err; |
---|
1210 | 1212 | } |
---|
1211 | 1213 | /* try to set the interface... */ |
---|
.. | .. |
---|
1216 | 1218 | return 0; |
---|
1217 | 1219 | } |
---|
1218 | 1220 | |
---|
| 1221 | +int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) |
---|
| 1222 | +{ |
---|
| 1223 | + int err; |
---|
| 1224 | + bool has_non_pcm = false; |
---|
| 1225 | + |
---|
| 1226 | + /* parse PCM formats */ |
---|
| 1227 | + err = __snd_usb_parse_audio_interface(chip, iface_no, &has_non_pcm, false); |
---|
| 1228 | + if (err < 0) |
---|
| 1229 | + return err; |
---|
| 1230 | + |
---|
| 1231 | + if (has_non_pcm) { |
---|
| 1232 | + /* parse non-PCM formats */ |
---|
| 1233 | + err = __snd_usb_parse_audio_interface(chip, iface_no, &has_non_pcm, true); |
---|
| 1234 | + if (err < 0) |
---|
| 1235 | + return err; |
---|
| 1236 | + } |
---|
| 1237 | + |
---|
| 1238 | + return 0; |
---|
| 1239 | +} |
---|
| 1240 | + |
---|