aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/ctxfi/Makefile2
-rw-r--r--sound/pci/ctxfi/ct20k1reg.h2
-rw-r--r--sound/pci/ctxfi/ctatc.c21
-rw-r--r--sound/pci/ctxfi/ctatc.h9
-rw-r--r--sound/pci/ctxfi/cthardware.h19
-rw-r--r--sound/pci/ctxfi/cthw20k1.c43
-rw-r--r--sound/pci/ctxfi/ctpcm.c106
-rw-r--r--sound/pci/ctxfi/cttimer.c417
-rw-r--r--sound/pci/ctxfi/cttimer.h29
9 files changed, 543 insertions, 105 deletions
diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile
index 29043237f9f8..15075f89e98a 100644
--- a/sound/pci/ctxfi/Makefile
+++ b/sound/pci/ctxfi/Makefile
@@ -1,5 +1,5 @@
1snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ 1snd-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 cthw20k2.o cthw20k1.o 3 cthw20k2.o cthw20k1.o
4 4
5obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o 5obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h
index c62e6775dab3..f2e34e3f27ee 100644
--- a/sound/pci/ctxfi/ct20k1reg.h
+++ b/sound/pci/ctxfi/ct20k1reg.h
@@ -589,6 +589,8 @@
589 589
590#define WC 0x1C6000 590#define WC 0x1C6000
591#define TIMR 0x1C6004 591#define TIMR 0x1C6004
592# define TIMR_IE (1<<15)
593# define TIMR_IP (1<<14)
592 594
593#define GIP 0x1C6010 595#define GIP 0x1C6010
594#define GIE 0x1C6014 596#define GIE 0x1C6014
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 684947546d81..10b741977dd7 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -22,6 +22,7 @@
22#include "ctsrc.h" 22#include "ctsrc.h"
23#include "ctamixer.h" 23#include "ctamixer.h"
24#include "ctdaio.h" 24#include "ctdaio.h"
25#include "cttimer.h"
25#include <linux/delay.h> 26#include <linux/delay.h>
26#include <sound/pcm.h> 27#include <sound/pcm.h>
27#include <sound/control.h> 28#include <sound/control.h>
@@ -307,6 +308,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
307 src = apcm->src; 308 src = apcm->src;
308 } 309 }
309 310
311 ct_timer_prepare(apcm->timer);
312
310 return 0; 313 return 0;
311 314
312error1: 315error1:
@@ -389,6 +392,7 @@ static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
389 src->ops->set_state(src, SRC_STATE_INIT); 392 src->ops->set_state(src, SRC_STATE_INIT);
390 src->ops->commit_write(src); 393 src->ops->commit_write(src);
391 394
395 ct_timer_start(apcm->timer);
392 return 0; 396 return 0;
393} 397}
394 398
@@ -397,6 +401,8 @@ static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
397 struct src *src = NULL; 401 struct src *src = NULL;
398 int i = 0; 402 int i = 0;
399 403
404 ct_timer_stop(apcm->timer);
405
400 src = apcm->src; 406 src = apcm->src;
401 src->ops->set_bm(src, 0); 407 src->ops->set_bm(src, 0);
402 src->ops->set_state(src, SRC_STATE_OFF); 408 src->ops->set_state(src, SRC_STATE_OFF);
@@ -701,6 +707,8 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
701 } 707 }
702 } 708 }
703 709
710 ct_timer_prepare(apcm->timer);
711
704 return 0; 712 return 0;
705} 713}
706 714
@@ -749,6 +757,7 @@ static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
749 /* Enable relevant SRCs synchronously */ 757 /* Enable relevant SRCs synchronously */
750 src_mgr->commit_write(src_mgr); 758 src_mgr->commit_write(src_mgr);
751 759
760 ct_timer_start(apcm->timer);
752 return 0; 761 return 0;
753} 762}
754 763
@@ -906,6 +915,8 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
906 dao->ops->set_right_input(dao, &amixer->rsc); 915 dao->ops->set_right_input(dao, &amixer->rsc);
907 spin_unlock_irqrestore(&atc->atc_lock, flags); 916 spin_unlock_irqrestore(&atc->atc_lock, flags);
908 917
918 ct_timer_prepare(apcm->timer);
919
909 return 0; 920 return 0;
910} 921}
911 922
@@ -1100,6 +1111,11 @@ static int ct_atc_destroy(struct ct_atc *atc)
1100 if (NULL == atc) 1111 if (NULL == atc)
1101 return 0; 1112 return 0;
1102 1113
1114 if (atc->timer) {
1115 ct_timer_free(atc->timer);
1116 atc->timer = NULL;
1117 }
1118
1103 /* Stop hardware and disable all interrupts */ 1119 /* Stop hardware and disable all interrupts */
1104 if (NULL != atc->hw) 1120 if (NULL != atc->hw)
1105 ((struct hw *)atc->hw)->card_stop(atc->hw); 1121 ((struct hw *)atc->hw)->card_stop(atc->hw);
@@ -1586,6 +1602,10 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
1586 /* Build topology */ 1602 /* Build topology */
1587 atc_connect_resources(atc); 1603 atc_connect_resources(atc);
1588 1604
1605 atc->timer = ct_timer_new(atc);
1606 if (!atc->timer)
1607 goto error1;
1608
1589 atc->create_alsa_devs = ct_create_alsa_devs; 1609 atc->create_alsa_devs = ct_create_alsa_devs;
1590 1610
1591 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); 1611 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
@@ -1602,4 +1622,3 @@ error1:
1602 printk(KERN_ERR "ctxfi: Something wrong!!!\n"); 1622 printk(KERN_ERR "ctxfi: Something wrong!!!\n");
1603 return err; 1623 return err;
1604} 1624}
1605
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index b86d12cd4a19..a3f9b1bc7dcc 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -59,16 +59,15 @@ struct ct_atc_chip_details {
59}; 59};
60 60
61struct ct_atc; 61struct ct_atc;
62struct ct_timer;
63struct ct_timer_instance;
62 64
63/* alsa pcm stream descriptor */ 65/* alsa pcm stream descriptor */
64struct ct_atc_pcm { 66struct ct_atc_pcm {
65 struct snd_pcm_substream *substream; 67 struct snd_pcm_substream *substream;
66 void (*interrupt)(struct ct_atc_pcm *apcm); 68 void (*interrupt)(struct ct_atc_pcm *apcm);
69 struct ct_timer_instance *timer;
67 unsigned int started:1; 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 /* Only mono and interleaved modes are supported now. */ 72 /* Only mono and interleaved modes are supported now. */
74 struct ct_vm_block *vm_block; 73 struct ct_vm_block *vm_block;
@@ -144,6 +143,8 @@ struct ct_atc {
144 unsigned char n_src; 143 unsigned char n_src;
145 unsigned char n_srcimp; 144 unsigned char n_srcimp;
146 unsigned char n_pcm; 145 unsigned char n_pcm;
146
147 struct ct_timer *timer;
147}; 148};
148 149
149 150
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index b0512df8b334..35350cf9d2f2 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -145,6 +145,12 @@ struct hw {
145 int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr); 145 int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
146 int (*daio_mgr_commit_write)(struct hw *hw, void *blk); 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 struct pci_dev *pci; /* the pci kernel structure of this card */ 154 struct pci_dev *pci; /* the pci kernel structure of this card */
149 int irq; 155 int irq;
150 unsigned long io_base; 156 unsigned long io_base;
@@ -157,4 +163,17 @@ int destroy_hw_obj(struct hw *hw);
157unsigned int get_field(unsigned int data, unsigned int field); 163unsigned int get_field(unsigned int data, unsigned int field);
158void set_field(unsigned int *data, unsigned int field, unsigned int value); 164void set_field(unsigned int *data, unsigned int field, unsigned int value);
159 165
166/* IRQ bits */
167#define PLL_INT (1 << 10) /* PLL input-clock out-of-range */
168#define FI_INT (1 << 9) /* forced interrupt */
169#define IT_INT (1 << 8) /* timer interrupt */
170#define PCI_INT (1 << 7) /* PCI bus error pending */
171#define URT_INT (1 << 6) /* UART Tx/Rx */
172#define GPI_INT (1 << 5) /* GPI pin */
173#define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */
174#define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */
175#define TP_INT (1 << 2) /* transport priority queue */
176#define DSP_INT (1 << 1) /* DSP */
177#define SRC_INT (1 << 0) /* SRC channels */
178
160#endif /* CTHARDWARE_H */ 179#endif /* CTHARDWARE_H */
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index e530a6d60422..550b30a2bcf1 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1171,6 +1171,21 @@ static int daio_mgr_put_ctrl_blk(void *blk)
1171 return 0; 1171 return 0;
1172} 1172}
1173 1173
1174/* Timer interrupt */
1175static 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
1181static 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/* Card hardware initialization block */ 1189/* Card hardware initialization block */
1175struct dac_conf { 1190struct dac_conf {
1176 unsigned int msr; /* master sample rate in rsrs */ 1191 unsigned int msr; /* master sample rate in rsrs */
@@ -1878,6 +1893,22 @@ static int uaa_to_xfi(struct pci_dev *pci)
1878 return 0; 1893 return 0;
1879} 1894}
1880 1895
1896static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id)
1897{
1898 struct hw *hw = dev_id;
1899 unsigned int status;
1900
1901 status = hw_read_20kx(hw, GIP);
1902 if (!status)
1903 return IRQ_NONE;
1904
1905 if (hw->irq_callback)
1906 hw->irq_callback(hw->irq_callback_data, status);
1907
1908 hw_write_20kx(hw, GIP, status);
1909 return IRQ_HANDLED;
1910}
1911
1881static int hw_card_start(struct hw *hw) 1912static int hw_card_start(struct hw *hw)
1882{ 1913{
1883 int err = 0; 1914 int err = 0;
@@ -1914,12 +1945,13 @@ static int hw_card_start(struct hw *hw)
1914 hw->io_base = pci_resource_start(pci, 0); 1945 hw->io_base = pci_resource_start(pci, 0);
1915 } 1946 }
1916 1947
1917 /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED, 1948 err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED,
1918 atc->chip_details->nm_card, hw))) { 1949 "ctxfi", hw);
1950 if (err < 0) {
1951 printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq);
1919 goto error2; 1952 goto error2;
1920 } 1953 }
1921 hw->irq = pci->irq; 1954 hw->irq = pci->irq;
1922 */
1923 1955
1924 pci_set_master(pci); 1956 pci_set_master(pci);
1925 1957
@@ -1936,6 +1968,8 @@ error1:
1936static int hw_card_stop(struct hw *hw) 1968static int hw_card_stop(struct hw *hw)
1937{ 1969{
1938 /* TODO: Disable interrupt and so on... */ 1970 /* TODO: Disable interrupt and so on... */
1971 if (hw->irq >= 0)
1972 synchronize_irq(hw->irq);
1939 return 0; 1973 return 0;
1940} 1974}
1941 1975
@@ -2215,6 +2249,9 @@ int create_20k1_hw_obj(struct hw **rhw)
2215 hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr; 2249 hw->daio_mgr_set_imapaddr = daio_mgr_set_imapaddr;
2216 hw->daio_mgr_commit_write = daio_mgr_commit_write; 2250 hw->daio_mgr_commit_write = daio_mgr_commit_write;
2217 2251
2252 hw->set_timer_irq = set_timer_irq;
2253 hw->set_timer_tick = set_timer_tick;
2254
2218 *rhw = hw; 2255 *rhw = hw;
2219 2256
2220 return 0; 2257 return 0;
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c
index 52ddf19d83bb..32b742dcd538 100644
--- a/sound/pci/ctxfi/ctpcm.c
+++ b/sound/pci/ctxfi/ctpcm.c
@@ -16,6 +16,7 @@
16 */ 16 */
17 17
18#include "ctpcm.h" 18#include "ctpcm.h"
19#include "cttimer.h"
19#include <sound/pcm.h> 20#include <sound/pcm.h>
20 21
21/* Hardware descriptions for playback */ 22/* Hardware descriptions for playback */
@@ -108,6 +109,7 @@ static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
108 struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream); 109 struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
109 110
110 atc->pcm_release_resources(atc, apcm); 111 atc->pcm_release_resources(atc, apcm);
112 ct_timer_instance_free(apcm->timer);
111 kfree(apcm); 113 kfree(apcm);
112 runtime->private_data = NULL; 114 runtime->private_data = NULL;
113} 115}
@@ -124,8 +126,6 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
124 if (NULL == apcm) 126 if (NULL == apcm)
125 return -ENOMEM; 127 return -ENOMEM;
126 128
127 spin_lock_init(&apcm->timer_lock);
128 apcm->stop_timer = 0;
129 apcm->substream = substream; 129 apcm->substream = substream;
130 apcm->interrupt = ct_atc_pcm_interrupt; 130 apcm->interrupt = ct_atc_pcm_interrupt;
131 runtime->private_data = apcm; 131 runtime->private_data = apcm;
@@ -153,6 +153,10 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
153 return err; 153 return err;
154 } 154 }
155 155
156 apcm->timer = ct_timer_instance_new(atc->timer, apcm);
157 if (!apcm->timer)
158 return -ENOMEM;
159
156 return 0; 160 return 0;
157} 161}
158 162
@@ -182,89 +186,6 @@ static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
182 return snd_pcm_lib_free_pages(substream); 186 return snd_pcm_lib_free_pages(substream);
183} 187}
184 188
185static void ct_pcm_timer_callback(unsigned long data)
186{
187 struct ct_atc_pcm *apcm = (struct ct_atc_pcm *)data;
188 struct snd_pcm_substream *substream = apcm->substream;
189 struct snd_pcm_runtime *runtime = substream->runtime;
190 unsigned int period_size = runtime->period_size;
191 unsigned int buffer_size = runtime->buffer_size;
192 unsigned long flags;
193 unsigned int position = 0, dist = 0, interval = 0;
194
195 position = substream->ops->pointer(substream);
196 dist = (position + buffer_size - apcm->position) % buffer_size;
197 if ((dist >= period_size) ||
198 (position/period_size != apcm->position/period_size)) {
199 apcm->interrupt(apcm);
200 apcm->position = position;
201 }
202 /* Add extra HZ*5/1000 to avoid overrun issue when recording
203 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
204 interval = ((period_size - (position % period_size))
205 * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
206 spin_lock_irqsave(&apcm->timer_lock, flags);
207 apcm->timer.expires = jiffies + interval;
208 if (!apcm->stop_timer)
209 add_timer(&apcm->timer);
210
211 spin_unlock_irqrestore(&apcm->timer_lock, flags);
212}
213
214static int ct_pcm_timer_prepare(struct ct_atc_pcm *apcm)
215{
216 unsigned long flags;
217
218 spin_lock_irqsave(&apcm->timer_lock, flags);
219 if (timer_pending(&apcm->timer)) {
220 /* The timer has already been started. */
221 spin_unlock_irqrestore(&apcm->timer_lock, flags);
222 return 0;
223 }
224
225 init_timer(&apcm->timer);
226 apcm->timer.data = (unsigned long)apcm;
227 apcm->timer.function = ct_pcm_timer_callback;
228 spin_unlock_irqrestore(&apcm->timer_lock, flags);
229 apcm->position = 0;
230
231 return 0;
232}
233
234static int ct_pcm_timer_start(struct ct_atc_pcm *apcm)
235{
236 struct snd_pcm_runtime *runtime = apcm->substream->runtime;
237 unsigned long flags;
238
239 spin_lock_irqsave(&apcm->timer_lock, flags);
240 if (timer_pending(&apcm->timer)) {
241 /* The timer has already been started. */
242 spin_unlock_irqrestore(&apcm->timer_lock, flags);
243 return 0;
244 }
245
246 apcm->timer.expires = jiffies + (runtime->period_size * HZ +
247 (runtime->rate - 1)) / runtime->rate;
248 apcm->stop_timer = 0;
249 add_timer(&apcm->timer);
250 spin_unlock_irqrestore(&apcm->timer_lock, flags);
251
252 return 0;
253}
254
255static int ct_pcm_timer_stop(struct ct_atc_pcm *apcm)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&apcm->timer_lock, flags);
260 apcm->stop_timer = 1;
261 del_timer(&apcm->timer);
262 spin_unlock_irqrestore(&apcm->timer_lock, flags);
263
264 try_to_del_timer_sync(&apcm->timer);
265
266 return 0;
267}
268 189
269static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) 190static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
270{ 191{
@@ -283,8 +204,6 @@ static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
283 return err; 204 return err;
284 } 205 }
285 206
286 ct_pcm_timer_prepare(apcm);
287
288 return 0; 207 return 0;
289} 208}
290 209
@@ -300,12 +219,10 @@ ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
300 case SNDRV_PCM_TRIGGER_RESUME: 219 case SNDRV_PCM_TRIGGER_RESUME:
301 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 220 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
302 atc->pcm_playback_start(atc, apcm); 221 atc->pcm_playback_start(atc, apcm);
303 ct_pcm_timer_start(apcm);
304 break; 222 break;
305 case SNDRV_PCM_TRIGGER_STOP: 223 case SNDRV_PCM_TRIGGER_STOP:
306 case SNDRV_PCM_TRIGGER_SUSPEND: 224 case SNDRV_PCM_TRIGGER_SUSPEND:
307 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 225 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
308 ct_pcm_timer_stop(apcm);
309 atc->pcm_playback_stop(atc, apcm); 226 atc->pcm_playback_stop(atc, apcm);
310 break; 227 break;
311 default: 228 default:
@@ -341,9 +258,7 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
341 if (NULL == apcm) 258 if (NULL == apcm)
342 return -ENOMEM; 259 return -ENOMEM;
343 260
344 spin_lock_init(&apcm->timer_lock);
345 apcm->started = 0; 261 apcm->started = 0;
346 apcm->stop_timer = 0;
347 apcm->substream = substream; 262 apcm->substream = substream;
348 apcm->interrupt = ct_atc_pcm_interrupt; 263 apcm->interrupt = ct_atc_pcm_interrupt;
349 runtime->private_data = apcm; 264 runtime->private_data = apcm;
@@ -365,6 +280,10 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
365 return err; 280 return err;
366 } 281 }
367 282
283 apcm->timer = ct_timer_instance_new(atc->timer, apcm);
284 if (!apcm->timer)
285 return -ENOMEM;
286
368 return 0; 287 return 0;
369} 288}
370 289
@@ -388,8 +307,6 @@ static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
388 return err; 307 return err;
389 } 308 }
390 309
391 ct_pcm_timer_prepare(apcm);
392
393 return 0; 310 return 0;
394} 311}
395 312
@@ -403,14 +320,11 @@ ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
403 switch (cmd) { 320 switch (cmd) {
404 case SNDRV_PCM_TRIGGER_START: 321 case SNDRV_PCM_TRIGGER_START:
405 atc->pcm_capture_start(atc, apcm); 322 atc->pcm_capture_start(atc, apcm);
406 ct_pcm_timer_start(apcm);
407 break; 323 break;
408 case SNDRV_PCM_TRIGGER_STOP: 324 case SNDRV_PCM_TRIGGER_STOP:
409 ct_pcm_timer_stop(apcm);
410 atc->pcm_capture_stop(atc, apcm); 325 atc->pcm_capture_stop(atc, apcm);
411 break; 326 break;
412 default: 327 default:
413 ct_pcm_timer_stop(apcm);
414 atc->pcm_capture_stop(atc, apcm); 328 atc->pcm_capture_stop(atc, apcm);
415 break; 329 break;
416 } 330 }
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
new file mode 100644
index 000000000000..3acb26d0c4cc
--- /dev/null
+++ b/sound/pci/ctxfi/cttimer.c
@@ -0,0 +1,417 @@
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
16struct 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 */
27struct 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 */
42struct 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
59static 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
87static void ct_systimer_init(struct ct_timer_instance *ti)
88{
89 setup_timer(&ti->timer, ct_systimer_callback,
90 (unsigned long)ti);
91}
92
93static 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
106static 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
116static 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
124static 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
140static 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
151static 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 */
169static 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 */
208static 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 */
224static 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
242static 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 */
250static 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
269static 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
280static 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
292static void ct_xfitimer_free_global(struct ct_timer *atimer)
293{
294 ct_xfitimer_irq_stop(atimer);
295}
296
297static 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
309struct ct_timer_instance *
310ct_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
333void 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
341void ct_timer_start(struct ct_timer_instance *ti)
342{
343 struct ct_timer *atimer = ti->timer_base;
344 atimer->ops->start(ti);
345}
346
347void ct_timer_stop(struct ct_timer_instance *ti)
348{
349 struct ct_timer *atimer = ti->timer_base;
350 atimer->ops->stop(ti);
351}
352
353void 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
374static 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
383struct 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
409void 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
diff --git a/sound/pci/ctxfi/cttimer.h b/sound/pci/ctxfi/cttimer.h
new file mode 100644
index 000000000000..979348229291
--- /dev/null
+++ b/sound/pci/ctxfi/cttimer.h
@@ -0,0 +1,29 @@
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
12struct snd_pcm_substream;
13struct ct_atc;
14struct ct_atc_pcm;
15
16struct ct_timer;
17struct ct_timer_instance;
18
19struct ct_timer *ct_timer_new(struct ct_atc *atc);
20void ct_timer_free(struct ct_timer *atimer);
21
22struct ct_timer_instance *
23ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm);
24void ct_timer_instance_free(struct ct_timer_instance *ti);
25void ct_timer_start(struct ct_timer_instance *ti);
26void ct_timer_stop(struct ct_timer_instance *ti);
27void ct_timer_prepare(struct ct_timer_instance *ti);
28
29#endif /* __CTTIMER_H */