Commit f331110f3539ee590b3a856d157f92fb34a88bce
1 parent
1236cab7
win32 serial port support (initial patch by kazu
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1807 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
444 additions
and
5 deletions
vl.c
... | ... | @@ -1713,11 +1713,381 @@ CharDriverState *qemu_chr_open_pty(void) |
1713 | 1713 | |
1714 | 1714 | #endif /* !defined(_WIN32) */ |
1715 | 1715 | |
1716 | +#ifdef _WIN32 | |
1717 | +typedef struct { | |
1718 | + IOCanRWHandler *fd_can_read; | |
1719 | + IOReadHandler *fd_read; | |
1720 | + void *win_opaque; | |
1721 | + int max_size; | |
1722 | + HANDLE hcom, hrecv, hsend; | |
1723 | + OVERLAPPED orecv, osend; | |
1724 | + BOOL fpipe; | |
1725 | + DWORD len; | |
1726 | +} WinCharState; | |
1727 | + | |
1728 | +#define NSENDBUF 2048 | |
1729 | +#define NRECVBUF 2048 | |
1730 | +#define MAXCONNECT 1 | |
1731 | +#define NTIMEOUT 5000 | |
1732 | + | |
1733 | +static int win_chr_poll(void *opaque); | |
1734 | +static int win_chr_pipe_poll(void *opaque); | |
1735 | + | |
1736 | +static void win_chr_close2(WinCharState *s) | |
1737 | +{ | |
1738 | + if (s->hsend) { | |
1739 | + CloseHandle(s->hsend); | |
1740 | + s->hsend = NULL; | |
1741 | + } | |
1742 | + if (s->hrecv) { | |
1743 | + CloseHandle(s->hrecv); | |
1744 | + s->hrecv = NULL; | |
1745 | + } | |
1746 | + if (s->hcom) { | |
1747 | + CloseHandle(s->hcom); | |
1748 | + s->hcom = NULL; | |
1749 | + } | |
1750 | + if (s->fpipe) | |
1751 | + qemu_del_polling_cb(win_chr_pipe_poll, s); | |
1752 | + else | |
1753 | + qemu_del_polling_cb(win_chr_poll, s); | |
1754 | +} | |
1755 | + | |
1756 | +static void win_chr_close(CharDriverState *chr) | |
1757 | +{ | |
1758 | + WinCharState *s = chr->opaque; | |
1759 | + win_chr_close2(s); | |
1760 | +} | |
1761 | + | |
1762 | +static int win_chr_init(WinCharState *s, const char *filename) | |
1763 | +{ | |
1764 | + COMMCONFIG comcfg; | |
1765 | + COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; | |
1766 | + COMSTAT comstat; | |
1767 | + DWORD size; | |
1768 | + DWORD err; | |
1769 | + | |
1770 | + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); | |
1771 | + if (!s->hsend) { | |
1772 | + fprintf(stderr, "Failed CreateEvent\n"); | |
1773 | + goto fail; | |
1774 | + } | |
1775 | + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); | |
1776 | + if (!s->hrecv) { | |
1777 | + fprintf(stderr, "Failed CreateEvent\n"); | |
1778 | + goto fail; | |
1779 | + } | |
1780 | + | |
1781 | + s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, | |
1782 | + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); | |
1783 | + if (s->hcom == INVALID_HANDLE_VALUE) { | |
1784 | + fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError()); | |
1785 | + s->hcom = NULL; | |
1786 | + goto fail; | |
1787 | + } | |
1788 | + | |
1789 | + if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { | |
1790 | + fprintf(stderr, "Failed SetupComm\n"); | |
1791 | + goto fail; | |
1792 | + } | |
1793 | + | |
1794 | + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); | |
1795 | + size = sizeof(COMMCONFIG); | |
1796 | + GetDefaultCommConfig(filename, &comcfg, &size); | |
1797 | + comcfg.dcb.DCBlength = sizeof(DCB); | |
1798 | + CommConfigDialog(filename, NULL, &comcfg); | |
1799 | + | |
1800 | + if (!SetCommState(s->hcom, &comcfg.dcb)) { | |
1801 | + fprintf(stderr, "Failed SetCommState\n"); | |
1802 | + goto fail; | |
1803 | + } | |
1804 | + | |
1805 | + if (!SetCommMask(s->hcom, EV_ERR)) { | |
1806 | + fprintf(stderr, "Failed SetCommMask\n"); | |
1807 | + goto fail; | |
1808 | + } | |
1809 | + | |
1810 | + cto.ReadIntervalTimeout = MAXDWORD; | |
1811 | + if (!SetCommTimeouts(s->hcom, &cto)) { | |
1812 | + fprintf(stderr, "Failed SetCommTimeouts\n"); | |
1813 | + goto fail; | |
1814 | + } | |
1815 | + | |
1816 | + if (!ClearCommError(s->hcom, &err, &comstat)) { | |
1817 | + fprintf(stderr, "Failed ClearCommError\n"); | |
1818 | + goto fail; | |
1819 | + } | |
1820 | + qemu_add_polling_cb(win_chr_poll, s); | |
1821 | + return 0; | |
1822 | + | |
1823 | + fail: | |
1824 | + win_chr_close2(s); | |
1825 | + return -1; | |
1826 | +} | |
1827 | + | |
1828 | +static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) | |
1829 | +{ | |
1830 | + WinCharState *s = chr->opaque; | |
1831 | + DWORD len, ret, size, err; | |
1832 | + | |
1833 | + len = len1; | |
1834 | + ZeroMemory(&s->osend, sizeof(s->osend)); | |
1835 | + s->osend.hEvent = s->hsend; | |
1836 | + while (len > 0) { | |
1837 | + if (s->hsend) | |
1838 | + ret = WriteFile(s->hcom, buf, len, &size, &s->osend); | |
1839 | + else | |
1840 | + ret = WriteFile(s->hcom, buf, len, &size, NULL); | |
1841 | + if (!ret) { | |
1842 | + err = GetLastError(); | |
1843 | + if (err == ERROR_IO_PENDING) { | |
1844 | + ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); | |
1845 | + if (ret) { | |
1846 | + buf += size; | |
1847 | + len -= size; | |
1848 | + } else { | |
1849 | + break; | |
1850 | + } | |
1851 | + } else { | |
1852 | + break; | |
1853 | + } | |
1854 | + } else { | |
1855 | + buf += size; | |
1856 | + len -= size; | |
1857 | + } | |
1858 | + } | |
1859 | + return len1 - len; | |
1860 | +} | |
1861 | + | |
1862 | +static int win_chr_read_poll(WinCharState *s) | |
1863 | +{ | |
1864 | + s->max_size = s->fd_can_read(s->win_opaque); | |
1865 | + return s->max_size; | |
1866 | +} | |
1867 | + | |
1868 | +static void win_chr_readfile(WinCharState *s) | |
1869 | +{ | |
1870 | + int ret, err; | |
1871 | + uint8_t buf[1024]; | |
1872 | + DWORD size; | |
1873 | + | |
1874 | + ZeroMemory(&s->orecv, sizeof(s->orecv)); | |
1875 | + s->orecv.hEvent = s->hrecv; | |
1876 | + ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); | |
1877 | + if (!ret) { | |
1878 | + err = GetLastError(); | |
1879 | + if (err == ERROR_IO_PENDING) { | |
1880 | + ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); | |
1881 | + } | |
1882 | + } | |
1883 | + | |
1884 | + if (size > 0) { | |
1885 | + s->fd_read(s->win_opaque, buf, size); | |
1886 | + } | |
1887 | +} | |
1888 | + | |
1889 | +static void win_chr_read(WinCharState *s) | |
1890 | +{ | |
1891 | + if (s->len > s->max_size) | |
1892 | + s->len = s->max_size; | |
1893 | + if (s->len == 0) | |
1894 | + return; | |
1895 | + | |
1896 | + win_chr_readfile(s); | |
1897 | +} | |
1898 | + | |
1899 | +static int win_chr_poll(void *opaque) | |
1900 | +{ | |
1901 | + WinCharState *s = opaque; | |
1902 | + COMSTAT status; | |
1903 | + DWORD comerr; | |
1904 | + | |
1905 | + ClearCommError(s->hcom, &comerr, &status); | |
1906 | + if (status.cbInQue > 0) { | |
1907 | + s->len = status.cbInQue; | |
1908 | + win_chr_read_poll(s); | |
1909 | + win_chr_read(s); | |
1910 | + return 1; | |
1911 | + } | |
1912 | + return 0; | |
1913 | +} | |
1914 | + | |
1915 | +static void win_chr_add_read_handler(CharDriverState *chr, | |
1916 | + IOCanRWHandler *fd_can_read, | |
1917 | + IOReadHandler *fd_read, void *opaque) | |
1918 | +{ | |
1919 | + WinCharState *s = chr->opaque; | |
1920 | + | |
1921 | + s->fd_can_read = fd_can_read; | |
1922 | + s->fd_read = fd_read; | |
1923 | + s->win_opaque = opaque; | |
1924 | +} | |
1925 | + | |
1926 | +CharDriverState *qemu_chr_open_win(const char *filename) | |
1927 | +{ | |
1928 | + CharDriverState *chr; | |
1929 | + WinCharState *s; | |
1930 | + | |
1931 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
1932 | + if (!chr) | |
1933 | + return NULL; | |
1934 | + s = qemu_mallocz(sizeof(WinCharState)); | |
1935 | + if (!s) { | |
1936 | + free(chr); | |
1937 | + return NULL; | |
1938 | + } | |
1939 | + chr->opaque = s; | |
1940 | + chr->chr_write = win_chr_write; | |
1941 | + chr->chr_add_read_handler = win_chr_add_read_handler; | |
1942 | + chr->chr_close = win_chr_close; | |
1943 | + | |
1944 | + if (win_chr_init(s, filename) < 0) { | |
1945 | + free(s); | |
1946 | + free(chr); | |
1947 | + return NULL; | |
1948 | + } | |
1949 | + return chr; | |
1950 | +} | |
1951 | + | |
1952 | +static int win_chr_pipe_poll(void *opaque) | |
1953 | +{ | |
1954 | + WinCharState *s = opaque; | |
1955 | + DWORD size; | |
1956 | + | |
1957 | + PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); | |
1958 | + if (size > 0) { | |
1959 | + s->len = size; | |
1960 | + win_chr_read_poll(s); | |
1961 | + win_chr_read(s); | |
1962 | + return 1; | |
1963 | + } | |
1964 | + return 0; | |
1965 | +} | |
1966 | + | |
1967 | +static int win_chr_pipe_init(WinCharState *s, const char *filename) | |
1968 | +{ | |
1969 | + OVERLAPPED ov; | |
1970 | + int ret; | |
1971 | + DWORD size; | |
1972 | + char openname[256]; | |
1973 | + | |
1974 | + s->fpipe = TRUE; | |
1975 | + | |
1976 | + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); | |
1977 | + if (!s->hsend) { | |
1978 | + fprintf(stderr, "Failed CreateEvent\n"); | |
1979 | + goto fail; | |
1980 | + } | |
1981 | + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); | |
1982 | + if (!s->hrecv) { | |
1983 | + fprintf(stderr, "Failed CreateEvent\n"); | |
1984 | + goto fail; | |
1985 | + } | |
1986 | + | |
1987 | + snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); | |
1988 | + s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, | |
1989 | + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | | |
1990 | + PIPE_WAIT, | |
1991 | + MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); | |
1992 | + if (s->hcom == INVALID_HANDLE_VALUE) { | |
1993 | + fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError()); | |
1994 | + s->hcom = NULL; | |
1995 | + goto fail; | |
1996 | + } | |
1997 | + | |
1998 | + ZeroMemory(&ov, sizeof(ov)); | |
1999 | + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | |
2000 | + ret = ConnectNamedPipe(s->hcom, &ov); | |
2001 | + if (ret) { | |
2002 | + fprintf(stderr, "Failed ConnectNamedPipe\n"); | |
2003 | + goto fail; | |
2004 | + } | |
2005 | + | |
2006 | + ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); | |
2007 | + if (!ret) { | |
2008 | + fprintf(stderr, "Failed GetOverlappedResult\n"); | |
2009 | + if (ov.hEvent) { | |
2010 | + CloseHandle(ov.hEvent); | |
2011 | + ov.hEvent = NULL; | |
2012 | + } | |
2013 | + goto fail; | |
2014 | + } | |
2015 | + | |
2016 | + if (ov.hEvent) { | |
2017 | + CloseHandle(ov.hEvent); | |
2018 | + ov.hEvent = NULL; | |
2019 | + } | |
2020 | + qemu_add_polling_cb(win_chr_pipe_poll, s); | |
2021 | + return 0; | |
2022 | + | |
2023 | + fail: | |
2024 | + win_chr_close2(s); | |
2025 | + return -1; | |
2026 | +} | |
2027 | + | |
2028 | + | |
2029 | +CharDriverState *qemu_chr_open_win_pipe(const char *filename) | |
2030 | +{ | |
2031 | + CharDriverState *chr; | |
2032 | + WinCharState *s; | |
2033 | + | |
2034 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
2035 | + if (!chr) | |
2036 | + return NULL; | |
2037 | + s = qemu_mallocz(sizeof(WinCharState)); | |
2038 | + if (!s) { | |
2039 | + free(chr); | |
2040 | + return NULL; | |
2041 | + } | |
2042 | + chr->opaque = s; | |
2043 | + chr->chr_write = win_chr_write; | |
2044 | + chr->chr_add_read_handler = win_chr_add_read_handler; | |
2045 | + chr->chr_close = win_chr_close; | |
2046 | + | |
2047 | + if (win_chr_pipe_init(s, filename) < 0) { | |
2048 | + free(s); | |
2049 | + free(chr); | |
2050 | + return NULL; | |
2051 | + } | |
2052 | + return chr; | |
2053 | +} | |
2054 | + | |
2055 | +CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) | |
2056 | +{ | |
2057 | + CharDriverState *chr; | |
2058 | + WinCharState *s; | |
2059 | + | |
2060 | + chr = qemu_mallocz(sizeof(CharDriverState)); | |
2061 | + if (!chr) | |
2062 | + return NULL; | |
2063 | + s = qemu_mallocz(sizeof(WinCharState)); | |
2064 | + if (!s) { | |
2065 | + free(chr); | |
2066 | + return NULL; | |
2067 | + } | |
2068 | + s->hcom = fd_out; | |
2069 | + chr->opaque = s; | |
2070 | + chr->chr_write = win_chr_write; | |
2071 | + chr->chr_add_read_handler = win_chr_add_read_handler; | |
2072 | + return chr; | |
2073 | +} | |
2074 | + | |
2075 | +CharDriverState *qemu_chr_open_win_file_out(const char *file_out) | |
2076 | +{ | |
2077 | + HANDLE fd_out; | |
2078 | + | |
2079 | + fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, | |
2080 | + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
2081 | + if (fd_out == INVALID_HANDLE_VALUE) | |
2082 | + return NULL; | |
2083 | + | |
2084 | + return qemu_chr_open_win_file(fd_out); | |
2085 | +} | |
2086 | +#endif | |
2087 | + | |
1716 | 2088 | CharDriverState *qemu_chr_open(const char *filename) |
1717 | 2089 | { |
1718 | -#ifndef _WIN32 | |
1719 | 2090 | const char *p; |
1720 | -#endif | |
1721 | 2091 | |
1722 | 2092 | if (!strcmp(filename, "vc")) { |
1723 | 2093 | return text_console_init(&display_state); |
... | ... | @@ -1743,11 +2113,28 @@ CharDriverState *qemu_chr_open(const char *filename) |
1743 | 2113 | return qemu_chr_open_tty(filename); |
1744 | 2114 | } else |
1745 | 2115 | #endif |
2116 | +#ifdef _WIN32 | |
2117 | + if (strstart(filename, "COM", NULL)) { | |
2118 | + return qemu_chr_open_win(filename); | |
2119 | + } else | |
2120 | + if (strstart(filename, "pipe:", &p)) { | |
2121 | + return qemu_chr_open_win_pipe(p); | |
2122 | + } else | |
2123 | + if (strstart(filename, "file:", &p)) { | |
2124 | + return qemu_chr_open_win_file_out(p); | |
2125 | + } | |
2126 | +#endif | |
1746 | 2127 | { |
1747 | 2128 | return NULL; |
1748 | 2129 | } |
1749 | 2130 | } |
1750 | 2131 | |
2132 | +void qemu_chr_close(CharDriverState *chr) | |
2133 | +{ | |
2134 | + if (chr->chr_close) | |
2135 | + chr->chr_close(chr); | |
2136 | +} | |
2137 | + | |
1751 | 2138 | /***********************************************************/ |
1752 | 2139 | /* network device redirectors */ |
1753 | 2140 | |
... | ... | @@ -3090,6 +3477,43 @@ int qemu_set_fd_handler(int fd, |
3090 | 3477 | } |
3091 | 3478 | |
3092 | 3479 | /***********************************************************/ |
3480 | +/* Polling handling */ | |
3481 | + | |
3482 | +typedef struct PollingEntry { | |
3483 | + PollingFunc *func; | |
3484 | + void *opaque; | |
3485 | + struct PollingEntry *next; | |
3486 | +} PollingEntry; | |
3487 | + | |
3488 | +static PollingEntry *first_polling_entry; | |
3489 | + | |
3490 | +int qemu_add_polling_cb(PollingFunc *func, void *opaque) | |
3491 | +{ | |
3492 | + PollingEntry **ppe, *pe; | |
3493 | + pe = qemu_mallocz(sizeof(PollingEntry)); | |
3494 | + if (!pe) | |
3495 | + return -1; | |
3496 | + pe->func = func; | |
3497 | + pe->opaque = opaque; | |
3498 | + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); | |
3499 | + *ppe = pe; | |
3500 | + return 0; | |
3501 | +} | |
3502 | + | |
3503 | +void qemu_del_polling_cb(PollingFunc *func, void *opaque) | |
3504 | +{ | |
3505 | + PollingEntry **ppe, *pe; | |
3506 | + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { | |
3507 | + pe = *ppe; | |
3508 | + if (pe->func == func && pe->opaque == opaque) { | |
3509 | + *ppe = pe->next; | |
3510 | + qemu_free(pe); | |
3511 | + break; | |
3512 | + } | |
3513 | + } | |
3514 | +} | |
3515 | + | |
3516 | +/***********************************************************/ | |
3093 | 3517 | /* savevm/loadvm support */ |
3094 | 3518 | |
3095 | 3519 | void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) |
... | ... | @@ -3955,12 +4379,18 @@ void main_loop_wait(int timeout) |
3955 | 4379 | fd_set rfds, wfds; |
3956 | 4380 | int ret, nfds; |
3957 | 4381 | struct timeval tv; |
4382 | + PollingEntry *pe; | |
4383 | + | |
3958 | 4384 | |
4385 | + /* XXX: need to suppress polling by better using win32 events */ | |
4386 | + ret = 0; | |
4387 | + for(pe = first_polling_entry; pe != NULL; pe = pe->next) { | |
4388 | + ret |= pe->func(pe->opaque); | |
4389 | + } | |
3959 | 4390 | #ifdef _WIN32 |
3960 | - /* XXX: see how to merge it with the select. The constraint is | |
3961 | - that the select must be interrupted by the timer */ | |
3962 | - if (timeout > 0) | |
4391 | + if (ret == 0 && timeout > 0) { | |
3963 | 4392 | Sleep(timeout); |
4393 | + } | |
3964 | 4394 | #endif |
3965 | 4395 | /* poll any events */ |
3966 | 4396 | /* XXX: separate device handlers from system ones */ | ... | ... |
vl.h
... | ... | @@ -204,6 +204,14 @@ int qemu_set_fd_handler(int fd, |
204 | 204 | IOHandler *fd_write, |
205 | 205 | void *opaque); |
206 | 206 | |
207 | +/* Polling handling */ | |
208 | + | |
209 | +/* return TRUE if no sleep should be done afterwards */ | |
210 | +typedef int PollingFunc(void *opaque); | |
211 | + | |
212 | +int qemu_add_polling_cb(PollingFunc *func, void *opaque); | |
213 | +void qemu_del_polling_cb(PollingFunc *func, void *opaque); | |
214 | + | |
207 | 215 | /* character device */ |
208 | 216 | |
209 | 217 | #define CHR_EVENT_BREAK 0 /* serial break char */ |
... | ... | @@ -237,6 +245,7 @@ typedef struct CharDriverState { |
237 | 245 | int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); |
238 | 246 | IOEventHandler *chr_event; |
239 | 247 | void (*chr_send_event)(struct CharDriverState *chr, int event); |
248 | + void (*chr_close)(struct CharDriverState *chr); | |
240 | 249 | void *opaque; |
241 | 250 | } CharDriverState; |
242 | 251 | ... | ... |