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

📄 dmasound_awacs.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
			awacs_reg[1] |= MASK_LOOPTHRU;		awacs_write(awacs_reg[0] | MASK_ADDR0);		awacs_write(awacs_reg[1] | MASK_ADDR1);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_STEREODEVS:		data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER			| SOUND_MASK_RECLEV;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_CAPS:		return IOCTL_OUT(arg, 0);	case SOUND_MIXER_READ_VOLUME:		data = (awacs_reg[1] & MASK_AMUTE)? 0:			awacs_get_volume(awacs_reg[2], 6);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_VOLUME:		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, PMacSetVolume(data));	case SOUND_MIXER_READ_SPEAKER:		if (awacs_revision == 3		    && sys_ctrler == SYS_CTRLER_CUDA)			data = awacs_spkr_vol;		else			data = (awacs_reg[1] & MASK_CMUTE)? 0:				awacs_get_volume(awacs_reg[4], 6);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_SPEAKER:		IOCTL_IN(arg, data);		if (awacs_revision == 3		    && sys_ctrler == SYS_CTRLER_CUDA)			awacs_enable_amp(data);		else			data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */		IOCTL_IN(arg, data);		beep_volume = data & 0xff;				/* fall through */	case SOUND_MIXER_READ_ALTPCM:		return IOCTL_OUT(arg, beep_volume);	case SOUND_MIXER_WRITE_LINE:		IOCTL_IN(arg, data);		awacs_reg[0] &= ~MASK_MUX_AUDIN;		if ((data & 0xff) >= 50)			awacs_reg[0] |= MASK_MUX_AUDIN;		awacs_write(MASK_ADDR0 | awacs_reg[0]);				/* fall through */	case SOUND_MIXER_READ_LINE:		data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_MIC:		IOCTL_IN(arg, data);		data &= 0xff;		awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);		if (data >= 25) {			awacs_reg[0] |= MASK_MUX_MIC;			if (data >= 75)				awacs_reg[0] |= MASK_GAINLINE;		}		awacs_write(MASK_ADDR0 | awacs_reg[0]);				/* fall through */	case SOUND_MIXER_READ_MIC:		data = (awacs_reg[0] & MASK_MUX_MIC)?			(awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_CD:		IOCTL_IN(arg, data);		awacs_reg[0] &= ~MASK_MUX_CD;		if ((data & 0xff) >= 50)			awacs_reg[0] |= MASK_MUX_CD;		awacs_write(MASK_ADDR0 | awacs_reg[0]);				/* fall through */	case SOUND_MIXER_READ_CD:		data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_RECLEV:		IOCTL_IN(arg, data);		data = awacs_volume_setter(data, 0, 0, 4);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_RECLEV:		data = awacs_get_volume(awacs_reg[0], 4);		return IOCTL_OUT(arg, data);	case MIXER_WRITE(SOUND_MIXER_MONITOR):		IOCTL_IN(arg, data);		awacs_reg[1] &= ~MASK_LOOPTHRU;		if ((data & 0xff) >= 50)			awacs_reg[1] |= MASK_LOOPTHRU;		awacs_write(MASK_ADDR1 | awacs_reg[1]);		/* fall through */	case MIXER_READ(SOUND_MIXER_MONITOR):		data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0;		return IOCTL_OUT(arg, data);	}	return -EINVAL;}static int burgundy_mixer_ioctl(u_int cmd, u_long arg){	int data;	/* We are, we are, we are... Burgundy or better */	switch(cmd) {	case SOUND_MIXER_READ_DEVMASK:		data = SOUND_MASK_VOLUME | SOUND_MASK_CD |			SOUND_MASK_LINE | SOUND_MASK_MIC |			SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_RECMASK:		data = SOUND_MASK_LINE | SOUND_MASK_MIC			| SOUND_MASK_CD;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_RECSRC:		data = 0;		if (awacs_reg[0] & MASK_MUX_AUDIN)			data |= SOUND_MASK_LINE;		if (awacs_reg[0] & MASK_MUX_MIC)			data |= SOUND_MASK_MIC;		if (awacs_reg[0] & MASK_MUX_CD)			data |= SOUND_MASK_CD;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_RECSRC:		IOCTL_IN(arg, data);		data &= (SOUND_MASK_LINE			 | SOUND_MASK_MIC | SOUND_MASK_CD);		awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC				  | MASK_MUX_AUDIN);		if (data & SOUND_MASK_LINE)			awacs_reg[0] |= MASK_MUX_AUDIN;		if (data & SOUND_MASK_MIC)			awacs_reg[0] |= MASK_MUX_MIC;		if (data & SOUND_MASK_CD)			awacs_reg[0] |= MASK_MUX_CD;		awacs_write(awacs_reg[0] | MASK_ADDR0);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_STEREODEVS:		data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER			| SOUND_MASK_RECLEV | SOUND_MASK_CD			| SOUND_MASK_LINE;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_CAPS:		return IOCTL_OUT(arg, 0);	case SOUND_MIXER_WRITE_VOLUME:		IOCTL_IN(arg, data);		awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);				/* Fall through */	case SOUND_MIXER_READ_VOLUME:		return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));	case SOUND_MIXER_WRITE_SPEAKER:		IOCTL_IN(arg, data);		if (!(data & 0xff)) {			/* Mute the left speaker */			awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,					   awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);		} else {			/* Unmute the left speaker */			awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,					   awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);		}		if (!(data & 0xff00)) {			/* Mute the right speaker */			awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,					   awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);		} else {			/* Unmute the right speaker */			awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,					   awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);		}		data = (((data&0xff)*16)/100 > 0xf ? 0xf :			(((data&0xff)*16)/100)) + 			((((data>>8)*16)/100 > 0xf ? 0xf :			  ((((data>>8)*16)/100)))<<4);		awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);				/* Fall through */	case SOUND_MIXER_READ_SPEAKER:		data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);		data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);		return IOCTL_OUT(arg, ~data);	case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */		IOCTL_IN(arg, data);		beep_volume = data & 0xff;				/* fall through */	case SOUND_MIXER_READ_ALTPCM:		return IOCTL_OUT(arg, beep_volume);	case SOUND_MIXER_WRITE_LINE:		IOCTL_IN(arg, data);		awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);				/* fall through */	case SOUND_MIXER_READ_LINE:		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);						return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_MIC:		IOCTL_IN(arg, data);				/* Mic is mono device */		data = (data << 8) + (data << 24);		awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);				/* fall through */	case SOUND_MIXER_READ_MIC:		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);						data <<= 24;		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_CD:		IOCTL_IN(arg, data);		awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);				/* fall through */	case SOUND_MIXER_READ_CD:		data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_WRITE_RECLEV:		IOCTL_IN(arg, data);		data = awacs_volume_setter(data, 0, 0, 4);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_READ_RECLEV:		data = awacs_get_volume(awacs_reg[0], 4);		return IOCTL_OUT(arg, data);	case SOUND_MIXER_OUTMASK:		break;	case SOUND_MIXER_OUTSRC:		break;	}	return -EINVAL;}static int PMacMixerIoctl(u_int cmd, u_long arg){	/* Different IOCTLS for burgundy*/	if (awacs_revision >= AWACS_BURGUNDY)		return burgundy_mixer_ioctl(cmd, arg);	return awacs_mixer_ioctl(cmd, arg);}static void PMacWriteSqSetup(void){	int i;	volatile struct dbdma_cmd *cp;	cp = awacs_tx_cmds;	memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd));	for (i = 0; i < write_sq.numBufs; ++i, ++cp) {		st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i]));	}	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));	out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));}static void PMacReadSqSetup(void){	int i;	volatile struct dbdma_cmd *cp;	cp = awacs_rx_cmds;	memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd));	/* Set dma buffers up in a loop */	for (i = 0; i < read_sq.numBufs; i++,cp++) {		st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i]));		st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);		st_le16(&cp->req_count, read_sq.block_size);		st_le16(&cp->xfer_status, 0);	}	/* The next two lines make the thing loop around.	*/	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);	st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));	/* Don't start until the first read is done.	 * This will also abort any operations in progress if the DMA	 * happens to be running (and it shouldn't).	 */	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));}static void PMacAbortRead(void){	int i;	volatile struct dbdma_cmd *cp;	cp = awacs_rx_cmds;	for (i = 0; i < read_sq.numBufs; i++,cp++)		st_le16(&cp->command, DBDMA_STOP);	/*	 * We should probably wait for the thing to stop before we	 * release the memory	 */}/*** Machine definitions *****************************************************/static MACHINE machPMac = {	name:		awacs_name,	name2:		"AWACS",	open:		PMacOpen,	release:	PMacRelease,	dma_alloc:	PMacAlloc,	dma_free:	PMacFree,	irqinit:	PMacIrqInit,#ifdef MODULE	irqcleanup:	PMacIrqCleanup,#endif /* MODULE */	init:		PMacInit,	silence:	PMacSilence,	setFormat:	PMacSetFormat,	setVolume:	PMacSetVolume,	play:		PMacPlay,	record:		PMacRecord,	mixer_ioctl:	PMacMixerIoctl,	write_sq_setup:	PMacWriteSqSetup,	read_sq_setup:	PMacReadSqSetup,	abort_read:	PMacAbortRead,	min_dsp_speed:	8000};/*** Config & Setup **********************************************************/int __init dmasound_awacs_init(void){	struct device_node *np;	if (_machine != _MACH_Pmac)		return -ENODEV;	awacs_subframe = 0;	awacs_revision = 0;	np = find_devices("awacs");	if (np == 0) {		/*		 * powermac G3 models have a node called "davbus"		 * with a child called "sound".		 */		struct device_node *sound;		np = find_devices("davbus");		sound = find_devices("sound");		if (sound != 0 && sound->parent == np) {			unsigned int *prop, l, i;			prop = (unsigned int *)				get_property(sound, "sub-frame", 0);			if (prop != 0 && *prop >= 0 && *prop < 16)				awacs_subframe = *prop;			if (device_is_compatible(sound, "burgundy"))				awacs_revision = AWACS_BURGUNDY;			/* This should be verified on older screamers */			if (device_is_compatible(sound, "screamer"))				awacs_is_screamer = 1;			prop = (unsigned int *)get_property(sound, "device-id", 0);			if (prop != 0)				awacs_device_id = *prop;			awacs_has_iic = (find_devices("perch") != NULL);			/* look for a property saying what sample rates			   are available */			for (i = 0; i < 8; ++i)				awacs_freqs_ok[i] = 0;			prop = (unsigned int *) get_property				(sound, "sample-rates", &l);			if (prop == 0)				prop = (unsigned int *) get_property					(sound, "output-frame-rates", &l);			if (prop != 0) {				for (l /= sizeof(int); l > 0; --l) {					/* sometimes the rate is in the					   high-order 16 bits (?) */					unsigned int r = *prop++;					if (r >= 0x10000)						r >>= 16;					for (i = 0; i < 8; ++i) {						if (r == awacs_freqs[i]) {							awacs_freqs_ok[i] = 1;							break;						}					}				}			} else {				/* assume just 44.1k is OK */				awacs_freqs_ok[0] = 1;			}		}	}	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {		int vol;		dmasound.mach = machPMac;		awacs = (volatile struct awacs_regs *)			ioremap(np->addrs[0].address, 0x80);		awacs_txdma = (volatile struct dbdma_regs *)			ioremap(np->addrs[1].address, 0x100);		awacs_rxdma = (volatile struct dbdma_regs *)			ioremap(np->addrs[2].address, 0x100);		awacs_irq = np->intrs[0].line;		awacs_tx_irq = np->intrs[1].line;		awacs_rx_irq = np->intrs[2].line;		awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd),					     GFP_KERNEL);		if (awacs_tx_cmd_space == NULL) {			printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");			return -ENOMEM;		}		awacs_node = np;#ifdef CONFIG_PMAC_PBOOK		if (machine_is_compatible("PowerBook1,1")		    || machine_is_compatible("AAPL,PowerBook1998")) {			pmu_suspend();			feature_set(np, FEATURE_Sound_CLK_enable);			feature_set(np, FEATURE_Sound_power);			/* Shorter delay will not work */			mdelay(1000);			pmu_resume();		}#endif		awacs_tx_cmds = (volatile struct dbdma_cmd *)			DBDMA_ALIGN(awacs_tx_cmd_space);		awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd),					     GFP_KERNEL);		if (awacs_rx_cmd_space == NULL) {		  printk("DMA sound driver: No memory for input");		}		awacs_rx_cmds = (volatile struct dbdma_cmd *)		  DBDMA_ALIGN(awacs_rx_cmd_space);		awacs_reg[0] = MASK_MUX_CD;		/* FIXME: Only machines with external SRS module need MASK_PAROUT */		awacs_reg[1] = MASK_LOOPTHRU;		if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8			|| */awacs_device_id == 0xb)			awacs_reg[1] |= MASK_PAROUT;		/* get default volume from nvram */		vol = (~nvram_read_byte(0x1308) & 7) << 1;		awacs_reg[2] = vol + (vol << 6);		awacs_reg[4] = vol + (vol << 6);		awacs_reg[5] = 0;		awacs_reg[6] = 0;		awacs_reg[7] = 0;		out_le32(&awacs->control, 0x11);		awacs_write(awacs_reg[0] + MASK_ADDR0);		awacs_write(awacs_reg[1] + MASK_ADDR1);		awacs_write(awacs_reg[2] + MASK_ADDR2);		awacs_write(awacs_reg[4] + MASK_ADDR4);		if (awacs_is_screamer) {			awacs_write(awacs_reg[5] + MASK_ADDR5);			awacs_write(awacs_reg[6] + MASK_ADDR6);			awacs_write(awacs_reg[7] + MASK_ADDR7);		}		/* Initialize recent versions of the awacs */		if (awacs_revision == 0) {			awacs_revision =				(in_le32(&awacs->codec_stat) >> 12) & 0xf;			if (awacs_revision == 3) {				mdelay(100);				awacs_write(0x6000);				mdelay(2);				awacs_write(awacs_reg[1] + MASK_ADDR1);				awacs_enable_amp(100 * 0x101);			}		}		if (awacs_revision >= AWACS_BURGUNDY)			awacs_burgundy_init();		/* Initialize beep stuff */		beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1);		orig_mksound = kd_mksound;		kd_mksound = awacs_mksound;		beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);		if (beep_buf == NULL)			printk(KERN_WARNING "dmasound: no memory for "			       "beep buffer\n");#ifdef CONFIG_PMAC_PBOOK		pmu_register_sleep_notifier(&awacs_sleep_notifier);#endif /* CONFIG_PMAC_PBOOK */		/* Powerbooks have odd ways of enabling inputs such as		   an expansion-bay CD or sound from an internal modem		   or a PC-card modem. */		if (machine_is_compatible("AAPL,3400/2400")			|| machine_is_compatible("AAPL,3500")) {			is_pbook_3400 = 1;			/*			 * Enable CD and PC-card sound inputs.			 * This is done by reading from address			 * f301a000, + 0x10 to enable the expansion-bay			 * CD sound input, + 0x80 to enable the PC-card			 * sound input.  The 0x100 enables the SCSI bus			 * terminator power.			 */			latch_base = (unsigned char *) ioremap				(0xf301a000, 0x1000);			in_8(latch_base + 0x190);		} else if (machine_is_compatible("PowerBook1,1")			   || machine_is_compatible("AAPL,PowerBook1998")) {			struct device_node* mio;			macio_base = 0;			is_pbook_G3 = 1;			for (mio = np->parent; mio; mio = mio->parent) {				if (strcmp(mio->name, "mac-io") == 0				    && mio->n_addrs > 0) {					macio_base = (unsigned char *) ioremap						(mio->addrs[0].address, 0x40);					break;				}			}			/*			 * Enable CD sound input.			 * The relevant bits for writing to this byte are 0x8f.			 * I haven't found out what the 0x80 bit does.			 * For the 0xf bits, writing 3 or 7 enables the CD			 * input, any other value disables it.  Values			 * 1, 3, 5, 7 enable the microphone.  Values 0, 2,			 * 4, 6, 8 - f enable the input from the modem.			 */			if (macio_base)				out_8(macio_base + 0x37, 3);		}		sprintf(awacs_name, "PowerMac (AWACS rev %d) ",			awacs_revision);		return dmasound_init();	}	return -ENODEV;}static void __exit dmasound_awacs_cleanup(void){	dmasound_deinit();}module_init(dmasound_awacs_init);module_exit(dmasound_awacs_cleanup);

⌨️ 快捷键说明

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