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

📄 cs4231_lib.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (status & CS4231_PLAYBACK_IRQ) {			if (chip->playback_substream)				snd_pcm_period_elapsed(chip->playback_substream);		}		if (status & CS4231_RECORD_IRQ) {			if (chip->capture_substream) {				snd_cs4231_overrange(chip);				snd_pcm_period_elapsed(chip->capture_substream);			}		}	}	spin_lock(&chip->reg_lock);	snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);	spin_unlock(&chip->reg_lock);	return IRQ_HANDLED;}#ifdef LEGACY_SUPPORTstatic snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))		return 0;	ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);	return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	size_t ptr;		if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))		return 0;	ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);	return bytes_to_frames(substream->runtime, ptr);}#endif /* LEGACY_SUPPORT *//* */static int snd_cs4231_probe(cs4231_t *chip){	unsigned long flags;	int i, id, rev;	unsigned char *ptr;	unsigned int hw;#if 0	snd_cs4231_debug(chip);#endif	id = 0;	for (i = 0; i < 50; i++) {		mb();		if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)			udelay(2000);		else {			spin_lock_irqsave(&chip->reg_lock, flags);			snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);			id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;			spin_unlock_irqrestore(&chip->reg_lock, flags);			if (id == 0x0a)				break;	/* this is valid value */		}	}	snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);	if (id != 0x0a)		return -ENODEV;	/* no valid device found */	if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {		rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7;		snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev);		if (rev == 0x80) {			unsigned char tmp = snd_cs4231_in(chip, 23);			snd_cs4231_out(chip, 23, ~tmp);			if (snd_cs4231_in(chip, 23) != tmp)				chip->hardware = CS4231_HW_AD1845;			else				chip->hardware = CS4231_HW_CS4231;		} else if (rev == 0xa0) {			chip->hardware = CS4231_HW_CS4231A;		} else if (rev == 0xa2) {			chip->hardware = CS4231_HW_CS4232;		} else if (rev == 0xb2) {			chip->hardware = CS4231_HW_CS4232A;		} else if (rev == 0x83) {			chip->hardware = CS4231_HW_CS4236;		} else if (rev == 0x03) {			chip->hardware = CS4231_HW_CS4236B;		} else {			snd_printk("unknown CS chip with version 0x%x\n", rev);			return -ENODEV;		/* unknown CS4231 chip? */		}	}	spin_lock_irqsave(&chip->reg_lock, flags);	cs4231_inb(chip, CS4231P(STATUS));	/* clear any pendings IRQ */	cs4231_outb(chip, CS4231P(STATUS), 0);	mb();	spin_unlock_irqrestore(&chip->reg_lock, flags);	chip->image[CS4231_MISC_INFO] = CS4231_MODE2;	switch (chip->hardware) {	case CS4231_HW_INTERWAVE:		chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3;		break;	case CS4231_HW_CS4235:	case CS4231_HW_CS4236B:	case CS4231_HW_CS4237B:	case CS4231_HW_CS4238B:	case CS4231_HW_CS4239:		if (hw == CS4231_HW_DETECT3)			chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3;		else			chip->hardware = CS4231_HW_CS4236;		break;	}	chip->image[CS4231_IFACE_CTRL] =	    (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |	    (chip->single_dma ? CS4231_SINGLE_DMA : 0);	chip->image[CS4231_ALT_FEATURE_1] = 0x80;	chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;	ptr = (unsigned char *) &chip->image;	snd_cs4231_mce_down(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	for (i = 0; i < 32; i++)	/* ok.. fill all CS4231 registers */		snd_cs4231_out(chip, i, *ptr++);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_cs4231_mce_up(chip);	snd_cs4231_mce_down(chip);	mdelay(2);	/* ok.. try check hardware version for CS4236+ chips */	if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) {		if (chip->hardware == CS4231_HW_CS4236B) {			rev = snd_cs4236_ext_in(chip, CS4236_VERSION);			snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff);			id = snd_cs4236_ext_in(chip, CS4236_VERSION);			snd_cs4236_ext_out(chip, CS4236_VERSION, rev);			snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id);			if ((id & 0x1f) == 0x1d) {	/* CS4235 */				chip->hardware = CS4231_HW_CS4235;				switch (id >> 5) {				case 4:				case 5:				case 6:					break;				default:					snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);				}			} else if ((id & 0x1f) == 0x0b) {	/* CS4236/B */				switch (id >> 5) {				case 4:				case 5:				case 6:				case 7:					chip->hardware = CS4231_HW_CS4236B;					break;				default:					snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);				}			} else if ((id & 0x1f) == 0x08) {	/* CS4237B */				chip->hardware = CS4231_HW_CS4237B;				switch (id >> 5) {				case 4:				case 5:				case 6:				case 7:					break;				default:					snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);				}			} else if ((id & 0x1f) == 0x09) {	/* CS4238B */				chip->hardware = CS4231_HW_CS4238B;				switch (id >> 5) {				case 5:				case 6:				case 7:					break;				default:					snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);				}			} else if ((id & 0x1f) == 0x1e) {	/* CS4239 */				chip->hardware = CS4231_HW_CS4239;				switch (id >> 5) {				case 4:				case 5:				case 6:					break;				default:					snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);				}			} else {				snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);			}		}	}	return 0;		/* all things are ok.. */}/* */static snd_pcm_hardware_t snd_cs4231_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_SYNC_START),	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5510,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static snd_pcm_hardware_t snd_cs4231_capture ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_SYNC_START),	.formats =		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5510,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};/* */static int snd_cs4231_playback_open(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	runtime->hw = snd_cs4231_playback;	/* hardware bug in InterWave chipset */	if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3)	    	runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW;		/* hardware limitation of cheap chips */	if (chip->hardware == CS4231_HW_CS4235 ||	    chip->hardware == CS4231_HW_CS4239)		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;#ifdef LEGACY_SUPPORT	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);	if (chip->claim_dma) {		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)			return err;	}#endif	if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {#ifdef LEGACY_SUPPORT		if (chip->release_dma)			chip->release_dma(chip, chip->dma_private_data, chip->dma1);#endif		snd_free_pages(runtime->dma_area, runtime->dma_bytes);		return err;	}	chip->playback_substream = substream;#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)	chip->p_periods_sent = 0;#endif	snd_pcm_set_sync(substream);	chip->rate_constraint(runtime);	return 0;}static int snd_cs4231_capture_open(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	runtime->hw = snd_cs4231_capture;	/* hardware limitation of cheap chips */	if (chip->hardware == CS4231_HW_CS4235 ||	    chip->hardware == CS4231_HW_CS4239)		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;#ifdef LEGACY_SUPPORT	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);	if (chip->claim_dma) {		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)			return err;	}#endif	if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {#ifdef LEGACY_SUPPORT		if (chip->release_dma)			chip->release_dma(chip, chip->dma_private_data, chip->dma2);#endif		snd_free_pages(runtime->dma_area, runtime->dma_bytes);		return err;	}	chip->capture_substream = substream;#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)	chip->c_periods_sent = 0;#endif	snd_pcm_set_sync(substream);	chip->rate_constraint(runtime);	return 0;}static int snd_cs4231_playback_close(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	chip->playback_substream = NULL;	snd_cs4231_close(chip, CS4231_MODE_PLAY);	return 0;}static int snd_cs4231_capture_close(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	chip->capture_substream = NULL;	snd_cs4231_close(chip, CS4231_MODE_RECORD);	return 0;}#ifdef CONFIG_PM/* lowlevel suspend callback for CS4231 */static void snd_cs4231_suspend(cs4231_t *chip){	int reg;	unsigned long flags;		if (chip->pcm)		snd_pcm_suspend_all(chip->pcm);	spin_lock_irqsave(&chip->reg_lock, flags);	for (reg = 0; reg < 32; reg++)		chip->image[reg] = snd_cs4231_in(chip, reg);	spin_unlock_irqrestore(&chip->reg_lock, flags);}/* lowlevel resume callback for CS4231 */static void snd_cs4231_resume(cs4231_t *chip){	int reg;	unsigned long flags;	int timeout;		snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	for (reg = 0; reg < 32; reg++) {		switch (reg) {		case CS4231_VERSION:			break;		default:			snd_cs4231_out(chip, reg, chip->image[reg]);			break;		}	}	spin_unlock_irqrestore(&chip->reg_lock, flags);#if 0	snd_cs4231_mce_down(chip);#else	/* The following is a workaround to avoid freeze after resume on TP600E.	   This is the first half of copy of snd_cs4231_mce_down(), but doesn't	   include rescheduling.  -- iwai	   */	snd_cs4231_busy_wait(chip);	spin_lock_irqsave(&chip->reg_lock, flags);	chip->mce_bit &= ~CS4231_MCE;	timeout = cs4231_inb(chip, CS4231P(REGSEL));	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));	spin_unlock_irqrestore(&chip->reg_lock, flags);	if (timeout == 0x80)		snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);	if ((timeout & CS4231_MCE) == 0 ||	    !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {		return;	}	snd_cs4231_busy_wait(chip);#endif}static int snd_cs4231_pm_suspend(snd_card_t *card, pm_message_t state){	cs4231_t *chip = card->pm_private_data;	if (chip->suspend)		chip->suspend(chip);	return 0;}static int snd_cs4231_pm_resume(snd_card_t *card){	cs4231_t *chip = card->pm_private_data;	if (chip->resume)		chip->resume(chip);	return 0;}#endif /* CONFIG_PM */#ifdef LEGACY_SUPPORTstatic int snd_cs4231_free(cs4231_t *chip){	release_and_free_resource(chip->res_port);	release_and_free_resource(chip->res_cport);	if (chip->irq >= 0) {		disable_irq(chip->irq);		if (!(chip->hwshare & CS4231_HWSHARE_IRQ))			free_irq(chip->irq, (void *) chip);	}	if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) {		snd_dma_disable(chip->dma1);		free_dma(chip->dma1);	}	if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) {		snd_dma_disable(chip->dma2);		free_dma(chip->dma2);	}	if (chip->timer)		snd_device_free(chip->card, chip->timer);	kfree(chip);	return 0;}static int snd_cs4231_dev_free(snd_device_t *device){	cs4231_t *chip = device->device_data;	return snd_cs4231_free(chip);	}#endif /* LEGACY_SUPPORT */const char *snd_cs4231_chip_id(cs4231_t *chip){	switch (chip->hardware) {	case CS4231_HW_CS4231:	return "CS4231";	case CS4231_HW_CS4231A: return "CS4231A";	case CS4231_HW_CS4232:	return "CS4232";	case CS4231_HW_CS4232A:	return "CS4232A";	case CS4231_HW_CS4235:	return "CS4235";	case CS4231_HW_CS4236:  return "CS4236";	case CS4231_HW_CS4236B: return "CS4236B";	case CS4231_HW_CS4237B: return "CS4237B";	case CS4231_HW_CS4238B: return "CS4238B";	case CS4231_HW_CS4239:	return "CS4239";	case CS4231_HW_INTERWAVE: return "AMD InterWave";	case CS4231_HW_OPL3SA2: return chip->card->shortname;	case CS4231_HW_AD1845: return "AD1845";	default: return "???";	}}static int snd_cs4231_new(snd_card_t * card,			  unsigned short hardware,			  unsigned short hwshare,			  cs4231_t ** rchip){

⌨️ 快捷键说明

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