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

📄 dmasound_paula.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/sound/oss/dmasound/dmasound_paula.c * *  Amiga `Paula' DMA Sound Driver * *  See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits *  prior to 28/01/2001 * *  28/01/2001 [0.1] Iain Sandoe *		     - added versioning *		     - put in and populated the hardware_afmts field. *             [0.2] - put in SNDCTL_DSP_GETCAPS value. *	       [0.3] - put in constraint on state buffer usage. *	       [0.4] - put in default hard/soft settings*/#include <linux/module.h>#include <linux/config.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/soundcard.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <asm/setup.h>#include <asm/amigahw.h>#include <asm/amigaints.h>#include <asm/machdep.h>#include "dmasound.h"#define DMASOUND_PAULA_REVISION 0#define DMASOUND_PAULA_EDITION 4   /*    *	The minimum period for audio depends on htotal (for OCS/ECS/AGA)    *	(Imported from arch/m68k/amiga/amisound.c)    */extern volatile u_short amiga_audio_min_period;   /*    *	amiga_mksound() should be able to restore the period after beeping    *	(Imported from arch/m68k/amiga/amisound.c)    */extern u_short amiga_audio_period;   /*    *	Audio DMA masks    */#define AMI_AUDIO_OFF	(DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)#define AMI_AUDIO_8	(DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)#define AMI_AUDIO_14	(AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)    /*     *  Helper pointers for 16(14)-bit sound     */static int write_sq_block_size_half, write_sq_block_size_quarter;/*** Low level stuff *********************************************************/static void *AmiAlloc(unsigned int size, gfp_t flags);static void AmiFree(void *obj, unsigned int size);static int AmiIrqInit(void);#ifdef MODULEstatic void AmiIrqCleanUp(void);#endifstatic void AmiSilence(void);static void AmiInit(void);static int AmiSetFormat(int format);static int AmiSetVolume(int volume);static int AmiSetTreble(int treble);static void AmiPlayNextFrame(int index);static void AmiPlay(void);static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);#ifdef CONFIG_HEARTBEAT    /*     *  Heartbeat interferes with sound since the 7 kHz low-pass filter and the     *  power LED are controlled by the same line.     */#ifdef CONFIG_APUS#define mach_heartbeat	ppc_md.heartbeat#endifstatic void (*saved_heartbeat)(int) = NULL;static inline void disable_heartbeat(void){	if (mach_heartbeat) {	    saved_heartbeat = mach_heartbeat;	    mach_heartbeat = NULL;	}	AmiSetTreble(dmasound.treble);}static inline void enable_heartbeat(void){	if (saved_heartbeat)	    mach_heartbeat = saved_heartbeat;}#else /* !CONFIG_HEARTBEAT */#define disable_heartbeat()	do { } while (0)#define enable_heartbeat()	do { } while (0)#endif /* !CONFIG_HEARTBEAT *//*** Mid level stuff *********************************************************/static void AmiMixerInit(void);static int AmiMixerIoctl(u_int cmd, u_long arg);static int AmiWriteSqSetup(void);static int AmiStateInfo(char *buffer, size_t space);/*** 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) */    /*     *  Native format     */static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,			 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft){	ssize_t count, used;	if (!dmasound.soft.stereo) {		void *p = &frame[*frameUsed];		count = min_t(unsigned long, userCount, frameLeft) & ~1;		used = count;		if (copy_from_user(p, userPtr, count))			return -EFAULT;	} else {		u_char *left = &frame[*frameUsed>>1];		u_char *right = left+write_sq_block_size_half;		count = min_t(unsigned long, userCount, frameLeft)>>1 & ~1;		used = count*2;		while (count > 0) {			if (get_user(*left++, userPtr++)			    || get_user(*right++, userPtr++))				return -EFAULT;			count--;		}	}	*frameUsed += used;	return used;}    /*     *  Copy and convert 8 bit data     */#define GENERATE_AMI_CT8(funcname, convsample)				\static ssize_t funcname(const u_char *userPtr, size_t userCount,	\			u_char frame[], ssize_t *frameUsed,		\			ssize_t frameLeft)				\{									\	ssize_t count, used;						\									\	if (!dmasound.soft.stereo) {					\		u_char *p = &frame[*frameUsed];				\		count = min_t(size_t, userCount, frameLeft) & ~1;	\		used = count;						\		while (count > 0) {					\			u_char data;					\			if (get_user(data, userPtr++))			\				return -EFAULT;				\			*p++ = convsample(data);			\			count--;					\		}							\	} else {							\		u_char *left = &frame[*frameUsed>>1];			\		u_char *right = left+write_sq_block_size_half;		\		count = min_t(size_t, userCount, frameLeft)>>1 & ~1;	\		used = count*2;						\		while (count > 0) {					\			u_char data;					\			if (get_user(data, userPtr++))			\				return -EFAULT;				\			*left++ = convsample(data);			\			if (get_user(data, userPtr++))			\				return -EFAULT;				\			*right++ = convsample(data);			\			count--;					\		}							\	}								\	*frameUsed += used;						\	return used;							\}#define AMI_CT_ULAW(x)	(dmasound_ulaw2dma8[(x)])#define AMI_CT_ALAW(x)	(dmasound_alaw2dma8[(x)])#define AMI_CT_U8(x)	((x) ^ 0x80)GENERATE_AMI_CT8(ami_ct_ulaw, AMI_CT_ULAW)GENERATE_AMI_CT8(ami_ct_alaw, AMI_CT_ALAW)GENERATE_AMI_CT8(ami_ct_u8, AMI_CT_U8)    /*     *  Copy and convert 16 bit data     */#define GENERATE_AMI_CT_16(funcname, convsample)			\static ssize_t funcname(const u_char *userPtr, size_t userCount,	\			u_char frame[], ssize_t *frameUsed,		\			ssize_t frameLeft)				\{									\	ssize_t count, used;						\	u_short data;							\									\	if (!dmasound.soft.stereo) {					\		u_char *high = &frame[*frameUsed>>1];			\		u_char *low = high+write_sq_block_size_half;		\		count = min_t(size_t, userCount, frameLeft)>>1 & ~1;	\		used = count*2;						\		while (count > 0) {					\			if (get_user(data, ((u_short *)userPtr)++))	\				return -EFAULT;				\			data = convsample(data);			\			*high++ = data>>8;				\			*low++ = (data>>2) & 0x3f;			\			count--;					\		}							\	} else {							\		u_char *lefth = &frame[*frameUsed>>2];			\		u_char *leftl = lefth+write_sq_block_size_quarter;	\		u_char *righth = lefth+write_sq_block_size_half;	\		u_char *rightl = righth+write_sq_block_size_quarter;	\		count = min_t(size_t, userCount, frameLeft)>>2 & ~1;	\		used = count*4;						\		while (count > 0) {					\			if (get_user(data, ((u_short *)userPtr)++))	\				return -EFAULT;				\			data = convsample(data);			\			*lefth++ = data>>8;				\			*leftl++ = (data>>2) & 0x3f;			\			if (get_user(data, ((u_short *)userPtr)++))	\				return -EFAULT;				\			data = convsample(data);			\			*righth++ = data>>8;				\			*rightl++ = (data>>2) & 0x3f;			\			count--;					\		}							\	}								\	*frameUsed += used;						\	return used;							\}#define AMI_CT_S16BE(x)	(x)#define AMI_CT_U16BE(x)	((x) ^ 0x8000)#define AMI_CT_S16LE(x)	(le2be16((x)))#define AMI_CT_U16LE(x)	(le2be16((x)) ^ 0x8000)GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE)GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE)GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE)GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE)static TRANS transAmiga = {	.ct_ulaw	= ami_ct_ulaw,	.ct_alaw	= ami_ct_alaw,	.ct_s8		= ami_ct_s8,	.ct_u8		= ami_ct_u8,	.ct_s16be	= ami_ct_s16be,	.ct_u16be	= ami_ct_u16be,	.ct_s16le	= ami_ct_s16le,	.ct_u16le	= ami_ct_u16le,};/*** Low level stuff *********************************************************/static inline void StopDMA(void){	custom.aud[0].audvol = custom.aud[1].audvol = 0;	custom.aud[2].audvol = custom.aud[3].audvol = 0;	custom.dmacon = AMI_AUDIO_OFF;	enable_heartbeat();}static void *AmiAlloc(unsigned int size, gfp_t flags){	return amiga_chip_alloc((long)size, "dmasound [Paula]");}static void AmiFree(void *obj, unsigned int size){	amiga_chip_free (obj);}static int __init AmiIrqInit(void){	/* turn off DMA for audio channels */	StopDMA();	/* Register interrupt handler. */	if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound",			AmiInterrupt))		return 0;	return 1;}#ifdef MODULEstatic void AmiIrqCleanUp(void){	/* turn off DMA for audio channels */	StopDMA();	/* release the interrupt */	free_irq(IRQ_AMIGA_AUD0, AmiInterrupt);}#endif /* MODULE */static void AmiSilence(void){	/* turn off DMA for audio channels */	StopDMA();}static void AmiInit(void){	int period, i;	AmiSilence();	if (dmasound.soft.speed)		period = amiga_colorclock/dmasound.soft.speed-1;	else		period = amiga_audio_min_period;	dmasound.hard = dmasound.soft;	dmasound.trans_write = &transAmiga;	if (period < amiga_audio_min_period) {

⌨️ 快捷键说明

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