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

📄 nm256.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
static intsnd_nm256_capture_close(struct snd_pcm_substream *substream){	struct nm256 *chip = snd_pcm_substream_chip(substream);	snd_nm256_release_irq(chip);	return 0;}/* * create a pcm instance */static struct snd_pcm_ops 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 struct snd_pcm_ops 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(struct nm256 *chip, int device){	struct snd_pcm *pcm;	int i, err;	for (i = 0; i < 2; i++) {		struct nm256_stream *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(struct nm256 *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(struct nm256 *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 nm256 *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 nm256 *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 * if it timed out. */static intsnd_nm256_ac97_ready(struct nm256 *chip){	int timeout = 10;	u32 testaddr;	u16 testb;	testaddr = chip->mixer_status_offset;	testb = chip->mixer_status_mask;	/* 	 * Loop around waiting for the mixer to become ready. 	 */	while (timeout-- > 0) {		if ((snd_nm256_readw(chip, testaddr) & testb) == 0)			return 1;		udelay(100);	}	return 0;}/*  * Initial register values to be written to the AC97 mixer. * While most of these are identical to the reset values, we do this * so that we have most of the register contents cached--this avoids * reading from the mixer directly (which seems to be problematic, * probably due to ignorance). */struct initialValues {	unsigned short reg;	unsigned short value;};static struct initialValues nm256_ac97_init_val[] ={	{ AC97_MASTER, 		0x8000 },	{ AC97_HEADPHONE,	0x8000 },	{ AC97_MASTER_MONO,	0x8000 },	{ AC97_PC_BEEP,		0x8000 },	{ AC97_PHONE,		0x8008 },	{ AC97_MIC,		0x8000 },	{ AC97_LINE,		0x8808 },	{ AC97_CD,		0x8808 },	{ AC97_VIDEO,		0x8808 },	{ AC97_AUX,		0x8808 },	{ AC97_PCM,		0x8808 },	{ AC97_REC_SEL,		0x0000 },	{ AC97_REC_GAIN,	0x0B0B },	{ AC97_GENERAL_PURPOSE,	0x0000 },	{ AC97_3D_CONTROL,	0x8000 }, 	{ AC97_VENDOR_ID1, 	0x8384 },	{ AC97_VENDOR_ID2,	0x7609 },};static int nm256_ac97_idx(unsigned short reg){	int i;	for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++)		if (nm256_ac97_init_val[i].reg == reg)			return i;	return -1;}/* * some nm256 easily crash when reading from mixer registers * thus we're treating it as a write-only mixer and cache the * written values */static unsigned shortsnd_nm256_ac97_read(struct snd_ac97 *ac97, unsigned short reg){	struct nm256 *chip = ac97->private_data;	int idx = nm256_ac97_idx(reg);	if (idx < 0)		return 0;	return chip->ac97_regs[idx];}/*  */static voidsnd_nm256_ac97_write(struct snd_ac97 *ac97,		     unsigned short reg, unsigned short val){	struct nm256 *chip = ac97->private_data;	int tries = 2;	int idx = nm256_ac97_idx(reg);	u32 base;	if (idx < 0)		return;	base = chip->mixer_base;	snd_nm256_ac97_ready(chip);	/* Wait for the write to take, too. */	while (tries-- > 0) {		snd_nm256_writew(chip, base + reg, val);		msleep(1);  /* a little delay here seems better.. */		if (snd_nm256_ac97_ready(chip)) {			/* successful write: set cache */			chip->ac97_regs[idx] = val;			return;		}	}	snd_printd("nm256: ac97 codec not ready..\n");}/* static resolution table */static struct snd_ac97_res_table nm256_res_table[] = {	{ AC97_MASTER, 0x1f1f },	{ AC97_HEADPHONE, 0x1f1f },	{ AC97_MASTER_MONO, 0x001f },	{ AC97_PC_BEEP, 0x001f },	{ AC97_PHONE, 0x001f },	{ AC97_MIC, 0x001f },	{ AC97_LINE, 0x1f1f },	{ AC97_CD, 0x1f1f },	{ AC97_VIDEO, 0x1f1f },	{ AC97_AUX, 0x1f1f },	{ AC97_PCM, 0x1f1f },	{ AC97_REC_GAIN, 0x0f0f },	{ } /* terminator */};/* initialize the ac97 into a known state */static voidsnd_nm256_ac97_reset(struct snd_ac97 *ac97){	struct nm256 *chip = ac97->private_data;	/* Reset the mixer.  'Tis magic!  */	snd_nm256_writeb(chip, 0x6c0, 1);	if (! chip->reset_workaround) {		/* Dell latitude LS will lock up by this */		snd_nm256_writeb(chip, 0x6cc, 0x87);	}	if (! chip->reset_workaround_2) {		/* Dell latitude CSx will lock up by this */		snd_nm256_writeb(chip, 0x6cc, 0x80);		snd_nm256_writeb(chip, 0x6cc, 0x0);	}	if (! chip->in_resume) {		int i;		for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++) {			/* preload the cache, so as to avoid even a single			 * read of the mixer regs			 */			snd_nm256_ac97_write(ac97, nm256_ac97_init_val[i].reg,					     nm256_ac97_init_val[i].value);		}	}}/* create an ac97 mixer interface */static int __devinitsnd_nm256_mixer(struct nm256 *chip){	struct snd_ac97_bus *pbus;	struct snd_ac97_template ac97;	int err;	static struct snd_ac97_bus_ops ops = {		.reset = snd_nm256_ac97_reset,		.write = snd_nm256_ac97_write,		.read = snd_nm256_ac97_read,	};	chip->ac97_regs = kcalloc(sizeof(short),				  ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL);	if (! chip->ac97_regs)		return -ENOMEM;	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)		return err;	memset(&ac97, 0, sizeof(ac97));	ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */	ac97.private_data = chip;	ac97.res_table = nm256_res_table;	pbus->no_vra = 1;	err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);	if (err < 0)		return err;	if (! (chip->ac97->id & (0xf0000000))) {		/* looks like an invalid id */		sprintf(chip->card->mixername, "%s AC97", chip->card->driver);	}	return 0;

⌨️ 快捷键说明

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