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 { ...@@ -272,6 +272,7 @@ enum sndrv_pcm_subformat {
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ #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_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_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 { enum sndrv_pcm_state {
SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ SNDRV_PCM_STATE_OPEN = 0, /* stream is open */
......
...@@ -620,7 +620,7 @@ struct action_ops { ...@@ -620,7 +620,7 @@ struct action_ops {
*/ */
static int snd_pcm_action_group(struct action_ops *ops, static int snd_pcm_action_group(struct action_ops *ops,
snd_pcm_substream_t *substream, snd_pcm_substream_t *substream,
int state) int state, int atomic_only)
{ {
struct list_head *pos; struct list_head *pos;
snd_pcm_substream_t *s = NULL; snd_pcm_substream_t *s = NULL;
...@@ -628,6 +628,8 @@ static int snd_pcm_action_group(struct action_ops *ops, ...@@ -628,6 +628,8 @@ static int snd_pcm_action_group(struct action_ops *ops,
snd_pcm_group_for_each(pos, substream) { snd_pcm_group_for_each(pos, substream) {
s = snd_pcm_group_substream_entry(pos); s = snd_pcm_group_substream_entry(pos);
if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS))
continue;
if (s != substream) if (s != substream)
spin_lock(&s->self_group.lock); spin_lock(&s->self_group.lock);
res = ops->pre_action(s, state); res = ops->pre_action(s, state);
...@@ -637,6 +639,8 @@ static int snd_pcm_action_group(struct action_ops *ops, ...@@ -637,6 +639,8 @@ static int snd_pcm_action_group(struct action_ops *ops,
if (res >= 0) { if (res >= 0) {
snd_pcm_group_for_each(pos, substream) { snd_pcm_group_for_each(pos, substream) {
s = snd_pcm_group_substream_entry(pos); 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); err = ops->do_action(s, state);
if (err < 0) { if (err < 0) {
if (res == 0) if (res == 0)
...@@ -652,7 +656,9 @@ static int snd_pcm_action_group(struct action_ops *ops, ...@@ -652,7 +656,9 @@ static int snd_pcm_action_group(struct action_ops *ops,
/* unlock all streams */ /* unlock all streams */
snd_pcm_group_for_each(pos, substream) { snd_pcm_group_for_each(pos, substream) {
s1 = snd_pcm_group_substream_entry(pos); 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); spin_unlock(&s1->self_group.lock);
if (s1 == s) /* end */ if (s1 == s) /* end */
break; break;
...@@ -682,6 +688,8 @@ static int snd_pcm_action_single(struct action_ops *ops, ...@@ -682,6 +688,8 @@ static int snd_pcm_action_single(struct action_ops *ops,
/* /*
* Note: call with stream lock * Note: call with stream lock
*
* NB2: this won't handle the non-atomic callbacks
*/ */
static int snd_pcm_action(struct action_ops *ops, static int snd_pcm_action(struct action_ops *ops,
snd_pcm_substream_t *substream, snd_pcm_substream_t *substream,
...@@ -695,7 +703,7 @@ static int snd_pcm_action(struct action_ops *ops, ...@@ -695,7 +703,7 @@ static int snd_pcm_action(struct action_ops *ops,
spin_lock(&substream->group->lock); spin_lock(&substream->group->lock);
spin_lock(&substream->self_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); spin_unlock(&substream->group->lock);
} else { } else {
res = snd_pcm_action_single(ops, substream, state); res = snd_pcm_action_single(ops, substream, state);
...@@ -705,10 +713,14 @@ static int snd_pcm_action(struct action_ops *ops, ...@@ -705,10 +713,14 @@ static int snd_pcm_action(struct action_ops *ops,
/* /*
* Note: don't use any locks before * 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, static int snd_pcm_action_lock_irq(struct action_ops *ops,
snd_pcm_substream_t *substream, snd_pcm_substream_t *substream,
int state) int state, int allow_nonatomic)
{ {
int res; int res;
...@@ -716,10 +728,43 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops, ...@@ -716,10 +728,43 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
if (snd_pcm_stream_linked(substream)) { if (snd_pcm_stream_linked(substream)) {
spin_lock(&substream->group->lock); spin_lock(&substream->group->lock);
spin_lock(&substream->self_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->self_group.lock);
spin_unlock(&substream->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 { } 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); spin_lock(&substream->self_group.lock);
res = snd_pcm_action_single(ops, substream, state); res = snd_pcm_action_single(ops, substream, state);
spin_unlock(&substream->self_group.lock); spin_unlock(&substream->self_group.lock);
...@@ -993,7 +1038,7 @@ static int snd_pcm_resume(snd_pcm_substream_t *substream) ...@@ -993,7 +1038,7 @@ static int snd_pcm_resume(snd_pcm_substream_t *substream)
snd_power_lock(card); snd_power_lock(card);
if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) 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); snd_power_unlock(card);
return res; return res;
} }
...@@ -1083,7 +1128,7 @@ static struct action_ops snd_pcm_action_reset = { ...@@ -1083,7 +1128,7 @@ static struct action_ops snd_pcm_action_reset = {
static int snd_pcm_reset(snd_pcm_substream_t *substream) 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) 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) ...@@ -1131,7 +1176,7 @@ int snd_pcm_prepare(snd_pcm_substream_t *substream)
snd_power_lock(card); snd_power_lock(card);
if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) 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); snd_power_unlock(card);
return res; return res;
} }
...@@ -2330,7 +2375,7 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream, ...@@ -2330,7 +2375,7 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
case SNDRV_PCM_IOCTL_RESET: case SNDRV_PCM_IOCTL_RESET:
return snd_pcm_reset(substream); return snd_pcm_reset(substream);
case SNDRV_PCM_IOCTL_START: 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: case SNDRV_PCM_IOCTL_LINK:
return snd_pcm_link(substream, (long) arg); return snd_pcm_link(substream, (long) arg);
case SNDRV_PCM_IOCTL_UNLINK: case SNDRV_PCM_IOCTL_UNLINK:
......
...@@ -28,9 +28,8 @@ ...@@ -28,9 +28,8 @@
* NOTES: * NOTES:
* *
* - async unlink should be used for avoiding the sleep inside lock. * - async unlink should be used for avoiding the sleep inside lock.
* however, it causes oops by unknown reason on usb-uhci, and * 2.4.22 usb-uhci seems buggy for async unlinking and results in
* disabled as default. the feature is enabled by async_unlink=1 * oops. in such a cse, pass async_unlink=0 option.
* option (especially when preempt is used).
* - the linked URBs would be preferred but not used so far because of * - the linked URBs would be preferred but not used so far because of
* the instability of unlinking. * the instability of unlinking.
* - type II is not supported properly. there is no device which supports * - 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 * ...@@ -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 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 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 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(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); 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) ...@@ -804,8 +803,7 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
int i; int i;
/* stop urbs (to be sure) */ /* stop urbs (to be sure) */
deactivate_urbs(subs, force, 1); if (deactivate_urbs(subs, force, 1) > 0)
if (async_unlink)
wait_clear_urbs(subs); wait_clear_urbs(subs);
for (i = 0; i < MAX_URBS; i++) 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 ...@@ -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->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
subs->phase = 0; 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 */ /* calculate the max. size of packet */
maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14; maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14;
if (subs->maxpacksize && maxsize > subs->maxpacksize) { if (subs->maxpacksize && maxsize > subs->maxpacksize) {
...@@ -1277,6 +1269,17 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) ...@@ -1277,6 +1269,17 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); 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; return 0;
} }
...@@ -2002,7 +2005,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor ...@@ -2002,7 +2005,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
as->pcm = pcm; as->pcm = pcm;
pcm->private_data = as; pcm->private_data = as;
pcm->private_free = snd_usb_audio_pcm_free; 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) if (chip->pcm_devs > 0)
sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
else 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