1/* 2 * sound/sys_timer.c 3 * 4 * The default timer for the Level 2 sequencer interface 5 * Uses the (1/HZ sec) timer of kernel. 6 */ 7/* 8 * Copyright (C) by Hannu Savolainen 1993-1997 9 * 10 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 11 * Version 2 (June 1991). See the "COPYING" file distributed with this software 12 * for more info. 13 */ 14/* 15 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) 16 * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow) 17 */ 18#include "sound_config.h" 19 20static volatile int opened = 0, tmr_running = 0; 21static volatile time_t tmr_offs, tmr_ctr; 22static volatile unsigned long ticks_offs; 23static volatile int curr_tempo, curr_timebase; 24static volatile unsigned long curr_ticks; 25static volatile unsigned long next_event_time; 26static unsigned long prev_event_time; 27 28static void poll_def_tmr(unsigned long dummy); 29 30 31static struct timer_list def_tmr = 32{function: poll_def_tmr}; 33 34static unsigned long 35tmr2ticks(int tmr_value) 36{ 37 /* 38 * Convert timer ticks to MIDI ticks 39 */ 40 41 unsigned long tmp; 42 unsigned long scale; 43 44 /* tmr_value (ticks per sec) * 45 1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */ 46 tmp = tmr_value * (1000000 / HZ); 47 scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ 48 return (tmp + scale / 2) / scale; 49} 50 51static void 52poll_def_tmr(unsigned long dummy) 53{ 54 55 if (opened) 56 { 57 58 { 59 def_tmr.expires = (1) + jiffies; 60 add_timer(&def_tmr); 61 }; 62 63 if (tmr_running) 64 { 65 tmr_ctr++; 66 curr_ticks = ticks_offs + tmr2ticks(tmr_ctr); 67 68 if (curr_ticks >= next_event_time) 69 { 70 next_event_time = (unsigned long) -1; 71 sequencer_timer(0); 72 } 73 } 74 } 75} 76 77static void 78tmr_reset(void) 79{ 80 unsigned long flags; 81 82 save_flags(flags); 83 cli(); 84 tmr_offs = 0; 85 ticks_offs = 0; 86 tmr_ctr = 0; 87 next_event_time = (unsigned long) -1; 88 prev_event_time = 0; 89 curr_ticks = 0; 90 restore_flags(flags); 91} 92 93static int 94def_tmr_open(int dev, int mode) 95{ 96 if (opened) 97 return -EBUSY; 98 99 tmr_reset(); 100 curr_tempo = 60; 101 curr_timebase = 100; 102 opened = 1; 103 104 ; 105 106 { 107 def_tmr.expires = (1) + jiffies; 108 add_timer(&def_tmr); 109 }; 110 111 return 0; 112} 113 114static void 115def_tmr_close(int dev) 116{ 117 opened = tmr_running = 0; 118 del_timer(&def_tmr);; 119} 120 121static int 122def_tmr_event(int dev, unsigned char *event) 123{ 124 unsigned char cmd = event[1]; 125 unsigned long parm = *(int *) &event[4]; 126 127 switch (cmd) 128 { 129 case TMR_WAIT_REL: 130 parm += prev_event_time; 131 case TMR_WAIT_ABS: 132 if (parm > 0) 133 { 134 long time; 135 136 if (parm <= curr_ticks) /* It's the time */ 137 return TIMER_NOT_ARMED; 138 139 time = parm; 140 next_event_time = prev_event_time = time; 141 142 return TIMER_ARMED; 143 } 144 break; 145 146 case TMR_START: 147 tmr_reset(); 148 tmr_running = 1; 149 break; 150 151 case TMR_STOP: 152 tmr_running = 0; 153 break; 154 155 case TMR_CONTINUE: 156 tmr_running = 1; 157 break; 158 159 case TMR_TEMPO: 160 if (parm) 161 { 162 if (parm < 8) 163 parm = 8; 164 if (parm > 360) 165 parm = 360; 166 tmr_offs = tmr_ctr; 167 ticks_offs += tmr2ticks(tmr_ctr); 168 tmr_ctr = 0; 169 curr_tempo = parm; 170 } 171 break; 172 173 case TMR_ECHO: 174 seq_copy_to_input(event, 8); 175 break; 176 177 default:; 178 } 179 180 return TIMER_NOT_ARMED; 181} 182 183static unsigned long 184def_tmr_get_time(int dev) 185{ 186 if (!opened) 187 return 0; 188 189 return curr_ticks; 190} 191 192/* same as sound_timer.c:timer_ioctl!? */ 193static int def_tmr_ioctl(int dev, unsigned int cmd, caddr_t arg) 194{ 195 int val; 196 197 switch (cmd) { 198 case SNDCTL_TMR_SOURCE: 199 return __put_user(TMR_INTERNAL, (int *)arg); 200 201 case SNDCTL_TMR_START: 202 tmr_reset(); 203 tmr_running = 1; 204 return 0; 205 206 case SNDCTL_TMR_STOP: 207 tmr_running = 0; 208 return 0; 209 210 case SNDCTL_TMR_CONTINUE: 211 tmr_running = 1; 212 return 0; 213 214 case SNDCTL_TMR_TIMEBASE: 215 if (__get_user(val, (int *)arg)) 216 return -EFAULT; 217 if (val) { 218 if (val < 1) 219 val = 1; 220 if (val > 1000) 221 val = 1000; 222 curr_timebase = val; 223 } 224 return __put_user(curr_timebase, (int *)arg); 225 226 case SNDCTL_TMR_TEMPO: 227 if (__get_user(val, (int *)arg)) 228 return -EFAULT; 229 if (val) { 230 if (val < 8) 231 val = 8; 232 if (val > 250) 233 val = 250; 234 tmr_offs = tmr_ctr; 235 ticks_offs += tmr2ticks(tmr_ctr); 236 tmr_ctr = 0; 237 curr_tempo = val; 238 reprogram_timer(); 239 } 240 return __put_user(curr_tempo, (int *)arg); 241 242 case SNDCTL_SEQ_CTRLRATE: 243 if (__get_user(val, (int *)arg)) 244 return -EFAULT; 245 if (val != 0) /* Can't change */ 246 return -EINVAL; 247 val = ((curr_tempo * curr_timebase) + 30) / 60; 248 return __put_user(val, (int *)arg); 249 250 case SNDCTL_SEQ_GETTIME: 251 return __put_user(curr_ticks, (int *)arg); 252 253 case SNDCTL_TMR_METRONOME: 254 /* NOP */ 255 break; 256 257 default:; 258 } 259 return -EINVAL; 260} 261 262static void 263def_tmr_arm(int dev, long time) 264{ 265 if (time < 0) 266 time = curr_ticks + 1; 267 else if (time <= curr_ticks) /* It's the time */ 268 return; 269 270 next_event_time = prev_event_time = time; 271 272 return; 273} 274 275struct sound_timer_operations default_sound_timer = 276{ 277 owner: THIS_MODULE, 278 info: {"System clock", 0}, 279 priority: 0, /* Priority */ 280 devlink: 0, /* Local device link */ 281 open: def_tmr_open, 282 close: def_tmr_close, 283 event: def_tmr_event, 284 get_time: def_tmr_get_time, 285 ioctl: def_tmr_ioctl, 286 arm_timer: def_tmr_arm 287}; 288