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

📄 tvaudio.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	},	{		.name       = "tda8425",		.insmodopt  = &tda8425,		.addr_lo    = I2C_ADDR_TDA8425 >> 1,		.addr_hi    = I2C_ADDR_TDA8425 >> 1,		.registers  = 9,		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,		.leftreg    = TDA8425_VL,		.rightreg   = TDA8425_VR,		.bassreg    = TDA8425_BA,		.treblereg  = TDA8425_TR,		.volfunc    = tda8425_shift10,		.bassfunc   = tda8425_shift12,		.treblefunc = tda8425_shift12,		.inputreg   = TDA8425_S1,		.inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },		.inputmute  = TDA8425_S1_OFF,		.setmode    = tda8425_setmode,		.initialize = tda8425_initialize,	},	{		.name       = "pic16c54 (PV951)",		.insmodopt  = &pic16c54,		.addr_lo    = I2C_ADDR_PIC16C54 >> 1,		.addr_hi    = I2C_ADDR_PIC16C54>> 1,		.registers  = 2,		.flags      = CHIP_HAS_INPUTSEL,		.inputreg   = PIC16C54_REG_MISC,		.inputmap   = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,			     PIC16C54_MISC_SND_MUTE},		.inputmute  = PIC16C54_MISC_SND_MUTE,	},	{		.name       = "ta8874z",		.checkit    = ta8874z_checkit,		.insmodopt  = &ta8874z,		.addr_lo    = I2C_ADDR_TDA9840 >> 1,		.addr_hi    = I2C_ADDR_TDA9840 >> 1,		.registers  = 2,		.getmode    = ta8874z_getmode,		.setmode    = ta8874z_setmode,		.checkmode  = generic_checkmode,		.init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},	},	{ .name = NULL } /* EOF */};/* ---------------------------------------------------------------------- *//* i2c registration                                                       */static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id){	struct CHIPSTATE *chip;	struct CHIPDESC  *desc;	if (debug) {		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");		printk(KERN_INFO "tvaudio: known chips: ");		for (desc = chiplist; desc->name != NULL; desc++)			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);		printk("\n");	}	chip = kzalloc(sizeof(*chip),GFP_KERNEL);	if (!chip)		return -ENOMEM;	chip->c = client;	i2c_set_clientdata(client, chip);	/* find description for the chip */	v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);	for (desc = chiplist; desc->name != NULL; desc++) {		if (0 == *(desc->insmodopt))			continue;		if (client->addr < desc->addr_lo ||		    client->addr > desc->addr_hi)			continue;		if (desc->checkit && !desc->checkit(chip))			continue;		break;	}	if (desc->name == NULL) {		v4l_dbg(1, debug, client, "no matching chip description found\n");		return -EIO;	}	v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);	if (desc->flags) {		v4l_dbg(1, debug, client, "matches:%s%s%s.\n",			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");	}	/* fill required data structures */#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)	strcpy(client->name, desc->name);#else	if (!id)		strlcpy(client->name, desc->name, I2C_NAME_SIZE);#endif	chip->type = desc-chiplist;	chip->shadow.count = desc->registers+1;	chip->prevmode = -1;	chip->audmode = V4L2_TUNER_MODE_LANG1;	/* initialization  */	if (desc->initialize != NULL)		desc->initialize(chip);	else		chip_cmd(chip,"init",&desc->init);	if (desc->flags & CHIP_HAS_VOLUME) {		chip->left   = desc->leftinit   ? desc->leftinit   : 65535;		chip->right  = desc->rightinit  ? desc->rightinit  : 65535;		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));	}	if (desc->flags & CHIP_HAS_BASSTREBLE) {		chip->treble = desc->trebleinit ? desc->trebleinit : 32768;		chip->bass   = desc->bassinit   ? desc->bassinit   : 32768;		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));	}	chip->thread = NULL;	if (desc->checkmode) {		/* start async thread */		init_timer(&chip->wt);		chip->wt.function = chip_thread_wake;		chip->wt.data     = (unsigned long)chip;		chip->thread = kthread_run(chip_thread, chip, chip->c->name);		if (IS_ERR(chip->thread)) {			v4l_warn(chip->c, "%s: failed to create kthread\n",			       chip->c->name);			chip->thread = NULL;		}	}	return 0;}static int chip_remove(struct i2c_client *client){	struct CHIPSTATE *chip = i2c_get_clientdata(client);	del_timer_sync(&chip->wt);	if (chip->thread) {		/* shutdown async thread */		kthread_stop(chip->thread);		chip->thread = NULL;	}	kfree(chip);	return 0;}static int tvaudio_get_ctrl(struct CHIPSTATE *chip,			    struct v4l2_control *ctrl){	struct CHIPDESC *desc = chiplist + chip->type;	switch (ctrl->id) {	case V4L2_CID_AUDIO_MUTE:		ctrl->value=chip->muted;		return 0;	case V4L2_CID_AUDIO_VOLUME:		if (!(desc->flags & CHIP_HAS_VOLUME))			break;		ctrl->value = max(chip->left,chip->right);		return 0;	case V4L2_CID_AUDIO_BALANCE:	{		int volume;		if (!(desc->flags & CHIP_HAS_VOLUME))			break;		volume = max(chip->left,chip->right);		if (volume)			ctrl->value=(32768*min(chip->left,chip->right))/volume;		else			ctrl->value=32768;		return 0;	}	case V4L2_CID_AUDIO_BASS:		if (desc->flags & CHIP_HAS_BASSTREBLE)			break;		ctrl->value = chip->bass;		return 0;	case V4L2_CID_AUDIO_TREBLE:		if (desc->flags & CHIP_HAS_BASSTREBLE)			return -EINVAL;		ctrl->value = chip->treble;		return 0;	}	return -EINVAL;}static int tvaudio_set_ctrl(struct CHIPSTATE *chip,			    struct v4l2_control *ctrl){	struct CHIPDESC *desc = chiplist + chip->type;	switch (ctrl->id) {	case V4L2_CID_AUDIO_MUTE:		if (ctrl->value < 0 || ctrl->value >= 2)			return -ERANGE;		chip->muted = ctrl->value;		if (chip->muted)			chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);		else			chip_write_masked(chip,desc->inputreg,					desc->inputmap[chip->input],desc->inputmask);		return 0;	case V4L2_CID_AUDIO_VOLUME:	{		int volume,balance;		if (!(desc->flags & CHIP_HAS_VOLUME))			break;		volume = max(chip->left,chip->right);		if (volume)			balance=(32768*min(chip->left,chip->right))/volume;		else			balance=32768;		volume=ctrl->value;		chip->left = (min(65536 - balance,32768) * volume) / 32768;		chip->right = (min(balance,volume *(__u16)32768)) / 32768;		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));		return 0;	}	case V4L2_CID_AUDIO_BALANCE:	{		int volume, balance;		if (!(desc->flags & CHIP_HAS_VOLUME))			break;		volume = max(chip->left,chip->right);		balance = ctrl->value;		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));		return 0;	}	case V4L2_CID_AUDIO_BASS:		if (desc->flags & CHIP_HAS_BASSTREBLE)			break;		chip->bass = ctrl->value;		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));		return 0;	case V4L2_CID_AUDIO_TREBLE:		if (desc->flags & CHIP_HAS_BASSTREBLE)			return -EINVAL;		chip->treble = ctrl->value;		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));		return 0;	}	return -EINVAL;}/* ---------------------------------------------------------------------- *//* video4linux interface                                                  */static int chip_command(struct i2c_client *client,			unsigned int cmd, void *arg){	struct CHIPSTATE *chip = i2c_get_clientdata(client);	struct CHIPDESC  *desc = chiplist + chip->type;	v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);	switch (cmd) {	case AUDC_SET_RADIO:		chip->radio = 1;		chip->watch_stereo = 0;		/* del_timer(&chip->wt); */		break;	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	kernel pointer here... */	case VIDIOC_QUERYCTRL:	{		struct v4l2_queryctrl *qc = arg;		switch (qc->id) {			case V4L2_CID_AUDIO_MUTE:				break;			case V4L2_CID_AUDIO_VOLUME:			case V4L2_CID_AUDIO_BALANCE:				if (!(desc->flags & CHIP_HAS_VOLUME))					return -EINVAL;				break;			case V4L2_CID_AUDIO_BASS:			case V4L2_CID_AUDIO_TREBLE:				if (desc->flags & CHIP_HAS_BASSTREBLE)					return -EINVAL;				break;			default:				return -EINVAL;		}		return v4l2_ctrl_query_fill_std(qc);	}	case VIDIOC_S_CTRL:		return tvaudio_set_ctrl(chip, arg);	case VIDIOC_G_CTRL:		return tvaudio_get_ctrl(chip, arg);	case VIDIOC_INT_G_AUDIO_ROUTING:	{		struct v4l2_routing *rt = arg;		rt->input = chip->input;		rt->output = 0;		break;	}	case VIDIOC_INT_S_AUDIO_ROUTING:	{		struct v4l2_routing *rt = arg;		if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)				return -EINVAL;		/* There are four inputs: tuner, radio, extern and intern. */		chip->input = rt->input;		if (chip->muted)			break;		chip_write_masked(chip, desc->inputreg,				desc->inputmap[chip->input], desc->inputmask);		break;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *vt = arg;		int mode = 0;		if (chip->radio)			break;		switch (vt->audmode) {		case V4L2_TUNER_MODE_MONO:		case V4L2_TUNER_MODE_STEREO:		case V4L2_TUNER_MODE_LANG1:		case V4L2_TUNER_MODE_LANG2:			mode = vt->audmode;			break;		case V4L2_TUNER_MODE_LANG1_LANG2:			mode = V4L2_TUNER_MODE_STEREO;			break;		default:			return -EINVAL;		}		chip->audmode = vt->audmode;		if (desc->setmode && mode) {			chip->watch_stereo = 0;			/* del_timer(&chip->wt); */			chip->mode = mode;			desc->setmode(chip, mode);		}		break;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *vt = arg;		int mode = V4L2_TUNER_MODE_MONO;		if (chip->radio)			break;		vt->audmode = chip->audmode;		vt->rxsubchans = 0;		vt->capability = V4L2_TUNER_CAP_STEREO |			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;		if (desc->getmode)			mode = desc->getmode(chip);		if (mode & V4L2_TUNER_MODE_MONO)			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;		if (mode & V4L2_TUNER_MODE_STEREO)			vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;		/* Note: for SAP it should be mono/lang2 or stereo/lang2.		   When this module is converted fully to v4l2, then this		   should change for those chips that can detect SAP. */		if (mode & V4L2_TUNER_MODE_LANG1)			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |					 V4L2_TUNER_SUB_LANG2;		break;	}	case VIDIOC_S_STD:		chip->radio = 0;		break;	case VIDIOC_S_FREQUENCY:		chip->mode = 0; /* automatic */		if (desc->checkmode && desc->setmode) {			desc->setmode(chip,V4L2_TUNER_MODE_MONO);			if (chip->prevmode != V4L2_TUNER_MODE_MONO)				chip->prevmode = -1; /* reset previous mode */			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));			/* the thread will call checkmode() later */		}		break;	case VIDIOC_G_CHIP_IDENT:		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0);	}	return 0;}static int chip_legacy_probe(struct i2c_adapter *adap){	/* don't attach on saa7146 based cards,	   because dedicated drivers are used */	if ((adap->id == I2C_HW_SAA7146))		return 0;	if (adap->class & I2C_CLASS_TV_ANALOG)		return 1;	return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)/* This driver supports many devices and the idea is to let the driver   detect which device is present. So rather than listing all supported   devices here, we pretend to support a single, fake device type. */static const struct i2c_device_id chip_id[] = {	{ "tvaudio", 0 },	{ }};MODULE_DEVICE_TABLE(i2c, chip_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = {	.name = "tvaudio",	.driverid = I2C_DRIVERID_TVAUDIO,	.command = chip_command,	.probe = chip_probe,	.remove = chip_remove,	.legacy_probe = chip_legacy_probe,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)	.id_table = chip_id,#endif};/* * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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