diff options
Diffstat (limited to 'sound/pci/ctxfi')
-rw-r--r-- | sound/pci/ctxfi/cthardware.h | 1 | ||||
-rw-r--r-- | sound/pci/ctxfi/cthw20k1.c | 6 | ||||
-rw-r--r-- | sound/pci/ctxfi/cttimer.c | 76 |
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 | ||
1189 | static 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 */ |
1190 | struct dac_conf { | 1195 | struct 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 | ||
2240 | int __devinit create_20k1_hw_obj(struct hw **rhw) | 2246 | int __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 | ||
141 | static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) | 143 | static 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 | ||
164 | static 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) | |||
170 | static int ct_xfitimer_reprogram(struct ct_timer *atimer) | 178 | static 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; |