aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ctxfi
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/ctxfi')
-rw-r--r--sound/pci/ctxfi/cthardware.h1
-rw-r--r--sound/pci/ctxfi/cthw20k1.c6
-rw-r--r--sound/pci/ctxfi/cttimer.c76
3 files changed, 55 insertions, 28 deletions
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 35350cf9d2f2..8f11644ddc92 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -147,6 +147,7 @@ struct hw {
147 147
148 int (*set_timer_irq)(struct hw *hw, int enable); 148 int (*set_timer_irq)(struct hw *hw, int enable);
149 int (*set_timer_tick)(struct hw *hw, unsigned int tick); 149 int (*set_timer_tick)(struct hw *hw, unsigned int tick);
150 unsigned int (*get_wc)(struct hw *hw);
150 151
151 void (*irq_callback)(void *data, unsigned int bit); 152 void (*irq_callback)(void *data, unsigned int bit);
152 void *irq_callback_data; 153 void *irq_callback_data;
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index df565c11fcca..b165466e1a54 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1186,6 +1186,11 @@ static int set_timer_tick(struct hw *hw, unsigned int ticks)
1186 return 0; 1186 return 0;
1187} 1187}
1188 1188
1189static unsigned int get_wc(struct hw *hw)
1190{
1191 return hw_read_20kx(hw, WC);
1192}
1193
1189/* Card hardware initialization block */ 1194/* Card hardware initialization block */
1190struct dac_conf { 1195struct dac_conf {
1191 unsigned int msr; /* master sample rate in rsrs */ 1196 unsigned int msr; /* master sample rate in rsrs */
@@ -2235,6 +2240,7 @@ static struct hw ct20k1_preset __devinitdata = {
2235 2240
2236 .set_timer_irq = set_timer_irq, 2241 .set_timer_irq = set_timer_irq,
2237 .set_timer_tick = set_timer_tick, 2242 .set_timer_tick = set_timer_tick,
2243 .get_wc = get_wc,
2238}; 2244};
2239 2245
2240int __devinit create_20k1_hw_obj(struct hw **rhw) 2246int __devinit create_20k1_hw_obj(struct hw **rhw)
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
index ceda74e356cb..ec869a4fe2b3 100644
--- a/sound/pci/ctxfi/cttimer.c
+++ b/sound/pci/ctxfi/cttimer.c
@@ -47,6 +47,7 @@ struct ct_timer {
47 struct ct_timer_ops *ops; 47 struct ct_timer_ops *ops;
48 struct list_head instance_head; 48 struct list_head instance_head;
49 struct list_head running_head; 49 struct list_head running_head;
50 unsigned int wc; /* current wallclock */
50 unsigned int irq_handling:1; /* in IRQ handling */ 51 unsigned int irq_handling:1; /* in IRQ handling */
51 unsigned int reprogram:1; /* need to reprogram the internval */ 52 unsigned int reprogram:1; /* need to reprogram the internval */
52 unsigned int running:1; /* global timer running */ 53 unsigned int running:1; /* global timer running */
@@ -136,6 +137,7 @@ static struct ct_timer_ops ct_systimer_ops = {
136 */ 137 */
137 138
138#define CT_TIMER_FREQ 48000 139#define CT_TIMER_FREQ 48000
140#define MIN_TICKS 1
139#define MAX_TICKS ((1 << 13) - 1) 141#define MAX_TICKS ((1 << 13) - 1)
140 142
141static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) 143static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
@@ -159,6 +161,12 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
159 } 161 }
160} 162}
161 163
164static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
165{
166 struct hw *hw = atimer->atc->hw;
167 return hw->get_wc(hw);
168}
169
162/* 170/*
163 * reprogram the timer interval; 171 * reprogram the timer interval;
164 * checks the running instance list and determines the next timer interval. 172 * checks the running instance list and determines the next timer interval.
@@ -170,37 +178,46 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
170static int ct_xfitimer_reprogram(struct ct_timer *atimer) 178static int ct_xfitimer_reprogram(struct ct_timer *atimer)
171{ 179{
172 struct ct_timer_instance *ti; 180 struct ct_timer_instance *ti;
173 int min_intr = -1; 181 unsigned int min_intr = (unsigned int)-1;
174 int updates = 0; 182 int updates = 0;
183 unsigned int wc, diff;
175 184
185 if (list_empty(&atimer->running_head)) {
186 ct_xfitimer_irq_stop(atimer);
187 atimer->reprogram = 0; /* clear flag */
188 return 0;
189 }
190
191 wc = ct_xfitimer_get_wc(atimer);
192 diff = wc - atimer->wc;
193 atimer->wc = wc;
176 list_for_each_entry(ti, &atimer->running_head, running_list) { 194 list_for_each_entry(ti, &atimer->running_head, running_list) {
177 struct snd_pcm_runtime *runtime; 195 if (ti->frag_count > diff)
178 unsigned int pos, diff; 196 ti->frag_count -= diff;
179 int intr; 197 else {
180 runtime = ti->substream->runtime; 198 unsigned int pos;
181 pos = ti->substream->ops->pointer(ti->substream); 199 unsigned int period_size, rate;
182 if (pos < ti->position) 200
183 diff = runtime->buffer_size - ti->position + pos; 201 period_size = ti->substream->runtime->period_size;
184 else 202 rate = ti->substream->runtime->rate;
185 diff = pos - ti->position; 203 pos = ti->substream->ops->pointer(ti->substream);
186 ti->position = pos; 204 if (pos / period_size != ti->position / period_size) {
187 while (diff >= ti->frag_count) { 205 ti->need_update = 1;
188 ti->frag_count += runtime->period_size; 206 ti->position = pos;
189 ti->need_update = 1; 207 updates++;
190 updates++; 208 }
209 pos %= period_size;
210 pos = period_size - pos;
211 ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
212 rate - 1, rate);
191 } 213 }
192 ti->frag_count -= diff; 214 if (ti->frag_count < min_intr)
193 intr = div_u64((u64)ti->frag_count * CT_TIMER_FREQ, 215 min_intr = ti->frag_count;
194 runtime->rate);
195 if (min_intr < 0 || intr < min_intr)
196 min_intr = intr;
197 } 216 }
198 217
199 if (min_intr > 0) 218 if (min_intr < MIN_TICKS)
200 ct_xfitimer_irq_rearm(atimer, min_intr); 219 min_intr = MIN_TICKS;
201 else 220 ct_xfitimer_irq_rearm(atimer, min_intr);
202 ct_xfitimer_irq_stop(atimer);
203
204 atimer->reprogram = 0; /* clear flag */ 221 atimer->reprogram = 0; /* clear flag */
205 return updates; 222 return updates;
206} 223}
@@ -253,13 +270,14 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
253 unsigned long flags; 270 unsigned long flags;
254 int update; 271 int update;
255 272
273 spin_lock_irqsave(&atimer->lock, flags);
256 if (atimer->irq_handling) { 274 if (atimer->irq_handling) {
257 /* reached from IRQ handler; let it handle later */ 275 /* reached from IRQ handler; let it handle later */
258 atimer->reprogram = 1; 276 atimer->reprogram = 1;
277 spin_unlock_irqrestore(&atimer->lock, flags);
259 return; 278 return;
260 } 279 }
261 280
262 spin_lock_irqsave(&atimer->lock, flags);
263 ct_xfitimer_irq_stop(atimer); 281 ct_xfitimer_irq_stop(atimer);
264 update = ct_xfitimer_reprogram(atimer); 282 update = ct_xfitimer_reprogram(atimer);
265 spin_unlock_irqrestore(&atimer->lock, flags); 283 spin_unlock_irqrestore(&atimer->lock, flags);
@@ -273,6 +291,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
273 unsigned long flags; 291 unsigned long flags;
274 292
275 spin_lock_irqsave(&atimer->lock, flags); 293 spin_lock_irqsave(&atimer->lock, flags);
294 if (list_empty(&ti->running_list))
295 atimer->wc = ct_xfitimer_get_wc(atimer);
276 list_add(&ti->running_list, &atimer->running_head); 296 list_add(&ti->running_list, &atimer->running_head);
277 spin_unlock_irqrestore(&atimer->lock, flags); 297 spin_unlock_irqrestore(&atimer->lock, flags);
278 ct_xfitimer_update(atimer); 298 ct_xfitimer_update(atimer);
@@ -396,12 +416,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc)
396 atimer->atc = atc; 416 atimer->atc = atc;
397 hw = atc->hw; 417 hw = atc->hw;
398 if (!USE_SYSTEM_TIMER && hw->set_timer_irq) { 418 if (!USE_SYSTEM_TIMER && hw->set_timer_irq) {
399 printk(KERN_INFO "ctxfi: Use xfi-native timer\n"); 419 snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
400 atimer->ops = &ct_xfitimer_ops; 420 atimer->ops = &ct_xfitimer_ops;
401 hw->irq_callback_data = atimer; 421 hw->irq_callback_data = atimer;
402 hw->irq_callback = ct_timer_interrupt; 422 hw->irq_callback = ct_timer_interrupt;
403 } else { 423 } else {
404 printk(KERN_INFO "ctxfi: Use system timer\n"); 424 snd_printd(KERN_INFO "ctxfi: Use system timer\n");
405 atimer->ops = &ct_systimer_ops; 425 atimer->ops = &ct_systimer_ops;
406 } 426 }
407 return atimer; 427 return atimer;