Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a
1 parent
f9d202833d
Exists in
master
and in
7 other branches
ALSA: rawmidi - Refactor rawmidi open/close codes
Refactor rawmidi open/close code messes. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 2 changed files with 194 additions and 184 deletions Side-by-side Diff
include/sound/rawmidi.h
sound/core/rawmidi.c
... | ... | @@ -224,159 +224,146 @@ |
224 | 224 | return 0; |
225 | 225 | } |
226 | 226 | |
227 | -int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, | |
228 | - int mode, struct snd_rawmidi_file * rfile) | |
227 | +/* look for an available substream for the given stream direction; | |
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; | |
231 | - struct list_head *list1, *list2; | |
232 | - struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; | |
233 | - struct snd_rawmidi_runtime *input = NULL, *output = NULL; | |
234 | - int err; | |
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 | + }; | |
235 | 240 | |
236 | - if (rfile) | |
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); | |
241 | + if (!(rmidi->info_flags & info_flags[stream])) | |
242 | + return -ENXIO; | |
243 | + if (subdevice >= 0 && subdevice >= s->substream_count) | |
242 | 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 | + } | |
243 | 258 | } |
244 | - if (!try_module_get(rmidi->card->module)) { | |
245 | - mutex_unlock(®ister_mutex); | |
246 | - return -ENXIO; | |
247 | - } | |
248 | - mutex_unlock(®ister_mutex); | |
259 | + return -EAGAIN; | |
260 | +} | |
249 | 261 | |
250 | - if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | |
251 | - mutex_lock(&rmidi->open_mutex); | |
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) | |
290 | +{ | |
291 | + struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL; | |
292 | + int err; | |
293 | + | |
294 | + rfile->input = rfile->output = NULL; | |
252 | 295 | if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { |
253 | - if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) { | |
254 | - err = -ENXIO; | |
296 | + err = assign_substream(rmidi, subdevice, | |
297 | + SNDRV_RAWMIDI_STREAM_INPUT, | |
298 | + mode, &sinput); | |
299 | + if (err < 0) | |
255 | 300 | goto __error; |
256 | - } | |
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; | |
265 | - } | |
266 | 301 | } |
267 | 302 | if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { |
268 | - if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) { | |
269 | - err = -ENXIO; | |
303 | + err = assign_substream(rmidi, subdevice, | |
304 | + SNDRV_RAWMIDI_STREAM_OUTPUT, | |
305 | + mode, &soutput); | |
306 | + if (err < 0) | |
270 | 307 | goto __error; |
271 | - } | |
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; | |
280 | - } | |
281 | 308 | } |
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 | - } | |
325 | - if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { | |
326 | - if ((err = snd_rawmidi_runtime_create(sinput)) < 0) | |
309 | + | |
310 | + if (sinput) { | |
311 | + err = open_substream(rmidi, sinput, mode); | |
312 | + if (err < 0) | |
327 | 313 | goto __error; |
328 | - input = sinput->runtime; | |
329 | - if ((err = sinput->ops->open(sinput)) < 0) | |
330 | - 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) { | |
337 | - if (soutput->opened) | |
338 | - goto __skip_output; | |
339 | - if ((err = snd_rawmidi_runtime_create(soutput)) < 0) { | |
340 | - if (mode & SNDRV_RAWMIDI_LFLG_INPUT) | |
341 | - sinput->ops->close(sinput); | |
315 | + if (soutput) { | |
316 | + err = open_substream(rmidi, soutput, mode); | |
317 | + if (err < 0) { | |
318 | + if (sinput) | |
319 | + close_substream(rmidi, sinput, 0); | |
342 | 320 | goto __error; |
343 | 321 | } |
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; | |
349 | - } | |
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 | 322 | } |
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 | - } | |
323 | + | |
324 | + rfile->rmidi = rmidi; | |
325 | + rfile->input = sinput; | |
326 | + rfile->output = soutput; | |
367 | 327 | return 0; |
368 | 328 | |
369 | 329 | __error: |
370 | - if (input != NULL) | |
330 | + if (sinput && sinput->runtime) | |
371 | 331 | snd_rawmidi_runtime_free(sinput); |
372 | - if (output != NULL) | |
332 | + if (soutput && soutput->runtime) | |
373 | 333 | snd_rawmidi_runtime_free(soutput); |
374 | - if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK)) | |
375 | - mutex_unlock(&rmidi->open_mutex); | |
376 | - module_put(rmidi->card->module); | |
377 | 334 | return err; |
378 | 335 | } |
379 | 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); | |
364 | + return err; | |
365 | +} | |
366 | + | |
380 | 367 | static int snd_rawmidi_open(struct inode *inode, struct file *file) |
381 | 368 | { |
382 | 369 | int maj = imajor(inode); |
383 | 370 | |
... | ... | @@ -385,10 +372,13 @@ |
385 | 372 | unsigned short fflags; |
386 | 373 | int err; |
387 | 374 | struct snd_rawmidi *rmidi; |
388 | - struct snd_rawmidi_file *rawmidi_file; | |
375 | + struct snd_rawmidi_file *rawmidi_file = NULL; | |
389 | 376 | wait_queue_t wait; |
390 | 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 | 382 | if (maj == snd_major) { |
393 | 383 | rmidi = snd_lookup_minor_data(iminor(inode), |
394 | 384 | SNDRV_DEVICE_TYPE_RAWMIDI); |
395 | 385 | |
396 | 386 | |
397 | 387 | |
398 | 388 | |
... | ... | @@ -402,24 +392,25 @@ |
402 | 392 | |
403 | 393 | if (rmidi == NULL) |
404 | 394 | return -ENODEV; |
405 | - if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) | |
406 | - return -EINVAL; /* invalid combination */ | |
395 | + | |
396 | + if (!try_module_get(rmidi->card->module)) | |
397 | + return -ENXIO; | |
398 | + | |
399 | + mutex_lock(&rmidi->open_mutex); | |
407 | 400 | card = rmidi->card; |
408 | 401 | err = snd_card_file_add(card, file); |
409 | 402 | if (err < 0) |
410 | - return -ENODEV; | |
403 | + goto __error_card; | |
411 | 404 | fflags = snd_rawmidi_file_flags(file); |
412 | 405 | if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ |
413 | 406 | fflags |= SNDRV_RAWMIDI_LFLG_APPEND; |
414 | - fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK; | |
415 | 407 | rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); |
416 | 408 | if (rawmidi_file == NULL) { |
417 | - snd_card_file_remove(card, file); | |
418 | - return -ENOMEM; | |
409 | + err = -ENOMEM; | |
410 | + goto __error; | |
419 | 411 | } |
420 | 412 | init_waitqueue_entry(&wait, current); |
421 | 413 | add_wait_queue(&rmidi->open_wait, &wait); |
422 | - mutex_lock(&rmidi->open_mutex); | |
423 | 414 | while (1) { |
424 | 415 | subdevice = -1; |
425 | 416 | read_lock(&card->ctl_files_rwlock); |
... | ... | @@ -431,8 +422,7 @@ |
431 | 422 | } |
432 | 423 | } |
433 | 424 | read_unlock(&card->ctl_files_rwlock); |
434 | - err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device, | |
435 | - subdevice, fflags, rawmidi_file); | |
425 | + err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file); | |
436 | 426 | if (err >= 0) |
437 | 427 | break; |
438 | 428 | if (err == -EAGAIN) { |
439 | 429 | |
440 | 430 | |
441 | 431 | |
442 | 432 | |
443 | 433 | |
444 | 434 | |
445 | 435 | |
446 | 436 | |
447 | 437 | |
448 | 438 | |
... | ... | @@ -451,67 +441,89 @@ |
451 | 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 | 449 | #ifdef CONFIG_SND_OSSEMUL |
455 | 450 | if (rawmidi_file->input && rawmidi_file->input->runtime) |
456 | 451 | rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR); |
457 | 452 | if (rawmidi_file->output && rawmidi_file->output->runtime) |
458 | 453 | rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR); |
459 | 454 | #endif |
460 | - remove_wait_queue(&rmidi->open_wait, &wait); | |
461 | - if (err >= 0) { | |
462 | - file->private_data = rawmidi_file; | |
463 | - } else { | |
464 | - snd_card_file_remove(card, file); | |
465 | - kfree(rawmidi_file); | |
466 | - } | |
455 | + file->private_data = rawmidi_file; | |
467 | 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 | 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; | |
474 | - struct snd_rawmidi_substream *substream; | |
475 | - struct snd_rawmidi_runtime *runtime; | |
471 | + rmidi->streams[substream->stream].substream_opened--; | |
472 | + if (--substream->use_count) | |
473 | + return; | |
476 | 474 | |
477 | - if (snd_BUG_ON(!rfile)) | |
478 | - return -ENXIO; | |
479 | - rmidi = rfile->rmidi; | |
480 | - mutex_lock(&rmidi->open_mutex); | |
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; | |
475 | + if (cleanup) { | |
476 | + if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) | |
477 | + snd_rawmidi_input_trigger(substream, 0); | |
478 | + else { | |
498 | 479 | if (substream->active_sensing) { |
499 | 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 | 484 | snd_rawmidi_kernel_write(substream, &buf, 1); |
502 | 485 | } |
503 | 486 | if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS) |
504 | 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 | 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 | 527 | module_put(rmidi->card->module); |
516 | 528 | return 0; |
517 | 529 | } |
518 | 530 | |
519 | 531 | |
520 | 532 | |
... | ... | @@ -520,15 +532,14 @@ |
520 | 532 | { |
521 | 533 | struct snd_rawmidi_file *rfile; |
522 | 534 | struct snd_rawmidi *rmidi; |
523 | - int err; | |
524 | 535 | |
525 | 536 | rfile = file->private_data; |
526 | - err = snd_rawmidi_kernel_release(rfile); | |
527 | 537 | rmidi = rfile->rmidi; |
528 | - wake_up(&rmidi->open_wait); | |
538 | + rawmidi_release_priv(rfile); | |
529 | 539 | kfree(rfile); |
530 | 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 | 545 | static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, |