Commit 633e73bb authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA CVS update - Takashi Iwai <tiwai@suse.de>

PCM Midlevel,ALSA Core,USB generic driver
- prepare callback can sleep if a flag is given in pcm->info_flags.
- usbaudio driver uses non-atomic prepare callback for synchronization
  of pending unlinked urbs.
- async_unlink option of usbaudio driver is enabled as default now.
- fixed the initialization of pseudo-dma pointers in usbaudio.
parent 8653142d
......@@ -272,6 +272,7 @@ enum sndrv_pcm_subformat {
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
#define SNDRV_PCM_INFO_NONATOMIC_OPS 0x00800000 /* non-atomic prepare callback */
enum sndrv_pcm_state {
SNDRV_PCM_STATE_OPEN = 0, /* stream is open */
......
......@@ -620,7 +620,7 @@ struct action_ops {
*/
static int snd_pcm_action_group(struct action_ops *ops,
snd_pcm_substream_t *substream,
int state)
int state, int atomic_only)
{
struct list_head *pos;
snd_pcm_substream_t *s = NULL;
......@@ -628,6 +628,8 @@ static int snd_pcm_action_group(struct action_ops *ops,
snd_pcm_group_for_each(pos, substream) {
s = snd_pcm_group_substream_entry(pos);
if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS))
continue;
if (s != substream)
spin_lock(&s->self_group.lock);
res = ops->pre_action(s, state);
......@@ -637,6 +639,8 @@ static int snd_pcm_action_group(struct action_ops *ops,
if (res >= 0) {
snd_pcm_group_for_each(pos, substream) {
s = snd_pcm_group_substream_entry(pos);
if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS))
continue;
err = ops->do_action(s, state);
if (err < 0) {
if (res == 0)
......@@ -652,7 +656,9 @@ static int snd_pcm_action_group(struct action_ops *ops,
/* unlock all streams */
snd_pcm_group_for_each(pos, substream) {
s1 = snd_pcm_group_substream_entry(pos);
if (s1 != substream)
if (atomic_only && (s1->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS))
;
else if (s1 != substream)
spin_unlock(&s1->self_group.lock);
if (s1 == s) /* end */
break;
......@@ -682,6 +688,8 @@ static int snd_pcm_action_single(struct action_ops *ops,
/*
* Note: call with stream lock
*
* NB2: this won't handle the non-atomic callbacks
*/
static int snd_pcm_action(struct action_ops *ops,
snd_pcm_substream_t *substream,
......@@ -695,7 +703,7 @@ static int snd_pcm_action(struct action_ops *ops,
spin_lock(&substream->group->lock);
spin_lock(&substream->self_group.lock);
}
res = snd_pcm_action_group(ops, substream, state);
res = snd_pcm_action_group(ops, substream, state, 0);
spin_unlock(&substream->group->lock);
} else {
res = snd_pcm_action_single(ops, substream, state);
......@@ -705,10 +713,14 @@ static int snd_pcm_action(struct action_ops *ops,
/*
* Note: don't use any locks before
*
* NB2: this can handle the non-atomic callbacks if allow_nonatomic = 1
* when the pcm->info_flags has NONATOMIC_OPS bit, it's handled
* ouside the lock to allow sleep in the callback.
*/
static int snd_pcm_action_lock_irq(struct action_ops *ops,
snd_pcm_substream_t *substream,
int state)
int state, int allow_nonatomic)
{
int res;
......@@ -716,10 +728,43 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
if (snd_pcm_stream_linked(substream)) {
spin_lock(&substream->group->lock);
spin_lock(&substream->self_group.lock);
res = snd_pcm_action_group(ops, substream, state);
res = snd_pcm_action_group(ops, substream, state, allow_nonatomic);
spin_unlock(&substream->self_group.lock);
spin_unlock(&substream->group->lock);
if (res >= 0 && allow_nonatomic) {
/* now process the non-atomic substreams separately
* outside the lock
*/
#define MAX_LINKED_STREAMS 16 /* FIXME: should be variable */
struct list_head *pos;
int i, num_s = 0;
snd_pcm_substream_t *s;
snd_pcm_substream_t *subs[MAX_LINKED_STREAMS];
snd_pcm_group_for_each(pos, substream) {
if (num_s >= MAX_LINKED_STREAMS) {
res = -ENOMEM;
num_s = 0; /* don't proceed */
break;
}
s = snd_pcm_group_substream_entry(pos);
if (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)
subs[num_s++] = s;
}
if (num_s > 0) {
read_unlock_irq(&snd_pcm_link_rwlock);
for (i = 0; i < num_s && res >= 0; i++)
res = snd_pcm_action_single(ops, subs[i], state);
return res;
}
}
} else {
if (allow_nonatomic &&
(substream->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) {
read_unlock_irq(&snd_pcm_link_rwlock);
/* process outside the lock */
return snd_pcm_action_single(ops, substream, state);
}
spin_lock(&substream->self_group.lock);
res = snd_pcm_action_single(ops, substream, state);
spin_unlock(&substream->self_group.lock);
......@@ -993,7 +1038,7 @@ static int snd_pcm_resume(snd_pcm_substream_t *substream)
snd_power_lock(card);
if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0, 0);
snd_power_unlock(card);
return res;
}
......@@ -1083,7 +1128,7 @@ static struct action_ops snd_pcm_action_reset = {
static int snd_pcm_reset(snd_pcm_substream_t *substream)
{
return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0);
return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0, 0);
}
static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state)
......@@ -1131,7 +1176,7 @@ int snd_pcm_prepare(snd_pcm_substream_t *substream)
snd_power_lock(card);
if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0);
res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0, 1); /* allow sleep if specified */
snd_power_unlock(card);
return res;
}
......@@ -2330,7 +2375,7 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
case SNDRV_PCM_IOCTL_RESET:
return snd_pcm_reset(substream);
case SNDRV_PCM_IOCTL_START:
return snd_pcm_action(&snd_pcm_action_start, substream, 0);
return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, 0, 0);
case SNDRV_PCM_IOCTL_LINK:
return snd_pcm_link(substream, (long) arg);
case SNDRV_PCM_IOCTL_UNLINK:
......
......@@ -28,9 +28,8 @@
* NOTES:
*
* - async unlink should be used for avoiding the sleep inside lock.
* however, it causes oops by unknown reason on usb-uhci, and
* disabled as default. the feature is enabled by async_unlink=1
* option (especially when preempt is used).
* 2.4.22 usb-uhci seems buggy for async unlinking and results in
* oops. in such a cse, pass async_unlink=0 option.
* - the linked URBs would be preferred but not used so far because of
* the instability of unlinking.
* - type II is not supported properly. there is no device which supports
......@@ -69,7 +68,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
static int nrpacks = 4; /* max. number of packets per urb */
static int async_unlink = 0;
static int async_unlink = 1;
MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
......@@ -804,8 +803,7 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
int i;
/* stop urbs (to be sure) */
deactivate_urbs(subs, force, 1);
if (async_unlink)
if (deactivate_urbs(subs, force, 1) > 0)
wait_clear_urbs(subs);
for (i = 0; i < MAX_URBS; i++)
......@@ -834,12 +832,6 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
subs->phase = 0;
/* reset the pointer */
subs->hwptr = 0;
subs->hwptr_done = 0;
subs->transfer_sched = 0;
subs->transfer_done = 0;
/* calculate the max. size of packet */
maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14;
if (subs->maxpacksize && maxsize > subs->maxpacksize) {
......@@ -1277,6 +1269,17 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
/* reset the pointer */
subs->hwptr = 0;
subs->hwptr_done = 0;
subs->transfer_sched = 0;
subs->transfer_done = 0;
subs->phase = 0;
/* clear urbs (to be sure) */
if (deactivate_urbs(subs, 0, 0) > 0)
wait_clear_urbs(subs);
return 0;
}
......@@ -2002,7 +2005,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
as->pcm = pcm;
pcm->private_data = as;
pcm->private_free = snd_usb_audio_pcm_free;
pcm->info_flags = 0;
pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS;
if (chip->pcm_devs > 0)
sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
else
......
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