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

📄 dbri.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	if ((sdp & 0xf800) != sdp) {		printk(KERN_ERR "DBRI: setup_pipe called "			"with strange SDP value\n");		/* sdp &= 0xf800; */	}	/* If this is a fixed receive pipe, arrange for an interrupt	 * every time its data changes	 */	if (D_SDP_MODE(sdp) == D_SDP_FIXED && !(sdp & D_SDP_TO_SER))		sdp |= D_SDP_CHANGE;	sdp |= D_PIPE(pipe);	dbri->pipes[pipe].sdp = sdp;	dbri->pipes[pipe].desc = -1;	dbri->pipes[pipe].first_desc = -1;	reset_pipe(dbri, pipe);}/* * Lock must be held before calling this. */static void link_time_slot(struct snd_dbri *dbri, int pipe,			   int prevpipe, int nextpipe,			   int length, int cycle){	s32 *cmd;	int val;	if (pipe < 0 || pipe > DBRI_MAX_PIPE			|| prevpipe < 0 || prevpipe > DBRI_MAX_PIPE			|| nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {		printk(KERN_ERR		    "DBRI: link_time_slot called with illegal pipe number\n");		return;	}	if (dbri->pipes[pipe].sdp == 0			|| dbri->pipes[prevpipe].sdp == 0			|| dbri->pipes[nextpipe].sdp == 0) {		printk(KERN_ERR "DBRI: link_time_slot called "			"on uninitialized pipe\n");		return;	}	dbri->pipes[prevpipe].nextpipe = pipe;	dbri->pipes[pipe].nextpipe = nextpipe;	dbri->pipes[pipe].length = length;	cmd = dbri_cmdlock(dbri, 4);	if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {		/* Deal with CHI special case:		 * "If transmission on edges 0 or 1 is desired, then cycle n		 *  (where n = # of bit times per frame...) must be used."		 *                  - DBRI data sheet, page 11		 */		if (prevpipe == 16 && cycle == 0)			cycle = dbri->chi_bpf;		val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;		*(cmd++) = DBRI_CMD(D_DTS, 0, val);		*(cmd++) = 0;		*(cmd++) =		    D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);	} else {		val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;		*(cmd++) = DBRI_CMD(D_DTS, 0, val);		*(cmd++) =		    D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);		*(cmd++) = 0;	}	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	dbri_cmdsend(dbri, cmd, 4);}#if 0/* * Lock must be held before calling this. */static void unlink_time_slot(struct snd_dbri *dbri, int pipe,			     enum in_or_out direction, int prevpipe,			     int nextpipe){	s32 *cmd;	int val;	if (pipe < 0 || pipe > DBRI_MAX_PIPE			|| prevpipe < 0 || prevpipe > DBRI_MAX_PIPE			|| nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {		printk(KERN_ERR		    "DBRI: unlink_time_slot called with illegal pipe number\n");		return;	}	cmd = dbri_cmdlock(dbri, 4);	if (direction == PIPEinput) {		val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;		*(cmd++) = DBRI_CMD(D_DTS, 0, val);		*(cmd++) = D_TS_NEXT(nextpipe);		*(cmd++) = 0;	} else {		val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;		*(cmd++) = DBRI_CMD(D_DTS, 0, val);		*(cmd++) = 0;		*(cmd++) = D_TS_NEXT(nextpipe);	}	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	dbri_cmdsend(dbri, cmd, 4);}#endif/* xmit_fixed() / recv_fixed() * * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not * expected to change much, and which we don't need to buffer. * The DBRI only interrupts us when the data changes (receive pipes), * or only changes the data when this function is called (transmit pipes). * Only short pipes (numbers 16-31) can be used in fixed data mode. * * These function operate on a 32-bit field, no matter how large * the actual time slot is.  The interrupt handler takes care of bit * ordering and alignment.  An 8-bit time slot will always end up * in the low-order 8 bits, filled either MSB-first or LSB-first, * depending on the settings passed to setup_pipe(). * * Lock must not be held before calling it. */static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data){	s32 *cmd;	unsigned long flags;	if (pipe < 16 || pipe > DBRI_MAX_PIPE) {		printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n");		return;	}	if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) {		printk(KERN_ERR "DBRI: xmit_fixed: "			"Uninitialized pipe %d\n", pipe);		return;	}	if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {		printk(KERN_ERR "DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe);		return;	}	if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) {		printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n",			pipe);		return;	}	/* DBRI short pipes always transmit LSB first */	if (dbri->pipes[pipe].sdp & D_SDP_MSB)		data = reverse_bytes(data, dbri->pipes[pipe].length);	cmd = dbri_cmdlock(dbri, 3);	*(cmd++) = DBRI_CMD(D_SSP, 0, pipe);	*(cmd++) = data;	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	spin_lock_irqsave(&dbri->lock, flags);	dbri_cmdsend(dbri, cmd, 3);	spin_unlock_irqrestore(&dbri->lock, flags);	dbri_cmdwait(dbri);}static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr){	if (pipe < 16 || pipe > DBRI_MAX_PIPE) {		printk(KERN_ERR "DBRI: recv_fixed called with "			"illegal pipe number\n");		return;	}	if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {		printk(KERN_ERR "DBRI: recv_fixed called on "			"non-fixed pipe %d\n", pipe);		return;	}	if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {		printk(KERN_ERR "DBRI: recv_fixed called on "			"transmit pipe %d\n", pipe);		return;	}	dbri->pipes[pipe].recv_fixed_ptr = ptr;}/* setup_descs() * * Setup transmit/receive data on a "long" pipe - i.e, one associated * with a DMA buffer. * * Only pipe numbers 0-15 can be used in this mode. * * This function takes a stream number pointing to a data buffer, * and work by building chains of descriptors which identify the * data buffers.  Buffers too large for a single descriptor will * be spread across multiple descriptors. * * All descriptors create a ring buffer. * * Lock must be held before calling this. */static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period){	struct dbri_streaminfo *info = &dbri->stream_info[streamno];	__u32 dvma_buffer;	int desc;	int len;	int first_desc = -1;	int last_desc = -1;	if (info->pipe < 0 || info->pipe > 15) {		printk(KERN_ERR "DBRI: setup_descs: Illegal pipe number\n");		return -2;	}	if (dbri->pipes[info->pipe].sdp == 0) {		printk(KERN_ERR "DBRI: setup_descs: Uninitialized pipe %d\n",		       info->pipe);		return -2;	}	dvma_buffer = info->dvma_buffer;	len = info->size;	if (streamno == DBRI_PLAY) {		if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) {			printk(KERN_ERR "DBRI: setup_descs: "				"Called on receive pipe %d\n", info->pipe);			return -2;		}	} else {		if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) {			printk(KERN_ERR			    "DBRI: setup_descs: Called on transmit pipe %d\n",			     info->pipe);			return -2;		}		/* Should be able to queue multiple buffers		 * to receive on a pipe		 */		if (pipe_active(dbri, info->pipe)) {			printk(KERN_ERR "DBRI: recv_on_pipe: "				"Called on active pipe %d\n", info->pipe);			return -2;		}		/* Make sure buffer size is multiple of four */		len &= ~3;	}	/* Free descriptors if pipe has any */	desc = dbri->pipes[info->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[info->pipe].first_desc);	dbri->pipes[info->pipe].desc = -1;	dbri->pipes[info->pipe].first_desc = -1;	desc = 0;	while (len > 0) {		int mylen;		for (; desc < DBRI_NO_DESCS; desc++) {			if (!dbri->dma->desc[desc].ba)				break;		}		if (desc == DBRI_NO_DESCS) {			printk(KERN_ERR "DBRI: setup_descs: No descriptors\n");			return -1;		}		if (len > DBRI_TD_MAXCNT)			mylen = DBRI_TD_MAXCNT;	/* 8KB - 4 */		else			mylen = len;		if (mylen > period)			mylen = period;		dbri->next_desc[desc] = -1;		dbri->dma->desc[desc].ba = dvma_buffer;		dbri->dma->desc[desc].nda = 0;		if (streamno == DBRI_PLAY) {			dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen);			dbri->dma->desc[desc].word4 = 0;			dbri->dma->desc[desc].word1 |= DBRI_TD_F | DBRI_TD_B;		} else {			dbri->dma->desc[desc].word1 = 0;			dbri->dma->desc[desc].word4 =			    DBRI_RD_B | DBRI_RD_BCNT(mylen);		}		if (first_desc == -1)			first_desc = desc;		else {			dbri->next_desc[last_desc] = desc;			dbri->dma->desc[last_desc].nda =			    dbri->dma_dvma + dbri_dma_off(desc, desc);		}		last_desc = desc;		dvma_buffer += mylen;		len -= mylen;	}	if (first_desc == -1 || last_desc == -1) {		printk(KERN_ERR "DBRI: setup_descs: "			" Not enough descriptors available\n");		return -1;	}	dbri->dma->desc[last_desc].nda =	    dbri->dma_dvma + dbri_dma_off(desc, first_desc);	dbri->next_desc[last_desc] = first_desc;	dbri->pipes[info->pipe].first_desc = first_desc;	dbri->pipes[info->pipe].desc = first_desc;#ifdef DBRI_DEBUG	for (desc = first_desc; desc != -1;) {		dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n",			desc,			dbri->dma->desc[desc].word1,			dbri->dma->desc[desc].ba,			dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4);			desc = dbri->next_desc[desc];			if (desc == first_desc)				break;	}#endif	return 0;}/******************************************************************************************************* DBRI - CHI interface ********************************************************************************************************The CHI is a four-wire (clock, frame sync, data in, data out) time-divisionmultiplexed serial interface which the DBRI can operate in either master(give clock/frame sync) or slave (take clock/frame sync) mode.*/enum master_or_slave { CHImaster, CHIslave };/* * Lock must not be held before calling it. */static void reset_chi(struct snd_dbri *dbri,		      enum master_or_slave master_or_slave,		      int bits_per_frame){	s32 *cmd;	int val;	/* Set CHI Anchor: Pipe 16 */	cmd = dbri_cmdlock(dbri, 4);	val = D_DTS_VO | D_DTS_VI | D_DTS_INS		| D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16);	*(cmd++) = DBRI_CMD(D_DTS, 0, val);	*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);	*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	dbri_cmdsend(dbri, cmd, 4);	dbri->pipes[16].sdp = 1;	dbri->pipes[16].nextpipe = 16;	cmd = dbri_cmdlock(dbri, 4);	if (master_or_slave == CHIslave) {		/* Setup DBRI for CHI Slave - receive clock, frame sync (FS)		 *		 * CHICM  = 0 (slave mode, 8 kHz frame rate)		 * IR     = give immediate CHI status interrupt		 * EN     = give CHI status interrupt upon change		 */		*(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));	} else {		/* Setup DBRI for CHI Master - generate clock, FS		 *		 * BPF				=  bits per 8 kHz frame		 * 12.288 MHz / CHICM_divisor	= clock rate		 * FD = 1 - drive CHIFS on rising edge of CHICK		 */		int clockrate = bits_per_frame * 8;		int divisor = 12288 / clockrate;		if (divisor > 255 || divisor * clockrate != 12288)			printk(KERN_ERR "DBRI: illegal bits_per_frame "				"in setup_chi\n");		*(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD				    | D_CHI_BPF(bits_per_frame));	}	dbri->chi_bpf = bits_per_frame;	/* CHI Data Mode	 *	 * RCE   =  0 - receive on falling edge of CHICK	 * XCE   =  1 - transmit on rising edge of CHICK	 * XEN   =  1 - enable transmitter

⌨️ 快捷键说明

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