patch-2.4.0-test3 linux/drivers/ieee1394/ohci1394.c

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

diff -u --recursive --new-file v2.4.0-test2/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
@@ -25,10 +25,10 @@
  * . Async Request Receive
  * . Async Response Transmit
  * . Iso Receive
+ * . DMA mmap for iso receive
  * 
  * Things not implemented:
  * . Iso Transmit
- * . DMA to user's space in iso receive mode
  * . DMA error recovery
  *
  * Things to be fixed:
@@ -38,7 +38,6 @@
  * . Self-id are sometimes not received properly 
  *   if card is initialized with no other nodes 
  *   on the bus
- * . SONY CXD3222 chip is not working properly
  * . Apple PowerBook detected but not working yet
  */
 
@@ -56,7 +55,7 @@
  * Albrecht Dress <ad@mpifr-bonn.mpg.de>
  *  . Apple PowerBook detection
  * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- *  . Reset the board properly before leaving
+ *  . Reset the board properly before leaving + misc cleanups
  */
 
 #include <linux/config.h>
@@ -130,6 +129,8 @@
 	{ 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 }
 };
 
@@ -142,617 +143,6 @@
 static void dma_trm_bh(void *data);
 static void dma_rcv_bh(void *data);
 static void dma_trm_reset(struct dma_trm_ctx *d);
-static void stop_context(struct ti_ohci *ohci, int reg, char *msg);
-
-#ifdef _VIDEO_1394_H
-
-/* Taken from bttv.c */
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
-
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- *    out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guarenteed.  We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-        unsigned long ret = 0UL;
-	pmd_t *pmd;
-	pte_t *ptep, pte;
-  
-	if (!pgd_none(*pgd)) {
-                pmd = pmd_offset(pgd, adr);
-                if (!pmd_none(*pmd)) {
-                        ptep = pte_offset(pmd, adr);
-                        pte = *ptep;
-                        if(pte_present(pte))
-                                ret = (pte_page(pte)|(adr&(PAGE_SIZE-1)));
-                }
-        }
-        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr) 
-{
-        unsigned long kva, ret;
-
-        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-        return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr) 
-{
-        unsigned long va, kva, ret;
-
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-        return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr) 
-{
-        unsigned long va, kva, ret;
-
-        va = VMALLOC_VMADDR(adr);
-        kva = uvirt_to_kva(pgd_offset_k(va), va);
-	ret = __pa(kva);
-        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-        return ret;
-}
-
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-	unsigned long adr, page;
-        
-	mem=vmalloc(size);
-	if (mem) 
-	{
-		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-	        adr=(unsigned long) mem;
-		while (size > 0) 
-                {
-	                page = kvirt_to_pa(adr);
-			mem_map_reserve(MAP_NR(__va(page)));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
-	return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-        unsigned long adr, page;
-        
-	if (mem) 
-	{
-	        adr=(unsigned long) mem;
-		while (size > 0) 
-                {
-	                page = kvirt_to_pa(adr);
-			mem_map_unreserve(MAP_NR(__va(page)));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
-	}
-}
-
-static int free_dma_fbuf_ctx(struct dma_fbuf_ctx **d)
-{
-	int i;
-	struct ti_ohci *ohci;
-	
-	if ((*d)==NULL) return -1;
-
-	ohci = (struct ti_ohci *)(*d)->ohci;
-
-	DBGMSG(ohci->id, "Freeing dma_fbuf_ctx %d", (*d)->ctx);
-
-	stop_context(ohci, (*d)->ctrlClear, NULL);
-
-	if ((*d)->buf) rvfree((void *)(*d)->buf, 
-			      (*d)->num_desc * (*d)->buf_size);
-
-	if ((*d)->prg) {
-		for (i=0;i<(*d)->num_desc;i++) 
-			if ((*d)->prg[i]) kfree((*d)->prg[i]);
-		kfree((*d)->prg);
-	}
-
-	if ((*d)->buffer_status)
-		kfree((*d)->buffer_status);
-	
-	kfree(*d);
-	*d = NULL;
-
-	return 0;
-}
-
-static struct dma_fbuf_ctx *
-alloc_dma_fbuf_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
-		   int buf_size, int channel)
-{
-	struct dma_fbuf_ctx *d=NULL;
-	int i;
-
-	d = (struct dma_fbuf_ctx *)kmalloc(sizeof(struct dma_fbuf_ctx), 
-					   GFP_KERNEL);
-
-	if (d==NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma_fbuf_ctx");
-		return NULL;
-	}
-
-	d->ohci = (void *)ohci;
-	d->ctx = ctx;
-	d->channel = channel;
-	d->num_desc = num_desc;
-	d->frame_size = buf_size;
-	if (buf_size%PAGE_SIZE) 
-		d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE);
-	else
-		d->buf_size = buf_size;
-	d->ctrlSet = OHCI1394_IrRcvContextControlSet+32*d->ctx;
-	d->ctrlClear = OHCI1394_IrRcvContextControlClear+32*d->ctx;
-	d->cmdPtr = OHCI1394_IrRcvCommandPtr+32*d->ctx;
-	d->ctxMatch = OHCI1394_IrRcvContextMatch+32*d->ctx;
-	d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
-	d->last_buffer = 0;
-	d->buf = NULL;
-	d->prg = NULL;
-	init_waitqueue_head(&d->waitq);
-
-	d->buf = rvmalloc(d->num_desc * d->buf_size);
-
-	if (d->buf == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuffer");
-		free_dma_fbuf_ctx(&d);
-		return NULL;
-	}
-	memset(d->buf, 0, d->num_desc * d->buf_size);
-
-	d->prg = kmalloc(d->num_desc * sizeof(struct dma_cmd *), 
-			 GFP_KERNEL);
-
-	if (d->prg == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuf prg");
-		free_dma_fbuf_ctx(&d);
-		return NULL;
-	}
-	memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd *));
-	
-	for (i=0;i<d->num_desc;i++) {
-		d->prg[i] = kmalloc(d->nb_cmd * sizeof(struct dma_cmd), 
-				    GFP_KERNEL);
-		if (d->prg[i] == NULL) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "failed to allocate dma fbuf prg");
-			free_dma_fbuf_ctx(&d);
-			return NULL;
-		}
-	}
-
-	d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
-				   GFP_KERNEL);
-
-	if (d->buffer_status == NULL) {
-		PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuf prg");
-		free_dma_fbuf_ctx(&d);
-		return NULL;
-	}
-	memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
-	
-	PRINT(KERN_INFO, ohci->id, "Iso DMA to User's Space: %d buffers "
-	      "of size %d allocated for a frame size %d, each with %d prgs",
-	      d->num_desc, d->buf_size, d->frame_size, d->nb_cmd);
-
-	return d;
-}
-
-static void initialize_dma_fbuf_prg(struct dma_cmd *prg, int n, 
-				    int frame_size, unsigned long buf)
-{
-	int i;
-	int leftsize = (frame_size%PAGE_SIZE) ? 
-		frame_size%PAGE_SIZE : PAGE_SIZE;
-	
-	/* the first descriptor will sync and read only 4 bytes */
-	prg[0].control = (0x280F << 16) | 4;
-	prg[0].address = kvirt_to_bus(buf);
-	prg[0].branchAddress =  (virt_to_bus(&(prg[1].control)) 
-				 & 0xfffffff0) | 0x1;
-	prg[0].status = 0;
-
-	/* the second descriptor will read PAGE_SIZE-4 bytes */
-	prg[1].control = (0x280C << 16) | (PAGE_SIZE-4);
-	prg[1].address = kvirt_to_bus(buf+4);
-	prg[1].branchAddress =  (virt_to_bus(&(prg[2].control)) 
-				 & 0xfffffff0) | 0x1;
-	prg[1].status = 0;
-	
-	for (i=2;i<n-1;i++) {
-		prg[i].control = (0x280C << 16) | PAGE_SIZE;
-		prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
-
-		prg[i].branchAddress =  
-			(virt_to_bus(&(prg[i+1].control)) 
-			 & 0xfffffff0) | 0x1;
-		
-		prg[i].status = 0;
-	}
-
-	/* the last descriptor will generate an interrupt */
-	prg[i].control = (0x283C << 16) | leftsize;
-	prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
-	prg[i].status = 0;
-}
-	
-static void initialize_dma_fbuf_ctx(struct dma_fbuf_ctx *d, int tag)
-{
-	struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
-	int i;
-
-	stop_context(ohci, d->ctrlClear, NULL);
-
-	for (i=0;i<d->num_desc;i++) {
-		initialize_dma_fbuf_prg(d->prg[i], d->nb_cmd, d->frame_size,
-					(unsigned long)d->buf+i*d->buf_size);
-	}
-	
-	/* Set bufferFill, no header */
-	reg_write(ohci, d->ctrlSet, 0x80000000);
-			
-	/* Set the context match register to match on all tags, 
-	   sync for sync tag, and listen to d->channel */
-	reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
-	
-	/* Set up isoRecvIntMask to generate interrupts */
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
-}
-
-/* find which context is listening to this channel */
-int fbuf_ctx_listening(struct ti_ohci *ohci, int channel)
-{
-	int i;
-	for (i=0;i<ohci->nb_iso_ctx-1;i++) 
-		if (ohci->fbuf_context[i]) {
-			if (ohci->fbuf_context[i]->channel==channel)
-				return i;
-		}
-		
-	PRINT(KERN_ERR, ohci->id, 
-	      "no iso context is listening to channel %d",
-	      channel);
-	return -1;
-}
-
-static int ohci_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, unsigned long arg)
-{
-	struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)];
-
-	switch(cmd)
-	{
-	case VIDEO1394_LISTEN_CHANNEL:
-	{
-		struct video1394_mmap v;
-		int i;
-
-		if(copy_from_user(&v, (void *)arg, sizeof(v)))
-			return -EFAULT;
-		if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "iso channel %d out of bound", v.channel);
-			return -EFAULT;
-		}
-                if (test_and_set_bit(v.channel, &ohci->IR_channel_usage)) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "channel %d is already taken", v.channel);
-			return -EFAULT;
-		}
-
-		/* find a free iso context */
-		for (i=0;i<ohci->nb_iso_ctx-1;i++) 
-			if (ohci->fbuf_context[i]==NULL) break;
-			    
-		if (i==(ohci->nb_iso_ctx-1)) {
-			PRINT(KERN_ERR, ohci->id, "no iso context available");
-			return -EFAULT;
-		}
-
-		if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "%d buffers of size %d bytes is too big", 
-			      v.nb_buffers, v.buf_size);
-			return -EFAULT;
-		}
-
-		ohci->fbuf_context[i] = 
-			alloc_dma_fbuf_ctx(ohci, i+1, v.nb_buffers, 
-					   v.buf_size, v.channel);
-
-		if (ohci->fbuf_context[i] == NULL) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "Couldn't allocate fbuf context");
-			return -EFAULT;
-		}
-		initialize_dma_fbuf_ctx(ohci->fbuf_context[i], v.sync_tag);
-
-		ohci->current_fbuf_ctx = ohci->fbuf_context[i];
-
-		v.buf_size = ohci->fbuf_context[i]->buf_size;
-
-		PRINT(KERN_INFO, ohci->id, 
-		      "iso context %d listen on channel %d", i+1, 
-		      v.channel);
-
-		if(copy_to_user((void *)arg, &v, sizeof(v)))
-			return -EFAULT;
-
-		return 0;
-	}
-	case VIDEO1394_UNLISTEN_CHANNEL: 
-	{
-		int channel;
-		int i;
-
-		if(copy_from_user(&channel, (void *)arg, sizeof(int)))
-			return -EFAULT;
-
-                if (!test_and_clear_bit(channel, &ohci->IR_channel_usage)) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "channel %d is not being used", channel);
-			return -EFAULT;
-		}
-
-		i = fbuf_ctx_listening(ohci, channel);
-		if (i<0) return -EFAULT;
-
-		free_dma_fbuf_ctx(&ohci->fbuf_context[i]);
-
-		PRINT(KERN_INFO, ohci->id, 
-		      "iso context %d stop listening on channel %d", 
-		      i+1, channel);
-		
-		return 0;
-	}
-	case VIDEO1394_QUEUE_BUFFER:
-	{
-		struct video1394_wait v;
-		struct dma_fbuf_ctx *d;
-		int i;
-
-		if(copy_from_user(&v, (void *)arg, sizeof(v)))
-			return -EFAULT;
-
-		i = fbuf_ctx_listening(ohci, v.channel);
-		if (i<0) return -EFAULT;
-		d = ohci->fbuf_context[i];
-
-		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "buffer %d out of range",v.buffer);
-			return -EFAULT;
-		}
-		
-		if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "buffer %d is already used",v.buffer);
-			return -EFAULT;
-		}
-		
-		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
-		d->prg[d->last_buffer][d->nb_cmd-1].branchAddress = 
-			(virt_to_bus(&(d->prg[v.buffer][0].control)) 
-			 & 0xfffffff0) | 0x1;
-
-		d->last_buffer = v.buffer;
-
-		if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) 
-		{
-			DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx);
-
-			/* Tell the controller where the first program is */
-			reg_write(ohci, d->cmdPtr, 
-				  virt_to_bus(&(d->prg[v.buffer][0])) | 0x1 );
-			
-			/* Run IR context */
-			reg_write(ohci, d->ctrlSet, 0x8000);
-		}
-		else {
-			/* Wake up dma context if necessary */
-			if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-				PRINT(KERN_INFO, ohci->id, 
-				      "Waking up iso dma ctx=%d", d->ctx);
-				reg_write(ohci, d->ctrlSet, 0x1000);
-			}
-		}
-		return 0;
-		
-	}
-	case VIDEO1394_WAIT_BUFFER:
-	{
-		struct video1394_wait v;
-		struct dma_fbuf_ctx *d;
-		int i;
-
-		if(copy_from_user(&v, (void *)arg, sizeof(v)))
-			return -EFAULT;
-
-		i = fbuf_ctx_listening(ohci, v.channel);
-		if (i<0) return -EFAULT;
-		d = ohci->fbuf_context[i];
-
-		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "buffer %d out of range",v.buffer);
-			return -EFAULT;
-		}
-
-		switch(d->buffer_status[v.buffer]) {
-		case VIDEO1394_BUFFER_READY:
-			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-			return 0;
-		case VIDEO1394_BUFFER_QUEUED:
-			while(d->buffer_status[v.buffer]!=
-			      VIDEO1394_BUFFER_READY) {
-				interruptible_sleep_on(&d->waitq);
-				if(signal_pending(current)) return -EINTR;
-			}
-			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-			return 0;
-		default:
-			PRINT(KERN_ERR, ohci->id, 
-			      "buffer %d is not queued",v.buffer);
-			return -EFAULT;
-		}
-	}
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- *	This maps the vmalloced and reserved fbuffer to user space.
- *
- *  FIXME: 
- *  - PAGE_READONLY should suffice!?
- *  - remap_page_range is kind of inefficient for page by page remapping.
- *    But e.g. pte_alloc() does not work in modules ... :-(
- */
-
-static int do_fbuf_mmap(struct ti_ohci *ohci, struct dma_fbuf_ctx *d, 
-			const char *adr, unsigned long size)
-{
-        unsigned long start=(unsigned long) adr;
-        unsigned long page,pos;
-
-        if (size>d->num_desc * d->buf_size) {
-		PRINT(KERN_ERR, ohci->id, 
-		      "fbuf context %d buf size is different from mmap size", 
-		      d->ctx);
-                return -EINVAL;
-	}
-        if (!d->buf) {
-		PRINT(KERN_ERR, ohci->id, 
-		      "fbuf context %d is not allocated", d->ctx);
-		return -EINVAL;
-	}
-
-        pos=(unsigned long) d->buf;
-        while (size > 0) {
-                page = kvirt_to_pa(pos);
-                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
-                        return -EAGAIN;
-                start+=PAGE_SIZE;
-                pos+=PAGE_SIZE;
-                size-=PAGE_SIZE;
-        }
-        return 0;
-}
-
-int ohci_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct ti_ohci *ohci=&cards[MINOR(file->f_dentry->d_inode->i_rdev)];
-	PRINT(KERN_INFO, ohci->id, "mmap");
-	if (ohci->current_fbuf_ctx == NULL) {
-		PRINT(KERN_ERR, ohci->id, "current fbuf context not set");
-		return -EINVAL;
-	}
-	
-	return do_fbuf_mmap(ohci, ohci->current_fbuf_ctx, 
-			    (char *)vma->vm_start, 
-			    (unsigned long)(vma->vm_end-vma->vm_start));
-	return 0;
-}
-
-static int ohci_open(struct inode *inode, struct file *file)
-{
-	struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)];
-	PRINT(KERN_INFO, ohci->id, "open");
-	return 0;
-}
-
-static int ohci_release(struct inode *inode, struct file *file)
-{
-	struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)];
-	int i;
-
-	PRINT(KERN_INFO, ohci->id, "release");
-	for (i=0;i<ohci->nb_iso_ctx-1;i++) 
-		if (ohci->fbuf_context[i]) {
-			if (!test_and_clear_bit(ohci->fbuf_context[i]->channel,
-						&ohci->IR_channel_usage)) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "channel %d is not being used", 
-				      ohci->fbuf_context[i]->channel);
-			}
-			PRINT(KERN_INFO, ohci->id, 
-			      "iso context %d stop listening on channel %d", 
-			      i+1, ohci->fbuf_context[i]->channel);
-			free_dma_fbuf_ctx(&ohci->fbuf_context[i]);
-		}
-	return 0;
-}
-
-static struct file_operations ohci_fops=
-{
-	owner:		THIS_MODULE,
-	ioctl:		ohci_ioctl,
-	mmap:		ohci_mmap,
-	open:		ohci_open,
-	release:	ohci_release
-};
-
-int wakeup_dma_fbuf_ctx(struct ti_ohci *ohci, struct dma_fbuf_ctx *d) 
-{
-	int i;
-
-	if (d==NULL) {
-		PRINT(KERN_ERR, ohci->id, "Iso receive event received but "
-		      "context not allocated");
-		return -EFAULT;
-	}
-
-	for (i=0;i<d->num_desc;i++) {
-		if (d->prg[i][d->nb_cmd-1].status) {
-			d->prg[i][d->nb_cmd-1].status=0;
-			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-		}
-	}
-	if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
-	return 0;
-}
-
-#endif
-
-
 
 /***********************************
  * IEEE-1394 functionality section *
@@ -827,14 +217,14 @@
 inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
 				int phyid, int isroot)
 {
-	quadlet_t *q = ohci->self_id_buffer;
+	quadlet_t *q = ohci->selfid_buf_cpu;
 	quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
 	size_t size;
 	quadlet_t lsid;
 
 	/* Self-id handling seems much easier than for the aic5800 chip.
 	   All the self-id packets, including this device own self-id,
-	   should be correctly arranged in the self_id_buffer at this
+	   should be correctly arranged in the selfid buffer at this
 	   stage */
 
 	/* Check status of self-id reception */
@@ -952,55 +342,36 @@
 	return 0;
 }
 
-static void stop_context(struct ti_ohci *ohci, int reg, char *msg)
-{
-	int i=0;
-
-	/* stop the channel program if it's still running */
-	reg_write(ohci, reg, 0x8000);
-   
-	/* Wait until it effectively stops */
-	while (reg_read(ohci, reg) & 0x400) {
-		i++;
-		if (i>5000) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "runaway loop while stopping context...");
-			break;
-		}
-	}
-	if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg);
-}
-
 /* Generate the dma receive prgs and start the context */
 static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d)
 {
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	int i;
 
-	stop_context(ohci, d->ctrlClear, NULL);
+	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
 
 	for (i=0; i<d->num_desc; i++) {
 		
 		/* end of descriptor list? */
 		if ((i+1) < d->num_desc) {
-			d->prg[i]->control = (0x283C << 16) | d->buf_size;
-			d->prg[i]->branchAddress =
-				(virt_to_bus(d->prg[i+1]) & 0xfffffff0) | 0x1;
+			d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;
+			d->prg_cpu[i]->branchAddress =
+				(d->prg_bus[i+1] & 0xfffffff0) | 0x1;
 		} else {
-			d->prg[i]->control = (0x283C << 16) | d->buf_size;
-			d->prg[i]->branchAddress =
-				(virt_to_bus(d->prg[0]) & 0xfffffff0);
+			d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;
+			d->prg_cpu[i]->branchAddress =
+				d->prg_bus[0] & 0xfffffff0;
 		}
 
-		d->prg[i]->address = virt_to_bus(d->buf[i]);
-		d->prg[i]->status = d->buf_size;
+		d->prg_cpu[i]->address = d->buf_bus[i];
+		d->prg_cpu[i]->status = d->buf_size;
 	}
 
         d->buf_ind = 0;
         d->buf_offset = 0;
 
 	/* Tell the controller where the first AR program is */
-	reg_write(ohci, d->cmdPtr, virt_to_bus(d->prg[0]) | 0x1);
+	reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
 
 	/* Run AR context */
 	reg_write(ohci, d->ctrlSet, 0x00008000);
@@ -1014,26 +385,30 @@
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 
 	/* Stop the context */
-	stop_context(ohci, d->ctrlClear, NULL);
+	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
 
         d->prg_ind = 0;
 	d->sent_ind = 0;
 	d->free_prgs = d->num_desc;
         d->branchAddrPtr = NULL;
-	d->first = NULL;
-	d->last = NULL;
+	d->fifo_first = NULL;
+	d->fifo_last = NULL;
+	d->pending_first = NULL;
+	d->pending_last = NULL;
 
 	PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
 }
 
 /* Count the number of available iso contexts */
-static int get_nb_iso_ctx(struct ti_ohci *ohci)
+static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
 {
 	int i,ctx=0;
 	u32 tmp;
 
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0xffffffff);
-	tmp = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+	reg_write(ohci, reg, 0xffffffff);
+	tmp = reg_read(ohci, reg);
+	
+	DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp);
 
 	/* Count the number of contexts */
 	for(i=0; i<32; i++) {
@@ -1062,7 +437,7 @@
 	if ((retval=ohci_soft_reset(ohci))<0) return retval;
 
 	/* 
-	 *Delay aftger soft reset to make sure everything has settled
+	 * Delay after soft reset to make sure everything has settled
 	 * down (sanity)
 	 */
 	mdelay(100);    
@@ -1089,31 +464,33 @@
 	reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000);
 
 	/* Clear interrupt registers */
-	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
 
 	/* Set up self-id dma buffer */
-	reg_write(ohci, OHCI1394_SelfIDBuffer, 
-		  virt_to_bus(ohci->self_id_buffer));
+	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
 
 	/* enable self-id dma */
 	reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);
 
 	/* Set the configuration ROM mapping register */
-	reg_write(ohci, OHCI1394_ConfigROMmap, 
-		  virt_to_bus(ohci->csr_config_rom));
-
-	/* Write the config ROM header */
-	reg_write(ohci, OHCI1394_ConfigROMhdr, 
-		  cpu_to_be32(ohci->csr_config_rom[0]));
+	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[2]));
-	
+		  cpu_to_be32(ohci->csr_config_rom_cpu[2]));
+
+#if 0	
 	/* Write the GUID into the csr config rom */
-	ohci->csr_config_rom[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
-	ohci->csr_config_rom[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
+	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);
@@ -1124,39 +501,56 @@
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
 
 	/* Initialize IR dma */
-	ohci->nb_iso_ctx = get_nb_iso_ctx(ohci);
-	PRINT(KERN_INFO, ohci->id, "%d iso contexts available",
-	      ohci->nb_iso_ctx);
-	for (i=0;i<ohci->nb_iso_ctx;i++) {
-		reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
+	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);
+	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
+		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
 			  0xffffffff);
-		reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
-		reg_write(ohci, OHCI1394_IrRcvCommandPtr+32*i, 0);
+		reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);
+		reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);
 	}
-#ifdef _VIDEO_1394_H
-	ohci->fbuf_context = (struct dma_fbuf_ctx **)
-		kmalloc((ohci->nb_iso_ctx-1)*sizeof(struct dma_fbuf_ctx *), 
-			GFP_KERNEL);
-	if (ohci->fbuf_context) 
-		memset(ohci->fbuf_context, 0,
-		       (ohci->nb_iso_ctx-1)*sizeof(struct dma_fbuf_ctx *));
-	else {
-		PRINT(KERN_ERR, ohci->id, "Cannot allocate fbuf_context");
-		return -1;
-	}
-#endif
+
 	/* Set bufferFill, isochHeader, multichannel for IR context */
-	reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
+	reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
 			
 	/* Set the context match register to match on all tags */
-	reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
+	reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000);
+
+	/* Clear the interrupt mask */
+	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
+
+	/* 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);
+	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
+		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
+			  0xffffffff);
+		reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);
+	}
+	
+	/* Clear the interrupt mask */
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
+
+	/* Clear the multi channel mask high and low registers */
+	reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
+
+	/* Initialize AR dma */
+	initialize_dma_rcv_ctx(ohci->ar_req_context);
+	initialize_dma_rcv_ctx(ohci->ar_resp_context);
 
-	/* Clear the multi channel mask high and low registers */
-	reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
+	/* Initialize AT dma */
+	initialize_dma_trm_ctx(ohci->at_req_context);
+	initialize_dma_trm_ctx(ohci->at_resp_context);
 
-	/* Clear the interrupt mask */
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+	/* Initialize IR dma */
+	initialize_dma_rcv_ctx(ohci->ir_context);
 
 	/* Set up isoRecvIntMask to generate interrupts for context 0
 	   (thanks to Michael Greger for seeing that I forgot this) */
@@ -1193,23 +587,13 @@
 		  OHCI1394_ARRQ |
 		  OHCI1394_respTxComplete |
 		  OHCI1394_reqTxComplete |
-		  OHCI1394_isochRx
+		  OHCI1394_isochRx |
+		  OHCI1394_isochTx
 		);
 
 	/* Enable link */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
 
-	/* Initialize AR dma */
-	initialize_dma_rcv_ctx(ohci->ar_req_context);
-	initialize_dma_rcv_ctx(ohci->ar_resp_context);
-
-	/* Initialize AT dma */
-	initialize_dma_trm_ctx(ohci->at_req_context);
-	initialize_dma_trm_ctx(ohci->at_resp_context);
-
-	/* Initialize IR dma */
-	initialize_dma_rcv_ctx(ohci->ir_context);
-
 	return 1;
 }
 
@@ -1223,74 +607,132 @@
 	}
 }
 
-/* Insert a packet in the AT DMA fifo and generate the DMA prg */
+/* 
+ * Insert a packet in the AT DMA fifo and generate the DMA prg
+ * FIXME: rewrite the program in order to accept packets crossing
+ *        page boundaries.
+ *        check also that a single dma descriptor doesn't cross a 
+ *        page boundary.
+ */
 static void insert_packet(struct ti_ohci *ohci,
 			  struct dma_trm_ctx *d, struct hpsb_packet *packet)
 {
 	u32 cycleTimer;
 	int idx = d->prg_ind;
 
-	d->prg[idx].begin.address = 0;
-	d->prg[idx].begin.branchAddress = 0;
+	d->prg_cpu[idx]->begin.address = 0;
+	d->prg_cpu[idx]->begin.branchAddress = 0;
 	if (d->ctx==1) {
 		/* 
 		 * For response packets, we need to put a timeout value in
 		 * the 16 lower bits of the status... let's try 1 sec timeout 
 		 */ 
 		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-		d->prg[idx].begin.status = 
+		d->prg_cpu[idx]->begin.status = 
 			(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | 
 			((cycleTimer&0x01fff000)>>12);
 
 		DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",
-		       cycleTimer, d->prg[idx].begin.status);
+		       cycleTimer, d->prg_cpu[idx]->begin.status);
 	}
 	else 
-		d->prg[idx].begin.status = 0;
+		d->prg_cpu[idx]->begin.status = 0;
 
-	d->prg[idx].data[0] = packet->speed_code<<16 |
+	d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
 		(packet->header[0] & 0xFFFF);
-	d->prg[idx].data[1] = (packet->header[1] & 0xFFFF) | 
+	d->prg_cpu[idx]->data[1] = (packet->header[1] & 0xFFFF) | 
 		(packet->header[0] & 0xFFFF0000);
-	d->prg[idx].data[2] = packet->header[2];
-	d->prg[idx].data[3] = packet->header[3];
+	d->prg_cpu[idx]->data[2] = packet->header[2];
+	d->prg_cpu[idx]->data[3] = packet->header[3];
 
 	if (packet->data_size) { /* block transmit */
-		d->prg[idx].begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;
-		d->prg[idx].end.control = OUTPUT_LAST | packet->data_size;
-		d->prg[idx].end.address = virt_to_bus(packet->data);
-		d->prg[idx].end.branchAddress = 0;
-		d->prg[idx].end.status = 0x4000;
+		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 
+		 */
+		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) = virt_to_bus(d->prg+idx) | 0x3;
-		d->branchAddrPtr = &(d->prg[idx].end.branchAddress);
+			*(d->branchAddrPtr) = d->prg_bus[idx] | 0x3;
+		d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
 	}
 	else { /* quadlet transmit */
-		d->prg[idx].begin.control = 
+		d->prg_cpu[idx]->begin.control = 
 			OUTPUT_LAST_IMMEDIATE | packet->header_size;
 		if (d->branchAddrPtr) 
-			*(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x2;
-		d->branchAddrPtr = &(d->prg[idx].begin.branchAddress);
+			*(d->branchAddrPtr) = d->prg_bus[idx] | 0x2;
+		d->branchAddrPtr = &(d->prg_cpu[idx]->begin.branchAddress);
 	}
 	d->free_prgs--;
 
 	/* queue the packet in the appropriate context queue */
-	if (d->last) {
-		d->last->xnext = packet;
-		d->last = packet;
+	if (d->fifo_last) {
+		d->fifo_last->xnext = packet;
+		d->fifo_last = packet;
+	}
+	else {
+		d->fifo_first = packet;
+		d->fifo_last = packet;
+	}
+	d->prg_ind = (d->prg_ind+1)%d->num_desc;
+}
+
+/*
+ * This function fills the AT FIFO with the (eventual) pending packets
+ * and runs or wake 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)
+{
+	int idx,z;
+
+	if (d->pending_first == NULL || d->free_prgs == 0) 
+		return 0;
+
+	idx = d->prg_ind;
+	z = (d->pending_first->data_size) ? 3 : 2;
+
+	/* insert the packets into the at dma fifo */
+	while (d->free_prgs>0 && d->pending_first) {
+		insert_packet(ohci, d, d->pending_first);
+		d->pending_first = d->pending_first->xnext;
+	}
+	if (d->pending_first == NULL) 
+		d->pending_last = NULL;
+	else
+		PRINT(KERN_INFO, ohci->id, 
+		      "AT DMA FIFO ctx=%d 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);
+		reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z);
+		run_context(ohci, d->ctrlSet, NULL);
 	}
 	else {
-		d->first = packet;
-		d->last = packet;
+		DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);
+		/* wake up the dma context if necessary */
+		if (!(reg_read(ohci, d->ctrlSet) & 0x400))
+			reg_write(ohci, d->ctrlSet, 0x1000);
 	}
+	return 1;
 }
 
+/*
+ * Transmission of an async packet
+ */
 static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 {
 	struct ti_ohci *ohci = host->hostdata;
 	struct dma_trm_ctx *d;
 	unsigned char tcode;
-	int timeout=50;
+	unsigned long flags;
 
 	if (packet->data_size >= ohci->max_packet_size) {
 		PRINT(KERN_ERR, ohci->id, 
@@ -1305,48 +747,21 @@
 	if (tcode & 0x02) d = ohci->at_resp_context;
 	else d = ohci->at_req_context;
 
-	spin_lock(&d->lock);
-
-	if (d->free_prgs<1) {
-		PRINT(KERN_INFO, ohci->id, 
-		      "AT DMA ctx=%d Running out of prgs... waiting",d->ctx);
-	}
-	while (d->free_prgs<1) {
-		spin_unlock(&d->lock);
-		interruptible_sleep_on(&d->waitq);
-		if(signal_pending(current)) return -EINTR;
-		if (timeout--<0) {
-			stop_context(ohci, d->ctrlClear, 
-				     "AT DMA runaway loop... bailing out");
-			return 0;
-		}
-		spin_lock(&d->lock);
-	}
-
-	insert_packet(ohci, d, packet);
-
-	/* 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);
-		if (packet->data_size) 
-			reg_write(ohci, d->cmdPtr, 
-				  virt_to_bus(&(d->prg[d->prg_ind])) | 0x3);
-		else 
-			reg_write(ohci, d->cmdPtr, 
-				  virt_to_bus(&(d->prg[d->prg_ind])) | 0x2);
+	spin_lock_irqsave(&d->lock,flags);
 
-		run_context(ohci, d->ctrlSet, NULL);
+	/* queue the packet for later insertion into to dma fifo */
+	if (d->pending_last) {
+		d->pending_last->xnext = packet;
+		d->pending_last = packet;
 	}
 	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))
-			reg_write(ohci, d->ctrlSet, 0x1000);
+		d->pending_first = packet;
+		d->pending_last = packet;
 	}
+	
+	dma_trm_flush(ohci, d);
 
-	d->prg_ind = (d->prg_ind+1)%d->num_desc;
-	spin_unlock(&d->lock);
+	spin_unlock_irqrestore(&d->lock,flags);
 
 	return 1;
 }
@@ -1359,7 +774,10 @@
 
 	switch (cmd) {
 	case RESET_BUS:
-	        host->attempt_root=1;
+		/*
+		 * FIXME: this flag might be necessary in some case
+		 */
+		/* host->attempt_root = 1; */
 		PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
 		      (host->attempt_root ? " and attempting to become root"
 		       : ""));
@@ -1415,14 +833,9 @@
 
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
-#if 0
-		PRINT(KERN_INFO, ohci->id, "!!! try listen on channel %d !!!",
-		      arg);
-#endif
-		
                 if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) {
-                        PRINT(KERN_INFO, ohci->id,
-                              "listening enabled on channel %d", arg);
+                        DBGMSG(ohci->id,
+			       "listening enabled on channel %d", arg);
 
                         if (arg > 31) {
                                 u32 setMask= 0x00000001;
@@ -1447,8 +860,8 @@
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
                 if (test_and_clear_bit(arg, &ohci->IR_channel_usage)) {
-                        PRINT(KERN_INFO, ohci->id,
-                              "listening disabled on iso channel %d", arg);
+                        DBGMSG(ohci->id,
+			       "listening disabled on iso channel %d", arg);
 
                         if (arg > 31) {
                                 u32 clearMask= 0x00000001;
@@ -1490,29 +903,42 @@
 static void dma_trm_reset(struct dma_trm_ctx *d)
 {
 	struct ti_ohci *ohci;
+	unsigned long flags;
 
 	if (d==NULL) {
 		PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg");
 		return;
 	}
 	ohci = (struct ti_ohci *)(d->ohci);
-	stop_context(ohci, d->ctrlClear, NULL);
+	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
 
-	spin_lock(&d->lock);
+	spin_lock_irqsave(&d->lock,flags);
+
+	/* 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", 
+		      d->ctx);
+		hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED);
+		d->fifo_first = d->fifo_first->xnext;
+	}
+	d->fifo_first = d->fifo_last = NULL;
 
 	/* is there still any packet pending ? */
-	while(d->first) {
+	while(d->pending_first) {
 		PRINT(KERN_INFO, ohci->id, 
 		      "AT dma reset ctx=%d, aborting transmission", 
 		      d->ctx);
-		hpsb_packet_sent(ohci->host, d->first, ACKX_ABORTED);
-		d->first = d->first->xnext;
+		hpsb_packet_sent(ohci->host, d->pending_first, 
+				 ACKX_ABORTED);
+		d->pending_first = d->pending_first->xnext;
 	}
-	d->first = d->last = NULL;
+	d->pending_first = d->pending_last = NULL;
+	
 	d->branchAddrPtr=NULL;
 	d->sent_ind = d->prg_ind;
 	d->free_prgs = d->num_desc;
-	spin_unlock(&d->lock);
+	spin_unlock_irqrestore(&d->lock,flags);
 }
 
 static void ohci_irq_handler(int irq, void *dev_id,
@@ -1528,10 +954,10 @@
 		/* read the interrupt event register */
 		event=reg_read(ohci, OHCI1394_IntEventClear);
 
-		DBGMSG(ohci->id, "IntEvent: %08x",event);
-
 		if (!event) return;
 
+		DBGMSG(ohci->id, "IntEvent: %08x",event);
+
 		/* clear the interrupt event register */
 		reg_write(ohci, OHCI1394_IntEventClear, event);
 
@@ -1560,7 +986,7 @@
 			DBGMSG(ohci->id, "Got reqTxComplete interrupt "
 			       "status=0x%08X", reg_read(ohci, d->ctrlSet));
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				stop_context(ohci, d->ctrlClear, 
+				ohci1394_stop_context(ohci, d->ctrlClear, 
 					     "reqTxComplete");
 			else
 				dma_trm_bh((void *)d);
@@ -1570,7 +996,7 @@
 			DBGMSG(ohci->id, "Got respTxComplete interrupt "
 			       "status=0x%08X", reg_read(ohci, d->ctrlSet));
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				stop_context(ohci, d->ctrlClear, 
+				ohci1394_stop_context(ohci, d->ctrlClear, 
 					     "respTxComplete");
 			else
 				dma_trm_bh((void *)d);
@@ -1580,9 +1006,9 @@
 			DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
 			       reg_read(ohci, d->ctrlSet));
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				stop_context(ohci, d->ctrlClear, "RQPkt");
+				ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
 			else {
-#if 1
+#if IEEE1394_USE_BOTTOM_HALVES
 				queue_task(&d->task, &tq_immediate);
 				mark_bh(IMMEDIATE_BH);
 #else
@@ -1595,9 +1021,9 @@
 			DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
 			       reg_read(ohci, d->ctrlSet));
 			if (reg_read(ohci, d->ctrlSet) & 0x800)
-				stop_context(ohci, d->ctrlClear, "RSPkt");
+				ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
 			else {
-#if 1
+#if IEEE1394_USE_BOTTOM_HALVES
 				queue_task(&d->task, &tq_immediate);
 				mark_bh(IMMEDIATE_BH);
 #else
@@ -1608,9 +1034,6 @@
 		if (event & OHCI1394_isochRx) {
 			quadlet_t isoRecvIntEvent;
 			struct dma_rcv_ctx *d = ohci->ir_context;
-#ifdef _VIDEO_1394_H
-			int i;
-#endif
 			isoRecvIntEvent = 
 				reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
 			reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
@@ -1620,10 +1043,10 @@
 			       reg_read(ohci, d->ctrlSet), isoRecvIntEvent);
 			if (isoRecvIntEvent & 0x1) {
 				if (reg_read(ohci, d->ctrlSet) & 0x800)
-					stop_context(ohci, d->ctrlClear, 
+					ohci1394_stop_context(ohci, d->ctrlClear, 
 						     "isochRx");
 				else {
-#if 1
+#if IEEE1394_USE_BOTTOM_HALVES
 					queue_task(&d->task, &tq_immediate);
 					mark_bh(IMMEDIATE_BH);
 #else
@@ -1631,12 +1054,21 @@
 #endif
 				}
 			}
-#ifdef _VIDEO_1394_H
-			for (i=0;i<ohci->nb_iso_ctx-1;i++)
-				if (isoRecvIntEvent & (1<<(i+1))) 
-					wakeup_dma_fbuf_ctx(
-						ohci,ohci->fbuf_context[i]);
-#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) {
@@ -1703,10 +1135,10 @@
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
 
-	d->prg[idx]->status = d->buf_size;
-	d->prg[idx]->branchAddress &= 0xfffffff0;
+	d->prg_cpu[idx]->status = d->buf_size;
+	d->prg_cpu[idx]->branchAddress &= 0xfffffff0;
 	idx = (idx + d->num_desc - 1 ) % d->num_desc;
-	d->prg[idx]->branchAddress |= 0x1;
+	d->prg_cpu[idx]->branchAddress |= 0x1;
 
 	/* wake up the dma context if necessary */
 	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
@@ -1724,7 +1156,7 @@
 
 	/* Where is the data length ? */
 	if (offset+12>=d->buf_size) 
-		length = (d->buf[(idx+1)%d->num_desc]
+		length = (d->buf_cpu[(idx+1)%d->num_desc]
 			  [3-(d->buf_size-offset)/4]>>16);
 	else 
 		length = (buf_ptr[3]>>16);
@@ -1769,7 +1201,7 @@
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	unsigned int split_left, idx, offset, rescount;
 	unsigned char tcode;
-	int length, bytes_left;
+	int length, bytes_left, ack;
 	quadlet_t *buf_ptr;
 	char *split_ptr;
 	char msg[256];
@@ -1778,9 +1210,9 @@
 
 	idx = d->buf_ind;
 	offset = d->buf_offset;
-	buf_ptr = d->buf[idx] + offset/4;
+	buf_ptr = d->buf_cpu[idx] + offset/4;
 
-	rescount = d->prg[idx]->status&0xffff;
+	rescount = d->prg_cpu[idx]->status&0xffff;
 	bytes_left = d->buf_size - rescount - offset;
 
 	while (bytes_left>0) {
@@ -1790,21 +1222,22 @@
 		if (length<4) { /* something is wrong */
 			sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d",
 				tcode, d->ctx);
-			stop_context(ohci, d->ctrlClear, msg);
+			ohci1394_stop_context(ohci, d->ctrlClear, msg);
 			spin_unlock(&d->lock);
 			return;
 		}
 
 		if ((offset+length)>d->buf_size) { /* Split packet */
 			if (length>d->split_buf_size) {
-				stop_context(ohci, d->ctrlClear,
+				ohci1394_stop_context(ohci, d->ctrlClear,
 					     "split packet size exceeded");
 				d->buf_ind = idx;
 				d->buf_offset = offset;
 				spin_unlock(&d->lock);
 				return;
 			}
-			if (d->prg[(idx+1)%d->num_desc]->status==d->buf_size) {
+			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 */
@@ -1822,7 +1255,7 @@
 			split_ptr += d->buf_size-offset;
 			insert_dma_buffer(d, idx);
 			idx = (idx+1) % d->num_desc;
-			buf_ptr = d->buf[idx];
+			buf_ptr = d->buf_cpu[idx];
 			offset=0;
 			while (split_left >= d->buf_size) {
 				memcpy(split_ptr,buf_ptr,d->buf_size);
@@ -1830,7 +1263,7 @@
 				split_left -= d->buf_size;
 				insert_dma_buffer(d, idx);
 				idx = (idx+1) % d->num_desc;
-				buf_ptr = d->buf[idx];
+				buf_ptr = d->buf_cpu[idx];
 			}
 			if (split_left>0) {
 				memcpy(split_ptr, buf_ptr, split_left);
@@ -1838,17 +1271,6 @@
 				buf_ptr += offset/4;
 			}
 
-			/*
-			 * Tip by James Goodwin <jamesg@Filanet.com>
-			 * We need to handle write requests that are received 
-			 * to our middle address space (posted writes).
-			 * In this case, the hardware generates an 
-			 * ack_complete... but, if we pass the packet up to 
-			 * the subsystem, it will try and send a response 
-			 * (which it shouldn't), because it assumes we 
-			 * returned ack_pending.
-			 */
-
 			/* 
 			 * We get one phy packet for each bus reset. 
 			 * we know that from now on the bus topology may
@@ -1862,22 +1284,12 @@
 				       (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;
 
-				/*
-				 * Tip by James Goodwin <jamesg@Filanet.com>
-				 * Handle case of posted writes. If we receive
-				 * an ack_complete, we should not send a
-				 * response. Fake out upper layers by turning 
-				 * the packet into a broadcast packet... we 
-				 * should really modify the core stack to 
-				 * accept an ack received argument and figure 
-				 * out whether to reply.
-				 */
-				if (((d->spb[length/4-1]>>16)&0x1f) == 0x11) {
-					d->spb[0] |= (ALL_NODES<<16);
-				}
 				hpsb_packet_received(ohci->host, d->spb, 
-						     length);
+						     length, ack);
 			}
 			else 
 				PRINT(KERN_INFO, ohci->id, 
@@ -1899,21 +1311,11 @@
 				       (buf_ptr[length/4-1]>>21)&0x3,
 				       tcode, length, buf_ptr[3], d->ctx);
 
-				/*
-				 * Tip by James Goodwin <jamesg@Filanet.com>
-				 * Handle case of posted writes. If we receive
-				 * an ack_complete, we should not send a
-				 * response. Fake out upper layers by turning 
-				 * the packet into a broadcast packet... we 
-				 * should really modify the core stack to 
-				 * accept an ack received argument and figure 
-				 * out whether to reply.
-				 */
-				if (((d->spb[length/4-1]>>16)&0x1f) == 0x11) {
-					buf_ptr[0] |= (ALL_NODES<<16);
-				}
+				ack = (((buf_ptr[length/4-1]>>16)&0x1f)
+				       == 0x11) ? 1 : 0;
+
 				hpsb_packet_received(ohci->host, buf_ptr, 
-						     length);
+						     length, ack);
 			}
 			else 
 				PRINT(KERN_INFO, ohci->id, 
@@ -1924,11 +1326,11 @@
 			if (offset==d->buf_size) {
 				insert_dma_buffer(d, idx);
 				idx = (idx+1) % d->num_desc;
-				buf_ptr = d->buf[idx];
+				buf_ptr = d->buf_cpu[idx];
 				offset=0;
 			}
 		}
-		rescount = d->prg[idx]->status & 0xffff;
+		rescount = d->prg_cpu[idx]->status & 0xffff;
 		bytes_left = d->buf_size - rescount - offset;
 
 	}
@@ -1945,32 +1347,51 @@
 	struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	struct hpsb_packet *packet;
+	unsigned long flags;
 	u32 ack;
 
-	spin_lock(&d->lock);
+	spin_lock_irqsave(&d->lock, flags);
 
-	if (d->first==NULL) {
-		stop_context(ohci, d->ctrlClear, 
+	if (d->fifo_first==NULL) {
+#if 0
+		ohci1394_stop_context(ohci, d->ctrlClear, 
 			     "Packet sent ack received but queue is empty");
-		spin_unlock(&d->lock);
+#endif
+		spin_unlock_irqrestore(&d->lock, flags);
 		return;
 	}
-	packet = d->first;
-	d->first = d->first->xnext;
-	if (d->first==NULL) d->last=NULL;
-	if (packet->data_size) 
-		ack = d->prg[d->sent_ind].end.status>>16;
-	else 
-		ack = d->prg[d->sent_ind].begin.status>>16;
-	d->sent_ind = (d->sent_ind+1)%d->num_desc;
-	d->free_prgs++;
-	spin_unlock(&d->lock);
 
-	if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
+	while (d->fifo_first) {
+		packet = d->fifo_first;
+		if (packet->data_size)
+			ack = d->prg_cpu[d->sent_ind]->end.status>>16;
+		else 
+			ack = d->prg_cpu[d->sent_ind]->begin.status>>16;
+
+		if (ack==0) 
+			/* this packet hasn't been sent yet*/
+			break;
+
+		DBGMSG(ohci->id, 
+		       "Packet sent to node %d ack=0x%X spd=%d ctx=%d",
+		       (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, 
+		       d->ctx);
+		hpsb_packet_sent(ohci->host, packet, ack&0xf);
+
+		if (packet->data_size)
+			pci_unmap_single(ohci->dev, 
+					 d->prg_cpu[d->sent_ind]->end.address,
+					 packet->data_size, PCI_DMA_TODEVICE);
+
+		d->sent_ind = (d->sent_ind+1)%d->num_desc;
+		d->free_prgs++;
+		d->fifo_first = d->fifo_first->xnext;
+	}
+	if (d->fifo_first==NULL) d->fifo_last=NULL;
+
+	dma_trm_flush(ohci, d);
 
-	DBGMSG(ohci->id, "Packet sent to node %d ack=0x%X spd=%d ctx=%d",
-	       (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, d->ctx);
-	hpsb_packet_sent(ohci->host, packet, ack&0xf);
+	spin_unlock_irqrestore(&d->lock, flags);
 }
 
 static int free_dma_rcv_ctx(struct dma_rcv_ctx **d)
@@ -1984,17 +1405,25 @@
 
 	DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx);
 	
-	stop_context(ohci, (*d)->ctrlClear, NULL);
+	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
 
-	if ((*d)->buf) {
-		for (i=0; i<(*d)->num_desc; i++)
-			if ((*d)->buf[i]) kfree((*d)->buf[i]);
-		kfree((*d)->buf);
-	}
-	if ((*d)->prg) {
+	if ((*d)->buf_cpu) {
 		for (i=0; i<(*d)->num_desc; i++)
-			if ((*d)->prg[i]) kfree((*d)->prg[i]);
-		kfree((*d)->prg);
+			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]);
+		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])
+				pci_free_consistent(
+					ohci->dev, sizeof(struct dma_cmd), 
+					(*d)->prg_cpu[i], (*d)->prg_bus[i]);
+		kfree((*d)->prg_cpu);
+		kfree((*d)->prg_bus);
 	}
 	if ((*d)->spb) kfree((*d)->spb);
 	
@@ -2030,27 +1459,34 @@
 	d->ctrlClear = ctrlClear;
 	d->cmdPtr = cmdPtr;
 
-	d->buf = NULL;
-	d->prg = NULL;
+	d->buf_cpu = NULL;
+	d->buf_bus = NULL;
+	d->prg_cpu = NULL;
+	d->prg_bus = NULL;
 	d->spb = NULL;
 
-	d->buf = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
+	d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
+	d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
 
-	if (d->buf == NULL) {
+	if (d->buf_cpu == NULL || d->buf_bus == NULL) {
 		PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer");
 		free_dma_rcv_ctx(&d);
 		return NULL;
 	}
-	memset(d->buf, 0, d->num_desc * sizeof(quadlet_t*));
+	memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*));
+	memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
-	d->prg = kmalloc(d->num_desc * 	sizeof(struct dma_cmd*), GFP_KERNEL);
+	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*), 
+			     GFP_KERNEL);
+	d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
 
-	if (d->prg == NULL) {
+	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
 		PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg");
 		free_dma_rcv_ctx(&d);
 		return NULL;
 	}
-	memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd*));
+	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*));
+	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
 	d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);
 
@@ -2061,10 +1497,12 @@
 	}
 
 	for (i=0; i<d->num_desc; i++) {
-                d->buf[i] = kmalloc(d->buf_size, GFP_KERNEL);
+                d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, 
+						     d->buf_size,
+						     d->buf_bus+i);
 		
-                if (d->buf[i] != NULL) {
-			memset(d->buf[i], 0, d->buf_size);
+                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");
@@ -2072,10 +1510,13 @@
 			return NULL;
 		}
 
-                d->prg[i]= kmalloc(sizeof(struct dma_cmd), GFP_KERNEL);
+		
+                d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
+						     sizeof(struct dma_cmd),
+						     d->prg_bus+i);
 
-                if (d->prg[i] != NULL) {
-                        memset(d->prg[i], 0, sizeof(struct dma_cmd));
+                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");
@@ -2098,6 +1539,7 @@
 static int free_dma_trm_ctx(struct dma_trm_ctx **d)
 {
 	struct ti_ohci *ohci;
+	int i;
 
 	if (*d==NULL) return -1;
 
@@ -2105,9 +1547,18 @@
 
 	DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx);
 
-	stop_context(ohci, (*d)->ctrlClear, NULL);
+	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
+
+	if ((*d)->prg_cpu) {
+		for (i=0; i<(*d)->num_desc; 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]);
+		kfree((*d)->prg_cpu);
+		kfree((*d)->prg_bus);
+	}
 
-	if ((*d)->prg) kfree((*d)->prg);
 	kfree(*d);
 	*d = NULL;
 	return 0;
@@ -2118,6 +1569,7 @@
 		  int ctrlSet, int ctrlClear, int cmdPtr)
 {
 	struct dma_trm_ctx *d=NULL;
+	int i;
 
 	d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), 
 					  GFP_KERNEL);
@@ -2133,16 +1585,35 @@
 	d->ctrlSet = ctrlSet;
 	d->ctrlClear = ctrlClear;
 	d->cmdPtr = cmdPtr;
-	d->prg = NULL;
+	d->prg_cpu = NULL;
+	d->prg_bus = NULL;
 
-	d->prg = kmalloc(d->num_desc * sizeof(struct at_dma_prg), GFP_KERNEL);
+	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), 
+			     GFP_KERNEL);
+	d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
 
-	if (d->prg == NULL) {
+	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
 		PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg");
 		free_dma_trm_ctx(&d);
 		return NULL;
 	}
-	memset(d->prg, 0, d->num_desc * sizeof(struct at_dma_prg));
+	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
+	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
+
+	for (i=0; i<d->num_desc; i++) {
+                d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
+						     sizeof(struct at_dma_prg),
+						     d->prg_bus+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");
+			free_dma_trm_ctx(&d);
+			return NULL;
+		}
+	}
 
         spin_lock_init(&d->lock);
 
@@ -2150,15 +1621,42 @@
         d->task.routine = dma_trm_bh;
         d->task.data = (void*)d;
 
-        init_waitqueue_head(&d->waitq);
-
 	return d;
 }
 
+static u32 ohci_crc16(unsigned *data, 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++;
+        }
+
+        return check;
+}
+
+static void ohci_init_config_rom(struct ti_ohci *ohci)
+{
+	int i;
+
+	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<sizeof(ohci_csr_rom)/4;i++)
+		ohci->csr_config_rom_cpu[i] = cpu_to_be32(ohci_csr_rom[i]);
+}
+
 static int add_card(struct pci_dev *dev)
 {
 	struct ti_ohci *ohci;	/* shortcut to currently handled device */
-	int i;
 
 	if (num_of_cards == MAX_OHCI1394_CARDS) {
 		PRINT_G(KERN_WARNING, "cannot handle more than %d cards.  "
@@ -2182,21 +1680,29 @@
 	ohci->state = 0;
 
 	/* csr_config rom allocation */
-	ohci->csr_config_rom = kmalloc(1024, GFP_KERNEL);
-	if (ohci->csr_config_rom == NULL) {
+	ohci->csr_config_rom_cpu = 
+		pci_alloc_consistent(ohci->dev, sizeof(ohci_csr_rom), 
+				     &ohci->csr_config_rom_bus);
+	if (ohci->csr_config_rom_cpu == NULL) {
 		FAIL("failed to allocate buffer config rom");
 	}
-	for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
-		ohci->csr_config_rom[i] = cpu_to_be32(ohci_csr_rom[i]);
 
 	DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
-	       *((char *)ohci->csr_config_rom+4));
+	       *((char *)ohci->csr_config_rom_cpu+4));
 
-	/* self-id dma buffer allocation */
-	ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL);
-	if (ohci->self_id_buffer == NULL) {
+	/* 
+	 * self-id dma buffer allocation
+	 * FIXME: some early chips may need 8KB alignment for the 
+	 * selfid buffer
+	 */
+	ohci->selfid_buf_cpu = 
+		pci_alloc_consistent(ohci->dev, 2048, &ohci->selfid_buf_bus);
+	if (ohci->selfid_buf_cpu == NULL) {
 		FAIL("failed to allocate DMA buffer for self-id packets");
 	}
+	if ((unsigned long)ohci->selfid_buf_cpu & 0xfff)
+		PRINT(KERN_INFO, ohci->id, "Selfid buffer %p not aligned on "
+		      "8Kb boundary", ohci->selfid_buf_cpu);  
 
 	ohci->ar_req_context = 
 		alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
@@ -2241,9 +1747,9 @@
 	ohci->ir_context =
 		alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
 				  IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-				  OHCI1394_IrRcvContextControlSet,
-				  OHCI1394_IrRcvContextControlClear,
-				  OHCI1394_IrRcvCommandPtr);
+				  OHCI1394_IsoRcvContextControlSet,
+				  OHCI1394_IsoRcvContextControlClear,
+				  OHCI1394_IsoRcvCommandPtr);
 
 	if (ohci->ir_context == NULL) {
 		FAIL("failed to allocate IR context");
@@ -2274,6 +1780,8 @@
 		FAIL("failed to allocate shared interrupt %d", dev->irq);
 	}
 
+	ohci_init_config_rom(ohci);
+
 	return 0;
 #undef FAIL
 }
@@ -2297,12 +1805,9 @@
 	//unsigned char phyreg;
 	//int i, nports;
 	int i;
+
 	struct dma_rcv_ctx *d=NULL;
 	struct dma_trm_ctx *dt=NULL;
-#ifdef _VIDEO_1394_H
-	int j;
-	struct dma_fbuf_ctx *f=ohci->fbuf_context[0];
-#endif
 
 	p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n");
 	p += sprintf(p,"  bus number: 0x%x Node ID: 0x%x\n", 
@@ -2332,26 +1837,6 @@
   
 	p += sprintf(p,"\n---Iso Receive DMA---\n");
 
-#ifdef _VIDEO_1394_H
-
-#if 0
-	if (f!=NULL) {
-		for (i=0; i<f->num_desc; i++) {
-			for (j=0;j<f->nb_cmd;j++) {
-				p += sprintf(p, 
-					     "prg[%d][%d]: %p %08x %08x %08x %08x\n",
-					     i,j,virt_to_bus(&(f->prg[i][j])),
-					     f->prg[i][j].control,
-					     f->prg[i][j].address,
-					     f->prg[i][j].branchAddress,
-					     f->prg[i][j].status);
-			}
-		}
-	}
-#endif
-
-#else
-
 	d = ohci->ir_context;
 #if 0
 	for (i=0; i<d->num_desc; i++) {
@@ -2389,7 +1874,7 @@
 		     dt->prg_ind, dt->sent_ind, dt->free_prgs, 
 		     dt->branchAddrPtr);
 	p += sprintf(p, "AT req queue: first: %p last: %p\n",
-		     dt->first, dt->last);
+		     dt->fifo_first, dt->fifo_last);
 	dt = ohci->at_resp_context;
 #if 0
 	for (i=0; i<dt->num_desc; i++) {
@@ -2437,15 +1922,14 @@
 		     dt->prg_ind, dt->sent_ind, dt->free_prgs, 
 		     dt->branchAddrPtr);
 	p += sprintf(p, "AT resp queue: first: %p last: %p\n",
-		     dt->first, dt->last);
-#endif
+		     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("CSRReadData : %08x  CSRCompData : %08x  CSRControl  : %08x\n",
-	   OHCI1394_CSRReadData, OHCI1394_CSRCompareData, OHCI1394_CSRControl);
+	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",
@@ -2481,14 +1965,21 @@
 	SR("AsRsRvCtxCtl: %08x  AsRsRvCmdPtr: %08x  IntEvent    : %08x\n",
 	   OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr, 
 	   OHCI1394_IntEventSet);
-	for (i=0;i<4;i++) {
+	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_IrRcvContextControlSet+32*i),
-			     i,reg_read(ohci, OHCI1394_IrRcvCommandPtr+32*i),
+				      OHCI1394_IsoRcvContextControlSet+32*i),
+			     i,reg_read(ohci, OHCI1394_IsoRcvCommandPtr+32*i),
 			     i,reg_read(ohci, 
-					OHCI1394_IrRcvContextMatch+32*i));
+					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
@@ -2554,9 +2045,11 @@
 
 static void remove_card(struct ti_ohci *ohci)
 {
-#ifdef _VIDEO_1394_H
-	int i;
-#endif
+	/*
+	 * Reset the board properly before leaving
+	 * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
+	 */
+	ohci_soft_reset(ohci);
 
 	/* Free AR dma */
 	free_dma_rcv_ctx(&ohci->ar_req_context);
@@ -2569,28 +2062,18 @@
 	/* Free IR dma */
 	free_dma_rcv_ctx(&ohci->ir_context);
 
-#ifdef _VIDEO_1394_H
-	/* Free the frame buffer context */
-	if (ohci->fbuf_context)
-		for (i=0;i<ohci->nb_iso_ctx-1;i++) {
-			free_dma_fbuf_ctx(&ohci->fbuf_context[i]);
-		}
-#endif
-
-	/*
-	 * Reset the board properly before leaving
-	 * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
-	 */
-	ohci_soft_reset(ohci);
-
 	/* Free self-id buffer */
-	if (ohci->self_id_buffer)
-		kfree(ohci->self_id_buffer);
+	if (ohci->selfid_buf_cpu)
+		pci_free_consistent(ohci->dev, 2048, 
+				    ohci->selfid_buf_cpu,
+				    ohci->selfid_buf_bus);
 	
 	/* Free config rom */
-	if (ohci->csr_config_rom)
-		kfree(ohci->csr_config_rom);
-
+	if (ohci->csr_config_rom_cpu)
+		pci_free_consistent(ohci->dev, sizeof(ohci_csr_rom), 
+				    ohci->csr_config_rom_cpu, 
+				    ohci->csr_config_rom_bus);
+	
 	/* Free the IRQ */
 	free_irq(ohci->dev->irq, ohci);
 
@@ -2646,9 +2129,9 @@
 	struct ti_ohci *ohci=host->hostdata;
 
 	DBGMSG(ohci->id, "request csr_rom address: %08X",
-	       (u32)ohci->csr_config_rom);
+	       (u32)ohci->csr_config_rom_cpu);
 
-	*ptr = ohci->csr_config_rom;
+	*ptr = ohci->csr_config_rom_cpu;
 	return sizeof(ohci_csr_rom);
 }
 
@@ -2675,6 +2158,118 @@
 	return &tmpl;
 }
 
+void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
+{
+	int i=0;
+
+	/* stop the channel program if it's still running */
+	reg_write(ohci, reg, 0x8000);
+   
+	/* Wait until it effectively stops */
+	while (reg_read(ohci, reg) & 0x400) {
+		i++;
+		if (i>5000) {
+			PRINT(KERN_ERR, ohci->id, 
+			      "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;
+}
+
+int ohci1394_register_video(struct ti_ohci *ohci,
+			    struct video_template *tmpl)
+{
+	if (ohci->video_tmpl)
+		return -ENFILE;
+	ohci->video_tmpl = tmpl;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+	
+void ohci1394_unregister_video(struct ti_ohci *ohci,
+			       struct video_template *tmpl)
+{
+	if (ohci->video_tmpl != tmpl) {
+		PRINT(KERN_ERR, ohci->id, 
+		      "Trying to unregister wrong video device");
+	}
+	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)
+{
+	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;
+		}
+	}
+	*data = reg_read(ohci, OHCI1394_CSRData);
+	return 0;
+}
+
+int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
+{
+	int csrSel;
+	quadlet_t chan, data1=0, data2=0;
+	int timeout = 32;
+
+	if (channel<32) {
+		chan = 1<<channel;
+		csrSel = 2;
+	}
+	else {
+		chan = 1<<(channel-32);
+		csrSel = 3;
+	}
+	if (ohci_compare_swap(ohci, &data1, 0, csrSel)<0) {
+		PRINT(KERN_INFO, ohci->id, "request_channel timeout");
+		return -1;
+	}
+	while (timeout--) {
+		if (data1 & chan) {
+			PRINT(KERN_INFO, ohci->id, 
+			      "request channel %d failed", channel);
+			return -1;
+		}
+		data2 = data1;
+		data1 |= chan;
+		if (ohci_compare_swap(ohci, &data1, data2, csrSel)<0) {
+			PRINT(KERN_INFO, ohci->id, "request_channel timeout");
+			return -1;
+		}
+		if (data1==data2) {
+			PRINT(KERN_INFO, ohci->id, 
+			      "request channel %d succeded", channel);
+			return 0;
+		}
+	}
+	PRINT(KERN_INFO, ohci->id, "request channel %d failed", channel);
+	return -1;
+}
+#endif
+
+EXPORT_SYMBOL(ohci1394_stop_context);
+EXPORT_SYMBOL(ohci1394_get_struct);
+EXPORT_SYMBOL(ohci1394_register_video);
+EXPORT_SYMBOL(ohci1394_unregister_video);
 
 #ifdef MODULE
 
@@ -2695,10 +2290,6 @@
 #endif
 #endif
 
-#ifdef _VIDEO_1394_H
-        unregister_chrdev(OHCI1394_MAJOR, "ohci1394");
-#endif
-	
 	PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n");
 }
 
@@ -2709,17 +2300,8 @@
 	if (hpsb_register_lowlevel(get_ohci_template())) {
 		PRINT_G(KERN_ERR, "registering failed\n");
 		return -ENXIO;
-	} else {
-#ifdef _VIDEO_1394_H
-		if (register_chrdev(OHCI1394_MAJOR, "ohci1394", &ohci_fops))
-		{
-			printk("ohci1394: unable to get major %d\n", 
-			       OHCI1394_MAJOR);
-			return -EIO;
-		}
-#endif
-		return 0;
-	}
+	} 
+	return 0;
 }
 
 #endif /* MODULE */

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