From: =?utf-8?q?Kristian_H=C3=B8gsberg?= Subject: [PATCH] firewire: Implement sync and tag matching for isochronous receive. Date: Fri, 16 Feb 2007 17:34:51 -0500 Signed-off-by: Kristian Høgsberg Signed-off-by: Stefan Richter Index: linux/drivers/firewire/fw-device-cdev.c =================================================================== --- linux.orig/drivers/firewire/fw-device-cdev.c +++ linux/drivers/firewire/fw-device-cdev.c @@ -416,6 +416,12 @@ static int ioctl_create_iso_context(stru 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(stru 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 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: linux/drivers/firewire/fw-device-cdev.h =================================================================== --- linux.orig/drivers/firewire/fw-device-cdev.h +++ linux/drivers/firewire/fw-device-cdev.h @@ -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: linux/drivers/firewire/fw-iso.c =================================================================== --- linux.orig/drivers/firewire/fw-iso.c +++ linux/drivers/firewire/fw-iso.c @@ -107,12 +107,14 @@ void fw_iso_buffer_destroy(struct fw_iso 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 *ca 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: linux/drivers/firewire/fw-ohci.c =================================================================== --- linux.orig/drivers/firewire/fw-ohci.c +++ linux/drivers/firewire/fw-ohci.c @@ -1337,7 +1337,8 @@ static int handle_it_packet(struct conte } 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_ 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_co 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 /* 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 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: linux/drivers/firewire/fw-transaction.h =================================================================== --- linux.orig/drivers/firewire/fw-transaction.h +++ linux/drivers/firewire/fw-transaction.h @@ -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_buff 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);