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

📄 ad1816.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* mark device as open */	devc->opened = 1; 	devc->audio_mode = 0;	devc->speed = 8000;	devc->audio_format=AFMT_U8;	devc->channels=1;	ad1816_reset(devc->dev_no); /* halt all pending output */	restore_flags (flags);	return 0;}static void ad1816_close (int dev) /* close device */{	unsigned long flags;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;	save_flags (flags); 	cli ();	/* halt all pending output */	ad1816_reset(devc->dev_no); 		devc->opened = 0;	devc->audio_mode = 0;	devc->speed = 8000;	devc->audio_format=AFMT_U8;	devc->format_bits = 0;	restore_flags (flags);}/* ------------------------------------------------------------------- *//* Audio driver structure */static struct audio_driver ad1816_audio_driver ={	owner:		THIS_MODULE,	open:		ad1816_open,	close:		ad1816_close,	output_block:	ad1816_output_block,	start_input:	ad1816_start_input,	prepare_for_input:	ad1816_prepare_for_input,	prepare_for_output:	ad1816_prepare_for_output,	halt_io:		ad1816_halt,	halt_input:	ad1816_halt_input,	halt_output:	ad1816_halt_output,	trigger:	ad1816_trigger,	set_speed:	ad1816_set_speed,	set_bits:	ad1816_set_bits,	set_channels:	ad1816_set_channels,};/* ------------------------------------------------------------------- *//* Interrupt handler */static void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy){	unsigned char	status;	ad1816_info	*devc;	int		dev;	unsigned long	flags;		if (irq < 0 || irq > 15) {	        printk ("ad1816: Got bogus interrupt %d\n", irq);		return;	}	dev = irq2dev[irq];		if (dev < 0 || dev >= num_audiodevs) {	        printk ("ad1816: IRQ2AD1816-mapping failed for irq %d device %d\n", irq,dev);		return;	        	}	devc = (ad1816_info *) audio_devs[dev]->devc;		save_flags(flags);	cli();	/* read interrupt register */	status = inb (devc->base+1); 	/* Clear all interrupt  */	outb (~status, devc->base+1);		DEBUGNOISE (printk("ad1816: Got interrupt subclass %d\n",status));		devc->irq_ok=1;	if (status == 0)		DEBUGWARN(printk ("ad1816: interrupt: Got interrupt, but no reason?\n"));	if (devc->opened && (devc->audio_mode & PCM_ENABLE_INPUT) && (status&64))		DMAbuf_inputintr (dev);	if (devc->opened && (devc->audio_mode & PCM_ENABLE_OUTPUT) && (status & 128))		DMAbuf_outputintr (dev, 1);	restore_flags(flags);}/* ------------------------------------------------------------------- *//* Mixer stuff */struct mixer_def {	unsigned int regno: 7;	unsigned int polarity:1;	/* 0=normal, 1=reversed */	unsigned int bitpos:4;	unsigned int nbits:4;};static char mix_cvt[101] = {	 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,	43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,	65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,	80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,	91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99,	100};typedef struct mixer_def mixer_ent;/* * Most of the mixer entries work in backwards. Setting the polarity field * makes them to work correctly. * * The channel numbering used by individual soundcards is not fixed. Some * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. * The current version doesn't try to compensate this. */#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r)	\  {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {MIX_ENT(SOUND_MIXER_VOLUME,	14, 1, 8, 5,	14, 1, 0, 5),MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH,	 5, 1, 8, 6,	 5, 1, 0, 6),MIX_ENT(SOUND_MIXER_PCM,	 4, 1, 8, 6,	 4, 1, 0, 6),MIX_ENT(SOUND_MIXER_SPEAKER,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_LINE,	18, 1, 8, 5,	18, 1, 0, 5),MIX_ENT(SOUND_MIXER_MIC,	19, 1, 8, 5,	19, 1, 0, 5),MIX_ENT(SOUND_MIXER_CD,	 	15, 1, 8, 5,	15, 1, 0, 5),MIX_ENT(SOUND_MIXER_IMIX,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV,	20, 0, 8, 4,	20, 0, 0, 4),MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 	17, 1, 8, 5,	17, 1, 0, 5),MIX_ENT(SOUND_MIXER_LINE2,	16, 1, 8, 5,	16, 1, 0, 5),MIX_ENT(SOUND_MIXER_LINE3,      39, 0, 9, 4,    39, 1, 0, 5)};static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] ={	0x4343,		/* Master Volume */	0x3232,		/* Bass */	0x3232,		/* Treble */	0x0000,		/* FM */	0x4343,		/* PCM */	0x0000,		/* PC Speaker */	0x0000,		/* Ext Line */	0x0000,		/* Mic */	0x0000,		/* CD */	0x0000,		/* Recording monitor */	0x0000,		/* SB PCM */	0x0000,		/* Recording level */	0x0000,		/* Input gain */	0x0000,		/* Output gain */	0x0000,		/* Line1 */	0x0000,		/* Line2 */	0x0000		/* Line3 (usually line in)*/};#define LEFT_CHN	0#define RIGHT_CHN	1static intad1816_set_recmask (ad1816_info * devc, int mask){	unsigned char   recdev;	int             i, n;		mask &= devc->supported_rec_devices;		n = 0;	/* Count selected device bits */	for (i = 0; i < 32; i++)		if (mask & (1 << i))			n++;		if (n == 0)		mask = SOUND_MASK_MIC;	else if (n != 1) { /* Too many devices selected */		/* Filter out active settings */		mask &= ~devc->recmask;					n = 0;		/* Count selected device bits */		for (i = 0; i < 32; i++) 			if (mask & (1 << i))				n++;				if (n != 1)			mask = SOUND_MASK_MIC;	}		switch (mask) {	case SOUND_MASK_MIC:		recdev = 5;		break;			case SOUND_MASK_LINE:		recdev = 0;		break;			case SOUND_MASK_CD:		recdev = 2;		break;			case SOUND_MASK_LINE1:		recdev = 4;		break;			case SOUND_MASK_LINE2:		recdev = 3;		break;			case SOUND_MASK_VOLUME:		recdev = 1;		break;			default:		mask = SOUND_MASK_MIC;		recdev = 5;	}		recdev <<= 4;	ad_write (devc, 20, 		  (ad_read (devc, 20) & 0x8f8f) | recdev | (recdev<<8));	devc->recmask = mask;	return mask;}static voidchange_bits (int *regval, int dev, int chn, int newval){	unsigned char   mask;	int             shift;  	/* Reverse polarity*/	if (mix_devices[dev][chn].polarity == 1) 		newval = 100 - newval;	mask = (1 << mix_devices[dev][chn].nbits) - 1;	shift = mix_devices[dev][chn].bitpos;	/* Scale it */	newval = (int) ((newval * mask) + 50) / 100;		/* Clear bits */	*regval &= ~(mask << shift);		/* Set new value */	*regval |= (newval & mask) << shift;	}static intad1816_mixer_get (ad1816_info * devc, int dev){	DEBUGINFO(printk("ad1816: mixer_get called!\n"));		/* range check + supported mixer check */	if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES )	        return (-(EINVAL));	if (!((1 << dev) & devc->supported_devices))		return -(EINVAL);		return devc->levels[dev];}static intad1816_mixer_set (ad1816_info * devc, int dev, int value){	int   left = value & 0x000000ff;	int   right = (value & 0x0000ff00) >> 8;	int   retvol;	int   regoffs;	int   val;	int   valmute;	DEBUGINFO(printk("ad1816: mixer_set called!\n"));		if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES )		return -(EINVAL);	if (left > 100)		left = 100;	if (left < 0)		left = 0;	if (right > 100)		right = 100;	if (right < 0)		right = 0;		/* Mono control */	if (mix_devices[dev][RIGHT_CHN].nbits == 0) 		right = left;	retvol = left | (right << 8);		/* Scale it */		left = mix_cvt[left];	right = mix_cvt[right];	/* reject all mixers that are not supported */	if (!(devc->supported_devices & (1 << dev)))		return -(EINVAL);		/* sanity check */	if (mix_devices[dev][LEFT_CHN].nbits == 0)		return -(EINVAL);	/* keep precise volume internal */	devc->levels[dev] = retvol;	/* Set the left channel */	regoffs = mix_devices[dev][LEFT_CHN].regno;	val = ad_read (devc, regoffs);	change_bits (&val, dev, LEFT_CHN, left);	valmute=val;	/* Mute bit masking on some registers */	if ( regoffs==5 || regoffs==14 || regoffs==15 ||	     regoffs==16 || regoffs==17 || regoffs==18 || 	     regoffs==19 || regoffs==39) {		if (left==0)			valmute |= 0x8000;		else			valmute &= ~0x8000;	}	ad_write (devc, regoffs, valmute); /* mute */	/*	 * Set the right channel	 */ 	/* Was just a mono channel */	if (mix_devices[dev][RIGHT_CHN].nbits == 0)		return retvol;			regoffs = mix_devices[dev][RIGHT_CHN].regno;	val = ad_read (devc, regoffs);	change_bits (&val, dev, RIGHT_CHN, right);	valmute=val;	if ( regoffs==5 || regoffs==14 || regoffs==15 ||	     regoffs==16 || regoffs==17 || regoffs==18 || 	     regoffs==19 || regoffs==39) {		if (right==0)			valmute |= 0x80;		else			valmute &= ~0x80;	}	ad_write (devc, regoffs, valmute); /* mute */	       	return retvol;}#define MIXER_DEVICES ( SOUND_MASK_VOLUME | \			SOUND_MASK_SYNTH | \			SOUND_MASK_PCM | \			SOUND_MASK_LINE | \			SOUND_MASK_LINE1 | \			SOUND_MASK_LINE2 | \			SOUND_MASK_LINE3 | \			SOUND_MASK_MIC | \			SOUND_MASK_CD | \			SOUND_MASK_RECLEV  \			)#define REC_DEVICES ( SOUND_MASK_LINE2 |\		      SOUND_MASK_LINE |\		      SOUND_MASK_LINE1 |\		      SOUND_MASK_MIC |\		      SOUND_MASK_CD |\		      SOUND_MASK_VOLUME \		      )     static voidad1816_mixer_reset (ad1816_info * devc){	int  i;	devc->supported_devices = MIXER_DEVICES;		devc->supported_rec_devices = REC_DEVICES;	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)		if (devc->supported_devices & (1 << i))			ad1816_mixer_set (devc, i, default_mixer_levels[i]);	ad1816_set_recmask (devc, SOUND_MASK_MIC);}static intad1816_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg){	ad1816_info    *devc = mixer_devs[dev]->devc;	int val;  	DEBUGINFO(printk("ad1816: mixer_ioctl called!\n"));  	/* Mixer ioctl */	if (((cmd >> 8) & 0xff) == 'M') { 				/* set ioctl */		if (_SIOC_DIR (cmd) & _SIOC_WRITE) { 			switch (cmd & 0xff){			case SOUND_MIXER_RECSRC:								if (get_user(val, (int *)arg))					return -EFAULT;				val=ad1816_set_recmask (devc, val);				return put_user(val, (int *)arg);				break;							default:				if (get_user(val, (int *)arg))					return -EFAULT;				if ((val=ad1816_mixer_set (devc, cmd & 0xff, val))<0)				        return val;				else				        return put_user(val, (int *)arg);			}		} else { 			/* read ioctl */			switch (cmd & 0xff) {							case SOUND_MIXER_RECSRC:				val=devc->recmask;				return put_user(val, (int *)arg);				break;							case SOUND_MIXER_DEVMASK:				val=devc->supported_devices;				return put_user(val, (int *)arg);				break;			case SOUND_MIXER_STEREODEVS:				val=devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);				return put_user(val, (int *)arg);				break;							case SOUND_MIXER_RECMASK:				val=devc->supported_rec_devices;				return put_user(val, (int *)arg);				break;							case SOUND_MIXER_CAPS:				val=SOUND_CAP_EXCL_INPUT;				return put_user(val, (int *)arg);				break;							default:			        if ((val=ad1816_mixer_get (devc, cmd & 0xff))<0)				        return val;				else				        return put_user(val, (int *)arg);			}		}	} else		/* not for mixer */

⌨️ 快捷键说明

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