Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: ctxfi - Use native timer interrupt on emu20k1

emu20k1 has a native timer interrupt based on the audio clock, which
is more accurate than the system timer (from the synchronization POV).
This patch adds the code to handle this with multiple streams.

The system timer is still used on emu20k2, and can be used also for
emu20k1 easily by changing USE_SYSTEM_TIMER to 1 in cttimer.c.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

+543 -105
+1 -1
sound/pci/ctxfi/Makefile
··· 1 1 snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ 2 - ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o \ 2 + ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \ 3 3 cthw20k2.o cthw20k1.o 4 4 5 5 obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
+2
sound/pci/ctxfi/ct20k1reg.h
··· 589 589 590 590 #define WC 0x1C6000 591 591 #define TIMR 0x1C6004 592 + # define TIMR_IE (1<<15) 593 + # define TIMR_IP (1<<14) 592 594 593 595 #define GIP 0x1C6010 594 596 #define GIE 0x1C6014
+20 -1
sound/pci/ctxfi/ctatc.c
··· 22 22 #include "ctsrc.h" 23 23 #include "ctamixer.h" 24 24 #include "ctdaio.h" 25 + #include "cttimer.h" 25 26 #include <linux/delay.h> 26 27 #include <sound/pcm.h> 27 28 #include <sound/control.h> ··· 308 307 src = apcm->src; 309 308 } 310 309 310 + ct_timer_prepare(apcm->timer); 311 + 311 312 return 0; 312 313 313 314 error1: ··· 392 389 src->ops->set_state(src, SRC_STATE_INIT); 393 390 src->ops->commit_write(src); 394 391 392 + ct_timer_start(apcm->timer); 395 393 return 0; 396 394 } 397 395 ··· 400 396 { 401 397 struct src *src = NULL; 402 398 int i = 0; 399 + 400 + ct_timer_stop(apcm->timer); 403 401 404 402 src = apcm->src; 405 403 src->ops->set_bm(src, 0); ··· 707 701 } 708 702 } 709 703 704 + ct_timer_prepare(apcm->timer); 705 + 710 706 return 0; 711 707 } 712 708 ··· 757 749 /* Enable relevant SRCs synchronously */ 758 750 src_mgr->commit_write(src_mgr); 759 751 752 + ct_timer_start(apcm->timer); 760 753 return 0; 761 754 } 762 755 ··· 914 905 amixer = apcm->amixers[1]; 915 906 dao->ops->set_right_input(dao, &amixer->rsc); 916 907 spin_unlock_irqrestore(&atc->atc_lock, flags); 908 + 909 + ct_timer_prepare(apcm->timer); 917 910 918 911 return 0; 919 912 } ··· 1110 1099 1111 1100 if (NULL == atc) 1112 1101 return 0; 1102 + 1103 + if (atc->timer) { 1104 + ct_timer_free(atc->timer); 1105 + atc->timer = NULL; 1106 + } 1113 1107 1114 1108 /* Stop hardware and disable all interrupts */ 1115 1109 if (NULL != atc->hw) ··· 1602 1586 /* Build topology */ 1603 1587 atc_connect_resources(atc); 1604 1588 1589 + atc->timer = ct_timer_new(atc); 1590 + if (!atc->timer) 1591 + goto error1; 1592 + 1605 1593 atc->create_alsa_devs = ct_create_alsa_devs; 1606 1594 1607 1595 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); ··· 1622 1602 printk(KERN_ERR "ctxfi: Something wrong!!!\n"); 1623 1603 return err; 1624 1604 } 1625 -
+5 -4
sound/pci/ctxfi/ctatc.h
··· 59 59 }; 60 60 61 61 struct ct_atc; 62 + struct ct_timer; 63 + struct ct_timer_instance; 62 64 63 65 /* alsa pcm stream descriptor */ 64 66 struct ct_atc_pcm { 65 67 struct snd_pcm_substream *substream; 66 68 void (*interrupt)(struct ct_atc_pcm *apcm); 69 + struct ct_timer_instance *timer; 67 70 unsigned int started:1; 68 - unsigned int stop_timer:1; 69 - struct timer_list timer; 70 - spinlock_t timer_lock; 71 - unsigned int position; 72 71 73 72 /* Only mono and interleaved modes are supported now. */ 74 73 struct ct_vm_block *vm_block; ··· 143 144 unsigned char n_src; 144 145 unsigned char n_srcimp; 145 146 unsigned char n_pcm; 147 + 148 + struct ct_timer *timer; 146 149 }; 147 150 148 151
+19
sound/pci/ctxfi/cthardware.h
··· 145 145 int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr); 146 146 int (*daio_mgr_commit_write)(struct hw *hw, void *blk); 147 147 148 + int (*set_timer_irq)(struct hw *hw, int enable); 149 + int (*set_timer_tick)(struct hw *hw, unsigned int tick); 150 + 151 + void (*irq_callback)(void *data, unsigned int bit); 152 + void *irq_callback_data; 153 + 148 154 struct pci_dev *pci; /* the pci kernel structure of this card */ 149 155 int irq; 150 156 unsigned long io_base; ··· 162 156 163 157 unsigned int get_field(unsigned int data, unsigned int field); 164 158 void set_field(unsigned int *data, unsigned int field, unsigned int value); 159 + 160 + /* IRQ bits */ 161 + #define PLL_INT (1 << 10) /* PLL input-clock out-of-range */ 162 + #define FI_INT (1 << 9) /* forced interrupt */ 163 + #define IT_INT (1 << 8) /* timer interrupt */ 164 + #define PCI_INT (1 << 7) /* PCI bus error pending */ 165 + #define URT_INT (1 << 6) /* UART Tx/Rx */ 166 + #define GPI_INT (1 << 5) /* GPI pin */ 167 + #define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */ 168 + #define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */ 169 + #define TP_INT (1 << 2) /* transport priority queue */ 170 + #define DSP_INT (1 << 1) /* DSP */ 171 + #define SRC_INT (1 << 0) /* SRC channels */ 165 172 166 173 #endif /* CTHARDWARE_H */
+40 -3
sound/pci/ctxfi/cthw20k1.c
··· 1171 1171 return 0; 1172 1172 } 1173 1173 1174 + /* Timer interrupt */ 1175 + static int set_timer_irq(struct hw *hw, int enable) 1176 + { 1177 + hw_write_20kx(hw, GIE, enable ? IT_INT : 0); 1178 + return 0; 1179 + } 1180 + 1181 + static int set_timer_tick(struct hw *hw, unsigned int ticks) 1182 + { 1183 + if (ticks) 1184 + ticks |= TIMR_IE | TIMR_IP; 1185 + hw_write_20kx(hw, TIMR, ticks); 1186 + return 0; 1187 + } 1188 + 1174 1189 /* Card hardware initialization block */ 1175 1190 struct dac_conf { 1176 1191 unsigned int msr; /* master sample rate in rsrs */ ··· 1893 1878 return 0; 1894 1879 } 1895 1880 1881 + static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id) 1882 + { 1883 + struct hw *hw = dev_id; 1884 + unsigned int status; 1885 + 1886 + status = hw_read_20kx(hw, GIP); 1887 + if (!status) 1888 + return IRQ_NONE; 1889 + 1890 + if (hw->irq_callback) 1891 + hw->irq_callback(hw->irq_callback_data, status); 1892 + 1893 + hw_write_20kx(hw, GIP, status); 1894 + return IRQ_HANDLED; 1895 + } 1896 + 1896 1897 static int hw_card_start(struct hw *hw) 1897 1898 { 1898 1899 int err = 0; ··· 1945 1914 hw->io_base = pci_resource_start(pci, 0); 1946 1915 } 1947 1916 1948 - /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED, 1949 - atc->chip_details->nm_card, hw))) { 1917 + err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, 1918 + "ctxfi", hw); 1919 + if (err < 0) { 1920 + printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); 1950 1921 goto error2; 1951 1922 } 1952 1923 hw->irq = pci->irq; 1953 - */ 1954 1924 1955 1925 pci_set_master(pci); 1956 1926 ··· 1968 1936 static int hw_card_stop(struct hw *hw) 1969 1937 { 1970 1938 /* TODO: Disable interrupt and so on... */ 1939 + if (hw->irq >= 0) 1940 + synchronize_irq(hw->irq); 1971 1941 return 0; 1972 1942 } 1973 1943 ··· 2248 2214 hw->daio_mgr_set_imapnxt = daio_mgr_set_imapnxt; 2249 2215 hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr; 2250 2216 hw->daio_mgr_commit_write = daio_mgr_commit_write; 2217 + 2218 + hw->set_timer_irq = set_timer_irq; 2219 + hw->set_timer_tick = set_timer_tick; 2251 2220 2252 2221 *rhw = hw; 2253 2222
+10 -96
sound/pci/ctxfi/ctpcm.c
··· 16 16 */ 17 17 18 18 #include "ctpcm.h" 19 + #include "cttimer.h" 19 20 #include <sound/pcm.h> 20 21 21 22 /* Hardware descriptions for playback */ ··· 109 108 struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream); 110 109 111 110 atc->pcm_release_resources(atc, apcm); 111 + ct_timer_instance_free(apcm->timer); 112 112 kfree(apcm); 113 113 runtime->private_data = NULL; 114 114 } ··· 126 124 if (NULL == apcm) 127 125 return -ENOMEM; 128 126 129 - spin_lock_init(&apcm->timer_lock); 130 - apcm->stop_timer = 0; 131 127 apcm->substream = substream; 132 128 apcm->interrupt = ct_atc_pcm_interrupt; 133 129 runtime->private_data = apcm; ··· 152 152 kfree(apcm); 153 153 return err; 154 154 } 155 + 156 + apcm->timer = ct_timer_instance_new(atc->timer, apcm); 157 + if (!apcm->timer) 158 + return -ENOMEM; 155 159 156 160 return 0; 157 161 } ··· 186 182 return snd_pcm_lib_free_pages(substream); 187 183 } 188 184 189 - static void ct_pcm_timer_callback(unsigned long data) 190 - { 191 - struct ct_atc_pcm *apcm = (struct ct_atc_pcm *)data; 192 - struct snd_pcm_substream *substream = apcm->substream; 193 - struct snd_pcm_runtime *runtime = substream->runtime; 194 - unsigned int period_size = runtime->period_size; 195 - unsigned int buffer_size = runtime->buffer_size; 196 - unsigned long flags; 197 - unsigned int position = 0, dist = 0, interval = 0; 198 - 199 - position = substream->ops->pointer(substream); 200 - dist = (position + buffer_size - apcm->position) % buffer_size; 201 - if ((dist >= period_size) || 202 - (position/period_size != apcm->position/period_size)) { 203 - apcm->interrupt(apcm); 204 - apcm->position = position; 205 - } 206 - /* Add extra HZ*5/1000 to avoid overrun issue when recording 207 - * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */ 208 - interval = ((period_size - (position % period_size)) 209 - * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000; 210 - spin_lock_irqsave(&apcm->timer_lock, flags); 211 - apcm->timer.expires = jiffies + interval; 212 - if (!apcm->stop_timer) 213 - add_timer(&apcm->timer); 214 - 215 - spin_unlock_irqrestore(&apcm->timer_lock, flags); 216 - } 217 - 218 - static int ct_pcm_timer_prepare(struct ct_atc_pcm *apcm) 219 - { 220 - unsigned long flags; 221 - 222 - spin_lock_irqsave(&apcm->timer_lock, flags); 223 - if (timer_pending(&apcm->timer)) { 224 - /* The timer has already been started. */ 225 - spin_unlock_irqrestore(&apcm->timer_lock, flags); 226 - return 0; 227 - } 228 - 229 - init_timer(&apcm->timer); 230 - apcm->timer.data = (unsigned long)apcm; 231 - apcm->timer.function = ct_pcm_timer_callback; 232 - spin_unlock_irqrestore(&apcm->timer_lock, flags); 233 - apcm->position = 0; 234 - 235 - return 0; 236 - } 237 - 238 - static int ct_pcm_timer_start(struct ct_atc_pcm *apcm) 239 - { 240 - struct snd_pcm_runtime *runtime = apcm->substream->runtime; 241 - unsigned long flags; 242 - 243 - spin_lock_irqsave(&apcm->timer_lock, flags); 244 - if (timer_pending(&apcm->timer)) { 245 - /* The timer has already been started. */ 246 - spin_unlock_irqrestore(&apcm->timer_lock, flags); 247 - return 0; 248 - } 249 - 250 - apcm->timer.expires = jiffies + (runtime->period_size * HZ + 251 - (runtime->rate - 1)) / runtime->rate; 252 - apcm->stop_timer = 0; 253 - add_timer(&apcm->timer); 254 - spin_unlock_irqrestore(&apcm->timer_lock, flags); 255 - 256 - return 0; 257 - } 258 - 259 - static int ct_pcm_timer_stop(struct ct_atc_pcm *apcm) 260 - { 261 - unsigned long flags; 262 - 263 - spin_lock_irqsave(&apcm->timer_lock, flags); 264 - apcm->stop_timer = 1; 265 - del_timer(&apcm->timer); 266 - spin_unlock_irqrestore(&apcm->timer_lock, flags); 267 - 268 - try_to_del_timer_sync(&apcm->timer); 269 - 270 - return 0; 271 - } 272 185 273 186 static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) 274 187 { ··· 204 283 return err; 205 284 } 206 285 207 - ct_pcm_timer_prepare(apcm); 208 - 209 286 return 0; 210 287 } 211 288 ··· 219 300 case SNDRV_PCM_TRIGGER_RESUME: 220 301 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 221 302 atc->pcm_playback_start(atc, apcm); 222 - ct_pcm_timer_start(apcm); 223 303 break; 224 304 case SNDRV_PCM_TRIGGER_STOP: 225 305 case SNDRV_PCM_TRIGGER_SUSPEND: 226 306 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 227 - ct_pcm_timer_stop(apcm); 228 307 atc->pcm_playback_stop(atc, apcm); 229 308 break; 230 309 default: ··· 258 341 if (NULL == apcm) 259 342 return -ENOMEM; 260 343 261 - spin_lock_init(&apcm->timer_lock); 262 344 apcm->started = 0; 263 - apcm->stop_timer = 0; 264 345 apcm->substream = substream; 265 346 apcm->interrupt = ct_atc_pcm_interrupt; 266 347 runtime->private_data = apcm; ··· 279 364 kfree(apcm); 280 365 return err; 281 366 } 367 + 368 + apcm->timer = ct_timer_instance_new(atc->timer, apcm); 369 + if (!apcm->timer) 370 + return -ENOMEM; 282 371 283 372 return 0; 284 373 } ··· 307 388 return err; 308 389 } 309 390 310 - ct_pcm_timer_prepare(apcm); 311 - 312 391 return 0; 313 392 } 314 393 ··· 320 403 switch (cmd) { 321 404 case SNDRV_PCM_TRIGGER_START: 322 405 atc->pcm_capture_start(atc, apcm); 323 - ct_pcm_timer_start(apcm); 324 406 break; 325 407 case SNDRV_PCM_TRIGGER_STOP: 326 - ct_pcm_timer_stop(apcm); 327 408 atc->pcm_capture_stop(atc, apcm); 328 409 break; 329 410 default: 330 - ct_pcm_timer_stop(apcm); 331 411 atc->pcm_capture_stop(atc, apcm); 332 412 break; 333 413 }
+417
sound/pci/ctxfi/cttimer.c
··· 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 <sound/core.h> 11 + #include <sound/pcm.h> 12 + #include "ctatc.h" 13 + #include "cthardware.h" 14 + #include "cttimer.h" 15 + 16 + struct ct_timer_ops { 17 + void (*init)(struct ct_timer_instance *); 18 + void (*prepare)(struct ct_timer_instance *); 19 + void (*start)(struct ct_timer_instance *); 20 + void (*stop)(struct ct_timer_instance *); 21 + void (*free_instance)(struct ct_timer_instance *); 22 + void (*interrupt)(struct ct_timer *); 23 + void (*free_global)(struct ct_timer *); 24 + }; 25 + 26 + /* timer instance -- assigned to each PCM stream */ 27 + struct ct_timer_instance { 28 + spinlock_t lock; 29 + struct ct_timer *timer_base; 30 + struct ct_atc_pcm *apcm; 31 + struct snd_pcm_substream *substream; 32 + struct timer_list timer; 33 + struct list_head instance_list; 34 + struct list_head running_list; 35 + unsigned int position; 36 + unsigned int frag_count; 37 + unsigned int running:1; 38 + unsigned int need_update:1; 39 + }; 40 + 41 + /* timer instance manager */ 42 + struct ct_timer { 43 + spinlock_t lock; /* global timer lock (for xfitimer) */ 44 + spinlock_t list_lock; /* lock for instance list */ 45 + struct ct_atc *atc; 46 + struct ct_timer_ops *ops; 47 + struct list_head instance_head; 48 + struct list_head running_head; 49 + unsigned int irq_handling:1; /* in IRQ handling */ 50 + unsigned int reprogram:1; /* need to reprogram the internval */ 51 + unsigned int running:1; /* global timer running */ 52 + }; 53 + 54 + 55 + /* 56 + * system-timer-based updates 57 + */ 58 + 59 + static void ct_systimer_callback(unsigned long data) 60 + { 61 + struct ct_timer_instance *ti = (struct ct_timer_instance *)data; 62 + struct snd_pcm_substream *substream = ti->substream; 63 + struct snd_pcm_runtime *runtime = substream->runtime; 64 + struct ct_atc_pcm *apcm = ti->apcm; 65 + unsigned int period_size = runtime->period_size; 66 + unsigned int buffer_size = runtime->buffer_size; 67 + unsigned long flags; 68 + unsigned int position, dist, interval; 69 + 70 + position = substream->ops->pointer(substream); 71 + dist = (position + buffer_size - ti->position) % buffer_size; 72 + if (dist >= period_size || 73 + position / period_size != ti->position / period_size) { 74 + apcm->interrupt(apcm); 75 + ti->position = position; 76 + } 77 + /* Add extra HZ*5/1000 to avoid overrun issue when recording 78 + * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */ 79 + interval = ((period_size - (position % period_size)) 80 + * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000; 81 + spin_lock_irqsave(&ti->lock, flags); 82 + if (ti->running) 83 + mod_timer(&ti->timer, jiffies + interval); 84 + spin_unlock_irqrestore(&ti->lock, flags); 85 + } 86 + 87 + static void ct_systimer_init(struct ct_timer_instance *ti) 88 + { 89 + setup_timer(&ti->timer, ct_systimer_callback, 90 + (unsigned long)ti); 91 + } 92 + 93 + static void ct_systimer_start(struct ct_timer_instance *ti) 94 + { 95 + struct snd_pcm_runtime *runtime = ti->substream->runtime; 96 + unsigned long flags; 97 + 98 + spin_lock_irqsave(&ti->lock, flags); 99 + ti->running = 1; 100 + mod_timer(&ti->timer, 101 + jiffies + (runtime->period_size * HZ + 102 + (runtime->rate - 1)) / runtime->rate); 103 + spin_unlock_irqrestore(&ti->lock, flags); 104 + } 105 + 106 + static void ct_systimer_stop(struct ct_timer_instance *ti) 107 + { 108 + unsigned long flags; 109 + 110 + spin_lock_irqsave(&ti->lock, flags); 111 + ti->running = 0; 112 + del_timer(&ti->timer); 113 + spin_unlock_irqrestore(&ti->lock, flags); 114 + } 115 + 116 + static void ct_systimer_prepare(struct ct_timer_instance *ti) 117 + { 118 + ct_systimer_stop(ti); 119 + try_to_del_timer_sync(&ti->timer); 120 + } 121 + 122 + #define ct_systimer_free ct_systimer_prepare 123 + 124 + static struct ct_timer_ops ct_systimer_ops = { 125 + .init = ct_systimer_init, 126 + .free_instance = ct_systimer_free, 127 + .prepare = ct_systimer_prepare, 128 + .start = ct_systimer_start, 129 + .stop = ct_systimer_stop, 130 + }; 131 + 132 + 133 + /* 134 + * Handling multiple streams using a global emu20k1 timer irq 135 + */ 136 + 137 + #define CT_TIMER_FREQ 48000 138 + #define MAX_TICKS ((1 << 13) - 1) 139 + 140 + static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) 141 + { 142 + struct hw *hw = atimer->atc->hw; 143 + if (ticks > MAX_TICKS) 144 + ticks = MAX_TICKS; 145 + hw->set_timer_tick(hw, ticks); 146 + if (!atimer->running) 147 + hw->set_timer_irq(hw, 1); 148 + atimer->running = 1; 149 + } 150 + 151 + static void ct_xfitimer_irq_stop(struct ct_timer *atimer) 152 + { 153 + if (atimer->running) { 154 + struct hw *hw = atimer->atc->hw; 155 + hw->set_timer_irq(hw, 0); 156 + hw->set_timer_tick(hw, 0); 157 + atimer->running = 0; 158 + } 159 + } 160 + 161 + /* 162 + * reprogram the timer interval; 163 + * checks the running instance list and determines the next timer interval. 164 + * also updates the each stream position, returns the number of streams 165 + * to call snd_pcm_period_elapsed() appropriately 166 + * 167 + * call this inside the lock and irq disabled 168 + */ 169 + static int ct_xfitimer_reprogram(struct ct_timer *atimer) 170 + { 171 + struct ct_timer_instance *ti; 172 + int min_intr = -1; 173 + int updates = 0; 174 + 175 + list_for_each_entry(ti, &atimer->running_head, running_list) { 176 + struct snd_pcm_runtime *runtime; 177 + unsigned int pos, diff; 178 + int intr; 179 + runtime = ti->substream->runtime; 180 + pos = ti->substream->ops->pointer(ti->substream); 181 + if (pos < ti->position) 182 + diff = runtime->buffer_size - ti->position + pos; 183 + else 184 + diff = pos - ti->position; 185 + ti->position = pos; 186 + while (diff >= ti->frag_count) { 187 + ti->frag_count += runtime->period_size; 188 + ti->need_update = 1; 189 + updates++; 190 + } 191 + ti->frag_count -= diff; 192 + intr = div_u64((u64)ti->frag_count * CT_TIMER_FREQ, 193 + runtime->rate); 194 + if (min_intr < 0 || intr < min_intr) 195 + min_intr = intr; 196 + } 197 + 198 + if (min_intr > 0) 199 + ct_xfitimer_irq_rearm(atimer, min_intr); 200 + else 201 + ct_xfitimer_irq_stop(atimer); 202 + 203 + atimer->reprogram = 0; /* clear flag */ 204 + return updates; 205 + } 206 + 207 + /* look through the instance list and call period_elapsed if needed */ 208 + static void ct_xfitimer_check_period(struct ct_timer *atimer) 209 + { 210 + struct ct_timer_instance *ti; 211 + unsigned long flags; 212 + 213 + spin_lock_irqsave(&atimer->list_lock, flags); 214 + list_for_each_entry(ti, &atimer->instance_head, instance_list) { 215 + if (ti->need_update) { 216 + ti->need_update = 0; 217 + ti->apcm->interrupt(ti->apcm); 218 + } 219 + } 220 + spin_unlock_irqrestore(&atimer->list_lock, flags); 221 + } 222 + 223 + /* Handle timer-interrupt */ 224 + static void ct_xfitimer_callback(struct ct_timer *atimer) 225 + { 226 + int update; 227 + unsigned long flags; 228 + 229 + spin_lock_irqsave(&atimer->lock, flags); 230 + atimer->irq_handling = 1; 231 + do { 232 + update = ct_xfitimer_reprogram(atimer); 233 + spin_unlock(&atimer->lock); 234 + if (update) 235 + ct_xfitimer_check_period(atimer); 236 + spin_lock(&atimer->lock); 237 + } while (atimer->reprogram); 238 + atimer->irq_handling = 0; 239 + spin_unlock_irqrestore(&atimer->lock, flags); 240 + } 241 + 242 + static void ct_xfitimer_prepare(struct ct_timer_instance *ti) 243 + { 244 + ti->frag_count = ti->substream->runtime->period_size; 245 + ti->need_update = 0; 246 + } 247 + 248 + 249 + /* start/stop the timer */ 250 + static void ct_xfitimer_update(struct ct_timer *atimer) 251 + { 252 + unsigned long flags; 253 + int update; 254 + 255 + if (atimer->irq_handling) { 256 + /* reached from IRQ handler; let it handle later */ 257 + atimer->reprogram = 1; 258 + return; 259 + } 260 + 261 + spin_lock_irqsave(&atimer->lock, flags); 262 + ct_xfitimer_irq_stop(atimer); 263 + update = ct_xfitimer_reprogram(atimer); 264 + spin_unlock_irqrestore(&atimer->lock, flags); 265 + if (update) 266 + ct_xfitimer_check_period(atimer); 267 + } 268 + 269 + static void ct_xfitimer_start(struct ct_timer_instance *ti) 270 + { 271 + struct ct_timer *atimer = ti->timer_base; 272 + unsigned long flags; 273 + 274 + spin_lock_irqsave(&atimer->lock, flags); 275 + list_add(&ti->running_list, &atimer->running_head); 276 + spin_unlock_irqrestore(&atimer->lock, flags); 277 + ct_xfitimer_update(atimer); 278 + } 279 + 280 + static void ct_xfitimer_stop(struct ct_timer_instance *ti) 281 + { 282 + struct ct_timer *atimer = ti->timer_base; 283 + unsigned long flags; 284 + 285 + spin_lock_irqsave(&atimer->lock, flags); 286 + list_del_init(&ti->running_list); 287 + ti->need_update = 0; 288 + spin_unlock_irqrestore(&atimer->lock, flags); 289 + ct_xfitimer_update(atimer); 290 + } 291 + 292 + static void ct_xfitimer_free_global(struct ct_timer *atimer) 293 + { 294 + ct_xfitimer_irq_stop(atimer); 295 + } 296 + 297 + static struct ct_timer_ops ct_xfitimer_ops = { 298 + .prepare = ct_xfitimer_prepare, 299 + .start = ct_xfitimer_start, 300 + .stop = ct_xfitimer_stop, 301 + .interrupt = ct_xfitimer_callback, 302 + .free_global = ct_xfitimer_free_global, 303 + }; 304 + 305 + /* 306 + * timer instance 307 + */ 308 + 309 + struct ct_timer_instance * 310 + ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm) 311 + { 312 + struct ct_timer_instance *ti; 313 + 314 + ti = kzalloc(sizeof(*ti), GFP_KERNEL); 315 + if (!ti) 316 + return NULL; 317 + spin_lock_init(&ti->lock); 318 + INIT_LIST_HEAD(&ti->instance_list); 319 + INIT_LIST_HEAD(&ti->running_list); 320 + ti->timer_base = atimer; 321 + ti->apcm = apcm; 322 + ti->substream = apcm->substream; 323 + if (atimer->ops->init) 324 + atimer->ops->init(ti); 325 + 326 + spin_lock_irq(&atimer->list_lock); 327 + list_add(&ti->instance_list, &atimer->instance_head); 328 + spin_unlock_irq(&atimer->list_lock); 329 + 330 + return ti; 331 + } 332 + 333 + void ct_timer_prepare(struct ct_timer_instance *ti) 334 + { 335 + if (ti->timer_base->ops->prepare) 336 + ti->timer_base->ops->prepare(ti); 337 + ti->position = 0; 338 + ti->running = 0; 339 + } 340 + 341 + void ct_timer_start(struct ct_timer_instance *ti) 342 + { 343 + struct ct_timer *atimer = ti->timer_base; 344 + atimer->ops->start(ti); 345 + } 346 + 347 + void ct_timer_stop(struct ct_timer_instance *ti) 348 + { 349 + struct ct_timer *atimer = ti->timer_base; 350 + atimer->ops->stop(ti); 351 + } 352 + 353 + void ct_timer_instance_free(struct ct_timer_instance *ti) 354 + { 355 + struct ct_timer *atimer = ti->timer_base; 356 + 357 + atimer->ops->stop(ti); /* to be sure */ 358 + if (atimer->ops->free_instance) 359 + atimer->ops->free_instance(ti); 360 + 361 + spin_lock_irq(&atimer->list_lock); 362 + list_del(&ti->instance_list); 363 + spin_unlock_irq(&atimer->list_lock); 364 + 365 + kfree(ti); 366 + } 367 + 368 + /* 369 + * timer manager 370 + */ 371 + 372 + #define USE_SYSTEM_TIMER 0 373 + 374 + static void ct_timer_interrupt(void *data, unsigned int status) 375 + { 376 + struct ct_timer *timer = data; 377 + 378 + /* Interval timer interrupt */ 379 + if ((status & IT_INT) && timer->ops->interrupt) 380 + timer->ops->interrupt(timer); 381 + } 382 + 383 + struct ct_timer *ct_timer_new(struct ct_atc *atc) 384 + { 385 + struct ct_timer *atimer; 386 + struct hw *hw; 387 + 388 + atimer = kzalloc(sizeof(*atimer), GFP_KERNEL); 389 + if (!atimer) 390 + return NULL; 391 + spin_lock_init(&atimer->lock); 392 + spin_lock_init(&atimer->list_lock); 393 + INIT_LIST_HEAD(&atimer->instance_head); 394 + INIT_LIST_HEAD(&atimer->running_head); 395 + atimer->atc = atc; 396 + hw = atc->hw; 397 + if (!USE_SYSTEM_TIMER && hw->set_timer_irq) { 398 + printk(KERN_INFO "ctxfi: Use xfi-native timer\n"); 399 + atimer->ops = &ct_xfitimer_ops; 400 + hw->irq_callback_data = atimer; 401 + hw->irq_callback = ct_timer_interrupt; 402 + } else { 403 + printk(KERN_INFO "ctxfi: Use system timer\n"); 404 + atimer->ops = &ct_systimer_ops; 405 + } 406 + return atimer; 407 + } 408 + 409 + void ct_timer_free(struct ct_timer *atimer) 410 + { 411 + struct hw *hw = atimer->atc->hw; 412 + hw->irq_callback = NULL; 413 + if (atimer->ops->free_global) 414 + atimer->ops->free_global(atimer); 415 + kfree(atimer); 416 + } 417 +
+29
sound/pci/ctxfi/cttimer.h
··· 1 + /* 2 + * Timer handling 3 + */ 4 + 5 + #ifndef __CTTIMER_H 6 + #define __CTTIMER_H 7 + 8 + #include <linux/spinlock.h> 9 + #include <linux/timer.h> 10 + #include <linux/list.h> 11 + 12 + struct snd_pcm_substream; 13 + struct ct_atc; 14 + struct ct_atc_pcm; 15 + 16 + struct ct_timer; 17 + struct ct_timer_instance; 18 + 19 + struct ct_timer *ct_timer_new(struct ct_atc *atc); 20 + void ct_timer_free(struct ct_timer *atimer); 21 + 22 + struct ct_timer_instance * 23 + ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm); 24 + void ct_timer_instance_free(struct ct_timer_instance *ti); 25 + void ct_timer_start(struct ct_timer_instance *ti); 26 + void ct_timer_stop(struct ct_timer_instance *ti); 27 + void ct_timer_prepare(struct ct_timer_instance *ti); 28 + 29 + #endif /* __CTTIMER_H */