Loading drivers/firewire/fw-device-cdev.c +19 −4 Original line number Diff line number Diff line Loading @@ -406,8 +406,12 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) if (copy_from_user(&request, arg, sizeof request)) return -EFAULT; if (request.type > FW_ISO_CONTEXT_RECEIVE) return -EINVAL; client->iso_context = fw_iso_context_create(client->device->card, FW_ISO_CONTEXT_TRANSMIT, request.type, request.header_size, iso_callback, client); if (IS_ERR(client->iso_context)) return PTR_ERR(client->iso_context); Loading @@ -419,7 +423,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) { struct fw_cdev_queue_iso request; struct fw_cdev_iso_packet __user *p, *end, *next; unsigned long payload, payload_end; unsigned long payload, payload_end, header_length; int count; struct { struct fw_iso_packet packet; Loading Loading @@ -456,12 +460,23 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) while (p < end) { if (__copy_from_user(&u.packet, p, sizeof *p)) return -EFAULT; if (client->iso_context->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) return -EINVAL; header_length = 0; } next = (struct fw_cdev_iso_packet __user *) &p->header[u.packet.header_length / 4]; &p->header[header_length / 4]; if (next > end) return -EINVAL; if (__copy_from_user (u.packet.header, p->header, u.packet.header_length)) (u.packet.header, p->header, header_length)) return -EFAULT; if (u.packet.skip && u.packet.header_length + u.packet.payload_length > 0) Loading drivers/firewire/fw-device-cdev.h +5 −0 Original line number Diff line number Diff line Loading @@ -125,7 +125,12 @@ struct fw_cdev_allocate { __u32 length; }; #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 #define FW_CDEV_ISO_CONTEXT_RECEIVE 1 struct fw_cdev_create_iso_context { __u32 type; __u32 header_size; __u32 handle; }; Loading drivers/firewire/fw-iso.c +4 −3 Original line number Diff line number Diff line Loading @@ -105,9 +105,9 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, buffer->pages = NULL; } struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, fw_iso_callback_t callback, void *callback_data) struct fw_iso_context * fw_iso_context_create(struct fw_card *card, int type, size_t header_size, fw_iso_callback_t callback, void *callback_data) { struct fw_iso_context *ctx; Loading @@ -117,6 +117,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, ctx->card = card; ctx->type = type; ctx->header_size = header_size; ctx->callback = callback; ctx->callback_data = callback_data; Loading drivers/firewire/fw-ohci.c +149 −19 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define descriptor_irq_error (1 << 4) #define descriptor_irq_always (3 << 4) #define descriptor_branch_always (3 << 2) #define descriptor_wait (3 << 0) struct descriptor { __le16 req_count; Loading @@ -55,6 +56,20 @@ struct descriptor { __le16 transfer_status; } __attribute__((aligned(16))); struct db_descriptor { __le16 first_size; __le16 control; __le16 second_req_count; __le16 first_req_count; __le32 branch_address; __le16 second_res_count; __le16 first_res_count; __le32 reserved0; __le32 first_buffer; __le32 second_buffer; __le32 reserved1; } __attribute__((aligned(16))); #define control_set(regs) (regs) #define control_clear(regs) ((regs) + 4) #define command_ptr(regs) ((regs) + 12) Loading Loading @@ -171,7 +186,12 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) return container_of(card, struct fw_ohci, card); } #define CONTEXT_CYCLE_MATCH_ENABLE 0x80000000 #define IT_CONTEXT_CYCLE_MATCH_ENABLE 0x80000000 #define IR_CONTEXT_BUFFER_FILL 0x80000000 #define IR_CONTEXT_ISOCH_HEADER 0x40000000 #define IR_CONTEXT_CYCLE_MATCH_ENABLE 0x20000000 #define IR_CONTEXT_MULTI_CHANNEL_MODE 0x10000000 #define IR_CONTEXT_DUAL_BUFFER_MODE 0x08000000 #define CONTEXT_RUN 0x8000 #define CONTEXT_WAKE 0x1000 Loading Loading @@ -518,14 +538,14 @@ context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus) return d; } static void context_run(struct context *ctx, u32 cycle_match) static void context_run(struct context *ctx, u32 extra) { struct fw_ohci *ohci = ctx->ohci; reg_write(ohci, command_ptr(ctx->regs), le32_to_cpu(ctx->tail_descriptor_last->branch_address)); reg_write(ohci, control_clear(ctx->regs), ~0); reg_write(ohci, control_set(ctx->regs), CONTEXT_RUN | cycle_match); reg_write(ohci, control_set(ctx->regs), CONTEXT_RUN | extra); flush_writes(ohci); } Loading Loading @@ -1240,11 +1260,25 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) return retval; } static void ir_context_tasklet(unsigned long data) static int handle_ir_packet(struct context *context, struct descriptor *d, struct descriptor *last) { struct iso_context *ctx = (struct iso_context *)data; struct iso_context *ctx = container_of(context, struct iso_context, context); struct db_descriptor *db = (struct db_descriptor *) d; (void)ctx; 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, ctx->base.callback_data); return 1; } #define ISO_BUFFER_SIZE (64 * 1024) Loading Loading @@ -1274,7 +1308,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type) struct fw_ohci *ohci = fw_ohci(card); struct iso_context *ctx, *list; descriptor_callback_t callback; u32 *mask; u32 *mask, regs; unsigned long flags; int index, retval; Loading @@ -1283,7 +1317,9 @@ ohci_allocate_iso_context(struct fw_card *card, int type) list = ohci->it_context_list; callback = handle_it_packet; } else { return ERR_PTR(-EINVAL); mask = &ohci->ir_context_mask; list = ohci->ir_context_list; callback = handle_ir_packet; } spin_lock_irqsave(&ohci->lock, flags); Loading @@ -1295,10 +1331,15 @@ ohci_allocate_iso_context(struct fw_card *card, int type) if (index < 0) return ERR_PTR(-EBUSY); if (type == FW_ISO_CONTEXT_TRANSMIT) regs = OHCI1394_IsoXmitContextBase(index); else regs = OHCI1394_IsoRcvContextBase(index); ctx = &list[index]; memset(ctx, 0, sizeof *ctx); retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE, OHCI1394_IsoXmitContextBase(index), callback); regs, callback); if (retval < 0) { spin_lock_irqsave(&ohci->lock, flags); *mask |= 1 << index; Loading @@ -1316,13 +1357,24 @@ static int ohci_send_iso(struct fw_iso_context *base, s32 cycle) u32 cycle_match = 0; int index; if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { index = ctx - ohci->it_context_list; if (cycle > 0) cycle_match = CONTEXT_CYCLE_MATCH_ENABLE | cycle_match = IT_CONTEXT_CYCLE_MATCH_ENABLE | (cycle & 0x7fff) << 16; reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index); context_run(&ctx->context, cycle_match); } else { index = ctx - ohci->ir_context_list; 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); context_run(&ctx->context, IR_CONTEXT_DUAL_BUFFER_MODE); } return 0; } Loading Loading @@ -1355,7 +1407,7 @@ static void ohci_free_iso_context(struct fw_iso_context *base) } static int ohci_queue_iso(struct fw_iso_context *base, ohci_queue_iso_transmit(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) Loading Loading @@ -1451,6 +1503,84 @@ ohci_queue_iso(struct fw_iso_context *base, return 0; } static int ohci_queue_iso_receive(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) { struct iso_context *ctx = container_of(base, struct iso_context, base); struct db_descriptor *db = NULL; struct descriptor *d; struct fw_iso_packet *p; dma_addr_t d_bus, page_bus; u32 z, header_z, length, rest; int page, offset; /* FIXME: Cycle lost behavior should be configurable: lose * packet, retransmit or terminate.. */ p = packet; z = 2; /* Get header size in number of descriptors. */ header_z = DIV_ROUND_UP(p->header_length, sizeof *d); page = payload >> PAGE_SHIFT; offset = payload & ~PAGE_MASK; rest = p->payload_length; /* FIXME: OHCI 1.0 doesn't support dual buffer receive */ /* FIXME: handle descriptor_wait */ /* FIXME: make packet-per-buffer/dual-buffer a context option */ while (rest > 0) { d = context_get_descriptors(&ctx->context, z + header_z, &d_bus); if (d == NULL) return -ENOMEM; db = (struct db_descriptor *) d; db->control = cpu_to_le16(descriptor_status | descriptor_branch_always); db->first_size = cpu_to_le16(ctx->base.header_size); db->first_req_count = cpu_to_le16(p->header_length); db->second_req_count = cpu_to_le16(p->payload_length); db->first_res_count = cpu_to_le16(db->first_req_count); db->second_res_count = cpu_to_le16(db->second_req_count); db->first_buffer = cpu_to_le32(d_bus + sizeof *db); if (offset + rest < PAGE_SIZE) length = rest; else length = PAGE_SIZE - offset; page_bus = page_private(buffer->pages[page]); db->second_buffer = cpu_to_le32(page_bus + offset); context_append(&ctx->context, d, z, header_z); offset = (offset + length) & ~PAGE_MASK; rest -= length; page++; } if (p->interrupt) db->control |= cpu_to_le16(descriptor_irq_always); return 0; } static int ohci_queue_iso(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) { if (base->type == FW_ISO_CONTEXT_TRANSMIT) return ohci_queue_iso_transmit(base, packet, buffer, payload); else return ohci_queue_iso_receive(base, packet, buffer, payload); } static const struct fw_card_driver ohci_driver = { .name = ohci_driver_name, .enable = ohci_enable, Loading drivers/firewire/fw-ohci.h +1 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ #define OHCI1394_IsoXmitCommandPtr(n) (0x20C + 16 * (n)) /* Isochronous receive registers */ #define OHCI1394_IsoRcvContextBase(n) (0x400 + 32 * (n)) #define OHCI1394_IsoRcvContextControlSet(n) (0x400 + 32 * (n)) #define OHCI1394_IsoRcvContextControlClear(n) (0x404 + 32 * (n)) #define OHCI1394_IsoRcvCommandPtr(n) (0x40C + 32 * (n)) Loading Loading
drivers/firewire/fw-device-cdev.c +19 −4 Original line number Diff line number Diff line Loading @@ -406,8 +406,12 @@ static int ioctl_create_iso_context(struct client *client, void __user *arg) if (copy_from_user(&request, arg, sizeof request)) return -EFAULT; if (request.type > FW_ISO_CONTEXT_RECEIVE) return -EINVAL; client->iso_context = fw_iso_context_create(client->device->card, FW_ISO_CONTEXT_TRANSMIT, request.type, request.header_size, iso_callback, client); if (IS_ERR(client->iso_context)) return PTR_ERR(client->iso_context); Loading @@ -419,7 +423,7 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) { struct fw_cdev_queue_iso request; struct fw_cdev_iso_packet __user *p, *end, *next; unsigned long payload, payload_end; unsigned long payload, payload_end, header_length; int count; struct { struct fw_iso_packet packet; Loading Loading @@ -456,12 +460,23 @@ static int ioctl_queue_iso(struct client *client, void __user *arg) while (p < end) { if (__copy_from_user(&u.packet, p, sizeof *p)) return -EFAULT; if (client->iso_context->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) return -EINVAL; header_length = 0; } next = (struct fw_cdev_iso_packet __user *) &p->header[u.packet.header_length / 4]; &p->header[header_length / 4]; if (next > end) return -EINVAL; if (__copy_from_user (u.packet.header, p->header, u.packet.header_length)) (u.packet.header, p->header, header_length)) return -EFAULT; if (u.packet.skip && u.packet.header_length + u.packet.payload_length > 0) Loading
drivers/firewire/fw-device-cdev.h +5 −0 Original line number Diff line number Diff line Loading @@ -125,7 +125,12 @@ struct fw_cdev_allocate { __u32 length; }; #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 #define FW_CDEV_ISO_CONTEXT_RECEIVE 1 struct fw_cdev_create_iso_context { __u32 type; __u32 header_size; __u32 handle; }; Loading
drivers/firewire/fw-iso.c +4 −3 Original line number Diff line number Diff line Loading @@ -105,9 +105,9 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, buffer->pages = NULL; } struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, fw_iso_callback_t callback, void *callback_data) struct fw_iso_context * fw_iso_context_create(struct fw_card *card, int type, size_t header_size, fw_iso_callback_t callback, void *callback_data) { struct fw_iso_context *ctx; Loading @@ -117,6 +117,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, ctx->card = card; ctx->type = type; ctx->header_size = header_size; ctx->callback = callback; ctx->callback_data = callback_data; Loading
drivers/firewire/fw-ohci.c +149 −19 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define descriptor_irq_error (1 << 4) #define descriptor_irq_always (3 << 4) #define descriptor_branch_always (3 << 2) #define descriptor_wait (3 << 0) struct descriptor { __le16 req_count; Loading @@ -55,6 +56,20 @@ struct descriptor { __le16 transfer_status; } __attribute__((aligned(16))); struct db_descriptor { __le16 first_size; __le16 control; __le16 second_req_count; __le16 first_req_count; __le32 branch_address; __le16 second_res_count; __le16 first_res_count; __le32 reserved0; __le32 first_buffer; __le32 second_buffer; __le32 reserved1; } __attribute__((aligned(16))); #define control_set(regs) (regs) #define control_clear(regs) ((regs) + 4) #define command_ptr(regs) ((regs) + 12) Loading Loading @@ -171,7 +186,12 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) return container_of(card, struct fw_ohci, card); } #define CONTEXT_CYCLE_MATCH_ENABLE 0x80000000 #define IT_CONTEXT_CYCLE_MATCH_ENABLE 0x80000000 #define IR_CONTEXT_BUFFER_FILL 0x80000000 #define IR_CONTEXT_ISOCH_HEADER 0x40000000 #define IR_CONTEXT_CYCLE_MATCH_ENABLE 0x20000000 #define IR_CONTEXT_MULTI_CHANNEL_MODE 0x10000000 #define IR_CONTEXT_DUAL_BUFFER_MODE 0x08000000 #define CONTEXT_RUN 0x8000 #define CONTEXT_WAKE 0x1000 Loading Loading @@ -518,14 +538,14 @@ context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus) return d; } static void context_run(struct context *ctx, u32 cycle_match) static void context_run(struct context *ctx, u32 extra) { struct fw_ohci *ohci = ctx->ohci; reg_write(ohci, command_ptr(ctx->regs), le32_to_cpu(ctx->tail_descriptor_last->branch_address)); reg_write(ohci, control_clear(ctx->regs), ~0); reg_write(ohci, control_set(ctx->regs), CONTEXT_RUN | cycle_match); reg_write(ohci, control_set(ctx->regs), CONTEXT_RUN | extra); flush_writes(ohci); } Loading Loading @@ -1240,11 +1260,25 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) return retval; } static void ir_context_tasklet(unsigned long data) static int handle_ir_packet(struct context *context, struct descriptor *d, struct descriptor *last) { struct iso_context *ctx = (struct iso_context *)data; struct iso_context *ctx = container_of(context, struct iso_context, context); struct db_descriptor *db = (struct db_descriptor *) d; (void)ctx; 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, ctx->base.callback_data); return 1; } #define ISO_BUFFER_SIZE (64 * 1024) Loading Loading @@ -1274,7 +1308,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type) struct fw_ohci *ohci = fw_ohci(card); struct iso_context *ctx, *list; descriptor_callback_t callback; u32 *mask; u32 *mask, regs; unsigned long flags; int index, retval; Loading @@ -1283,7 +1317,9 @@ ohci_allocate_iso_context(struct fw_card *card, int type) list = ohci->it_context_list; callback = handle_it_packet; } else { return ERR_PTR(-EINVAL); mask = &ohci->ir_context_mask; list = ohci->ir_context_list; callback = handle_ir_packet; } spin_lock_irqsave(&ohci->lock, flags); Loading @@ -1295,10 +1331,15 @@ ohci_allocate_iso_context(struct fw_card *card, int type) if (index < 0) return ERR_PTR(-EBUSY); if (type == FW_ISO_CONTEXT_TRANSMIT) regs = OHCI1394_IsoXmitContextBase(index); else regs = OHCI1394_IsoRcvContextBase(index); ctx = &list[index]; memset(ctx, 0, sizeof *ctx); retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE, OHCI1394_IsoXmitContextBase(index), callback); regs, callback); if (retval < 0) { spin_lock_irqsave(&ohci->lock, flags); *mask |= 1 << index; Loading @@ -1316,13 +1357,24 @@ static int ohci_send_iso(struct fw_iso_context *base, s32 cycle) u32 cycle_match = 0; int index; if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { index = ctx - ohci->it_context_list; if (cycle > 0) cycle_match = CONTEXT_CYCLE_MATCH_ENABLE | cycle_match = IT_CONTEXT_CYCLE_MATCH_ENABLE | (cycle & 0x7fff) << 16; reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index); context_run(&ctx->context, cycle_match); } else { index = ctx - ohci->ir_context_list; 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); context_run(&ctx->context, IR_CONTEXT_DUAL_BUFFER_MODE); } return 0; } Loading Loading @@ -1355,7 +1407,7 @@ static void ohci_free_iso_context(struct fw_iso_context *base) } static int ohci_queue_iso(struct fw_iso_context *base, ohci_queue_iso_transmit(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) Loading Loading @@ -1451,6 +1503,84 @@ ohci_queue_iso(struct fw_iso_context *base, return 0; } static int ohci_queue_iso_receive(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) { struct iso_context *ctx = container_of(base, struct iso_context, base); struct db_descriptor *db = NULL; struct descriptor *d; struct fw_iso_packet *p; dma_addr_t d_bus, page_bus; u32 z, header_z, length, rest; int page, offset; /* FIXME: Cycle lost behavior should be configurable: lose * packet, retransmit or terminate.. */ p = packet; z = 2; /* Get header size in number of descriptors. */ header_z = DIV_ROUND_UP(p->header_length, sizeof *d); page = payload >> PAGE_SHIFT; offset = payload & ~PAGE_MASK; rest = p->payload_length; /* FIXME: OHCI 1.0 doesn't support dual buffer receive */ /* FIXME: handle descriptor_wait */ /* FIXME: make packet-per-buffer/dual-buffer a context option */ while (rest > 0) { d = context_get_descriptors(&ctx->context, z + header_z, &d_bus); if (d == NULL) return -ENOMEM; db = (struct db_descriptor *) d; db->control = cpu_to_le16(descriptor_status | descriptor_branch_always); db->first_size = cpu_to_le16(ctx->base.header_size); db->first_req_count = cpu_to_le16(p->header_length); db->second_req_count = cpu_to_le16(p->payload_length); db->first_res_count = cpu_to_le16(db->first_req_count); db->second_res_count = cpu_to_le16(db->second_req_count); db->first_buffer = cpu_to_le32(d_bus + sizeof *db); if (offset + rest < PAGE_SIZE) length = rest; else length = PAGE_SIZE - offset; page_bus = page_private(buffer->pages[page]); db->second_buffer = cpu_to_le32(page_bus + offset); context_append(&ctx->context, d, z, header_z); offset = (offset + length) & ~PAGE_MASK; rest -= length; page++; } if (p->interrupt) db->control |= cpu_to_le16(descriptor_irq_always); return 0; } static int ohci_queue_iso(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) { if (base->type == FW_ISO_CONTEXT_TRANSMIT) return ohci_queue_iso_transmit(base, packet, buffer, payload); else return ohci_queue_iso_receive(base, packet, buffer, payload); } static const struct fw_card_driver ohci_driver = { .name = ohci_driver_name, .enable = ohci_enable, Loading
drivers/firewire/fw-ohci.h +1 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ #define OHCI1394_IsoXmitCommandPtr(n) (0x20C + 16 * (n)) /* Isochronous receive registers */ #define OHCI1394_IsoRcvContextBase(n) (0x400 + 32 * (n)) #define OHCI1394_IsoRcvContextControlSet(n) (0x400 + 32 * (n)) #define OHCI1394_IsoRcvContextControlClear(n) (0x404 + 32 * (n)) #define OHCI1394_IsoRcvCommandPtr(n) (0x40C + 32 * (n)) Loading