diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/core-device.c | 59 | ||||
-rw-r--r-- | drivers/firewire/device-attribute-test.c | 5 |
2 files changed, 49 insertions, 15 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 37fdf820acf1..2c8771305aca 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -49,6 +49,22 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value) } EXPORT_SYMBOL(fw_csr_iterator_next); +static const u32 *search_directory(const u32 *directory, int search_key) +{ + struct fw_csr_iterator ci; + int key, value; + + search_key |= CSR_DIRECTORY; + + fw_csr_iterator_init(&ci, directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + if (key == search_key) + return ci.p - 1 + value; + } + + return NULL; +} + static const u32 *search_leaf(const u32 *directory, int search_key) { struct fw_csr_iterator ci; @@ -253,27 +269,44 @@ static ssize_t show_immediate(struct device *dev, struct config_rom_attribute *attr = container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; - const u32 *dir; - int key, value, ret = -ENOENT; + const u32 *directories[] = {NULL, NULL}; + int i, value = -1; down_read(&fw_device_rwsem); - if (is_fw_unit(dev)) - dir = fw_unit(dev)->directory; - else - dir = fw_device(dev)->config_rom + ROOT_DIR_OFFSET; + if (is_fw_unit(dev)) { + directories[0] = fw_unit(dev)->directory; + } else { + const u32 *root_directory = fw_device(dev)->config_rom + ROOT_DIR_OFFSET; + const u32 *vendor_directory = search_directory(root_directory, CSR_VENDOR); - fw_csr_iterator_init(&ci, dir); - while (fw_csr_iterator_next(&ci, &key, &value)) - if (attr->key == key) { - ret = snprintf(buf, buf ? PAGE_SIZE : 0, - "0x%06x\n", value); - break; + if (!vendor_directory) { + directories[0] = root_directory; + } else { + // Legacy layout of configuration ROM described in Annex 1 of + // 'Configuration ROM for AV/C Devices 1.0 (December 12, 2000, 1394 Trading + // Association, TA Document 1999027)'. + directories[0] = vendor_directory; + directories[1] = root_directory; + } + } + + for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) { + int key, val; + + fw_csr_iterator_init(&ci, directories[i]); + while (fw_csr_iterator_next(&ci, &key, &val)) { + if (attr->key == key) + value = val; } + } up_read(&fw_device_rwsem); - return ret; + if (value < 0) + return -ENOENT; + + return snprintf(buf, buf ? PAGE_SIZE : 0, "0x%06x\n", value); } #define IMMEDIATE_ATTR(name, key) \ diff --git a/drivers/firewire/device-attribute-test.c b/drivers/firewire/device-attribute-test.c index 495af65c33b5..689115433425 100644 --- a/drivers/firewire/device-attribute-test.c +++ b/drivers/firewire/device-attribute-test.c @@ -199,8 +199,9 @@ static void device_attr_legacy_avc(struct kunit *test) KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[0].attr, buf), 0); KUNIT_EXPECT_STREQ(test, buf, "0x012345\n"); - // Model immediate entry is not found. - KUNIT_EXPECT_LT(test, show_immediate(node_dev, &config_rom_attributes[4].attr, buf), 0); + // Model immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[4].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0xfedcba\n"); // Descriptor leaf entry for vendor is not found. KUNIT_EXPECT_LT(test, show_text_leaf(node_dev, &config_rom_attributes[5].attr, buf), 0); |