OSDN Git Service

direct plugins (dmix) - suspend/resume fixes
authorJaroslav Kysela <perex@perex.cz>
Tue, 16 Aug 2005 12:19:15 +0000 (12:19 +0000)
committerJaroslav Kysela <perex@perex.cz>
Tue, 16 Aug 2005 12:19:15 +0000 (12:19 +0000)
- this patch adds support for suspend & result for dmix and other
  direct plugins
- the timer detection / initialization (TREAD support) was redesigned and
  the check for proper driver version was moved to the timer_hw.c

include/sound/asound.h
include/timer.h
src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c
src/timer/timer_hw.c

index 39d6f0a..32582ef 100644 (file)
@@ -693,7 +693,7 @@ enum sndrv_timer_event {
        SNDRV_TIMER_EVENT_PAUSE,                /* val = 0 */
        SNDRV_TIMER_EVENT_EARLY,                /* val = 0, early event */
        SNDRV_TIMER_EVENT_SUSPEND,              /* val = 0 */
-       SNDRV_TIMER_EVENT_RESUME,               /* val = 0 */
+       SNDRV_TIMER_EVENT_RESUME,               /* val = resolution in ns */
        /* master timer events for slave timer instances */
        SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
        SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
index 10d7264..a367149 100644 (file)
@@ -85,11 +85,15 @@ typedef enum _snd_timer_event {
        SND_TIMER_EVENT_CONTINUE,       /* val = resolution in ns */
        SND_TIMER_EVENT_PAUSE,          /* val = 0 */
        SND_TIMER_EVENT_EARLY,          /* val = 0 */
+       SND_TIMER_EVENT_SUSPEND,        /* val = 0 */
+       SND_TIMER_EVENT_RESUME,         /* val = resolution in ns */
        /* master timer events for slave timer instances */
        SND_TIMER_EVENT_MSTART = SND_TIMER_EVENT_START + 10,
        SND_TIMER_EVENT_MSTOP = SND_TIMER_EVENT_STOP + 10,
        SND_TIMER_EVENT_MCONTINUE = SND_TIMER_EVENT_CONTINUE + 10,
        SND_TIMER_EVENT_MPAUSE = SND_TIMER_EVENT_PAUSE + 10,
+       SND_TIMER_EVENT_MSUSPEND = SND_TIMER_EVENT_SUSPEND + 10,
+       SND_TIMER_EVENT_MRESUME = SND_TIMER_EVENT_RESUME + 10   
 } snd_timer_event_t;
 
 /** timer read structure */
index 3d3f1d4..e578010 100644 (file)
@@ -431,6 +431,13 @@ int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid)
        return snd_timer_async(dmix->timer, sig, pid);
 }
 
+static inline void process_timer_event(snd_pcm_direct_t *dmix, snd_timer_tread_t *te)
+{
+#if 0
+       printf("te->event = %i\n", te->event);
+#endif
+}
+
 /* empty the timer read queue */
 void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
 {
@@ -440,6 +447,7 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
                        if (dmix->tread) {
                                snd_timer_tread_t rbuf;
                                snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf));
+                               process_timer_event(dmix, &rbuf);
                        } else {
                                snd_timer_read_t rbuf;
                                snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf));
@@ -449,7 +457,7 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
                if (dmix->tread) {
                        snd_timer_tread_t rbuf;
                        while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0)
-                               ;
+                               process_timer_event(dmix, &rbuf);
                } else {
                        snd_timer_read_t rbuf;
                        while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0)
@@ -666,6 +674,23 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
        return 0;
 }
 
+int snd_pcm_direct_resume(snd_pcm_t *pcm)
+{
+       snd_pcm_direct_t *dmix = pcm->private_data;
+       int err;
+       
+       snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
+       err = snd_pcm_resume(dmix->spcm);
+       if (err == -ENOSYS) {
+               /* FIXME: error handling? */
+               snd_pcm_prepare(dmix->spcm);
+               snd_pcm_start(dmix->spcm);
+               err = 0;
+       }
+       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+       return err;
+}
+
 /*
  * this function initializes hardware and starts playback operation with
  * no stop threshold (it operates all time without xrun checking)
@@ -909,8 +934,8 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
        snd_pcm_info_t *info;
        char name[128];
        int capture = dmix->type == SND_PCM_TYPE_DSNOOP ? 1 : 0;
-       
-       dmix->tread = 0;
+
+       dmix->tread = 1;
        dmix->timer_need_poll = 0;
        snd_pcm_info_alloca(&info);
        ret = snd_pcm_info(dmix->spcm, info);
@@ -923,11 +948,14 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
                                snd_pcm_info_get_card(info),
                                snd_pcm_info_get_device(info),
                                snd_pcm_info_get_subdevice(info) * 2 + capture);
-       ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK
-                            /*| SND_TIMER_OPEN_TREAD*/);  /* XXX: TREAD is set later */
+       ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
        if (ret < 0) {
-               SNDERR("unable to open timer '%s'", name);
-               return ret;
+               dmix->tread = 1;
+               ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK);
+               if (ret < 0) {
+                       SNDERR("unable to open timer '%s'", name);
+                       return ret;
+               }
        }
 
        if (snd_timer_poll_descriptors_count(dmix->timer) != 1) {
@@ -937,27 +965,30 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
        snd_timer_poll_descriptors(dmix->timer, &dmix->timer_fd, 1);
        dmix->poll_fd = dmix->timer_fd.fd;
 
+       dmix->timer_event_suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
+       dmix->timer_event_resume = 1<<SND_TIMER_EVENT_MRESUME;
+
        /*
-        * A hack to avoid Oops in the older kernel
-        *
-        * Enable TREAD mode only when protocl is newer than 2.0.2.
+        * Some hacks for older kernel drivers
         */
        {
                int ver = 0;
                ioctl(dmix->poll_fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
-               if (ver >= SNDRV_PROTOCOL_VERSION(2, 0, 3)) {
-                       dmix->tread = 1;
-                       if (ioctl(dmix->poll_fd, SNDRV_TIMER_IOCTL_TREAD, &dmix->tread) < 0)
-                               dmix->tread = 0;
-               }
                /* In older versions, check via poll before read() is needed
                 * because of the confliction between TIMER_START and
                 * FIONBIO ioctls.
                 */
                if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
                        dmix->timer_need_poll = 1;
+               /*
+                * In older versions, timer uses pause events instead
+                * suspend/resume events.
+                */
+               if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
+                       dmix->timer_event_suspend = 1<<SND_TIMER_EVENT_MPAUSE;
+                       dmix->timer_event_resume = 1<<SND_TIMER_EVENT_MCONTINUE;
+               }
        }
-
        return 0;
 }
 
@@ -1012,6 +1043,7 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm
 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
 {
        snd_timer_params_t *params;
+       unsigned int filter;
        int ret;
 
        snd_timer_params_alloca(&params);
@@ -1019,8 +1051,12 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
        if (dmix->type != SND_PCM_TYPE_DSNOOP)
                snd_timer_params_set_early_event(params, 1);
        snd_timer_params_set_ticks(params, 1);
-       if (dmix->tread)
-               snd_timer_params_set_filter(params, (1<<SND_TIMER_EVENT_TICK)|(1<<SND_TIMER_EVENT_MPAUSE));
+       if (dmix->tread) {
+               filter = (1<<SND_TIMER_EVENT_TICK) |
+                        dmix->timer_event_suspend |
+                        dmix->timer_event_resume;
+               snd_timer_params_set_filter(params, filter);
+       }
        ret = snd_timer_params(dmix->timer, params);
        if (ret < 0) {
                SNDERR("unable to set timer parameters");
index da300b7..ed49e03 100644 (file)
@@ -105,6 +105,8 @@ struct snd_pcm_direct {
        int poll_fd;
        int tread;
        int timer_need_poll;
+       unsigned int timer_event_suspend;
+       unsigned int timer_event_resume;
        int server_fd;
        pid_t server_pid;
        snd_timer_t *timer;             /* timer used as poll_fd */
@@ -153,6 +155,7 @@ int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
 int snd_pcm_direct_mmap(snd_pcm_t *pcm);
 int snd_pcm_direct_munmap(snd_pcm_t *pcm);
+int snd_pcm_direct_resume(snd_pcm_t *pcm);
 int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
 void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
index 36a7a5c..c9cfdcc 100644 (file)
@@ -580,13 +580,6 @@ static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
        return frames;
 }
 
-static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
-{
-       snd_pcm_direct_t *dmix = pcm->private_data;
-       snd_pcm_resume(dmix->spcm);
-       return 0;
-}
-
 static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
 {
        return -ENODEV;
@@ -715,7 +708,7 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
        .pause = snd_pcm_dmix_pause,
        .rewind = snd_pcm_dmix_rewind,
        .forward = snd_pcm_dmix_forward,
-       .resume = snd_pcm_dmix_resume,
+       .resume = snd_pcm_direct_resume,
        .link_fd = NULL,
        .link = NULL,
        .unlink = NULL,
index a90cd63..30a57bc 100644 (file)
@@ -434,13 +434,6 @@ static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_
        return frames;
 }
 
-static int snd_pcm_dshare_resume(snd_pcm_t *pcm)
-{
-       snd_pcm_direct_t *dshare = pcm->private_data;
-       snd_pcm_resume(dshare->spcm);
-       return 0;
-}
-
 static snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
 {
        return -ENODEV;
@@ -561,7 +554,7 @@ static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
        .pause = snd_pcm_dshare_pause,
        .rewind = snd_pcm_dshare_rewind,
        .forward = snd_pcm_dshare_forward,
-       .resume = snd_pcm_dshare_resume,
+       .resume = snd_pcm_direct_resume,
        .link_fd = NULL,
        .link = NULL,
        .unlink = NULL,
index d0f4357..e2da4b7 100644 (file)
@@ -457,7 +457,7 @@ static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
        .pause = snd_pcm_dsnoop_pause,
        .rewind = snd_pcm_dsnoop_rewind,
        .forward = snd_pcm_dsnoop_forward,
-       .resume = snd_pcm_dsnoop_resume,
+       .resume = snd_pcm_direct_resume,
        .link_fd = NULL,
        .link = NULL,
        .unlink = NULL,
index 4b5cff7..2fc576c 100644 (file)
@@ -258,9 +258,14 @@ int snd_timer_hw_open(snd_timer_t **handle, const char *name, int dev_class, int
        }
        if (mode & SND_TIMER_OPEN_TREAD) {
                int arg = 1;
+               if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 3)) {
+                       ret = -ENOTTY;
+                       goto __no_tread;
+               }
                if (ioctl(fd, SNDRV_TIMER_IOCTL_TREAD, &arg) < 0) {
                        ret = -errno;
                        close(fd);
+                     __no_tread:
                        SNDERR("extended read is not supported (SNDRV_TIMER_IOCTL_TREAD)");
                        return ret;
                }