diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-03-23 19:35:46 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-03-23 19:35:46 -0400 |
commit | c944a93df0d566a66409628c4524f4fc4f62eaf5 (patch) | |
tree | 64bd4f7f750344f5031172721f43778a0e95b768 | |
parent | 65b3864b85485a91f70988e1a222e3935bce87e4 (diff) | |
parent | 9a1b64caac82aa02cb74587ffc798e6f42c6170a (diff) |
Merge branch 'topic/rawmidi-fix' into for-linus
-rw-r--r-- | include/sound/rawmidi.h | 1 | ||||
-rw-r--r-- | sound/core/rawmidi.c | 379 |
2 files changed, 195 insertions, 185 deletions
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index b550a416d075..c23c26585700 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h | |||
@@ -42,7 +42,6 @@ | |||
42 | #define SNDRV_RAWMIDI_LFLG_INPUT (1<<1) | 42 | #define SNDRV_RAWMIDI_LFLG_INPUT (1<<1) |
43 | #define SNDRV_RAWMIDI_LFLG_OPEN (3<<0) | 43 | #define SNDRV_RAWMIDI_LFLG_OPEN (3<<0) |
44 | #define SNDRV_RAWMIDI_LFLG_APPEND (1<<2) | 44 | #define SNDRV_RAWMIDI_LFLG_APPEND (1<<2) |
45 | #define SNDRV_RAWMIDI_LFLG_NOOPENLOCK (1<<3) | ||
46 | 45 | ||
47 | struct snd_rawmidi; | 46 | struct snd_rawmidi; |
48 | struct snd_rawmidi_substream; | 47 | struct snd_rawmidi_substream; |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 002777ba336a..473247c8e6d3 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -224,156 +224,143 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) | |||
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, | 227 | /* look for an available substream for the given stream direction; |
228 | int mode, struct snd_rawmidi_file * rfile) | 228 | * if a specific subdevice is given, try to assign it |
229 | */ | ||
230 | static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, | ||
231 | int stream, int mode, | ||
232 | struct snd_rawmidi_substream **sub_ret) | ||
233 | { | ||
234 | struct snd_rawmidi_substream *substream; | ||
235 | struct snd_rawmidi_str *s = &rmidi->streams[stream]; | ||
236 | static unsigned int info_flags[2] = { | ||
237 | [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT, | ||
238 | [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT, | ||
239 | }; | ||
240 | |||
241 | if (!(rmidi->info_flags & info_flags[stream])) | ||
242 | return -ENXIO; | ||
243 | if (subdevice >= 0 && subdevice >= s->substream_count) | ||
244 | return -ENODEV; | ||
245 | if (s->substream_opened >= s->substream_count) | ||
246 | return -EAGAIN; | ||
247 | |||
248 | list_for_each_entry(substream, &s->substreams, list) { | ||
249 | if (substream->opened) { | ||
250 | if (stream == SNDRV_RAWMIDI_STREAM_INPUT || | ||
251 | !(mode & SNDRV_RAWMIDI_LFLG_APPEND)) | ||
252 | continue; | ||
253 | } | ||
254 | if (subdevice < 0 || subdevice == substream->number) { | ||
255 | *sub_ret = substream; | ||
256 | return 0; | ||
257 | } | ||
258 | } | ||
259 | return -EAGAIN; | ||
260 | } | ||
261 | |||
262 | /* open and do ref-counting for the given substream */ | ||
263 | static int open_substream(struct snd_rawmidi *rmidi, | ||
264 | struct snd_rawmidi_substream *substream, | ||
265 | int mode) | ||
266 | { | ||
267 | int err; | ||
268 | |||
269 | err = snd_rawmidi_runtime_create(substream); | ||
270 | if (err < 0) | ||
271 | return err; | ||
272 | err = substream->ops->open(substream); | ||
273 | if (err < 0) | ||
274 | return err; | ||
275 | substream->opened = 1; | ||
276 | if (substream->use_count++ == 0) | ||
277 | substream->active_sensing = 1; | ||
278 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) | ||
279 | substream->append = 1; | ||
280 | rmidi->streams[substream->stream].substream_opened++; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static void close_substream(struct snd_rawmidi *rmidi, | ||
285 | struct snd_rawmidi_substream *substream, | ||
286 | int cleanup); | ||
287 | |||
288 | static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, | ||
289 | struct snd_rawmidi_file *rfile) | ||
229 | { | 290 | { |
230 | struct snd_rawmidi *rmidi; | ||
231 | struct list_head *list1, *list2; | ||
232 | struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; | 291 | struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; |
233 | struct snd_rawmidi_runtime *input = NULL, *output = NULL; | ||
234 | int err; | 292 | int err; |
235 | 293 | ||
236 | if (rfile) | 294 | rfile->input = rfile->output = NULL; |
237 | rfile->input = rfile->output = NULL; | ||
238 | mutex_lock(®ister_mutex); | ||
239 | rmidi = snd_rawmidi_search(card, device); | ||
240 | mutex_unlock(®ister_mutex); | ||
241 | if (rmidi == NULL) { | ||
242 | err = -ENODEV; | ||
243 | goto __error1; | ||
244 | } | ||
245 | if (!try_module_get(rmidi->card->module)) { | ||
246 | err = -EFAULT; | ||
247 | goto __error1; | ||
248 | } | ||
249 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | ||
250 | mutex_lock(&rmidi->open_mutex); | ||
251 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | 295 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { |
252 | if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) { | 296 | err = assign_substream(rmidi, subdevice, |
253 | err = -ENXIO; | 297 | SNDRV_RAWMIDI_STREAM_INPUT, |
254 | goto __error; | 298 | mode, &sinput); |
255 | } | 299 | if (err < 0) |
256 | if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { | ||
257 | err = -ENODEV; | ||
258 | goto __error; | ||
259 | } | ||
260 | if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >= | ||
261 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { | ||
262 | err = -EAGAIN; | ||
263 | goto __error; | 300 | goto __error; |
264 | } | ||
265 | } | 301 | } |
266 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | 302 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { |
267 | if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) { | 303 | err = assign_substream(rmidi, subdevice, |
268 | err = -ENXIO; | 304 | SNDRV_RAWMIDI_STREAM_OUTPUT, |
269 | goto __error; | 305 | mode, &soutput); |
270 | } | 306 | if (err < 0) |
271 | if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { | ||
272 | err = -ENODEV; | ||
273 | goto __error; | ||
274 | } | ||
275 | if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >= | ||
276 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { | ||
277 | err = -EAGAIN; | ||
278 | goto __error; | 307 | goto __error; |
279 | } | ||
280 | } | ||
281 | list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next; | ||
282 | while (1) { | ||
283 | if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { | ||
284 | sinput = NULL; | ||
285 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | ||
286 | err = -EAGAIN; | ||
287 | goto __error; | ||
288 | } | ||
289 | break; | ||
290 | } | ||
291 | sinput = list_entry(list1, struct snd_rawmidi_substream, list); | ||
292 | if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened) | ||
293 | goto __nexti; | ||
294 | if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number)) | ||
295 | break; | ||
296 | __nexti: | ||
297 | list1 = list1->next; | ||
298 | } | 308 | } |
299 | list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next; | 309 | |
300 | while (1) { | 310 | if (sinput) { |
301 | if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | 311 | err = open_substream(rmidi, sinput, mode); |
302 | soutput = NULL; | 312 | if (err < 0) |
303 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | ||
304 | err = -EAGAIN; | ||
305 | goto __error; | ||
306 | } | ||
307 | break; | ||
308 | } | ||
309 | soutput = list_entry(list2, struct snd_rawmidi_substream, list); | ||
310 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | ||
311 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) { | ||
312 | if (soutput->opened && !soutput->append) | ||
313 | goto __nexto; | ||
314 | } else { | ||
315 | if (soutput->opened) | ||
316 | goto __nexto; | ||
317 | } | ||
318 | } | ||
319 | if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number)) | ||
320 | break; | ||
321 | __nexto: | ||
322 | list2 = list2->next; | ||
323 | } | ||
324 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | ||
325 | if ((err = snd_rawmidi_runtime_create(sinput)) < 0) | ||
326 | goto __error; | ||
327 | input = sinput->runtime; | ||
328 | if ((err = sinput->ops->open(sinput)) < 0) | ||
329 | goto __error; | 313 | goto __error; |
330 | sinput->opened = 1; | ||
331 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++; | ||
332 | } else { | ||
333 | sinput = NULL; | ||
334 | } | 314 | } |
335 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | 315 | if (soutput) { |
336 | if (soutput->opened) | 316 | err = open_substream(rmidi, soutput, mode); |
337 | goto __skip_output; | 317 | if (err < 0) { |
338 | if ((err = snd_rawmidi_runtime_create(soutput)) < 0) { | 318 | if (sinput) |
339 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | 319 | close_substream(rmidi, sinput, 0); |
340 | sinput->ops->close(sinput); | ||
341 | goto __error; | ||
342 | } | ||
343 | output = soutput->runtime; | ||
344 | if ((err = soutput->ops->open(soutput)) < 0) { | ||
345 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | ||
346 | sinput->ops->close(sinput); | ||
347 | goto __error; | 320 | goto __error; |
348 | } | 321 | } |
349 | __skip_output: | ||
350 | soutput->opened = 1; | ||
351 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) | ||
352 | soutput->append = 1; | ||
353 | if (soutput->use_count++ == 0) | ||
354 | soutput->active_sensing = 1; | ||
355 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++; | ||
356 | } else { | ||
357 | soutput = NULL; | ||
358 | } | ||
359 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | ||
360 | mutex_unlock(&rmidi->open_mutex); | ||
361 | if (rfile) { | ||
362 | rfile->rmidi = rmidi; | ||
363 | rfile->input = sinput; | ||
364 | rfile->output = soutput; | ||
365 | } | 322 | } |
323 | |||
324 | rfile->rmidi = rmidi; | ||
325 | rfile->input = sinput; | ||
326 | rfile->output = soutput; | ||
366 | return 0; | 327 | return 0; |
367 | 328 | ||
368 | __error: | 329 | __error: |
369 | if (input != NULL) | 330 | if (sinput && sinput->runtime) |
370 | snd_rawmidi_runtime_free(sinput); | 331 | snd_rawmidi_runtime_free(sinput); |
371 | if (output != NULL) | 332 | if (soutput && soutput->runtime) |
372 | snd_rawmidi_runtime_free(soutput); | 333 | snd_rawmidi_runtime_free(soutput); |
373 | module_put(rmidi->card->module); | 334 | return err; |
374 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | 335 | } |
375 | mutex_unlock(&rmidi->open_mutex); | 336 | |
376 | __error1: | 337 | /* called from sound/core/seq/seq_midi.c */ |
338 | int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, | ||
339 | int mode, struct snd_rawmidi_file * rfile) | ||
340 | { | ||
341 | struct snd_rawmidi *rmidi; | ||
342 | int err; | ||
343 | |||
344 | if (snd_BUG_ON(!rfile)) | ||
345 | return -EINVAL; | ||
346 | |||
347 | mutex_lock(®ister_mutex); | ||
348 | rmidi = snd_rawmidi_search(card, device); | ||
349 | if (rmidi == NULL) { | ||
350 | mutex_unlock(®ister_mutex); | ||
351 | return -ENODEV; | ||
352 | } | ||
353 | if (!try_module_get(rmidi->card->module)) { | ||
354 | mutex_unlock(®ister_mutex); | ||
355 | return -ENXIO; | ||
356 | } | ||
357 | mutex_unlock(®ister_mutex); | ||
358 | |||
359 | mutex_lock(&rmidi->open_mutex); | ||
360 | err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); | ||
361 | mutex_unlock(&rmidi->open_mutex); | ||
362 | if (err < 0) | ||
363 | module_put(rmidi->card->module); | ||
377 | return err; | 364 | return err; |
378 | } | 365 | } |
379 | 366 | ||
@@ -385,10 +372,13 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
385 | unsigned short fflags; | 372 | unsigned short fflags; |
386 | int err; | 373 | int err; |
387 | struct snd_rawmidi *rmidi; | 374 | struct snd_rawmidi *rmidi; |
388 | struct snd_rawmidi_file *rawmidi_file; | 375 | struct snd_rawmidi_file *rawmidi_file = NULL; |
389 | wait_queue_t wait; | 376 | wait_queue_t wait; |
390 | struct snd_ctl_file *kctl; | 377 | struct snd_ctl_file *kctl; |
391 | 378 | ||
379 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) | ||
380 | return -EINVAL; /* invalid combination */ | ||
381 | |||
392 | if (maj == snd_major) { | 382 | if (maj == snd_major) { |
393 | rmidi = snd_lookup_minor_data(iminor(inode), | 383 | rmidi = snd_lookup_minor_data(iminor(inode), |
394 | SNDRV_DEVICE_TYPE_RAWMIDI); | 384 | SNDRV_DEVICE_TYPE_RAWMIDI); |
@@ -402,24 +392,25 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
402 | 392 | ||
403 | if (rmidi == NULL) | 393 | if (rmidi == NULL) |
404 | return -ENODEV; | 394 | return -ENODEV; |
405 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) | 395 | |
406 | return -EINVAL; /* invalid combination */ | 396 | if (!try_module_get(rmidi->card->module)) |
397 | return -ENXIO; | ||
398 | |||
399 | mutex_lock(&rmidi->open_mutex); | ||
407 | card = rmidi->card; | 400 | card = rmidi->card; |
408 | err = snd_card_file_add(card, file); | 401 | err = snd_card_file_add(card, file); |
409 | if (err < 0) | 402 | if (err < 0) |
410 | return -ENODEV; | 403 | goto __error_card; |
411 | fflags = snd_rawmidi_file_flags(file); | 404 | fflags = snd_rawmidi_file_flags(file); |
412 | if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ | 405 | if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ |
413 | fflags |= SNDRV_RAWMIDI_LFLG_APPEND; | 406 | fflags |= SNDRV_RAWMIDI_LFLG_APPEND; |
414 | fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK; | ||
415 | rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); | 407 | rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); |
416 | if (rawmidi_file == NULL) { | 408 | if (rawmidi_file == NULL) { |
417 | snd_card_file_remove(card, file); | 409 | err = -ENOMEM; |
418 | return -ENOMEM; | 410 | goto __error; |
419 | } | 411 | } |
420 | init_waitqueue_entry(&wait, current); | 412 | init_waitqueue_entry(&wait, current); |
421 | add_wait_queue(&rmidi->open_wait, &wait); | 413 | add_wait_queue(&rmidi->open_wait, &wait); |
422 | mutex_lock(&rmidi->open_mutex); | ||
423 | while (1) { | 414 | while (1) { |
424 | subdevice = -1; | 415 | subdevice = -1; |
425 | read_lock(&card->ctl_files_rwlock); | 416 | read_lock(&card->ctl_files_rwlock); |
@@ -431,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
431 | } | 422 | } |
432 | } | 423 | } |
433 | read_unlock(&card->ctl_files_rwlock); | 424 | read_unlock(&card->ctl_files_rwlock); |
434 | err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device, | 425 | err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); |
435 | subdevice, fflags, rawmidi_file); | ||
436 | if (err >= 0) | 426 | if (err >= 0) |
437 | break; | 427 | break; |
438 | if (err == -EAGAIN) { | 428 | if (err == -EAGAIN) { |
@@ -451,67 +441,89 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
451 | break; | 441 | break; |
452 | } | 442 | } |
453 | } | 443 | } |
444 | remove_wait_queue(&rmidi->open_wait, &wait); | ||
445 | if (err < 0) { | ||
446 | kfree(rawmidi_file); | ||
447 | goto __error; | ||
448 | } | ||
454 | #ifdef CONFIG_SND_OSSEMUL | 449 | #ifdef CONFIG_SND_OSSEMUL |
455 | if (rawmidi_file->input && rawmidi_file->input->runtime) | 450 | if (rawmidi_file->input && rawmidi_file->input->runtime) |
456 | rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR); | 451 | rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR); |
457 | if (rawmidi_file->output && rawmidi_file->output->runtime) | 452 | if (rawmidi_file->output && rawmidi_file->output->runtime) |
458 | rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR); | 453 | rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR); |
459 | #endif | 454 | #endif |
460 | remove_wait_queue(&rmidi->open_wait, &wait); | 455 | file->private_data = rawmidi_file; |
461 | if (err >= 0) { | 456 | mutex_unlock(&rmidi->open_mutex); |
462 | file->private_data = rawmidi_file; | 457 | return 0; |
463 | } else { | 458 | |
464 | snd_card_file_remove(card, file); | 459 | __error: |
465 | kfree(rawmidi_file); | 460 | snd_card_file_remove(card, file); |
466 | } | 461 | __error_card: |
467 | mutex_unlock(&rmidi->open_mutex); | 462 | mutex_unlock(&rmidi->open_mutex); |
463 | module_put(rmidi->card->module); | ||
468 | return err; | 464 | return err; |
469 | } | 465 | } |
470 | 466 | ||
471 | int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile) | 467 | static void close_substream(struct snd_rawmidi *rmidi, |
468 | struct snd_rawmidi_substream *substream, | ||
469 | int cleanup) | ||
472 | { | 470 | { |
473 | struct snd_rawmidi *rmidi; | 471 | rmidi->streams[substream->stream].substream_opened--; |
474 | struct snd_rawmidi_substream *substream; | 472 | if (--substream->use_count) |
475 | struct snd_rawmidi_runtime *runtime; | 473 | return; |
476 | 474 | ||
477 | if (snd_BUG_ON(!rfile)) | 475 | if (cleanup) { |
478 | return -ENXIO; | 476 | if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) |
479 | rmidi = rfile->rmidi; | 477 | snd_rawmidi_input_trigger(substream, 0); |
480 | mutex_lock(&rmidi->open_mutex); | 478 | else { |
481 | if (rfile->input != NULL) { | ||
482 | substream = rfile->input; | ||
483 | rfile->input = NULL; | ||
484 | runtime = substream->runtime; | ||
485 | snd_rawmidi_input_trigger(substream, 0); | ||
486 | substream->ops->close(substream); | ||
487 | if (runtime->private_free != NULL) | ||
488 | runtime->private_free(substream); | ||
489 | snd_rawmidi_runtime_free(substream); | ||
490 | substream->opened = 0; | ||
491 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--; | ||
492 | } | ||
493 | if (rfile->output != NULL) { | ||
494 | substream = rfile->output; | ||
495 | rfile->output = NULL; | ||
496 | if (--substream->use_count == 0) { | ||
497 | runtime = substream->runtime; | ||
498 | if (substream->active_sensing) { | 479 | if (substream->active_sensing) { |
499 | unsigned char buf = 0xfe; | 480 | unsigned char buf = 0xfe; |
500 | /* sending single active sensing message to shut the device up */ | 481 | /* sending single active sensing message |
482 | * to shut the device up | ||
483 | */ | ||
501 | snd_rawmidi_kernel_write(substream, &buf, 1); | 484 | snd_rawmidi_kernel_write(substream, &buf, 1); |
502 | } | 485 | } |
503 | if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) | 486 | if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) |
504 | snd_rawmidi_output_trigger(substream, 0); | 487 | snd_rawmidi_output_trigger(substream, 0); |
505 | substream->ops->close(substream); | ||
506 | if (runtime->private_free != NULL) | ||
507 | runtime->private_free(substream); | ||
508 | snd_rawmidi_runtime_free(substream); | ||
509 | substream->opened = 0; | ||
510 | substream->append = 0; | ||
511 | } | 488 | } |
512 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--; | ||
513 | } | 489 | } |
490 | substream->ops->close(substream); | ||
491 | if (substream->runtime->private_free) | ||
492 | substream->runtime->private_free(substream); | ||
493 | snd_rawmidi_runtime_free(substream); | ||
494 | substream->opened = 0; | ||
495 | substream->append = 0; | ||
496 | } | ||
497 | |||
498 | static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) | ||
499 | { | ||
500 | struct snd_rawmidi *rmidi; | ||
501 | |||
502 | rmidi = rfile->rmidi; | ||
503 | mutex_lock(&rmidi->open_mutex); | ||
504 | if (rfile->input) { | ||
505 | close_substream(rmidi, rfile->input, 1); | ||
506 | rfile->input = NULL; | ||
507 | } | ||
508 | if (rfile->output) { | ||
509 | close_substream(rmidi, rfile->output, 1); | ||
510 | rfile->output = NULL; | ||
511 | } | ||
512 | rfile->rmidi = NULL; | ||
514 | mutex_unlock(&rmidi->open_mutex); | 513 | mutex_unlock(&rmidi->open_mutex); |
514 | wake_up(&rmidi->open_wait); | ||
515 | } | ||
516 | |||
517 | /* called from sound/core/seq/seq_midi.c */ | ||
518 | int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) | ||
519 | { | ||
520 | struct snd_rawmidi *rmidi; | ||
521 | |||
522 | if (snd_BUG_ON(!rfile)) | ||
523 | return -ENXIO; | ||
524 | |||
525 | rmidi = rfile->rmidi; | ||
526 | rawmidi_release_priv(rfile); | ||
515 | module_put(rmidi->card->module); | 527 | module_put(rmidi->card->module); |
516 | return 0; | 528 | return 0; |
517 | } | 529 | } |
@@ -520,15 +532,14 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file) | |||
520 | { | 532 | { |
521 | struct snd_rawmidi_file *rfile; | 533 | struct snd_rawmidi_file *rfile; |
522 | struct snd_rawmidi *rmidi; | 534 | struct snd_rawmidi *rmidi; |
523 | int err; | ||
524 | 535 | ||
525 | rfile = file->private_data; | 536 | rfile = file->private_data; |
526 | err = snd_rawmidi_kernel_release(rfile); | ||
527 | rmidi = rfile->rmidi; | 537 | rmidi = rfile->rmidi; |
528 | wake_up(&rmidi->open_wait); | 538 | rawmidi_release_priv(rfile); |
529 | kfree(rfile); | 539 | kfree(rfile); |
530 | snd_card_file_remove(rmidi->card, file); | 540 | snd_card_file_remove(rmidi->card, file); |
531 | return err; | 541 | module_put(rmidi->card->module); |
542 | return 0; | ||
532 | } | 543 | } |
533 | 544 | ||
534 | static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, | 545 | static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, |