예제 #1
0
static int oxygen_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *hw_params)
{
	struct oxygen *chip = snd_pcm_substream_chip(substream);
	unsigned int channel = oxygen_substream_channel(substream);
	int err;

	err = snd_pcm_lib_malloc_pages(substream,
				       params_buffer_bytes(hw_params));
	if (err < 0)
		return err;

	oxygen_write32(chip, channel_base_registers[channel],
		       (u32)substream->runtime->dma_addr);
	if (channel == PCM_MULTICH) {
		oxygen_write32(chip, OXYGEN_DMA_MULTICH_COUNT,
			       params_buffer_bytes(hw_params) / 4 - 1);
		oxygen_write32(chip, OXYGEN_DMA_MULTICH_TCOUNT,
			       params_period_bytes(hw_params) / 4 - 1);
	} else {
		oxygen_write16(chip, channel_base_registers[channel] + 4,
			       params_buffer_bytes(hw_params) / 4 - 1);
		oxygen_write16(chip, channel_base_registers[channel] + 6,
			       params_period_bytes(hw_params) / 4 - 1);
	}
	return 0;
}
예제 #2
0
static snd_pcm_uframes_t oxygen_pointer(struct snd_pcm_substream *substream)
{
	struct oxygen *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned int channel = oxygen_substream_channel(substream);
	u32 curr_addr;

	/* no spinlock, this read should be atomic */
	curr_addr = oxygen_read32(chip, channel_base_registers[channel]);
	return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr);
}
예제 #3
0
static int oxygen_prepare(struct snd_pcm_substream *substream)
{
	struct oxygen *chip = snd_pcm_substream_chip(substream);
	unsigned int channel = oxygen_substream_channel(substream);
	unsigned int channel_mask = 1 << channel;

	spin_lock_irq(&chip->reg_lock);
	oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
	oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);

	chip->interrupt_mask |= channel_mask;
	oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
	spin_unlock_irq(&chip->reg_lock);
	return 0;
}
예제 #4
0
static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct oxygen *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_substream *s;
	unsigned int mask = 0;
	int pausing;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_SUSPEND:
		pausing = 0;
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		pausing = 1;
		break;
	default:
		return -EINVAL;
	}

	snd_pcm_group_for_each_entry(s, substream) {
		if (snd_pcm_substream_chip(s) == chip) {
			mask |= 1 << oxygen_substream_channel(s);
			snd_pcm_trigger_done(s, substream);
		}
	}

	spin_lock(&chip->reg_lock);
	if (!pausing) {
		if (cmd == SNDRV_PCM_TRIGGER_START)
			chip->pcm_running |= mask;
		else
			chip->pcm_running &= ~mask;
		oxygen_write8(chip, OXYGEN_DMA_STATUS, chip->pcm_running);
	} else {
		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
			oxygen_set_bits8(chip, OXYGEN_DMA_PAUSE, mask);
		else
			oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask);
	}
	spin_unlock(&chip->reg_lock);
	return 0;
}
예제 #5
0
static int oxygen_close(struct snd_pcm_substream *substream)
{
	struct oxygen *chip = snd_pcm_substream_chip(substream);
	unsigned int channel = oxygen_substream_channel(substream);

	mutex_lock(&chip->mutex);
	chip->pcm_active &= ~(1 << channel);
	if (channel == PCM_SPDIF) {
		chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |=
			SNDRV_CTL_ELEM_ACCESS_INACTIVE;
		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
			       SNDRV_CTL_EVENT_MASK_INFO,
			       &chip->controls[CONTROL_SPDIF_PCM]->id);
	}
	if (channel == PCM_SPDIF || channel == PCM_MULTICH)
		oxygen_update_spdif_source(chip);
	mutex_unlock(&chip->mutex);

	chip->streams[channel] = NULL;
	return 0;
}