diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c index 5c876188677f99136b2d0de70d868a56571e5544..33fe5768a078a1b40962858b01d247ebb2c5b979 100644 --- a/drivers/firewire/fw-device-cdev.c +++ b/drivers/firewire/fw-device-cdev.c @@ -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) diff --git a/drivers/firewire/fw-device-cdev.h b/drivers/firewire/fw-device-cdev.h index 99e6aa629f4acf62636c5a23b0c12bf26272dbd6..739f54fe08cf5b885b24e22db03958026428befa 100644 --- a/drivers/firewire/fw-device-cdev.h +++ b/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 { diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c index dc5a7e3558ec3c817e25e80dfe82fbc0179ef373..728cbb3ee91db11377ac09b5eaea4c6cc234c06d 100644 --- a/drivers/firewire/fw-iso.c +++ b/drivers/firewire/fw-iso.c @@ -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; diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 0088acd7718e291160fdf9aedbd83bcf9b3ac188..ea43a5ed18cf9ad224932ef68dfa7174979ef9d2 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -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) diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 22e45ccd7b1dc38304491f14fafc023882dff538..cbea845dc40a7e9295fbcb6c4395893092df04e9 100644 --- a/drivers/firewire/fw-transaction.h +++ b/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_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);