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