linux/sound/core/seq/oss/seq_oss_writeq.c
<<
>>
Prefs
   1/*
   2 * OSS compatible sequencer driver
   3 *
   4 * seq_oss_writeq.c - write queue and sync
   5 *
   6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  21 */
  22
  23#include "seq_oss_writeq.h"
  24#include "seq_oss_event.h"
  25#include "seq_oss_timer.h"
  26#include <sound/seq_oss_legacy.h>
  27#include "../seq_lock.h"
  28#include "../seq_clientmgr.h"
  29#include <linux/wait.h>
  30#include <linux/slab.h>
  31
  32
  33/*
  34 * create a write queue record
  35 */
  36struct seq_oss_writeq *
  37snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
  38{
  39        struct seq_oss_writeq *q;
  40        struct snd_seq_client_pool pool;
  41
  42        if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
  43                return NULL;
  44        q->dp = dp;
  45        q->maxlen = maxlen;
  46        spin_lock_init(&q->sync_lock);
  47        q->sync_event_put = 0;
  48        q->sync_time = 0;
  49        init_waitqueue_head(&q->sync_sleep);
  50
  51        memset(&pool, 0, sizeof(pool));
  52        pool.client = dp->cseq;
  53        pool.output_pool = maxlen;
  54        pool.output_room = maxlen / 2;
  55
  56        snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
  57
  58        return q;
  59}
  60
  61/*
  62 * delete the write queue
  63 */
  64void
  65snd_seq_oss_writeq_delete(struct seq_oss_writeq *q)
  66{
  67        if (q) {
  68                snd_seq_oss_writeq_clear(q);    /* to be sure */
  69                kfree(q);
  70        }
  71}
  72
  73
  74/*
  75 * reset the write queue
  76 */
  77void
  78snd_seq_oss_writeq_clear(struct seq_oss_writeq *q)
  79{
  80        struct snd_seq_remove_events reset;
  81
  82        memset(&reset, 0, sizeof(reset));
  83        reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */
  84        snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset);
  85
  86        /* wake up sleepers if any */
  87        snd_seq_oss_writeq_wakeup(q, 0);
  88}
  89
  90/*
  91 * wait until the write buffer has enough room
  92 */
  93int
  94snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
  95{
  96        struct seq_oss_devinfo *dp = q->dp;
  97        abstime_t time;
  98
  99        time = snd_seq_oss_timer_cur_tick(dp->timer);
 100        if (q->sync_time >= time)
 101                return 0; /* already finished */
 102
 103        if (! q->sync_event_put) {
 104                struct snd_seq_event ev;
 105                union evrec *rec;
 106
 107                /* put echoback event */
 108                memset(&ev, 0, sizeof(ev));
 109                ev.flags = 0;
 110                ev.type = SNDRV_SEQ_EVENT_ECHO;
 111                ev.time.tick = time;
 112                /* echo back to itself */
 113                snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
 114                rec = (union evrec *)&ev.data;
 115                rec->t.code = SEQ_SYNCTIMER;
 116                rec->t.time = time;
 117                q->sync_event_put = 1;
 118                snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
 119        }
 120
 121        wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
 122        if (signal_pending(current))
 123                /* interrupted - return 0 to finish sync */
 124                q->sync_event_put = 0;
 125        if (! q->sync_event_put || q->sync_time >= time)
 126                return 0;
 127        return 1;
 128}
 129
 130/*
 131 * wake up sync - echo event was catched
 132 */
 133void
 134snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
 135{
 136        unsigned long flags;
 137
 138        spin_lock_irqsave(&q->sync_lock, flags);
 139        q->sync_time = time;
 140        q->sync_event_put = 0;
 141        if (waitqueue_active(&q->sync_sleep)) {
 142                wake_up(&q->sync_sleep);
 143        }
 144        spin_unlock_irqrestore(&q->sync_lock, flags);
 145}
 146
 147
 148/*
 149 * return the unused pool size
 150 */
 151int
 152snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q)
 153{
 154        struct snd_seq_client_pool pool;
 155        pool.client = q->dp->cseq;
 156        snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
 157        return pool.output_free;
 158}
 159
 160
 161/*
 162 * set output threshold size from ioctl
 163 */
 164void
 165snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val)
 166{
 167        struct snd_seq_client_pool pool;
 168        pool.client = q->dp->cseq;
 169        snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
 170        pool.output_room = val;
 171        snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
 172}
 173
 174