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

📄 esssolo1.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
			return -ENOMEM;		db->buforder = order;		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);		for (page = virt_to_page(db->rawbuf); page <= pend; page++)			mem_map_reserve(page);	}	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))		sample_shift++;	if (s->channels > 1)		sample_shift++;	bytespersec = s->rate << sample_shift;	bufs = PAGE_SIZE << db->buforder;	if (db->ossfragshift) {		if ((1000 << db->ossfragshift) < bytespersec)			db->fragshift = ld2(bytespersec/1000);		else			db->fragshift = db->ossfragshift;	} else {		db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));		if (db->fragshift < 3)			db->fragshift = 3;	}	db->numfrag = bufs >> db->fragshift;	while (db->numfrag < 4 && db->fragshift > 3) {		db->fragshift--;		db->numfrag = bufs >> db->fragshift;	}	db->fragsize = 1 << db->fragshift;	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)		db->numfrag = db->ossmaxfrags;	db->fragsamples = db->fragsize >> sample_shift;	db->dmasize = db->numfrag << db->fragshift;	db->enabled = 1;	return 0;}static inline int prog_dmabuf_adc(struct solo1_state *s){	unsigned long va;	int c;	stop_adc(s);	/* check if PCI implementation supports 24bit busmaster DMA */	if (s->dev->dma_mask > 0xffffff)		return -EIO;	if ((c = prog_dmabuf(s, &s->dma_adc)))		return c;	va = s->dma_adc.dmaaddr;	if ((va & ~((1<<24)-1)))		panic("solo1: buffer above 16M boundary");	outb(0, s->ddmabase+0xd);  /* clear */	outb(1, s->ddmabase+0xf); /* mask */	/*outb(0, s->ddmabase+8);*/  /* enable (enable is active low!) */	outb(0x54, s->ddmabase+0xb);  /* DMA_MODE_READ | DMA_MODE_AUTOINIT */	outl(va, s->ddmabase);	outw(s->dma_adc.dmasize-1, s->ddmabase+4);	c = - s->dma_adc.fragsamples;	write_ctrl(s, 0xa4, c);	write_ctrl(s, 0xa5, c >> 8);	outb(0, s->ddmabase+0xf);	s->dma_adc.ready = 1;	return 0;}static inline int prog_dmabuf_dac(struct solo1_state *s){	unsigned long va;	int c;	stop_dac(s);	if ((c = prog_dmabuf(s, &s->dma_dac)))		return c;	memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */	va = s->dma_dac.dmaaddr;	if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))		panic("solo1: buffer crosses 1M boundary");	outl(va, s->iobase);	/* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */	outw(s->dma_dac.dmasize, s->iobase+4);	c = - s->dma_dac.fragsamples;	write_mixer(s, 0x74, c);	write_mixer(s, 0x76, c >> 8);	outb(0xa, s->iobase+6);	s->dma_dac.ready = 1;	return 0;}static inline 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;	}	memset(((char *)buf) + bptr, c, len);}/* call with spinlock held! */static void solo1_update_ptr(struct solo1_state *s){	int diff;	unsigned hwptr;	/* update ADC pointer */	if (s->ena & FMODE_READ) {		hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize;                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 0		printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",		       s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);#endif		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 > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {				s->ena &= ~FMODE_READ;				write_ctrl(s, 0xb8, 0xe);				s->dma_adc.error++;			}			if (s->dma_adc.count > 0)				wake_up(&s->dma_adc.wait);		}	}	/* update DAC pointer */	if (s->ena & FMODE_WRITE) {                hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize;                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 0		printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",		       s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);#endif		if (s->dma_dac.mapped) {			s->dma_dac.count += diff;			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)				wake_up(&s->dma_dac.wait);		} else {			s->dma_dac.count -= diff;			if (s->dma_dac.count <= 0) {				s->ena &= ~FMODE_WRITE;				write_mixer(s, 0x78, 0x12);				s->dma_dac.error++;			} 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->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);				s->dma_dac.endcleared = 1;			}			if (s->dma_dac.count < (signed)s->dma_dac.dmasize)				wake_up(&s->dma_dac.wait);		}	}}/* --------------------------------------------------------------------- */static void prog_codec(struct solo1_state *s){	unsigned long flags;	int fdiv, filter;	unsigned char c;	reset_ctrl(s);	write_seq(s, 0xd3);	/* program sampling rates */	filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */	fdiv = 256 - 7160000 / (filter * 82);	spin_lock_irqsave(&s->lock, flags);	write_ctrl(s, 0xa1, s->clkdiv);	write_ctrl(s, 0xa2, fdiv);	write_mixer(s, 0x70, s->clkdiv);	write_mixer(s, 0x72, fdiv);	/* program ADC parameters */	write_ctrl(s, 0xb8, 0xe);	write_ctrl(s, 0xb9, /*0x1*/0);	write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);	c = 0xd0;	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))		c |= 0x04;	if (s->fmt & (AFMT_S16_LE | AFMT_S8))		c |= 0x20;	if (s->channels > 1)		c ^= 0x48;	write_ctrl(s, 0xb7, (c & 0x70) | 1);	write_ctrl(s, 0xb7, c);	write_ctrl(s, 0xb1, 0x50);	write_ctrl(s, 0xb2, 0x50);	/* program DAC parameters */	c = 0x40;	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))		c |= 1;	if (s->fmt & (AFMT_S16_LE | AFMT_S8))		c |= 4;	if (s->channels > 1)		c |= 2;	write_mixer(s, 0x7a, c);	write_mixer(s, 0x78, 0x10);	s->ena = 0;	spin_unlock_irqrestore(&s->lock, flags);}/* --------------------------------------------------------------------- */static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";#define VALIDATE_STATE(s)                         \({                                                \	if (!(s) || (s)->magic != SOLO1_MAGIC) { \		printk(invalid_magic);            \		return -ENXIO;                    \	}                                         \})/* --------------------------------------------------------------------- */static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg){	static const unsigned int mixer_src[8] = {		SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,		SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0	};	static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {		[SOUND_MIXER_PCM]     = 1,   /* voice */		[SOUND_MIXER_SYNTH]   = 2,   /* FM */		[SOUND_MIXER_CD]      = 3,   /* CD */		[SOUND_MIXER_LINE]    = 4,   /* Line */		[SOUND_MIXER_LINE1]   = 5,   /* AUX */		[SOUND_MIXER_MIC]     = 6,   /* Mic */		[SOUND_MIXER_LINE2]   = 7,   /* Mono in */		[SOUND_MIXER_SPEAKER] = 8,   /* Speaker */		[SOUND_MIXER_RECLEV]  = 9,   /* Recording level */		[SOUND_MIXER_VOLUME]  = 10   /* Master Volume */	};	static const unsigned char mixreg[] = {		0x7c,   /* voice */		0x36,   /* FM */		0x38,   /* CD */		0x3e,   /* Line */		0x3a,   /* AUX */		0x1a,   /* Mic */		0x6d    /* Mono in */	};	unsigned char l, r, rl, rr, vidx;	int i, val;	VALIDATE_STATE(s);	if (cmd == SOUND_MIXER_PRIVATE1) {		/* enable/disable/query mixer preamp */		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != -1) {			val = val ? 0xff : 0xf7;			write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);		}		val = (read_mixer(s, 0x7d) & 0x08) ? 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) {			val &= 0x3f;			write_mixer(s, 0x52, val);			write_mixer(s, 0x50, val ? 0x08 : 0);		}		return put_user(read_mixer(s, 0x52), (int *)arg);	}        if (cmd == SOUND_MIXER_INFO) {		mixer_info info;		strncpy(info.id, "Solo1", sizeof(info.id));		strncpy(info.name, "ESS Solo1", 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, "Solo1", sizeof(info.id));		strncpy(info.name, "ESS Solo1", 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 (_SIOC_DIR(cmd) == _SIOC_READ) {                switch (_IOC_NR(cmd)) {                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */			return put_user(mixer_src[read_mixer(s, 0x1c) & 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_LINE2 | 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, (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_LINE2 | SOUND_MASK_RECLEV, (int *)arg);			                case SOUND_MIXER_CAPS:			return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);		default:			i = _IOC_NR(cmd);                        if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))                                return -EINVAL;			return put_user(s->mix.vol[vidx-1], (int *)arg);		}	}        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 		return -EINVAL;	s->mix.modcnt++;	switch (_IOC_NR(cmd)) {	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */#if 0	        {			static const unsigned char regs[] = {				0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c			};			int i;						for (i = 0; i < sizeof(regs); i++)				printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",				       regs[i], read_mixer(s, regs[i]));			printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",			       0xb4, read_ctrl(s, 0xb4));		}#endif	        if (get_user(val, (int *)arg))			return -EFAULT;                i = hweight32(val);                if (i == 0)                        return 0;                else if (i > 1)                         val &= ~mixer_src[read_mixer(s, 0x1c) & 7];		for (i = 0; i < 8; i++) {			if (mixer_src[i] & val)				break;		}		if (i > 7)			return 0;		write_mixer(s, 0x1c, i);		return 0;	case SOUND_MIXER_VOLUME:		if (get_user(val, (int *)arg))			return -EFAULT;		l = val & 0xff;		if (l > 100)			l = 100;		r = (val >> 8) & 0xff;		if (r > 100)			r = 100;		if (l < 6) {			rl = 0x40;			l = 0;		} else {			rl = (l * 2 - 11) / 3;			l = (rl * 3 + 11) / 2;		}		if (r < 6) {			rr = 0x40;			r = 0;		} else {			rr = (r * 2 - 11) / 3;			r = (rr * 3 + 11) / 2;		}		write_mixer(s, 0x60, rl);		write_mixer(s, 0x62, rr);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS                s->mix.vol[9] = ((unsigned int)r << 8) | l;#else                s->mix.vol[9] = val;#endif		return put_user(s->mix.vol[9], (int *)arg);	case SOUND_MIXER_SPEAKER:		if (get_user(val, (int *)arg))			return -EFAULT;		l = val & 0xff;		if (l > 100)			l = 100;		else if (l < 2)			l = 2;		rl = (l - 2) / 14;		l = rl * 14 + 2;		write_mixer(s, 0x3c, rl);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS                s->mix.vol[7] = l * 0x101;#else                s->mix.vol[7] = val;#endif		return put_user(s->mix.vol[7], (int *)arg);	case SOUND_MIXER_RECLEV:		if (get_user(val, (int *)arg))			return -EFAULT;		l = (val << 1) & 0x1fe;		if (l > 200)			l = 200;		else if (l < 5)			l = 5;		r = (val >> 7) & 0x1fe;		if (r > 200)			r = 200;		else if (r < 5)			r = 5;		rl = (l - 5) / 13;		rr = (r - 5) / 13;		r = (rl * 13 + 5) / 2;		l = (rr * 13 + 5) / 2;		write_ctrl(s, 0xb4, (rl << 4) | rr);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS                s->mix.vol[8] = ((unsigned int)r << 8) | l;#else                s->mix.vol[8] = val;#endif		return put_user(s->mix.vol[8], (int *)arg);	default:		i = _IOC_NR(cmd);		if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))			return -EINVAL;		if (get_user(val, (int *)arg))			return -EFAULT;		l = (val << 1) & 0x1fe;		if (l > 200)			l = 200;

⌨️ 快捷键说明

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