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

📄 cs46xx_lib.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			chip->midcr |= MIDCR_RIE;			snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	} else {		if (chip->midcr & MIDCR_RIE) {			chip->midcr &= ~MIDCR_RIE;			snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	}	spin_unlock_irqrestore(&chip->reg_lock, flags);}static void snd_cs46xx_midi_output_trigger(snd_rawmidi_substream_t * substream, int up){	unsigned long flags;	cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return);	unsigned char byte;	spin_lock_irqsave(&chip->reg_lock, flags);	if (up) {		if ((chip->midcr & MIDCR_TIE) == 0) {			chip->midcr |= MIDCR_TIE;			/* fill UART FIFO buffer at first, and turn Tx interrupts only if necessary */			while ((chip->midcr & MIDCR_TIE) &&			       (snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) {				if (snd_rawmidi_transmit(substream, &byte, 1) != 1) {					chip->midcr &= ~MIDCR_TIE;				} else {					snd_cs46xx_pokeBA0(chip, BA0_MIDWP, byte);				}			}			snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	} else {		if (chip->midcr & MIDCR_TIE) {			chip->midcr &= ~MIDCR_TIE;			snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);		}	}	spin_unlock_irqrestore(&chip->reg_lock, flags);}static snd_rawmidi_ops_t snd_cs46xx_midi_output ={	open:           snd_cs46xx_midi_output_open,	close:          snd_cs46xx_midi_output_close,	trigger:        snd_cs46xx_midi_output_trigger,};static snd_rawmidi_ops_t snd_cs46xx_midi_input ={	open:           snd_cs46xx_midi_input_open,	close:          snd_cs46xx_midi_input_close,	trigger:        snd_cs46xx_midi_input_trigger,};int __devinit snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi){	snd_rawmidi_t *rmidi;	int err;	if (rrawmidi)		*rrawmidi = NULL;	if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0)		return err;	strcpy(rmidi->name, "CS46XX");	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_cs46xx_midi_output);	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_cs46xx_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 = NULL;	return 0;}/* * gameport interface */#ifndef LINUX_2_2typedef struct snd_cs46xx_gameport {	struct gameport info;	cs46xx_t *chip;} cs46xx_gameport_t;static void snd_cs46xx_gameport_trigger(struct gameport *gameport){	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;	cs46xx_t *chip;	snd_assert(gp, return);	chip = snd_magic_cast(cs46xx_t, gp->chip, return);	snd_cs46xx_pokeBA0(chip, BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);}static unsigned char snd_cs46xx_gameport_read(struct gameport *gameport){	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;	cs46xx_t *chip;	snd_assert(gp, return 0);	chip = snd_magic_cast(cs46xx_t, gp->chip, return 0);	return snd_cs46xx_peekBA0(chip, BA0_JSPT); //inb(gameport->io);}static int snd_cs46xx_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons){	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;	cs46xx_t *chip;	unsigned js1, js2, jst;		snd_assert(gp, return 0);	chip = snd_magic_cast(cs46xx_t, gp->chip, return 0);	js1 = snd_cs46xx_peekBA0(chip, BA0_JSC1);	js2 = snd_cs46xx_peekBA0(chip, BA0_JSC2);	jst = snd_cs46xx_peekBA0(chip, BA0_JSPT);		*buttons = (~jst >> 4) & 0x0F; 		axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;	for(jst=0;jst<4;++jst)		if(axes[jst]==0xFFFF) axes[jst] = -1;	return 0;}static int snd_cs46xx_gameport_open(struct gameport *gameport, int mode){	switch (mode) {	case GAMEPORT_MODE_COOKED:		return 0;	case GAMEPORT_MODE_RAW:		return 0;	default:		return -1;	}	return 0;}void __devinit snd_cs46xx_gameport(cs46xx_t *chip){	cs46xx_gameport_t *gp;	gp = kmalloc(sizeof(*gp), GFP_KERNEL);	if (! gp) {		snd_printk("cannot allocate gameport area\n");		return;	}	memset(gp, 0, sizeof(*gp));	gp->info.open = snd_cs46xx_gameport_open;	gp->info.read = snd_cs46xx_gameport_read;	gp->info.trigger = snd_cs46xx_gameport_trigger;	gp->info.cooked_read = snd_cs46xx_gameport_cooked_read;	gp->chip = chip;	chip->gameport = gp;	snd_cs46xx_pokeBA0(chip, BA0_JSIO, 0xFF); // ?	snd_cs46xx_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);	gameport_register_port(&gp->info);}#else /* LINUX_2_2 */void __devinit snd_cs46xx_gameport(cs46xx_t *chip){}#endif /* !LINUX_2_2 *//* *  proc interface */static long snd_cs46xx_io_read(snd_info_entry_t *entry, void *file_private_data,			       struct file *file, char *buf, long count){	long size;	snd_cs46xx_region_t *region = (snd_cs46xx_region_t *)entry->private_data;		size = count;	if (file->f_pos + size > region->size)		size = region->size - file->f_pos;	if (size > 0) {		char *tmp;		long res;		unsigned long virt;		if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL)			return -ENOMEM;		virt = region->remap_addr + file->f_pos;		memcpy_fromio(tmp, virt, size);		if (copy_to_user(buf, tmp, size))			res = -EFAULT;		else {			res = size;			file->f_pos += size;		}		kfree(tmp);		return res;	}	return 0;}static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {	read: snd_cs46xx_io_read,};static int __devinit snd_cs46xx_proc_init(snd_card_t * card, cs46xx_t *chip){	snd_info_entry_t *entry;	int idx;		for (idx = 0; idx < 5; idx++) {		snd_cs46xx_region_t *region = &chip->region.idx[idx];		entry = snd_info_create_card_entry(card, region->name, card->proc_root);		if (entry) {			entry->content = SNDRV_INFO_CONTENT_DATA;			entry->private_data = chip;			entry->c.ops = &snd_cs46xx_proc_io_ops;			entry->size = region->size;			entry->mode = S_IFREG | S_IRUSR;			if (snd_info_register(entry) < 0) {				snd_info_unregister(entry);				entry = NULL;			}		}		region->proc_entry = entry;	}	return 0;}static int snd_cs46xx_proc_done(cs46xx_t *chip){	int idx;	for (idx = 0; idx < 5; idx++) {		snd_cs46xx_region_t *region = &chip->region.idx[idx];		if (region->proc_entry) {			snd_info_unregister((snd_info_entry_t *) region->proc_entry);			region->proc_entry = NULL;		}	}	return 0;}/* * stop the h/w */static void snd_cs46xx_hw_stop(cs46xx_t *chip){	unsigned int tmp;	tmp = snd_cs46xx_peek(chip, BA1_PFIE);	tmp &= ~0x0000f03f;	tmp |=  0x00000010;	snd_cs46xx_poke(chip, BA1_PFIE, tmp);	/* playback interrupt disable */	tmp = snd_cs46xx_peek(chip, BA1_CIE);	tmp &= ~0x0000003f;	tmp |=  0x00000011;	snd_cs46xx_poke(chip, BA1_CIE, tmp);	/* capture interrupt disable */	/*         *  Stop playback DMA.	 */	tmp = snd_cs46xx_peek(chip, BA1_PCTL);	snd_cs46xx_poke(chip, BA1_PCTL, tmp & 0x0000ffff);	/*         *  Stop capture DMA.	 */	tmp = snd_cs46xx_peek(chip, BA1_CCTL);	snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000);	/*         *  Reset the processor.         */	snd_cs46xx_reset(chip);	snd_cs46xx_proc_stop(chip);	/*	 *  Power down the PLL.	 */	snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, 0);	/*	 *  Turn off the Processor by turning off the software clock enable flag in 	 *  the clock control register.	 */	tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1) & ~CLKCR1_SWCE;	snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);}static int snd_cs46xx_free(cs46xx_t *chip){	int idx;	snd_assert(chip != NULL, return -EINVAL);	if (chip->active_ctrl)		chip->active_ctrl(chip, 1);#ifndef LINUX_2_2	if (chip->gameport) {		gameport_unregister_port(&chip->gameport->info);		kfree(chip->gameport);	}#endif#ifdef CONFIG_PM	if (chip->pm_dev)		pm_unregister(chip->pm_dev);#endif	if (chip->amplifier_ctrl)		chip->amplifier_ctrl(chip, -chip->amplifier); /* force to off */		snd_cs46xx_proc_done(chip);	if (chip->region.idx[0].resource)		snd_cs46xx_hw_stop(chip);	for (idx = 0; idx < 5; idx++) {		snd_cs46xx_region_t *region = &chip->region.idx[idx];		if (region->remap_addr)			iounmap((void *) region->remap_addr);		if (region->resource) {			release_resource(region->resource);			kfree_nocheck(region->resource);		}	}	if (chip->irq >= 0)		free_irq(chip->irq, (void *)chip);	if (chip->active_ctrl)		chip->active_ctrl(chip, -chip->amplifier);	snd_magic_kfree(chip);	return 0;}static int snd_cs46xx_dev_free(snd_device_t *device){	cs46xx_t *chip = snd_magic_cast(cs46xx_t, device->device_data, return -ENXIO);	return snd_cs46xx_free(chip);}/* *  initialize chip */static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait){	unsigned int tmp;	int timeout;	/* 	 *  First, 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_cs46xx_pokeBA0(chip, BA0_CLKCR1, 0);        snd_cs46xx_pokeBA0(chip, BA0_SERMC1, 0);	/*	 *  If we are in AC97 mode, then we must set the part to a host controlled         *  AC-link.  Otherwise, we won't be able to bring up the link.         */                snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_1_03);	/* 1.03 codec */        /* snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_2_0); */ /* 2.00 codec */        /*         *  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 CS461x that uses the ARST# line         *  for a reset.         */        snd_cs46xx_pokeBA0(chip, BA0_ACCTL, 0);        udelay(50);        snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_RSTN);	/*	 *  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_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);	/*	 *  Now wait for a short while to allow the AC97 part to start	 *  generating bit clock (so we don't try to start the PLL without an	 *  input clock).	 */	mdelay(1);	/*	 *  Set the serial port timing configuration, so that	 *  the clock control circuit gets its clock from the correct place.	 */	snd_cs46xx_pokeBA0(chip, BA0_SERMC1, SERMC1_PTC_AC97);	/*	 *  Write the selected clock control setup to the hardware.  Do not turn on	 *  SWCE yet (if requested), so that the devices clocked by the output of	 *  PLL are not clocked until the PLL is stable.	 */	snd_cs46xx_pokeBA0(chip, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ);	snd_cs46xx_pokeBA0(chip, BA0_PLLM, 0x3a);	snd_cs46xx_pokeBA0(chip, BA0_CLKCR2, CLKCR2_PDIVS_8);	/*	 *  Power up the PLL.	 */	snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, CLKCR1_PLLP);	/*         *  Wait until the PLL has stabilized.	 */	mdelay(1);	/*	 *  Turn on clocking of the core so that we can setup the serial ports.	 */	snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, CLKCR1_PLLP | CLKCR1_SWCE);	/*	 *  Fill the serial port FIFOs with silence.	 */	snd_cs46xx_clear_serial_FIFOs(chip);	/*	 *  Set the serial port FIFO pointer to the first sample in the FIFO.	 */	/* snd_cs46xx_pokeBA0(chip, BA0_SERBSP, 0); */	/*	 *  Write the serial port configuration to the part.  The master	 *  enable bit is not set until all other values have been written.	 */	snd_cs46xx_pokeBA0(chip, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN);	snd_cs46xx_pokeBA0(chip, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);	snd_cs46xx_pokeBA0(chip, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);	/*	 * Wait for the codec ready signal from the AC97 codec.	 */	timeout = 150;	while (timeout-- > 0) {		/*		 *  Read the AC97 status register to see if we've seen a CODEC READY		 *  signal from the AC97 codec.		 */		if (snd_cs46xx_peekBA0(chip, BA0_ACSTS) & ACSTS_CRDY)			goto ok1;		if (busywait)			mdelay(10);		else {			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout((HZ+99)/100);		}	}	snd_printk("create - never read codec ready from AC'97\n");	snd_printk("it is not probably bug, try to use CS4236 driver\n");	snd_cs46xx_free(chip);	return -EIO; ok1:	/*	 *  Assert the vaid frame signal so that we can start sending commands	 *  to the AC97 codec.

⌨️ 快捷键说明

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