fixed refresh logic (initial patch by Igor Kovalenko)
[qemu] / vl.c
diff --git a/vl.c b/vl.c
index 118a1e2..b31b239 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -482,114 +482,105 @@ int kbd_mouse_is_absolute(void)
     return qemu_put_mouse_event_absolute;
 }
 
-/***********************************************************/
-/* timers */
-
-#if defined(__powerpc__)
-
-static inline uint32_t get_tbl(void) 
+/* compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
 {
-    uint32_t tbl;
-    asm volatile("mftb %0" : "=r" (tbl));
-    return tbl;
-}
+    union {
+        uint64_t ll;
+        struct {
+#ifdef WORDS_BIGENDIAN
+            uint32_t high, low;
+#else
+            uint32_t low, high;
+#endif            
+        } l;
+    } u, res;
+    uint64_t rl, rh;
 
-static inline uint32_t get_tbu(void) 
-{
-       uint32_t tbl;
-       asm volatile("mftbu %0" : "=r" (tbl));
-       return tbl;
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
 }
 
-int64_t cpu_get_real_ticks(void)
-{
-    uint32_t l, h, h1;
-    /* NOTE: we test if wrapping has occurred */
-    do {
-        h = get_tbu();
-        l = get_tbl();
-        h1 = get_tbu();
-    } while (h != h1);
-    return ((int64_t)h << 32) | l;
-}
+/***********************************************************/
+/* real time host monotonic timer */
 
-#elif defined(__i386__)
+#define QEMU_TIMER_BASE 1000000000LL
 
-int64_t cpu_get_real_ticks(void)
-{
-#ifdef _WIN32
-    LARGE_INTEGER ti;
-    QueryPerformanceCounter(&ti);
-    return ti.QuadPart;
-#else
-    int64_t val;
-    asm volatile ("rdtsc" : "=A" (val));
-    return val;
-#endif
-}
+#ifdef WIN32
 
-#elif defined(__x86_64__)
+static int64_t clock_freq;
 
-int64_t cpu_get_real_ticks(void)
+static void init_get_clock(void)
 {
-    uint32_t low,high;
-    int64_t val;
-    asm volatile("rdtsc" : "=a" (low), "=d" (high));
-    val = high;
-    val <<= 32;
-    val |= low;
-    return val;
+    LARGE_INTEGER freq;
+    int ret;
+    ret = QueryPerformanceFrequency(&freq);
+    if (ret == 0) {
+        fprintf(stderr, "Could not calibrate ticks\n");
+        exit(1);
+    }
+    clock_freq = freq.QuadPart;
 }
 
-#elif defined(__ia64)
-
-int64_t cpu_get_real_ticks(void)
+static int64_t get_clock(void)
 {
-       int64_t val;
-       asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
-       return val;
+    LARGE_INTEGER ti;
+    QueryPerformanceCounter(&ti);
+    return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
 }
 
-#elif defined(__s390__)
+#else
 
-int64_t cpu_get_real_ticks(void)
+static int use_rt_clock;
+
+static void init_get_clock(void)
 {
-    int64_t val;
-    asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
-    return val;
+    use_rt_clock = 0;
+#if defined(__linux__)
+    {
+        struct timespec ts;
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+            use_rt_clock = 1;
+        }
+    }
+#endif
 }
 
-#elif defined(__sparc__) && defined(HOST_SOLARIS)
-
-uint64_t cpu_get_real_ticks (void)
+static int64_t get_clock(void)
 {
-#if     defined(_LP64)
-        uint64_t        rval;
-        asm volatile("rd %%tick,%0" : "=r"(rval));
-        return rval;
-#else
-        union {
-                uint64_t i64;
-                struct {
-                        uint32_t high;
-                        uint32_t low;
-                }       i32;
-        } rval;
-        asm volatile("rd %%tick,%1; srlx %1,32,%0"
-                : "=r"(rval.i32.high), "=r"(rval.i32.low));
-        return rval.i64;
+#if defined(__linux__)
+    if (use_rt_clock) {
+        struct timespec ts;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+    } else 
 #endif
+    {
+        /* XXX: using gettimeofday leads to problems if the date
+           changes, so it should be avoided. */
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+    }
 }
 
-#else
-#error unsupported CPU
 #endif
 
+/***********************************************************/
+/* guest cycle counter */
+
 static int64_t cpu_ticks_prev;
 static int64_t cpu_ticks_offset;
+static int64_t cpu_clock_offset;
 static int cpu_ticks_enabled;
 
-static inline int64_t cpu_get_ticks(void)
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
 {
     if (!cpu_ticks_enabled) {
         return cpu_ticks_offset;
@@ -606,11 +597,24 @@ static inline int64_t cpu_get_ticks(void)
     }
 }
 
+/* return the host CPU monotonic timer and handle stop/restart */
+static int64_t cpu_get_clock(void)
+{
+    int64_t ti;
+    if (!cpu_ticks_enabled) {
+        return cpu_clock_offset;
+    } else {
+        ti = get_clock();
+        return ti + cpu_clock_offset;
+    }
+}
+
 /* enable cpu_get_ticks() */
 void cpu_enable_ticks(void)
 {
     if (!cpu_ticks_enabled) {
         cpu_ticks_offset -= cpu_get_real_ticks();
+        cpu_clock_offset -= get_clock();
         cpu_ticks_enabled = 1;
     }
 }
@@ -621,69 +625,14 @@ void cpu_disable_ticks(void)
 {
     if (cpu_ticks_enabled) {
         cpu_ticks_offset = cpu_get_ticks();
+        cpu_clock_offset = cpu_get_clock();
         cpu_ticks_enabled = 0;
     }
 }
 
-#ifdef _WIN32
-void cpu_calibrate_ticks(void)
-{
-    LARGE_INTEGER freq;
-    int ret;
-
-    ret = QueryPerformanceFrequency(&freq);
-    if (ret == 0) {
-        fprintf(stderr, "Could not calibrate ticks\n");
-        exit(1);
-    }
-    ticks_per_sec = freq.QuadPart;
-}
-
-#else
-static int64_t get_clock(void)
-{
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return tv.tv_sec * 1000000LL + tv.tv_usec;
-}
-
-void cpu_calibrate_ticks(void)
-{
-    int64_t usec, ticks;
-
-    usec = get_clock();
-    ticks = cpu_get_real_ticks();
-    usleep(50 * 1000);
-    usec = get_clock() - usec;
-    ticks = cpu_get_real_ticks() - ticks;
-    ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec;
-}
-#endif /* !_WIN32 */
-
-/* compute with 96 bit intermediate result: (a*b)/c */
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
-{
-    union {
-        uint64_t ll;
-        struct {
-#ifdef WORDS_BIGENDIAN
-            uint32_t high, low;
-#else
-            uint32_t low, high;
-#endif            
-        } l;
-    } u, res;
-    uint64_t rl, rh;
-
-    u.ll = a;
-    rl = (uint64_t)u.l.low * (uint64_t)b;
-    rh = (uint64_t)u.l.high * (uint64_t)b;
-    rh += (rl >> 32);
-    res.l.high = rh / c;
-    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
-    return res.ll;
-}
-
+/***********************************************************/
+/* timers */
 #define QEMU_TIMER_REALTIME 0
 #define QEMU_TIMER_VIRTUAL  1
 
@@ -822,28 +771,21 @@ int64_t qemu_get_clock(QEMUClock *clock)
 {
     switch(clock->type) {
     case QEMU_TIMER_REALTIME:
-#ifdef _WIN32
-        return GetTickCount();
-#else
-        {
-            struct tms tp;
-
-            /* Note that using gettimeofday() is not a good solution
-               for timers because its value change when the date is
-               modified. */
-            if (timer_freq == 100) {
-                return times(&tp) * 10;
-            } else {
-                return ((int64_t)times(&tp) * 1000) / timer_freq;
-            }
-        }
-#endif
+        return get_clock() / 1000000;
     default:
     case QEMU_TIMER_VIRTUAL:
-        return cpu_get_ticks();
+        return cpu_get_clock();
     }
 }
 
+static void init_timers(void)
+{
+    init_get_clock();
+    ticks_per_sec = QEMU_TIMER_BASE;
+    rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
+    vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
+}
+
 /* save a timer */
 void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
 {
@@ -912,7 +854,7 @@ static void host_alarm_handler(int host_signum)
                 delta_max = delta;
             delta_cum += delta;
             if (++count == DISP_FREQ) {
-                printf("timer: min=%lld us max=%lld us avg=%lld us avg_freq=%0.3f Hz\n",
+                printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
                        muldiv64(delta_min, 1000000, ticks_per_sec),
                        muldiv64(delta_max, 1000000, ticks_per_sec),
                        muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec),
@@ -985,11 +927,8 @@ static int start_rtc_timer(void)
 
 #endif /* !defined(_WIN32) */
 
-static void init_timers(void)
+static void init_timer_alarm(void)
 {
-    rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
-    vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
-
 #ifdef _WIN32
     {
         int count=0;
@@ -1354,7 +1293,9 @@ CharDriverState *qemu_chr_open_pipe(const char *filename)
 
 static int term_got_escape, client_index;
 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
-int term_fifo_size;
+static int term_fifo_size;
+static int term_timestamps;
+static int64_t term_timestamps_start;
 
 void term_print_help(void)
 {
@@ -1363,6 +1304,7 @@ void term_print_help(void)
            "C-a x    exit emulator\n"
            "C-a s    save disk data back to file (if -snapshot)\n"
            "C-a b    send break (magic sysrq)\n"
+           "C-a t    toggle console timestamps\n"
            "C-a c    switch between console and monitor\n"
            "C-a C-a  send C-a\n"
            );
@@ -1409,6 +1351,10 @@ static void stdio_received_byte(int ch)
                 goto send_char;
             }
             break;
+        case 't':
+            term_timestamps = !term_timestamps;
+            term_timestamps_start = -1;
+            break;
         case TERM_ESCAPE:
             goto send_char;
         }
@@ -1466,6 +1412,39 @@ static void stdio_read(void *opaque)
         stdio_received_byte(buf[0]);
 }
 
+static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    FDCharDriver *s = chr->opaque;
+    if (!term_timestamps) {
+        return unix_write(s->fd_out, buf, len);
+    } else {
+        int i;
+        char buf1[64];
+
+        for(i = 0; i < len; i++) {
+            unix_write(s->fd_out, buf + i, 1);
+            if (buf[i] == '\n') {
+                int64_t ti;
+                int secs;
+
+                ti = get_clock();
+                if (term_timestamps_start == -1)
+                    term_timestamps_start = ti;
+                ti -= term_timestamps_start;
+                secs = ti / 1000000000;
+                snprintf(buf1, sizeof(buf1), 
+                         "[%02d:%02d:%02d.%03d] ",
+                         secs / 3600,
+                         (secs / 60) % 60,
+                         secs % 60,
+                         (int)((ti / 1000000) % 1000));
+                unix_write(s->fd_out, buf1, strlen(buf1));
+            }
+        }
+        return len;
+    }
+}
+
 /* init terminal so that we can grab keys */
 static struct termios oldtty;
 static int old_fd0_flags;
@@ -1511,6 +1490,7 @@ CharDriverState *qemu_chr_open_stdio(void)
         if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
             return NULL;
         chr = qemu_chr_open_fd(0, 1);
+        chr->chr_write = stdio_write;
         if (stdio_nb_clients == 0)
             qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
         client_index = stdio_nb_clients;
@@ -2203,16 +2183,16 @@ static void udp_chr_add_read_handler(CharDriverState *chr,
 }
 
 int parse_host_port(struct sockaddr_in *saddr, const char *str);
+int parse_host_src_port(struct sockaddr_in *haddr,
+                        struct sockaddr_in *saddr,
+                        const char *str);
 
 CharDriverState *qemu_chr_open_udp(const char *def)
 {
     CharDriverState *chr = NULL;
     NetCharDriver *s = NULL;
     int fd = -1;
-    int con_type;
-    struct sockaddr_in addr;
-    const char *p, *r;
-    int port;
+    struct sockaddr_in saddr;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
     if (!chr)
@@ -2227,58 +2207,12 @@ CharDriverState *qemu_chr_open_udp(const char *def)
         goto return_err;
     }
 
-    /* There are three types of port definitions
-     * 1) udp:remote_port
-     *    Juse use 0.0.0.0 for the IP and send to remote
-     * 2) udp:remote_host:port
-     *    Use a IP and send traffic to remote
-     * 3) udp:local_port:remote_host:remote_port
-     *    Use local_port as the originator + #2
-     */
-    con_type = 0;
-    p = def;
-    while ((p = strchr(p, ':'))) {
-        p++;
-        con_type++;
-    }
-
-    p = def;
-    memset(&addr,0,sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    s->daddr.sin_family = AF_INET;
-    s->daddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    switch (con_type) {
-        case 0:
-            port = strtol(p, (char **)&r, 0);
-            if (r == p) {
-                fprintf(stderr, "Error parsing port number\n");
-                goto return_err;
-            }
-            s->daddr.sin_port = htons((short)port);
-            break;
-        case 2:
-            port = strtol(p, (char **)&r, 0);
-            if (r == p) {
-                fprintf(stderr, "Error parsing port number\n");
-                goto return_err;
-            }
-            addr.sin_port = htons((short)port);
-            p = r + 1;
-            /* Fall through to case 1 now that we have the local port */
-        case 1:
-            if (parse_host_port(&s->daddr, p) < 0) {
-                fprintf(stderr, "Error parsing host name and port\n");
-                goto return_err;
-            }
-            break;
-        default:
-            fprintf(stderr, "Too many ':' characters\n");
-            goto return_err;
+    if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
+        printf("Could not parse: %s\n", def);
+        goto return_err;
     }
 
-    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+    if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
     {
         perror("bind");
         goto return_err;
@@ -2312,6 +2246,7 @@ typedef struct {
     int fd, listen_fd;
     int connected;
     int max_size;
+    int do_telnetopt;
 } TCPCharDriver;
 
 static void tcp_chr_accept(void *opaque);
@@ -2337,6 +2272,56 @@ static int tcp_chr_read_poll(void *opaque)
     return s->max_size;
 }
 
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+                                      TCPCharDriver *s,
+                                      char *buf, int *size)
+{
+    /* Handle any telnet client's basic IAC options to satisfy char by
+     * char mode with no echo.  All IAC options will be removed from
+     * the buf and the do_telnetopt variable will be used to track the
+     * state of the width of the IAC information.
+     *
+     * IAC commands come in sets of 3 bytes with the exception of the
+     * "IAC BREAK" command and the double IAC.
+     */
+
+    int i;
+    int j = 0;
+
+    for (i = 0; i < *size; i++) {
+        if (s->do_telnetopt > 1) {
+            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+                /* Double IAC means send an IAC */
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+                s->do_telnetopt = 1;
+            } else {
+                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+                    /* Handle IAC break commands by sending a serial break */
+                    chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
+                    s->do_telnetopt++;
+                }
+                s->do_telnetopt++;
+            }
+            if (s->do_telnetopt >= 4) {
+                s->do_telnetopt = 1;
+            }
+        } else {
+            if ((unsigned char)buf[i] == IAC) {
+                s->do_telnetopt = 2;
+            } else {
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+            }
+        }
+    }
+    *size = j;
+}
+
 static void tcp_chr_read(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2360,7 +2345,10 @@ static void tcp_chr_read(void *opaque)
         closesocket(s->fd);
         s->fd = -1;
     } else if (size > 0) {
-        s->fd_read(s->fd_opaque, buf, size);
+        if (s->do_telnetopt)
+            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+        if (size > 0)
+            s->fd_read(s->fd_opaque, buf, size);
     }
 }
 
@@ -2385,6 +2373,21 @@ static void tcp_chr_connect(void *opaque)
                          tcp_chr_read, NULL, chr);
 }
 
+#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+static void tcp_chr_telnet_init(int fd)
+{
+    char buf[3];
+    /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+    IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+    send(fd, (char *)buf, 3, 0);
+}
+
 static void tcp_chr_accept(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2399,6 +2402,8 @@ static void tcp_chr_accept(void *opaque)
         if (fd < 0 && errno != EINTR) {
             return;
         } else if (fd >= 0) {
+            if (s->do_telnetopt)
+                tcp_chr_telnet_init(fd);
             break;
         }
     }
@@ -2419,16 +2424,34 @@ static void tcp_chr_close(CharDriverState *chr)
 }
 
 static CharDriverState *qemu_chr_open_tcp(const char *host_str, 
-                                          int is_listen)
+                                          int is_telnet)
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
     int fd = -1, ret, err, val;
+    int is_listen = 0;
+    int is_waitconnect = 1;
+    const char *ptr;
     struct sockaddr_in saddr;
 
     if (parse_host_port(&saddr, host_str) < 0)
         goto fail;
 
+    ptr = host_str;
+    while((ptr = strchr(ptr,','))) {
+        ptr++;
+        if (!strncmp(ptr,"server",6)) {
+            is_listen = 1;
+        } else if (!strncmp(ptr,"nowait",6)) {
+            is_waitconnect = 0;
+        } else {
+            printf("Unknown option: %s\n", ptr);
+            goto fail;
+        }
+    }
+    if (!is_listen)
+        is_waitconnect = 0;
+
     chr = qemu_mallocz(sizeof(CharDriverState));
     if (!chr)
         goto fail;
@@ -2439,7 +2462,9 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     fd = socket(PF_INET, SOCK_STREAM, 0);
     if (fd < 0) 
         goto fail;
-    socket_set_nonblock(fd);
+
+    if (!is_waitconnect)
+        socket_set_nonblock(fd);
 
     s->connected = 0;
     s->fd = -1;
@@ -2457,6 +2482,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
             goto fail;
         s->listen_fd = fd;
         qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        if (is_telnet)
+            s->do_telnetopt = 1;
     } else {
         for(;;) {
             ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
@@ -2484,6 +2511,12 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     chr->chr_write = tcp_chr_write;
     chr->chr_add_read_handler = tcp_chr_add_read_handler;
     chr->chr_close = tcp_chr_close;
+    if (is_listen && is_waitconnect) {
+        printf("QEMU waiting for connection on: %s\n", host_str);
+        tcp_chr_accept(chr);
+        socket_set_nonblock(s->listen_fd);
+    }
+
     return chr;
  fail:
     if (fd >= 0)
@@ -2505,7 +2538,7 @@ CharDriverState *qemu_chr_open(const char *filename)
     if (strstart(filename, "tcp:", &p)) {
         return qemu_chr_open_tcp(p, 0);
     } else
-    if (strstart(filename, "tcpl:", &p)) {
+    if (strstart(filename, "telnet:", &p)) {
         return qemu_chr_open_tcp(p, 1);
     } else
     if (strstart(filename, "udp:", &p)) {
@@ -2618,6 +2651,45 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
     return 0;
 }
 
+int parse_host_src_port(struct sockaddr_in *haddr,
+                        struct sockaddr_in *saddr,
+                        const char *input_str)
+{
+    char *str = strdup(input_str);
+    char *host_str = str;
+    char *src_str;
+    char *ptr;
+
+    /*
+     * Chop off any extra arguments at the end of the string which
+     * would start with a comma, then fill in the src port information
+     * if it was provided else use the "any address" and "any port".
+     */
+    if ((ptr = strchr(str,',')))
+        *ptr = '\0';
+
+    if ((src_str = strchr(input_str,'@'))) {
+        *src_str = '\0';
+        src_str++;
+    }
+
+    if (parse_host_port(haddr, host_str) < 0)
+        goto fail;
+
+    if (!src_str || *src_str == '\0')
+        src_str = ":0";
+
+    if (parse_host_port(saddr, src_str) < 0)
+        goto fail;
+
+    free(str);
+    return(0);
+
+fail:
+    free(str);
+    return -1;
+}
+
 int parse_host_port(struct sockaddr_in *saddr, const char *str)
 {
     char buf[512];
@@ -3709,6 +3781,7 @@ static int usb_device_del(const char *devname)
 {
     USBPort *port;
     USBPort **lastp;
+    USBDevice *dev;
     int bus_num, addr;
     const char *p;
 
@@ -3733,8 +3806,10 @@ static int usb_device_del(const char *devname)
     if (!port)
         return -1;
 
+    dev = port->dev;
     *lastp = port->next;
     usb_attach(port, NULL);
+    dev->handle_destroy(dev);
     port->next = free_usb_ports;
     free_usb_ports = port;
     return 0;
@@ -3785,8 +3860,8 @@ void usb_info(void)
             speed_str = "?"; 
             break;
         }
-        term_printf("  Device %d.%d, speed %s Mb/s\n", 
-                    0, dev->addr, speed_str);
+        term_printf("  Device %d.%d, Speed %s Mb/s, Product %s\n", 
+                    0, dev->addr, speed_str, dev->devname);
     }
 }
 
@@ -4697,6 +4772,77 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
 }
 
 /***********************************************************/
+/* bottom halves (can be seen as timers which expire ASAP) */
+
+struct QEMUBH {
+    QEMUBHFunc *cb;
+    void *opaque;
+    int scheduled;
+    QEMUBH *next;
+};
+
+static QEMUBH *first_bh = NULL;
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+{
+    QEMUBH *bh;
+    bh = qemu_mallocz(sizeof(QEMUBH));
+    if (!bh)
+        return NULL;
+    bh->cb = cb;
+    bh->opaque = opaque;
+    return bh;
+}
+
+void qemu_bh_poll(void)
+{
+    QEMUBH *bh, **pbh;
+
+    for(;;) {
+        pbh = &first_bh;
+        bh = *pbh;
+        if (!bh)
+            break;
+        *pbh = bh->next;
+        bh->scheduled = 0;
+        bh->cb(bh->opaque);
+    }
+}
+
+void qemu_bh_schedule(QEMUBH *bh)
+{
+    CPUState *env = cpu_single_env;
+    if (bh->scheduled)
+        return;
+    bh->scheduled = 1;
+    bh->next = first_bh;
+    first_bh = bh;
+
+    /* stop the currently executing CPU to execute the BH ASAP */
+    if (env) {
+        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+    }
+}
+
+void qemu_bh_cancel(QEMUBH *bh)
+{
+    QEMUBH **pbh;
+    if (bh->scheduled) {
+        pbh = &first_bh;
+        while (*pbh != bh)
+            pbh = &(*pbh)->next;
+        *pbh = bh->next;
+        bh->scheduled = 0;
+    }
+}
+
+void qemu_bh_delete(QEMUBH *bh)
+{
+    qemu_bh_cancel(bh);
+    qemu_free(bh);
+}
+
+/***********************************************************/
 /* machine registration */
 
 QEMUMachine *first_machine = NULL;
@@ -4955,6 +5101,8 @@ void main_loop_wait(int timeout)
 #ifdef _WIN32
     tap_win32_poll();
 #endif
+    qemu_aio_poll();
+    qemu_bh_poll();
 
     if (vm_running) {
         qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], 
@@ -5495,6 +5643,14 @@ static void select_soundhw (const char *optarg)
 }
 #endif
 
+#ifdef _WIN32
+static BOOL WINAPI qemu_ctrl_handler(DWORD type)
+{
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+#endif
+
 #define MAX_NET_CLIENTS 32
 
 int main(int argc, char **argv)
@@ -5534,8 +5690,27 @@ int main(int argc, char **argv)
         act.sa_handler = SIG_IGN;
         sigaction(SIGPIPE, &act, NULL);
     }
+#else
+    SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+    /* Note: cpu_interrupt() is currently not SMP safe, so we force
+       QEMU to run on a single CPU */
+    {
+        HANDLE h;
+        DWORD mask, smask;
+        int i;
+        h = GetCurrentProcess();
+        if (GetProcessAffinityMask(h, &mask, &smask)) {
+            for(i = 0; i < 32; i++) {
+                if (mask & (1 << i))
+                    break;
+            }
+            if (i != 32) {
+                mask = 1 << i;
+                SetProcessAffinityMask(h, mask);
+            }
+        }
+    }
 #endif
-    init_timers();
 
     register_machines();
     machine = first_machine;
@@ -5945,6 +6120,10 @@ int main(int argc, char **argv)
 
     setvbuf(stdout, NULL, _IOLBF, 0);
     
+    init_timers();
+    init_timer_alarm();
+    qemu_aio_init();
+
 #ifdef _WIN32
     socket_init();
 #endif
@@ -5988,7 +6167,7 @@ int main(int argc, char **argv)
                 snprintf(buf, sizeof(buf), "hd%c", i + 'a');
                 bs_table[i] = bdrv_new(buf);
             }
-            if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) {
+            if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
                 fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
                         hd_filename[i]);
                 exit(1);
@@ -6013,7 +6192,8 @@ int main(int argc, char **argv)
                 bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
             }
             if (fd_filename[i] != '\0') {
-                if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) {
+                if (bdrv_open(fd_table[i], fd_filename[i],
+                              snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
                     fprintf(stderr, "qemu: could not open floppy disk image '%s'\n",
                             fd_filename[i]);
                     exit(1);
@@ -6026,7 +6206,6 @@ int main(int argc, char **argv)
     register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
 
     init_ioports();
-    cpu_calibrate_ticks();
 
     /* terminal init */
     if (nographic) {
@@ -6059,7 +6238,7 @@ int main(int argc, char **argv)
                 exit(1);
             }
             if (!strcmp(serial_devices[i], "vc"))
-                qemu_chr_printf(serial_hds[i], "serial%d console\n", i);
+                qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
         }
     }
 
@@ -6072,7 +6251,7 @@ int main(int argc, char **argv)
                 exit(1);
             }
             if (!strcmp(parallel_devices[i], "vc"))
-                qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i);
+                qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
         }
     }