Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    3)  * Driver for Digigram VX soundcards
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    5)  * PCM part
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    7)  * Copyright (c) 2002,2003 by Takashi Iwai <tiwai@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300    9)  * STRATEGY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   10)  *  for playback, we send series of "chunks", which size is equal with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   11)  *  IBL size, typically 126 samples.  at each end of chunk, the end-of-buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   12)  *  interrupt is notified, and the interrupt handler will feed the next chunk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   13)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   14)  *  the current position is calculated from the sample count RMH.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   15)  *  pipe->transferred is the counter of data which has been already transferred.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   16)  *  if this counter reaches to the period size, snd_pcm_period_elapsed() will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   17)  *  be issued.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   18)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   19)  *  for capture, the situation is much easier.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   20)  *  to get a low latency response, we'll check the capture streams at each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   21)  *  interrupt (capture stream has no EOB notification).  if the pending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   22)  *  data is accumulated to the period size, snd_pcm_period_elapsed() is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   23)  *  called and the pointer is updated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   24)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   25)  *  the current point of read buffer is kept in pipe->hw_ptr.  note that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   26)  *  this is in bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   27)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   28)  * TODO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   29)  *  - linked trigger for full-duplex mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   30)  *  - scheduled action on the stream.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   31)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   33) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   34) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   35) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   36) #include <sound/asoundef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   37) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   38) #include <sound/vx_core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   39) #include "vx_cmd.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   42) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   43)  * read three pending pcm bytes via inb()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   44)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   45) static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   46) 				  struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   48) 	int offset = pipe->hw_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   49) 	unsigned char *buf = (unsigned char *)(runtime->dma_area + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   50) 	*buf++ = vx_inb(chip, RXH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   51) 	if (++offset >= pipe->buffer_bytes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   52) 		offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   53) 		buf = (unsigned char *)runtime->dma_area;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   54) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   55) 	*buf++ = vx_inb(chip, RXM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   56) 	if (++offset >= pipe->buffer_bytes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   57) 		offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   58) 		buf = (unsigned char *)runtime->dma_area;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   59) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   60) 	*buf++ = vx_inb(chip, RXL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   61) 	if (++offset >= pipe->buffer_bytes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   62) 		offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   63) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   64) 	pipe->hw_ptr = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   68)  * vx_set_pcx_time - convert from the PC time to the RMH status time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   69)  * @pc_time: the pointer for the PC-time to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   70)  * @dsp_time: the pointer for RMH status time array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   71)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   72) static void vx_set_pcx_time(struct vx_core *chip, pcx_time_t *pc_time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   73) 			    unsigned int *dsp_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   75) 	dsp_time[0] = (unsigned int)((*pc_time) >> 24) & PCX_TIME_HI_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   76) 	dsp_time[1] = (unsigned int)(*pc_time) &  MASK_DSP_WORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   79) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   80)  * vx_set_differed_time - set the differed time if specified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   81)  * @rmh: the rmh record to modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   82)  * @pipe: the pipe to be checked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   83)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   84)  * if the pipe is programmed with the differed time, set the DSP time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   85)  * on the rmh and changes its command length.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   86)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   87)  * returns the increase of the command length.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   88)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   89) static int vx_set_differed_time(struct vx_core *chip, struct vx_rmh *rmh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   90) 				struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   92) 	/* Update The length added to the RMH command by the timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   93) 	if (! (pipe->differed_type & DC_DIFFERED_DELAY))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   94) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   95) 		
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   96) 	/* Set the T bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   97) 	rmh->Cmd[0] |= DSP_DIFFERED_COMMAND_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   99) 	/* Time stamp is the 1st following parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  100) 	vx_set_pcx_time(chip, &pipe->pcx_time, &rmh->Cmd[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  102) 	/* Add the flags to a notified differed command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  103) 	if (pipe->differed_type & DC_NOTIFY_DELAY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  104) 		rmh->Cmd[1] |= NOTIFY_MASK_TIME_HIGH ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  106) 	/* Add the flags to a multiple differed command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  107) 	if (pipe->differed_type & DC_MULTIPLE_DELAY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  108) 		rmh->Cmd[1] |= MULTIPLE_MASK_TIME_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  110) 	/* Add the flags to a stream-time differed command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  111) 	if (pipe->differed_type & DC_STREAM_TIME_DELAY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  112) 		rmh->Cmd[1] |= STREAM_MASK_TIME_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  113) 		
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  114) 	rmh->LgCmd += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  115) 	return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  118) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  119)  * vx_set_stream_format - send the stream format command
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  120)  * @pipe: the affected pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  121)  * @data: format bitmask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  122)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  123) static int vx_set_stream_format(struct vx_core *chip, struct vx_pipe *pipe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  124) 				unsigned int data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  126) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  128) 	vx_init_rmh(&rmh, pipe->is_capture ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  129) 		    CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  130) 	rmh.Cmd[0] |= pipe->number << FIELD_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  132)         /* Command might be longer since we may have to add a timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  133) 	vx_set_differed_time(chip, &rmh, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  135) 	rmh.Cmd[rmh.LgCmd] = (data & 0xFFFFFF00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  136) 	rmh.Cmd[rmh.LgCmd + 1] = (data & 0xFF) << 16 /*| (datal & 0xFFFF00) >> 8*/;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  137) 	rmh.LgCmd += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  138)     
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  139) 	return vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  143) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  144)  * vx_set_format - set the format of a pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  145)  * @pipe: the affected pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  146)  * @runtime: pcm runtime instance to be referred
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  147)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  148)  * returns 0 if successful, or a negative error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  149)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  150) static int vx_set_format(struct vx_core *chip, struct vx_pipe *pipe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  151) 			 struct snd_pcm_runtime *runtime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  153) 	unsigned int header = HEADER_FMT_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  155) 	if (runtime->channels == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  156) 		header |= HEADER_FMT_MONO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  157) 	if (snd_pcm_format_little_endian(runtime->format))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  158) 		header |= HEADER_FMT_INTEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  159) 	if (runtime->rate < 32000 && runtime->rate > 11025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  160) 		header |= HEADER_FMT_UPTO32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  161) 	else if (runtime->rate <= 11025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  162) 		header |= HEADER_FMT_UPTO11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  163) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  164) 	switch (snd_pcm_format_physical_width(runtime->format)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  165) 	// case 8: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  166) 	case 16: header |= HEADER_FMT_16BITS; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  167) 	case 24: header |= HEADER_FMT_24BITS; break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  168) 	default : 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  169) 		snd_BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  170) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  171) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  173) 	return vx_set_stream_format(chip, pipe, header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  176) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  177)  * set / query the IBL size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  178)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  179) static int vx_set_ibl(struct vx_core *chip, struct vx_ibl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  181) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  182) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  184) 	vx_init_rmh(&rmh, CMD_IBL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  185) 	rmh.Cmd[0] |= info->size & 0x03ffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  186) 	err = vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  187) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  188) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  189) 	info->size = rmh.Stat[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  190) 	info->max_size = rmh.Stat[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  191) 	info->min_size = rmh.Stat[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  192) 	info->granularity = rmh.Stat[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  193) 	snd_printdd(KERN_DEBUG "vx_set_ibl: size = %d, max = %d, min = %d, gran = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  194) 		   info->size, info->max_size, info->min_size, info->granularity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  195) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  199) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  200)  * vx_get_pipe_state - get the state of a pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  201)  * @pipe: the pipe to be checked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  202)  * @state: the pointer for the returned state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  203)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  204)  * checks the state of a given pipe, and stores the state (1 = running,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  205)  * 0 = paused) on the given pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  206)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  207)  * called from trigger callback only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  208)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  209) static int vx_get_pipe_state(struct vx_core *chip, struct vx_pipe *pipe, int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  211) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  212) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  214) 	vx_init_rmh(&rmh, CMD_PIPE_STATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  215) 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  216) 	err = vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  217) 	if (! err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  218) 		*state = (rmh.Stat[0] & (1 << pipe->number)) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  219) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  223) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  224)  * vx_query_hbuffer_size - query available h-buffer size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  225)  * @pipe: the pipe to be checked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  226)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  227)  * return the available size on h-buffer in bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  228)  * or a negative error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  229)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  230)  * NOTE: calling this function always switches to the stream mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  231)  *       you'll need to disconnect the host to get back to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  232)  *       normal mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  233)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  234) static int vx_query_hbuffer_size(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  236) 	int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  237) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  238) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  239) 	vx_init_rmh(&rmh, CMD_SIZE_HBUFFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  240) 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  241) 	if (pipe->is_capture)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  242) 		rmh.Cmd[0] |= 0x00000001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  243) 	result = vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  244) 	if (! result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  245) 		result = rmh.Stat[0] & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  246) 	return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  248) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  250) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  251)  * vx_pipe_can_start - query whether a pipe is ready for start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  252)  * @pipe: the pipe to be checked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  253)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  254)  * return 1 if ready, 0 if not ready, and negative value on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  255)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  256)  * called from trigger callback only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  257)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  258) static int vx_pipe_can_start(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  260) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  261) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  262)         
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  263) 	vx_init_rmh(&rmh, CMD_CAN_START_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  264) 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  265) 	rmh.Cmd[0] |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  267) 	err = vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  268) 	if (! err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  269) 		if (rmh.Stat[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  270) 			err = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  271) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  272) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  274) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  275) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  276)  * vx_conf_pipe - tell the pipe to stand by and wait for IRQA.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  277)  * @pipe: the pipe to be configured
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  278)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  279) static int vx_conf_pipe(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  281) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  283) 	vx_init_rmh(&rmh, CMD_CONF_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  284) 	if (pipe->is_capture)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  285) 		rmh.Cmd[0] |= COMMAND_RECORD_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  286) 	rmh.Cmd[1] = 1 << pipe->number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  287) 	return vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  290) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  291)  * vx_send_irqa - trigger IRQA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  292)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  293) static int vx_send_irqa(struct vx_core *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  295) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  297) 	vx_init_rmh(&rmh, CMD_SEND_IRQA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  298) 	return vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  301) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  302) #define MAX_WAIT_FOR_DSP        250
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  303) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  304)  * vx boards do not support inter-card sync, besides
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  305)  * only 126 samples require to be prepared before a pipe can start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  306)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  307) #define CAN_START_DELAY         2	/* wait 2ms only before asking if the pipe is ready*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  308) #define WAIT_STATE_DELAY        2	/* wait 2ms after irqA was requested and check if the pipe state toggled*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  310) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  311)  * vx_toggle_pipe - start / pause a pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  312)  * @pipe: the pipe to be triggered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  313)  * @state: start = 1, pause = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  314)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  315)  * called from trigger callback only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  316)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  317)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  318) static int vx_toggle_pipe(struct vx_core *chip, struct vx_pipe *pipe, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  320) 	int err, i, cur_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  322) 	/* Check the pipe is not already in the requested state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  323) 	if (vx_get_pipe_state(chip, pipe, &cur_state) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  324) 		return -EBADFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  325) 	if (state == cur_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  326) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  328) 	/* If a start is requested, ask the DSP to get prepared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  329) 	 * and wait for a positive acknowledge (when there are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  330) 	 * enough sound buffer for this pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  331) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  332) 	if (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  333) 		for (i = 0 ; i < MAX_WAIT_FOR_DSP; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  334) 			err = vx_pipe_can_start(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  335) 			if (err > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  336) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  337) 			/* Wait for a few, before asking again
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  338) 			 * to avoid flooding the DSP with our requests
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  339) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  340) 			mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  341) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  342) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  343)     
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  344) 	if ((err = vx_conf_pipe(chip, pipe)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  345) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  346) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  347) 	if ((err = vx_send_irqa(chip)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  348) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  349)     
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  350) 	/* If it completes successfully, wait for the pipes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  351) 	 * reaching the expected state before returning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  352) 	 * Check one pipe only (since they are synchronous)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  353) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  354) 	for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  355) 		err = vx_get_pipe_state(chip, pipe, &cur_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  356) 		if (err < 0 || cur_state == state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  357) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  358) 		err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  359) 		mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  360) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  361) 	return err < 0 ? -EIO : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  363) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  364)     
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  365) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  366)  * vx_stop_pipe - stop a pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  367)  * @pipe: the pipe to be stopped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  368)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  369)  * called from trigger callback only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  370)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  371) static int vx_stop_pipe(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  373) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  374) 	vx_init_rmh(&rmh, CMD_STOP_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  375) 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  376) 	return vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  380) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  381)  * vx_alloc_pipe - allocate a pipe and initialize the pipe instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  382)  * @capture: 0 = playback, 1 = capture operation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  383)  * @audioid: the audio id to be assigned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  384)  * @num_audio: number of audio channels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  385)  * @pipep: the returned pipe instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  386)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  387)  * return 0 on success, or a negative error code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  388)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  389) static int vx_alloc_pipe(struct vx_core *chip, int capture,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  390) 			 int audioid, int num_audio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  391) 			 struct vx_pipe **pipep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  393) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  394) 	struct vx_pipe *pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  395) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  396) 	int data_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  398) 	*pipep = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  399) 	vx_init_rmh(&rmh, CMD_RES_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  400) 	vx_set_pipe_cmd_params(&rmh, capture, audioid, num_audio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  401) #if 0	// NYI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  402) 	if (underrun_skip_sound)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  403) 		rmh.Cmd[0] |= BIT_SKIP_SOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  404) #endif	// NYI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  405) 	data_mode = (chip->uer_bits & IEC958_AES0_NONAUDIO) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  406) 	if (! capture && data_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  407) 		rmh.Cmd[0] |= BIT_DATA_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  408) 	err = vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  409) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  410) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  411) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  412) 	/* initialize the pipe record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  413) 	pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  414) 	if (! pipe) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  415) 		/* release the pipe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  416) 		vx_init_rmh(&rmh, CMD_FREE_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  417) 		vx_set_pipe_cmd_params(&rmh, capture, audioid, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  418) 		vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  419) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  420) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  422) 	/* the pipe index should be identical with the audio index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  423) 	pipe->number = audioid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  424) 	pipe->is_capture = capture;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  425) 	pipe->channels = num_audio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  426) 	pipe->differed_type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  427) 	pipe->pcx_time = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  428) 	pipe->data_mode = data_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  429) 	*pipep = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  430) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  431) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  433) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  434) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  435) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  436)  * vx_free_pipe - release a pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  437)  * @pipe: pipe to be released
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  438)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  439) static int vx_free_pipe(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  441) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  442) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  443) 	vx_init_rmh(&rmh, CMD_FREE_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  444) 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  445) 	vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  447) 	kfree(pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  448) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  450) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  451) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  452) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  453)  * vx_start_stream - start the stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  454)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  455)  * called from trigger callback only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  456)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  457) static int vx_start_stream(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  458) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  459) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  461) 	vx_init_rmh(&rmh, CMD_START_ONE_STREAM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  462) 	vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  463) 	vx_set_differed_time(chip, &rmh, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  464) 	return vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  466) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  467) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  468) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  469)  * vx_stop_stream - stop the stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  470)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  471)  * called from trigger callback only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  472)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  473) static int vx_stop_stream(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  475) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  476) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  477) 	vx_init_rmh(&rmh, CMD_STOP_STREAM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  478) 	vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  479) 	return vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  481) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  482) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  483) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  484)  * playback hw information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  485)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  486) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  487) static const struct snd_pcm_hardware vx_pcm_playback_hw = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  488) 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  489) 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  490) 				 /*SNDRV_PCM_INFO_RESUME*/),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  491) 	.formats =		(/*SNDRV_PCM_FMTBIT_U8 |*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  492) 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  493) 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  494) 	.rate_min =		5000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  495) 	.rate_max =		48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  496) 	.channels_min =		1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  497) 	.channels_max =		2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  498) 	.buffer_bytes_max =	(128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  499) 	.period_bytes_min =	126,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  500) 	.period_bytes_max =	(128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  501) 	.periods_min =		2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  502) 	.periods_max =		VX_MAX_PERIODS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  503) 	.fifo_size =		126,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  504) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  505) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  506) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  507) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  508)  * vx_pcm_playback_open - open callback for playback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  509)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  510) static int vx_pcm_playback_open(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  512) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  513) 	struct vx_core *chip = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  514) 	struct vx_pipe *pipe = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  515) 	unsigned int audio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  516) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  517) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  518) 	if (chip->chip_status & VX_STAT_IS_STALE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  519) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  521) 	audio = subs->pcm->device * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  522) 	if (snd_BUG_ON(audio >= chip->audio_outs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  523) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  524) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  525) 	/* playback pipe may have been already allocated for monitoring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  526) 	pipe = chip->playback_pipes[audio];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  527) 	if (! pipe) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  528) 		/* not allocated yet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  529) 		err = vx_alloc_pipe(chip, 0, audio, 2, &pipe); /* stereo playback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  530) 		if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  531) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  532) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  533) 	/* open for playback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  534) 	pipe->references++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  535) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  536) 	pipe->substream = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  537) 	chip->playback_pipes[audio] = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  538) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  539) 	runtime->hw = vx_pcm_playback_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  540) 	runtime->hw.period_bytes_min = chip->ibl.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  541) 	runtime->private_data = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  542) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  543) 	/* align to 4 bytes (otherwise will be problematic when 24bit is used) */ 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  544) 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  545) 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  546) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  547) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  549) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  550) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  551)  * vx_pcm_playback_close - close callback for playback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  552)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  553) static int vx_pcm_playback_close(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  554) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  555) 	struct vx_core *chip = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  556) 	struct vx_pipe *pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  557) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  558) 	if (! subs->runtime->private_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  559) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  560) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  561) 	pipe = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  562) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  563) 	if (--pipe->references == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  564) 		chip->playback_pipes[pipe->number] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  565) 		vx_free_pipe(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  566) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  567) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  568) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  569) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  571) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  572) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  573) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  574)  * vx_notify_end_of_buffer - send "end-of-buffer" notifier at the given pipe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  575)  * @pipe: the pipe to notify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  576)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  577)  * NB: call with a certain lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  578)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  579) static int vx_notify_end_of_buffer(struct vx_core *chip, struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  580) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  581) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  582) 	struct vx_rmh rmh;  /* use a temporary rmh here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  583) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  584) 	/* Toggle Dsp Host Interface into Message mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  585) 	vx_send_rih_nolock(chip, IRQ_PAUSE_START_CONNECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  586) 	vx_init_rmh(&rmh, CMD_NOTIFY_END_OF_BUFFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  587) 	vx_set_stream_cmd_params(&rmh, 0, pipe->number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  588) 	err = vx_send_msg_nolock(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  589) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  590) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  591) 	/* Toggle Dsp Host Interface back to sound transfer mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  592) 	vx_send_rih_nolock(chip, IRQ_PAUSE_START_CONNECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  593) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  596) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  597)  * vx_pcm_playback_transfer_chunk - transfer a single chunk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  598)  * @subs: substream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  599)  * @pipe: the pipe to transfer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  600)  * @size: chunk size in bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  601)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  602)  * transfer a single buffer chunk.  EOB notificaton is added after that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  603)  * called from the interrupt handler, too.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  604)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  605)  * return 0 if ok.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  606)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  607) static int vx_pcm_playback_transfer_chunk(struct vx_core *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  608) 					  struct snd_pcm_runtime *runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  609) 					  struct vx_pipe *pipe, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  610) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  611) 	int space, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  612) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  613) 	space = vx_query_hbuffer_size(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  614) 	if (space < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  615) 		/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  616) 		vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  617) 		snd_printd("error hbuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  618) 		return space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  619) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  620) 	if (space < size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  621) 		vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  622) 		snd_printd("no enough hbuffer space %d\n", space);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  623) 		return -EIO; /* XRUN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  624) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  625) 		
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  626) 	/* we don't need irqsave here, because this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  627) 	 * is called from either trigger callback or irq handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  628) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  629) 	mutex_lock(&chip->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  630) 	vx_pseudo_dma_write(chip, runtime, pipe, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  631) 	err = vx_notify_end_of_buffer(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  632) 	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  633) 	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  634) 	mutex_unlock(&chip->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  635) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  637) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  638) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  639)  * update the position of the given pipe.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  640)  * pipe->position is updated and wrapped within the buffer size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  641)  * pipe->transferred is updated, too, but the size is not wrapped,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  642)  * so that the caller can check the total transferred size later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  643)  * (to call snd_pcm_period_elapsed).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  644)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  645) static int vx_update_pipe_position(struct vx_core *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  646) 				   struct snd_pcm_runtime *runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  647) 				   struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  648) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  649) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  650) 	int err, update;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  651) 	u64 count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  652) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  653) 	vx_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  654) 	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  655) 	err = vx_send_msg(chip, &rmh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  656) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  657) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  658) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  659) 	count = ((u64)(rmh.Stat[0] & 0xfffff) << 24) | (u64)rmh.Stat[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  660) 	update = (int)(count - pipe->cur_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  661) 	pipe->cur_count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  662) 	pipe->position += update;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  663) 	if (pipe->position >= (int)runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  664) 		pipe->position %= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  665) 	pipe->transferred += update;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  666) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  668) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  669) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  670)  * transfer the pending playback buffer data to DSP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  671)  * called from interrupt handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  672)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  673) static void vx_pcm_playback_transfer(struct vx_core *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  674) 				     struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  675) 				     struct vx_pipe *pipe, int nchunks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  677) 	int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  678) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  679) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  680) 	if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  681) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  682) 	for (i = 0; i < nchunks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  683) 		if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  684) 							  chip->ibl.size)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  685) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  686) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  687) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  688) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  689) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  690)  * update the playback position and call snd_pcm_period_elapsed() if necessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  691)  * called from interrupt handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  692)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  693) static void vx_pcm_playback_update(struct vx_core *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  694) 				   struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  695) 				   struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  697) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  698) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  699) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  700) 	if (pipe->running && ! (chip->chip_status & VX_STAT_IS_STALE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  701) 		if ((err = vx_update_pipe_position(chip, runtime, pipe)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  702) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  703) 		if (pipe->transferred >= (int)runtime->period_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  704) 			pipe->transferred %= runtime->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  705) 			snd_pcm_period_elapsed(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  706) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  707) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  708) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  709) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  710) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  711)  * vx_pcm_playback_trigger - trigger callback for playback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  712)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  713) static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  714) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  715) 	struct vx_core *chip = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  716) 	struct vx_pipe *pipe = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  717) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  718) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  719) 	if (chip->chip_status & VX_STAT_IS_STALE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  720) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  721) 		
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  722) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  723) 	case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  724) 	case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  725) 		if (! pipe->is_capture)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  726) 			vx_pcm_playback_transfer(chip, subs, pipe, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  727) 		err = vx_start_stream(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  728) 		if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  729) 			pr_debug("vx: cannot start stream\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  730) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  731) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  732) 		err = vx_toggle_pipe(chip, pipe, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  733) 		if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  734) 			pr_debug("vx: cannot start pipe\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  735) 			vx_stop_stream(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  736) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  737) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  738) 		chip->pcm_running++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  739) 		pipe->running = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  740) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  741) 	case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  742) 	case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  743) 		vx_toggle_pipe(chip, pipe, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  744) 		vx_stop_pipe(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  745) 		vx_stop_stream(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  746) 		chip->pcm_running--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  747) 		pipe->running = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  748) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  749) 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  750) 		if ((err = vx_toggle_pipe(chip, pipe, 0)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  751) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  752) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  753) 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  754) 		if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  755) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  756) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  757) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  758) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  759) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  760) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  762) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  763) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  764)  * vx_pcm_playback_pointer - pointer callback for playback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  765)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  766) static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  767) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  768) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  769) 	struct vx_pipe *pipe = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  770) 	return pipe->position;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  772) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  773) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  774)  * vx_pcm_prepare - prepare callback for playback and capture
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  775)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  776) static int vx_pcm_prepare(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  778) 	struct vx_core *chip = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  779) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  780) 	struct vx_pipe *pipe = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  781) 	int err, data_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  782) 	// int max_size, nchunks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  783) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  784) 	if (chip->chip_status & VX_STAT_IS_STALE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  785) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  786) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  787) 	data_mode = (chip->uer_bits & IEC958_AES0_NONAUDIO) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  788) 	if (data_mode != pipe->data_mode && ! pipe->is_capture) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  789) 		/* IEC958 status (raw-mode) was changed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  790) 		/* we reopen the pipe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  791) 		struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  792) 		snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  793) 		vx_init_rmh(&rmh, CMD_FREE_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  794) 		vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  795) 		if ((err = vx_send_msg(chip, &rmh)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  796) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  797) 		vx_init_rmh(&rmh, CMD_RES_PIPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  798) 		vx_set_pipe_cmd_params(&rmh, 0, pipe->number, pipe->channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  799) 		if (data_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  800) 			rmh.Cmd[0] |= BIT_DATA_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  801) 		if ((err = vx_send_msg(chip, &rmh)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  802) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  803) 		pipe->data_mode = data_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  804) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  805) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  806) 	if (chip->pcm_running && chip->freq != runtime->rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  807) 		snd_printk(KERN_ERR "vx: cannot set different clock %d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  808) 			   "from the current %d\n", runtime->rate, chip->freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  809) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  810) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  811) 	vx_set_clock(chip, runtime->rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  812) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  813) 	if ((err = vx_set_format(chip, pipe, runtime)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  814) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  815) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  816) 	if (vx_is_pcmcia(chip)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  817) 		pipe->align = 2; /* 16bit word */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  818) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  819) 		pipe->align = 4; /* 32bit word */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  820) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  821) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  822) 	pipe->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  823) 	pipe->period_bytes = frames_to_bytes(runtime, runtime->period_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  824) 	pipe->hw_ptr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  825) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  826) 	/* set the timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  827) 	vx_update_pipe_position(chip, runtime, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  828) 	/* clear again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  829) 	pipe->transferred = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  830) 	pipe->position = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  831) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  832) 	pipe->prepared = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  833) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  834) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  835) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  836) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  837) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  838) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  839)  * operators for PCM playback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  840)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  841) static const struct snd_pcm_ops vx_pcm_playback_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  842) 	.open =		vx_pcm_playback_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  843) 	.close =	vx_pcm_playback_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  844) 	.prepare =	vx_pcm_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  845) 	.trigger =	vx_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  846) 	.pointer =	vx_pcm_playback_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  847) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  848) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  849) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  850) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  851)  * playback hw information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  852)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  853) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  854) static const struct snd_pcm_hardware vx_pcm_capture_hw = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  855) 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  856) 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  857) 				 /*SNDRV_PCM_INFO_RESUME*/),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  858) 	.formats =		(/*SNDRV_PCM_FMTBIT_U8 |*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  859) 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  860) 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  861) 	.rate_min =		5000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  862) 	.rate_max =		48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  863) 	.channels_min =		1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  864) 	.channels_max =		2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  865) 	.buffer_bytes_max =	(128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  866) 	.period_bytes_min =	126,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  867) 	.period_bytes_max =	(128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  868) 	.periods_min =		2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  869) 	.periods_max =		VX_MAX_PERIODS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  870) 	.fifo_size =		126,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  871) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  872) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  873) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  874) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  875)  * vx_pcm_capture_open - open callback for capture
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  876)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  877) static int vx_pcm_capture_open(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  878) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  879) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  880) 	struct vx_core *chip = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  881) 	struct vx_pipe *pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  882) 	struct vx_pipe *pipe_out_monitoring = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  883) 	unsigned int audio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  884) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  885) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  886) 	if (chip->chip_status & VX_STAT_IS_STALE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  887) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  888) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  889) 	audio = subs->pcm->device * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  890) 	if (snd_BUG_ON(audio >= chip->audio_ins))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  891) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  892) 	err = vx_alloc_pipe(chip, 1, audio, 2, &pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  893) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  894) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  895) 	pipe->substream = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  896) 	chip->capture_pipes[audio] = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  897) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  898) 	/* check if monitoring is needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  899) 	if (chip->audio_monitor_active[audio]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  900) 		pipe_out_monitoring = chip->playback_pipes[audio];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  901) 		if (! pipe_out_monitoring) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  902) 			/* allocate a pipe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  903) 			err = vx_alloc_pipe(chip, 0, audio, 2, &pipe_out_monitoring);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  904) 			if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  905) 				return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  906) 			chip->playback_pipes[audio] = pipe_out_monitoring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  907) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  908) 		pipe_out_monitoring->references++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  909) 		/* 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  910) 		   if an output pipe is available, it's audios still may need to be 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  911) 		   unmuted. hence we'll have to call a mixer entry point.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  912) 		*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  913) 		vx_set_monitor_level(chip, audio, chip->audio_monitor[audio],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  914) 				     chip->audio_monitor_active[audio]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  915) 		/* assuming stereo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  916) 		vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  917) 				     chip->audio_monitor_active[audio+1]); 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  918) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  919) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  920) 	pipe->monitoring_pipe = pipe_out_monitoring; /* default value NULL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  921) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  922) 	runtime->hw = vx_pcm_capture_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  923) 	runtime->hw.period_bytes_min = chip->ibl.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  924) 	runtime->private_data = pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  925) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  926) 	/* align to 4 bytes (otherwise will be problematic when 24bit is used) */ 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  927) 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  928) 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  929) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  930) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  932) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  933) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  934)  * vx_pcm_capture_close - close callback for capture
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  935)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  936) static int vx_pcm_capture_close(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  937) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  938) 	struct vx_core *chip = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  939) 	struct vx_pipe *pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  940) 	struct vx_pipe *pipe_out_monitoring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  941) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  942) 	if (! subs->runtime->private_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  943) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  944) 	pipe = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  945) 	chip->capture_pipes[pipe->number] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  946) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  947) 	pipe_out_monitoring = pipe->monitoring_pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  948) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  949) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  950) 	  if an output pipe is attached to this input, 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  951) 	  check if it needs to be released.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  952) 	*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  953) 	if (pipe_out_monitoring) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  954) 		if (--pipe_out_monitoring->references == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  955) 			vx_free_pipe(chip, pipe_out_monitoring);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  956) 			chip->playback_pipes[pipe->number] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  957) 			pipe->monitoring_pipe = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  958) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  959) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  960) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  961) 	vx_free_pipe(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  962) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  963) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  964) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  965) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  966) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  967) #define DMA_READ_ALIGN	6	/* hardware alignment for read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  968) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  969) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  970)  * vx_pcm_capture_update - update the capture buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  971)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  972) static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  973) 				  struct vx_pipe *pipe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  974) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  975) 	int size, space, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  976) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  977) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  978) 	if (!pipe->running || (chip->chip_status & VX_STAT_IS_STALE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  979) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  980) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  981) 	size = runtime->buffer_size - snd_pcm_capture_avail(runtime);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  982) 	if (! size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  983) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  984) 	size = frames_to_bytes(runtime, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  985) 	space = vx_query_hbuffer_size(chip, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  986) 	if (space < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  987) 		goto _error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  988) 	if (size > space)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  989) 		size = space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  990) 	size = (size / 3) * 3; /* align to 3 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  991) 	if (size < DMA_READ_ALIGN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  992) 		goto _error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  993) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  994) 	/* keep the last 6 bytes, they will be read after disconnection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  995) 	count = size - DMA_READ_ALIGN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  996) 	/* read bytes until the current pointer reaches to the aligned position
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  997) 	 * for word-transfer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  998) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  999) 	while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) 		if ((pipe->hw_ptr % pipe->align) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) 		if (vx_wait_for_rx_full(chip) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) 			goto _error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) 		vx_pcm_read_per_bytes(chip, runtime, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) 		count -= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) 	if (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) 		/* ok, let's accelerate! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) 		int align = pipe->align * 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) 		space = (count / align) * align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) 		if (space > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) 			vx_pseudo_dma_read(chip, runtime, pipe, space);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) 			count -= space;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) 	/* read the rest of bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) 	while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) 		if (vx_wait_for_rx_full(chip) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) 			goto _error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) 		vx_pcm_read_per_bytes(chip, runtime, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) 		count -= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) 	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) 	vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) 	/* read the last pending 6 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) 	count = DMA_READ_ALIGN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) 	while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) 		vx_pcm_read_per_bytes(chip, runtime, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) 		count -= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) 	/* update the position */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) 	pipe->transferred += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) 	if (pipe->transferred >= pipe->period_bytes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) 		pipe->transferred %= pipe->period_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) 		snd_pcm_period_elapsed(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) 	return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)  _error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) 	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) 	vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) 	return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)  * vx_pcm_capture_pointer - pointer callback for capture
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) static snd_pcm_uframes_t vx_pcm_capture_pointer(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) 	struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) 	struct vx_pipe *pipe = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) 	return bytes_to_frames(runtime, pipe->hw_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)  * operators for PCM capture
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) static const struct snd_pcm_ops vx_pcm_capture_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) 	.open =		vx_pcm_capture_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) 	.close =	vx_pcm_capture_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) 	.prepare =	vx_pcm_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) 	.trigger =	vx_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) 	.pointer =	vx_pcm_capture_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)  * interrupt handler for pcm streams
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) void vx_pcm_update_intr(struct vx_core *chip, unsigned int events)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) 	struct vx_pipe *pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) #define EVENT_MASK	(END_OF_BUFFER_EVENTS_PENDING|ASYNC_EVENTS_PENDING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) 	if (events & EVENT_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) 		vx_init_rmh(&chip->irq_rmh, CMD_ASYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) 		if (events & ASYNC_EVENTS_PENDING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) 			chip->irq_rmh.Cmd[0] |= 0x00000001;	/* SEL_ASYNC_EVENTS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) 		if (events & END_OF_BUFFER_EVENTS_PENDING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) 			chip->irq_rmh.Cmd[0] |= 0x00000002;	/* SEL_END_OF_BUF_EVENTS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) 		if (vx_send_msg(chip, &chip->irq_rmh) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) 			snd_printdd(KERN_ERR "msg send error!!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) 		i = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) 		while (i < chip->irq_rmh.LgStat) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) 			int p, buf, capture, eob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) 			p = chip->irq_rmh.Stat[i] & MASK_FIRST_FIELD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) 			capture = (chip->irq_rmh.Stat[i] & 0x400000) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) 			eob = (chip->irq_rmh.Stat[i] & 0x800000) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) 			i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) 			if (events & ASYNC_EVENTS_PENDING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) 				i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) 			buf = 1; /* force to transfer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) 			if (events & END_OF_BUFFER_EVENTS_PENDING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) 				if (eob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) 					buf = chip->irq_rmh.Stat[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) 				i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) 			if (capture)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) 			if (snd_BUG_ON(p < 0 || p >= chip->audio_outs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) 			pipe = chip->playback_pipes[p];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) 			if (pipe && pipe->substream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) 				vx_pcm_playback_update(chip, pipe->substream, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) 				vx_pcm_playback_transfer(chip, pipe->substream, pipe, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) 	/* update the capture pcm pointers as frequently as possible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) 	for (i = 0; i < chip->audio_ins; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) 		pipe = chip->capture_pipes[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) 		if (pipe && pipe->substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) 			vx_pcm_capture_update(chip, pipe->substream, pipe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)  * vx_init_audio_io - check the available audio i/o and allocate pipe arrays
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) static int vx_init_audio_io(struct vx_core *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) 	struct vx_rmh rmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) 	int preferred;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) 	vx_init_rmh(&rmh, CMD_SUPPORTED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) 	if (vx_send_msg(chip, &rmh) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) 		snd_printk(KERN_ERR "vx: cannot get the supported audio data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) 		return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) 	chip->audio_outs = rmh.Stat[0] & MASK_FIRST_FIELD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) 	chip->audio_ins = (rmh.Stat[0] >> (FIELD_SIZE*2)) & MASK_FIRST_FIELD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) 	chip->audio_info = rmh.Stat[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) 	/* allocate pipes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) 	chip->playback_pipes = kcalloc(chip->audio_outs, sizeof(struct vx_pipe *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) 	if (!chip->playback_pipes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) 	chip->capture_pipes = kcalloc(chip->audio_ins, sizeof(struct vx_pipe *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) 	if (!chip->capture_pipes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) 		kfree(chip->playback_pipes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) 	preferred = chip->ibl.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) 	chip->ibl.size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) 	vx_set_ibl(chip, &chip->ibl); /* query the info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) 	if (preferred > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) 		chip->ibl.size = ((preferred + chip->ibl.granularity - 1) /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) 				  chip->ibl.granularity) * chip->ibl.granularity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) 		if (chip->ibl.size > chip->ibl.max_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) 			chip->ibl.size = chip->ibl.max_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) 		chip->ibl.size = chip->ibl.min_size; /* set to the minimum */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) 	vx_set_ibl(chip, &chip->ibl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)  * free callback for pcm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) static void snd_vx_pcm_free(struct snd_pcm *pcm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) 	struct vx_core *chip = pcm->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) 	chip->pcm[pcm->device] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) 	kfree(chip->playback_pipes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) 	chip->playback_pipes = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) 	kfree(chip->capture_pipes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) 	chip->capture_pipes = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)  * snd_vx_pcm_new - create and initialize a pcm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) int snd_vx_pcm_new(struct vx_core *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) 	struct snd_pcm *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) 	if ((err = vx_init_audio_io(chip)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) 	for (i = 0; i < chip->hw->num_codecs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) 		unsigned int outs, ins;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) 		outs = chip->audio_outs > i * 2 ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) 		ins = chip->audio_ins > i * 2 ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) 		if (! outs && ! ins)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) 		err = snd_pcm_new(chip->card, "VX PCM", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) 				  outs, ins, &pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) 		if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) 		if (outs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &vx_pcm_playback_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) 		if (ins)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) 		snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) 					       snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) 					       0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) 		pcm->private_data = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) 		pcm->private_free = snd_vx_pcm_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) 		pcm->info_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) 		pcm->nonatomic = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) 		strcpy(pcm->name, chip->card->shortname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) 		chip->pcm[i] = pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) }