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

📄 dv1394.c

📁 ieee1394驱动,不多说了!直接可以在linux2.6内核中使用
💻 C
📖 第 1 页 / 共 5 页
字号:
		return -EINVAL;	/* first sanitize all the parameters */	if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )		return -EINVAL;	if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )		return -EINVAL;	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->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) */	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 */	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;		}		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;		}		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;		}	}	if (!video->dv_buf.kvirt) {		/* allocate the ringbuffer */		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;		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 			     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->dv_buf.kvirt + i * video->frame_size;	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);	}	/* 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:	do_dv1394_shutdown(video, 1);	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 = DV1394_MAX_FRAMES / 4;	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);	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)) ||	    (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 */				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);				break;			}			i++;		}		if (i == 1000) {			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 void do_dv1394_shutdown(struct video_card *video, int free_dv_buf){	int i;	debug_printk("dv1394: shutdown...\n");	/* stop DMA if in progress */	stop_dma(video);	/* 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));		/* 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;	}	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));		/* 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;	}	/* 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_dv_buf) {		dma_region_free(&video->dv_buf);		video->dv_buf_size = 0;	}	/* free packet buffer */	dma_region_free(&video->packet_buf);	video->packet_buf_size = 0;	debug_printk("dv1394: shutdown OK\n");}/*       **********************************       *** MMAP() THEORY OF OPERATION ***       **********************************        The ringbuffer cannot be re-allocated or freed while        a user program maintains a mapping of it. (note that a mapping	can persist even after the device fd is closed!)	So, only let the user process allocate the DMA buffer once.	To resize or deallocate it, you must close the device file	and open it again.	Previously Dan M. hacked out a scheme that allowed the DMA	buffer to change by forcefully unmapping it from the user's	address space. It was prone to error because it's very hard to	track all the places the buffer could have been mapped (we	would have had to walk the vma list of every process in the	system to be sure we found all the mappings!). Instead, we	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.*/static int dv1394_mmap(struct file *file, struct vm_area_struct *vma){	struct video_card *video = file_to_video_card(file);	int retval = -EINVAL;	/* serialize mmap */	mutex_lock(&video->mtx);	if ( ! video_card_initialized(video) ) {		retval = do_dv1394_init_default(video);		if (retval)			goto out;	}	retval = dma_region_mmap(&video->dv_buf, file, vma);out:	mutex_unlock(&video->mtx);	return retval;}/*** DEVICE FILE INTERFACE *************************************************//* no need to serialize, multiple threads OK */static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait){	struct video_card *video = file_to_video_card(file);	unsigned int mask = 0;	unsigned long flags;	poll_wait(file, &video->waitq, wait);	spin_lock_irqsave(&video->spinlock, flags);	if ( video->n_frames == 0 ) {	} else if ( video->active_frame == -1 ) {		/* nothing going on */		mask |= POLLOUT;	} else {		/* any clear/ready buffers? */		if (video->n_clear_frames >0)			mask |= POLLOUT | POLLIN;	}	spin_unlock_irqrestore(&video->spinlock, flags);	return mask;}static int dv1394_fasync(int fd, struct file *file, int on){	/* I just copied this code verbatim from Alan Cox's mouse driver example	   (Documentation/DocBook/) */	struct video_card *video = file_to_video_card(file);	int retval = fasync_helper(fd, file, on, &video->fasync);	if (retval < 0)		return retval;        return 0;}static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){	struct video_card *video = file_to_video_card(file);	DECLARE_WAITQUEUE(wait, current);	ssize_t ret;	size_t cnt;	unsigned long flags;	int target_frame;	/* serialize this to prevent multi-threaded mayhem */	if (file->f_flags & O_NONBLOCK) {		if (!mutex_trylock(&video->mtx))			return -EAGAIN;	} else {		if (mutex_lock_interruptible(&video->mtx))			return -ERESTARTSYS;	}	if ( !video_card_initialized(video) ) {		ret = do_dv1394_init_default(video);		if (ret) {			mutex_unlock(&video->mtx);			return ret;		}	}	ret = 0;	add_wait_queue(&video->waitq, &wait);	while (count > 0) {		/* must set TASK_INTERRUPTIBLE *before* checking for free		   buffers; otherwise we could miss a wakeup if the interrupt

⌨️ 快捷键说明

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