aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/rawmidi.c377
1 files changed, 194 insertions, 183 deletions
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
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)
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(&register_mutex);
239 rmidi = snd_rawmidi_search(card, device);
240 if (rmidi == NULL) {
241 mutex_unlock(&register_mutex);
242 return -ENODEV;
243 }
244 if (!try_module_get(rmidi->card->module)) {
245 mutex_unlock(&register_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(&register_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); 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)
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 */
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) {
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
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,