Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
sound
core
seq
oss
seq_oss_timer.c
Go to the documentation of this file.
1
/*
2
* OSS compatible sequencer driver
3
*
4
* Timer control routines
5
*
6
* Copyright (C) 1998,99 Takashi Iwai <
[email protected]
>
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*/
22
23
#include "
seq_oss_timer.h
"
24
#include "
seq_oss_event.h
"
25
#include <
sound/seq_oss_legacy.h
>
26
#include <linux/slab.h>
27
28
/*
29
*/
30
#define MIN_OSS_TEMPO 8
31
#define MAX_OSS_TEMPO 360
32
#define MIN_OSS_TIMEBASE 1
33
#define MAX_OSS_TIMEBASE 1000
34
35
/*
36
*/
37
static
void
calc_alsa_tempo(
struct
seq_oss_timer
*
timer
);
38
static
int
send_timer_event(
struct
seq_oss_devinfo
*
dp
,
int
type
,
int
value
);
39
40
41
/*
42
* create and register a new timer.
43
* if queue is not started yet, start it.
44
*/
45
struct
seq_oss_timer
*
46
snd_seq_oss_timer_new
(
struct
seq_oss_devinfo
*
dp
)
47
{
48
struct
seq_oss_timer
*rec;
49
50
rec = kzalloc(
sizeof
(*rec),
GFP_KERNEL
);
51
if
(rec ==
NULL
)
52
return
NULL
;
53
54
rec->
dp
=
dp
;
55
rec->
cur_tick
= 0;
56
rec->
realtime
= 0;
57
rec->
running
= 0;
58
rec->
oss_tempo
= 60;
59
rec->
oss_timebase
= 100;
60
calc_alsa_tempo(rec);
61
62
return
rec;
63
}
64
65
66
/*
67
* delete timer.
68
* if no more timer exists, stop the queue.
69
*/
70
void
71
snd_seq_oss_timer_delete
(
struct
seq_oss_timer
*rec)
72
{
73
if
(rec) {
74
snd_seq_oss_timer_stop
(rec);
75
kfree
(rec);
76
}
77
}
78
79
80
/*
81
* process one timing event
82
* return 1 : event proceseed -- skip this event
83
* 0 : not a timer event -- enqueue this event
84
*/
85
int
86
snd_seq_oss_process_timer_event
(
struct
seq_oss_timer
*rec,
union
evrec
*ev)
87
{
88
abstime_t
parm
= ev->
t
.time;
89
90
if
(ev->
t
.code ==
EV_TIMING
) {
91
switch
(ev->
t
.cmd) {
92
case
TMR_WAIT_REL
:
93
parm += rec->
cur_tick
;
94
rec->
realtime
= 0;
95
/* continue to next */
96
case
TMR_WAIT_ABS
:
97
if
(parm == 0) {
98
rec->
realtime
= 1;
99
}
else
if
(parm >= rec->
cur_tick
) {
100
rec->
realtime
= 0;
101
rec->
cur_tick
=
parm
;
102
}
103
return
1;
/* skip this event */
104
105
case
TMR_START
:
106
snd_seq_oss_timer_start
(rec);
107
return
1;
108
109
}
110
}
else
if
(ev->
s
.code ==
SEQ_WAIT
) {
111
/* time = from 1 to 3 bytes */
112
parm = (ev->
echo
>> 8) & 0xffffff;
113
if
(parm > rec->
cur_tick
) {
114
/* set next event time */
115
rec->
cur_tick
=
parm
;
116
rec->
realtime
= 0;
117
}
118
return
1;
119
}
120
121
return
0;
122
}
123
124
125
/*
126
* convert tempo units
127
*/
128
static
void
129
calc_alsa_tempo(
struct
seq_oss_timer
*
timer
)
130
{
131
timer->
tempo
= (60 * 1000000) / timer->
oss_tempo
;
132
timer->
ppq
= timer->
oss_timebase
;
133
}
134
135
136
/*
137
* dispatch a timer event
138
*/
139
static
int
140
send_timer_event(
struct
seq_oss_devinfo
*
dp
,
int
type
,
int
value
)
141
{
142
struct
snd_seq_event
ev;
143
144
memset
(&ev, 0,
sizeof
(ev));
145
ev.type =
type
;
146
ev.source.client = dp->
cseq
;
147
ev.source.port = 0;
148
ev.dest.client =
SNDRV_SEQ_CLIENT_SYSTEM
;
149
ev.dest.port =
SNDRV_SEQ_PORT_SYSTEM_TIMER
;
150
ev.queue = dp->
queue
;
151
ev.data.queue.queue = dp->
queue
;
152
ev.data.queue.param.value =
value
;
153
return
snd_seq_kernel_client_dispatch
(dp->
cseq
, &ev, 1, 0);
154
}
155
156
/*
157
* set queue tempo and start queue
158
*/
159
int
160
snd_seq_oss_timer_start
(
struct
seq_oss_timer
*
timer
)
161
{
162
struct
seq_oss_devinfo
*dp = timer->
dp
;
163
struct
snd_seq_queue_tempo
tmprec;
164
165
if
(timer->
running
)
166
snd_seq_oss_timer_stop
(timer);
167
168
memset
(&tmprec, 0,
sizeof
(tmprec));
169
tmprec.
queue
= dp->
queue
;
170
tmprec.
ppq
= timer->
ppq
;
171
tmprec.
tempo
= timer->
tempo
;
172
snd_seq_set_queue_tempo
(dp->
cseq
, &tmprec);
173
174
send_timer_event(dp,
SNDRV_SEQ_EVENT_START
, 0);
175
timer->
running
= 1;
176
timer->
cur_tick
= 0;
177
return
0;
178
}
179
180
181
/*
182
* stop queue
183
*/
184
int
185
snd_seq_oss_timer_stop
(
struct
seq_oss_timer
*
timer
)
186
{
187
if
(! timer->
running
)
188
return
0;
189
send_timer_event(timer->
dp
,
SNDRV_SEQ_EVENT_STOP
, 0);
190
timer->
running
= 0;
191
return
0;
192
}
193
194
195
/*
196
* continue queue
197
*/
198
int
199
snd_seq_oss_timer_continue
(
struct
seq_oss_timer
*
timer
)
200
{
201
if
(timer->
running
)
202
return
0;
203
send_timer_event(timer->
dp
,
SNDRV_SEQ_EVENT_CONTINUE
, 0);
204
timer->
running
= 1;
205
return
0;
206
}
207
208
209
/*
210
* change queue tempo
211
*/
212
int
213
snd_seq_oss_timer_tempo
(
struct
seq_oss_timer
*
timer
,
int
value)
214
{
215
if
(value <
MIN_OSS_TEMPO
)
216
value =
MIN_OSS_TEMPO
;
217
else
if
(value >
MAX_OSS_TEMPO
)
218
value =
MAX_OSS_TEMPO
;
219
timer->
oss_tempo
=
value
;
220
calc_alsa_tempo(timer);
221
if
(timer->
running
)
222
send_timer_event(timer->
dp
,
SNDRV_SEQ_EVENT_TEMPO
, timer->
tempo
);
223
return
0;
224
}
225
226
227
/*
228
* ioctls
229
*/
230
int
231
snd_seq_oss_timer_ioctl
(
struct
seq_oss_timer
*
timer
,
unsigned
int
cmd
,
int
__user *
arg
)
232
{
233
int
value
;
234
235
if
(cmd ==
SNDCTL_SEQ_CTRLRATE
) {
236
debug_printk
((
"ctrl rate\n"
));
237
/* if *arg == 0, just return the current rate */
238
if
(
get_user
(value, arg))
239
return
-
EFAULT
;
240
if
(value)
241
return
-
EINVAL
;
242
value = ((timer->
oss_tempo
* timer->
oss_timebase
) + 30) / 60;
243
return
put_user
(value, arg) ? -
EFAULT
: 0;
244
}
245
246
if
(timer->
dp
->seq_mode ==
SNDRV_SEQ_OSS_MODE_SYNTH
)
247
return
0;
248
249
switch
(cmd) {
250
case
SNDCTL_TMR_START
:
251
debug_printk
((
"timer start\n"
));
252
return
snd_seq_oss_timer_start
(timer);
253
case
SNDCTL_TMR_STOP
:
254
debug_printk
((
"timer stop\n"
));
255
return
snd_seq_oss_timer_stop
(timer);
256
case
SNDCTL_TMR_CONTINUE
:
257
debug_printk
((
"timer continue\n"
));
258
return
snd_seq_oss_timer_continue
(timer);
259
case
SNDCTL_TMR_TEMPO
:
260
debug_printk
((
"timer tempo\n"
));
261
if
(
get_user
(value, arg))
262
return
-
EFAULT
;
263
return
snd_seq_oss_timer_tempo
(timer, value);
264
case
SNDCTL_TMR_TIMEBASE
:
265
debug_printk
((
"timer timebase\n"
));
266
if
(
get_user
(value, arg))
267
return
-
EFAULT
;
268
if
(value <
MIN_OSS_TIMEBASE
)
269
value =
MIN_OSS_TIMEBASE
;
270
else
if
(value >
MAX_OSS_TIMEBASE
)
271
value =
MAX_OSS_TIMEBASE
;
272
timer->
oss_timebase
=
value
;
273
calc_alsa_tempo(timer);
274
return
0;
275
276
case
SNDCTL_TMR_METRONOME
:
277
case
SNDCTL_TMR_SELECT
:
278
case
SNDCTL_TMR_SOURCE
:
279
debug_printk
((
"timer XXX\n"
));
280
/* not supported */
281
return
0;
282
}
283
return
0;
284
}
Generated on Thu Jan 10 2013 15:03:59 for Linux Kernel by
1.8.2