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

📄 dbri.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
                        first_td = td;                } else {                        dbri->descs[last_td].next = td;                        dbri->dma->desc[last_td].nda =                                dbri->dma_dvma + dbri_dma_off(desc, td);                }                last_td = td;                dvma_buffer += mylen;                len -= mylen;        }	if (first_td == -1 || last_td == -1) {		sbus_unmap_single(dbri->sdev, dvma_buffer_base,				  dvma_buffer - dvma_buffer_base + len,				  SBUS_DMA_TODEVICE);                return;        }        dbri->dma->desc[last_td].word1 |= DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;        dbri->descs[last_td].buffer = buffer;        dbri->descs[last_td].buffer_dvma = dvma_buffer_base;        dbri->descs[last_td].len = dvma_buffer - dvma_buffer_base + len;        dbri->descs[last_td].output_callback = callback;        dbri->descs[last_td].output_callback_arg = callback_arg;	for (td=first_td; td != -1; td = dbri->descs[td].next) {		dprintk(D_DESC, ("DBRI TD %d: %08x %08x %08x %08x\n",				 td,				 dbri->dma->desc[td].word1,				 dbri->dma->desc[td].ba,				 dbri->dma->desc[td].nda,				 dbri->dma->desc[td].word4));	}	save_and_cli(flags);	if (pipe_active(dbri, pipe)) {		/* Pipe is already active - find last TD in use		 * and link our first TD onto its end.  Then issue		 * a CDP command to let the DBRI know there's more data.		 */		last_td = dbri->pipes[pipe].desc;		while (dbri->descs[last_td].next != -1)			last_td = dbri->descs[last_td].next;		dbri->descs[last_td].next = first_td;		dbri->dma->desc[last_td].nda =                        dbri->dma_dvma + dbri_dma_off(desc, first_td);		cmd = dbri_cmdlock(dbri);		*(cmd++) = DBRI_CMD(D_CDP, 0, pipe);		dbri_cmdsend(dbri,cmd);	} else {		/* Pipe isn't active - issue an SDP command to start		 * our chain of TDs running.		 */		dbri->pipes[pipe].desc = first_td;		cmd = dbri_cmdlock(dbri);		*(cmd++) = DBRI_CMD(D_SDP, 0,				    dbri->pipes[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);	}	restore_flags(flags);}static void recv_on_pipe(struct dbri *dbri, int pipe,                         void * buffer, unsigned int len,                         void (*callback)(void *, int, unsigned int),                         void * callback_arg){        volatile s32 *cmd;	int first_rd = -1;	int last_rd = -1;        int rd;	__u32 bus_buffer, bus_buffer_base;        if (pipe < 0 || pipe > 15) {		printk("DBRI: recv_on_pipe: Illegal pipe number\n");                return;        }        if (dbri->pipes[pipe].sdp == 0) {		printk("DBRI: recv_on_pipe: Uninitialized pipe %d\n", pipe);                return;        }        if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {		printk("DBRI: recv_on_pipe: Called on transmit pipe %d\n",		       pipe);                return;        }        /* XXX Fix this XXX	 * Should be able to queue multiple buffers to receive on a pipe         */        if (dbri->pipes[pipe].desc != -1) {		printk("DBRI: recv_on_pipe: Called on active pipe %d\n", pipe);                return;        }        /* Make sure buffer size is multiple of four */        len &= ~3;        bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len,						       SBUS_DMA_FROMDEVICE);	while (len > 0) {		int rd, mylen;		if (len > ((1 << 13) - 4)) {			mylen = (1 << 13) - 4;		} else {			mylen = len;		}		for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {			if (! dbri->descs[rd].inuse)                                break;		}		if (rd == DBRI_NO_DESCS) {			printk("DBRI recv_on_pipe: No descriptors\n");			break;		}		dbri->dma->desc[rd].word1 = 0;		dbri->dma->desc[rd].ba = bus_buffer;		dbri->dma->desc[rd].nda = 0;		dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(mylen);		dbri->descs[rd].buffer = NULL;		dbri->descs[rd].len = 0;		dbri->descs[rd].input_callback = NULL;		dbri->descs[rd].output_callback = NULL;		dbri->descs[rd].next = -1;		dbri->descs[rd].inuse = 1;		if (first_rd == -1) first_rd = rd;		if (last_rd != -1) {			dbri->dma->desc[last_rd].nda =                                dbri->dma_dvma + dbri_dma_off(desc, rd);			dbri->descs[last_rd].next = rd;		}		last_rd = rd;		bus_buffer += mylen;		len -= mylen;        }	if (last_rd == -1 || first_rd == -1) {		sbus_unmap_single(dbri->sdev, bus_buffer_base,				  bus_buffer - bus_buffer_base + len,				  SBUS_DMA_FROMDEVICE);                return;	}	for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) {		dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n",				 rd,				 dbri->dma->desc[rd].word1,				 dbri->dma->desc[rd].ba,				 dbri->dma->desc[rd].nda,				 dbri->dma->desc[rd].word4));	}	dbri->descs[last_rd].buffer = buffer;        dbri->descs[last_rd].buffer_dvma = bus_buffer_base;	dbri->descs[last_rd].len = bus_buffer - bus_buffer_base + len;	dbri->descs[last_rd].input_callback = callback;	dbri->descs[last_rd].input_callback_arg = callback_arg;	dbri->pipes[pipe].desc = first_rd;        cmd = dbri_cmdlock(dbri);	*(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);        *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_rd);        dbri_cmdsend(dbri, cmd);}/******************************************************************************************************* 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 };static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,		      int bits_per_frame){	volatile s32 *cmd;	int val;	static int chi_initialized = 0;	if (!chi_initialized) {		cmd = dbri_cmdlock(dbri);		/* Set CHI Anchor: Pipe 16 */		val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);		*(cmd++) = DBRI_CMD(D_DTS, 0, val);		*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);		*(cmd++) = 0;		val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);		*(cmd++) = DBRI_CMD(D_DTS, 0, val);		*(cmd++) = 0;		*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);		dbri->pipes[16].sdp = 1;		dbri->pipes[16].nextpipe = 16;		dbri->chi_in_pipe = 16;		dbri->chi_out_pipe = 16;#if 0		chi_initialized ++;#endif	} else {		int pipe;		for (pipe = dbri->chi_in_pipe;		     pipe != 16;		     pipe = dbri->pipes[pipe].nextpipe) {			unlink_time_slot(dbri, pipe, PIPEinput,					 16, dbri->pipes[pipe].nextpipe);		}		for (pipe = dbri->chi_out_pipe;		     pipe != 16;		     pipe = dbri->pipes[pipe].nextpipe) {			unlink_time_slot(dbri, pipe, PIPEoutput,					 16, dbri->pipes[pipe].nextpipe);		}		dbri->chi_in_pipe = 16;		dbri->chi_out_pipe = 16;		cmd = dbri_cmdlock(dbri);	}	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("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	 * REN   =  1 - enable receiver	 */	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	*(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);	dbri_cmdsend(dbri, cmd);}/**************************************************************************************************** CS4215 audio codec management **************************************************************************************************In the standard SPARC audio configuration, the CS4215 codec is attachedto the DBRI via the CHI interface and few of the DBRI's PIO pins.*/static void mmcodec_default(struct cs4215 *mm){	/*	 * No action, memory resetting only.	 *	 * Data Time Slot 5-8	 * Speaker,Line and Headphone enable. Gain set to the half.	 * Input is mike.	 */	mm->data[0] = CS4215_LO(0x20) | CS4215_HE|CS4215_LE;	mm->data[1] = CS4215_RO(0x20) | CS4215_SE;	mm->data[2] = CS4215_LG( 0x8) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1;	mm->data[3] = CS4215_RG( 0x8) | CS4215_MA(0xf);	/*	 * Control Time Slot 1-4	 * 0: Default I/O voltage scale	 * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled	 * 2: Serial enable, CHI master, 128 bits per frame, clock 1	 * 3: Tests disabled	 */	mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;	mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;	mm->ctrl[2] = CS4215_XCLK |			CS4215_BSEL_128 | CS4215_FREQ[0].xtal;	mm->ctrl[3] = 0;}static void mmcodec_setup_pipes(struct dbri *dbri){	/*	 * Data mode:	 * Pipe  4: Send timeslots 1-4 (audio data)	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)	 * Pipe  6: Receive timeslots 1-4 (audio data)	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via	 *          interrupt, and the rest of the data (slot 5 and 8) is	 *	    not relevant for us (only for doublechecking).	 *	 * Control mode:	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)	 * Pipe 18: Receive timeslot 1 (clb).	 * Pipe 19: Receive timeslot 7 (version). 	 */	setup_pipe(dbri,  4, D_SDP_MEM   | D_SDP_TO_SER | D_SDP_MSB);	setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);	setup_pipe(dbri,  6, D_SDP_MEM   | D_SDP_FROM_SER | D_SDP_MSB);	setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);	setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER   | D_SDP_MSB);	setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);	setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);	dbri->mm.status = 0;	recv_fixed(dbri, 18, & dbri->mm.status);	recv_fixed(dbri, 19, & dbri->mm.version);}static void mmcodec_setgain(struct dbri *dbri, int muted){	if (muted || dbri->perchip_info.output_muted) {		dbri->mm.data[0] = 63;		dbri->mm.data[1] = 63;	} else {		int left_gain = (dbri->perchip_info.play.gain / 4) % 64;		int right_gain = (dbri->perchip_info.play.gain / 4) % 64;		int outport = dbri->perchip_info.play.port;		if (dbri->perchip_info.play.balance < AUDIO_MID_BALANCE) {			right_gain *= dbri->perchip_info.play.balance;			right_gain /= AUDIO_MID_BALANCE;		} else {			left_gain *= AUDIO_RIGHT_BALANCE				- dbri->perchip_info.play.balance;			left_gain /= AUDIO_MID_BALANCE;		}		dprintk(D_MM, ("DBRI: Setting codec gain left: %d right: %d\n",			       left_gain, right_gain));		dbri->mm.data[0] = (63 - left_gain);		if (outport & AUDIO_HEADPHONE) dbri->mm.data[0] |= CS4215_HE;		if (outport & AUDIO_LINE_OUT)  dbri->mm.data[0] |= CS4215_LE;		dbri->mm.data[1] = (63 - right_gain);		if (outport & AUDIO_SPEAKER)   dbri->mm.data[1] |= CS4215_SE;	}	xmit_fixed(dbri, 20, *(int *)dbri->mm.data);}static void mmcodec_init_data(struct dbri *dbri){	int data_width;        u32 tmp;	/*	 * Data mode:	 * Pipe  4: Send timeslots 1-4 (audio data)	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)	 * Pipe  6: Receive timeslots 1-4 (audio data)	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via	 *          interrupt, and the rest of the data (slot 5 and 8) is	 *	    not relevant for us (only for doublechecking).         *         * Just like in control mode, the time slots are all offset by eight         * bits.  The CS4215, it seems, observes TSIN (the delayed signal)         * even if it's the CHI master.  Don't ask me...	 */        tmp = sbus_readl(dbri->regs + REG0);        tmp &= ~(D_C);	/* Disable CHI */        sbus_writel(tmp, dbri->regs + REG0);        /* Switch CS4215 to data mode - set PIO3 to 1 */        sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 |                    (dbri->mm.onboard ? D_PIO0 : D_PIO2),                    dbri->regs + REG2);	reset_chi(dbri, CHIslave, 128);	/* Note: this next doesn't work for 8-bit stereo, because the two	 * channels would be on timeslots 1 and 3, with 2 and 4 idle.	 * (See CS4215 datasheet Fig 15)	 *	 * DBRI non-contiguous mode would be required to make this work.	 */	data_width = dbri->perchip_info.play.channels		* dbri->perchip_info.play.precision;	link_time_slot(dbri, 20, PIPEoutput, 16,		       32, dbri->mm.offset + 32);	link_time_slot(dbri,  4, PIPEoutput, 16,		       data_width, dbri->mm.offset);	link_time_slot(dbri,  6, PIPEinput, 16,		       data_width, dbri->mm.offset);	link_time_slot(dbri, 21, PIPEinput, 16,		       16, dbri->mm.offset + 40);	mmcodec_setgain(dbri, 0);        tmp = sbus_readl(dbri->regs + REG0);	tmp |= D_C;	/* Enable CHI */        sbus_writel(tmp, dbri->regs + REG0);}/* * Send the control information (i.e. audio format)

⌨️ 快捷键说明

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