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

📄 dmasound_awacs.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft){	unsigned int *p = (unsigned int *) &frame[*frameUsed];	unsigned int data = expand_data;	unsigned short *up = (unsigned short *) userPtr;	int bal = expand_bal;	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;	int stereo = dmasound.soft.stereo;	int utotal, ftotal;	frameLeft >>= 2;	userCount >>= (stereo? 2: 1);	ftotal = frameLeft;	utotal = userCount;	while (frameLeft) {		unsigned short c;		if (bal < 0) {			if (userCount == 0)				break;			if (get_user(data, up++))				return -EFAULT;			if (stereo) {				if (get_user(c, up++))					return -EFAULT;				data = (data << 16) + c;			} else				data = (data << 16) + data;			userCount--;			bal += hSpeed;		}		*p++ = data;		frameLeft--;		bal -= sSpeed;	}	expand_bal = bal;	expand_data = data;	*frameUsed += (ftotal - frameLeft) * 4;	utotal -= userCount;	return stereo? utotal * 4: utotal * 2;}static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft){	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);	unsigned int *p = (unsigned int *) &frame[*frameUsed];	unsigned int data = expand_data;	unsigned short *up = (unsigned short *) userPtr;	int bal = expand_bal;	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;	int stereo = dmasound.soft.stereo;	int utotal, ftotal;	frameLeft >>= 2;	userCount >>= (stereo? 2: 1);	ftotal = frameLeft;	utotal = userCount;	while (frameLeft) {		unsigned short c;		if (bal < 0) {			if (userCount == 0)				break;			if (get_user(data, up++))				return -EFAULT;			data ^= mask;			if (stereo) {				if (get_user(c, up++))					return -EFAULT;				data = (data << 16) + (c ^ mask);			} else				data = (data << 16) + data;			userCount--;			bal += hSpeed;		}		*p++ = data;		frameLeft--;		bal -= sSpeed;	}	expand_bal = bal;	expand_data = data;	*frameUsed += (ftotal - frameLeft) * 4;	utotal -= userCount;	return stereo? utotal * 4: utotal * 2;}static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,			  u_char frame[], ssize_t *frameUsed,			  ssize_t frameLeft){	ssize_t count, used;	short *p = (short *) &frame[*frameUsed];	int val, stereo = dmasound.soft.stereo;	frameLeft >>= 2;	if (stereo)		userCount >>= 1;	used = count = min(userCount, frameLeft);	while (count > 0) {		u_char data;		val = *p++;		data = val >> 8;		if (put_user(data, (u_char *)userPtr++))			return -EFAULT;		if (stereo) {			val = *p;			data = val >> 8;			if (put_user(data, (u_char *)userPtr++))				return -EFAULT;		}		p++;		count--;	}	*frameUsed += used * 4;	return stereo? used * 2: used;}static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,			  u_char frame[], ssize_t *frameUsed,			  ssize_t frameLeft){	ssize_t count, used;	short *p = (short *) &frame[*frameUsed];	int val, stereo = dmasound.soft.stereo;	frameLeft >>= 2;	if (stereo)		userCount >>= 1;	used = count = min(userCount, frameLeft);	while (count > 0) {		u_char data;		val = *p++;		data = (val >> 8) ^ 0x80;		if (put_user(data, (u_char *)userPtr++))			return -EFAULT;		if (stereo) {			val = *p;			data = (val >> 8) ^ 0x80;			if (put_user(data, (u_char *)userPtr++))				return -EFAULT;		}		p++;		count--;	}	*frameUsed += used * 4;	return stereo? used * 2: used;}static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft){	ssize_t count, used;	int stereo = dmasound.soft.stereo;	short *fp = (short *) &frame[*frameUsed];	frameLeft >>= 2;	userCount >>= (stereo? 2: 1);	used = count = min(userCount, frameLeft);	if (!stereo) {		short *up = (short *) userPtr;		while (count > 0) {			short data;			data = *fp;			if (put_user(data, up++))				return -EFAULT;			fp+=2;			count--;		}	} else {		if (copy_to_user((u_char *)userPtr, fp, count * 4))			return -EFAULT;	}	*frameUsed += used * 4;	return stereo? used * 4: used * 2;}static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft){	ssize_t count, used;	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);	int stereo = dmasound.soft.stereo;	short *fp = (short *) &frame[*frameUsed];	short *up = (short *) userPtr;	frameLeft >>= 2;	userCount >>= (stereo? 2: 1);	used = count = min(userCount, frameLeft);	while (count > 0) {		int data;		data = *fp++;		data ^= mask;		if (put_user(data, up++))			return -EFAULT;		if (stereo) {			data = *fp;			data ^= mask;			if (put_user(data, up++))				return -EFAULT;		}		fp++;		count--;	}	*frameUsed += used * 4;	return stereo? used * 4: used * 2;}static TRANS transAwacsNormal = {	ct_ulaw:	pmac_ct_law,	ct_alaw:	pmac_ct_law,	ct_s8:		pmac_ct_s8,	ct_u8:		pmac_ct_u8,	ct_s16be:	pmac_ct_s16,	ct_u16be:	pmac_ct_u16,	ct_s16le:	pmac_ct_s16,	ct_u16le:	pmac_ct_u16,};static TRANS transAwacsExpand = {	ct_ulaw:	pmac_ctx_law,	ct_alaw:	pmac_ctx_law,	ct_s8:		pmac_ctx_s8,	ct_u8:		pmac_ctx_u8,	ct_s16be:	pmac_ctx_s16,	ct_u16be:	pmac_ctx_u16,	ct_s16le:	pmac_ctx_s16,	ct_u16le:	pmac_ctx_u16,};static TRANS transAwacsNormalRead = {	ct_s8:		pmac_ct_s8_read,	ct_u8:		pmac_ct_u8_read,	ct_s16be:	pmac_ct_s16_read,	ct_u16be:	pmac_ct_u16_read,	ct_s16le:	pmac_ct_s16_read,	ct_u16le:	pmac_ct_u16_read,};/*** Low level stuff *********************************************************//* * PCI PowerMac, with AWACS and DBDMA. */static void PMacOpen(void){	MOD_INC_USE_COUNT;}static void PMacRelease(void){	MOD_DEC_USE_COUNT;}static void *PMacAlloc(unsigned int size, int flags){	return kmalloc(size, flags);}static void PMacFree(void *ptr, unsigned int size){	kfree(ptr);}static int __init PMacIrqInit(void){	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))		return 0;	return 1;}#ifdef MODULEstatic void PMacIrqCleanup(void){	/* turn off output dma */	out_le32(&awacs_txdma->control, RUN<<16);	/* disable interrupts from awacs interface */	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);#ifdef CONFIG_PMAC_PBOOK	if (is_pbook_G3) {		feature_clear(awacs_node, FEATURE_Sound_power);		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);	}#endif	free_irq(awacs_irq, 0);	free_irq(awacs_tx_irq, 0);	free_irq(awacs_rx_irq, 0);	kfree(awacs_tx_cmd_space);	if (awacs_rx_cmd_space)		kfree(awacs_rx_cmd_space);	if (beep_buf)		kfree(beep_buf);	kd_mksound = orig_mksound;#ifdef CONFIG_PMAC_PBOOK	pmu_unregister_sleep_notifier(&awacs_sleep_notifier);#endif}#endif /* MODULE */static void PMacSilence(void){	/* turn off output dma */	out_le32(&awacs_txdma->control, RUN<<16);}static int awacs_freqs[8] = {	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350};static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };static void PMacInit(void){	int i, tolerance;	switch (dmasound.soft.format) {	case AFMT_S16_LE:	case AFMT_U16_LE:		dmasound.hard.format = AFMT_S16_LE;		break;	default:		dmasound.hard.format = AFMT_S16_BE;		break;	}	dmasound.hard.stereo = 1;	dmasound.hard.size = 16;	/*	 * If we have a sample rate which is within catchRadius percent	 * of the requested value, we don't have to expand the samples.	 * Otherwise choose the next higher rate.	 * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.	 */	i = 8;	do {		tolerance = catchRadius * awacs_freqs[--i] / 100;		if (awacs_freqs_ok[i]		    && dmasound.soft.speed <= awacs_freqs[i] + tolerance)			break;	} while (i > 0);	if (dmasound.soft.speed >= awacs_freqs[i] - tolerance)		dmasound.trans_write = &transAwacsNormal;	else		dmasound.trans_write = &transAwacsExpand;	dmasound.trans_read = &transAwacsNormalRead;	dmasound.hard.speed = awacs_freqs[i];	awacs_rate_index = i;	/* XXX disable error interrupt on burgundy for now */	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11		 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));	awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);	awacs_write(awacs_reg[1] | MASK_ADDR1);	out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);	/* We really want to execute a DMA stop command, after the AWACS	 * is initialized.	 * For reasons I don't understand, it stops the hissing noise	 * common to many PowerBook G3 systems (like mine :-).	 */	out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);	st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);	out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));	out_le32(&awacs_txdma->control, RUN | (RUN << 16));	expand_bal = -dmasound.soft.speed;}static int PMacSetFormat(int format){	int size;	switch (format) {	case AFMT_QUERY:		return dmasound.soft.format;	case AFMT_MU_LAW:	case AFMT_A_LAW:	case AFMT_U8:	case AFMT_S8:		size = 8;		break;	case AFMT_S16_BE:	case AFMT_U16_BE:	case AFMT_S16_LE:	case AFMT_U16_LE:		size = 16;		break;	default: /* :-) */		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",		       format);		size = 8;		format = AFMT_U8;	}	dmasound.soft.format = format;	dmasound.soft.size = size;	if (dmasound.minDev == SND_DEV_DSP) {		dmasound.dsp.format = format;		dmasound.dsp.size = size;	}	PMacInit();	return format;}#define AWACS_VOLUME_TO_MASK(x)	(15 - ((((x) - 1) * 15) / 99))#define AWACS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 15))static int awacs_get_volume(int reg, int lshift){	int volume;	volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);	volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;	return volume;}static int awacs_volume_setter(int volume, int n, int mute, int lshift){	int r1, rn;	if (mute && volume == 0) {		r1 = awacs_reg[1] | mute;	} else {		r1 = awacs_reg[1] & ~mute;		rn = awacs_reg[n] & ~(0xf | (0xf << lshift));		rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);		rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;		awacs_reg[n] = rn;		awacs_write((n << 12) | rn);		volume = awacs_get_volume(rn, lshift);	}	if (r1 != awacs_reg[1]) {		awacs_reg[1] = r1;		awacs_write(r1 | MASK_ADDR1);	}	return volume;}static int PMacSetVolume(int volume){	return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);}static void PMacPlay(void){	volatile struct dbdma_cmd *cp;	int i, count;	unsigned long flags;	save_flags(flags); cli();	if (awacs_beep_state) {		/* sound takes precedence over beeps */		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);		out_le32(&awacs->control,			 (in_le32(&awacs->control) & ~0x1f00)			 | (awacs_rate_index << 8));		out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count])));		beep_playing = 0;		awacs_beep_state = 0;	}	i = write_sq.front + write_sq.active;	if (i >= write_sq.max_count)		i -= write_sq.max_count;	while (write_sq.active < 2 && write_sq.active < write_sq.count) {		count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size;		if (count < write_sq.block_size && !write_sq.syncing)			/* last block not yet filled, and we're not syncing. */			break;		cp = &awacs_tx_cmds[i];		st_le16(&cp->req_count, count);		st_le16(&cp->xfer_status, 0);		if (++i >= write_sq.max_count)			i = 0;		out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);		out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);		if (write_sq.active == 0)			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));		++write_sq.active;	}	restore_flags(flags);}static void PMacRecord(void){	unsigned long flags;	if (read_sq.active)		return;	save_flags(flags); cli();	/* This is all we have to do......Just start it up.	*/	out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));	read_sq.active = 1;	restore_flags(flags);}static voidpmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs){	int i = write_sq.front;	int stat;	volatile struct dbdma_cmd *cp;	while (write_sq.active > 0) {		cp = &awacs_tx_cmds[i];		stat = ld_le16(&cp->xfer_status);		if ((stat & ACTIVE) == 0)			break;	/* this frame is still going */		--write_sq.count;		--write_sq.active;		if (++i >= write_sq.max_count)			i = 0;	}	if (i != write_sq.front)		WAKE_UP(write_sq.action_queue);	write_sq.front = i;	PMacPlay();

⌨️ 快捷键说明

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