Add quotes missing from previous patch.
[qemu] / vl.c
diff --git a/vl.c b/vl.c
index 3a99cbd..4f9b8c8 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -137,7 +137,6 @@ int graphic_height = 600;
 #endif
 int graphic_depth = 15;
 int full_screen = 0;
-TextConsole *vga_console;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 #ifdef TARGET_I386
@@ -475,6 +474,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_event;
 static void *qemu_put_kbd_event_opaque;
 static QEMUPutMouseEvent *qemu_put_mouse_event;
 static void *qemu_put_mouse_event_opaque;
+static int qemu_put_mouse_event_absolute;
 
 void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
 {
@@ -482,10 +482,11 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
     qemu_put_kbd_event = func;
 }
 
-void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque)
+void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute)
 {
     qemu_put_mouse_event_opaque = opaque;
     qemu_put_mouse_event = func;
+    qemu_put_mouse_event_absolute = absolute;
 }
 
 void kbd_put_keycode(int keycode)
@@ -503,6 +504,11 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
     }
 }
 
+int kbd_mouse_is_absolute(void)
+{
+    return qemu_put_mouse_event_absolute;
+}
+
 /***********************************************************/
 /* timers */
 
@@ -1714,11 +1720,381 @@ CharDriverState *qemu_chr_open_pty(void)
 
 #endif /* !defined(_WIN32) */
 
+#ifdef _WIN32
+typedef struct {
+    IOCanRWHandler *fd_can_read; 
+    IOReadHandler *fd_read;
+    void *win_opaque;
+    int max_size;
+    HANDLE hcom, hrecv, hsend;
+    OVERLAPPED orecv, osend;
+    BOOL fpipe;
+    DWORD len;
+} WinCharState;
+
+#define NSENDBUF 2048
+#define NRECVBUF 2048
+#define MAXCONNECT 1
+#define NTIMEOUT 5000
+
+static int win_chr_poll(void *opaque);
+static int win_chr_pipe_poll(void *opaque);
+
+static void win_chr_close2(WinCharState *s)
+{
+    if (s->hsend) {
+        CloseHandle(s->hsend);
+        s->hsend = NULL;
+    }
+    if (s->hrecv) {
+        CloseHandle(s->hrecv);
+        s->hrecv = NULL;
+    }
+    if (s->hcom) {
+        CloseHandle(s->hcom);
+        s->hcom = NULL;
+    }
+    if (s->fpipe)
+        qemu_del_polling_cb(win_chr_pipe_poll, s);
+    else
+        qemu_del_polling_cb(win_chr_poll, s);
+}
+
+static void win_chr_close(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+    win_chr_close2(s);
+}
+
+static int win_chr_init(WinCharState *s, const char *filename)
+{
+    COMMCONFIG comcfg;
+    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
+    COMSTAT comstat;
+    DWORD size;
+    DWORD err;
+    
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+    
+    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
+        fprintf(stderr, "Failed SetupComm\n");
+        goto fail;
+    }
+    
+    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
+    size = sizeof(COMMCONFIG);
+    GetDefaultCommConfig(filename, &comcfg, &size);
+    comcfg.dcb.DCBlength = sizeof(DCB);
+    CommConfigDialog(filename, NULL, &comcfg);
+
+    if (!SetCommState(s->hcom, &comcfg.dcb)) {
+        fprintf(stderr, "Failed SetCommState\n");
+        goto fail;
+    }
+
+    if (!SetCommMask(s->hcom, EV_ERR)) {
+        fprintf(stderr, "Failed SetCommMask\n");
+        goto fail;
+    }
+
+    cto.ReadIntervalTimeout = MAXDWORD;
+    if (!SetCommTimeouts(s->hcom, &cto)) {
+        fprintf(stderr, "Failed SetCommTimeouts\n");
+        goto fail;
+    }
+    
+    if (!ClearCommError(s->hcom, &err, &comstat)) {
+        fprintf(stderr, "Failed ClearCommError\n");
+        goto fail;
+    }
+    qemu_add_polling_cb(win_chr_poll, s);
+    return 0;
+
+ fail:
+    win_chr_close2(s);
+    return -1;
+}
+
+static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+{
+    WinCharState *s = chr->opaque;
+    DWORD len, ret, size, err;
+
+    len = len1;
+    ZeroMemory(&s->osend, sizeof(s->osend));
+    s->osend.hEvent = s->hsend;
+    while (len > 0) {
+        if (s->hsend)
+            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
+        else
+            ret = WriteFile(s->hcom, buf, len, &size, NULL);
+        if (!ret) {
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
+                if (ret) {
+                    buf += size;
+                    len -= size;
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        } else {
+            buf += size;
+            len -= size;
+        }
+    }
+    return len1 - len;
+}
+
+static int win_chr_read_poll(WinCharState *s)
+{
+    s->max_size = s->fd_can_read(s->win_opaque);
+    return s->max_size;
+}
+            
+static void win_chr_readfile(WinCharState *s)
+{
+    int ret, err;
+    uint8_t buf[1024];
+    DWORD size;
+    
+    ZeroMemory(&s->orecv, sizeof(s->orecv));
+    s->orecv.hEvent = s->hrecv;
+    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+        }
+    }
+
+    if (size > 0) {
+        s->fd_read(s->win_opaque, buf, size);
+    }
+}
+
+static void win_chr_read(WinCharState *s)
+{
+    if (s->len > s->max_size)
+        s->len = s->max_size;
+    if (s->len == 0)
+        return;
+    
+    win_chr_readfile(s);
+}
+
+static int win_chr_poll(void *opaque)
+{
+    WinCharState *s = opaque;
+    COMSTAT status;
+    DWORD comerr;
+    
+    ClearCommError(s->hcom, &comerr, &status);
+    if (status.cbInQue > 0) {
+        s->len = status.cbInQue;
+        win_chr_read_poll(s);
+        win_chr_read(s);
+        return 1;
+    }
+    return 0;
+}
+
+static void win_chr_add_read_handler(CharDriverState *chr, 
+                                    IOCanRWHandler *fd_can_read, 
+                                    IOReadHandler *fd_read, void *opaque)
+{
+    WinCharState *s = chr->opaque;
+
+    s->fd_can_read = fd_can_read;
+    s->fd_read = fd_read;
+    s->win_opaque = opaque;
+}
+
+CharDriverState *qemu_chr_open_win(const char *filename)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+    
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    s = qemu_mallocz(sizeof(WinCharState));
+    if (!s) {
+        free(chr);
+        return NULL;
+    }
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_add_read_handler = win_chr_add_read_handler;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_init(s, filename) < 0) {
+        free(s);
+        free(chr);
+        return NULL;
+    }
+    return chr;
+}
+
+static int win_chr_pipe_poll(void *opaque)
+{
+    WinCharState *s = opaque;
+    DWORD size;
+
+    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
+    if (size > 0) {
+        s->len = size;
+        win_chr_read_poll(s);
+        win_chr_read(s);
+        return 1;
+    }
+    return 0;
+}
+
+static int win_chr_pipe_init(WinCharState *s, const char *filename)
+{
+    OVERLAPPED ov;
+    int ret;
+    DWORD size;
+    char openname[256];
+    
+    s->fpipe = TRUE;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    
+    snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
+    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
+                              PIPE_WAIT,
+                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    ZeroMemory(&ov, sizeof(ov));
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ret = ConnectNamedPipe(s->hcom, &ov);
+    if (ret) {
+        fprintf(stderr, "Failed ConnectNamedPipe\n");
+        goto fail;
+    }
+
+    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
+    if (!ret) {
+        fprintf(stderr, "Failed GetOverlappedResult\n");
+        if (ov.hEvent) {
+            CloseHandle(ov.hEvent);
+            ov.hEvent = NULL;
+        }
+        goto fail;
+    }
+
+    if (ov.hEvent) {
+        CloseHandle(ov.hEvent);
+        ov.hEvent = NULL;
+    }
+    qemu_add_polling_cb(win_chr_pipe_poll, s);
+    return 0;
+
+ fail:
+    win_chr_close2(s);
+    return -1;
+}
+
+
+CharDriverState *qemu_chr_open_win_pipe(const char *filename)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    s = qemu_mallocz(sizeof(WinCharState));
+    if (!s) {
+        free(chr);
+        return NULL;
+    }
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_add_read_handler = win_chr_add_read_handler;
+    chr->chr_close = win_chr_close;
+    
+    if (win_chr_pipe_init(s, filename) < 0) {
+        free(s);
+        free(chr);
+        return NULL;
+    }
+    return chr;
+}
+
+CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    s = qemu_mallocz(sizeof(WinCharState));
+    if (!s) {
+        free(chr);
+        return NULL;
+    }
+    s->hcom = fd_out;
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_add_read_handler = win_chr_add_read_handler;
+    return chr;
+}
+    
+CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
+{
+    HANDLE fd_out;
+    
+    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (fd_out == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    return qemu_chr_open_win_file(fd_out);
+}
+#endif
+
 CharDriverState *qemu_chr_open(const char *filename)
 {
-#ifndef _WIN32
     const char *p;
-#endif
 
     if (!strcmp(filename, "vc")) {
         return text_console_init(&display_state);
@@ -1744,11 +2120,28 @@ CharDriverState *qemu_chr_open(const char *filename)
         return qemu_chr_open_tty(filename);
     } else 
 #endif
+#ifdef _WIN32
+    if (strstart(filename, "COM", NULL)) {
+        return qemu_chr_open_win(filename);
+    } else
+    if (strstart(filename, "pipe:", &p)) {
+        return qemu_chr_open_win_pipe(p);
+    } else
+    if (strstart(filename, "file:", &p)) {
+        return qemu_chr_open_win_file_out(p);
+    }
+#endif
     {
         return NULL;
     }
 }
 
+void qemu_chr_close(CharDriverState *chr)
+{
+    if (chr->chr_close)
+        chr->chr_close(chr);
+}
+
 /***********************************************************/
 /* network device redirectors */
 
@@ -2758,6 +3151,11 @@ int net_client_init(const char *str)
     } else
 #ifdef CONFIG_SLIRP
     if (!strcmp(device, "user")) {
+        if (get_param_value(buf, sizeof(buf), "hostname", p)) {
+            if (strlen(buf) > 32)
+              buf[32] = 0;
+            strcpy(slirp_hostname, buf);
+        }
         ret = net_slirp_init(vlan);
     } else
 #endif
@@ -2856,6 +3254,10 @@ static int usb_device_add(const char *devname)
         dev = usb_mouse_init();
         if (!dev)
             return -1;
+    } else if (!strcmp(devname, "tablet")) {
+       dev = usb_tablet_init();
+       if (!dev)
+           return -1;
     } else {
         return -1;
     }
@@ -2994,7 +3396,7 @@ static void dumb_resize(DisplayState *ds, int w, int h)
 
 static void dumb_refresh(DisplayState *ds)
 {
-    vga_update_display();
+    vga_hw_update();
 }
 
 void dumb_display_init(DisplayState *ds)
@@ -3091,6 +3493,43 @@ int qemu_set_fd_handler(int fd,
 }
 
 /***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+    PollingFunc *func;
+    void *opaque;
+    struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    pe = qemu_mallocz(sizeof(PollingEntry));
+    if (!pe)
+        return -1;
+    pe->func = func;
+    pe->opaque = opaque;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+    *ppe = pe;
+    return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+        pe = *ppe;
+        if (pe->func == func && pe->opaque == opaque) {
+            *ppe = pe->next;
+            qemu_free(pe);
+            break;
+        }
+    }
+}
+
+/***********************************************************/
 /* savevm/loadvm support */
 
 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
@@ -3956,12 +4395,18 @@ void main_loop_wait(int timeout)
     fd_set rfds, wfds;
     int ret, nfds;
     struct timeval tv;
+    PollingEntry *pe;
 
+
+    /* XXX: need to suppress polling by better using win32 events */
+    ret = 0;
+    for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
+        ret |= pe->func(pe->opaque);
+    }
 #ifdef _WIN32
-    /* XXX: see how to merge it with the select. The constraint is
-       that the select must be interrupted by the timer */
-    if (timeout > 0)
+    if (ret == 0 && timeout > 0) {
         Sleep(timeout);
+    }
 #endif
     /* poll any events */
     /* XXX: separate device handlers from system ones */
@@ -4157,8 +4602,9 @@ void help(void)
            "-net nic[,vlan=n][,macaddr=addr][,model=type]\n"
            "                create a new Network Interface Card and connect it to VLAN 'n'\n"
 #ifdef CONFIG_SLIRP
-           "-net user[,vlan=n]\n"
-           "                connect the user mode network stack to VLAN 'n'\n"
+           "-net user[,vlan=n][,hostname=host]\n"
+           "                connect the user mode network stack to VLAN 'n' and send\n"
+           "                hostname 'host' to DHCP clients\n"
 #endif
 #ifdef _WIN32
            "-net tap[,vlan=n],ifname=name\n"
@@ -4437,6 +4883,7 @@ void register_machines(void)
 #elif defined(TARGET_ARM)
     qemu_register_machine(&integratorcp926_machine);
     qemu_register_machine(&integratorcp1026_machine);
+    qemu_register_machine(&versatilepb_machine);
 #else
 #error unsupported CPU
 #endif
@@ -5123,8 +5570,6 @@ int main(int argc, char **argv)
 #endif
     }
 
-    vga_console = graphic_console_init(ds);
-    
     monitor_hd = qemu_chr_open(monitor_device);
     if (!monitor_hd) {
         fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);