Commit 56599bb0 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/usb-endpoint' into topic/misc

parents 7536c301 22026c1a
...@@ -131,8 +131,9 @@ static void snd_usb_stream_disconnect(struct list_head *head) ...@@ -131,8 +131,9 @@ static void snd_usb_stream_disconnect(struct list_head *head)
subs = &as->substream[idx]; subs = &as->substream[idx];
if (!subs->num_formats) if (!subs->num_formats)
continue; continue;
snd_usb_release_substream_urbs(subs, 1);
subs->interface = -1; subs->interface = -1;
subs->data_endpoint = NULL;
subs->sync_endpoint = NULL;
} }
} }
...@@ -276,6 +277,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -276,6 +277,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
static int snd_usb_audio_free(struct snd_usb_audio *chip) static int snd_usb_audio_free(struct snd_usb_audio *chip)
{ {
mutex_destroy(&chip->mutex);
kfree(chip); kfree(chip);
return 0; return 0;
} }
...@@ -336,6 +338,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, ...@@ -336,6 +338,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&chip->mutex);
mutex_init(&chip->shutdown_mutex); mutex_init(&chip->shutdown_mutex);
chip->index = idx; chip->index = idx;
chip->dev = dev; chip->dev = dev;
...@@ -348,6 +351,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, ...@@ -348,6 +351,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct)); le16_to_cpu(dev->descriptor.idProduct));
INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->ep_list);
INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list); INIT_LIST_HEAD(&chip->mixer_list);
...@@ -565,6 +569,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, ...@@ -565,6 +569,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
list_for_each(p, &chip->pcm_list) { list_for_each(p, &chip->pcm_list) {
snd_usb_stream_disconnect(p); snd_usb_stream_disconnect(p);
} }
/* release the endpoint resources */
list_for_each(p, &chip->ep_list) {
snd_usb_endpoint_free(p);
}
/* release the midi resources */ /* release the midi resources */
list_for_each(p, &chip->midi_list) { list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p); snd_usbmidi_disconnect(p);
......
...@@ -30,13 +30,17 @@ struct audioformat { ...@@ -30,13 +30,17 @@ struct audioformat {
}; };
struct snd_usb_substream; struct snd_usb_substream;
struct snd_usb_endpoint;
struct snd_urb_ctx { struct snd_urb_ctx {
struct urb *urb; struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */ unsigned int buffer_size; /* size of data buffer, if data URB */
struct snd_usb_substream *subs; struct snd_usb_substream *subs;
struct snd_usb_endpoint *ep;
int index; /* index for urb array */ int index; /* index for urb array */
int packets; /* number of packets per urb */ 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 { struct snd_urb_ops {
...@@ -46,6 +50,60 @@ 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); 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_substream {
struct snd_usb_stream *stream; struct snd_usb_stream *stream;
struct usb_device *dev; struct usb_device *dev;
...@@ -57,21 +115,6 @@ struct snd_usb_substream { ...@@ -57,21 +115,6 @@ struct snd_usb_substream {
unsigned int cur_rate; /* current rate (for hw_params callback) */ unsigned int cur_rate; /* current rate (for hw_params callback) */
unsigned int period_bytes; /* current period bytes (for hw_params callback) */ unsigned int period_bytes; /* current period bytes (for hw_params callback) */
unsigned int altset_idx; /* USB data format: index of alternate setting */ unsigned int altset_idx; /* USB data format: index of alternate setting */
unsigned int datapipe; /* the data i/o pipe */
unsigned int syncpipe; /* 1 - async out or adaptive in */
unsigned int datainterval; /* log_2 of data packet interval */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
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 txfr_quirk:1; /* allow sub-frame alignment */ unsigned int txfr_quirk:1; /* allow sub-frame alignment */
unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int fmt_type; /* USB audio format type (1-3) */
...@@ -87,6 +130,10 @@ struct snd_usb_substream { ...@@ -87,6 +130,10 @@ struct snd_usb_substream {
struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */ struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */
char *syncbuf; /* sync buffer for all sync URBs */ char *syncbuf; /* sync buffer for all sync URBs */
dma_addr_t sync_dma; /* DMA address of syncbuf */ dma_addr_t sync_dma; /* DMA address of syncbuf */
/* data and sync endpoints for this stream */
struct snd_usb_endpoint *data_endpoint;
struct snd_usb_endpoint *sync_endpoint;
unsigned long flags;
u64 formats; /* format bitmasks (all or'ed) */ u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */ unsigned int num_formats; /* number of supported audio formats (list) */
......
This diff is collapsed.
#ifndef __USBAUDIO_ENDPOINT_H #ifndef __USBAUDIO_ENDPOINT_H
#define __USBAUDIO_ENDPOINT_H #define __USBAUDIO_ENDPOINT_H
void snd_usb_init_substream(struct snd_usb_stream *as, #define SND_USB_ENDPOINT_TYPE_DATA 0
int stream, #define SND_USB_ENDPOINT_TYPE_SYNC 1
struct audioformat *fp);
int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
unsigned int period_bytes, struct usb_host_interface *alts,
unsigned int rate, int ep_num, int direction, int type);
unsigned int frame_bits);
void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force); 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_substream_prepare(struct snd_usb_substream *subs, int snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
struct snd_pcm_runtime *runtime); 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_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd); int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
struct snd_usb_endpoint *sender,
const struct urb *urb);
#endif /* __USBAUDIO_ENDPOINT_H */ #endif /* __USBAUDIO_ENDPOINT_H */
This diff is collapsed.
...@@ -115,6 +115,25 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s ...@@ -115,6 +115,25 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
} }
} }
static void proc_dump_ep_status(struct snd_usb_substream *subs,
struct snd_usb_endpoint *ep,
struct snd_info_buffer *buffer)
{
if (!ep)
return;
snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize);
snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
? get_full_speed_hz(ep->freqm)
: get_high_speed_hz(ep->freqm),
ep->freqm >> 16, ep->freqm & 0xffff);
if (ep->freqshift != INT_MIN) {
int res = 16 - ep->freqshift;
snd_iprintf(buffer, " Feedback Format = %d.%d\n",
(ep->syncmaxsize > 3 ? 32 : 24) - res, res);
}
}
static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
{ {
if (subs->running) { if (subs->running) {
...@@ -126,17 +145,8 @@ static void proc_dump_substream_status(struct snd_usb_substream *subs, struct sn ...@@ -126,17 +145,8 @@ static void proc_dump_substream_status(struct snd_usb_substream *subs, struct sn
for (i = 0; i < subs->nurbs; i++) for (i = 0; i < subs->nurbs; i++)
snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, "]\n");
snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); proc_dump_ep_status(subs, subs->data_endpoint, buffer);
snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", proc_dump_ep_status(subs, subs->sync_endpoint, buffer);
snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
? get_full_speed_hz(subs->freqm)
: get_high_speed_hz(subs->freqm),
subs->freqm >> 16, subs->freqm & 0xffff);
if (subs->freqshift != INT_MIN)
snd_iprintf(buffer, " Feedback Format = %d.%d\n",
(subs->syncmaxsize > 3 ? 32 : 24)
- (16 - subs->freqshift),
16 - subs->freqshift);
} else { } else {
snd_iprintf(buffer, " Status: Stop\n"); snd_iprintf(buffer, " Status: Stop\n");
} }
......
...@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) ...@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
} }
} }
/*
* initialize the substream instance.
*/
static void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
struct audioformat *fp)
{
struct snd_usb_substream *subs = &as->substream[stream];
INIT_LIST_HEAD(&subs->fmt_list);
spin_lock_init(&subs->lock);
subs->stream = as;
subs->direction = stream;
subs->dev = as->chip->dev;
subs->txfr_quirk = as->chip->txfr_quirk;
snd_usb_set_pcm_ops(as->pcm, stream);
list_add_tail(&fp->list, &subs->fmt_list);
subs->formats |= fp->formats;
subs->num_formats++;
subs->fmt_type = fp->fmt_type;
}
/* /*
* add this endpoint to the chip instance. * add this endpoint to the chip instance.
...@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ...@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if (as->fmt_type != fp->fmt_type) if (as->fmt_type != fp->fmt_type)
continue; continue;
subs = &as->substream[stream]; subs = &as->substream[stream];
if (!subs->endpoint) if (!subs->data_endpoint)
continue; continue;
if (subs->endpoint == fp->endpoint) { if (subs->data_endpoint->ep_num == fp->endpoint) {
list_add_tail(&fp->list, &subs->fmt_list); list_add_tail(&fp->list, &subs->fmt_list);
subs->num_formats++; subs->num_formats++;
subs->formats |= fp->formats; subs->formats |= fp->formats;
...@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ...@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if (as->fmt_type != fp->fmt_type) if (as->fmt_type != fp->fmt_type)
continue; continue;
subs = &as->substream[stream]; subs = &as->substream[stream];
if (subs->endpoint) if (subs->data_endpoint)
continue; continue;
err = snd_pcm_new_stream(as->pcm, stream, 1); err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0) if (err < 0)
......
...@@ -36,6 +36,7 @@ struct snd_usb_audio { ...@@ -36,6 +36,7 @@ struct snd_usb_audio {
struct snd_card *card; struct snd_card *card;
struct usb_interface *pm_intf; struct usb_interface *pm_intf;
u32 usb_id; u32 usb_id;
struct mutex mutex;
struct mutex shutdown_mutex; struct mutex shutdown_mutex;
unsigned int shutdown:1; unsigned int shutdown:1;
unsigned int probing:1; unsigned int probing:1;
...@@ -46,6 +47,7 @@ struct snd_usb_audio { ...@@ -46,6 +47,7 @@ struct snd_usb_audio {
int num_suspended_intf; int num_suspended_intf;
struct list_head pcm_list; /* list of pcm streams */ struct list_head pcm_list; /* list of pcm streams */
struct list_head ep_list; /* list of audio-related endpoints */
int pcm_devs; int pcm_devs;
struct list_head midi_list; /* list of midi interfaces */ struct list_head midi_list; /* list of midi interfaces */
......
Markdown is supported
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