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

📄 harmony.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
 */static void harmony_mixer_set_gain(void){	harmony_wait_CNTL();	gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);}/*  *  Read gain of selected channel. *  The OSS rate is from 0 (silent) to 100 -> need some conversions * *  The harmony gain are attenuation for output and monitor gain. *                   is amplifaction for input gain */#define to_harmony_level(level,max) ((level)*max/100)#define to_oss_level(level,max) ((level)*100/max)static int harmony_mixer_get_level(int channel){	int left_level;	int right_level;	switch (channel) {		case SOUND_MIXER_VOLUME:			left_level  = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;			right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;			left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);			right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);			return (right_level << 8)+left_level;					case SOUND_MIXER_IGAIN:			left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;			right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;			left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);			right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);			return (right_level << 8)+left_level;					case SOUND_MIXER_MONITOR:			left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;			left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);			return (left_level << 8)+left_level;	}	return -EINVAL;}/* * Some conversions for the same reasons. * We give back the new real value(s) due to * the rescale. */static int harmony_mixer_set_level(int channel, int value){	int left_level;	int right_level;	int new_left_level;	int new_right_level;	right_level = (value & 0x0000ff00) >> 8;	left_level = value & 0x000000ff;	if (right_level > 100) right_level = 100;	if (left_level > 100) left_level = 100;  	switch (channel) {		case SOUND_MIXER_VOLUME:			right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);			left_level  = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);			new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);			new_left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);			harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK)) 					| (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);			harmony_mixer_set_gain();			return (new_right_level << 8) + new_left_level;					case SOUND_MIXER_IGAIN:			right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);			left_level  = to_harmony_level(left_level, MAX_INPUT_LEVEL);			new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);			new_left_level  = to_oss_level(left_level, MAX_INPUT_LEVEL);			harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))					| (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);			harmony_mixer_set_gain();			return (new_right_level << 8) + new_left_level;			case SOUND_MIXER_MONITOR:			left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL);			new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);			harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT);			harmony_mixer_set_gain();			return (new_left_level << 8) + new_left_level;	}	return -EINVAL;}#undef to_harmony_level#undef to_oss_level/*  * Return the selected input device (mic or line) */static int harmony_mixer_get_recmask(void) {	int current_input_line;		current_input_line = (harmony.current_gain & GAIN_IS_MASK) 				    >> GAIN_IS_SHIFT;	if (current_input_line) 		return SOUND_MASK_MIC;	return SOUND_MASK_LINE;}/* * Set the input (only one at time, arbitrary priority to line in) */static int harmony_mixer_set_recmask(int recmask){	int new_input_line;	int new_input_mask;	int current_input_line;		current_input_line = (harmony.current_gain & GAIN_IS_MASK)				    >> GAIN_IS_SHIFT;	if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) ||		(!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) {		new_input_line = 0;		new_input_mask = SOUND_MASK_LINE;	} else {		new_input_line = 1;		new_input_mask = SOUND_MASK_MIC;	}	harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) | 				(new_input_line << GAIN_IS_SHIFT ));	harmony_mixer_set_gain();	return new_input_mask;}/*  * give the active outlines */static int harmony_mixer_get_outmask(void){	int outmask = 0;		if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL;	if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT;	if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES;		return outmask;}static int harmony_mixer_set_outmask(int outmask){	if (outmask & MASK_INTERNAL) 		harmony.current_gain |= GAIN_SE_MASK;	else 		harmony.current_gain &= ~GAIN_SE_MASK;		if (outmask & MASK_LINEOUT) 		harmony.current_gain |= GAIN_LE_MASK;	else 		harmony.current_gain &= ~GAIN_LE_MASK;		if (outmask & MASK_HEADPHONES) 		harmony.current_gain |= GAIN_HE_MASK; 	else 		harmony.current_gain &= ~GAIN_HE_MASK;		harmony_mixer_set_gain();	return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES));}/* * This code is inspired from sb_mixer.c */static int harmony_mixer_ioctl(struct inode * inode, struct file * file,		unsigned int cmd, unsigned long arg){	int val;	int ret;	if (cmd == SOUND_MIXER_INFO) {		mixer_info info;		memset(&info, 0, sizeof(info));                strncpy(info.id, "harmony", sizeof(info.id)-1);                strncpy(info.name, "Harmony audio", sizeof(info.name)-1);                info.modify_counter = 1; /* ? */                if (copy_to_user((void *)arg, &info, sizeof(info)))                        return -EFAULT;		return 0;	}		if (cmd == OSS_GETVERSION)		return put_user(SOUND_VERSION, (int *)arg);	/* read */	val = 0;	if (_SIOC_DIR(cmd) & _SIOC_WRITE)		if (get_user(val, (int *)arg))			return -EFAULT;	switch (cmd) {	case MIXER_READ(SOUND_MIXER_CAPS):		ret = SOUND_CAP_EXCL_INPUT;		break;	case MIXER_READ(SOUND_MIXER_STEREODEVS):		ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;		break;			case MIXER_READ(SOUND_MIXER_RECMASK):		ret = SOUND_MASK_MIC | SOUND_MASK_LINE;		break;	case MIXER_READ(SOUND_MIXER_DEVMASK):		ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN |			SOUND_MASK_MONITOR;		break;	case MIXER_READ(SOUND_MIXER_OUTMASK):		ret = MASK_INTERNAL | MASK_LINEOUT |			MASK_HEADPHONES;		break;			case MIXER_WRITE(SOUND_MIXER_RECSRC):		ret = harmony_mixer_set_recmask(val);		break;	case MIXER_READ(SOUND_MIXER_RECSRC):		ret = harmony_mixer_get_recmask();		break;	      	case MIXER_WRITE(SOUND_MIXER_OUTSRC):		ret = harmony_mixer_set_outmask(val);		break;	case MIXER_READ(SOUND_MIXER_OUTSRC):		ret = harmony_mixer_get_outmask();		break;		case MIXER_WRITE(SOUND_MIXER_VOLUME):	case MIXER_WRITE(SOUND_MIXER_IGAIN):	case MIXER_WRITE(SOUND_MIXER_MONITOR):		ret = harmony_mixer_set_level(cmd & 0xff, val);		break;	case MIXER_READ(SOUND_MIXER_VOLUME):	case MIXER_READ(SOUND_MIXER_IGAIN):	case MIXER_READ(SOUND_MIXER_MONITOR):		ret = harmony_mixer_get_level(cmd & 0xff);		break;	default:		return -EINVAL;	}	if (put_user(ret, (int *)arg))		return -EFAULT;	return 0;}static int harmony_mixer_open(struct inode *inode, struct file *file){	if (harmony.mixer_open) 		return -EBUSY;	harmony.mixer_open = 1;	return 0;}static int harmony_mixer_release(struct inode *inode, struct file *file){	if (!harmony.mixer_open) 		return -EBUSY;	harmony.mixer_open = 0;	return 0;}static struct file_operations harmony_mixer_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.open		= harmony_mixer_open,	.release	= harmony_mixer_release,	.ioctl		= harmony_mixer_ioctl,};/* * Mute all the output and reset Harmony. */static void __init harmony_mixer_reset(void){	harmony.current_gain = GAIN_TOTAL_SILENCE;	harmony_mixer_set_gain();	harmony_wait_CNTL();	gsc_writel(1, &harmony.hpa->reset);	mdelay(50);		/* wait 50 ms */	gsc_writel(0, &harmony.hpa->reset);	harmony.current_gain = GAIN_DEFAULT;	harmony_mixer_set_gain();}static int __init harmony_mixer_init(void){	/* Register the device file operations */	harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);	if (harmony.mixer_unit < 0) {		printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");		return -EFAULT;	}  	harmony_mixer_reset();	harmony.mixer_open = 0;		return 0;}/*  * This is the callback that's called by the inventory hardware code  * if it finds a match to the registered driver.  */static int __devinitharmony_driver_probe(struct parisc_device *dev){	u8	id;	u8	rev;	u32	cntl;	int	ret;	if (harmony.hpa) {		/* We only support one Harmony at this time */		printk(KERN_ERR PFX "driver already registered\n");		return -EBUSY;	}	if (!dev->irq) {		printk(KERN_ERR PFX "no irq found\n");		return -ENODEV;	}	/* Set the HPA of harmony */	harmony.hpa = (struct harmony_hpa *)dev->hpa;	harmony.dev = dev;	/* Grab the ID and revision from the device */	id = gsc_readb(&harmony.hpa->id);	if ((id | 1) != 0x15) {		printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);		return -EBUSY;	}	cntl = gsc_readl(&harmony.hpa->cntl);	rev = (cntl>>20) & 0xff;	printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "			"h/w id %i, rev. %i at 0x%lx, IRQ %i\n",			id, rev, dev->hpa, harmony.dev->irq);		/* Make sure the control bit isn't set, although I don't think it 	   ever is. */	if (cntl & CNTL_C) {		printk(KERN_WARNING PFX "CNTL busy\n");		harmony.hpa = 0;		return -EBUSY;	}	/* Initialize the memory buffers */	if (harmony_alloc_buffer(&played_buf, MAX_BUFS) || 	    harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||	    harmony_alloc_buffer(&graveyard, 1) ||	    harmony_alloc_buffer(&silent, 1)) {		ret = -EBUSY;		goto out_err;	}	/* Initialize /dev/mixer and /dev/audio  */	if ((ret=harmony_mixer_init())) 		goto out_err;	if ((ret=harmony_audio_init())) 		goto out_err;	return 0;out_err:	harmony.hpa = 0;	harmony_free_buffer(&played_buf);	harmony_free_buffer(&recorded_buf);	harmony_free_buffer(&graveyard);	harmony_free_buffer(&silent);	return ret;}static struct parisc_device_id harmony_tbl[] = { /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */ { 0, }};MODULE_DEVICE_TABLE(parisc, harmony_tbl);static struct parisc_driver harmony_driver = {	.name		= "Lasi Harmony",	.id_table	= harmony_tbl,	.probe		= harmony_driver_probe,};static int __init init_harmony(void){	return register_parisc_driver(&harmony_driver);}static void __exit cleanup_harmony(void){	free_irq(harmony.dev->irq, &harmony);	unregister_sound_mixer(harmony.mixer_unit);	unregister_sound_dsp(harmony.dsp_unit);	harmony_free_buffer(&played_buf);	harmony_free_buffer(&recorded_buf);	harmony_free_buffer(&graveyard);	harmony_free_buffer(&silent);	unregister_parisc_driver(&harmony_driver);}MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>");MODULE_DESCRIPTION("Harmony sound driver");MODULE_LICENSE("GPL");module_init(init_harmony);module_exit(cleanup_harmony);

⌨️ 快捷键说明

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