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

📄 vino.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	if (i == 0) {		/* no buffers to process */		return 0;	}	fb = vino_queue_peek(&vcs->fb_queue, &i);	if (fb == NULL) {		dprintk("vino_queue_peek() failed\n");		return -EINVAL;	}	spin_lock_irqsave(&fb->state_lock, flags);	if (fb->state == VINO_FRAMEBUFFER_IN_USE) {		fb->state = VINO_FRAMEBUFFER_UNUSED;		vino_queue_transfer(&vcs->fb_queue);		vino_queue_remove(&vcs->fb_queue, &i);		/* we should actually discard the newest frame,		 * but who cares ... */	}	spin_unlock_irqrestore(&fb->state_lock, flags);	return 0;}#endifstatic void vino_skip_frame(struct vino_channel_settings *vcs){	struct vino_framebuffer *fb;	unsigned long flags;	unsigned int id;	spin_lock_irqsave(&vcs->capture_lock, flags);	fb = vino_queue_peek(&vcs->fb_queue, &id);	if (!fb) {		spin_unlock_irqrestore(&vcs->capture_lock, flags);		dprintk("vino_skip_frame(): vino_queue_peek() failed!\n");		return;	}	spin_unlock_irqrestore(&vcs->capture_lock, flags);	spin_lock_irqsave(&fb->state_lock, flags);	fb->state = VINO_FRAMEBUFFER_UNUSED;	spin_unlock_irqrestore(&fb->state_lock, flags);	vino_capture_next(vcs, 0);}static void vino_frame_done(struct vino_channel_settings *vcs){	struct vino_framebuffer *fb;	unsigned long flags;	spin_lock_irqsave(&vcs->capture_lock, flags);	fb = vino_queue_transfer(&vcs->fb_queue);	if (!fb) {		spin_unlock_irqrestore(&vcs->capture_lock, flags);		dprintk("vino_frame_done(): vino_queue_transfer() failed!\n");		return;	}	spin_unlock_irqrestore(&vcs->capture_lock, flags);	fb->frame_counter = vcs->int_data.frame_counter;	memcpy(&fb->timestamp, &vcs->int_data.timestamp,	       sizeof(struct timeval));	spin_lock_irqsave(&fb->state_lock, flags);	if (fb->state == VINO_FRAMEBUFFER_IN_USE)		fb->state = VINO_FRAMEBUFFER_READY;	spin_unlock_irqrestore(&fb->state_lock, flags);	wake_up(&vcs->fb_queue.frame_wait_queue);	vino_capture_next(vcs, 0);}static void vino_capture_tasklet(unsigned long channel) {	struct vino_channel_settings *vcs;	vcs = (channel == VINO_CHANNEL_A)		? &vino_drvdata->a : &vino_drvdata->b;	if (vcs->int_data.skip)		vcs->int_data.skip_count++;	if (vcs->int_data.skip && (vcs->int_data.skip_count				   <= VINO_MAX_FRAME_SKIP_COUNT)) {		vino_skip_frame(vcs);	} else {		vcs->int_data.skip_count = 0;		vino_frame_done(vcs);	}}static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs){	u32 ctrl, intr;	unsigned int fc_a, fc_b;	int handled_a = 0, skip_a = 0, done_a = 0;	int handled_b = 0, skip_b = 0, done_b = 0;#ifdef VINO_DEBUG_INT	int loop = 0;	unsigned int line_count = vino->a.line_count,		page_index = vino->a.page_index,		field_counter = vino->a.field_counter,		start_desc_tbl = vino->a.start_desc_tbl,		next_4_desc = vino->a.next_4_desc;	unsigned int line_count_2,		page_index_2,		field_counter_2,		start_desc_tbl_2,		next_4_desc_2;#endif	spin_lock(&vino_drvdata->vino_lock);	while ((intr = vino->intr_status)) {		fc_a = vino->a.field_counter >> 1;		fc_b = vino->b.field_counter >> 1;		/* handle error-interrupts in some special way ?		 * --> skips frames */		if (intr & VINO_INTSTAT_A) {			if (intr & VINO_INTSTAT_A_EOF) {				vino_drvdata->a.field++;				if (vino_drvdata->a.field > 1) {					vino_dma_stop(&vino_drvdata->a);					vino_clear_interrupt(&vino_drvdata->a);					vino_drvdata->a.field = 0;					done_a = 1;				} else {					if (vino->a.page_index					    != vino_drvdata->a.line_size) {						vino->a.line_count = 0;						vino->a.page_index =							vino_drvdata->							a.line_size;						vino->a.next_4_desc =							vino->a.start_desc_tbl;					}				}				dprintk("channel A end-of-field "					"interrupt: %04x\n", intr);			} else {				vino_dma_stop(&vino_drvdata->a);				vino_clear_interrupt(&vino_drvdata->a);				vino_drvdata->a.field = 0;				skip_a = 1;				dprintk("channel A error interrupt: %04x\n",					intr);			}#ifdef VINO_DEBUG_INT			line_count_2 = vino->a.line_count;			page_index_2 = vino->a.page_index;			field_counter_2 = vino->a.field_counter;			start_desc_tbl_2 = vino->a.start_desc_tbl;			next_4_desc_2 = vino->a.next_4_desc;			printk("intr = %04x, loop = %d, field = %d\n",			       intr, loop, vino_drvdata->a.field);			printk("1- line count = %04d, page index = %04d, "			       "start = %08x, next = %08x\n"			       "   fieldc = %d, framec = %d\n",			       line_count, page_index, start_desc_tbl,			       next_4_desc, field_counter, fc_a);			printk("12-line count = %04d, page index = %04d, "			       "   start = %08x, next = %08x\n",			       line_count_2, page_index_2, start_desc_tbl_2,			       next_4_desc_2);			if (done_a)				printk("\n");#endif		}		if (intr & VINO_INTSTAT_B) {			if (intr & VINO_INTSTAT_B_EOF) {				vino_drvdata->b.field++;				if (vino_drvdata->b.field > 1) {					vino_dma_stop(&vino_drvdata->b);					vino_clear_interrupt(&vino_drvdata->b);					vino_drvdata->b.field = 0;					done_b = 1;				}				dprintk("channel B end-of-field "					"interrupt: %04x\n", intr);			} else {				vino_dma_stop(&vino_drvdata->b);				vino_clear_interrupt(&vino_drvdata->b);				vino_drvdata->b.field = 0;				skip_b = 1;				dprintk("channel B error interrupt: %04x\n",					intr);			}		}		/* Always remember to clear interrupt status.		 * Disable VINO interrupts while we do this. */		ctrl = vino->control;		vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT);		vino->intr_status = ~intr;		vino->control = ctrl;		spin_unlock(&vino_drvdata->vino_lock);		if ((!handled_a) && (done_a || skip_a)) {			if (!skip_a) {				do_gettimeofday(&vino_drvdata->						a.int_data.timestamp);				vino_drvdata->a.int_data.frame_counter = fc_a;			}			vino_drvdata->a.int_data.skip = skip_a;			dprintk("channel A %s, interrupt: %d\n",				skip_a ? "skipping frame" : "frame done",				intr);			tasklet_hi_schedule(&vino_tasklet_a);			handled_a = 1;		}		if ((!handled_b) && (done_b || skip_b)) {			if (!skip_b) {				do_gettimeofday(&vino_drvdata->						b.int_data.timestamp);				vino_drvdata->b.int_data.frame_counter = fc_b;			}			vino_drvdata->b.int_data.skip = skip_b;			dprintk("channel B %s, interrupt: %d\n",				skip_b ? "skipping frame" : "frame done",				intr);			tasklet_hi_schedule(&vino_tasklet_b);			handled_b = 1;		}#ifdef VINO_DEBUG_INT		loop++;#endif		spin_lock(&vino_drvdata->vino_lock);	}	spin_unlock(&vino_drvdata->vino_lock);	return IRQ_HANDLED;}/* VINO video input management */static int vino_get_saa7191_input(int input){	switch (input) {	case VINO_INPUT_COMPOSITE:		return SAA7191_INPUT_COMPOSITE;	case VINO_INPUT_SVIDEO:		return SAA7191_INPUT_SVIDEO;	default:		printk(KERN_ERR "VINO: vino_get_saa7191_input(): "		       "invalid input!\n");		return -1;	}}static int vino_get_saa7191_norm(unsigned int data_norm){	switch (data_norm) {	case VINO_DATA_NORM_AUTO:		return SAA7191_NORM_AUTO;	case VINO_DATA_NORM_AUTO_EXT:		return SAA7191_NORM_AUTO_EXT;	case VINO_DATA_NORM_PAL:		return SAA7191_NORM_PAL;	case VINO_DATA_NORM_NTSC:		return SAA7191_NORM_NTSC;	case VINO_DATA_NORM_SECAM:		return SAA7191_NORM_SECAM;	default:		printk(KERN_ERR "VINO: vino_get_saa7191_norm(): "		       "invalid norm!\n");		return -1;	}}static int vino_get_from_saa7191_norm(int saa7191_norm){	switch (saa7191_norm) {	case SAA7191_NORM_PAL:		return VINO_DATA_NORM_PAL;	case SAA7191_NORM_NTSC:		return VINO_DATA_NORM_NTSC;	case SAA7191_NORM_SECAM:		return VINO_DATA_NORM_SECAM;	default:		printk(KERN_ERR "VINO: vino_get_from_saa7191_norm(): "		       "invalid norm!\n");		return VINO_DATA_NORM_NONE;	}}static int vino_saa7191_set_norm(unsigned int *data_norm){	int saa7191_norm, new_data_norm;	int err = 0;	saa7191_norm = vino_get_saa7191_norm(*data_norm);	err = i2c_decoder_command(DECODER_SAA7191_SET_NORM,				  &saa7191_norm);	if (err)		goto out;	if ((*data_norm == VINO_DATA_NORM_AUTO)	    || (*data_norm == VINO_DATA_NORM_AUTO_EXT)) {		struct saa7191_status status;		err = i2c_decoder_command(DECODER_SAA7191_GET_STATUS,					  &status);		if (err)			goto out;		new_data_norm =			vino_get_from_saa7191_norm(status.norm);		if (new_data_norm == VINO_DATA_NORM_NONE) {			err = -EINVAL;			goto out;		}		*data_norm = (unsigned int)new_data_norm;	}out:	return err;}/* execute with input_lock locked */static int vino_is_input_owner(struct vino_channel_settings *vcs){	switch(vcs->input) {	case VINO_INPUT_COMPOSITE:	case VINO_INPUT_SVIDEO:		return (vino_drvdata->decoder.owner == vcs->channel);	case VINO_INPUT_D1:		return (vino_drvdata->camera.owner == vcs->channel);	default:		return 0;	}}static int vino_acquire_input(struct vino_channel_settings *vcs){	unsigned long flags;	int ret = 0;	dprintk("vino_acquire_input():\n");	spin_lock_irqsave(&vino_drvdata->input_lock, flags);	/* First try D1 and then SAA7191 */	if (vino_drvdata->camera.driver	    && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {		if (i2c_use_client(vino_drvdata->camera.driver)) {			ret = -ENODEV;			goto out;		}		vino_drvdata->camera.owner = vcs->channel;		vcs->input = VINO_INPUT_D1;		vcs->data_norm = VINO_DATA_NORM_D1;	} else if (vino_drvdata->decoder.driver		   && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) {		int input, data_norm;		int saa7191_input;		if (i2c_use_client(vino_drvdata->decoder.driver)) {			ret = -ENODEV;			goto out;		}		input = VINO_INPUT_COMPOSITE;		saa7191_input = vino_get_saa7191_input(input);		ret = i2c_decoder_command(DECODER_SET_INPUT,					  &saa7191_input);		if (ret) {			ret = -EINVAL;			goto out;		}		spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);		/* Don't hold spinlocks while auto-detecting norm		 * as it may take a while... */		data_norm = VINO_DATA_NORM_AUTO_EXT;		ret = vino_saa7191_set_norm(&data_norm);		if ((ret == -EBUSY) || (ret == -EAGAIN)) {			data_norm = VINO_DATA_NORM_PAL;			ret = vino_saa7191_set_norm(&data_norm);		}		spin_lock_irqsave(&vino_drvdata->input_lock, flags);		if (ret) {			ret = -EINVAL;			goto out;		}		vino_drvdata->decoder.owner = vcs->channel;		vcs->input = input;		vcs->data_norm = data_norm;	} else {		vcs->input = (vcs->channel == VINO_CHANNEL_A) ?			vino_drvdata->b.input : vino_drvdata->a.input;		vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ?			vino_drvdata->b.data_norm : vino_drvdata->a.data_norm;	}	if (vcs->input == VINO_INPUT_NONE) {		ret = -ENODEV;		goto out;	}	vino_set_default_clipping(vcs);	vino_set_default_scaling(vcs);	vino_set_default_framerate(vcs);	dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);out:	spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);	return ret;}static int vino_set_input(struct vino_channel_settings *vcs, int input){	struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?		&vino_drvdata->b : &vino_drvdata->a;	unsigned long flags;	int ret = 0;	dprintk("vino_set_input():\n");	spin_lock_irqsave(&vino_drvdata->input_lock, flags);	if (vcs->input == input)		goto out;	switch (input) {	case VINO_INPUT_COMPOSITE:	case VINO_INPUT_SVIDEO:		if (!vino_drvdata->decoder.driver) {			ret = -EINVAL;			goto out;		}		if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {			if (i2c_use_client(vino_drvdata->decoder.driver)) {				ret = -ENODEV;				goto out;			}			vino_drvdata->decoder.owner = vcs->channel;		}		if (vino_drvdata->decoder.owner == vcs->channel) {			int data_norm;			int saa7191_input;			saa7191_input = vino_get_saa7191_input(input);			ret = i2c_decoder_command(DECODER_SET_INPUT,						  &saa7191_input);			if (ret) {				vino_drvdata->decoder.owner = VINO_NO_CHANNEL;				ret = -EINVAL;				goto out;			}			spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);			/* Don't hold spinlocks while auto-detecting norm			 * as it may take a while... */			data_norm = VINO_DATA_NORM_AUTO_EXT;			ret = vino_saa7191_set_norm(&data_norm);			if ((ret  == -EBUSY) || (ret == -EAGAIN)) {				data_norm = VINO_DATA_NORM_PAL;				ret = vino_saa7191_set_norm(&data_norm);			}			spin_lock_irqsave(&vino_drvdata->input_lock, flags);			if (ret) {				vino_drvdata->decoder.owner = VINO_NO_CHANNEL;				ret = -EINVAL;				goto out;			}			vcs->input = input;			vcs->data_norm = data_norm;		} else {			if (input != vcs2->input) {				ret = -EBUSY;				goto out;			}			vcs->input = input;			vcs->data_norm = vcs2->data_norm;		}		if (vino_drvdata->camera.owner == vcs->channel) {			/* Transfer the ownership or release the input */			if (vcs2->input == VINO_INPUT_D1) {				vino_drvdata->camera.owner = vcs2->channel;			} else {				i2c_release_client(vino_drvdata->						   camera.driver);				vino_drvdata->camera.owner = VINO_NO_CHANNEL;			}		}		break;	case VINO_INPUT_D1:		if (!vino_drvdata->camera.driver) {			ret = -EINVAL;			goto out;		}		if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {			if (i2c_use_client(vino_drvdata->camera.driver)) {				ret = -ENODEV;				goto out;			}			vino_drvdata->camera.owner = vcs->channel;		}		if (vino_drvdata->decoder.owner == vcs->channel) {			/* Transfer the ownership or release the input */			if ((vcs2->input == VINO_INPUT_COMPOSITE) ||				 (vcs2->input == VINO_INPUT_SVIDEO)) {				vino_drvdata->decoder.owner = vcs2->channel;			} else {				i2c_release_client(vino_drvdata->						   decoder.driver);				vino_drvdata->decoder.owner = VINO_NO_CHANNEL;			}		}		vcs->input = input;		vcs->data_norm = VINO_DATA_NORM_D1;		break;	default:		ret = -EINVAL;		goto out;	}

⌨️ 快捷键说明

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