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

📄 ad1848.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * sound/ad1848.c * * The low level driver for the AD1848/CS4248 codec chip which * is used for example in the MS Sound System. * * The CS4231 which is used in the GUS MAX and some other cards is * upwards compatible with AD1848 and this driver is able to drive it. * * CS4231A and AD1845 are upward compatible with CS4231. However * the new features of these chips are different. * * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). * CS4232A is an improved version of CS4232. * * * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * * Thomas Sailer	: ioctl code reworked (vmalloc/vfree removed) *			  general sleep/wakeup clean up. * Alan Cox		: reformatted. Fixed SMP bugs. Moved to kernel alloc/free *		          of irqs. Use dev_id. * Christoph Hellwig	: adapted to module_init/module_exit * Aki Laukkanen	: added power management support * * Status: *		Tested. Believed fully functional. */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include <linux/stddef.h>#include <linux/pm.h>#define DEB(x)#define DEB1(x)#include "sound_config.h"#include "ad1848.h"#include "ad1848_mixer.h"typedef struct{	int             base;	int             irq;	int             dma1, dma2;	int             dual_dma;	/* 1, when two DMA channels allocated */	int 		subtype;	unsigned char   MCE_bit;	unsigned char   saved_regs[32];	int             debug_flag;	int             audio_flags;	int             record_dev, playback_dev;	int             xfer_count;	int             audio_mode;	int             open_mode;	int             intr_active;	char           *chip_name, *name;	int             model;#define MD_1848		1#define MD_4231		2#define MD_4231A	3#define MD_1845		4#define MD_4232		5#define MD_C930		6#define MD_IWAVE	7#define MD_4235         8 /* Crystal Audio CS4235  */#define MD_1845_SSCAPE  9 /* Ensoniq Soundscape PNP*/	/* Mixer parameters */	int             recmask;	int             supported_devices, orig_devices;	int             supported_rec_devices, orig_rec_devices;	int            *levels;	short           mixer_reroute[32];	int             dev_no;	volatile unsigned long timer_ticks;	int             timer_running;	int             irq_ok;	mixer_ents     *mix_devices;	int             mixer_output_port;	/* Power management */	struct		pm_dev *pmdev;} ad1848_info;typedef struct ad1848_port_info{	int             open_mode;	int             speed;	unsigned char   speed_bits;	int             channels;	int             audio_format;	unsigned char   format_bits;}ad1848_port_info;static struct address_info cfg;static int nr_ad1848_devs = 0;int deskpro_xl = 0;int deskpro_m = 0;int soundpro = 0;static volatile signed char irq2dev[17] = {	-1, -1, -1, -1, -1, -1, -1, -1,	-1, -1, -1, -1, -1, -1, -1, -1, -1};#ifndef EXCLUDE_TIMERSstatic int timer_installed = -1;#endifstatic int loaded = 0;static int ad_format_mask[10 /*devc->model */ ] ={	0,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,	/* AD1845 */	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,	AFMT_U8 | AFMT_S16_LE /* CS4235 */,	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW	/* Ensoniq Soundscape*/};static ad1848_info adev_info[MAX_AUDIO_DEV];#define io_Index_Addr(d)	((d)->base)#define io_Indexed_Data(d)	((d)->base+1)#define io_Status(d)		((d)->base+2)#define io_Polled_IO(d)		((d)->base+3)static struct {     unsigned char flags;#define CAP_F_TIMER 0x01     } capabilities [10 /*devc->model */ ] = {     {0}    ,{0}           /* MD_1848  */    ,{CAP_F_TIMER} /* MD_4231  */    ,{CAP_F_TIMER} /* MD_4231A */    ,{CAP_F_TIMER} /* MD_1845  */    ,{CAP_F_TIMER} /* MD_4232  */    ,{0}           /* MD_C930  */    ,{CAP_F_TIMER} /* MD_IWAVE */    ,{0}           /* MD_4235  */    ,{CAP_F_TIMER} /* MD_1845_SSCAPE */};static int      ad1848_open(int dev, int mode);static void     ad1848_close(int dev);static void     ad1848_output_block(int dev, unsigned long buf, int count, int intrflag);static void     ad1848_start_input(int dev, unsigned long buf, int count, int intrflag);static int      ad1848_prepare_for_output(int dev, int bsize, int bcount);static int      ad1848_prepare_for_input(int dev, int bsize, int bcount);static void     ad1848_halt(int dev);static void     ad1848_halt_input(int dev);static void     ad1848_halt_output(int dev);static void     ad1848_trigger(int dev, int bits);static int	ad1848_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);#ifndef EXCLUDE_TIMERSstatic int ad1848_tmr_install(int dev);static void ad1848_tmr_reprogram(int dev);#endifstatic int ad_read(ad1848_info * devc, int reg){	unsigned long flags;	int x;	int timeout = 900000;	while (timeout > 0 && inb(devc->base) == 0x80)	/*Are we initializing */		timeout--;	save_flags(flags);	cli();	outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));	x = inb(io_Indexed_Data(devc));/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */	restore_flags(flags);	return x;}static void ad_write(ad1848_info * devc, int reg, int data){	unsigned long flags;	int timeout = 900000;	while (timeout > 0 && inb(devc->base) == 0x80)	/* Are we initializing */		timeout--;	save_flags(flags);	cli();	outb(((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr(devc));	outb(((unsigned char) (data & 0xff)), io_Indexed_Data(devc));	/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */	restore_flags(flags);}static void wait_for_calibration(ad1848_info * devc){	int timeout = 0;	/*	 * Wait until the auto calibration process has finished.	 *	 * 1)       Wait until the chip becomes ready (reads don't return 0x80).	 * 2)       Wait until the ACI bit of I11 gets on and then off.	 */	timeout = 100000;	while (timeout > 0 && inb(devc->base) == 0x80)		timeout--;	if (inb(devc->base) & 0x80)		printk(KERN_WARNING "ad1848: Auto calibration timed out(1).\n");	timeout = 100;	while (timeout > 0 && !(ad_read(devc, 11) & 0x20))		timeout--;	if (!(ad_read(devc, 11) & 0x20))		return;	timeout = 80000;	while (timeout > 0 && (ad_read(devc, 11) & 0x20))		timeout--;	if (ad_read(devc, 11) & 0x20)		if ( (devc->model != MD_1845) || (devc->model != MD_1845_SSCAPE))			printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n");}static void ad_mute(ad1848_info * devc){	int i;	unsigned char prev;	/*	 * Save old register settings and mute output channels	 */	 	for (i = 6; i < 8; i++)	{		prev = devc->saved_regs[i] = ad_read(devc, i);	}}static void ad_unmute(ad1848_info * devc){}static void ad_enter_MCE(ad1848_info * devc){	unsigned long flags;	int timeout = 1000;	unsigned short prev;	while (timeout > 0 && inb(devc->base) == 0x80)	/*Are we initializing */		timeout--;	save_flags(flags);	cli();	devc->MCE_bit = 0x40;	prev = inb(io_Index_Addr(devc));	if (prev & 0x40)	{		restore_flags(flags);		return;	}	outb((devc->MCE_bit), io_Index_Addr(devc));	restore_flags(flags);}static void ad_leave_MCE(ad1848_info * devc){	unsigned long flags;	unsigned char prev, acal;	int timeout = 1000;	while (timeout > 0 && inb(devc->base) == 0x80)	/*Are we initializing */		timeout--;	save_flags(flags);	cli();	acal = ad_read(devc, 9);	devc->MCE_bit = 0x00;	prev = inb(io_Index_Addr(devc));	outb((0x00), io_Index_Addr(devc));	/* Clear the MCE bit */	if ((prev & 0x40) == 0)	/* Not in MCE mode */	{		restore_flags(flags);		return;	}	outb((0x00), io_Index_Addr(devc));	/* Clear the MCE bit */	if (acal & 0x08)	/* Auto calibration is enabled */		wait_for_calibration(devc);	restore_flags(flags);}static int ad1848_set_recmask(ad1848_info * devc, int mask){	unsigned char   recdev;	int             i, n;	mask &= devc->supported_rec_devices;	/* Rename the mixer bits if necessary */	for (i = 0; i < 32; i++)	{		if (devc->mixer_reroute[i] != i)		{			if (mask & (1 << i))			{				mask &= ~(1 << i);				mask |= (1 << devc->mixer_reroute[i]);			}		}	}		n = 0;	for (i = 0; i < 32; i++)	/* Count selected device bits */		if (mask & (1 << i))			n++;	if (!soundpro) {		if (n == 0)			mask = SOUND_MASK_MIC;		else if (n != 1) {	/* Too many devices selected */			mask &= ~devc->recmask;	/* Filter out active settings */			n = 0;			for (i = 0; i < 32; i++)	/* Count selected device bits */				if (mask & (1 << i))					n++;			if (n != 1)				mask = SOUND_MASK_MIC;		}		switch (mask) {		case SOUND_MASK_MIC:			recdev = 2;			break;		case SOUND_MASK_LINE:		case SOUND_MASK_LINE3:			recdev = 0;			break;		case SOUND_MASK_CD:		case SOUND_MASK_LINE1:			recdev = 1;			break;		case SOUND_MASK_IMIX:			recdev = 3;			break;		default:			mask = SOUND_MASK_MIC;			recdev = 2;		}		recdev <<= 6;		ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev);		ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev);	} else { /* soundpro */		unsigned char val;		int set_rec_bit;		int j;		for (i = 0; i < 32; i++) {	/* For each bit */			if ((devc->supported_rec_devices & (1 << i)) == 0)				continue;	/* Device not supported */			for (j = LEFT_CHN; j <= RIGHT_CHN; j++) {				if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */					continue;				/*				 * This is tricky:				 * set_rec_bit becomes 1 if the corresponding bit in mask is set				 * then it gets flipped if the polarity is inverse				 */				set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol;				val = ad_read(devc, devc->mix_devices[i][j].recreg);				val &= ~(1 << devc->mix_devices[i][j].recpos);				val |= (set_rec_bit << devc->mix_devices[i][j].recpos);				ad_write(devc, devc->mix_devices[i][j].recreg, val);			}		}	}	/* Rename the mixer bits back if necessary */	for (i = 0; i < 32; i++)	{		if (devc->mixer_reroute[i] != i)		{			if (mask & (1 << devc->mixer_reroute[i]))			{				mask &= ~(1 << devc->mixer_reroute[i]);				mask |= (1 << i);			}		}	}	devc->recmask = mask;	return mask;}static void change_bits(ad1848_info * devc, unsigned char *regval,			unsigned char *muteval, int dev, int chn, int newval){	unsigned char mask;	int shift;	int mute;	int mutemask;	int set_mute_bit;	set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol;	if (devc->mix_devices[dev][chn].polarity == 1)	/* Reverse */		newval = 100 - newval;	mask = (1 << devc->mix_devices[dev][chn].nbits) - 1;	shift = devc->mix_devices[dev][chn].bitpos;	if (devc->mix_devices[dev][chn].mutepos == 8)	{			/* if there is no mute bit */		mute = 0;	/* No mute bit; do nothing special */		mutemask = ~0;	/* No mute bit; do nothing special */	}	else	{		mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos);		mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos);	}	newval = (int) ((newval * mask) + 50) / 100;	/* Scale it */	*regval &= ~(mask << shift);			/* Clear bits */	*regval |= (newval & mask) << shift;		/* Set new value */	*muteval &= mutemask;	*muteval |= mute;}static int ad1848_mixer_get(ad1848_info * devc, int dev){	if (!((1 << dev) & devc->supported_devices))		return -EINVAL;	dev = devc->mixer_reroute[dev];	return devc->levels[dev];}static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel){	int regoffs, muteregoffs;	unsigned char val, muteval;	regoffs = devc->mix_devices[dev][channel].regno;	muteregoffs = devc->mix_devices[dev][channel].mutereg;	val = ad_read(devc, regoffs);	if (muteregoffs != regoffs) {		muteval = ad_read(devc, muteregoffs);		change_bits(devc, &val, &muteval, dev, channel, value);	}	else		change_bits(devc, &val, &val, dev, channel, value);	ad_write(devc, regoffs, val);	devc->saved_regs[regoffs] = val;	if (muteregoffs != regoffs) {		ad_write(devc, muteregoffs, muteval);		devc->saved_regs[muteregoffs] = muteval;	}}static int ad1848_mixer_set(ad1848_info * devc, int dev, int value){	int left = value & 0x000000ff;	int right = (value & 0x0000ff00) >> 8;	int retvol;	if (dev > 31)		return -EINVAL;	if (!(devc->supported_devices & (1 << dev)))		return -EINVAL;	dev = devc->mixer_reroute[dev];	if (devc->mix_devices[dev][LEFT_CHN].nbits == 0)		return -EINVAL;	if (left > 100)		left = 100;	if (right > 100)		right = 100;	if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)	/* Mono control */		right = left;	retvol = left | (right << 8);	/* Scale volumes */	left = mix_cvt[left];	right = mix_cvt[right];	devc->levels[dev] = retvol;	/*	 * Set the left channel	 */	ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN);	/*	 * Set the right channel	 */	if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)		goto out;	ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); out:	return retvol;}static void ad1848_mixer_reset(ad1848_info * devc){	int i;	char name[32];

⌨️ 快捷键说明

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