patch-2.4.21 linux-2.4.21/drivers/ieee1394/dv1394.c

Next file: linux-2.4.21/drivers/ieee1394/dv1394.h
Previous file: linux-2.4.21/drivers/ieee1394/dv1394-private.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/ieee1394/dv1394.c linux-2.4.21/drivers/ieee1394/dv1394.c
@@ -53,6 +53,12 @@
     via pci_alloc_consistent()
     
   DONE:
+  - during reception, better handling of dropped frames and continuity errors
+  - during reception, prevent DMA from bypassing the irq tasklets
+  - reduce irq rate during reception (1/250 packets).
+  - add many more internal buffers during reception with scatter/gather dma.
+  - add dbc (continuity) checking on receive, increment status.dropped_frames
+    if not continuous.
   - restart IT DMA after a bus reset
   - safely obtain and release ISO Tx channels in cooperation with OHCI driver
   - map received DIF blocks to their proper location in DV frame (ensure
@@ -91,13 +97,12 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -109,6 +114,7 @@
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
+#include "ieee1394_hotplug.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"	
@@ -168,8 +174,6 @@
 static LIST_HEAD(dv1394_cards);
 static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
 
-static struct hpsb_highlevel *hl_handle; /* = NULL; */
-
 static LIST_HEAD(dv1394_devfs);
 struct dv1394_devfs_entry {
 	struct list_head list;
@@ -186,39 +190,6 @@
 	return (struct video_card*) file->private_data;
 }
 
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-/* note: we no longer use mem_map_reserve, because it causes a memory
-   leak, and setting vma->vm_flags to VM_RESERVED should be sufficient
-   to pin the pages in memory anyway. */
-
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-
-	mem = vmalloc_32(size);
-
-	if(mem)
-		memset(mem, 0, size); /* Clear the ram out, 
-					 no junk to the user */
-	return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-	if (mem) {
-		vfree(mem);
-	}
-}
-
-/***********************************/
-/* END Memory management functions */
-/***********************************/
-
-
 /*** FRAME METHODS *********************************************************/
 
 static void frame_reset(struct frame *f)
@@ -447,11 +418,7 @@
 		/******************************/
 
 		/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
-		fill_output_more_immediate( &(block->u.out.omi),
-					    /* tag - what is this??? */ 1,
-					    video->channel,
-					    /* sync tag - what is this??? */ 0,
-					    payload_size);
+		fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
 
 		if(empty_packet) {
 			/* second descriptor - OUTPUT_LAST for CIP header */
@@ -502,8 +469,8 @@
 						  PAGE_SIZE - (data_p % PAGE_SIZE),
 
 						  /* DMA address of data_p */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p - (unsigned long) video->dv_buf.kvirt));
 
 				fill_output_last( &(block->u.out.u.full.u.cross.ol),
 					  
@@ -517,8 +484,8 @@
 						  480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
 
 						  /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
 
 				if(first_packet)
 					f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
@@ -552,8 +519,8 @@
 
 						  
 						  /* DMA address of data_p */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p - (unsigned long) video->dv_buf.kvirt));
 				
 				if(first_packet)
 					f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
@@ -594,13 +561,8 @@
 	   to loop back up to the top */
 	*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
-
-	/* make the latest version of the frame buffer visible to the PCI card */
-	/* could optimize this by only syncing the pages associated with this frame */
-	pci_dma_sync_sg(video->ohci->dev,
-			&video->user_dma.sglist[0],
-			video->user_dma.n_dma_pages,
-			PCI_DMA_TODEVICE);
+	/* make the latest version of this frame visible to the PCI card */
+	dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
 
 	/* lock against DMA interrupt */
 	spin_lock_irqsave(&video->spinlock, irq_flags);
@@ -732,7 +694,7 @@
 		wmb();
 #endif
 
-		
+		video->dma_running = 1;
 
 		/* set the 'run' bit */
 		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
@@ -799,6 +761,9 @@
 	int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
 	int dif_block = p->data[2];
 
+	/* sanity check */
+	if (dif_sequence > 11 || dif_block > 149) return;
+		
 	switch (section_type) {
 	case 0:           /* 1 Header block */
 	        memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
@@ -826,47 +791,66 @@
 }
 
 
-static void start_dma_receive(struct video_card *video, struct frame *frame)
+static void start_dma_receive(struct video_card *video)
 {
-	/* reset iso recv control register */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
-	wmb();
+	if (video->first_run == 1) {
+		video->first_run = 0;
+		
+		/* start DMA once all of the frames are READY */
+		video->n_clear_frames = 0;
+		video->first_clear_frame = -1;
+		video->current_packet = 0;
+		video->active_frame = 0;
+		
+		/* reset iso recv control register */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+		wmb();
+		
+		/* clear bufferFill, set isochHeader and speed (0=100) */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
 	
-	/* clear bufferFill, set isochHeader and speed (0=100) */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+		/* match on all tags, listen on channel */
+		reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+		
+		/* address and first descriptor block + Z=1 */
+		reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
+			  video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
+		wmb();
 
-	/* match on all tags, listen on channel */
-	reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-	
-	/* address and first descriptor block + Z=1 */
-	reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
-		  frame->descriptor_pool_dma | 1); /* Z=1 */
-	wmb();
-	
-	/* run */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
-	flush_pci_write(video->ohci);
-	
-	debug_printk("dv1394: DMA started\n");
+		video->dma_running = 1;
 
-#if DV1394_DEBUG_LEVEL >= 2
-	{
-		int i;
+		/* run */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+		flush_pci_write(video->ohci);
+		
+		debug_printk("dv1394: DMA started\n");
 	
-		for(i = 0; i < 1000; ++i) {
-			mdelay(1);
-			if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
-				printk("DMA ACTIVE after %d msec\n", i);
-				break;
+#if DV1394_DEBUG_LEVEL >= 2
+		{
+			int i;
+		
+			for(i = 0; i < 1000; ++i) {
+				mdelay(1);
+				if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+					printk("DMA ACTIVE after %d msec\n", i);
+					break;
+				}
 			}
+			if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+				printk("DEAD, event = %x\n", 
+					   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+			} else
+				printk("RUNNING!\n");
 		}
-		if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-			printk("DEAD, event = %x\n", 
-			       reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-		} else
-			printk("RUNNING!\n");
-	}
 #endif
+	} 
+	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+		debug_printk("DEAD, event = %x\n", 
+			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+		/* wake */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+	}
 }
 
 
@@ -874,7 +858,7 @@
    receive_packets() - build the DMA program for receiving
 */
 
-static void receive_packets(struct video_card *video, struct frame *f)
+static void receive_packets(struct video_card *video)
 {
 	struct DMA_descriptor_block *block = NULL;
 	dma_addr_t block_dma = 0;
@@ -882,52 +866,46 @@
 	dma_addr_t data_dma = 0;
 	u32 *last_branch_address = NULL;
 	unsigned long irq_flags;
+	int want_interrupt = 0;
+	struct frame *f = NULL;
+	int i, j;
 
 	spin_lock_irqsave(&video->spinlock, irq_flags);
 
-	video->n_clear_frames = 0;
-	video->first_clear_frame = -1;
+	for (j = 0; j < video->n_frames; j++) {
 
-	for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
-		/* locate a descriptor block and packet from the buffer */
-		block = &(f->descriptor_pool[video->current_packet]);
-		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-		
-		data = &(video->packet_buffer[video->current_packet]);
-		data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
-		
-		/* setup DMA descriptor block */
-		fill_input_last( &(block->u.in.il), 512, data_dma);
+		/* connect frames */
+		if (j > 0 && f != NULL && f->frame_end_branch != NULL)
+			*(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
 
-		/* link descriptors */
-		last_branch_address = f->frame_end_branch;
+		f = video->frames[j];
 
-		if (last_branch_address)
-			*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
-		f->frame_end_branch = &(block->u.in.il.q[2]);
-	}
+		for (i = 0; i < MAX_PACKETS; i++) {
+			/* locate a descriptor block and packet from the buffer */
+			block = &(f->descriptor_pool[i]);
+			block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+			
+			data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
+			data_dma = dma_region_offset_to_bus( &video->packet_buf, 
+							     ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
+			
+			/* setup DMA descriptor block */
+			want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
+			fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
+	
+			/* link descriptors */
+			last_branch_address = f->frame_end_branch;
 	
-	/* loop tail to head */
-	if (f->frame_end_branch)
-		*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */
+			if (last_branch_address != NULL)
+				*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
+	
+			f->frame_end_branch = &(block->u.in.il.q[2]);
+		}
+	
+	} /* next j */
 
 	spin_unlock_irqrestore(&video->spinlock, irq_flags);
 
-	if (video->first_run) {
-		/* start DMA once all of the frames are READY */
-		video->first_run = 0;
-		video->current_packet = 0;
-		video->active_frame = f->frame_num;
-		start_dma_receive(video, f);
-	} 
-	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-		debug_printk("DEAD, event = %x\n", 
-			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
-		/* wake */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-	}
 }
 
 
@@ -941,15 +919,16 @@
 	u64 chan_mask;
 	int retval = -EINVAL;
 
+	debug_printk("dv1394: initialising %d\n", video->id);
 	if(init->api_version != DV1394_API_VERSION)
-		goto err;
+		return -EINVAL;
 	
 	/* first sanitize all the parameters */
 	if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
-		goto err;
+		return -EINVAL;
 
 	if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
-		goto err;
+		return -EINVAL;
 
 	if( (init->syt_offset == 0) || (init->syt_offset > 50) )
 		/* default SYT offset is 3 cycles */
@@ -970,17 +949,15 @@
 	if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
 
 	/* don't allow the user to allocate the DMA buffer more than once */
-	if( (video->user_buf) &&
-	    (video->user_buf_size != new_buf_size) ) {
-		goto err;
+	if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
+		printk("dv1394: re-sizing the DMA buffer is not allowed\n");
+		return -EINVAL;
 	}
-	
+
 	/* shutdown the card if it's currently active */
 	/* (the card should not be reset if the parameters are screwy) */
-	if( video_card_initialized(video) )
-		do_dv1394_shutdown(video, 0);
-
 
+	do_dv1394_shutdown(video, 0);
 	
 	/* try to claim the ISO channel */
 	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
@@ -997,7 +974,6 @@
 	/* initialize misc. fields of video */
 	video->n_frames = init->n_frames;
 	video->pal_or_ntsc = init->format;
-	
 
 	video->cip_accum = 0;
 	video->continuity_counter = 0;
@@ -1013,7 +989,6 @@
 	video->current_packet = -1;
 	video->first_frame = 0;
 
-
 	if(video->pal_or_ntsc == DV1394_NTSC) {
 		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
 		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
@@ -1026,14 +1001,8 @@
 
 	video->syt_offset = init->syt_offset;
 	
-	
 	/* find and claim DMA contexts on the OHCI card */
 
-	/* XXX this should be the last step of initialization, since the interrupt
-	   handler uses ohci_i*_ctx to indicate whether or not it is safe to touch
-	   frames. I'm not making this change quite yet, since it would be better
-	   to clean up the init/shutdown process first.*/
-
 	if(video->ohci_it_ctx == -1) {
 		ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
 					  it_tasklet_func, (unsigned long) video);
@@ -1041,14 +1010,12 @@
 		if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {	
 			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
 			retval = -EBUSY;
-			goto err_ctx;
-		}
-		else {
-			video->ohci_it_ctx = video->it_tasklet.context;
-			debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+			goto err;
 		}
+		
+		video->ohci_it_ctx = video->it_tasklet.context;
+		debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
 	}
-	
 
 	if(video->ohci_ir_ctx == -1) {
 		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
@@ -1057,14 +1024,11 @@
 		if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
 			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
 			retval = -EBUSY;
-			goto err_ctx;
-		}
-		else {
-			video->ohci_ir_ctx = video->ir_tasklet.context;
-			debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+			goto err;
 		}
+		video->ohci_ir_ctx = video->ir_tasklet.context;
+		debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
 	}
-
 	
 	/* allocate struct frames */
 	for(i = 0; i < init->n_frames; i++) {
@@ -1073,97 +1037,43 @@
 		if(!video->frames[i]) {
 			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
 			retval = -ENOMEM;
-			goto err_frames;
+			goto err;
 		}
 	}
 
-	
-
-	if(video->user_buf == NULL) {
-		unsigned int i;
-		
+	if(!video->dv_buf.kvirt) {
 		/* allocate the ringbuffer */
-		video->user_buf = rvmalloc(new_buf_size);
-		if(!video->user_buf) {
-			printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
-			goto err_frames;
-		}
-		video->user_buf_size = new_buf_size;
-
-		/* allocate the sglist to hold the DMA addresses */
-		video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
-		video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
-		if(!video->user_dma.sglist) {
-			printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
-			goto err_user_buf;
-		}
-
-		/* initialize all fields of all sglist entries to zero
-		   (new requirement due to PCI changes in 2.4.13) */
-
-		memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+		retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
+		if(retval)
+			goto err;
+					  
+		video->dv_buf_size = new_buf_size;
 
-		
-		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
-		for(i = 0; i < video->user_dma.n_pages; i++) {
-			unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
-			
-			video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
-			video->user_dma.sglist[i].length = PAGE_SIZE;
-		}
-		
-		/* map the buffer in the IOMMU */
-		/* the user_data buffer only allows DMA *to* the card for transmission;
-		   incoming DV data comes through the packet_buffer first, and then is copied to user_data */
-		video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
-							 &video->user_dma.sglist[0],
-							 video->user_dma.n_pages,
-							 PCI_DMA_TODEVICE);
-		if(video->user_dma.n_dma_pages == 0) {
-			printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
-			goto err_user_buf;
-		}
-		
 		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
-			     video->n_frames, video->user_dma.n_pages,
-			     video->user_dma.n_dma_pages, video->user_buf_size);
+			     video->n_frames, video->dv_buf.n_pages,
+			     video->dv_buf.n_dma_pages, video->dv_buf_size);
 	}
 	
 	/* set up the frame->data pointers */
 	for(i = 0; i < video->n_frames; i++)
-		video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+		video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
 
-	/* allocate packet buffers */
-	video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
-	if (video->packet_buffer_size % PAGE_SIZE)
-		video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
-
-	
-	video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
-	
-	if(!video->packet_buffer) {
-		printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
-		retval = -ENOMEM;
-		goto err_user_buf;
-	}
-
-	/* map the packet buffer into the IOMMU */
-	video->packet_buffer_dma = pci_map_single(video->ohci->dev,
-						  video->packet_buffer,
-						  video->packet_buffer_size,
-						  PCI_DMA_FROMDEVICE);
-	if(!video->packet_buffer_dma) {
-		printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
-		kfree(video->packet_buffer);
-		video->packet_buffer = NULL;
-		retval = -ENOMEM;
-		goto err_user_buf;
+	if(!video->packet_buf.kvirt) {
+		/* allocate packet buffer */
+		video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
+		if (video->packet_buf_size % PAGE_SIZE)
+			video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
+		
+		retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
+					  video->ohci->dev, PCI_DMA_FROMDEVICE);
+		if(retval)
+			goto err;
+		
+		debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", 
+				 video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
+				 video->packet_buf.n_dma_pages, video->packet_buf_size);
 	}
-
-	debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", 
-		     MAX_PACKET_BUFFER, video->packet_buffer_size);
-
-
+	
 	/* set up register offsets for IT context */
 	/* IT DMA context registers are spaced 16 bytes apart */
 	video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
@@ -1187,47 +1097,8 @@
 	
 	return 0;
 
- err_user_buf:
-	if(video->user_buf) {
-		if(video->user_dma.sglist) {
-			if(video->user_dma.n_dma_pages > 0) {
-				/* unmap it from the IOMMU */
-				pci_unmap_sg(video->ohci->dev,
-					     video->user_dma.sglist,
-					     video->user_dma.n_pages,
-					     PCI_DMA_TODEVICE);
-				video->user_dma.n_dma_pages = 0;
-			}
-			kfree(video->user_dma.sglist);
-			video->user_dma.sglist = NULL;
-			video->user_dma.n_pages = 0;
-		}
-		rvfree(video->user_buf, video->user_buf_size);
-		video->user_buf = NULL;
-		video->user_buf_size = 0;
-	}
-		
- err_frames:
-	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
-		if(video->frames[i])
-			frame_delete(video->frames[i]);
-	}	
-	video->n_frames = 0;
-
- err_ctx:
-	if(video->ohci_it_ctx != -1) {
-		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
-		video->ohci_it_ctx = -1;
-	}
-	if(video->ohci_ir_ctx != -1) {
-		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
-		video->ohci_ir_ctx = -1;
-	}
-	
-	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-	video->ohci->ISO_channel_usage &= ~chan_mask;
-	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
- err:
+err:
+	do_dv1394_shutdown(video, 1);
 	return retval;
 }
 
@@ -1239,7 +1110,7 @@
 	struct dv1394_init init;
 
 	init.api_version = DV1394_API_VERSION;
-	init.n_frames = 2;
+	init.n_frames = DV1394_MAX_FRAMES / 4;
 	/* the following are now set via proc_fs or devfs */
 	init.channel = video->channel;
 	init.format = video->pal_or_ntsc;
@@ -1255,10 +1126,15 @@
 {
 	unsigned long flags;
 	int i;
-	
+
 	/* no interrupts */
 	spin_lock_irqsave(&video->spinlock, flags);
 
+	video->dma_running = 0;
+
+	if( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
+		goto out;
+
 	/* stop DMA if in progress */
 	if( (video->active_frame != -1) ||
 	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
@@ -1271,7 +1147,6 @@
 		
 		video->active_frame = -1;
 		video->first_run = 1;
-
 		
 		/* wait until DMA really stops */
 		i = 0;
@@ -1283,6 +1158,7 @@
 			if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
 			    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {
 				/* still active */
+				debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
 				mb();
 			} else {
 				debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
@@ -1296,24 +1172,24 @@
 			printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
 		}
 	}
+	else
+		debug_printk("dv1394: stop_dma: already stopped.\n");
 
+out:
 	spin_unlock_irqrestore(&video->spinlock, flags);
 }
 
 
 
-static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
+static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
 {
 	int i;
-	unsigned long flags;
 	
 	debug_printk("dv1394: shutdown...\n");
 
 	/* stop DMA if in progress */
 	stop_dma(video);
 	
-	spin_lock_irqsave(&video->spinlock, flags);
-
 	/* release the DMA contexts */
 	if(video->ohci_it_ctx != -1) {
 		video->ohci_IsoXmitContextControlSet = 0;
@@ -1323,7 +1199,8 @@
 		/* disable interrupts for IT context */
 		reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
 		
-		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		/* remove tasklet */
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
 		debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
 		video->ohci_it_ctx = -1;
 	}
@@ -1337,13 +1214,12 @@
 		/* disable interrupts for IR context */
 		reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
 
-		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		/* remove tasklet */
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
 		debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
 		video->ohci_ir_ctx = -1;
 	}
 
-	spin_unlock_irqrestore(&video->spinlock, flags);
-	
 	/* release the ISO channel */
 	if(video->channel != -1) {
 		u64 chan_mask;
@@ -1370,42 +1246,18 @@
 	/* we can't free the DMA buffer unless it is guaranteed that
 	   no more user-space mappings exist */
 	
-	if(free_user_buf && video->user_buf) {
-		if(video->user_dma.sglist) {
-			if(video->user_dma.n_dma_pages > 0) {
-				/* unmap it from the IOMMU */
-				pci_unmap_sg(video->ohci->dev,
-					     video->user_dma.sglist,
-					     video->user_dma.n_pages,
-					     PCI_DMA_TODEVICE);
-				video->user_dma.n_dma_pages = 0;
-			}
-			kfree(video->user_dma.sglist);
-			video->user_dma.sglist = NULL;
-			video->user_dma.n_pages = 0;
-		}
-		rvfree(video->user_buf, video->user_buf_size);
-		video->user_buf = NULL;
-		video->user_buf_size = 0;
-	}
-	
-	if (video->packet_buffer) {
-		pci_unmap_single(video->ohci->dev,
-				 video->packet_buffer_dma,
-				 video->packet_buffer_size,
-				 PCI_DMA_FROMDEVICE);
-		kfree(video->packet_buffer);
-		video->packet_buffer = NULL;
-		video->packet_buffer_size = 0;
+	if(free_dv_buf) {
+		dma_region_free(&video->dv_buf);
+		video->dv_buf_size = 0;
 	}
 
-	debug_printk("dv1394: shutdown complete\n");
+	/* free packet buffer */
+	dma_region_free(&video->packet_buf);
+	video->packet_buf_size = 0;
 
-	return 0;
+	debug_printk("dv1394: shutdown OK\n");
 }
 
-
-
 /*
        **********************************
        *** MMAP() THEORY OF OPERATION ***
@@ -1428,96 +1280,28 @@
 	force the user to choose one buffer size and stick with
 	it. This small sacrifice is worth the huge reduction in
 	error-prone code in dv1394.
-
-	Note: dv1394_mmap does no page table manipulation. The page
-	table entries are created by the dv1394_nopage() handler as
-	page faults are taken by the user.
-*/
-
-static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
-{
-	unsigned long offset;
-	unsigned long kernel_virt_addr;
-	struct page *ret = NOPAGE_SIGBUS;
-
-	struct video_card *video = (struct video_card*) area->vm_private_data;
-	
-	/* guard against process-context operations and the interrupt */
-	/* (by definition page faults are taken in interrupt context) */
-	spin_lock(&video->spinlock);
-
-	if(!video->user_buf)
-		goto out;
-
-	if( (address < (unsigned long) area->vm_start) ||
-	    (address > (unsigned long) area->vm_start + video->user_buf_size) )
-		goto out;
-
-	offset = address - area->vm_start;
-	kernel_virt_addr = (unsigned long) video->user_buf + offset;
-	ret = vmalloc_to_page((void *)kernel_virt_addr);
-	get_page(ret);
-
- out:
-	spin_unlock(&video->spinlock);
-	return ret;
-}
-
-static struct vm_operations_struct dv1394_vm_ops = {
-	.nopage = dv1394_nopage
-};
-
-/*
-  dv1394_mmap does no page table manipulation. The page table entries
-  are created by the dv1394_nopage() handler as page faults are taken
-  by the user.
 */
 
 int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct video_card *video = file_to_video_card(file);
-	unsigned long size;
-	int res = -EINVAL;
+	int retval = -EINVAL;
 
 	/* serialize mmap */
 	down(&video->sem);
 
 	if( ! video_card_initialized(video) ) {
-		res = do_dv1394_init_default(video);
-		if(res)
-			goto err;
+		retval = do_dv1394_init_default(video);
+		if(retval)
+			goto out;
 	}
 
-	/* region must be page-aligned */
-	if(vma->vm_pgoff != 0)
-		goto err;
-	
-	/* check the size the user is trying to map */
-	size = vma->vm_end - vma->vm_start;
-	if(size > video->user_buf_size)
-		goto err;
-
-	/* 
-	   we don't actually mess with the page tables here.
-	   (nopage() takes care of that from the page fault handler)
-	   Just set up the vma->vm_ops.
-	*/
-
-        vma->vm_ops = &dv1394_vm_ops;
-	vma->vm_private_data = video;
-	vma->vm_file = file;
-
-	/* don't try to swap this out =) */
-	vma->vm_flags |= VM_RESERVED;
-
-	up(&video->sem);
-	return 0;
- err:
+	retval = dma_region_mmap(&video->dv_buf, file, vma);
+out:
 	up(&video->sem);
-	return res;
+	return retval;
 }
 
-
 /*** DEVICE FILE INTERFACE *************************************************/
 
 /* no need to serialize, multiple threads OK */
@@ -1633,7 +1417,7 @@
 			continue; /* start over from 'while(count > 0)...' */
 		}
 
-		if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) {
+		if(copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
 			if(!ret)
 				ret = -EFAULT;
 			break;
@@ -1680,7 +1464,11 @@
 			up(&video->sem);
 			return ret;
 		}
-		receive_packets(video, video->frames[video->first_clear_frame]);
+		video->continuity_counter = -1;
+		
+		receive_packets(video);
+		
+		start_dma_receive(video);
 	}
 
 	ret = 0;
@@ -1733,7 +1521,7 @@
 			continue; /* start over from 'while(count > 0)...' */
 		}
 
-		if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) {
+		if(copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
 				if(!ret)
 					ret = -EFAULT;
 				break;
@@ -1785,7 +1573,8 @@
 
 	switch(cmd)
 	{
-	case DV1394_SUBMIT_FRAMES: {
+	case DV1394_SUBMIT_FRAMES:
+	case DV1394_IOC_SUBMIT_FRAMES: {
 		unsigned int n_submit;
 
 		if( !video_card_initialized(video) ) {
@@ -1838,8 +1627,8 @@
 		ret = 0;
 		break;
 	}
-
-	case DV1394_WAIT_FRAMES: {
+	case DV1394_WAIT_FRAMES:
+	case DV1394_IOC_WAIT_FRAMES: {
 		unsigned int n_wait;
 
 		if( !video_card_initialized(video) ) {
@@ -1887,8 +1676,8 @@
 		ret = 0;
 		break;
 	}
-
-	case DV1394_RECEIVE_FRAMES: {
+	case DV1394_RECEIVE_FRAMES:
+	case DV1394_IOC_RECEIVE_FRAMES: {
 		unsigned int n_recv;
 
 		if( !video_card_initialized(video) ) {
@@ -1920,22 +1709,25 @@
 		ret = 0;
 		break;
 	}
-
-	case DV1394_START_RECEIVE: {
-
+	case DV1394_START_RECEIVE:
+	case DV1394_IOC_START_RECEIVE: {
 		if( !video_card_initialized(video) ) {
 			ret = do_dv1394_init_default(video);
 			if(ret)
 				goto out;
 		}
 	
-		receive_packets(video, video->frames[video->first_clear_frame]);
+		video->continuity_counter = -1;
+		
+		receive_packets(video);
+		
+		start_dma_receive(video);
 
 		ret = 0;
 		break;
 	}
-
-	case DV1394_INIT: {
+	case DV1394_INIT:
+	case DV1394_IOC_INIT: {
 		struct dv1394_init init;
 		if(arg == (unsigned long) NULL) {
 			ret = do_dv1394_init_default(video);
@@ -1948,13 +1740,14 @@
 		}
 		break;
 	}
-
 	case DV1394_SHUTDOWN:
-		ret = do_dv1394_shutdown(video, 0);
+	case DV1394_IOC_SHUTDOWN:
+		do_dv1394_shutdown(video, 0);
+		ret = 0;
 		break;
 
-
-        case DV1394_GET_STATUS: {
+	case DV1394_GET_STATUS:
+        case DV1394_IOC_GET_STATUS: {
 		struct dv1394_status status;
 
 		if( !video_card_initialized(video) ) {
@@ -2027,7 +1820,7 @@
 			struct video_card *p;
 			list_for_each(lh, &dv1394_cards) {
 				p = list_entry(lh, struct video_card, list);
-				if((p->id >> 2) == ieee1394_file_to_instance(file)) {
+				if((p->id) == ieee1394_file_to_instance(file)) {
 					video = p;
 					break;
 				}
@@ -2319,9 +2112,10 @@
 	struct video_card *video = (struct video_card*) data;
 
 	spin_lock(&video->spinlock);
-	
-	irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
-		   (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
+
+	if(!video->dma_running)
+		goto out;
+
 	irq_printk("ContextControl = %08x, CommandPtr = %08x\n", 
 	       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
 	       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
@@ -2448,14 +2242,15 @@
 		} /* for(each frame) */
 	}
 
-	spin_unlock(&video->spinlock);
-
 	if(wake) {
 		kill_fasync(&video->fasync, SIGIO, POLL_OUT);
 		
 		/* wake readers/writers/ioctl'ers */
 		wake_up_interruptible(&video->waitq);
 	}
+
+out:
+	spin_unlock(&video->spinlock);
 }
 
 static void ir_tasklet_func(unsigned long data)
@@ -2463,83 +2258,151 @@
 	int wake = 0;
 	struct video_card *video = (struct video_card*) data;
 
+	spin_lock(&video->spinlock);
+
+	if(!video->dma_running)
+		goto out;
+	
 	if( (video->ohci_ir_ctx != -1) &&
-	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
+	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) )
+	{ 
 
 		int sof=0; /* start-of-frame flag */
 		struct frame *f;
 		u16 packet_length, packet_time;
-
-		packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length);
-		packet_time   = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp);
-
-		irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
-			   packet_time, packet_length, 
-			   video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
-		
-		f = video->frames[video->active_frame];
-
-		/* exclude empty packet */
-		if (packet_length > 8) {
-		
-			/* check for start of frame */
-			sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
-				video->packet_buffer[video->current_packet].data[1] == 0x07);
-
-			if (!video->first_frame) {
-				if (sof) {
-					video->first_frame = 1;
-				}
-
-			} else if (sof) {
-				/* close current frame */
-				frame_reset(f);  /* f->state = STATE_CLEAR */
-				video->n_clear_frames++;
-				if (video->n_clear_frames > video->n_frames) {
-					video->n_clear_frames = video->n_frames;
-					video->dropped_frames++;
-				}
-				if (video->first_clear_frame == -1)
-					video->first_clear_frame = video->active_frame;
-
-				/* get the next frame */
-				video->active_frame = (video->active_frame + 1) % video->n_frames;
-				f = video->frames[video->active_frame];
-			
-				irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
-					   video->active_frame, video->n_clear_frames, video->first_clear_frame);
- 			}
-			if (video->first_frame) {
-				if (sof) {
-					/* open next frame */
-					f->state = FRAME_READY;
+		int i, dbc=0;
+		struct DMA_descriptor_block *block = NULL;
+		u16 xferstatus;
+
+		int next_i, prev_i;
+		struct DMA_descriptor_block *next = NULL;
+		dma_addr_t next_dma = 0;
+		struct DMA_descriptor_block *prev = NULL;
+
+		/* loop over all descriptors in all frames */
+		for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
+			struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
+
+			/* make sure we are seeing the latest changes to p */
+			dma_region_sync(&video->packet_buf,
+					(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
+					sizeof(struct packet));
+					
+			packet_length = le16_to_cpu(p->data_length);
+			packet_time   = le16_to_cpu(p->timestamp);
+	
+			irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
+				   packet_time, packet_length, 
+				   p->data[0], p->data[1]);
+			
+			/* get the descriptor based on packet_buffer cursor */
+			f = video->frames[video->current_packet / MAX_PACKETS];
+			block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
+			xferstatus = le16_to_cpu(block->u.in.il.q[3] >> 16);
+			xferstatus &= 0x1F;
+
+			/* get the current frame */
+			f = video->frames[video->active_frame];
+		
+			/* exclude empty packet */
+			if (packet_length > 8 && xferstatus == 0x11) {
+				irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
+			
+				/* check for start of frame */
+				/* DRD> Changed to check section type ([0]>>5==0) 
+				   and dif sequence ([1]>>4==0) */
+				sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
+	
+				dbc = (int) (p->cip_h1 >> 24);
+				if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
+				{
+					printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
+					video->dropped_frames += video->n_clear_frames + 1;
+					video->first_frame = 0;
+					video->n_clear_frames = 0;
+					video->first_clear_frame = -1;
 				}
+				video->continuity_counter = dbc;
 				
-				/* copy to buffer */
-				if (f->n_packets > (video->frame_size / 480)) {
-					printk(KERN_ERR "frame buffer overflow during receive\n");
+				if (!video->first_frame) {
+					if (sof) {
+						video->first_frame = 1;
+					}
+	
+				} else if (sof) {
+					/* close current frame */
+					frame_reset(f);  /* f->state = STATE_CLEAR */
+					video->n_clear_frames++;
+					if (video->n_clear_frames > video->n_frames) {
+						video->dropped_frames++;
+						printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
+						video->n_clear_frames = video->n_frames-1;
+						video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+					}
+					if (video->first_clear_frame == -1)
+						video->first_clear_frame = video->active_frame;
+	
+					/* get the next frame */
+					video->active_frame = (video->active_frame + 1) % video->n_frames;
+					f = video->frames[video->active_frame];
+					irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
+						   video->active_frame, video->n_clear_frames, video->first_clear_frame);
 				}
+				if (video->first_frame) {
+					if (sof) {
+						/* open next frame */
+						f->state = FRAME_READY;
+					}
+					
+					/* copy to buffer */
+					if (f->n_packets > (video->frame_size / 480)) {
+						printk(KERN_ERR "frame buffer overflow during receive\n");
+					}
+					
+					frame_put_packet(f, p);
+					
+				} /* first_frame */
+			}
+			
+			/* stop, end of ready packets */
+			else if (xferstatus == 0) {
+				break;
+			}
+	 
+			/* reset xferStatus & resCount */
+			block->u.in.il.q[3] = cpu_to_le32(512);
 
-				/* make sure we are seeing the latest changes to packet_buffer */
-				pci_dma_sync_single(video->ohci->dev,
-						    video->packet_buffer_dma,
-						    video->packet_buffer_size,
-						    PCI_DMA_FROMDEVICE);
-				
-				frame_put_packet( f, &video->packet_buffer[video->current_packet]);
-				
-			} /* first_frame */
- 
-		} /* not empty packet */
- 
-		/* advance packet_buffer cursor */
-		video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
+			/* terminate dma chain at this (next) packet */
+			next_i = video->current_packet;
+			f = video->frames[next_i / MAX_PACKETS];
+			next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
+			next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+			next->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
+			next->u.in.il.q[2] = 0; /* disable branch */
+			
+			/* link previous to next */
+			prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
+			f = video->frames[prev_i / MAX_PACKETS];
+			prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
+			if(prev_i % (MAX_PACKETS/2)) {
+				prev->u.in.il.q[0] &= ~(3 << 20); /* no interrupt */
+			} else {
+				prev->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
+			}
+			prev->u.in.il.q[2] =  (cpu_to_le32(next_dma) | 1); /* set Z=1 */
+			wmb();
+
+			/* wake up DMA in case it fell asleep */
+			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+
+			/* advance packet_buffer cursor */
+			video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
+			
+		} /* for all packets */
  
 		wake = 1; /* why the hell not? */
-
+		
 	} /* receive interrupt */
-
-	spin_unlock(&video->spinlock);
 	
 	if(wake) {
 		kill_fasync(&video->fasync, SIGIO, POLL_IN);
@@ -2547,6 +2410,9 @@
 		/* wake readers/writers/ioctl'ers */
 		wake_up_interruptible(&video->waitq);
 	}
+	
+out:
+	spin_unlock(&video->spinlock);
 }
 
 static struct file_operations dv1394_fops=
@@ -2587,6 +2453,7 @@
 	return p;
 }
 
+#ifdef CONFIG_DEVFS_FS
 static int dv1394_devfs_add_entry(struct video_card *video)
 {
 	char buf[32];
@@ -2694,6 +2561,29 @@
 		kfree(p);
 	}
 }
+#endif /* CONFIG_DEVFS_FS */
+
+
+/*** HOTPLUG STUFF **********************************************************/
+/*
+ * Export information about protocols/devices supported by this driver.
+ */
+static struct ieee1394_device_id dv1394_id_table[] = {
+	{
+		.match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+		.version	= AVC_SW_VERSION_ENTRY & 0xffffff
+	},
+	{ }
+};
+
+static struct hpsb_protocol_driver dv1394_driver = {
+	.name =		"DV/1394 Driver",
+	.id_table = 	dv1394_id_table,
+};
+
+MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
+
 
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
@@ -2715,6 +2605,10 @@
 	/* lower 2 bits of id indicate which of four "plugs"
 	   per host */
 	video->id = ohci->id << 2; 
+	if (format == DV1394_NTSC)
+		video->id |= mode;
+	else
+		video->id |= 2 + mode;
 
 	video->ohci_it_ctx = -1;
 	video->ohci_ir_ctx = -1;
@@ -2747,11 +2641,14 @@
 	for(i = 0; i < DV1394_MAX_FRAMES; i++)
 		video->frames[i] = NULL;
 
-	video->user_buf = NULL;
-	video->user_buf_size = 0;
+	dma_region_init(&video->dv_buf);
+	video->dv_buf_size = 0;
+	dma_region_init(&video->packet_buf);
+	video->packet_buf_size = 0;
 
 	clear_bit(0, &video->open);
 	spin_lock_init(&video->spinlock);
+	video->dma_running = 0;
 	init_MUTEX(&video->sem);
 	init_waitqueue_head(&video->waitq);
 	video->fasync = NULL;
@@ -2761,10 +2658,6 @@
 	list_add_tail(&video->list, &dv1394_cards);
 	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 	
-	if (format == DV1394_NTSC)
-		video->id |= mode;
-	else video->id |= 2 + mode;
-
 #ifdef CONFIG_DEVFS_FS
 	if (dv1394_devfs_add_entry(video) < 0)
 			goto err_free;
@@ -2806,7 +2699,7 @@
 	struct ti_ohci *ohci;
 	struct video_card *video = NULL;
 	unsigned long flags;
-	struct list_head *lh;
+	struct list_head *lh, *templh;
 	char buf[32];
 	int	n;
 	
@@ -2820,7 +2713,7 @@
 	/* find the corresponding video_cards */
 	spin_lock_irqsave(&dv1394_cards_lock, flags);
 	if(!list_empty(&dv1394_cards)) {
-		list_for_each(lh, &dv1394_cards) {
+		list_for_each_safe(lh, templh, &dv1394_cards) {
 			video = list_entry(lh, struct video_card, list);
 			if((video->id >> 2) == ohci->id)
 				dv1394_un_init(video);
@@ -2852,7 +2745,6 @@
 {
 	struct ti_ohci *ohci;
 	char buf[16];
-	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2874,13 +2766,15 @@
 #endif
 
 #ifdef CONFIG_DEVFS_FS
-	devfs_entry = dv1394_devfs_find("dv");
+{
+	struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv");
 	if (devfs_entry != NULL) {
 		snprintf(buf, sizeof(buf), "host%d", ohci->id);
 		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
 		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
 		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
 	}
+}
 #endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
@@ -2926,6 +2820,9 @@
 	
 	spin_lock_irqsave(&video->spinlock, flags);
 
+	if(!video->dma_running)
+		goto out;
+
 	/* check IT context */
 	if(video->ohci_it_ctx != -1) {
 		u32 ctx;
@@ -2998,14 +2895,16 @@
 				   reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
 		}
 	}
-	
+
+out:
 	spin_unlock_irqrestore(&video->spinlock, flags);
 	
 	/* wake readers/writers/ioctl'ers */
 	wake_up_interruptible(&video->waitq);
 }
 
-static struct hpsb_highlevel_ops hl_ops = {
+static struct hpsb_highlevel dv1394_highlevel = {
+	.name =		"dv1394",
 	.add_host =	dv1394_add_host,
 	.remove_host =	dv1394_remove_host,
 	.host_reset =   dv1394_host_reset,
@@ -3021,8 +2920,11 @@
 
 static void __exit dv1394_exit_module(void)
 {
-	hpsb_unregister_highlevel (hl_handle);
+	hpsb_unregister_protocol(&dv1394_driver);
+
+	hpsb_unregister_highlevel(&dv1394_highlevel);
 	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+
 #ifdef CONFIG_DEVFS_FS
 	dv1394_devfs_del("dv");
 #endif
@@ -3058,22 +2960,12 @@
 	}
 #endif
 
-	hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops);
-	if (hl_handle == NULL) {
-		printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n");
-		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-#ifdef CONFIG_DEVFS_FS
-		dv1394_devfs_del("dv");
-#endif
-#ifdef CONFIG_PROC_FS
-		dv1394_procfs_del("dv");
-#endif
-		return -ENOMEM;
-	}
+	hpsb_register_highlevel (&dv1394_highlevel);
+
+	hpsb_register_protocol(&dv1394_driver);
 
 	return 0;
 }
 
 module_init(dv1394_init_module);
 module_exit(dv1394_exit_module);
-

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