aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-06-20 16:53:55 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-06-20 17:11:56 -0400
commite205597d188a9ea69ce43f740a14f07b3f5b996a (patch)
tree9b894920db99c784c9abbe95269b972d0a1fc5c7 /drivers/firewire
parentc82f91f2663e79b150afd896ec72e798ba4e243d (diff)
firewire: cdev: fix ABI for FCP and address range mapping, add fw_cdev_event_request2
The problem: A target-like userspace driver, e.g. AV/C target or SBP-2/3 target, needs to be able to act as responder and requester. In the latter role, it needs to send requests to nods from which it received requests. This is currently impossible because fw_cdev_event_request lacks information about sender node ID. Reported-by: Jay Fenlason <fenlason@redhat.com> Libffado + libraw1394 + firewire-core is currently unable to drive two or more audio devices on the same bus. Reported-by: Arnold Krille <arnold@arnoldarts.de> This is because libffado requires destination node ID of FCP requests and sender node ID of FCP responses to match. It even prohibits libffado from working with a bus on which libraw1394 opens a /dev/fw* as default ioctl device that does not correspond with the audio device. This is because libraw1394 does not receive the sender node ID from the kernel. Moreover, fw_cdev_event_request makes it impossible to tell unicast and broadcast write requests apart. The fix: Add a replacement of struct fw_cdev_event_request request, boringly called struct fw_cdev_event_request2. The new event will be sent to a userspace client instead of the old one if the client claims compatibility with <linux/firewire-cdev.h> ABI version 4 or later. libraw1394 needs to be extended to make use of the new event, in order to properly support libffado and other FCP or address range mapping users who require correct sender node IDs. Further notes: While we are at it, change back the range of possible values of fw_cdev_event_request.tcode to 0x0...0xb like in ABI version <= 3. The preceding change "firewire: expose extended tcode of incoming lock requests to (userspace) drivers" expanded it to 0x0...0x17 which could catch sloppily coded clients by surprise. The extended range of codes is only used in the new fw_cdev_event_request2.tcode. Jay and I also suggested an alternative approach to fix the ABI for incoming requests: Add an FW_CDEV_IOC_GET_REQUEST_INFO ioctl which can be called after reception of an fw_cdev_event_request, before issuing of the closing FW_CDEV_IOC_SEND_RESPONSE ioctl. The new ioctl would reveal the vital information about a request that fw_cdev_event_request lacks. Jay showed an implementation of this approach. The former event approach adds 27 LOC of rather trivial code to core-cdev.c, the ioctl approach 34 LOC, some of which is nontrivial. The ioctl approach would certainly also add more LOC to userspace programs which require the expanded information on inbound requests. This approach is probably only on the lighter-weight side in case of clients that want to be compatible with kernels that lack the new capability, like libraw1394. However, the code to be added to such libraw1394-like clients in case of the event approach is a straight- forward additional switch () case in its event handler. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-cdev.c45
1 files changed, 36 insertions, 9 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 0cf86bcbeea2..9b8df2039155 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -49,7 +49,8 @@
49/* 49/*
50 * ABI version history is documented in linux/firewire-cdev.h. 50 * ABI version history is documented in linux/firewire-cdev.h.
51 */ 51 */
52#define FW_CDEV_KERNEL_VERSION 3 52#define FW_CDEV_KERNEL_VERSION 4
53#define FW_CDEV_VERSION_EVENT_REQUEST2 4
53 54
54struct client { 55struct client {
55 u32 version; 56 u32 version;
@@ -176,7 +177,10 @@ struct outbound_transaction_event {
176 177
177struct inbound_transaction_event { 178struct inbound_transaction_event {
178 struct event event; 179 struct event event;
179 struct fw_cdev_event_request request; 180 union {
181 struct fw_cdev_event_request request;
182 struct fw_cdev_event_request2 request2;
183 } req;
180}; 184};
181 185
182struct iso_interrupt_event { 186struct iso_interrupt_event {
@@ -645,6 +649,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
645 struct address_handler_resource *handler = callback_data; 649 struct address_handler_resource *handler = callback_data;
646 struct inbound_transaction_resource *r; 650 struct inbound_transaction_resource *r;
647 struct inbound_transaction_event *e; 651 struct inbound_transaction_event *e;
652 size_t event_size0;
648 void *fcp_frame = NULL; 653 void *fcp_frame = NULL;
649 int ret; 654 int ret;
650 655
@@ -678,15 +683,37 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
678 if (ret < 0) 683 if (ret < 0)
679 goto failed; 684 goto failed;
680 685
681 e->request.type = FW_CDEV_EVENT_REQUEST; 686 if (handler->client->version < FW_CDEV_VERSION_EVENT_REQUEST2) {
682 e->request.tcode = tcode; 687 struct fw_cdev_event_request *req = &e->req.request;
683 e->request.offset = offset; 688
684 e->request.length = length; 689 if (tcode & 0x10)
685 e->request.handle = r->resource.handle; 690 tcode = TCODE_LOCK_REQUEST;
686 e->request.closure = handler->closure; 691
692 req->type = FW_CDEV_EVENT_REQUEST;
693 req->tcode = tcode;
694 req->offset = offset;
695 req->length = length;
696 req->handle = r->resource.handle;
697 req->closure = handler->closure;
698 event_size0 = sizeof(*req);
699 } else {
700 struct fw_cdev_event_request2 *req = &e->req.request2;
701
702 req->type = FW_CDEV_EVENT_REQUEST2;
703 req->tcode = tcode;
704 req->offset = offset;
705 req->source_node_id = source;
706 req->destination_node_id = destination;
707 req->card = card->index;
708 req->generation = generation;
709 req->length = length;
710 req->handle = r->resource.handle;
711 req->closure = handler->closure;
712 event_size0 = sizeof(*req);
713 }
687 714
688 queue_event(handler->client, &e->event, 715 queue_event(handler->client, &e->event,
689 &e->request, sizeof(e->request), r->data, length); 716 &e->req, event_size0, r->data, length);
690 return; 717 return;
691 718
692 failed: 719 failed: