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

📄 dmasound_awacs.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  linux/drivers/sound/dmasound/dmasound_awacs.c * *  PowerMac `AWACS' and `Burgundy' DMA Sound Driver * *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits */#include <linux/module.h>#include <linux/config.h>#include <linux/malloc.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/soundcard.h>#include <linux/adb.h>#include <linux/nvram.h>#include <linux/vt_kern.h>#ifdef CONFIG_ADB_CUDA#include <linux/cuda.h>#endif#ifdef CONFIG_ADB_PMU#include <linux/pmu.h>#endif#include <asm/uaccess.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/io.h>#include <asm/dbdma.h>#include <asm/feature.h>#include <asm/irq.h>#include "awacs_defs.h"#include "dmasound.h"/* * Interrupt numbers and addresses, obtained from the device tree. */static int awacs_irq, awacs_tx_irq, awacs_rx_irq;static volatile struct awacs_regs *awacs;static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;static int awacs_rate_index;static int awacs_subframe;static int awacs_spkr_vol;static struct device_node* awacs_node;static char awacs_name[64];static int awacs_revision;int awacs_is_screamer = 0;int awacs_device_id = 0;int awacs_has_iic = 0;#define AWACS_BURGUNDY	100		/* fake revision # for burgundy *//* * Space for the DBDMA command blocks. */static void *awacs_tx_cmd_space;static volatile struct dbdma_cmd *awacs_tx_cmds;static void *awacs_rx_cmd_space;static volatile struct dbdma_cmd *awacs_rx_cmds;/* * Cached values of AWACS registers (we can't read them). * Except on the burgundy. XXX */int awacs_reg[8];#define HAS_16BIT_TABLES#undef HAS_8BIT_TABLES/* * Stuff for outputting a beep.  The values range from -327 to +327 * so we can multiply by an amplitude in the range 0..100 to get a * signed short value to put in the output buffer. */static short beep_wform[256] = {	0,	40,	79,	117,	153,	187,	218,	245,	269,	288,	304,	316,	323,	327,	327,	324,	318,	310,	299,	288,	275,	262,	249,	236,	224,	213,	204,	196,	190,	186,	183,	182,	182,	183,	186,	189,	192,	196,	200,	203,	206,	208,	209,	209,	209,	207,	204,	201,	197,	193,	188,	183,	179,	174,	170,	166,	163,	161,	160,	159,	159,	160,	161,	162,	164,	166,	168,	169,	171,	171,	171,	170,	169,	167,	163,	159,	155,	150,	144,	139,	133,	128,	122,	117,	113,	110,	107,	105,	103,	103,	103,	103,	104,	104,	105,	105,	105,	103,	101,	97,	92,	86,	78,	68,	58,	45,	32,	18,	3,	-11,	-26,	-41,	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,	0,	16,	33,	48,	62,	75,	85,	93,	99,	102,	102,	100,	95,	88,	79,	68,	55,	41,	26,	11,	-3,	-18,	-32,	-45,	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,};#define BEEP_SRATE	22050	/* 22050 Hz sample rate */#define BEEP_BUFLEN	512#define BEEP_VOLUME	15	/* 0 - 100 */static int beep_volume = BEEP_VOLUME;static int beep_playing = 0;static int awacs_beep_state = 0;static short *beep_buf;static volatile struct dbdma_cmd *beep_dbdma_cmd;static void (*orig_mksound)(unsigned int, unsigned int);static int is_pbook_3400;static unsigned char *latch_base;static int is_pbook_G3;static unsigned char *macio_base;/* Burgundy functions */static void awacs_burgundy_wcw(unsigned addr,unsigned newval);static unsigned awacs_burgundy_rcw(unsigned addr);static void awacs_burgundy_write_volume(unsigned address, int volume);static int awacs_burgundy_read_volume(unsigned address);static void awacs_burgundy_write_mvolume(unsigned address, int volume);static int awacs_burgundy_read_mvolume(unsigned address);#ifdef CONFIG_PMAC_PBOOK/* * Stuff for restoring after a sleep. */static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);struct pmu_sleep_notifier awacs_sleep_notifier = {	awacs_sleep_notify, SLEEP_LEVEL_SOUND,};#endif /* CONFIG_PMAC_PBOOK */static int expand_bal;	/* Balance factor for expanding (not volume!) */static int expand_data;	/* Data for expanding *//*** Translations ************************************************************//* ++TeSche: radically changed for new expanding purposes... * * These two routines now deal with copying/expanding/translating the samples * from user space into our buffer at the right frequency. They take care about * how much data there's actually to read, how much buffer space there is and * to convert samples into the right frequency/encoding. They will only work on * complete samples so it may happen they leave some bytes in the input stream * if the user didn't write a multiple of the current sample size. They both * return the number of bytes they've used from both streams so you may detect * such a situation. Luckily all programs should be able to cope with that. * * I think I've optimized anything as far as one can do in plain C, all * variables should fit in registers and the loops are really short. There's * one loop for every possible situation. Writing a more generalized and thus * parameterized loop would only produce slower code. Feel free to optimize * this in assembler if you like. :) * * I think these routines belong here because they're not yet really hardware * independent, especially the fact that the Falcon can play 16bit samples * only in stereo is hardcoded in both of them! * * ++geert: split in even more functions (one per format) */static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,			  u_char frame[], ssize_t *frameUsed,			  ssize_t frameLeft);static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,			  u_char frame[], ssize_t *frameUsed,			  ssize_t frameLeft);static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft);static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft);static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft);static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);/*** Low level stuff *********************************************************/static void PMacOpen(void);static void PMacRelease(void);static void *PMacAlloc(unsigned int size, int flags);static void PMacFree(void *ptr, unsigned int size);static int PMacIrqInit(void);#ifdef MODULEstatic void PMacIrqCleanup(void);#endifstatic void PMacSilence(void);static void PMacInit(void);static int PMacSetFormat(int format);static int PMacSetVolume(int volume);static void PMacPlay(void);static void PMacRecord(void);static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);static void awacs_write(int val);static int awacs_get_volume(int reg, int lshift);static int awacs_volume_setter(int volume, int n, int mute, int lshift);static void awacs_mksound(unsigned int hz, unsigned int ticks);static void awacs_nosound(unsigned long xx);/*** Mid level stuff **********************************************************/static int PMacMixerIoctl(u_int cmd, u_long arg);static void PMacWriteSqSetup(void);static void PMacReadSqSetup(void);static void PMacAbortRead(void);/*** Translations ************************************************************/static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft){	short *table = dmasound.soft.format == AFMT_MU_LAW		? dmasound_ulaw2dma16 : dmasound_alaw2dma16;	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;		if (get_user(data, userPtr++))			return -EFAULT;		val = table[data];		*p++ = val;		if (stereo) {			if (get_user(data, userPtr++))				return -EFAULT;			val = table[data];		}		*p++ = val;		count--;	}	*frameUsed += used * 4;	return stereo? used * 2: used;}static ssize_t pmac_ct_s8(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;		if (get_user(data, userPtr++))			return -EFAULT;		val = data << 8;		*p++ = val;		if (stereo) {			if (get_user(data, userPtr++))				return -EFAULT;			val = data << 8;		}		*p++ = val;		count--;	}	*frameUsed += used * 4;	return stereo? used * 2: used;}static ssize_t pmac_ct_u8(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;		if (get_user(data, userPtr++))			return -EFAULT;		val = (data ^ 0x80) << 8;		*p++ = val;		if (stereo) {			if (get_user(data, userPtr++))				return -EFAULT;			val = (data ^ 0x80) << 8;		}		*p++ = val;		count--;	}	*frameUsed += used * 4;	return stereo? used * 2: used;}static ssize_t pmac_ct_s16(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;			if (get_user(data, up++))				return -EFAULT;			*fp++ = data;			*fp++ = data;			count--;		}	} else {		if (copy_from_user(fp, userPtr, count * 4))			return -EFAULT;	}	*frameUsed += used * 4;	return stereo? used * 4: used * 2;}static ssize_t pmac_ct_u16(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;		if (get_user(data, up++))			return -EFAULT;		data ^= mask;		*fp++ = data;		if (stereo) {			if (get_user(data, up++))				return -EFAULT;			data ^= mask;		}		*fp++ = data;		count--;	}	*frameUsed += used * 4;	return stereo? used * 4: used * 2;}static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft){	unsigned short *table = (unsigned short *)		(dmasound.soft.format == AFMT_MU_LAW		 ? dmasound_ulaw2dma16 : dmasound_alaw2dma16);	unsigned int data = expand_data;	unsigned int *p = (unsigned int *) &frame[*frameUsed];	int bal = expand_bal;	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;	int utotal, ftotal;	int stereo = dmasound.soft.stereo;	frameLeft >>= 2;	if (stereo)		userCount >>= 1;	ftotal = frameLeft;	utotal = userCount;	while (frameLeft) {		u_char c;		if (bal < 0) {			if (userCount == 0)				break;			if (get_user(c, userPtr++))				return -EFAULT;			data = table[c];			if (stereo) {				if (get_user(c, userPtr++))					return -EFAULT;				data = (data << 16) + table[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 * 2: utotal;}static ssize_t pmac_ctx_s8(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;	int bal = expand_bal;	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;	int stereo = dmasound.soft.stereo;	int utotal, ftotal;	frameLeft >>= 2;	if (stereo)		userCount >>= 1;	ftotal = frameLeft;	utotal = userCount;	while (frameLeft) {		u_char c;		if (bal < 0) {			if (userCount == 0)				break;			if (get_user(c, userPtr++))				return -EFAULT;			data = c << 8;			if (stereo) {				if (get_user(c, userPtr++))					return -EFAULT;				data = (data << 16) + (c << 8);			} 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 * 2: utotal;}static ssize_t pmac_ctx_u8(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;	int bal = expand_bal;	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;	int stereo = dmasound.soft.stereo;	int utotal, ftotal;	frameLeft >>= 2;	if (stereo)		userCount >>= 1;	ftotal = frameLeft;	utotal = userCount;	while (frameLeft) {		u_char c;		if (bal < 0) {			if (userCount == 0)				break;			if (get_user(c, userPtr++))				return -EFAULT;			data = (c ^ 0x80) << 8;			if (stereo) {				if (get_user(c, userPtr++))					return -EFAULT;				data = (data << 16) + ((c ^ 0x80) << 8);			} 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 * 2: utotal;

⌨️ 快捷键说明

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