mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-11-18 07:00:03 -05:00
615 lines
15 KiB
C
615 lines
15 KiB
C
/*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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;
|
|
}
|