sound_timer.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * sound/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 spinlock_t 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. static void tmr_reset(void)
  67. {
  68. unsigned long flags;
  69. spin_lock_irqsave(&lock,flags);
  70. tmr_offs = 0;
  71. ticks_offs = 0;
  72. tmr_ctr = 0;
  73. next_event_time = (unsigned long) -1;
  74. prev_event_time = 0;
  75. curr_ticks = 0;
  76. spin_unlock_irqrestore(&lock,flags);
  77. }
  78. static int timer_open(int dev, int mode)
  79. {
  80. if (opened)
  81. return -EBUSY;
  82. tmr_reset();
  83. curr_tempo = 60;
  84. curr_timebase = 100;
  85. opened = 1;
  86. reprogram_timer();
  87. return 0;
  88. }
  89. static void timer_close(int dev)
  90. {
  91. opened = tmr_running = 0;
  92. tmr->tmr_disable(tmr->dev);
  93. }
  94. static int timer_event(int dev, unsigned char *event)
  95. {
  96. unsigned char cmd = event[1];
  97. unsigned long parm = *(int *) &event[4];
  98. switch (cmd)
  99. {
  100. case TMR_WAIT_REL:
  101. parm += prev_event_time;
  102. case TMR_WAIT_ABS:
  103. if (parm > 0)
  104. {
  105. long time;
  106. if (parm <= curr_ticks) /* It's the time */
  107. return TIMER_NOT_ARMED;
  108. time = parm;
  109. next_event_time = prev_event_time = time;
  110. return TIMER_ARMED;
  111. }
  112. break;
  113. case TMR_START:
  114. tmr_reset();
  115. tmr_running = 1;
  116. reprogram_timer();
  117. break;
  118. case TMR_STOP:
  119. tmr_running = 0;
  120. break;
  121. case TMR_CONTINUE:
  122. tmr_running = 1;
  123. reprogram_timer();
  124. break;
  125. case TMR_TEMPO:
  126. if (parm)
  127. {
  128. if (parm < 8)
  129. parm = 8;
  130. if (parm > 250)
  131. parm = 250;
  132. tmr_offs = tmr_ctr;
  133. ticks_offs += tmr2ticks(tmr_ctr);
  134. tmr_ctr = 0;
  135. curr_tempo = parm;
  136. reprogram_timer();
  137. }
  138. break;
  139. case TMR_ECHO:
  140. seq_copy_to_input(event, 8);
  141. break;
  142. default:;
  143. }
  144. return TIMER_NOT_ARMED;
  145. }
  146. static unsigned long timer_get_time(int dev)
  147. {
  148. if (!opened)
  149. return 0;
  150. return curr_ticks;
  151. }
  152. static int timer_ioctl(int dev, unsigned int cmd, void __user *arg)
  153. {
  154. int __user *p = arg;
  155. int val;
  156. switch (cmd)
  157. {
  158. case SNDCTL_TMR_SOURCE:
  159. val = TMR_INTERNAL;
  160. break;
  161. case SNDCTL_TMR_START:
  162. tmr_reset();
  163. tmr_running = 1;
  164. return 0;
  165. case SNDCTL_TMR_STOP:
  166. tmr_running = 0;
  167. return 0;
  168. case SNDCTL_TMR_CONTINUE:
  169. tmr_running = 1;
  170. return 0;
  171. case SNDCTL_TMR_TIMEBASE:
  172. if (get_user(val, p))
  173. return -EFAULT;
  174. if (val)
  175. {
  176. if (val < 1)
  177. val = 1;
  178. if (val > 1000)
  179. val = 1000;
  180. curr_timebase = val;
  181. }
  182. val = curr_timebase;
  183. break;
  184. case SNDCTL_TMR_TEMPO:
  185. if (get_user(val, p))
  186. return -EFAULT;
  187. if (val)
  188. {
  189. if (val < 8)
  190. val = 8;
  191. if (val > 250)
  192. val = 250;
  193. tmr_offs = tmr_ctr;
  194. ticks_offs += tmr2ticks(tmr_ctr);
  195. tmr_ctr = 0;
  196. curr_tempo = val;
  197. reprogram_timer();
  198. }
  199. val = curr_tempo;
  200. break;
  201. case SNDCTL_SEQ_CTRLRATE:
  202. if (get_user(val, p))
  203. return -EFAULT;
  204. if (val != 0) /* Can't change */
  205. return -EINVAL;
  206. val = ((curr_tempo * curr_timebase) + 30) / 60;
  207. break;
  208. case SNDCTL_SEQ_GETTIME:
  209. val = curr_ticks;
  210. break;
  211. case SNDCTL_TMR_METRONOME:
  212. default:
  213. return -EINVAL;
  214. }
  215. return put_user(val, p);
  216. }
  217. static void timer_arm(int dev, long time)
  218. {
  219. if (time < 0)
  220. time = curr_ticks + 1;
  221. else if (time <= curr_ticks) /* It's the time */
  222. return;
  223. next_event_time = prev_event_time = time;
  224. return;
  225. }
  226. static struct sound_timer_operations sound_timer =
  227. {
  228. .owner = THIS_MODULE,
  229. .info = {"Sound Timer", 0},
  230. .priority = 1, /* Priority */
  231. .devlink = 0, /* Local device link */
  232. .open = timer_open,
  233. .close = timer_close,
  234. .event = timer_event,
  235. .get_time = timer_get_time,
  236. .ioctl = timer_ioctl,
  237. .arm_timer = timer_arm
  238. };
  239. void sound_timer_interrupt(void)
  240. {
  241. unsigned long flags;
  242. if (!opened)
  243. return;
  244. tmr->tmr_restart(tmr->dev);
  245. if (!tmr_running)
  246. return;
  247. spin_lock_irqsave(&lock,flags);
  248. tmr_ctr++;
  249. curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
  250. if (curr_ticks >= next_event_time)
  251. {
  252. next_event_time = (unsigned long) -1;
  253. sequencer_timer(0);
  254. }
  255. spin_unlock_irqrestore(&lock,flags);
  256. }
  257. void sound_timer_init(struct sound_lowlev_timer *t, char *name)
  258. {
  259. int n;
  260. if (initialized)
  261. {
  262. if (t->priority <= tmr->priority)
  263. return; /* There is already a similar or better timer */
  264. tmr = t;
  265. return;
  266. }
  267. initialized = 1;
  268. tmr = t;
  269. n = sound_alloc_timerdev();
  270. if (n == -1)
  271. n = 0; /* Overwrite the system timer */
  272. strcpy(sound_timer.info.name, name);
  273. sound_timer_devs[n] = &sound_timer;
  274. }