1 From 10389536742cefbedecb67a5b2906f155cf3a1c3 Mon Sep 17 00:00:00 2001
2 From: Stefan Richter <stefanr@s5r6.in-berlin.de>
3 Date: Sun, 30 May 2010 19:43:52 +0200
4 Subject: firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder
6 From: Stefan Richter <stefanr@s5r6.in-berlin.de>
8 commit 10389536742cefbedecb67a5b2906f155cf3a1c3 upstream.
10 Per IEEE 1394 clause 8.4.2.3, a contender for the IRM role shall check
11 whether the current IRM complies to 1394a-2000 or later. If not force a
12 compliant node (e.g. itself) to become IRM. This was implemented in the
13 older ieee1394 driver but not yet in firewire-core.
15 An older Sony camcorder (Sony DCR-TRV25) which implements 1394-1995 IRM
16 but neither 1394a-2000 IRM nor BM was now found to cause an
18 - Camcorder becomes root node when plugged in, hence gets IRM role.
19 - firewire-core successfully contends for BM role, proceeds to perform
20 gap count optimization and resets the bus.
21 - Sony camcorder ignores presence of a BM (against the spec, this is
22 a firmware bug), performs its idea of gap count optimization and
24 - Preceding two steps are repeated endlessly, bus never settles,
25 regular I/O is practically impossible.
26 http://thread.gmane.org/gmane.linux.kernel.firewire.user/3913
28 This is an interoperability regression from the old to the new drivers.
29 Fix it indirectly by adding the 1394a IRM check. The spec suggests
30 three and a half methods to determine 1394a compliance of a remote IRM;
31 we choose the method of testing the Config_ROM.Bus_Info.generation
32 field. This is data that firewire-core should have readily available at
33 this point, i.e. does not require extra I/O.
35 Reported-by: Clemens Ladisch <clemens@ladisch.de> (missing 1394a check)
36 Reported-by: H. S. <hs.samix@gmail.com> (issue with Sony DCR-TRV25)
37 Tested-by: H. S. <hs.samix@gmail.com>
38 Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
42 drivers/firewire/core-card.c | 24 +++++++++++++++++++-----
43 1 file changed, 19 insertions(+), 5 deletions(-)
45 --- a/drivers/firewire/core-card.c
46 +++ b/drivers/firewire/core-card.c
47 @@ -239,7 +239,7 @@ void fw_schedule_bm_work(struct fw_card
48 static void fw_card_bm_work(struct work_struct *work)
50 struct fw_card *card = container_of(work, struct fw_card, work.work);
51 - struct fw_device *root_device;
52 + struct fw_device *root_device, *irm_device;
53 struct fw_node *root_node;
55 int root_id, new_root_id, irm_id, local_id;
56 @@ -247,6 +247,7 @@ static void fw_card_bm_work(struct work_
57 bool do_reset = false;
58 bool root_device_is_running;
59 bool root_device_is_cmc;
60 + bool irm_is_1394_1995_only;
62 spin_lock_irqsave(&card->lock, flags);
64 @@ -256,12 +257,18 @@ static void fw_card_bm_work(struct work_
67 generation = card->generation;
69 root_node = card->root_node;
70 fw_node_get(root_node);
71 root_device = root_node->data;
72 root_device_is_running = root_device &&
73 atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
74 root_device_is_cmc = root_device && root_device->cmc;
76 + irm_device = card->irm_node->data;
77 + irm_is_1394_1995_only = irm_device && irm_device->config_rom &&
78 + (irm_device->config_rom[2] & 0x000000f0) == 0;
80 root_id = root_node->node_id;
81 irm_id = card->irm_node->node_id;
82 local_id = card->local_node->node_id;
83 @@ -284,8 +291,15 @@ static void fw_card_bm_work(struct work_
85 if (!card->irm_node->link_on) {
86 new_root_id = local_id;
87 - fw_notify("IRM has link off, making local node (%02x) root.\n",
89 + fw_notify("%s, making local node (%02x) root.\n",
90 + "IRM has link off", new_root_id);
94 + if (irm_is_1394_1995_only) {
95 + new_root_id = local_id;
96 + fw_notify("%s, making local node (%02x) root.\n",
97 + "IRM is not 1394a compliant", new_root_id);
101 @@ -324,8 +338,8 @@ static void fw_card_bm_work(struct work_
102 * root, and thus, IRM.
104 new_root_id = local_id;
105 - fw_notify("BM lock failed, making local node (%02x) root.\n",
107 + fw_notify("%s, making local node (%02x) root.\n",
108 + "BM lock failed", new_root_id);
111 } else if (card->bm_generation != generation) {