From: Jon Masters This fixes a hang in mpu401_uart.c that can occur when the mpu401 interface is non-existent or otherwise doesn't respond to commands but we issue IO anyway. snd_mpu401_uart_cmd now returns an error code that is passed up the stack so that an open() will fail immediately in such cases. Eventually discovered after wine/cxoffice would constantly cause hard lockups on my desktop immediately after loading (emulating Windows too well). Turned out that I'd recently moved my sound cards around and using /dev/sequencer now talks to a sound card with a broken MPU. Signed-off-by: Jon Masters Cc: Jaroslav Kysela Cc: Takashi Iwai Signed-off-by: Andrew Morton --- sound/drivers/mpu401/mpu401_uart.c | 34 +++++++++++++++++++-------- 1 files changed, 25 insertions(+), 9 deletions(-) diff -puN sound/drivers/mpu401/mpu401_uart.c~sound-fix-hang-in-mpu401_uartc sound/drivers/mpu401/mpu401_uart.c --- devel/sound/drivers/mpu401/mpu401_uart.c~sound-fix-hang-in-mpu401_uartc 2006-04-16 18:17:12.000000000 -0700 +++ devel-akpm/sound/drivers/mpu401/mpu401_uart.c 2006-04-16 18:18:15.000000000 -0700 @@ -183,7 +183,7 @@ static void snd_mpu401_uart_remove_timer */ -static void snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, int ack) +static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, int ack) { unsigned long flags; int timeout, ok; @@ -218,9 +218,12 @@ static void snd_mpu401_uart_cmd(struct s ok = 1; } spin_unlock_irqrestore(&mpu->input_lock, flags); - if (! ok) + if (ok) + return 0; + else { snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); - // snd_printk("cmd: 0x%x at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); + return 1; + } } /* @@ -235,8 +238,12 @@ static int snd_mpu401_uart_input_open(st if (mpu->open_input && (err = mpu->open_input(mpu)) < 0) return err; if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) { - snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1); - snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); + if ((err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1))) { + return -EFAULT; + } + if ((err = snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1))) { + return -EFAULT; + } } mpu->substream_input = substream; set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); @@ -252,8 +259,10 @@ static int snd_mpu401_uart_output_open(s if (mpu->open_output && (err = mpu->open_output(mpu)) < 0) return err; if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { - snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1); - snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); + if ((err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1))) + return -EFAULT; + if ((err = snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1))) + return -EFAULT; } mpu->substream_output = substream; set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); @@ -263,28 +272,34 @@ static int snd_mpu401_uart_output_open(s static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream) { struct snd_mpu401 *mpu; + int err = 0; mpu = substream->rmidi->private_data; clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); mpu->substream_input = NULL; if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) - snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); + err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); if (mpu->close_input) mpu->close_input(mpu); + if (err) + return -EFAULT; return 0; } static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) { struct snd_mpu401 *mpu; + int err = 0; mpu = substream->rmidi->private_data; clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); mpu->substream_output = NULL; if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) - snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); + err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); if (mpu->close_output) mpu->close_output(mpu); + if (err) + return -EFAULT; return 0; } @@ -316,6 +331,7 @@ static void snd_mpu401_uart_input_trigge snd_mpu401_uart_remove_timer(mpu, 1); clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); } + } /* _