/* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #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, "%s", 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(¶ms, 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; }