diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/core/pcm_timer.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/core/pcm_timer.c')
-rw-r--r-- | sound/core/pcm_timer.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c new file mode 100644 index 000000000000..884eaea31fec --- /dev/null +++ b/sound/core/pcm_timer.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * Digital Audio (PCM) abstract layer | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/timer.h> | ||
27 | |||
28 | /* | ||
29 | * Timer functions | ||
30 | */ | ||
31 | |||
32 | /* Greatest common divisor */ | ||
33 | static unsigned long gcd(unsigned long a, unsigned long b) | ||
34 | { | ||
35 | unsigned long r; | ||
36 | if (a < b) { | ||
37 | r = a; | ||
38 | a = b; | ||
39 | b = r; | ||
40 | } | ||
41 | while ((r = a % b) != 0) { | ||
42 | a = b; | ||
43 | b = r; | ||
44 | } | ||
45 | return b; | ||
46 | } | ||
47 | |||
48 | void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream) | ||
49 | { | ||
50 | unsigned long rate, mult, fsize, l, post; | ||
51 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
52 | |||
53 | mult = 1000000000; | ||
54 | rate = runtime->rate; | ||
55 | snd_assert(rate != 0, return); | ||
56 | l = gcd(mult, rate); | ||
57 | mult /= l; | ||
58 | rate /= l; | ||
59 | fsize = runtime->period_size; | ||
60 | snd_assert(fsize != 0, return); | ||
61 | l = gcd(rate, fsize); | ||
62 | rate /= l; | ||
63 | fsize /= l; | ||
64 | post = 1; | ||
65 | while ((mult * fsize) / fsize != mult) { | ||
66 | mult /= 2; | ||
67 | post *= 2; | ||
68 | } | ||
69 | if (rate == 0) { | ||
70 | snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size); | ||
71 | runtime->timer_resolution = -1; | ||
72 | return; | ||
73 | } | ||
74 | runtime->timer_resolution = (mult * fsize / rate) * post; | ||
75 | } | ||
76 | |||
77 | static unsigned long snd_pcm_timer_resolution(snd_timer_t * timer) | ||
78 | { | ||
79 | snd_pcm_substream_t * substream; | ||
80 | |||
81 | substream = timer->private_data; | ||
82 | return substream->runtime ? substream->runtime->timer_resolution : 0; | ||
83 | } | ||
84 | |||
85 | static int snd_pcm_timer_start(snd_timer_t * timer) | ||
86 | { | ||
87 | unsigned long flags; | ||
88 | snd_pcm_substream_t * substream; | ||
89 | |||
90 | substream = snd_timer_chip(timer); | ||
91 | spin_lock_irqsave(&substream->timer_lock, flags); | ||
92 | substream->timer_running = 1; | ||
93 | spin_unlock_irqrestore(&substream->timer_lock, flags); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int snd_pcm_timer_stop(snd_timer_t * timer) | ||
98 | { | ||
99 | unsigned long flags; | ||
100 | snd_pcm_substream_t * substream; | ||
101 | |||
102 | substream = snd_timer_chip(timer); | ||
103 | spin_lock_irqsave(&substream->timer_lock, flags); | ||
104 | substream->timer_running = 0; | ||
105 | spin_unlock_irqrestore(&substream->timer_lock, flags); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static struct _snd_timer_hardware snd_pcm_timer = | ||
110 | { | ||
111 | .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE, | ||
112 | .resolution = 0, | ||
113 | .ticks = 1, | ||
114 | .c_resolution = snd_pcm_timer_resolution, | ||
115 | .start = snd_pcm_timer_start, | ||
116 | .stop = snd_pcm_timer_stop, | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * Init functions | ||
121 | */ | ||
122 | |||
123 | static void snd_pcm_timer_free(snd_timer_t *timer) | ||
124 | { | ||
125 | snd_pcm_substream_t *substream = timer->private_data; | ||
126 | substream->timer = NULL; | ||
127 | } | ||
128 | |||
129 | void snd_pcm_timer_init(snd_pcm_substream_t *substream) | ||
130 | { | ||
131 | snd_timer_id_t tid; | ||
132 | snd_timer_t *timer; | ||
133 | |||
134 | tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; | ||
135 | tid.dev_class = SNDRV_TIMER_CLASS_PCM; | ||
136 | tid.card = substream->pcm->card->number; | ||
137 | tid.device = substream->pcm->device; | ||
138 | tid.subdevice = (substream->number << 1) | (substream->stream & 1); | ||
139 | if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0) | ||
140 | return; | ||
141 | sprintf(timer->name, "PCM %s %i-%i-%i", | ||
142 | substream->stream == SNDRV_PCM_STREAM_CAPTURE ? | ||
143 | "capture" : "playback", | ||
144 | tid.card, tid.device, tid.subdevice); | ||
145 | timer->hw = snd_pcm_timer; | ||
146 | if (snd_device_register(timer->card, timer) < 0) { | ||
147 | snd_device_free(timer->card, timer); | ||
148 | return; | ||
149 | } | ||
150 | timer->private_data = substream; | ||
151 | timer->private_free = snd_pcm_timer_free; | ||
152 | substream->timer = timer; | ||
153 | } | ||
154 | |||
155 | void snd_pcm_timer_done(snd_pcm_substream_t *substream) | ||
156 | { | ||
157 | if (substream->timer) { | ||
158 | snd_device_free(substream->pcm->card, substream->timer); | ||
159 | substream->timer = NULL; | ||
160 | } | ||
161 | } | ||