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

📄 azt3328.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}static irqreturn_tsnd_azf3328_interrupt(int irq, void *dev_id){	struct snd_azf3328 *chip = dev_id;	u8 status, which;	static unsigned long irq_count;	status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS);        /* fast path out, to ease interrupt sharing */	if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_TIMER)))		return IRQ_NONE; /* must be interrupt for another device */	snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n",		irq_count,		snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS),		snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),		status);			if (status & IRQ_TIMER) {		/* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */		if (chip->timer)			snd_timer_interrupt(chip->timer, chip->timer->sticks);		/* ACK timer */                spin_lock(&chip->reg_lock);		snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07);		spin_unlock(&chip->reg_lock);		snd_azf3328_dbgplay("azt3328: timer IRQ\n");	}	if (status & IRQ_PLAYBACK) {		spin_lock(&chip->reg_lock);		which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE);		/* ack all IRQ types immediately */		snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which);               	spin_unlock(&chip->reg_lock);		if (chip->pcm && chip->playback_substream) {			snd_pcm_period_elapsed(chip->playback_substream);			snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n",				which,				inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS));		} else			snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");		if (which & IRQ_PLAY_SOMETHING)			snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n");	}	if (status & IRQ_RECORDING) {                spin_lock(&chip->reg_lock);		which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE);		/* ack all IRQ types immediately */		snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which);		spin_unlock(&chip->reg_lock);		if (chip->pcm && chip->capture_substream) {			snd_pcm_period_elapsed(chip->capture_substream);			snd_azf3328_dbgplay("REC  period done (#%x), @ %x\n",				which,				inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS));		} else			snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");		if (which & IRQ_REC_SOMETHING)			snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n");	}	/* MPU401 has less critical IRQ requirements	 * than timer and playback/recording, right? */	if (status & IRQ_MPU401) {		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);		/* hmm, do we have to ack the IRQ here somehow?		 * If so, then I don't know how... */		snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n");	}	irq_count++;	return IRQ_HANDLED;}/*****************************************************************/static const struct snd_pcm_hardware snd_azf3328_playback ={	/* FIXME!! Correct? */	.info =			SNDRV_PCM_INFO_MMAP |				SNDRV_PCM_INFO_INTERLEAVED |				SNDRV_PCM_INFO_MMAP_VALID,	.formats =		SNDRV_PCM_FMTBIT_S8 |				SNDRV_PCM_FMTBIT_U8 |				SNDRV_PCM_FMTBIT_S16_LE |				SNDRV_PCM_FMTBIT_U16_LE,	.rates =		SNDRV_PCM_RATE_5512 |				SNDRV_PCM_RATE_8000_48000 |				SNDRV_PCM_RATE_KNOT,	.rate_min =		4000,	.rate_max =		66200,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	65536,	.period_bytes_min =	64,	.period_bytes_max =	65536,	.periods_min =		1,	.periods_max =		1024,	/* FIXME: maybe that card actually has a FIFO?	 * Hmm, it seems newer revisions do have one, but we still don't know	 * its size... */	.fifo_size =		0,};static const struct snd_pcm_hardware snd_azf3328_capture ={	/* FIXME */	.info =			SNDRV_PCM_INFO_MMAP |				SNDRV_PCM_INFO_INTERLEAVED |				SNDRV_PCM_INFO_MMAP_VALID,	.formats =		SNDRV_PCM_FMTBIT_S8 |				SNDRV_PCM_FMTBIT_U8 |				SNDRV_PCM_FMTBIT_S16_LE |				SNDRV_PCM_FMTBIT_U16_LE,	.rates =		SNDRV_PCM_RATE_5512 |				SNDRV_PCM_RATE_8000_48000 |				SNDRV_PCM_RATE_KNOT,	.rate_min =		4000,	.rate_max =		66200,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	65536,	.period_bytes_min =	64,	.period_bytes_max =	65536,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static unsigned int snd_azf3328_fixed_rates[] = {	4000, 4800, 5512, 6620, 8000, 9600, 11025, 13240, 16000, 22050, 32000,	44100, 48000, 66200 };static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = {	.count = ARRAY_SIZE(snd_azf3328_fixed_rates), 	.list = snd_azf3328_fixed_rates,	.mask = 0,};/*****************************************************************/static intsnd_azf3328_playback_open(struct snd_pcm_substream *substream){	struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	snd_azf3328_dbgcallenter();	chip->playback_substream = substream;	runtime->hw = snd_azf3328_playback;	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				   &snd_azf3328_hw_constraints_rates);	snd_azf3328_dbgcallleave();	return 0;}static intsnd_azf3328_capture_open(struct snd_pcm_substream *substream){	struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	snd_azf3328_dbgcallenter();	chip->capture_substream = substream;	runtime->hw = snd_azf3328_capture;	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				   &snd_azf3328_hw_constraints_rates);	snd_azf3328_dbgcallleave();	return 0;}static intsnd_azf3328_playback_close(struct snd_pcm_substream *substream){	struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);	snd_azf3328_dbgcallenter();	chip->playback_substream = NULL;	snd_azf3328_dbgcallleave();	return 0;}static intsnd_azf3328_capture_close(struct snd_pcm_substream *substream){	struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);	snd_azf3328_dbgcallenter();	chip->capture_substream = NULL;	snd_azf3328_dbgcallleave();	return 0;}/******************************************************************/static struct snd_pcm_ops snd_azf3328_playback_ops = {	.open =		snd_azf3328_playback_open,	.close =	snd_azf3328_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_azf3328_hw_params,	.hw_free =	snd_azf3328_hw_free,	.prepare =	snd_azf3328_playback_prepare,	.trigger =	snd_azf3328_playback_trigger,	.pointer =	snd_azf3328_playback_pointer};static struct snd_pcm_ops snd_azf3328_capture_ops = {	.open =		snd_azf3328_capture_open,	.close =	snd_azf3328_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_azf3328_hw_params,	.hw_free =	snd_azf3328_hw_free,	.prepare =	snd_azf3328_capture_prepare,	.trigger =	snd_azf3328_capture_trigger,	.pointer =	snd_azf3328_capture_pointer};static int __devinitsnd_azf3328_pcm(struct snd_azf3328 *chip, int device){	struct snd_pcm *pcm;	int err;	snd_azf3328_dbgcallenter();	if ((err = snd_pcm_new(chip->card, "AZF3328 DSP", device, 1, 1, &pcm)) < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_azf3328_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_azf3328_capture_ops);	pcm->private_data = chip;	pcm->info_flags = 0;	strcpy(pcm->name, chip->card->shortname);	chip->pcm = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci), 64*1024, 64*1024);	snd_azf3328_dbgcallleave();	return 0;}/******************************************************************/#ifdef SUPPORT_JOYSTICKstatic int __devinitsnd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev){	struct gameport *gp;	struct resource *r;	if (!joystick[dev])		return -ENODEV;	if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) {		printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n");		return -EBUSY;	}	chip->gameport = gp = gameport_allocate_port();	if (!gp) {		printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n");		release_and_free_resource(r);		return -ENOMEM;	}	gameport_set_name(gp, "AZF3328 Gameport");	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));	gameport_set_dev_parent(gp, &chip->pci->dev);	gp->io = 0x200;	gameport_set_port_data(gp, r);	snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR,			      snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY);	gameport_register_port(chip->gameport);	return 0;}static voidsnd_azf3328_free_joystick(struct snd_azf3328 *chip){	if (chip->gameport) {		struct resource *r = gameport_get_port_data(chip->gameport);		gameport_unregister_port(chip->gameport);		chip->gameport = NULL;		/* disable gameport */		snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR,				      snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);		release_and_free_resource(r);	}}#elsestatic inline intsnd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) { return -ENOSYS; }static inline voidsnd_azf3328_free_joystick(struct snd_azf3328 *chip) { }#endif/******************************************************************/static intsnd_azf3328_free(struct snd_azf3328 *chip){        if (chip->irq < 0)                goto __end_hw;	/* reset (close) mixer */	snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */	snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);        /* interrupt setup - mask everything (FIXME!) */	/* well, at least we know how to disable the timer IRQ */	snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00);        synchronize_irq(chip->irq);__end_hw:	snd_azf3328_free_joystick(chip);        if (chip->irq >= 0)		free_irq(chip->irq, chip);	pci_release_regions(chip->pci);	pci_disable_device(chip->pci);        kfree(chip);        return 0;}static intsnd_azf3328_dev_free(struct snd_device *device){	struct snd_azf3328 *chip = device->device_data;	return snd_azf3328_free(chip);}/******************************************************************//*** NOTE: the physical timer resolution actually is 1024000 ticks per second, *** but announcing those attributes to user-space would make programs *** configure the timer to a 1 tick value, resulting in an absolutely fatal *** timer IRQ storm. *** Thus I chose to announce a down-scaled virtual timer to the outside and *** calculate real timer countdown values internally. *** (the scale factor can be set via module parameter "seqtimer_scaling"). ***/static intsnd_azf3328_timer_start(struct snd_timer *timer){	struct snd_azf3328 *chip;	unsigned long flags;	unsigned int delay;	snd_azf3328_dbgcallenter();	chip = snd_timer_chip(timer);	delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK;	if (delay < 49) {		/* uhoh, that's not good, since user-space won't know about		 * this timing tweak		 * (we need to do it to avoid a lockup, though) */		snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay);		delay = 49; /* minimum time is 49 ticks */	}	snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay);	delay |= TIMER_ENABLE_COUNTDOWN | TIMER_ENABLE_IRQ;	spin_lock_irqsave(&chip->reg_lock, flags);	snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_azf3328_dbgcallleave();	return 0;}static intsnd_azf3328_timer_stop(struct snd_timer *timer){	struct snd_azf3328 *chip;	unsigned long flags;	snd_azf3328_dbgcallenter();	chip = snd_timer_chip(timer);	spin_lock_irqsave(&chip->reg_lock, flags);	/* disable timer countdown and interrupt */	/* FIXME: should we write TIMER_ACK_IRQ here? */	snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);	spin_unlock_irqrestore(&chip->reg_lock, flags);	snd_azf3328_dbgcallleave();	return 0;}static intsnd_azf3328_timer_precise_resolution(struct snd_timer *timer,					       unsigned long *num, unsigned long *den){

⌨️ 快捷键说明

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