}
static void
-iso_callback(struct fw_iso_context *context, int status, u32 cycle, void *data)
+iso_callback(struct fw_iso_context *context, u32 cycle,
+ size_t header_length, void *header, void *data)
{
struct client *client = data;
struct iso_interrupt *interrupt;
- interrupt = kzalloc(sizeof *interrupt, GFP_ATOMIC);
+ interrupt = kzalloc(sizeof *interrupt + header_length, GFP_ATOMIC);
if (interrupt == NULL)
return;
interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
interrupt->interrupt.closure = 0;
interrupt->interrupt.cycle = cycle;
+ interrupt->interrupt.header_length = header_length;
+ memcpy(interrupt->interrupt.header, header, header_length);
queue_event(client, &interrupt->event,
- &interrupt->interrupt, sizeof interrupt->interrupt, NULL, 0);
+ &interrupt->interrupt,
+ sizeof interrupt->interrupt + header_length, NULL, 0);
}
static int ioctl_create_iso_context(struct client *client, void __user *arg)
{
struct fw_cdev_queue_iso request;
struct fw_cdev_iso_packet __user *p, *end, *next;
+ struct fw_iso_context *ctx = client->iso_context;
unsigned long payload, payload_end, header_length;
int count;
struct {
u8 header[256];
} u;
- if (client->iso_context == NULL)
+ if (ctx == NULL)
return -EINVAL;
if (copy_from_user(&request, arg, sizeof request))
return -EFAULT;
if (__copy_from_user(&u.packet, p, sizeof *p))
return -EFAULT;
- if (client->iso_context->type == FW_ISO_CONTEXT_TRANSMIT) {
+ if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
header_length = u.packet.header_length;
} else {
/* We require that header_length is a multiple of
* the fixed header size, ctx->header_size */
- if (u.packet.header_length % client->iso_context->header_size != 0)
+ if (ctx->header_size == 0) {
+ if (u.packet.header_length > 0)
+ return -EINVAL;
+ } else if (u.packet.header_length % ctx->header_size != 0) {
return -EINVAL;
+ }
header_length = 0;
}
if (payload + u.packet.payload_length > payload_end)
return -EINVAL;
- if (fw_iso_context_queue(client->iso_context,
- &u.packet, &client->buffer, payload))
+ if (fw_iso_context_queue(ctx, &u.packet,
+ &client->buffer, payload))
break;
p = next;
struct iso_context {
struct fw_iso_context base;
struct context context;
+ void *header;
+ size_t header_length;
};
#define CONFIG_ROM_SIZE 1024
return 0;
}
- static void
+static void
context_release(struct context *ctx)
{
struct fw_card *card = &ctx->ohci->card;
struct iso_context *ctx =
container_of(context, struct iso_context, context);
struct db_descriptor *db = (struct db_descriptor *) d;
+ size_t header_length;
if (db->first_res_count > 0 && db->second_res_count > 0)
/* This descriptor isn't done yet, stop iteration. */
return 0;
- if (le16_to_cpu(db->control) & descriptor_irq_always)
- /* FIXME: we should pass payload address here. */
- ctx->base.callback(&ctx->base,
- 0, 0,
+ header_length = db->first_req_count - db->first_res_count;
+ if (ctx->header_length + header_length <= PAGE_SIZE)
+ memcpy(ctx->header + ctx->header_length, db + 1, header_length);
+ ctx->header_length += header_length;
+
+ if (le16_to_cpu(db->control) & descriptor_irq_always) {
+ ctx->base.callback(&ctx->base, 0,
+ ctx->header_length, ctx->header,
ctx->base.callback_data);
+ ctx->header_length = 0;
+ }
return 1;
}
return 0;
if (le16_to_cpu(last->control) & descriptor_irq_always)
- ctx->base.callback(&ctx->base,
- 0, le16_to_cpu(last->res_count),
- ctx->base.callback_data);
+ ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
+ 0, NULL, ctx->base.callback_data);
return 1;
}
descriptor_callback_t callback;
u32 *mask, regs;
unsigned long flags;
- int index, retval;
+ int index, retval = -ENOMEM;
if (type == FW_ISO_CONTEXT_TRANSMIT) {
mask = &ohci->it_context_mask;
ctx = &list[index];
memset(ctx, 0, sizeof *ctx);
+ ctx->header_length = 0;
+ ctx->header = (void *) __get_free_page(GFP_KERNEL);
+ if (ctx->header == NULL)
+ goto out;
+
retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE,
regs, callback);
- if (retval < 0) {
- spin_lock_irqsave(&ohci->lock, flags);
- *mask |= 1 << index;
- spin_unlock_irqrestore(&ohci->lock, flags);
- return ERR_PTR(retval);
- }
+ if (retval < 0)
+ goto out_with_header;
return &ctx->base;
+
+ out_with_header:
+ free_page((unsigned long)ctx->header);
+ out:
+ spin_lock_irqsave(&ohci->lock, flags);
+ *mask |= 1 << index;
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ return ERR_PTR(retval);
}
static int ohci_start_iso(struct fw_iso_context *base, s32 cycle)
ohci_stop_iso(base);
context_release(&ctx->context);
+ free_page((unsigned long)ctx->header);
spin_lock_irqsave(&ohci->lock, flags);