* [PATCH] m68k: dmasound: Keep the Q40 IRQ handler registered
@ 2026-09-29 8:54 Runyu Xiao
2026-09-29 15:09 ` Takashi Iwai
0 siblings, 1 reply; 2+ messages in thread
From: Runyu Xiao @ 2026-09-29 8:54 UTC (permalink / raw)
To: Jaroslav Kysela
Cc: Takashi Iwai, linux-sound, linux-kernel, Runyu Xiao, Jianhao Xu, stable
Q40PlayNextFrame() re-registers the sample IRQ after stopping it. This
function can be called with dmasound.lock held and from the sample IRQ
handler, so free_irq() and request_irq() can sleep or deadlock. A failed
re-registration can also leave playback without an IRQ.
Register one handler for the lifetime of the driver and select mono or
stereo sample handling inside that handler. Call the frame completion
path after releasing dmasound.lock so it can refill the queue safely.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
sound/oss/dmasound/dmasound_q40.c | 65 ++++++++++++++-----------------
1 file changed, 29 insertions(+), 36 deletions(-)
diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
index e25a78dd1..339311e5d 100644
--- a/sound/oss/dmasound/dmasound_q40.c
+++ b/sound/oss/dmasound/dmasound_q40.c
@@ -49,9 +49,8 @@ static int Q40SetFormat(int format);
static int Q40SetVolume(int volume);
static void Q40PlayNextFrame(int index);
static void Q40Play(void);
-static irqreturn_t Q40StereoInterrupt(int irq, void *dummy);
-static irqreturn_t Q40MonoInterrupt(int irq, void *dummy);
-static void Q40Interrupt(void);
+static irqreturn_t q40_audio_interrupt(int irq, void *dummy);
+static void q40_frame_done(void);
/*** Mid level stuff *********************************************************/
@@ -372,8 +371,8 @@ static void Q40Free(void *ptr, unsigned int size)
static int __init Q40IrqInit(void)
{
/* Register interrupt handler. */
- if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
- "DMA sound", Q40Interrupt))
+ if (request_irq(Q40_IRQ_SAMPLE, q40_audio_interrupt, 0,
+ "DMA sound", q40_frame_done))
return 0;
return(1);
@@ -384,7 +383,7 @@ static int __init Q40IrqInit(void)
static void Q40IrqCleanUp(void)
{
master_outb(0,SAMPLE_ENABLE_REG);
- free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+ free_irq(Q40_IRQ_SAMPLE, q40_frame_done);
}
#endif /* MODULE */
@@ -403,7 +402,6 @@ static void Q40PlayNextFrame(int index)
u_char *start;
u_long size;
u_char speed;
- int error;
/* used by Q40Play() if all doubts whether there really is something
* to be played are already wiped out.
@@ -420,15 +418,6 @@ static void Q40PlayNextFrame(int index)
speed=(dmasound.hard.speed==10000 ? 0 : 1);
master_outb( 0,SAMPLE_ENABLE_REG);
- free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
- if (dmasound.soft.stereo)
- error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
- "Q40 sound", Q40Interrupt);
- else
- error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
- "Q40 sound", Q40Interrupt);
- if (error && printk_ratelimit())
- pr_err("Couldn't register sound interrupt\n");
master_outb( speed, SAMPLE_RATE_REG);
master_outb( 1,SAMPLE_CLEAR_REG);
@@ -456,31 +445,35 @@ static void Q40Play(void)
spin_unlock_irqrestore(&dmasound.lock, flags);
}
-static irqreturn_t Q40StereoInterrupt(int irq, void *dummy)
-{
- spin_lock(&dmasound.lock);
- if (q40_sc>1){
- *DAC_LEFT=*q40_pp++;
- *DAC_RIGHT=*q40_pp++;
- q40_sc -=2;
- master_outb(1,SAMPLE_CLEAR_REG);
- }else Q40Interrupt();
- spin_unlock(&dmasound.lock);
- return IRQ_HANDLED;
-}
-static irqreturn_t Q40MonoInterrupt(int irq, void *dummy)
+static irqreturn_t q40_audio_interrupt(int irq, void *dummy)
{
+ bool frame_done = false;
+
spin_lock(&dmasound.lock);
- if (q40_sc>0){
- *DAC_LEFT=*q40_pp;
- *DAC_RIGHT=*q40_pp++;
- q40_sc --;
- master_outb(1,SAMPLE_CLEAR_REG);
- }else Q40Interrupt();
+ if (dmasound.hard.stereo) {
+ if (q40_sc > 1) {
+ *DAC_LEFT = *q40_pp++;
+ *DAC_RIGHT = *q40_pp++;
+ q40_sc -= 2;
+ master_outb(1, SAMPLE_CLEAR_REG);
+ } else {
+ frame_done = true;
+ }
+ } else if (q40_sc > 0) {
+ *DAC_LEFT = *q40_pp;
+ *DAC_RIGHT = *q40_pp++;
+ q40_sc--;
+ master_outb(1, SAMPLE_CLEAR_REG);
+ } else {
+ frame_done = true;
+ }
spin_unlock(&dmasound.lock);
+ if (frame_done)
+ q40_frame_done();
return IRQ_HANDLED;
}
-static void Q40Interrupt(void)
+
+static void q40_frame_done(void)
{
if (!write_sq.active) {
/* playing was interrupted and sq_reset() has already cleared
--
2.34.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] m68k: dmasound: Keep the Q40 IRQ handler registered
2026-09-29 8:54 [PATCH] m68k: dmasound: Keep the Q40 IRQ handler registered Runyu Xiao
@ 2026-09-29 15:09 ` Takashi Iwai
0 siblings, 0 replies; 2+ messages in thread
From: Takashi Iwai @ 2026-09-29 15:09 UTC (permalink / raw)
To: Runyu Xiao
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel,
Jianhao Xu, stable
On Tue, 29 Sep 2026 10:54:00 +0200,
Runyu Xiao wrote:
>
> Q40PlayNextFrame() re-registers the sample IRQ after stopping it. This
> function can be called with dmasound.lock held and from the sample IRQ
> handler, so free_irq() and request_irq() can sleep or deadlock. A failed
> re-registration can also leave playback without an IRQ.
>
> Register one handler for the lifetime of the driver and select mono or
> stereo sample handling inside that handler. Call the frame completion
> path after releasing dmasound.lock so it can refill the queue safely.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Applied to for-next branch. Thanks.
Takashi
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-29 15:09 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-29 8:54 [PATCH] m68k: dmasound: Keep the Q40 IRQ handler registered Runyu Xiao
2026-09-29 15:09 ` Takashi Iwai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®