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

📄 pmac.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_8000_44100,	.rate_min =		7350,	.rate_max =		44100,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	131072,	.period_bytes_min =	256,	.period_bytes_max =	16384,	.periods_min =		3,	.periods_max =		PMAC_MAX_FRAGS,};#if 0 // NYIstatic int snd_pmac_hw_rule_rate(struct snd_pcm_hw_params *params,				 struct snd_pcm_hw_rule *rule){	struct snd_pmac *chip = rule->private;	struct pmac_stream *rec = snd_pmac_get_stream(chip, rule->deps[0]);	int i, freq_table[8], num_freqs;	if (! 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(struct snd_pcm_hw_params *params,				   struct snd_pcm_hw_rule *rule){	struct snd_pmac *chip = rule->private;	struct pmac_stream *rec = snd_pmac_get_stream(chip, rule->deps[0]);	if (! 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(struct snd_pmac *chip, struct pmac_stream *rec,			     struct snd_pcm_substream *subs){	struct snd_pcm_runtime *runtime = subs->runtime;	int i;	/* look up frequency table and fill bit mask */	runtime->hw.rates = 0;	for (i = 0; i < chip->num_freqs; i++)		if (chip->freqs_ok & (1 << i))			runtime->hw.rates |=				snd_pcm_rate_to_rate_bit(chip->freq_table[i]);	/* 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;	/* constraints to fix choppy sound */	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);	return 0;}static int snd_pmac_pcm_close(struct snd_pmac *chip, struct pmac_stream *rec,			      struct snd_pcm_substream *subs){	struct pmac_stream *astr;	snd_pmac_dma_stop(rec);	astr = snd_pmac_get_stream(chip, another_stream(rec->stream));	if (! 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(struct snd_pcm_substream *subs){	struct snd_pmac *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(struct snd_pcm_substream *subs){	struct snd_pmac *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(struct snd_pcm_substream *subs){	struct snd_pmac *chip = snd_pcm_substream_chip(subs);	return snd_pmac_pcm_close(chip, &chip->playback, subs);}static int snd_pmac_capture_close(struct snd_pcm_substream *subs){	struct snd_pmac *chip = snd_pcm_substream_chip(subs);	return snd_pmac_pcm_close(chip, &chip->capture, subs);}/* */static struct snd_pcm_ops 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 struct snd_pcm_ops 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,};int __init snd_pmac_pcm_new(struct snd_pmac *chip){	struct snd_pcm *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->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_DEV,					      &chip->pdev->dev,					      64 * 1024, 64 * 1024);	return 0;}static void snd_pmac_dbdma_reset(struct snd_pmac *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(struct snd_pmac *chip, int bytes, unsigned long addr, int speed){	struct pmac_stream *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(struct snd_pmac *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 snd_pmac *chip = devid;	snd_pmac_pcm_update(chip, &chip->playback);	return IRQ_HANDLED;}static irqreturn_tsnd_pmac_rx_intr(int irq, void *devid){	struct snd_pmac *chip = devid;	snd_pmac_pcm_update(chip, &chip->capture);	return IRQ_HANDLED;}static irqreturn_tsnd_pmac_ctrl_intr(int irq, void *devid){	struct snd_pmac *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 */static void snd_pmac_sound_feature(struct snd_pmac *chip, int enable){	if (ppc_md.feature_call)		ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);}/* * release resources */static int snd_pmac_free(struct snd_pmac *chip){	/* 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);	}	if (chip->node)		snd_pmac_sound_feature(chip, 0);	/* 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, &chip->playback.cmd);	snd_pmac_dbdma_free(chip, &chip->capture.cmd);	snd_pmac_dbdma_free(chip, &chip->extra_dma);	if (chip->macio_base)		iounmap(chip->macio_base);	if (chip->latch_base)		iounmap(chip->latch_base);	if (chip->awacs)		iounmap(chip->awacs);	if (chip->playback.dma)		iounmap(chip->playback.dma);	if (chip->capture.dma)		iounmap(chip->capture.dma);	if (chip->node) {		int i;		for (i = 0; i < 3; i++) {			if (chip->requested & (1 << i))				release_mem_region(chip->rsrc[i].start,						   chip->rsrc[i].end -						   chip->rsrc[i].start + 1);		}	}	if (chip->pdev)		pci_dev_put(chip->pdev);	of_node_put(chip->node);	kfree(chip);	return 0;}/* * free the device */static int snd_pmac_dev_free(struct snd_device *device){	struct snd_pmac *chip = device->device_data;	return snd_pmac_free(chip);}/* * check the machine support byteswap (little-endian) */static void __init detect_byte_swap(struct snd_pmac *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 (of_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(struct snd_pmac *chip){	struct device_node *sound;	struct device_node *dn;	const unsigned int *prop;	unsigned int l;	struct macio_chip* macio;	if (!machine_is(powermac))		return -ENODEV;	chip->subframe = 0;	chip->revision = 0;	chip->freqs_ok = 0xff; /* all ok */	chip->model = PMAC_AWACS;	chip->can_byte_swap = 1;	chip->can_duplex = 1;	chip->can_capture = 1;	chip->num_freqs = ARRAY_SIZE(awacs_freqs);	chip->freq_table = awacs_freqs;	chip->pdev = NULL;	chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */	/* check machine type */	if (machine_is_compatible("AAPL,3400/2400")	    || machine_is_compatible("AAPL,3500"))		chip->is_pbook_3400 = 1;	else if (machine_is_compatible("PowerBook1,1")		 || machine_is_compatible("AAPL,PowerBook1998"))		chip->is_pbook_G3 = 1;	chip->node = of_find_node_by_name(NULL, "awacs");	sound = of_node_get(chip->node);	/*	 * powermac G3 models have a node called "davbus"	 * with a child called "sound".

⌨️ 快捷键说明

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