#include <malloc.h>
#include <sys/timeb.h>
#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
#define getopt_long_only getopt_long
#define memalign(align, size) malloc(size)
#endif
NICInfo nd_table[MAX_NICS];
QEMUTimer *gui_timer;
int vm_running;
-#ifdef HAS_AUDIO
-int audio_enabled = 0;
-int sb16_enabled = 0;
-int adlib_enabled = 0;
-int gus_enabled = 0;
-int es1370_enabled = 0;
-#endif
int rtc_utc = 1;
int cirrus_vga_enabled = 1;
#ifdef TARGET_SPARC
USBDevice *vm_usb_hub;
static VLANState *first_vlan;
int smp_cpus = 1;
+#if defined(TARGET_SPARC)
+#define MAX_CPUS 16
+#elif defined(TARGET_I386)
+#define MAX_CPUS 255
+#else
+#define MAX_CPUS 1
+#endif
/***********************************************************/
/* x86 ISA bus support */
return chr;
}
-#ifndef _WIN32
+#ifdef _WIN32
-typedef struct {
- int fd_in, fd_out;
- IOCanRWHandler *fd_can_read;
- IOReadHandler *fd_read;
- void *fd_opaque;
- int max_size;
-} FDCharDriver;
+#define socket_error() WSAGetLastError()
+#undef EINTR
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
-#define STDIO_MAX_CLIENTS 2
+static void socket_cleanup(void)
+{
+ WSACleanup();
+}
-static int stdio_nb_clients;
-static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+static int socket_init(void)
+{
+ WSADATA Data;
+ int ret, err;
+
+ ret = WSAStartup(MAKEWORD(2,2), &Data);
+ if (ret != 0) {
+ err = WSAGetLastError();
+ fprintf(stderr, "WSAStartup: %d\n", err);
+ return -1;
+ }
+ atexit(socket_cleanup);
+ return 0;
+}
+
+static int send_all(int fd, const uint8_t *buf, int len1)
+{
+ int ret, len;
+
+ len = len1;
+ while (len > 0) {
+ ret = send(fd, buf, len, 0);
+ if (ret < 0) {
+ int errno;
+ errno = WSAGetLastError();
+ if (errno != WSAEWOULDBLOCK) {
+ return -1;
+ }
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ len -= ret;
+ }
+ }
+ return len1 - len;
+}
+
+void socket_set_nonblock(int fd)
+{
+ unsigned long opt = 1;
+ ioctlsocket(fd, FIONBIO, &opt);
+}
+
+#else
+
+#define socket_error() errno
+#define closesocket(s) close(s)
static int unix_write(int fd, const uint8_t *buf, int len1)
{
return len1 - len;
}
+static inline int send_all(int fd, const uint8_t *buf, int len1)
+{
+ return unix_write(fd, buf, len1);
+}
+
+void socket_set_nonblock(int fd)
+{
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+}
+#endif /* !_WIN32 */
+
+#ifndef _WIN32
+
+typedef struct {
+ int fd_in, fd_out;
+ IOCanRWHandler *fd_can_read;
+ IOReadHandler *fd_read;
+ void *fd_opaque;
+ int max_size;
+} FDCharDriver;
+
+#define STDIO_MAX_CLIENTS 2
+
+static int stdio_nb_clients;
+static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
FDCharDriver *s = chr->opaque;
#if defined(__linux__)
CharDriverState *qemu_chr_open_pty(void)
{
+ struct termios tty;
char slave_name[1024];
int master_fd, slave_fd;
if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
return NULL;
}
+
+ /* Disabling local echo and line-buffered output */
+ tcgetattr (master_fd, &tty);
+ tty.c_lflag &= ~(ECHO|ICANON|ISIG);
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VTIME] = 0;
+ tcsetattr (master_fd, TCSAFLUSH, &tty);
+
fprintf(stderr, "char device redirected to %s\n", slave_name);
return qemu_chr_open_fd(master_fd, master_fd);
}
CharDriverState *qemu_chr_open(const char *filename)
{
+#ifndef _WIN32
const char *p;
+#endif
+
if (!strcmp(filename, "vc")) {
return text_console_init(&display_state);
} else if (!strcmp(filename, "null")) {
if (!inet_aton(buf, &saddr->sin_addr))
return -1;
} else {
-#ifdef _WIN32
- return -1;
-#else
if ((he = gethostbyname(buf)) == NULL)
return - 1;
saddr->sin_addr = *(struct in_addr *)he->h_addr;
-#endif
}
}
port = strtol(p, (char **)&r, 0);
return 0;
}
+#endif /* !_WIN32 */
+
/* network connection */
typedef struct NetSocketState {
VLANClientState *vc;
int index;
int packet_len;
uint8_t buf[4096];
+ struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
} NetSocketState;
typedef struct NetSocketListenState {
uint32_t len;
len = htonl(size);
- unix_write(s->fd, (const uint8_t *)&len, sizeof(len));
- unix_write(s->fd, buf, size);
+ send_all(s->fd, (const uint8_t *)&len, sizeof(len));
+ send_all(s->fd, buf, size);
+}
+
+static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
+{
+ NetSocketState *s = opaque;
+ sendto(s->fd, buf, size, 0,
+ (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
}
static void net_socket_send(void *opaque)
{
NetSocketState *s = opaque;
- int l, size;
+ int l, size, err;
uint8_t buf1[4096];
const uint8_t *buf;
- size = read(s->fd, buf1, sizeof(buf1));
- if (size < 0)
- return;
- if (size == 0) {
+ size = recv(s->fd, buf1, sizeof(buf1), 0);
+ if (size < 0) {
+ err = socket_error();
+ if (err != EWOULDBLOCK)
+ goto eoc;
+ } else if (size == 0) {
/* end of connection */
+ eoc:
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+ closesocket(s->fd);
return;
}
buf = buf1;
}
}
+static void net_socket_send_dgram(void *opaque)
+{
+ NetSocketState *s = opaque;
+ int size;
+
+ size = recv(s->fd, s->buf, sizeof(s->buf), 0);
+ if (size < 0)
+ return;
+ if (size == 0) {
+ /* end of connection */
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+ return;
+ }
+ qemu_send_packet(s->vc, s->buf, size);
+}
+
+static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
+{
+ struct ip_mreq imr;
+ int fd;
+ int val, ret;
+ if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
+ fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
+ inet_ntoa(mcastaddr->sin_addr),
+ (int)ntohl(mcastaddr->sin_addr.s_addr));
+ return -1;
+
+ }
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("socket(PF_INET, SOCK_DGRAM)");
+ return -1;
+ }
+
+ val = 1;
+ ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&val, sizeof(val));
+ if (ret < 0) {
+ perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+ goto fail;
+ }
+
+ ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
+ if (ret < 0) {
+ perror("bind");
+ goto fail;
+ }
+
+ /* Add host to multicast group */
+ imr.imr_multiaddr = mcastaddr->sin_addr;
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (const char *)&imr, sizeof(struct ip_mreq));
+ if (ret < 0) {
+ perror("setsockopt(IP_ADD_MEMBERSHIP)");
+ goto fail;
+ }
+
+ /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+ val = 1;
+ ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (const char *)&val, sizeof(val));
+ if (ret < 0) {
+ perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+ goto fail;
+ }
+
+ socket_set_nonblock(fd);
+ return fd;
+fail:
+ if (fd>=0) close(fd);
+ return -1;
+}
+
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
+ int is_connected)
+{
+ struct sockaddr_in saddr;
+ int newfd;
+ socklen_t saddr_len;
+ NetSocketState *s;
+
+ /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
+ * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+ * by ONLY ONE process: we must "clone" this dgram socket --jjo
+ */
+
+ if (is_connected) {
+ if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
+ /* must be bound */
+ if (saddr.sin_addr.s_addr==0) {
+ fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
+ fd);
+ return NULL;
+ }
+ /* clone dgram socket */
+ newfd = net_socket_mcast_create(&saddr);
+ if (newfd < 0) {
+ /* error already reported by net_socket_mcast_create() */
+ close(fd);
+ return NULL;
+ }
+ /* clone newfd to fd, close newfd */
+ dup2(newfd, fd);
+ close(newfd);
+
+ } else {
+ fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
+ fd, strerror(errno));
+ return NULL;
+ }
+ }
+
+ s = qemu_mallocz(sizeof(NetSocketState));
+ if (!s)
+ return NULL;
+ s->fd = fd;
+
+ s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, s);
+ qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
+
+ /* mcast: save bound address as dst */
+ if (is_connected) s->dgram_dst=saddr;
+
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+ "socket: fd=%d (%s mcast=%s:%d)",
+ fd, is_connected? "cloned" : "",
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+ return s;
+}
+
static void net_socket_connect(void *opaque)
{
NetSocketState *s = opaque;
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
}
-static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
int is_connected)
{
NetSocketState *s;
return s;
}
+static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
+ int is_connected)
+{
+ int so_type=-1, optlen=sizeof(so_type);
+
+ if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) {
+ fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd);
+ return NULL;
+ }
+ switch(so_type) {
+ case SOCK_DGRAM:
+ return net_socket_fd_init_dgram(vlan, fd, is_connected);
+ case SOCK_STREAM:
+ return net_socket_fd_init_stream(vlan, fd, is_connected);
+ default:
+ /* who knows ... this could be a eg. a pty, do warn and continue as stream */
+ fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
+ return net_socket_fd_init_stream(vlan, fd, is_connected);
+ }
+ return NULL;
+}
+
static void net_socket_accept(void *opaque)
{
NetSocketListenState *s = opaque;
perror("socket");
return -1;
}
- fcntl(fd, F_SETFL, O_NONBLOCK);
+ socket_set_nonblock(fd);
/* allow fast reuse */
val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
static int net_socket_connect_init(VLANState *vlan, const char *host_str)
{
NetSocketState *s;
- int fd, connected, ret;
+ int fd, connected, ret, err;
struct sockaddr_in saddr;
if (parse_host_port(&saddr, host_str) < 0)
perror("socket");
return -1;
}
- fcntl(fd, F_SETFL, O_NONBLOCK);
+ socket_set_nonblock(fd);
connected = 0;
for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
- if (errno == EINTR || errno == EAGAIN) {
- } else if (errno == EINPROGRESS) {
+ err = socket_error();
+ if (err == EINTR || err == EWOULDBLOCK) {
+ } else if (err == EINPROGRESS) {
break;
} else {
perror("connect");
- close(fd);
+ closesocket(fd);
return -1;
}
} else {
return 0;
}
-#endif /* !_WIN32 */
+static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
+{
+ NetSocketState *s;
+ int fd;
+ struct sockaddr_in saddr;
+
+ if (parse_host_port(&saddr, host_str) < 0)
+ return -1;
+
+
+ fd = net_socket_mcast_create(&saddr);
+ if (fd < 0)
+ return -1;
+
+ s = net_socket_fd_init(vlan, fd, 0);
+ if (!s)
+ return -1;
+
+ s->dgram_dst = saddr;
+
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+ "socket: mcast=%s:%d",
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+ return 0;
+
+}
static int get_param_value(char *buf, int buf_size,
const char *tag, const char *str)
ret = net_slirp_init(vlan);
} else
#endif
-#ifndef _WIN32
+#ifdef _WIN32
+ if (!strcmp(device, "tap")) {
+ char ifname[64];
+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+ fprintf(stderr, "tap: no interface name\n");
+ return -1;
+ }
+ ret = tap_win32_init(vlan, ifname);
+ } else
+#else
if (!strcmp(device, "tap")) {
char ifname[64];
char setup_script[1024];
ret = net_tap_init(vlan, ifname, setup_script);
}
} else
+#endif
if (!strcmp(device, "socket")) {
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
int fd;
ret = net_socket_listen_init(vlan, buf);
} else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
ret = net_socket_connect_init(vlan, buf);
+ } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
+ ret = net_socket_mcast_init(vlan, buf);
} else {
fprintf(stderr, "Unknown socket options: %s\n", p);
return -1;
}
} else
-#endif
{
fprintf(stderr, "Unknown network device: %s\n", device);
return -1;
break;
if (ioh->fd == fd) {
*pioh = ioh->next;
+ qemu_free(ioh);
break;
}
pioh = &ioh->next;
void main_loop_wait(int timeout)
{
-#ifndef _WIN32
- struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf;
IOHandlerRecord *ioh, *ioh_next;
-#endif
- int ret;
+ fd_set rfds, wfds;
+ int ret, nfds;
+ struct timeval tv;
#ifdef _WIN32
- if (timeout > 0)
- Sleep(timeout);
-#else
- /* poll any events */
- /* XXX: separate device handlers from system ones */
- pf = ufds;
- for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
- pf->events = 0;
- pf->fd = ioh->fd;
- if (ioh->fd_read &&
- (!ioh->fd_read_poll ||
- ioh->fd_read_poll(ioh->opaque) != 0)) {
- pf->events |= POLLIN;
- }
- if (ioh->fd_write) {
- pf->events |= POLLOUT;
- }
- ioh->ufd = pf;
- pf++;
+ /* XXX: see how to merge it with the select. The constraint is
+ that the select must be interrupted by the timer */
+ if (timeout > 0)
+ Sleep(timeout);
+#endif
+ /* poll any events */
+ /* XXX: separate device handlers from system ones */
+ nfds = -1;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+ if (ioh->fd_read &&
+ (!ioh->fd_read_poll ||
+ ioh->fd_read_poll(ioh->opaque) != 0)) {
+ FD_SET(ioh->fd, &rfds);
+ if (ioh->fd > nfds)
+ nfds = ioh->fd;
}
-
- ret = poll(ufds, pf - ufds, timeout);
- if (ret > 0) {
- /* XXX: better handling of removal */
- for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
- ioh_next = ioh->next;
- pf = ioh->ufd;
- if (pf->revents & POLLIN) {
- ioh->fd_read(ioh->opaque);
- }
- if (pf->revents & POLLOUT) {
- ioh->fd_write(ioh->opaque);
- }
- }
+ if (ioh->fd_write) {
+ FD_SET(ioh->fd, &wfds);
+ if (ioh->fd > nfds)
+ nfds = ioh->fd;
}
-#endif /* !defined(_WIN32) */
-#if defined(CONFIG_SLIRP)
- /* XXX: merge with poll() */
- if (slirp_inited) {
- fd_set rfds, wfds, xfds;
- int nfds;
- struct timeval tv;
-
- nfds = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
- slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
- if (ret >= 0) {
- slirp_select_poll(&rfds, &wfds, &xfds);
+ }
+
+ tv.tv_sec = 0;
+#ifdef _WIN32
+ tv.tv_usec = 0;
+#else
+ tv.tv_usec = timeout * 1000;
+#endif
+ ret = select(nfds + 1, &rfds, &wfds, NULL, &tv);
+ if (ret > 0) {
+ /* XXX: better handling of removal */
+ for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
+ ioh_next = ioh->next;
+ if (FD_ISSET(ioh->fd, &rfds)) {
+ ioh->fd_read(ioh->opaque);
+ }
+ if (FD_ISSET(ioh->fd, &wfds)) {
+ ioh->fd_write(ioh->opaque);
}
}
+ }
+#ifdef _WIN32
+ tap_win32_poll();
#endif
- if (vm_running) {
- qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
- qemu_get_clock(vm_clock));
- /* run dma transfers, if any */
- DMA_run();
+#if defined(CONFIG_SLIRP)
+ /* XXX: merge with the previous select() */
+ if (slirp_inited) {
+ fd_set rfds, wfds, xfds;
+ int nfds;
+ struct timeval tv;
+
+ nfds = -1;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+ slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+ if (ret >= 0) {
+ slirp_select_poll(&rfds, &wfds, &xfds);
}
+ }
+#endif
- /* real time timers */
- qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
- qemu_get_clock(rt_clock));
+ if (vm_running) {
+ qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+ qemu_get_clock(vm_clock));
+ /* run dma transfers, if any */
+ DMA_run();
+ }
+
+ /* real time timers */
+ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
+ qemu_get_clock(rt_clock));
}
static CPUState *cur_cpu;
"-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n"
"-snapshot write to temporary files instead of disk image files\n"
"-m megs set virtual RAM size to megs MB [default=%d]\n"
+ "-smp n set the number of CPUs to 'n' [default=1]\n"
"-nographic disable graphical output and redirect serial I/Os to console\n"
#ifndef _WIN32
"-k language use keyboard layout (for example \"fr\" for French)\n"
#endif
#ifdef HAS_AUDIO
- "-enable-audio enable audio support, and all the sound cars\n"
"-audio-help print list of audio drivers and their options\n"
"-soundhw c1,... enable audio support\n"
" and only specified sound cards (comma separated list)\n"
" use -soundhw ? to get the list of supported cards\n"
+ " use -soundhw all to enable all of them\n"
#endif
"-localtime set the real time clock to local time [default=utc]\n"
"-full-screen start in full screen\n"
"-net user[,vlan=n]\n"
" connect the user mode network stack to VLAN 'n'\n"
#endif
-#ifndef _WIN32
+#ifdef _WIN32
+ "-net tap[,vlan=n],ifname=name\n"
+ " connect the host TAP network interface to VLAN 'n'\n"
+#else
"-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n"
" connect the host TAP network interface to VLAN 'n' and use\n"
" the network script 'file' (default=%s);\n"
" use 'fd=h' to connect to an already opened TAP interface\n"
+#endif
"-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
" connect the vlan 'n' to another VLAN using a socket connection\n"
-#endif
+ "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n"
+ " connect the vlan 'n' to multicast maddr and port\n"
"-net none use it alone to have zero network devices; if no -net option\n"
" is provided, the default is '-net nic -net user'\n"
"\n"
QEMU_OPTION_m,
QEMU_OPTION_nographic,
#ifdef HAS_AUDIO
- QEMU_OPTION_enable_audio,
QEMU_OPTION_audio_help,
QEMU_OPTION_soundhw,
#endif
{ "nographic", 0, QEMU_OPTION_nographic },
{ "k", HAS_ARG, QEMU_OPTION_k },
#ifdef HAS_AUDIO
- { "enable-audio", 0, QEMU_OPTION_enable_audio },
{ "audio-help", 0, QEMU_OPTION_audio_help },
{ "soundhw", HAS_ARG, QEMU_OPTION_soundhw },
#endif
}
#ifdef HAS_AUDIO
-static void select_soundhw (const char *optarg)
-{
- if (*optarg == '?') {
- show_valid_cards:
- printf ("Valid sound card names (comma separated):\n");
- printf ("sb16 Creative Sound Blaster 16\n");
+struct soundhw soundhw[] = {
+ {
+ "sb16",
+ "Creative Sound Blaster 16",
+ 0,
+ 1,
+ { .init_isa = SB16_init }
+ },
+
#ifdef CONFIG_ADLIB
+ {
+ "adlib",
#ifdef HAS_YMF262
- printf ("adlib Yamaha YMF262 (OPL3)\n");
+ "Yamaha YMF262 (OPL3)",
#else
- printf ("adlib Yamaha YM3812 (OPL2)\n");
+ "Yamaha YM3812 (OPL2)",
#endif
+ 0,
+ 1,
+ { .init_isa = Adlib_init }
+ },
#endif
+
#ifdef CONFIG_GUS
- printf ("gus Gravis Ultrasound GF1\n");
+ {
+ "gus",
+ "Gravis Ultrasound GF1",
+ 0,
+ 1,
+ { .init_isa = GUS_init }
+ },
#endif
- printf ("es1370 ENSONIQ AudioPCI ES1370\n");
+
+ {
+ "es1370",
+ "ENSONIQ AudioPCI ES1370",
+ 0,
+ 0,
+ { .init_pci = es1370_init }
+ },
+
+ { NULL, NULL, 0, 0, { NULL } }
+};
+
+static void select_soundhw (const char *optarg)
+{
+ struct soundhw *c;
+
+ if (*optarg == '?') {
+ show_valid_cards:
+
+ printf ("Valid sound card names (comma separated):\n");
+ for (c = soundhw; c->name; ++c) {
+ printf ("%-11s %s\n", c->name, c->descr);
+ }
+ printf ("\n-soundhw all will enable all of the above\n");
exit (*optarg != '?');
}
else {
- struct {
- char *name;
- int *enabledp;
- } soundhw_tab[] = {
- { "sb16", &sb16_enabled },
-#ifdef CONFIG_ADLIB
- { "adlib", &adlib_enabled },
-#endif
-#ifdef CONFIG_GUS
- { "gus", &gus_enabled },
-#endif
- { "es1370", &es1370_enabled },
- };
- size_t tablen, l, i;
+ size_t l;
const char *p;
char *e;
int bad_card = 0;
- p = optarg;
- tablen = sizeof (soundhw_tab) / sizeof (soundhw_tab[0]);
+ if (!strcmp (optarg, "all")) {
+ for (c = soundhw; c->name; ++c) {
+ c->enabled = 1;
+ }
+ return;
+ }
+ p = optarg;
while (*p) {
e = strchr (p, ',');
l = !e ? strlen (p) : (size_t) (e - p);
- for (i = 0; i < tablen; ++i) {
- if (!strncmp (soundhw_tab[i].name, p, l)) {
- audio_enabled = 1;
- *soundhw_tab[i].enabledp = 1;
+
+ for (c = soundhw; c->name; ++c) {
+ if (!strncmp (c->name, p, l)) {
+ c->enabled = 1;
break;
}
}
- if (i == tablen) {
+
+ if (!c->name) {
if (l > 80) {
fprintf (stderr,
"Unknown sound card name (too big to show)\n");
break;
#endif
#ifdef HAS_AUDIO
- case QEMU_OPTION_enable_audio:
- audio_enabled = 1;
- sb16_enabled = 1;
- adlib_enabled = 1;
- gus_enabled = 1;
- es1370_enabled = 1;
- break;
case QEMU_OPTION_audio_help:
AUD_help ();
exit (0);
break;
case QEMU_OPTION_smp:
smp_cpus = atoi(optarg);
- if (smp_cpus < 1 || smp_cpus > 8) {
+ if (smp_cpus < 1 || smp_cpus > MAX_CPUS) {
fprintf(stderr, "Invalid number of CPUs\n");
exit(1);
}
}
}
+#ifdef USE_KQEMU
+ if (smp_cpus > 1)
+ kqemu_allowed = 0;
+#endif
linux_boot = (kernel_filename != NULL);
if (!linux_boot &&
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
+#ifdef _WIN32
+ socket_init();
+#endif
+
/* init network clients */
if (nb_net_clients == 0) {
/* if no clients, we use a default config */