Example #1
0
static int lx_pcm_hw_free(struct snd_pcm_substream *substream)
{
	struct lx6464es *chip = snd_pcm_substream_chip(substream);
	int err = 0;
	int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);

	dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n");
	mutex_lock(&chip->setup_mutex);

	if (chip->hardware_running[is_capture]) {
		err = lx_hardware_stop(chip, substream);
		if (err < 0) {
			dev_err(chip->card->dev, "failed to stop hardware. "
				   "Error code %d\n", err);
			goto exit;
		}

		err = lx_hardware_close(chip, substream);
		if (err < 0) {
			dev_err(chip->card->dev, "failed to close hardware. "
				   "Error code %d\n", err);
			goto exit;
		}

		chip->hardware_running[is_capture] = 0;
	}

	err = snd_pcm_lib_free_pages(substream);

	if (is_capture)
		chip->capture_stream.stream = 0;
	else
		chip->playback_stream.stream = 0;

exit:
	mutex_unlock(&chip->setup_mutex);
	return err;
}
Example #2
0
/* hw_free callback */
static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
{
	vortex_t *chip = snd_pcm_substream_chip(substream);
	stream_t *stream = (stream_t *) (substream->runtime->private_data);

	spin_lock_irq(&chip->lock);
	// Delete audio routes.
	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
		if (stream != NULL)
			vortex_adb_allocroute(chip, stream->dma,
					      stream->nr_ch, stream->dir,
					      stream->type);
	}
#ifndef CHIP_AU8810
	else {
		if (stream != NULL)
			vortex_wt_allocroute(chip, stream->dma, 0);
	}
#endif
	substream->runtime->private_data = NULL;
	spin_unlock_irq(&chip->lock);

	return snd_pcm_lib_free_pages(substream);
}
Example #3
0
static int skl_substream_free_pages(struct hdac_bus *bus,
				struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #4
0
static int snd_als300_pcm_hw_free(struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
	snd_pcm_lib_free_pages(substream);

	return 0;
}
Example #6
0
/* hw_free callback */
static int snd_p16v_pcm_hw_free_capture(struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #7
0
static int snd_ice1712_hw_free(struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #8
0
static int substream_free_pages(struct azx *chip,
				struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #9
0
static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #10
0
static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)
{
	snd_pcm_lib_free_pages(substream);
	return 0;
}
Example #11
0
static int snd_intelmad_hw_free(struct snd_pcm_substream *substream)
{
	pr_debug("snd_intelmad_hw_free called\n");
	return snd_pcm_lib_free_pages(substream);
}
Example #12
0
/* hw_free callback */
static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
{
	audio_info(" .. IN\n");
	return snd_pcm_lib_free_pages(substream);
}
Example #13
0
/**
 * snd_intelhad_init_audio_ctrl - to initialize audio channel status
 * registers and confgiuration registers
 *
 * @substream:substream for which the prepare function is called
 * @intelhaddata:substream private data
 *
 * This function is called in the prepare callback
 */
int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream,
					struct snd_intelhad *intelhaddata,
					int flag_silence)
{
	union aud_cfg cfg_val = {.cfg_regval = 0};
	union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0};
	union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0};
	union aud_buf_config buf_cfg = {.buf_cfgval = 0};
	u8 channels;
	int format, retval;
	u32 data;

	ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits &
						IEC958_AES0_NONAUDIO)>>1;
	ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits &
						IEC958_AES3_CON_CLOCK)>>4;
	switch (substream->runtime->rate) {
	case AUD_SAMPLE_RATE_32:
		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ;
	break;

	case AUD_SAMPLE_RATE_44_1:
	case AUD_SAMPLE_RATE_88_2:
	case AUD_SAMPLE_RATE_176_4:
		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ;
	break;

	case AUD_SAMPLE_RATE_48:
	case AUD_SAMPLE_RATE_96:
	case HAD_MAX_RATE:
		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ;
	break;

	default:
		return -EINVAL;
	break;

	}
	had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval);

	format = substream->runtime->format;

	if (format == SNDRV_PCM_FORMAT_S16_LE) {
		ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20;
		ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS;
	} else if (format == SNDRV_PCM_FORMAT_S24_LE) {
		ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24;
		ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS;
	} else {
		ch_stat1.status_1_regx.max_wrd_len = 0;
		ch_stat1.status_1_regx.wrd_len = 0;
	}
	had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval);

	buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD;
	buf_cfg.buf_cfg_regx.aud_delay = 0;
	had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval);

	channels = substream->runtime->channels;

	switch (channels) {
	case 1:
	case 2:
		cfg_val.cfg_regx.num_ch = CH_STEREO;
		cfg_val.cfg_regx.layout = LAYOUT0;
	break;

	case 3:
	case 4:
		cfg_val.cfg_regx.num_ch = CH_THREE_FOUR;
		cfg_val.cfg_regx.layout = LAYOUT1;
	break;

	case 5:
	case 6:
		cfg_val.cfg_regx.num_ch = CH_FIVE_SIX;
		cfg_val.cfg_regx.layout = LAYOUT1;
	break;

	case 7:
	case 8:
		cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT;
		cfg_val.cfg_regx.layout = LAYOUT1;
	break;

	}

	cfg_val.cfg_regx.val_bit = 1;
	had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
	return 0;
}

/**
 * snd_intelhad_prog_dip - to initialize Data Island Packets registers
 *
 * @substream:substream for which the prepare function is called
 * @intelhaddata:substream private data
 *
 * This function is called in the prepare callback
 */
static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream,
				struct snd_intelhad *intelhaddata,
				int flag_silence)
{
	int i;
	union aud_ctrl_st ctrl_state = {.ctrl_val = 0};
	union aud_info_frame2 frame2 = {.fr2_val = 0};
	union aud_info_frame3 frame3 = {.fr3_val = 0};
	u8 checksum = 0;

	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);

	frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;

	/*TODO: Read from intelhaddata->eeld.speaker_allocation_block;*/
	frame3.fr3_regx.chnl_alloc = CHANNEL_ALLOCATION;

	/*Calculte the byte wide checksum for all valid DIP words*/
	for (i = 0; i < BYTES_PER_WORD; i++)
		checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
	for (i = 0; i < BYTES_PER_WORD; i++)
		checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
	for (i = 0; i < BYTES_PER_WORD; i++)
		checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;

	frame2.fr2_regx.chksum = -(checksum);

	had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1);
	had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val);
	had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val);

	/* program remaining DIP words with zero */
	for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
		had_write_register(AUD_HDMIW_INFOFR, 0x0);

	ctrl_state.ctrl_regx.dip_freq = 1;
	ctrl_state.ctrl_regx.dip_en_sta = 1;
	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
}

/**
 * snd_intelhad_prog_buffer - programs buffer
 * address and length registers
 *
 * @substream:substream for which the prepare function is called
 * @intelhaddata:substream private data
 *
 * This function programs ring buffer address and length into registers.
 */
int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata,
					int start, int end)
{
	u32 ring_buf_addr, ring_buf_size, period_bytes;
	u8 i, num_periods;
	struct snd_pcm_substream *substream;

	substream = intelhaddata->stream_info.had_substream;
	if (!substream) {
		pr_err("substream is NULL\n");
		dump_stack();
		return 0;
	}

	ring_buf_addr = substream->runtime->dma_addr;
	ring_buf_size = snd_pcm_lib_buffer_bytes(substream);
	intelhaddata->stream_info.ring_buf_size = ring_buf_size;
	period_bytes = frames_to_bytes(substream->runtime,
				substream->runtime->period_size);
	num_periods = substream->runtime->periods;

	/* buffer addr should  be 64 byte aligned, period bytes
	 will be used to calculate addr offset*/
	period_bytes &= ~0x3F;

	/* Hardware supports MAX_PERIODS buffers */
	if (end >= HAD_MAX_PERIODS)
		return -EINVAL;

	for (i = start; i <= end; i++) {
		/* Program the buf registers with addr and len */
		intelhaddata->buf_info[i].buf_addr = ring_buf_addr +
							 (i * period_bytes);
		if (i < num_periods-1)
			intelhaddata->buf_info[i].buf_size = period_bytes;
		else
			intelhaddata->buf_info[i].buf_size = ring_buf_size -
							(period_bytes*i);

		had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH),
					intelhaddata->buf_info[i].buf_addr |
					BIT(0) | BIT(1));
		had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
					period_bytes);
		intelhaddata->buf_info[i].is_valid = true;
	}
	pr_debug("%s:buf[%d-%d] addr=%#x  and size=%d\n", __func__, start, end,
			intelhaddata->buf_info[start].buf_addr,
			intelhaddata->buf_info[start].buf_size);
	intelhaddata->valid_buf_cnt = num_periods;
	return 0;
}

inline int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
{
	int i, retval = 0;
	u32 len[4];

	for (i = 0; i < 4 ; i++) {
		had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
					&len[i]);
		if (!len[i])
			retval++;
	}
	if (retval != 1) {
		for (i = 0; i < 4 ; i++)
			pr_debug("buf[%d] size=%d\n", i, len[i]);
	}

	return retval;
}

/**
 * snd_intelhad_prog_cts - Program HDMI audio CTS value
 *
 * @aud_samp_freq: sampling frequency of audio data
 * @tmds: sampling frequency of the display data
 * @n_param: N value, depends on aud_samp_freq
 * @intelhaddata:substream private data
 *
 * Program CTS register based on the audio and display sampling frequency
 */
static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, u32 n_param,
				struct snd_intelhad *intelhaddata)
{
	u32 cts_val;
	u64 dividend, divisor;

	/* Calculate CTS according to HDMI 1.3a spec*/
	dividend = (u64)tmds * n_param*1000;
	divisor = 128 * aud_samp_freq;
	cts_val = div64_u64(dividend, divisor);
	pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
			tmds, n_param, cts_val);
	had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val));
}

/**
 * snd_intelhad_prog_n - Program HDMI audio N value
 *
 * @aud_samp_freq: sampling frequency of audio data
 * @n_param: N value, depends on aud_samp_freq
 * @intelhaddata:substream private data
 *
 * This function is called in the prepare callback.
 * It programs based on the audio and display sampling frequency
 */
static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param,
				struct snd_intelhad *intelhaddata)
{
	u32 n_val;
	int retval = 0;

	/* Select N according to HDMI 1.3a spec*/
	switch (aud_samp_freq) {
	case AUD_SAMPLE_RATE_32:
		n_val = 4096;
	break;

	case AUD_SAMPLE_RATE_44_1:
		n_val = 6272;
	break;

	case AUD_SAMPLE_RATE_48:
		n_val = 6144;
	break;

	case AUD_SAMPLE_RATE_88_2:
		n_val = 12544;
	break;

	case AUD_SAMPLE_RATE_96:
		n_val = 12288;
	break;

	case AUD_SAMPLE_RATE_176_4:
		n_val = 25088;
	break;

	case HAD_MAX_RATE:
		n_val = 24576;
	break;

	default:
		retval = -EINVAL;
	break;

	}
	if (retval)
		return retval;
	had_write_register(AUD_N_ENABLE, (BIT(20) | n_val));
	*n_param = n_val;
	return retval;
}

/**
* snd_intelhad_open - stream initializations are done here
* @substream:substream for which the stream function is called
*
* This function is called whenever a PCM stream is opened
*/
static int snd_intelhad_open(struct snd_pcm_substream *substream)
{
	struct snd_intelhad *intelhaddata;
	struct snd_pcm_runtime *runtime;
	struct had_stream_pvt *stream;
	struct had_pvt_data *had_stream;
	int retval;

	pr_debug("snd_intelhad_open called\n");
	intelhaddata = snd_pcm_substream_chip(substream);
	had_stream = intelhaddata->private_data;

	/*
	 * HDMI driver might suspend the device already,
	 * so we return it on
	 */
	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
			OSPM_UHB_FORCE_POWER_ON)) {
		pr_err("HDMI device can't be turned on\n");
		return -ENODEV;
	}

	if (had_get_hwstate(intelhaddata)) {
		pr_err("%s: HDMI cable plugged-out\n", __func__);
		ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
		return -ENODEV;
	}
	runtime = substream->runtime;

	/* Check, if device already in use */
	if (runtime->private_data) {
		pr_err("Device already in use\n");
		ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
		return -EBUSY;
	}

	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);

	/* set the runtime hw parameter with local snd_pcm_hardware struct */
	runtime->hw = snd_intel_hadstream;

	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
	if (!stream) {
		retval = -ENOMEM;
		goto exit_err;
	}
	stream->stream_status = STREAM_INIT;
	runtime->private_data = stream;

	retval = snd_pcm_hw_constraint_integer(runtime,
			 SNDRV_PCM_HW_PARAM_PERIODS);
	if (retval < 0) {
		kfree(stream);
		goto exit_err;
	}

	/* Make sure, that the period size is always aligned
	 * 64byte boundary
	 */
	retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
			SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
	if (retval < 0) {
		pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval);
		kfree(stream);
		goto exit_err;
	}

	return retval;
exit_err:
	runtime->private_data = NULL;
	return retval;
}

/**
* had_period_elapsed - updates the hardware pointer status
* @had_substream:substream for which the stream function is called
*
*/
static void had_period_elapsed(void *had_substream)
{
	struct snd_pcm_substream *substream = had_substream;
	struct had_stream_pvt *stream;

	if (!substream || !substream->runtime)
		return;
	stream = substream->runtime->private_data;
	if (!stream)
		return;

	if (stream->stream_status != STREAM_RUNNING)
		return;
	snd_pcm_period_elapsed(substream);
	return;
}

/**
* snd_intelhad_init_stream - internal function to initialize stream info
* @substream:substream for which the stream function is called
*
*/
static int snd_intelhad_init_stream(struct snd_pcm_substream *substream)
{
	struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream);

	pr_debug("setting buffer ptr param\n");
	intelhaddata->stream_info.period_elapsed = had_period_elapsed;
	intelhaddata->stream_info.had_substream = substream;
	intelhaddata->stream_info.buffer_ptr = 0;
	intelhaddata->stream_info.buffer_rendered = 0;
	intelhaddata->stream_info.sfreq = substream->runtime->rate;
	return 0;
}

/**
 * snd_intelhad_close- to free parameteres when stream is stopped
 *
 * @substream:  substream for which the function is called
 *
 * This function is called by ALSA framework when stream is stopped
 */
static int snd_intelhad_close(struct snd_pcm_substream *substream)
{
	struct snd_intelhad *intelhaddata;
	struct snd_pcm_runtime *runtime;

	pr_debug("snd_intelhad_close called\n");
	intelhaddata = snd_pcm_substream_chip(substream);
	runtime = substream->runtime;

	intelhaddata->stream_info.buffer_rendered = 0;
	intelhaddata->stream_info.buffer_ptr = 0;
	intelhaddata->stream_info.str_id = 0;
	intelhaddata->stream_info.had_substream = NULL;

	/* Check if following drv_status modification is required - VA */
	if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED)
		intelhaddata->drv_status = HAD_DRV_CONNECTED;
	kfree(runtime->private_data);
	runtime->private_data = NULL;
	return 0;
}

/**
 * snd_intelhad_hw_params- to setup the hardware parameters
 * like allocating the buffers
 *
 * @substream:  substream for which the function is called
 * @hw_params: hardware parameters
 *
 * This function is called by ALSA framework when hardware params are set
 */
static int snd_intelhad_hw_params(struct snd_pcm_substream *substream,
				    struct snd_pcm_hw_params *hw_params)
{
	unsigned long addr;
	int pages, buf_size, retval;

	BUG_ON(!hw_params);

	buf_size = params_buffer_bytes(hw_params);
	retval = snd_pcm_lib_malloc_pages(substream, buf_size);
	if (retval < 0)
		return retval;
	pr_debug("%s:allocated memory = %d\n", __func__, buf_size);
	/* mark the pages as uncached region */
	addr = (unsigned long) substream->runtime->dma_area;
	pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
	retval = set_memory_uc(addr, pages);
	if (retval) {
		pr_err("set_memory_uc failed.Error:%d\n", retval);
		return retval;
	}
	memset(substream->runtime->dma_area, 0, buf_size);

	return retval;
}

/**
 * snd_intelhad_hw_free- to release the resources allocated during
 * hardware params setup
 *
 * @substream:  substream for which the function is called
 *
 * This function is called by ALSA framework before close callback.
 *
 */
static int snd_intelhad_hw_free(struct snd_pcm_substream *substream)
{
	unsigned long addr;
	u32 pages;

	pr_debug("snd_intelhad_hw_free called\n");

	/* mark back the pages as cached/writeback region before the free */
	addr = (unsigned long) substream->runtime->dma_area;
	pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
	set_memory_wb(addr, pages);
	return snd_pcm_lib_free_pages(substream);
}
Example #14
0
static int minivosc_hw_free(struct snd_pcm_substream *ss)
{
	dbg("%s", __func__);
	return snd_pcm_lib_free_pages(ss);
}
static int mtk_uldlloopback_pcm_hw_free(struct snd_pcm_substream *substream)
{
    PRINTK_AUDDRV("mtk_uldlloopback_pcm_hw_free \n");
    return snd_pcm_lib_free_pages(substream);
}
Example #16
0
int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
			     struct mixart_pipe *pipe, int monitoring)
{
	int err = 0;

	if(pipe->status == PIPE_UNDEFINED)
		return 0;

	if(monitoring)
		pipe->monitoring = 0;
	else
		pipe->references--;

	if((pipe->references <= 0) && (pipe->monitoring == 0)) {

		struct mixart_msg request;
		struct mixart_delete_group_resp delete_resp;

		/* release the clock */
		err = mixart_set_clock( mgr, pipe, 0);
		if( err < 0 ) {
			snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
		}

		/* stop the pipe */
		err = mixart_set_pipe_state(mgr, pipe, 0);
		if( err < 0 ) {
			snd_printk(KERN_ERR "error stopping pipe!\n");
		}

		request.message_id = MSG_STREAM_DELETE_GROUP;
		request.uid = (struct mixart_uid){0,0};
		request.data = &pipe->group_uid;            /* the streaming group ! */
		request.size = sizeof(pipe->group_uid);

		/* delete the pipe */
		err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
		if ((err < 0) || (delete_resp.status != 0)) {
			snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
		}

		pipe->group_uid = (struct mixart_uid){0,0};
		pipe->stream_count = 0;
		pipe->status = PIPE_UNDEFINED;
	}

	return err;
}

static int mixart_set_stream_state(struct mixart_stream *stream, int start)
{
	struct snd_mixart *chip;
	struct mixart_stream_state_req stream_state_req;
	struct mixart_msg request;

	if(!stream->substream)
		return -EINVAL;

	memset(&stream_state_req, 0, sizeof(stream_state_req));
	stream_state_req.stream_count = 1;
	stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid;
	stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number;

	if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET;
	else
		request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET;

	request.uid = (struct mixart_uid){0,0};
	request.data = &stream_state_req;
	request.size = sizeof(stream_state_req);

	stream->abs_period_elapsed = 0;            /* reset stream pos      */
	stream->buf_periods = 0;
	stream->buf_period_frag = 0;

	chip = snd_pcm_substream_chip(stream->substream);

	return snd_mixart_send_msg_nonblock(chip->mgr, &request);
}

/*
 *  Trigger callback
 */

static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
{
	struct mixart_stream *stream = subs->runtime->private_data;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:

		snd_printdd("SNDRV_PCM_TRIGGER_START\n");

		/* START_STREAM */
		if( mixart_set_stream_state(stream, 1) )
			return -EINVAL;

		stream->status = MIXART_STREAM_STATUS_RUNNING;

		break;
	case SNDRV_PCM_TRIGGER_STOP:

		/* STOP_STREAM */
		if( mixart_set_stream_state(stream, 0) )
			return -EINVAL;

		stream->status = MIXART_STREAM_STATUS_OPEN;

		snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");

		break;

	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		/* TODO */
		stream->status = MIXART_STREAM_STATUS_PAUSE;
		snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		/* TODO */
		stream->status = MIXART_STREAM_STATUS_RUNNING;
		snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int mixart_sync_nonblock_events(struct mixart_mgr *mgr)
{
	unsigned long timeout = jiffies + HZ;
	while (atomic_read(&mgr->msg_processed) > 0) {
		if (time_after(jiffies, timeout)) {
			snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
			return -EBUSY;
		}
		schedule_timeout_uninterruptible(1);
	}
	return 0;
}

/*
 *  prepare callback for all pcms
 */
static int snd_mixart_prepare(struct snd_pcm_substream *subs)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	struct mixart_stream *stream = subs->runtime->private_data;

	/* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */

	snd_printdd("snd_mixart_prepare\n");

	mixart_sync_nonblock_events(chip->mgr);

	/* only the first stream can choose the sample rate */
	/* the further opened streams will be limited to its frequency (see open) */
	if(chip->mgr->ref_count_rate == 1)
		chip->mgr->sample_rate = subs->runtime->rate;

	/* set the clock only once (first stream) on the same pipe */
	if(stream->pipe->references == 1) {
		if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) )
			return -EINVAL;
	}

	return 0;
}


static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t format)
{
	int err;
	struct snd_mixart *chip;
	struct mixart_msg request;
	struct mixart_stream_param_desc stream_param;
	struct mixart_return_uid resp;

	chip = snd_pcm_substream_chip(stream->substream);

	memset(&stream_param, 0, sizeof(stream_param));

	stream_param.coding_type = CT_LINEAR;
	stream_param.number_of_channel = stream->channels;

	stream_param.sampling_freq = chip->mgr->sample_rate;
	if(stream_param.sampling_freq == 0)
		stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */

	switch(format){
	case SNDRV_PCM_FORMAT_U8:
		stream_param.sample_type = ST_INTEGER_8;
		stream_param.sample_size = 8;
		break;
	case SNDRV_PCM_FORMAT_S16_LE:
		stream_param.sample_type = ST_INTEGER_16LE;
		stream_param.sample_size = 16;
		break;
	case SNDRV_PCM_FORMAT_S16_BE:
		stream_param.sample_type = ST_INTEGER_16BE;
		stream_param.sample_size = 16;
		break;
	case SNDRV_PCM_FORMAT_S24_3LE:
		stream_param.sample_type = ST_INTEGER_24LE;
		stream_param.sample_size = 24;
		break;
	case SNDRV_PCM_FORMAT_S24_3BE:
		stream_param.sample_type = ST_INTEGER_24BE;
		stream_param.sample_size = 24;
		break;
	case SNDRV_PCM_FORMAT_FLOAT_LE:
		stream_param.sample_type = ST_FLOATING_POINT_32LE;
		stream_param.sample_size = 32;
		break;
	case  SNDRV_PCM_FORMAT_FLOAT_BE:
		stream_param.sample_type = ST_FLOATING_POINT_32BE;
		stream_param.sample_size = 32;
		break;
	default:
		snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n");
		return -EINVAL;
	}

	snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
		   stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);

	/* TODO: what else to configure ? */
	/* stream_param.samples_per_frame = 2; */
	/* stream_param.bytes_per_frame = 4; */
	/* stream_param.bytes_per_sample = 2; */

	stream_param.pipe_count = 1;      /* set to 1 */
	stream_param.stream_count = 1;    /* set to 1 */
	stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid;
	stream_param.stream_desc[0].stream_idx = stream->substream->number;

	request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM;
	request.uid = (struct mixart_uid){0,0};
	request.data = &stream_param;
	request.size = sizeof(stream_param);

	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
	if((err < 0) || resp.error_code) {
		snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
		return -EINVAL;
	}
	return 0;
}


/*
 *  HW_PARAMS callback for all pcms
 */
static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
                                struct snd_pcm_hw_params *hw)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr *mgr = chip->mgr;
	struct mixart_stream *stream = subs->runtime->private_data;
	snd_pcm_format_t format;
	int err;
	int channels;

	/* set up channels */
	channels = params_channels(hw);

	/*  set up format for the stream */
	format = params_format(hw);

	mutex_lock(&mgr->setup_mutex);

	/* update the stream levels */
	if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
		int is_aes = stream->pcm_number > MIXART_PCM_ANALOG;
		if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK )
			mixart_update_playback_stream_level(chip, is_aes, subs->number);
		else
			mixart_update_capture_stream_level( chip, is_aes);
	}

	stream->channels = channels;

	/* set the format to the board */
	err = mixart_set_format(stream, format);
	if(err < 0) {
		mutex_unlock(&mgr->setup_mutex);
		return err;
	}

	/* allocate buffer */
	err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));

	if (err > 0) {
		struct mixart_bufferinfo *bufferinfo;
		int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number;
		if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) {
			i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */
		}
		
		bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
		bufferinfo[i].buffer_address = subs->runtime->dma_addr;
		bufferinfo[i].available_length = subs->runtime->dma_bytes;
		/* bufferinfo[i].buffer_id  is already defined */

		snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i,
				bufferinfo[i].buffer_address,
				bufferinfo[i].available_length,
				subs->number);
	}
	mutex_unlock(&mgr->setup_mutex);

	return err;
}

static int snd_mixart_hw_free(struct snd_pcm_substream *subs)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	snd_pcm_lib_free_pages(subs);
	mixart_sync_nonblock_events(chip->mgr);
	return 0;
}



/*
 *  TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max
 */
static struct snd_pcm_hardware snd_mixart_analog_caps =
{
	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
			      SNDRV_PCM_INFO_MMAP_VALID |
			      SNDRV_PCM_INFO_PAUSE),
	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
	.rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
	.rate_min         = 8000,
	.rate_max         = 48000,
	.channels_min     = 1,
	.channels_max     = 2,
	.buffer_bytes_max = (32*1024),
	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
	.period_bytes_max = (16*1024),
	.periods_min      = 2,
	.periods_max      = (32*1024/256),
};

static struct snd_pcm_hardware snd_mixart_digital_caps =
{
	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
			      SNDRV_PCM_INFO_MMAP_VALID |
			      SNDRV_PCM_INFO_PAUSE),
	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
	.rates            = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
	.rate_min         = 32000,
	.rate_max         = 48000,
	.channels_min     = 1,
	.channels_max     = 2,
	.buffer_bytes_max = (32*1024),
	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
	.period_bytes_max = (16*1024),
	.periods_min      = 2,
	.periods_max      = (32*1024/256),
};


static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
{
	struct snd_mixart            *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr        *mgr = chip->mgr;
	struct snd_pcm_runtime *runtime = subs->runtime;
	struct snd_pcm *pcm = subs->pcm;
	struct mixart_stream     *stream;
	struct mixart_pipe       *pipe;
	int err = 0;
	int pcm_number;

	mutex_lock(&mgr->setup_mutex);

	if ( pcm == chip->pcm ) {
		pcm_number = MIXART_PCM_ANALOG;
		runtime->hw = snd_mixart_analog_caps;
	} else {
		snd_BUG_ON(pcm != chip->pcm_dig);
		pcm_number = MIXART_PCM_DIGITAL;
		runtime->hw = snd_mixart_digital_caps;
	}
	snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);

	/* get stream info */
	stream = &(chip->playback_stream[pcm_number][subs->number]);

	if (stream->status != MIXART_STREAM_STATUS_FREE){
		/* streams in use */
		snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
		err = -EBUSY;
		goto _exit_open;
	}

	/* get pipe pointer (out pipe) */
	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0);

	if (pipe == NULL) {
		err = -EINVAL;
		goto _exit_open;
	}

	/* start the pipe if necessary */
	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
	if( err < 0 ) {
		snd_printk(KERN_ERR "error starting pipe!\n");
		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
		err = -EINVAL;
		goto _exit_open;
	}

	stream->pipe        = pipe;
	stream->pcm_number  = pcm_number;
	stream->status      = MIXART_STREAM_STATUS_OPEN;
	stream->substream   = subs;
	stream->channels    = 0; /* not configured yet */

	runtime->private_data = stream;

	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);

	/* if a sample rate is already used, another stream cannot change */
	if(mgr->ref_count_rate++) {
		if(mgr->sample_rate) {
			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
		}
	}

 _exit_open:
	mutex_unlock(&mgr->setup_mutex);

	return err;
}


static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
{
	struct snd_mixart            *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr        *mgr = chip->mgr;
	struct snd_pcm_runtime *runtime = subs->runtime;
	struct snd_pcm *pcm = subs->pcm;
	struct mixart_stream     *stream;
	struct mixart_pipe       *pipe;
	int err = 0;
	int pcm_number;

	mutex_lock(&mgr->setup_mutex);

	if ( pcm == chip->pcm ) {
		pcm_number = MIXART_PCM_ANALOG;
		runtime->hw = snd_mixart_analog_caps;
	} else {
		snd_BUG_ON(pcm != chip->pcm_dig);
		pcm_number = MIXART_PCM_DIGITAL;
		runtime->hw = snd_mixart_digital_caps;
	}

	runtime->hw.channels_min = 2; /* for instance, no mono */

	snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);

	/* get stream info */
	stream = &(chip->capture_stream[pcm_number]);

	if (stream->status != MIXART_STREAM_STATUS_FREE){
		/* streams in use */
		snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
		err = -EBUSY;
		goto _exit_open;
	}

	/* get pipe pointer (in pipe) */
	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0);

	if (pipe == NULL) {
		err = -EINVAL;
		goto _exit_open;
	}

	/* start the pipe if necessary */
	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
	if( err < 0 ) {
		snd_printk(KERN_ERR "error starting pipe!\n");
		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
		err = -EINVAL;
		goto _exit_open;
	}

	stream->pipe        = pipe;
	stream->pcm_number  = pcm_number;
	stream->status      = MIXART_STREAM_STATUS_OPEN;
	stream->substream   = subs;
	stream->channels    = 0; /* not configured yet */

	runtime->private_data = stream;

	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);

	/* if a sample rate is already used, another stream cannot change */
	if(mgr->ref_count_rate++) {
		if(mgr->sample_rate) {
			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
		}
	}

 _exit_open:
	mutex_unlock(&mgr->setup_mutex);

	return err;
}



static int snd_mixart_close(struct snd_pcm_substream *subs)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr *mgr = chip->mgr;
	struct mixart_stream *stream = subs->runtime->private_data;

	mutex_lock(&mgr->setup_mutex);

	snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);

	/* sample rate released */
	if(--mgr->ref_count_rate == 0) {
		mgr->sample_rate = 0;
	}

	/* delete pipe */
	if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {

		snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
	}

	stream->pipe      = NULL;
	stream->status    = MIXART_STREAM_STATUS_FREE;
	stream->substream = NULL;

	mutex_unlock(&mgr->setup_mutex);
	return 0;
}


static snd_pcm_uframes_t snd_mixart_stream_pointer(struct snd_pcm_substream *subs)
{
	struct snd_pcm_runtime *runtime = subs->runtime;
	struct mixart_stream   *stream  = runtime->private_data;

	return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);
}



static struct snd_pcm_ops snd_mixart_playback_ops = {
	.open      = snd_mixart_playback_open,
	.close     = snd_mixart_close,
	.ioctl     = snd_pcm_lib_ioctl,
	.prepare   = snd_mixart_prepare,
	.hw_params = snd_mixart_hw_params,
	.hw_free   = snd_mixart_hw_free,
	.trigger   = snd_mixart_trigger,
	.pointer   = snd_mixart_stream_pointer,
};

static struct snd_pcm_ops snd_mixart_capture_ops = {
	.open      = snd_mixart_capture_open,
	.close     = snd_mixart_close,
	.ioctl     = snd_pcm_lib_ioctl,
	.prepare   = snd_mixart_prepare,
	.hw_params = snd_mixart_hw_params,
	.hw_free   = snd_mixart_hw_free,
	.trigger   = snd_mixart_trigger,
	.pointer   = snd_mixart_stream_pointer,
};

static void preallocate_buffers(struct snd_mixart *chip, struct snd_pcm *pcm)
{
#if 0
	struct snd_pcm_substream *subs;
	int stream;

	for (stream = 0; stream < 2; stream++) {
		int idx = 0;
		for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++)
			/* set up the unique device id with the chip index */
			subs->dma_device.id = subs->pcm->device << 16 |
				subs->stream << 8 | (subs->number + 1) |
				(chip->chip_idx + 1) << 24;
	}
#endif
	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
					      snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024);
}

/*
 */
static int snd_mixart_pcm_analog(struct snd_mixart *chip)
{
	int err;
	struct snd_pcm *pcm;
	char name[32];

	sprintf(name, "miXart analog %d", chip->chip_idx);
	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
			       MIXART_PLAYBACK_STREAMS,
			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
		snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
		return err;
	}

	pcm->private_data = chip;

	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);

	pcm->info_flags = 0;
	strcpy(pcm->name, name);

	preallocate_buffers(chip, pcm);

	chip->pcm = pcm;
	return 0;
}


/*
 */
static int snd_mixart_pcm_digital(struct snd_mixart *chip)
{
	int err;
	struct snd_pcm *pcm;
	char name[32];

	sprintf(name, "miXart AES/EBU %d", chip->chip_idx);
	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
			       MIXART_PLAYBACK_STREAMS,
			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
		snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
		return err;
	}

	pcm->private_data = chip;

	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);

	pcm->info_flags = 0;
	strcpy(pcm->name, name);

	preallocate_buffers(chip, pcm);

	chip->pcm_dig = pcm;
	return 0;
}

static int snd_mixart_chip_free(struct snd_mixart *chip)
{
	kfree(chip);
	return 0;
}

static int snd_mixart_chip_dev_free(struct snd_device *device)
{
	struct snd_mixart *chip = device->device_data;
	return snd_mixart_chip_free(chip);
}


/*
 */
static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx)
{
	int err;
	struct snd_mixart *chip;
	static struct snd_device_ops ops = {
		.dev_free = snd_mixart_chip_dev_free,
	};

	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
	if (! chip) {
		snd_printk(KERN_ERR "cannot allocate chip\n");
		return -ENOMEM;
	}

	chip->card = card;
	chip->chip_idx = idx;
	chip->mgr = mgr;

	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
		snd_mixart_chip_free(chip);
		return err;
	}

	mgr->chip[idx] = chip;
	snd_card_set_dev(card, &mgr->pci->dev);

	return 0;
}
Example #17
0
/* hw_free callback */
static int snd_p16v_pcm_hw_free_capture(struct snd_pcm_substream *substream)
{
	int result;
	result = snd_pcm_lib_free_pages(substream);
	return result;
}
static int sst_media_hw_free(struct snd_pcm_substream *substream,
		struct snd_soc_dai *dai)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #19
0
/*
 * release buffers
 */
static int snd_pmac_pcm_hw_free(struct snd_pcm_substream *subs)
{
	snd_pcm_lib_free_pages(subs);
	return 0;
}
Example #20
0
static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
{
	int ret;
	ret = snd_pcm_lib_free_pages(substream);
	return ret;
};
Example #21
0
static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
{
	if (fake_buffer)
		return 0;
	return snd_pcm_lib_free_pages(substream);
}
Example #22
0
static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #23
0
static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
				   *substream)
{
	/* Free the DMA buffer */
	return snd_pcm_lib_free_pages(substream);
}
static int snd_em8300_pcm_hw_free(struct snd_pcm_substream *substream)
{
//	printk("em8300-%d: snd_em8300_pcm_hw_free called.\n", em->instance);
	return snd_pcm_lib_free_pages(substream);
}
Example #25
0
static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
{
	return snd_pcm_lib_free_pages(substream);
}
Example #26
0
/* hw_free callback */
static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream)
{
	int result;
	result = snd_pcm_lib_free_pages(substream);
	return result;
}
static int mtk_voice_bt_hw_free(struct snd_pcm_substream *substream)
{
	PRINTK_AUDDRV("mtk_voice_bt_hw_free\n");
	return snd_pcm_lib_free_pages(substream);
}
static int hi3630_srcup_normal_hw_params(struct snd_pcm_substream *substream,
					 struct snd_pcm_hw_params *params)
{
	struct hi3630_srcup_runtime_data *prtd = substream->runtime->private_data;
	struct hi3630_srcup_data *pdata = prtd->pdata;
	unsigned long bytes = params_buffer_bytes(params);
	unsigned int params_value = 0;
	unsigned int channels = 0;
	unsigned int format = 0;
	int ret = 0;

	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		ret = snd_pcm_lib_malloc_pages(substream, bytes);
		if (0 > ret) {
			loge("snd_pcm_lib_malloc_pages ret is %d", ret);
			return ret;
		}

		/* CHECK SUPPORT CHANNELS : mono or stereo */
		params_value = params_channels(params);
		if (2 == params_value || 1 == params_value) {
			channels = params_value;
		} else {
			loge("DAC not support %d channels\n", params_value);
			ret = -EINVAL;
			goto err_out;
		}

		params_value = params_format(params);
		/* check formats */
		switch (params_value) {
		case SNDRV_PCM_FORMAT_S16_BE :
			format |= SRCUP_BIG_DIAN_BIT;
			/* fallthrough */
		case SNDRV_PCM_FORMAT_S16_LE :
			if (2 == channels)
				format |= STEREO_16BIT;
			else
				format |= MONO_16BIT;
			break;
		default :
			loge("format err : %d, not support\n", params_value);
			ret = -EINVAL;
			goto err_out;
		}

		format |= SRCUP_CH0_HLC;

		mutex_lock(&prtd->mutex);
		prtd->period_size = params_period_bytes(params);
		mutex_unlock(&prtd->mutex);

		/*output format 24bit, single req mode*/
		hi3630_srcup_reg_write(pdata, HI3630_SRCUP_SINGLE_REQ_MODE_REG, SRCUP_OUT_FORMT_24BIT |
					SRCUP_STEREO_DATA | SRCUP_SINGLE_REQ_MODE);

		/*channel ctrl*/
		hi3630_srcup_reg_write(pdata, HI3630_SRCUP_CH0_CTRL_REG, format);

err_out:
		if (0 > ret) {
			loge("hw params error, ret : %d\n", ret);
			snd_pcm_lib_free_pages(substream);
		}
	}

	return ret;
}
static int mtk_pcm_mrgrx_hw_free(struct snd_pcm_substream *substream)
{
    printk("mtk_pcm_mrgrx_hw_free \n");
    return snd_pcm_lib_free_pages(substream);
}
static int hi3630_pcm_hdmi_hw_params(struct snd_pcm_substream *substream,
					 struct snd_pcm_hw_params *params)
{
	struct hi3630_hdmi_runtime_data *prtd = substream->runtime->private_data;
	struct hi3630_hdmi_data *pdata = prtd->pdata;
	unsigned long bytes = params_buffer_bytes(params);
	unsigned int params_value = 0;
	unsigned int channels = 0;
	unsigned int infreq_index = 0;
	unsigned int outfreq_index = 0;
	unsigned int width = 0;
	unsigned int format = 0;
	int txValue = 0;
	int ret = 0;

	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
		ret = snd_pcm_lib_malloc_pages(substream, bytes);
		if (0 > ret) {
			loge("snd_pcm_lib_malloc_pages ret is %d", ret);
			return ret;
		}

		/* CHECK SUPPORT CHANNELS : mono or stereo */
		params_value = params_channels(params);
		if (2 == params_value || 1 == params_value) {
			channels = params_value;
		} else {
			loge("DAC not support %d channels\n", params_value);
			ret = -EINVAL;
			goto err_out;
		}
		params_value = params_rate(params);
		logd("set rate = %d \n", params_value);
		for (infreq_index = 0; infreq_index < ARRAY_SIZE(freq); infreq_index++) {
			if(params_value == freq[infreq_index])
				break;
		}
		if ( ARRAY_SIZE(freq) <= infreq_index) {
			loge("set rate = %d error\n", params_value);
			return -EINVAL;
		}
		hi3630_get_afrequency(infreq_index, &outfreq_index, channels);

		params_value = params_format(params);
		/* check formats */
		switch (params_value) {
		case SNDRV_PCM_FORMAT_S16_BE :
			format = HDMI_BIG_DIAN_BIT;
			/* fallthrough */
		case SNDRV_PCM_FORMAT_S16_LE :
			if (2 == channels)
				width = STEREO_16BIT;
			break;
		default :
			loge("format err : %d, not support\n", params_value);
			ret = -EINVAL;
			goto err_out;
		}

		mutex_lock(&prtd->mutex);
		prtd->period_size = params_period_bytes(params);
		mutex_unlock(&prtd->mutex);

		txValue = hi3630_hdmi_reg_read(pdata, HI3630_ASP_TX3);
		txValue |= (width << 3) | (1 << 6) | ((channels-1) << 7) |format;
		hi3630_hdmi_reg_write(pdata, HI3630_ASP_TX3, txValue);
		logi("hdmi params.freq:%d, channel:%d\n", freq[outfreq_index], channels);
		k3_hdmi_audio_set_param(freq[outfreq_index], HDMI_SAMPLE_16BITS, true, 0, 1, channels);

err_out:
		if (0 > ret) {
			loge("hw params error, ret : %d\n", ret);
			snd_pcm_lib_free_pages(substream);
		}
	}

	return ret;
}