aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2011-08-13 17:08:29 +0200
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-08-21 20:25:50 +0200
commitdb5f202d5d050cb78bb6696f7ec56954da3a8a6c (patch)
treed6d201637fcb088cb151cb7a310ee1d900daf58a
parent52099f7148149c80f59979da2d274004c9a2b148 (diff)
downloadlibraw1394-db5f202d5d050cb78bb6696f7ec56954da3a8a6c.tar.gz
redirect Config ROM reads into the kernel's ROM cache
The kernel already read each node's Configuration ROM and cached it. So let all libraw1394 clients read from that cache instead of having to perform all those transactions all over again. This reduces bus traffic at application start-up and at each bus reset. It also makes all Configuration ROM accesses fool-proof and robust. This together with the kernel patch "firewire: core: handle ack_busy when fetching the Config ROM" lets me use an old Panasonic camcorder which requires us to keep pauses between response and request --- longer than librom1394's retry pause --- with dvgrab (though still with frequent failures of write requests to FCP_COMMAND, i.e. with lots of "send oops" noise in the console and occasionally having to repeat key-presses in interactive mode). For simplicity of implementation, only the blocking raw1394_read() is modified, not the nonblocking raw1394_start_read(). Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Dan Dennedy <dan@dennedy.org>
-rw-r--r--src/fw.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/fw.c b/src/fw.c
index baa3e93..fc51e2f 100644
--- a/src/fw.c
+++ b/src/fw.c
@@ -1310,11 +1310,63 @@ send_request_sync(raw1394handle_t handle, int tcode,
}
int
+read_config_rom(fw_handle_t handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *buffer)
+{
+ struct fw_cdev_get_info get_info;
+ quadlet_t rom[256];
+ int offset, fd, i, err;
+
+ if (node > handle->reset.root_node_id) {
+ handle->err = -RCODE_NO_ACK;
+ errno = fw_errcode_to_errno(handle->err);
+ return -1;
+ }
+
+ i = handle->nodes[node & 0x3f];
+ if (i == -1) {
+ handle->err = -RCODE_NO_ACK;
+ errno = fw_errcode_to_errno(handle->err);
+ return -1;
+ }
+
+ if (handle->generation != handle->devices[i].generation) {
+ handle->err = -RCODE_GENERATION;
+ errno = fw_errcode_to_errno(handle->err);
+ return -1;
+ }
+ fd = handle->devices[i].fd;
+
+ memset(&get_info, 0, sizeof(get_info));
+ memset(&rom, 0, sizeof(rom));
+ get_info.version = IMPLEMENTED_CDEV_ABI_VERSION;
+ get_info.rom = ptr_to_u64(rom);
+ get_info.rom_length = sizeof(rom);
+ get_info.bus_reset = 0;
+
+ err = ioctl(fd, FW_CDEV_IOC_GET_INFO, &get_info);
+ if (err)
+ return err;
+
+ offset = (addr - CSR_REGISTER_BASE - CSR_CONFIG_ROM) / 4;
+ for (i = 0; i < length / 4; i++)
+ buffer[i] = cpu_to_be32(rom[offset + i]);
+
+ return 0;
+}
+
+int
fw_read(raw1394handle_t handle, nodeid_t node, nodeaddr_t addr,
size_t length, quadlet_t *buffer)
{
int tcode;
+ if (addr >= CSR_REGISTER_BASE + CSR_CONFIG_ROM &&
+ addr + length <= CSR_REGISTER_BASE + CSR_CONFIG_ROM_END &&
+ !(addr & 3) && length > 0 && !(length & 3))
+ return read_config_rom(handle->mode.fw,
+ node, addr, length, buffer);
+
if (length == 4)
tcode = TCODE_READ_QUADLET_REQUEST;
else