aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2016-03-30 19:47:08 -0400
committerTakashi Iwai <tiwai@suse.de>2016-03-31 09:36:20 -0400
commit86c8dd7f4da3fb3f92fc5ab5144c971639d39745 (patch)
tree2f6b61bd721eedf7a945412efb4e7b499148f2b0
parent6c29230e2a5ff84df2b1358681414bad3e4bd220 (diff)
ALSA: firewire-digi00x: delayed registration of sound card
When some digi00x units are connected sequentially, userspace applications are involved at bus-reset state on IEEE 1394 bus. In the state, any communications can be canceled. Therefore, sound card registration should be delayed till the bus gets calm. This commit achieves it. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/firewire/digi00x/digi00x-transaction.c7
-rw-r--r--sound/firewire/digi00x/digi00x.c107
-rw-r--r--sound/firewire/digi00x/digi00x.h3
3 files changed, 85 insertions, 32 deletions
diff --git a/sound/firewire/digi00x/digi00x-transaction.c b/sound/firewire/digi00x/digi00x-transaction.c
index 554324d8c602..735d35640807 100644
--- a/sound/firewire/digi00x/digi00x-transaction.c
+++ b/sound/firewire/digi00x/digi00x-transaction.c
@@ -126,12 +126,17 @@ int snd_dg00x_transaction_register(struct snd_dg00x *dg00x)
126 return err; 126 return err;
127error: 127error:
128 fw_core_remove_address_handler(&dg00x->async_handler); 128 fw_core_remove_address_handler(&dg00x->async_handler);
129 dg00x->async_handler.address_callback = NULL; 129 dg00x->async_handler.callback_data = NULL;
130 return err; 130 return err;
131} 131}
132 132
133void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) 133void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x)
134{ 134{
135 if (dg00x->async_handler.callback_data == NULL)
136 return;
137
135 snd_fw_async_midi_port_destroy(&dg00x->out_control); 138 snd_fw_async_midi_port_destroy(&dg00x->out_control);
136 fw_core_remove_address_handler(&dg00x->async_handler); 139 fw_core_remove_address_handler(&dg00x->async_handler);
140
141 dg00x->async_handler.callback_data = NULL;
137} 142}
diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c
index 1f33b7a1fca4..cc4776c6ded3 100644
--- a/sound/firewire/digi00x/digi00x.c
+++ b/sound/firewire/digi00x/digi00x.c
@@ -40,10 +40,8 @@ static int name_card(struct snd_dg00x *dg00x)
40 return 0; 40 return 0;
41} 41}
42 42
43static void dg00x_card_free(struct snd_card *card) 43static void dg00x_free(struct snd_dg00x *dg00x)
44{ 44{
45 struct snd_dg00x *dg00x = card->private_data;
46
47 snd_dg00x_stream_destroy_duplex(dg00x); 45 snd_dg00x_stream_destroy_duplex(dg00x);
48 snd_dg00x_transaction_unregister(dg00x); 46 snd_dg00x_transaction_unregister(dg00x);
49 47
@@ -52,28 +50,24 @@ static void dg00x_card_free(struct snd_card *card)
52 mutex_destroy(&dg00x->mutex); 50 mutex_destroy(&dg00x->mutex);
53} 51}
54 52
55static int snd_dg00x_probe(struct fw_unit *unit, 53static void dg00x_card_free(struct snd_card *card)
56 const struct ieee1394_device_id *entry)
57{ 54{
58 struct snd_card *card; 55 dg00x_free(card->private_data);
59 struct snd_dg00x *dg00x; 56}
60 int err;
61 57
62 /* create card */ 58static void do_registration(struct work_struct *work)
63 err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, 59{
64 sizeof(struct snd_dg00x), &card); 60 struct snd_dg00x *dg00x =
65 if (err < 0) 61 container_of(work, struct snd_dg00x, dwork.work);
66 return err; 62 int err;
67 card->private_free = dg00x_card_free;
68 63
69 /* initialize myself */ 64 if (dg00x->registered)
70 dg00x = card->private_data; 65 return;
71 dg00x->card = card;
72 dg00x->unit = fw_unit_get(unit);
73 66
74 mutex_init(&dg00x->mutex); 67 err = snd_card_new(&dg00x->unit->device, -1, NULL, THIS_MODULE, 0,
75 spin_lock_init(&dg00x->lock); 68 &dg00x->card);
76 init_waitqueue_head(&dg00x->hwdep_wait); 69 if (err < 0)
70 return;
77 71
78 err = name_card(dg00x); 72 err = name_card(dg00x);
79 if (err < 0) 73 if (err < 0)
@@ -101,35 +95,86 @@ static int snd_dg00x_probe(struct fw_unit *unit,
101 if (err < 0) 95 if (err < 0)
102 goto error; 96 goto error;
103 97
104 err = snd_card_register(card); 98 err = snd_card_register(dg00x->card);
105 if (err < 0) 99 if (err < 0)
106 goto error; 100 goto error;
107 101
108 dev_set_drvdata(&unit->device, dg00x); 102 dg00x->card->private_free = dg00x_card_free;
103 dg00x->card->private_data = dg00x;
104 dg00x->registered = true;
109 105
110 return err; 106 return;
111error: 107error:
112 snd_card_free(card); 108 snd_dg00x_transaction_unregister(dg00x);
113 return err; 109 snd_dg00x_stream_destroy_duplex(dg00x);
110 snd_card_free(dg00x->card);
111 dev_info(&dg00x->unit->device,
112 "Sound card registration failed: %d\n", err);
113}
114
115static int snd_dg00x_probe(struct fw_unit *unit,
116 const struct ieee1394_device_id *entry)
117{
118 struct snd_dg00x *dg00x;
119
120 /* Allocate this independent of sound card instance. */
121 dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL);
122 if (dg00x == NULL)
123 return -ENOMEM;
124
125 dg00x->unit = fw_unit_get(unit);
126 dev_set_drvdata(&unit->device, dg00x);
127
128 mutex_init(&dg00x->mutex);
129 spin_lock_init(&dg00x->lock);
130 init_waitqueue_head(&dg00x->hwdep_wait);
131
132 /* Allocate and register this sound card later. */
133 INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration);
134 snd_fw_schedule_registration(unit, &dg00x->dwork);
135
136 return 0;
114} 137}
115 138
116static void snd_dg00x_update(struct fw_unit *unit) 139static void snd_dg00x_update(struct fw_unit *unit)
117{ 140{
118 struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); 141 struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
119 142
143 /* Postpone a workqueue for deferred registration. */
144 if (!dg00x->registered)
145 snd_fw_schedule_registration(unit, &dg00x->dwork);
146
120 snd_dg00x_transaction_reregister(dg00x); 147 snd_dg00x_transaction_reregister(dg00x);
121 148
122 mutex_lock(&dg00x->mutex); 149 /*
123 snd_dg00x_stream_update_duplex(dg00x); 150 * After registration, userspace can start packet streaming, then this
124 mutex_unlock(&dg00x->mutex); 151 * code block works fine.
152 */
153 if (dg00x->registered) {
154 mutex_lock(&dg00x->mutex);
155 snd_dg00x_stream_update_duplex(dg00x);
156 mutex_unlock(&dg00x->mutex);
157 }
125} 158}
126 159
127static void snd_dg00x_remove(struct fw_unit *unit) 160static void snd_dg00x_remove(struct fw_unit *unit)
128{ 161{
129 struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); 162 struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device);
130 163
131 /* No need to wait for releasing card object in this context. */ 164 /*
132 snd_card_free_when_closed(dg00x->card); 165 * Confirm to stop the work for registration before the sound card is
166 * going to be released. The work is not scheduled again because bus
167 * reset handler is not called anymore.
168 */
169 cancel_delayed_work_sync(&dg00x->dwork);
170
171 if (dg00x->registered) {
172 /* No need to wait for releasing card object in this context. */
173 snd_card_free_when_closed(dg00x->card);
174 } else {
175 /* Don't forget this case. */
176 dg00x_free(dg00x);
177 }
133} 178}
134 179
135static const struct ieee1394_device_id snd_dg00x_id_table[] = { 180static const struct ieee1394_device_id snd_dg00x_id_table[] = {
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 907e73993677..2cd465c0caae 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -37,6 +37,9 @@ struct snd_dg00x {
37 struct mutex mutex; 37 struct mutex mutex;
38 spinlock_t lock; 38 spinlock_t lock;
39 39
40 bool registered;
41 struct delayed_work dwork;
42
40 struct amdtp_stream tx_stream; 43 struct amdtp_stream tx_stream;
41 struct fw_iso_resources tx_resources; 44 struct fw_iso_resources tx_resources;
42 45