aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/rawmidi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/rawmidi.c')
-rw-r--r--sound/core/rawmidi.c379
1 files changed, 195 insertions, 184 deletions
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
227int 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 */
230static 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 */
263static 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
284static void close_substream(struct snd_rawmidi *rmidi,
285 struct snd_rawmidi_substream *substream,
286 int cleanup);
287
288static 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(&register_mutex);
239 rmidi = snd_rawmidi_search(card, device);
240 mutex_unlock(&register_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 */
338int 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);
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
471int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile) 467static 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
498static 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 */
518int 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
534static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, 545static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,