~ubuntu-branches/ubuntu/precise/alsa-driver/precise

« back to all changes in this revision

Viewing changes to alsa-kernel/pci/ctxfi/cttimer.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-11-04 16:28:58 UTC
  • mfrom: (1.1.12 upstream) (3.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091104162858-7ky0tu33d7mn6oys
Tags: 1.0.21+dfsg-3ubuntu1
* Merge from debian unstable, remaining changes:
  - Script paths (/usr/sbin -> /sbin, /usr/bin -> /bin);
  - debian/rules:
    + Don't install snddevices and program-wrapper
    + install alsa-base apport hook
    + Package separate USB card list file
  - Vcs and maintainer fields mangling
  - Rename blacklist files in /etc/modprobe.d to be consistant with the rest
    of the distro
  - debian/alsa-base.init:
    + create /var/run/alsa if it doesn't exist
    + Run alsactl store before force unloading modules
    + Run alsactl restore after reloading unloaded modules
  - debian/linux-sound-base.postrm: Remove /etc/modprobe.d/blacklist* files
    on package removal
  - Add missing $CMDLINE_OPTS to all install rules.
  - Replace -Q with --quiet.
  - Add --use-blacklist to all rules so the blacklist still takes effect.
  - debian/alsa-base.postinst: Do not run snddevices
  - retain patches:
    + add_suspend_quirk_hp_nc6220_nw8240.patch,
    + refix_lp_68659_by_disabling_dxs_for_0x1458a002.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PCM timer handling on ctxfi
 
3
 *
 
4
 * This source file is released under GPL v2 license (no other versions).
 
5
 * See the COPYING file included in the main directory of this source
 
6
 * distribution for the license terms and conditions.
 
7
 */
 
8
 
 
9
#include <linux/slab.h>
 
10
#include <linux/math64.h>
 
11
#include <linux/moduleparam.h>
 
12
#include <sound/core.h>
 
13
#include <sound/pcm.h>
 
14
#include "ctatc.h"
 
15
#include "cthardware.h"
 
16
#include "cttimer.h"
 
17
 
 
18
static int use_system_timer;
 
19
MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer");
 
20
module_param(use_system_timer, bool, S_IRUGO);
 
21
 
 
22
struct ct_timer_ops {
 
23
        void (*init)(struct ct_timer_instance *);
 
24
        void (*prepare)(struct ct_timer_instance *);
 
25
        void (*start)(struct ct_timer_instance *);
 
26
        void (*stop)(struct ct_timer_instance *);
 
27
        void (*free_instance)(struct ct_timer_instance *);
 
28
        void (*interrupt)(struct ct_timer *);
 
29
        void (*free_global)(struct ct_timer *);
 
30
};
 
31
 
 
32
/* timer instance -- assigned to each PCM stream */
 
33
struct ct_timer_instance {
 
34
        spinlock_t lock;
 
35
        struct ct_timer *timer_base;
 
36
        struct ct_atc_pcm *apcm;
 
37
        struct snd_pcm_substream *substream;
 
38
        struct timer_list timer;
 
39
        struct list_head instance_list;
 
40
        struct list_head running_list;
 
41
        unsigned int position;
 
42
        unsigned int frag_count;
 
43
        unsigned int running:1;
 
44
        unsigned int need_update:1;
 
45
};
 
46
 
 
47
/* timer instance manager */
 
48
struct ct_timer {
 
49
        spinlock_t lock;                /* global timer lock (for xfitimer) */
 
50
        spinlock_t list_lock;           /* lock for instance list */
 
51
        struct ct_atc *atc;
 
52
        struct ct_timer_ops *ops;
 
53
        struct list_head instance_head;
 
54
        struct list_head running_head;
 
55
        unsigned int wc;                /* current wallclock */
 
56
        unsigned int irq_handling:1;    /* in IRQ handling */
 
57
        unsigned int reprogram:1;       /* need to reprogram the internval */
 
58
        unsigned int running:1;         /* global timer running */
 
59
};
 
60
 
 
61
 
 
62
/*
 
63
 * system-timer-based updates
 
64
 */
 
65
 
 
66
static void ct_systimer_callback(unsigned long data)
 
67
{
 
68
        struct ct_timer_instance *ti = (struct ct_timer_instance *)data;
 
69
        struct snd_pcm_substream *substream = ti->substream;
 
70
        struct snd_pcm_runtime *runtime = substream->runtime;
 
71
        struct ct_atc_pcm *apcm = ti->apcm;
 
72
        unsigned int period_size = runtime->period_size;
 
73
        unsigned int buffer_size = runtime->buffer_size;
 
74
        unsigned long flags;
 
75
        unsigned int position, dist, interval;
 
76
 
 
77
        position = substream->ops->pointer(substream);
 
78
        dist = (position + buffer_size - ti->position) % buffer_size;
 
79
        if (dist >= period_size ||
 
80
            position / period_size != ti->position / period_size) {
 
81
                apcm->interrupt(apcm);
 
82
                ti->position = position;
 
83
        }
 
84
        /* Add extra HZ*5/1000 to avoid overrun issue when recording
 
85
         * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
 
86
        interval = ((period_size - (position % period_size))
 
87
                   * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
 
88
        spin_lock_irqsave(&ti->lock, flags);
 
89
        if (ti->running)
 
90
                mod_timer(&ti->timer, jiffies + interval);
 
91
        spin_unlock_irqrestore(&ti->lock, flags);
 
92
}
 
93
 
 
94
static void ct_systimer_init(struct ct_timer_instance *ti)
 
95
{
 
96
        setup_timer(&ti->timer, ct_systimer_callback,
 
97
                    (unsigned long)ti);
 
98
}
 
99
 
 
100
static void ct_systimer_start(struct ct_timer_instance *ti)
 
101
{
 
102
        struct snd_pcm_runtime *runtime = ti->substream->runtime;
 
103
        unsigned long flags;
 
104
 
 
105
        spin_lock_irqsave(&ti->lock, flags);
 
106
        ti->running = 1;
 
107
        mod_timer(&ti->timer,
 
108
                  jiffies + (runtime->period_size * HZ +
 
109
                             (runtime->rate - 1)) / runtime->rate);
 
110
        spin_unlock_irqrestore(&ti->lock, flags);
 
111
}
 
112
 
 
113
static void ct_systimer_stop(struct ct_timer_instance *ti)
 
114
{
 
115
        unsigned long flags;
 
116
 
 
117
        spin_lock_irqsave(&ti->lock, flags);
 
118
        ti->running = 0;
 
119
        del_timer(&ti->timer);
 
120
        spin_unlock_irqrestore(&ti->lock, flags);
 
121
}
 
122
 
 
123
static void ct_systimer_prepare(struct ct_timer_instance *ti)
 
124
{
 
125
        ct_systimer_stop(ti);
 
126
        try_to_del_timer_sync(&ti->timer);
 
127
}
 
128
 
 
129
#define ct_systimer_free        ct_systimer_prepare
 
130
 
 
131
static struct ct_timer_ops ct_systimer_ops = {
 
132
        .init = ct_systimer_init,
 
133
        .free_instance = ct_systimer_free,
 
134
        .prepare = ct_systimer_prepare,
 
135
        .start = ct_systimer_start,
 
136
        .stop = ct_systimer_stop,
 
137
};
 
138
 
 
139
 
 
140
/*
 
141
 * Handling multiple streams using a global emu20k1 timer irq
 
142
 */
 
143
 
 
144
#define CT_TIMER_FREQ   48000
 
145
#define MIN_TICKS       1
 
146
#define MAX_TICKS       ((1 << 13) - 1)
 
147
 
 
148
static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
 
149
{
 
150
        struct hw *hw = atimer->atc->hw;
 
151
        if (ticks > MAX_TICKS)
 
152
                ticks = MAX_TICKS;
 
153
        hw->set_timer_tick(hw, ticks);
 
154
        if (!atimer->running)
 
155
                hw->set_timer_irq(hw, 1);
 
156
        atimer->running = 1;
 
157
}
 
158
 
 
159
static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
 
160
{
 
161
        if (atimer->running) {
 
162
                struct hw *hw = atimer->atc->hw;
 
163
                hw->set_timer_irq(hw, 0);
 
164
                hw->set_timer_tick(hw, 0);
 
165
                atimer->running = 0;
 
166
        }
 
167
}
 
168
 
 
169
static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
 
170
{
 
171
        struct hw *hw = atimer->atc->hw;
 
172
        return hw->get_wc(hw);
 
173
}
 
174
 
 
175
/*
 
176
 * reprogram the timer interval;
 
177
 * checks the running instance list and determines the next timer interval.
 
178
 * also updates the each stream position, returns the number of streams
 
179
 * to call snd_pcm_period_elapsed() appropriately
 
180
 *
 
181
 * call this inside the lock and irq disabled
 
182
 */
 
183
static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
 
184
{
 
185
        struct ct_timer_instance *ti;
 
186
        unsigned int min_intr = (unsigned int)-1;
 
187
        int updates = 0;
 
188
        unsigned int wc, diff;
 
189
 
 
190
        if (list_empty(&atimer->running_head)) {
 
191
                ct_xfitimer_irq_stop(atimer);
 
192
                atimer->reprogram = 0; /* clear flag */
 
193
                return 0;
 
194
        }
 
195
 
 
196
        wc = ct_xfitimer_get_wc(atimer);
 
197
        diff = wc - atimer->wc;
 
198
        atimer->wc = wc;
 
199
        list_for_each_entry(ti, &atimer->running_head, running_list) {
 
200
                if (ti->frag_count > diff)
 
201
                        ti->frag_count -= diff;
 
202
                else {
 
203
                        unsigned int pos;
 
204
                        unsigned int period_size, rate;
 
205
 
 
206
                        period_size = ti->substream->runtime->period_size;
 
207
                        rate = ti->substream->runtime->rate;
 
208
                        pos = ti->substream->ops->pointer(ti->substream);
 
209
                        if (pos / period_size != ti->position / period_size) {
 
210
                                ti->need_update = 1;
 
211
                                ti->position = pos;
 
212
                                updates++;
 
213
                        }
 
214
                        pos %= period_size;
 
215
                        pos = period_size - pos;
 
216
                        ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
 
217
                                                 rate - 1, rate);
 
218
                }
 
219
                if (ti->need_update && !can_update)
 
220
                        min_intr = 0; /* pending to the next irq */
 
221
                if (ti->frag_count < min_intr)
 
222
                        min_intr = ti->frag_count;
 
223
        }
 
224
 
 
225
        if (min_intr < MIN_TICKS)
 
226
                min_intr = MIN_TICKS;
 
227
        ct_xfitimer_irq_rearm(atimer, min_intr);
 
228
        atimer->reprogram = 0; /* clear flag */
 
229
        return updates;
 
230
}
 
231
 
 
232
/* look through the instance list and call period_elapsed if needed */
 
233
static void ct_xfitimer_check_period(struct ct_timer *atimer)
 
234
{
 
235
        struct ct_timer_instance *ti;
 
236
        unsigned long flags;
 
237
 
 
238
        spin_lock_irqsave(&atimer->list_lock, flags);
 
239
        list_for_each_entry(ti, &atimer->instance_head, instance_list) {
 
240
                if (ti->running && ti->need_update) {
 
241
                        ti->need_update = 0;
 
242
                        ti->apcm->interrupt(ti->apcm);
 
243
                }
 
244
        }
 
245
        spin_unlock_irqrestore(&atimer->list_lock, flags);
 
246
}
 
247
 
 
248
/* Handle timer-interrupt */
 
249
static void ct_xfitimer_callback(struct ct_timer *atimer)
 
250
{
 
251
        int update;
 
252
        unsigned long flags;
 
253
 
 
254
        spin_lock_irqsave(&atimer->lock, flags);
 
255
        atimer->irq_handling = 1;
 
256
        do {
 
257
                update = ct_xfitimer_reprogram(atimer, 1);
 
258
                spin_unlock(&atimer->lock);
 
259
                if (update)
 
260
                        ct_xfitimer_check_period(atimer);
 
261
                spin_lock(&atimer->lock);
 
262
        } while (atimer->reprogram);
 
263
        atimer->irq_handling = 0;
 
264
        spin_unlock_irqrestore(&atimer->lock, flags);
 
265
}
 
266
 
 
267
static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
 
268
{
 
269
        ti->frag_count = ti->substream->runtime->period_size;
 
270
        ti->running = 0;
 
271
        ti->need_update = 0;
 
272
}
 
273
 
 
274
 
 
275
/* start/stop the timer */
 
276
static void ct_xfitimer_update(struct ct_timer *atimer)
 
277
{
 
278
        unsigned long flags;
 
279
 
 
280
        spin_lock_irqsave(&atimer->lock, flags);
 
281
        if (atimer->irq_handling) {
 
282
                /* reached from IRQ handler; let it handle later */
 
283
                atimer->reprogram = 1;
 
284
                spin_unlock_irqrestore(&atimer->lock, flags);
 
285
                return;
 
286
        }
 
287
 
 
288
        ct_xfitimer_irq_stop(atimer);
 
289
        ct_xfitimer_reprogram(atimer, 0);
 
290
        spin_unlock_irqrestore(&atimer->lock, flags);
 
291
}
 
292
 
 
293
static void ct_xfitimer_start(struct ct_timer_instance *ti)
 
294
{
 
295
        struct ct_timer *atimer = ti->timer_base;
 
296
        unsigned long flags;
 
297
 
 
298
        spin_lock_irqsave(&atimer->lock, flags);
 
299
        if (list_empty(&ti->running_list))
 
300
                atimer->wc = ct_xfitimer_get_wc(atimer);
 
301
        ti->running = 1;
 
302
        ti->need_update = 0;
 
303
        list_add(&ti->running_list, &atimer->running_head);
 
304
        spin_unlock_irqrestore(&atimer->lock, flags);
 
305
        ct_xfitimer_update(atimer);
 
306
}
 
307
 
 
308
static void ct_xfitimer_stop(struct ct_timer_instance *ti)
 
309
{
 
310
        struct ct_timer *atimer = ti->timer_base;
 
311
        unsigned long flags;
 
312
 
 
313
        spin_lock_irqsave(&atimer->lock, flags);
 
314
        list_del_init(&ti->running_list);
 
315
        ti->running = 0;
 
316
        spin_unlock_irqrestore(&atimer->lock, flags);
 
317
        ct_xfitimer_update(atimer);
 
318
}
 
319
 
 
320
static void ct_xfitimer_free_global(struct ct_timer *atimer)
 
321
{
 
322
        ct_xfitimer_irq_stop(atimer);
 
323
}
 
324
 
 
325
static struct ct_timer_ops ct_xfitimer_ops = {
 
326
        .prepare = ct_xfitimer_prepare,
 
327
        .start = ct_xfitimer_start,
 
328
        .stop = ct_xfitimer_stop,
 
329
        .interrupt = ct_xfitimer_callback,
 
330
        .free_global = ct_xfitimer_free_global,
 
331
};
 
332
 
 
333
/*
 
334
 * timer instance
 
335
 */
 
336
 
 
337
struct ct_timer_instance *
 
338
ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
 
339
{
 
340
        struct ct_timer_instance *ti;
 
341
 
 
342
        ti = kzalloc(sizeof(*ti), GFP_KERNEL);
 
343
        if (!ti)
 
344
                return NULL;
 
345
        spin_lock_init(&ti->lock);
 
346
        INIT_LIST_HEAD(&ti->instance_list);
 
347
        INIT_LIST_HEAD(&ti->running_list);
 
348
        ti->timer_base = atimer;
 
349
        ti->apcm = apcm;
 
350
        ti->substream = apcm->substream;
 
351
        if (atimer->ops->init)
 
352
                atimer->ops->init(ti);
 
353
 
 
354
        spin_lock_irq(&atimer->list_lock);
 
355
        list_add(&ti->instance_list, &atimer->instance_head);
 
356
        spin_unlock_irq(&atimer->list_lock);
 
357
 
 
358
        return ti;
 
359
}
 
360
 
 
361
void ct_timer_prepare(struct ct_timer_instance *ti)
 
362
{
 
363
        if (ti->timer_base->ops->prepare)
 
364
                ti->timer_base->ops->prepare(ti);
 
365
        ti->position = 0;
 
366
        ti->running = 0;
 
367
}
 
368
 
 
369
void ct_timer_start(struct ct_timer_instance *ti)
 
370
{
 
371
        struct ct_timer *atimer = ti->timer_base;
 
372
        atimer->ops->start(ti);
 
373
}
 
374
 
 
375
void ct_timer_stop(struct ct_timer_instance *ti)
 
376
{
 
377
        struct ct_timer *atimer = ti->timer_base;
 
378
        atimer->ops->stop(ti);
 
379
}
 
380
 
 
381
void ct_timer_instance_free(struct ct_timer_instance *ti)
 
382
{
 
383
        struct ct_timer *atimer = ti->timer_base;
 
384
 
 
385
        atimer->ops->stop(ti); /* to be sure */
 
386
        if (atimer->ops->free_instance)
 
387
                atimer->ops->free_instance(ti);
 
388
 
 
389
        spin_lock_irq(&atimer->list_lock);
 
390
        list_del(&ti->instance_list);
 
391
        spin_unlock_irq(&atimer->list_lock);
 
392
 
 
393
        kfree(ti);
 
394
}
 
395
 
 
396
/*
 
397
 * timer manager
 
398
 */
 
399
 
 
400
static void ct_timer_interrupt(void *data, unsigned int status)
 
401
{
 
402
        struct ct_timer *timer = data;
 
403
 
 
404
        /* Interval timer interrupt */
 
405
        if ((status & IT_INT) && timer->ops->interrupt)
 
406
                timer->ops->interrupt(timer);
 
407
}
 
408
 
 
409
struct ct_timer *ct_timer_new(struct ct_atc *atc)
 
410
{
 
411
        struct ct_timer *atimer;
 
412
        struct hw *hw;
 
413
 
 
414
        atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
 
415
        if (!atimer)
 
416
                return NULL;
 
417
        spin_lock_init(&atimer->lock);
 
418
        spin_lock_init(&atimer->list_lock);
 
419
        INIT_LIST_HEAD(&atimer->instance_head);
 
420
        INIT_LIST_HEAD(&atimer->running_head);
 
421
        atimer->atc = atc;
 
422
        hw = atc->hw;
 
423
        if (!use_system_timer && hw->set_timer_irq) {
 
424
                snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
 
425
                atimer->ops = &ct_xfitimer_ops;
 
426
                hw->irq_callback_data = atimer;
 
427
                hw->irq_callback = ct_timer_interrupt;
 
428
        } else {
 
429
                snd_printd(KERN_INFO "ctxfi: Use system timer\n");
 
430
                atimer->ops = &ct_systimer_ops;
 
431
        }
 
432
        return atimer;
 
433
}
 
434
 
 
435
void ct_timer_free(struct ct_timer *atimer)
 
436
{
 
437
        struct hw *hw = atimer->atc->hw;
 
438
        hw->irq_callback = NULL;
 
439
        if (atimer->ops->free_global)
 
440
                atimer->ops->free_global(atimer);
 
441
        kfree(atimer);
 
442
}
 
443