Lines Matching +full:pcm +full:- +full:sync +full:- +full:mode

1 // SPDX-License-Identifier: GPL-2.0
3 * PC-Speaker driver for Linux
5 * Copyright (C) 1993-1997 Michael Beck
6 * Copyright (C) 1997-2001 David Woodhouse
7 * Copyright (C) 2001-2008 Stas Sergeev
16 #include <sound/pcm.h>
28 * This avoids spinlock messes and long-running irq contexts
43 * called at the trigger-start and in hrtimer callback
53 if (chip->thalf) { in pcsp_timer_update()
54 outb(chip->val61, 0x61); in pcsp_timer_update()
55 chip->thalf = 0; in pcsp_timer_update()
56 return chip->ns_rem; in pcsp_timer_update()
59 substream = chip->playback_substream; in pcsp_timer_update()
63 runtime = substream->runtime; in pcsp_timer_update()
65 val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1]; in pcsp_timer_update()
66 if (chip->is_signed) in pcsp_timer_update()
70 if (timer_cnt && chip->enable) { in pcsp_timer_update()
73 outb_p(chip->val61, 0x61); in pcsp_timer_update()
75 outb(chip->val61 ^ 1, 0x61); in pcsp_timer_update()
77 outb(chip->val61 ^ 2, 0x61); in pcsp_timer_update()
78 chip->thalf = 1; in pcsp_timer_update()
83 chip->ns_rem = PCSP_PERIOD_NS(); in pcsp_timer_update()
84 ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); in pcsp_timer_update()
85 chip->ns_rem -= ns; in pcsp_timer_update()
97 substream = chip->playback_substream; in pcsp_pointer_update()
104 spin_lock_irqsave(&chip->substream_lock, flags); in pcsp_pointer_update()
105 chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size; in pcsp_pointer_update()
106 periods_elapsed = chip->playback_ptr - chip->period_ptr; in pcsp_pointer_update()
109 dev_dbg(chip->card->dev, in pcsp_pointer_update()
111 chip->playback_ptr, period_bytes, buffer_bytes); in pcsp_pointer_update()
118 chip->playback_ptr %= buffer_bytes; in pcsp_pointer_update()
121 chip->period_ptr += periods_elapsed * period_bytes; in pcsp_pointer_update()
122 chip->period_ptr %= buffer_bytes; in pcsp_pointer_update()
125 spin_unlock_irqrestore(&chip->substream_lock, flags); in pcsp_pointer_update()
134 if (!atomic_read(&chip->timer_active) || !chip->playback_substream) in pcsp_do_timer()
137 pointer_update = !chip->thalf; in pcsp_do_timer()
140 dev_warn(chip->card->dev, "PCSP: unexpected stop\n"); in pcsp_do_timer()
155 dev_dbg(chip->card->dev, "PCSP: start_playing called\n"); in pcsp_start_playing()
157 if (atomic_read(&chip->timer_active)) { in pcsp_start_playing()
158 dev_err(chip->card->dev, "PCSP: Timer already active\n"); in pcsp_start_playing()
159 return -EIO; in pcsp_start_playing()
163 chip->val61 = inb(0x61) | 0x03; in pcsp_start_playing()
164 outb_p(0x92, 0x43); /* binary, mode 1, LSB only, ch 2 */ in pcsp_start_playing()
166 atomic_set(&chip->timer_active, 1); in pcsp_start_playing()
167 chip->thalf = 0; in pcsp_start_playing()
176 dev_dbg(chip->card->dev, "PCSP: stop_playing called\n"); in pcsp_stop_playing()
178 if (!atomic_read(&chip->timer_active)) in pcsp_stop_playing()
181 atomic_set(&chip->timer_active, 0); in pcsp_stop_playing()
184 outb_p(0xb6, 0x43); /* binary, mode 3, LSB/MSB, ch 2 */ in pcsp_stop_playing()
185 outb(chip->val61 & 0xFC, 0x61); in pcsp_stop_playing()
190 * Force to stop and sync the stream
197 hrtimer_cancel(&chip->timer); in pcsp_sync_stop()
205 dev_dbg(chip->card->dev, "PCSP: close called\n"); in snd_pcsp_playback_close()
208 chip->playback_substream = NULL; in snd_pcsp_playback_close()
224 dev_dbg(chip->card->dev, "PCSP: hw_free called\n"); in snd_pcsp_playback_hw_free()
234 chip->playback_ptr = 0; in snd_pcsp_playback_prepare()
235 chip->period_ptr = 0; in snd_pcsp_playback_prepare()
236 chip->fmt_size = in snd_pcsp_playback_prepare()
237 snd_pcm_format_physical_width(substream->runtime->format) >> 3; in snd_pcsp_playback_prepare()
238 chip->is_signed = snd_pcm_format_signed(substream->runtime->format); in snd_pcsp_playback_prepare()
240 dev_dbg(chip->card->dev, "PCSP: prepare called, size=%zi psize=%zi f=%zi f1=%i fsize=%i\n", in snd_pcsp_playback_prepare()
245 substream->runtime->periods, in snd_pcsp_playback_prepare()
246 chip->fmt_size); in snd_pcsp_playback_prepare()
255 dev_dbg(chip->card->dev, "PCSP: trigger called\n"); in snd_pcsp_trigger()
266 return -EINVAL; in snd_pcsp_trigger()
276 spin_lock(&chip->substream_lock); in snd_pcsp_playback_pointer()
277 pos = chip->playback_ptr; in snd_pcsp_playback_pointer()
278 spin_unlock(&chip->substream_lock); in snd_pcsp_playback_pointer()
279 return bytes_to_frames(substream->runtime, pos); in snd_pcsp_playback_pointer()
307 struct snd_pcm_runtime *runtime = substream->runtime; in snd_pcsp_playback_open()
309 dev_dbg(chip->card->dev, "PCSP: open called\n"); in snd_pcsp_playback_open()
311 if (atomic_read(&chip->timer_active)) { in snd_pcsp_playback_open()
312 dev_err(chip->card->dev, "PCSP: still active!!\n"); in snd_pcsp_playback_open()
313 return -EBUSY; in snd_pcsp_playback_open()
315 runtime->hw = snd_pcsp_playback; in snd_pcsp_playback_open()
316 chip->playback_substream = substream; in snd_pcsp_playback_open()
334 err = snd_pcm_new(chip->card, "pcspeaker", 0, 1, 0, &chip->pcm); in snd_pcsp_new_pcm()
338 snd_pcm_set_ops(chip->pcm, SNDRV_PCM_STREAM_PLAYBACK, in snd_pcsp_new_pcm()
341 chip->pcm->private_data = chip; in snd_pcsp_new_pcm()
342 chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; in snd_pcsp_new_pcm()
343 strcpy(chip->pcm->name, "pcsp"); in snd_pcsp_new_pcm()
345 snd_pcm_set_managed_buffer_all(chip->pcm, in snd_pcsp_new_pcm()