⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dv1394.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
}/*** MANAGEMENT FUNCTIONS **************************************************/static int do_dv1394_init(struct video_card *video, struct dv1394_init *init){	unsigned long flags, new_buf_size;	int i;	u64 chan_mask;	int retval = -EINVAL;	if(init->api_version != DV1394_API_VERSION)		goto err;		/* first sanitize all the parameters */	if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )		goto err;	if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )		goto err;	if( (init->syt_offset == 0) || (init->syt_offset > 50) )		/* default SYT offset is 3 cycles */		init->syt_offset = 3;	if( (init->channel > 63) || (init->channel < 0) )		init->channel = 63;	chan_mask = (u64)1 << init->channel;	/* calculate what size DMA buffer is needed */	if(init->format == DV1394_NTSC)		new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;	else		new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;	/* round up to PAGE_SIZE */	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;	}		/* 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);		/* try to claim the ISO channel */	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);	if(video->ohci->ISO_channel_usage & chan_mask) {		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);		retval = -EBUSY;		goto err;	}	video->ohci->ISO_channel_usage |= chan_mask;	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);	video->channel = init->channel;	/* 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;			/* 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);		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) {		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,					  ir_tasklet_func, (unsigned long) video);		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);		}	}		/* allocate struct frames */	for(i = 0; i < init->n_frames; i++) {		video->frames[i] = frame_new(i, video);		if(!video->frames[i]) {			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");			retval = -ENOMEM;			goto err_frames;		}	}		if(video->user_buf == NULL) {		unsigned int i;				/* 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));				/* 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);	}		/* 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;	/* 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;	}	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;	video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;	video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;	/* enable interrupts for IT context */	reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));	debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);	/* set up register offsets for IR context */	/* IR DMA context registers are spaced 32 bytes apart */	video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;	video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;	video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;	video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;	/* enable interrupts for IR context */	reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );	debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);		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:	return retval;}/* if the user doesn't bother to call ioctl(INIT) before starting   mmap() or read()/write(), just give him some default values */static int do_dv1394_init_default(struct video_card *video){	struct dv1394_init init;	init.api_version = DV1394_API_VERSION;	init.n_frames = 2;	/* the following are now set via proc_fs or devfs */	init.channel = video->channel;	init.format = video->pal_or_ntsc;	init.cip_n = video->cip_n; 	init.cip_d = video->cip_d;	init.syt_offset = video->syt_offset;	return do_dv1394_init(video, &init);}/* do NOT call from interrupt context */static void stop_dma(struct video_card *video){	unsigned long flags;	int i;		/* no interrupts */	spin_lock_irqsave(&video->spinlock, flags);	/* stop DMA if in progress */	if( (video->active_frame != -1) ||	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) &  (1 << 10)) ) {		/* clear the .run bits */		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));		flush_pci_write(video->ohci);				video->active_frame = -1;		video->first_run = 1;				/* wait until DMA really stops */		i = 0;		while(i < 1000) {							/* wait 0.1 millisecond */			udelay(100); 						if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||			    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {				/* still active */				mb();			} else {				debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);				break;			}							i++;		}					if(i == 1000) {			printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);		}	}	spin_unlock_irqrestore(&video->spinlock, flags);}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);		spin_lock_irqsave(&video->spinlock, flags);	/* release the DMA contexts */	if(video->ohci_it_ctx != -1) {		video->ohci_IsoXmitContextControlSet = 0;		video->ohci_IsoXmitContextControlClear = 0;		video->ohci_IsoXmitCommandPtr = 0;		/* 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);		debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);		video->ohci_it_ctx = -1;	}	if(video->ohci_ir_ctx != -1) {		video->ohci_IsoRcvContextControlSet = 0;		video->ohci_IsoRcvContextControlClear = 0;		video->ohci_IsoRcvCommandPtr = 0;		video->ohci_IsoRcvContextMatch = 0;		/* 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);		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;		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])			frame_delete(video->frames[i]);		video->frames[i] = NULL;	}	video->n_frames = 0;			/* 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,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -