firewire: Implement sync and tag matching for isochronous receive.
Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
Родитель
21efb3cfc6
Коммит
98b6cbe83b
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1574,6 +1576,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,
|
||||
struct fw_iso_packet *packet,
|
||||
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче