firewire: Implement sync and tag matching for isochronous receive.
authorKristian Høgsberg <krh@redhat.com>
Fri, 16 Feb 2007 22:34:51 +0000 (17:34 -0500)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Fri, 9 Mar 2007 21:03:04 +0000 (22:03 +0100)
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/fw-device-cdev.c
drivers/firewire/fw-device-cdev.h
drivers/firewire/fw-iso.c
drivers/firewire/fw-ohci.c
drivers/firewire/fw-transaction.h

index 5c876188677f99136b2d0de70d868a56571e5544..33fe5768a078a1b40962858b01d247ebb2c5b979 100644 (file)
@@ -416,6 +416,12 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg)
        if (request.channel > 63)
                return -EINVAL;
 
+       if (request.sync > 15)
+               return -EINVAL;
+
+       if (request.tags == 0 || request.tags > 15)
+               return -EINVAL;
+
        if (request.speed > SCODE_3200)
                return -EINVAL;
 
@@ -424,6 +430,8 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg)
                                                    request.channel,
                                                    request.speed,
                                                    request.header_size,
+                                                   request.sync,
+                                                   request.tags,
                                                    iso_callback, client);
        if (IS_ERR(client->iso_context))
                return PTR_ERR(client->iso_context);
@@ -495,7 +503,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg)
                if (__copy_from_user
                    (u.packet.header, p->header, header_length))
                        return -EFAULT;
-               if (u.packet.skip &&
+               if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT &&
                    u.packet.header_length + u.packet.payload_length > 0)
                        return -EINVAL;
                if (payload + u.packet.payload_length > payload_end)
index 99e6aa629f4acf62636c5a23b0c12bf26272dbd6..739f54fe08cf5b885b24e22db03958026428befa 100644 (file)
@@ -131,11 +131,19 @@ struct fw_cdev_allocate {
 #define FW_CDEV_ISO_CONTEXT_TRANSMIT   0
 #define FW_CDEV_ISO_CONTEXT_RECEIVE    1
 
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG0          1
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG1          2
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG2          4
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG3          8
+#define FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS     15
+
 struct fw_cdev_create_iso_context {
        __u32 type;
        __u32 header_size;
        __u32 channel;
        __u32 speed;
+       __u32 sync;
+       __u32 tags;
 };
 
 struct fw_cdev_iso_packet {
index dc5a7e3558ec3c817e25e80dfe82fbc0179ef373..728cbb3ee91db11377ac09b5eaea4c6cc234c06d 100644 (file)
@@ -107,12 +107,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
 
 struct fw_iso_context *
 fw_iso_context_create(struct fw_card *card, int type,
-                     int channel, int speed, size_t header_size,
+                     int channel, int speed,
+                     int sync, int tags, size_t header_size,
                      fw_iso_callback_t callback, void *callback_data)
 {
        struct fw_iso_context *ctx;
 
-       ctx = card->driver->allocate_iso_context(card, type, header_size);
+       ctx = card->driver->allocate_iso_context(card, type,
+                                                sync, tags, header_size);
        if (IS_ERR(ctx))
                return ctx;
 
@@ -120,6 +122,8 @@ fw_iso_context_create(struct fw_card *card, int type,
        ctx->type = type;
        ctx->channel = channel;
        ctx->speed = speed;
+       ctx->sync = sync;
+       ctx->tags = tags;
        ctx->header_size = header_size;
        ctx->callback = callback;
        ctx->callback_data = callback_data;
index 0088acd7718e291160fdf9aedbd83bcf9b3ac188..ea43a5ed18cf9ad224932ef68dfa7174979ef9d2 100644 (file)
@@ -1337,7 +1337,8 @@ static int handle_it_packet(struct context *context,
 }
 
 static struct fw_iso_context *
-ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
+ohci_allocate_iso_context(struct fw_card *card, int type,
+                         int sync, int tags, size_t header_size)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        struct iso_context *ctx, *list;
@@ -1427,7 +1428,8 @@ static int ohci_start_iso(struct fw_iso_context *base, s32 cycle)
                reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index);
                reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
                reg_write(ohci, context_match(ctx->context.regs),
-                         0xf0000000 | ctx->base.channel);
+                         (ctx->base.tags << 28) |
+                         (ctx->base.sync << 8) | ctx->base.channel);
                context_run(&ctx->context, mode);
        }
 
@@ -1573,6 +1575,26 @@ ohci_queue_iso_transmit(struct fw_iso_context *base,
 
        return 0;
 }
+static int
+setup_wait_descriptor(struct context *ctx)
+{
+       struct descriptor *d;
+       dma_addr_t d_bus;
+
+       d = context_get_descriptors(ctx, 1, &d_bus);
+       if (d == NULL)
+               return -ENOMEM;
+
+       d->control = cpu_to_le16(descriptor_input_more |
+                                descriptor_status |
+                                descriptor_branch_always |
+                                descriptor_wait);
+
+       context_append(ctx, d, 1, 0);
+
+       return 0;
+}
 
 static int
 ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
@@ -1591,6 +1613,9 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
        /* FIXME: Cycle lost behavior should be configurable: lose
         * packet, retransmit or terminate.. */
 
+       if (packet->skip && setup_wait_descriptor(&ctx->context) < 0)
+               return -ENOMEM;
+
        p = packet;
        z = 2;
 
@@ -1655,6 +1680,9 @@ ohci_queue_iso_receive_bufferfill(struct fw_iso_context *base,
        offset = payload & ~PAGE_MASK;
        rest   = packet->payload_length;
 
+       if (packet->skip && setup_wait_descriptor(&ctx->context) < 0)
+               return -ENOMEM;
+
        while (rest > 0) {
                d = context_get_descriptors(&ctx->context, 1, &d_bus);
                if (d == NULL)
index 22e45ccd7b1dc38304491f14fafc023882dff538..cbea845dc40a7e9295fbcb6c4395893092df04e9 100644 (file)
@@ -332,6 +332,12 @@ struct fw_iso_packet {
 #define FW_ISO_CONTEXT_TRANSMIT        0
 #define FW_ISO_CONTEXT_RECEIVE 1
 
+#define FW_ISO_CONTEXT_MATCH_TAG0       1
+#define FW_ISO_CONTEXT_MATCH_TAG1       2
+#define FW_ISO_CONTEXT_MATCH_TAG2       4
+#define FW_ISO_CONTEXT_MATCH_TAG3       8
+#define FW_ISO_CONTEXT_MATCH_ALL_TAGS  15
+
 struct fw_iso_context;
 
 typedef void (*fw_iso_callback_t) (struct fw_iso_context *context,
@@ -357,6 +363,8 @@ struct fw_iso_context {
        int type;
        int channel;
        int speed;
+       int sync;
+       int tags;
        size_t header_size;
        fw_iso_callback_t callback;
        void *callback_data;
@@ -374,7 +382,8 @@ fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
 
 struct fw_iso_context *
 fw_iso_context_create(struct fw_card *card, int type,
-                     int channel, int speed, size_t header_size,
+                     int channel, int speed,
+                     int sync, int tags, size_t header_size,
                      fw_iso_callback_t callback, void *callback_data);
 
 void
@@ -425,7 +434,7 @@ struct fw_card_driver {
                                int node_id, int generation);
 
        struct fw_iso_context *
-       (*allocate_iso_context)(struct fw_card *card,
+       (*allocate_iso_context)(struct fw_card *card, int sync, int tags,
                                int type, size_t header_size);
        void (*free_iso_context)(struct fw_iso_context *ctx);