123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /*
- * OSS compatible sequencer driver
- *
- * seq_oss_writeq.c - write queue and sync
- *
- * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "seq_oss_writeq.h"
- #include "seq_oss_event.h"
- #include "seq_oss_timer.h"
- #include <sound/seq_oss_legacy.h>
- #include "../seq_lock.h"
- #include "../seq_clientmgr.h"
- #include <linux/wait.h>
- #include <linux/slab.h>
- /*
- * create a write queue record
- */
- struct seq_oss_writeq *
- snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
- {
- struct seq_oss_writeq *q;
- struct snd_seq_client_pool pool;
- if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
- return NULL;
- q->dp = dp;
- q->maxlen = maxlen;
- spin_lock_init(&q->sync_lock);
- q->sync_event_put = 0;
- q->sync_time = 0;
- init_waitqueue_head(&q->sync_sleep);
- memset(&pool, 0, sizeof(pool));
- pool.client = dp->cseq;
- pool.output_pool = maxlen;
- pool.output_room = maxlen / 2;
- snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
- return q;
- }
- /*
- * delete the write queue
- */
- void
- snd_seq_oss_writeq_delete(struct seq_oss_writeq *q)
- {
- if (q) {
- snd_seq_oss_writeq_clear(q); /* to be sure */
- kfree(q);
- }
- }
- /*
- * reset the write queue
- */
- void
- snd_seq_oss_writeq_clear(struct seq_oss_writeq *q)
- {
- struct snd_seq_remove_events reset;
- memset(&reset, 0, sizeof(reset));
- reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */
- snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset);
- /* wake up sleepers if any */
- snd_seq_oss_writeq_wakeup(q, 0);
- }
- /*
- * wait until the write buffer has enough room
- */
- int
- snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
- {
- struct seq_oss_devinfo *dp = q->dp;
- abstime_t time;
- time = snd_seq_oss_timer_cur_tick(dp->timer);
- if (q->sync_time >= time)
- return 0; /* already finished */
- if (! q->sync_event_put) {
- struct snd_seq_event ev;
- union evrec *rec;
- /* put echoback event */
- memset(&ev, 0, sizeof(ev));
- ev.flags = 0;
- ev.type = SNDRV_SEQ_EVENT_ECHO;
- ev.time.tick = time;
- /* echo back to itself */
- snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
- rec = (union evrec *)&ev.data;
- rec->t.code = SEQ_SYNCTIMER;
- rec->t.time = time;
- q->sync_event_put = 1;
- snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
- }
- wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
- if (signal_pending(current))
- /* interrupted - return 0 to finish sync */
- q->sync_event_put = 0;
- if (! q->sync_event_put || q->sync_time >= time)
- return 0;
- return 1;
- }
- /*
- * wake up sync - echo event was catched
- */
- void
- snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
- {
- unsigned long flags;
- spin_lock_irqsave(&q->sync_lock, flags);
- q->sync_time = time;
- q->sync_event_put = 0;
- if (waitqueue_active(&q->sync_sleep)) {
- wake_up(&q->sync_sleep);
- }
- spin_unlock_irqrestore(&q->sync_lock, flags);
- }
- /*
- * return the unused pool size
- */
- int
- snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q)
- {
- struct snd_seq_client_pool pool;
- pool.client = q->dp->cseq;
- snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
- return pool.output_free;
- }
- /*
- * set output threshold size from ioctl
- */
- void
- snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val)
- {
- struct snd_seq_client_pool pool;
- pool.client = q->dp->cseq;
- snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
- pool.output_room = val;
- snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
- }
|