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

📄 tas3001c.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			u_int channel,			u_int filter,			union tas_biquad_t *biquad){	tas_shadow_t *shadow=self->super.shadow;	enum tas3001c_reg_t reg;	if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||	    filter  >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;	reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter;	biquad->coeff.b0=GET_4_20(shadow[reg], 0);	biquad->coeff.b1=GET_4_20(shadow[reg], 3);	biquad->coeff.b2=GET_4_20(shadow[reg], 6);	biquad->coeff.a1=GET_4_20(shadow[reg], 9);	biquad->coeff.a2=GET_4_20(shadow[reg],12);		return 0;	}static inttas3001c_eq_rw(	struct tas3001c_data_t *self,		u_int cmd,		u_long arg){	int rc;	struct tas_biquad_ctrl_t biquad;	void __user *argp = (void __user *)arg;	if (copy_from_user(&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) {		return -EFAULT;	}	if (cmd & SIOC_IN) {		rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data);		if (rc != 0) return rc;	}	if (cmd & SIOC_OUT) {		rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);		if (rc != 0) return rc;		if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) {			return -EFAULT;		}	}	return 0;}static inttas3001c_eq_list_rw(	struct tas3001c_data_t *self,			u_int cmd,			u_long arg){	int rc;	int filter_count;	int flags;	int i,j;	char sync_required[2][6];	struct tas_biquad_ctrl_t biquad;	struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg;	memset(sync_required,0,sizeof(sync_required));	if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int)))		return -EFAULT;	if (copy_from_user(&flags, &argp->flags, sizeof(int)))		return -EFAULT;	if (cmd & SIOC_IN) {	}	for (i=0; i < filter_count; i++) {		if (copy_from_user(&biquad, &argp->biquads[i],				   sizeof(struct tas_biquad_ctrl_t))) {			return -EFAULT;		}		if (cmd & SIOC_IN) {			sync_required[biquad.channel][biquad.filter]=1;			rc=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data);			if (rc != 0) return rc;		}		if (cmd & SIOC_OUT) {			rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);			if (rc != 0) return rc;			if (copy_to_user(&argp->biquads[i], &biquad,					 sizeof(struct tas_biquad_ctrl_t))) {				return -EFAULT;			}		}	}	if (cmd & SIOC_IN) {		if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1);		for (i=0; i<2; i++) {			for (j=0; j<6; j++) {				if (sync_required[i][j]) {					rc=tas3001c_sync_biquad(self, i, j);					if (rc < 0) return rc;				}			}		}		if (flags & TAS_BIQUAD_FAST_LOAD) {			tas3001c_fast_load(self,0);			/* now we need to set up the mixers again,			   because leaving fast mode resets them. */			(void)tas3001c_sync_register(self,TAS3001C_REG_BASS);			(void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);			(void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);			(void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);			(void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);		}	}	return 0;}static inttas3001c_update_drce(	struct tas3001c_data_t *self,			int flags,			struct tas_drce_t *drce){	tas_shadow_t *shadow;	shadow=self->super.shadow;	shadow[TAS3001C_REG_DRC][1] = 0xc1;	if (flags & TAS_DRCE_THRESHOLD) {		self->drce_state.threshold=quantize_db(drce->threshold);		shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold);	}	if (flags & TAS_DRCE_ENABLE) {		self->drce_state.enable = drce->enable;	}	if (!self->drce_state.enable) {		shadow[TAS3001C_REG_DRC][0] = 0xf0;	}#ifdef DEBUG_DRCE	printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n",	       self->drce_state.enable,	       self->drce_state.threshold);	printk("DRCE IOCTL: reg [ %02x %02x ]\n",	       (unsigned char)shadow[TAS3001C_REG_DRC][0],	       (unsigned char)shadow[TAS3001C_REG_DRC][1]);#endif	return tas3001c_sync_register(self, TAS3001C_REG_DRC);}static inttas3001c_drce_rw(	struct tas3001c_data_t *self,			u_int cmd,			u_long arg){	int rc;	struct tas_drce_ctrl_t drce_ctrl;	void __user *argp = (void __user *)arg;	if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t)))		return -EFAULT;#ifdef DEBUG_DRCE	printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n",	       drce_ctrl.flags,	       drce_ctrl.data.enable,	       drce_ctrl.data.threshold);#endif	if (cmd & SIOC_IN) {		rc = tas3001c_update_drce(self, drce_ctrl.flags, &drce_ctrl.data);		if (rc < 0)			return rc;	}	if (cmd & SIOC_OUT) {		if (drce_ctrl.flags & TAS_DRCE_ENABLE)			drce_ctrl.data.enable = self->drce_state.enable;		if (drce_ctrl.flags & TAS_DRCE_THRESHOLD)			drce_ctrl.data.threshold = self->drce_state.threshold;		if (copy_to_user(argp, &drce_ctrl,				 sizeof(struct tas_drce_ctrl_t))) {			return -EFAULT;		}	}	return 0;}static voidtas3001c_update_device_parameters(struct tas3001c_data_t *self){	int i,j;	if (!self) return;	if (self->output_id == TAS_OUTPUT_HEADPHONES) {		tas3001c_fast_load(self, 1);		for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) {			for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) {				tas3001c_write_biquad(self, i, j, &tas3001c_eq_unity);			}		}		tas3001c_fast_load(self, 0);		(void)tas3001c_sync_register(self,TAS3001C_REG_BASS);		(void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);		(void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);		(void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);		(void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);		return;	}	for (i=0; tas3001c_eq_prefs[i]; i++) {		struct tas_eq_pref_t *eq = tas3001c_eq_prefs[i];		if (eq->device_id == self->device_id &&		    (eq->output_id == 0 || eq->output_id == self->output_id) &&		    (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) {			tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce);			tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads);			break;		}	}}static voidtas3001c_device_change_handler(void *self){	if (self)		tas3001c_update_device_parameters(self);}static struct work_struct device_change;static inttas3001c_output_device_change(	struct tas3001c_data_t *self,				int device_id,				int output_id,				int speaker_id){	self->device_id=device_id;	self->output_id=output_id;	self->speaker_id=speaker_id;	schedule_work(&device_change);	return 0;}static inttas3001c_device_ioctl(	struct tas3001c_data_t *self,			u_int cmd,			u_long arg){	uint __user *argp = (void __user *)arg;	switch (cmd) {	case TAS_READ_EQ:	case TAS_WRITE_EQ:		return tas3001c_eq_rw(self, cmd, arg);	case TAS_READ_EQ_LIST:	case TAS_WRITE_EQ_LIST:		return tas3001c_eq_list_rw(self, cmd, arg);	case TAS_READ_EQ_FILTER_COUNT:		put_user(TAS3001C_BIQUAD_FILTER_COUNT, argp);		return 0;	case TAS_READ_EQ_CHANNEL_COUNT:		put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, argp);		return 0;	case TAS_READ_DRCE:	case TAS_WRITE_DRCE:		return tas3001c_drce_rw(self, cmd, arg);	case TAS_READ_DRCE_CAPS:		put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, argp);		return 0;	case TAS_READ_DRCE_MIN:	case TAS_READ_DRCE_MAX: {		struct tas_drce_ctrl_t drce_ctrl;		if (copy_from_user(&drce_ctrl, argp,				   sizeof(struct tas_drce_ctrl_t))) {			return -EFAULT;		}		if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) {			if (cmd == TAS_READ_DRCE_MIN) {				drce_ctrl.data.threshold=-36<<8;			} else {				drce_ctrl.data.threshold=-6<<8;			}		}		if (copy_to_user(argp, &drce_ctrl,				 sizeof(struct tas_drce_ctrl_t))) {			return -EFAULT;		}	}	}	return -EINVAL;}static inttas3001c_init_mixer(struct tas3001c_data_t *self){	unsigned char mcr = (1<<6)+(2<<4)+(2<<2);	/* Make sure something answers on the i2c bus */	if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr,	    WRITE_NORMAL|FORCE_WRITE) < 0)		return -1;	tas3001c_fast_load(self, 1);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5);	(void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5);	(void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6);	tas3001c_fast_load(self, 0);	tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT);	tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT);	tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);	tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT);	tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT);	return 0;}static inttas3001c_uninit_mixer(struct tas3001c_data_t *self){	tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0);	tas3001c_set_mixer_level(self, SOUND_MIXER_PCM,    0);	tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);	tas3001c_set_mixer_level(self, SOUND_MIXER_BASS,   0);	tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0);	return 0;}static inttas3001c_init(struct i2c_client *client){	struct tas3001c_data_t *self;	size_t sz = sizeof(*self) + (TAS3001C_REG_MAX*sizeof(tas_shadow_t));	int i, j;	self = kmalloc(sz, GFP_KERNEL);	if (!self)		return -ENOMEM;	memset(self, 0, sz);	self->super.client = client;	self->super.shadow = (tas_shadow_t *)(self+1);	self->output_id = TAS_OUTPUT_HEADPHONES;	dev_set_drvdata(&client->dev, self);	for (i = 0; i < TAS3001C_BIQUAD_CHANNEL_COUNT; i++)		for (j = 0; j < TAS3001C_BIQUAD_FILTER_COUNT; j++)			tas3001c_write_biquad_shadow(self, i, j,				&tas3001c_eq_unity);	INIT_WORK(&device_change, tas3001c_device_change_handler, self);	return 0;}static voidtas3001c_uninit(struct tas3001c_data_t *self){	tas3001c_uninit_mixer(self);	kfree(self);}struct tas_driver_hooks_t tas3001c_hooks = {	.init			= (tas_hook_init_t)tas3001c_init,	.post_init		= (tas_hook_post_init_t)tas3001c_init_mixer,	.uninit			= (tas_hook_uninit_t)tas3001c_uninit,	.get_mixer_level	= (tas_hook_get_mixer_level_t)tas3001c_get_mixer_level,	.set_mixer_level	= (tas_hook_set_mixer_level_t)tas3001c_set_mixer_level,	.enter_sleep		= (tas_hook_enter_sleep_t)tas3001c_enter_sleep,	.leave_sleep		= (tas_hook_leave_sleep_t)tas3001c_leave_sleep,	.supported_mixers	= (tas_hook_supported_mixers_t)tas3001c_supported_mixers,	.mixer_is_stereo	= (tas_hook_mixer_is_stereo_t)tas3001c_mixer_is_stereo,	.stereo_mixers		= (tas_hook_stereo_mixers_t)tas3001c_stereo_mixers,	.output_device_change	= (tas_hook_output_device_change_t)tas3001c_output_device_change,	.device_ioctl		= (tas_hook_device_ioctl_t)tas3001c_device_ioctl};

⌨️ 快捷键说明

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