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

📄 ivtv-fileops.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&	    test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {		ivtv_stop_v4l2_encode_stream(s_vbi, 0);		clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);	}	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);	ivtv_release_stream(s);	return -EIO;}ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos){	struct ivtv_open_id *id = filp->private_data;	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	int rc;	IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);	mutex_lock(&itv->serialize_lock);	rc = ivtv_start_capture(id);	mutex_unlock(&itv->serialize_lock);	if (rc)		return rc;	return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);}int ivtv_start_decoding(struct ivtv_open_id *id, int speed){	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	if (atomic_read(&itv->decoding) == 0) {		if (ivtv_claim_stream(id, s->type)) {			/* someone else is using this stream already */			IVTV_DEBUG_WARN("start decode, stream already claimed\n");			return -EBUSY;		}		ivtv_start_v4l2_decode_stream(s, 0);	}	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)		return ivtv_set_speed(itv, speed);	return 0;}ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos){	struct ivtv_open_id *id = filp->private_data;	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	struct ivtv_buffer *buf;	struct ivtv_queue q;	int bytes_written = 0;	int mode;	int rc;	DEFINE_WAIT(wait);	IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);	if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&	    s->type != IVTV_DEC_STREAM_TYPE_YUV &&	    s->type != IVTV_DEC_STREAM_TYPE_VOUT)		/* not decoder streams */		return -EPERM;	/* Try to claim this stream */	if (ivtv_claim_stream(id, s->type))		return -EBUSY;	/* This stream does not need to start any decoding */	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {		int elems = count / sizeof(struct v4l2_sliced_vbi_data);		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);		ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems);		return elems * sizeof(struct v4l2_sliced_vbi_data);	}	mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;	if (ivtv_set_output_mode(itv, mode) != mode) {	    ivtv_release_stream(s);	    return -EBUSY;	}	ivtv_queue_init(&q);	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);retry:	for (;;) {		/* Gather buffers */		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))			ivtv_enqueue(s, buf, &q);		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) {			ivtv_enqueue(s, buf, &q);		}		if (q.buffers)			break;		if (filp->f_flags & O_NONBLOCK)			return -EAGAIN;		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);		/* New buffers might have become free before we were added to the waitqueue */		if (!s->q_free.buffers)			schedule();		finish_wait(&s->waitq, &wait);		if (signal_pending(current)) {			IVTV_DEBUG_INFO("User stopped %s\n", s->name);			return -EINTR;		}	}	/* copy user data into buffers */	while ((buf = ivtv_dequeue(s, &q))) {		/* Make sure we really got all the user data */		rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);		if (rc < 0) {			ivtv_queue_move(s, &q, NULL, &s->q_free, 0);			return rc;		}		user_buf += rc;		count -= rc;		bytes_written += rc;		if (buf->bytesused != s->buf_size) {			/* incomplete, leave in q_io for next time */			ivtv_enqueue(s, buf, &s->q_io);			break;		}		/* Byteswap MPEG buffer */		if (s->type == IVTV_DEC_STREAM_TYPE_MPG)			ivtv_buf_swap(buf);		ivtv_enqueue(s, buf, &s->q_full);	}	/* Start decoder (returns 0 if already started) */	mutex_lock(&itv->serialize_lock);	rc = ivtv_start_decoding(id, itv->speed);	mutex_unlock(&itv->serialize_lock);	if (rc) {		IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);		/* failure, clean up */		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);		return rc;	}	if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {		if (s->q_full.length >= itv->dma_data_req_size) {			int got_sig;			prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);			while (!(got_sig = signal_pending(current)) &&					test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {				schedule();			}			finish_wait(&itv->dma_waitq, &wait);			if (got_sig) {				IVTV_DEBUG_INFO("User interrupted %s\n", s->name);				return -EINTR;			}			clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);			ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);			ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1);		}	}	/* more user data is available, wait until buffers become free	   to transfer the rest. */	if (count && !(filp->f_flags & O_NONBLOCK))		goto retry;	IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);	return bytes_written;}unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait){	struct ivtv_open_id *id = filp->private_data;	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	int res = 0;	/* add stream's waitq to the poll list */	IVTV_DEBUG_HI_FILE("Decoder poll\n");	poll_wait(filp, &s->waitq, wait);	set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);	if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||	    test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))		res = POLLPRI;	/* Allow write if buffers are available for writing */	if (s->q_free.buffers)		res |= POLLOUT | POLLWRNORM;	return res;}unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait){	struct ivtv_open_id *id = filp->private_data;	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);	/* Start a capture if there is none */	if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {		int rc;		mutex_lock(&itv->serialize_lock);		rc = ivtv_start_capture(id);		mutex_unlock(&itv->serialize_lock);		if (rc) {			IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",					s->name, rc);			return POLLERR;		}		IVTV_DEBUG_FILE("Encoder poll started capture\n");	}	/* add stream's waitq to the poll list */	IVTV_DEBUG_HI_FILE("Encoder poll\n");	poll_wait(filp, &s->waitq, wait);	if (eof || s->q_full.length)		return POLLIN | POLLRDNORM;	return 0;}void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end){	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	IVTV_DEBUG_FILE("close() of %s\n", s->name);	/* 'Unclaim' this stream */	/* Stop capturing */	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {		struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];		IVTV_DEBUG_INFO("close stopping capture\n");		/* Special case: a running VBI capture for VBI insertion		   in the mpeg stream. Need to stop that too. */		if (id->type == IVTV_ENC_STREAM_TYPE_MPG &&		    test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) &&		    !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {			IVTV_DEBUG_INFO("close stopping embedded VBI capture\n");			ivtv_stop_v4l2_encode_stream(s_vbi, 0);		}		if ((id->type == IVTV_DEC_STREAM_TYPE_VBI ||		     id->type == IVTV_ENC_STREAM_TYPE_VBI) &&		    test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {			/* Also used internally, don't stop capturing */			s->id = -1;		}		else {			ivtv_stop_v4l2_encode_stream(s, gop_end);		}	}	if (!gop_end) {		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);		clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);		ivtv_release_stream(s);	}}static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts){	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	IVTV_DEBUG_FILE("close() of %s\n", s->name);	/* Stop decoding */	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {		IVTV_DEBUG_INFO("close stopping decode\n");		ivtv_stop_v4l2_decode_stream(s, flags, pts);		itv->output_mode = OUT_NONE;	}	clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);	if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {		/* Restore registers we've changed & clean up any mess we've made */		ivtv_yuv_close(itv);	}	if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)		itv->output_mode = OUT_NONE;	itv->speed = 0;	clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);	ivtv_release_stream(s);}int ivtv_v4l2_close(struct inode *inode, struct file *filp){	struct ivtv_open_id *id = filp->private_data;	struct ivtv *itv = id->itv;	struct ivtv_stream *s = &itv->streams[id->type];	IVTV_DEBUG_FILE("close %s\n", s->name);	v4l2_prio_close(&itv->prio, &id->prio);	/* Easy case first: this stream was never claimed by us */	if (s->id != id->open_id) {		kfree(id);		return 0;	}	/* 'Unclaim' this stream */	/* Stop radio */	mutex_lock(&itv->serialize_lock);	if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {		/* Closing radio device, return to TV mode */		ivtv_mute(itv);		/* Mark that the radio is no longer in use */		clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);		/* Switch tuner to TV */		ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);		/* Select correct audio input (i.e. TV tuner or Line in) */		ivtv_audio_set_io(itv);		if (itv->hw_flags & IVTV_HW_SAA711X)		{			struct v4l2_crystal_freq crystal_freq;			crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;			crystal_freq.flags = 0;			ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);		}		if (atomic_read(&itv->capturing) > 0) {			/* Undo video mute */			ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,				itv->params.video_mute | (itv->params.video_mute_yuv << 8));		}		/* Done! Unmute and continue. */		ivtv_unmute(itv);		ivtv_release_stream(s);	} else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {		struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];		ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);		/* If all output streams are closed, and if the user doesn't have		   IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */		if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {			/* disable CC on TV-out */			ivtv_disable_cc(itv);		}	} else {		ivtv_stop_capture(id, 0);	}	kfree(id);	mutex_unlock(&itv->serialize_lock);	return 0;}static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp){	struct ivtv *itv = s->itv;	struct ivtv_open_id *item;	IVTV_DEBUG_FILE("open %s\n", s->name);	if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))		return -EBUSY;	if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))		return -EBUSY;	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {		if (read_reg(0x82c) == 0) {			IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");			/* return -ENODEV; */		}		ivtv_udma_alloc(itv);	}	/* Allocate memory */	item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);	if (NULL == item) {		IVTV_DEBUG_WARN("nomem on v4l2 open\n");		return -ENOMEM;	}	item->itv = itv;	item->type = s->type;	v4l2_prio_open(&itv->prio, &item->prio);	item->open_id = itv->open_id++;	filp->private_data = item;	if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {		/* Try to claim this stream */		if (ivtv_claim_stream(item, item->type)) {			/* No, it's already in use */			kfree(item);			return -EBUSY;		}		if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {			if (atomic_read(&itv->capturing) > 0) {				/* switching to radio while capture is				   in progress is not polite */				ivtv_release_stream(s);				kfree(item);				return -EBUSY;			}		}		/* Mark that the radio is being used. */		set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);		/* We have the radio */		ivtv_mute(itv);		/* Switch tuner to radio */		ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);		/* Select the correct audio input (i.e. radio tuner) */		ivtv_audio_set_io(itv);		if (itv->hw_flags & IVTV_HW_SAA711X)		{			struct v4l2_crystal_freq crystal_freq;			crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;			crystal_freq.flags = SAA7115_FREQ_FL_APLL;			ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);		}		/* Done! Unmute and continue. */		ivtv_unmute(itv);	}	/* YUV or MPG Decoding Mode? */	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);	else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);	return 0;}int ivtv_v4l2_open(struct inode *inode, struct file *filp){	int res, x, y = 0;	struct ivtv *itv = NULL;	struct ivtv_stream *s = NULL;	int minor = iminor(inode);	/* Find which card this open was on */	spin_lock(&ivtv_cards_lock);	for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {		/* find out which stream this open was on */		for (y = 0; y < IVTV_MAX_STREAMS; y++) {			s = &ivtv_cards[x]->streams[y];			if (s->v4l2dev && s->v4l2dev->minor == minor) {				itv = ivtv_cards[x];				break;			}		}	}	spin_unlock(&ivtv_cards_lock);	if (itv == NULL) {		/* Couldn't find a device registered		   on that minor, shouldn't happen! */		printk(KERN_WARNING "No ivtv device found on minor %d\n", minor);		return -ENXIO;	}	mutex_lock(&itv->serialize_lock);	if (ivtv_init_on_first_open(itv)) {		IVTV_ERR("Failed to initialize on minor %d\n", minor);		mutex_unlock(&itv->serialize_lock);		return -ENXIO;	}	res = ivtv_serialized_open(s, filp);	mutex_unlock(&itv->serialize_lock);	return res;}void ivtv_mute(struct ivtv *itv){	if (atomic_read(&itv->capturing))		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);	IVTV_DEBUG_INFO("Mute\n");}void ivtv_unmute(struct ivtv *itv){	if (atomic_read(&itv->capturing)) {		ivtv_msleep_timeout(100, 0);		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);	}	IVTV_DEBUG_INFO("Unmute\n");}

⌨️ 快捷键说明

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