1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * PC-Speaker driver for Linux
4 *
5 * Copyright (C) 1993-1997 Michael Beck
6 * Copyright (C) 1997-2001 David Woodhouse
7 * Copyright (C) 2001-2008 Stas Sergeev
8 */
9
10 #include <linux/module.h>
11 #include <linux/gfp.h>
12 #include <linux/moduleparam.h>
13 #include <linux/interrupt.h>
14 #include <linux/io.h>
15 #include <sound/core.h>
16 #include <sound/pcm.h>
17 #include "pcsp.h"
18
19 static bool nforce_wa;
20 module_param(nforce_wa, bool, 0444);
21 MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
22 "(expect bad sound)");
23
24 #define DMIX_WANTS_S16 1
25
26 /*
27 * Call snd_pcm_period_elapsed in a work
28 * This avoids spinlock messes and long-running irq contexts
29 */
pcsp_call_pcm_elapsed(struct work_struct * work)30 static void pcsp_call_pcm_elapsed(struct work_struct *work)
31 {
32 if (atomic_read(&pcsp_chip.timer_active)) {
33 struct snd_pcm_substream *substream;
34 substream = pcsp_chip.playback_substream;
35 if (substream)
36 snd_pcm_period_elapsed(substream);
37 }
38 }
39
40 static DECLARE_WORK(pcsp_pcm_work, pcsp_call_pcm_elapsed);
41
42 /* write the port and returns the next expire time in ns;
43 * called at the trigger-start and in hrtimer callback
44 */
pcsp_timer_update(struct snd_pcsp * chip)45 static u64 pcsp_timer_update(struct snd_pcsp *chip)
46 {
47 unsigned char timer_cnt, val;
48 u64 ns;
49 struct snd_pcm_substream *substream;
50 struct snd_pcm_runtime *runtime;
51 unsigned long flags;
52
53 if (chip->thalf) {
54 outb(chip->val61, 0x61);
55 chip->thalf = 0;
56 return chip->ns_rem;
57 }
58
59 substream = chip->playback_substream;
60 if (!substream)
61 return 0;
62
63 runtime = substream->runtime;
64 /* assume it is mono! */
65 val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1];
66 if (chip->is_signed)
67 val ^= 0x80;
68 timer_cnt = val * CUR_DIV() / 256;
69
70 if (timer_cnt && chip->enable) {
71 raw_spin_lock_irqsave(&i8253_lock, flags);
72 if (!nforce_wa) {
73 outb_p(chip->val61, 0x61);
74 outb_p(timer_cnt, 0x42);
75 outb(chip->val61 ^ 1, 0x61);
76 } else {
77 outb(chip->val61 ^ 2, 0x61);
78 chip->thalf = 1;
79 }
80 raw_spin_unlock_irqrestore(&i8253_lock, flags);
81 }
82
83 chip->ns_rem = PCSP_PERIOD_NS();
84 ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
85 chip->ns_rem -= ns;
86 return ns;
87 }
88
pcsp_pointer_update(struct snd_pcsp * chip)89 static void pcsp_pointer_update(struct snd_pcsp *chip)
90 {
91 struct snd_pcm_substream *substream;
92 size_t period_bytes, buffer_bytes;
93 int periods_elapsed;
94 unsigned long flags;
95
96 /* update the playback position */
97 substream = chip->playback_substream;
98 if (!substream)
99 return;
100
101 period_bytes = snd_pcm_lib_period_bytes(substream);
102 buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
103
104 spin_lock_irqsave(&chip->substream_lock, flags);
105 chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size;
106 periods_elapsed = chip->playback_ptr - chip->period_ptr;
107 if (periods_elapsed < 0) {
108 #if PCSP_DEBUG
109 dev_dbg(chip->card->dev,
110 "PCSP: buffer_bytes mod period_bytes != 0 ? (%zi %zi %zi)\n",
111 chip->playback_ptr, period_bytes, buffer_bytes);
112 #endif
113 periods_elapsed += buffer_bytes;
114 }
115 periods_elapsed /= period_bytes;
116 /* wrap the pointer _before_ calling snd_pcm_period_elapsed(),
117 * or ALSA will BUG on us. */
118 chip->playback_ptr %= buffer_bytes;
119
120 if (periods_elapsed) {
121 chip->period_ptr += periods_elapsed * period_bytes;
122 chip->period_ptr %= buffer_bytes;
123 queue_work(system_highpri_wq, &pcsp_pcm_work);
124 }
125 spin_unlock_irqrestore(&chip->substream_lock, flags);
126 }
127
pcsp_do_timer(struct hrtimer * handle)128 enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
129 {
130 struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
131 int pointer_update;
132 u64 ns;
133
134 if (!atomic_read(&chip->timer_active) || !chip->playback_substream)
135 return HRTIMER_NORESTART;
136
137 pointer_update = !chip->thalf;
138 ns = pcsp_timer_update(chip);
139 if (!ns) {
140 dev_warn(chip->card->dev, "PCSP: unexpected stop\n");
141 return HRTIMER_NORESTART;
142 }
143
144 if (pointer_update)
145 pcsp_pointer_update(chip);
146
147 hrtimer_forward_now(handle, ns_to_ktime(ns));
148
149 return HRTIMER_RESTART;
150 }
151
pcsp_start_playing(struct snd_pcsp * chip)152 static int pcsp_start_playing(struct snd_pcsp *chip)
153 {
154 #if PCSP_DEBUG
155 dev_dbg(chip->card->dev, "PCSP: start_playing called\n");
156 #endif
157 if (atomic_read(&chip->timer_active)) {
158 dev_err(chip->card->dev, "PCSP: Timer already active\n");
159 return -EIO;
160 }
161
162 raw_spin_lock(&i8253_lock);
163 chip->val61 = inb(0x61) | 0x03;
164 outb_p(0x92, 0x43); /* binary, mode 1, LSB only, ch 2 */
165 raw_spin_unlock(&i8253_lock);
166 atomic_set(&chip->timer_active, 1);
167 chip->thalf = 0;
168
169 hrtimer_start(&pcsp_chip.timer, 0, HRTIMER_MODE_REL);
170 return 0;
171 }
172
pcsp_stop_playing(struct snd_pcsp * chip)173 static void pcsp_stop_playing(struct snd_pcsp *chip)
174 {
175 #if PCSP_DEBUG
176 dev_dbg(chip->card->dev, "PCSP: stop_playing called\n");
177 #endif
178 if (!atomic_read(&chip->timer_active))
179 return;
180
181 atomic_set(&chip->timer_active, 0);
182 raw_spin_lock(&i8253_lock);
183 /* restore the timer */
184 outb_p(0xb6, 0x43); /* binary, mode 3, LSB/MSB, ch 2 */
185 outb(chip->val61 & 0xFC, 0x61);
186 raw_spin_unlock(&i8253_lock);
187 }
188
189 /*
190 * Force to stop and sync the stream
191 */
pcsp_sync_stop(struct snd_pcsp * chip)192 void pcsp_sync_stop(struct snd_pcsp *chip)
193 {
194 local_irq_disable();
195 pcsp_stop_playing(chip);
196 local_irq_enable();
197 hrtimer_cancel(&chip->timer);
198 cancel_work_sync(&pcsp_pcm_work);
199 }
200
snd_pcsp_playback_close(struct snd_pcm_substream * substream)201 static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
202 {
203 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
204 #if PCSP_DEBUG
205 dev_dbg(chip->card->dev, "PCSP: close called\n");
206 #endif
207 pcsp_sync_stop(chip);
208 chip->playback_substream = NULL;
209 return 0;
210 }
211
snd_pcsp_playback_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)212 static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
213 struct snd_pcm_hw_params *hw_params)
214 {
215 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
216 pcsp_sync_stop(chip);
217 return 0;
218 }
219
snd_pcsp_playback_hw_free(struct snd_pcm_substream * substream)220 static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
221 {
222 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
223 #if PCSP_DEBUG
224 dev_dbg(chip->card->dev, "PCSP: hw_free called\n");
225 #endif
226 pcsp_sync_stop(chip);
227 return 0;
228 }
229
snd_pcsp_playback_prepare(struct snd_pcm_substream * substream)230 static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
231 {
232 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
233 pcsp_sync_stop(chip);
234 chip->playback_ptr = 0;
235 chip->period_ptr = 0;
236 chip->fmt_size =
237 snd_pcm_format_physical_width(substream->runtime->format) >> 3;
238 chip->is_signed = snd_pcm_format_signed(substream->runtime->format);
239 #if PCSP_DEBUG
240 dev_dbg(chip->card->dev, "PCSP: prepare called, size=%zi psize=%zi f=%zi f1=%i fsize=%i\n",
241 snd_pcm_lib_buffer_bytes(substream),
242 snd_pcm_lib_period_bytes(substream),
243 snd_pcm_lib_buffer_bytes(substream) /
244 snd_pcm_lib_period_bytes(substream),
245 substream->runtime->periods,
246 chip->fmt_size);
247 #endif
248 return 0;
249 }
250
snd_pcsp_trigger(struct snd_pcm_substream * substream,int cmd)251 static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd)
252 {
253 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
254 #if PCSP_DEBUG
255 dev_dbg(chip->card->dev, "PCSP: trigger called\n");
256 #endif
257 switch (cmd) {
258 case SNDRV_PCM_TRIGGER_START:
259 case SNDRV_PCM_TRIGGER_RESUME:
260 return pcsp_start_playing(chip);
261 case SNDRV_PCM_TRIGGER_STOP:
262 case SNDRV_PCM_TRIGGER_SUSPEND:
263 pcsp_stop_playing(chip);
264 break;
265 default:
266 return -EINVAL;
267 }
268 return 0;
269 }
270
snd_pcsp_playback_pointer(struct snd_pcm_substream * substream)271 static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream
272 *substream)
273 {
274 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
275 unsigned int pos;
276 spin_lock(&chip->substream_lock);
277 pos = chip->playback_ptr;
278 spin_unlock(&chip->substream_lock);
279 return bytes_to_frames(substream->runtime, pos);
280 }
281
282 static const struct snd_pcm_hardware snd_pcsp_playback = {
283 .info = (SNDRV_PCM_INFO_INTERLEAVED |
284 SNDRV_PCM_INFO_HALF_DUPLEX |
285 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
286 .formats = (SNDRV_PCM_FMTBIT_U8
287 #if DMIX_WANTS_S16
288 | SNDRV_PCM_FMTBIT_S16_LE
289 #endif
290 ),
291 .rates = SNDRV_PCM_RATE_KNOT,
292 .rate_min = PCSP_DEFAULT_SRATE,
293 .rate_max = PCSP_DEFAULT_SRATE,
294 .channels_min = 1,
295 .channels_max = 1,
296 .buffer_bytes_max = PCSP_BUFFER_SIZE,
297 .period_bytes_min = 64,
298 .period_bytes_max = PCSP_MAX_PERIOD_SIZE,
299 .periods_min = 2,
300 .periods_max = PCSP_MAX_PERIODS,
301 .fifo_size = 0,
302 };
303
snd_pcsp_playback_open(struct snd_pcm_substream * substream)304 static int snd_pcsp_playback_open(struct snd_pcm_substream *substream)
305 {
306 struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
307 struct snd_pcm_runtime *runtime = substream->runtime;
308 #if PCSP_DEBUG
309 dev_dbg(chip->card->dev, "PCSP: open called\n");
310 #endif
311 if (atomic_read(&chip->timer_active)) {
312 dev_err(chip->card->dev, "PCSP: still active!!\n");
313 return -EBUSY;
314 }
315 runtime->hw = snd_pcsp_playback;
316 chip->playback_substream = substream;
317 return 0;
318 }
319
320 static const struct snd_pcm_ops snd_pcsp_playback_ops = {
321 .open = snd_pcsp_playback_open,
322 .close = snd_pcsp_playback_close,
323 .hw_params = snd_pcsp_playback_hw_params,
324 .hw_free = snd_pcsp_playback_hw_free,
325 .prepare = snd_pcsp_playback_prepare,
326 .trigger = snd_pcsp_trigger,
327 .pointer = snd_pcsp_playback_pointer,
328 };
329
snd_pcsp_new_pcm(struct snd_pcsp * chip)330 int snd_pcsp_new_pcm(struct snd_pcsp *chip)
331 {
332 int err;
333
334 err = snd_pcm_new(chip->card, "pcspeaker", 0, 1, 0, &chip->pcm);
335 if (err < 0)
336 return err;
337
338 snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_PLAYBACK,
339 &snd_pcsp_playback_ops);
340
341 chip->pcm->private_data = chip;
342 chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
343 strcpy(chip->pcm->name, "pcsp");
344
345 snd_pcm_set_managed_buffer_all(chip->pcm,
346 SNDRV_DMA_TYPE_CONTINUOUS,
347 NULL,
348 PCSP_BUFFER_SIZE,
349 PCSP_BUFFER_SIZE);
350
351 return 0;
352 }
353