diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/usb/card.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r-- | sound/usb/card.c | 138 |
1 files changed, 109 insertions, 29 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 4eabafa5b037..220c6167dd86 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -41,12 +41,14 @@ | |||
41 | #include <linux/list.h> | 41 | #include <linux/list.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/string.h> | 43 | #include <linux/string.h> |
44 | #include <linux/ctype.h> | ||
44 | #include <linux/usb.h> | 45 | #include <linux/usb.h> |
45 | #include <linux/moduleparam.h> | 46 | #include <linux/moduleparam.h> |
46 | #include <linux/mutex.h> | 47 | #include <linux/mutex.h> |
47 | #include <linux/usb/audio.h> | 48 | #include <linux/usb/audio.h> |
48 | #include <linux/usb/audio-v2.h> | 49 | #include <linux/usb/audio-v2.h> |
49 | 50 | ||
51 | #include <sound/control.h> | ||
50 | #include <sound/core.h> | 52 | #include <sound/core.h> |
51 | #include <sound/info.h> | 53 | #include <sound/info.h> |
52 | #include <sound/pcm.h> | 54 | #include <sound/pcm.h> |
@@ -65,6 +67,7 @@ | |||
65 | #include "pcm.h" | 67 | #include "pcm.h" |
66 | #include "urb.h" | 68 | #include "urb.h" |
67 | #include "format.h" | 69 | #include "format.h" |
70 | #include "power.h" | ||
68 | 71 | ||
69 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 72 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
70 | MODULE_DESCRIPTION("USB Audio"); | 73 | MODULE_DESCRIPTION("USB Audio"); |
@@ -282,6 +285,15 @@ static int snd_usb_audio_dev_free(struct snd_device *device) | |||
282 | return snd_usb_audio_free(chip); | 285 | return snd_usb_audio_free(chip); |
283 | } | 286 | } |
284 | 287 | ||
288 | static void remove_trailing_spaces(char *str) | ||
289 | { | ||
290 | char *p; | ||
291 | |||
292 | if (!*str) | ||
293 | return; | ||
294 | for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--) | ||
295 | *p = 0; | ||
296 | } | ||
285 | 297 | ||
286 | /* | 298 | /* |
287 | * create a chip instance and set its names. | 299 | * create a chip instance and set its names. |
@@ -300,9 +312,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
300 | 312 | ||
301 | *rchip = NULL; | 313 | *rchip = NULL; |
302 | 314 | ||
303 | if (snd_usb_get_speed(dev) != USB_SPEED_LOW && | 315 | switch (snd_usb_get_speed(dev)) { |
304 | snd_usb_get_speed(dev) != USB_SPEED_FULL && | 316 | case USB_SPEED_LOW: |
305 | snd_usb_get_speed(dev) != USB_SPEED_HIGH) { | 317 | case USB_SPEED_FULL: |
318 | case USB_SPEED_HIGH: | ||
319 | case USB_SPEED_SUPER: | ||
320 | break; | ||
321 | default: | ||
306 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); | 322 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); |
307 | return -ENXIO; | 323 | return -ENXIO; |
308 | } | 324 | } |
@@ -319,12 +335,14 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
319 | return -ENOMEM; | 335 | return -ENOMEM; |
320 | } | 336 | } |
321 | 337 | ||
338 | mutex_init(&chip->shutdown_mutex); | ||
322 | chip->index = idx; | 339 | chip->index = idx; |
323 | chip->dev = dev; | 340 | chip->dev = dev; |
324 | chip->card = card; | 341 | chip->card = card; |
325 | chip->setup = device_setup[idx]; | 342 | chip->setup = device_setup[idx]; |
326 | chip->nrpacks = nrpacks; | 343 | chip->nrpacks = nrpacks; |
327 | chip->async_unlink = async_unlink; | 344 | chip->async_unlink = async_unlink; |
345 | chip->probing = 1; | ||
328 | 346 | ||
329 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 347 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), |
330 | le16_to_cpu(dev->descriptor.idProduct)); | 348 | le16_to_cpu(dev->descriptor.idProduct)); |
@@ -344,7 +362,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
344 | snd_component_add(card, component); | 362 | snd_component_add(card, component); |
345 | 363 | ||
346 | /* retrieve the device string as shortname */ | 364 | /* retrieve the device string as shortname */ |
347 | if (quirk && quirk->product_name) { | 365 | if (quirk && quirk->product_name && *quirk->product_name) { |
348 | strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); | 366 | strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); |
349 | } else { | 367 | } else { |
350 | if (!dev->descriptor.iProduct || | 368 | if (!dev->descriptor.iProduct || |
@@ -356,9 +374,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
356 | USB_ID_PRODUCT(chip->usb_id)); | 374 | USB_ID_PRODUCT(chip->usb_id)); |
357 | } | 375 | } |
358 | } | 376 | } |
377 | remove_trailing_spaces(card->shortname); | ||
359 | 378 | ||
360 | /* retrieve the vendor and device strings as longname */ | 379 | /* retrieve the vendor and device strings as longname */ |
361 | if (quirk && quirk->vendor_name) { | 380 | if (quirk && quirk->vendor_name && *quirk->vendor_name) { |
362 | len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); | 381 | len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); |
363 | } else { | 382 | } else { |
364 | if (dev->descriptor.iManufacturer) | 383 | if (dev->descriptor.iManufacturer) |
@@ -368,8 +387,11 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
368 | len = 0; | 387 | len = 0; |
369 | /* we don't really care if there isn't any vendor string */ | 388 | /* we don't really care if there isn't any vendor string */ |
370 | } | 389 | } |
371 | if (len > 0) | 390 | if (len > 0) { |
372 | strlcat(card->longname, " ", sizeof(card->longname)); | 391 | remove_trailing_spaces(card->longname); |
392 | if (*card->longname) | ||
393 | strlcat(card->longname, " ", sizeof(card->longname)); | ||
394 | } | ||
373 | 395 | ||
374 | strlcat(card->longname, card->shortname, sizeof(card->longname)); | 396 | strlcat(card->longname, card->shortname, sizeof(card->longname)); |
375 | 397 | ||
@@ -378,11 +400,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
378 | if (len < sizeof(card->longname)) | 400 | if (len < sizeof(card->longname)) |
379 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); | 401 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); |
380 | 402 | ||
381 | strlcat(card->longname, | 403 | switch (snd_usb_get_speed(dev)) { |
382 | snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : | 404 | case USB_SPEED_LOW: |
383 | snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : | 405 | strlcat(card->longname, ", low speed", sizeof(card->longname)); |
384 | ", high speed", | 406 | break; |
385 | sizeof(card->longname)); | 407 | case USB_SPEED_FULL: |
408 | strlcat(card->longname, ", full speed", sizeof(card->longname)); | ||
409 | break; | ||
410 | case USB_SPEED_HIGH: | ||
411 | strlcat(card->longname, ", high speed", sizeof(card->longname)); | ||
412 | break; | ||
413 | case USB_SPEED_SUPER: | ||
414 | strlcat(card->longname, ", super speed", sizeof(card->longname)); | ||
415 | break; | ||
416 | default: | ||
417 | break; | ||
418 | } | ||
386 | 419 | ||
387 | snd_usb_audio_create_proc(chip); | 420 | snd_usb_audio_create_proc(chip); |
388 | 421 | ||
@@ -435,6 +468,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
435 | goto __error; | 468 | goto __error; |
436 | } | 469 | } |
437 | chip = usb_chip[i]; | 470 | chip = usb_chip[i]; |
471 | chip->probing = 1; | ||
438 | break; | 472 | break; |
439 | } | 473 | } |
440 | } | 474 | } |
@@ -450,6 +484,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
450 | goto __error; | 484 | goto __error; |
451 | } | 485 | } |
452 | snd_card_set_dev(chip->card, &intf->dev); | 486 | snd_card_set_dev(chip->card, &intf->dev); |
487 | chip->pm_intf = intf; | ||
453 | break; | 488 | break; |
454 | } | 489 | } |
455 | if (!chip) { | 490 | if (!chip) { |
@@ -458,14 +493,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
458 | } | 493 | } |
459 | } | 494 | } |
460 | 495 | ||
461 | chip->txfr_quirk = 0; | ||
462 | err = 1; /* continue */ | ||
463 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { | ||
464 | /* need some special handlings */ | ||
465 | if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) | ||
466 | goto __error; | ||
467 | } | ||
468 | |||
469 | /* | 496 | /* |
470 | * For devices with more than one control interface, we assume the | 497 | * For devices with more than one control interface, we assume the |
471 | * first contains the audio controls. We might need a more specific | 498 | * first contains the audio controls. We might need a more specific |
@@ -474,6 +501,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
474 | if (!chip->ctrl_intf) | 501 | if (!chip->ctrl_intf) |
475 | chip->ctrl_intf = alts; | 502 | chip->ctrl_intf = alts; |
476 | 503 | ||
504 | chip->txfr_quirk = 0; | ||
505 | err = 1; /* continue */ | ||
506 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { | ||
507 | /* need some special handlings */ | ||
508 | if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) | ||
509 | goto __error; | ||
510 | } | ||
511 | |||
477 | if (err > 0) { | 512 | if (err > 0) { |
478 | /* create normal USB audio interfaces */ | 513 | /* create normal USB audio interfaces */ |
479 | if (snd_usb_create_streams(chip, ifnum) < 0 || | 514 | if (snd_usb_create_streams(chip, ifnum) < 0 || |
@@ -489,6 +524,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
489 | 524 | ||
490 | usb_chip[chip->index] = chip; | 525 | usb_chip[chip->index] = chip; |
491 | chip->num_interfaces++; | 526 | chip->num_interfaces++; |
527 | chip->probing = 0; | ||
492 | mutex_unlock(®ister_mutex); | 528 | mutex_unlock(®ister_mutex); |
493 | return chip; | 529 | return chip; |
494 | 530 | ||
@@ -516,6 +552,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) | |||
516 | chip = ptr; | 552 | chip = ptr; |
517 | card = chip->card; | 553 | card = chip->card; |
518 | mutex_lock(®ister_mutex); | 554 | mutex_lock(®ister_mutex); |
555 | mutex_lock(&chip->shutdown_mutex); | ||
519 | chip->shutdown = 1; | 556 | chip->shutdown = 1; |
520 | chip->num_interfaces--; | 557 | chip->num_interfaces--; |
521 | if (chip->num_interfaces <= 0) { | 558 | if (chip->num_interfaces <= 0) { |
@@ -533,9 +570,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) | |||
533 | snd_usb_mixer_disconnect(p); | 570 | snd_usb_mixer_disconnect(p); |
534 | } | 571 | } |
535 | usb_chip[chip->index] = NULL; | 572 | usb_chip[chip->index] = NULL; |
573 | mutex_unlock(&chip->shutdown_mutex); | ||
536 | mutex_unlock(®ister_mutex); | 574 | mutex_unlock(®ister_mutex); |
537 | snd_card_free_when_closed(card); | 575 | snd_card_free_when_closed(card); |
538 | } else { | 576 | } else { |
577 | mutex_unlock(&chip->shutdown_mutex); | ||
539 | mutex_unlock(®ister_mutex); | 578 | mutex_unlock(®ister_mutex); |
540 | } | 579 | } |
541 | } | 580 | } |
@@ -562,29 +601,61 @@ static void usb_audio_disconnect(struct usb_interface *intf) | |||
562 | } | 601 | } |
563 | 602 | ||
564 | #ifdef CONFIG_PM | 603 | #ifdef CONFIG_PM |
604 | |||
605 | int snd_usb_autoresume(struct snd_usb_audio *chip) | ||
606 | { | ||
607 | int err = -ENODEV; | ||
608 | |||
609 | if (!chip->shutdown && !chip->probing) | ||
610 | err = usb_autopm_get_interface(chip->pm_intf); | ||
611 | |||
612 | return err; | ||
613 | } | ||
614 | |||
615 | void snd_usb_autosuspend(struct snd_usb_audio *chip) | ||
616 | { | ||
617 | if (!chip->shutdown && !chip->probing) | ||
618 | usb_autopm_put_interface(chip->pm_intf); | ||
619 | } | ||
620 | |||
565 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | 621 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) |
566 | { | 622 | { |
567 | struct snd_usb_audio *chip = usb_get_intfdata(intf); | 623 | struct snd_usb_audio *chip = usb_get_intfdata(intf); |
568 | struct list_head *p; | 624 | struct list_head *p; |
569 | struct snd_usb_stream *as; | 625 | struct snd_usb_stream *as; |
626 | struct usb_mixer_interface *mixer; | ||
570 | 627 | ||
571 | if (chip == (void *)-1L) | 628 | if (chip == (void *)-1L) |
572 | return 0; | 629 | return 0; |
573 | 630 | ||
574 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); | 631 | if (!(message.event & PM_EVENT_AUTO)) { |
575 | if (!chip->num_suspended_intf++) { | 632 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); |
576 | list_for_each(p, &chip->pcm_list) { | 633 | if (!chip->num_suspended_intf++) { |
577 | as = list_entry(p, struct snd_usb_stream, list); | 634 | list_for_each(p, &chip->pcm_list) { |
578 | snd_pcm_suspend_all(as->pcm); | 635 | as = list_entry(p, struct snd_usb_stream, list); |
579 | } | 636 | snd_pcm_suspend_all(as->pcm); |
637 | } | ||
638 | } | ||
639 | } else { | ||
640 | /* | ||
641 | * otherwise we keep the rest of the system in the dark | ||
642 | * to keep this transparent | ||
643 | */ | ||
644 | if (!chip->num_suspended_intf++) | ||
645 | chip->autosuspended = 1; | ||
580 | } | 646 | } |
581 | 647 | ||
648 | list_for_each_entry(mixer, &chip->mixer_list, list) | ||
649 | snd_usb_mixer_inactivate(mixer); | ||
650 | |||
582 | return 0; | 651 | return 0; |
583 | } | 652 | } |
584 | 653 | ||
585 | static int usb_audio_resume(struct usb_interface *intf) | 654 | static int usb_audio_resume(struct usb_interface *intf) |
586 | { | 655 | { |
587 | struct snd_usb_audio *chip = usb_get_intfdata(intf); | 656 | struct snd_usb_audio *chip = usb_get_intfdata(intf); |
657 | struct usb_mixer_interface *mixer; | ||
658 | int err = 0; | ||
588 | 659 | ||
589 | if (chip == (void *)-1L) | 660 | if (chip == (void *)-1L) |
590 | return 0; | 661 | return 0; |
@@ -592,12 +663,20 @@ static int usb_audio_resume(struct usb_interface *intf) | |||
592 | return 0; | 663 | return 0; |
593 | /* | 664 | /* |
594 | * ALSA leaves material resumption to user space | 665 | * ALSA leaves material resumption to user space |
595 | * we just notify | 666 | * we just notify and restart the mixers |
596 | */ | 667 | */ |
668 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
669 | err = snd_usb_mixer_activate(mixer); | ||
670 | if (err < 0) | ||
671 | goto err_out; | ||
672 | } | ||
597 | 673 | ||
598 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); | 674 | if (!chip->autosuspended) |
675 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); | ||
676 | chip->autosuspended = 0; | ||
599 | 677 | ||
600 | return 0; | 678 | err_out: |
679 | return err; | ||
601 | } | 680 | } |
602 | #else | 681 | #else |
603 | #define usb_audio_suspend NULL | 682 | #define usb_audio_suspend NULL |
@@ -625,6 +704,7 @@ static struct usb_driver usb_audio_driver = { | |||
625 | .suspend = usb_audio_suspend, | 704 | .suspend = usb_audio_suspend, |
626 | .resume = usb_audio_resume, | 705 | .resume = usb_audio_resume, |
627 | .id_table = usb_audio_ids, | 706 | .id_table = usb_audio_ids, |
707 | .supports_autosuspend = 1, | ||
628 | }; | 708 | }; |
629 | 709 | ||
630 | static int __init snd_usb_audio_init(void) | 710 | static int __init snd_usb_audio_init(void) |