Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 148374
b: refs/heads/master
c: 54de6bc
h: refs/heads/master
v: v3
  • Loading branch information
Takashi Iwai committed Jun 8, 2009
1 parent aa6832d commit 1963cde
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 28cd4aa43de2b6d3b1e3385d450bfb31cbe8d72a
refs/heads/master: 54de6bc8b2437f642844cecb8d183df2368ffceb
1 change: 1 addition & 0 deletions trunk/sound/pci/ctxfi/cthardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ struct hw {

int (*set_timer_irq)(struct hw *hw, int enable);
int (*set_timer_tick)(struct hw *hw, unsigned int tick);
unsigned int (*get_wc)(struct hw *hw);

void (*irq_callback)(void *data, unsigned int bit);
void *irq_callback_data;
Expand Down
6 changes: 6 additions & 0 deletions trunk/sound/pci/ctxfi/cthw20k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,11 @@ static int set_timer_tick(struct hw *hw, unsigned int ticks)
return 0;
}

static unsigned int get_wc(struct hw *hw)
{
return hw_read_20kx(hw, WC);
}

/* Card hardware initialization block */
struct dac_conf {
unsigned int msr; /* master sample rate in rsrs */
Expand Down Expand Up @@ -2235,6 +2240,7 @@ static struct hw ct20k1_preset __devinitdata = {

.set_timer_irq = set_timer_irq,
.set_timer_tick = set_timer_tick,
.get_wc = get_wc,
};

int __devinit create_20k1_hw_obj(struct hw **rhw)
Expand Down
76 changes: 48 additions & 28 deletions trunk/sound/pci/ctxfi/cttimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct ct_timer {
struct ct_timer_ops *ops;
struct list_head instance_head;
struct list_head running_head;
unsigned int wc; /* current wallclock */
unsigned int irq_handling:1; /* in IRQ handling */
unsigned int reprogram:1; /* need to reprogram the internval */
unsigned int running:1; /* global timer running */
Expand Down Expand Up @@ -136,6 +137,7 @@ static struct ct_timer_ops ct_systimer_ops = {
*/

#define CT_TIMER_FREQ 48000
#define MIN_TICKS 1
#define MAX_TICKS ((1 << 13) - 1)

static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
Expand All @@ -159,6 +161,12 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
}
}

static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
{
struct hw *hw = atimer->atc->hw;
return hw->get_wc(hw);
}

/*
* reprogram the timer interval;
* checks the running instance list and determines the next timer interval.
Expand All @@ -170,37 +178,46 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
static int ct_xfitimer_reprogram(struct ct_timer *atimer)
{
struct ct_timer_instance *ti;
int min_intr = -1;
unsigned int min_intr = (unsigned int)-1;
int updates = 0;
unsigned int wc, diff;

if (list_empty(&atimer->running_head)) {
ct_xfitimer_irq_stop(atimer);
atimer->reprogram = 0; /* clear flag */
return 0;
}

wc = ct_xfitimer_get_wc(atimer);
diff = wc - atimer->wc;
atimer->wc = wc;
list_for_each_entry(ti, &atimer->running_head, running_list) {
struct snd_pcm_runtime *runtime;
unsigned int pos, diff;
int intr;
runtime = ti->substream->runtime;
pos = ti->substream->ops->pointer(ti->substream);
if (pos < ti->position)
diff = runtime->buffer_size - ti->position + pos;
else
diff = pos - ti->position;
ti->position = pos;
while (diff >= ti->frag_count) {
ti->frag_count += runtime->period_size;
ti->need_update = 1;
updates++;
if (ti->frag_count > diff)
ti->frag_count -= diff;
else {
unsigned int pos;
unsigned int period_size, rate;

period_size = ti->substream->runtime->period_size;
rate = ti->substream->runtime->rate;
pos = ti->substream->ops->pointer(ti->substream);
if (pos / period_size != ti->position / period_size) {
ti->need_update = 1;
ti->position = pos;
updates++;
}
pos %= period_size;
pos = period_size - pos;
ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
rate - 1, rate);
}
ti->frag_count -= diff;
intr = div_u64((u64)ti->frag_count * CT_TIMER_FREQ,
runtime->rate);
if (min_intr < 0 || intr < min_intr)
min_intr = intr;
if (ti->frag_count < min_intr)
min_intr = ti->frag_count;
}

if (min_intr > 0)
ct_xfitimer_irq_rearm(atimer, min_intr);
else
ct_xfitimer_irq_stop(atimer);

if (min_intr < MIN_TICKS)
min_intr = MIN_TICKS;
ct_xfitimer_irq_rearm(atimer, min_intr);
atimer->reprogram = 0; /* clear flag */
return updates;
}
Expand Down Expand Up @@ -253,13 +270,14 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
unsigned long flags;
int update;

spin_lock_irqsave(&atimer->lock, flags);
if (atimer->irq_handling) {
/* reached from IRQ handler; let it handle later */
atimer->reprogram = 1;
spin_unlock_irqrestore(&atimer->lock, flags);
return;
}

spin_lock_irqsave(&atimer->lock, flags);
ct_xfitimer_irq_stop(atimer);
update = ct_xfitimer_reprogram(atimer);
spin_unlock_irqrestore(&atimer->lock, flags);
Expand All @@ -273,6 +291,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
unsigned long flags;

spin_lock_irqsave(&atimer->lock, flags);
if (list_empty(&ti->running_list))
atimer->wc = ct_xfitimer_get_wc(atimer);
list_add(&ti->running_list, &atimer->running_head);
spin_unlock_irqrestore(&atimer->lock, flags);
ct_xfitimer_update(atimer);
Expand Down Expand Up @@ -396,12 +416,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc)
atimer->atc = atc;
hw = atc->hw;
if (!USE_SYSTEM_TIMER && hw->set_timer_irq) {
printk(KERN_INFO "ctxfi: Use xfi-native timer\n");
snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
atimer->ops = &ct_xfitimer_ops;
hw->irq_callback_data = atimer;
hw->irq_callback = ct_timer_interrupt;
} else {
printk(KERN_INFO "ctxfi: Use system timer\n");
snd_printd(KERN_INFO "ctxfi: Use system timer\n");
atimer->ops = &ct_systimer_ops;
}
return atimer;
Expand Down

0 comments on commit 1963cde

Please sign in to comment.