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

📄 dbri.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* Stream could be closed by the time we run. */		if (first_td >= 0) {			cmd = dbri_cmdlock(dbri, 2);			*(cmd++) = DBRI_CMD(D_SDP, 0,					    dbri->pipes[info->pipe].sdp					    | D_SDP_P | D_SDP_EVERY | D_SDP_C);			*(cmd++) = dbri->dma_dvma +				   dbri_dma_off(desc, first_td);			dbri_cmdsend(dbri, cmd, 2);			/* Reset our admin of the pipe. */			dbri->pipes[info->pipe].desc = first_td;		}	}	info = &dbri->stream_info[DBRI_PLAY];	if (info->pipe >= 0) {		first_td = dbri->pipes[info->pipe].first_desc;		dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td);		/* Stream could be closed by the time we run. */		if (first_td >= 0) {			cmd = dbri_cmdlock(dbri, 2);			*(cmd++) = DBRI_CMD(D_SDP, 0,					    dbri->pipes[info->pipe].sdp					    | D_SDP_P | D_SDP_EVERY | D_SDP_C);			*(cmd++) = dbri->dma_dvma +				   dbri_dma_off(desc, first_td);			dbri_cmdsend(dbri, cmd, 2);			/* Reset our admin of the pipe. */			dbri->pipes[info->pipe].desc = first_td;		}	}	spin_unlock_irqrestore(&dbri->lock, flags);}/* transmission_complete_intr() * * Called by main interrupt handler when DBRI signals transmission complete * on a pipe (interrupt triggered by the B bit in a transmit descriptor). * * Walks through the pipe's list of transmit buffer descriptors and marks * them as available. Stops when the first descriptor is found without * TBC (Transmit Buffer Complete) set, or we've run through them all. * * The DMA buffers are not released. They form a ring buffer and * they are filled by ALSA while others are transmitted by DMA. * */static void transmission_complete_intr(struct snd_dbri *dbri, int pipe){	struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];	int td = dbri->pipes[pipe].desc;	int status;	while (td >= 0) {		if (td >= DBRI_NO_DESCS) {			printk(KERN_ERR "DBRI: invalid td on pipe %d\n", pipe);			return;		}		status = DBRI_TD_STATUS(dbri->dma->desc[td].word4);		if (!(status & DBRI_TD_TBC))			break;		dprintk(D_INT, "TD %d, status 0x%02x\n", td, status);		dbri->dma->desc[td].word4 = 0;	/* Reset it for next time. */		info->offset += DBRI_RD_CNT(dbri->dma->desc[td].word1);		td = dbri->next_desc[td];		dbri->pipes[pipe].desc = td;	}	/* Notify ALSA */	spin_unlock(&dbri->lock);	snd_pcm_period_elapsed(info->substream);	spin_lock(&dbri->lock);}static void reception_complete_intr(struct snd_dbri *dbri, int pipe){	struct dbri_streaminfo *info;	int rd = dbri->pipes[pipe].desc;	s32 status;	if (rd < 0 || rd >= DBRI_NO_DESCS) {		printk(KERN_ERR "DBRI: invalid rd on pipe %d\n", pipe);		return;	}	dbri->pipes[pipe].desc = dbri->next_desc[rd];	status = dbri->dma->desc[rd].word1;	dbri->dma->desc[rd].word1 = 0;	/* Reset it for next time. */	info = &dbri->stream_info[DBRI_REC];	info->offset += DBRI_RD_CNT(status);	/* FIXME: Check status */	dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n",		rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));	/* Notify ALSA */	spin_unlock(&dbri->lock);	snd_pcm_period_elapsed(info->substream);	spin_lock(&dbri->lock);}static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x){	int val = D_INTR_GETVAL(x);	int channel = D_INTR_GETCHAN(x);	int command = D_INTR_GETCMD(x);	int code = D_INTR_GETCODE(x);#ifdef DBRI_DEBUG	int rval = D_INTR_GETRVAL(x);#endif	if (channel == D_INTR_CMD) {		dprintk(D_CMD, "INTR: Command: %-5s  Value:%d\n",			cmds[command], val);	} else {		dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n",			channel, code, rval);	}	switch (code) {	case D_INTR_CMDI:		if (command != D_WAIT)			printk(KERN_ERR "DBRI: Command read interrupt\n");		break;	case D_INTR_BRDY:		reception_complete_intr(dbri, channel);		break;	case D_INTR_XCMP:	case D_INTR_MINT:		transmission_complete_intr(dbri, channel);		break;	case D_INTR_UNDR:		/* UNDR - Transmission underrun		 * resend SDP command with clear pipe bit (C) set		 */		{	/* FIXME: do something useful in case of underrun */			printk(KERN_ERR "DBRI: Underrun error\n");#if 0			s32 *cmd;			int pipe = channel;			int td = dbri->pipes[pipe].desc;			dbri->dma->desc[td].word4 = 0;			cmd = dbri_cmdlock(dbri, NoGetLock);			*(cmd++) = DBRI_CMD(D_SDP, 0,					    dbri->pipes[pipe].sdp					    | D_SDP_P | D_SDP_C | D_SDP_2SAME);			*(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td);			dbri_cmdsend(dbri, cmd);#endif		}		break;	case D_INTR_FXDT:		/* FXDT - Fixed data change */		if (dbri->pipes[channel].sdp & D_SDP_MSB)			val = reverse_bytes(val, dbri->pipes[channel].length);		if (dbri->pipes[channel].recv_fixed_ptr)			*(dbri->pipes[channel].recv_fixed_ptr) = val;		break;	default:		if (channel != D_INTR_CMD)			printk(KERN_WARNING			       "DBRI: Ignored Interrupt: %d (0x%x)\n", code, x);	}}/* dbri_process_interrupt_buffer advances through the DBRI's interrupt * buffer until it finds a zero word (indicating nothing more to do * right now).  Non-zero words require processing and are handed off * to dbri_process_one_interrupt AFTER advancing the pointer. */static void dbri_process_interrupt_buffer(struct snd_dbri *dbri){	s32 x;	while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {		dbri->dma->intr[dbri->dbri_irqp] = 0;		dbri->dbri_irqp++;		if (dbri->dbri_irqp == DBRI_INT_BLK)			dbri->dbri_irqp = 1;		dbri_process_one_interrupt(dbri, x);	}}static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id){	struct snd_dbri *dbri = dev_id;	static int errcnt = 0;	int x;	if (dbri == NULL)		return IRQ_NONE;	spin_lock(&dbri->lock);	/*	 * Read it, so the interrupt goes away.	 */	x = sbus_readl(dbri->regs + REG1);	if (x & (D_MRR | D_MLE | D_LBG | D_MBE)) {		u32 tmp;		if (x & D_MRR)			printk(KERN_ERR			       "DBRI: Multiple Error Ack on SBus reg1=0x%x\n",			       x);		if (x & D_MLE)			printk(KERN_ERR			       "DBRI: Multiple Late Error on SBus reg1=0x%x\n",			       x);		if (x & D_LBG)			printk(KERN_ERR			       "DBRI: Lost Bus Grant on SBus reg1=0x%x\n", x);		if (x & D_MBE)			printk(KERN_ERR			       "DBRI: Burst Error on SBus reg1=0x%x\n", x);		/* Some of these SBus errors cause the chip's SBus circuitry		 * to be disabled, so just re-enable and try to keep going.		 *		 * The only one I've seen is MRR, which will be triggered		 * if you let a transmit pipe underrun, then try to CDP it.		 *		 * If these things persist, we reset the chip.		 */		if ((++errcnt) % 10 == 0) {			dprintk(D_INT, "Interrupt errors exceeded.\n");			dbri_reset(dbri);		} else {			tmp = sbus_readl(dbri->regs + REG0);			tmp &= ~(D_D);			sbus_writel(tmp, dbri->regs + REG0);		}	}	dbri_process_interrupt_buffer(dbri);	spin_unlock(&dbri->lock);	return IRQ_HANDLED;}/****************************************************************************		PCM Interface****************************************************************************/static struct snd_pcm_hardware snd_dbri_pcm_hw = {	.info		= SNDRV_PCM_INFO_MMAP |			  SNDRV_PCM_INFO_INTERLEAVED |			  SNDRV_PCM_INFO_BLOCK_TRANSFER |			  SNDRV_PCM_INFO_MMAP_VALID,	.formats	= SNDRV_PCM_FMTBIT_MU_LAW |			  SNDRV_PCM_FMTBIT_A_LAW |			  SNDRV_PCM_FMTBIT_U8 |			  SNDRV_PCM_FMTBIT_S16_BE,	.rates		= SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512,	.rate_min		= 5512,	.rate_max		= 48000,	.channels_min		= 1,	.channels_max		= 2,	.buffer_bytes_max	= 64 * 1024,	.period_bytes_min	= 1,	.period_bytes_max	= DBRI_TD_MAXCNT,	.periods_min		= 1,	.periods_max		= 1024,};static int snd_hw_rule_format(struct snd_pcm_hw_params *params,			      struct snd_pcm_hw_rule *rule){	struct snd_interval *c = hw_param_interval(params,				SNDRV_PCM_HW_PARAM_CHANNELS);	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);	struct snd_mask fmt;	snd_mask_any(&fmt);	if (c->min > 1) {		fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_BE;		return snd_mask_refine(f, &fmt);	}	return 0;}static int snd_hw_rule_channels(struct snd_pcm_hw_params *params,				struct snd_pcm_hw_rule *rule){	struct snd_interval *c = hw_param_interval(params,				SNDRV_PCM_HW_PARAM_CHANNELS);	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);	struct snd_interval ch;	snd_interval_any(&ch);	if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) {		ch.min = 1;		ch.max = 1;		ch.integer = 1;		return snd_interval_refine(c, &ch);	}	return 0;}static int snd_dbri_open(struct snd_pcm_substream *substream){	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);	unsigned long flags;	dprintk(D_USR, "open audio output.\n");	runtime->hw = snd_dbri_pcm_hw;	spin_lock_irqsave(&dbri->lock, flags);	info->substream = substream;	info->offset = 0;	info->dvma_buffer = 0;	info->pipe = -1;	spin_unlock_irqrestore(&dbri->lock, flags);	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,			    snd_hw_rule_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT,			    -1);	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,			    snd_hw_rule_channels, NULL,			    SNDRV_PCM_HW_PARAM_CHANNELS,			    -1);	cs4215_open(dbri);	return 0;}static int snd_dbri_close(struct snd_pcm_substream *substream){	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);	dprintk(D_USR, "close audio output.\n");	info->substream = NULL;	info->offset = 0;	return 0;}static int snd_dbri_hw_params(struct snd_pcm_substream *substream,			      struct snd_pcm_hw_params *hw_params){	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);	int direction;	int ret;	/* set sampling rate, audio format and number of channels */	ret = cs4215_prepare(dbri, params_rate(hw_params),			     params_format(hw_params),			     params_channels(hw_params));	if (ret != 0)		return ret;	if ((ret = snd_pcm_lib_malloc_pages(substream,				params_buffer_bytes(hw_params))) < 0) {		printk(KERN_ERR "malloc_pages failed with %d\n", ret);		return ret;	}	/* hw_params can get called multiple times. Only map the DMA once.	 */	if (info->dvma_buffer == 0) {		if (DBRI_STREAMNO(substream) == DBRI_PLAY)			direction = SBUS_DMA_TODEVICE;		else			direction = SBUS_DMA_FROMDEVICE;		info->dvma_buffer = sbus_map_single(dbri->sdev,					runtime->dma_area,					params_buffer_bytes(hw_params),					direction);	}	direction = params_buffer_bytes(hw_params);	dprintk(D_USR, "hw_params: %d bytes, dvma=%x\n",		direction, info->dvma_buffer);	return 0;}static int snd_dbri_hw_free(struct snd_pcm_substream *substream){	struct snd_dbri *dbri = snd_pcm_substream_chip(substream);	struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream);	int direction;	dprintk(D_USR, "hw_free.\n");	/* hw_free can get called multiple times. Only unmap the DMA once.	 */	if (info->dvma_buffer) {		if (DBRI_STREAMNO(substream) == DBRI_PLAY)			direction = SBUS_DMA_TODEVICE;		else			direction = SBUS_DMA_FROMDEVICE;		sbus_unmap_single(dbri->sdev, info->dvma_buffer,				  substream->runtime->buffer_size, direction);		info->dvma_buffer = 0;	}	if (info->pipe != -1) {		reset_pipe(dbri, info->pipe);		info->pipe = -1;	}

⌨️ 快捷键说明

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