summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Stefan Richter 2010-08-05 11:50:32 +0200
committerGravatar Stefan Richter 2010-09-07 11:27:01 +0200
commitd3ace3dfb4a14aea275fda605d2856e307afddc1 (patch)
tree1bc4c6201d904fc618dbca6a1c3b151dfebf8d29 /src
parentRename a few kernel ABI testing helpers (diff)
Fix FCP and ARM source node ID on firewire-core
The firewire-core (juju) backend of libraw1394 installs address range mappings on the default ioctl fd, i.e. a file that represents a random device on the chosen port. It receives incoming requests from any sender node via this address range mapping. Due to a kernel ABI limitation, the sender node ID is not known though. So far libraw1394 simply assumed the node ID of the device that provided the default ioctl fd. This only works if there is only one accessible fd on the entire bus. This limitation caused for example libffado to fail to work with another AV/C or IIDC device attached to the bus, because node IDs of FCP requests and FCP responses did not match since the latter were wrong. FCP clients which did not check sender node IDs were seemingly not affected by this bug. The bug is fixed by a kernel ABI extension in Linux 2.6.36. This libraw1394 change implements libraw1394's counterpart to this ABI extension. Hence this libraw1394 fix requires - kernel-headers 2.6.36 or later at build time of libraw1394 - kernel 2.6.36 or later at runtime. Otherwise, libraw1394 simply degrades to the faulty previous behaviour. Side note: The change of IMPLEMENTED_CDEV_ABI_VERSION to 4 requires that we fill in struct fw_cdev_allocate.region_end which was added in the ABI v4. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'src')
-rw-r--r--src/fw.c117
1 files changed, 75 insertions, 42 deletions
diff --git a/src/fw.c b/src/fw.c
index 5f5bc69..e5c23d1 100644
--- a/src/fw.c
+++ b/src/fw.c
@@ -28,7 +28,11 @@
/*
* ABI version history is documented in linux/firewire-cdev.h.
*/
+#ifdef FW_CDEV_EVENT_REQUEST2
+#define IMPLEMENTED_CDEV_ABI_VERSION 4
+#else
#define IMPLEMENTED_CDEV_ABI_VERSION 2
+#endif
int
fw_errcode_to_errno(raw1394_errcode_t errcode)
@@ -215,41 +219,41 @@ handle_lost_device(fw_handle_t handle, int i)
struct address_closure {
int (*callback)(raw1394handle_t handle, struct address_closure *ac,
- struct fw_cdev_event_request *request, int i);
+ int tcode, unsigned long long offset,
+ int source_node_id, unsigned kernel_handle,
+ size_t length, void *data);
};
static int
handle_fcp_request(raw1394handle_t handle, struct address_closure *ac,
- struct fw_cdev_event_request *request, int i)
+ int tcode, unsigned long long offset, int source_node_id,
+ unsigned kernel_handle, size_t length, void *data)
{
struct fw_cdev_send_response response;
int is_response;
- response.handle = request->handle;
- response.rcode = RCODE_COMPLETE;
- response.length = 0;
- response.data = 0;
+ response.handle = kernel_handle;
+ response.rcode = RCODE_COMPLETE;
+ response.length = 0;
+ response.data = 0;
if (handle->mode.fw->fcp_handler == NULL)
response.rcode = RCODE_ADDRESS_ERROR;
- if (request->tcode >= TCODE_WRITE_RESPONSE)
+ if (tcode >= TCODE_WRITE_RESPONSE)
response.rcode = RCODE_CONFLICT_ERROR;
- if (ioctl(handle->mode.fw->devices[i].fd,
+ if (ioctl(handle->mode.fw->ioctl_fd,
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
return -1;
if (response.rcode != RCODE_COMPLETE)
return 0;
- is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
+ is_response = offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
- return handle->mode.fw->fcp_handler(handle,
- handle->mode.fw->devices[i].node_id,
- is_response,
- request->length,
- (unsigned char *) request->data);
+ return handle->mode.fw->fcp_handler(handle, source_node_id,
+ is_response, length, data);
}
static int
@@ -307,7 +311,22 @@ handle_device_event(raw1394handle_t handle,
case FW_CDEV_EVENT_REQUEST:
ac = u64_to_ptr(u->request.closure);
- return ac->callback(handle, ac, &u->request, i);
+ return ac->callback(handle, ac, u->request.tcode,
+ u->request.offset,
+ /* wild guess, but can't do better */
+ fwhandle->devices[i].node_id,
+ u->request.handle,
+ u->request.length, u->request.data);
+
+#ifdef FW_CDEV_EVENT_REQUEST2 /* added in kernel 2.6.36 */
+ case FW_CDEV_EVENT_REQUEST2:
+ ac = u64_to_ptr(u->request.closure);
+ return ac->callback(handle, ac, u->request2.tcode,
+ u->request2.offset,
+ u->request2.source_node_id,
+ u->request2.handle,
+ u->request2.length, u->request2.data);
+#endif
#ifdef FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED /* added in kernel 2.6.30 */
case FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED:
@@ -695,7 +714,7 @@ struct request_response_block {
};
struct allocation {
- struct address_closure closure;
+ struct address_closure closure; /* must be first member */
struct allocation *next;
__u32 handle;
byte_t *buffer;
@@ -710,7 +729,8 @@ struct allocation {
static int
handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
- struct fw_cdev_event_request *request, int i)
+ int tcode, unsigned long long offset, int source_node_id,
+ unsigned kernel_handle, size_t length, void *data)
{
fw_handle_t fwhandle = handle->mode.fw;
struct allocation *allocation = (struct allocation *) ac;
@@ -718,19 +738,19 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
struct fw_cdev_send_response response;
arm_options_t type;
size_t in_length;
- int offset;
+ int pos;
- offset = request->offset - allocation->offset;
- response.handle = request->handle;
+ pos = offset - allocation->offset;
+ response.handle = kernel_handle;
- switch (request->tcode) {
+ switch (tcode) {
case TCODE_WRITE_QUADLET_REQUEST:
case TCODE_WRITE_BLOCK_REQUEST:
printf("got write request, offset=0x%012llx, length=%d\n",
- request->offset, request->length);
+ offset, (int)length);
type = RAW1394_ARM_WRITE;
- in_length = request->length;
+ in_length = length;
response.rcode = RCODE_COMPLETE;
response.length = 0;
response.data = 0;
@@ -739,18 +759,29 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
case TCODE_READ_QUADLET_REQUEST:
case TCODE_READ_BLOCK_REQUEST:
printf("got read request, offset=0x%012llx, length=%d\n",
- request->offset, request->length);
+ offset, (int)length);
type = RAW1394_ARM_READ;
in_length = 0;
response.rcode = RCODE_COMPLETE;
- response.length = request->length;
- response.data = ptr_to_u64(allocation->data + offset);
+ response.length = length;
+ response.data = ptr_to_u64(allocation->data + pos);
break;
case TCODE_LOCK_REQUEST:
+ /*
+ * TCODE_LOCK_REQUEST is generated by ABI v3 and older, cannot
+ * be handled. Fall through for now. FIXME.
+ */
+ case TCODE_LOCK_MASK_SWAP:
+ case TCODE_LOCK_COMPARE_SWAP:
+ case TCODE_LOCK_FETCH_ADD:
+ case TCODE_LOCK_LITTLE_ADD:
+ case TCODE_LOCK_BOUNDED_ADD:
+ case TCODE_LOCK_WRAP_ADD:
+ case TCODE_LOCK_VENDOR_DEPENDENT:
type = RAW1394_ARM_LOCK;
- in_length = request->length;
+ in_length = length;
response.length = 4;
break;
@@ -764,17 +795,16 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
response.rcode = RCODE_TYPE_ERROR;
response.length = 0;
response.data = 0;
- if (ioctl(fwhandle->devices[i].fd,
+ if (ioctl(fwhandle->ioctl_fd,
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
return -1;
} else if (!(allocation->client_transactions & type)) {
if (type == RAW1394_ARM_WRITE)
- memcpy(allocation->data + offset,
- request->data, request->length);
+ memcpy(allocation->data + pos, data, length);
else if (type == RAW1394_ARM_LOCK)
/* FIXME: do lock ops here */;
- if (ioctl(fwhandle->devices[i].fd,
+ if (ioctl(fwhandle->ioctl_fd,
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
return -1;
}
@@ -792,30 +822,28 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
rrb->request_response.response = &rrb->response;
rrb->request.destination_nodeid = fwhandle->reset.local_node_id;
- rrb->request.source_nodeid = fwhandle->devices[i].node_id;
- rrb->request.destination_offset = request->offset;
+ rrb->request.source_nodeid = source_node_id;
+ rrb->request.destination_offset = offset;
rrb->request.tlabel = 0;
- if (request->tcode < 0x10) {
- rrb->request.tcode = request->tcode;
+ if (tcode < 0x10) {
+ rrb->request.tcode = tcode;
rrb->request.extended_transaction_code = 0;
} else {
rrb->request.tcode = TCODE_LOCK_REQUEST;
- rrb->request.extended_transaction_code = request->tcode - 0x10;
+ rrb->request.extended_transaction_code = tcode - 0x10;
}
rrb->request.generation = fwhandle->reset.generation;
rrb->request.buffer_length = in_length;
rrb->request.buffer = rrb->data;
- memcpy(rrb->request.buffer, request->data, in_length);
+ memcpy(rrb->request.buffer, data, in_length);
rrb->response.response_code = response.rcode;
rrb->response.buffer_length = response.length;
rrb->response.buffer = rrb->data + in_length;
- memcpy(rrb->response.buffer,
- allocation->data + offset, response.length);
+ memcpy(rrb->response.buffer, allocation->data + pos, response.length);
return fwhandle->arm_tag_handler(handle, allocation->tag, type,
- request->length,
- &rrb->request_response);
+ length, &rrb->request_response);
}
int
@@ -849,7 +877,9 @@ fw_arm_register(fw_handle_t handle, nodeaddr_t start,
request.offset = start;
request.length = length;
request.closure = ptr_to_u64(&allocation->closure);
-
+#if IMPLEMENTED_CDEV_ABI_VERSION >= 4
+ request.region_end = start + length;
+#endif
retval = ioctl(handle->ioctl_fd, FW_CDEV_IOC_ALLOCATE, &request);
if (retval < 0) {
free(allocation);
@@ -1343,6 +1373,9 @@ fw_start_fcp_listen(fw_handle_t handle)
request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND;
request.length = CSR_FCP_END - CSR_FCP_COMMAND;
request.closure = ptr_to_u64(closure);
+#if IMPLEMENTED_CDEV_ABI_VERSION >= 4
+ request.region_end = CSR_REGISTER_BASE + CSR_FCP_END;
+#endif
if (ioctl(handle->ioctl_fd, FW_CDEV_IOC_ALLOCATE, &request) < 0)
return -1;
-37/+125 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@103 53a565d1-3bb7-0310-b661-cf11e63c67ab 2003-01-15add iso_xmit_sync() and iso_xmit_write(); clean up iso handling a bitGravatar dmaas 5-39/+161 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@102 53a565d1-3bb7-0310-b661-cf11e63c67ab 2003-01-15implement tag matching for rawiso receptionGravatar dmaas 3-4/+12 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@101 53a565d1-3bb7-0310-b661-cf11e63c67ab 2003-01-06back out previous commit - don't drop the legacy API just yetGravatar dmaas 6-173/+130 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@100 53a565d1-3bb7-0310-b661-cf11e63c67ab 2003-01-05emulate legacy ISO reception API on top of new rawiso APIGravatar dmaas 7-131/+174 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@99 53a565d1-3bb7-0310-b661-cf11e63c67ab 2002-12-24update iso API for multi-channel reception and new packet buffer layoutGravatar dmaas 4-123/+236 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@98 53a565d1-3bb7-0310-b661-cf11e63c67ab 2002-12-20oops, irq_interval needs to be signedGravatar anonymous 1-1/+1 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@97 53a565d1-3bb7-0310-b661-cf11e63c67ab 2002-12-20dmaas - renamed exported arm definitions into the raw1394_ namespace; ↵Gravatar anonymous 3-124/+48 brought kernel-raw1394.h back in sync with the kernel version git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@96 53a565d1-3bb7-0310-b661-cf11e63c67ab 2002-12-16rawiso updates:Gravatar dmaas 3-18/+25 - changed return type of rawiso xmit/recv handlers from int to enum raw1394_iso_disposition - added an ioctl (RAW1394_ISO_QUEUE_ACTIVITY) to force an ISO_ACTIVITY event into the queue. This is needed for handling RAW1394_ISO_DEFER, to kick us out of the next read() instead of sleeping forever. - removed references to "8-byte" isochronous header - this is an OHCI-specific implementation detail git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@95 53a565d1-3bb7-0310-b661-cf11e63c67ab 2002-11-18fix cplusplus extern C blockGravatar ddennedy 1-4/+4 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@94 53a565d1-3bb7-0310-b661-cf11e63c67ab 2002-11-18merged rawiso branchGravatar ddennedy 7-6/+488 git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@93 53a565d1-3bb7-0310-b661-cf11e63c67ab