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

📄 dmasound_awacs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/sound/oss/dmasound/dmasound_awacs.c * *  PowerMac `AWACS' and `Burgundy' DMA Sound Driver *  with some limited support for DACA & Tumbler * *  See linux/sound/oss/dmasound/dmasound_core.c for copyright and *  history prior to 2001/01/26. * *	26/01/2001 ed 0.1 Iain Sandoe *		- added version info. *		- moved dbdma command buffer allocation to PMacXXXSqSetup() *		- fixed up beep dbdma cmd buffers * *	08/02/2001 [0.2] *		- make SNDCTL_DSP_GETFMTS return the correct info for the h/w *		- move soft format translations to a separate file *		- [0.3] make SNDCTL_DSP_GETCAPS return correct info. *		- [0.4] more informative machine name strings. *		- [0.5] *		- record changes. *		- made the default_hard/soft entries. *	04/04/2001 [0.6] *		- minor correction to bit assignments in awacs_defs.h *		- incorporate mixer changes from 2.2.x back-port. *		- take out passthru as a rec input (it isn't). *              - make Input Gain slider work the 'right way up'. *              - try to make the mixer sliders more logical - so now the *                input selectors are just two-state (>50% == ON) and the *                Input Gain slider handles the rest of the gain issues. *              - try to pick slider representations that most closely match *                the actual use - e.g. IGain for input gain...  *              - first stab at over/under-run detection. *		- minor cosmetic changes to IRQ identification. *		- fix bug where rates > max would be reported as supported. *              - first stab at over/under-run detection. *              - make use of i2c for mixer settings conditional on perch *                rather than cuda (some machines without perch have cuda). *              - fix bug where TX stops when dbdma status comes up "DEAD" *		  so far only reported on PowerComputing clones ... but. *		- put in AWACS/Screamer register write timeouts. *		- part way to partitioning the init() stuff *		- first pass at 'tumbler' stuff (not support - just an attempt *		  to allow the driver to load on new G4s). *      01/02/2002 [0.7] - BenH *	        - all sort of minor bits went in since the latest update, I *	          bumped the version number for that reason * *      07/26/2002 [0.8] - BenH *	        - More minor bits since last changelog (I should be more careful *	          with those) *	        - Support for snapper & better tumbler integration by Toby Sargeant *	        - Headphone detect for scremer by Julien Blache *	        - More tumbler fixed by Andreas Schwab *	11/29/2003 [0.8.1] - Renzo Davoli (King Enzo) *		- Support for Snapper line in *		- snapper input resampling (for rates < 44100) *		- software line gain control *//* GENERAL FIXME/TODO: check that the assumptions about what is written to   mac-io is valid for DACA & Tumbler.   This driver is in bad need of a rewrite. The dbdma code has to be split,   some proper device-tree parsing code has to be written, etc...*/#include <linux/types.h>#include <linux/module.h>#include <linux/config.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/soundcard.h>#include <linux/adb.h>#include <linux/nvram.h>#include <linux/tty.h>#include <linux/vt_kern.h>#include <linux/spinlock.h>#include <linux/kmod.h>#include <linux/interrupt.h>#include <linux/input.h>#include <asm/semaphore.h>#ifdef CONFIG_ADB_CUDA#include <linux/cuda.h>#endif#ifdef CONFIG_ADB_PMU#include <linux/pmu.h>#endif#include <linux/i2c-dev.h>#include <asm/uaccess.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/io.h>#include <asm/dbdma.h>#include <asm/pmac_feature.h>#include <asm/irq.h>#include <asm/nvram.h>#include "awacs_defs.h"#include "dmasound.h"#include "tas3001c.h"#include "tas3004.h"#include "tas_common.h"#define DMASOUND_AWACS_REVISION	0#define DMASOUND_AWACS_EDITION	7#define AWACS_SNAPPER   110	/* fake revision # for snapper */#define AWACS_BURGUNDY	100	/* fake revision # for burgundy */#define AWACS_TUMBLER    90	/* fake revision # for tumbler */#define AWACS_DACA	 80	/* fake revision # for daca (ibook) */#define AWACS_AWACS       2     /* holding revision for AWACS */#define AWACS_SCREAMER    3     /* holding revision for Screamer *//* * Interrupt numbers and addresses, & info obtained from the device tree. */static int awacs_irq, awacs_tx_irq, awacs_rx_irq;static volatile struct awacs_regs __iomem *awacs;static volatile u32 __iomem *i2s;static volatile struct dbdma_regs __iomem *awacs_txdma, *awacs_rxdma;static int awacs_rate_index;static int awacs_subframe;static struct device_node* awacs_node;static struct device_node* i2s_node;static char awacs_name[64];static int awacs_revision;static int awacs_sleeping;static DECLARE_MUTEX(dmasound_sem);static int sound_device_id;		/* exists after iMac revA */static int hw_can_byteswap = 1 ;	/* most pmac sound h/w can *//* model info *//* To be replaced with better interaction with pmac_feature.c */static int is_pbook_3X00;static int is_pbook_g3;/* expansion info */static int has_perch;static int has_ziva;/* for earlier powerbooks which need fiddling with mac-io to enable * cd etc.*/static unsigned char __iomem *latch_base;static unsigned char __iomem *macio_base;/* * Space for the DBDMA command blocks. */static void *awacs_tx_cmd_space;static volatile struct dbdma_cmd *awacs_tx_cmds;static int number_of_tx_cmd_buffers;static void *awacs_rx_cmd_space;static volatile struct dbdma_cmd *awacs_rx_cmds;static int number_of_rx_cmd_buffers;/* * Cached values of AWACS registers (we can't read them). * Except on the burgundy (and screamer). XXX */int awacs_reg[8];int awacs_reg1_save;/* tracking values for the mixer contents*/static int spk_vol;static int line_vol;static int passthru_vol;static int ip_gain;           /* mic preamp settings */static int rec_lev = 0x4545 ; /* default CD gain 69 % */static int mic_lev;static int cd_lev = 0x6363 ; /* 99 % */static int line_lev;static int hdp_connected;/* * 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,};/* beep support */#define BEEP_SRATE	22050	/* 22050 Hz sample rate */#define BEEP_BUFLEN	512#define BEEP_VOLUME	15	/* 0 - 100 */static int beep_vol = BEEP_VOLUME;static int beep_playing;static int awacs_beep_state;static short *beep_buf;static void *beep_dbdma_cmd_space;static volatile struct dbdma_cmd *beep_dbdma_cmd;/* 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);/* we will allocate a single 'emergency' dbdma cmd block to use if the   tx status comes up "DEAD".  This happens on some PowerComputing Pmac   clones, either owing to a bug in dbdma or some interaction between   IDE and sound.  However, this measure would deal with DEAD status if   if appeared elsewhere.   for the sake of memory efficiency we'll allocate this cmd as part of   the beep cmd stuff.*/static volatile struct dbdma_cmd *emergency_dbdma_cmd;#ifdef CONFIG_PM/* * 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_PM *//* for (soft) sample rate translations */int expand_bal;		/* Balance factor for expanding (not volume!) */int expand_read_bal;	/* Balance factor for expanding reads (not volume!) *//*** Low level stuff *********************************************************/static void *PMacAlloc(unsigned int size, gfp_t 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 irqreturn_t pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);static irqreturn_t 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);/*** Mid level stuff **********************************************************/static int PMacMixerIoctl(u_int cmd, u_long arg);static int PMacWriteSqSetup(void);static int PMacReadSqSetup(void);static void PMacAbortRead(void);extern TRANS transAwacsNormal ;extern TRANS transAwacsExpand ;extern TRANS transAwacsNormalRead ;extern TRANS transAwacsExpandRead ;extern int daca_init(void);extern void daca_cleanup(void);extern int daca_set_volume(uint left_vol, uint right_vol);extern void daca_get_volume(uint * left_vol, uint  *right_vol);extern int daca_enter_sleep(void);extern int daca_leave_sleep(void);#define TRY_LOCK()	\	if ((rc = down_interruptible(&dmasound_sem)) != 0)	\		return rc;#define LOCK()		down(&dmasound_sem);#define UNLOCK()	up(&dmasound_sem);/* We use different versions that the ones provided in dmasound.h *  * FIXME: Use different names ;) */#undef IOCTL_IN#undef IOCTL_OUT#define IOCTL_IN(arg, ret)	\	rc = get_user(ret, (int __user *)(arg)); \	if (rc) break;#define IOCTL_OUT(arg, ret)	\	ioctl_return2((int __user *)(arg), ret)static inline int ioctl_return2(int __user *addr, int value){	return value < 0 ? value : put_user(value, addr);}/*** AE - TUMBLER / SNAPPER START ************************************************/int gpio_audio_reset, gpio_audio_reset_pol;int gpio_amp_mute, gpio_amp_mute_pol;int gpio_headphone_mute, gpio_headphone_mute_pol;int gpio_headphone_detect, gpio_headphone_detect_pol;int gpio_headphone_irq;intsetup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol){	struct device_node *np;	u32* pp;		np = find_devices("gpio");	if (!np)		return -ENODEV;	np = np->child;	while(np != 0) {		if (name) {			char *property = get_property(np,"audio-gpio",NULL);			if (property != 0 && strcmp(property,name) == 0)				break;		} else if (compatible && device_is_compatible(np, compatible))			break;		np = np->sibling;	}	if (!np)		return -ENODEV;	pp = (u32 *)get_property(np, "AAPL,address", NULL);	if (!pp)		return -ENODEV;	*gpio_addr = (*pp) & 0x0000ffff;	pp = (u32 *)get_property(np, "audio-gpio-active-state", NULL);	if (pp)		*gpio_pol = *pp;	else		*gpio_pol = 1;	if (np->n_intrs > 0)		return np->intrs[0].line;		return 0;}static inline voidwrite_audio_gpio(int gpio_addr, int data){	if (!gpio_addr)		return;	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04);}static inline intread_audio_gpio(int gpio_addr){	if (!gpio_addr)		return 0;	return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0);}/* * Headphone interrupt via GPIO (Tumbler, Snapper, DACA) */static irqreturn_theadphone_intr(int irq, void *devid, struct pt_regs *regs){	unsigned long flags;	spin_lock_irqsave(&dmasound.lock, flags);	if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) {		printk(KERN_INFO "Audio jack plugged, muting speakers.\n");		write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol);		write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);		tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0);	} else {		printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n");		write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);		write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);		tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0);	}	spin_unlock_irqrestore(&dmasound.lock, flags);	return IRQ_HANDLED;}/* Initialize tumbler */static inttas_dmasound_init(void){	setup_audio_gpio(		"audio-hw-reset",		NULL,		&gpio_audio_reset,		&gpio_audio_reset_pol);	setup_audio_gpio(		"amp-mute",		NULL,		&gpio_amp_mute,		&gpio_amp_mute_pol);	setup_audio_gpio("headphone-mute",		NULL,		&gpio_headphone_mute,		&gpio_headphone_mute_pol);	gpio_headphone_irq = setup_audio_gpio(		"headphone-detect",		NULL,		&gpio_headphone_detect,		&gpio_headphone_detect_pol);	/* Fix some broken OF entries in desktop machines */	if (!gpio_headphone_irq)		gpio_headphone_irq = setup_audio_gpio(			NULL,			"keywest-gpio15",			&gpio_headphone_detect,			&gpio_headphone_detect_pol);	write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol);	msleep(100);	write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);	msleep(100);  	if (gpio_headphone_irq) {		if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",NULL) < 0) {    			printk(KERN_ERR "tumbler: Can't request headphone interrupt\n");    			gpio_headphone_irq = 0;    		} else {			u8 val;			/* Activate headphone status interrupts */			val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0);			pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80);

⌨️ 快捷键说明

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