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

📄 nm256.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	switch (cmd) {	case SNDRV_PCM_TRIGGER_RESUME:		s->suspended = 0;		/* fallthru */	case SNDRV_PCM_TRIGGER_START:		if (! s->running) {			snd_nm256_playback_start(chip, s, substream);			s->running = 1;		}		break;	case SNDRV_PCM_TRIGGER_SUSPEND:		s->suspended = 1;		/* fallthru */	case SNDRV_PCM_TRIGGER_STOP:		if (s->running) {			snd_nm256_playback_stop(chip);			s->running = 0;		}		break;	default:		err = -EINVAL;		break;	}	spin_unlock(&chip->reg_lock);	return err;}static intsnd_nm256_capture_trigger(snd_pcm_substream_t *substream, int cmd){	nm256_t *chip = snd_pcm_substream_chip(substream);	nm256_stream_t *s = (nm256_stream_t*)substream->runtime->private_data;	int err = 0;	snd_assert(s != NULL, return -ENXIO);	spin_lock(&chip->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (! s->running) {			snd_nm256_capture_start(chip, s, substream);			s->running = 1;		}		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		if (s->running) {			snd_nm256_capture_stop(chip);			s->running = 0;		}		break;	default:		err = -EINVAL;		break;	}	spin_unlock(&chip->reg_lock);	return err;}/* * prepare playback/capture channel */static int snd_nm256_pcm_prepare(snd_pcm_substream_t *substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	nm256_stream_t *s = (nm256_stream_t*)runtime->private_data;	snd_assert(s, return -ENXIO);	s->dma_size = frames_to_bytes(runtime, substream->runtime->buffer_size);	s->period_size = frames_to_bytes(runtime, substream->runtime->period_size);	s->periods = substream->runtime->periods;	s->cur_period = 0;	spin_lock_irq(&chip->reg_lock);	s->running = 0;	snd_nm256_set_format(chip, s, substream);	spin_unlock_irq(&chip->reg_lock);	return 0;}/* * get the current pointer */static snd_pcm_uframes_tsnd_nm256_playback_pointer(snd_pcm_substream_t * substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	nm256_stream_t *s = (nm256_stream_t*)substream->runtime->private_data;	unsigned long curp;	snd_assert(s, return 0);	curp = snd_nm256_readl(chip, NM_PBUFFER_CURRP) - (unsigned long)s->buf;	curp %= s->dma_size;	return bytes_to_frames(substream->runtime, curp);}static snd_pcm_uframes_tsnd_nm256_capture_pointer(snd_pcm_substream_t * substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	nm256_stream_t *s = (nm256_stream_t*)substream->runtime->private_data;	unsigned long curp;	snd_assert(s != NULL, return 0);	curp = snd_nm256_readl(chip, NM_RBUFFER_CURRP) - (unsigned long)s->buf;	curp %= s->dma_size;		return bytes_to_frames(substream->runtime, curp);}/* Remapped I/O space can be accessible as pointer on i386 *//* This might be changed in the future */#ifndef __i386__/* * silence / copy for playback */static intsnd_nm256_playback_silence(snd_pcm_substream_t *substream,			   int channel, /* not used (interleaved data) */			   snd_pcm_uframes_t pos,			   snd_pcm_uframes_t count){	snd_pcm_runtime_t *runtime = substream->runtime;	nm256_stream_t *s = (nm256_stream_t*)runtime->private_data;	count = frames_to_bytes(runtime, count);	pos = frames_to_bytes(runtime, pos);	memset_io(s->bufptr + pos, 0, count);	return 0;}static intsnd_nm256_playback_copy(snd_pcm_substream_t *substream,			int channel, /* not used (interleaved data) */			snd_pcm_uframes_t pos,			void __user *src,			snd_pcm_uframes_t count){	snd_pcm_runtime_t *runtime = substream->runtime;	nm256_stream_t *s = (nm256_stream_t*)runtime->private_data;	count = frames_to_bytes(runtime, count);	pos = frames_to_bytes(runtime, pos);	if (copy_from_user_toio(s->bufptr + pos, src, count))		return -EFAULT;	return 0;}/* * copy to user */static intsnd_nm256_capture_copy(snd_pcm_substream_t *substream,		       int channel, /* not used (interleaved data) */		       snd_pcm_uframes_t pos,		       void __user *dst,		       snd_pcm_uframes_t count){	snd_pcm_runtime_t *runtime = substream->runtime;	nm256_stream_t *s = (nm256_stream_t*)runtime->private_data;	count = frames_to_bytes(runtime, count);	pos = frames_to_bytes(runtime, pos);	if (copy_to_user_fromio(dst, s->bufptr + pos, count))		return -EFAULT;	return 0;}#endif /* !__i386__ *//* * update playback/capture watermarks *//* spinlock held! */static voidsnd_nm256_playback_update(nm256_t *chip){	nm256_stream_t *s;	s = &chip->streams[SNDRV_PCM_STREAM_PLAYBACK];	if (s->running && s->substream) {		spin_unlock(&chip->reg_lock);		snd_pcm_period_elapsed(s->substream);		spin_lock(&chip->reg_lock);		snd_nm256_playback_mark(chip, s);	}}/* spinlock held! */static voidsnd_nm256_capture_update(nm256_t *chip){	nm256_stream_t *s;	s = &chip->streams[SNDRV_PCM_STREAM_CAPTURE];	if (s->running && s->substream) {		spin_unlock(&chip->reg_lock);		snd_pcm_period_elapsed(s->substream);		spin_lock(&chip->reg_lock);		snd_nm256_capture_mark(chip, s);	}}/* * hardware info */static snd_pcm_hardware_t snd_nm256_playback ={	.info =			SNDRV_PCM_INFO_MMAP_IOMEM |SNDRV_PCM_INFO_MMAP_VALID |				SNDRV_PCM_INFO_INTERLEAVED |				/*SNDRV_PCM_INFO_PAUSE |*/				SNDRV_PCM_INFO_RESUME,	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_KNOT/*24k*/ | SNDRV_PCM_RATE_8000_48000,	.rate_min =		8000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.periods_min =		2,	.periods_max =		1024,	.buffer_bytes_max =	128 * 1024,	.period_bytes_min =	256,	.period_bytes_max =	128 * 1024,};static snd_pcm_hardware_t snd_nm256_capture ={	.info =			SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID |				SNDRV_PCM_INFO_INTERLEAVED |				/*SNDRV_PCM_INFO_PAUSE |*/				SNDRV_PCM_INFO_RESUME,	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_KNOT/*24k*/ | SNDRV_PCM_RATE_8000_48000,	.rate_min =		8000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.periods_min =		2,	.periods_max =		1024,	.buffer_bytes_max =	128 * 1024,	.period_bytes_min =	256,	.period_bytes_max =	128 * 1024,};/* set dma transfer size */static int snd_nm256_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params){	/* area and addr are already set and unchanged */	substream->runtime->dma_bytes = params_buffer_bytes(hw_params);	return 0;}/* * open */static void snd_nm256_setup_stream(nm256_t *chip, nm256_stream_t *s,				   snd_pcm_substream_t *substream,				   snd_pcm_hardware_t *hw_ptr){	snd_pcm_runtime_t *runtime = substream->runtime;	s->running = 0;	runtime->hw = *hw_ptr;	runtime->hw.buffer_bytes_max = s->bufsize;	runtime->hw.period_bytes_max = s->bufsize / 2;	runtime->dma_area = (void __force *) s->bufptr;	runtime->dma_addr = s->bufptr_addr;	runtime->dma_bytes = s->bufsize;	runtime->private_data = s;	s->substream = substream;	snd_pcm_set_sync(substream);	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				   &constraints_rates);}static intsnd_nm256_playback_open(snd_pcm_substream_t *substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	if (snd_nm256_acquire_irq(chip) < 0)		return -EBUSY;	snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],			       substream, &snd_nm256_playback);	return 0;}static intsnd_nm256_capture_open(snd_pcm_substream_t *substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	if (snd_nm256_acquire_irq(chip) < 0)		return -EBUSY;	snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],			       substream, &snd_nm256_capture);	return 0;}/* * close - we don't have to do special.. */static intsnd_nm256_playback_close(snd_pcm_substream_t *substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	snd_nm256_release_irq(chip);	return 0;}static intsnd_nm256_capture_close(snd_pcm_substream_t *substream){	nm256_t *chip = snd_pcm_substream_chip(substream);	snd_nm256_release_irq(chip);	return 0;}/* * create a pcm instance */static snd_pcm_ops_t snd_nm256_playback_ops = {	.open =		snd_nm256_playback_open,	.close =	snd_nm256_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_nm256_pcm_hw_params,	.prepare =	snd_nm256_pcm_prepare,	.trigger =	snd_nm256_playback_trigger,	.pointer =	snd_nm256_playback_pointer,#ifndef __i386__	.copy =		snd_nm256_playback_copy,	.silence =	snd_nm256_playback_silence,#endif	.mmap =		snd_pcm_lib_mmap_iomem,};static snd_pcm_ops_t snd_nm256_capture_ops = {	.open =		snd_nm256_capture_open,	.close =	snd_nm256_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_nm256_pcm_hw_params,	.prepare =	snd_nm256_pcm_prepare,	.trigger =	snd_nm256_capture_trigger,	.pointer =	snd_nm256_capture_pointer,#ifndef __i386__	.copy =		snd_nm256_capture_copy,#endif	.mmap =		snd_pcm_lib_mmap_iomem,};static int __devinitsnd_nm256_pcm(nm256_t *chip, int device){	snd_pcm_t *pcm;	int i, err;	for (i = 0; i < 2; i++) {		nm256_stream_t *s = &chip->streams[i];		s->bufptr = chip->buffer + (s->buf - chip->buffer_start);		s->bufptr_addr = chip->buffer_addr + (s->buf - chip->buffer_start);	}	err = snd_pcm_new(chip->card, chip->card->driver, device,			  1, 1, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_nm256_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_nm256_capture_ops);	pcm->private_data = chip;	pcm->info_flags = 0;	chip->pcm = pcm;	return 0;}/*  * Initialize the hardware.  */static voidsnd_nm256_init_chip(nm256_t *chip){	/* Reset everything. */	snd_nm256_writeb(chip, 0x0, 0x11);	snd_nm256_writew(chip, 0x214, 0);	/* stop sounds.. */	//snd_nm256_playback_stop(chip);	//snd_nm256_capture_stop(chip);}static irqreturn_tsnd_nm256_intr_check(nm256_t *chip){	if (chip->badintrcount++ > 1000) {		/*		 * I'm not sure if the best thing is to stop the card from		 * playing or just release the interrupt (after all, we're in		 * a bad situation, so doing fancy stuff may not be such a good		 * idea).		 *		 * I worry about the card engine continuing to play noise		 * over and over, however--that could become a very		 * obnoxious problem.  And we know that when this usually		 * happens things are fairly safe, it just means the user's		 * inserted a PCMCIA card and someone's spamming us with IRQ 9s.		 */		if (chip->streams[SNDRV_PCM_STREAM_PLAYBACK].running)			snd_nm256_playback_stop(chip);		if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)			snd_nm256_capture_stop(chip);		chip->badintrcount = 0;		return IRQ_HANDLED;	}	return IRQ_NONE;}/*  * Handle a potential interrupt for the device referred to by DEV_ID.  * * I don't like the cut-n-paste job here either between the two routines, * but there are sufficient differences between the two interrupt handlers * that parameterizing it isn't all that great either.  (Could use a macro, * I suppose...yucky bleah.) */static irqreturn_tsnd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy){	nm256_t *chip = dev_id;	u16 status;	u8 cbyte;	status = snd_nm256_readw(chip, NM_INT_REG);	/* Not ours. */	if (status == 0)		return snd_nm256_intr_check(chip);	chip->badintrcount = 0;	/* Rather boring; check for individual interrupts and process them. */	spin_lock(&chip->reg_lock);	if (status & NM_PLAYBACK_INT) {		status &= ~NM_PLAYBACK_INT;		NM_ACK_INT(chip, NM_PLAYBACK_INT);		snd_nm256_playback_update(chip);	}	if (status & NM_RECORD_INT) {		status &= ~NM_RECORD_INT;		NM_ACK_INT(chip, NM_RECORD_INT);		snd_nm256_capture_update(chip);	}	if (status & NM_MISC_INT_1) {		status &= ~NM_MISC_INT_1;		NM_ACK_INT(chip, NM_MISC_INT_1);		snd_printd("NM256: Got misc interrupt #1\n");		snd_nm256_writew(chip, NM_INT_REG, 0x8000);		cbyte = snd_nm256_readb(chip, 0x400);		snd_nm256_writeb(chip, 0x400, cbyte | 2);	}	if (status & NM_MISC_INT_2) {		status &= ~NM_MISC_INT_2;		NM_ACK_INT(chip, NM_MISC_INT_2);		snd_printd("NM256: Got misc interrupt #2\n");		cbyte = snd_nm256_readb(chip, 0x400);		snd_nm256_writeb(chip, 0x400, cbyte & ~2);	}	/* Unknown interrupt. */	if (status) {		snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n",			   status);		/* Pray. */		NM_ACK_INT(chip, status);	}	spin_unlock(&chip->reg_lock);	return IRQ_HANDLED;}/* * Handle a potential interrupt for the device referred to by DEV_ID. * This handler is for the 256ZX, and is very similar to the non-ZX * routine. */static irqreturn_tsnd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy){	nm256_t *chip = dev_id;	u32 status;	u8 cbyte;	status = snd_nm256_readl(chip, NM_INT_REG);	/* Not ours. */	if (status == 0)		return snd_nm256_intr_check(chip);	chip->badintrcount = 0;	/* Rather boring; check for individual interrupts and process them. */	spin_lock(&chip->reg_lock);	if (status & NM2_PLAYBACK_INT) {		status &= ~NM2_PLAYBACK_INT;		NM2_ACK_INT(chip, NM2_PLAYBACK_INT);		snd_nm256_playback_update(chip);	}	if (status & NM2_RECORD_INT) {		status &= ~NM2_RECORD_INT;		NM2_ACK_INT(chip, NM2_RECORD_INT);		snd_nm256_capture_update(chip);	}	if (status & NM2_MISC_INT_1) {		status &= ~NM2_MISC_INT_1;		NM2_ACK_INT(chip, NM2_MISC_INT_1);		snd_printd("NM256: Got misc interrupt #1\n");		cbyte = snd_nm256_readb(chip, 0x400);		snd_nm256_writeb(chip, 0x400, cbyte | 2);	}	if (status & NM2_MISC_INT_2) {		status &= ~NM2_MISC_INT_2;		NM2_ACK_INT(chip, NM2_MISC_INT_2);		snd_printd("NM256: Got misc interrupt #2\n");		cbyte = snd_nm256_readb(chip, 0x400);		snd_nm256_writeb(chip, 0x400, cbyte & ~2);	}	/* Unknown interrupt. */	if (status) {		snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n",			   status);		/* Pray. */		NM2_ACK_INT(chip, status);	}	spin_unlock(&chip->reg_lock);	return IRQ_HANDLED;}/* * AC97 interface *//* * Waits for the mixer to become ready to be written; returns a zero value

⌨️ 快捷键说明

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