Commit f331110f3539ee590b3a856d157f92fb34a88bce

Authored by bellard
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
... ... @@ -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 */
... ...
... ... @@ -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  
... ...