Blame view
sound/core/rtctimer.c
4.13 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* * RTC based high-frequency timer * * Copyright (C) 2000 Takashi Iwai * based on rtctimer.c by Steve Ratcliffe * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ |
1da177e4c
|
22 |
#include <linux/init.h> |
1da177e4c
|
23 |
#include <linux/interrupt.h> |
ec2cf68e0
|
24 |
#include <linux/module.h> |
62e96a1ca
|
25 |
#include <linux/log2.h> |
1da177e4c
|
26 27 |
#include <sound/core.h> #include <sound/timer.h> |
1da177e4c
|
28 29 30 31 32 33 34 35 36 37 38 |
#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE) #include <linux/mc146818rtc.h> #define RTC_FREQ 1024 /* default frequency */ #define NANO_SEC 1000000000L /* 10^9 in sec */ /* * prototypes */ |
53d2f744a
|
39 40 41 42 |
static int rtctimer_open(struct snd_timer *t); static int rtctimer_close(struct snd_timer *t); static int rtctimer_start(struct snd_timer *t); static int rtctimer_stop(struct snd_timer *t); |
1da177e4c
|
43 44 45 46 47 |
/* * The hardware dependent description for this timer. */ |
53d2f744a
|
48 |
static struct snd_timer_hardware rtc_hw = { |
ac5d1a7d2
|
49 50 51 |
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, |
1da177e4c
|
52 53 54 55 56 57 58 59 |
.ticks = 100000000L, /* FIXME: XXX */ .open = rtctimer_open, .close = rtctimer_close, .start = rtctimer_start, .stop = rtctimer_stop, }; static int rtctimer_freq = RTC_FREQ; /* frequency */ |
53d2f744a
|
60 |
static struct snd_timer *rtctimer; |
ac5d1a7d2
|
61 |
static struct tasklet_struct rtc_tasklet; |
1da177e4c
|
62 63 64 65 |
static rtc_task_t rtc_task; static int |
53d2f744a
|
66 |
rtctimer_open(struct snd_timer *t) |
1da177e4c
|
67 68 69 70 71 72 73 74 75 76 77 |
{ int err; err = rtc_register(&rtc_task); if (err < 0) return err; t->private_data = &rtc_task; return 0; } static int |
53d2f744a
|
78 |
rtctimer_close(struct snd_timer *t) |
1da177e4c
|
79 80 81 82 |
{ rtc_task_t *rtc = t->private_data; if (rtc) { rtc_unregister(rtc); |
ac5d1a7d2
|
83 |
tasklet_kill(&rtc_tasklet); |
1da177e4c
|
84 85 86 87 88 89 |
t->private_data = NULL; } return 0; } static int |
53d2f744a
|
90 |
rtctimer_start(struct snd_timer *timer) |
1da177e4c
|
91 92 |
{ rtc_task_t *rtc = timer->private_data; |
7eaa943c8
|
93 94 |
if (snd_BUG_ON(!rtc)) return -EINVAL; |
1da177e4c
|
95 96 |
rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq); rtc_control(rtc, RTC_PIE_ON, 0); |
1da177e4c
|
97 98 99 100 |
return 0; } static int |
53d2f744a
|
101 |
rtctimer_stop(struct snd_timer *timer) |
1da177e4c
|
102 103 |
{ rtc_task_t *rtc = timer->private_data; |
7eaa943c8
|
104 105 |
if (snd_BUG_ON(!rtc)) return -EINVAL; |
1da177e4c
|
106 107 108 |
rtc_control(rtc, RTC_PIE_OFF, 0); return 0; } |
ac5d1a7d2
|
109 110 111 112 |
static void rtctimer_tasklet(unsigned long data) { snd_timer_interrupt((struct snd_timer *)data, 1); } |
1da177e4c
|
113 114 115 116 117 |
/* * interrupt */ static void rtctimer_interrupt(void *private_data) { |
1f04128a3
|
118 |
tasklet_schedule(private_data); |
1da177e4c
|
119 120 121 122 123 124 125 126 |
} /* * ENTRY functions */ static int __init rtctimer_init(void) { |
d9ad1bdd6
|
127 |
int err; |
53d2f744a
|
128 |
struct snd_timer *timer; |
1da177e4c
|
129 |
|
d9ad1bdd6
|
130 |
if (rtctimer_freq < 2 || rtctimer_freq > 8192 || |
62e96a1ca
|
131 |
!is_power_of_2(rtctimer_freq)) { |
de24214d0
|
132 133 134 |
snd_printk(KERN_ERR "rtctimer: invalid frequency %d ", rtctimer_freq); |
1da177e4c
|
135 136 137 138 139 140 141 |
return -EINVAL; } /* Create a new timer and set up the fields */ err = snd_timer_global_new("rtc", SNDRV_TIMER_GLOBAL_RTC, &timer); if (err < 0) return err; |
de24214d0
|
142 |
timer->module = THIS_MODULE; |
1da177e4c
|
143 144 145 |
strcpy(timer->name, "RTC timer"); timer->hw = rtc_hw; timer->hw.resolution = NANO_SEC / rtctimer_freq; |
ac5d1a7d2
|
146 |
tasklet_init(&rtc_tasklet, rtctimer_tasklet, (unsigned long)timer); |
1da177e4c
|
147 148 |
/* set up RTC callback */ rtc_task.func = rtctimer_interrupt; |
ac5d1a7d2
|
149 |
rtc_task.private_data = &rtc_tasklet; |
1da177e4c
|
150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
err = snd_timer_global_register(timer); if (err < 0) { snd_timer_global_free(timer); return err; } rtctimer = timer; /* remember this */ return 0; } static void __exit rtctimer_exit(void) { if (rtctimer) { |
c461482c8
|
164 |
snd_timer_global_free(rtctimer); |
1da177e4c
|
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
rtctimer = NULL; } } /* * exported stuff */ module_init(rtctimer_init) module_exit(rtctimer_exit) module_param(rtctimer_freq, int, 0444); MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz"); MODULE_LICENSE("GPL"); MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC)); #endif /* CONFIG_RTC || CONFIG_RTC_MODULE */ |