Add ld10k1 tool

Added ld10k1 tool by Peter Zubaj.
This commit is contained in:
Takashi Iwai 2005-03-18 13:40:44 +00:00
parent 37104ebf62
commit 2df1aa7c20
98 changed files with 19970 additions and 1 deletions

25
ld10k1/src/Makefile.am Normal file
View file

@ -0,0 +1,25 @@
bin_PROGRAMS = lo10k1
sbin_PROGRAMS = ld10k1 dl10k1
ld10k1_SOURCES = ld10k1.c ld10k1_fnc.c ld10k1_fnc1.c ld10k1_debug.c \
ld10k1_driver.c comm.c ld10k1_tram.c \
ld10k1_dump.c ld10k1_mixer.c\
ld10k1.h ld10k1_fnc_int.h ld10k1_fnc1.h ld10k1_debug.h \
ld10k1_driver.h bitops.h ld10k1_tram.h \
ld10k1_dump.h ld10k1_dump_file.h ld10k1_mixer.h
ld10k1_CFLAGS = $(AM_CFLAGS) $(ALSA_CFLAGS)
ld10k1_LDADD = $(ALSA_LIBS)
#liblo10k1_ladir = $(includedir)/lo10k1
lib_LTLIBRARIES = liblo10k1.la
liblo10k1_la_SOURCES = comm.c liblo10k1.c liblo10k1ef.c liblo10k1lf.c
#liblo10k1_la_HEADERS = comm.h liblo10k1.h liblo10k1ef.h ld10k1_error.h ld10k1_fnc.h liblo10k1lf.h
lo10k1_SOURCES = lo10k1.c
lo10k1_CFLAGS = $(ALSA_CFLAGS) -DEFFECTSDIR='"$(effectsdir)"'
lo10k1_LDADD = liblo10k1.la
dl10k1_SOURCES = dl10k1.c ld10k1_dump_file.h
dl10k1_CFLAGS = $(ALSA_CFLAGS)
dl10k1_LDADD = $(ALSA_LIBS)
INCLUDES=-I$(top_srcdir)/include

50
ld10k1/src/bitops.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef _PZ_GENERIC_BITOPS_H_
#define _PZ_GENERIC_BITOPS_H_
/* this is from linux kernel header */
/*
* For the benefit of those who are trying to port Linux to another
* architecture, here are some C-language equivalents. You should
* recode these in the native assembly language, if at all possible.
* To guarantee atomicity, these routines call cli() and sti() to
* disable interrupts while they operate. (You have to provide inline
* routines to cli() and sti().)
*
* Also note, these routines assume that you have 32 bit longs.
* You will have to change this if you are trying to port Linux to the
* Alpha architecture or to a Cray. :-)
*
* C language equivalents written by Theodore Ts'o, 9/26/92
*/
__inline__ int set_bit(int nr, unsigned long * addr)
{
int mask, retval;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
retval = (mask & *addr) != 0;
*addr |= mask;
return retval;
}
__inline__ int clear_bit(int nr, unsigned long * addr)
{
int mask, retval;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
retval = (mask & *addr) != 0;
*addr &= ~mask;
return retval;
}
__inline__ int test_bit(int nr, unsigned long * addr)
{
int mask;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
return ((mask & *addr) != 0);
}
#endif /* _PZ_GENERIC_BITOPS_H */

349
ld10k1/src/comm.c Normal file
View file

@ -0,0 +1,349 @@
/*
* EMU10k1 loader lib
* Copyright (c) 2003,2004 by Peter Zubaj
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
#include "comm.h"
#include "ld10k1_error.h"
/* taken from glibc example */
int setup_comm(comm_param *param)
{
int sock;
struct sockaddr_un lname;
struct sockaddr_in iname;
size_t size;
/* Create the socket. */
if (param->type == COMM_TYPE_LOCAL)
sock = socket (PF_LOCAL, SOCK_STREAM, 0);
else
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0)
return -1;
if (param->server) {
if (param->type == COMM_TYPE_LOCAL) {
unlink(param->name);
/* Bind a name to the socket. */
memset(&lname, 0, sizeof(struct sockaddr_un));
lname.sun_family = AF_LOCAL;
strncpy (lname.sun_path, param->name, sizeof (lname.sun_path) - 1);
lname.sun_path[sizeof (lname.sun_path) - 1] = '\0';
/* The size of the address is
the offset of the start of the filename,
plus its length,
plus one for the terminating null byte.
Alternatively you can just do:
size = SUN_LEN (&name);
*/
size = (offsetof (struct sockaddr_un, sun_path) + strlen (lname.sun_path) + 1);
if (bind (sock, (struct sockaddr *) &lname, size) < 0)
return -1;
chmod(param->name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
} else {
/* Give the socket a name. */
memset(&iname, 0, sizeof(struct sockaddr_in));
iname.sin_family = AF_INET;
iname.sin_port = htons (param->port);
iname.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr *) &iname, sizeof (iname)) < 0)
return -1;
}
}
return sock;
}
int connect_comm(int conn_num, comm_param *param)
{
struct sockaddr_un lname;
struct sockaddr_in iname;
struct hostent *hostinfo;
size_t size;
int attempt;
int max_attempt;
int not_connected;
attempt = 0;
if (param->wfc)
max_attempt = param->wfc / 10;
else
max_attempt = 0;
if (param->type == COMM_TYPE_LOCAL) {
memset(&lname, 0, sizeof(struct sockaddr_un));
lname.sun_family = AF_LOCAL;
strncpy (lname.sun_path, param->name, sizeof (lname.sun_path) - 1);
lname.sun_path[sizeof(lname.sun_path) - 1] = '\0';
size = (offsetof(struct sockaddr_un, sun_path)) + strlen(lname.sun_path) + 1;
while (1)
{
not_connected = connect(conn_num, (struct sockaddr *) &lname, size);
if (!not_connected)
break;
if (attempt >= max_attempt)
return -1;
attempt++;
usleep(10000);
}
} else {
memset(&iname, 0, sizeof(struct sockaddr_in));
iname.sin_family = AF_INET;
iname.sin_port = htons(param->port);
hostinfo = gethostbyname(param->name);
if (hostinfo == NULL)
return -1;
iname.sin_addr = *(struct in_addr *)hostinfo->h_addr;
while (1)
{
not_connected = connect(conn_num, (struct sockaddr *) &iname, sizeof(struct sockaddr_in));
if (!not_connected)
break;
if (attempt >= max_attempt)
return -1;
attempt++;
usleep(10000);
}
}
return 0;
}
int listen_comm(int conn_num)
{
if (listen(conn_num, 1) < 0)
return -1;
return 0;
}
int accept_comm(int conn_num)
{
struct sockaddr addr;
socklen_t addr_len;
int sock;
addr_len = sizeof(addr);
sock = accept(conn_num, &addr, &addr_len);
if (sock < 0)
return -1;
return sock;
}
int free_comm(int conn_num)
{
if (shutdown(conn_num, 2))
return -1;
if (close(conn_num) < 0)
return -1;
return 0;
}
#define MAX_ATEMPT 5
int read_all(int conn_num, void *data, int data_size)
{
int offset = 0;
int how_much = data_size;
int atempt = 0;
int readed = 0;
while (atempt < MAX_ATEMPT && how_much > 0) {
readed = read(conn_num, ((char *)data) + offset, how_much);
if (readed < 0)
return LD10K1_ERR_COMM_READ;
offset += readed;
how_much -= readed;
atempt++;
if (how_much > 0)
usleep(10000);
}
if (how_much > 0)
return LD10K1_ERR_COMM_READ;
else
return data_size;
}
int write_all(int conn_num, void *data, int data_size)
{
int offset = 0;
int how_much = data_size;
int atempt = 0;
int writed = 0;
while (atempt < MAX_ATEMPT && how_much > 0) {
writed = write(conn_num, ((char *)data) + offset, how_much);
if (writed < 0)
return LD10K1_ERR_COMM_WRITE;
offset += writed;
how_much -= writed;
atempt++;
if (how_much > 0)
usleep(50000);
}
if (how_much > 0)
return LD10K1_ERR_COMM_WRITE;
else
return data_size;
}
int send_request(int conn_num, int op, void *data, int data_size)
{
int nbytes;
struct msg_req header;
header.op = op;
header.size = data_size;
/* header */
nbytes = write_all(conn_num, &header, sizeof(header));
if (nbytes < 0)
return nbytes;
if (data_size > 0) {
/* data */
nbytes = write_all(conn_num, data, data_size);
if (nbytes < 0)
return nbytes;
}
return 0;
}
int send_response(int conn_num, int op, int err, void *data, int data_size)
{
int nbytes;
struct msg_resp header;
header.op = op;
header.err = err;
header.size = data_size;
/* header */
nbytes = write_all(conn_num, &header, sizeof(header));
if (nbytes < 0)
return nbytes;
if (data_size > 0) {
/* data */
nbytes = write_all(conn_num, data, data_size);
if (nbytes < 0)
return nbytes;
}
return 0;
}
int send_msg_data(int conn_num, void *data, int data_size)
{
int nbytes;
if (data_size > 0) {
/* data */
nbytes = write_all(conn_num, data, data_size);
if (nbytes < 0)
return nbytes;
}
return 0;
}
int receive_request(int conn_num, int *op, int *data_size)
{
struct msg_req header;
int nbytes;
nbytes = read_all(conn_num, &header, sizeof(header));
if (nbytes < 0)
return nbytes;
if (nbytes == 0) {
*op = -1;
*data_size = 0;
return 0;
}
*op = header.op;
*data_size = header.size;
return 0;
}
int receive_response(int conn_num, int *op, int *data_size)
{
struct msg_resp header;
int nbytes;
nbytes = read_all(conn_num, &header, sizeof(header));
if (nbytes < 0)
return nbytes;
if (nbytes == 0) {
*op = -1;
*data_size = 0;
return 0;
}
*op = header.op;
*data_size = header.size;
if (header.err < 0)
return header.err;
return 0;
}
int receive_msg_data(int conn_num, void *data, int data_size)
{
int nbytes;
nbytes = read_all(conn_num, data, data_size);
if (nbytes < 0)
return nbytes;
return 0;
}
void *receive_msg_data_malloc(int conn_num, int data_size)
{
void *tmp;
tmp = malloc(data_size);
if (!tmp)
return NULL;
if (receive_msg_data(conn_num, tmp, data_size)) {
free(tmp);
return NULL;
}
return tmp;
}

615
ld10k1/src/dl10k1.c Normal file
View file

@ -0,0 +1,615 @@
/*
* EMU10k1 dump loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* Hwdep usage based on sb16_csp
*
* 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
*
*/
/* TODO - kontrola dat, ktore nahravam */
#include <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/ioctl.h>
#include <alsa/asoundlib.h>
#include <alsa/sound/emu10k1.h>
#include <getopt.h>
#include <bitops.h>
#include "ld10k1_dump_file.h"
#define DL10K1_SIGNATURE "DUMP Image (dl10k1)"
int card = 0;
snd_hwdep_t *handle;
const char *card_proc_id;
void error(const char *fmt,...)
{
va_list va;
va_start(va, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
}
static void help(char *command)
{
fprintf(stderr,
"Usage: %s [-options]\n"
"\nAvailable options:\n"
" -h, --help this help\n"
" -c, --card select card number, default = 0\n"
" -d, --dump file with dump\n"
, command);
}
int driver_set_tram_size(int tram_size)
{
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_TRAM_SETUP, &tram_size) < 0) {
error("unable to setup tram");
return 1;
}
return 0;
}
void free_code_struct(emu10k1_fx8010_code_t *code)
{
if (code->gpr_map)
free(code->gpr_map);
if (code->tram_data_map)
free(code->tram_data_map);
if (code->tram_addr_map)
free(code->tram_addr_map);
if (code->code)
free(code->code);
}
int alloc_code_struct(emu10k1_fx8010_code_t *code)
{
/* alloc code structure */
code->gpr_map = NULL;
code->tram_data_map = NULL;
code->tram_addr_map = NULL;
code->code = NULL;
code->gpr_map = (uint32_t *)malloc(sizeof(uint32_t) * 0x200);
if (!code->gpr_map)
goto err;
memset(code->gpr_map, 0, sizeof(uint32_t) * 0x200);
code->tram_data_map = (uint32_t *)malloc(sizeof(uint32_t) * 0x100);
if (!code->tram_data_map)
goto err;
memset(code->tram_data_map, 0, sizeof(uint32_t) * 0x100);
code->tram_addr_map = (uint32_t *)malloc(sizeof(uint32_t) * 0x100);
if (!code->tram_addr_map)
goto err;
memset(code->tram_addr_map, 0, sizeof(uint32_t) * 0x100);
code->code = (uint32_t *)malloc(sizeof(uint32_t) * 1024 * 2);
if (!code->code)
goto err;
memset(code->code, 0, sizeof(uint32_t) * 1024 * 2);
return 0;
err:
free_code_struct(code);
return -1;
}
int driver_init_dsp(int audigy)
{
int i;
emu10k1_fx8010_code_t code;
emu10k1_fx8010_control_gpr_t *ctrl;
emu10k1_ctl_elem_id_t *ids;
emu10k1_fx8010_pcm_t ipcm;
unsigned int *iptr;
if (alloc_code_struct(&code) < 0) {
error("no mem");
return 1;
}
/* get count of controls */
code.gpr_list_control_count = 0;
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_PEEK, &code) < 0) {
error("unable to peek code");
free_code_struct(&code);
return 1;
}
ctrl = (emu10k1_fx8010_control_gpr_t *)malloc(sizeof(emu10k1_fx8010_control_gpr_t) * code.gpr_list_control_total);
if (!ctrl) {
error("no mem");
free_code_struct(&code);
return 1;
}
code.gpr_list_control_count = code.gpr_list_control_total;
code.gpr_list_controls = ctrl;
for (i = 0; i < sizeof(code.gpr_valid) / sizeof(unsigned long); i++)
code.gpr_valid[i] = 0x0;
for (i = 0; i < sizeof(code.tram_valid) / sizeof(unsigned long); i++)
code.tram_valid[i] = 0x0;
for (i = 0; i < sizeof(code.code_valid) / sizeof(unsigned long); i++)
code.code_valid[i] = 0x0;;
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_PEEK, &code) < 0) {
error("unable to peek code");
free_code_struct(&code);
free(ctrl);
return 1;
}
/* new name */
strcpy(code.name, DL10K1_SIGNATURE);
for (i = 0; i < sizeof(code.gpr_valid) / sizeof(unsigned long); i++)
code.gpr_valid[i] = ~0;
for (i = 0; i < sizeof(code.gpr_valid) * 8; i++)
code.gpr_map[i] = 0;
ids = (emu10k1_ctl_elem_id_t *)malloc(sizeof(emu10k1_ctl_elem_id_t) * code.gpr_list_control_total);
if (!ids) {
free_code_struct(&code);
free(ctrl);
error("no mem");
return 1;
}
code.gpr_del_control_count = code.gpr_list_control_total;
if (code.gpr_del_control_count) {
for (i = 0; i < code.gpr_del_control_count; i++) {
memcpy(&(ids[i]), &(ctrl[i].id), sizeof(emu10k1_ctl_elem_id_t));
}
}
free(ctrl);
code.gpr_del_controls = ids;
code.gpr_list_control_count = 0;
code.gpr_add_control_count = 0;
code.gpr_list_control_count = 0;
for (i = 0; i < sizeof(code.tram_valid) / sizeof(unsigned long); i++)
code.tram_valid[i] = ~0;
for (i = 0; i < sizeof(code.code_valid) / sizeof(unsigned long); i++)
code.code_valid[i] = ~0;
for (i = 0; i < sizeof(code.tram_valid) * 8; i++) {
code.tram_addr_map[i] = 0;
code.tram_data_map[i] = 0;
}
for (iptr = code.code, i = 0; i < sizeof(code.code_valid) * 8; i++, iptr += 2)
if (audigy) {
*iptr = ((0xcf & 0x7ff) << 12) | (0xc0 & 0x7ff);
*(iptr + 1) = ((0x0f & 0x0f) << 24) | ((0xc0 & 0x7ff) << 12) | (0xc0 & 0x7ff);
} else {
*iptr = ((0x40 & 0x3ff) << 10) | (0x40 & 0x3ff);
*(iptr + 1) = ((0x06 & 0x0f) << 20) | ((0x40 & 0x3ff) << 10) | (0x40 & 0x3ff);
}
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_POKE, &code) < 0) {
error("unable to poke code");
free_code_struct(&code);
free(ids);
return 1;
}
free(ids);
/* delete tram pcm dsp part */
if (!audigy) {
for (i = 0; i < EMU10K1_FX8010_PCM_COUNT; i++) {
ipcm.substream = i;
ipcm.channels = 0;
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_PCM_POKE, &ipcm) < 0) {
error("unable to poke code");
free_code_struct(&code);
return 1;
}
}
}
return 0;
}
int dump_load(int audigy, char *file_name)
{
struct stat dump_stat;
void *dump_data, *ptr;
FILE *dump_file;
emu10k1_fx8010_control_gpr_t *ctrl = NULL;
ld10k1_ctl_dump_t *fctrl = NULL;
unsigned int *fgpr = NULL;
ld10k1_tram_dump_t *ftram = NULL;
ld10k1_instr_dump_t *finstr = NULL;
int i, j;
unsigned int vaddr, addr;
int op;
unsigned int *iptr;
emu10k1_fx8010_code_t code;
ld10k1_dump_t *header = NULL;
/* first load patch to mem */
if (stat(file_name, &dump_stat)) {
error("unable to load patch %s", file_name);
return 1;
}
/* minimal dump len is size of header */
if (dump_stat.st_size < sizeof(ld10k1_dump_t)) {
error("unable to load dump %s (wrong file size)", file_name);
return 1;
}
dump_data = malloc(dump_stat.st_size);
if (!dump_data) {
error("no mem");
return 1;
}
dump_file = fopen(file_name, "r");
if (!dump_file) {
error("unable to open file %s", file_name);
goto err;
}
if (fread(dump_data, dump_stat.st_size, 1, dump_file) != 1) {
error("unable to read data from file %s", file_name);
goto err;
} else
fclose(dump_file);
/* signature check */
header = (ld10k1_dump_t *)dump_data;
if (strncmp(header->signature, "LD10K1 DUMP 001", 16) != 0) {
error("wrong dump file %s (wrong signature)", file_name);
goto err;
}
/*printf("Size header%d\nctc %d %d\ngpr %d %d\ntram %d %d\ninstr %d %d\n", sizeof(ld10k1_dump_t),
header->ctl_count, sizeof(ld10k1_ctl_dump_t),
header->gpr_count, sizeof(unsigned int),
header->tram_count, sizeof(ld10k1_tram_dump_t),
header->instr_count, sizeof(ld10k1_instr_dump_t));*/
/*check size */
if (sizeof(ld10k1_dump_t) +
header->ctl_count * sizeof(ld10k1_ctl_dump_t) +
header->gpr_count * sizeof(unsigned int) +
header->tram_count * sizeof(ld10k1_tram_dump_t) +
header->instr_count * sizeof(ld10k1_instr_dump_t) != dump_stat.st_size)
goto err;
/* check dump type */
if (header->dump_type == DUMP_TYPE_LIVE && audigy) {
error("can't load dump from Live to Audigy");
goto err1;
} else if ((header->dump_type == DUMP_TYPE_AUDIGY_OLD ||
header->dump_type == DUMP_TYPE_AUDIGY) &&
!audigy) {
error("can't load dump from Audigy to Live");
goto err1;
} else if (header->dump_type == DUMP_TYPE_AUDIGY_OLD) {
error("can't load dump from Audigy (not patched drivers) to Audigy (current drivers)");
goto err1;
}
ptr = dump_data;
ptr += sizeof(ld10k1_dump_t);
ctrl = (emu10k1_fx8010_control_gpr_t *)malloc(sizeof(emu10k1_fx8010_control_gpr_t) * header->ctl_count);
if (!ctrl) {
error("no mem");
goto err1;
}
if (alloc_code_struct(&code) < 0) {
error("no mem");
return 1;
}
strcpy(code.name, DL10K1_SIGNATURE);
/* copy ctls */
fctrl = (ld10k1_ctl_dump_t *)ptr;
memset(ctrl, 0, sizeof(emu10k1_fx8010_control_gpr_t) * header->ctl_count);
for (i = 0; i < header->ctl_count; i++) {
strcpy(ctrl[i].id.name, fctrl[i].name);
ctrl[i].id.iface = EMU10K1_CTL_ELEM_IFACE_MIXER;
ctrl[i].id.index = fctrl[i].index;
ctrl[i].vcount = fctrl[i].vcount;
ctrl[i].count = fctrl[i].count;
for (j = 0; j < 32; j++) {
ctrl[i].gpr[j] = fctrl[i].gpr_idx[j];
ctrl[i].value[j] = fctrl[i].value[j];
}
ctrl[i].min = fctrl[i].min;
ctrl[i].max = fctrl[i].max;
ctrl[i].translation = fctrl[i].translation;
}
code.gpr_add_control_count = header->ctl_count;
code.gpr_add_controls = ctrl;
code.gpr_del_control_count = 0;
code.gpr_del_controls = NULL;
code.gpr_list_control_count = 0;
code.gpr_list_controls = NULL;
/* copy gprs */
ptr += sizeof(ld10k1_ctl_dump_t) * header->ctl_count;
fgpr = (unsigned int *)ptr;
for (i = 0; i < sizeof(code.gpr_valid) / sizeof(unsigned long); i++)
code.gpr_valid[i] = ~0;
for (i = 0; i < header->gpr_count; i++)
code.gpr_map[i] = fgpr[i];
ptr += sizeof(unsigned int) * header->gpr_count;
ftram = (ld10k1_tram_dump_t *)ptr;
/* tram addr + data */
for (i = 0; i < header->tram_count; i++) {
addr = ftram[i].addr;
vaddr = addr & 0xFFFFF;
op = ftram[i].type;
set_bit(i, code.tram_valid);
switch(op) {
case DUMP_TRAM_READ:
if (audigy)
vaddr = vaddr | 0x2 << 20;
else
vaddr = vaddr | TANKMEMADDRREG_READ | TANKMEMADDRREG_ALIGN;
break;
case DUMP_TRAM_WRITE:
if (audigy)
vaddr = vaddr | 0x6 << 20;
else
vaddr = vaddr | TANKMEMADDRREG_WRITE | TANKMEMADDRREG_ALIGN;
break;
case DUMP_TRAM_NULL:
default:
vaddr = 0;
break;
}
code.tram_addr_map[i] = vaddr;
code.tram_data_map[i] = ftram[i].data;
}
ptr += sizeof(ld10k1_tram_dump_t) * header->tram_count;
finstr = (ld10k1_instr_dump_t *)ptr;
for (iptr = code.code, i = 0; i < header->instr_count; i++, iptr += 2) {
set_bit(i, code.code_valid);
if (finstr[i].used) {
if (audigy) {
*iptr = ((finstr[i].arg[2] & 0x7ff) << 12) | (finstr[i].arg[3] & 0x7ff);
*(iptr + 1) = ((finstr[i].op & 0x0f) << 24) | ((finstr[i].arg[0] & 0x7ff) << 12) | (finstr[i].arg[1] & 0x7ff);
} else {
if (i < 0x200) {
*iptr = ((finstr[i].arg[2] & 0x3ff) << 10) | (finstr[i].arg[3] & 0x3ff);
*(iptr + 1) = ((finstr[i].op & 0x0f) << 20) | ((finstr[i].arg[0] & 0x3ff) << 10) | (finstr[i].arg[1] & 0x3ff);
}
}
} else {
if (audigy) {
*iptr = ((0xcf & 0x7ff) << 12) | (0xc0 & 0x7ff);
*(iptr + 1) = ((0x0f & 0x0f) << 24) | ((0xc0 & 0x7ff) << 12) | (0xc0 & 0x7ff);
} else {
if (i < 0x200) {
*iptr = ((0x40 & 0x3ff) << 10) | (0x40 & 0x3ff);
*(iptr + 1) = ((0x06 & 0x0f) << 20) | ((0x40 & 0x3ff) << 10) | (0x40 & 0x3ff);
}
}
}
}
if (header->dump_type != DUMP_TYPE_AUDIGY_OLD &&
driver_set_tram_size(header->tram_size))
goto err1;
if (driver_init_dsp(audigy))
goto err1;
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_POKE, &code) < 0) {
error("unable to poke code");
goto err1;
}
if (dump_data)
free(dump_data);
if (ctrl)
free(ctrl);
return 0;
err:
error("wrong dump file format %s", file_name);
err1:
free_code_struct(&code);
if (dump_data)
free(dump_data);
if (ctrl)
free(ctrl);
return 1;
}
int main(int argc, char *argv[])
{
int dev;
int c;
int err;
int audigy;
int opt_help = 0;
char *opt_dump_file = NULL;
char card_id[32];
snd_ctl_t *ctl_handle;
snd_ctl_card_info_t *card_info;
snd_hwdep_info_t *hwdep_info;
char name[16];
snd_ctl_card_info_alloca(&card_info);
snd_hwdep_info_alloca(&hwdep_info);
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"card", 1, 0, 'c'},
{"dump", 1, 0, 'd'},
{0, 0, 0, 0}
};
int option_index = 0;
while ((c = getopt_long(argc, argv, "hc:d:",
long_options, &option_index)) != EOF) {
switch (c) {
/* case 0: */
/* break; */
case 'h':
opt_help = 1;
break;
case 'd':
opt_dump_file = optarg;
break;
case 'c':
card = snd_card_get_index(optarg);
if (card < 0 || card > 31) {
error("wrong -c argument '%s'\n", optarg);
return 1;
}
break;
default:
return 1;
}
}
if (opt_help) {
help(argv[0]);
return 0;
}
if (!opt_dump_file) {
error("dump file not specified");
return 1;
}
if (getuid() != 0 )
{
error("You are not running dl10k1 as root.");
return 1;
}
/* Get control handle for selected card */
sprintf(card_id, "hw:%i", card);
if ((err = snd_ctl_open(&ctl_handle, card_id, 0)) < 0) {
error("control open (%s): %s", card_id, snd_strerror(err));
return 1;
}
/* Read control hardware info from card */
if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
error("control hardware info (%s): %s", card_id, snd_strerror(err));
exit(1);
}
if (!(card_proc_id = snd_ctl_card_info_get_id (card_info))) {
error("card id (%s): %s", card_id, snd_strerror(err));
exit(1);
}
/* EMU10k1/EMU10k2 chip is present only on SB Live, Audigy, Audigy 2, E-mu APS cards */
if (strcmp(snd_ctl_card_info_get_driver(card_info), "EMU10K1") != 0 &&
strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy") != 0 &&
strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy2") != 0 &&
strcmp(snd_ctl_card_info_get_driver(card_info), "E-mu APS") != 0) {
error("not a EMU10K1/EMU10K2 based card");
exit(1);
}
if (strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy") == 0 ||
strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy2") == 0)
audigy = 1;
else
audigy = 0;
/* find EMU10k1 hardware dependant device and execute command */
dev = -1;
err = 1;
while (1) {
if (snd_ctl_hwdep_next_device(ctl_handle, &dev) < 0)
error("hwdep next device (%s): %s", card_id, snd_strerror(err));
if (dev < 0)
break;
snd_hwdep_info_set_device(hwdep_info, dev);
if (snd_ctl_hwdep_info(ctl_handle, hwdep_info) < 0) {
if (err != -ENOENT)
error("control hwdep info (%s): %s", card_id, snd_strerror(err));
continue;
}
if (snd_hwdep_info_get_iface(hwdep_info) == SND_HWDEP_IFACE_EMU10K1) {
sprintf(name, "hw:%i,%i", card, dev);
/* open EMU10k1 hwdep device */
if ((err = snd_hwdep_open(&handle, name, O_WRONLY)) < 0) {
error("EMU10k1 open (%i-%i): %s", card, dev, snd_strerror(err));
exit(1);
}
err = dump_load(audigy, opt_dump_file);
snd_hwdep_close(handle);
break;
}
}
snd_ctl_close(ctl_handle);
return 0;
}

347
ld10k1/src/ld10k1.c Normal file
View file

@ -0,0 +1,347 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* Hwdep usage based on sb16_csp
*
* 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 <limits.h>
#include <sys/stat.h>
#include <alsa/asoundlib.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/ioctl.h>
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include "ld10k1.h"
#include "ld10k1_fnc.h"
#include "ld10k1_fnc1.h"
int card = 0;
snd_hwdep_t *handle;
char comm_pipe[256];
FILE *comm;
char pidpath[256];
FILE *logfile=NULL;
static void vlog(const char *label, const char *fmt, va_list va)
{
FILE *out = stderr;
if (logfile)
out = logfile;
if (logfile) {
char timestr[20];
time_t tp;
tp = time(NULL);
strftime(timestr, sizeof(timestr), "%b %d %H:%M:%S",
localtime(&tp));
fprintf(out, "%s %s", timestr, label);
} else
fprintf(out, label);
vfprintf(out, fmt, va);
fprintf(out, "\n");
fflush(out);
}
void error(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vlog("Error: ", fmt, va);
va_end(va);
}
static void log(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vlog("", fmt, va);
va_end(va);
}
static void help(char *command)
{
fprintf(stderr,
"Usage: %s [-options]\n"
"\nAvailable options:\n"
" -h, --help this help\n"
" -c, --card select card number, default = 0\n"
" -p, --pipe_name connect to this, default = /tmp/.ld10k1_port\n"
" -n, --network listen on port\n"
" --port port number, default = 20480\n"
" -d --daemon start in background\n"
" -i --pidfile print daemon process id to file, default /var/run/ld10k1.pid\n"
" -l --logfile \n"
" -t, --tram_size initialize tram with given size\n"
" 0 - 0 KB\n"
" 1 - 16 KB\n"
" 2 - 32 KB\n"
" 3 - 64 KB\n"
" 4 - 128 KB\n"
" 5 - 256 KB\n"
" 6 - 512 KB\n"
" 7 - 1024 KB\n"
" 8 - 2048 KB\n"
, command);
}
static void cleanup()
{
if (pidpath[0])
unlink(pidpath);
log("Exiting daemon");
}
static void term_handler(int i)
{
exit(1);
}
int tram_size_table[] = {0, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576};
int main(int argc, char *argv[])
{
int dev;
int c;
int err;
int audigy;
int opt_help = 0;
int tram_size = 0;
int opt_daemon = 0;
unsigned short opt_port = 20480;
int uses_pipe = 1;
char logpath[255];
char card_id[32];
const char *card_proc_id;
snd_ctl_t *ctl_handle;
snd_ctl_card_info_t *card_info;
snd_hwdep_info_t *hwdep_info;
char name[16];
comm_param params;
int option_index;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"card", 1, 0, 'c'},
{"pipe_name", 1, 0, 'p'},
{"network", 0, 0, 'n'},
{"port", 1, 0, 0},
{"daemon", 0, 0, 'd'},
{"tram_size", 1, 0, 't'},
{"pidfile", 1, 0, 'i'},
{"logfile", 1, 0, 'l'},
{0, 0, 0, 0}
};
snd_ctl_card_info_alloca(&card_info);
snd_hwdep_info_alloca(&hwdep_info);
strcpy(comm_pipe,"/tmp/.ld10k1_port");
strcpy(pidpath, "/var/run/ld10k1.pid");
memset(logpath, 0, sizeof(logpath));
option_index = 0;
while ((c = getopt_long(argc, argv, "hc:p:t:ndl:i:",
long_options, &option_index)) != EOF) {
switch (c) {
case 0:
if (strcmp(long_options[option_index].name, "port") == 0) {
opt_port = atoi(optarg);
}
break;
case 'h':
opt_help = 1;
break;
case 'c':
card = snd_card_get_index(optarg);
if (card < 0 || card > 31) {
error ("wrong -c argument '%s'\n", optarg);
return 1;
}
break;
case 'p':
uses_pipe = 1;
strncpy(comm_pipe, optarg, sizeof(comm_pipe) - 1);
comm_pipe[sizeof(comm_pipe) - 1] = '\0';
break;
case 'n':
uses_pipe = 0;
break;
case 'd':
opt_daemon = 1;
break;
case 't':
tram_size = atoi(optarg);
if (tram_size < 0)
tram_size = 0;
else if (tram_size > 8)
tram_size = 8;
tram_size = tram_size_table[tram_size];
break;
case 'i':
strncpy(pidpath, optarg, sizeof(pidpath) - 1);
pidpath[sizeof(pidpath) - 1] = '\0';
break;
case 'l':
strncpy(logpath, optarg, sizeof(logpath) - 1);
logpath[sizeof(logpath) - 1] = '\0';
break;
default:
return 1;
}
}
if (opt_help) {
help(argv[0]);
return 0;
}
if (getuid() != 0 ) {
error("You are not running ld10k1 as root.");
return 1;
}
if (logpath[0])
logfile = fopen(logpath, "at");
if (opt_daemon) {
FILE *pidfile;
if (daemon(0, 0) < 0) {
error("Unable to run as daemon.");
return 1;
}
pidfile = fopen(pidpath, "wt");
if (!pidfile) {
log("%s: pidfile (%s)\n", strerror(errno), pidpath);
return 1;
}
fprintf(pidfile, "%d\n", getpid());
fflush(pidfile);
fclose(pidfile);
atexit(cleanup);
signal(SIGTERM, term_handler);
if (logfile) {
dup2(fileno(logfile), fileno(stderr));
dup2(fileno(logfile), fileno(stdout));
}
log("Starting daemon");
}
params.type = uses_pipe ? COMM_TYPE_LOCAL : COMM_TYPE_IP;
params.name = comm_pipe;
params.server = 1;
params.port = opt_port;
params.wfc = 0;
/* Get control handle for selected card */
sprintf(card_id, "hw:%i", card);
if ((err = snd_ctl_open(&ctl_handle, card_id, 0)) < 0) {
error("control open (%s): %s", card_id, snd_strerror(err));
return 1;
}
/* Read control hardware info from card */
if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
error("control hardware info (%s): %s", card_id, snd_strerror(err));
exit(1);
}
if (!(card_proc_id = snd_ctl_card_info_get_id (card_info))) {
error("card id (%s): %s", card_id, snd_strerror(err));
exit(1);
}
/* EMU10k1/EMU10k2 chip is present only on SB Live, Audigy, Audigy 2, E-mu APS cards */
if (strcmp(snd_ctl_card_info_get_driver(card_info), "EMU10K1") != 0 &&
strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy") != 0 &&
strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy2") != 0 &&
strcmp(snd_ctl_card_info_get_driver(card_info), "E-mu APS") != 0) {
error("not a EMU10K1/EMU10K2 based card");
exit(1);
}
if (strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy") == 0 ||
strcmp(snd_ctl_card_info_get_driver(card_info), "Audigy2") == 0)
audigy = 1;
else
audigy = 0;
/* find EMU10k1 hardware dependant device and execute command */
dev = -1;
err = 1;
while (1) {
if (snd_ctl_hwdep_next_device(ctl_handle, &dev) < 0)
error("hwdep next device (%s): %s", card_id, snd_strerror(err));
if (dev < 0)
break;
snd_hwdep_info_set_device(hwdep_info, dev);
if (snd_ctl_hwdep_info(ctl_handle, hwdep_info) < 0) {
if (err != -ENOENT)
error("control hwdep info (%s): %s", card_id, snd_strerror(err));
continue;
}
if (snd_hwdep_info_get_iface(hwdep_info) == SND_HWDEP_IFACE_EMU10K1) {
sprintf(name, "hw:%i,%i", card, dev);
/* open EMU10k1 hwdep device */
if ((err = snd_hwdep_open(&handle, name, O_WRONLY)) < 0) {
error("EMU10k1 open (%i-%i): %s", card, dev, snd_strerror(err));
exit(1);
}
while (1)
if (main_loop(&params, audigy, card_proc_id, tram_size, ctl_handle)) {
error("error in main loop");
break;
}
snd_hwdep_close(handle);
break;
}
}
snd_ctl_close(ctl_handle);
return 0;
}

292
ld10k1/src/ld10k1.h Normal file
View file

@ -0,0 +1,292 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_H
#define __LD10K1_H
#define MAX_CONST_COUNT 0x220
#define MAX_GPR_COUNT 0x200
#define MAX_TRAM_COUNT 0x100
/* instructions */
typedef struct {
unsigned int used: 1,
modified: 1;
unsigned int op_code;
unsigned int arg[4];
} ld10k1_instr_t;
/* tram */
typedef struct {
unsigned int used: 1,
type: 2,
req_pos: 2,
pos: 2;
unsigned int size;
unsigned int offset;
int acc_count;
} ld10k1_tram_grp_t;
#define TRAM_OP_NULL 0
#define TRAM_OP_READ 1
#define TRAM_OP_WRITE 2
typedef struct {
unsigned int used: 1,
modified: 1;
unsigned int op;
unsigned int addr_val;
unsigned int data_val;
} ld10k1_tram_hwacc_t;
typedef struct {
unsigned int used: 1,
type: 2;
unsigned int offset;
unsigned int hwacc;
unsigned int grp;
} ld10k1_tram_acc_t;
typedef struct {
unsigned int size;
unsigned int max_hwacc;
ld10k1_tram_hwacc_t *hwacc;
unsigned int used_hwacc;
} ld10k1_tram_t;
#define MAX_CONN_PER_POINT 15
#define MAX_INSTR_PER_POINT 7
#define INSERT_BEFORE_OWNER 0
#define INSERT_AFTER_OWNER 1
typedef struct ld10k1_conn_point_tag
{
struct ld10k1_conn_point_tag *next;
int id;
int con_count; /* count of io connected to this point */
unsigned int con_gpr_idx;
int type[MAX_CONN_PER_POINT];
struct ld10k1_patch_tag *patch[MAX_CONN_PER_POINT];
int io[MAX_CONN_PER_POINT];
unsigned int out_gpr_idx[MAX_CONN_PER_POINT];
int simple;
int reserved_gpr;
int reserved_instr;
struct ld10k1_patch_tag *owner;
int position;
unsigned int out_instr_offset;
ld10k1_instr_t out_instr[MAX_INSTR_PER_POINT];
} ld10k1_conn_point_t;
typedef struct {
char *name;
ld10k1_conn_point_t *point;
} ld10k1_p_in_out_t;
typedef struct {
unsigned int gpr_idx;
unsigned int const_val;
} ld10k1_p_const_sta_t;
typedef struct {
unsigned int gpr_idx;
} ld10k1_p_dyn_t;
typedef struct {
unsigned int reg_idx;
unsigned int gpr_idx;
} ld10k1_p_hw_t;
typedef struct {
unsigned int grp_type;
unsigned int grp_size;
unsigned int grp_pos;
unsigned int grp_idx;
} ld10k1_p_tram_grp_t;
typedef struct {
unsigned int acc_type;
unsigned int acc_offset;
unsigned int acc_idx;
unsigned int grp;
} ld10k1_p_tram_acc_t;
typedef struct {
char name[44];
int index;
int want_index;
unsigned int vcount; /* count of GPR (1..32) */
unsigned int count; /* count of GPR (1..32) */
unsigned int gpr_idx[32]; /* GPR number(s) */
unsigned int value[32];
unsigned int min; /* minimum range */
unsigned int max; /* maximum range */
unsigned int translation; /* typ - 0 - bool, num 1 - enum */
} ld10k1_ctl_t;
typedef struct ld10k1_ctl_list_item_tag {
struct ld10k1_ctl_list_item_tag *next;
ld10k1_ctl_t ctl;
} ld10k1_ctl_list_item_t;
typedef struct ld10k1_patch_tag {
char *patch_name;
int order;
int id;
unsigned int in_count;
ld10k1_p_in_out_t *ins;
unsigned int out_count;
ld10k1_p_in_out_t *outs;
unsigned int const_count;
ld10k1_p_const_sta_t *consts;
unsigned int sta_count;
ld10k1_p_const_sta_t *stas;
unsigned int dyn_count;
ld10k1_p_dyn_t *dyns;
unsigned int hw_count;
ld10k1_p_hw_t *hws;
unsigned int tram_count;
ld10k1_p_tram_grp_t *tram_grp;
unsigned int tram_acc_count;
ld10k1_p_tram_acc_t *tram_acc;
unsigned int ctl_count;
ld10k1_ctl_t *ctl;
unsigned int instr_count;
unsigned int instr_offset;
ld10k1_instr_t *instr;
} ld10k1_patch_t;
#define EMU10K1_PATCH_MAX 128
typedef struct {
unsigned int gpr_idx;
unsigned int const_val;
unsigned int hw;
unsigned int ref;
unsigned int used: 1;
} ld10k1_dsp_const_t;
#define GPR_USAGE_NONE 0
#define GPR_USAGE_NORMAL 1
#define GPR_USAGE_CONST 2
#define GPR_USAGE_DYNAMIC 3
typedef struct {
unsigned int gpr_usage;
unsigned int val;
unsigned int ref;
unsigned int modified: 1,
used: 1;
} ld10k1_dsp_gpr_t;
/* reserved ctls - for example AC97 */
typedef struct {
char name[44];
unsigned int index;
} ld10k1_reserved_ctl_t;
typedef struct ld10k1_reserved_ctl_list_item_tag {
struct ld10k1_reserved_ctl_list_item_tag *next;
ld10k1_reserved_ctl_t res_ctl;
} ld10k1_reserved_ctl_list_item_t;
typedef struct {
int audigy;
const char *card_id;
/* registers */
unsigned int fx_count;
ld10k1_p_in_out_t fxs[0x40];
unsigned int in_count;
ld10k1_p_in_out_t ins[0x20];
unsigned int out_count;
ld10k1_p_in_out_t outs[0x40];
unsigned int consts_max_count;
ld10k1_dsp_const_t consts[MAX_CONST_COUNT];
unsigned int regs_max_count;
ld10k1_dsp_gpr_t regs[MAX_GPR_COUNT];
/* instructions */
unsigned int instr_count;
ld10k1_instr_t instr[1024];
unsigned int instr_free;
/* internal tram */
ld10k1_tram_t i_tram;
/* external tram */
ld10k1_tram_t e_tram;
unsigned int max_tram_grp;
ld10k1_tram_grp_t tram_grp[MAX_TRAM_COUNT];
unsigned int max_tram_acc;
ld10k1_tram_acc_t tram_acc[MAX_TRAM_COUNT];
unsigned int max_itram_hwacc;
ld10k1_tram_hwacc_t itram_hwacc[0xC0];
unsigned int max_etram_hwacc;
ld10k1_tram_hwacc_t etram_hwacc[0x40];
unsigned int patch_count;
ld10k1_patch_t *patch_ptr[EMU10K1_PATCH_MAX];
unsigned int patch_order[EMU10K1_PATCH_MAX];
unsigned short patch_id_gens[EMU10K1_PATCH_MAX];
ld10k1_ctl_list_item_t *add_ctl_list;
int add_list_count;
ld10k1_ctl_list_item_t *del_ctl_list;
int del_list_count;
ld10k1_ctl_list_item_t *ctl_list;
int ctl_list_count;
ld10k1_reserved_ctl_list_item_t *reserved_ctl_list;
ld10k1_conn_point_t *point_list;
} ld10k1_dsp_mgr_t;
void error(const char *fmt,...);
#endif /* __LD10K1_H */

667
ld10k1/src/ld10k1_debug.c Normal file
View file

@ -0,0 +1,667 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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 <alsa/asoundlib.h>
#include "ld10k1.h"
#include "ld10k1_fnc.h"
#include "ld10k1_fnc1.h"
#include "ld10k1_debug.h"
#include "ld10k1_error.h"
#include "ld10k1_tram.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static char *usage_str[] = {
"NONE",
"NORMAL",
"CONST",
"DYNAMIC"
};
char debug_line[1000];
int send_debug_line(int data_conn)
{
return send_response(data_conn, FNC_CONTINUE, 0, debug_line, strlen(debug_line) + 1);
}
int ld10k1_debug_new_gpr_read_one(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr, unsigned int idx)
{
int usage;
int value;
int ref_count;
int modified;
modified = dsp_mgr->regs[idx].modified;
usage = dsp_mgr->regs[idx].gpr_usage;
value = dsp_mgr->regs[idx].val;
ref_count = dsp_mgr->regs[idx].ref;
sprintf(debug_line, "%c 0x%03x : %-12s 0x%08x %3d\n",
modified ? '*' : ' ',
idx,
usage_str[usage],
value,
ref_count);
return send_debug_line(data_conn);
}
int ld10k1_debug_new_gpr_read_hdr(int data_conn)
{
sprintf(debug_line, "M Idx Usage Value Ref\n");
return send_debug_line(data_conn);
}
static int ld10k1_debug_new_gpr_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
int err;
sprintf(debug_line, "FX8010 GPR List\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
if ((err = ld10k1_debug_new_gpr_read_hdr(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->regs_max_count; i++)
if (dsp_mgr->regs[i].used)
if ((err = ld10k1_debug_new_gpr_read_one(data_conn, dsp_mgr, i)) < 0)
return err;
return 0;
}
static int ld10k1_debug_new_fx_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
int err;
sprintf(debug_line, "FX8010 FX List\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->fx_count; i++) {
sprintf(debug_line, "%03x : %-20s\n",
i,
dsp_mgr->fxs[i].name ? dsp_mgr->fxs[i].name : "");
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
return 0;
}
static int ld10k1_debug_new_in_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
int err;
sprintf(debug_line, "FX8010 IN List\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->in_count; i++) {
sprintf(debug_line, "%03x : %-20s\n",
i,
dsp_mgr->ins[i].name ? dsp_mgr->ins[i].name : "");
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
return 0;
}
static int ld10k1_debug_new_out_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
int err;
sprintf(debug_line, "FX8010 OUT List\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->out_count; i++) {
sprintf(debug_line, "%03x : %-20s\n",
i,
dsp_mgr->outs[i].name ? dsp_mgr->outs[i].name : "");
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
return 0;
}
int ld10k1_debug_new_const_read_one(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr, unsigned int idx)
{
int hw;
int value;
int ref_count;
hw = dsp_mgr->consts[idx].hw;
value = dsp_mgr->consts[idx].const_val;
ref_count = dsp_mgr->consts[idx].ref;
sprintf(debug_line, "0x%03x : 0x%08x %c %3d\n",
idx,
value,
hw ? '*' : ' ',
ref_count);
return send_debug_line(data_conn);
}
int ld10k1_debug_new_const_read_hdr(int data_conn)
{
sprintf(debug_line, "Idx Value HW Ref\n");
return send_debug_line(data_conn);
}
static int ld10k1_debug_new_const_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
int err;
sprintf(debug_line, "CONST List\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
if ((err = ld10k1_debug_new_const_read_hdr(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->consts_max_count; i++)
if (dsp_mgr->consts[i].used)
if ((err = ld10k1_debug_new_const_read_one(data_conn, dsp_mgr, i)) < 0)
return err;
return 0;
}
char *instr_name[] = {
"MACS",
"MACS1",
"MACW",
"MACW1",
"MACINTS",
"MACINTW",
"ACC3",
"MACMV",
"ANDXOR",
"TSTNEG",
"LIMIT",
"LIMIT1",
"LOG",
"EXP",
"INTERP",
"SKIP",
};
static void ld10k1_debug_decode_preg_idx(char *type, unsigned int reg)
{
switch ((reg & EMU10K1_PREG_TYPE_MASK) >> 28) {
case EMU10K1_PREG_TYPE_IN:
sprintf(type, "IN(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_OUT:
sprintf(type, "OUT(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_CONST:
sprintf(type, "CON(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_STA:
sprintf(type, "STA(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_DYN:
sprintf(type, "DYN(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_HW:
sprintf(type, "HW(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_CTL:
sprintf(type, "CTL(%03d, %03d)", (reg & ~EMU10K1_PREG_TYPE_MASK) >> 8, reg & ~EMU10K1_PREG_TYPE_MASK & 0xFF);
break;
case EMU10K1_PREG_TYPE_TRAM_DATA:
sprintf(type, "TD(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
case EMU10K1_PREG_TYPE_TRAM_ADDR:
sprintf(type, "TA(%03d)", reg & ~EMU10K1_PREG_TYPE_MASK);
break;
default:
sprintf(type, "??? 0x%08x", reg);
}
}
int ld10k1_debug_new_code_read_one(int data_conn, int preg, ld10k1_instr_t *instr, unsigned int idx)
{
char type1[100];
char type2[100];
char type3[100];
char type4[100];
if (instr->used) {
if (preg) {
ld10k1_debug_decode_preg_idx(type1, instr->arg[0]);
ld10k1_debug_decode_preg_idx(type2, instr->arg[1]);
ld10k1_debug_decode_preg_idx(type3, instr->arg[2]);
ld10k1_debug_decode_preg_idx(type4, instr->arg[3]);
sprintf(debug_line, "%c 0x%03x : %-10s %s, %s, %s, %s\n",
instr->modified ? '*' : ' ',
idx,
instr_name[instr->op_code],
type1,
type2,
type3,
type4);
} else {
sprintf(debug_line, "%c 0x%03x : %-10s 0x%03x, 0x%03x, 0x%03x, 0x%03x\n",
instr->modified ? '*' : ' ',
idx,
instr_name[instr->op_code],
instr->arg[0],
instr->arg[1],
instr->arg[2],
instr->arg[3]);
}
return send_debug_line(data_conn);
} else {
sprintf(debug_line, "%c 0x%03x : NOT USED\n",
instr->modified ? '*' : ' ',
idx);
return send_debug_line(data_conn);
}
}
int ld10k1_debug_new_code_read_hdr(int data_conn)
{
sprintf(debug_line, "M Idx OPCODE\n");
return send_debug_line(data_conn);
}
static int ld10k1_debug_new_code_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
int err;
ld10k1_instr_t *instr;
sprintf(debug_line, "FX8010 Code\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
if ((err = ld10k1_debug_new_code_read_hdr(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->instr_count; i++) {
instr = &(dsp_mgr->instr[i]);
if (instr->used)
if ((err = ld10k1_debug_new_code_read_one(data_conn, 0, instr, i)) < 0)
return err;
}
return 0;
}
static int ld10k1_debug_new_tram_info_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i, j;
int err;
char *req_pos_str;
char *pos_str;
ld10k1_tram_acc_t *tram_acc;
unsigned int data, addr;
int ifree = dsp_mgr->i_tram.size;
int efree = dsp_mgr->e_tram.size;
sprintf(debug_line, "TRAM\n\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, "Internal tram size: 0x%08x\n", dsp_mgr->i_tram.size);
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, "External tram size: 0x%08x\n", dsp_mgr->e_tram.size);
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, "\nTram groups:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->max_tram_grp; i++) {
if (dsp_mgr->tram_grp[i].used) {
sprintf(debug_line, "%03d %10s ", i, dsp_mgr->tram_grp[i].type == TRAM_GRP_DELAY ? "DELAY" : "TABLE");
if ((err = send_debug_line(data_conn)) < 0)
return err;
req_pos_str = "NONE";
if (dsp_mgr->tram_grp[i].req_pos == TRAM_POS_AUTO)
req_pos_str = "AUTO";
else if (dsp_mgr->tram_grp[i].req_pos == TRAM_POS_INTERNAL)
req_pos_str = "INTERNAL";
else if (dsp_mgr->tram_grp[i].req_pos == TRAM_POS_EXTERNAL)
req_pos_str = "EXTERNAL";
pos_str = "NONE";
if (dsp_mgr->tram_grp[i].pos == TRAM_POS_INTERNAL) {
pos_str = "INTERNAL";
ifree -= dsp_mgr->tram_grp[i].size;
} else if (dsp_mgr->tram_grp[i].pos == TRAM_POS_EXTERNAL) {
pos_str = "EXTERNAL";
efree -= dsp_mgr->tram_grp[i].size;
}
sprintf(debug_line, "%10s %10s %08x %08x %03d\n", req_pos_str, pos_str,
dsp_mgr->tram_grp[i].size, dsp_mgr->tram_grp[i].offset, dsp_mgr->tram_grp[i].acc_count);
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (j = 0; j < dsp_mgr->max_tram_acc; j++) {
tram_acc = &(dsp_mgr->tram_acc[j]);
ld10k1_tram_get_hwacc(dsp_mgr, tram_acc->hwacc, &addr, &data);
if ((tram_acc->used) && (tram_acc->grp == i)) {
sprintf(debug_line, " %c%c%c Off:0x%08x HWacc:%03d ADDR:0x%08x DATA:0x%08x\n",
(tram_acc->type & TRAM_ACC_READ) ? 'R' : '-',
(tram_acc->type & TRAM_ACC_WRITE) ? 'W' : '-',
(tram_acc->type & TRAM_ACC_ZERO) ? 'Z' : '-',
tram_acc->offset,
tram_acc->hwacc,
addr,
data);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
}
}
}
return 0;
}
int ld10k1_debug_new_patch_read1(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch)
{
int i, j;
int err;
ld10k1_conn_point_t *point;
sprintf(debug_line, "Patch name: %s\n\n", patch->patch_name);
if ((err = send_debug_line(data_conn)) < 0)
return err;
/* in list */
sprintf(debug_line, "IN registers:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->in_count; i++) {
sprintf(debug_line, "%03d %s -> 0x%08x\n", i,
patch->ins[i].name ? patch->ins[i].name : "",
patch->ins[i].point ? patch->ins[i].point->con_gpr_idx : 0);
if ((err = send_debug_line(data_conn)) < 0)
return err;
point = patch->ins[i].point;
if (point != NULL)
for (j = 0; j < MAX_CONN_PER_POINT; j++) {
if (point->out_gpr_idx[j] != 0) {
sprintf(debug_line, " +0x%08x\n", point->out_gpr_idx[j]);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
}
}
/* out list */
sprintf(debug_line, "OUT registers:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->out_count; i++) {
sprintf(debug_line, "%03d %s -> 0x%08x\n", i,
patch->outs[i].name ? patch->outs[i].name : "",
patch->outs[i].point ? patch->outs[i].point->con_gpr_idx : 0);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
/* const list */
sprintf(debug_line, "CONST registers:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->const_count; i++) {
sprintf(debug_line, "%03d 0x%08x -> 0x%08x\n", i,
patch->consts[i].const_val,
patch->consts[i].gpr_idx);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
/* sta list */
sprintf(debug_line, "STA registers:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->sta_count; i++) {
sprintf(debug_line, "%03d 0x%08x -> 0x%08x\n", i,
patch->stas[i].const_val,
patch->stas[i].gpr_idx);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
/* hw list */
sprintf(debug_line, "HW registers:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->hw_count; i++) {
sprintf(debug_line, "%03d 0x%08x -> 0x%08x\n", i,
patch->hws[i].reg_idx,
patch->hws[i].gpr_idx);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
/* tram list */
sprintf(debug_line, "\nUsed tram groups:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->tram_count; i++) {
sprintf(debug_line, "%03d 0x%01x 0x%08x 0x%01x -> %03d\n", i,
patch->tram_grp[i].grp_type,
patch->tram_grp[i].grp_size,
patch->tram_grp[i].grp_pos,
patch->tram_grp[i].grp_idx);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
/* tram acc list */
sprintf(debug_line, "\nUsed tram acc:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->tram_acc_count; i++) {
sprintf(debug_line, "%03d 0x%01x 0x%08x 0x%03x -> 0x%03x\n", i,
patch->tram_acc[i].acc_type,
patch->tram_acc[i].acc_offset,
patch->tram_acc[i].grp,
patch->tram_acc[i].acc_idx);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
/* cotrol list */
sprintf(debug_line, "\nUsed controls:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < patch->ctl_count; i++) {
sprintf(debug_line, "%03d\n", i);
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, " Name:%s\n", patch->ctl[i].name);
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, " Min: 0x%08x\n", patch->ctl[i].min);
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, " Max: 0x%08x\n", patch->ctl[i].max);
if ((err = send_debug_line(data_conn)) < 0)
return err;
sprintf(debug_line, " GPRS:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (j = 0; j < patch->ctl[i].count; j++) {
sprintf(debug_line, " %03d 0x%08x -> 0x%08x %c\n", j,
patch->ctl[i].value[j],
patch->ctl[i].gpr_idx[j],
j < patch->ctl[i].vcount ? 'v' : ' ');
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
}
/* instruction list */
sprintf(debug_line, "\nCode:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
if ((err = ld10k1_debug_new_code_read_hdr(data_conn)) < 0)
return err;
for (i = 0; i < patch->instr_count; i++) {
ld10k1_instr_t *instr;
instr = &(patch->instr[i]);
if ((err = ld10k1_debug_new_code_read_one(data_conn, 1, instr, i)) < 0)
return err;
}
return 0;
}
static int ld10k1_debug_new_patch_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr, int idx)
{
ld10k1_patch_t *patch;
patch = dsp_mgr->patch_ptr[idx];
if (!patch)
return LD10K1_ERR_UNKNOWN_PATCH_NUM;
return ld10k1_debug_new_patch_read1(data_conn, dsp_mgr, patch);
}
static int ld10k1_debug_new_patch_list_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
ld10k1_patch_t *patch;
int err;
sprintf(debug_line, "\nPatch List:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < EMU10K1_PATCH_MAX; i++) {
patch = dsp_mgr->patch_ptr[i];
if (patch) {
sprintf(debug_line, "%03d %s\n\n", i, patch->patch_name);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
}
return 0;
}
static int ld10k1_debug_new_patch_order_read(int data_conn, ld10k1_dsp_mgr_t *dsp_mgr)
{
int i, idx;
ld10k1_patch_t *patch;
int err;
sprintf(debug_line, "\nPatch order:\n");
if ((err = send_debug_line(data_conn)) < 0)
return err;
for (i = 0; i < dsp_mgr->patch_count; i++) {
idx = dsp_mgr->patch_order[i];
patch = dsp_mgr->patch_ptr[idx];
if (patch) {
sprintf(debug_line, "%03d %03d %s\n\n", i, idx, patch->patch_name);
if ((err = send_debug_line(data_conn)) < 0)
return err;
}
}
return 0;
}
int ld10k1_fnc_debug(int data_conn, int op, int size)
{
ld10k1_fnc_debug_t debug_info;
int err;
if (size != sizeof(ld10k1_fnc_debug_t))
return LD10K1_ERR_PROTOCOL;
if ((err = receive_msg_data(data_conn, &debug_info, sizeof(ld10k1_fnc_debug_t))))
return err;
if (debug_info.what >= 100 && debug_info.what <= 100 + EMU10K1_PATCH_MAX) {
if ((err = ld10k1_debug_new_patch_read(data_conn, &dsp_mgr, debug_info.what - 100)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 1) {
/* registers */
if ((err = ld10k1_debug_new_gpr_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 2) {
/* registers */
if ((err = ld10k1_debug_new_const_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 3) {
/* instruction */
if ((err = ld10k1_debug_new_code_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 4) {
/* tram */
if ((err = ld10k1_debug_new_tram_info_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 5) {
if ((err = ld10k1_debug_new_patch_list_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 6) {
if ((err = ld10k1_debug_new_patch_order_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 7) {
/* fx */
if ((err = ld10k1_debug_new_fx_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 8) {
/* in */
if ((err = ld10k1_debug_new_in_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else if (debug_info.what == 9) {
/* out */
if ((err = ld10k1_debug_new_out_read(data_conn, &dsp_mgr)) < 0)
return err;
if ((err = send_response_ok(data_conn)) < 0)
return err;
} else
if ((err = send_response_ok(data_conn)) < 0)
return err;
return 0;
}

30
ld10k1/src/ld10k1_debug.h Normal file
View file

@ -0,0 +1,30 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003 by Peter Zubaj
*
* 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;
*
* 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
*
*/
#ifndef __LD10K1_DEBUG_H
#define __LD10K1_DEBUG_H
typedef struct {
int what;
} ld10k1_fnc_debug_t;
int ld10k1_fnc_debug(int data_conn, int op, int size);
#endif /* __LD10K1_DEBUG_H */

541
ld10k1/src/ld10k1_driver.c Normal file
View file

@ -0,0 +1,541 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/ioctl.h>
#include <alsa/asoundlib.h>
#include <alsa/sound/emu10k1.h>
#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "bitops.h"
#include "ld10k1.h"
#include "ld10k1_driver.h"
#include "ld10k1_error.h"
#include "ld10k1_fnc.h"
#include "ld10k1_fnc_int.h"
//#define DEBUG_DRIVER 1
extern snd_hwdep_t *handle;
void ld10k1_syntetize_instr(int audigy, int op, int arg1, int arg2, int arg3, int arg4, unsigned int *out)
{
if (audigy) {
*out = ((arg3 & 0x7ff) << 12) | (arg4 & 0x7ff);
*(out + 1) = ((op & 0x0f) << 24) | ((arg1 & 0x7ff) << 12) | (arg2 & 0x7ff);
} else {
*out = ((arg3 & 0x3ff) << 10) | (arg4 & 0x3ff);
*(out + 1) = ((op & 0x0f) << 20) | ((arg1 & 0x3ff) << 10) | (arg2 & 0x3ff);
}
}
void ld10k1_init_must_init_output(ld10k1_dsp_mgr_t *dsp_mgr);
void ld10k1_set_must_init_output(ld10k1_dsp_mgr_t *dsp_mgr, int reg);
void ld10k1_check_must_init_output(ld10k1_dsp_mgr_t *dsp_mgr, emu10k1_fx8010_code_t *code);
/* outputs what must be initialized on audigy */
static int audigy_must_init_output[] = {
0x68, 0,
0x69, 0,
0x6a, 0,
0x6b, 0,
0x6e, 0,
0x6f, 0,
-1};
#define LD10K1_SIGNATURE "LD10K1 ver. " VERSION " managed DSP code"
void ld10k1_free_code_struct(emu10k1_fx8010_code_t *code)
{
if (code->gpr_map)
free(code->gpr_map);
if (code->tram_data_map)
free(code->tram_data_map);
if (code->tram_addr_map)
free(code->tram_addr_map);
if (code->code)
free(code->code);
}
int ld10k1_alloc_code_struct(emu10k1_fx8010_code_t *code)
{
/* alloc code structure */
code->gpr_map = NULL;
code->tram_data_map = NULL;
code->tram_addr_map = NULL;
code->code = NULL;
code->gpr_map = (uint32_t *)malloc(sizeof(uint32_t) * 0x200);
if (!code->gpr_map)
goto err;
memset(code->gpr_map, 0, sizeof(uint32_t) * 0x200);
code->tram_data_map = (uint32_t *)malloc(sizeof(uint32_t) * 0x100);
if (!code->tram_data_map)
goto err;
memset(code->tram_data_map, 0, sizeof(uint32_t) * 0x100);
code->tram_addr_map = (uint32_t *)malloc(sizeof(uint32_t) * 0x100);
if (!code->tram_addr_map)
goto err;
memset(code->tram_addr_map, 0, sizeof(uint32_t) * 0x100);
code->code = (uint32_t *)malloc(sizeof(uint32_t) * 1024 * 2);
if (!code->code)
goto err;
memset(code->code, 0, sizeof(uint32_t) * 1024 * 2);
return 0;
err:
ld10k1_free_code_struct(code);
return LD10K1_ERR_NO_MEM;
}
int ld10k1_update_driver(ld10k1_dsp_mgr_t *dsp_mgr)
{
emu10k1_fx8010_code_t code;
emu10k1_fx8010_control_gpr_t *add_ctrl;
emu10k1_ctl_elem_id_t *del_ids;
ld10k1_ctl_list_item_t *item;
unsigned int i, j;
int max;
int modified;
unsigned int addr;
unsigned int vaddr;
unsigned int op;
unsigned int idx_offset;
unsigned int *iptr;
ld10k1_ctl_t gctl;
int err;
if ((err = ld10k1_alloc_code_struct(&code)) < 0)
return err;
/* new name */
strcpy(code.name, LD10K1_SIGNATURE);
for (i = 0; i < sizeof(code.gpr_valid) / sizeof(unsigned long); i++)
code.gpr_valid[i] = 0;
for (i = 0; i < sizeof(code.tram_valid) / sizeof(unsigned long); i++)
code.tram_valid[i] = 0;
for (i = 0; i < sizeof(code.code_valid) / sizeof(unsigned long); i++)
code.code_valid[i] = 0;
/* registers */
for (i = 0; i < dsp_mgr->regs_max_count; i++)
if (dsp_mgr->regs[i].modified) {
set_bit(i, code.gpr_valid);
code.gpr_map[i] = dsp_mgr->regs[i].val;
}
/* tram addr + data */
for (j = 0; j < 2; j++) {
max = (j == 0 ? dsp_mgr->max_itram_hwacc : dsp_mgr->max_etram_hwacc);
for (i = 0; i < max; i++) {
modified = (j == 0 ? dsp_mgr->itram_hwacc[i].modified : dsp_mgr->etram_hwacc[i].modified);
if (modified) {
addr = (j == 0 ? dsp_mgr->itram_hwacc[i].addr_val : dsp_mgr->etram_hwacc[i].addr_val);
vaddr = addr & 0xFFFFF;
idx_offset = (j == 0 ? 0 : dsp_mgr->max_itram_hwacc);
op = (j == 0 ? dsp_mgr->itram_hwacc[i].op : dsp_mgr->etram_hwacc[i].op);
set_bit(i + idx_offset, code.tram_valid);
switch(op) {
case TRAM_OP_READ:
if (dsp_mgr->audigy)
vaddr = vaddr | 0x2 << 20;
else
vaddr = vaddr | TANKMEMADDRREG_READ | TANKMEMADDRREG_ALIGN;
break;
case TRAM_OP_WRITE:
if (dsp_mgr->audigy)
vaddr = vaddr | 0x6 << 20;
else
vaddr = vaddr | TANKMEMADDRREG_WRITE | TANKMEMADDRREG_ALIGN;
break;
case TRAM_OP_NULL:
default:
vaddr = 0;
break;
}
code.tram_addr_map[i + idx_offset] = vaddr;
code.tram_data_map[i + idx_offset] = (j == 0 ? dsp_mgr->itram_hwacc[i].data_val : dsp_mgr->etram_hwacc[i].data_val);
}
}
}
/* controls to add */
if (dsp_mgr->add_list_count > 0) {
add_ctrl = (emu10k1_fx8010_control_gpr_t *)malloc(sizeof(emu10k1_fx8010_control_gpr_t) * dsp_mgr->add_list_count);
memset(add_ctrl, 0, sizeof(emu10k1_fx8010_control_gpr_t) * dsp_mgr->add_list_count);
for (i = 0, item = dsp_mgr->add_ctl_list; item != NULL; item = item->next, i++) {
strcpy(add_ctrl[i].id.name, item->ctl.name);
add_ctrl[i].id.iface = EMU10K1_CTL_ELEM_IFACE_MIXER;
add_ctrl[i].id.index = item->ctl.index;
add_ctrl[i].vcount = item->ctl.vcount;
add_ctrl[i].count = item->ctl.count;
for (j = 0; j < 32; j++) {
add_ctrl[i].gpr[j] = item->ctl.gpr_idx[j];
add_ctrl[i].value[j] = item->ctl.value[j];
}
add_ctrl[i].min = item->ctl.min;
add_ctrl[i].max = item->ctl.max;
add_ctrl[i].translation = item->ctl.translation;
}
} else
add_ctrl = NULL;
code.gpr_add_control_count = dsp_mgr->add_list_count;
code.gpr_add_controls = add_ctrl;
/* controls to del */
if (dsp_mgr->del_list_count > 0) {
del_ids = (emu10k1_ctl_elem_id_t *)malloc(sizeof(emu10k1_ctl_elem_id_t) * dsp_mgr->del_list_count);
memset(del_ids, 0, sizeof(emu10k1_ctl_elem_id_t) * dsp_mgr->del_list_count);
for (i = 0, item = dsp_mgr->del_ctl_list; item != NULL; item = item->next, i++) {
strcpy(del_ids[i].name, item->ctl.name);
del_ids[i].iface = EMU10K1_CTL_ELEM_IFACE_MIXER;
del_ids[i].index = item->ctl.index;
}
} else
del_ids = NULL;
code.gpr_del_control_count = dsp_mgr->del_list_count;
code.gpr_del_controls = del_ids;
code.gpr_list_control_count = 0;
for (iptr = code.code, i = 0; i < dsp_mgr->instr_count; i++, iptr += 2) {
if (dsp_mgr->instr[i].modified) {
set_bit(i, code.code_valid);
if (dsp_mgr->instr[i].used) {
if (dsp_mgr->audigy) {
ld10k1_syntetize_instr(dsp_mgr->audigy,
dsp_mgr->instr[i].op_code,
dsp_mgr->instr[i].arg[0], dsp_mgr->instr[i].arg[1], dsp_mgr->instr[i].arg[2], dsp_mgr->instr[i].arg[3], iptr);
} else {
if (i < 0x200) {
ld10k1_syntetize_instr(dsp_mgr->audigy,
dsp_mgr->instr[i].op_code,
dsp_mgr->instr[i].arg[0], dsp_mgr->instr[i].arg[1], dsp_mgr->instr[i].arg[2], dsp_mgr->instr[i].arg[3], iptr);
}
}
} else {
if (dsp_mgr->audigy) {
ld10k1_syntetize_instr(dsp_mgr->audigy,
0x0f,
0xc0, 0xc0, 0xcf, 0xc0, iptr);
} else {
if (i < 0x200) {
ld10k1_syntetize_instr(dsp_mgr->audigy,
0x06,
0x40, 0x40, 0x40, 0x40, iptr);
}
}
}
}
}
/* check initialization of i2s outputs on audigy */
if (dsp_mgr->audigy)
ld10k1_check_must_init_output(dsp_mgr, &code);
#ifndef DEBUG_DRIVER
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_POKE, &code) < 0) {
error("unable to poke code");
ld10k1_free_code_struct(&code);
if (add_ctrl)
free(add_ctrl);
if (del_ids)
free(del_ids);
return LD10K1_ERR_DRIVER_CODE_POKE;
}
#endif
/* update state */
for (item = dsp_mgr->del_ctl_list; item != NULL; item = item->next) {
strcpy(gctl.name, item->ctl.name);
ld10k1_del_control_from_list(&(dsp_mgr->ctl_list), &(dsp_mgr->ctl_list_count), &gctl);
}
ld10k1_del_all_controls_from_list(&(dsp_mgr->del_ctl_list), &dsp_mgr->del_list_count);
for (item = dsp_mgr->add_ctl_list; item != NULL; item = item->next)
ld10k1_add_control_to_list(&(dsp_mgr->ctl_list), &(dsp_mgr->ctl_list_count), &(item->ctl));
ld10k1_del_all_controls_from_list(&(dsp_mgr->add_ctl_list), &dsp_mgr->add_list_count);
for (i = 0; i < dsp_mgr->regs_max_count; i++)
dsp_mgr->regs[i].modified = 0;
for (i = 0; i < dsp_mgr->instr_count; i++)
dsp_mgr->instr[i].modified = 0;
for (j = 0; j < 2; j++) {
max = (j == 0 ? dsp_mgr->max_itram_hwacc : dsp_mgr->max_etram_hwacc);
for (i = 0; i < max; i++) {
if (j == 0)
dsp_mgr->itram_hwacc[i].modified = 0;
else
dsp_mgr->etram_hwacc[i].modified = 0;
}
}
ld10k1_free_code_struct(&code);
if (add_ctrl)
free(add_ctrl);
if (del_ids)
free(del_ids);
return 0;
}
int ld10k1_init_driver(ld10k1_dsp_mgr_t *dsp_mgr, int tram_size)
{
emu10k1_fx8010_info_t info;
int i;
emu10k1_fx8010_code_t code;
emu10k1_fx8010_control_gpr_t *ctrl;
emu10k1_ctl_elem_id_t *ids;
emu10k1_fx8010_pcm_t ipcm;
unsigned int *iptr;
int err;
if ((err = ld10k1_alloc_code_struct(&code)) < 0)
return err;
/* setup tram size */
if (tram_size >= 0 && snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_TRAM_SETUP, &tram_size) < 0) {
error("unable to setup tram");
if (dsp_mgr->audigy)
error("You are probably user of audigy, audigy 2 and you not aplyed patch to enable tram");
/* this is not fatal, but do not use tram */
dsp_mgr->i_tram.size = 0;
dsp_mgr->e_tram.size = 0;
} else {
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_INFO, &info) < 0) {
error("unable to get info ");
ld10k1_free_code_struct(&code);
return LD10K1_ERR_DRIVER_INFO;
}
dsp_mgr->i_tram.size = info.internal_tram_size;
dsp_mgr->e_tram.size = info.external_tram_size;
}
/* get count of controls */
code.gpr_list_control_count = 0;
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_PEEK, &code) < 0) {
error("unable to peek code");
ld10k1_free_code_struct(&code);
return LD10K1_ERR_DRIVER_CODE_PEEK;
}
ctrl = (emu10k1_fx8010_control_gpr_t *)malloc(sizeof(emu10k1_fx8010_control_gpr_t) * code.gpr_list_control_total);
if (!ctrl) {
ld10k1_free_code_struct(&code);
return LD10K1_ERR_NO_MEM;
}
code.gpr_list_control_count = code.gpr_list_control_total;
code.gpr_list_controls = ctrl;
for (i = 0; i < sizeof(code.gpr_valid) / sizeof(unsigned long); i++)
code.gpr_valid[i] = 0x0;
for (i = 0; i < sizeof(code.tram_valid) / sizeof(unsigned long); i++)
code.tram_valid[i] = 0x0;
for (i = 0; i < sizeof(code.code_valid) / sizeof(unsigned long); i++)
code.code_valid[i] = 0x0;;
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_PEEK, &code) < 0) {
error("unable to peek code");
ld10k1_free_code_struct(&code);
free(ctrl);
return LD10K1_ERR_DRIVER_CODE_PEEK;
}
/* new name */
strcpy(code.name, LD10K1_SIGNATURE);
for (i = 0; i < sizeof(code.gpr_valid) / sizeof(unsigned long); i++)
code.gpr_valid[i] = ~0;
for (i = 0; i < sizeof(code.gpr_valid) * 8; i++) {
code.gpr_map[i] = 0;
}
ids = (emu10k1_ctl_elem_id_t *)malloc(sizeof(emu10k1_ctl_elem_id_t) * code.gpr_list_control_total);
if (!ids) {
ld10k1_free_code_struct(&code);
free(ctrl);
return LD10K1_ERR_NO_MEM;
}
code.gpr_del_control_count = code.gpr_list_control_total;
if (code.gpr_del_control_count) {
for (i = 0; i < code.gpr_del_control_count; i++) {
memcpy(&(ids[i]), &(ctrl[i].id), sizeof(emu10k1_ctl_elem_id_t));
}
}
free(ctrl);
code.gpr_del_controls = ids;
code.gpr_list_control_count = 0;
code.gpr_add_control_count = 0;
code.gpr_list_control_count = 0;
for (i = 0; i < sizeof(code.tram_valid) / sizeof(unsigned long); i++)
code.tram_valid[i] = ~0;
for (i = 0; i < sizeof(code.code_valid) / sizeof(unsigned long); i++)
code.code_valid[i] = ~0;
for (i = 0; i < sizeof(code.tram_valid) * 8; i++) {
code.tram_addr_map[i] = 0;
code.tram_data_map[i] = 0;
}
for (iptr = code.code, i = 0; i < sizeof(code.code_valid) * 8; i++, iptr += 2)
if (dsp_mgr->audigy) {
ld10k1_syntetize_instr(dsp_mgr->audigy,
0x0f,
0xc0, 0xc0, 0xcf, 0xc0, iptr);
} else {
ld10k1_syntetize_instr(dsp_mgr->audigy,
0x06,
0x40, 0x40, 0x40, 0x40, iptr);
}
/* initialize i2s outputs on audigy */
if (dsp_mgr->audigy) {
for (iptr = code.code, i = 0; audigy_must_init_output[i] > 0; i += 2, iptr += 2)
ld10k1_syntetize_instr(dsp_mgr->audigy, 0x00,
audigy_must_init_output[i], 0xc0, 0xc0, 0xc0, iptr);
}
#ifndef DEBUG_DRIVER
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_CODE_POKE, &code) < 0) {
error("unable to poke code");
ld10k1_free_code_struct(&code);
free(ids);
return LD10K1_ERR_DRIVER_CODE_POKE;
}
#endif
free(ids);
/* delete tram pcm dsp part */
if (!dsp_mgr->audigy) {
for (i = 0; i < EMU10K1_FX8010_PCM_COUNT; i++) {
ipcm.substream = i;
ipcm.channels = 0;
#ifndef DEBUG_DRIVER
if (snd_hwdep_ioctl(handle, SNDRV_EMU10K1_IOCTL_PCM_POKE, &ipcm) < 0) {
error("unable to poke code");
ld10k1_free_code_struct(&code);
return LD10K1_ERR_DRIVER_PCM_POKE;
}
#endif
}
}
ld10k1_free_code_struct(&code);
return 0;
}
void ld10k1_init_must_init_output(ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
if (dsp_mgr->audigy) {
for (i = 0; audigy_must_init_output[i] > 0; i += 2)
audigy_must_init_output[i + 1] = 1;
}
}
void ld10k1_set_must_init_output(ld10k1_dsp_mgr_t *dsp_mgr, int reg)
{
int i ;
if (dsp_mgr->audigy) {
for (i = 0; audigy_must_init_output[i] > 0; i += 2) {
if (audigy_must_init_output[i] == reg) {
audigy_must_init_output[i + 1] = 0;
return;
}
}
}
}
void ld10k1_check_must_init_output(ld10k1_dsp_mgr_t *dsp_mgr, emu10k1_fx8010_code_t *code)
{
int j;
ld10k1_init_must_init_output(dsp_mgr);
for (j = 0; j < dsp_mgr->instr_count; j++) {
if (dsp_mgr->instr[j].used)
ld10k1_set_must_init_output(dsp_mgr, dsp_mgr->instr[j].arg[0]);
}
int i;
int l;
int ioffset = dsp_mgr->instr_count - 1;
if (dsp_mgr->audigy) {
for (i = 0; audigy_must_init_output[i] > 0; i += 2) {
if (audigy_must_init_output[i + 1]) {
/* find free instruction slot */
for (;ioffset >= 0; ioffset--) {
if (!dsp_mgr->instr[ioffset].used) {
ld10k1_instr_t *instr = &(dsp_mgr->instr[ioffset]);
ld10k1_syntetize_instr(dsp_mgr->audigy,
0x0,
audigy_must_init_output[i], 0xc0, 0xc0, 0xc0,
code->code + ioffset * 2);
instr->op_code = 0;
instr->arg[0] = audigy_must_init_output[i];
for (l = 1; l < 4; l++)
instr->arg[l] = 0xc0;
set_bit(ioffset, code->code_valid);
dsp_mgr->instr[ioffset].used = 1;
ioffset--;
break;
}
}
if (ioffset < 0)
return;
}
}
}
}

View file

@ -0,0 +1,28 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_DRIVER_H
#define __LD10K1_DRIVER_H
int ld10k1_update_driver(ld10k1_dsp_mgr_t *dsp_mgr);
int ld10k1_init_driver(ld10k1_dsp_mgr_t *dsp_mgr, int tram_size);
#endif /* __LD10K1_DRIVER_H */

153
ld10k1/src/ld10k1_dump.c Normal file
View file

@ -0,0 +1,153 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <alsa/asoundlib.h>
#include "ld10k1.h"
#include "ld10k1_dump_file.h"
#include "ld10k1_dump.h"
#include "ld10k1_error.h"
int ld10k1_make_dump(ld10k1_dsp_mgr_t *dsp_mgr, void **dump, int *size)
{
int dump_size = 0;
void *dump_file = NULL;
void *ptr = NULL;
ld10k1_dump_t *header = NULL;
ld10k1_ctl_dump_t *ctl = NULL;
int i, j;
ld10k1_ctl_list_item_t *item;
unsigned int *ival = NULL;
ld10k1_tram_dump_t *tram = NULL;
ld10k1_instr_dump_t *instr = NULL;
dump_size += sizeof(ld10k1_dump_t);
dump_size += sizeof(ld10k1_ctl_dump_t) * dsp_mgr->ctl_list_count;
dump_size += sizeof(unsigned int) * dsp_mgr->regs_max_count;
dump_size += sizeof(ld10k1_tram_dump_t) * (dsp_mgr->max_itram_hwacc + dsp_mgr->max_etram_hwacc);
dump_size += sizeof(ld10k1_instr_dump_t) * dsp_mgr->instr_count;
dump_file = malloc(dump_size);
if (!dump_file)
return LD10K1_ERR_NO_MEM;
ptr = dump_file;
header = (ld10k1_dump_t *)ptr;
strcpy(header->signature, "LD10K1 DUMP 001");
if (!dsp_mgr->audigy)
header->dump_type = DUMP_TYPE_LIVE;
else
header->dump_type = DUMP_TYPE_AUDIGY;
header->tram_size = dsp_mgr->e_tram.size;
header->ctl_count = dsp_mgr->ctl_list_count;
header->gpr_count = dsp_mgr->regs_max_count;
header->tram_count = dsp_mgr->max_itram_hwacc + dsp_mgr->max_etram_hwacc;
header->instr_count = dsp_mgr->instr_count;
/*printf("Size header%d\n", dump_size);
printf("Size header%d\nctc %d %d\ngpr %d %d\ntram %d %d\ninstr %d %d\n", sizeof(ld10k1_dump_t),
header->ctl_count, sizeof(ld10k1_ctl_dump_t),
header->gpr_count, sizeof(unsigned int),
header->tram_count, sizeof(ld10k1_tram_dump_t),
header->instr_count, sizeof(ld10k1_instr_dump_t));*/
ptr += sizeof(ld10k1_dump_t);
/* ctls */
for (item = dsp_mgr->ctl_list; item != NULL; item = item->next) {
ctl = (ld10k1_ctl_dump_t *)ptr;
strcpy(ctl->name, item->ctl.name);
ctl->index = item->ctl.index;
ctl->vcount = item->ctl.vcount;
ctl->count = item->ctl.count;
for (j = 0; j < 32; j++) {
ctl->gpr_idx[j] = item->ctl.gpr_idx[j];
ctl->value[j] = item->ctl.value[j];
}
ctl->min = item->ctl.min;
ctl->max = item->ctl.max;
ctl->translation = item->ctl.translation;
ptr += sizeof(ld10k1_ctl_dump_t);
}
/* regs */
for (i = 0; i < dsp_mgr->regs_max_count; i++) {
ival = (unsigned int *) ptr;
*ival = dsp_mgr->regs[i].val;
ptr += sizeof(unsigned int);
}
/* tram */
for (i = 0; i < dsp_mgr->max_itram_hwacc; i++) {
tram = (ld10k1_tram_dump_t *) ptr;
if (dsp_mgr->itram_hwacc[i].used) {
tram->type = dsp_mgr->itram_hwacc[i].op;
tram->addr = dsp_mgr->itram_hwacc[i].addr_val;
tram->data = dsp_mgr->itram_hwacc[i].data_val;
} else {
tram->type = 0;
tram->addr = 0;
tram->data = 0;
}
ptr += sizeof(ld10k1_tram_dump_t);
}
for (i = 0; i < dsp_mgr->max_etram_hwacc; i++) {
tram = (ld10k1_tram_dump_t *) ptr;
if (dsp_mgr->etram_hwacc[i].used) {
if (dsp_mgr->etram_hwacc[i].op == TRAM_OP_READ)
tram->type = DUMP_TRAM_READ;
else if (dsp_mgr->etram_hwacc[i].op == TRAM_OP_WRITE)
tram->type = DUMP_TRAM_WRITE;
else
tram->type = DUMP_TRAM_NULL;
tram->addr = dsp_mgr->etram_hwacc[i].addr_val;
tram->data = dsp_mgr->etram_hwacc[i].data_val;
} else {
tram->type = 0;
tram->addr = 0;
tram->data = 0;
}
ptr += sizeof(ld10k1_tram_dump_t);
}
/* instr */
for (i = 0; i < dsp_mgr->instr_count; i++) {
instr = (ld10k1_instr_dump_t *) ptr;
instr->used = dsp_mgr->instr[i].used;
instr->op = dsp_mgr->instr[i].op_code;
instr->arg[0] = dsp_mgr->instr[i].arg[0];
instr->arg[1] = dsp_mgr->instr[i].arg[1];
instr->arg[2] = dsp_mgr->instr[i].arg[2];
instr->arg[3] = dsp_mgr->instr[i].arg[3];
ptr += sizeof(ld10k1_instr_dump_t);
}
*dump = dump_file;
*size = dump_size;
return 0;
}

27
ld10k1/src/ld10k1_dump.h Normal file
View file

@ -0,0 +1,27 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_DUMP_H
#define __LD10K1_DUMP_H
int ld10k1_make_dump(ld10k1_dsp_mgr_t *dsp_mgr, void **dump, int *size);
#endif /* __LD10K1_DUMP_H */

View file

@ -0,0 +1,67 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_DUMP_FILE_H
#define __LD10K1_DUMP_FILE_H
#define DUMP_TYPE_LIVE 0
#define DUMP_TYPE_AUDIGY_OLD 1
#define DUMP_TYPE_AUDIGY 2
typedef struct {
char signature[16]; /* LD10K1 DUMP 001 */
int dump_type;
int tram_size;
int ctl_count;
int gpr_count;
int tram_count;
int instr_count;
} ld10k1_dump_t;
#define DUMP_TRAM_NULL 0
#define DUMP_TRAM_READ 1
#define DUMP_TRAM_WRITE 2
typedef struct {
int type;
unsigned int addr;
unsigned int data;
} ld10k1_tram_dump_t;
typedef struct {
int used;
unsigned int op;
unsigned int arg[4];
} ld10k1_instr_dump_t;
typedef struct {
char name[44];
int index;
unsigned int vcount; /* count of GPR (1..32) */
unsigned int count; /* count of GPR (1..32) */
unsigned int gpr_idx[32]; /* GPR number(s) */
unsigned int value[32];
unsigned int min; /* minimum range */
unsigned int max; /* maximum range */
unsigned int translation; /* typ - 0 - bool, num 1 - enum */
} ld10k1_ctl_dump_t;
#endif /* __LD10K1_DUMP_FILE_H */

2373
ld10k1/src/ld10k1_fnc.c Normal file

File diff suppressed because it is too large Load diff

1507
ld10k1/src/ld10k1_fnc1.c Normal file

File diff suppressed because it is too large Load diff

35
ld10k1/src/ld10k1_fnc1.h Normal file
View file

@ -0,0 +1,35 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_FNC1_H
#define __LD10K1_FNC1_H
#include "comm.h"
extern ld10k1_dsp_mgr_t dsp_mgr;
int main_loop(comm_param *param, int audigy, const char *card_id, int tram_size, snd_ctl_t *ctlp);
int send_response_ok(int conn_num);
int send_response_err(int conn_num, int err);
int send_response_wd(int conn_num, void *data, int data_size);
#endif /* __LD10K1_FNC1_H */

View file

@ -0,0 +1,52 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_FNC_INT_H
#define __LD10K1_FNC_INT_H
int ld10k1_dsp_mgr_init(ld10k1_dsp_mgr_t *dsp_mgr);
void ld10k1_dsp_mgr_init_id_gen(ld10k1_dsp_mgr_t *dsp_mgr);
void ld10k1_dsp_mgr_free(ld10k1_dsp_mgr_t *dsp_mgr);
ld10k1_patch_t *ld10k1_dsp_mgr_patch_new(void);
void ld10k1_dsp_mgr_patch_free(ld10k1_patch_t *patch);
ld10k1_p_in_out_t *ld10k1_dsp_mgr_patch_in_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_in_out_t *ld10k1_dsp_mgr_patch_out_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_const_sta_t *ld10k1_dsp_mgr_patch_const_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_const_sta_t *ld10k1_dsp_mgr_patch_sta_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_dyn_t *ld10k1_dsp_mgr_patch_dyn_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_hw_t *ld10k1_dsp_mgr_patch_hw_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_tram_grp_t *ld10k1_dsp_mgr_patch_tram_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_p_tram_acc_t *ld10k1_dsp_mgr_patch_tram_acc_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_instr_t *ld10k1_dsp_mgr_patch_instr_new(ld10k1_patch_t *patch, unsigned int count);
ld10k1_ctl_t *ld10k1_dsp_mgr_patch_ctl_new(ld10k1_patch_t *patch, unsigned int count);
char *ld10k1_dsp_mgr_name_new(char **where, const char *from);
int ld10k1_dsp_mgr_patch_load(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch, int before, int *loaded);
int ld10k1_patch_fnc_check_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *new_patch);
int ld10k1_patch_fnc_del(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_fnc_patch_del_t *patch_fnc);
int ld10k1_connection_fnc(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_fnc_connection_t *connection_fnc, int *conn_id);
void ld10k1_del_control_from_list(ld10k1_ctl_list_item_t **list, int *count, ld10k1_ctl_t *gctl);
void ld10k1_del_all_controls_from_list(ld10k1_ctl_list_item_t **list, int *count);
int ld10k1_add_control_to_list(ld10k1_ctl_list_item_t **list, int *count, ld10k1_ctl_t *gctl);
#endif /* __LD10K1_FNC_INT_H */

97
ld10k1/src/ld10k1_mixer.c Normal file
View file

@ -0,0 +1,97 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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 <alsa/asoundlib.h>
#include "ld10k1.h"
#include "ld10k1_mixer.h"
#include "ld10k1_error.h"
int ld10k1_init_reserved_ctls(ld10k1_dsp_mgr_t *dsp_mgr, snd_ctl_t *ctlp)
{
snd_ctl_elem_list_t *clist;
int count;
int i;
const char *ctl_name;
unsigned int ctl_index;
ld10k1_reserved_ctl_list_item_t *res_ctl;
dsp_mgr->reserved_ctl_list = NULL;
snd_ctl_elem_list_alloca(&clist);
if (snd_ctl_elem_list(ctlp, clist) < 0)
return LD10K1_ERR_NO_MEM;
if ((count = snd_ctl_elem_list_get_count(clist)) < 0)
return LD10K1_ERR_NO_MEM;
snd_ctl_elem_list_set_offset(clist, 0);
if (snd_ctl_elem_list_alloc_space(clist, count) < 0)
return LD10K1_ERR_NO_MEM;
if (snd_ctl_elem_list(ctlp, clist) < 0) {
snd_ctl_elem_list_free_space(clist);
return LD10K1_ERR_NO_MEM;
}
for (i = 0; i < count; i++) {
snd_ctl_elem_id_t *id;
snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_list_get_id(clist, i, id);
ctl_name = snd_ctl_elem_id_get_name(id);
ctl_index = snd_ctl_elem_id_get_index(id);
res_ctl = (ld10k1_reserved_ctl_list_item_t *)malloc(sizeof(ld10k1_reserved_ctl_list_item_t));
if (!res_ctl) {
snd_ctl_elem_list_free_space(clist);
return LD10K1_ERR_NO_MEM;
}
res_ctl->next = dsp_mgr->reserved_ctl_list;
dsp_mgr->reserved_ctl_list = res_ctl;
strncpy(res_ctl->res_ctl.name, ctl_name, 43);
res_ctl->res_ctl.name[43] = '\0';
res_ctl->res_ctl.index = ctl_index;
}
snd_ctl_elem_list_free_space(clist);
return 0;
}
int ld10k1_free_reserved_ctls(ld10k1_dsp_mgr_t *dsp_mgr)
{
ld10k1_reserved_ctl_list_item_t *item;
ld10k1_reserved_ctl_list_item_t *item1;
for (item = dsp_mgr->reserved_ctl_list; item != NULL;) {
item1 = item->next;
free(item);
item = item1;
}
dsp_mgr->reserved_ctl_list = NULL;
return 0;
}

28
ld10k1/src/ld10k1_mixer.h Normal file
View file

@ -0,0 +1,28 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_MIXER_H
#define __LD10K1_MIXER_H
int ld10k1_init_reserved_ctls(ld10k1_dsp_mgr_t *dsp_mgr, snd_ctl_t *ctlp);
int ld10k1_free_reserved_ctls(ld10k1_dsp_mgr_t *dsp_mgr);
#endif /* __LD10K1_MIXER_H */

481
ld10k1/src/ld10k1_tram.c Normal file
View file

@ -0,0 +1,481 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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 "ld10k1.h"
#include "ld10k1_fnc.h"
#include "ld10k1_tram.h"
#include "ld10k1_error.h"
#include <stdlib.h>
int ld10k1_tram_res_alloc_hwacc(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res);
int ld10k1_tram_realloc_space(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res);
void ld10k1_tram_init_res(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res)
{
res->isize = dsp_mgr->i_tram.size;
res->ifree = dsp_mgr->i_tram.size;
res->iacc_count = dsp_mgr->i_tram.max_hwacc;
res->iacc_free_count = dsp_mgr->i_tram.max_hwacc;
res->esize = dsp_mgr->e_tram.size;
res->efree = dsp_mgr->e_tram.size;
res->eacc_count = dsp_mgr->e_tram.max_hwacc;
res->eacc_free_count = dsp_mgr->e_tram.max_hwacc;
res->grp_free = res->iacc_free_count + res->eacc_free_count;
res->item_count = 0;
}
void ld10k1_tram_init_res_from_dsp_mgr(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res)
{
/* throught all groups */
int i;
for (i = 0; i < dsp_mgr->max_tram_grp; i++) {
if (dsp_mgr->tram_grp[i].used) {
/* get position */
res->grp_free--;
switch (dsp_mgr->tram_grp[i].req_pos) {
case TRAM_POS_NONE:
case TRAM_POS_AUTO:
/* add to res */
res->items[res->item_count].grp_idx = i;
res->items[res->item_count].grp_size = dsp_mgr->tram_grp[i].size;
res->items[res->item_count].grp_acc_count = dsp_mgr->tram_grp[i].acc_count;
res->items[res->item_count].res_value = 0;
res->items[res->item_count].pos = TRAM_POS_NONE;
res->item_count++;
break;
case TRAM_POS_INTERNAL:
/* decrease resources */
res->ifree -= dsp_mgr->tram_grp[i].size;
res->iacc_free_count -= dsp_mgr->tram_grp[i].acc_count;
break;
case TRAM_POS_EXTERNAL:
res->efree -= dsp_mgr->tram_grp[i].size;
res->eacc_free_count -= dsp_mgr->tram_grp[i].acc_count;
break;
}
}
}
}
int ld10k1_tram_acc_count_from_patch(ld10k1_patch_t *patch, int grp)
{
int i, count;
for (count = 0, i = 0; i < patch->tram_acc_count; i++)
if (patch->tram_acc[i].grp == grp)
count++;
return count;
}
int ld10k1_tram_init_res_from_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res, ld10k1_patch_t *patch)
{
int i;
int acc_count;
/* through all groups */
for (i = 0; i < patch->tram_count; i++) {
if (res->grp_free <= 0)
return LD10K1_ERR_TRAM_FULL_GRP;
/* get acc count */
acc_count = ld10k1_tram_acc_count_from_patch(patch, i);
if (acc_count <= 0)
continue;
/* get position */
switch (patch->tram_grp[i].grp_pos) {
case TRAM_POS_NONE:
case TRAM_POS_AUTO:
/* add to res */
res->items[res->item_count].grp_idx = -i - 1;
res->items[res->item_count].grp_size = patch->tram_grp[i].grp_size;
res->items[res->item_count].grp_acc_count = acc_count;
res->items[res->item_count].res_value = 0;
res->items[res->item_count].pos = TRAM_POS_NONE;
res->item_count++;
break;
case TRAM_POS_INTERNAL:
/* decrease resources */
if (res->ifree < patch->tram_grp[i].grp_size)
return LD10K1_ERR_ITRAM_FULL;
if (res->iacc_free_count < acc_count)
return LD10K1_ERR_ITRAM_FULL_ACC;
res->ifree -= patch->tram_grp[i].grp_size;
res->iacc_free_count -= acc_count;
break;
case TRAM_POS_EXTERNAL:
/* decrease resources */
if (res->efree < patch->tram_grp[i].grp_size)
return LD10K1_ERR_ETRAM_FULL;
if (res->eacc_free_count < acc_count)
return LD10K1_ERR_ETRAM_FULL_ACC;
res->efree -= patch->tram_grp[i].grp_size;
res->eacc_free_count -= acc_count;
break;
}
}
return 0;
}
int ld10k1_tram_init_res_from_patch_copy(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res, ld10k1_patch_t *patch)
{
/* throught all groups */
int i;
int acc_count;
for (i = 0; i < patch->tram_count; i++) {
/* get acc count */
acc_count = ld10k1_tram_acc_count_from_patch(patch, i);
/* get position */
if (patch->tram_grp[i].grp_pos == TRAM_POS_INTERNAL ||
patch->tram_grp[i].grp_pos == TRAM_POS_EXTERNAL) {
res->items[res->item_count].grp_idx = -i - 1;
res->items[res->item_count].grp_size = patch->tram_grp[i].grp_size;
res->items[res->item_count].grp_acc_count = acc_count;
res->items[res->item_count].pos = patch->tram_grp[i].grp_pos;
res->items[res->item_count].res_value = 0;
res->item_count++;
}
}
return 0;
}
int ld10k1_tram_calc_res_value(ld10k1_dsp_tram_resolve_t *res)
{
/* res_value is calculated as grp_size / acc_count */
int i;
for (i = 0; i < res->item_count; i++)
res->items[i].res_value = res->items[i].grp_size / res->items[i].grp_acc_count;
return 0;
}
static int ld10k1_tram_sort_res_compare(const void *item1, const void *item2)
{
ld10k1_dsp_tram_resolve_item_t *i1 = (ld10k1_dsp_tram_resolve_item_t *)item1;
ld10k1_dsp_tram_resolve_item_t *i2 = (ld10k1_dsp_tram_resolve_item_t *)item2;
if (i1->res_value == i2->res_value)
return 0;
else if (i1->res_value > i2->res_value)
return 1;
else
return -1;
}
int ld10k1_tram_sort_res(ld10k1_dsp_tram_resolve_t *res)
{
qsort(res->items, res->item_count, sizeof(ld10k1_dsp_tram_resolve_item_t), ld10k1_tram_sort_res_compare);
return 0;
}
int ld10k1_tram_resolve_res(ld10k1_dsp_tram_resolve_t *res)
{
int i;
for (i = 0; i < res->item_count; i++) {
/* first try internal tram then external tram */
if (res->items[i].grp_size <= res->ifree &&
res->items[i].grp_acc_count <= res->iacc_free_count) {
/* put it into itram */
res->ifree -= res->items[i].grp_size;
res->iacc_free_count -= res->items[i].grp_acc_count;
res->items[i].pos = TRAM_POS_INTERNAL;
} else if (res->items[i].grp_size <= res->efree &&
res->items[i].grp_acc_count <= res->eacc_free_count) {
/* put it into etram */
res->efree -= res->items[i].grp_size;
res->eacc_free_count -= res->items[i].grp_acc_count;
res->items[i].pos = TRAM_POS_EXTERNAL;
} else
return LD10K1_ERR_TRAM_FULL;
}
return 0;
}
int ld10k1_tram_grp_alloc(ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
for (i = 0; i < dsp_mgr->max_tram_grp; i++) {
if (!dsp_mgr->tram_grp[i].used) {
dsp_mgr->tram_grp[i].used = 1;
return i;
}
}
return LD10K1_ERR_TRAM_FULL_GRP;
}
void ld10k1_tram_grp_free(ld10k1_dsp_mgr_t *dsp_mgr, int grp)
{
dsp_mgr->tram_grp[grp].used = 0;
}
int ld10k1_tram_acc_alloc(ld10k1_dsp_mgr_t *dsp_mgr)
{
int i;
for (i = 0; i < dsp_mgr->max_tram_acc; i++) {
if (!dsp_mgr->tram_acc[i].used) {
dsp_mgr->tram_acc[i].used = 1;
return i;
}
}
return LD10K1_ERR_TRAM_FULL_ACC;
}
void ld10k1_tram_acc_free(ld10k1_dsp_mgr_t *dsp_mgr, int acc)
{
dsp_mgr->tram_acc[acc].used = 0;
}
int ld10k1_tram_reserve_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch, ld10k1_dsp_tram_resolve_t *res)
{
int err;
ld10k1_tram_init_res(dsp_mgr, res);
ld10k1_tram_init_res_from_dsp_mgr(dsp_mgr, res);
if ((err = ld10k1_tram_init_res_from_patch(dsp_mgr, res, patch)) < 0)
return err;
ld10k1_tram_calc_res_value(res);
ld10k1_tram_sort_res(res);
if ((err = ld10k1_tram_resolve_res(res)) < 0)
return err;
ld10k1_tram_init_res_from_patch_copy(dsp_mgr, res, patch);
return 0;
}
int ld10k1_tram_alloc_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch, ld10k1_dsp_tram_resolve_t *res)
{
int i;
int grp;
int acc;
/* allocate tram grp and acc for patch */
for (i = 0; i < patch->tram_count; i++) {
grp = ld10k1_tram_grp_alloc(dsp_mgr);
patch->tram_grp[i].grp_idx = grp;
dsp_mgr->tram_grp[grp].type = patch->tram_grp[i].grp_type;
dsp_mgr->tram_grp[grp].size = patch->tram_grp[i].grp_size;
}
for (i = 0; i < res->item_count; i++) {
if (res->items[i].grp_idx < 0) {
res->items[i].grp_idx = patch->tram_grp[-(res->items[i].grp_idx + 1)].grp_idx;
dsp_mgr->tram_grp[res->items[i].grp_idx].pos = TRAM_POS_NONE;
dsp_mgr->tram_grp[res->items[i].grp_idx].acc_count = res->items[i].grp_acc_count;
}
}
for (i = 0; i < patch->tram_acc_count; i++) {
acc = ld10k1_tram_acc_alloc(dsp_mgr);
patch->tram_acc[i].acc_idx = acc;
dsp_mgr->tram_acc[acc].type = patch->tram_acc[i].acc_type;
dsp_mgr->tram_acc[acc].offset = patch->tram_acc[i].acc_offset;
dsp_mgr->tram_acc[acc].grp = patch->tram_grp[patch->tram_acc[i].grp].grp_idx;
}
ld10k1_tram_res_alloc_hwacc(dsp_mgr, res);
ld10k1_tram_realloc_space(dsp_mgr, res);
return 0;
}
int ld10k1_tram_hwacc_alloc(ld10k1_dsp_mgr_t *dsp_mgr, int external)
{
int i;
if (!external) {
for (i = 0; i < dsp_mgr->max_itram_hwacc; i++) {
if (!dsp_mgr->itram_hwacc[i].used) {
dsp_mgr->itram_hwacc[i].used = 1;
dsp_mgr->i_tram.used_hwacc++;
return i;
}
}
} else {
for (i = 0; i < dsp_mgr->max_etram_hwacc; i++) {
if (!dsp_mgr->etram_hwacc[i].used) {
dsp_mgr->etram_hwacc[i].used = 1;
dsp_mgr->e_tram.used_hwacc++;
return i + dsp_mgr->max_itram_hwacc;
}
}
}
return LD10K1_ERR_TRAM_FULL_ACC;
}
void ld10k1_tram_hwacc_free(ld10k1_dsp_mgr_t *dsp_mgr, int acc)
{
if (acc < dsp_mgr->max_itram_hwacc) {
dsp_mgr->itram_hwacc[acc].used = 0;
dsp_mgr->itram_hwacc[acc].addr_val = 0;
dsp_mgr->itram_hwacc[acc].data_val = 0;
dsp_mgr->itram_hwacc[acc].modified = 1;
dsp_mgr->i_tram.used_hwacc--;
} else {
int nacc = acc - dsp_mgr->max_itram_hwacc;
dsp_mgr->etram_hwacc[nacc].used = 0;
dsp_mgr->etram_hwacc[nacc].used = 0;
dsp_mgr->etram_hwacc[nacc].addr_val = 0;
dsp_mgr->etram_hwacc[nacc].data_val = 0;
dsp_mgr->etram_hwacc[nacc].modified = 1;
dsp_mgr->e_tram.used_hwacc--;
}
}
void ld10k1_tram_actualize_hwacc(ld10k1_dsp_mgr_t *dsp_mgr, int acc, unsigned int op, unsigned int addr, unsigned int data)
{
if (acc < dsp_mgr->max_itram_hwacc) {
dsp_mgr->itram_hwacc[acc].op = op;
dsp_mgr->itram_hwacc[acc].addr_val = addr;
dsp_mgr->itram_hwacc[acc].data_val = data;
dsp_mgr->itram_hwacc[acc].modified = 1;
} else {
int nacc = acc - dsp_mgr->max_itram_hwacc;
dsp_mgr->etram_hwacc[nacc].op = op;
dsp_mgr->etram_hwacc[nacc].addr_val = addr;
dsp_mgr->etram_hwacc[nacc].data_val = data;
dsp_mgr->etram_hwacc[nacc].modified = 1;
}
}
void ld10k1_tram_get_hwacc(ld10k1_dsp_mgr_t *dsp_mgr, int acc, unsigned int *addr, unsigned int *data)
{
int nacc;
if (acc < dsp_mgr->max_itram_hwacc) {
*addr = dsp_mgr->itram_hwacc[acc].addr_val;
*data = dsp_mgr->itram_hwacc[acc].data_val;
} else {
nacc = acc - dsp_mgr->max_itram_hwacc;
*addr = dsp_mgr->etram_hwacc[nacc].addr_val;
*data = dsp_mgr->etram_hwacc[nacc].data_val;
}
}
int ld10k1_tram_res_alloc_hwacc(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res)
{
int i, j;
int grp_idx;
int hwacc;
/* free hw acc - where pos changed */
for (i = 0; i < res->item_count; i++) {
grp_idx = res->items[i].grp_idx;
if (dsp_mgr->tram_grp[grp_idx].pos != TRAM_POS_NONE &&
dsp_mgr->tram_grp[grp_idx].pos != res->items[i].pos) {
for (j = 0; j < dsp_mgr->max_tram_acc; j++)
if (dsp_mgr->tram_acc[j].used &&
dsp_mgr->tram_acc[j].grp == grp_idx)
ld10k1_tram_hwacc_free(dsp_mgr, dsp_mgr->tram_acc[j].hwacc);
dsp_mgr->tram_grp[grp_idx].pos = TRAM_POS_NONE;
}
}
/* now allocate */
for (i = 0; i < res->item_count; i++) {
grp_idx = res->items[i].grp_idx;
if (dsp_mgr->tram_grp[grp_idx].pos == TRAM_POS_NONE &&
dsp_mgr->tram_grp[grp_idx].pos != res->items[i].pos) {
dsp_mgr->tram_grp[grp_idx].pos = res->items[i].pos;
for (j = 0; j < dsp_mgr->max_tram_acc; j++)
if (dsp_mgr->tram_acc[j].used &&
dsp_mgr->tram_acc[j].grp == grp_idx) {
hwacc = ld10k1_tram_hwacc_alloc(dsp_mgr, res->items[i].pos == TRAM_POS_EXTERNAL ? 1 : 0);
dsp_mgr->tram_acc[j].hwacc = hwacc;
}
}
}
return 0;
}
int ld10k1_tram_realloc_space(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_dsp_tram_resolve_t *res)
{
int itram_size = res->isize;
int etram_size = res->esize;
int i;
/* allocate from end */
for (i = 0; i < dsp_mgr->max_tram_grp; i++)
if (dsp_mgr->tram_grp[i].used) {
if (dsp_mgr->tram_grp[i].pos == TRAM_POS_INTERNAL) {
itram_size -= dsp_mgr->tram_grp[i].size;
dsp_mgr->tram_grp[i].offset = itram_size;
} else if (dsp_mgr->tram_grp[i].pos == TRAM_POS_EXTERNAL) {
etram_size -= dsp_mgr->tram_grp[i].size;
dsp_mgr->tram_grp[i].offset = etram_size;
}
}
return 0;
}
int ld10k1_tram_actualize_tram_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch)
{
int i;
int grp_idx;
int acc_idx;
int tram_op;
/* for all patch accs */
for (i = 0; i < patch->tram_acc_count; i++) {
grp_idx = patch->tram_grp[patch->tram_acc[i].grp].grp_idx;
acc_idx = patch->tram_acc[i].acc_idx;
tram_op = 0;
if (dsp_mgr->tram_acc[acc_idx].type == TRAM_ACC_WRITE)
tram_op = TRAM_OP_WRITE;
else
tram_op = TRAM_OP_READ;
ld10k1_tram_actualize_hwacc(dsp_mgr, dsp_mgr->tram_acc[acc_idx].hwacc,
tram_op, dsp_mgr->tram_grp[grp_idx].offset + patch->tram_acc[i].acc_offset, 0);
}
return 0;
}
int ld10k1_tram_free_tram_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch)
{
int i;
int acc_idx;
int grp_idx;
/* free all patch accs */
for (i = 0; i < patch->tram_acc_count; i++) {
acc_idx = patch->tram_acc[i].acc_idx;
ld10k1_tram_hwacc_free(dsp_mgr, dsp_mgr->tram_acc[acc_idx].hwacc);
ld10k1_tram_acc_free(dsp_mgr, acc_idx);
}
/* free all patch grps */
for (i = 0; i < patch->tram_count; i++) {
grp_idx = patch->tram_grp[i].grp_idx;
ld10k1_tram_grp_free(dsp_mgr, grp_idx);
}
return 0;
}

53
ld10k1/src/ld10k1_tram.h Normal file
View file

@ -0,0 +1,53 @@
/*
* EMU10k1 loader
*
* Copyright (c) 2003,2004 by Peter Zubaj
*
* 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
*
*/
#ifndef __LD10K1_TRAM_H
#define __LD10K1_TRAM_H
typedef struct {
int grp_idx;
unsigned int grp_size;
unsigned int grp_acc_count;
unsigned int res_value;
unsigned int pos;
} ld10k1_dsp_tram_resolve_item_t;
typedef struct {
int isize;
int ifree;
int iacc_count;
int iacc_free_count;
int esize;
int efree;
int eacc_count;
int eacc_free_count;
int grp_free;
int item_count;
ld10k1_dsp_tram_resolve_item_t items[MAX_TRAM_COUNT];
} ld10k1_dsp_tram_resolve_t;
int ld10k1_tram_reserve_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch, ld10k1_dsp_tram_resolve_t *res);
int ld10k1_tram_alloc_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch, ld10k1_dsp_tram_resolve_t *res);
int ld10k1_tram_actualize_tram_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch);
void ld10k1_tram_get_hwacc(ld10k1_dsp_mgr_t *dsp_mgr, int acc, unsigned int *addr, unsigned int *data);
int ld10k1_tram_free_tram_for_patch(ld10k1_dsp_mgr_t *dsp_mgr, ld10k1_patch_t *patch);
#endif /* __LD10K1_TRAM_H */

1168
ld10k1/src/liblo10k1.c Normal file

File diff suppressed because it is too large Load diff

1099
ld10k1/src/liblo10k1ef.c Normal file

File diff suppressed because it is too large Load diff

1388
ld10k1/src/liblo10k1lf.c Normal file

File diff suppressed because it is too large Load diff

1737
ld10k1/src/lo10k1.c Normal file

File diff suppressed because it is too large Load diff