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

📄 dv1394.c

📁 Ieee1394驱动实现
💻 C
📖 第 1 页 / 共 5 页
字号:
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
		   fires between the check and the schedule() */

		set_current_state(TASK_INTERRUPTIBLE);

		spin_lock_irqsave(&video->spinlock, flags);

		target_frame = video->first_clear_frame;

		spin_unlock_irqrestore(&video->spinlock, flags);

		if (video->frames[target_frame]->state == FRAME_CLEAR) {

			/* how much room is left in the target frame buffer */
			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);

		} else {
			/* buffer is already used */
			cnt = 0;
		}

		if (cnt > count)
			cnt = count;

		if (cnt <= 0) {
			/* no room left, gotta wait */
			if (file->f_flags & O_NONBLOCK) {
				if (!ret)
					ret = -EAGAIN;
				break;
			}
			if (signal_pending(current)) {
				if (!ret)
					ret = -ERESTARTSYS;
				break;
			}

			schedule();

			continue; /* start over from 'while(count > 0)...' */
		}

		if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
			if (!ret)
				ret = -EFAULT;
			break;
		}

		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);

		count -= cnt;
		buffer += cnt;
		ret += cnt;

		if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
				frame_prepare(video, target_frame);
	}

	remove_wait_queue(&video->waitq, &wait);
	set_current_state(TASK_RUNNING);
	mutex_unlock(&video->mtx);
	return ret;
}


static ssize_t dv1394_read(struct file *file,  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;
		}
		video->continuity_counter = -1;

		receive_packets(video);

		start_dma_receive(video);
	}

	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
		   fires between the check and the schedule() */

		set_current_state(TASK_INTERRUPTIBLE);

		spin_lock_irqsave(&video->spinlock, flags);

		target_frame = video->first_clear_frame;

		spin_unlock_irqrestore(&video->spinlock, flags);

		if (target_frame >= 0 &&
			video->n_clear_frames > 0 &&
			video->frames[target_frame]->state == FRAME_CLEAR) {

			/* how much room is left in the target frame buffer */
			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);

		} else {
			/* buffer is already used */
			cnt = 0;
		}

		if (cnt > count)
			cnt = count;

		if (cnt <= 0) {
			/* no room left, gotta wait */
			if (file->f_flags & O_NONBLOCK) {
				if (!ret)
					ret = -EAGAIN;
				break;
			}
			if (signal_pending(current)) {
				if (!ret)
					ret = -ERESTARTSYS;
				break;
			}

			schedule();

			continue; /* start over from 'while(count > 0)...' */
		}

		if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
				if (!ret)
					ret = -EFAULT;
				break;
		}

		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);

		count -= cnt;
		buffer += cnt;
		ret += cnt;

		if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
			spin_lock_irqsave(&video->spinlock, flags);
			video->n_clear_frames--;
			video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
			spin_unlock_irqrestore(&video->spinlock, flags);
		}
	}

	remove_wait_queue(&video->waitq, &wait);
	set_current_state(TASK_RUNNING);
	mutex_unlock(&video->mtx);
	return ret;
}


/*** DEVICE IOCTL INTERFACE ************************************************/

static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct video_card *video = file_to_video_card(file);
	unsigned long flags;
	int ret = -EINVAL;
	void __user *argp = (void __user *)arg;

	DECLARE_WAITQUEUE(wait, current);

	/* 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;
	}

	switch(cmd)
	{
	case DV1394_IOC_SUBMIT_FRAMES: {
		unsigned int n_submit;

		if ( !video_card_initialized(video) ) {
			ret = do_dv1394_init_default(video);
			if (ret)
				goto out;
		}

		n_submit = (unsigned int) arg;

		if (n_submit > video->n_frames) {
			ret = -EINVAL;
			goto out;
		}

		while (n_submit > 0) {

			add_wait_queue(&video->waitq, &wait);
			set_current_state(TASK_INTERRUPTIBLE);

			spin_lock_irqsave(&video->spinlock, flags);

			/* wait until video->first_clear_frame is really CLEAR */
			while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {

				spin_unlock_irqrestore(&video->spinlock, flags);

				if (signal_pending(current)) {
					remove_wait_queue(&video->waitq, &wait);
					set_current_state(TASK_RUNNING);
					ret = -EINTR;
					goto out;
				}

				schedule();
				set_current_state(TASK_INTERRUPTIBLE);

				spin_lock_irqsave(&video->spinlock, flags);
			}
			spin_unlock_irqrestore(&video->spinlock, flags);

			remove_wait_queue(&video->waitq, &wait);
			set_current_state(TASK_RUNNING);

			frame_prepare(video, video->first_clear_frame);

			n_submit--;
		}

		ret = 0;
		break;
	}

	case DV1394_IOC_WAIT_FRAMES: {
		unsigned int n_wait;

		if ( !video_card_initialized(video) ) {
			ret = -EINVAL;
			goto out;
		}

		n_wait = (unsigned int) arg;

		/* since we re-run the last frame on underflow, we will
		   never actually have n_frames clear frames; at most only
		   n_frames - 1 */

		if (n_wait > (video->n_frames-1) ) {
			ret = -EINVAL;
			goto out;
		}

		add_wait_queue(&video->waitq, &wait);
		set_current_state(TASK_INTERRUPTIBLE);

		spin_lock_irqsave(&video->spinlock, flags);

		while (video->n_clear_frames < n_wait) {

			spin_unlock_irqrestore(&video->spinlock, flags);

			if (signal_pending(current)) {
				remove_wait_queue(&video->waitq, &wait);
				set_current_state(TASK_RUNNING);
				ret = -EINTR;
				goto out;
			}

			schedule();
			set_current_state(TASK_INTERRUPTIBLE);

			spin_lock_irqsave(&video->spinlock, flags);
		}

		spin_unlock_irqrestore(&video->spinlock, flags);

		remove_wait_queue(&video->waitq, &wait);
		set_current_state(TASK_RUNNING);
		ret = 0;
		break;
	}

	case DV1394_IOC_RECEIVE_FRAMES: {
		unsigned int n_recv;

		if ( !video_card_initialized(video) ) {
			ret = -EINVAL;
			goto out;
		}

		n_recv = (unsigned int) arg;

		/* at least one frame must be active */
		if (n_recv > (video->n_frames-1) ) {
			ret = -EINVAL;
			goto out;
		}

		spin_lock_irqsave(&video->spinlock, flags);

		/* release the clear frames */
		video->n_clear_frames -= n_recv;

		/* advance the clear frame cursor */
		video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;

		/* reset dropped_frames */
		video->dropped_frames = 0;

		spin_unlock_irqrestore(&video->spinlock, flags);

		ret = 0;
		break;
	}

	case DV1394_IOC_START_RECEIVE: {
		if ( !video_card_initialized(video) ) {
			ret = do_dv1394_init_default(video);
			if (ret)
				goto out;
		}

		video->continuity_counter = -1;

		receive_packets(video);

		start_dma_receive(video);

		ret = 0;
		break;
	}

	case DV1394_IOC_INIT: {
		struct dv1394_init init;
		if (!argp) {
			ret = do_dv1394_init_default(video);
		} else {
			if (copy_from_user(&init, argp, sizeof(init))) {
				ret = -EFAULT;
				goto out;
			}
			ret = do_dv1394_init(video, &init);
		}
		break;
	}

	case DV1394_IOC_SHUTDOWN:
		do_dv1394_shutdown(video, 0);
		ret = 0;
		break;


        case DV1394_IOC_GET_STATUS: {
		struct dv1394_status status;

		if ( !video_card_initialized(video) ) {
			ret = -EINVAL;
			goto out;
		}

		status.init.api_version = DV1394_API_VERSION;
		status.init.channel = video->channel;
		status.init.n_frames = video->n_frames;
		status.init.format = video->pal_or_ntsc;
		status.init.cip_n = video->cip_n;
		status.init.cip_d = video->cip_d;
		status.init.syt_offset = video->syt_offset;

		status.first_clear_frame = video->first_clear_frame;

		/* the rest of the fields need to be locked against the interrupt */
		spin_lock_irqsave(&video->spinlock, flags);

		status.active_frame = video->active_frame;
		status.n_clear_frames = video->n_clear_frames;

⌨️ 快捷键说明

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