diff options
-rw-r--r-- | include/sound/rawmidi.h | 1 | ||||
-rw-r--r-- | sound/core/rawmidi.c | 377 |
2 files changed, 194 insertions, 184 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 60f33e9412ad..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) | ||
229 | { | 233 | { |
230 | struct snd_rawmidi *rmidi; | 234 | struct snd_rawmidi_substream *substream; |
231 | struct list_head *list1, *list2; | 235 | struct snd_rawmidi_str *s = &rmidi->streams[stream]; |
232 | struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; | 236 | static unsigned int info_flags[2] = { |
233 | struct snd_rawmidi_runtime *input = NULL, *output = NULL; | 237 | [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT, |
234 | int err; | 238 | [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT, |
239 | }; | ||
235 | 240 | ||
236 | if (rfile) | 241 | if (!(rmidi->info_flags & info_flags[stream])) |
237 | rfile->input = rfile->output = NULL; | ||
238 | mutex_lock(®ister_mutex); | ||
239 | rmidi = snd_rawmidi_search(card, device); | ||
240 | if (rmidi == NULL) { | ||
241 | mutex_unlock(®ister_mutex); | ||
242 | return -ENODEV; | ||
243 | } | ||
244 | if (!try_module_get(rmidi->card->module)) { | ||
245 | mutex_unlock(®ister_mutex); | ||
246 | return -ENXIO; | 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 | } | ||
247 | } | 258 | } |
248 | mutex_unlock(®ister_mutex); | 259 | return -EAGAIN; |
260 | } | ||
249 | 261 | ||
250 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | 262 | /* open and do ref-counting for the given substream */ |
251 | mutex_lock(&rmidi->open_mutex); | 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) | ||
290 | { | ||
291 | struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; | ||
292 | int err; | ||
293 | |||
294 | rfile->input = rfile->output = NULL; | ||
252 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | 295 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { |
253 | if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) { | 296 | err = assign_substream(rmidi, subdevice, |
254 | err = -ENXIO; | 297 | SNDRV_RAWMIDI_STREAM_INPUT, |
255 | goto __error; | 298 | mode, &sinput); |
256 | } | 299 | if (err < 0) |
257 | if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { | ||
258 | err = -ENODEV; | ||
259 | goto __error; | ||
260 | } | ||
261 | if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >= | ||
262 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) { | ||
263 | err = -EAGAIN; | ||
264 | goto __error; | 300 | goto __error; |
265 | } | ||
266 | } | 301 | } |
267 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | 302 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { |
268 | if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) { | 303 | err = assign_substream(rmidi, subdevice, |
269 | err = -ENXIO; | 304 | SNDRV_RAWMIDI_STREAM_OUTPUT, |
270 | goto __error; | 305 | mode, &soutput); |
271 | } | 306 | if (err < 0) |
272 | if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { | ||
273 | err = -ENODEV; | ||
274 | goto __error; | ||
275 | } | ||
276 | if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >= | ||
277 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) { | ||
278 | err = -EAGAIN; | ||
279 | goto __error; | 307 | goto __error; |
280 | } | ||
281 | } | ||
282 | list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next; | ||
283 | while (1) { | ||
284 | if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { | ||
285 | sinput = NULL; | ||
286 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | ||
287 | err = -EAGAIN; | ||
288 | goto __error; | ||
289 | } | ||
290 | break; | ||
291 | } | ||
292 | sinput = list_entry(list1, struct snd_rawmidi_substream, list); | ||
293 | if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened) | ||
294 | goto __nexti; | ||
295 | if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number)) | ||
296 | break; | ||
297 | __nexti: | ||
298 | list1 = list1->next; | ||
299 | } | ||
300 | list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next; | ||
301 | while (1) { | ||
302 | if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | ||
303 | soutput = NULL; | ||
304 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | ||
305 | err = -EAGAIN; | ||
306 | goto __error; | ||
307 | } | ||
308 | break; | ||
309 | } | ||
310 | soutput = list_entry(list2, struct snd_rawmidi_substream, list); | ||
311 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | ||
312 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) { | ||
313 | if (soutput->opened && !soutput->append) | ||
314 | goto __nexto; | ||
315 | } else { | ||
316 | if (soutput->opened) | ||
317 | goto __nexto; | ||
318 | } | ||
319 | } | ||
320 | if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number)) | ||
321 | break; | ||
322 | __nexto: | ||
323 | list2 = list2->next; | ||
324 | } | 308 | } |
325 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | 309 | |
326 | if ((err = snd_rawmidi_runtime_create(sinput)) < 0) | 310 | if (sinput) { |
327 | goto __error; | 311 | err = open_substream(rmidi, sinput, mode); |
328 | input = sinput->runtime; | 312 | if (err < 0) |
329 | if ((err = sinput->ops->open(sinput)) < 0) | ||
330 | goto __error; | 313 | goto __error; |
331 | sinput->opened = 1; | ||
332 | rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++; | ||
333 | } else { | ||
334 | sinput = NULL; | ||
335 | } | 314 | } |
336 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { | 315 | if (soutput) { |
337 | if (soutput->opened) | 316 | err = open_substream(rmidi, soutput, mode); |
338 | goto __skip_output; | 317 | if (err < 0) { |
339 | if ((err = snd_rawmidi_runtime_create(soutput)) < 0) { | 318 | if (sinput) |
340 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | 319 | close_substream(rmidi, sinput, 0); |
341 | sinput->ops->close(sinput); | ||
342 | goto __error; | ||
343 | } | ||
344 | output = soutput->runtime; | ||
345 | if ((err = soutput->ops->open(soutput)) < 0) { | ||
346 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | ||
347 | sinput->ops->close(sinput); | ||
348 | goto __error; | 320 | goto __error; |
349 | } | 321 | } |
350 | __skip_output: | ||
351 | soutput->opened = 1; | ||
352 | if (mode & SNDRV_RAWMIDI_LFLG_APPEND) | ||
353 | soutput->append = 1; | ||
354 | if (soutput->use_count++ == 0) | ||
355 | soutput->active_sensing = 1; | ||
356 | rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++; | ||
357 | } else { | ||
358 | soutput = NULL; | ||
359 | } | ||
360 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | ||
361 | mutex_unlock(&rmidi->open_mutex); | ||
362 | if (rfile) { | ||
363 | rfile->rmidi = rmidi; | ||
364 | rfile->input = sinput; | ||
365 | rfile->output = soutput; | ||
366 | } | 322 | } |
323 | |||
324 | rfile->rmidi = rmidi; | ||
325 | rfile->input = sinput; | ||
326 | rfile->output = soutput; | ||
367 | return 0; | 327 | return 0; |
368 | 328 | ||
369 | __error: | 329 | __error: |
370 | if (input != NULL) | 330 | if (sinput && sinput->runtime) |
371 | snd_rawmidi_runtime_free(sinput); | 331 | snd_rawmidi_runtime_free(sinput); |
372 | if (output != NULL) | 332 | if (soutput && soutput->runtime) |
373 | snd_rawmidi_runtime_free(soutput); | 333 | snd_rawmidi_runtime_free(soutput); |
374 | if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | 334 | return err; |
375 | mutex_unlock(&rmidi->open_mutex); | 335 | } |
376 | module_put(rmidi->card->module); | 336 | |
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) { | ||
462 | file->private_data = rawmidi_file; | ||
463 | } else { | ||
464 | snd_card_file_remove(card, file); | ||
465 | kfree(rawmidi_file); | ||
466 | } | ||
467 | mutex_unlock(&rmidi->open_mutex); | 456 | mutex_unlock(&rmidi->open_mutex); |
457 | return 0; | ||
458 | |||
459 | __error: | ||
460 | snd_card_file_remove(card, file); | ||
461 | __error_card: | ||
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, |