aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-device.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-02-17 19:50:31 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-02-24 14:36:54 -0500
commitd54423c62c2f687919d4e5bdd4bb064234ff2d44 (patch)
treed5f32f6188e69c1bca388b92127cb0f26ac0f3aa /drivers/firewire/core-device.c
parent109d28152b6e9d5de64cd23e3bc08885ccb3d1ef (diff)
firewire: core: fix "giving up on config rom" with Panasonic AG-DV2500
The Panasonic AG-DV2500 tape deck contains an invalid entry in its configuration ROM root directory: A leaf pointer with the undefined key ID 0 and an offset that points way out of the standard config ROM area. This caused firewire-core to dismiss the device with the generic log message "giving up on config rom for node id...", after which it was of course impossible to access the tape deck with dvgrab or any other program. https://bugzilla.redhat.com/show_bug.cgi?id=449252#c29 The fix is to simply ignore this invalid ROM entry and proceed to read the valid rest of the ROM. There is a catch though: When the kernel later iterates over the ROM, it would be nasty having to check again for such too large ROM offsets. Therefore we manipulate the defective or unsupported ROM entry to become a harmless immediate entry that won't have any side effects later (an entry with the value 0x00000000). Reported-by: George Chriss Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/core-device.c')
-rw-r--r--drivers/firewire/core-device.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index eecd52dc8e98..e02bf2dff845 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -18,6 +18,7 @@
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */ 19 */
20 20
21#include <linux/bug.h>
21#include <linux/ctype.h> 22#include <linux/ctype.h>
22#include <linux/delay.h> 23#include <linux/delay.h>
23#include <linux/device.h> 24#include <linux/device.h>
@@ -580,11 +581,7 @@ static int read_bus_info_block(struct fw_device *device, int generation)
580 */ 581 */
581 key = stack[--sp]; 582 key = stack[--sp];
582 i = key & 0xffffff; 583 i = key & 0xffffff;
583 if (i >= READ_BIB_ROM_SIZE) 584 if (WARN_ON(i >= READ_BIB_ROM_SIZE))
584 /*
585 * The reference points outside the standard
586 * config rom area, something's fishy.
587 */
588 goto out; 585 goto out;
589 586
590 /* Read header quadlet for the block to get the length. */ 587 /* Read header quadlet for the block to get the length. */
@@ -606,14 +603,29 @@ static int read_bus_info_block(struct fw_device *device, int generation)
606 * block, check the entries as we read them to see if 603 * block, check the entries as we read them to see if
607 * it references another block, and push it in that case. 604 * it references another block, and push it in that case.
608 */ 605 */
609 while (i < end) { 606 for (; i < end; i++) {
610 if (read_rom(device, generation, i, &rom[i]) != 607 if (read_rom(device, generation, i, &rom[i]) !=
611 RCODE_COMPLETE) 608 RCODE_COMPLETE)
612 goto out; 609 goto out;
613 if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && 610
614 sp < READ_BIB_STACK_SIZE) 611 if ((key >> 30) != 3 || (rom[i] >> 30) < 2 ||
615 stack[sp++] = i + rom[i]; 612 sp >= READ_BIB_STACK_SIZE)
616 i++; 613 continue;
614 /*
615 * Offset points outside the ROM. May be a firmware
616 * bug or an Extended ROM entry (IEEE 1212-2001 clause
617 * 7.7.18). Simply overwrite this pointer here by a
618 * fake immediate entry so that later iterators over
619 * the ROM don't have to check offsets all the time.
620 */
621 if (i + (rom[i] & 0xffffff) >= READ_BIB_ROM_SIZE) {
622 fw_error("skipped unsupported ROM entry %x at %llx\n",
623 rom[i],
624 i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM);
625 rom[i] = 0;
626 continue;
627 }
628 stack[sp++] = i + rom[i];
617 } 629 }
618 if (length < i) 630 if (length < i)
619 length = i; 631 length = i;