Commit 8fdff6a3 authored by Daniel Mack's avatar Daniel Mack Committed by Takashi Iwai
Browse files

ALSA: snd-usb: implement new endpoint streaming model

This patch adds a new generic streaming logic for audio over USB.

It defines a model (snd_usb_endpoint) that handles everything that
is related to an USB endpoint and its streaming. There are functions to
activate and deactivate an endpoint (which call usb_set_interface()),
and to start and stop its URBs. It also has function pointers to be
called when data was received or is about to be sent, and pointer to
a sync slave (another snd_usb_endpoint) that is informed when data has
been received.

A snd_usb_endpoint knows about its state and implements a refcounting,
so only the first user will actually start the URBs and only the last
one to stop it will tear them down again.

With this sort of abstraction, the actual streaming is decoupled from
the pcm handling, which makes the "implicit feedback" mechanisms easy to

In order to split changes properly, this patch only adds the new
implementation but leaves the old one around, so the the driver doesn't
change its behaviour. The switch to actually use the new code is
submitted separately.

Signed-off-by: default avatarDaniel Mack <>
Signed-off-by: default avatarTakashi Iwai <>
parent 596580d0
......@@ -30,13 +30,17 @@ struct audioformat {
struct snd_usb_substream;
struct snd_usb_endpoint;
struct snd_urb_ctx {
struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */
struct snd_usb_substream *subs;
struct snd_usb_endpoint *ep;
int index; /* index for urb array */
int packets; /* number of packets per urb */
int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
struct list_head ready_list;
struct snd_urb_ops {
......@@ -46,6 +50,60 @@ struct snd_urb_ops {
int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
struct snd_usb_endpoint {
struct snd_usb_audio *chip;
int use_count;
int ep_num; /* the referenced endpoint number */
int type; /* SND_USB_ENDPOINT_TYPE_* */
unsigned long flags;
void (*prepare_data_urb) (struct snd_usb_substream *subs,
struct urb *urb);
void (*retire_data_urb) (struct snd_usb_substream *subs,
struct urb *urb);
struct snd_usb_substream *data_subs;
struct snd_usb_endpoint *sync_master;
struct snd_usb_endpoint *sync_slave;
struct snd_urb_ctx urb[MAX_URBS];
struct snd_usb_packet_info {
uint32_t packet_size[MAX_PACKS_HS];
int packets;
} next_packet[MAX_URBS];
int next_packet_read_pos, next_packet_write_pos;
struct list_head ready_playback_urbs;
unsigned int nurbs; /* # urbs */
unsigned long active_mask; /* bitmask of active urbs */
unsigned long unlink_mask; /* bitmask of unlinked urbs */
char *syncbuf; /* sync buffer for all sync URBs */
dma_addr_t sync_dma; /* DMA address of syncbuf */
unsigned int pipe; /* the data i/o pipe */
unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
int freqshift; /* how much to shift the feedback value to get Q16.16 */
unsigned int freqmax; /* maximum sampling rate, used for buffer management */
unsigned int phase; /* phase accumulator */
unsigned int maxpacksize; /* max packet size in bytes */
unsigned int maxframesize; /* max packet size in frames */
unsigned int curpacksize; /* current packet size in bytes (for capture) */
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int syncmaxsize; /* sync endpoint packet size */
unsigned int fill_max:1; /* fill max packet size always */
unsigned int datainterval; /* log_2 of data packet interval */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
unsigned char silence_value;
unsigned int stride;
int iface, alt_idx;
spinlock_t lock;
struct list_head list;
struct snd_usb_substream {
struct snd_usb_stream *stream;
struct usb_device *dev;
This diff is collapsed.
......@@ -18,4 +18,30 @@ int snd_usb_substream_prepare(struct snd_usb_substream *subs,
int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
int ep_num, int direction, int type);
int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
struct snd_pcm_hw_params *hw_params,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep);
int snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
int force, int can_sleep, int wait);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_free(struct list_head *head);
int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
struct snd_usb_endpoint *sender,
const struct urb *urb);
#endif /* __USBAUDIO_ENDPOINT_H */
......@@ -47,6 +47,7 @@ struct snd_usb_audio {
int num_suspended_intf;
struct list_head pcm_list; /* list of pcm streams */
struct list_head ep_list; /* list of audio-related endpoints */
int pcm_devs;
struct list_head midi_list; /* list of midi interfaces */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment