patch-2.4.7 linux/drivers/ieee1394/ohci1394.c

Next file: linux/drivers/ieee1394/ohci1394.h
Previous file: linux/drivers/ieee1394/nodemgr.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
@@ -2,6 +2,7 @@
  * ohci1394.c - driver for OHCI 1394 boards
  * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
  *                        Gord Peters <GordPeters@smarttech.com>
+ *              2001      Ben Collins <bcollins@debian.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,16 +27,20 @@
  * . Async Response Transmit
  * . Iso Receive
  * . DMA mmap for iso receive
+ * . Config ROM generation
+ *
+ * Things implemented, but still in test phase:
+ * . Iso Transmit
  * 
  * Things not implemented:
- * . Iso Transmit
+ * . Async Stream Packets
  * . DMA error recovery
  *
  * Things to be fixed:
- * . Config ROM
+ * . Latency problems on UltraSPARC
  *
  * Known bugs:
- * . Self-id are sometimes not received properly 
+ * . SelfID are sometimes not received properly 
  *   if card is initialized with no other nodes 
  *   on the bus
  * . Apple PowerBook detected but not working yet
@@ -46,26 +51,41 @@
  *
  * Adam J Richter <adam@yggdrasil.com>
  *  . Use of pci_class to find device
+ *
  * Andreas Tobler <toa@pop.agri.ch>
  *  . Updated proc_fs calls
+ *
  * Emilie Chung	<emilie.chung@axis.com>
  *  . Tip on Async Request Filter
+ *
  * Pascal Drolet <pascal.drolet@informission.ca>
  *  . Various tips for optimization and functionnalities
+ *
  * Robert Ficklin <rficklin@westengineering.com>
  *  . Loop in irq_handler
+ *
  * James Goodwin <jamesg@Filanet.com>
  *  . Various tips on initialization, self-id reception, etc.
+ *
  * Albrecht Dress <ad@mpifr-bonn.mpg.de>
  *  . Apple PowerBook detection
+ *
  * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
  *  . Reset the board properly before leaving + misc cleanups
+ *
  * Leon van Stuivenberg <leonvs@iae.nl>
  *  . Bug fixes
+ *
+ * Ben Collins <bcollins@debian.org>
+ *  . Working big-endian support
+ *  . Updated to 2.4.x module scheme (PCI aswell)
+ *  . Removed procfs support since it trashes random mem
+ *  . Config ROM generation
  */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
@@ -78,9 +98,9 @@
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <linux/proc_fs.h>
 #include <linux/tqueue.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -95,83 +115,10 @@
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
+#include "highlevel.h"
 #include "ohci1394.h"
 
 
-/* This structure is not properly initialized ... it is taken from
-   the lynx_csr_rom written by Andreas ... Some fields in the root
-   directory and the module dependent info needs to be modified
-   I do not have the proper doc */
-quadlet_t ohci_csr_rom[] = {
-        /* bus info block */
-        0x04040000, /* info/CRC length, CRC */
-        0x31333934, /* 1394 magic number */
-        0xf07da002, /* cyc_clk_acc = 125us, max_rec = 1024 */
-        0x00000000, /* vendor ID, chip ID high (written from card info) */
-        0x00000000, /* chip ID low (written from card info) */
-        /* root directory - FIXME */
-        0x00090000, /* CRC length, CRC */
-        0x03080028, /* vendor ID (Texas Instr.) */
-        0x81000009, /* offset to textual ID */
-        0x0c000200, /* node capabilities */
-        0x8d00000e, /* offset to unique ID */
-        0xc7000010, /* offset to module independent info */
-        0x04000000, /* module hardware version */
-        0x81000026, /* offset to textual ID */
-        0x09000000, /* node hardware version */
-        0x81000026, /* offset to textual ID */
-        /* module vendor ID textual */
-        0x00080000, /* CRC length, CRC */
-        0x00000000,
-        0x00000000,
-        0x54455841, /* "Texas Instruments" */
-        0x5320494e,
-        0x53545255,
-        0x4d454e54,
-        0x53000000,
-        /* node unique ID leaf */
-        0x00020000, /* CRC length, CRC */
-        0x08002856, /* vendor ID, chip ID high */
-        0x0000083E, /* chip ID low */
-        /* module dependent info - FIXME */
-        0x00060000, /* CRC length, CRC */
-        0xb8000006, /* ??? offset to module textual ID */
-        0x81000004, /* ??? textual descriptor */
-        0x00000000, /* SRAM size */
-        0x00000000, /* AUXRAM size */
-        0x00000000, /* AUX device */
-        /* module textual ID */
-        0x00050000, /* CRC length, CRC */
-        0x00000000,
-        0x00000000,
-        0x54534231, /* "TSB12LV22" */
-        0x324c5632,
-        0x32000000,
-        /* part number */
-        0x00060000, /* CRC length, CRC */
-        0x00000000,
-        0x00000000,
-        0x39383036, /* "9806000-0001" */
-        0x3030342d,
-        0x30303431,
-        0x20000001,
-        /* module hardware version textual */
-        0x00050000, /* CRC length, CRC */
-        0x00000000,
-        0x00000000,
-        0x5453424b, /* "TSBKOHCI403" */
-        0x4f484349,
-        0x34303300,
-        /* node hardware version textual */
-        0x00050000, /* CRC length, CRC */
-        0x00000000,
-        0x00000000,
-        0x54534234, /* "TSB41LV03" */
-        0x314c5630,
-        0x33000000
-};
-
-
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 #define OHCI1394_DEBUG
 #endif
@@ -187,6 +134,19 @@
 #define DBGMSG(card, fmt, args...)
 #endif
 
+#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
+#define OHCI_DMA_ALLOC(fmt, args...) \
+	HPSB_ERR("ohci1394("__FUNCTION__")alloc(%d): "fmt, \
+		++global_outstanding_dmas, ## args)
+#define OHCI_DMA_FREE(fmt, args...) \
+	HPSB_ERR("ohci1394("__FUNCTION__")free(%d): "fmt, \
+		--global_outstanding_dmas, ## args)
+u32 global_outstanding_dmas = 0;
+#else
+#define OHCI_DMA_ALLOC(fmt, args...)
+#define OHCI_DMA_FREE(fmt, args...)
+#endif
+
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) \
 printk(level "ohci1394: " fmt "\n" , ## args)
@@ -195,36 +155,16 @@
 #define PRINT(level, card, fmt, args...) \
 printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
 
-#define FAIL(fmt, args...) \
-	PRINT_G(KERN_ERR, fmt , ## args); \
-	  num_of_cards--; \
-	    remove_card(ohci); \
-	      return 1;
-
-#if USE_DEVICE
-
-int supported_chips[][2] = {
-	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 },
-	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 },
-	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 },
-	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_PCI4450 },
-	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
-	{ PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },
-	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 },
-	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 },
-	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 },
-	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW },
-	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_ALI_OHCI1394_M5251 },
-	{ PCI_VENDOR_ID_LUCENT, PCI_DEVICE_ID_LUCENT_FW323 },
-	{ -1, -1 }
-};
-
-#else
+#define FAIL(fmt, args...)				\
+do {							\
+	PRINT_G(KERN_ERR, fmt , ## args);		\
+	remove_card(ohci);				\
+	return 1;					\
+} while(0)
 
 #define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static struct pci_device_id ohci1394_pci_tbl[] __initdata = {
+static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
 	{
 		class: 		PCI_CLASS_FIREWIRE_OHCI,
 		class_mask: 	0x00ffffff,
@@ -236,191 +176,181 @@
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-#endif
 
-#endif /* USE_DEVICE */
+static char version[] __devinitdata =
+	"v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>";
 
+/* Module Parameters */
 MODULE_PARM(attempt_root,"i");
+MODULE_PARM_DESC(attempt_root, "Attempt to make the host root.");
 static int attempt_root = 0;
 
-static struct ti_ohci cards[MAX_OHCI1394_CARDS];
-static int num_of_cards = 0;
+#ifdef __LITTLE_ENDIAN
+/* Don't waste cycles on same sex byte swaps */
+#define packet_swab(w,x,y,z)
+#define block_swab32(x,y)
+#else
+static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap);
+static __inline__ void block_swab32(quadlet_t *data, size_t size);
+#endif
+
+static unsigned int card_id_counter = 0;
 
-static int add_card(struct pci_dev *dev);
+static void dma_trm_tasklet(unsigned long data);
 static void remove_card(struct ti_ohci *ohci);
-static int init_driver(void);
-static void dma_trm_bh(void *data);
-static void dma_rcv_bh(void *data);
 static void dma_trm_reset(struct dma_trm_ctx *d);
 
 /***********************************
  * IEEE-1394 functionality section *
  ***********************************/
 
-#if 0 /* not needed at this time */
-static int get_phy_reg(struct ti_ohci *ohci, int addr) 
+static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) 
 {
-	int timeout=10000;
-	static quadlet_t r;
-
-	if ((addr < 1) || (addr > 15)) {
-		PRINT(KERN_ERR, ohci->id, __FUNCTION__
-		      ": PHY register address %d out of range", addr);
-		return -EFAULT;
-	}
-
-	spin_lock(&ohci->phy_reg_lock);
+	int i, flags;
+	quadlet_t r;
 
-	/* initiate read request */
-	reg_write(ohci, OHCI1394_PhyControl, 
-		  ((addr<<8)&0x00000f00) | 0x00008000);
+	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
 
-	/* wait */
-	while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
-		timeout--;
+	reg_write(ohci, OHCI1394_PhyControl, (((u16)addr << 8) & 0x00000f00) | 0x00008000);
 
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
+			break;
 
-	if (!timeout) {
-		PRINT(KERN_ERR, ohci->id, "get_phy_reg timeout !!!\n");
-		spin_unlock(&ohci->phy_reg_lock);
-		return -EFAULT;
+		mdelay(1);
 	}
+
 	r = reg_read(ohci, OHCI1394_PhyControl);
+
+	if (i >= OHCI_LOOP_COUNT)
+		PRINT (KERN_ERR, ohci->id, "Get PHY Reg timeout [0x%08x/0x%08x/%d]\n",
+		       r, r & 0x80000000, i);
   
-	spin_unlock(&ohci->phy_reg_lock);
+	spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
      
-	return (r&0x00ff0000)>>16;
+	return (r & 0x00ff0000) >> 16;
 }
 
-static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) {
-	int timeout=10000;
+static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
+{
+	int i, flags;
 	u32 r;
 
-	if ((addr < 1) || (addr > 15)) {
-		PRINT(KERN_ERR, ohci->id, __FUNCTION__
-		      ": PHY register address %d out of range", addr);
-		return -EFAULT;
-	}
+	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
+
+	reg_write(ohci, OHCI1394_PhyControl, 0x00004000 | (((u16)addr << 8) & 0x00000f00) | data);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		r = reg_read(ohci, OHCI1394_PhyControl);
+		if (!(r & 0x00004000))
+			break;
 
-	r = ((addr<<8)&0x00000f00) | 0x00004000 | ((u32)data & 0x000000ff);
+		mdelay(1);
+	}
 
-	spin_lock(&ohci->phy_reg_lock);
+	if (i == OHCI_LOOP_COUNT)
+		PRINT (KERN_ERR, ohci->id, "Set PHY Reg timeout [0x%08x/0x%08x/%d]\n",
+		       r, r & 0x00004000, i);
 
-	reg_write(ohci, OHCI1394_PhyControl, r);
+	spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
 
-	/* wait */
-	while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)
-		timeout--;
+	return;
+}
 
-	spin_unlock(&ohci->phy_reg_lock);
+/* Or's our value into the current value */
+static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data)
+{
+	u8 old;
 
-	if (!timeout) {
-		PRINT(KERN_ERR, ohci->id, "set_phy_reg timeout !!!\n");
-		return -EFAULT;
-	}
+	old = get_phy_reg (ohci, addr);
+	old |= data;
+	set_phy_reg (ohci, addr, old);
 
-	return 0;
+	return;
 }
-#endif /* unneeded functions */
 
-inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
+static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
 				int phyid, int isroot)
 {
 	quadlet_t *q = ohci->selfid_buf_cpu;
 	quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
 	size_t size;
-	quadlet_t lsid;
+	quadlet_t q0, q1;
 
-	/* Self-id handling seems much easier than for the aic5800 chip.
-	   All the self-id packets, including this device own self-id,
+	/* SelfID handling seems much easier than for the aic5800 chip.
+	   All the self-id packets, including this devices own self-id,
 	   should be correctly arranged in the selfid buffer at this
 	   stage */
 
 	/* Check status of self-id reception */
-	if ((self_id_count&0x80000000) || 
-	    ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) {
+
+	if (ohci->selfid_swap)
+		q0 = le32_to_cpu(q[0]);
+	else
+		q0 = q[0];
+
+	if ((self_id_count & 0x80000000) || 
+	    ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
 		PRINT(KERN_ERR, ohci->id, 
-		      "Error in reception of self-id packets"
-		      "Self-id count: %08x q[0]: %08x",
-		      self_id_count, q[0]);
-
-		/*
-		 * Tip by James Goodwin <jamesg@Filanet.com>:
-		 * We had an error, generate another bus reset in response. 
-		 * TODO. Actually read the current value in the phy before 
-		 * generating a bus reset (read modify write). This way
-		 * we don't stomp any current gap count settings, etc.
-		 */
+		      "Error in reception of SelfID packets [0x%08x/0x%08x]",
+		      self_id_count, q0);
+
+		/* Tip by James Goodwin <jamesg@Filanet.com>:
+		 * We had an error, generate another bus reset in response.  */
 		if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {
-			reg_write(ohci, OHCI1394_PhyControl, 0x000041ff);      
+			set_phy_reg_mask (ohci, 1, 0x40);
 			ohci->self_id_errors++;
-		}
-		else {
+		} else {
 			PRINT(KERN_ERR, ohci->id, 
-			      "Timeout on self-id error reception");
+			      "Too many errors on SelfID error reception, giving up!");
 		}
 		return -1;
 	}
 	
-	size = ((self_id_count&0x00001FFC)>>2) - 1;
+	size = ((self_id_count & 0x00001FFC) >> 2) - 1;
 	q++;
 
 	while (size > 0) {
-		if (q[0] == ~q[1]) {
-			PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd", 
-			      q[0]);
-			hpsb_selfid_received(host, cpu_to_be32(q[0]));
-			if (((q[0]&0x3f000000)>>24)==phyid) {
-				lsid=q[0];
-				PRINT(KERN_INFO, ohci->id, 
-				      "This node self-id is 0x%08x", lsid);
-			}
+		if (ohci->selfid_swap) {
+			q0 = le32_to_cpu(q[0]);
+			q1 = le32_to_cpu(q[1]);
+		} else {
+			q0 = q[0];
+			q1 = q[1];
+		}
+		
+		if (q0 == ~q1) {
+			PRINT(KERN_DEBUG, ohci->id, "SelfID packet 0x%x received", q0);
+			hpsb_selfid_received(host, cpu_to_be32(q0));
+			if (((q0 & 0x3f000000) >> 24) == phyid)
+				DBGMSG (ohci->id, "SelfID for this node is 0x%08x", q0);
 		} else {
 			PRINT(KERN_ERR, ohci->id,
-			      "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
+			      "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);
 		}
 		q += 2;
 		size -= 2;
 	}
 
-	PRINT(KERN_INFO, ohci->id, "calling self-id complete");
+	PRINT(KERN_DEBUG, ohci->id, "SelfID complete");
 
 	hpsb_selfid_complete(host, phyid, isroot);
 	return 0;
 }
 
-static int ohci_detect(struct hpsb_host_template *tmpl)
-{
-	struct hpsb_host *host;
-	int i;
-
-	init_driver();
-
-	for (i = 0; i < num_of_cards; i++) {
-		host = hpsb_get_host(tmpl, 0);
-		if (host == NULL) {
-			/* simply don't init more after out of mem */
-			return i;
-		}
-		host->hostdata = &cards[i];
-		cards[i].host = host;
-	}
-  
-	return num_of_cards;
-}
-
 static int ohci_soft_reset(struct ti_ohci *ohci) {
-	int timeout=10000;
+	int i;
 
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
   
-	while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout) 
-		timeout--;
-	if (!timeout) {
-		PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!");
-		return -EFAULT;
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (reg_read(ohci, OHCI1394_HCControlSet) & 0x00010000)
+			break;
+		mdelay(10);
 	}
-	else PRINT(KERN_INFO, ohci->id, "soft reset finished");
+
+	PRINT(KERN_DEBUG, ohci->id, "Soft reset finished");
+
 	return 0;
 }
 
@@ -432,7 +362,7 @@
 	nodeId = reg_read(ohci, OHCI1394_NodeID);
 	if (!(nodeId&0x80000000)) {
 		PRINT(KERN_ERR, ohci->id, 
-		      "Running dma failed because Node ID not valid");
+		      "Running dma failed because Node ID is not valid");
 		return -1;
 	}
 
@@ -446,7 +376,7 @@
 	/* Run the dma context */
 	reg_write(ohci, reg, 0x8000);
 	
-	if (msg) PRINT(KERN_INFO, ohci->id, "%s", msg);
+	if (msg) PRINT(KERN_DEBUG, ohci->id, "%s", msg);
 	
 	return 0;
 }
@@ -461,19 +391,20 @@
 
 	for (i=0; i<d->num_desc; i++) {
 		
-		/* end of descriptor list? */
+		d->prg_cpu[i]->control =
+                   cpu_to_le32((0x280C << 16) | d->buf_size);
+
+		/* End of descriptor list? */
 		if ((i+1) < d->num_desc) {
-			d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;
 			d->prg_cpu[i]->branchAddress =
-				(d->prg_bus[i+1] & 0xfffffff0) | 0x1;
+				cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
 		} else {
-			d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;
 			d->prg_cpu[i]->branchAddress =
-				d->prg_bus[0] & 0xfffffff0;
+				cpu_to_le32((d->prg_bus[0] & 0xfffffff0));
 		}
 
-		d->prg_cpu[i]->address = d->buf_bus[i];
-		d->prg_cpu[i]->status = d->buf_size;
+		d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]);
+		d->prg_cpu[i]->status = cpu_to_le32(d->buf_size);
 	}
 
         d->buf_ind = 0;
@@ -485,7 +416,7 @@
 	/* Run AR context */
 	reg_write(ohci, d->ctrlSet, 0x00008000);
 
-	PRINT(KERN_INFO, ohci->id, "Receive DMA ctx=%d initialized", d->ctx);
+	DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx);
 }
 
 /* Initialize the dma transmit context */
@@ -505,7 +436,7 @@
 	d->pending_first = NULL;
 	d->pending_last = NULL;
 
-	PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
+	DBGMSG(ohci->id, "Transmit dma ctx=%d initialized", d->ctx);
 }
 
 /* Count the number of available iso contexts */
@@ -534,6 +465,7 @@
 	int retval, i;
 
 	spin_lock_init(&ohci->phy_reg_lock);
+	spin_lock_init(&ohci->event_lock);
   
 	/*
 	 * Tip by James Goodwin <jamesg@Filanet.com>:
@@ -543,13 +475,14 @@
 	 */ 
 
 	/* Soft reset */
-	if ((retval=ohci_soft_reset(ohci))<0) return retval;
+	if ((retval = ohci_soft_reset(ohci)) < 0)
+		return retval;
 
 	/* 
 	 * Delay after soft reset to make sure everything has settled
 	 * down (sanity)
 	 */
-	mdelay(100);    
+	mdelay(10);    
   
 	/* Set Link Power Status (LPS) */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
@@ -558,7 +491,7 @@
 	 * Delay after setting LPS in order to make sure link/phy
 	 * communication is established
 	 */
-	mdelay(100);   
+	mdelay(10);   
 
 	/* Set the bus number */
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
@@ -585,26 +518,10 @@
 	/* Set the configuration ROM mapping register */
 	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
 
-	/* Set bus options */
-	reg_write(ohci, OHCI1394_BusOptions, 
-		  cpu_to_be32(ohci->csr_config_rom_cpu[2]));
-
-#if 0	
-	/* Write the GUID into the csr config rom */
-	ohci->csr_config_rom_cpu[3] = 
-		be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
-	ohci->csr_config_rom_cpu[4] = 
-		be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
-#endif
-
-	/* Write the config ROM header */
-	reg_write(ohci, OHCI1394_ConfigROMhdr, 
-		  cpu_to_be32(ohci->csr_config_rom_cpu[0]));
-
 	ohci->max_packet_size = 
 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-	PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes",
-	      ohci->max_packet_size);
+	PRINT(KERN_DEBUG, ohci->id, "Max packet size = %d bytes",
+	       ohci->max_packet_size);
 
 	/* Don't accept phy packets into AR request context */ 
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -612,8 +529,8 @@
 	/* Initialize IR dma */
 	ohci->nb_iso_rcv_ctx = 
 		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-	PRINT(KERN_INFO, ohci->id, "%d iso receive contexts available",
-	      ohci->nb_iso_rcv_ctx);
+	DBGMSG(ohci->id, "%d iso receive contexts available",
+	       ohci->nb_iso_rcv_ctx);
 	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
 		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
 			  0xffffffff);
@@ -634,8 +551,8 @@
 	/* Initialize IT dma */
 	ohci->nb_iso_xmit_ctx = 
 		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-	PRINT(KERN_INFO, ohci->id, "%d iso transmit contexts available",
-	      ohci->nb_iso_xmit_ctx);
+	DBGMSG(ohci->id, "%d iso transmit contexts available",
+	       ohci->nb_iso_xmit_ctx);
 	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
 		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
 			  0xffffffff);
@@ -661,10 +578,16 @@
 	/* Initialize IR dma */
 	initialize_dma_rcv_ctx(ohci->ir_context);
 
+        /* Initialize IT dma */
+        initialize_dma_trm_ctx(ohci->it_context);
+
 	/* Set up isoRecvIntMask to generate interrupts for context 0
 	   (thanks to Michael Greger for seeing that I forgot this) */
 	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
 
+	/* Set up isoXmitIntMask to generate interrupts for context 0 */
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001);
+
 	/* 
 	 * Accept AT requests from all nodes. This probably 
 	 * will have to be controlled from the subsystem
@@ -678,11 +601,8 @@
 		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
 		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
 
-#ifndef __BIG_ENDIAN
+	/* We don't want hardware swapping */
 	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
-#else
-	reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
-#endif
 
 	/* Enable interrupts */
 	reg_write(ohci, OHCI1394_IntMaskSet, 
@@ -692,12 +612,11 @@
 		  OHCI1394_selfIDComplete |
 		  OHCI1394_RSPkt |
 		  OHCI1394_RQPkt |
-		  OHCI1394_ARRS |
-		  OHCI1394_ARRQ |
 		  OHCI1394_respTxComplete |
 		  OHCI1394_reqTxComplete |
 		  OHCI1394_isochRx |
-		  OHCI1394_isochTx
+		  OHCI1394_isochTx |
+		  OHCI1394_unrecoverableError
 		);
 
 	/* Enable link */
@@ -709,7 +628,7 @@
 static void ohci_remove(struct hpsb_host *host)
 {
 	struct ti_ohci *ohci;
-        
+
 	if (host != NULL) {
 		ohci = host->hostdata;
 		remove_card(ohci);
@@ -729,6 +648,9 @@
 	u32 cycleTimer;
 	int idx = d->prg_ind;
 
+	DBGMSG(ohci->id, "Inserting packet for node %d, tlabel=%d, tcode=0x%x, speed=%d\n",
+			packet->node_id, packet->tlabel, packet->tcode, packet->speed_code);
+
 	d->prg_cpu[idx]->begin.address = 0;
 	d->prg_cpu[idx]->begin.branchAddress = 0;
 	if (d->ctx==1) {
@@ -737,75 +659,132 @@
 		 * the 16 lower bits of the status... let's try 1 sec timeout 
 		 */ 
 		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-		d->prg_cpu[idx]->begin.status = 
+		d->prg_cpu[idx]->begin.status = cpu_to_le32(
 			(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | 
-			((cycleTimer&0x01fff000)>>12);
+			((cycleTimer&0x01fff000)>>12));
 
 		DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",
 		       cycleTimer, d->prg_cpu[idx]->begin.status);
-	}
-	else 
+	} else 
 		d->prg_cpu[idx]->begin.status = 0;
 
-        if (packet->type == raw) {
-		d->prg_cpu[idx]->data[0] = OHCI1394_TCODE_PHY<<4;
-		d->prg_cpu[idx]->data[1] = packet->header[0];
-		d->prg_cpu[idx]->data[2] = packet->header[1];
-        }
-        else {
-		d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
-			(packet->header[0] & 0xFFFF);
-		d->prg_cpu[idx]->data[1] = (packet->header[1] & 0xFFFF) | 
-			(packet->header[0] & 0xFFFF0000);
-		d->prg_cpu[idx]->data[2] = packet->header[2];
-		d->prg_cpu[idx]->data[3] = packet->header[3];
-        }
+        if ( (packet->type == async) || (packet->type == raw) ) {
 
-	if (packet->data_size) { /* block transmit */
-		d->prg_cpu[idx]->begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;
-		d->prg_cpu[idx]->end.control = OUTPUT_LAST | packet->data_size;
-		/* 
-		 * FIXME: check that the packet data buffer
-		 * do not cross a page boundary 
-		 */
-		if (cross_bound((unsigned long)packet->data, 
-				packet->data_size)>0) {
-			/* FIXME: do something about it */
-			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      ": packet data addr: %p size %d bytes "
-			      "cross page boundary", 
-			      packet->data, packet->data_size);
-		}
-
-		d->prg_cpu[idx]->end.address =
-			pci_map_single(ohci->dev, packet->data,
-				       packet->data_size, PCI_DMA_TODEVICE);
-		d->prg_cpu[idx]->end.branchAddress = 0;
-		d->prg_cpu[idx]->end.status = 0;
-		if (d->branchAddrPtr) 
-			*(d->branchAddrPtr) = d->prg_bus[idx] | 0x3;
-		d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
-	}
-	else { /* quadlet transmit */
-                if (packet->type == raw)
-                        d->prg_cpu[idx]->begin.control =
-				OUTPUT_LAST_IMMEDIATE|(packet->header_size+4);
-                else
+                if (packet->type == raw) {
+			d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
+                        d->prg_cpu[idx]->data[1] = packet->header[0];
+                        d->prg_cpu[idx]->data[2] = packet->header[1];
+                } else {
+                        d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
+                                (packet->header[0] & 0xFFFF);
+                        d->prg_cpu[idx]->data[1] =
+                                (packet->header[1] & 0xFFFF) | 
+                                (packet->header[0] & 0xFFFF0000);
+                        d->prg_cpu[idx]->data[2] = packet->header[2];
+                        d->prg_cpu[idx]->data[3] = packet->header[3];
+			packet_swab(d->prg_cpu[idx]->data, packet->tcode,
+					packet->header_size>>2, ohci->payload_swap);
+                }
+
+                if (packet->data_size) { /* block transmit */
                         d->prg_cpu[idx]->begin.control =
-                                OUTPUT_LAST_IMMEDIATE|packet->header_size;
+                                cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x10);
+                        d->prg_cpu[idx]->end.control =
+                                cpu_to_le32(OUTPUT_LAST | packet->data_size);
+                        /* 
+                         * Check that the packet data buffer
+                         * does not cross a page boundary.
+                         */
+                        if (cross_bound((unsigned long)packet->data, 
+                                        packet->data_size)>0) {
+                                /* FIXME: do something about it */
+                                PRINT(KERN_ERR, ohci->id, __FUNCTION__
+                                      ": packet data addr: %p size %Zd bytes "
+                                      "cross page boundary", 
+                                      packet->data, packet->data_size);
+                        }
+
+                        d->prg_cpu[idx]->end.address = cpu_to_le32(
+                                pci_map_single(ohci->dev, packet->data,
+                                               packet->data_size,
+                                               PCI_DMA_TODEVICE));
+			OHCI_DMA_ALLOC("single, block transmit packet");
+
+			if (ohci->payload_swap)
+				block_swab32(packet->data, packet->data_size >> 2);
+
+                        d->prg_cpu[idx]->end.branchAddress = 0;
+                        d->prg_cpu[idx]->end.status = 0;
+                        if (d->branchAddrPtr) 
+                                *(d->branchAddrPtr) =
+					cpu_to_le32(d->prg_bus[idx] | 0x3);
+                        d->branchAddrPtr =
+                                &(d->prg_cpu[idx]->end.branchAddress);
+                } else { /* quadlet transmit */
+                        if (packet->type == raw)
+                                d->prg_cpu[idx]->begin.control = cpu_to_le32(
+                                        OUTPUT_LAST_IMMEDIATE |
+                                        (packet->header_size+4));
+                        else
+                                d->prg_cpu[idx]->begin.control = cpu_to_le32(
+                                        OUTPUT_LAST_IMMEDIATE |
+                                        packet->header_size);
+
+                        if (d->branchAddrPtr) 
+                                *(d->branchAddrPtr) =
+					cpu_to_le32(d->prg_bus[idx] | 0x2);
+                        d->branchAddrPtr =
+                                &(d->prg_cpu[idx]->begin.branchAddress);
+                }
 
-		if (d->branchAddrPtr) 
-			*(d->branchAddrPtr) = d->prg_bus[idx] | 0x2;
-		d->branchAddrPtr = &(d->prg_cpu[idx]->begin.branchAddress);
-	}
+        } else { /* iso packet */
+                d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
+                        (packet->header[0] & 0xFFFF);
+                d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
+		packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2,
+				ohci->payload_swap);
+  
+                d->prg_cpu[idx]->begin.control = cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x8);
+                d->prg_cpu[idx]->end.control = cpu_to_le32(
+                        OUTPUT_LAST | 0x08000000 | packet->data_size);
+                d->prg_cpu[idx]->end.address = cpu_to_le32(
+				pci_map_single(ohci->dev, packet->data,
+				packet->data_size, PCI_DMA_TODEVICE));
+		OHCI_DMA_ALLOC("single, iso transmit packet");
+
+		if (ohci->payload_swap)
+			block_swab32(packet->data, packet->data_size>>2);
+
+                d->prg_cpu[idx]->end.branchAddress = 0;
+                d->prg_cpu[idx]->end.status = 0;
+                DBGMSG(ohci->id, "iso xmit context info: header[%08x %08x]\n"
+                       "                       begin=%08x %08x %08x %08x\n"
+                       "                             %08x %08x %08x %08x\n"
+                       "                       end  =%08x %08x %08x %08x",
+                       d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
+                       d->prg_cpu[idx]->begin.control,
+                       d->prg_cpu[idx]->begin.address,
+                       d->prg_cpu[idx]->begin.branchAddress,
+                       d->prg_cpu[idx]->begin.status,
+                       d->prg_cpu[idx]->data[0],
+                       d->prg_cpu[idx]->data[1],
+                       d->prg_cpu[idx]->data[2],
+                       d->prg_cpu[idx]->data[3],
+                       d->prg_cpu[idx]->end.control,
+                       d->prg_cpu[idx]->end.address,
+                       d->prg_cpu[idx]->end.branchAddress,
+                       d->prg_cpu[idx]->end.status);
+                if (d->branchAddrPtr) 
+  		        *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
+                d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
+        }
 	d->free_prgs--;
 
 	/* queue the packet in the appropriate context queue */
 	if (d->fifo_last) {
 		d->fifo_last->xnext = packet;
 		d->fifo_last = packet;
-	}
-	else {
+	} else {
 		d->fifo_first = packet;
 		d->fifo_last = packet;
 	}
@@ -814,7 +793,8 @@
 
 /*
  * This function fills the AT FIFO with the (eventual) pending packets
- * and runs or wake up the AT DMA prg if necessary.
+ * and runs or wakes up the AT DMA prg if necessary.
+ *
  * The function MUST be called with the d->lock held.
  */ 
 static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
@@ -836,27 +816,26 @@
 		d->pending_last = NULL;
 	else
 		PRINT(KERN_INFO, ohci->id, 
-		      "AT DMA FIFO ctx=%d full... waiting",d->ctx);
+		      "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx);
 
 	/* Is the context running ? (should be unless it is 
 	   the first packet to be sent in this context) */
 	if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
-		DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx);
+		DBGMSG(ohci->id,"Starting transmit DMA ctx=%d",d->ctx);
 		reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z);
 		run_context(ohci, d->ctrlSet, NULL);
 	}
 	else {
-		DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);
-		/* wake up the dma context if necessary */
-		if (!(reg_read(ohci, d->ctrlSet) & 0x400))
+		/* Wake up the dma context if necessary */
+		if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
+			DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx);
 			reg_write(ohci, d->ctrlSet, 0x1000);
+		}
 	}
 	return 1;
 }
 
-/*
- * Transmission of an async packet
- */
+/* Transmission of an async packet */
 static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 {
 	struct ti_ohci *ohci = host->hostdata;
@@ -866,20 +845,21 @@
 
 	if (packet->data_size > ohci->max_packet_size) {
 		PRINT(KERN_ERR, ohci->id, 
-		      "transmit packet size = %d too big",
+		      "Transmit packet size %Zd is too big",
 		      packet->data_size);
 		return 0;
 	}
 	packet->xnext = NULL;
 
-	/* Decide wether we have a request or a response packet */
+	/* Decide wether we have an iso, a request, or a response packet */
 	tcode = (packet->header[0]>>4)&0xf;
-	if (tcode & 0x02) d = ohci->at_resp_context;
+	if (tcode == TCODE_ISO_DATA) d = ohci->it_context;
+	else if (tcode & 0x02) d = ohci->at_resp_context;
 	else d = ohci->at_req_context;
 
 	spin_lock_irqsave(&d->lock,flags);
 
-	/* queue the packet for later insertion into to dma fifo */
+	/* queue the packet for later insertion into the dma fifo */
 	if (d->pending_last) {
 		d->pending_last->xnext = packet;
 		d->pending_last = packet;
@@ -904,15 +884,11 @@
 
 	switch (cmd) {
 	case RESET_BUS:
-		/*
-		 * FIXME: this flag might be necessary in some case
-		 */
-		PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
-		      ((host->attempt_root || attempt_root) ? 
+		PRINT (KERN_DEBUG, ohci->id, "Resetting bus on request%s",
+		       ((host->attempt_root || attempt_root) ? 
 		       " and attempting to become root" : ""));
-		reg_write(ohci, OHCI1394_PhyControl, 
-			  (host->attempt_root || attempt_root) ? 
-			  0x000041ff : 0x0000417f);
+		set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?
+				  0x80 : 0));
 		break;
 
 	case GET_CYCLE_COUNTER:
@@ -965,7 +941,7 @@
 
 		if (arg<0 || arg>63) {
 			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0_LISTEN_CHANNEL channel %d out of range", 
+			      "IS0 listne channel %d is out of range", 
 			      arg);
 			return -EFAULT;
 		}
@@ -976,7 +952,7 @@
 
 		if (ohci->ISO_channel_usage & mask) {
 			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0_LISTEN_CHANNEL channel %d already used", 
+			      "IS0 listen channel %d is already used", 
 			      arg);
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
@@ -992,7 +968,7 @@
 				  1<<arg);			
 
                 spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-                DBGMSG(ohci->id, "listening enabled on channel %d", arg);
+                DBGMSG(ohci->id, "Listening enabled on channel %d", arg);
                 break;
         }
 	case ISO_UNLISTEN_CHANNEL:
@@ -1001,7 +977,7 @@
 
 		if (arg<0 || arg>63) {
 			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0_UNLISTEN_CHANNEL channel %d out of range", 
+			      "IS0 unlisten channel %d is out of range", 
 			      arg);
 			return -EFAULT;
 		}
@@ -1012,7 +988,7 @@
 
 		if (!(ohci->ISO_channel_usage & mask)) {
 			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0_UNLISTEN_CHANNEL channel %d not used", 
+			      "IS0 unlisten channel %d is not used", 
 			      arg);
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
@@ -1028,7 +1004,7 @@
 				  1<<arg);			
 
                 spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
-                DBGMSG(ohci->id, "listening disabled on channel %d", arg);
+                DBGMSG(ohci->id, "Listening disabled on channel %d", arg);
                 break;
         }
 	default:
@@ -1063,7 +1039,7 @@
 
 	spin_lock_irqsave(&d->lock,flags);
 
-	/* is there still any packet pending in the fifo ? */
+	/* Is there still any packet pending in the fifo ? */
 	while(d->fifo_first) {
 		PRINT(KERN_INFO, ohci->id, 
 		      "AT dma reset ctx=%d, aborting transmission", 
@@ -1095,203 +1071,198 @@
 static void ohci_irq_handler(int irq, void *dev_id,
                              struct pt_regs *regs_are_unused)
 {
-	quadlet_t event,node_id;
+	quadlet_t event, node_id;
 	struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
 	struct hpsb_host *host = ohci->host;
-	int phyid = -1, isroot = 0;
-	int timeout = 255;
+	int phyid = -1, isroot = 0, flags;
 
-	do {
-		/* read the interrupt event register */
-		event=reg_read(ohci, OHCI1394_IntEventClear);
-
-		if (!event) return;
-
-		DBGMSG(ohci->id, "IntEvent: %08x",event);
-
-		/* clear the interrupt event register */
-		reg_write(ohci, OHCI1394_IntEventClear, event);
-
-		if (event & OHCI1394_busReset) {
-			if (!host->in_bus_reset) {
-				PRINT(KERN_INFO, ohci->id, "Bus reset");
-				
-				/* Wait for the AT fifo to be flushed */
-				dma_trm_reset(ohci->at_req_context);
-				dma_trm_reset(ohci->at_resp_context);
-
-				/* Subsystem call */
-				hpsb_bus_reset(ohci->host);
-				
-				ohci->NumBusResets++;
-			}
+	/* Read the interrupt event register */
+	spin_lock_irqsave(&ohci->event_lock, flags);
+	event = reg_read(ohci, OHCI1394_IntEventClear);
+	reg_write(ohci, OHCI1394_IntEventClear, event);
+	spin_unlock_irqrestore(&ohci->event_lock, flags);
+
+	if (!event) return;
+
+	DBGMSG(ohci->id, "IntEvent: %08x", event);
+
+	/* Die right here an now */
+	if (event & OHCI1394_unrecoverableError) {
+		PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!");
+		remove_card(ohci);
+		return;
+	}
+
+	/* Someone wants a bus reset. Better watch what you wish for...
+	 *
+	 * XXX: Read 6.1.1 of the OHCI1394 spec. We need to take special
+	 * care with the BusReset Interrupt, before and until the SelfID
+	 * phase is over. This is why the SelfID phase sometimes fails for
+	 * this driver.  */
+	if (event & OHCI1394_busReset) {
+		if (!host->in_bus_reset) {
+			PRINT(KERN_DEBUG, ohci->id, "Bus reset requested");
+			
+			/* Wait for the AT fifo to be flushed */
+			dma_trm_reset(ohci->at_req_context);
+			dma_trm_reset(ohci->at_resp_context);
+
+			/* Subsystem call */
+			hpsb_bus_reset(ohci->host);
+			
+			ohci->NumBusResets++;
 		}
-		/*
-		 * Problem: How can I ensure that the AT bottom half will be
-		 * executed before the AR bottom half (both events may have
-		 * occurred within a single irq event)
-		 * Quick hack: just launch it within the IRQ handler
-		 */
-		if (event & OHCI1394_reqTxComplete) { 
-			struct dma_trm_ctx *d = ohci->at_req_context;
-			DBGMSG(ohci->id, "Got reqTxComplete interrupt "
-			       "status=0x%08X", reg_read(ohci, d->ctrlSet));
+		event &= ~OHCI1394_busReset;
+	}
+
+	/* XXX: We need a way to also queue the OHCI1394_reqTxComplete,
+	 * but for right now we simply run it upon reception, to make sure
+	 * we get sent acks before response packets. This sucks mainly
+	 * because it halts the interrupt handler.  */
+	if (event & OHCI1394_reqTxComplete) {
+		struct dma_trm_ctx *d = ohci->at_req_context;
+		DBGMSG(ohci->id, "Got reqTxComplete interrupt "
+		       "status=0x%08X", reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			ohci1394_stop_context(ohci, d->ctrlClear,
+					      "reqTxComplete");
+		else
+			dma_trm_tasklet ((unsigned long)d);
+		event &= ~OHCI1394_reqTxComplete;
+	}
+	if (event & OHCI1394_respTxComplete) {
+		struct dma_trm_ctx *d = ohci->at_resp_context;
+		DBGMSG(ohci->id, "Got respTxComplete interrupt "
+		       "status=0x%08X", reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			ohci1394_stop_context(ohci, d->ctrlClear,
+					      "respTxComplete");
+		else
+			tasklet_schedule(&d->task);
+		event &= ~OHCI1394_respTxComplete;
+	}
+	if (event & OHCI1394_RQPkt) {
+		struct dma_rcv_ctx *d = ohci->ar_req_context;
+		DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
+		else
+			tasklet_schedule(&d->task);
+		event &= ~OHCI1394_RQPkt;
+	}
+	if (event & OHCI1394_RSPkt) {
+		struct dma_rcv_ctx *d = ohci->ar_resp_context;
+		DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
+		       reg_read(ohci, d->ctrlSet));
+		if (reg_read(ohci, d->ctrlSet) & 0x800)
+			ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
+		else
+			tasklet_schedule(&d->task);
+		event &= ~OHCI1394_RSPkt;
+	}
+	if (event & OHCI1394_isochRx) {
+		quadlet_t isoRecvIntEvent;
+		struct dma_rcv_ctx *d = ohci->ir_context;
+		isoRecvIntEvent = 
+			reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
+		reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
+			  isoRecvIntEvent);
+		DBGMSG(ohci->id, "Got isochRx interrupt "
+		       "status=0x%08X isoRecvIntEvent=%08x", 
+		       reg_read(ohci, d->ctrlSet), isoRecvIntEvent);
+		if (isoRecvIntEvent & 0x1) {
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
 				ohci1394_stop_context(ohci, d->ctrlClear, 
-					     "reqTxComplete");
+					     "isochRx");
 			else
-				dma_trm_bh((void *)d);
+				tasklet_schedule(&d->task);
 		}
-		if (event & OHCI1394_respTxComplete) { 
-			struct dma_trm_ctx *d = ohci->at_resp_context;
-			DBGMSG(ohci->id, "Got respTxComplete interrupt "
-			       "status=0x%08X", reg_read(ohci, d->ctrlSet));
+		if (ohci->video_tmpl) 
+			ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent,
+						      0);
+		event &= ~OHCI1394_isochRx;
+	}
+	if (event & OHCI1394_isochTx) {
+		quadlet_t isoXmitIntEvent;
+		struct dma_trm_ctx *d = ohci->it_context;
+		isoXmitIntEvent = 
+			reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
+		reg_write(ohci, OHCI1394_IsoXmitIntEventClear,
+			  isoXmitIntEvent);
+                       DBGMSG(ohci->id, "Got isochTx interrupt "
+                               "status=0x%08x isoXmitIntEvent=%08x",
+                              reg_read(ohci, d->ctrlSet), isoXmitIntEvent);
+		if (ohci->video_tmpl) 
+			ohci->video_tmpl->irq_handler(ohci->id, 0,
+						      isoXmitIntEvent);
+		if (isoXmitIntEvent & 0x1) {
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				ohci1394_stop_context(ohci, d->ctrlClear, 
-					     "respTxComplete");
+				ohci1394_stop_context(ohci, d->ctrlClear, "isochTx");
 			else
-				dma_trm_bh((void *)d);
-		}
-		if (event & OHCI1394_RQPkt) {
-			struct dma_rcv_ctx *d = ohci->ar_req_context;
-			DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
-			       reg_read(ohci, d->ctrlSet));
-			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
-			else {
-#if IEEE1394_USE_BOTTOM_HALVES
-				queue_task(&d->task, &tq_immediate);
-				mark_bh(IMMEDIATE_BH);
-#else
-				dma_rcv_bh((void *)d);
-#endif
-			}
-		}
-		if (event & OHCI1394_RSPkt) {
-			struct dma_rcv_ctx *d = ohci->ar_resp_context;
-			DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
-			       reg_read(ohci, d->ctrlSet));
-			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
-			else {
-#if IEEE1394_USE_BOTTOM_HALVES
-				queue_task(&d->task, &tq_immediate);
-				mark_bh(IMMEDIATE_BH);
-#else
-				dma_rcv_bh((void *)d);
-#endif
-			}
+				tasklet_schedule(&d->task);
 		}
-		if (event & OHCI1394_isochRx) {
-			quadlet_t isoRecvIntEvent;
-			struct dma_rcv_ctx *d = ohci->ir_context;
-			isoRecvIntEvent = 
-				reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
-			reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
-				  isoRecvIntEvent);
-			DBGMSG(ohci->id, "Got isochRx interrupt "
-			       "status=0x%08X isoRecvIntEvent=%08x", 
-			       reg_read(ohci, d->ctrlSet), isoRecvIntEvent);
-			if (isoRecvIntEvent & 0x1) {
-				if (reg_read(ohci, d->ctrlSet) & 0x800)
-					ohci1394_stop_context(ohci, d->ctrlClear, 
-						     "isochRx");
-				else {
-#if IEEE1394_USE_BOTTOM_HALVES
-					queue_task(&d->task, &tq_immediate);
-					mark_bh(IMMEDIATE_BH);
-#else
-					dma_rcv_bh((void *)d);
-#endif
-				}
-			}
-			if (ohci->video_tmpl) 
-				ohci->video_tmpl->irq_handler(ohci->id,
-							      isoRecvIntEvent,
-							      0);
-		}
-		if (event & OHCI1394_isochTx) {
-			quadlet_t isoXmitIntEvent;
-			isoXmitIntEvent = 
-				reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
-			reg_write(ohci, OHCI1394_IsoXmitIntEventClear,
-				  isoXmitIntEvent);
-			DBGMSG(ohci->id, "Got isochTx interrupt");
-			if (ohci->video_tmpl) 
-				ohci->video_tmpl->irq_handler(ohci->id, 0,
-							      isoXmitIntEvent);
-		}
-		if (event & OHCI1394_selfIDComplete) {
-			if (host->in_bus_reset) {
-				/* 
-				 * Begin Fix (JSG): Check to make sure our 
-				 * node id is valid 
-				 */
-				node_id = reg_read(ohci, OHCI1394_NodeID); 
-				if (!(node_id & 0x80000000)) {
-					mdelay(1); /* phy is upset - 
-						    * this happens once in 
-						    * a while on hot-plugs...
-						    * give it a ms to recover 
-						    */
-				}
-				/* End Fix (JSG) */
-
+		event &= ~OHCI1394_isochTx;
+	}
+	if (event & OHCI1394_selfIDComplete) {
+		if (host->in_bus_reset) {
+			node_id = reg_read(ohci, OHCI1394_NodeID); 
+
+			/* If our nodeid is not valid, give a msec delay
+			 * to let it settle in and try again.  */
+			if (!(node_id & 0x80000000)) {
+				mdelay(1);
 				node_id = reg_read(ohci, OHCI1394_NodeID);
-				if (node_id & 0x80000000) { /* NodeID valid */
-					phyid =  node_id & 0x0000003f;
-					isroot = (node_id & 0x40000000) != 0;
-
-					PRINT(KERN_INFO, ohci->id,
-					      "SelfID process finished "
-					      "(phyid %d, %s)", phyid, 
-					      (isroot ? "root" : "not root"));
-
-					handle_selfid(ohci, host, 
-						      phyid, isroot);
-				}
-				else 
-					PRINT(KERN_ERR, ohci->id, 
-					      "SelfID process finished but "
-					      "NodeID not valid: %08X",
-					      node_id);
-
-				/* Accept Physical requests from all nodes. */
-				reg_write(ohci,OHCI1394_AsReqFilterHiSet, 
-					  0xffffffff);
-				reg_write(ohci,OHCI1394_AsReqFilterLoSet, 
-					  0xffffffff);
-                       		/*
-				 * Tip by James Goodwin <jamesg@Filanet.com>
-				 * Turn on phys dma reception. We should
-				 * probably manage the filtering somehow, 
-				 * instead of blindly turning it on.
-				 */
-				reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
-					  0xffffffff);
-				reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
-					  0xffffffff);
-                        	reg_write(ohci,OHCI1394_PhyUpperBound,
-					  0xffff0000);
-			} 
-			else PRINT(KERN_ERR, ohci->id, 
-				   "self-id received outside of bus reset"
-				   "sequence");
-		}
-		if (event & OHCI1394_phyRegRcvd) {
-#if 1
-			if (host->in_bus_reset) {
-				PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", 
-				      reg_read(ohci, OHCI1394_PhyControl));
 			}
-			else PRINT(KERN_ERR, ohci->id, 
-				   "phy reg received outside of bus reset"
-				   "sequence");
-#endif
-		}
-	} while (--timeout);
 
-	PRINT(KERN_ERR, ohci->id, "irq_handler timeout event=0x%08x", event);
+			if (node_id & 0x80000000) { /* NodeID valid */
+				phyid =  node_id & 0x0000003f;
+				isroot = (node_id & 0x40000000) != 0;
+
+				PRINT(KERN_DEBUG, ohci->id,
+				      "SelfID interrupt received "
+				      "(phyid %d, %s)", phyid, 
+				      (isroot ? "root" : "not root"));
+
+				handle_selfid(ohci, host, 
+					      phyid, isroot);
+			} else 
+				PRINT(KERN_ERR, ohci->id, 
+				      "SelfID interrupt received, but "
+				      "NodeID is not valid: %08X",
+				      node_id);
+
+			/* Accept Physical requests from all nodes. */
+			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 
+				  0xffffffff);
+			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 
+				  0xffffffff);
+			/* Turn on phys dma reception. We should
+			 * probably manage the filtering somehow, 
+			 * instead of blindly turning it on.  */
+			reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
+				  0xffffffff);
+			reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
+				  0xffffffff);
+                       	reg_write(ohci,OHCI1394_PhyUpperBound,
+				  0xffff0000);
+		} else
+			PRINT(KERN_ERR, ohci->id, 
+			      "SelfID received outside of bus reset sequence");
+		event &= ~OHCI1394_selfIDComplete;
+	}
+	if (event & OHCI1394_phyRegRcvd) {
+		if (host->in_bus_reset) {
+			DBGMSG (ohci->id, "PhyControl: %08X", 
+				reg_read(ohci, OHCI1394_PhyControl));
+		} else
+			PRINT(KERN_ERR, ohci->id, 
+			      "Physical register received outside of bus reset sequence");
+		event &= ~OHCI1394_phyRegRcvd;
+	}
+	if (event)
+		PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x\n",
+		      event);
 }
 
 /* Put the buffer back into the dma context */
@@ -1300,119 +1271,123 @@
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
 
-	d->prg_cpu[idx]->status = d->buf_size;
-	d->prg_cpu[idx]->branchAddress &= 0xfffffff0;
+	d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size);
+	d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);
 	idx = (idx + d->num_desc - 1 ) % d->num_desc;
-	d->prg_cpu[idx]->branchAddress |= 0x1;
+	d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
 
 	/* wake up the dma context if necessary */
 	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
 		PRINT(KERN_INFO, ohci->id, 
-		      "Waking dma cxt=%d ... processing is probably too slow",
+		      "Waking dma ctx=%d ... processing is probably too slow",
 		      d->ctx);
 		reg_write(ohci, d->ctrlSet, 0x1000);
 	}
-}	
-
-static int block_length(struct dma_rcv_ctx *d, int idx, 
-			 quadlet_t *buf_ptr, int offset)
-{
-	int length=0;
-
-	/* Where is the data length ? */
-	if (offset+12>=d->buf_size) 
-		length = (d->buf_cpu[(idx+1)%d->num_desc]
-			  [3-(d->buf_size-offset)/4]>>16);
-	else 
-		length = (buf_ptr[3]>>16);
-	if (length % 4) length += 4 - (length % 4);
-	return length;
 }
 
-const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, 
+#define cond_le32_to_cpu(data, noswap) \
+	(noswap ? data : le32_to_cpu(data))
+
+static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, 
 			    -1, 0, -1, 0, -1, -1, 16, -1};
 
 /* 
  * Determine the length of a packet in the buffer
  * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
  */
-static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
-int offset)
+static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
+			 int offset, unsigned char tcode, int noswap)
 {
-	unsigned char 	tcode;
-	int 		length 	= -1;
-
-	/* Let's see what kind of packet is in there */
-	tcode = (buf_ptr[0] >> 4) & 0xf;
+	int length = -1;
 
 	if (d->ctx < 2) { /* Async Receive Response/Request */
 		length = TCODE_SIZE[tcode];
-		if (length == 0) 
-			length = block_length(d, idx, buf_ptr, offset) + 20;
-	}
-	else if (d->ctx==2) { /* Iso receive */
+		if (length == 0) {
+			if (offset + 12 >= d->buf_size) {
+				length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]
+						[3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);
+			} else {
+				length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);
+			}
+			length += 20;
+		}
+	} else if (d->ctx == 2) { /* Iso receive */
 		/* Assumption: buffer fill mode with header/trailer */
-		length = (buf_ptr[0]>>16);
-		if (length % 4) length += 4 - (length % 4);
-		length+=8;
+		length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
 	}
+
+	if (length > 0 && length % 4)
+		length += 4 - (length % 4);
+
 	return length;
 }
 
-/* Bottom half that processes dma receive buffers */
-static void dma_rcv_bh(void *data)
+/* Tasklet that processes dma receive buffers */
+static void dma_rcv_tasklet (unsigned long data)
 {
 	struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	unsigned int split_left, idx, offset, rescount;
 	unsigned char tcode;
-	int length, bytes_left, ack;
+	int length, bytes_left, ack, flags;
 	quadlet_t *buf_ptr;
 	char *split_ptr;
 	char msg[256];
 
-	spin_lock(&d->lock);
+	spin_lock_irqsave(&d->lock, flags);
 
 	idx = d->buf_ind;
 	offset = d->buf_offset;
 	buf_ptr = d->buf_cpu[idx] + offset/4;
 
-	rescount = d->prg_cpu[idx]->status&0xffff;
+	dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status));
+	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
+
 	bytes_left = d->buf_size - rescount - offset;
+	dma_cache_wback_inv(buf_ptr, bytes_left);
+
+	while (bytes_left > 0) {
+		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap) >> 4) & 0xf;
+
+		/* packet_length() will return < 4 for an error */
+		length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->payload_swap);
 
-	while (bytes_left>0) {
-		tcode = (buf_ptr[0]>>4)&0xf;
-		length = packet_length(d, idx, buf_ptr, offset);
-
-		if (length<4) { /* something is wrong */
-			sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d",
-				tcode, d->ctx);
+		if (length < 4) { /* something is wrong */
+			sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
+				tcode, cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap),
+				d->ctx, length);
 			ohci1394_stop_context(ohci, d->ctrlClear, msg);
-			spin_unlock(&d->lock);
+			spin_unlock_irqrestore(&d->lock, flags);
 			return;
 		}
 
-		if ((offset+length)>d->buf_size) { /* Split packet */
-			if (length>d->split_buf_size) {
+		/* The first case is where we have a packet that crosses
+		 * over more than one descriptor. The next case is where
+		 * it's all in the first descriptor.  */
+		if ((offset + length) > d->buf_size) {
+			DBGMSG(ohci->id,"Split packet rcv'd\n");
+			if (length > d->split_buf_size) {
 				ohci1394_stop_context(ohci, d->ctrlClear,
-					     "split packet size exceeded");
+					     "Split packet size exceeded");
 				d->buf_ind = idx;
 				d->buf_offset = offset;
-				spin_unlock(&d->lock);
+				spin_unlock_irqrestore(&d->lock, flags);
 				return;
 			}
-			if (d->prg_cpu[(idx+1)%d->num_desc]->status
-			    ==d->buf_size) {
-				/* other part of packet not written yet */
-				/* this should never happen I think */
-				/* anyway we'll get it on the next call */
+#if 0
+			if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
+			    == d->buf_size) {
+				/* Other part of packet not written yet.
+				 * this should never happen I think
+				 * anyway we'll get it on the next call.  */
 				PRINT(KERN_INFO, ohci->id,
-				      "Got only half a packet !!!");
+				      "Got only half a packet!");
 				d->buf_ind = idx;
 				d->buf_offset = offset;
-				spin_unlock(&d->lock);
+				spin_unlock_irqrestore(&d->lock, flags);
 				return;
 			}
+#endif
 			split_left = length;
 			split_ptr = (char *)d->spb;
 			memcpy(split_ptr,buf_ptr,d->buf_size-offset);
@@ -1421,7 +1396,9 @@
 			insert_dma_buffer(d, idx);
 			idx = (idx+1) % d->num_desc;
 			buf_ptr = d->buf_cpu[idx];
+			dma_cache_wback_inv(buf_ptr, d->buf_size);
 			offset=0;
+
 			while (split_left >= d->buf_size) {
 				memcpy(split_ptr,buf_ptr,d->buf_size);
 				split_ptr += d->buf_size;
@@ -1429,63 +1406,17 @@
 				insert_dma_buffer(d, idx);
 				idx = (idx+1) % d->num_desc;
 				buf_ptr = d->buf_cpu[idx];
+                                dma_cache_wback_inv(buf_ptr, d->buf_size);
 			}
-			if (split_left>0) {
+
+			if (split_left > 0) {
 				memcpy(split_ptr, buf_ptr, split_left);
 				offset = split_left;
 				buf_ptr += offset/4;
 			}
-
-			/* 
-			 * We get one phy packet for each bus reset. 
-			 * we know that from now on the bus topology may
-			 * have changed. Just ignore it for the moment
-			 */
-			if (tcode != 0xE) {
-				DBGMSG(ohci->id, "Split packet received from"
-				       " node %d ack=0x%02X spd=%d tcode=0x%X"
-				       " length=%d data=0x%08x ctx=%d",
-				       (d->spb[1]>>16)&0x3f,
-				       (d->spb[length/4-1]>>16)&0x1f,
-				       (d->spb[length/4-1]>>21)&0x3,
-				       tcode, length, d->spb[3], d->ctx);
-				
-				ack = (((d->spb[length/4-1]>>16)&0x1f) 
-				       == 0x11) ? 1 : 0;
-
-				hpsb_packet_received(ohci->host, d->spb, 
-						     length, ack);
-			}
-			else 
-				PRINT(KERN_INFO, ohci->id, 
-				      "Got phy packet ctx=%d ... discarded",
-				      d->ctx);
-		}
-		else {
-			/* 
-			 * We get one phy packet for each bus reset. 
-			 * we know that from now on the bus topology may
-			 * have changed. Just ignore it for the moment
-			 */
-			if (tcode != 0xE) {
-				DBGMSG(ohci->id, "Packet received from node"
-				       " %d ack=0x%02X spd=%d tcode=0x%X"
-				       " length=%d data=0x%08x ctx=%d",
-				       (buf_ptr[1]>>16)&0x3f,
-				       (buf_ptr[length/4-1]>>16)&0x1f,
-				       (buf_ptr[length/4-1]>>21)&0x3,
-				       tcode, length, buf_ptr[3], d->ctx);
-
-				ack = (((buf_ptr[length/4-1]>>16)&0x1f)
-				       == 0x11) ? 1 : 0;
-
-				hpsb_packet_received(ohci->host, buf_ptr, 
-						     length, ack);
-			}
-			else 
-				PRINT(KERN_INFO, ohci->id, 
-				      "Got phy packet ctx=%d ... discarded",
-				      d->ctx);
+		} else {
+			DBGMSG(ohci->id,"Single packet rcv'd\n");
+			memcpy(d->spb, buf_ptr, length);
 			offset += length;
 			buf_ptr += length/4;
 			if (offset==d->buf_size) {
@@ -1495,7 +1426,38 @@
 				offset=0;
 			}
 		}
-		rescount = d->prg_cpu[idx]->status & 0xffff;
+		
+		/* We get one phy packet to the async descriptor for each
+		 * bus reset. We always ignore it.  */
+		if (tcode != OHCI1394_TCODE_PHY) {
+			if (!ohci->payload_swap)
+				packet_swab(d->spb, tcode, (length - 4) >> 2, 0);
+
+			DBGMSG(ohci->id, "Packet received from node"
+				" %d ack=0x%02X spd=%d tcode=0x%X"
+				" length=%d ctx=%d tlabel=%d",
+				(d->spb[1]>>16)&0x3f,
+				(cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f,
+				(cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>21)&0x3,
+				tcode, length, d->ctx,
+				(cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>10)&0x3f);
+
+			ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f)
+				== 0x11) ? 1 : 0;
+
+			hpsb_packet_received(ohci->host, d->spb, 
+					     length-4, ack);
+		}
+#if OHCI1394_DEBUG
+		else
+			PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded",
+			       d->ctx);
+#endif
+
+                dma_cache_wback_inv(&(d->prg_cpu[idx]->status),
+                        sizeof(d->prg_cpu[idx]->status));
+	       	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
+
 		bytes_left = d->buf_size - rescount - offset;
 
 	}
@@ -1503,11 +1465,11 @@
 	d->buf_ind = idx;
 	d->buf_offset = offset;
 
-	spin_unlock(&d->lock);
+	spin_unlock_irqrestore(&d->lock, flags);
 }
 
 /* Bottom half that processes sent packets */
-static void dma_trm_bh(void *data)
+static void dma_trm_tasklet (unsigned long data)
 {
 	struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
@@ -1518,7 +1480,7 @@
 
 	spin_lock_irqsave(&d->lock, flags);
 
-	if (d->fifo_first==NULL) {
+	if (d->fifo_first == NULL) {
 #if 0
 		ohci1394_stop_context(ohci, d->ctrlClear, 
 			     "Packet sent ack received but queue is empty");
@@ -1530,12 +1492,14 @@
 	while (d->fifo_first) {
 		packet = d->fifo_first;
                 datasize = d->fifo_first->data_size;
-		if (datasize)
-			ack = d->prg_cpu[d->sent_ind]->end.status>>16;
+		if (datasize && packet->type != raw)
+			ack = le32_to_cpu(
+				d->prg_cpu[d->sent_ind]->end.status) >> 16;
 		else 
-			ack = d->prg_cpu[d->sent_ind]->begin.status>>16;
+			ack = le32_to_cpu(
+				d->prg_cpu[d->sent_ind]->begin.status) >> 16;
 
-		if (ack==0) 
+		if (ack == 0) 
 			/* this packet hasn't been sent yet*/
 			break;
 
@@ -1544,37 +1508,47 @@
 			DBGMSG(ohci->id,
 			       "Packet sent to node %d tcode=0x%X tLabel="
 			       "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", 
-			       (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f,
-			       (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf,
-			       (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f,
-			       ack&0x1f, (ack>>5)&0x3, 
-			       d->prg_cpu[d->sent_ind]->data[3]>>16,
-			       d->ctx);
+                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
+                                        >>16)&0x3f,
+                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
+                                        >>4)&0xf,
+                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
+                                        >>10)&0x3f,
+                                ack&0x1f, (ack>>5)&0x3, 
+                                le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])
+                                        >>16,
+                                d->ctx);
 		else 
 			DBGMSG(ohci->id,
 			       "Packet sent to node %d tcode=0x%X tLabel="
 			       "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", 
-			       (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f,
-			       (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf,
-			       (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f,
-			       ack&0x1f, (ack>>5)&0x3, 
-			       d->prg_cpu[d->sent_ind]->data[3],
-			       d->ctx);
+                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
+                                        >>16)&0x3f,
+                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
+                                        >>4)&0xf,
+                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
+                                        >>10)&0x3f,
+                                ack&0x1f, (ack>>5)&0x3, 
+                                le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
+                                d->ctx);
 #endif		
 
                 nextpacket = packet->xnext;
-		hpsb_packet_sent(ohci->host, packet, ack&0xf);
+		hpsb_packet_sent(ohci->host, packet, ack & 0xf);
 
-		if (datasize)
+		if (datasize) {
 			pci_unmap_single(ohci->dev, 
-					 d->prg_cpu[d->sent_ind]->end.address,
+					 cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
 					 datasize, PCI_DMA_TODEVICE);
+			OHCI_DMA_FREE("single Xmit data packet");
+		}
 
 		d->sent_ind = (d->sent_ind+1)%d->num_desc;
 		d->free_prgs++;
 		d->fifo_first = nextpacket;
 	}
-	if (d->fifo_first==NULL) d->fifo_last=NULL;
+	if (d->fifo_first == NULL)
+		d->fifo_last = NULL;
 
 	dma_trm_flush(ohci, d);
 
@@ -1594,26 +1568,32 @@
 	
 	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
 
+	tasklet_kill(&(*d)->task);
+
 	if ((*d)->buf_cpu) {
 		for (i=0; i<(*d)->num_desc; i++)
-			if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) 
+			if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) {
 				pci_free_consistent(
 					ohci->dev, (*d)->buf_size, 
 					(*d)->buf_cpu[i], (*d)->buf_bus[i]);
+				OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i);
+			}
 		kfree((*d)->buf_cpu);
 		kfree((*d)->buf_bus);
 	}
 	if ((*d)->prg_cpu) {
 		for (i=0; i<(*d)->num_desc; i++) 
-			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i])
+			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) {
 				pci_free_consistent(
 					ohci->dev, sizeof(struct dma_cmd), 
 					(*d)->prg_cpu[i], (*d)->prg_bus[i]);
+				OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i);
+			}
 		kfree((*d)->prg_cpu);
 		kfree((*d)->prg_bus);
 	}
 	if ((*d)->spb) kfree((*d)->spb);
-	
+
 	kfree(*d);
 	*d = NULL;
 
@@ -1631,11 +1611,13 @@
 	d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), 
 					  GFP_KERNEL);
 
-	if (d==NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma_rcv_ctx");
+	if (d == NULL) {
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx");
 		return NULL;
 	}
 
+	memset (d, 0, sizeof (struct dma_rcv_ctx));
+
 	d->ohci = (void *)ohci;
 	d->ctx = ctx;
 
@@ -1656,7 +1638,7 @@
 	d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
 
 	if (d->buf_cpu == NULL || d->buf_bus == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer");
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer");
 		free_dma_rcv_ctx(&d);
 		return NULL;
 	}
@@ -1668,7 +1650,7 @@
 	d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
 
 	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg");
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg");
 		free_dma_rcv_ctx(&d);
 		return NULL;
 	}
@@ -1678,21 +1660,22 @@
 	d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);
 
 	if (d->spb == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate split buffer");
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer");
 		free_dma_rcv_ctx(&d);
 		return NULL;
 	}
 
 	for (i=0; i<d->num_desc; i++) {
-                d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, 
+		d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, 
 						     d->buf_size,
 						     d->buf_bus+i);
+		OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i);
 		
-                if (d->buf_cpu[i] != NULL) {
+		if (d->buf_cpu[i] != NULL) {
 			memset(d->buf_cpu[i], 0, d->buf_size);
 		} else {
 			PRINT(KERN_ERR, ohci->id, 
-			      "failed to allocate dma buffer");
+			      "Failed to allocate dma buffer");
 			free_dma_rcv_ctx(&d);
 			return NULL;
 		}
@@ -1701,12 +1684,13 @@
                 d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
 						     sizeof(struct dma_cmd),
 						     d->prg_bus+i);
+		OHCI_DMA_ALLOC("consistent dma_rcv prg[%d]", i);
 
                 if (d->prg_cpu[i] != NULL) {
                         memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
 		} else {
 			PRINT(KERN_ERR, ohci->id, 
-			      "failed to allocate dma prg");
+			      "Failed to allocate dma prg");
 			free_dma_rcv_ctx(&d);
 			return NULL;
 		}
@@ -1714,11 +1698,8 @@
 
         spin_lock_init(&d->lock);
 
-        /* initialize bottom handler */
-        d->task.sync = 0;
-        INIT_TQ_LINK(d->task);
-        d->task.routine = dma_rcv_bh;
-        d->task.data = (void*)d;
+	/* initialize tasklet */
+	tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d);
 
 	return d;
 }
@@ -1736,12 +1717,16 @@
 
 	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
 
+	tasklet_kill(&(*d)->task);
+
 	if ((*d)->prg_cpu) {
 		for (i=0; i<(*d)->num_desc; i++) 
-			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i])
+			if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) {
 				pci_free_consistent(
 					ohci->dev, sizeof(struct at_dma_prg), 
 					(*d)->prg_cpu[i], (*d)->prg_bus[i]);
+				OHCI_DMA_FREE("consistent dma_trm prg[%d]", i);
+			}
 		kfree((*d)->prg_cpu);
 		kfree((*d)->prg_bus);
 	}
@@ -1762,10 +1747,12 @@
 					  GFP_KERNEL);
 
 	if (d==NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma_trm_ctx");
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx");
 		return NULL;
 	}
 
+	memset (d, 0, sizeof (struct dma_trm_ctx));
+
 	d->ohci = (void *)ohci;
 	d->ctx = ctx;
 	d->num_desc = num_desc;
@@ -1780,7 +1767,7 @@
 	d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
 
 	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg");
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate at dma prg");
 		free_dma_trm_ctx(&d);
 		return NULL;
 	}
@@ -1791,12 +1778,13 @@
                 d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
 						     sizeof(struct at_dma_prg),
 						     d->prg_bus+i);
+		OHCI_DMA_ALLOC("consistent dma_trm prg[%d]", i);
 
                 if (d->prg_cpu[i] != NULL) {
                         memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
 		} else {
 			PRINT(KERN_ERR, ohci->id, 
-			      "failed to allocate at dma prg");
+			      "Failed to allocate at dma prg");
 			free_dma_trm_ctx(&d);
 			return NULL;
 		}
@@ -1805,105 +1793,333 @@
         spin_lock_init(&d->lock);
 
         /* initialize bottom handler */
-        INIT_TQ_LINK(d->task);
-        d->task.routine = dma_trm_bh;
-        d->task.data = (void*)d;
+	tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);
 
 	return d;
 }
 
-static u32 ohci_crc16(unsigned *data, int length)
+static u16 ohci_crc16 (u32 *ptr, int length)
 {
-        int check=0, i;
-        int shift, sum, next=0;
-
-        for (i = length; i; i--) {
-                for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
-                        next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-                }
-                check = next & 0xffff;
-                data++;
-        }
+	int shift;
+	u32 crc, sum, data;
 
-        return check;
+	crc = 0;
+	for (; length > 0; length--) {
+		data = *ptr++;
+		for (shift = 28; shift >= 0; shift -= 4) {
+			sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;
+			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
+		}
+		crc &= 0xffff;
+	}
+	return crc;
 }
 
+/* Config ROM macro implementation influenced by NetBSD OHCI driver */
+
+struct config_rom_unit {
+	u32 *start;
+	u32 *refer;
+	int length;
+	int refunit;
+};
+
+struct config_rom_ptr {
+	u32 *data;
+	int unitnum;
+	struct config_rom_unit unitdir[10];
+};
+
+#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q))
+
+#define cf_put_4bytes(cr, b1, b2, b3, b4) \
+	(((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4)))
+
+#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32((key) << 24) | (val))
+
+#define cf_put_crc16(cr, unit) \
+	(*(cr)->unitdir[unit].start = cpu_to_be32(((cr)->unitdir[unit].length << 16) | \
+	 ohci_crc16((cr)->unitdir[unit].start + 1, (cr)->unitdir[unit].length)))
+
+#define cf_unit_begin(cr, unit)					\
+do {								\
+	if ((cr)->unitdir[unit].refer != NULL) {		\
+		*(cr)->unitdir[unit].refer |=			\
+			(cr)->data - (cr)->unitdir[unit].refer;	\
+		cf_put_crc16(cr, (cr)->unitdir[unit].refunit);	\
+        }							\
+        (cr)->unitnum = (unit);					\
+        (cr)->unitdir[unit].start = (cr)->data++;		\
+} while (0)
+
+#define cf_put_refer(cr, key, unit)			\
+do {							\
+	(cr)->unitdir[unit].refer = (cr)->data;		\
+	(cr)->unitdir[unit].refunit = (cr)->unitnum;	\
+	((cr)->data++)[0] = cpu_to_be32((key) << 24);		\
+} while(0)
+
+#define cf_unit_end(cr)						\
+do {								\
+	(cr)->unitdir[(cr)->unitnum].length = (cr)->data -	\
+		((cr)->unitdir[(cr)->unitnum].start + 1);	\
+	cf_put_crc16((cr), (cr)->unitnum);			\
+} while(0)
+
 static void ohci_init_config_rom(struct ti_ohci *ohci)
 {
+	struct config_rom_ptr cr;
+
+	memset(&cr, 0, sizeof(cr));
+	memset (ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));
+
+	cr.data = ohci->csr_config_rom_cpu;
+
+	/* Bus info block */
+	cf_unit_begin(&cr, 0);
+	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusID));
+	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusOptions));
+	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDHi));
+	cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo));
+	cf_unit_end(&cr);
+
+	DBGMSG(ohci->id, "GUID: %08x:%08x\n", reg_read(ohci, OHCI1394_GUIDHi),
+		reg_read(ohci, OHCI1394_GUIDLo));
+
+	/* IEEE P1212 suggests the initial ROM header CRC should only
+	 * cover the header itself (and not the entire ROM). Since we use
+	 * this, then we can make our bus_info_len the same as the CRC
+	 * length.  */
+	ohci->csr_config_rom_cpu[0] |= cpu_to_be32(
+		(be32_to_cpu(ohci->csr_config_rom_cpu[0]) & 0x00ff0000) << 8);
+	reg_write(ohci, OHCI1394_ConfigROMhdr,
+		  be32_to_cpu(ohci->csr_config_rom_cpu[0]));
+
+	/* Root directory */
+	cf_unit_begin(&cr, 1);
+	cf_put_keyval(&cr, 0x03, 0x00005e);	/* Vendor ID */
+	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */
+	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */
+	cf_put_refer(&cr, 0xd1, 3);		/* IPv4 unit directory */
+	cf_put_refer(&cr, 0xd1, 4);		/* IPv6 unit directory */
+	/* NOTE: Add other unit referers here, and append at bottom */
+	cf_unit_end(&cr);
+
+	/* Textual description - "Linux 1394" */
+	cf_unit_begin(&cr, 2);
+	cf_put_keyval(&cr, 0, 0);
+	cf_put_1quad(&cr, 0);
+	cf_put_4bytes(&cr, 'L', 'i', 'n', 'u');
+	cf_put_4bytes(&cr, 'x', ' ', '1', '3');
+	cf_put_4bytes(&cr, '9', '4', 0x0, 0x0);
+	cf_unit_end(&cr);
+
+	/* IPv4 unit directory, RFC 2734 */
+	cf_unit_begin(&cr, 3);
+	cf_put_keyval(&cr, 0x12, 0x00005e);	/* Unit spec ID */
+	cf_put_refer(&cr, 0x81, 6);		/* Textual description unit */
+	cf_put_keyval(&cr, 0x13, 0x000001);	/* Unit software version */
+	cf_put_refer(&cr, 0x81, 7);		/* Textual description unit */
+	cf_unit_end(&cr);
+
+	cf_unit_begin(&cr, 6);
+	cf_put_keyval(&cr, 0, 0);
+	cf_put_1quad(&cr, 0);
+	cf_put_4bytes(&cr, 'I', 'A', 'N', 'A');
+	cf_unit_end(&cr);
+
+	cf_unit_begin(&cr, 7);
+	cf_put_keyval(&cr, 0, 0);
+	cf_put_1quad(&cr, 0);
+	cf_put_4bytes(&cr, 'I', 'P', 'v', '4');
+	cf_unit_end(&cr);
+
+	/* IPv6 unit directory, draft-ietf-ipngwg-1394-01.txt */
+	cf_unit_begin(&cr, 4);
+	cf_put_keyval(&cr, 0x12, 0x00005e);	/* Unit spec ID */
+	cf_put_refer(&cr, 0x81, 8);		/* Textual description unit */
+	cf_put_keyval(&cr, 0x13, 0x000002);	/* (Proposed) Unit software version */
+	cf_put_refer(&cr, 0x81, 9);		/* Textual description unit */
+	cf_unit_end(&cr);
+
+	cf_unit_begin(&cr, 8);
+	cf_put_keyval(&cr, 0, 0);
+	cf_put_1quad(&cr, 0);
+	cf_put_4bytes(&cr, 'I', 'A', 'N', 'A');
+	cf_unit_end(&cr);
+
+	cf_unit_begin(&cr, 9);
+	cf_put_keyval(&cr, 0, 0);
+	cf_put_1quad(&cr, 0);
+	cf_put_4bytes(&cr, 'I', 'P', 'v', '6');
+	cf_unit_end(&cr);
+
+	return;
+}
+
+static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr)
+{
+	struct ti_ohci *ohci=host->hostdata;
+
+	DBGMSG(ohci->id, "request csr_rom address: %p",
+		ohci->csr_config_rom_cpu);
+
+	*ptr = ohci->csr_config_rom_cpu;
+
+	return sizeof(ohci->csr_config_rom_cpu);
+}
+
+int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,
+                      quadlet_t compare, int sel)
+{
 	int i;
+	reg_write(ohci, OHCI1394_CSRData, *data);
+	reg_write(ohci, OHCI1394_CSRCompareData, compare);
+	reg_write(ohci, OHCI1394_CSRControl, sel & 0x3);
 
-	ohci_csr_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
-	ohci_csr_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
-	
-	ohci_csr_rom[0] = 0x04040000 | ohci_crc16(ohci_csr_rom+1, 4);
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
+			break;
+
+		mdelay(10);
+	}
 
-	for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
-		ohci->csr_config_rom_cpu[i] = cpu_to_be32(ohci_csr_rom[i]);
+	*data = reg_read(ohci, OHCI1394_CSRData);
+	return 0;
 }
 
-static int add_card(struct pci_dev *dev)
+static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
+                                 quadlet_t data, quadlet_t compare)
 {
-	struct ti_ohci *ohci;	/* shortcut to currently handled device */
+	struct ti_ohci *ohci=host->hostdata;
+
+	ohci_compare_swap (ohci, &data, compare, reg);
+
+	return data;
+}
+
+struct hpsb_host_template *get_ohci_template(void)
+{
+	static struct hpsb_host_template tmpl;
+	static int initialized = 0;
+
+	if (!initialized) {
+		memset (&tmpl, 0, sizeof (struct hpsb_host_template));
 
-	if (num_of_cards == MAX_OHCI1394_CARDS) {
-		PRINT_G(KERN_WARNING, "cannot handle more than %d cards.  "
-			"Adjust MAX_OHCI1394_CARDS in ti_ohci1394.h.",
-			MAX_OHCI1394_CARDS);
-		return 1;
+		/* Initialize by field names so that a template structure
+		 * reorganization does not influence this code. */
+		tmpl.name = "ohci1394";
+
+		tmpl.initialize_host = ohci_initialize;
+		tmpl.release_host = ohci_remove;
+		tmpl.get_rom = get_ohci_rom;
+		tmpl.transmit_packet = ohci_transmit;
+		tmpl.devctl = ohci_devctl;
+		tmpl.hw_csr_reg = ohci_hw_csr_reg;
+		initialized = 1;
 	}
 
+	return &tmpl;
+}
+
+static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+	struct ti_ohci *ohci;	/* shortcut to currently handled device */
+	struct hpsb_host *host;
+	unsigned long ohci_base, ohci_len;
+	static int version_printed = 0;
+
+	if (version_printed++ == 0)
+		PRINT_G(KERN_INFO, "%s", version);
+
         if (pci_enable_device(dev)) {
-                PRINT_G(KERN_NOTICE, "failed to enable OHCI hardware %d",
-                        num_of_cards);
-                return 1;
+		/* Skip ID's that fail */
+		PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d",
+			card_id_counter++);
+		return -ENXIO;
         }
         pci_set_master(dev);
 
-	ohci = &cards[num_of_cards++];
-
-	ohci->id = num_of_cards-1;
+	host = hpsb_get_host(get_ohci_template(), sizeof (struct ti_ohci));
+	if (!host) {
+		PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");
+		return -ENOMEM;
+	}
+	ohci = host->hostdata;
+	ohci->host = host;
+	INIT_LIST_HEAD(&ohci->list);
+	ohci->id = card_id_counter++;
 	ohci->dev = dev;
-	
-	ohci->state = 0;
+	host->pdev = dev;
+	ohci->host = host;
+	pci_set_drvdata(dev, ohci);
+
+	PRINT(KERN_INFO, ohci->id, "OHCI (PCI) IEEE-1394 Controller");
+
+	/* We don't want hardware swapping */
+	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
+
+	/* Some oddball Apple controllers do not order the selfid
+	 * properly, so we make up for it here.  */
+#ifndef __LITTLE_ENDIAN
+	/* XXX: Need a better way to check this. I'm wondering if we can
+	 * read the values of the OHCI1394_PCI_HCI_Control and the
+	 * noByteSwapData registers to see if they were not cleared to
+	 * zero. Should this work? Obviously it's not defined what these
+	 * registers will read when they aren't supported. Bleh! */
+	if (dev->vendor == PCI_VENDOR_ID_APPLE) {
+		ohci->payload_swap = 1;
+		if (dev->device != PCI_DEVICE_ID_APPLE_UNI_N_FW)
+			ohci->selfid_swap = 1;
+	} else
+		ohci->selfid_swap = 1;
+#endif
 
 	/* csr_config rom allocation */
 	ohci->csr_config_rom_cpu = 
-		pci_alloc_consistent(ohci->dev, sizeof(ohci_csr_rom), 
+		pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
 				     &ohci->csr_config_rom_bus);
-	if (ohci->csr_config_rom_cpu == NULL) {
-		FAIL("failed to allocate buffer config rom");
-	}
+	OHCI_DMA_ALLOC("consistent csr_config_rom");
+	if (ohci->csr_config_rom_cpu == NULL)
+		FAIL("Failed to allocate buffer config rom");
 
 	/* 
 	 * self-id dma buffer allocation
-	 * FIXME: some early chips may need 8KB alignment for the 
-	 * selfid buffer... if you have problems a temporary fic
-	 * is to allocate 8192 bytes instead of 2048
 	 */
 	ohci->selfid_buf_cpu = 
-		pci_alloc_consistent(ohci->dev, 8192, &ohci->selfid_buf_bus);
-	if (ohci->selfid_buf_cpu == NULL) {
-		FAIL("failed to allocate DMA buffer for self-id packets");
-	}
+		pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
+                      &ohci->selfid_buf_bus);
+	OHCI_DMA_ALLOC("consistent selfid_buf");
+	if (ohci->selfid_buf_cpu == NULL)
+		FAIL("Failed to allocate DMA buffer for self-id packets");
+
 	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
-		PRINT(KERN_INFO, ohci->id, "Selfid buffer %p not aligned on "
-		      "8Kb boundary... may cause pb on some CXD3222 chip", 
+		PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on "
+		      "8Kb boundary... may cause problems on some CXD3222 chip", 
 		      ohci->selfid_buf_cpu);  
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
-	ohci->registers = ioremap_nocache(dev->base_address[0],
-					  OHCI1394_REGISTER_SIZE);
-#else
-	ohci->registers = ioremap_nocache(dev->resource[0].start,
-					  OHCI1394_REGISTER_SIZE);
-#endif
+	ohci->it_context =
+		alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC,
+				  OHCI1394_IsoXmitContextControlSet,
+				  OHCI1394_IsoXmitContextControlClear,
+				  OHCI1394_IsoXmitCommandPtr);
 
-	if (ohci->registers == NULL) {
-		FAIL("failed to remap registers - card not accessible");
-	}
+	if (ohci->it_context == NULL)
+		FAIL("Failed to allocate IT context");
+
+	ohci_base = pci_resource_start(dev, 0);
+	ohci_len = pci_resource_len(dev, 0);
 
-	PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p",
+	if (!request_mem_region (ohci_base, ohci_len, host->template->name))
+		FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.",
+		     ohci_base, ohci_len);
+
+	ohci->registers = ioremap(ohci_base, ohci_len);
+
+	if (ohci->registers == NULL)
+		FAIL("Failed to remap registers - card not accessible");
+
+	DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p",
 	      ohci->registers);
 
 	ohci->ar_req_context = 
@@ -1913,9 +2129,8 @@
 				  OHCI1394_AsReqRcvContextControlClear,
 				  OHCI1394_AsReqRcvCommandPtr);
 
-	if (ohci->ar_req_context == NULL) {
-		FAIL("failed to allocate AR Req context");
-	}
+	if (ohci->ar_req_context == NULL)
+		FAIL("Failed to allocate AR Req context");
 
 	ohci->ar_resp_context = 
 		alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC,
@@ -1924,9 +2139,8 @@
 				  OHCI1394_AsRspRcvContextControlClear,
 				  OHCI1394_AsRspRcvCommandPtr);
 	
-	if (ohci->ar_resp_context == NULL) {
-		FAIL("failed to allocate AR Resp context");
-	}
+	if (ohci->ar_resp_context == NULL)
+		FAIL("Failed to allocate AR Resp context");
 
 	ohci->at_req_context = 
 		alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC,
@@ -1934,9 +2148,8 @@
 				  OHCI1394_AsReqTrContextControlClear,
 				  OHCI1394_AsReqTrCommandPtr);
 	
-	if (ohci->at_req_context == NULL) {
-		FAIL("failed to allocate AT Req context");
-	}
+	if (ohci->at_req_context == NULL)
+		FAIL("Failed to allocate AT Req context");
 
 	ohci->at_resp_context = 
 		alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC,
@@ -1944,10 +2157,9 @@
 				  OHCI1394_AsRspTrContextControlClear,
 				  OHCI1394_AsRspTrCommandPtr);
 	
-	if (ohci->at_resp_context == NULL) {
-		FAIL("failed to allocate AT Resp context");
-	}
-				      
+	if (ohci->at_resp_context == NULL)
+		FAIL("Failed to allocate AT Resp context");
+
 	ohci->ir_context =
 		alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
 				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
@@ -1955,275 +2167,30 @@
 				  OHCI1394_IsoRcvContextControlClear,
 				  OHCI1394_IsoRcvCommandPtr);
 
-	if (ohci->ir_context == NULL) {
-		FAIL("failed to allocate IR context");
-	}
+	if (ohci->ir_context == NULL)
+		FAIL("Failed to allocate IR context");
 
-        ohci->ISO_channel_usage= 0;
+	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
 	if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
-			 OHCI1394_DRIVER_NAME, ohci)) {
-		PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq);
-	} else {
-		FAIL("failed to allocate shared interrupt %d", dev->irq);
-	}
+			 OHCI1394_DRIVER_NAME, ohci))
+		PRINT(KERN_DEBUG, ohci->id, "Allocated interrupt %d", dev->irq);
+	else
+		FAIL("Failed to allocate shared interrupt %d", dev->irq);
 
 	ohci_init_config_rom(ohci);
 
-	DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
-	       *((char *)ohci->csr_config_rom_cpu+4));
+	/* Tell the highlevel this host is ready */
+	highlevel_add_one_host (host);
 
 	return 0;
 #undef FAIL
 }
 
-#ifdef CONFIG_PROC_FS
-
-#define SR(fmt, reg0, reg1, reg2)\
-p += sprintf(p,fmt,reg_read(ohci, reg0),\
-	       reg_read(ohci, reg1),reg_read(ohci, reg2));
-
-static int ohci_get_status(char *buf)
-{
-	struct ti_ohci *ohci=&cards[0];
-	struct hpsb_host *host=ohci->host;
-	char *p=buf;
-	//unsigned char phyreg;
-	//int i, nports;
-	int i;
-
-	struct dma_rcv_ctx *d=NULL;
-	struct dma_trm_ctx *dt=NULL;
-
-	p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n");
-	p += sprintf(p,"  bus number: 0x%x Node ID: 0x%x\n", 
-		     (reg_read(ohci, OHCI1394_NodeID) & 0xFFC0) >> 6, 
-		     reg_read(ohci, OHCI1394_NodeID)&0x3f);
-#if 0
-	p += sprintf(p,"  hardware version %d.%d GUID_ROM is %s\n\n", 
-		     (reg_read(ohci, OHCI1394_Version) & 0xFF0000) >>16, 
-		     reg_read(ohci, OHCI1394_Version) & 0xFF,
-		     (reg_read(ohci, OHCI1394_Version) & 0x01000000) 
-		     ? "set" : "clear");
-#endif
-	p += sprintf(p,"\n### Host data ###\n");
-	p += sprintf(p,"node_count: %8d  ",host->node_count);
-	p += sprintf(p,"node_id   : %08X\n",host->node_id);
-	p += sprintf(p,"irm_id    : %08X  ",host->irm_id);
-	p += sprintf(p,"busmgr_id : %08X\n",host->busmgr_id);
-	p += sprintf(p,"%s %s %s\n",
-		     host->initialized ? "initialized" : "",
-		     host->in_bus_reset ? "in_bus_reset" : "",
-		     host->attempt_root ? "attempt_root" : "");
-	p += sprintf(p,"%s %s %s %s\n",
-		     host->is_root ? "root" : "",
-		     host->is_cycmst ? "cycle_master" : "",
-		     host->is_irm ? "iso_res_mgr" : "",
-		     host->is_busmgr ? "bus_mgr" : "");
-  
-	p += sprintf(p,"\n---Iso Receive DMA---\n");
-
-	d = ohci->ir_context;
-#if 0
-	for (i=0; i<d->num_desc; i++) {
-		p += sprintf(p, "IR buf[%d] : %p prg[%d]: %p\n",
-			     i, d->buf[i], i, d->prg[i]);
-	}
-#endif
-	p += sprintf(p, "Current buf: %d offset: %d\n",
-		     d->buf_ind,d->buf_offset);
-
-	p += sprintf(p,"\n---Async Receive DMA---\n");
-	d = ohci->ar_req_context;
-#if 0
-	for (i=0; i<d->num_desc; i++) {
-		p += sprintf(p, "AR req buf[%d] : %p prg[%d]: %p\n",
-			     i, d->buf[i], i, d->prg[i]);
-	}
-#endif
-	p += sprintf(p, "Ar req current buf: %d offset: %d\n",
-		     d->buf_ind,d->buf_offset);
-
-	d = ohci->ar_resp_context;
-#if 0
-	for (i=0; i<d->num_desc; i++) {
-		p += sprintf(p, "AR resp buf[%d] : %p prg[%d]: %p\n",
-			     i, d->buf[i], i, d->prg[i]);
-	}
-#endif
-	p += sprintf(p, "AR resp current buf: %d offset: %d\n",
-		     d->buf_ind,d->buf_offset);
-
-	p += sprintf(p,"\n---Async Transmit DMA---\n");
-	dt = ohci->at_req_context;
-	p += sprintf(p, "AT req prg: %d sent: %d free: %d branchAddrPtr: %p\n",
-		     dt->prg_ind, dt->sent_ind, dt->free_prgs, 
-		     dt->branchAddrPtr);
-	p += sprintf(p, "AT req queue: first: %p last: %p\n",
-		     dt->fifo_first, dt->fifo_last);
-	dt = ohci->at_resp_context;
-#if 0
-	for (i=0; i<dt->num_desc; i++) {
-		p += sprintf(p, "------- AT resp prg[%02d] ------\n",i);
-		p += sprintf(p, "%p: control  : %08x\n",
-			     &(dt->prg[i].begin.control),
-			     dt->prg[i].begin.control);
-		p += sprintf(p, "%p: address  : %08x\n",
-			     &(dt->prg[i].begin.address),
-			     dt->prg[i].begin.address);
-		p += sprintf(p, "%p: brancAddr: %08x\n",
-			     &(dt->prg[i].begin.branchAddress),
-			     dt->prg[i].begin.branchAddress);
-		p += sprintf(p, "%p: status   : %08x\n",
-			     &(dt->prg[i].begin.status),
-			     dt->prg[i].begin.status);
-		p += sprintf(p, "%p: header[0]: %08x\n",
-			     &(dt->prg[i].data[0]),
-			     dt->prg[i].data[0]);
-		p += sprintf(p, "%p: header[1]: %08x\n",
-			     &(dt->prg[i].data[1]),
-			     dt->prg[i].data[1]);
-		p += sprintf(p, "%p: header[2]: %08x\n",
-			     &(dt->prg[i].data[2]),
-			     dt->prg[i].data[2]);
-		p += sprintf(p, "%p: header[3]: %08x\n",
-			     &(dt->prg[i].data[3]),
-			     dt->prg[i].data[3]);
-		p += sprintf(p, "%p: control  : %08x\n",
-			     &(dt->prg[i].end.control),
-			     dt->prg[i].end.control);
-		p += sprintf(p, "%p: address  : %08x\n",
-			     &(dt->prg[i].end.address),
-			     dt->prg[i].end.address);
-		p += sprintf(p, "%p: brancAddr: %08x\n",
-			     &(dt->prg[i].end.branchAddress),
-			     dt->prg[i].end.branchAddress);
-		p += sprintf(p, "%p: status   : %08x\n",
-			     &(dt->prg[i].end.status),
-			     dt->prg[i].end.status);
-	}
-#endif
-	p += sprintf(p, "AR resp prg: %d sent: %d free: %d"
-		     " branchAddrPtr: %p\n",
-		     dt->prg_ind, dt->sent_ind, dt->free_prgs, 
-		     dt->branchAddrPtr);
-	p += sprintf(p, "AT resp queue: first: %p last: %p\n",
-		     dt->fifo_first, dt->fifo_last);
-	
-	/* ----- Register Dump ----- */
-	p += sprintf(p,"\n### HC Register dump ###\n");
-	SR("Version     : %08x  GUID_ROM    : %08x  ATRetries   : %08x\n",
-	   OHCI1394_Version, OHCI1394_GUID_ROM, OHCI1394_ATRetries);
-	SR("CSRData     : %08x  CSRCompData : %08x  CSRControl  : %08x\n",
-	   OHCI1394_CSRData, OHCI1394_CSRCompareData, OHCI1394_CSRControl);
-	SR("ConfigROMhdr: %08x  BusID       : %08x  BusOptions  : %08x\n",
-	   OHCI1394_ConfigROMhdr, OHCI1394_BusID, OHCI1394_BusOptions);
-	SR("GUIDHi      : %08x  GUIDLo      : %08x  ConfigROMmap: %08x\n",
-	   OHCI1394_GUIDHi, OHCI1394_GUIDLo, OHCI1394_ConfigROMmap);
-	SR("PtdWrAddrLo : %08x  PtdWrAddrHi : %08x  VendorID    : %08x\n",
-	   OHCI1394_PostedWriteAddressLo, OHCI1394_PostedWriteAddressHi, 
-	   OHCI1394_VendorID);
-	SR("HCControl   : %08x  SelfIDBuffer: %08x  SelfIDCount : %08x\n",
-	   OHCI1394_HCControlSet, OHCI1394_SelfIDBuffer, OHCI1394_SelfIDCount);
-	SR("IRMuChMaskHi: %08x  IRMuChMaskLo: %08x  IntEvent    : %08x\n",
-	   OHCI1394_IRMultiChanMaskHiSet, OHCI1394_IRMultiChanMaskLoSet, 
-	   OHCI1394_IntEventSet);
-	SR("IntMask     : %08x  IsoXmIntEvnt: %08x  IsoXmIntMask: %08x\n",
-	   OHCI1394_IntMaskSet, OHCI1394_IsoXmitIntEventSet, 
-	   OHCI1394_IsoXmitIntMaskSet);
-	SR("IsoRcvIntEvt: %08x  IsoRcvIntMsk: %08x  FairnessCtrl: %08x\n",
-	   OHCI1394_IsoRecvIntEventSet, OHCI1394_IsoRecvIntMaskSet, 
-	   OHCI1394_FairnessControl);
-	SR("LinkControl : %08x  NodeID      : %08x  PhyControl  : %08x\n",
-	   OHCI1394_LinkControlSet, OHCI1394_NodeID, OHCI1394_PhyControl);
-	SR("IsoCyclTimer: %08x  AsRqFilterHi: %08x  AsRqFilterLo: %08x\n",
-	   OHCI1394_IsochronousCycleTimer, 
-	   OHCI1394_AsReqFilterHiSet, OHCI1394_AsReqFilterLoSet);
-	SR("PhyReqFiltHi: %08x  PhyReqFiltLo: %08x  PhyUpperBnd : %08x\n",
-	   OHCI1394_PhyReqFilterHiSet, OHCI1394_PhyReqFilterLoSet, 
-	   OHCI1394_PhyUpperBound);
-	SR("AsRqTrCxtCtl: %08x  AsRqTrCmdPtr: %08x  AsRsTrCtxCtl: %08x\n",
-	   OHCI1394_AsReqTrContextControlSet, OHCI1394_AsReqTrCommandPtr, 
-	   OHCI1394_AsRspTrContextControlSet);
-	SR("AsRsTrCmdPtr: %08x  AsRqRvCtxCtl: %08x  AsRqRvCmdPtr: %08x\n",
-	   OHCI1394_AsRspTrCommandPtr, OHCI1394_AsReqRcvContextControlSet,
-	   OHCI1394_AsReqRcvCommandPtr);
-	SR("AsRsRvCtxCtl: %08x  AsRsRvCmdPtr: %08x  IntEvent    : %08x\n",
-	   OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr, 
-	   OHCI1394_IntEventSet);
-	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
-		p += sprintf(p,"IsoRCtxCtl%02d: %08x  IsoRCmdPtr%02d: %08x"
-			     "  IsoRCxtMch%02d: %08x\n", i,
-			     reg_read(ohci, 
-				      OHCI1394_IsoRcvContextControlSet+32*i),
-			     i,reg_read(ohci, OHCI1394_IsoRcvCommandPtr+32*i),
-			     i,reg_read(ohci, 
-					OHCI1394_IsoRcvContextMatch+32*i));
-	}
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
-		p += sprintf(p,"IsoTCtxCtl%02d: %08x  IsoTCmdPtr%02d: %08x\n",
-			     i, 
-			     reg_read(ohci, 
-				      OHCI1394_IsoXmitContextControlSet+32*i),
-			     i,reg_read(ohci,OHCI1394_IsoXmitCommandPtr+32*i));
-	}
-
-#if 0
-	p += sprintf(p,"\n### Phy Register dump ###\n");
-	phyreg=get_phy_reg(ohci,1);
-	p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d"
-		     "IBR: %d Gap_count: %d\n",
-		     1,phyreg,(phyreg&0x80) != 0, 
-		     (phyreg&0x40) !=0, phyreg&0x3f);
-	phyreg=get_phy_reg(ohci,2);
-	nports=phyreg&0x1f;
-	p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d"
-		     " E  : %d Ports    : %2d\n",
-		     2,phyreg, (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports);
-	for (i=0;i<nports;i++) {
-		phyreg=get_phy_reg(ohci,3+i);
-		p += sprintf(p,"offset: %d val: 0x%02x -> [port %d]"
-			     " TPA: %d TPB: %d | %s %s\n",
-			     3+i,phyreg,
-			     i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4,
-			     (phyreg&0x08) ? "child" : "parent",
-			     (phyreg&0x04) ? "connected" : "disconnected");
-	}
-	phyreg=get_phy_reg(ohci,3+i);
-	p += sprintf(p,"offset: %d val: 0x%02x -> ENV: %s Reg_count: %d\n",
-		     3+i,phyreg,
-		     (((phyreg&0xC0)>>6)==0) ? "backplane" :
-		     (((phyreg&0xC0)>>6)==1) ? "cable" : "reserved",
-		     phyreg&0x3f);
-#endif
-
-	return  p - buf;
-}
-
-static int ohci1394_read_proc(char *page, char **start, off_t off,
-			      int count, int *eof, void *data)
-{
-        int len = ohci_get_status(page);
-        if (len <= off+count) *eof = 1;
-        *start = page + off;
-        len -= off;
-        if (len>count) len = count;
-        if (len<0) len = 0;
-        return len;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-struct proc_dir_entry *ohci_proc_entry;
-#endif /* LINUX_VERSION_CODE */
-#endif /* CONFIG_PROC_FS */
-
 static void remove_card(struct ti_ohci *ohci)
 {
-	/*
-	 * Reset the board properly before leaving
-	 * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
-	 */
+	/* Reset the board properly before leaving */
 	ohci_soft_reset(ohci);
 
 	/* Free AR dma */
@@ -2237,122 +2204,35 @@
 	/* Free IR dma */
 	free_dma_rcv_ctx(&ohci->ir_context);
 
+        /* Free IT dma */
+        free_dma_trm_ctx(&ohci->it_context);
+
 	/* Free self-id buffer */
-	if (ohci->selfid_buf_cpu)
-		pci_free_consistent(ohci->dev, 2048, 
+	if (ohci->selfid_buf_cpu) {
+		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, 
 				    ohci->selfid_buf_cpu,
 				    ohci->selfid_buf_bus);
+		OHCI_DMA_FREE("consistent selfid_buf");
+	}
 	
 	/* Free config rom */
-	if (ohci->csr_config_rom_cpu)
-		pci_free_consistent(ohci->dev, sizeof(ohci_csr_rom), 
+	if (ohci->csr_config_rom_cpu) {
+		pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
 				    ohci->csr_config_rom_cpu, 
 				    ohci->csr_config_rom_bus);
+		OHCI_DMA_FREE("consistent csr_config_rom");
+	}
 	
 	/* Free the IRQ */
 	free_irq(ohci->dev->irq, ohci);
 
-	if (ohci->registers) 
+	if (ohci->registers)
 		iounmap(ohci->registers);
 
-	ohci->state = 0;
-}
-
-static int init_driver()
-{
-	struct pci_dev *dev = NULL;
-	int success = 0;
-#if USE_DEVICE
-	int i;
-#endif
-	if (num_of_cards) {
-		PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
-		return 0;
-	}
-
-	PRINT_G(KERN_INFO, "looking for Ohci1394 cards");
-
-#if USE_DEVICE
-	for (i = 0; supported_chips[i][0] != -1; i++) {
-		while ((dev = pci_find_device(supported_chips[i][0],
-					      supported_chips[i][1], dev)) 
-		       != NULL) {
-			if (add_card(dev) == 0) {
-				success = 1;
-			}
-		}
-	}
-#else
-	while ((dev = pci_find_class(PCI_CLASS_FIREWIRE_OHCI, dev)) != NULL ) {
-		if (add_card(dev) == 0) success = 1;
- 	}
-#endif /* USE_DEVICE */
-	if (success == 0) {
-		PRINT_G(KERN_WARNING, "no operable Ohci1394 cards found");
-		return -ENXIO;
-	}
+	release_mem_region (pci_resource_start(ohci->dev, 0),
+			    pci_resource_len(ohci->dev, 0));
 
-#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-	create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL);
-#else
-	if ((ohci_proc_entry = create_proc_entry("ohci1394", 0, NULL)))
-		ohci_proc_entry->read_proc = ohci1394_read_proc;
-#endif
-#endif
-	return 0;
-}
-
-static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr)
-{
-	struct ti_ohci *ohci=host->hostdata;
-
-	DBGMSG(ohci->id, "request csr_rom address: %08X",
-	       (u32)ohci->csr_config_rom_cpu);
-
-	*ptr = ohci->csr_config_rom_cpu;
-	return sizeof(ohci_csr_rom);
-}
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
-				 quadlet_t data, quadlet_t compare)
-{
-	struct ti_ohci *ohci=host->hostdata;
-	int timeout = 255;
-
-	reg_write(ohci, OHCI1394_CSRData, data);
-	reg_write(ohci, OHCI1394_CSRCompareData, compare);
-	reg_write(ohci, OHCI1394_CSRControl, reg&0x3);
-
-	while (timeout-- && !(reg_read(ohci, OHCI1394_CSRControl)&0x80000000));
-
-	if (!timeout)
-		PRINT(KERN_ERR, ohci->id, __FUNCTION__ "timeout!");
-
-	return reg_read(ohci, OHCI1394_CSRData);
-}
-		
-struct hpsb_host_template *get_ohci_template(void)
-{
-	static struct hpsb_host_template tmpl;
-	static int initialized = 0;
-
-	if (!initialized) {
-		/* Initialize by field names so that a template structure
-		 * reorganization does not influence this code. */
-		tmpl.name = "ohci1394";
-                
-		tmpl.detect_hosts = ohci_detect;
-		tmpl.initialize_host = ohci_initialize;
-		tmpl.release_host = ohci_remove;
-		tmpl.get_rom = get_ohci_rom;
-		tmpl.transmit_packet = ohci_transmit;
-		tmpl.devctl = ohci_devctl;
-		tmpl.hw_csr_reg = ohci_hw_csr_reg;
-		initialized = 1;
-	}
-
-	return &tmpl;
+	pci_set_drvdata(ohci->dev, NULL);
 }
 
 void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
@@ -2367,18 +2247,11 @@
 		i++;
 		if (i>5000) {
 			PRINT(KERN_ERR, ohci->id, 
-			      "runaway loop while stopping context...");
+			      "Runaway loop while stopping context...");
 			break;
 		}
 	}
-	if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg);
-}
-
-struct ti_ohci *ohci1394_get_struct(int card_num)
-{
-	if (card_num>=0 && card_num<num_of_cards) 
-		return &cards[card_num];
-	return NULL;
+	if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg);
 }
 
 int ohci1394_register_video(struct ti_ohci *ohci,
@@ -2397,31 +2270,75 @@
 	if (ohci->video_tmpl != tmpl) {
 		PRINT(KERN_ERR, ohci->id, 
 		      "Trying to unregister wrong video device");
-	}
-	else {
+	} else {
 		ohci->video_tmpl = NULL;
 		MOD_DEC_USE_COUNT;
 	}
 }
 
-#if 0
-int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data, 
-		      quadlet_t compare, int sel)
+#ifndef __LITTLE_ENDIAN
+
+/* Swap a series of quads inplace. */
+static __inline__ void block_swab32(quadlet_t *data, size_t size) {
+	while (size--)
+		data[size] = swab32(data[size]);
+}
+
+/* Swap headers and sometimes data too */
+static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap)
 {
-	int timeout = 255;
-	reg_write(ohci, OHCI1394_CSRData, *data);
-	reg_write(ohci, OHCI1394_CSRCompareData, compare);
-	reg_write(ohci, OHCI1394_CSRControl, sel);
-	while(!(reg_read(ohci, OHCI1394_CSRControl)&0x80000000)) {
-		if (timeout--) {
-			PRINT(KERN_INFO, ohci->id, "request_channel timeout");
-			return -1;
-		}
+	if (payload_swap) {
+		block_swab32(data, len);
+		return;
 	}
-	*data = reg_read(ohci, OHCI1394_CSRData);
-	return 0;
+
+        switch(tcode)
+        {
+		/* 4 quad header */
+		case TCODE_READB_RESPONSE:
+		case TCODE_LOCK_RESPONSE:
+		case TCODE_LOCK_REQUEST:
+		case TCODE_WRITEB:
+		case TCODE_READB:
+			block_swab32(data, 4);
+			break;
+
+		/* 3 quad header, 1 quad payload */
+		case TCODE_WRITEQ:
+		case TCODE_READQ_RESPONSE:
+			block_swab32(data, 3);
+			break;
+
+		/* 3 quad header */
+		case TCODE_WRITE_RESPONSE:
+		case TCODE_READQ:
+			block_swab32(data, 3);
+			break;
+
+		/* 2 quad header */
+		case TCODE_ISO_DATA:
+			block_swab32(data, 2);
+			break;
+
+		case OHCI1394_TCODE_PHY:
+			break; /* should never happen anyway */
+
+		case TCODE_CYCLE_START:
+			PRINT_G(KERN_ERR, "Unhandled tcode in packet_swab (0x%x)", tcode);
+			/* Atleast swap one quad */
+			block_swab32(data, 1);
+			break;
+                default:
+			PRINT_G(KERN_ERR, "Invalid tcode in packet_swab (0x%x)\n", tcode);
+                        break;
+        }
+	return;
 }
 
+#endif /* !LITTLE_ENDIAN */
+
+
+#if 0
 int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
 {
 	int csrSel;
@@ -2464,37 +2381,49 @@
 #endif
 
 EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_get_struct);
 EXPORT_SYMBOL(ohci1394_register_video);
 EXPORT_SYMBOL(ohci1394_unregister_video);
 
-#ifdef MODULE
+MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
 
-/* EXPORT_NO_SYMBOLS; */
+static void __devexit ohci1394_remove_one(struct pci_dev *pdev)
+{
+	struct ti_ohci *ohci = pci_get_drvdata(pdev);
 
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("driver for PCI Ohci IEEE-1394 controller");
-MODULE_SUPPORTED_DEVICE("ohci1394");
+	if (ohci) {
+		remove_card (ohci);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static struct pci_driver ohci1394_driver = {
+	name:		"ohci1394",
+	id_table:	ohci1394_pci_tbl,
+	probe:		ohci1394_add_one,
+	remove:		ohci1394_remove_one,
+};
 
-void cleanup_module(void)
+static void __exit ohci1394_cleanup (void)
 {
 	hpsb_unregister_lowlevel(get_ohci_template());
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry ("ohci1394", NULL);
-#endif
-
-	PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module");
+	pci_unregister_driver(&ohci1394_driver);
 }
 
-int init_module(void)
+static int __init ohci1394_init(void)
 {
-	memset(cards, 0, MAX_OHCI1394_CARDS * sizeof (struct ti_ohci));
-	
+	int ret;
 	if (hpsb_register_lowlevel(get_ohci_template())) {
-		PRINT_G(KERN_ERR, "registering failed");
+		PRINT_G(KERN_ERR, "Registering failed");
 		return -ENXIO;
-	} 
-	return 0;
+	}
+	if ((ret = pci_module_init(&ohci1394_driver))) {
+		PRINT_G(KERN_ERR, "PCI module init failed\n");
+		hpsb_unregister_lowlevel(get_ohci_template());
+		return ret;
+	}
+	return ret;
 }
 
-#endif /* MODULE */
+module_init(ohci1394_init);
+module_exit(ohci1394_cleanup);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)