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

📄 cs4281.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (axes[jst] == 0xFFFF) axes[jst] = -1;	return 0;}#else#define snd_cs4281_gameport_cooked_read	NULL#endifstatic int snd_cs4281_gameport_open(struct gameport *gameport, int mode){	switch (mode) {#ifdef COOKED_MODE	case GAMEPORT_MODE_COOKED:		return 0;#endif	case GAMEPORT_MODE_RAW:		return 0;	default:		return -1;	}	return 0;}static int __devinit snd_cs4281_create_gameport(struct cs4281 *chip){	struct gameport *gp;	chip->gameport = gp = gameport_allocate_port();	if (!gp) {		printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n");		return -ENOMEM;	}	gameport_set_name(gp, "CS4281 Gameport");	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));	gameport_set_dev_parent(gp, &chip->pci->dev);	gp->open = snd_cs4281_gameport_open;	gp->read = snd_cs4281_gameport_read;	gp->trigger = snd_cs4281_gameport_trigger;	gp->cooked_read = snd_cs4281_gameport_cooked_read;	gameport_set_port_data(gp, chip);	snd_cs4281_pokeBA0(chip, BA0_JSIO, 0xFF); // ?	snd_cs4281_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);	gameport_register_port(gp);	return 0;}static void snd_cs4281_free_gameport(struct cs4281 *chip){	if (chip->gameport) {		gameport_unregister_port(chip->gameport);		chip->gameport = NULL;	}}#elsestatic inline int snd_cs4281_create_gameport(struct cs4281 *chip) { return -ENOSYS; }static inline void snd_cs4281_free_gameport(struct cs4281 *chip) { }#endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */static int snd_cs4281_free(struct cs4281 *chip){	snd_cs4281_free_gameport(chip);	if (chip->irq >= 0)		synchronize_irq(chip->irq);	/* Mask interrupts */	snd_cs4281_pokeBA0(chip, BA0_HIMR, 0x7fffffff);	/* Stop the DLL Clock logic. */	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, 0);	/* Sound System Power Management - Turn Everything OFF */	snd_cs4281_pokeBA0(chip, BA0_SSPM, 0);	/* PCI interface - D3 state */	pci_set_power_state(chip->pci, 3);	if (chip->irq >= 0)		free_irq(chip->irq, chip);	if (chip->ba0)		iounmap(chip->ba0);	if (chip->ba1)		iounmap(chip->ba1);	pci_release_regions(chip->pci);	pci_disable_device(chip->pci);	kfree(chip);	return 0;}static int snd_cs4281_dev_free(struct snd_device *device){	struct cs4281 *chip = device->device_data;	return snd_cs4281_free(chip);}static int snd_cs4281_chip_init(struct cs4281 *chip); /* defined below */static int __devinit snd_cs4281_create(struct snd_card *card,				       struct pci_dev *pci,				       struct cs4281 ** rchip,				       int dual_codec){	struct cs4281 *chip;	unsigned int tmp;	int err;	static struct snd_device_ops ops = {		.dev_free =	snd_cs4281_dev_free,	};	*rchip = NULL;	if ((err = pci_enable_device(pci)) < 0)		return err;	chip = kzalloc(sizeof(*chip), GFP_KERNEL);	if (chip == NULL) {		pci_disable_device(pci);		return -ENOMEM;	}	spin_lock_init(&chip->reg_lock);	chip->card = card;	chip->pci = pci;	chip->irq = -1;	pci_set_master(pci);	if (dual_codec < 0 || dual_codec > 3) {		snd_printk(KERN_ERR "invalid dual_codec option %d\n", dual_codec);		dual_codec = 0;	}	chip->dual_codec = dual_codec;	if ((err = pci_request_regions(pci, "CS4281")) < 0) {		kfree(chip);		pci_disable_device(pci);		return err;	}	chip->ba0_addr = pci_resource_start(pci, 0);	chip->ba1_addr = pci_resource_start(pci, 1);	chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));	chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));	if (!chip->ba0 || !chip->ba1) {		snd_cs4281_free(chip);		return -ENOMEM;	}		if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,			"CS4281", chip)) {		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);		snd_cs4281_free(chip);		return -ENOMEM;	}	chip->irq = pci->irq;	tmp = snd_cs4281_chip_init(chip);	if (tmp) {		snd_cs4281_free(chip);		return tmp;	}	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {		snd_cs4281_free(chip);		return err;	}	snd_cs4281_proc_init(chip);	snd_card_set_dev(card, &pci->dev);	*rchip = chip;	return 0;}static int snd_cs4281_chip_init(struct cs4281 *chip){	unsigned int tmp;	unsigned long end_time;	int retry_count = 2;	/* Having EPPMC.FPDN=1 prevent proper chip initialisation */	tmp = snd_cs4281_peekBA0(chip, BA0_EPPMC);	if (tmp & BA0_EPPMC_FPDN)		snd_cs4281_pokeBA0(chip, BA0_EPPMC, tmp & ~BA0_EPPMC_FPDN);      __retry:	tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);	if (tmp != BA0_CFLR_DEFAULT) {		snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT);		tmp = snd_cs4281_peekBA0(chip, BA0_CFLR);		if (tmp != BA0_CFLR_DEFAULT) {			snd_printk(KERN_ERR "CFLR setup failed (0x%x)\n", tmp);			return -EIO;		}	}	/* Set the 'Configuration Write Protect' register	 * to 4281h.  Allows vendor-defined configuration         * space between 0e4h and 0ffh to be written. */		snd_cs4281_pokeBA0(chip, BA0_CWPR, 0x4281);		if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) {		snd_printk(KERN_ERR "SERC1 AC'97 check failed (0x%x)\n", tmp);		return -EIO;	}	if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) {		snd_printk(KERN_ERR "SERC2 AC'97 check failed (0x%x)\n", tmp);		return -EIO;	}	/* Sound System Power Management */	snd_cs4281_pokeBA0(chip, BA0_SSPM, BA0_SSPM_MIXEN | BA0_SSPM_CSRCEN |				           BA0_SSPM_PSRCEN | BA0_SSPM_JSEN |				           BA0_SSPM_ACLEN | BA0_SSPM_FMEN);	/* Serial Port Power Management */ 	/* Blast the clock control register to zero so that the         * PLL starts out in a known state, and blast the master serial         * port control register to zero so that the serial ports also         * start out in a known state. */	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, 0);	snd_cs4281_pokeBA0(chip, BA0_SERMC, 0);        /* Make ESYN go to zero to turn off         * the Sync pulse on the AC97 link. */	snd_cs4281_pokeBA0(chip, BA0_ACCTL, 0);	udelay(50);                	/*  Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97	 *  spec) and then drive it high.  This is done for non AC97 modes since	 *  there might be logic external to the CS4281 that uses the ARST# line	 *  for a reset. */	snd_cs4281_pokeBA0(chip, BA0_SPMC, 0);	udelay(50);	snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN);	msleep(50);	if (chip->dual_codec)		snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN | BA0_SPMC_ASDI2E);	/*	 *  Set the serial port timing configuration.	 */	snd_cs4281_pokeBA0(chip, BA0_SERMC,			   (chip->dual_codec ? BA0_SERMC_TCID(chip->dual_codec) : BA0_SERMC_TCID(1)) |			   BA0_SERMC_PTC_AC97 | BA0_SERMC_MSPE);	/*	 *  Start the DLL Clock logic.	 */	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_DLLP);	msleep(50);	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_SWCE | BA0_CLKCR1_DLLP);	/*	 * Wait for the DLL ready signal from the clock logic.	 */	end_time = jiffies + HZ;	do {		/*		 *  Read the AC97 status register to see if we've seen a CODEC		 *  signal from the AC97 codec.		 */		if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY)			goto __ok0;		schedule_timeout_uninterruptible(1);	} while (time_after_eq(end_time, jiffies));	snd_printk(KERN_ERR "DLLRDY not seen\n");	return -EIO;      __ok0:	/*	 *  The first thing we do here is to enable sync generation.  As soon	 *  as we start receiving bit clock, we'll start producing the SYNC	 *  signal.	 */	snd_cs4281_pokeBA0(chip, BA0_ACCTL, BA0_ACCTL_ESYN);	/*	 * Wait for the codec ready signal from the AC97 codec.	 */	end_time = jiffies + HZ;	do {		/*		 *  Read the AC97 status register to see if we've seen a CODEC		 *  signal from the AC97 codec.		 */		if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY)			goto __ok1;		schedule_timeout_uninterruptible(1);	} while (time_after_eq(end_time, jiffies));	snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));	return -EIO;      __ok1:	if (chip->dual_codec) {		end_time = jiffies + HZ;		do {			if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY)				goto __codec2_ok;			schedule_timeout_uninterruptible(1);		} while (time_after_eq(end_time, jiffies));		snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");		chip->dual_codec = 0;	__codec2_ok: ;	}	/*	 *  Assert the valid frame signal so that we can start sending commands	 *  to the AC97 codec.	 */	snd_cs4281_pokeBA0(chip, BA0_ACCTL, BA0_ACCTL_VFRM | BA0_ACCTL_ESYN);	/*	 *  Wait until we've sampled input slots 3 and 4 as valid, meaning that	 *  the codec is pumping ADC data across the AC-link.	 */	end_time = jiffies + HZ;	do {		/*		 *  Read the input slot valid register and see if input slots 3		 *  4 are valid yet.		 */                if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4)))                        goto __ok2;		schedule_timeout_uninterruptible(1);	} while (time_after_eq(end_time, jiffies));	if (--retry_count > 0)		goto __retry;	snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n");	return -EIO;      __ok2:	/*	 *  Now, assert valid frame and the slot 3 and 4 valid bits.  This will	 *  commense the transfer of digital audio data to the AC97 codec.	 */	snd_cs4281_pokeBA0(chip, BA0_ACOSV, BA0_ACOSV_SLV(3) | BA0_ACOSV_SLV(4));	/*	 *  Initialize DMA structures	 */	for (tmp = 0; tmp < 4; tmp++) {		struct cs4281_dma *dma = &chip->dma[tmp];		dma->regDBA = BA0_DBA0 + (tmp * 0x10);		dma->regDCA = BA0_DCA0 + (tmp * 0x10);		dma->regDBC = BA0_DBC0 + (tmp * 0x10);		dma->regDCC = BA0_DCC0 + (tmp * 0x10);		dma->regDMR = BA0_DMR0 + (tmp * 8);		dma->regDCR = BA0_DCR0 + (tmp * 8);		dma->regHDSR = BA0_HDSR0 + (tmp * 4);		dma->regFCR = BA0_FCR0 + (tmp * 4);		dma->regFSIC = BA0_FSIC0 + (tmp * 4);		dma->fifo_offset = tmp * CS4281_FIFO_SIZE;		snd_cs4281_pokeBA0(chip, dma->regFCR,				   BA0_FCR_LS(31) |				   BA0_FCR_RS(31) |				   BA0_FCR_SZ(CS4281_FIFO_SIZE) |				   BA0_FCR_OF(dma->fifo_offset));	}	chip->src_left_play_slot = 0;	/* AC'97 left PCM playback (3) */	chip->src_right_play_slot = 1;	/* AC'97 right PCM playback (4) */	chip->src_left_rec_slot = 10;	/* AC'97 left PCM record (3) */	chip->src_right_rec_slot = 11;	/* AC'97 right PCM record (4) */	/* Activate wave playback FIFO for FM playback */	chip->dma[0].valFCR = BA0_FCR_FEN | BA0_FCR_LS(0) |		              BA0_FCR_RS(1) | 	  	              BA0_FCR_SZ(CS4281_FIFO_SIZE) |		              BA0_FCR_OF(chip->dma[0].fifo_offset);	snd_cs4281_pokeBA0(chip, chip->dma[0].regFCR, chip->dma[0].valFCR);	snd_cs4281_pokeBA0(chip, BA0_SRCSA, (chip->src_left_play_slot << 0) |					    (chip->src_right_play_slot << 8) |					    (chip->src_left_rec_slot << 16) |					    (chip->src_right_rec_slot << 24));	/* Initialize digital volume */	snd_cs4281_pokeBA0(chip, BA0_PPLVC, 0);	snd_cs4281_pokeBA0(chip, BA0_PPRVC, 0);	/* Enable IRQs */	snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_EOI);	/* Unmask interrupts */	snd_cs4281_pokeBA0(chip, BA0_HIMR, 0x7fffffff & ~(					BA0_HISR_MIDI |					BA0_HISR_DMAI |					BA0_HISR_DMA(0) |					BA0_HISR_DMA(1) |					BA0_HISR_DMA(2) |					BA0_HISR_DMA(3)));	synchronize_irq(chip->irq);	return 0;}/* *  MIDI section */static void snd_cs4281_midi_reset(struct cs4281 *chip){	snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr | BA0_MIDCR_MRST);	udelay(100);	snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);}static int snd_cs4281_midi_input_open(struct snd_rawmidi_substream *substream){	struct cs4281 *chip = substream->rmidi->private_data;

⌨️ 快捷键说明

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