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

📄 ucb1x00-audio.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
字号:
/* *  linux/drivers/misc/ucb1x00-audio.c * *  Copyright (C) 2001 Russell King, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/list.h>#include <asm/dma.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include "ucb1x00.h"#include "../drivers/sound/sa1100-audio.h"#define MAGIC	0x41544154struct ucb1x00_audio {	struct file_operations	fops;	struct file_operations	mops;	struct ucb1x00		*ucb;	audio_stream_t		output_stream;	audio_stream_t		input_stream;	audio_state_t		state;	unsigned int		rate;	int			dev_id;	int			mix_id;	unsigned int		daa_oh_bit;	unsigned int		telecom;	unsigned int		magic;	unsigned int		ctrl_a;	unsigned int		ctrl_b;	/* mixer info */	unsigned int		mod_cnt;	unsigned short		output_level;	unsigned short		input_level;};#define REC_MASK	(SOUND_MASK_VOLUME | SOUND_MASK_MIC)#define DEV_MASK	REC_MASKstatic intucb1x00_mixer_ioctl(struct inode *ino, struct file *filp, uint cmd, ulong arg){	struct ucb1x00_audio *ucba;	unsigned int val, gain;	int ret = 0;	ucba = list_entry(filp->f_op, struct ucb1x00_audio, mops);	if (_IOC_TYPE(cmd) != 'M')		return -EINVAL;	if (cmd == SOUND_MIXER_INFO) {		struct mixer_info mi;		strncpy(mi.id, "UCB1x00", sizeof(mi.id));		strncpy(mi.name, "Philips UCB1x00", sizeof(mi.name));		mi.modify_counter = ucba->mod_cnt;		return copy_to_user(arg, &mi, sizeof(mi)) ? -EFAULT : 0;	}	if (_IOC_DIR(cmd) == _IOC_WRITE) {		unsigned int left, right;		ret = get_user(val, (unsigned int *)arg);		if (ret)			goto out;		left  = val & 255;		right = val >> 8;		if (left > 100)			left = 100;		if (right > 100)			right = 100;		gain = (left + right) / 2;		ret = -EINVAL;		if (!ucba->telecom) {			switch(_IOC_NR(cmd)) {			case SOUND_MIXER_VOLUME:				ucba->output_level = gain | gain << 8;				ucba->mod_cnt++;				ucba->ctrl_b = (ucba->ctrl_b & 0xff00) |					       ((gain * 31) / 100);				ucb1x00_reg_write(ucba->ucb, UCB_AC_B,						  ucba->ctrl_b);				ret = 0;				break;			case SOUND_MIXER_MIC:				ucba->input_level = gain | gain << 8;				ucba->mod_cnt++;				ucba->ctrl_a = (ucba->ctrl_a & 0x7f) |					       ((gain * 31) / 100);				ucb1x00_reg_write(ucba->ucb, UCB_AC_A,						  ucba->ctrl_a);				ret = 0;				break;			}		}	}	if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {		switch (_IOC_NR(cmd)) {		case SOUND_MIXER_VOLUME:			val = ucba->output_level;			break;		case SOUND_MIXER_MIC:			val = ucba->input_level;			break;		case SOUND_MIXER_RECSRC:		case SOUND_MIXER_RECMASK:			val = ucba->telecom ? 0 : REC_MASK;			break;		case SOUND_MIXER_DEVMASK:			val = ucba->telecom ? 0 : DEV_MASK;			break;		case SOUND_MIXER_CAPS:		case SOUND_MIXER_STEREODEVS:			val = 0;			break;		default:			val = 0;			ret = -EINVAL;			break;		}		if (ret == 0)			ret = put_user(val, (int *)arg);	} out:	return ret;}static int ucb1x00_audio_setrate(struct ucb1x00_audio *ucba, int rate){	unsigned int div_rate = ucb1x00_clkrate(ucba->ucb) / 32;	unsigned int div;	div = (div_rate + (rate / 2)) / rate;	if (div < 6)		div = 6;	if (div > 127)		div = 127;	ucba->ctrl_a = (ucba->ctrl_a & ~0x7f) | div;	if (ucba->telecom) {		ucb1x00_reg_write(ucba->ucb, UCB_TC_B, 0);		ucb1x00_set_telecom_divisor(ucba->ucb, div * 32);		ucb1x00_reg_write(ucba->ucb, UCB_TC_A, ucba->ctrl_a);		ucb1x00_reg_write(ucba->ucb, UCB_TC_B, ucba->ctrl_b);	} else {		ucb1x00_reg_write(ucba->ucb, UCB_AC_B, 0);		ucb1x00_set_audio_divisor(ucba->ucb, div * 32);		ucb1x00_reg_write(ucba->ucb, UCB_AC_A, ucba->ctrl_a);		ucb1x00_reg_write(ucba->ucb, UCB_AC_B, ucba->ctrl_b);	}	ucba->rate = div_rate / div;	return ucba->rate;}static int ucb1x00_audio_getrate(struct ucb1x00_audio *ucba){	return ucba->rate;}static void ucb1x00_audio_startup(void *data){	struct ucb1x00_audio *ucba = data;	ucb1x00_enable(ucba->ucb);	ucb1x00_audio_setrate(ucba, ucba->rate);	ucb1x00_reg_write(ucba->ucb, UCB_MODE, UCB_MODE_DYN_VFLAG_ENA);	/*	 * Take off-hook	 */	if (ucba->daa_oh_bit)		ucb1x00_io_write(ucba->ucb, 0, ucba->daa_oh_bit);}static void ucb1x00_audio_shutdown(void *data){	struct ucb1x00_audio *ucba = data;	/*	 * Place on-hook	 */	if (ucba->daa_oh_bit)		ucb1x00_io_write(ucba->ucb, ucba->daa_oh_bit, 0);	ucb1x00_reg_write(ucba->ucb, ucba->telecom ? UCB_TC_B : UCB_AC_B, 0);	ucb1x00_disable(ucba->ucb);}static intucb1x00_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){	struct ucb1x00_audio *ucba;	int val, ret = 0;	ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);	/*	 * Make sure we have our magic number	 */	if (ucba->magic != MAGIC)		return -ENODEV;	switch (cmd) {	case SNDCTL_DSP_STEREO:		ret = get_user(val, (int *)arg);		if (ret)			return ret;		if (val != 0)			return -EINVAL;		val = 0;		break;	case SNDCTL_DSP_CHANNELS:	case SOUND_PCM_READ_CHANNELS:		val = 1;		break;	case SNDCTL_DSP_SPEED:		ret = get_user(val, (int *)arg);		if (ret)			return ret;		val = ucb1x00_audio_setrate(ucba, val);		break;	case SOUND_PCM_READ_RATE:		val = ucb1x00_audio_getrate(ucba);		break;	case SNDCTL_DSP_SETFMT:	case SNDCTL_DSP_GETFMTS:		val = AFMT_S16_LE;		break;	default:		return ucb1x00_mixer_ioctl(inode, file, cmd, arg);	}	return put_user(val, (int *)arg);}static int ucb1x00_audio_open(struct inode *inode, struct file *file){	struct ucb1x00_audio *ucba;	ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);	return sa1100_audio_attach(inode, file, &ucba->state);}static struct ucb1x00_audio *ucb1x00_audio_alloc(struct ucb1x00 *ucb){	struct ucb1x00_audio *ucba;	ucba = kmalloc(sizeof(*ucba), GFP_KERNEL);	if (ucba) {		memset(ucba, 0, sizeof(*ucba));		ucba->magic = MAGIC;		ucba->ucb = ucb;		ucba->fops.owner = THIS_MODULE;		ucba->fops.open  = ucb1x00_audio_open;		ucba->mops.owner = THIS_MODULE;		ucba->mops.ioctl = ucb1x00_mixer_ioctl;		ucba->state.output_stream = &ucba->output_stream;		ucba->state.input_stream = &ucba->input_stream;		ucba->state.data = ucba;		ucba->state.hw_init = ucb1x00_audio_startup;		ucba->state.hw_shutdown = ucb1x00_audio_shutdown;		ucba->state.client_ioctl = ucb1x00_audio_ioctl;		init_MUTEX(&ucba->state.sem);		ucba->rate = 8000;	}	return ucba;}static struct ucb1x00_audio *audio, *telecom;static int __init ucb1x00_audio_init(void){	struct ucb1x00 *ucb = ucb1x00_get();	struct ucb1x00_audio *a;	if (!ucb)		return -ENODEV;	a = ucb1x00_audio_alloc(ucb);	if (a) {		a->state.input_dma  = ucb->mcp->dma_audio_rd;		a->state.input_id   = "UCB1x00 audio in";		a->state.output_dma = ucb->mcp->dma_audio_wr;		a->state.output_id  = "UCB1x00 audio out";		a->dev_id = register_sound_dsp(&a->fops, -1);		a->mix_id = register_sound_mixer(&a->mops, -1);		a->ctrl_a = 0;		a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA;		audio = a;	}	a = ucb1x00_audio_alloc(ucb);	if (a) {#if 0		a->daa_oh_bit = UCB_IO_8;		ucb1x00_enable(ucb);		ucb1x00_io_write(ucb, a->daa_oh_bit, 0);		ucb1x00_io_set_dir(ucb, UCB_IO_7 | UCB_IO_6, a->daa_oh_bit);		ucb1x00_disable(ucb);#endif		a->telecom = 1;		a->state.input_dma  = ucb->mcp->dma_telco_rd;		a->state.input_id   = "UCB1x00 telco in";		a->state.output_dma = ucb->mcp->dma_telco_wr;		a->state.output_id  = "UCB1x00 telco out";		a->dev_id = register_sound_dsp(&a->fops, -1);		a->mix_id = register_sound_mixer(&a->mops, -1);		a->ctrl_a = 0;		a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA;		telecom = a;	}	return 0;}static void __exit ucb1x00_audio_exit(void){	unregister_sound_dsp(telecom->dev_id);	unregister_sound_dsp(audio->dev_id);}module_init(ucb1x00_audio_init);module_exit(ucb1x00_audio_exit);MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");MODULE_DESCRIPTION("UCB1x00 telecom/audio driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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