Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a

Authored by Takashi Iwai
1 parent f9d202833d

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
... ... @@ -42,7 +42,6 @@
42 42 #define SNDRV_RAWMIDI_LFLG_INPUT (1<<1)
43 43 #define SNDRV_RAWMIDI_LFLG_OPEN (3<<0)
44 44 #define SNDRV_RAWMIDI_LFLG_APPEND (1<<2)
45   -#define SNDRV_RAWMIDI_LFLG_NOOPENLOCK (1<<3)
46 45  
47 46 struct snd_rawmidi;
48 47 struct snd_rawmidi_substream;
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(&register_mutex);
239   - rmidi = snd_rawmidi_search(card, device);
240   - if (rmidi == NULL) {
241   - mutex_unlock(&register_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(&register_mutex);
246   - return -ENXIO;
247   - }
248   - mutex_unlock(&register_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(&register_mutex);
  348 + rmidi = snd_rawmidi_search(card, device);
  349 + if (rmidi == NULL) {
  350 + mutex_unlock(&register_mutex);
  351 + return -ENODEV;
  352 + }
  353 + if (!try_module_get(rmidi->card->module)) {
  354 + mutex_unlock(&register_mutex);
  355 + return -ENXIO;
  356 + }
  357 + mutex_unlock(&register_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,