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

📄 cmpci.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	unsigned long flags;	fmt = s->fmt;	if (rec) {		stop_adc(s);		fmt >>= CM_CFMT_ADCSHIFT;	} else {		stop_dac(s);		fmt >>= CM_CFMT_DACSHIFT;	}	fmt &= CM_CFMT_MASK;	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;	if (!db->rawbuf) {		db->ready = db->mapped = 0;		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)			if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))				break;		if (!db->rawbuf || !db->dmaaddr)			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 (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)			SetPageReserved(pstart);	}	bytepersec = rate << sample_shift[fmt];	bufs = PAGE_SIZE << db->buforder;	if (db->ossfragshift) {		if ((1000 << db->ossfragshift) < bytepersec)			db->fragshift = ld2(bytepersec/1000);		else			db->fragshift = db->ossfragshift;	} else {		db->fragshift = ld2(bytepersec/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; 	/* to make fragsize >= 4096 */	db->fragsamples = db->fragsize >> sample_shift[fmt];	db->dmasize = db->numfrag << db->fragshift;	db->dmasamples = db->dmasize >> sample_shift[fmt];	memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);	spin_lock_irqsave(&s->lock, flags);	if (rec) {		if (s->status & DO_DUAL_DAC)		    set_dmadac1(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);		else		    set_dmaadc(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);		/* program sample counts */		set_countdac(s, db->fragsamples);	} else {		set_dmadac(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);		/* program sample counts */		set_countdac(s, db->fragsamples);	}	spin_unlock_irqrestore(&s->lock, flags);	db->enabled = 1;	db->ready = 1;	return 0;}static inline void clear_advance(struct cm_state *s){	unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;	unsigned char *buf = s->dma_dac.rawbuf;	unsigned char *buf1 = s->dma_adc.rawbuf;	unsigned bsize = s->dma_dac.dmasize;	unsigned bptr = s->dma_dac.swptr;	unsigned len = s->dma_dac.fragsize;	if (bptr + len > bsize) {		unsigned x = bsize - bptr;		memset(buf + bptr, c, x);		if (s->status & DO_DUAL_DAC)			memset(buf1 + bptr, c, x);		bptr = 0;		len -= x;	}	memset(buf + bptr, c, len);	if (s->status & DO_DUAL_DAC)		memset(buf1 + bptr, c, len);}/* call with spinlock held! */static void cm_update_ptr(struct cm_state *s){	unsigned hwptr;	int diff;	/* update ADC pointer */	if (s->dma_adc.ready) {	    if (s->status & DO_DUAL_DAC) {		    /* the dac part will finish for this */	    } else {		hwptr = get_dmaadc(s) % 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 (s->dma_adc.count >= (signed)s->dma_adc.fragsize)			wake_up(&s->dma_adc.wait);		if (!s->dma_adc.mapped) {			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {				pause_adc(s);				s->dma_adc.error++;			}		}	    }	}	/* update DAC pointer */	if (s->dma_dac.ready) {		hwptr = get_dmadac(s) % 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 (s->status & DO_DUAL_DAC) {			s->dma_adc.hwptr = hwptr;			s->dma_adc.total_bytes += diff;		}		if (s->dma_dac.mapped) {			s->dma_dac.count += diff;			if (s->status & DO_DUAL_DAC)				s->dma_adc.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->status & DO_DUAL_DAC)				s->dma_adc.count -= diff;			if (s->dma_dac.count <= 0) {				pause_dac(s);				s->dma_dac.error++;			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {				clear_advance(s);				s->dma_dac.endcleared = 1;				if (s->status & DO_DUAL_DAC)					s->dma_adc.endcleared = 1;			}			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)				wake_up(&s->dma_dac.wait);		}	}}static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs){        struct cm_state *s = (struct cm_state *)dev_id;	unsigned int intsrc, intstat;	unsigned char mask = 0;	/* fastpath out, to ease interrupt sharing */	intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);	if (!(intsrc & 0x80000000))		return IRQ_NONE;	spin_lock(&s->lock);	intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);	/* acknowledge interrupt */	if (intsrc & ADCINT)		mask |= ENADCINT;	if (intsrc & DACINT)		mask |= ENDACINT;	outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);	outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);	cm_update_ptr(s);	spin_unlock(&s->lock);#ifdef CONFIG_SOUND_CMPCI_MIDI	if (intsrc & 0x00010000) {	// UART interrupt		if (s->midi_devc && intchk_mpu401((void *)s->midi_devc))			mpuintr(irq, (void *)s->midi_devc, regs);		else			inb(s->iomidi);// dummy read	}#endif	return IRQ_HANDLED;}/* --------------------------------------------------------------------- */static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";#define VALIDATE_STATE(s)                         \({                                                \	if (!(s) || (s)->magic != CM_MAGIC) { \		printk(invalid_magic);            \		return -ENXIO;                    \	}                                         \})/* --------------------------------------------------------------------- */#define MT_4          1#define MT_5MUTE      2#define MT_4MUTEMONO  3#define MT_6MUTE      4#define MT_5MUTEMONO  5static const struct {	unsigned left;	unsigned right;	unsigned type;	unsigned rec;	unsigned play;} mixtable[SOUND_MIXER_NRDEVICES] = {	[SOUND_MIXER_CD]     = { DSP_MIX_CDVOLIDX_L,     DSP_MIX_CDVOLIDX_R,     MT_5MUTE,     0x04, 0x06 },	[SOUND_MIXER_LINE]   = { DSP_MIX_LINEVOLIDX_L,   DSP_MIX_LINEVOLIDX_R,   MT_5MUTE,     0x10, 0x18 },	[SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      DSP_MIX_MICVOLIDX,      MT_5MUTEMONO, 0x01, 0x01 },	[SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,  	 DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },	[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },	[SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 },	[SOUND_MIXER_LINE1]  = { DSP_MIX_AUXVOL_L,       DSP_MIX_AUXVOL_R,       MT_5MUTE,     0x80, 0x60 },	[SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX,	 DSP_MIX_SPKRVOLIDX,	 MT_5MUTEMONO, 0x00, 0x01 }};static const unsigned char volidx[SOUND_MIXER_NRDEVICES] ={	[SOUND_MIXER_CD]     = 1,	[SOUND_MIXER_LINE]   = 2,	[SOUND_MIXER_MIC]    = 3,	[SOUND_MIXER_SYNTH]  = 4,	[SOUND_MIXER_VOLUME] = 5,	[SOUND_MIXER_PCM]    = 6,	[SOUND_MIXER_LINE1]  = 7,	[SOUND_MIXER_SPEAKER]= 8};static unsigned mixer_outmask(struct cm_state *s){	unsigned long flags;	int i, j, k;	spin_lock_irqsave(&s->lock, flags);	j = rdmixer(s, DSP_MIX_OUTMIXIDX);	spin_unlock_irqrestore(&s->lock, flags);	for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)		if (j & mixtable[i].play)			k |= 1 << i;	return k;}static unsigned mixer_recmask(struct cm_state *s){	unsigned long flags;	int i, j, k;	spin_lock_irqsave(&s->lock, flags);	j = rdmixer(s, DSP_MIX_ADCMIXIDX_L);	spin_unlock_irqrestore(&s->lock, flags);	for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)		if (j & mixtable[i].rec)			k |= 1 << i;	return k;}static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg){	unsigned long flags;	int i, val, j;	unsigned char l, r, rl, rr;	void __user *argp = (void __user *)arg;	int __user *p = argp;	VALIDATE_STATE(s);        if (cmd == SOUND_MIXER_INFO) {		mixer_info info;		memset(&info, 0, sizeof(info));		strlcpy(info.id, "cmpci", sizeof(info.id));		strlcpy(info.name, "C-Media PCI", sizeof(info.name));		info.modify_counter = s->mix.modcnt;		if (copy_to_user(argp, &info, sizeof(info)))			return -EFAULT;		return 0;	}	if (cmd == SOUND_OLD_MIXER_INFO) {		_old_mixer_info info;		memset(&info, 0, sizeof(info));		strlcpy(info.id, "cmpci", sizeof(info.id));		strlcpy(info.name, "C-Media cmpci", sizeof(info.name));		if (copy_to_user(argp, &info, sizeof(info)))			return -EFAULT;		return 0;	}	if (cmd == OSS_GETVERSION)		return put_user(SOUND_VERSION, p);	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 */			val = mixer_recmask(s);			return put_user(val, p);                case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */			val = mixer_outmask(s);			return put_user(val, p);                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)				if (mixtable[i].type)					val |= 1 << i;			return put_user(val, p);                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)				if (mixtable[i].rec)					val |= 1 << i;			return put_user(val, p);                case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)				if (mixtable[i].play)					val |= 1 << i;			return put_user(val, p);                 case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)				if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)					val |= 1 << i;			return put_user(val, p);                case SOUND_MIXER_CAPS:			return put_user(0, p);		default:			i = _IOC_NR(cmd);                        if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)                                return -EINVAL;			if (!volidx[i])				return -EINVAL;			return put_user(s->mix.vol[volidx[i]-1], p);		}	}        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 (get_user(val, p))			return -EFAULT;		i = generic_hweight32(val);		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {			if (!(val & (1 << i)))				continue;			if (!mixtable[i].rec) {				val &= ~(1 << i);				continue;			}			j |= mixtable[i].rec;		}		spin_lock_irqsave(&s->lock, flags);		wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);		wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80));		spin_unlock_irqrestore(&s->lock, flags);		return 0;	case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */		if (get_user(val, p))			return -EFAULT;		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {			if (!(val & (1 << i)))				continue;			if (!mixtable[i].play) {				val &= ~(1 << i);				continue;			}			j |= mixtable[i].play;		}		spin_lock_irqsave(&s->lock, flags);		wrmixer(s, DSP_MIX_OUTMIXIDX, j);		spin_unlock_irqrestore(&s->lock, flags);		return 0;	default:		i = _IOC_NR(cmd);		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)			return -EINVAL;		if (get_user(val, p))			return -EFAULT;		l = val & 0xff;		r = (val >> 8) & 0xff;		if (l > 100)			l = 100;		if (r > 100)			r = 100;		spin_lock_irqsave(&s->lock, flags);		switch (mixtable[i].type) {		case MT_4:			if (l >= 10)				l -= 10;			if (r >= 10)				r -= 10;			frobindir(s, mixtable[i].left, 0xf0, l / 6);			frobindir(s, mixtable[i].right, 0xf0, l / 6);			break;		case MT_4MUTEMONO:			rl = (l < 4 ? 0 : (l - 5) / 3) & 31;			rr = (rl >> 2) & 7;			wrmixer(s, mixtable[i].left, rl<<3);			if (i == SOUND_MIXER_MIC)				maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);			break;		case MT_5MUTEMONO:			rl = l < 4 ? 0 : (l - 5) / 3; 			wrmixer(s, mixtable[i].left, rl<<3);			l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play;			r = rl ? mixtable[i].play : 0;			wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);			/* for recording */			if (i == SOUND_MIXER_MIC) {				if (s->chip_version >= 37) {					rr = rl >> 1;					maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, (rr&0x07)<<1);					frobindir(s, DSP_MIX_EXTENSION, ~0x01, rr>>3);				} else {					rr = rl >> 2;					maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);				}			}			break;		case MT_5MUTE:			rl = l < 4 ? 0 : (l - 5) / 3;			rr = r < 4 ? 0 : (r - 5) / 3; 			wrmixer(s, mixtable[i].left, rl<<3);			wrmixer(s, mixtable[i].right, rr<<3);			l = rdmixer(s, DSP_MIX_OUTMIXIDX);			l &= ~mixtable[i].play;			r = (rl|rr) ? mixtable[i].play : 0;			wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);			break;		case MT_6MUTE:			if (l < 6)				rl = 0x00;			else				rl = l * 2 / 3;			if (r < 6)				rr = 0x00;			else				rr = r * 2 / 3;			wrmixer(s, mixtable[i].left, rl);			wrmixer(s, mixtable[i].right, rr);			break;		}		spin_unlock_irqrestore(&s->lock, flags);		if (!volidx[i])			return -EINVAL;

⌨️ 快捷键说明

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