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

📄 cs4281.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
{	unsigned long va;	unsigned count;	int c;	stop_dac(s);	s->dma_dac.type = CS_TYPE_DAC;	if ((c = prog_dmabuf(s, &s->dma_dac)))		return c;	memset(s->dma_dac.rawbuf,	       (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,	       s->dma_dac.dmasize);	va = virt_to_bus(s->dma_dac.rawbuf);	count = s->dma_dac.dmasize;	if (s->prop_dac.	    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))		    count /= 2;	// 16-bit.	if (s->prop_dac.channels > 1)		count /= 2;	// Assume stereo.	writel(va, s->pBA0 + BA0_DBA0);	// Set buffer start address.	writel(count - 1, s->pBA0 + BA0_DBC0);	// Set count.             	CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO					   "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",					   count, (unsigned) va));	s->dma_dac.ready = 1;	return 0;}static void clear_advance(void *buf, unsigned bsize, unsigned bptr,			  unsigned len, unsigned char c){	if (bptr + len > bsize) {		unsigned x = bsize - bptr;		memset(((char *) buf) + bptr, c, x);		bptr = 0;		len -= x;	}	CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO					   "cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n",					   (unsigned) c,					   (unsigned) ((char *) buf) +					   bptr, len));	memset(((char *) buf) + bptr, c, len);}// call with spinlock held! static void cs4281_update_ptr(struct cs4281_state *s){	int diff;	unsigned hwptr, va;	// update ADC pointer 	if (s->ena & FMODE_READ) {		hwptr = readl(s->pBA0 + BA0_DCA1);	// Read capture DMA address.		va = virt_to_bus(s->dma_adc.rawbuf);		hwptr -= (unsigned) va;		diff =		    (s->dma_adc.dmasize + hwptr -		     s->dma_adc.hwptr) % s->dma_adc.dmasize;		s->dma_adc.hwptr = hwptr;		s->dma_adc.total_bytes += diff;		s->dma_adc.count += diff;		if (s->dma_adc.count > s->dma_adc.dmasize)			s->dma_adc.count = s->dma_adc.dmasize;		if (s->dma_adc.mapped) {			if (s->dma_adc.count >=			    (signed) s->dma_adc.fragsize) wake_up(&s->								  dma_adc.								  wait);		} else {			if (s->dma_adc.count > 0)				wake_up(&s->dma_adc.wait);		}		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO					      "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",					      (unsigned) s,					      s->dma_adc.hwptr,					      s->dma_adc.total_bytes,					      s->dma_adc.count));	}	// update DAC pointer 	//	// check for end of buffer, means that we are going to wait for another interrupt	// to allow silence to fill the fifos on the part, to keep pops down to a minimum.	//	if (s->ena & FMODE_WRITE) {		hwptr = readl(s->pBA0 + BA0_DCA0);	// Read play DMA address.		va = virt_to_bus(s->dma_dac.rawbuf);		hwptr -= (unsigned) va;		diff =		    (s->dma_dac.dmasize + hwptr -		     s->dma_dac.hwptr) % s->dma_dac.dmasize;		s->dma_dac.hwptr = hwptr;		s->dma_dac.total_bytes += diff;		if (s->dma_dac.mapped) {			s->dma_dac.count += diff;			if (s->dma_dac.count >= s->dma_dac.fragsize) {				s->dma_dac.wakeup = 1;				wake_up(&s->dma_dac.wait);				if (s->dma_dac.count > s->dma_dac.dmasize)					s->dma_dac.count &=					    s->dma_dac.dmasize - 1;			}		} else {			s->dma_dac.count -= diff;			if (s->dma_dac.count <= 0) {				//				// fill with silence, and do not shut down the DAC.				// Continue to play silence until the _release.				//				CS_DBGOUT(CS_WAVE_WRITE, 6,					  printk(KERN_INFO						 "cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n",						 (unsigned) (s->prop_dac.							     fmt & (AFMT_U8								    |								    AFMT_U16_LE))						 ? 0x80 : 0,						 (unsigned) s->dma_dac.						 rawbuf,						 s->dma_dac.dmasize));				memset(s->dma_dac.rawbuf,				       (s->prop_dac.					fmt & (AFMT_U8 | AFMT_U16_LE)) ?				       0x80 : 0, s->dma_dac.dmasize);			} else if (s->dma_dac.count <=				   (signed) s->dma_dac.fragsize				   && !s->dma_dac.endcleared) {				clear_advance(s->dma_dac.rawbuf,					      s->dma_dac.dmasize,					      s->dma_dac.swptr,					      s->dma_dac.fragsize,					      (s->prop_dac.					       fmt & (AFMT_U8 |						      AFMT_U16_LE)) ? 0x80					      : 0);				s->dma_dac.endcleared = 1;			}			if (s->dma_dac.count < (signed) s->dma_dac.dmasize)				wake_up(&s->dma_dac.wait);		}		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO					      "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",					      (unsigned) s,					      s->dma_dac.hwptr,					      s->dma_dac.total_bytes,					      s->dma_dac.count));	}}// --------------------------------------------------------------------- static void prog_codec(struct cs4281_state *s, unsigned type){	unsigned long flags;	unsigned temp1, format;	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: prog_codec()+ \n"));	spin_lock_irqsave(&s->lock, flags);	if (type == CS_TYPE_ADC) {		temp1 = readl(s->pBA0 + BA0_DCR1);		writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1);	// Stop capture DMA, if active.		// program sampling rates  		// Note, for CS4281, capture & play rates can be set independently.		cs4281_record_rate(s, s->prop_adc.rate);		// program ADC parameters 		format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;		if (s->prop_adc.		    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) {	// 16-bit			if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE))	// Big-endian?				format |= DMRn_BEND;			if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))				format |= DMRn_USIGN;	// Unsigned.      		} else			format |= DMRn_SIZE8 | DMRn_USIGN;	// 8-bit, unsigned		if (s->prop_adc.channels < 2)			format |= DMRn_MONO;		writel(format, s->pBA0 + BA0_DMR1);		CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO					      "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",					      (format & DMRn_SIZE8) ? "8" :					      "16",					      (format & DMRn_USIGN) ?					      "Unsigned" : "Signed",					      (format & DMRn_MONO) ? "Mono"					      : "Stereo", s->prop_adc.rate,					      format));		s->ena &= ~FMODE_READ;	// not capturing data yet	}	if (type == CS_TYPE_DAC) {		temp1 = readl(s->pBA0 + BA0_DCR0);		writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0);	// Stop play DMA, if active.		// program sampling rates  		// Note, for CS4281, capture & play rates can be set independently.		cs4281_play_rate(s, s->prop_dac.rate);		// program DAC parameters 		format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;		if (s->prop_dac.		    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) {	// 16-bit			if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE))				format |= DMRn_BEND;	// Big Endian.			if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE))				format |= DMRn_USIGN;	// Unsigned.      		} else			format |= DMRn_SIZE8 | DMRn_USIGN;	// 8-bit, unsigned		if (s->prop_dac.channels < 2)			format |= DMRn_MONO;		writel(format, s->pBA0 + BA0_DMR0);		CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO					      "cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n",					      (format & DMRn_SIZE8) ? "8" :					      "16",					      (format & DMRn_USIGN) ?					      "Unsigned" : "Signed",					      (format & DMRn_MONO) ? "Mono"					      : "Stereo", s->prop_dac.rate,					      format));		s->ena &= ~FMODE_WRITE;	// not capturing data yet	}	spin_unlock_irqrestore(&s->lock, flags);	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: prog_codec()- \n"));}// --------------------------------------------------------------------- static const char invalid_magic[] =    KERN_CRIT "cs4281: invalid magic value\n";#define VALIDATE_STATE(s)                         \({                                                \        if (!(s) || (s)->magic != CS4281_MAGIC) { \                printk(invalid_magic);            \                return -ENXIO;                    \        }                                         \})// --------------------------------------------------------------------- static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,		       unsigned long arg){	// Index to mixer_src[] is value of AC97 Input Mux Select Reg.	// Value of array member is recording source Device ID Mask.	static const unsigned int mixer_src[8] = {		SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,		SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0	};	// Index of mixtable1[] member is Device ID 	// and must be <= SOUND_MIXER_NRDEVICES.	// Value of array member is index into s->mix.vol[]	static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {		[SOUND_MIXER_PCM] = 1,	// voice 		[SOUND_MIXER_LINE1] = 2,	// AUX		[SOUND_MIXER_CD] = 3,	// CD 		[SOUND_MIXER_LINE] = 4,	// Line 		[SOUND_MIXER_SYNTH] = 5,	// FM		[SOUND_MIXER_MIC] = 6,	// Mic 		[SOUND_MIXER_SPEAKER] = 7,	// Speaker 		[SOUND_MIXER_RECLEV] = 8,	// Recording level 		[SOUND_MIXER_VOLUME] = 9	// Master Volume 	};	static const unsigned mixreg[] = {		BA0_AC97_PCM_OUT_VOLUME,		BA0_AC97_AUX_VOLUME,		BA0_AC97_CD_VOLUME,		BA0_AC97_LINE_IN_VOLUME	};	unsigned char l, r, rl, rr, vidx;	unsigned char attentbl[11] =	    { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 };	unsigned temp1;	int i, val;	VALIDATE_STATE(s);	CS_DBGOUT(CS_FUNCTION, 4,		  printk(KERN_INFO			 "cs4281: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n",			 (unsigned) s, cmd));#if CSDEBUG	printioctl(cmd);#endif#if CSDEBUG_INTERFACE	if ((cmd == SOUND_MIXER_CS_GETDBGMASK) ||	    (cmd == SOUND_MIXER_CS_SETDBGMASK) ||	    (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||	    (cmd == SOUND_MIXER_CS_SETDBGLEVEL)) {		switch (cmd) {		case SOUND_MIXER_CS_GETDBGMASK:			return put_user(cs_debugmask,					(unsigned long *) arg);		case SOUND_MIXER_CS_GETDBGLEVEL:			return put_user(cs_debuglevel,					(unsigned long *) arg);		case SOUND_MIXER_CS_SETDBGMASK:			if (get_user(val, (unsigned long *) arg))				return -EFAULT;			cs_debugmask = val;			return 0;		case SOUND_MIXER_CS_SETDBGLEVEL:			if (get_user(val, (unsigned long *) arg))				return -EFAULT;			cs_debuglevel = val;			return 0;		default:			CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO						      "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n"));			return 0;		}	}#endif	if (cmd == SOUND_MIXER_PRIVATE1) {		// enable/disable/query mixer preamp 		if (get_user(val, (int *) arg))			return -EFAULT;		if (val != -1) {			cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);			temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf);			cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);		}		cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);		val = (temp1 & 0x40) ? 1 : 0;		return put_user(val, (int *) arg);	}	if (cmd == SOUND_MIXER_PRIVATE2) {		// enable/disable/query spatializer 		if (get_user(val, (int *) arg))			return -EFAULT;		if (val != -1) {			temp1 = (val & 0x3f) >> 2;			cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);			cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE,					 &temp1);			cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,					  temp1 | 0x2000);		}		cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);		return put_user((temp1 << 2) | 3, (int *) arg);	}	if (cmd == SOUND_MIXER_INFO) {		mixer_info info;		strncpy(info.id, "CS4281", sizeof(info.id));		strncpy(info.name, "Crystal CS4281", sizeof(info.name));		info.modify_counter = s->mix.modcnt;		if (copy_to_user((void *) arg, &info, sizeof(info)))			return -EFAULT;		return 0;	}	if (cmd == SOUND_OLD_MIXER_INFO) {		_old_mixer_info info;		strncpy(info.id, "CS4281", sizeof(info.id));		strncpy(info.name, "Crystal CS4281", sizeof(info.name));		if (copy_to_user((void *) arg, &info, sizeof(info)))			return -EFAULT;		return 0;	}	if (cmd == OSS_GETVERSION)		return put_user(SOUND_VERSION, (int *) arg);	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))		return -EINVAL;	// If ioctl has only the SIOC_READ bit(bit 31)	// on, process the only-read commands. 	if (_SIOC_DIR(cmd) == _SIOC_READ) {		switch (_IOC_NR(cmd)) {		case SOUND_MIXER_RECSRC:	// Arg contains a bit for each recording source 			cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT,					 &temp1);			return put_user(mixer_src[temp1 & 7], (int *) arg);		case SOUND_MIXER_DEVMASK:	// Arg contains a bit for each supported device 			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |					SOUND_MASK_CD | SOUND_MASK_LINE |					SOUND_MASK_LINE1 | SOUND_MASK_MIC |					SOUND_MASK_VOLUME |					SOUND_MASK_RECLEV |					SOUND_MASK_SPEAKER, (int *) arg);		case SOUND_MIXER_RECMASK:	// Arg contains a bit for each supported recording source 			return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC |					SOUND_MASK_CD | SOUND_MASK_VOLUME |					SOUND_MASK_LINE1, (int *) arg);		case SOUND_MIXER_STEREODEVS:	// Mixer channels supporting stereo 			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |					SOUND_MASK_CD | SOUND_MASK_LINE |					SOUND_MASK_LINE1 | SOUND_MASK_MIC |					SOUND_MASK_VOLUME |					SOUND_MASK_RECLEV, (int *) arg);		case SOUND_MIXER_CAPS:			return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);		default:			i = _IOC_NR(cmd);

⌨️ 快捷键说明

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