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

📄 cs4218_tdm.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* This is a modified version of linux/drivers/sound/dmasound.c to * support the CS4218 codec on the 8xx TDM port.  Thanks to everyone * that contributed to the dmasound software (which includes me :-). * * The CS4218 is configured in Mode 4, sub-mode 0.  This provides * left/right data only on the TDM port, as a 32-bit word, per frame * pulse.  The control of the CS4218 is provided by some other means, * like the SPI port. * Dan Malek (dmalek@jlc.net) */#include <linux/module.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/major.h>#include <linux/config.h>#include <linux/fcntl.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/sound.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/uaccess.h>#include <asm/io.h>/* Should probably do something different with this path name..... * Actually, I should just stop using it... */#include "cs4218.h"#include <linux/soundcard.h>#include <asm/mpc8xx.h>#include <asm/8xx_immap.h>#include <asm/commproc.h>#define DMASND_CS4218		5#define MAX_CATCH_RADIUS	10#define MIN_BUFFERS		4#define MIN_BUFSIZE 		4#define MAX_BUFSIZE		128#define HAS_8BIT_TABLESstatic int sq_unit = -1;static int mixer_unit = -1;static int state_unit = -1;static int irq_installed = 0;static char **sound_buffers = NULL;static char **sound_read_buffers = NULL;/* Local copies of things we put in the control register.  Output * volume, like most codecs is really attenuation. */static int cs4218_rate_index;/* * 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_SPEED	5	/* 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 beep_state = 0;static short *beep_buf;static void (*orig_mksound)(unsigned int, unsigned int);/* This is found someplace else......I guess in the keyboard driver * we don't include. */static void (*kd_mksound)(unsigned int, unsigned int);static int catchRadius = 0;static int numBufs = 4, bufSize = 32;static int numReadBufs = 4, readbufSize = 32;/* TDM/Serial transmit and receive buffer descriptors.*/static volatile cbd_t	*rx_base, *rx_cur, *tx_base, *tx_cur;MODULE_PARM(catchRadius, "i");MODULE_PARM(numBufs, "i");MODULE_PARM(bufSize, "i");MODULE_PARM(numreadBufs, "i");MODULE_PARM(readbufSize, "i");#define arraysize(x)	(sizeof(x)/sizeof(*(x)))#define le2be16(x)	(((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))#define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))#define IOCTL_IN(arg, ret) \	do { int error = get_user(ret, (int *)(arg)); \		if (error) return error; \	} while (0)#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)/* CS4218 serial port control in mode 4.*/#define CS_INTMASK	((uint)0x40000000)#define CS_DO1		((uint)0x20000000)#define CS_LATTEN	((uint)0x1f000000)#define CS_RATTEN	((uint)0x00f80000)#define CS_MUTE		((uint)0x00040000)#define CS_ISL		((uint)0x00020000)#define CS_ISR		((uint)0x00010000)#define CS_LGAIN	((uint)0x0000f000)#define CS_RGAIN	((uint)0x00000f00)#define CS_LATTEN_SET(X)	(((X) & 0x1f) << 24)#define CS_RATTEN_SET(X)	(((X) & 0x1f) << 19)#define CS_LGAIN_SET(X)		(((X) & 0x0f) << 12)#define CS_RGAIN_SET(X)		(((X) & 0x0f) << 8)#define CS_LATTEN_GET(X)	(((X) >> 24) & 0x1f)#define CS_RATTEN_GET(X)	(((X) >> 19) & 0x1f)#define CS_LGAIN_GET(X)		(((X) >> 12) & 0x0f)#define CS_RGAIN_GET(X)		(((X) >> 8) & 0x0f)/* The control register is effectively write only.  We have to keep a copy * of what we write. */static	uint	cs4218_control;/* A place to store expanding information.*/static int	expand_bal;static int	expand_data;/* Since I can't make the microcode patch work for the SPI, I just * clock the bits using software. */static	void	sw_spi_init(void);static	void	sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt);static	uint	cs4218_ctl_write(uint ctlreg);/*** Some low level helpers **************************************************//* 16 bit mu-law */static short ulaw2dma16[] = {	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,	876,	844,	812,	780,	748,	716,	684,	652,	620,	588,	556,	524,	492,	460,	428,	396,	372,	356,	340,	324,	308,	292,	276,	260,	244,	228,	212,	196,	180,	164,	148,	132,	120,	112,	104,	96,	88,	80,	72,	64,	56,	48,	40,	32,	24,	16,	8,	0,};/* 16 bit A-law */static short alaw2dma16[] = {	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,	344,	328,	376,	360,	280,	264,	312,	296,	472,	456,	504,	488,	408,	392,	440,	424,	88,	72,	120,	104,	24,	8,	56,	40,	216,	200,	248,	232,	152,	136,	184,	168,	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,	688,	656,	752,	720,	560,	528,	624,	592,	944,	912,	1008,	976,	816,	784,	880,	848,};/*** Translations ************************************************************/static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,			  u_char frame[], ssize_t *frameUsed,			  ssize_t frameLeft);static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,			  u_char frame[], ssize_t *frameUsed,			  ssize_t frameLeft);static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft);static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft);static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,			    u_char frame[], ssize_t *frameUsed,			    ssize_t frameLeft);static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft);/*** Low level stuff *********************************************************/struct cs_sound_settings {	MACHINE mach;		/* machine dependent things */	SETTINGS hard;		/* hardware settings */	SETTINGS soft;		/* software settings */	SETTINGS dsp;		/* /dev/dsp default settings */	TRANS *trans_write;	/* supported translations for playback */	TRANS *trans_read;	/* supported translations for record */	int volume_left;	/* volume (range is machine dependent) */	int volume_right;	int bass;		/* tone (range is machine dependent) */	int treble;	int gain;	int minDev;		/* minor device number currently open */};static struct cs_sound_settings sound;static void *CS_Alloc(unsigned int size, int flags);static void CS_Free(void *ptr, unsigned int size);static int CS_IrqInit(void);#ifdef MODULEstatic void CS_IrqCleanup(void);#endif /* MODULE */static void CS_Silence(void);static void CS_Init(void);static void CS_Play(void);static void CS_Record(void);static int CS_SetFormat(int format);static int CS_SetVolume(int volume);static void cs4218_tdm_tx_intr(void *devid);static void cs4218_tdm_rx_intr(void *devid);static void cs4218_intr(void *devid, struct pt_regs *regs);static int cs_get_volume(uint reg);static int cs_volume_setter(int volume, int mute);static int cs_get_gain(uint reg);static int cs_set_gain(int gain);static void cs_mksound(unsigned int hz, unsigned int ticks);static void cs_nosound(unsigned long xx);/*** Mid level stuff *********************************************************/static void sound_silence(void);static void sound_init(void);static int sound_set_format(int format);static int sound_set_speed(int speed);static int sound_set_stereo(int stereo);static int sound_set_volume(int volume);static ssize_t sound_copy_translate(const u_char *userPtr,				    size_t userCount,				    u_char frame[], ssize_t *frameUsed,				    ssize_t frameLeft);static ssize_t sound_copy_translate_read(const u_char *userPtr,				    size_t userCount,				    u_char frame[], ssize_t *frameUsed,				    ssize_t frameLeft);/* * /dev/mixer abstraction */struct sound_mixer {    int busy;    int modify_counter;};static struct sound_mixer mixer;static struct sound_queue sq;static struct sound_queue read_sq;#define sq_block_address(i)	(sq.buffers[i])#define SIGNAL_RECEIVED	(signal_pending(current))#define NON_BLOCKING(open_mode)	(open_mode & O_NONBLOCK)#define ONE_SECOND	HZ	/* in jiffies (100ths of a second) */#define NO_TIME_LIMIT	0xffffffff/* * /dev/sndstat */struct sound_state {	int busy;	char buf[512];	int len, ptr;};static struct sound_state state;/*** Common stuff ********************************************************/static long long sound_lseek(struct file *file, long long offset, int orig);/*** Config & Setup **********************************************************/void dmasound_setup(char *str, int *ints);/*** 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 cs4218_ct_law(const u_char *userPtr, size_t userCount,			   u_char frame[], ssize_t *frameUsed,			   ssize_t frameLeft){	short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;	ssize_t count, used;	short *p = (short *) &frame[*frameUsed];	int val, stereo = sound.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 cs4218_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 = sound.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 cs4218_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 = sound.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;}/* This is the default format of the codec.  Signed, 16-bit stereo

⌨️ 快捷键说明

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