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

📄 dbri.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#define D_CHI_BPF(v)	((v)<<0)	/* Bits per Frame *//* NT: These are here for completeness */#define D_NT_FBIT	(1<<17)	/* Frame Bit */#define D_NT_NBF	(1<<16)	/* Number of bad frames to loose framing */#define D_NT_IRM_IMM	(1<<15)	/* Interrupt Report & Mask: Immediate */#define D_NT_IRM_EN	(1<<14)	/* Interrupt Report & Mask: Enable */#define D_NT_ISNT	(1<<13)	/* Configure interface as NT */#define D_NT_FT		(1<<12)	/* Fixed Timing */#define D_NT_EZ		(1<<11)	/* Echo Channel is Zeros */#define D_NT_IFA	(1<<10)	/* Inhibit Final Activation */#define D_NT_ACT	(1<<9)	/* Activate Interface */#define D_NT_MFE	(1<<8)	/* Multiframe Enable */#define D_NT_RLB(v)	((v)<<5)	/* Remote Loopback */#define D_NT_LLB(v)	((v)<<2)	/* Local Loopback */#define D_NT_FACT	(1<<1)	/* Force Activation */#define D_NT_ABV	(1<<0)	/* Activate Bipolar Violation *//* Codec Setup */#define D_CDEC_CK(v)	((v)<<24)	/* Clock Select */#define D_CDEC_FED(v)	((v)<<12)	/* FSCOD Falling Edge Delay */#define D_CDEC_RED(v)	((v)<<0)	/* FSCOD Rising Edge Delay *//* Test */#define D_TEST_RAM(v)	((v)<<16)	/* RAM Pointer */#define D_TEST_SIZE(v)	((v)<<11)	/* */#define D_TEST_ROMONOFF	0x5	/* Toggle ROM opcode monitor on/off */#define D_TEST_PROC	0x6	/* Microprocessor test */#define D_TEST_SER	0x7	/* Serial-Controller test */#define D_TEST_RAMREAD	0x8	/* Copy from Ram to system memory */#define D_TEST_RAMWRITE	0x9	/* Copy into Ram from system memory */#define D_TEST_RAMBIST	0xa	/* RAM Built-In Self Test */#define D_TEST_MCBIST	0xb	/* Microcontroller Built-In Self Test */#define D_TEST_DUMP	0xe	/* ROM Dump *//* CHI Data Mode */#define D_CDM_THI	(1 << 8)	/* Transmit Data on CHIDR Pin */#define D_CDM_RHI	(1 << 7)	/* Receive Data on CHIDX Pin */#define D_CDM_RCE	(1 << 6)	/* Receive on Rising Edge of CHICK */#define D_CDM_XCE	(1 << 2) /* Transmit Data on Rising Edge of CHICK */#define D_CDM_XEN	(1 << 1)	/* Transmit Highway Enable */#define D_CDM_REN	(1 << 0)	/* Receive Highway Enable *//* The Interrupts */#define D_INTR_BRDY	1	/* Buffer Ready for processing */#define D_INTR_MINT	2	/* Marked Interrupt in RD/TD */#define D_INTR_IBEG	3	/* Flag to idle transition detected (HDLC) */#define D_INTR_IEND	4	/* Idle to flag transition detected (HDLC) */#define D_INTR_EOL	5	/* End of List */#define D_INTR_CMDI	6	/* Command has bean read */#define D_INTR_XCMP	8	/* Transmission of frame complete */#define D_INTR_SBRI	9	/* BRI status change info */#define D_INTR_FXDT	10	/* Fixed data change */#define D_INTR_CHIL	11	/* CHI lost frame sync (channel 36 only) */#define D_INTR_COLL	11	/* Unrecoverable D-Channel collision */#define D_INTR_DBYT	12	/* Dropped by frame slip */#define D_INTR_RBYT	13	/* Repeated by frame slip */#define D_INTR_LINT	14	/* Lost Interrupt */#define D_INTR_UNDR	15	/* DMA underrun */#define D_INTR_TE	32#define D_INTR_NT	34#define D_INTR_CHI	36#define D_INTR_CMD	38#define D_INTR_GETCHAN(v)	(((v) >> 24) & 0x3f)#define D_INTR_GETCODE(v)	(((v) >> 20) & 0xf)#define D_INTR_GETCMD(v)	(((v) >> 16) & 0xf)#define D_INTR_GETVAL(v)	((v) & 0xffff)#define D_INTR_GETRVAL(v)	((v) & 0xfffff)#define D_P_0		0	/* TE receive anchor */#define D_P_1		1	/* TE transmit anchor */#define D_P_2		2	/* NT transmit anchor */#define D_P_3		3	/* NT receive anchor */#define D_P_4		4	/* CHI send data */#define D_P_5		5	/* CHI receive data */#define D_P_6		6	/* */#define D_P_7		7	/* */#define D_P_8		8	/* */#define D_P_9		9	/* */#define D_P_10		10	/* */#define D_P_11		11	/* */#define D_P_12		12	/* */#define D_P_13		13	/* */#define D_P_14		14	/* */#define D_P_15		15	/* */#define D_P_16		16	/* CHI anchor pipe */#define D_P_17		17	/* CHI send */#define D_P_18		18	/* CHI receive */#define D_P_19		19	/* CHI receive */#define D_P_20		20	/* CHI receive */#define D_P_21		21	/* */#define D_P_22		22	/* */#define D_P_23		23	/* */#define D_P_24		24	/* */#define D_P_25		25	/* */#define D_P_26		26	/* */#define D_P_27		27	/* */#define D_P_28		28	/* */#define D_P_29		29	/* */#define D_P_30		30	/* */#define D_P_31		31	/* *//* Transmit descriptor defines */#define DBRI_TD_F	(1 << 31)	/* End of Frame */#define DBRI_TD_D	(1 << 30)	/* Do not append CRC */#define DBRI_TD_CNT(v)	((v) << 16) /* Number of valid bytes in the buffer */#define DBRI_TD_B	(1 << 15)	/* Final interrupt */#define DBRI_TD_M	(1 << 14)	/* Marker interrupt */#define DBRI_TD_I	(1 << 13)	/* Transmit Idle Characters */#define DBRI_TD_FCNT(v)	(v)		/* Flag Count */#define DBRI_TD_UNR	(1 << 3) /* Underrun: transmitter is out of data */#define DBRI_TD_ABT	(1 << 2)	/* Abort: frame aborted */#define DBRI_TD_TBC	(1 << 0)	/* Transmit buffer Complete */#define DBRI_TD_STATUS(v)       ((v) & 0xff)	/* Transmit status */			/* Maximum buffer size per TD: almost 8KB */#define DBRI_TD_MAXCNT	((1 << 13) - 4)/* Receive descriptor defines */#define DBRI_RD_F	(1 << 31)	/* End of Frame */#define DBRI_RD_C	(1 << 30)	/* Completed buffer */#define DBRI_RD_B	(1 << 15)	/* Final interrupt */#define DBRI_RD_M	(1 << 14)	/* Marker interrupt */#define DBRI_RD_BCNT(v)	(v)		/* Buffer size */#define DBRI_RD_CRC	(1 << 7)	/* 0: CRC is correct */#define DBRI_RD_BBC	(1 << 6)	/* 1: Bad Byte received */#define DBRI_RD_ABT	(1 << 5)	/* Abort: frame aborted */#define DBRI_RD_OVRN	(1 << 3)	/* Overrun: data lost */#define DBRI_RD_STATUS(v)      ((v) & 0xff)	/* Receive status */#define DBRI_RD_CNT(v) (((v) >> 16) & 0x1fff)	/* Valid bytes in the buffer *//* stream_info[] access *//* Translate the ALSA direction into the array index */#define DBRI_STREAMNO(substream)				\		(substream->stream ==				\		 SNDRV_PCM_STREAM_PLAYBACK ? DBRI_PLAY: DBRI_REC)/* Return a pointer to dbri_streaminfo */#define DBRI_STREAM(dbri, substream)	\		&dbri->stream_info[DBRI_STREAMNO(substream)]/* * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. * So we have to reverse the bits. Note: not all bit lengths are supported */static __u32 reverse_bytes(__u32 b, int len){	switch (len) {	case 32:		b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);	case 16:		b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8);	case 8:		b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4);	case 4:		b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2);	case 2:		b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);	case 1:	case 0:		break;	default:		printk(KERN_ERR "DBRI reverse_bytes: unsupported length\n");	};	return b;}/******************************************************************************************* DBRI initialization and command synchronization *****************************************************************************************Commands are sent to the DBRI by building a list of them in memory,then writing the address of the first list item to DBRI register 8.The list is terminated with a WAIT command, which generates aCPU interrupt to signal completion.Since the DBRI can run in parallel with the CPU, several means ofsynchronization present themselves. The method implemented here usesthe dbri_cmdwait() to wait for execution of batch of sent commands.A circular command buffer is used here. A new command is being addedwhile another can be executed. The scheme works by adding two WAIT commandsafter each sent batch of commands. When the next batch is prepared it isadded after the WAIT commands then the WAITs are replaced with single JUMPcommand to the new batch. The the DBRI is forced to reread the last WAITcommand (replaced by the JUMP by then). If the DBRI is still executingprevious commands the request to reread the WAIT command is ignored.Every time a routine wants to write commands to the DBRI, it mustfirst call dbri_cmdlock() and get pointer to a free space indbri->dma->cmd buffer. After this, the commands can be written tothe buffer, and dbri_cmdsend() is called with the final pointer valueto send them to the DBRI.*/#define MAXLOOPS 20/* * Wait for the current command string to execute */static void dbri_cmdwait(struct snd_dbri *dbri){	int maxloops = MAXLOOPS;	unsigned long flags;	/* Delay if previous commands are still being processed */	spin_lock_irqsave(&dbri->lock, flags);	while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) {		spin_unlock_irqrestore(&dbri->lock, flags);		msleep_interruptible(1);		spin_lock_irqsave(&dbri->lock, flags);	}	spin_unlock_irqrestore(&dbri->lock, flags);	if (maxloops == 0)		printk(KERN_ERR "DBRI: Chip never completed command buffer\n");	else		dprintk(D_CMD, "Chip completed command buffer (%d)\n",			MAXLOOPS - maxloops - 1);}/* * Lock the command queue and return pointer to space for len cmd words * It locks the cmdlock spinlock. */static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len){	/* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */	len += 2;	spin_lock(&dbri->cmdlock);	if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2)		return dbri->cmdptr + 2;	else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma)		return dbri->dma->cmd;	else		printk(KERN_ERR "DBRI: no space for commands.");	return NULL;}/* * Send prepared cmd string. It works by writing a JUMP cmd into * the last WAIT cmd and force DBRI to reread the cmd. * The JUMP cmd points to the new cmd string. * It also releases the cmdlock spinlock. * * Lock must be held before calling this. */static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len){	s32 tmp, addr;	static int wait_id = 0;	wait_id++;	wait_id &= 0xffff;	/* restrict it to a 16 bit counter. */	*(cmd) = DBRI_CMD(D_WAIT, 1, wait_id);	*(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id);	/* Replace the last command with JUMP */	addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32);	*(dbri->cmdptr+1) = addr;	*(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0);#ifdef DBRI_DEBUG	if (cmd > dbri->cmdptr) {		s32 *ptr;		for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++)			dprintk(D_CMD, "cmd: %lx:%08x\n",				(unsigned long)ptr, *ptr);	} else {		s32 *ptr = dbri->cmdptr;		dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);		ptr++;		dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);		for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++)			dprintk(D_CMD, "cmd: %lx:%08x\n",				(unsigned long)ptr, *ptr);	}#endif	/* Reread the last command */	tmp = sbus_readl(dbri->regs + REG0);	tmp |= D_P;	sbus_writel(tmp, dbri->regs + REG0);	dbri->cmdptr = cmd;	spin_unlock(&dbri->cmdlock);}/* Lock must be held when calling this */static void dbri_reset(struct snd_dbri *dbri){	int i;	u32 tmp;	dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n",		sbus_readl(dbri->regs + REG0),		sbus_readl(dbri->regs + REG2),		sbus_readl(dbri->regs + REG8), sbus_readl(dbri->regs + REG9));	sbus_writel(D_R, dbri->regs + REG0);	/* Soft Reset */	for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)		udelay(10);	/* A brute approach - DBRI falls back to working burst size by itself	 * On SS20 D_S does not work, so do not try so high. */	tmp = sbus_readl(dbri->regs + REG0);	tmp |= D_G | D_E;	tmp &= ~D_S;	sbus_writel(tmp, dbri->regs + REG0);}/* Lock must not be held before calling this */static void __devinit dbri_initialize(struct snd_dbri *dbri){	s32 *cmd;	u32 dma_addr;	unsigned long flags;	int n;	spin_lock_irqsave(&dbri->lock, flags);	dbri_reset(dbri);	/* Initialize pipes */	for (n = 0; n < DBRI_NO_PIPES; n++)		dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;	spin_lock_init(&dbri->cmdlock);	/*	 * Initialize the interrupt ring buffer.	 */	dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);	dbri->dma->intr[0] = dma_addr;	dbri->dbri_irqp = 1;	/*	 * Set up the interrupt queue	 */	spin_lock(&dbri->cmdlock);	cmd = dbri->cmdptr = dbri->dma->cmd;	*(cmd++) = DBRI_CMD(D_IIQ, 0, 0);	*(cmd++) = dma_addr;	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	dbri->cmdptr = cmd;	*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);	*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);	dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0);	sbus_writel(dma_addr, dbri->regs + REG8);	spin_unlock(&dbri->cmdlock);	spin_unlock_irqrestore(&dbri->lock, flags);	dbri_cmdwait(dbri);}/******************************************************************************************************* DBRI data pipe management ***************************************************************************************************While DBRI control functions use the command and interrupt buffers, themain data path takes the form of data pipes, which can be short (commandand interrupt driven), or long (attached to DMA buffers).  These functionsprovide a rudimentary means of setting up and managing the DBRI's pipes,but the calling functions have to make sure they respect the pipes' linkedlist ordering, among other things.  The transmit and receive functionshere interface closely with the transmit and receive interrupt code.*/static inline int pipe_active(struct snd_dbri *dbri, int pipe){	return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1));}/* reset_pipe(dbri, pipe) * * Called on an in-use pipe to clear anything being transmitted or received * Lock must be held before calling this. */static void reset_pipe(struct snd_dbri *dbri, int pipe){	int sdp;	int desc;	s32 *cmd;	if (pipe < 0 || pipe > DBRI_MAX_PIPE) {		printk(KERN_ERR "DBRI: reset_pipe called with "			"illegal pipe number\n");		return;	}	sdp = dbri->pipes[pipe].sdp;	if (sdp == 0) {		printk(KERN_ERR "DBRI: reset_pipe called "			"on uninitialized pipe\n");		return;	}	cmd = dbri_cmdlock(dbri, 3);	*(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);	*(cmd++) = 0;	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	dbri_cmdsend(dbri, cmd, 3);	desc = dbri->pipes[pipe].first_desc;	if (desc >= 0)		do {			dbri->dma->desc[desc].ba = 0;			dbri->dma->desc[desc].nda = 0;			desc = dbri->next_desc[desc];		} while (desc != -1 && desc != dbri->pipes[pipe].first_desc);	dbri->pipes[pipe].desc = -1;	dbri->pipes[pipe].first_desc = -1;}/* * Lock must be held before calling this. */static void setup_pipe(struct snd_dbri *dbri, int pipe, int sdp){	if (pipe < 0 || pipe > DBRI_MAX_PIPE) {		printk(KERN_ERR "DBRI: setup_pipe called "			"with illegal pipe number\n");		return;

⌨️ 快捷键说明

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