OSDN Git Service

pcm: dmix: resume workaround for buggy driver
authorTakashi Iwai <tiwai@suse.de>
Wed, 25 May 2016 13:03:51 +0000 (15:03 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 31 May 2016 10:45:26 +0000 (12:45 +0200)
The previous commit removed the whole handling of resume in dmix, but
this seems causing another regression; some buggy drivers assume that
the device-resume needs to be triggered before transitioning to
PREPARED state.  As an ugly workaround, in this patch, when the slave
PCM supports resume, snd_pcm_direct_resume() does resume of the slave
PCM but immediately drop the stream after that.  In that way, the
device is brought to the sane active state, then the apps can prepare
and restart the stream properly.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
src/pcm/pcm_direct.c

index 53c4992..343fd3c 100644 (file)
@@ -837,6 +837,27 @@ int snd_pcm_direct_prepare(snd_pcm_t *pcm)
 
 int snd_pcm_direct_resume(snd_pcm_t *pcm)
 {
+       snd_pcm_direct_t *dmix = pcm->private_data;
+       snd_pcm_t *spcm = dmix->spcm;
+
+       snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
+       /* some buggy drivers require the device resumed before prepared;
+        * when a device has RESUME flag and is in SUSPENDED state, resume
+        * here but immediately drop to bring it to a sane active state.
+        */
+       if ((spcm->info & SND_PCM_INFO_RESUME) &&
+           snd_pcm_state(spcm) == SND_PCM_STATE_SUSPENDED) {
+               snd_pcm_resume(spcm);
+               snd_pcm_drop(spcm);
+               snd_pcm_direct_timer_stop(dmix);
+               snd_pcm_direct_clear_timer_queue(dmix);
+               snd_pcm_areas_silence(snd_pcm_mmap_areas(spcm), 0,
+                                     spcm->channels, spcm->buffer_size,
+                                     spcm->format);
+               snd_pcm_prepare(spcm);
+               snd_pcm_start(spcm);
+       }
+       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
        return -ENOSYS;
 }
 
@@ -845,7 +866,7 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
 /* copy the slave setting */
 static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
 {
-       spcm->info &= ~(SND_PCM_INFO_PAUSE | SND_PCM_INFO_RESUME);
+       spcm->info &= ~SND_PCM_INFO_PAUSE;
 
        COPY_SLAVE(access);
        COPY_SLAVE(format);
@@ -874,6 +895,8 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
        COPY_SLAVE(buffer_time);
        COPY_SLAVE(sample_bits);
        COPY_SLAVE(frame_bits);
+
+       dmix->shmptr->s.info &= ~SND_PCM_INFO_RESUME;
 }
 
 #undef COPY_SLAVE