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

📄 echoaudio_dsp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	chip->comm_page->monitors[monitor_index(chip, output, input)] = gain;	return 0;}#endif /* ECHOCARD_HAS_MONITOR *//* Tell the DSP to read and update output, nominal & monitor levels in comm page. */static int update_output_line_level(struct echoaudio *chip){	if (wait_handshake(chip))		return -EIO;	clear_handshake(chip);	return send_vector(chip, DSP_VC_UPDATE_OUTVOL);}/* Tell the DSP to read and update input levels in comm page */static int update_input_line_level(struct echoaudio *chip){	if (wait_handshake(chip))		return -EIO;	clear_handshake(chip);	return send_vector(chip, DSP_VC_UPDATE_INGAIN);}/* set_meters_on turns the meters on or off.  If meters are turned on, the DSPwill write the meter and clock detect values to the comm page at about 30Hz */static void set_meters_on(struct echoaudio *chip, char on){	if (on && !chip->meters_enabled) {		send_vector(chip, DSP_VC_METERS_ON);		chip->meters_enabled = 1;	} else if (!on && chip->meters_enabled) {		send_vector(chip, DSP_VC_METERS_OFF);		chip->meters_enabled = 0;		memset((s8 *)chip->comm_page->vu_meter, ECHOGAIN_MUTED,		       DSP_MAXPIPES);		memset((s8 *)chip->comm_page->peak_meter, ECHOGAIN_MUTED,		       DSP_MAXPIPES);	}}/* Fill out an the given array using the current values in the comm page.Meters are written in the comm page by the DSP in this order: Output busses Input busses Output pipes (vmixer cards only)This function assumes there are no more than 16 in/out busses or pipesMeters is an array [3][16][2] of long. */static void get_audio_meters(struct echoaudio *chip, long *meters){	int i, m, n;	m = 0;	n = 0;	for (i = 0; i < num_busses_out(chip); i++, m++) {		meters[n++] = chip->comm_page->vu_meter[m];		meters[n++] = chip->comm_page->peak_meter[m];	}	for (; n < 32; n++)		meters[n] = 0;#ifdef ECHOCARD_ECHO3G	m = E3G_MAX_OUTPUTS;	/* Skip unused meters */#endif	for (i = 0; i < num_busses_in(chip); i++, m++) {		meters[n++] = chip->comm_page->vu_meter[m];		meters[n++] = chip->comm_page->peak_meter[m];	}	for (; n < 64; n++)		meters[n] = 0;#ifdef ECHOCARD_HAS_VMIXER	for (i = 0; i < num_pipes_out(chip); i++, m++) {		meters[n++] = chip->comm_page->vu_meter[m];		meters[n++] = chip->comm_page->peak_meter[m];	}#endif	for (; n < 96; n++)		meters[n] = 0;}static int restore_dsp_rettings(struct echoaudio *chip){	int err;	DE_INIT(("restore_dsp_settings\n"));	if ((err = check_asic_status(chip)) < 0)		return err;	/* @ Gina20/Darla20 only. Should be harmless for other cards. */	chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF;	chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF;	chip->comm_page->handshake = 0xffffffff;	if ((err = set_sample_rate(chip, chip->sample_rate)) < 0)		return err;	if (chip->meters_enabled)		if (send_vector(chip, DSP_VC_METERS_ON) < 0)			return -EIO;#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK	if (set_input_clock(chip, chip->input_clock) < 0)		return -EIO;#endif#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH	if (set_output_clock(chip, chip->output_clock) < 0)		return -EIO;#endif	if (update_output_line_level(chip) < 0)		return -EIO;	if (update_input_line_level(chip) < 0)		return -EIO;#ifdef ECHOCARD_HAS_VMIXER	if (update_vmixer_level(chip) < 0)		return -EIO;#endif	if (wait_handshake(chip) < 0)		return -EIO;	clear_handshake(chip);	DE_INIT(("restore_dsp_rettings done\n"));	return send_vector(chip, DSP_VC_UPDATE_FLAGS);}/****************************************************************************	Transport functions ****************************************************************************//* set_audio_format() sets the format of the audio data in host memory forthis pipe.  Note that _MS_ (mono-to-stereo) playback modes are not used by ALSAbut they are here because they are just mono while capturing */static void set_audio_format(struct echoaudio *chip, u16 pipe_index,			     const struct audioformat *format){	u16 dsp_format;	dsp_format = DSP_AUDIOFORM_SS_16LE;	/* Look for super-interleave (no big-endian and 8 bits) */	if (format->interleave > 2) {		switch (format->bits_per_sample) {		case 16:			dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_16LE;			break;		case 24:			dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_24LE;			break;		case 32:			dsp_format = DSP_AUDIOFORM_SUPER_INTERLEAVE_32LE;			break;		}		dsp_format |= format->interleave;	} else if (format->data_are_bigendian) {		/* For big-endian data, only 32 bit samples are supported */		switch (format->interleave) {		case 1:			dsp_format = DSP_AUDIOFORM_MM_32BE;			break;#ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32		case 2:			dsp_format = DSP_AUDIOFORM_SS_32BE;			break;#endif		}	} else if (format->interleave == 1 &&		   format->bits_per_sample == 32 && !format->mono_to_stereo) {		/* 32 bit little-endian mono->mono case */		dsp_format = DSP_AUDIOFORM_MM_32LE;	} else {		/* Handle the other little-endian formats */		switch (format->bits_per_sample) {		case 8:			if (format->interleave == 2)				dsp_format = DSP_AUDIOFORM_SS_8;			else				dsp_format = DSP_AUDIOFORM_MS_8;			break;		default:		case 16:			if (format->interleave == 2)				dsp_format = DSP_AUDIOFORM_SS_16LE;			else				dsp_format = DSP_AUDIOFORM_MS_16LE;			break;		case 24:			if (format->interleave == 2)				dsp_format = DSP_AUDIOFORM_SS_24LE;			else				dsp_format = DSP_AUDIOFORM_MS_24LE;			break;		case 32:			if (format->interleave == 2)				dsp_format = DSP_AUDIOFORM_SS_32LE;			else				dsp_format = DSP_AUDIOFORM_MS_32LE;			break;		}	}	DE_ACT(("set_audio_format[%d] = %x\n", pipe_index, dsp_format));	chip->comm_page->audio_format[pipe_index] = cpu_to_le16(dsp_format);}/* start_transport starts transport for a set of pipes.The bits 1 in channel_mask specify what pipes to start. Only the bit of thefirst channel must be set, regardless its interleave.Same thing for pause_ and stop_ -trasport below. */static int start_transport(struct echoaudio *chip, u32 channel_mask,			   u32 cyclic_mask){	DE_ACT(("start_transport %x\n", channel_mask));	if (wait_handshake(chip))		return -EIO;	chip->comm_page->cmd_start |= cpu_to_le32(channel_mask);	if (chip->comm_page->cmd_start) {		clear_handshake(chip);		send_vector(chip, DSP_VC_START_TRANSFER);		if (wait_handshake(chip))			return -EIO;		/* Keep track of which pipes are transporting */		chip->active_mask |= channel_mask;		chip->comm_page->cmd_start = 0;		return 0;	}	DE_ACT(("start_transport: No pipes to start!\n"));	return -EINVAL;}static int pause_transport(struct echoaudio *chip, u32 channel_mask){	DE_ACT(("pause_transport %x\n", channel_mask));	if (wait_handshake(chip))		return -EIO;	chip->comm_page->cmd_stop |= cpu_to_le32(channel_mask);	chip->comm_page->cmd_reset = 0;	if (chip->comm_page->cmd_stop) {		clear_handshake(chip);		send_vector(chip, DSP_VC_STOP_TRANSFER);		if (wait_handshake(chip))			return -EIO;		/* Keep track of which pipes are transporting */		chip->active_mask &= ~channel_mask;		chip->comm_page->cmd_stop = 0;		chip->comm_page->cmd_reset = 0;		return 0;	}	DE_ACT(("pause_transport: No pipes to stop!\n"));	return 0;}static int stop_transport(struct echoaudio *chip, u32 channel_mask){	DE_ACT(("stop_transport %x\n", channel_mask));	if (wait_handshake(chip))		return -EIO;	chip->comm_page->cmd_stop |= cpu_to_le32(channel_mask);	chip->comm_page->cmd_reset |= cpu_to_le32(channel_mask);	if (chip->comm_page->cmd_reset) {		clear_handshake(chip);		send_vector(chip, DSP_VC_STOP_TRANSFER);		if (wait_handshake(chip))			return -EIO;		/* Keep track of which pipes are transporting */		chip->active_mask &= ~channel_mask;		chip->comm_page->cmd_stop = 0;		chip->comm_page->cmd_reset = 0;		return 0;	}	DE_ACT(("stop_transport: No pipes to stop!\n"));	return 0;}static inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index){	return (chip->pipe_alloc_mask & (1 << pipe_index));}/* Stops everything and turns off the DSP. All pipes should be alreadystopped and unallocated. */static int rest_in_peace(struct echoaudio *chip){	DE_ACT(("rest_in_peace() open=%x\n", chip->pipe_alloc_mask));	/* Stops all active pipes (just to be sure) */	stop_transport(chip, chip->active_mask);	set_meters_on(chip, FALSE);#ifdef ECHOCARD_HAS_MIDI	enable_midi_input(chip, FALSE);#endif	/* Go to sleep */	if (chip->dsp_code) {		/* Make load_firmware do a complete reload */		chip->dsp_code = NULL;		/* Put the DSP to sleep */		return send_vector(chip, DSP_VC_GO_COMATOSE);	}	return 0;}/* Fills the comm page with default values */static int init_dsp_comm_page(struct echoaudio *chip){	/* Check if the compiler added extra padding inside the structure */	if (offsetof(struct comm_page, midi_output) != 0xbe0) {		DE_INIT(("init_dsp_comm_page() - Invalid struct comm_page structure\n"));		return -EPERM;	}	/* Init all the basic stuff */	chip->card_name = ECHOCARD_NAME;	chip->bad_board = TRUE;	/* Set TRUE until DSP loaded */	chip->dsp_code = NULL;	/* Current DSP code not loaded */	chip->digital_mode = DIGITAL_MODE_NONE;	chip->input_clock = ECHO_CLOCK_INTERNAL;	chip->output_clock = ECHO_CLOCK_WORD;	chip->asic_loaded = FALSE;	memset(chip->comm_page, 0, sizeof(struct comm_page));	/* Init the comm page */	chip->comm_page->comm_size =		__constant_cpu_to_le32(sizeof(struct comm_page));	chip->comm_page->handshake = 0xffffffff;	chip->comm_page->midi_out_free_count =		__constant_cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);	chip->comm_page->sample_rate = __constant_cpu_to_le32(44100);	chip->sample_rate = 44100;	/* Set line levels so we don't blast any inputs on startup */	memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE);	memset(chip->comm_page->vmixer, ECHOGAIN_MUTED, VMIXER_ARRAY_SIZE);	return 0;}/* This function initializes the several volume controls for busses and pipes.This MUST be called after the DSP is up and running ! */static int init_line_levels(struct echoaudio *chip){	int st, i, o;	DE_INIT(("init_line_levels\n"));	/* Mute output busses */	for (i = 0; i < num_busses_out(chip); i++)		if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED)))			return st;	if ((st = update_output_line_level(chip)))		return st;#ifdef ECHOCARD_HAS_VMIXER	/* Mute the Vmixer */	for (i = 0; i < num_pipes_out(chip); i++)		for (o = 0; o < num_busses_out(chip); o++)			if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED)))				return st;	if ((st = update_vmixer_level(chip)))		return st;#endif /* ECHOCARD_HAS_VMIXER */#ifdef ECHOCARD_HAS_MONITOR	/* Mute the monitor mixer */	for (o = 0; o < num_busses_out(chip); o++)		for (i = 0; i < num_busses_in(chip); i++)			if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED)))				return st;	if ((st = update_output_line_level(chip)))		return st;#endif /* ECHOCARD_HAS_MONITOR */#ifdef ECHOCARD_HAS_INPUT_GAIN	for (i = 0; i < num_busses_in(chip); i++)		if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED)))			return st;	if ((st = update_input_line_level(chip)))		return st;#endif /* ECHOCARD_HAS_INPUT_GAIN */	return 0;}/* This is low level part of the interrupt handler.It returns -1 if the IRQ is not ours, or N>=0 if it is, where N is the numberof midi data in the input queue. */static int service_irq(struct echoaudio *chip){	int st;	/* Read the DSP status register and see if this DSP generated this interrupt */	if (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_IRQ) {		st = 0;#ifdef ECHOCARD_HAS_MIDI		/* Get and parse midi data if present */		if (chip->comm_page->midi_input[0])	/* The count is at index 0 */			st = midi_service_irq(chip);	/* Returns how many midi bytes we received */#endif		/* Clear the hardware interrupt */		chip->comm_page->midi_input[0] = 0;		send_vector(chip, DSP_VC_ACK_INT);		return st;	}	return -1;}/******************************************************************************	Functions for opening and closing pipes ******************************************************************************//* allocate_pipes is used to reserve audio pipes for your exclusive use.The call will fail if some pipes are already allocated. */static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,			  int pipe_index, int interleave){	int i;	u32 channel_mask;	char is_cyclic;	DE_ACT(("allocate_pipes: ch=%d int=%d\n", pipe_index, interleave));	if (chip->bad_board)		return -EIO;	is_cyclic = 1;	/* This driver uses cyclic buffers only */	for (channel_mask = i = 0; i < interleave; i++)		channel_mask |= 1 << (pipe_index + i);	if (chip->pipe_alloc_mask & channel_mask) {		DE_ACT(("allocate_pipes: channel already open\n"));		return -EAGAIN;	}	chip->comm_page->position[pipe_index] = 0;	chip->pipe_alloc_mask |= channel_mask;	if (is_cyclic)		chip->pipe_cyclic_mask |= channel_mask;	pipe->index = pipe_index;	pipe->interleave = interleave;	pipe->state = PIPE_STATE_STOPPED;	/* The counter register is where the DSP writes the 32 bit DMA	position for a pipe.  The DSP is constantly updating this value as	it moves data. The DMA counter is in units of bytes, not samples. */	pipe->dma_counter = &chip->comm_page->position[pipe_index];	*pipe->dma_counter = 0;	DE_ACT(("allocate_pipes: ok\n"));	return pipe_index;}static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe){	u32 channel_mask;	int i;	DE_ACT(("free_pipes: Pipe %d\n", pipe->index));	snd_assert(is_pipe_allocated(chip, pipe->index), return -EINVAL);	snd_assert(pipe->state == PIPE_STATE_STOPPED, return -EINVAL);	for (channel_mask = i = 0; i < pipe->interleave; i++)		channel_mask |= 1 << (pipe->index + i);	chip->pipe_alloc_mask &= ~channel_mask;	chip->pipe_cyclic_mask &= ~channel_mask;	return 0;}/******************************************************************************	Functions for managing the scatter-gather list******************************************************************************/static int sglist_init(struct echoaudio *chip, struct audiopipe *pipe){	pipe->sglist_head = 0;	memset(pipe->sgpage.area, 0, PAGE_SIZE);	chip->comm_page->sglist_addr[pipe->index].addr =		cpu_to_le32(pipe->sgpage.addr);	return 0;}static int sglist_add_mapping(struct echoaudio *chip, struct audiopipe *pipe,				dma_addr_t address, size_t length){	int head = pipe->sglist_head;	struct sg_entry *list = (struct sg_entry *)pipe->sgpage.area;	if (head < MAX_SGLIST_ENTRIES - 1) {		list[head].addr = cpu_to_le32(address);		list[head].size = cpu_to_le32(length);		pipe->sglist_head++;	} else {		DE_ACT(("SGlist: too many fragments\n"));		return -ENOMEM;	}	return 0;}static inline int sglist_add_irq(struct echoaudio *chip, struct audiopipe *pipe){	return sglist_add_mapping(chip, pipe, 0, 0);}static inline int sglist_wrap(struct echoaudio *chip, struct audiopipe *pipe){	return sglist_add_mapping(chip, pipe, pipe->sgpage.addr, 0);}

⌨️ 快捷键说明

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