Skip to content

Commit bf6313a

Browse files
committed
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management for achieving more robust and clean code. The goals of this patch are: - More clear endpoint resource changes - The interface altsetting control in a single place Below are brief description of the whole changes. First off, most of the endpoint operations are moved into endpoint.c, so that the snd_usb_endpoint object is only referred in other places. The endpoint object is acquired and released via the new functions snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called at PCM hw_params and hw_free callbacks, respectively. Those are ref-counted and EPs can manage the multiple opens. The open callback receives the audioformat and hw_params arguments, and those are used for initializing the EP parameters; especially the endpoint, interface and altset numbers are read from there, as well as the PCM parameters like the format, rate and channels. Those are stored in snd_usb_endpoint object. If it's the secondary open, the function checks whether the given parameters are compatible with the already opened EP setup, too. The coupling with a sync EP (including an implicit feedback sync) is done by the sole snd_usb_endpoint_set_sync() call. The configuration of each endpoint is done in a single shot via snd_usb_endpoint_configure() call. This is the place where most of PCM configurations are done. A few flags and special handling in the snd_usb_substream are dropped along with this change. A significant difference wrt the configuration from the previous code is the order of USB host interface setups. Now the interface is always disabled at beginning and (re-)enabled at the last step of snd_usb_endpoint_configure(), in order to be compliant with the standard UAC2/3. For UAC1, the interface is set before the parameter setups since there seem devices that require it (e.g. Yamaha THR10), just like how it was done in the previous driver code. The start/stop are almost same as before, also single-shots. The URB callbacks need to be set via snd_usb_endpoint_set_callback() like the previous code at the trigger phase, too. Finally, the flag for the re-setup is set at the device suspend through the full EP list, instead of PCM trigger. This catches the overlooked cases where the PCM hasn't been running yet but the device needs the full setup after resume. Tested-by: Keith Milner <[email protected]> Tested-by: Dylan Robinson <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 61cc2d7 commit bf6313a

File tree

6 files changed

+616
-734
lines changed

6 files changed

+616
-734
lines changed

sound/usb/card.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -980,18 +980,18 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
980980
{
981981
struct snd_usb_audio *chip = usb_get_intfdata(intf);
982982
struct snd_usb_stream *as;
983+
struct snd_usb_endpoint *ep;
983984
struct usb_mixer_interface *mixer;
984985
struct list_head *p;
985986

986987
if (chip == (void *)-1L)
987988
return 0;
988989

989990
if (!chip->num_suspended_intf++) {
990-
list_for_each_entry(as, &chip->pcm_list, list) {
991+
list_for_each_entry(as, &chip->pcm_list, list)
991992
snd_usb_pcm_suspend(as);
992-
as->substream[0].need_setup_ep =
993-
as->substream[1].need_setup_ep = true;
994-
}
993+
list_for_each_entry(ep, &chip->ep_list, list)
994+
snd_usb_endpoint_suspend(ep);
995995
list_for_each(p, &chip->midi_list)
996996
snd_usbmidi_suspend(p);
997997
list_for_each_entry(mixer, &chip->mixer_list, list)

sound/usb/card.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct audioformat {
2626
unsigned char sync_ep; /* sync endpoint number */
2727
unsigned char sync_iface; /* sync EP interface */
2828
unsigned char sync_altsetting; /* sync EP alternate setting */
29+
unsigned char sync_ep_idx; /* sync EP array index */
2930
unsigned char datainterval; /* log_2 of data packet interval */
3031
unsigned char protocol; /* UAC_VERSION_1/2/3 */
3132
unsigned int maxpacksize; /* max. packet size */
@@ -58,6 +59,7 @@ struct snd_urb_ctx {
5859
struct snd_usb_endpoint {
5960
struct snd_usb_audio *chip;
6061

62+
int opened; /* open refcount; protect with chip->mutex */
6163
int use_count;
6264
int ep_num; /* the referenced endpoint number */
6365
int type; /* SND_USB_ENDPOINT_TYPE_* */
@@ -110,14 +112,18 @@ struct snd_usb_endpoint {
110112
unsigned char silence_value;
111113
unsigned int stride;
112114
int iface, altsetting;
115+
unsigned char ep_idx; /* endpoint array index */
113116
int skip_packets; /* quirks for devices to ignore the first n packets
114117
in a stream */
115-
bool is_implicit_feedback; /* This endpoint is used as implicit feedback */
118+
bool implicit_fb_sync; /* syncs with implicit feedback */
119+
bool need_setup; /* (re-)need for configure? */
116120

117121
/* for hw constraints */
122+
struct audioformat *cur_audiofmt;
118123
unsigned int cur_rate;
119124
snd_pcm_format_t cur_format;
120125
unsigned int cur_channels;
126+
unsigned int cur_frame_bytes;
121127
unsigned int cur_period_frames;
122128
unsigned int cur_period_bytes;
123129
unsigned int cur_buffer_periods;
@@ -152,7 +158,6 @@ struct snd_usb_substream {
152158
unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */
153159

154160
unsigned int running: 1; /* running status */
155-
unsigned int fixed_hw:1; /* fixed hw constraints due to sync EP */
156161

157162
unsigned int hwptr_done; /* processed byte position in the buffer */
158163
unsigned int transfer_done; /* processed frames since last period update */
@@ -163,8 +168,6 @@ struct snd_usb_substream {
163168
struct snd_usb_endpoint *data_endpoint;
164169
struct snd_usb_endpoint *sync_endpoint;
165170
unsigned long flags;
166-
bool need_setup_ep; /* (re)configure EP at prepare? */
167-
bool need_setup_fmt; /* (re)configure fmt after resume? */
168171
unsigned int speed; /* USB_SPEED_XXX */
169172

170173
u64 formats; /* format bitmasks (all or'ed) */

sound/usb/clock.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,6 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
613613
static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
614614
struct audioformat *fmt, int rate)
615615
{
616-
struct usb_device *dev = chip->dev;
617616
int cur_rate, prev_rate;
618617
int clock;
619618

@@ -656,15 +655,6 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
656655
return -ENXIO;
657656
}
658657

659-
/* Some devices doesn't respond to sample rate changes while the
660-
* interface is active. */
661-
if (rate != prev_rate) {
662-
usb_set_interface(dev, fmt->iface, 0);
663-
snd_usb_set_interface_quirk(chip);
664-
usb_set_interface(dev, fmt->iface, fmt->altsetting);
665-
snd_usb_set_interface_quirk(chip);
666-
}
667-
668658
validation:
669659
/* validate clock after rate change */
670660
if (!uac_clock_source_is_valid(chip, fmt, clock))
@@ -675,6 +665,9 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
675665
int snd_usb_init_sample_rate(struct snd_usb_audio *chip,
676666
struct audioformat *fmt, int rate)
677667
{
668+
usb_audio_dbg(chip, "%d:%d Set sample rate %d, clock %d\n",
669+
fmt->iface, fmt->altsetting, rate, fmt->clock);
670+
678671
switch (fmt->protocol) {
679672
case UAC_VERSION_1:
680673
default:

0 commit comments

Comments
 (0)