firewire: cdev: add ioctl for broadcast write requests
authorJay Fenlason, Stefan Richter <stefanr@s5r6.in-berlin.de>
Sun, 4 Jan 2009 15:23:29 +0000 (16:23 +0100)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Tue, 24 Mar 2009 19:56:44 +0000 (20:56 +0100)
Write transactions to the broadcast node ID are a convenient way to
trigger functions of multiple nodes at once.  IIDC is a protocol which
can make use of this if multiple cameras with same command_regs_base are
connected at the same bus.

Based on
    Date: Wed, 10 Sep 2008 11:32:16 -0400
    From: Jay Fenlason <fenlason@redhat.com>
    Subject: [patch] SEND_BROADCAST_REQUEST
Changes:  ioctl_send_request() and ioctl_send_broadcast_request() now
share code.  Broadcast speed corrected to S100.  Check for proper tcode.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/fw-cdev.c
include/linux/firewire-cdev.h

index 05ad2a8..a1637a8 100644 (file)
@@ -518,10 +518,10 @@ static void complete_transaction(struct fw_card *card, int rcode,
        client_put(client);
 }
 
-static int ioctl_send_request(struct client *client, void *buffer)
+static int init_request(struct client *client,
+                       struct fw_cdev_send_request *request,
+                       int destination_id, int speed)
 {
-       struct fw_device *device = client->device;
-       struct fw_cdev_send_request *request = buffer;
        struct outbound_transaction_event *e;
        int ret;
 
@@ -544,24 +544,6 @@ static int ioctl_send_request(struct client *client, void *buffer)
                goto failed;
        }
 
-       switch (request->tcode) {
-       case TCODE_WRITE_QUADLET_REQUEST:
-       case TCODE_WRITE_BLOCK_REQUEST:
-       case TCODE_READ_QUADLET_REQUEST:
-       case TCODE_READ_BLOCK_REQUEST:
-       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:
-               break;
-       default:
-               ret = -EINVAL;
-               goto failed;
-       }
-
        e->r.resource.release = release_transaction;
        ret = add_client_resource(client, &e->r.resource, GFP_KERNEL);
        if (ret < 0)
@@ -570,12 +552,9 @@ static int ioctl_send_request(struct client *client, void *buffer)
        /* Get a reference for the transaction callback */
        client_get(client);
 
-       fw_send_request(device->card, &e->r.transaction,
-                       request->tcode & 0x1f,
-                       device->node->node_id,
-                       request->generation,
-                       device->max_speed,
-                       request->offset,
+       fw_send_request(client->device->card, &e->r.transaction,
+                       request->tcode & 0x1f, destination_id,
+                       request->generation, speed, request->offset,
                        e->response.data, request->length,
                        complete_transaction, e);
 
@@ -589,6 +568,31 @@ static int ioctl_send_request(struct client *client, void *buffer)
        return ret;
 }
 
+static int ioctl_send_request(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_request *request = buffer;
+
+       switch (request->tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+       case TCODE_READ_QUADLET_REQUEST:
+       case TCODE_READ_BLOCK_REQUEST:
+       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:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return init_request(client, request, client->device->node->node_id,
+                           client->device->max_speed);
+}
+
 static void release_request(struct client *client,
                            struct client_resource *resource)
 {
@@ -1229,6 +1233,21 @@ static int ioctl_get_speed(struct client *client, void *buffer)
        return 0;
 }
 
+static int ioctl_send_broadcast_request(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_request *request = buffer;
+
+       switch (request->tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100);
+}
+
 static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_get_info,
        ioctl_send_request,
@@ -1248,6 +1267,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
        ioctl_allocate_iso_resource_once,
        ioctl_deallocate_iso_resource_once,
        ioctl_get_speed,
+       ioctl_send_broadcast_request,
 };
 
 static int dispatch_ioctl(struct client *client,
index f819c10..340a785 100644 (file)
@@ -230,6 +230,7 @@ union fw_cdev_event {
 #define FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE   _IOW('#', 0x0f, struct fw_cdev_allocate_iso_resource)
 #define FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE _IOW('#', 0x10, struct fw_cdev_allocate_iso_resource)
 #define FW_CDEV_IOC_GET_SPEED                    _IOR('#', 0x11, struct fw_cdev_get_speed)
+#define FW_CDEV_IOC_SEND_BROADCAST_REQUEST       _IOW('#', 0x12, struct fw_cdev_send_request)
 
 /* FW_CDEV_VERSION History
  *