diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:45:30 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:33:10 -0400 |
commit | 9b1ee0b2cb8bffdbb3003b1d5205f3ae0592c15a (patch) | |
tree | 31124c27fddbaca390e63ebb47174ade02952a89 | |
parent | a2b2a7798fb6a5c639189e5c8f608a56fdc7a222 (diff) |
ALSA: firewire/bebob: Add a workaround for M-Audio special Firewire series
In post commit, a quirk of this firmware about transactions is reported.
This commit apply a workaround for this quirk.
They often fail transactions due to gap_count mismatch. This state is changed
by generating bus reset.
The fw_schedule_bus_reset() is an exported symbol in firewire-core. But there
are no header for public. This commit moves its prototype from
drivers/firewire/core.h to include/linux/firewire.h.
This mismatch still affects bus management before generating this bus reset.
It still takes a time to call driver's probe() because transactions are still
often failed.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | drivers/firewire/core.h | 1 | ||||
-rw-r--r-- | include/linux/firewire.h | 3 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.c | 32 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.h | 1 |
4 files changed, 32 insertions, 5 deletions
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index c98764aeeec6..870044e82316 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h | |||
@@ -118,7 +118,6 @@ int fw_card_add(struct fw_card *card, | |||
118 | u32 max_receive, u32 link_speed, u64 guid); | 118 | u32 max_receive, u32 link_speed, u64 guid); |
119 | void fw_core_remove_card(struct fw_card *card); | 119 | void fw_core_remove_card(struct fw_card *card); |
120 | int fw_compute_block_crc(__be32 *block); | 120 | int fw_compute_block_crc(__be32 *block); |
121 | void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset); | ||
122 | void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); | 121 | void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); |
123 | 122 | ||
124 | /* -cdev */ | 123 | /* -cdev */ |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index c3683bdf28fe..d4b7683c722d 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
@@ -367,6 +367,9 @@ static inline int fw_stream_packet_destination_id(int tag, int channel, int sy) | |||
367 | return tag << 14 | channel << 8 | sy; | 367 | return tag << 14 | channel << 8 | sy; |
368 | } | 368 | } |
369 | 369 | ||
370 | void fw_schedule_bus_reset(struct fw_card *card, bool delayed, | ||
371 | bool short_reset); | ||
372 | |||
370 | struct fw_descriptor { | 373 | struct fw_descriptor { |
371 | struct list_head link; | 374 | struct list_head link; |
372 | size_t length; | 375 | size_t length; |
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index e1dd4219ea6c..31b96b7264cf 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c | |||
@@ -247,10 +247,26 @@ bebob_probe(struct fw_unit *unit, | |||
247 | if (err < 0) | 247 | if (err < 0) |
248 | goto error; | 248 | goto error; |
249 | 249 | ||
250 | err = snd_card_register(card); | 250 | if (!bebob->maudio_special_quirk) { |
251 | if (err < 0) { | 251 | err = snd_card_register(card); |
252 | snd_bebob_stream_destroy_duplex(bebob); | 252 | if (err < 0) { |
253 | goto error; | 253 | snd_bebob_stream_destroy_duplex(bebob); |
254 | goto error; | ||
255 | } | ||
256 | } else { | ||
257 | /* | ||
258 | * This is a workaround. This bus reset seems to have an effect | ||
259 | * to make devices correctly handling transactions. Without | ||
260 | * this, the devices have gap_count mismatch. This causes much | ||
261 | * failure of transaction. | ||
262 | * | ||
263 | * Just after registration, user-land application receive | ||
264 | * signals from dbus and starts I/Os. To avoid I/Os till the | ||
265 | * future bus reset, registration is done in next update(). | ||
266 | */ | ||
267 | bebob->deferred_registration = true; | ||
268 | fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, | ||
269 | false, true); | ||
254 | } | 270 | } |
255 | 271 | ||
256 | dev_set_drvdata(&unit->device, bebob); | 272 | dev_set_drvdata(&unit->device, bebob); |
@@ -273,6 +289,14 @@ bebob_update(struct fw_unit *unit) | |||
273 | 289 | ||
274 | fcp_bus_reset(bebob->unit); | 290 | fcp_bus_reset(bebob->unit); |
275 | snd_bebob_stream_update_duplex(bebob); | 291 | snd_bebob_stream_update_duplex(bebob); |
292 | |||
293 | if (bebob->deferred_registration) { | ||
294 | if (snd_card_register(bebob->card) < 0) { | ||
295 | snd_bebob_stream_destroy_duplex(bebob); | ||
296 | snd_card_free(bebob->card); | ||
297 | } | ||
298 | bebob->deferred_registration = false; | ||
299 | } | ||
276 | } | 300 | } |
277 | 301 | ||
278 | static void bebob_remove(struct fw_unit *unit) | 302 | static void bebob_remove(struct fw_unit *unit) |
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 4a54e746c5c6..91b26b0c649a 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h | |||
@@ -109,6 +109,7 @@ struct snd_bebob { | |||
109 | 109 | ||
110 | /* for M-Audio special devices */ | 110 | /* for M-Audio special devices */ |
111 | void *maudio_special_quirk; | 111 | void *maudio_special_quirk; |
112 | bool deferred_registration; | ||
112 | }; | 113 | }; |
113 | 114 | ||
114 | static inline int | 115 | static inline int |