diff options
-rw-r--r-- | sound/firewire/digi00x/digi00x-transaction.c | 7 | ||||
-rw-r--r-- | sound/firewire/digi00x/digi00x.c | 107 | ||||
-rw-r--r-- | sound/firewire/digi00x/digi00x.h | 3 |
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; |
127 | error: | 127 | error: |
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 | ||
133 | void snd_dg00x_transaction_unregister(struct snd_dg00x *dg00x) | 133 | void 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 | ||
43 | static void dg00x_card_free(struct snd_card *card) | 43 | static 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 | ||
55 | static int snd_dg00x_probe(struct fw_unit *unit, | 53 | static 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 */ | 58 | static 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; |
111 | error: | 107 | error: |
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 | |||
115 | static 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 | ||
116 | static void snd_dg00x_update(struct fw_unit *unit) | 139 | static 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 | ||
127 | static void snd_dg00x_remove(struct fw_unit *unit) | 160 | static 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 | ||
135 | static const struct ieee1394_device_id snd_dg00x_id_table[] = { | 180 | static 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 | ||