From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: [PATCH] usbaudio fixes Date: Mon, 24 Nov 2003 13:51:50 +0100 Sender: alsa-devel-admin@lists.sourceforge.net Message-ID: References: Mime-Version: 1.0 (generated by SEMI 1.14.5 - "Awara-Onsen") Content-Type: multipart/mixed; boundary="Multipart_Mon_Nov_24_13:51:50_2003-1" Return-path: In-Reply-To: Errors-To: alsa-devel-admin@lists.sourceforge.net List-Help: List-Post: List-Subscribe: , List-Unsubscribe: , List-Archive: To: Clemens Ladisch Cc: alsa-devel@lists.sourceforge.net List-Id: alsa-devel@alsa-project.org --Multipart_Mon_Nov_24_13:51:50_2003-1 Content-Type: text/plain; charset=US-ASCII At Mon, 24 Nov 2003 13:36:42 +0100, I wrote: > > meanwhile, i'm trying to implement: > > (4) allow prepare callback to sleep with a special flag. > > this will be useful for other drivers, too, such as vx and korg1212 > drivers which require the handshaking. > but what i'm doing is still a hack, and will be a fundamental rewrite > later. the attached is a quick-hacked version. it's untested for linked streams. we need a test case here. Takashi --Multipart_Mon_Nov_24_13:51:50_2003-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="nonatomic-prepare.dif" Content-Transfer-Encoding: 7bit Index: alsa-kernel/core/pcm_native.c =================================================================== RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/pcm_native.c,v retrieving revision 1.63 diff -u -r1.63 pcm_native.c --- alsa-kernel/core/pcm_native.c 21 Oct 2003 09:49:34 -0000 1.63 +++ alsa-kernel/core/pcm_native.c 24 Nov 2003 12:42:32 -0000 @@ -620,7 +620,7 @@ */ 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 @@ 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 @@ 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 @@ /* 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 @@ /* * 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 @@ 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 @@ /* * 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,42 @@ 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); + 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 +1037,7 @@ 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 +1127,7 @@ 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 +1175,7 @@ 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; } Index: alsa-kernel/include/asound.h =================================================================== RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/include/asound.h,v retrieving revision 1.24 diff -u -r1.24 asound.h --- alsa-kernel/include/asound.h 22 Oct 2003 09:41:06 -0000 1.24 +++ alsa-kernel/include/asound.h 24 Nov 2003 12:23:47 -0000 @@ -272,6 +272,7 @@ #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 */ Index: alsa-kernel/usb/usbaudio.c =================================================================== RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/usb/usbaudio.c,v retrieving revision 1.77 diff -u -r1.77 usbaudio.c --- alsa-kernel/usb/usbaudio.c 24 Nov 2003 11:51:02 -0000 1.77 +++ alsa-kernel/usb/usbaudio.c 24 Nov 2003 12:44:47 -0000 @@ -804,8 +804,7 @@ 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++) @@ -1277,6 +1276,10 @@ subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); + /* clear urbs (to be sure) */ + if (deactivate_urbs(subs, 0, 1) > 0) + wait_clear_urbs(subs); + return 0; } @@ -2002,7 +2005,7 @@ 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 --Multipart_Mon_Nov_24_13:51:50_2003-1-- ------------------------------------------------------- This SF.net email is sponsored by: SF.net Giveback Program. Does SourceForge.net help you be more productive? Does it help you create better code? SHARE THE LOVE, and help us help YOU! Click Here: http://sourceforge.net/donate/