Branch data Line data Source code
1 : : /*
2 : : * Digital Audio (PCM) abstract layer
3 : : * Copyright (c) by Jaroslav Kysela <perex@perex.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 <linux/time.h>
23 : : #include <linux/gcd.h>
24 : : #include <sound/core.h>
25 : : #include <sound/pcm.h>
26 : : #include <sound/timer.h>
27 : :
28 : : /*
29 : : * Timer functions
30 : : */
31 : :
32 : 0 : void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
33 : : {
34 : : unsigned long rate, mult, fsize, l, post;
35 : 0 : struct snd_pcm_runtime *runtime = substream->runtime;
36 : :
37 : : mult = 1000000000;
38 : 0 : rate = runtime->rate;
39 [ # # ]: 0 : if (snd_BUG_ON(!rate))
40 : : return;
41 : 0 : l = gcd(mult, rate);
42 : 0 : mult /= l;
43 : 0 : rate /= l;
44 : 0 : fsize = runtime->period_size;
45 [ # # ]: 0 : if (snd_BUG_ON(!fsize))
46 : : return;
47 : 0 : l = gcd(rate, fsize);
48 : 0 : rate /= l;
49 : 0 : fsize /= l;
50 : : post = 1;
51 [ # # ]: 0 : while ((mult * fsize) / fsize != mult) {
52 : 0 : mult /= 2;
53 : 0 : post *= 2;
54 : : }
55 [ # # ]: 0 : if (rate == 0) {
56 : 0 : snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
57 : 0 : runtime->timer_resolution = -1;
58 : 0 : return;
59 : : }
60 : 0 : runtime->timer_resolution = (mult * fsize / rate) * post;
61 : : }
62 : :
63 : 0 : static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
64 : : {
65 : : struct snd_pcm_substream *substream;
66 : :
67 : 0 : substream = timer->private_data;
68 [ # # ]: 0 : return substream->runtime ? substream->runtime->timer_resolution : 0;
69 : : }
70 : :
71 : 0 : static int snd_pcm_timer_start(struct snd_timer * timer)
72 : : {
73 : : struct snd_pcm_substream *substream;
74 : :
75 : 0 : substream = snd_timer_chip(timer);
76 : 0 : substream->timer_running = 1;
77 : 0 : return 0;
78 : : }
79 : :
80 : 0 : static int snd_pcm_timer_stop(struct snd_timer * timer)
81 : : {
82 : : struct snd_pcm_substream *substream;
83 : :
84 : 0 : substream = snd_timer_chip(timer);
85 : 0 : substream->timer_running = 0;
86 : 0 : return 0;
87 : : }
88 : :
89 : : static struct snd_timer_hardware snd_pcm_timer =
90 : : {
91 : : .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE,
92 : : .resolution = 0,
93 : : .ticks = 1,
94 : : .c_resolution = snd_pcm_timer_resolution,
95 : : .start = snd_pcm_timer_start,
96 : : .stop = snd_pcm_timer_stop,
97 : : };
98 : :
99 : : /*
100 : : * Init functions
101 : : */
102 : :
103 : 0 : static void snd_pcm_timer_free(struct snd_timer *timer)
104 : : {
105 : 0 : struct snd_pcm_substream *substream = timer->private_data;
106 : 0 : substream->timer = NULL;
107 : 0 : }
108 : :
109 : 0 : void snd_pcm_timer_init(struct snd_pcm_substream *substream)
110 : : {
111 : : struct snd_timer_id tid;
112 : : struct snd_timer *timer;
113 : :
114 : 0 : tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
115 : 0 : tid.dev_class = SNDRV_TIMER_CLASS_PCM;
116 : 0 : tid.card = substream->pcm->card->number;
117 : 0 : tid.device = substream->pcm->device;
118 : 0 : tid.subdevice = (substream->number << 1) | (substream->stream & 1);
119 [ # # ]: 0 : if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0)
120 : 0 : return;
121 [ # # ]: 0 : sprintf(timer->name, "PCM %s %i-%i-%i",
122 : 0 : substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
123 : : "capture" : "playback",
124 : : tid.card, tid.device, tid.subdevice);
125 : 0 : timer->hw = snd_pcm_timer;
126 [ # # ]: 0 : if (snd_device_register(timer->card, timer) < 0) {
127 : 0 : snd_device_free(timer->card, timer);
128 : 0 : return;
129 : : }
130 : 0 : timer->private_data = substream;
131 : 0 : timer->private_free = snd_pcm_timer_free;
132 : 0 : substream->timer = timer;
133 : : }
134 : :
135 : 0 : void snd_pcm_timer_done(struct snd_pcm_substream *substream)
136 : : {
137 [ # # ]: 0 : if (substream->timer) {
138 : 0 : snd_device_free(substream->pcm->card, substream->timer);
139 : 0 : substream->timer = NULL;
140 : : }
141 : 0 : }
|