diff options
author | Jon Masters <jcm@jonmasters.org> | 2006-04-20 05:43:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-20 10:54:04 -0400 |
commit | 962f831f67301265dcd2cd96408d07d95d556aed (patch) | |
tree | 3034e297898c922479b7ad0c4d964d9fb173a50e /sound | |
parent | c79cfbaccac0ef81ab3e796da1582a83dcef0ff9 (diff) |
[PATCH] sound: fix hang in mpu401_uart.c
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.
This second version changes -EFAULT to -EIO and frees open resources on
error too. Test booted and seems to work ok.
Signed-off-by: Jon Masters <jcm@jonmasters.org>
Cc: Jaroslav Kysela <perex@suse.cz>
Acked-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/drivers/mpu401/mpu401_uart.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 8687ae3c66b8..b49a45cbf67a 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c | |||
@@ -183,7 +183,8 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) | |||
183 | 183 | ||
184 | */ | 184 | */ |
185 | 185 | ||
186 | static void snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, int ack) | 186 | static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, |
187 | int ack) | ||
187 | { | 188 | { |
188 | unsigned long flags; | 189 | unsigned long flags; |
189 | int timeout, ok; | 190 | int timeout, ok; |
@@ -218,9 +219,11 @@ static void snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, int | |||
218 | ok = 1; | 219 | ok = 1; |
219 | } | 220 | } |
220 | spin_unlock_irqrestore(&mpu->input_lock, flags); | 221 | spin_unlock_irqrestore(&mpu->input_lock, flags); |
221 | if (! ok) | 222 | if (!ok) { |
222 | 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))); | 223 | 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))); |
223 | // 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))); | 224 | return 1; |
225 | } | ||
226 | return 0; | ||
224 | } | 227 | } |
225 | 228 | ||
226 | /* | 229 | /* |
@@ -235,12 +238,19 @@ static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream) | |||
235 | if (mpu->open_input && (err = mpu->open_input(mpu)) < 0) | 238 | if (mpu->open_input && (err = mpu->open_input(mpu)) < 0) |
236 | return err; | 239 | return err; |
237 | if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) { | 240 | if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) { |
238 | snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1); | 241 | if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1)) |
239 | snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); | 242 | goto error_out; |
243 | if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1)) | ||
244 | goto error_out; | ||
240 | } | 245 | } |
241 | mpu->substream_input = substream; | 246 | mpu->substream_input = substream; |
242 | set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); | 247 | set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); |
243 | return 0; | 248 | return 0; |
249 | |||
250 | error_out: | ||
251 | if (mpu->open_input && mpu->close_input) | ||
252 | mpu->close_input(mpu); | ||
253 | return -EIO; | ||
244 | } | 254 | } |
245 | 255 | ||
246 | static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream) | 256 | static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream) |
@@ -252,39 +262,52 @@ static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream) | |||
252 | if (mpu->open_output && (err = mpu->open_output(mpu)) < 0) | 262 | if (mpu->open_output && (err = mpu->open_output(mpu)) < 0) |
253 | return err; | 263 | return err; |
254 | if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { | 264 | if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { |
255 | snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1); | 265 | if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1)) |
256 | snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); | 266 | goto error_out; |
267 | if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1)) | ||
268 | goto error_out; | ||
257 | } | 269 | } |
258 | mpu->substream_output = substream; | 270 | mpu->substream_output = substream; |
259 | set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); | 271 | set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); |
260 | return 0; | 272 | return 0; |
273 | |||
274 | error_out: | ||
275 | if (mpu->open_output && mpu->close_output) | ||
276 | mpu->close_output(mpu); | ||
277 | return -EIO; | ||
261 | } | 278 | } |
262 | 279 | ||
263 | static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream) | 280 | static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream) |
264 | { | 281 | { |
265 | struct snd_mpu401 *mpu; | 282 | struct snd_mpu401 *mpu; |
283 | int err = 0; | ||
266 | 284 | ||
267 | mpu = substream->rmidi->private_data; | 285 | mpu = substream->rmidi->private_data; |
268 | clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); | 286 | clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); |
269 | mpu->substream_input = NULL; | 287 | mpu->substream_input = NULL; |
270 | if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) | 288 | if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) |
271 | snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); | 289 | err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); |
272 | if (mpu->close_input) | 290 | if (mpu->close_input) |
273 | mpu->close_input(mpu); | 291 | mpu->close_input(mpu); |
292 | if (err) | ||
293 | return -EIO; | ||
274 | return 0; | 294 | return 0; |
275 | } | 295 | } |
276 | 296 | ||
277 | static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) | 297 | static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) |
278 | { | 298 | { |
279 | struct snd_mpu401 *mpu; | 299 | struct snd_mpu401 *mpu; |
300 | int err = 0; | ||
280 | 301 | ||
281 | mpu = substream->rmidi->private_data; | 302 | mpu = substream->rmidi->private_data; |
282 | clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); | 303 | clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); |
283 | mpu->substream_output = NULL; | 304 | mpu->substream_output = NULL; |
284 | if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) | 305 | if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) |
285 | snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); | 306 | err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0); |
286 | if (mpu->close_output) | 307 | if (mpu->close_output) |
287 | mpu->close_output(mpu); | 308 | mpu->close_output(mpu); |
309 | if (err) | ||
310 | return -EIO; | ||
288 | return 0; | 311 | return 0; |
289 | } | 312 | } |
290 | 313 | ||
@@ -316,6 +339,7 @@ static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substrea | |||
316 | snd_mpu401_uart_remove_timer(mpu, 1); | 339 | snd_mpu401_uart_remove_timer(mpu, 1); |
317 | clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); | 340 | clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); |
318 | } | 341 | } |
342 | |||
319 | } | 343 | } |
320 | 344 | ||
321 | /* | 345 | /* |