sound_timer.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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 "sound_config.h"
  16. static volatile int initialized, opened, tmr_running;
  17. static volatile time_t tmr_offs, tmr_ctr;
  18. static volatile unsigned long ticks_offs;
  19. static volatile int curr_tempo, curr_timebase;
  20. static volatile unsigned long curr_ticks;
  21. static volatile unsigned long next_event_time;
  22. static unsigned long prev_event_time;
  23. static volatile unsigned long usecs_per_tmr; /* Length of the current interval */
  24. static struct sound_lowlev_timer *tmr;
  25. static unsigned long tmr2ticks(int tmr_value)
  26. {
  27. /*
  28.  *    Convert timer ticks to MIDI ticks
  29.  */
  30. unsigned long tmp;
  31. unsigned long scale;
  32. tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */
  33. scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */
  34. return (tmp + (scale / 2)) / scale;
  35. }
  36. void reprogram_timer(void)
  37. {
  38. unsigned long   usecs_per_tick;
  39. /*
  40.  * The user is changing the timer rate before setting a timer
  41.  * slap, bad bad not allowed.
  42.  */
  43.  
  44. if(!tmr)
  45. return;
  46. usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
  47. /*
  48.  * Don't kill the system by setting too high timer rate
  49.  */
  50. if (usecs_per_tick < 2000)
  51. usecs_per_tick = 2000;
  52. usecs_per_tmr = tmr->tmr_start(tmr->dev, usecs_per_tick);
  53. }
  54. void sound_timer_syncinterval(unsigned int new_usecs)
  55. {
  56. /*
  57.  *    This routine is called by the hardware level if
  58.  *      the clock frequency has changed for some reason.
  59.  */
  60. tmr_offs = tmr_ctr;
  61. ticks_offs += tmr2ticks(tmr_ctr);
  62. tmr_ctr = 0;
  63. usecs_per_tmr = new_usecs;
  64. }
  65. static void tmr_reset(void)
  66. {
  67. unsigned long   flags;
  68. save_flags(flags);
  69. cli();
  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. restore_flags(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, caddr_t arg)
  153. {
  154. int val;
  155. switch (cmd) 
  156. {
  157. case SNDCTL_TMR_SOURCE:
  158. val = TMR_INTERNAL;
  159. break;
  160. case SNDCTL_TMR_START:
  161. tmr_reset();
  162. tmr_running = 1;
  163. return 0;
  164. case SNDCTL_TMR_STOP:
  165. tmr_running = 0;
  166. return 0;
  167. case SNDCTL_TMR_CONTINUE:
  168. tmr_running = 1;
  169. return 0;
  170. case SNDCTL_TMR_TIMEBASE:
  171. if (get_user(val, (int *)arg))
  172. return -EFAULT;
  173. if (val) 
  174. {
  175. if (val < 1)
  176. val = 1;
  177. if (val > 1000)
  178. val = 1000;
  179. curr_timebase = val;
  180. }
  181. val = curr_timebase;
  182. break;
  183. case SNDCTL_TMR_TEMPO:
  184. if (get_user(val, (int *)arg))
  185. return -EFAULT;
  186. if (val) 
  187. {
  188. if (val < 8)
  189. val = 8;
  190. if (val > 250)
  191. val = 250;
  192. tmr_offs = tmr_ctr;
  193. ticks_offs += tmr2ticks(tmr_ctr);
  194. tmr_ctr = 0;
  195. curr_tempo = val;
  196. reprogram_timer();
  197. }
  198. val = curr_tempo;
  199. break;
  200. case SNDCTL_SEQ_CTRLRATE:
  201. if (get_user(val, (int *)arg))
  202. return -EFAULT;
  203. if (val != 0) /* Can't change */
  204. return -EINVAL;
  205. val = ((curr_tempo * curr_timebase) + 30) / 60;
  206. break;
  207. case SNDCTL_SEQ_GETTIME:
  208. val = curr_ticks;
  209. break;
  210. case SNDCTL_TMR_METRONOME:
  211. default:
  212. return -EINVAL;
  213. }
  214. return put_user(val, (int *)arg);
  215. }
  216. static void timer_arm(int dev, long time)
  217. {
  218. if (time < 0)
  219. time = curr_ticks + 1;
  220. else if (time <= curr_ticks) /* It's the time */
  221. return;
  222. next_event_time = prev_event_time = time;
  223. return;
  224. }
  225. static struct sound_timer_operations sound_timer =
  226. {
  227. owner: THIS_MODULE,
  228. info: {"Sound Timer", 0},
  229. priority: 1, /* Priority */
  230. devlink: 0, /* Local device link */
  231. open: timer_open,
  232. close: timer_close,
  233. event: timer_event,
  234. get_time: timer_get_time,
  235. ioctl: timer_ioctl,
  236. arm_timer: timer_arm
  237. };
  238. void sound_timer_interrupt(void)
  239. {
  240. if (!opened)
  241. return;
  242. tmr->tmr_restart(tmr->dev);
  243. if (!tmr_running)
  244. return;
  245. tmr_ctr++;
  246. curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
  247. if (curr_ticks >= next_event_time)
  248. {
  249. next_event_time = (unsigned long) -1;
  250. sequencer_timer(0);
  251. }
  252. }
  253. void  sound_timer_init(struct sound_lowlev_timer *t, char *name)
  254. {
  255. int n;
  256. if (initialized)
  257. {
  258. if (t->priority <= tmr->priority)
  259. return; /* There is already a similar or better timer */
  260. tmr = t;
  261. return;
  262. }
  263. initialized = 1;
  264. tmr = t;
  265. n = sound_alloc_timerdev();
  266. if (n == -1)
  267. n = 0; /* Overwrite the system timer */
  268. strcpy(sound_timer.info.name, name);
  269. sound_timer_devs[n] = &sound_timer;
  270. }