Skip to content

Commit

Permalink
ALSA: Add hrtimer backend for ALSA timer interface
Browse files Browse the repository at this point in the history
Added the hrtimer backend for ALSA timer interface.
It can be used for the sequencer timer source.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Oct 24, 2008
1 parent 52948b3 commit bbaf5e9
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 1 deletion.
1 change: 1 addition & 0 deletions include/sound/asound.h
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ enum {
#define SNDRV_TIMER_GLOBAL_SYSTEM 0
#define SNDRV_TIMER_GLOBAL_RTC 1
#define SNDRV_TIMER_GLOBAL_HPET 2
#define SNDRV_TIMER_GLOBAL_HRTIMER 3

/* info flags */
#define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */
Expand Down
21 changes: 21 additions & 0 deletions sound/core/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ config SND_SEQUENCER_OSS
this will be compiled as a module. The module will be called
snd-seq-oss.

config SND_HRTIMER
tristate "HR-timer backend support"
depends on HIGH_RES_TIMERS
select SND_TIMER
help
Say Y here to enable HR-timer backend for ALSA timer. ALSA uses
the hrtimer as a precise timing source. The ALSA sequencer code
also can use this timing source.

To compile this driver as a module, choose M here: the module
will be called snd-hrtimer.

config SND_SEQ_HRTIMER_DEFAULT
bool "Use HR-timer as default sequencer timer"
depends on SND_HRTIMER && SND_SEQUENCER
default y
help
Say Y here to use the HR-timer backend as the default sequencer
timer.

config SND_RTCTIMER
tristate "RTC Timer support"
depends on RTC
Expand All @@ -114,6 +134,7 @@ config SND_RTCTIMER
config SND_SEQ_RTCTIMER_DEFAULT
bool "Use RTC as default sequencer timer"
depends on SND_RTCTIMER && SND_SEQUENCER
dpeends on !SND_SEQ_HRTIMER_DEFAULT
default y
help
Say Y here to use the RTC timer as the default sequencer
Expand Down
2 changes: 2 additions & 0 deletions sound/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o

snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
snd-hrtimer-objs := hrtimer.o
snd-rtctimer-objs := rtctimer.o
snd-hwdep-objs := hwdep.o

obj-$(CONFIG_SND) += snd.o
obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
obj-$(CONFIG_SND_TIMER) += snd-timer.o
obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
Expand Down
140 changes: 140 additions & 0 deletions sound/core/hrtimer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
*/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/hrtimer.h>
#include <sound/core.h>
#include <sound/timer.h>

MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA hrtimer backend");
MODULE_LICENSE("GPL");

MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));

#define NANO_SEC 1000000000UL /* 10^9 in sec */
static unsigned int resolution;

struct snd_hrtimer {
struct snd_timer *timer;
struct hrtimer hrt;
};

static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
{
struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
struct snd_timer *t = stime->timer;
hrtimer_forward_now(hrt, ktime_set(0, t->sticks * resolution));
snd_timer_interrupt(stime->timer, t->sticks);
return HRTIMER_RESTART;
}

static int snd_hrtimer_open(struct snd_timer *t)
{
struct snd_hrtimer *stime;

stime = kmalloc(sizeof(*stime), GFP_KERNEL);
if (!stime)
return -ENOMEM;
hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
stime->timer = t;
stime->hrt.cb_mode = HRTIMER_CB_SOFTIRQ;
stime->hrt.function = snd_hrtimer_callback;
t->private_data = stime;
return 0;
}

static int snd_hrtimer_close(struct snd_timer *t)
{
struct snd_hrtimer *stime = t->private_data;

if (stime) {
hrtimer_cancel(&stime->hrt);
kfree(stime);
t->private_data = NULL;
}
return 0;
}

static int snd_hrtimer_start(struct snd_timer *t)
{
struct snd_hrtimer *stime = t->private_data;

hrtimer_start(&stime->hrt, ktime_set(0, t->sticks * resolution),
HRTIMER_MODE_REL);
return 0;
}

static int snd_hrtimer_stop(struct snd_timer *t)
{
struct snd_hrtimer *stime = t->private_data;

hrtimer_cancel(&stime->hrt);
return 0;
}

static struct snd_timer_hardware hrtimer_hw = {
.flags = (SNDRV_TIMER_HW_AUTO |
/*SNDRV_TIMER_HW_FIRST |*/
SNDRV_TIMER_HW_TASKLET),
.open = snd_hrtimer_open,
.close = snd_hrtimer_close,
.start = snd_hrtimer_start,
.stop = snd_hrtimer_stop,
};

/*
* entry functions
*/

static struct snd_timer *mytimer;

static int __init snd_hrtimer_init(void)
{
struct snd_timer *timer;
struct timespec tp;
int err;

hrtimer_get_res(CLOCK_MONOTONIC, &tp);
if (tp.tv_sec > 0 || !tp.tv_nsec) {
snd_printk(KERN_ERR
"snd-hrtimer: Invalid resolution %u.%09u",
(unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
return -EINVAL;
}
resolution = tp.tv_nsec;

/* Create a new timer and set up the fields */
err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
&timer);
if (err < 0)
return err;

timer->module = THIS_MODULE;
strcpy(timer->name, "HR timer");
timer->hw = hrtimer_hw;
timer->hw.resolution = resolution;
timer->hw.ticks = NANO_SEC / resolution;

err = snd_timer_global_register(timer);
if (err < 0) {
snd_timer_global_free(timer);
return err;
}
mytimer = timer; /* remember this */

return 0;
}

static void __exit snd_hrtimer_exit(void)
{
if (mytimer) {
snd_timer_global_free(mytimer);
mytimer = NULL;
}
}

module_init(snd_hrtimer_init);
module_exit(snd_hrtimer_exit);
4 changes: 3 additions & 1 deletion sound/core/seq/seq.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL;
int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
int seq_default_timer_card = -1;
int seq_default_timer_device =
#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT
#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT
SNDRV_TIMER_GLOBAL_HRTIMER
#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT)
SNDRV_TIMER_GLOBAL_RTC
#else
SNDRV_TIMER_GLOBAL_SYSTEM
Expand Down

0 comments on commit bbaf5e9

Please sign in to comment.