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

📄 hda_intel.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1);	/* program the BDL address */	/* lower BDL address */	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr);	/* upper BDL address */	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));	/* enable the position buffer */	if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))		azx_writel(chip, DPLBASE,			   (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE);	/* set the interrupt enable bits in the descriptor control register */	azx_sd_writel(azx_dev, SD_CTL,		      azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK);	return 0;}/* * Codec initialization */static unsigned int azx_max_codecs[] __devinitdata = {	[AZX_DRIVER_ICH] = 3,	[AZX_DRIVER_ATI] = 4,	[AZX_DRIVER_ATIHDMI] = 4,	[AZX_DRIVER_VIA] = 3,		/* FIXME: correct? */	[AZX_DRIVER_SIS] = 3,		/* FIXME: correct? */	[AZX_DRIVER_ULI] = 3,		/* FIXME: correct? */	[AZX_DRIVER_NVIDIA] = 3,	/* FIXME: correct? */};static int __devinit azx_codec_create(struct azx *chip, const char *model){	struct hda_bus_template bus_temp;	int c, codecs, audio_codecs, err;	memset(&bus_temp, 0, sizeof(bus_temp));	bus_temp.private_data = chip;	bus_temp.modelname = model;	bus_temp.pci = chip->pci;	bus_temp.ops.command = azx_send_cmd;	bus_temp.ops.get_response = azx_get_response;#ifdef CONFIG_SND_HDA_POWER_SAVE	bus_temp.ops.pm_notify = azx_power_notify;#endif	err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);	if (err < 0)		return err;	codecs = audio_codecs = 0;	for (c = 0; c < AZX_MAX_CODECS; c++) {		if ((chip->codec_mask & (1 << c)) & probe_mask) {			struct hda_codec *codec;			err = snd_hda_codec_new(chip->bus, c, &codec);			if (err < 0)				continue;			codecs++;			if (codec->afg)				audio_codecs++;		}	}	if (!audio_codecs) {		/* probe additional slots if no codec is found */		for (; c < azx_max_codecs[chip->driver_type]; c++) {			if ((chip->codec_mask & (1 << c)) & probe_mask) {				err = snd_hda_codec_new(chip->bus, c, NULL);				if (err < 0)					continue;				codecs++;			}		}	}	if (!codecs) {		snd_printk(KERN_ERR SFX "no codecs initialized\n");		return -ENXIO;	}	return 0;}/* * PCM support *//* assign a stream for the PCM */static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream){	int dev, i, nums;	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {		dev = chip->playback_index_offset;		nums = chip->playback_streams;	} else {		dev = chip->capture_index_offset;		nums = chip->capture_streams;	}	for (i = 0; i < nums; i++, dev++)		if (!chip->azx_dev[dev].opened) {			chip->azx_dev[dev].opened = 1;			return &chip->azx_dev[dev];		}	return NULL;}/* release the assigned stream */static inline void azx_release_device(struct azx_dev *azx_dev){	azx_dev->opened = 0;}static struct snd_pcm_hardware azx_pcm_hw = {	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID |				 /* No full-resume yet implemented */				 /* SNDRV_PCM_INFO_RESUME |*/				 SNDRV_PCM_INFO_PAUSE),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_48000,	.rate_min =		48000,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	AZX_MAX_BUF_SIZE,	.period_bytes_min =	128,	.period_bytes_max =	AZX_MAX_BUF_SIZE / 2,	.periods_min =		2,	.periods_max =		AZX_MAX_FRAG,	.fifo_size =		0,};struct azx_pcm {	struct azx *chip;	struct hda_codec *codec;	struct hda_pcm_stream *hinfo[2];};static int azx_pcm_open(struct snd_pcm_substream *substream){	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];	struct azx *chip = apcm->chip;	struct azx_dev *azx_dev;	struct snd_pcm_runtime *runtime = substream->runtime;	unsigned long flags;	int err;	mutex_lock(&chip->open_mutex);	azx_dev = azx_assign_device(chip, substream->stream);	if (azx_dev == NULL) {		mutex_unlock(&chip->open_mutex);		return -EBUSY;	}	runtime->hw = azx_pcm_hw;	runtime->hw.channels_min = hinfo->channels_min;	runtime->hw.channels_max = hinfo->channels_max;	runtime->hw.formats = hinfo->formats;	runtime->hw.rates = hinfo->rates;	snd_pcm_limit_hw_rates(runtime);	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,				   128);	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,				   128);	snd_hda_power_up(apcm->codec);	err = hinfo->ops.open(hinfo, apcm->codec, substream);	if (err < 0) {		azx_release_device(azx_dev);		snd_hda_power_down(apcm->codec);		mutex_unlock(&chip->open_mutex);		return err;	}	spin_lock_irqsave(&chip->reg_lock, flags);	azx_dev->substream = substream;	azx_dev->running = 0;	spin_unlock_irqrestore(&chip->reg_lock, flags);	runtime->private_data = azx_dev;	mutex_unlock(&chip->open_mutex);	return 0;}static int azx_pcm_close(struct snd_pcm_substream *substream){	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];	struct azx *chip = apcm->chip;	struct azx_dev *azx_dev = get_azx_dev(substream);	unsigned long flags;	mutex_lock(&chip->open_mutex);	spin_lock_irqsave(&chip->reg_lock, flags);	azx_dev->substream = NULL;	azx_dev->running = 0;	spin_unlock_irqrestore(&chip->reg_lock, flags);	azx_release_device(azx_dev);	hinfo->ops.close(hinfo, apcm->codec, substream);	snd_hda_power_down(apcm->codec);	mutex_unlock(&chip->open_mutex);	return 0;}static int azx_pcm_hw_params(struct snd_pcm_substream *substream,			     struct snd_pcm_hw_params *hw_params){	return snd_pcm_lib_malloc_pages(substream,					params_buffer_bytes(hw_params));}static int azx_pcm_hw_free(struct snd_pcm_substream *substream){	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);	struct azx_dev *azx_dev = get_azx_dev(substream);	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];	/* reset BDL address */	azx_sd_writel(azx_dev, SD_BDLPL, 0);	azx_sd_writel(azx_dev, SD_BDLPU, 0);	azx_sd_writel(azx_dev, SD_CTL, 0);	hinfo->ops.cleanup(hinfo, apcm->codec, substream);	return snd_pcm_lib_free_pages(substream);}static int azx_pcm_prepare(struct snd_pcm_substream *substream){	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);	struct azx *chip = apcm->chip;	struct azx_dev *azx_dev = get_azx_dev(substream);	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];	struct snd_pcm_runtime *runtime = substream->runtime;	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);	azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);	azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,							 runtime->channels,							 runtime->format,							 hinfo->maxbps);	if (!azx_dev->format_val) {		snd_printk(KERN_ERR SFX			   "invalid format_val, rate=%d, ch=%d, format=%d\n",			   runtime->rate, runtime->channels, runtime->format);		return -EINVAL;	}	snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, "		    "format=0x%x\n",		    azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);	azx_setup_periods(azx_dev);	azx_setup_controller(chip, azx_dev);	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;	else		azx_dev->fifo_size = 0;	return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,				  azx_dev->format_val, substream);}static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd){	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);	struct azx_dev *azx_dev = get_azx_dev(substream);	struct azx *chip = apcm->chip;	int err = 0;	spin_lock(&chip->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:	case SNDRV_PCM_TRIGGER_RESUME:	case SNDRV_PCM_TRIGGER_START:		azx_stream_start(chip, azx_dev);		azx_dev->running = 1;		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:	case SNDRV_PCM_TRIGGER_SUSPEND:	case SNDRV_PCM_TRIGGER_STOP:		azx_stream_stop(chip, azx_dev);		azx_dev->running = 0;		break;	default:		err = -EINVAL;	}	spin_unlock(&chip->reg_lock);	if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||	    cmd == SNDRV_PCM_TRIGGER_SUSPEND ||	    cmd == SNDRV_PCM_TRIGGER_STOP) {		int timeout = 5000;		while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) &&		       --timeout)			;	}	return err;}static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream){	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);	struct azx *chip = apcm->chip;	struct azx_dev *azx_dev = get_azx_dev(substream);	unsigned int pos;	if (chip->position_fix == POS_FIX_POSBUF ||	    chip->position_fix == POS_FIX_AUTO) {		/* use the position buffer */		pos = le32_to_cpu(*azx_dev->posbuf);		if (chip->position_fix == POS_FIX_AUTO &&		    azx_dev->period_intr == 1 && !pos) {			printk(KERN_WARNING			       "hda-intel: Invalid position buffer, "			       "using LPIB read method instead.\n");			chip->position_fix = POS_FIX_NONE;			goto read_lpib;		}	} else {	read_lpib:		/* read LPIB */		pos = azx_sd_readl(azx_dev, SD_LPIB);		if (chip->position_fix == POS_FIX_FIFO)			pos += azx_dev->fifo_size;	}	if (pos >= azx_dev->bufsize)		pos = 0;	return bytes_to_frames(substream->runtime, pos);}static struct snd_pcm_ops azx_pcm_ops = {	.open = azx_pcm_open,	.close = azx_pcm_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = azx_pcm_hw_params,	.hw_free = azx_pcm_hw_free,	.prepare = azx_pcm_prepare,	.trigger = azx_pcm_trigger,	.pointer = azx_pcm_pointer,};static void azx_pcm_free(struct snd_pcm *pcm){	kfree(pcm->private_data);}static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,				      struct hda_pcm *cpcm, int pcm_dev){	int err;	struct snd_pcm *pcm;	struct azx_pcm *apcm;	/* if no substreams are defined for both playback and capture,	 * it's just a placeholder.  ignore it.	 */	if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)		return 0;	snd_assert(cpcm->name, return -EINVAL);	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,			  cpcm->stream[0].substreams,			  cpcm->stream[1].substreams,			  &pcm);	if (err < 0)		return err;	strcpy(pcm->name, cpcm->name);	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);	if (apcm == NULL)		return -ENOMEM;	apcm->chip = chip;	apcm->codec = codec;	apcm->hinfo[0] = &cpcm->stream[0];	apcm->hinfo[1] = &cpcm->stream[1];	pcm->private_data = apcm;	pcm->private_free = azx_pcm_free;	if (cpcm->stream[0].substreams)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);	if (cpcm->stream[1].substreams)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci),					      1024 * 64, 1024 * 1024);	chip->pcm[pcm_dev] = pcm;	if (chip->pcm_devs < pcm_dev + 1)		chip->pcm_devs = pcm_dev + 1;	return 0;}static int __devinit azx_pcm_create(struct azx *chip){	struct hda_codec *codec;	int c, err;	int pcm_dev;	err = snd_hda_build_pcms(chip->bus);	if (err < 0)		return err;	/* create audio PCMs */	pcm_dev = 0;	list_for_each_entry(codec, &chip->bus->codec_list, list) {		for (c = 0; c < codec->num_pcms; c++) {			if (codec->pcm_info[c].is_modem)				continue; /* create later */			if (pcm_dev >= AZX_MAX_AUDIO_PCMS) {				snd_printk(KERN_ERR SFX					   "Too many audio PCMs\n");				return -EINVAL;			}			err = create_codec_pcm(chip, codec,					       &codec->pcm_info[c], pcm_dev);			if (err < 0)				return err;			pcm_dev++;		}	}	/* create modem PCMs */	pcm_dev = AZX_MAX_AUDIO_PCMS;	list_for_each_entry(codec, &chip->bus->codec_list, list) {		for (c = 0; c < codec->num_pcms; c++) {			if (!codec->pcm_info[c].is_modem)				continue; /* already created */			if (pcm_dev >= AZX_MAX_PCMS) {				snd_printk(KERN_ERR SFX					   "Too many modem PCMs\n");				return -EINVAL;			}			err = create_codec_pcm(chip, codec,					       &codec->pcm_info[c], pcm_dev);			if (err < 0)				return err;			chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;			pcm_dev++;		}	}	return 0;}/* * mixer creation - all stuff is implemented in hda module */static int __devinit azx_mixer_create(struct azx *chip){	return snd_hda_build_controls(chip->bus);}/* * initialize SD streams */static int __devinit azx_init_stream(struct azx *chip){	int i;	/* initialize each stream (aka device)	 * assign the starting bdl address to each stream (device)	 * and initialize	 */	for (i = 0; i < chip->num_streams; i++) {		unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);		struct azx_dev *azx_dev = &chip->azx_dev[i];		azx_dev->bdl = (u32 *)(chip->bdl.area + off);		azx_dev->bdl_addr = chip->bdl.addr + off;		azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */		azx_dev->sd_int_sta_mask = 1 << i;		/* stream tag: must be non-zero and unique */		azx_dev->index = i;		azx_dev->stream_tag = i + 1;	}	return 0;}static int azx_acquire_irq(struct azx *chip, int do_disconnect){	if (request_irq(chip->pci->irq, azx_interrupt,			chip->msi ? 0 : IRQF_SHARED,			"HDA Intel", chip)) {		printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "		       "disabling device\n", chip->pci->irq);		if (do_disconnect)			snd_card_disconnect(chip->card);		return -1;	}	chip->irq = chip->pci->irq;	pci_intx(chip->pci, !chip->msi);	return 0;}

⌨️ 快捷键说明

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