Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at c9a28fa7b9ac19b676deefa0a171ce7df8755c08 172 lines 4.2 kB view raw
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 31 32/* 33 * create a write queue record 34 */ 35struct seq_oss_writeq * 36snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen) 37{ 38 struct seq_oss_writeq *q; 39 struct snd_seq_client_pool pool; 40 41 if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) 42 return NULL; 43 q->dp = dp; 44 q->maxlen = maxlen; 45 spin_lock_init(&q->sync_lock); 46 q->sync_event_put = 0; 47 q->sync_time = 0; 48 init_waitqueue_head(&q->sync_sleep); 49 50 memset(&pool, 0, sizeof(pool)); 51 pool.client = dp->cseq; 52 pool.output_pool = maxlen; 53 pool.output_room = maxlen / 2; 54 55 snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool); 56 57 return q; 58} 59 60/* 61 * delete the write queue 62 */ 63void 64snd_seq_oss_writeq_delete(struct seq_oss_writeq *q) 65{ 66 if (q) { 67 snd_seq_oss_writeq_clear(q); /* to be sure */ 68 kfree(q); 69 } 70} 71 72 73/* 74 * reset the write queue 75 */ 76void 77snd_seq_oss_writeq_clear(struct seq_oss_writeq *q) 78{ 79 struct snd_seq_remove_events reset; 80 81 memset(&reset, 0, sizeof(reset)); 82 reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */ 83 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset); 84 85 /* wake up sleepers if any */ 86 snd_seq_oss_writeq_wakeup(q, 0); 87} 88 89/* 90 * wait until the write buffer has enough room 91 */ 92int 93snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) 94{ 95 struct seq_oss_devinfo *dp = q->dp; 96 abstime_t time; 97 98 time = snd_seq_oss_timer_cur_tick(dp->timer); 99 if (q->sync_time >= time) 100 return 0; /* already finished */ 101 102 if (! q->sync_event_put) { 103 struct snd_seq_event ev; 104 union evrec *rec; 105 106 /* put echoback event */ 107 memset(&ev, 0, sizeof(ev)); 108 ev.flags = 0; 109 ev.type = SNDRV_SEQ_EVENT_ECHO; 110 ev.time.tick = time; 111 /* echo back to itself */ 112 snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port); 113 rec = (union evrec *)&ev.data; 114 rec->t.code = SEQ_SYNCTIMER; 115 rec->t.time = time; 116 q->sync_event_put = 1; 117 snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0); 118 } 119 120 wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ); 121 if (signal_pending(current)) 122 /* interrupted - return 0 to finish sync */ 123 q->sync_event_put = 0; 124 if (! q->sync_event_put || q->sync_time >= time) 125 return 0; 126 return 1; 127} 128 129/* 130 * wake up sync - echo event was catched 131 */ 132void 133snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time) 134{ 135 unsigned long flags; 136 137 spin_lock_irqsave(&q->sync_lock, flags); 138 q->sync_time = time; 139 q->sync_event_put = 0; 140 if (waitqueue_active(&q->sync_sleep)) { 141 wake_up(&q->sync_sleep); 142 } 143 spin_unlock_irqrestore(&q->sync_lock, flags); 144} 145 146 147/* 148 * return the unused pool size 149 */ 150int 151snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q) 152{ 153 struct snd_seq_client_pool pool; 154 pool.client = q->dp->cseq; 155 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool); 156 return pool.output_free; 157} 158 159 160/* 161 * set output threshold size from ioctl 162 */ 163void 164snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val) 165{ 166 struct snd_seq_client_pool pool; 167 pool.client = q->dp->cseq; 168 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool); 169 pool.output_room = val; 170 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool); 171} 172