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

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

diff -urN linux-2.4.19/drivers/ieee1394/dv1394.c linux-2.4.20/drivers/ieee1394/dv1394.c
@@ -159,9 +159,8 @@
 	reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 }
 
-static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-			quadlet_t isoXmitIntEvent, void *data);
-
+static void it_tasklet_func(unsigned long data);
+static void ir_tasklet_func(unsigned long data);
 
 /* GLOBAL DATA */
 
@@ -188,42 +187,29 @@
 }
 
 
-/* Taken from bttv.c */
 /*******************************/
 /* 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;
-	unsigned long adr;
 
-	size = PAGE_ALIGN(size);
-	mem=vmalloc_32(size);
-	if (mem) {
+	mem = vmalloc_32(size);
+
+	if(mem)
 		memset(mem, 0, size); /* Clear the ram out, 
 					 no junk to the user */
-	        adr=(unsigned long) mem;
-		while (size > 0) {
-			mem_map_reserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
 	return mem;
 }
 
 static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr;
-
 	if (mem) {
-	        adr=(unsigned long) mem;
-		while (size > 0) {
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
 		vfree(mem);
 	}
 }
@@ -594,7 +580,7 @@
 		/* note: we are not linked into the active DMA chain yet */
 
 		if(last_branch_address) {
-			*(last_branch_address) = block_dma | n_descriptors; 
+			*(last_branch_address) = cpu_to_le32(block_dma | n_descriptors);
 		}
 
 		last_branch_address = branch_address;
@@ -606,7 +592,7 @@
 
 	/* when we first assemble a new frame, set the final branch 
 	   to loop back up to the top */
-	*(f->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors;
+	*(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 */
@@ -643,15 +629,18 @@
 		/* if DMA is already active, we are almost done */
 		/* just link us onto the active DMA chain */
 		if(video->frames[last_frame]->frame_end_branch) {
+			u32 temp;
 
 			/* point the previous frame's tail to this frame's head */
-			*(video->frames[last_frame]->frame_end_branch) = f->descriptor_pool_dma | f->first_n_descriptors; 
+			*(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
 			/* this write MUST precede the next one, or we could silently drop frames */
 			wmb();
 			
 			/* disable the want_status semaphore on the last packet */
-			*(video->frames[last_frame]->frame_end_branch - 2) &= 0xF7CFFFFF;
+			temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2));
+			temp &= 0xF7CFFFFF;
+			*(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp);
 
 			/* flush these writes to memory ASAP */
 			flush_pci_write(video->ohci);
@@ -914,14 +903,14 @@
 		last_branch_address = f->frame_end_branch;
 
 		if (last_branch_address)
-			*(last_branch_address) = block_dma | 1; /* set Z=1 */
+			*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
 
 		f->frame_end_branch = &(block->u.in.il.q[2]);
 	}
 	
 	/* loop tail to head */
 	if (f->frame_end_branch)
-		*(f->frame_end_branch) =  f->descriptor_pool_dma | 1; /* set Z=1 */
+		*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */
 
 	spin_unlock_irqrestore(&video->spinlock, irq_flags);
 
@@ -992,6 +981,7 @@
 		do_dv1394_shutdown(video, 0);
 
 
+	
 	/* try to claim the ISO channel */
 	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
 	if(video->ohci->ISO_channel_usage & chan_mask) {
@@ -1004,43 +994,75 @@
 
 	video->channel = init->channel;
 
+	/* initialize misc. fields of video */
+	video->n_frames = init->n_frames;
+	video->pal_or_ntsc = init->format;
 	
-	/* find and claim DMA contexts on the OHCI card */
+
+	video->cip_accum = 0;
+	video->continuity_counter = 0;
+
+	video->active_frame = -1;
+	video->first_clear_frame = 0;
+	video->n_clear_frames = video->n_frames;
+	video->dropped_frames = 0;
+
+	video->write_off = 0;
+
+	video->first_run = 1;
+	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;
+		video->frame_size = DV1394_NTSC_FRAME_SIZE;
+	} else {
+		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
+		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
+		video->frame_size = DV1394_PAL_FRAME_SIZE;
+	}
+
+	video->syt_offset = init->syt_offset;
 	
-	if(video->ohci_it_ctx == -1) {
+	
+	/* find and claim DMA contexts on the OHCI card */
 
-		for(i = 0; i < video->ohci->nb_iso_xmit_ctx; i++) {
+	/* 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(! test_and_set_bit(i, &video->ohci->it_ctx_usage)) {
-				video->ohci_it_ctx = i;
-				debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
-				break;
-			}
-		}
-				
-		if(i == video->ohci->nb_iso_xmit_ctx) {
+	if(video->ohci_it_ctx == -1) {
+		ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
+					  it_tasklet_func, (unsigned long) video);
+
+		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);
+		}
 	}
 	
 
 	if(video->ohci_ir_ctx == -1) {
-		for(i = 0; i < video->ohci->nb_iso_rcv_ctx; i++) {
+		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
+					  ir_tasklet_func, (unsigned long) video);
 
-			if(! test_and_set_bit(i, &video->ohci->ir_ctx_usage)) {
-				video->ohci_ir_ctx = i;
-				debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
-				break;
-			}
-		}
-				
-		if(i == video->ohci->nb_iso_rcv_ctx) {
+		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);
+		}
 	}
 
 	
@@ -1055,38 +1077,8 @@
 		}
 	}
 
-	/* 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;
-
-	video->active_frame = -1;
-	video->first_clear_frame = 0;
-	video->n_clear_frames = video->n_frames;
-	video->dropped_frames = 0;
-
-	video->write_off = 0;
-
-	video->first_run = 1;
-	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;
-		video->frame_size = DV1394_NTSC_FRAME_SIZE;
-	} else {
-		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
-		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
-		video->frame_size = DV1394_PAL_FRAME_SIZE;
-	}
-
-	video->syt_offset = init->syt_offset;
-
 	if(video->user_buf == NULL) {
 		unsigned int i;
 		
@@ -1224,11 +1216,11 @@
 
  err_ctx:
 	if(video->ohci_it_ctx != -1) {
-		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
 		video->ohci_it_ctx = -1;
 	}
 	if(video->ohci_ir_ctx != -1) {
-		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
 		video->ohci_ir_ctx = -1;
 	}
 	
@@ -1313,25 +1305,14 @@
 static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
 {
 	int i;
-
+	unsigned long flags;
+	
 	debug_printk("dv1394: shutdown...\n");
 
 	/* stop DMA if in progress */
 	stop_dma(video);
 	
-	/* release the ISO channel */
-	if(video->channel != -1) {
-		u64 chan_mask;
-		unsigned long flags;
-		
-		chan_mask = (u64)1 << video->channel;
-		
-		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);
-		
-		video->channel = -1;
-	}
+	spin_lock_irqsave(&video->spinlock, flags);
 
 	/* release the DMA contexts */
 	if(video->ohci_it_ctx != -1) {
@@ -1361,6 +1342,22 @@
 		video->ohci_ir_ctx = -1;
 	}
 
+	spin_unlock_irqrestore(&video->spinlock, flags);
+	
+	/* release the ISO channel */
+	if(video->channel != -1) {
+		u64 chan_mask;
+		unsigned long flags;
+		
+		chan_mask = (u64)1 << video->channel;
+		
+		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);
+		
+		video->channel = -1;
+	}
+	
 	/* free the frame structs */
 	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
 		if(video->frames[i])
@@ -2142,7 +2139,7 @@
 			const char *buffer, unsigned long count, void *data)
 {
 	int len = 0;
-	char new_value[64];
+	char new_value[65];
 	char *pos;
 	struct video_card *video = (struct video_card*) data;
 	
@@ -2154,11 +2151,12 @@
 	if (copy_from_user( new_value, buffer, len))
 		return -EFAULT;
 	
+	new_value[len] = 0;
 	pos = strchr(new_value, '=');
 	if (pos != NULL) {
 		int val_len = len - (pos-new_value) - 1;
-		char buf[64];
-		memset(buf, 0, 64);
+		char buf[65];
+		memset(buf, 0, 65);
 		strncpy(buf, pos+1, val_len);
 		if (buf[val_len-1] == '\n') buf[val_len-1] = 0;
 		
@@ -2315,12 +2313,13 @@
 
 /*** DEVICE DRIVER HANDLERS ************************************************/
 
-static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
-			quadlet_t isoXmitIntEvent, void *data)
+static void it_tasklet_func(unsigned long data)
 {
 	int wake = 0;
 	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);
 	irq_printk("ContextControl = %08x, CommandPtr = %08x\n", 
@@ -2330,13 +2329,12 @@
 
 	
 	if( (video->ohci_it_ctx != -1) &&
-	    (isoXmitIntEvent & (1 << video->ohci_it_ctx)) &&
 	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
 
 		struct frame *f;
 		unsigned int frame, i;
 
-		spin_lock(&video->spinlock);
+		
 		if(video->active_frame == -1)
 			frame = 0;
 		else
@@ -2392,13 +2390,15 @@
 			/* see if we need to set the timestamp for the next frame */
 			if( *(f->mid_frame_timestamp) ) {
 				struct frame *next_frame;
-				u32 ts_cyc, ts_off;
+				u32 begin_ts, ts_cyc, ts_off;
 
 				*(f->mid_frame_timestamp) = 0;
 
+				begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
+
 				irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
-				       *(f->frame_begin_timestamp) & 0x1FFF, *(f->frame_begin_timestamp) & 0xF,
-				       f->assigned_timestamp >> 12,       f->assigned_timestamp & 0xFFF);
+					   begin_ts & 0x1FFF, begin_ts & 0xF,
+					   f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
 
 				/* prepare next frame and assign timestamp */
 				next_frame = video->frames[ (frame+1) % video->n_frames ];
@@ -2412,7 +2412,7 @@
 
 				/* set the timestamp to the timestamp of the last frame sent,
 				   plus the length of the last frame sent, plus the syt latency */
-				ts_cyc = *(f->frame_begin_timestamp) & 0xF;
+				ts_cyc = begin_ts & 0xF;
 				/* advance one frame, plus syt latency (typically 2-3) */
 				ts_cyc += f->n_packets + video->syt_offset ; 
 
@@ -2446,30 +2446,41 @@
 
 		
 		} /* for(each frame) */
+	}
+
+	spin_unlock(&video->spinlock);
 
-		spin_unlock(&video->spinlock);
+	if(wake) {
+		kill_fasync(&video->fasync, SIGIO, POLL_OUT);
 		
-	} /* end XMIT portion */
+		/* wake readers/writers/ioctl'ers */
+		wake_up_interruptible(&video->waitq);
+	}
+}
 
-	/***** RECEIVE INTERRUPT and DMA ACTIVE *****/
+static void ir_tasklet_func(unsigned long data)
+{
+	int wake = 0;
+	struct video_card *video = (struct video_card*) data;
 
-	else if( (video->ohci_ir_ctx != -1) &&
-		 (isoRecvIntEvent & (1 << video->ohci_ir_ctx)) &&
-		 (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
+	if( (video->ohci_ir_ctx != -1) &&
+	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
 
 		int sof=0; /* start-of-frame flag */
 		struct frame *f;
+		u16 packet_length, packet_time;
 
-		spin_lock(&video->spinlock);
+		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,
-			   video->packet_buffer[video->current_packet].timestamp, video->packet_buffer[video->current_packet].data_length, 
+			   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 (video->packet_buffer[video->current_packet].data_length > 8) {
+		if (packet_length > 8) {
 		
 			/* check for start of frame */
 			sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
@@ -2524,22 +2535,15 @@
 		/* advance packet_buffer cursor */
 		video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
  
- 		spin_unlock(&video->spinlock);
-
 		wake = 1; /* why the hell not? */
 
 	} /* receive interrupt */
 
+	spin_unlock(&video->spinlock);
+	
 	if(wake) {
-		
-		/* send SIGIO */
-		
-		if(isoRecvIntEvent & (1))
-			kill_fasync(&video->fasync, SIGIO, POLL_IN);
-		
-		if(isoXmitIntEvent & (1))
-			kill_fasync(&video->fasync, SIGIO, POLL_OUT);
-		
+		kill_fasync(&video->fasync, SIGIO, POLL_IN);
+
 		/* wake readers/writers/ioctl'ers */
 		wake_up_interruptible(&video->waitq);
 	}
@@ -2572,12 +2576,15 @@
 		list_for_each(lh, &dv1394_devfs) {
 			p = list_entry(lh, struct dv1394_devfs_entry, list);
 			if(!strncmp(p->name, name, sizeof(p->name))) {
-				spin_unlock( &dv1394_devfs_lock);
-				return p;
+				goto found;
 			}
 		}
 	}
-	return NULL;
+	p = NULL;
+	
+found:
+	spin_unlock( &dv1394_devfs_lock);
+	return p;
 }
 
 static int dv1394_devfs_add_entry(struct video_card *video)
@@ -2704,12 +2711,6 @@
 	
 	memset(video, 0, sizeof(struct video_card));
 	
-	if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
-		printk(KERN_ERR "dv1394: ohci1394_hook_irq() failed\n");
-		goto err_free;
-	}
-
-	
 	video->ohci = ohci;
 	/* lower 2 bits of id indicate which of four "plugs"
 	   per host */
@@ -2763,7 +2764,7 @@
 	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;
@@ -2785,7 +2786,6 @@
 	
 	/* obviously nobody has the driver open at this point */
 	do_dv1394_shutdown(video, 1);
-	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
 	snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
 		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
 		(video->mode == MODE_RECEIVE ? "in" : "out")
@@ -2923,12 +2923,13 @@
 	if(!video)
 		return;
 
+	
+	spin_lock_irqsave(&video->spinlock, flags);
+
 	/* check IT context */
 	if(video->ohci_it_ctx != -1) {
 		u32 ctx;
 		
-		spin_lock_irqsave(&video->spinlock, flags);
-		
 		ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
 
 		/* if(RUN but not ACTIVE) */
@@ -2959,16 +2960,12 @@
 				   reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
 				   reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
 		}
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
 	}
 	
 	/* check IR context */
 	if(video->ohci_ir_ctx != -1) {
 		u32 ctx;
 		
-		spin_lock_irqsave(&video->spinlock, flags);
-		
 		ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
 
 		/* if(RUN but not ACTIVE) */
@@ -3000,10 +2997,10 @@
 				   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
 				   reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
 		}
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
 	}
-
+	
+	spin_unlock_irqrestore(&video->spinlock, flags);
+	
 	/* wake readers/writers/ioctl'ers */
 	wake_up_interruptible(&video->waitq);
 }

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