rpms/kernel/F-7 linux-2.6-firewire-ohci-1.0-iso-receive.patch, NONE, 1.1 kernel-2.6.spec, 1.3379, 1.3380

Jarod Wilson (jwilson) fedora-extras-commits at redhat.com
Wed Nov 14 23:20:42 UTC 2007


Author: jwilson

Update of /cvs/pkgs/rpms/kernel/F-7
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv1045

Modified Files:
	kernel-2.6.spec 
Added Files:
	linux-2.6-firewire-ohci-1.0-iso-receive.patch 
Log Message:
* Wed Nov 14 2007 Jarod Wilson <jwilson at redhat.com>
- Initial FireWire OHCI 1.0 Isochronous Receive support (#344851)


linux-2.6-firewire-ohci-1.0-iso-receive.patch:

--- NEW FILE linux-2.6-firewire-ohci-1.0-iso-receive.patch ---
diff -Naurp linux-2.6.23.noarch/drivers/firewire/fw-ohci.c linux-2.6.23.noarch.fw/drivers/firewire/fw-ohci.c
--- linux-2.6.23.noarch/drivers/firewire/fw-ohci.c	2007-10-09 16:31:38.000000000 -0400
+++ linux-2.6.23.noarch.fw/drivers/firewire/fw-ohci.c	2007-11-14 17:41:26.000000000 -0500
@@ -71,6 +71,13 @@ struct db_descriptor {
 	__le32 reserved1;
 } __attribute__((aligned(16)));
 
+struct ppb_context {
+	/* the userspace buffer */
+	u64 buffer;
+	/* ofset into userspace buffer to put data, 0 to append */
+	u32 data_start;
+};
+
 #define CONTROL_SET(regs)	(regs)
 #define CONTROL_CLEAR(regs)	((regs) + 4)
 #define COMMAND_PTR(regs)	((regs) + 12)
@@ -125,6 +132,8 @@ struct iso_context {
 	struct context context;
 	void *header;
 	size_t header_length;
+	struct fw_iso_buffer *iso_buffer;
+	u32 data_start;
 };
 
 #define CONFIG_ROM_SIZE 1024
@@ -1403,6 +1412,69 @@ static int handle_ir_dualbuffer_packet(s
 	return 1;
 }
 
+static int handle_ir_packet_per_buffer(struct context *context,
+				       struct descriptor *d,
+				       struct descriptor *last)
+{
+	struct iso_context *ctx =
+		container_of(context, struct iso_context, context);
+	struct page **pages = ctx->iso_buffer->pages;
+	struct device *dev = context->ohci->card.device;
+	struct ppb_context *ppbc;
+	void *p;
+	u32 length, rest, offset;
+	int i, page, timestamp;
+
+	if (d->res_count == d->req_count)
+		/* This descriptor isn't done yet, stop iteration. */
+		return 0;
+
+	dma_unmap_single(dev, le32_to_cpu(d->data_address),
+			 le16_to_cpu(d->req_count), DMA_FROM_DEVICE);
+
+	ppbc = (struct ppb_context *) (d + 1);
+	p    = (void *) ppbc->buffer;
+	timestamp = le32_to_cpu(* (__le32 *) p) & 0xffff;
+	i    = ctx->header_length;
+
+	/* Put properly formatted headers where they belong */
+	*(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
+	memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
+	ctx->header_length += ctx->base.header_size;
+
+	if (ppbc->data_start != 0)
+		ctx->data_start = ppbc->data_start;
+	page   = ctx->data_start >> PAGE_SHIFT;
+	offset = ctx->data_start & ~PAGE_MASK;
+	rest   = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count) -
+		 ctx->base.header_size - 4;
+	p += ctx->base.header_size + 4;
+
+	while (rest > 0) {
+		if (offset + rest < PAGE_SIZE)
+			length = rest;
+		else
+			length = PAGE_SIZE - offset;
+
+		/* Put data payload where it belongs */
+		memcpy(page_address(pages[page]) + offset, p, length);
+		offset = (offset + length) & ~PAGE_MASK;
+		page++;
+		rest -= length;
+	}
+
+	if (le16_to_cpu(d->control) & DESCRIPTOR_IRQ_ALWAYS) {
+		ctx->base.callback(&ctx->base, timestamp,
+				   ctx->header_length, ctx->header,
+				   ctx->base.callback_data);
+		ctx->header_length = 0;
+	}
+
+	kfree((void *) (unsigned long) ppbc->buffer);
+
+	return 1;
+}
+
 static int handle_it_packet(struct context *context,
 			    struct descriptor *d,
 			    struct descriptor *last)
@@ -1438,14 +1510,12 @@ ohci_allocate_iso_context(struct fw_card
 	} else {
 		mask = &ohci->ir_context_mask;
 		list = ohci->ir_context_list;
-		callback = handle_ir_dualbuffer_packet;
+		if (ohci->version >= OHCI_VERSION_1_1)
+			callback = handle_ir_dualbuffer_packet;
+		else
+			callback = handle_ir_packet_per_buffer;
 	}
 
-	/* FIXME: We need a fallback for pre 1.1 OHCI. */
-	if (callback == handle_ir_dualbuffer_packet &&
-	    ohci->version < OHCI_VERSION_1_1)
-		return ERR_PTR(-EINVAL);
-
 	spin_lock_irqsave(&ohci->lock, flags);
 	index = ffs(*mask) - 1;
 	if (index >= 0)
@@ -1504,7 +1574,9 @@ static int ohci_start_iso(struct fw_iso_
 		context_run(&ctx->context, match);
 	} else {
 		index = ctx - ohci->ir_context_list;
-		control = IR_CONTEXT_DUAL_BUFFER_MODE | IR_CONTEXT_ISOCH_HEADER;
+		control = IR_CONTEXT_ISOCH_HEADER;
+		if (ohci->version >= OHCI_VERSION_1_1)
+			control |= IR_CONTEXT_DUAL_BUFFER_MODE;
 		match = (tags << 28) | (sync << 8) | ctx->base.channel;
 		if (cycle >= 0) {
 			match |= (cycle & 0x07fff) << 12;
@@ -1710,7 +1782,6 @@ ohci_queue_iso_receive_dualbuffer(struct
 	offset   = payload & ~PAGE_MASK;
 	rest     = p->payload_length;
 
-	/* FIXME: OHCI 1.0 doesn't support dual buffer receive */
 	/* FIXME: make packet-per-buffer/dual-buffer a context option */
 	while (rest > 0) {
 		d = context_get_descriptors(&ctx->context,
@@ -1749,6 +1820,93 @@ ohci_queue_iso_receive_dualbuffer(struct
 }
 
 static int
+ohci_queue_iso_receive_packet_per_buffer(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 descriptor *d = NULL;
+	struct fw_iso_packet *p;
+	void *tmpbuf;
+	dma_addr_t d_bus, tmpbuf_bus;
+	u32 z, length;
+	int i, packet_count, header_size;
+ 
+	struct context *context = &ctx->context;
+	struct device *dev = context->ohci->card.device;
+	struct ppb_context *ppbc;
+
+	/* save iso_buffer pointer for packet handling later */
+	ctx->iso_buffer = buffer;
+
+	z = 1;
+
+	if (packet->skip) {
+		d = context_get_descriptors(&ctx->context, z, &d_bus);
+		if (d == NULL)
+			return -ENOMEM;
+
+		d->control = cpu_to_le16(DESCRIPTOR_STATUS |
+					 DESCRIPTOR_INPUT_LAST |
+					 DESCRIPTOR_BRANCH_ALWAYS |
+					 DESCRIPTOR_WAIT);
+		context_append(&ctx->context, d, z, 0);
+	}
+
+	p = packet;
+
+	/*
+	 * The OHCI controller puts the status word in the
+	 * buffer too, so we need 4 extra bytes per packet.
+	 */
+	packet_count = p->header_length / ctx->base.header_size;
+	header_size  = packet_count * (ctx->base.header_size + 4);
+
+	for (i = 0; i < packet_count; i++) {
+		d = context_get_descriptors(&ctx->context, z + 1, &d_bus);
+		if (d == NULL)
+			return -ENOMEM;
+
+		d->control = cpu_to_le16(DESCRIPTOR_STATUS |
+					 DESCRIPTOR_INPUT_LAST |
+					 DESCRIPTOR_BRANCH_ALWAYS);
+
+		length = p->payload_length + header_size;
+
+		tmpbuf = kmalloc(length, GFP_KERNEL);
+		if (tmpbuf == NULL)
+			return -ENOMEM;
+
+		d->req_count = cpu_to_le16(length);
+		d->res_count = d->req_count;
+
+		tmpbuf_bus = dma_map_single(dev, tmpbuf,
+					    length, DMA_FROM_DEVICE);
+		if (dma_mapping_error(tmpbuf_bus)) {
+			kfree(tmpbuf);
+			return -ENOMEM;
+		}
+
+		d->data_address = cpu_to_le32(tmpbuf_bus);
+
+		ppbc = (struct ppb_context *) (d + 1);
+		if (i == 0)
+			ppbc->data_start = payload;
+		else
+			ppbc->data_start = 0;
+		ppbc->buffer = (unsigned long) tmpbuf;
+
+		context_append(&ctx->context, d, z, 1);
+	}
+
+	if (p->interrupt)
+		d->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,
@@ -1762,8 +1920,9 @@ ohci_queue_iso(struct fw_iso_context *ba
 		return ohci_queue_iso_receive_dualbuffer(base, packet,
 							 buffer, payload);
 	else
-		/* FIXME: Implement fallback for OHCI 1.0 controllers. */
-		return -EINVAL;
+		return ohci_queue_iso_receive_packet_per_buffer(base, packet,
+								buffer,
+								payload);
 }
 
 static const struct fw_card_driver ohci_driver = {


Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-7/kernel-2.6.spec,v
retrieving revision 1.3379
retrieving revision 1.3380
diff -u -r1.3379 -r1.3380
--- kernel-2.6.spec	12 Nov 2007 22:00:38 -0000	1.3379
+++ kernel-2.6.spec	14 Nov 2007 23:20:07 -0000	1.3380
@@ -627,6 +627,7 @@
 
 Patch750: linux-2.6-firewire-multi-lun.patch
 Patch751: linux-2.6-firewire-lockdep.patch
+Patch752: linux-2.6-firewire-ohci-1.0-iso-receive.patch
 
 Patch770: linux-2.6-acpi-sleep-fix-GPE-suspend-cleanup.patch
 Patch771: linux-2.6-acpi-suspend-wrong-order-of-GPE-restore.patch
@@ -1343,6 +1344,7 @@
 #
 ApplyPatch linux-2.6-firewire-multi-lun.patch
 ApplyPatch linux-2.6-firewire-lockdep.patch
+ApplyPatch linux-2.6-firewire-ohci-1.0-iso-receive.patch
 
 # USB
 #
@@ -2309,6 +2311,9 @@
 %endif
 
 %changelog
+* Wed Nov 14 2007 Jarod Wilson <jwilson at redhat.com>
+- Initial FireWire OHCI 1.0 Isochronous Receive support (#344851)
+
 * Mon Nov 12 2007 Chuck Ebbert <cebbert at redhat.com>
 - Disable USB autosuspend by default.
 - Fix oops in CIFS when mounting a filesystem a second time.




More information about the fedora-extras-commits mailing list