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

📄 cs4218_tdm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
				SLEEP(read_sq.open_queue);				if (SIGNAL_RECEIVED)					goto err_out;			}			rc = 0;		}		read_sq.busy = 1;		if (sq_allocate_read_buffers()) goto err_out_nobusy;		read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);		read_sq.open_mode = file->f_mode;	}	/* Start up the 4218 by:	 * Reset.	 * Enable, unreset.	 */	*((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO;	eieio();	*((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO;	mdelay(50);	*((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;	/* We need to send the current control word in case someone	 * opened /dev/mixer and changed things while we were shut	 * down.  Chances are good the initialization that follows	 * would have done this, but it is still possible it wouldn't.	 */	cs4218_ctl_write(cs4218_control);	sound.minDev = iminor(inode) & 0x0f;	sound.soft = sound.dsp;	sound.hard = sound.dsp;	sound_init();	if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) {		sound_set_speed(8000);		sound_set_stereo(0);		sound_set_format(AFMT_MU_LAW);	}	return nonseekable_open(inode, file);err_out_nobusy:	if (file->f_mode & FMODE_WRITE) {		sq.busy = 0;		WAKE_UP(sq.open_queue);	}	if (file->f_mode & FMODE_READ) {		read_sq.busy = 0;		WAKE_UP(read_sq.open_queue);	}err_out:	return rc;}static void sq_reset(void){	sound_silence();	sq.active = 0;	sq.count = 0;	sq.front = (sq.rear+1) % sq.max_count;#if 0	init_tdm_buffers();#endif}static int sq_fsync(struct file *filp, struct dentry *dentry){	int rc = 0;	sq.syncing = 1;	sq_play();	/* there may be an incomplete frame waiting */	while (sq.active) {		SLEEP(sq.sync_queue);		if (SIGNAL_RECEIVED) {			/* While waiting for audio output to drain, an			 * interrupt occurred.  Stop audio output immediately			 * and clear the queue. */			sq_reset();			rc = -EINTR;			break;		}	}	sq.syncing = 0;	return rc;}static int sq_release(struct inode *inode, struct file *file){	int rc = 0;	if (sq.busy)		rc = sq_fsync(file, file->f_dentry);	sound.soft = sound.dsp;	sound.hard = sound.dsp;	sound_silence();	sq_release_read_buffers();	sq_release_buffers();	if (file->f_mode & FMODE_READ) {		read_sq.busy = 0;		WAKE_UP(read_sq.open_queue);	}	if (file->f_mode & FMODE_WRITE) {		sq.busy = 0;		WAKE_UP(sq.open_queue);	}	/* Shut down the SMC.	*/	cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN);	/* Shut down the codec.	*/	*((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;	eieio();	*((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO;	/* Wake up a process waiting for the queue being released.	 * Note: There may be several processes waiting for a call	 * to open() returning. */	return rc;}static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,		    u_long arg){	u_long fmt;	int data;#if 0	int size, nbufs;#else	int size;#endif	switch (cmd) {	case SNDCTL_DSP_RESET:		sq_reset();		return 0;	case SNDCTL_DSP_POST:	case SNDCTL_DSP_SYNC:		return sq_fsync(file, file->f_dentry);		/* ++TeSche: before changing any of these it's		 * probably wise to wait until sound playing has		 * settled down. */	case SNDCTL_DSP_SPEED:		sq_fsync(file, file->f_dentry);		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, sound_set_speed(data));	case SNDCTL_DSP_STEREO:		sq_fsync(file, file->f_dentry);		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, sound_set_stereo(data));	case SOUND_PCM_WRITE_CHANNELS:		sq_fsync(file, file->f_dentry);		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);	case SNDCTL_DSP_SETFMT:		sq_fsync(file, file->f_dentry);		IOCTL_IN(arg, data);		return IOCTL_OUT(arg, sound_set_format(data));	case SNDCTL_DSP_GETFMTS:		fmt = 0;		if (sound.trans_write) {			if (sound.trans_write->ct_ulaw)				fmt |= AFMT_MU_LAW;			if (sound.trans_write->ct_alaw)				fmt |= AFMT_A_LAW;			if (sound.trans_write->ct_s8)				fmt |= AFMT_S8;			if (sound.trans_write->ct_u8)				fmt |= AFMT_U8;			if (sound.trans_write->ct_s16be)				fmt |= AFMT_S16_BE;			if (sound.trans_write->ct_u16be)				fmt |= AFMT_U16_BE;			if (sound.trans_write->ct_s16le)				fmt |= AFMT_S16_LE;			if (sound.trans_write->ct_u16le)				fmt |= AFMT_U16_LE;		}		return IOCTL_OUT(arg, fmt);	case SNDCTL_DSP_GETBLKSIZE:		size = sq.block_size			* sound.soft.size * (sound.soft.stereo + 1)			/ (sound.hard.size * (sound.hard.stereo + 1));		return IOCTL_OUT(arg, size);	case SNDCTL_DSP_SUBDIVIDE:		break;#if 0	/* Sorry can't do this at the moment.  The CPM allocated buffers	 * long ago that can't be changed.	 */	case SNDCTL_DSP_SETFRAGMENT:		if (sq.count || sq.active || sq.syncing)			return -EINVAL;		IOCTL_IN(arg, size);		nbufs = size >> 16;		if (nbufs < 2 || nbufs > numBufs)			nbufs = numBufs;		size &= 0xffff;		if (size >= 8 && size <= 30) {			size = 1 << size;			size *= sound.hard.size * (sound.hard.stereo + 1);			size /= sound.soft.size * (sound.soft.stereo + 1);			if (size > (bufSize << 10))				size = bufSize << 10;		} else			size = bufSize << 10;		sq_setup(numBufs, size, sound_buffers);		sq.max_active = nbufs;		return 0;#endif	default:		return mixer_ioctl(inode, file, cmd, arg);	}	return -EINVAL;}static struct file_operations sq_fops ={	.owner =	THIS_MODULE,	.llseek =	sound_lseek,	.read =		sq_read,			/* sq_read */	.write =	sq_write,	.ioctl =	sq_ioctl,	.open =		sq_open,	.release =	sq_release,};static void __init sq_init(void){	sq_unit = register_sound_dsp(&sq_fops, -1);	if (sq_unit < 0)		return;	init_waitqueue_head(&sq.action_queue);	init_waitqueue_head(&sq.open_queue);	init_waitqueue_head(&sq.sync_queue);	init_waitqueue_head(&read_sq.action_queue);	init_waitqueue_head(&read_sq.open_queue);	init_waitqueue_head(&read_sq.sync_queue);	sq.busy = 0;	read_sq.busy = 0;	/* whatever you like as startup mode for /dev/dsp,	 * (/dev/audio hasn't got a startup mode). note that	 * once changed a new open() will *not* restore these!	 */	sound.dsp.format = AFMT_S16_BE;	sound.dsp.stereo = 1;	sound.dsp.size = 16;	/* set minimum rate possible without expanding */	sound.dsp.speed = 8000;	/* before the first open to /dev/dsp this wouldn't be set */	sound.soft = sound.dsp;	sound.hard = sound.dsp;	sound_silence();}/* * /dev/sndstat *//* state.buf should not overflow! */static int state_open(struct inode *inode, struct file *file){	char *buffer = state.buf, *mach = "", cs4218_buf[50];	int len = 0;	if (state.busy)		return -EBUSY;	state.ptr = 0;	state.busy = 1;	sprintf(cs4218_buf, "Crystal CS4218 on TDM, ");	mach = cs4218_buf;	len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);	switch (sound.soft.format) {	case AFMT_MU_LAW:		len += sprintf(buffer+len, " (mu-law)");		break;	case AFMT_A_LAW:		len += sprintf(buffer+len, " (A-law)");		break;	case AFMT_U8:		len += sprintf(buffer+len, " (unsigned 8 bit)");		break;	case AFMT_S8:		len += sprintf(buffer+len, " (signed 8 bit)");		break;	case AFMT_S16_BE:		len += sprintf(buffer+len, " (signed 16 bit big)");		break;	case AFMT_U16_BE:		len += sprintf(buffer+len, " (unsigned 16 bit big)");		break;	case AFMT_S16_LE:		len += sprintf(buffer+len, " (signed 16 bit little)");		break;	case AFMT_U16_LE:		len += sprintf(buffer+len, " (unsigned 16 bit little)");		break;	}	len += sprintf(buffer+len, "\n");	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",		       sound.soft.speed, sound.hard.speed);	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",		       sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");	len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"		       " sq.max_active = %d\n",		       sq.block_size, sq.max_count, sq.max_active);	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,		       sq.rear_size);	len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",		       sq.active, sq.syncing);	state.len = len;	return nonseekable_open(inode, file);}static int state_release(struct inode *inode, struct file *file){	state.busy = 0;	return 0;}static ssize_t state_read(struct file *file, char *buf, size_t count,			  loff_t *ppos){	int n = state.len - state.ptr;	if (n > count)		n = count;	if (n <= 0)		return 0;	if (copy_to_user(buf, &state.buf[state.ptr], n))		return -EFAULT;	state.ptr += n;	return n;}static struct file_operations state_fops ={	.owner =	THIS_MODULE,	.llseek =	sound_lseek,	.read =		state_read,	.open =		state_open,	.release =	state_release,};static void __init state_init(void){	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);	if (state_unit < 0)		return;	state.busy = 0;}/*** Common stuff ********************************************************/static long long sound_lseek(struct file *file, long long offset, int orig){	return -ESPIPE;}/*** Config & Setup **********************************************************/int __init tdm8xx_sound_init(void){	int i, has_sound;	uint			dp_offset;	volatile uint		*sirp;	volatile cbd_t		*bdp;	volatile cpm8xx_t	*cp;	volatile smc_t		*sp;	volatile smc_uart_t	*up;	volatile immap_t	*immap;	has_sound = 0;	/* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes.	*/	cp = cpmp;	/* Get pointer to Communication Processor */	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */	/* Set all TDMa control bits to zero.  This enables most features	 * we want.	 */	cp->cp_simode &= ~0x00000fff;	/* Enable common receive/transmit clock pins, use IDL format.	 * Sync on falling edge, transmit rising clock, receive falling	 * clock, delay 1 bit on both Tx and Rx.  Common Tx/Rx clocks and	 * sync.	 * Connect SMC2 to TSA.	 */	cp->cp_simode |= 0x80000141;	/* Configure port A pins for TDMa operation.	 * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used.	 */	immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */	immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */	immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */	immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */	immap->im_ioport.iop_pcdir &= ~0x0800;	/* Initialize the SI TDM routing table.  We use TDMa only.	 * The receive table and transmit table each have only one	 * entry, to capture/send four bytes after each frame pulse.	 * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2)	 */	cp->cp_sigmr = 0;	sirp = (uint *)cp->cp_siram;	*sirp = 0x018f0000;		/* Receive entry */	sirp += 64;	*sirp = 0x018f0000;		/* Tramsmit entry */	/* Enable single TDMa routing.	*/	cp->cp_sigmr = 0x04;	/* Initialize the SMC for transparent operation.	*/	sp = &cpmp->cp_smc[1];	up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];	/* We need to allocate a transmit and receive buffer	 * descriptors from dual port ram.	 */	dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8);	/* Set the physical address of the host memory	 * buffers in the buffer descriptors, and the	 * virtual address for us to work with.	 */	bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];	up->smc_rbase = dp_offset;	rx_cur = rx_base = (cbd_t *)bdp;	for (i=0; i<(numReadBufs-1); i++) {		bdp->cbd_bufaddr = 0;		bdp->cbd_datlen = 0;		bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;		bdp++;	}	bdp->cbd_bufaddr = 0;	bdp->cbd_datlen = 0;	bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;	/* Now, do the same for the transmit buffers.	*/	dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8);	bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];	up->smc_tbase = dp_offset;	tx_cur = tx_base = (cbd_t *)bdp;	for (i=0; i<(numBufs-1); i++) {		bdp->cbd_bufaddr = 0;		bdp->cbd_datlen = 0;		bdp->cbd_sc = BD_SC_INTRPT;		bdp++;	}	bdp->cbd_bufaddr = 0;	bdp->cbd_datlen = 0;	bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);	/* Set transparent SMC mode.	 * A few things are specific to our application.  The codec interface	 * is MSB first, hence the REVD selection.  The CD/CTS pulse are	 * used by the TSA to indicate the frame start to the SMC.	 */	up->smc_rfcr = SCC_EB;	up->smc_tfcr = SCC_EB;	up->smc_mrblr = readbufSize * 1024;	/* Set 16-bit reversed data, transparent mode.	*/	sp->smc_smcmr = smcr_mk_clen(15) |		SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS;	/* Enable and clear events.	 * Because of FIFO delays, all we need is the receive interrupt	 * and we can process both the current receive and current	 * transmit interrupt within a few microseconds of

⌨️ 快捷键说明

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