diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /sound/usb/card.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r-- | sound/usb/card.c | 46 |
1 files changed, 19 insertions, 27 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index ccf95cfe186..d8f2bf40145 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -25,6 +25,9 @@ | |||
25 | * | 25 | * |
26 | * NOTES: | 26 | * NOTES: |
27 | * | 27 | * |
28 | * - async unlink should be used for avoiding the sleep inside lock. | ||
29 | * 2.4.22 usb-uhci seems buggy for async unlinking and results in | ||
30 | * oops. in such a cse, pass async_unlink=0 option. | ||
28 | * - the linked URBs would be preferred but not used so far because of | 31 | * - the linked URBs would be preferred but not used so far because of |
29 | * the instability of unlinking. | 32 | * the instability of unlinking. |
30 | * - type II is not supported properly. there is no device which supports | 33 | * - type II is not supported properly. there is no device which supports |
@@ -44,7 +47,6 @@ | |||
44 | #include <linux/mutex.h> | 47 | #include <linux/mutex.h> |
45 | #include <linux/usb/audio.h> | 48 | #include <linux/usb/audio.h> |
46 | #include <linux/usb/audio-v2.h> | 49 | #include <linux/usb/audio-v2.h> |
47 | #include <linux/module.h> | ||
48 | 50 | ||
49 | #include <sound/control.h> | 51 | #include <sound/control.h> |
50 | #include <sound/core.h> | 52 | #include <sound/core.h> |
@@ -63,9 +65,9 @@ | |||
63 | #include "helper.h" | 65 | #include "helper.h" |
64 | #include "debug.h" | 66 | #include "debug.h" |
65 | #include "pcm.h" | 67 | #include "pcm.h" |
68 | #include "urb.h" | ||
66 | #include "format.h" | 69 | #include "format.h" |
67 | #include "power.h" | 70 | #include "power.h" |
68 | #include "stream.h" | ||
69 | 71 | ||
70 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 72 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
71 | MODULE_DESCRIPTION("USB Audio"); | 73 | MODULE_DESCRIPTION("USB Audio"); |
@@ -75,13 +77,14 @@ MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}"); | |||
75 | 77 | ||
76 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 78 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
77 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 79 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
78 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ | 80 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ |
79 | /* Vendor/product IDs for this card */ | 81 | /* Vendor/product IDs for this card */ |
80 | static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; | 82 | static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; |
81 | static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; | 83 | static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; |
82 | static int nrpacks = 8; /* max. number of packets per urb */ | 84 | static int nrpacks = 8; /* max. number of packets per urb */ |
85 | static int async_unlink = 1; | ||
83 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ | 86 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card */ |
84 | static bool ignore_ctl_error; | 87 | static int ignore_ctl_error; |
85 | 88 | ||
86 | module_param_array(index, int, NULL, 0444); | 89 | module_param_array(index, int, NULL, 0444); |
87 | MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); | 90 | MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); |
@@ -95,6 +98,8 @@ module_param_array(pid, int, NULL, 0444); | |||
95 | MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); | 98 | MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); |
96 | module_param(nrpacks, int, 0644); | 99 | module_param(nrpacks, int, 0644); |
97 | MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); | 100 | MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); |
101 | module_param(async_unlink, bool, 0444); | ||
102 | MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); | ||
98 | module_param_array(device_setup, int, NULL, 0444); | 103 | module_param_array(device_setup, int, NULL, 0444); |
99 | MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); | 104 | MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); |
100 | module_param(ignore_ctl_error, bool, 0444); | 105 | module_param(ignore_ctl_error, bool, 0444); |
@@ -125,9 +130,8 @@ static void snd_usb_stream_disconnect(struct list_head *head) | |||
125 | subs = &as->substream[idx]; | 130 | subs = &as->substream[idx]; |
126 | if (!subs->num_formats) | 131 | if (!subs->num_formats) |
127 | continue; | 132 | continue; |
133 | snd_usb_release_substream_urbs(subs, 1); | ||
128 | subs->interface = -1; | 134 | subs->interface = -1; |
129 | subs->data_endpoint = NULL; | ||
130 | subs->sync_endpoint = NULL; | ||
131 | } | 135 | } |
132 | } | 136 | } |
133 | 137 | ||
@@ -181,7 +185,7 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int | |||
181 | return -EINVAL; | 185 | return -EINVAL; |
182 | } | 186 | } |
183 | 187 | ||
184 | if (! snd_usb_parse_audio_interface(chip, interface)) { | 188 | if (! snd_usb_parse_audio_endpoints(chip, interface)) { |
185 | usb_set_interface(dev, interface, 0); /* reset the current interface */ | 189 | usb_set_interface(dev, interface, 0); /* reset the current interface */ |
186 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | 190 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); |
187 | return -EINVAL; | 191 | return -EINVAL; |
@@ -271,7 +275,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
271 | 275 | ||
272 | static int snd_usb_audio_free(struct snd_usb_audio *chip) | 276 | static int snd_usb_audio_free(struct snd_usb_audio *chip) |
273 | { | 277 | { |
274 | mutex_destroy(&chip->mutex); | ||
275 | kfree(chip); | 278 | kfree(chip); |
276 | return 0; | 279 | return 0; |
277 | } | 280 | } |
@@ -332,19 +335,18 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
332 | return -ENOMEM; | 335 | return -ENOMEM; |
333 | } | 336 | } |
334 | 337 | ||
335 | mutex_init(&chip->mutex); | 338 | mutex_init(&chip->shutdown_mutex); |
336 | init_rwsem(&chip->shutdown_rwsem); | ||
337 | chip->index = idx; | 339 | chip->index = idx; |
338 | chip->dev = dev; | 340 | chip->dev = dev; |
339 | chip->card = card; | 341 | chip->card = card; |
340 | chip->setup = device_setup[idx]; | 342 | chip->setup = device_setup[idx]; |
341 | chip->nrpacks = nrpacks; | 343 | chip->nrpacks = nrpacks; |
344 | chip->async_unlink = async_unlink; | ||
342 | chip->probing = 1; | 345 | chip->probing = 1; |
343 | 346 | ||
344 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 347 | chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), |
345 | le16_to_cpu(dev->descriptor.idProduct)); | 348 | le16_to_cpu(dev->descriptor.idProduct)); |
346 | INIT_LIST_HEAD(&chip->pcm_list); | 349 | INIT_LIST_HEAD(&chip->pcm_list); |
347 | INIT_LIST_HEAD(&chip->ep_list); | ||
348 | INIT_LIST_HEAD(&chip->midi_list); | 350 | INIT_LIST_HEAD(&chip->midi_list); |
349 | INIT_LIST_HEAD(&chip->mixer_list); | 351 | INIT_LIST_HEAD(&chip->mixer_list); |
350 | 352 | ||
@@ -546,17 +548,15 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
546 | struct snd_usb_audio *chip) | 548 | struct snd_usb_audio *chip) |
547 | { | 549 | { |
548 | struct snd_card *card; | 550 | struct snd_card *card; |
549 | struct list_head *p, *n; | 551 | struct list_head *p; |
550 | 552 | ||
551 | if (chip == (void *)-1L) | 553 | if (chip == (void *)-1L) |
552 | return; | 554 | return; |
553 | 555 | ||
554 | card = chip->card; | 556 | card = chip->card; |
555 | down_write(&chip->shutdown_rwsem); | ||
556 | chip->shutdown = 1; | ||
557 | up_write(&chip->shutdown_rwsem); | ||
558 | |||
559 | mutex_lock(®ister_mutex); | 557 | mutex_lock(®ister_mutex); |
558 | mutex_lock(&chip->shutdown_mutex); | ||
559 | chip->shutdown = 1; | ||
560 | chip->num_interfaces--; | 560 | chip->num_interfaces--; |
561 | if (chip->num_interfaces <= 0) { | 561 | if (chip->num_interfaces <= 0) { |
562 | snd_card_disconnect(card); | 562 | snd_card_disconnect(card); |
@@ -564,10 +564,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
564 | list_for_each(p, &chip->pcm_list) { | 564 | list_for_each(p, &chip->pcm_list) { |
565 | snd_usb_stream_disconnect(p); | 565 | snd_usb_stream_disconnect(p); |
566 | } | 566 | } |
567 | /* release the endpoint resources */ | ||
568 | list_for_each_safe(p, n, &chip->ep_list) { | ||
569 | snd_usb_endpoint_free(p); | ||
570 | } | ||
571 | /* release the midi resources */ | 567 | /* release the midi resources */ |
572 | list_for_each(p, &chip->midi_list) { | 568 | list_for_each(p, &chip->midi_list) { |
573 | snd_usbmidi_disconnect(p); | 569 | snd_usbmidi_disconnect(p); |
@@ -577,9 +573,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, | |||
577 | snd_usb_mixer_disconnect(p); | 573 | snd_usb_mixer_disconnect(p); |
578 | } | 574 | } |
579 | usb_chip[chip->index] = NULL; | 575 | usb_chip[chip->index] = NULL; |
576 | mutex_unlock(&chip->shutdown_mutex); | ||
580 | mutex_unlock(®ister_mutex); | 577 | mutex_unlock(®ister_mutex); |
581 | snd_card_free_when_closed(card); | 578 | snd_card_free_when_closed(card); |
582 | } else { | 579 | } else { |
580 | mutex_unlock(&chip->shutdown_mutex); | ||
583 | mutex_unlock(®ister_mutex); | 581 | mutex_unlock(®ister_mutex); |
584 | } | 582 | } |
585 | } | 583 | } |
@@ -611,20 +609,16 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) | |||
611 | { | 609 | { |
612 | int err = -ENODEV; | 610 | int err = -ENODEV; |
613 | 611 | ||
614 | down_read(&chip->shutdown_rwsem); | ||
615 | if (!chip->shutdown && !chip->probing) | 612 | if (!chip->shutdown && !chip->probing) |
616 | err = usb_autopm_get_interface(chip->pm_intf); | 613 | err = usb_autopm_get_interface(chip->pm_intf); |
617 | up_read(&chip->shutdown_rwsem); | ||
618 | 614 | ||
619 | return err; | 615 | return err; |
620 | } | 616 | } |
621 | 617 | ||
622 | void snd_usb_autosuspend(struct snd_usb_audio *chip) | 618 | void snd_usb_autosuspend(struct snd_usb_audio *chip) |
623 | { | 619 | { |
624 | down_read(&chip->shutdown_rwsem); | ||
625 | if (!chip->shutdown && !chip->probing) | 620 | if (!chip->shutdown && !chip->probing) |
626 | usb_autopm_put_interface(chip->pm_intf); | 621 | usb_autopm_put_interface(chip->pm_intf); |
627 | up_read(&chip->shutdown_rwsem); | ||
628 | } | 622 | } |
629 | 623 | ||
630 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | 624 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) |
@@ -637,14 +631,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | |||
637 | if (chip == (void *)-1L) | 631 | if (chip == (void *)-1L) |
638 | return 0; | 632 | return 0; |
639 | 633 | ||
640 | if (!PMSG_IS_AUTO(message)) { | 634 | if (!(message.event & PM_EVENT_AUTO)) { |
641 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); | 635 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); |
642 | if (!chip->num_suspended_intf++) { | 636 | if (!chip->num_suspended_intf++) { |
643 | list_for_each(p, &chip->pcm_list) { | 637 | list_for_each(p, &chip->pcm_list) { |
644 | as = list_entry(p, struct snd_usb_stream, list); | 638 | as = list_entry(p, struct snd_usb_stream, list); |
645 | snd_pcm_suspend_all(as->pcm); | 639 | snd_pcm_suspend_all(as->pcm); |
646 | as->substream[0].need_setup_ep = | ||
647 | as->substream[1].need_setup_ep = true; | ||
648 | } | 640 | } |
649 | } | 641 | } |
650 | } else { | 642 | } else { |