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

📄 mxb.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
static int mxb_detach(struct saa7146_dev *dev){	struct mxb *mxb = (struct mxb *)dev->ext_priv;	DEB_EE(("dev:%p\n", dev));	i2c_release_client(mxb->tea6420_1);	i2c_release_client(mxb->tea6420_2);	i2c_release_client(mxb->tea6415c);	i2c_release_client(mxb->tda9840);	i2c_release_client(mxb->saa7111a);	i2c_release_client(mxb->tuner);	saa7146_unregister_device(&mxb->video_dev,dev);	if (MXB_BOARD_CAN_DO_VBI(dev))		saa7146_unregister_device(&mxb->vbi_dev, dev);	saa7146_vv_release(dev);	mxb_num--;	i2c_del_adapter(&mxb->i2c_adapter);	kfree(mxb);	return 0;}static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg){	struct saa7146_dev *dev = fh->dev;	struct mxb *mxb = (struct mxb *)dev->ext_priv;	struct saa7146_vv *vv = dev->vv_data;	switch(cmd) {	case VIDIOC_ENUMINPUT:	{		struct v4l2_input *i = arg;		DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));		if (i->index < 0 || i->index >= MXB_INPUTS)			return -EINVAL;		memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));		return 0;	}	/* the saa7146 provides some controls (brightness, contrast, saturation)	   which gets registered *after* this function. because of this we have	   to return with a value != 0 even if the function succeded.. */	case VIDIOC_QUERYCTRL:	{		struct v4l2_queryctrl *qc = arg;		int i;		for (i = MAXCONTROLS - 1; i >= 0; i--) {			if (mxb_controls[i].id == qc->id) {				*qc = mxb_controls[i];				DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));				return 0;			}		}		return -EAGAIN;	}	case VIDIOC_G_CTRL:	{		struct v4l2_control *vc = arg;		int i;		for (i = MAXCONTROLS - 1; i >= 0; i--) {			if (mxb_controls[i].id == vc->id)				break;		}		if (i < 0)			return -EAGAIN;		if (vc->id == V4L2_CID_AUDIO_MUTE) {			vc->value = mxb->cur_mute;			DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));			return 0;		}		DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));		return 0;	}	case VIDIOC_S_CTRL:	{		struct v4l2_control *vc = arg;		int i = 0;		for (i = MAXCONTROLS - 1; i >= 0; i--) {			if (mxb_controls[i].id == vc->id)				break;		}		if (i < 0)			return -EAGAIN;		if (vc->id == V4L2_CID_AUDIO_MUTE) {			mxb->cur_mute = vc->value;			if (!vc->value) {				/* switch the audio-source */				mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,						&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);				mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,						&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);			} else {				mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,						&TEA6420_line[6][0]);				mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,						&TEA6420_line[6][1]);			}			DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));		}		return 0;	}	case VIDIOC_G_INPUT:	{		int *input = (int *)arg;		*input = mxb->cur_input;		DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));		return 0;	}	case VIDIOC_S_INPUT:	{		int input = *(int *)arg;		struct tea6415c_multiplex vm;		struct v4l2_routing route;		int i = 0;		DEB_EE(("VIDIOC_S_INPUT %d.\n", input));		if (input < 0 || input >= MXB_INPUTS)			return -EINVAL;		mxb->cur_input = input;		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,				input_port_selection[input].hps_sync);		/* prepare switching of tea6415c and saa7111a;		   have a look at the 'background'-file for further informations  */		switch (input) {		case TUNER:			i = SAA7115_COMPOSITE0;			vm.in  = 3;			vm.out = 17;			if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {				printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");				return -EFAULT;			}			/* connect tuner-output always to multicable */			vm.in  = 3;			vm.out = 13;			break;		case AUX3_YC:			/* nothing to be done here. aux3_yc is			   directly connected to the saa711a */			i = SAA7115_SVIDEO1;			break;		case AUX3:			/* nothing to be done here. aux3 is			   directly connected to the saa711a */			i = SAA7115_COMPOSITE1;			break;		case AUX1:			i = SAA7115_COMPOSITE0;			vm.in  = 1;			vm.out = 17;			break;		}		/* switch video in tea6415c only if necessary */		switch (input) {		case TUNER:		case AUX1:			if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {				printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");				return -EFAULT;			}			break;		default:			break;		}		/* switch video in saa7111a */		route.input = i;		route.output = 0;		if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))			printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");		/* switch the audio-source only if necessary */		if( 0 == mxb->cur_mute ) {			mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,					&TEA6420_line[video_audio_connect[input]][0]);			mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,				       &TEA6420_line[video_audio_connect[input]][1]);		}		return 0;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *t = arg;		if (t->index) {			DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));			return -EINVAL;		}		DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));		memset(t, 0, sizeof(*t));		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);		strlcpy(t->name, "TV Tuner", sizeof(t->name));		t->type = V4L2_TUNER_ANALOG_TV;		t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;		t->audmode = mxb->cur_mode;		return 0;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *t = arg;		if (t->index) {			DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));			return -EINVAL;		}		mxb->cur_mode = t->audmode;		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);		return 0;	}	case VIDIOC_G_FREQUENCY:	{		struct v4l2_frequency *f = arg;		if (mxb->cur_input) {			DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",						mxb->cur_input));			return -EINVAL;		}		*f = mxb->cur_freq;		DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));		return 0;	}	case VIDIOC_S_FREQUENCY:	{		struct v4l2_frequency *f = arg;		if (f->tuner)			return -EINVAL;		if (V4L2_TUNER_ANALOG_TV != f->type)			return -EINVAL;		if (mxb->cur_input) {			DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));			return -EINVAL;		}		mxb->cur_freq = *f;		DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));		/* tune in desired frequency */		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);		/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */		spin_lock(&dev->slock);		vv->vbi_fieldcount = 0;		spin_unlock(&dev->slock);		return 0;	}	case MXB_S_AUDIO_CD:	{		int i = *(int*)arg;		if (i < 0 || i >= MXB_AUDIOS) {			DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));			return -EINVAL;		}		DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));		mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);		mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);		return 0;	}	case MXB_S_AUDIO_LINE:	{		int i = *(int*)arg;		if (i < 0 || i >= MXB_AUDIOS) {			DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));			return -EINVAL;		}		DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));		mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);		mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);		return 0;	}	case VIDIOC_G_AUDIO:	{		struct v4l2_audio *a = arg;		if (a->index < 0 || a->index > MXB_INPUTS) {			DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));			return -EINVAL;		}		DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));		memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));		return 0;	}	case VIDIOC_S_AUDIO:	{		struct v4l2_audio *a = arg;		DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));		return 0;	}#ifdef CONFIG_VIDEO_ADV_DEBUG	case VIDIOC_DBG_S_REGISTER:	case VIDIOC_DBG_G_REGISTER:		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);		return 0;#endif	default:/*		DEB2(printk("does not handle this ioctl.\n"));*/		return -ENOIOCTLCMD;	}	return 0;}static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard){	struct mxb *mxb = (struct mxb *)dev->ext_priv;	int zero = 0;	int one = 1;	if (V4L2_STD_PAL_I == standard->id) {		v4l2_std_id std = V4L2_STD_PAL_I;		DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));		/* set the 7146 gpio register -- I don't know what this does exactly */		saa7146_write(dev, GPIO_CTRL, 0x00404050);		/* unset the 7111 gpio register -- I don't know what this does exactly */		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);	} else {		v4l2_std_id std = V4L2_STD_PAL_BG;		DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));		/* set the 7146 gpio register -- I don't know what this does exactly */		saa7146_write(dev, GPIO_CTRL, 0x00404050);		/* set the 7111 gpio register -- I don't know what this does exactly */		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);	}	return 0;}static struct saa7146_standard standard[] = {	{		.name	= "PAL-BG", 	.id	= V4L2_STD_PAL_BG,		.v_offset	= 0x17,	.v_field 	= 288,		.h_offset	= 0x14,	.h_pixels 	= 680,		.v_max_out	= 576,	.h_max_out	= 768,	}, {		.name	= "PAL-I", 	.id	= V4L2_STD_PAL_I,		.v_offset	= 0x17,	.v_field 	= 288,		.h_offset	= 0x14,	.h_pixels 	= 680,		.v_max_out	= 576,	.h_max_out	= 768,	}, {		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,		.v_offset	= 0x16,	.v_field 	= 240,		.h_offset	= 0x06,	.h_pixels 	= 708,		.v_max_out	= 480,	.h_max_out	= 640,	}, {		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,		.v_offset	= 0x14,	.v_field 	= 288,		.h_offset	= 0x14,	.h_pixels 	= 720,		.v_max_out	= 576,	.h_max_out	= 768,	}};static struct saa7146_pci_extension_data mxb = {	.ext_priv = "Multimedia eXtension Board",	.ext = &extension,};static struct pci_device_id pci_tbl[] = {	{		.vendor    = PCI_VENDOR_ID_PHILIPS,		.device	   = PCI_DEVICE_ID_PHILIPS_SAA7146,		.subvendor = 0x0000,		.subdevice = 0x0000,		.driver_data = (unsigned long)&mxb,	}, {		.vendor	= 0,	}};MODULE_DEVICE_TABLE(pci, pci_tbl);static struct saa7146_ext_vv vv_data = {	.inputs		= MXB_INPUTS,	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,	.stds		= &standard[0],	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),	.std_callback	= &std_callback,	.ioctls		= &ioctls[0],	.ioctl		= mxb_ioctl,};static struct saa7146_extension extension = {	.name		= MXB_IDENTIFIER,	.flags		= SAA7146_USE_I2C_IRQ,	.pci_tbl	= &pci_tbl[0],	.module		= THIS_MODULE,	.probe		= mxb_probe,	.attach		= mxb_attach,	.detach		= mxb_detach,	.irq_mask	= 0,	.irq_func	= NULL,};static int __init mxb_init_module(void){	if (saa7146_register_extension(&extension)) {		DEB_S(("failed to register extension.\n"));		return -ENODEV;	}	return 0;}static void __exit mxb_cleanup_module(void){	saa7146_unregister_extension(&extension);}module_init(mxb_init_module);module_exit(mxb_cleanup_module);MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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