diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2017-03-22 08:30:12 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2017-03-28 06:33:19 -0400 |
commit | 8865a31e0fd8beb157b99e78cdf1f0241a67bd54 (patch) | |
tree | bf4f9b02fed5bb64ca4a83937f6a6c42654e0b80 /sound/firewire/motu | |
parent | 6c3cef4890d072afa2d77371f358abaea54ec134 (diff) |
ALSA: firewire-motu: postpone sound card registration
Just after appearing on IEEE 1394 bus, this unit generates several bus
resets. This is due to loading firmware from on-board flash memory and
initialize hardware. It's better to postpone sound card registration.
This commit applies this idea.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/motu')
-rw-r--r-- | sound/firewire/motu/motu.c | 97 | ||||
-rw-r--r-- | sound/firewire/motu/motu.h | 5 |
2 files changed, 78 insertions, 24 deletions
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index 2684e7447432..bdd82ddeb6ec 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c | |||
@@ -38,59 +38,108 @@ static void name_card(struct snd_motu *motu) | |||
38 | dev_name(&motu->unit->device), 100 << fw_dev->max_speed); | 38 | dev_name(&motu->unit->device), 100 << fw_dev->max_speed); |
39 | } | 39 | } |
40 | 40 | ||
41 | static void motu_card_free(struct snd_card *card) | 41 | static void motu_free(struct snd_motu *motu) |
42 | { | 42 | { |
43 | struct snd_motu *motu = card->private_data; | ||
44 | |||
45 | fw_unit_put(motu->unit); | 43 | fw_unit_put(motu->unit); |
46 | 44 | ||
47 | mutex_destroy(&motu->mutex); | 45 | mutex_destroy(&motu->mutex); |
46 | kfree(motu); | ||
48 | } | 47 | } |
49 | 48 | ||
50 | static int motu_probe(struct fw_unit *unit, | 49 | /* |
51 | const struct ieee1394_device_id *entry) | 50 | * This module releases the FireWire unit data after all ALSA character devices |
51 | * are released by applications. This is for releasing stream data or finishing | ||
52 | * transactions safely. Thus at returning from .remove(), this module still keep | ||
53 | * references for the unit. | ||
54 | */ | ||
55 | static void motu_card_free(struct snd_card *card) | ||
52 | { | 56 | { |
53 | struct snd_card *card; | 57 | motu_free(card->private_data); |
54 | struct snd_motu *motu; | 58 | } |
55 | int err; | ||
56 | 59 | ||
57 | err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, | 60 | static void do_registration(struct work_struct *work) |
58 | sizeof(*motu), &card); | 61 | { |
59 | if (err < 0) | 62 | struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work); |
60 | return err; | 63 | int err; |
61 | 64 | ||
62 | motu = card->private_data; | 65 | if (motu->registered) |
63 | motu->card = card; | 66 | return; |
64 | motu->unit = fw_unit_get(unit); | ||
65 | card->private_free = motu_card_free; | ||
66 | 67 | ||
67 | mutex_init(&motu->mutex); | 68 | err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0, |
69 | &motu->card); | ||
70 | if (err < 0) | ||
71 | return; | ||
68 | 72 | ||
69 | name_card(motu); | 73 | name_card(motu); |
70 | 74 | ||
71 | err = snd_card_register(card); | 75 | err = snd_card_register(motu->card); |
72 | if (err < 0) | 76 | if (err < 0) |
73 | goto error; | 77 | goto error; |
74 | 78 | ||
79 | /* | ||
80 | * After registered, motu instance can be released corresponding to | ||
81 | * releasing the sound card instance. | ||
82 | */ | ||
83 | motu->card->private_free = motu_card_free; | ||
84 | motu->card->private_data = motu; | ||
85 | motu->registered = true; | ||
86 | |||
87 | return; | ||
88 | error: | ||
89 | snd_card_free(motu->card); | ||
90 | dev_info(&motu->unit->device, | ||
91 | "Sound card registration failed: %d\n", err); | ||
92 | } | ||
93 | |||
94 | static int motu_probe(struct fw_unit *unit, | ||
95 | const struct ieee1394_device_id *entry) | ||
96 | { | ||
97 | struct snd_motu *motu; | ||
98 | |||
99 | /* Allocate this independently of sound card instance. */ | ||
100 | motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL); | ||
101 | if (motu == NULL) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | motu->unit = fw_unit_get(unit); | ||
75 | dev_set_drvdata(&unit->device, motu); | 105 | dev_set_drvdata(&unit->device, motu); |
76 | 106 | ||
107 | mutex_init(&motu->mutex); | ||
108 | |||
109 | /* Allocate and register this sound card later. */ | ||
110 | INIT_DEFERRABLE_WORK(&motu->dwork, do_registration); | ||
111 | snd_fw_schedule_registration(unit, &motu->dwork); | ||
112 | |||
77 | return 0; | 113 | return 0; |
78 | error: | ||
79 | snd_card_free(card); | ||
80 | return err; | ||
81 | } | 114 | } |
82 | 115 | ||
83 | static void motu_remove(struct fw_unit *unit) | 116 | static void motu_remove(struct fw_unit *unit) |
84 | { | 117 | { |
85 | struct snd_motu *motu = dev_get_drvdata(&unit->device); | 118 | struct snd_motu *motu = dev_get_drvdata(&unit->device); |
86 | 119 | ||
87 | /* No need to wait for releasing card object in this context. */ | 120 | /* |
88 | snd_card_free_when_closed(motu->card); | 121 | * Confirm to stop the work for registration before the sound card is |
122 | * going to be released. The work is not scheduled again because bus | ||
123 | * reset handler is not called anymore. | ||
124 | */ | ||
125 | cancel_delayed_work_sync(&motu->dwork); | ||
126 | |||
127 | if (motu->registered) { | ||
128 | /* No need to wait for releasing card object in this context. */ | ||
129 | snd_card_free_when_closed(motu->card); | ||
130 | } else { | ||
131 | /* Don't forget this case. */ | ||
132 | motu_free(motu); | ||
133 | } | ||
89 | } | 134 | } |
90 | 135 | ||
91 | static void motu_bus_update(struct fw_unit *unit) | 136 | static void motu_bus_update(struct fw_unit *unit) |
92 | { | 137 | { |
93 | return; | 138 | struct snd_motu *motu = dev_get_drvdata(&unit->device); |
139 | |||
140 | /* Postpone a workqueue for deferred registration. */ | ||
141 | if (!motu->registered) | ||
142 | snd_fw_schedule_registration(unit, &motu->dwork); | ||
94 | } | 143 | } |
95 | 144 | ||
96 | #define SND_MOTU_DEV_ENTRY(model) \ | 145 | #define SND_MOTU_DEV_ENTRY(model) \ |
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index f3d0b2834942..eb0ffd56c835 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h | |||
@@ -20,10 +20,15 @@ | |||
20 | #include <sound/control.h> | 20 | #include <sound/control.h> |
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | 22 | ||
23 | #include "../lib.h" | ||
24 | |||
23 | struct snd_motu { | 25 | struct snd_motu { |
24 | struct snd_card *card; | 26 | struct snd_card *card; |
25 | struct fw_unit *unit; | 27 | struct fw_unit *unit; |
26 | struct mutex mutex; | 28 | struct mutex mutex; |
29 | |||
30 | bool registered; | ||
31 | struct delayed_work dwork; | ||
27 | }; | 32 | }; |
28 | 33 | ||
29 | #endif | 34 | #endif |