Loading sound/pci/ctxfi/cthardware.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -147,6 +147,7 @@ struct hw { int (*set_timer_irq)(struct hw *hw, int enable); int (*set_timer_irq)(struct hw *hw, int enable); int (*set_timer_tick)(struct hw *hw, unsigned int tick); 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)(void *data, unsigned int bit); void *irq_callback_data; void *irq_callback_data; Loading sound/pci/ctxfi/cthw20k1.c +6 −0 Original line number Original line Diff line number Diff line Loading @@ -1186,6 +1186,11 @@ static int set_timer_tick(struct hw *hw, unsigned int ticks) return 0; return 0; } } static unsigned int get_wc(struct hw *hw) { return hw_read_20kx(hw, WC); } /* Card hardware initialization block */ /* Card hardware initialization block */ struct dac_conf { struct dac_conf { unsigned int msr; /* master sample rate in rsrs */ unsigned int msr; /* master sample rate in rsrs */ Loading Loading @@ -2235,6 +2240,7 @@ static struct hw ct20k1_preset __devinitdata = { .set_timer_irq = set_timer_irq, .set_timer_irq = set_timer_irq, .set_timer_tick = set_timer_tick, .set_timer_tick = set_timer_tick, .get_wc = get_wc, }; }; int __devinit create_20k1_hw_obj(struct hw **rhw) int __devinit create_20k1_hw_obj(struct hw **rhw) Loading sound/pci/ctxfi/cttimer.c +48 −28 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ struct ct_timer { struct ct_timer_ops *ops; struct ct_timer_ops *ops; struct list_head instance_head; struct list_head instance_head; struct list_head running_head; struct list_head running_head; unsigned int wc; /* current wallclock */ unsigned int irq_handling:1; /* in IRQ handling */ unsigned int irq_handling:1; /* in IRQ handling */ unsigned int reprogram:1; /* need to reprogram the internval */ unsigned int reprogram:1; /* need to reprogram the internval */ unsigned int running:1; /* global timer running */ unsigned int running:1; /* global timer running */ Loading Loading @@ -136,6 +137,7 @@ static struct ct_timer_ops ct_systimer_ops = { */ */ #define CT_TIMER_FREQ 48000 #define CT_TIMER_FREQ 48000 #define MIN_TICKS 1 #define MAX_TICKS ((1 << 13) - 1) #define MAX_TICKS ((1 << 13) - 1) static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) Loading @@ -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; * reprogram the timer interval; * checks the running instance list and determines the next timer interval. * checks the running instance list and determines the next timer interval. Loading @@ -170,37 +178,46 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer) static int ct_xfitimer_reprogram(struct ct_timer *atimer) static int ct_xfitimer_reprogram(struct ct_timer *atimer) { { struct ct_timer_instance *ti; struct ct_timer_instance *ti; int min_intr = -1; unsigned int min_intr = (unsigned int)-1; int updates = 0; 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) { list_for_each_entry(ti, &atimer->running_head, running_list) { struct snd_pcm_runtime *runtime; if (ti->frag_count > diff) unsigned int pos, diff; ti->frag_count -= diff; int intr; else { runtime = ti->substream->runtime; 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); pos = ti->substream->ops->pointer(ti->substream); if (pos < ti->position) if (pos / period_size != ti->position / period_size) { 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; ti->need_update = 1; ti->position = pos; updates++; updates++; } } ti->frag_count -= diff; pos %= period_size; intr = div_u64((u64)ti->frag_count * CT_TIMER_FREQ, pos = period_size - pos; runtime->rate); ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + if (min_intr < 0 || intr < min_intr) rate - 1, rate); min_intr = intr; } if (ti->frag_count < min_intr) min_intr = ti->frag_count; } } if (min_intr > 0) if (min_intr < MIN_TICKS) min_intr = MIN_TICKS; ct_xfitimer_irq_rearm(atimer, min_intr); ct_xfitimer_irq_rearm(atimer, min_intr); else ct_xfitimer_irq_stop(atimer); atimer->reprogram = 0; /* clear flag */ atimer->reprogram = 0; /* clear flag */ return updates; return updates; } } Loading Loading @@ -253,13 +270,14 @@ static void ct_xfitimer_update(struct ct_timer *atimer) unsigned long flags; unsigned long flags; int update; int update; spin_lock_irqsave(&atimer->lock, flags); if (atimer->irq_handling) { if (atimer->irq_handling) { /* reached from IRQ handler; let it handle later */ /* reached from IRQ handler; let it handle later */ atimer->reprogram = 1; atimer->reprogram = 1; spin_unlock_irqrestore(&atimer->lock, flags); return; return; } } spin_lock_irqsave(&atimer->lock, flags); ct_xfitimer_irq_stop(atimer); ct_xfitimer_irq_stop(atimer); update = ct_xfitimer_reprogram(atimer); update = ct_xfitimer_reprogram(atimer); spin_unlock_irqrestore(&atimer->lock, flags); spin_unlock_irqrestore(&atimer->lock, flags); Loading @@ -273,6 +291,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti) unsigned long flags; unsigned long flags; spin_lock_irqsave(&atimer->lock, 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); list_add(&ti->running_list, &atimer->running_head); spin_unlock_irqrestore(&atimer->lock, flags); spin_unlock_irqrestore(&atimer->lock, flags); ct_xfitimer_update(atimer); ct_xfitimer_update(atimer); Loading Loading @@ -396,12 +416,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc) atimer->atc = atc; atimer->atc = atc; hw = atc->hw; hw = atc->hw; if (!USE_SYSTEM_TIMER && hw->set_timer_irq) { 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; atimer->ops = &ct_xfitimer_ops; hw->irq_callback_data = atimer; hw->irq_callback_data = atimer; hw->irq_callback = ct_timer_interrupt; hw->irq_callback = ct_timer_interrupt; } else { } else { printk(KERN_INFO "ctxfi: Use system timer\n"); snd_printd(KERN_INFO "ctxfi: Use system timer\n"); atimer->ops = &ct_systimer_ops; atimer->ops = &ct_systimer_ops; } } return atimer; return atimer; Loading Loading
sound/pci/ctxfi/cthardware.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -147,6 +147,7 @@ struct hw { int (*set_timer_irq)(struct hw *hw, int enable); int (*set_timer_irq)(struct hw *hw, int enable); int (*set_timer_tick)(struct hw *hw, unsigned int tick); 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)(void *data, unsigned int bit); void *irq_callback_data; void *irq_callback_data; Loading
sound/pci/ctxfi/cthw20k1.c +6 −0 Original line number Original line Diff line number Diff line Loading @@ -1186,6 +1186,11 @@ static int set_timer_tick(struct hw *hw, unsigned int ticks) return 0; return 0; } } static unsigned int get_wc(struct hw *hw) { return hw_read_20kx(hw, WC); } /* Card hardware initialization block */ /* Card hardware initialization block */ struct dac_conf { struct dac_conf { unsigned int msr; /* master sample rate in rsrs */ unsigned int msr; /* master sample rate in rsrs */ Loading Loading @@ -2235,6 +2240,7 @@ static struct hw ct20k1_preset __devinitdata = { .set_timer_irq = set_timer_irq, .set_timer_irq = set_timer_irq, .set_timer_tick = set_timer_tick, .set_timer_tick = set_timer_tick, .get_wc = get_wc, }; }; int __devinit create_20k1_hw_obj(struct hw **rhw) int __devinit create_20k1_hw_obj(struct hw **rhw) Loading
sound/pci/ctxfi/cttimer.c +48 −28 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ struct ct_timer { struct ct_timer_ops *ops; struct ct_timer_ops *ops; struct list_head instance_head; struct list_head instance_head; struct list_head running_head; struct list_head running_head; unsigned int wc; /* current wallclock */ unsigned int irq_handling:1; /* in IRQ handling */ unsigned int irq_handling:1; /* in IRQ handling */ unsigned int reprogram:1; /* need to reprogram the internval */ unsigned int reprogram:1; /* need to reprogram the internval */ unsigned int running:1; /* global timer running */ unsigned int running:1; /* global timer running */ Loading Loading @@ -136,6 +137,7 @@ static struct ct_timer_ops ct_systimer_ops = { */ */ #define CT_TIMER_FREQ 48000 #define CT_TIMER_FREQ 48000 #define MIN_TICKS 1 #define MAX_TICKS ((1 << 13) - 1) #define MAX_TICKS ((1 << 13) - 1) static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) Loading @@ -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; * reprogram the timer interval; * checks the running instance list and determines the next timer interval. * checks the running instance list and determines the next timer interval. Loading @@ -170,37 +178,46 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer) static int ct_xfitimer_reprogram(struct ct_timer *atimer) static int ct_xfitimer_reprogram(struct ct_timer *atimer) { { struct ct_timer_instance *ti; struct ct_timer_instance *ti; int min_intr = -1; unsigned int min_intr = (unsigned int)-1; int updates = 0; 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) { list_for_each_entry(ti, &atimer->running_head, running_list) { struct snd_pcm_runtime *runtime; if (ti->frag_count > diff) unsigned int pos, diff; ti->frag_count -= diff; int intr; else { runtime = ti->substream->runtime; 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); pos = ti->substream->ops->pointer(ti->substream); if (pos < ti->position) if (pos / period_size != ti->position / period_size) { 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; ti->need_update = 1; ti->position = pos; updates++; updates++; } } ti->frag_count -= diff; pos %= period_size; intr = div_u64((u64)ti->frag_count * CT_TIMER_FREQ, pos = period_size - pos; runtime->rate); ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + if (min_intr < 0 || intr < min_intr) rate - 1, rate); min_intr = intr; } if (ti->frag_count < min_intr) min_intr = ti->frag_count; } } if (min_intr > 0) if (min_intr < MIN_TICKS) min_intr = MIN_TICKS; ct_xfitimer_irq_rearm(atimer, min_intr); ct_xfitimer_irq_rearm(atimer, min_intr); else ct_xfitimer_irq_stop(atimer); atimer->reprogram = 0; /* clear flag */ atimer->reprogram = 0; /* clear flag */ return updates; return updates; } } Loading Loading @@ -253,13 +270,14 @@ static void ct_xfitimer_update(struct ct_timer *atimer) unsigned long flags; unsigned long flags; int update; int update; spin_lock_irqsave(&atimer->lock, flags); if (atimer->irq_handling) { if (atimer->irq_handling) { /* reached from IRQ handler; let it handle later */ /* reached from IRQ handler; let it handle later */ atimer->reprogram = 1; atimer->reprogram = 1; spin_unlock_irqrestore(&atimer->lock, flags); return; return; } } spin_lock_irqsave(&atimer->lock, flags); ct_xfitimer_irq_stop(atimer); ct_xfitimer_irq_stop(atimer); update = ct_xfitimer_reprogram(atimer); update = ct_xfitimer_reprogram(atimer); spin_unlock_irqrestore(&atimer->lock, flags); spin_unlock_irqrestore(&atimer->lock, flags); Loading @@ -273,6 +291,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti) unsigned long flags; unsigned long flags; spin_lock_irqsave(&atimer->lock, 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); list_add(&ti->running_list, &atimer->running_head); spin_unlock_irqrestore(&atimer->lock, flags); spin_unlock_irqrestore(&atimer->lock, flags); ct_xfitimer_update(atimer); ct_xfitimer_update(atimer); Loading Loading @@ -396,12 +416,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc) atimer->atc = atc; atimer->atc = atc; hw = atc->hw; hw = atc->hw; if (!USE_SYSTEM_TIMER && hw->set_timer_irq) { 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; atimer->ops = &ct_xfitimer_ops; hw->irq_callback_data = atimer; hw->irq_callback_data = atimer; hw->irq_callback = ct_timer_interrupt; hw->irq_callback = ct_timer_interrupt; } else { } else { printk(KERN_INFO "ctxfi: Use system timer\n"); snd_printd(KERN_INFO "ctxfi: Use system timer\n"); atimer->ops = &ct_systimer_ops; atimer->ops = &ct_systimer_ops; } } return atimer; return atimer; Loading