root/sound/core/seq/oss/seq_oss_timer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_seq_oss_timer_new
  2. snd_seq_oss_timer_delete
  3. snd_seq_oss_process_timer_event
  4. calc_alsa_tempo
  5. send_timer_event
  6. snd_seq_oss_timer_start
  7. snd_seq_oss_timer_stop
  8. snd_seq_oss_timer_continue
  9. snd_seq_oss_timer_tempo
  10. snd_seq_oss_timer_ioctl

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * OSS compatible sequencer driver
   4  *
   5  * Timer control routines
   6  *
   7  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
   8  */
   9 
  10 #include "seq_oss_timer.h"
  11 #include "seq_oss_event.h"
  12 #include <sound/seq_oss_legacy.h>
  13 #include <linux/slab.h>
  14 
  15 /*
  16  */
  17 #define MIN_OSS_TEMPO           8
  18 #define MAX_OSS_TEMPO           360
  19 #define MIN_OSS_TIMEBASE        1
  20 #define MAX_OSS_TIMEBASE        1000
  21 
  22 /*
  23  */
  24 static void calc_alsa_tempo(struct seq_oss_timer *timer);
  25 static int send_timer_event(struct seq_oss_devinfo *dp, int type, int value);
  26 
  27 
  28 /*
  29  * create and register a new timer.
  30  * if queue is not started yet, start it.
  31  */
  32 struct seq_oss_timer *
  33 snd_seq_oss_timer_new(struct seq_oss_devinfo *dp)
  34 {
  35         struct seq_oss_timer *rec;
  36 
  37         rec = kzalloc(sizeof(*rec), GFP_KERNEL);
  38         if (rec == NULL)
  39                 return NULL;
  40 
  41         rec->dp = dp;
  42         rec->cur_tick = 0;
  43         rec->realtime = 0;
  44         rec->running = 0;
  45         rec->oss_tempo = 60;
  46         rec->oss_timebase = 100;
  47         calc_alsa_tempo(rec);
  48 
  49         return rec;
  50 }
  51 
  52 
  53 /*
  54  * delete timer.
  55  * if no more timer exists, stop the queue.
  56  */
  57 void
  58 snd_seq_oss_timer_delete(struct seq_oss_timer *rec)
  59 {
  60         if (rec) {
  61                 snd_seq_oss_timer_stop(rec);
  62                 kfree(rec);
  63         }
  64 }
  65 
  66 
  67 /*
  68  * process one timing event
  69  * return 1 : event proceseed -- skip this event
  70  *        0 : not a timer event -- enqueue this event
  71  */
  72 int
  73 snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
  74 {
  75         abstime_t parm = ev->t.time;
  76 
  77         if (ev->t.code == EV_TIMING) {
  78                 switch (ev->t.cmd) {
  79                 case TMR_WAIT_REL:
  80                         parm += rec->cur_tick;
  81                         rec->realtime = 0;
  82                         /* fall through */
  83                 case TMR_WAIT_ABS:
  84                         if (parm == 0) {
  85                                 rec->realtime = 1;
  86                         } else if (parm >= rec->cur_tick) {
  87                                 rec->realtime = 0;
  88                                 rec->cur_tick = parm;
  89                         }
  90                         return 1;       /* skip this event */
  91                         
  92                 case TMR_START:
  93                         snd_seq_oss_timer_start(rec);
  94                         return 1;
  95 
  96                 }
  97         } else if (ev->s.code == SEQ_WAIT) {
  98                 /* time = from 1 to 3 bytes */
  99                 parm = (ev->echo >> 8) & 0xffffff;
 100                 if (parm > rec->cur_tick) {
 101                         /* set next event time */
 102                         rec->cur_tick = parm;
 103                         rec->realtime = 0;
 104                 }
 105                 return 1;
 106         }
 107 
 108         return 0;
 109 }
 110 
 111 
 112 /*
 113  * convert tempo units
 114  */
 115 static void
 116 calc_alsa_tempo(struct seq_oss_timer *timer)
 117 {
 118         timer->tempo = (60 * 1000000) / timer->oss_tempo;
 119         timer->ppq = timer->oss_timebase;
 120 }
 121 
 122 
 123 /*
 124  * dispatch a timer event
 125  */
 126 static int
 127 send_timer_event(struct seq_oss_devinfo *dp, int type, int value)
 128 {
 129         struct snd_seq_event ev;
 130 
 131         memset(&ev, 0, sizeof(ev));
 132         ev.type = type;
 133         ev.source.client = dp->cseq;
 134         ev.source.port = 0;
 135         ev.dest.client = SNDRV_SEQ_CLIENT_SYSTEM;
 136         ev.dest.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
 137         ev.queue = dp->queue;
 138         ev.data.queue.queue = dp->queue;
 139         ev.data.queue.param.value = value;
 140         return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 1, 0);
 141 }
 142 
 143 /*
 144  * set queue tempo and start queue
 145  */
 146 int
 147 snd_seq_oss_timer_start(struct seq_oss_timer *timer)
 148 {
 149         struct seq_oss_devinfo *dp = timer->dp;
 150         struct snd_seq_queue_tempo tmprec;
 151 
 152         if (timer->running)
 153                 snd_seq_oss_timer_stop(timer);
 154 
 155         memset(&tmprec, 0, sizeof(tmprec));
 156         tmprec.queue = dp->queue;
 157         tmprec.ppq = timer->ppq;
 158         tmprec.tempo = timer->tempo;
 159         snd_seq_set_queue_tempo(dp->cseq, &tmprec);
 160 
 161         send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0);
 162         timer->running = 1;
 163         timer->cur_tick = 0;
 164         return 0;
 165 }
 166 
 167 
 168 /*
 169  * stop queue
 170  */
 171 int
 172 snd_seq_oss_timer_stop(struct seq_oss_timer *timer)
 173 {
 174         if (! timer->running)
 175                 return 0;
 176         send_timer_event(timer->dp, SNDRV_SEQ_EVENT_STOP, 0);
 177         timer->running = 0;
 178         return 0;
 179 }
 180 
 181 
 182 /*
 183  * continue queue
 184  */
 185 int
 186 snd_seq_oss_timer_continue(struct seq_oss_timer *timer)
 187 {
 188         if (timer->running)
 189                 return 0;
 190         send_timer_event(timer->dp, SNDRV_SEQ_EVENT_CONTINUE, 0);
 191         timer->running = 1;
 192         return 0;
 193 }
 194 
 195 
 196 /*
 197  * change queue tempo
 198  */
 199 int
 200 snd_seq_oss_timer_tempo(struct seq_oss_timer *timer, int value)
 201 {
 202         if (value < MIN_OSS_TEMPO)
 203                 value = MIN_OSS_TEMPO;
 204         else if (value > MAX_OSS_TEMPO)
 205                 value = MAX_OSS_TEMPO;
 206         timer->oss_tempo = value;
 207         calc_alsa_tempo(timer);
 208         if (timer->running)
 209                 send_timer_event(timer->dp, SNDRV_SEQ_EVENT_TEMPO, timer->tempo);
 210         return 0;
 211 }
 212 
 213 
 214 /*
 215  * ioctls
 216  */
 217 int
 218 snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __user *arg)
 219 {
 220         int value;
 221 
 222         if (cmd == SNDCTL_SEQ_CTRLRATE) {
 223                 /* if *arg == 0, just return the current rate */
 224                 if (get_user(value, arg))
 225                         return -EFAULT;
 226                 if (value)
 227                         return -EINVAL;
 228                 value = ((timer->oss_tempo * timer->oss_timebase) + 30) / 60;
 229                 return put_user(value, arg) ? -EFAULT : 0;
 230         }
 231 
 232         if (timer->dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
 233                 return 0;
 234 
 235         switch (cmd) {
 236         case SNDCTL_TMR_START:
 237                 return snd_seq_oss_timer_start(timer);
 238         case SNDCTL_TMR_STOP:
 239                 return snd_seq_oss_timer_stop(timer);
 240         case SNDCTL_TMR_CONTINUE:
 241                 return snd_seq_oss_timer_continue(timer);
 242         case SNDCTL_TMR_TEMPO:
 243                 if (get_user(value, arg))
 244                         return -EFAULT;
 245                 return snd_seq_oss_timer_tempo(timer, value);
 246         case SNDCTL_TMR_TIMEBASE:
 247                 if (get_user(value, arg))
 248                         return -EFAULT;
 249                 if (value < MIN_OSS_TIMEBASE)
 250                         value = MIN_OSS_TIMEBASE;
 251                 else if (value > MAX_OSS_TIMEBASE)
 252                         value = MAX_OSS_TIMEBASE;
 253                 timer->oss_timebase = value;
 254                 calc_alsa_tempo(timer);
 255                 return 0;
 256 
 257         case SNDCTL_TMR_METRONOME:
 258         case SNDCTL_TMR_SELECT:
 259         case SNDCTL_TMR_SOURCE:
 260                 /* not supported */
 261                 return 0;
 262         }
 263         return 0;
 264 }

/* [<][>][^][v][top][bottom][index][help] */