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

📄 pmac.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	.rate_max =		44100,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	32768,	.period_bytes_min =	256,	.period_bytes_max =	16384,	.periods_min =		1,	.periods_max =		PMAC_MAX_FRAGS,};#if 0 // NYIstatic int snd_pmac_hw_rule_rate(snd_pcm_hw_params_t *params,				 snd_pcm_hw_rule_t *rule){	pmac_t *chip = rule->private;	pmac_stream_t *rec = snd_pmac_get_stream(chip, rule->deps[0]);	int i, freq_table[8], num_freqs;	snd_runtime_check(rec, return -EINVAL);	num_freqs = 0;	for (i = chip->num_freqs - 1; i >= 0; i--) {		if (rec->cur_freqs & (1 << i))			freq_table[num_freqs++] = chip->freq_table[i];	}	return snd_interval_list(hw_param_interval(params, rule->var),				 num_freqs, freq_table, 0);}static int snd_pmac_hw_rule_format(snd_pcm_hw_params_t *params,				   snd_pcm_hw_rule_t *rule){	pmac_t *chip = rule->private;	pmac_stream_t *rec = snd_pmac_get_stream(chip, rule->deps[0]);	snd_runtime_check(rec, return -EINVAL);	return snd_mask_refine_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),				   rec->cur_formats);}#endif // NYIstatic int snd_pmac_pcm_open(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substream_t *subs){	snd_pcm_runtime_t *runtime = subs->runtime;	int i, j, fflags;	static int typical_freqs[] = {		44100,		22050,		11025,		0,	};	static int typical_freq_flags[] = {		SNDRV_PCM_RATE_44100,		SNDRV_PCM_RATE_22050,		SNDRV_PCM_RATE_11025,		0,	};	/* look up frequency table and fill bit mask */	runtime->hw.rates = 0;	fflags = chip->freqs_ok;	for (i = 0; typical_freqs[i]; i++) {		for (j = 0; j < chip->num_freqs; j++) {			if ((chip->freqs_ok & (1 << j)) &&			    chip->freq_table[j] == typical_freqs[i]) {				runtime->hw.rates |= typical_freq_flags[i];				fflags &= ~(1 << j);				break;			}		}	}	if (fflags) /* rest */		runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;	/* check for minimum and maximum rates */	for (i = 0; i < chip->num_freqs; i++) {		if (chip->freqs_ok & (1 << i)) {			runtime->hw.rate_max = chip->freq_table[i];			break;		}	}	for (i = chip->num_freqs - 1; i >= 0; i--) {		if (chip->freqs_ok & (1 << i)) {			runtime->hw.rate_min = chip->freq_table[i];			break;		}	}	runtime->hw.formats = chip->formats_ok;	if (chip->can_capture) {		if (! chip->can_duplex)			runtime->hw.info |= SNDRV_PCM_INFO_HALF_DUPLEX;		runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;	}	runtime->private_data = rec;	rec->substream = subs;#if 0 /* FIXME: still under development.. */	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,			    snd_pmac_hw_rule_rate, chip, rec->stream, -1);	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,			    snd_pmac_hw_rule_format, chip, rec->stream, -1);#endif	runtime->hw.periods_max = rec->cmd.size - 1;	if (chip->can_duplex)		snd_pcm_set_sync(subs);	return 0;}static int snd_pmac_pcm_close(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substream_t *subs){	pmac_stream_t *astr;	snd_pmac_dma_stop(rec);	astr = snd_pmac_get_stream(chip, another_stream(rec->stream));	snd_runtime_check(astr, return -EINVAL);	/* reset constraints */	astr->cur_freqs = chip->freqs_ok;	astr->cur_formats = chip->formats_ok;		return 0;}static int snd_pmac_playback_open(snd_pcm_substream_t *subs){	pmac_t *chip = snd_pcm_substream_chip(subs);	subs->runtime->hw = snd_pmac_playback;	return snd_pmac_pcm_open(chip, &chip->playback, subs);}static int snd_pmac_capture_open(snd_pcm_substream_t *subs){	pmac_t *chip = snd_pcm_substream_chip(subs);	subs->runtime->hw = snd_pmac_capture;	return snd_pmac_pcm_open(chip, &chip->capture, subs);}static int snd_pmac_playback_close(snd_pcm_substream_t *subs){	pmac_t *chip = snd_pcm_substream_chip(subs);	return snd_pmac_pcm_close(chip, &chip->playback, subs);}static int snd_pmac_capture_close(snd_pcm_substream_t *subs){	pmac_t *chip = snd_pcm_substream_chip(subs);	return snd_pmac_pcm_close(chip, &chip->capture, subs);}/* */static snd_pcm_ops_t snd_pmac_playback_ops = {	.open =		snd_pmac_playback_open,	.close =	snd_pmac_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_pmac_pcm_hw_params,	.hw_free =	snd_pmac_pcm_hw_free,	.prepare =	snd_pmac_playback_prepare,	.trigger =	snd_pmac_playback_trigger,	.pointer =	snd_pmac_playback_pointer,};static snd_pcm_ops_t snd_pmac_capture_ops = {	.open =		snd_pmac_capture_open,	.close =	snd_pmac_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_pmac_pcm_hw_params,	.hw_free =	snd_pmac_pcm_hw_free,	.prepare =	snd_pmac_capture_prepare,	.trigger =	snd_pmac_capture_trigger,	.pointer =	snd_pmac_capture_pointer,};static void pmac_pcm_free(snd_pcm_t *pcm){	snd_pcm_lib_preallocate_free_for_all(pcm);}int __init snd_pmac_pcm_new(pmac_t *chip){	snd_pcm_t *pcm;	int err;	int num_captures = 1;	if (! chip->can_capture)		num_captures = 0;	err = snd_pcm_new(chip->card, chip->card->driver, 0, 1, num_captures, &pcm);	if (err < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pmac_playback_ops);	if (chip->can_capture)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pmac_capture_ops);	pcm->private_data = chip;	pcm->private_free = pmac_pcm_free;	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;	strcpy(pcm->name, chip->card->shortname);	chip->pcm = pcm;	chip->formats_ok = SNDRV_PCM_FMTBIT_S16_BE;	if (chip->can_byte_swap)		chip->formats_ok |= SNDRV_PCM_FMTBIT_S16_LE;	chip->playback.cur_formats = chip->formats_ok;	chip->capture.cur_formats = chip->formats_ok;	chip->playback.cur_freqs = chip->freqs_ok;	chip->capture.cur_freqs = chip->freqs_ok;	/* preallocate 64k buffer */	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 					      snd_dma_continuous_data(GFP_KERNEL),					      64 * 1024, 64 * 1024);	return 0;}static void snd_pmac_dbdma_reset(pmac_t *chip){	out_le32(&chip->playback.dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);	snd_pmac_wait_ack(&chip->playback);	out_le32(&chip->capture.dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);	snd_pmac_wait_ack(&chip->capture);}/* * handling beep */void snd_pmac_beep_dma_start(pmac_t *chip, int bytes, unsigned long addr, int speed){	pmac_stream_t *rec = &chip->playback;	snd_pmac_dma_stop(rec);	st_le16(&chip->extra_dma.cmds->req_count, bytes);	st_le16(&chip->extra_dma.cmds->xfer_status, 0);	st_le32(&chip->extra_dma.cmds->cmd_dep, chip->extra_dma.addr);	st_le32(&chip->extra_dma.cmds->phy_addr, addr);	st_le16(&chip->extra_dma.cmds->command, OUTPUT_MORE + BR_ALWAYS);	out_le32(&chip->awacs->control,		 (in_le32(&chip->awacs->control) & ~0x1f00)		 | (speed << 8));	out_le32(&chip->awacs->byteswap, 0);	snd_pmac_dma_set_command(rec, &chip->extra_dma);	snd_pmac_dma_run(rec, RUN);}void snd_pmac_beep_dma_stop(pmac_t *chip){	snd_pmac_dma_stop(&chip->playback);	st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP);	snd_pmac_pcm_set_format(chip); /* reset format */}/* * interrupt handlers */static irqreturn_tsnd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs){	pmac_t *chip = devid;	snd_pmac_pcm_update(chip, &chip->playback);	return IRQ_HANDLED;}static irqreturn_tsnd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs){	pmac_t *chip = devid;	snd_pmac_pcm_update(chip, &chip->capture);	return IRQ_HANDLED;}static irqreturn_tsnd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs){	pmac_t *chip = devid;	int ctrl = in_le32(&chip->awacs->control);	/*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/	if (ctrl & MASK_PORTCHG) {		/* do something when headphone is plugged/unplugged? */		if (chip->update_automute)			chip->update_automute(chip, 1);	}	if (ctrl & MASK_CNTLERR) {		int err = (in_le32(&chip->awacs->codec_stat) & MASK_ERRCODE) >> 16;		if (err && chip->model <= PMAC_SCREAMER)			snd_printk(KERN_DEBUG "error %x\n", err);	}	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */	out_le32(&chip->awacs->control, ctrl);	return IRQ_HANDLED;}/* * a wrapper to feature call for compatibility */#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)static void snd_pmac_sound_feature(pmac_t *chip, int enable){#ifdef CONFIG_PPC_HAS_FEATURE_CALLS	ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);#else	if (chip->is_pbook_G3) {		pmu_suspend();		feature_clear(chip->node, FEATURE_Sound_power);		feature_clear(chip->node, FEATURE_Sound_CLK_enable);		big_mdelay(1000); /* XXX */		pmu_resume();	}	if (chip->is_pbook_3400) {		feature_set(chip->node, FEATURE_IOBUS_enable);		udelay(10);	}#endif}#else /* CONFIG_PM && CONFIG_PMAC_PBOOK */#define snd_pmac_sound_feature(chip,enable) /**/#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK *//* * release resources */static int snd_pmac_free(pmac_t *chip){	int i;	/* stop sounds */	if (chip->initialized) {		snd_pmac_dbdma_reset(chip);		/* disable interrupts from awacs interface */		out_le32(&chip->awacs->control, in_le32(&chip->awacs->control) & 0xfff);	}	snd_pmac_sound_feature(chip, 0);#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)	snd_pmac_unregister_sleep_notifier(chip);#endif	/* clean up mixer if any */	if (chip->mixer_free)		chip->mixer_free(chip);	snd_pmac_detach_beep(chip);	/* release resources */	if (chip->irq >= 0)		free_irq(chip->irq, (void*)chip);	if (chip->tx_irq >= 0)		free_irq(chip->tx_irq, (void*)chip);	if (chip->rx_irq >= 0)		free_irq(chip->rx_irq, (void*)chip);	snd_pmac_dbdma_free(&chip->playback.cmd);	snd_pmac_dbdma_free(&chip->capture.cmd);	snd_pmac_dbdma_free(&chip->extra_dma);	if (chip->macio_base)		iounmap(chip->macio_base);	if (chip->latch_base)		iounmap(chip->latch_base);	if (chip->awacs)		iounmap((void*)chip->awacs);	if (chip->playback.dma)		iounmap((void*)chip->playback.dma);	if (chip->capture.dma)		iounmap((void*)chip->capture.dma);	if (chip->node) {		for (i = 0; i < 3; i++) {			if (chip->of_requested & (1 << i))				release_OF_resource(chip->node, i);		}	}	kfree(chip);	return 0;}/* * free the device */static int snd_pmac_dev_free(snd_device_t *device){	pmac_t *chip = device->device_data;	return snd_pmac_free(chip);}/* * check the machine support byteswap (little-endian) */static void __init detect_byte_swap(pmac_t *chip){	struct device_node *mio;	/* if seems that Keylargo can't byte-swap  */	for (mio = chip->node->parent; mio; mio = mio->parent) {		if (strcmp(mio->name, "mac-io") == 0) {			if (device_is_compatible(mio, "Keylargo"))				chip->can_byte_swap = 0;			break;		}	}	/* it seems the Pismo & iBook can't byte-swap in hardware. */	if (machine_is_compatible("PowerBook3,1") ||	    machine_is_compatible("PowerBook2,1"))		chip->can_byte_swap = 0 ;	if (machine_is_compatible("PowerBook2,1"))		chip->can_duplex = 0;}/* * detect a sound chip */static int __init snd_pmac_detect(pmac_t *chip){	struct device_node *sound;	unsigned int *prop, l;	if (_machine != _MACH_Pmac)		return -ENODEV;	chip->subframe = 0;	chip->revision = 0;

⌨️ 快捷键说明

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