aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/drivers/pcsp/pcsp.h2
-rw-r--r--sound/drivers/pcsp/pcsp_lib.c87
2 files changed, 58 insertions, 31 deletions
diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h
index 70533a333b5b..cdef2664218f 100644
--- a/sound/drivers/pcsp/pcsp.h
+++ b/sound/drivers/pcsp/pcsp.h
@@ -62,6 +62,8 @@ struct snd_pcsp {
62 unsigned short port, irq, dma; 62 unsigned short port, irq, dma;
63 spinlock_t substream_lock; 63 spinlock_t substream_lock;
64 struct snd_pcm_substream *playback_substream; 64 struct snd_pcm_substream *playback_substream;
65 unsigned int fmt_size;
66 unsigned int is_signed;
65 size_t playback_ptr; 67 size_t playback_ptr;
66 size_t period_ptr; 68 size_t period_ptr;
67 atomic_t timer_active; 69 atomic_t timer_active;
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index f8d8470861da..84cc2658c05b 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -36,12 +36,13 @@ static void pcsp_call_pcm_elapsed(unsigned long priv)
36 36
37static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); 37static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0);
38 38
39enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) 39/* write the port and returns the next expire time in ns;
40 * called at the trigger-start and in hrtimer callback
41 */
42static unsigned long pcsp_timer_update(struct hrtimer *handle)
40{ 43{
41 unsigned char timer_cnt, val; 44 unsigned char timer_cnt, val;
42 int fmt_size, periods_elapsed;
43 u64 ns; 45 u64 ns;
44 size_t period_bytes, buffer_bytes;
45 struct snd_pcm_substream *substream; 46 struct snd_pcm_substream *substream;
46 struct snd_pcm_runtime *runtime; 47 struct snd_pcm_runtime *runtime;
47 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); 48 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
@@ -51,28 +52,25 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
51 outb(chip->val61, 0x61); 52 outb(chip->val61, 0x61);
52 chip->thalf = 0; 53 chip->thalf = 0;
53 if (!atomic_read(&chip->timer_active)) 54 if (!atomic_read(&chip->timer_active))
54 goto stop; 55 return 0;
55 hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer), 56 return chip->ns_rem;
56 ktime_set(0, chip->ns_rem));
57 return HRTIMER_RESTART;
58 } 57 }
59 58
60 if (!atomic_read(&chip->timer_active)) 59 if (!atomic_read(&chip->timer_active))
61 goto stop; 60 return 0;
62 substream = chip->playback_substream; 61 substream = chip->playback_substream;
63 if (!substream) 62 if (!substream)
64 goto stop; 63 return 0;
65 64
66 runtime = substream->runtime; 65 runtime = substream->runtime;
67 fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3;
68 /* assume it is mono! */ 66 /* assume it is mono! */
69 val = runtime->dma_area[chip->playback_ptr + fmt_size - 1]; 67 val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1];
70 if (snd_pcm_format_signed(runtime->format)) 68 if (chip->is_signed)
71 val ^= 0x80; 69 val ^= 0x80;
72 timer_cnt = val * CUR_DIV() / 256; 70 timer_cnt = val * CUR_DIV() / 256;
73 71
74 if (timer_cnt && chip->enable) { 72 if (timer_cnt && chip->enable) {
75 spin_lock(&i8253_lock); 73 spin_lock_irqsave(&i8253_lock, flags);
76 if (!nforce_wa) { 74 if (!nforce_wa) {
77 outb_p(chip->val61, 0x61); 75 outb_p(chip->val61, 0x61);
78 outb_p(timer_cnt, 0x42); 76 outb_p(timer_cnt, 0x42);
@@ -81,14 +79,39 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
81 outb(chip->val61 ^ 2, 0x61); 79 outb(chip->val61 ^ 2, 0x61);
82 chip->thalf = 1; 80 chip->thalf = 1;
83 } 81 }
84 spin_unlock(&i8253_lock); 82 spin_unlock_irqrestore(&i8253_lock, flags);
85 } 83 }
86 84
85 chip->ns_rem = PCSP_PERIOD_NS();
86 ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
87 chip->ns_rem -= ns;
88 return ns;
89}
90
91enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
92{
93 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
94 struct snd_pcm_substream *substream;
95 int periods_elapsed, pointer_update;
96 size_t period_bytes, buffer_bytes;
97 unsigned long ns;
98 unsigned long flags;
99
100 pointer_update = !chip->thalf;
101 ns = pcsp_timer_update(handle);
102 if (!ns)
103 return HRTIMER_NORESTART;
104
105 /* update the playback position */
106 substream = chip->playback_substream;
107 if (!substream)
108 return HRTIMER_NORESTART;
109
87 period_bytes = snd_pcm_lib_period_bytes(substream); 110 period_bytes = snd_pcm_lib_period_bytes(substream);
88 buffer_bytes = snd_pcm_lib_buffer_bytes(substream); 111 buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
89 112
90 spin_lock_irqsave(&chip->substream_lock, flags); 113 spin_lock_irqsave(&chip->substream_lock, flags);
91 chip->playback_ptr += PCSP_INDEX_INC() * fmt_size; 114 chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size;
92 periods_elapsed = chip->playback_ptr - chip->period_ptr; 115 periods_elapsed = chip->playback_ptr - chip->period_ptr;
93 if (periods_elapsed < 0) { 116 if (periods_elapsed < 0) {
94#if PCSP_DEBUG 117#if PCSP_DEBUG
@@ -106,32 +129,27 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
106 if (periods_elapsed) { 129 if (periods_elapsed) {
107 chip->period_ptr += periods_elapsed * period_bytes; 130 chip->period_ptr += periods_elapsed * period_bytes;
108 chip->period_ptr %= buffer_bytes; 131 chip->period_ptr %= buffer_bytes;
109 tasklet_schedule(&pcsp_pcm_tasklet);
110 } 132 }
111 spin_unlock_irqrestore(&chip->substream_lock, flags); 133 spin_unlock_irqrestore(&chip->substream_lock, flags);
112 134
113 if (!atomic_read(&chip->timer_active)) 135 if (periods_elapsed)
114 goto stop; 136 tasklet_schedule(&pcsp_pcm_tasklet);
115 137
116 chip->ns_rem = PCSP_PERIOD_NS(); 138 hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns));
117 ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
118 chip->ns_rem -= ns;
119 hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer),
120 ktime_set(0, ns));
121 return HRTIMER_RESTART;
122 139
123 stop: 140 return HRTIMER_RESTART;
124 return HRTIMER_NORESTART;
125} 141}
126 142
127static void pcsp_start_playing(struct snd_pcsp *chip) 143static int pcsp_start_playing(struct snd_pcsp *chip)
128{ 144{
145 unsigned long ns;
146
129#if PCSP_DEBUG 147#if PCSP_DEBUG
130 printk(KERN_INFO "PCSP: start_playing called\n"); 148 printk(KERN_INFO "PCSP: start_playing called\n");
131#endif 149#endif
132 if (atomic_read(&chip->timer_active)) { 150 if (atomic_read(&chip->timer_active)) {
133 printk(KERN_ERR "PCSP: Timer already active\n"); 151 printk(KERN_ERR "PCSP: Timer already active\n");
134 return; 152 return -EIO;
135 } 153 }
136 154
137 spin_lock(&i8253_lock); 155 spin_lock(&i8253_lock);
@@ -141,7 +159,12 @@ static void pcsp_start_playing(struct snd_pcsp *chip)
141 atomic_set(&chip->timer_active, 1); 159 atomic_set(&chip->timer_active, 1);
142 chip->thalf = 0; 160 chip->thalf = 0;
143 161
144 hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL); 162 ns = pcsp_timer_update(&pcsp_chip.timer);
163 if (!ns)
164 return -EIO;
165
166 hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL);
167 return 0;
145} 168}
146 169
147static void pcsp_stop_playing(struct snd_pcsp *chip) 170static void pcsp_stop_playing(struct snd_pcsp *chip)
@@ -221,6 +244,9 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
221 pcsp_sync_stop(chip); 244 pcsp_sync_stop(chip);
222 chip->playback_ptr = 0; 245 chip->playback_ptr = 0;
223 chip->period_ptr = 0; 246 chip->period_ptr = 0;
247 chip->fmt_size =
248 snd_pcm_format_physical_width(substream->runtime->format) >> 3;
249 chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
224 return 0; 250 return 0;
225} 251}
226 252
@@ -233,8 +259,7 @@ static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd)
233 switch (cmd) { 259 switch (cmd) {
234 case SNDRV_PCM_TRIGGER_START: 260 case SNDRV_PCM_TRIGGER_START:
235 case SNDRV_PCM_TRIGGER_RESUME: 261 case SNDRV_PCM_TRIGGER_RESUME:
236 pcsp_start_playing(chip); 262 return pcsp_start_playing(chip);
237 break;
238 case SNDRV_PCM_TRIGGER_STOP: 263 case SNDRV_PCM_TRIGGER_STOP:
239 case SNDRV_PCM_TRIGGER_SUSPEND: 264 case SNDRV_PCM_TRIGGER_SUSPEND:
240 pcsp_stop_playing(chip); 265 pcsp_stop_playing(chip);