aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-05-30 13:43:52 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-06-02 13:48:13 -0400
commit10389536742cefbedecb67a5b2906f155cf3a1c3 (patch)
treecf0dbc030578e267e7f9fe1349083c3af3090f19 /drivers/firewire
parent67a3e12b05e055c0415c556a315a3d3eb637e29e (diff)
firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder
Per IEEE 1394 clause 8.4.2.3, a contender for the IRM role shall check whether the current IRM complies to 1394a-2000 or later. If not force a compliant node (e.g. itself) to become IRM. This was implemented in the older ieee1394 driver but not yet in firewire-core. An older Sony camcorder (Sony DCR-TRV25) which implements 1394-1995 IRM but neither 1394a-2000 IRM nor BM was now found to cause an interoperability bug: - Camcorder becomes root node when plugged in, hence gets IRM role. - firewire-core successfully contends for BM role, proceeds to perform gap count optimization and resets the bus. - Sony camcorder ignores presence of a BM (against the spec, this is a firmware bug), performs its idea of gap count optimization and resets the bus. - Preceding two steps are repeated endlessly, bus never settles, regular I/O is practically impossible. http://thread.gmane.org/gmane.linux.kernel.firewire.user/3913 This is an interoperability regression from the old to the new drivers. Fix it indirectly by adding the 1394a IRM check. The spec suggests three and a half methods to determine 1394a compliance of a remote IRM; we choose the method of testing the Config_ROM.Bus_Info.generation field. This is data that firewire-core should have readily available at this point, i.e. does not require extra I/O. Reported-by: Clemens Ladisch <clemens@ladisch.de> (missing 1394a check) Reported-by: H. S. <hs.samix@gmail.com> (issue with Sony DCR-TRV25) Tested-by: H. S. <hs.samix@gmail.com> Cc: <stable@kernel.org> # .32.x and newer Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-card.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 9dcb30466ec0..371713ff0266 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -231,7 +231,7 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
231static void fw_card_bm_work(struct work_struct *work) 231static void fw_card_bm_work(struct work_struct *work)
232{ 232{
233 struct fw_card *card = container_of(work, struct fw_card, work.work); 233 struct fw_card *card = container_of(work, struct fw_card, work.work);
234 struct fw_device *root_device; 234 struct fw_device *root_device, *irm_device;
235 struct fw_node *root_node; 235 struct fw_node *root_node;
236 unsigned long flags; 236 unsigned long flags;
237 int root_id, new_root_id, irm_id, local_id; 237 int root_id, new_root_id, irm_id, local_id;
@@ -239,6 +239,7 @@ static void fw_card_bm_work(struct work_struct *work)
239 bool do_reset = false; 239 bool do_reset = false;
240 bool root_device_is_running; 240 bool root_device_is_running;
241 bool root_device_is_cmc; 241 bool root_device_is_cmc;
242 bool irm_is_1394_1995_only;
242 243
243 spin_lock_irqsave(&card->lock, flags); 244 spin_lock_irqsave(&card->lock, flags);
244 245
@@ -248,12 +249,18 @@ static void fw_card_bm_work(struct work_struct *work)
248 } 249 }
249 250
250 generation = card->generation; 251 generation = card->generation;
252
251 root_node = card->root_node; 253 root_node = card->root_node;
252 fw_node_get(root_node); 254 fw_node_get(root_node);
253 root_device = root_node->data; 255 root_device = root_node->data;
254 root_device_is_running = root_device && 256 root_device_is_running = root_device &&
255 atomic_read(&root_device->state) == FW_DEVICE_RUNNING; 257 atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
256 root_device_is_cmc = root_device && root_device->cmc; 258 root_device_is_cmc = root_device && root_device->cmc;
259
260 irm_device = card->irm_node->data;
261 irm_is_1394_1995_only = irm_device && irm_device->config_rom &&
262 (irm_device->config_rom[2] & 0x000000f0) == 0;
263
257 root_id = root_node->node_id; 264 root_id = root_node->node_id;
258 irm_id = card->irm_node->node_id; 265 irm_id = card->irm_node->node_id;
259 local_id = card->local_node->node_id; 266 local_id = card->local_node->node_id;
@@ -276,8 +283,15 @@ static void fw_card_bm_work(struct work_struct *work)
276 283
277 if (!card->irm_node->link_on) { 284 if (!card->irm_node->link_on) {
278 new_root_id = local_id; 285 new_root_id = local_id;
279 fw_notify("IRM has link off, making local node (%02x) root.\n", 286 fw_notify("%s, making local node (%02x) root.\n",
280 new_root_id); 287 "IRM has link off", new_root_id);
288 goto pick_me;
289 }
290
291 if (irm_is_1394_1995_only) {
292 new_root_id = local_id;
293 fw_notify("%s, making local node (%02x) root.\n",
294 "IRM is not 1394a compliant", new_root_id);
281 goto pick_me; 295 goto pick_me;
282 } 296 }
283 297
@@ -316,8 +330,8 @@ static void fw_card_bm_work(struct work_struct *work)
316 * root, and thus, IRM. 330 * root, and thus, IRM.
317 */ 331 */
318 new_root_id = local_id; 332 new_root_id = local_id;
319 fw_notify("BM lock failed, making local node (%02x) root.\n", 333 fw_notify("%s, making local node (%02x) root.\n",
320 new_root_id); 334 "BM lock failed", new_root_id);
321 goto pick_me; 335 goto pick_me;
322 } 336 }
323 } else if (card->bm_generation != generation) { 337 } else if (card->bm_generation != generation) {