summaryrefslogtreecommitdiffstats
path: root/sound/firewire/motu
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2017-03-22 08:30:12 -0400
committerTakashi Iwai <tiwai@suse.de>2017-03-28 06:33:19 -0400
commit8865a31e0fd8beb157b99e78cdf1f0241a67bd54 (patch)
treebf4f9b02fed5bb64ca4a83937f6a6c42654e0b80 /sound/firewire/motu
parent6c3cef4890d072afa2d77371f358abaea54ec134 (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.c97
-rw-r--r--sound/firewire/motu/motu.h5
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
41static void motu_card_free(struct snd_card *card) 41static 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
50static 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 */
55static 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, 60static 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;
88error:
89 snd_card_free(motu->card);
90 dev_info(&motu->unit->device,
91 "Sound card registration failed: %d\n", err);
92}
93
94static 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;
78error:
79 snd_card_free(card);
80 return err;
81} 114}
82 115
83static void motu_remove(struct fw_unit *unit) 116static 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
91static void motu_bus_update(struct fw_unit *unit) 136static 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
23struct snd_motu { 25struct 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