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

📄 cs4281.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	spin_lock_irq(&chip->reg_lock); 	chip->midcr |= BA0_MIDCR_RXE;	chip->midi_input = substream;	if (!(chip->uartm & CS4281_MODE_OUTPUT)) {		snd_cs4281_midi_reset(chip);	} else {		snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);	}	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_cs4281_midi_input_close(struct snd_rawmidi_substream *substream){	struct cs4281 *chip = substream->rmidi->private_data;	spin_lock_irq(&chip->reg_lock);	chip->midcr &= ~(BA0_MIDCR_RXE | BA0_MIDCR_RIE);	chip->midi_input = NULL;	if (!(chip->uartm & CS4281_MODE_OUTPUT)) {		snd_cs4281_midi_reset(chip);	} else {		snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);	}	chip->uartm &= ~CS4281_MODE_INPUT;	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_cs4281_midi_output_open(struct snd_rawmidi_substream *substream){	struct cs4281 *chip = substream->rmidi->private_data;	spin_lock_irq(&chip->reg_lock);	chip->uartm |= CS4281_MODE_OUTPUT;	chip->midcr |= BA0_MIDCR_TXE;	chip->midi_output = substream;	if (!(chip->uartm & CS4281_MODE_INPUT)) {		snd_cs4281_midi_reset(chip);	} else {		snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);	}	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_cs4281_midi_output_close(struct snd_rawmidi_substream *substream){	struct cs4281 *chip = substream->rmidi->private_data;	spin_lock_irq(&chip->reg_lock);	chip->midcr &= ~(BA0_MIDCR_TXE | BA0_MIDCR_TIE);	chip->midi_output = NULL;	if (!(chip->uartm & CS4281_MODE_INPUT)) {		snd_cs4281_midi_reset(chip);	} else {		snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);	}	chip->uartm &= ~CS4281_MODE_OUTPUT;	spin_unlock_irq(&chip->reg_lock);	return 0;}static void snd_cs4281_midi_input_trigger(struct snd_rawmidi_substream *substream, int up){	unsigned long flags;	struct cs4281 *chip = substream->rmidi->private_data;	spin_lock_irqsave(&chip->reg_lock, flags);	if (up) {		if ((chip->midcr & BA0_MIDCR_RIE) == 0) {			chip->midcr |= BA0_MIDCR_RIE;			snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	} else {		if (chip->midcr & BA0_MIDCR_RIE) {			chip->midcr &= ~BA0_MIDCR_RIE;			snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	}	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substream, int up){	unsigned long flags;	struct cs4281 *chip = substream->rmidi->private_data;	unsigned char byte;	spin_lock_irqsave(&chip->reg_lock, flags);	if (up) {		if ((chip->midcr & BA0_MIDCR_TIE) == 0) {			chip->midcr |= BA0_MIDCR_TIE;			/* fill UART FIFO buffer at first, and turn Tx interrupts only if necessary */			while ((chip->midcr & BA0_MIDCR_TIE) &&			       (snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_TBF) == 0) {				if (snd_rawmidi_transmit(substream, &byte, 1) != 1) {					chip->midcr &= ~BA0_MIDCR_TIE;				} else {					snd_cs4281_pokeBA0(chip, BA0_MIDWP, byte);				}			}			snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	} else {		if (chip->midcr & BA0_MIDCR_TIE) {			chip->midcr &= ~BA0_MIDCR_TIE;			snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	}	spin_unlock_irqrestore(&chip->reg_lock, flags);}static struct snd_rawmidi_ops snd_cs4281_midi_output ={	.open =		snd_cs4281_midi_output_open,	.close =	snd_cs4281_midi_output_close,	.trigger =	snd_cs4281_midi_output_trigger,};static struct snd_rawmidi_ops snd_cs4281_midi_input ={	.open = 	snd_cs4281_midi_input_open,	.close =	snd_cs4281_midi_input_close,	.trigger =	snd_cs4281_midi_input_trigger,};static int __devinit snd_cs4281_midi(struct cs4281 * chip, int device,				     struct snd_rawmidi **rrawmidi){	struct snd_rawmidi *rmidi;	int err;	if (rrawmidi)		*rrawmidi = NULL;	if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0)		return err;	strcpy(rmidi->name, "CS4281");	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs4281_midi_output);	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_cs4281_midi_input);	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;	rmidi->private_data = chip;	chip->rmidi = rmidi;	if (rrawmidi)		*rrawmidi = rmidi;	return 0;}/* *  Interrupt handler */static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id){	struct cs4281 *chip = dev_id;	unsigned int status, dma, val;	struct cs4281_dma *cdma;	if (chip == NULL)		return IRQ_NONE;	status = snd_cs4281_peekBA0(chip, BA0_HISR);	if ((status & 0x7fffffff) == 0) {		snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_EOI);		return IRQ_NONE;	}	if (status & (BA0_HISR_DMA(0)|BA0_HISR_DMA(1)|BA0_HISR_DMA(2)|BA0_HISR_DMA(3))) {		for (dma = 0; dma < 4; dma++)			if (status & BA0_HISR_DMA(dma)) {				cdma = &chip->dma[dma];				spin_lock(&chip->reg_lock);				/* ack DMA IRQ */				val = snd_cs4281_peekBA0(chip, cdma->regHDSR);				/* workaround, sometimes CS4281 acknowledges */				/* end or middle transfer position twice */				cdma->frag++;				if ((val & BA0_HDSR_DHTC) && !(cdma->frag & 1)) {					cdma->frag--;					chip->spurious_dhtc_irq++;					spin_unlock(&chip->reg_lock);					continue;				}				if ((val & BA0_HDSR_DTC) && (cdma->frag & 1)) {					cdma->frag--;					chip->spurious_dtc_irq++;					spin_unlock(&chip->reg_lock);					continue;				}				spin_unlock(&chip->reg_lock);				snd_pcm_period_elapsed(cdma->substream);			}	}	if ((status & BA0_HISR_MIDI) && chip->rmidi) {		unsigned char c;				spin_lock(&chip->reg_lock);		while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_RBE) == 0) {			c = snd_cs4281_peekBA0(chip, BA0_MIDRP);			if ((chip->midcr & BA0_MIDCR_RIE) == 0)				continue;			snd_rawmidi_receive(chip->midi_input, &c, 1);		}		while ((snd_cs4281_peekBA0(chip, BA0_MIDSR) & BA0_MIDSR_TBF) == 0) {			if ((chip->midcr & BA0_MIDCR_TIE) == 0)				break;			if (snd_rawmidi_transmit(chip->midi_output, &c, 1) != 1) {				chip->midcr &= ~BA0_MIDCR_TIE;				snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);				break;			}			snd_cs4281_pokeBA0(chip, BA0_MIDWP, c);		}		spin_unlock(&chip->reg_lock);	}	/* EOI to the PCI part... reenables interrupts */	snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_EOI);	return IRQ_HANDLED;}/* * OPL3 command */static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd,				    unsigned char val){	unsigned long flags;	struct cs4281 *chip = opl3->private_data;	void __iomem *port;	if (cmd & OPL3_RIGHT)		port = chip->ba0 + BA0_B1AP; /* right port */	else		port = chip->ba0 + BA0_B0AP; /* left port */	spin_lock_irqsave(&opl3->reg_lock, flags);	writel((unsigned int)cmd, port);	udelay(10);	writel((unsigned int)val, port + 4);	udelay(30);	spin_unlock_irqrestore(&opl3->reg_lock, flags);}static int __devinit snd_cs4281_probe(struct pci_dev *pci,				      const struct pci_device_id *pci_id){	static int dev;	struct snd_card *card;	struct cs4281 *chip;	struct snd_opl3 *opl3;	int err;        if (dev >= SNDRV_CARDS)                return -ENODEV;	if (!enable[dev]) {		dev++;		return -ENOENT;	}	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	if ((err = snd_cs4281_create(card, pci, &chip, dual_codec[dev])) < 0) {		snd_card_free(card);		return err;	}	card->private_data = chip;	if ((err = snd_cs4281_mixer(chip)) < 0) {		snd_card_free(card);		return err;	}	if ((err = snd_cs4281_pcm(chip, 0, NULL)) < 0) {		snd_card_free(card);		return err;	}	if ((err = snd_cs4281_midi(chip, 0, NULL)) < 0) {		snd_card_free(card);		return err;	}	if ((err = snd_opl3_new(card, OPL3_HW_OPL3_CS4281, &opl3)) < 0) {		snd_card_free(card);		return err;	}	opl3->private_data = chip;	opl3->command = snd_cs4281_opl3_command;	snd_opl3_init(opl3);	if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {		snd_card_free(card);		return err;	}	snd_cs4281_create_gameport(chip);	strcpy(card->driver, "CS4281");	strcpy(card->shortname, "Cirrus Logic CS4281");	sprintf(card->longname, "%s at 0x%lx, irq %d",		card->shortname,		chip->ba0_addr,		chip->irq);	if ((err = snd_card_register(card)) < 0) {		snd_card_free(card);		return err;	}	pci_set_drvdata(pci, card);	dev++;	return 0;}static void __devexit snd_cs4281_remove(struct pci_dev *pci){	snd_card_free(pci_get_drvdata(pci));	pci_set_drvdata(pci, NULL);}/* * Power Management */#ifdef CONFIG_PMstatic int saved_regs[SUSPEND_REGISTERS] = {	BA0_JSCTL,	BA0_GPIOR,	BA0_SSCR,	BA0_MIDCR,	BA0_SRCSA,	BA0_PASR,	BA0_CASR,	BA0_DACSR,	BA0_ADCSR,	BA0_FMLVC,	BA0_FMRVC,	BA0_PPLVC,	BA0_PPRVC,};#define CLKCR1_CKRA                             0x00010000Lstatic int cs4281_suspend(struct pci_dev *pci, pm_message_t state){	struct snd_card *card = pci_get_drvdata(pci);	struct cs4281 *chip = card->private_data;	u32 ulCLK;	unsigned int i;	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	snd_pcm_suspend_all(chip->pcm);	snd_ac97_suspend(chip->ac97);	snd_ac97_suspend(chip->ac97_secondary);	ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);	ulCLK |= CLKCR1_CKRA;	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);	/* Disable interrupts. */	snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_CHGM);	/* remember the status registers */	for (i = 0; i < ARRAY_SIZE(saved_regs); i++)		if (saved_regs[i])			chip->suspend_regs[i] = snd_cs4281_peekBA0(chip, saved_regs[i]);	/* Turn off the serial ports. */	snd_cs4281_pokeBA0(chip, BA0_SERMC, 0);	/* Power off FM, Joystick, AC link, */	snd_cs4281_pokeBA0(chip, BA0_SSPM, 0);	/* DLL off. */	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, 0);	/* AC link off. */	snd_cs4281_pokeBA0(chip, BA0_SPMC, 0);	ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);	ulCLK &= ~CLKCR1_CKRA;	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);	pci_disable_device(pci);	pci_save_state(pci);	pci_set_power_state(pci, pci_choose_state(pci, state));	return 0;}static int cs4281_resume(struct pci_dev *pci){	struct snd_card *card = pci_get_drvdata(pci);	struct cs4281 *chip = card->private_data;	unsigned int i;	u32 ulCLK;	pci_set_power_state(pci, PCI_D0);	pci_restore_state(pci);	if (pci_enable_device(pci) < 0) {		printk(KERN_ERR "cs4281: pci_enable_device failed, "		       "disabling device\n");		snd_card_disconnect(card);		return -EIO;	}	pci_set_master(pci);	ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);	ulCLK |= CLKCR1_CKRA;	snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);	snd_cs4281_chip_init(

⌨️ 快捷键说明

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