sound_timer.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * sound/oss/sound_timer.c
  3. */
  4. /*
  5. * Copyright (C) by Hannu Savolainen 1993-1997
  6. *
  7. * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  8. * Version 2 (June 1991). See the "COPYING" file distributed with this software
  9. * for more info.
  10. */
  11. /*
  12. * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
  13. */
  14. #include <linux/string.h>
  15. #include <linux/spinlock.h>
  16. #include "sound_config.h"
  17. static volatile int initialized, opened, tmr_running;
  18. static volatile time_t tmr_offs, tmr_ctr;
  19. static volatile unsigned long ticks_offs;
  20. static volatile int curr_tempo, curr_timebase;
  21. static volatile unsigned long curr_ticks;
  22. static volatile unsigned long next_event_time;
  23. static unsigned long prev_event_time;
  24. static volatile unsigned long usecs_per_tmr; /* Length of the current interval */
  25. static struct sound_lowlev_timer *tmr;
  26. static DEFINE_SPINLOCK(lock);
  27. static unsigned long tmr2ticks(int tmr_value)
  28. {
  29. /*
  30. * Convert timer ticks to MIDI ticks
  31. */
  32. unsigned long tmp;
  33. unsigned long scale;
  34. tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */
  35. scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */
  36. return (tmp + (scale / 2)) / scale;
  37. }
  38. void reprogram_timer(void)
  39. {
  40. unsigned long usecs_per_tick;
  41. /*
  42. * The user is changing the timer rate before setting a timer
  43. * slap, bad bad not allowed.
  44. */
  45. if(!tmr)
  46. return;
  47. usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
  48. /*
  49. * Don't kill the system by setting too high timer rate
  50. */
  51. if (usecs_per_tick < 2000)
  52. usecs_per_tick = 2000;
  53. usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick);
  54. }
  55. void sound_timer_syncinterval(unsigned int new_usecs)
  56. {
  57. /*
  58. * This routine is called by the hardware level if
  59. * the clock frequency has changed for some reason.
  60. */
  61. tmr_offs = tmr_ctr;
  62. ticks_offs += tmr2ticks(tmr_ctr);
  63. tmr_ctr = 0;
  64. usecs_per_tmr = new_usecs;
  65. }
  66. EXPORT_SYMBOL(sound_timer_syncinterval);
  67. static void tmr_reset(void)
  68. {
  69. unsigned long flags;
  70. spin_lock_irqsave(&lock,flags);
  71. tmr_offs = 0;
  72. ticks_offs = 0;
  73. tmr_ctr = 0;
  74. next_event_time = (unsigned long) -1;
  75. prev_event_time = 0;
  76. curr_ticks = 0;
  77. spin_unlock_irqrestore(&lock,flags);
  78. }
  79. static int timer_open(int dev, int mode)
  80. {
  81. if (opened)
  82. return -EBUSY;
  83. tmr_reset();
  84. curr_tempo = 60;
  85. curr_timebase = 100;
  86. opened = 1;
  87. reprogram_timer();
  88. return 0;
  89. }
  90. static void timer_close(int dev)
  91. {
  92. opened = tmr_running = 0;
  93. tmr->tmr_disable(tmr->dev);
  94. }
  95. static int timer_event(int dev, unsigned char *event)
  96. {
  97. unsigned char cmd = event[1];
  98. unsigned long parm = *(int *) &event[4];
  99. switch (cmd)
  100. {
  101. case TMR_WAIT_REL:
  102. parm += prev_event_time;
  103. case TMR_WAIT_ABS:
  104. if (parm > 0)
  105. {
  106. long time;
  107. if (parm <= curr_ticks) /* It's the time */
  108. return TIMER_NOT_ARMED;
  109. time = parm;
  110. next_event_time = prev_event_time = time;
  111. return TIMER_ARMED;
  112. }
  113. break;
  114. case TMR_START:
  115. tmr_reset();
  116. tmr_running = 1;
  117. reprogram_timer();
  118. break;
  119. case TMR_STOP:
  120. tmr_running = 0;
  121. break;
  122. case TMR_CONTINUE:
  123. tmr_running = 1;
  124. reprogram_timer();
  125. break;
  126. case TMR_TEMPO:
  127. if (parm)
  128. {
  129. if (parm < 8)
  130. parm = 8;
  131. if (parm > 250)
  132. parm = 250;
  133. tmr_offs = tmr_ctr;
  134. ticks_offs += tmr2ticks(tmr_ctr);
  135. tmr_ctr = 0;
  136. curr_tempo = parm;
  137. reprogram_timer();
  138. }
  139. break;
  140. case TMR_ECHO:
  141. seq_copy_to_input(event, 8);
  142. break;
  143. default:;
  144. }
  145. return TIMER_NOT_ARMED;
  146. }
  147. static unsigned long timer_get_time(int dev)
  148. {
  149. if (!opened)
  150. return 0;
  151. return curr_ticks;
  152. }
  153. static int timer_ioctl(int dev, unsigned int cmd, void __user *arg)
  154. {
  155. int __user *p = arg;
  156. int val;
  157. switch (cmd)
  158. {
  159. case SNDCTL_TMR_SOURCE:
  160. val = TMR_INTERNAL;
  161. break;
  162. case SNDCTL_TMR_START:
  163. tmr_reset();
  164. tmr_running = 1;
  165. return 0;
  166. case SNDCTL_TMR_STOP:
  167. tmr_running = 0;
  168. return 0;
  169. case SNDCTL_TMR_CONTINUE:
  170. tmr_running = 1;
  171. return 0;
  172. case SNDCTL_TMR_TIMEBASE:
  173. if (get_user(val, p))
  174. return -EFAULT;
  175. if (val)
  176. {
  177. if (val < 1)
  178. val = 1;
  179. if (val > 1000)
  180. val = 1000;
  181. curr_timebase = val;
  182. }
  183. val = curr_timebase;
  184. break;
  185. case SNDCTL_TMR_TEMPO:
  186. if (get_user(val, p))
  187. return -EFAULT;
  188. if (val)
  189. {
  190. if (val < 8)
  191. val = 8;
  192. if (val > 250)
  193. val = 250;
  194. tmr_offs = tmr_ctr;
  195. ticks_offs += tmr2ticks(tmr_ctr);
  196. tmr_ctr = 0;
  197. curr_tempo = val;
  198. reprogram_timer();
  199. }
  200. val = curr_tempo;
  201. break;
  202. case SNDCTL_SEQ_CTRLRATE:
  203. if (get_user(val, p))
  204. return -EFAULT;
  205. if (val != 0) /* Can't change */
  206. return -EINVAL;
  207. val = ((curr_tempo * curr_timebase) + 30) / 60;
  208. break;
  209. case SNDCTL_SEQ_GETTIME:
  210. val = curr_ticks;
  211. break;
  212. case SNDCTL_TMR_METRONOME:
  213. default:
  214. return -EINVAL;
  215. }
  216. return put_user(val, p);
  217. }
  218. static void timer_arm(int dev, long time)
  219. {
  220. if (time < 0)
  221. time = curr_ticks + 1;
  222. else if (time <= curr_ticks) /* It's the time */
  223. return;
  224. next_event_time = prev_event_time = time;
  225. return;
  226. }
  227. static struct sound_timer_operations sound_timer =
  228. {
  229. .owner = THIS_MODULE,
  230. .info = {"Sound Timer", 0},
  231. .priority = 1, /* Priority */
  232. .devlink = 0, /* Local device link */
  233. .open = timer_open,
  234. .close = timer_close,
  235. .event = timer_event,
  236. .get_time = timer_get_time,
  237. .ioctl = timer_ioctl,
  238. .arm_timer = timer_arm
  239. };
  240. void sound_timer_interrupt(void)
  241. {
  242. unsigned long flags;
  243. if (!opened)
  244. return;
  245. tmr->tmr_restart(tmr->dev);
  246. if (!tmr_running)
  247. return;
  248. spin_lock_irqsave(&lock,flags);
  249. tmr_ctr++;
  250. curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
  251. if (curr_ticks >= next_event_time)
  252. {
  253. next_event_time = (unsigned long) -1;
  254. sequencer_timer(0);
  255. }
  256. spin_unlock_irqrestore(&lock,flags);
  257. }
  258. EXPORT_SYMBOL(sound_timer_interrupt);
  259. void sound_timer_init(struct sound_lowlev_timer *t, char *name)
  260. {
  261. int n;
  262. if (initialized)
  263. {
  264. if (t->priority <= tmr->priority)
  265. return; /* There is already a similar or better timer */
  266. tmr = t;
  267. return;
  268. }
  269. initialized = 1;
  270. tmr = t;
  271. n = sound_alloc_timerdev();
  272. if (n == -1)
  273. n = 0; /* Overwrite the system timer */
  274. strcpy(sound_timer.info.name, name);
  275. sound_timer_devs[n] = &sound_timer;
  276. }
  277. EXPORT_SYMBOL(sound_timer_init);