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

📄 mixart_hwdep.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Driver for Digigram miXart soundcards * * DSP firmware management * * Copyright (c) 2003 by Digigram <alsa@digigram.com> * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */#include <sound/driver.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/firmware.h>#include <asm/io.h>#include <sound/core.h>#include "mixart.h"#include "mixart_mixer.h"#include "mixart_core.h"#include "mixart_hwdep.h"/** * wait for a value on a peudo register, exit with a timeout * * @param mgr pointer to miXart manager structure * @param offset unsigned pseudo_register base + offset of value * @param value value * @param timeout timeout in centisenconds */static int mixart_wait_nice_for_register_value(mixart_mgr_t *mgr, u32 offset, int is_egal, u32 value, unsigned long timeout){	unsigned long end_time = jiffies + (timeout * HZ / 100);	u32 read;	do {	/* we may take too long time in this loop.		 * so give controls back to kernel if needed.		 */		cond_resched();		read = readl_be( MIXART_MEM( mgr, offset ));		if(is_egal) {			if(read == value) return 0;		}		else { /* wait for different value */			if(read != value) return 0;		}	} while ( time_after_eq(end_time, jiffies) );	return -EBUSY;}/*  structures needed to upload elf code packets  */typedef struct snd_mixart_elf32_ehdr snd_mixart_elf32_ehdr_t;struct snd_mixart_elf32_ehdr {	u8      e_ident[16];	u16     e_type;	u16     e_machine;	u32     e_version;	u32     e_entry;	u32     e_phoff;	u32     e_shoff;	u32     e_flags;	u16     e_ehsize;	u16     e_phentsize;	u16     e_phnum;	u16     e_shentsize;	u16     e_shnum;	u16     e_shstrndx;};typedef struct snd_mixart_elf32_phdr snd_mixart_elf32_phdr_t;struct snd_mixart_elf32_phdr {	u32     p_type;	u32     p_offset;	u32     p_vaddr;	u32     p_paddr;	u32     p_filesz;	u32     p_memsz;	u32     p_flags;	u32     p_align;};static int mixart_load_elf(mixart_mgr_t *mgr, const struct firmware *dsp ){	char                    elf32_magic_number[4] = {0x7f,'E','L','F'};	snd_mixart_elf32_ehdr_t *elf_header;	int                     i;	elf_header = (snd_mixart_elf32_ehdr_t *)dsp->data;	for( i=0; i<4; i++ )		if ( elf32_magic_number[i] != elf_header->e_ident[i] )			return -EINVAL;	if( elf_header->e_phoff != 0 ) {		snd_mixart_elf32_phdr_t     elf_programheader;		for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {			u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));			memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );			if(elf_programheader.p_type != 0) {				if( elf_programheader.p_filesz != 0 ) {					memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),						     dsp->data + be32_to_cpu( elf_programheader.p_offset ),						     be32_to_cpu( elf_programheader.p_filesz ));				}			}		}	}	return 0;}/* * get basic information and init miXart *//* audio IDs for request to the board */#define MIXART_FIRST_ANA_AUDIO_ID       0#define MIXART_FIRST_DIG_AUDIO_ID       8static int mixart_enum_connectors(mixart_mgr_t *mgr){	u32 k;	int err;	mixart_msg_t request;	mixart_enum_connector_resp_t *connector;	mixart_audio_info_req_t  *audio_info_req;	mixart_audio_info_resp_t *audio_info;	connector = kmalloc(sizeof(*connector), GFP_KERNEL);	audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);	audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);	if (! connector || ! audio_info_req || ! audio_info) {		err = -ENOMEM;		goto __error;	}	audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;	audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;	audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;	request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */	request.data = NULL;	request.size = 0;	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");		err = -EINVAL;		goto __error;	}	for(k=0; k < connector->uid_count; k++) {		mixart_pipe_t* pipe;		if(k < MIXART_FIRST_DIG_AUDIO_ID) {			pipe = &mgr->chip[k/2]->pipe_out_ana;		} else {			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;		}		if(k & 1) {			pipe->uid_right_connector = connector->uid[k];   /* odd */		} else {			pipe->uid_left_connector = connector->uid[k];    /* even */		}		/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;		request.uid = connector->uid[k];		request.data = audio_info_req;		request.size = sizeof(*audio_info_req);		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);		if( err < 0 ) {			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");			goto __error;		}		/*snd_printk(KERN_DEBUG "play  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/	}	request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */	request.data = NULL;	request.size = 0;	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");		err = -EINVAL;		goto __error;	}	for(k=0; k < connector->uid_count; k++) {		mixart_pipe_t* pipe;		if(k < MIXART_FIRST_DIG_AUDIO_ID) {			pipe = &mgr->chip[k/2]->pipe_in_ana;		} else {			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;		}		if(k & 1) {			pipe->uid_right_connector = connector->uid[k];   /* odd */		} else {			pipe->uid_left_connector = connector->uid[k];    /* even */		}		/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;		request.uid = connector->uid[k];		request.data = audio_info_req;		request.size = sizeof(*audio_info_req);		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);		if( err < 0 ) {			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");			goto __error;		}		/*snd_printk(KERN_DEBUG "rec  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/	}	err = 0; __error:	kfree(connector);	kfree(audio_info_req);	kfree(audio_info);	return err;}static int mixart_enum_physio(mixart_mgr_t *mgr){	u32 k;	int err;	mixart_msg_t request;	mixart_uid_t get_console_mgr;	mixart_return_uid_t console_mgr;	mixart_uid_enumeration_t phys_io;	/* get the uid for the console manager */	get_console_mgr.object_id = 0;	get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */	request.message_id = MSG_CONSOLE_GET_CLOCK_UID;	request.uid = get_console_mgr;	request.data = &get_console_mgr;	request.size = sizeof(get_console_mgr);	err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);	if( (err < 0) || (console_mgr.error_code != 0) ) {		snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);		return -EINVAL;	}	/* used later for clock issues ! */	mgr->uid_console_manager = console_mgr.uid;	request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;	request.uid = (mixart_uid_t){0,0};	request.data = &console_mgr.uid;	request.size = sizeof(console_mgr.uid);	err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);	if( (err < 0) || ( phys_io.error_code != 0 ) ) {		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );		return -EINVAL;	}	snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2),  return -EINVAL); /* min 2 phys io per card (analog in + analog out) */	for(k=0; k<mgr->num_cards; k++) {		mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];		mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k]; 	}	return 0;}static int mixart_first_init(mixart_mgr_t *mgr){	u32 k;	int err;	mixart_msg_t request;	if((err = mixart_enum_connectors(mgr)) < 0) return err;	if((err = mixart_enum_physio(mgr)) < 0) return err;	/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */	/* though why not here */	request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;	request.uid = (mixart_uid_t){0,0};	request.data = NULL;	request.size = 0;	/* this command has no data. response is a 32 bit status */	err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);	if( (err < 0) || (k != 0) ) {		snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");		return err == 0 ? -EINVAL : err;

⌨️ 快捷键说明

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