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

📄 aci.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
 * following nice properties: * * - SCALE(xmax,ymax,xmax) = ymax * - SCALE(xmax,ymax,0) = 0 * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) * * In addition, the rounding error is minimal and nicely distributed. * The proofs are left as an exercise to the reader. */#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))static int getvolume(caddr_t arg,		     unsigned char left_index, unsigned char right_index){	int vol;	unsigned char buf;	/* left channel */	if (aci_indexed_cmd(0xf0, left_index, &buf))		return -EIO;	vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);		/* right channel */	if (aci_indexed_cmd(0xf0, right_index, &buf))		return -EIO;	vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;	return (*(int *) arg = vol);}static int setvolume(caddr_t arg, 		     unsigned char left_index, unsigned char right_index){	int vol, ret;	/* left channel */	vol = *(int *)arg & 0xff;	if (vol > 100)		vol = 100;	vol = SCALE(100, 0x20, vol);	if (aci_write_cmd(left_index, 0x20 - vol))		return -EIO;	ret = SCALE(0x20, 100, vol);	/* right channel */	vol = (*(int *)arg >> 8) & 0xff;	if (vol > 100)		vol = 100;	vol = SCALE(100, 0x20, vol);	if (aci_write_cmd(right_index, 0x20 - vol))		return -EIO;	ret |= SCALE(0x20, 100, vol) << 8; 	return (*(int *) arg = ret);}static intaci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg){	int status, vol;	unsigned char buf;	/* handle solo mode control */	if (cmd == SOUND_MIXER_PRIVATE1) {		if (*(int *) arg >= 0) {			aci_solo = !!*(int *) arg;			if (aci_write_cmd(0xd2, aci_solo))				return -EIO;		} else if (aci_version >= 0xb0) {			if ((status = read_general_status()) < 0)				return -EIO;			return (*(int *) arg = (status & 0x20) == 0);		}				return (*(int *) arg = aci_solo);	}		if (((cmd >> 8) & 0xff) == 'M') {		if (cmd & SIOC_IN)			/* read and write */			switch (cmd & 0xff) {				case SOUND_MIXER_VOLUME:					return setvolume(arg, 0x01, 0x00);				case SOUND_MIXER_CD:					return setvolume(arg, 0x3c, 0x34);				case SOUND_MIXER_MIC:					return setvolume(arg, 0x38, 0x30);				case SOUND_MIXER_LINE:					return setvolume(arg, 0x39, 0x31);				case SOUND_MIXER_SYNTH:					return setvolume(arg, 0x3b, 0x33);				case SOUND_MIXER_PCM:					return setvolume(arg, 0x3a, 0x32);				case SOUND_MIXER_LINE1:  /* AUX1 */					return setvolume(arg, 0x3d, 0x35);				case SOUND_MIXER_LINE2:  /* AUX2 */					return setvolume(arg, 0x3e, 0x36);				case SOUND_MIXER_IGAIN:  /* MIC pre-amp */					vol = *(int *) arg & 0xff;					if (vol > 100)						vol = 100;					vol = SCALE(100, 3, vol);					if (aci_write_cmd(0x03, vol))						return -EIO;					vol = SCALE(3, 100, vol);					return (*(int *) arg = vol | (vol << 8));				case SOUND_MIXER_RECSRC:					return (*(int *) arg = 0);					break;				default:					return -EINVAL;			}		else			/* only read */			switch (cmd & 0xff) {				case SOUND_MIXER_DEVMASK:					return (*(int *) arg =				 SOUND_MASK_VOLUME | SOUND_MASK_CD    |				 SOUND_MASK_MIC    | SOUND_MASK_LINE  |				 SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |#if 0				 SOUND_MASK_IGAIN  |#endif				 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);				 	break;				case SOUND_MIXER_STEREODEVS:					return (*(int *) arg =				 SOUND_MASK_VOLUME | SOUND_MASK_CD   |				 SOUND_MASK_MIC    | SOUND_MASK_LINE |				 SOUND_MASK_SYNTH  | SOUND_MASK_PCM  |				 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);				 	break;				case SOUND_MIXER_RECMASK:					return (*(int *) arg = 0);					break;				case SOUND_MIXER_RECSRC:					return (*(int *) arg = 0);					break;				case SOUND_MIXER_CAPS:					return (*(int *) arg = 0);					break;				case SOUND_MIXER_VOLUME:					return getvolume(arg, 0x04, 0x03);				case SOUND_MIXER_CD:					return getvolume(arg, 0x0a, 0x09);				case SOUND_MIXER_MIC:					return getvolume(arg, 0x06, 0x05);				case SOUND_MIXER_LINE:					return getvolume(arg, 0x08, 0x07);				case SOUND_MIXER_SYNTH:					return getvolume(arg, 0x0c, 0x0b);				case SOUND_MIXER_PCM:					return getvolume(arg, 0x0e, 0x0d);				case SOUND_MIXER_LINE1:  /* AUX1 */					return getvolume(arg, 0x11, 0x10);				case SOUND_MIXER_LINE2:  /* AUX2 */					return getvolume(arg, 0x13, 0x12);				case SOUND_MIXER_IGAIN:  /* MIC pre-amp */					if (aci_indexed_cmd(0xf0, 0x21, &buf))						return -EIO;					vol = SCALE(3, 100, buf <= 3 ? buf : 3);					vol |= vol << 8;					return (*(int *) arg = vol);				default:					return -EINVAL;			}	}		return -EINVAL;}static struct mixer_operations aci_mixer_operations ={	owner:	THIS_MODULE,	id:	"ACI",	name:	"ACI mixer",	ioctl:	aci_mixer_ioctl};static unsigned charmad_read (int port){	outb (0xE3, 0xf8f); /* Write MAD16 password */	return inb (port);  /* Read from port */}/* * Check, whether there actually is any ACI port operational and if * one was found, then initialize the ACI interface, reserve the I/O * addresses and attach the new mixer to the relevant VoxWare data * structures. * * Returns:  1   ACI mixer detected *           0   nothing there * * There is also an internal mixer in the codec (CS4231A or AD1845), * that deserves no purpose in an ACI based system which uses an * external ACI controlled stereo mixer. Make sure that this codec * mixer has the AUX1 input selected as the recording source, that the * input gain is set near maximum and that the other channels going * from the inputs to the codec output are muted. */static int __init attach_aci(void){	char *boardname = "unknown";	int volume;#define MC4_PORT	0xf90	aci_port =		(mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;	if (check_region(aci_port, 3)) {#ifdef DEBUG		printk("ACI: I/O area 0x%03x-0x%03x already used.\n",			aci_port, aci_port+2);#endif		return 0;	}		if (aci_read_cmd(0xf2, 2, aci_idcode)) {#ifdef DEBUG		printk("ACI: Failed to read idcode.\n");#endif		return 0;	}		if (aci_read_cmd(0xf1, 1, &aci_version)) {#ifdef DEBUG		printk("ACI: Failed to read version.\n");#endif		return 0;	}	if (aci_idcode[0] == 0x6d) {		/* It looks like a miro sound card. */		switch (aci_idcode[1]) {			case 0x41:				boardname = "PCM1 pro / early PCM12";				break;			case 0x42:				boardname = "PCM12";				break;			case 0x43:				boardname = "PCM20";				break;			default:				boardname = "unknown miro";		}	} else#ifndef DEBUG	return 0;#endif    	printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",		aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);	if (aci_reset) {		/* initialize ACI mixer */		aci_implied_cmd(0xff);		aci_solo = 0;	}	/* attach the mixer */	request_region(aci_port, 3, "sound mixer (ACI)");	if (num_mixers < MAX_MIXER_DEV) {		if (num_mixers > 0 &&		  !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {			/*			 * The previously registered mixer device is the CS4231A which			 * has no function on an ACI card. Make the ACI mixer the first			 * of the two mixer devices.			 */			mixer_devs[num_mixers] = mixer_devs[num_mixers-1];			mixer_devs[num_mixers-1] = &aci_mixer_operations;			/*			 * Initialize the CS4231A mixer with reasonable values. It is			 * unlikely that the user ever will want to change these as all			 * channels can be mixed via ACI.			 */			volume = 0x6464;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);			volume = 0x6464;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_IGAIN,   (caddr_t) &volume);			volume = 0;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);			volume = 0;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);			volume = 0;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume);			volume = 0;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);			volume = 0;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);			volume = 0;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume);			volume = SOUND_MASK_LINE1;			mixer_devs[num_mixers]->ioctl(num_mixers,				SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume);			num_mixers++;		} else			mixer_devs[num_mixers++] = &aci_mixer_operations;	}	/* Just do something; otherwise the first write command fails, at	 * least with my PCM20.	 */	aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);		if (aci_reset) {		/* Initialize ACI mixer with reasonable power-up values */		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH,  (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM,    (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE,   (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC,    (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD,     (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1,  (caddr_t) &volume);		volume = 0x3232;		aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2,  (caddr_t) &volume);	}	aci_present = 1;	return 1;}static void __exit unload_aci(void){	if (aci_present)		release_region(aci_port, 3);}module_init(attach_aci);module_exit(unload_aci);

⌨️ 快捷键说明

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