Commit 98b6cbe8 authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Stefan Richter

firewire: Implement sync and tag matching for isochronous receive.

Signed-off-by: default avatarKristian Høgsberg <krh@redhat.com>
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 21efb3cf
...@@ -416,6 +416,12 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) ...@@ -416,6 +416,12 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg)
if (request.channel > 63) if (request.channel > 63)
return -EINVAL; return -EINVAL;
if (request.sync > 15)
return -EINVAL;
if (request.tags == 0 || request.tags > 15)
return -EINVAL;
if (request.speed > SCODE_3200) if (request.speed > SCODE_3200)
return -EINVAL; return -EINVAL;
...@@ -424,6 +430,8 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) ...@@ -424,6 +430,8 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg)
request.channel, request.channel,
request.speed, request.speed,
request.header_size, request.header_size,
request.sync,
request.tags,
iso_callback, client); iso_callback, client);
if (IS_ERR(client->iso_context)) if (IS_ERR(client->iso_context))
return PTR_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) ...@@ -495,7 +503,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg)
if (__copy_from_user if (__copy_from_user
(u.packet.header, p->header, header_length)) (u.packet.header, p->header, header_length))
return -EFAULT; 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) u.packet.header_length + u.packet.payload_length > 0)
return -EINVAL; return -EINVAL;
if (payload + u.packet.payload_length > payload_end) if (payload + u.packet.payload_length > payload_end)
......
...@@ -131,11 +131,19 @@ struct fw_cdev_allocate { ...@@ -131,11 +131,19 @@ struct fw_cdev_allocate {
#define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0
#define FW_CDEV_ISO_CONTEXT_RECEIVE 1 #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 { struct fw_cdev_create_iso_context {
__u32 type; __u32 type;
__u32 header_size; __u32 header_size;
__u32 channel; __u32 channel;
__u32 speed; __u32 speed;
__u32 sync;
__u32 tags;
}; };
struct fw_cdev_iso_packet { struct fw_cdev_iso_packet {
......
...@@ -107,12 +107,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, ...@@ -107,12 +107,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
struct fw_iso_context * struct fw_iso_context *
fw_iso_context_create(struct fw_card *card, int type, 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) fw_iso_callback_t callback, void *callback_data)
{ {
struct fw_iso_context *ctx; 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)) if (IS_ERR(ctx))
return ctx; return ctx;
...@@ -120,6 +122,8 @@ fw_iso_context_create(struct fw_card *card, int type, ...@@ -120,6 +122,8 @@ fw_iso_context_create(struct fw_card *card, int type,
ctx->type = type; ctx->type = type;
ctx->channel = channel; ctx->channel = channel;
ctx->speed = speed; ctx->speed = speed;
ctx->sync = sync;
ctx->tags = tags;
ctx->header_size = header_size; ctx->header_size = header_size;
ctx->callback = callback; ctx->callback = callback;
ctx->callback_data = callback_data; ctx->callback_data = callback_data;
......
...@@ -1337,7 +1337,8 @@ static int handle_it_packet(struct context *context, ...@@ -1337,7 +1337,8 @@ static int handle_it_packet(struct context *context,
} }
static struct fw_iso_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 fw_ohci *ohci = fw_ohci(card);
struct iso_context *ctx, *list; struct iso_context *ctx, *list;
...@@ -1427,7 +1428,8 @@ static int ohci_start_iso(struct fw_iso_context *base, s32 cycle) ...@@ -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_IsoRecvIntEventClear, 1 << index);
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
reg_write(ohci, context_match(ctx->context.regs), 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); context_run(&ctx->context, mode);
} }
...@@ -1574,6 +1576,26 @@ ohci_queue_iso_transmit(struct fw_iso_context *base, ...@@ -1574,6 +1576,26 @@ ohci_queue_iso_transmit(struct fw_iso_context *base,
return 0; 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 static int
ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
struct fw_iso_packet *packet, struct fw_iso_packet *packet,
...@@ -1591,6 +1613,9 @@ 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 /* FIXME: Cycle lost behavior should be configurable: lose
* packet, retransmit or terminate.. */ * packet, retransmit or terminate.. */
if (packet->skip && setup_wait_descriptor(&ctx->context) < 0)
return -ENOMEM;
p = packet; p = packet;
z = 2; z = 2;
...@@ -1655,6 +1680,9 @@ ohci_queue_iso_receive_bufferfill(struct fw_iso_context *base, ...@@ -1655,6 +1680,9 @@ ohci_queue_iso_receive_bufferfill(struct fw_iso_context *base,
offset = payload & ~PAGE_MASK; offset = payload & ~PAGE_MASK;
rest = packet->payload_length; rest = packet->payload_length;
if (packet->skip && setup_wait_descriptor(&ctx->context) < 0)
return -ENOMEM;
while (rest > 0) { while (rest > 0) {
d = context_get_descriptors(&ctx->context, 1, &d_bus); d = context_get_descriptors(&ctx->context, 1, &d_bus);
if (d == NULL) if (d == NULL)
......
...@@ -332,6 +332,12 @@ struct fw_iso_packet { ...@@ -332,6 +332,12 @@ struct fw_iso_packet {
#define FW_ISO_CONTEXT_TRANSMIT 0 #define FW_ISO_CONTEXT_TRANSMIT 0
#define FW_ISO_CONTEXT_RECEIVE 1 #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; struct fw_iso_context;
typedef void (*fw_iso_callback_t) (struct fw_iso_context *context, typedef void (*fw_iso_callback_t) (struct fw_iso_context *context,
...@@ -357,6 +363,8 @@ struct fw_iso_context { ...@@ -357,6 +363,8 @@ struct fw_iso_context {
int type; int type;
int channel; int channel;
int speed; int speed;
int sync;
int tags;
size_t header_size; size_t header_size;
fw_iso_callback_t callback; fw_iso_callback_t callback;
void *callback_data; void *callback_data;
...@@ -374,7 +382,8 @@ fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card); ...@@ -374,7 +382,8 @@ fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
struct fw_iso_context * struct fw_iso_context *
fw_iso_context_create(struct fw_card *card, int type, 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); fw_iso_callback_t callback, void *callback_data);
void void
...@@ -425,7 +434,7 @@ struct fw_card_driver { ...@@ -425,7 +434,7 @@ struct fw_card_driver {
int node_id, int generation); int node_id, int generation);
struct fw_iso_context * 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); int type, size_t header_size);
void (*free_iso_context)(struct fw_iso_context *ctx); void (*free_iso_context)(struct fw_iso_context *ctx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment