Commit f8d179e33d71ddac580fb41f2b452099e7805d67
1 parent
3f87bf69
use host serial port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1609 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
232 additions
and
10 deletions
Changelog
@@ -7,7 +7,8 @@ version 0.7.3: | @@ -7,7 +7,8 @@ version 0.7.3: | ||
7 | - new audio options: '-soundhw' and '-audio-help' (malc) | 7 | - new audio options: '-soundhw' and '-audio-help' (malc) |
8 | - ES1370 PCI audio device (malc) | 8 | - ES1370 PCI audio device (malc) |
9 | - Initial USB support | 9 | - Initial USB support |
10 | - | 10 | + - Linux host serial port access |
11 | + | ||
11 | version 0.7.2: | 12 | version 0.7.2: |
12 | 13 | ||
13 | - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit) | 14 | - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit) |
hw/serial.c
@@ -85,6 +85,7 @@ struct SerialState { | @@ -85,6 +85,7 @@ struct SerialState { | ||
85 | int thr_ipending; | 85 | int thr_ipending; |
86 | int irq; | 86 | int irq; |
87 | CharDriverState *chr; | 87 | CharDriverState *chr; |
88 | + int last_break_enable; | ||
88 | }; | 89 | }; |
89 | 90 | ||
90 | static void serial_update_irq(SerialState *s) | 91 | static void serial_update_irq(SerialState *s) |
@@ -103,6 +104,32 @@ static void serial_update_irq(SerialState *s) | @@ -103,6 +104,32 @@ static void serial_update_irq(SerialState *s) | ||
103 | } | 104 | } |
104 | } | 105 | } |
105 | 106 | ||
107 | +static void serial_update_parameters(SerialState *s) | ||
108 | +{ | ||
109 | + int speed, parity, data_bits, stop_bits; | ||
110 | + | ||
111 | + if (s->lcr & 0x08) { | ||
112 | + if (s->lcr & 0x10) | ||
113 | + parity = 'E'; | ||
114 | + else | ||
115 | + parity = 'O'; | ||
116 | + } else { | ||
117 | + parity = 'N'; | ||
118 | + } | ||
119 | + if (s->lcr & 0x04) | ||
120 | + stop_bits = 2; | ||
121 | + else | ||
122 | + stop_bits = 1; | ||
123 | + data_bits = (s->lcr & 0x03) + 5; | ||
124 | + if (s->divider == 0) | ||
125 | + return; | ||
126 | + speed = 115200 / s->divider; | ||
127 | +#if 0 | ||
128 | + printf("speed=%d parity=%c data=%d stop=%d\n", | ||
129 | + speed, parity, data_bits, stop_bits); | ||
130 | +#endif | ||
131 | +} | ||
132 | + | ||
106 | static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | 133 | static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
107 | { | 134 | { |
108 | SerialState *s = opaque; | 135 | SerialState *s = opaque; |
@@ -117,6 +144,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | @@ -117,6 +144,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | ||
117 | case 0: | 144 | case 0: |
118 | if (s->lcr & UART_LCR_DLAB) { | 145 | if (s->lcr & UART_LCR_DLAB) { |
119 | s->divider = (s->divider & 0xff00) | val; | 146 | s->divider = (s->divider & 0xff00) | val; |
147 | + serial_update_parameters(s); | ||
120 | } else { | 148 | } else { |
121 | s->thr_ipending = 0; | 149 | s->thr_ipending = 0; |
122 | s->lsr &= ~UART_LSR_THRE; | 150 | s->lsr &= ~UART_LSR_THRE; |
@@ -132,6 +160,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | @@ -132,6 +160,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | ||
132 | case 1: | 160 | case 1: |
133 | if (s->lcr & UART_LCR_DLAB) { | 161 | if (s->lcr & UART_LCR_DLAB) { |
134 | s->divider = (s->divider & 0x00ff) | (val << 8); | 162 | s->divider = (s->divider & 0x00ff) | (val << 8); |
163 | + serial_update_parameters(s); | ||
135 | } else { | 164 | } else { |
136 | s->ier = val & 0x0f; | 165 | s->ier = val & 0x0f; |
137 | if (s->lsr & UART_LSR_THRE) { | 166 | if (s->lsr & UART_LSR_THRE) { |
@@ -143,7 +172,16 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | @@ -143,7 +172,16 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | ||
143 | case 2: | 172 | case 2: |
144 | break; | 173 | break; |
145 | case 3: | 174 | case 3: |
146 | - s->lcr = val; | 175 | + { |
176 | + int break_enable; | ||
177 | + s->lcr = val; | ||
178 | + serial_update_parameters(s); | ||
179 | + break_enable = (val >> 6) & 1; | ||
180 | + if (break_enable != s->last_break_enable) { | ||
181 | + s->last_break_enable = break_enable; | ||
182 | + qemu_chr_set_serial_break(s, break_enable); | ||
183 | + } | ||
184 | + } | ||
147 | break; | 185 | break; |
148 | case 4: | 186 | case 4: |
149 | s->mcr = val & 0x1f; | 187 | s->mcr = val & 0x1f; |
qemu-doc.texi
@@ -363,8 +363,15 @@ Virtual console | @@ -363,8 +363,15 @@ Virtual console | ||
363 | [Linux only] Pseudo TTY (a new PTY is automatically allocated) | 363 | [Linux only] Pseudo TTY (a new PTY is automatically allocated) |
364 | @item null | 364 | @item null |
365 | void device | 365 | void device |
366 | +@item /dev/XXX | ||
367 | +[Linux only]Use host tty, e.g. @file{/dev/ttyS0}. The host serial port | ||
368 | +parameters are set according to the emulated ones. | ||
369 | +@item file:filename | ||
370 | +Write output to filename. No character can be read. | ||
366 | @item stdio | 371 | @item stdio |
367 | [Unix only] standard input/output | 372 | [Unix only] standard input/output |
373 | +@item pipe:filename | ||
374 | +[Unix only] name pipe @var{filename} | ||
368 | @end table | 375 | @end table |
369 | The default device is @code{vc} in graphical mode and @code{stdio} in | 376 | The default device is @code{vc} in graphical mode and @code{stdio} in |
370 | non graphical mode. | 377 | non graphical mode. |
vl.c
@@ -1013,6 +1013,21 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) | @@ -1013,6 +1013,21 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) | ||
1013 | return s->chr_write(s, buf, len); | 1013 | return s->chr_write(s, buf, len); |
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | +void qemu_chr_set_serial_parameters(CharDriverState *s, | ||
1017 | + int speed, int parity, | ||
1018 | + int data_bits, int stop_bits) | ||
1019 | +{ | ||
1020 | + if (s->chr_set_serial_parameters) | ||
1021 | + s->chr_set_serial_parameters(s, speed, parity, data_bits, stop_bits); | ||
1022 | +} | ||
1023 | + | ||
1024 | +void qemu_chr_set_serial_break(CharDriverState *s, int enable) | ||
1025 | +{ | ||
1026 | + if (s->chr_set_serial_break) | ||
1027 | + s->chr_set_serial_break(s, enable); | ||
1028 | +} | ||
1029 | + | ||
1030 | + | ||
1016 | void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) | 1031 | void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) |
1017 | { | 1032 | { |
1018 | char buf[4096]; | 1033 | char buf[4096]; |
@@ -1111,12 +1126,14 @@ static void fd_chr_add_read_handler(CharDriverState *chr, | @@ -1111,12 +1126,14 @@ static void fd_chr_add_read_handler(CharDriverState *chr, | ||
1111 | { | 1126 | { |
1112 | FDCharDriver *s = chr->opaque; | 1127 | FDCharDriver *s = chr->opaque; |
1113 | 1128 | ||
1114 | - if (nographic && s->fd_in == 0) { | ||
1115 | - s->fd_can_read = fd_can_read; | ||
1116 | - s->fd_read = fd_read; | ||
1117 | - s->fd_opaque = opaque; | ||
1118 | - } else { | ||
1119 | - qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); | 1129 | + if (s->fd_in >= 0) { |
1130 | + if (nographic && s->fd_in == 0) { | ||
1131 | + s->fd_can_read = fd_can_read; | ||
1132 | + s->fd_read = fd_read; | ||
1133 | + s->fd_opaque = opaque; | ||
1134 | + } else { | ||
1135 | + qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); | ||
1136 | + } | ||
1120 | } | 1137 | } |
1121 | } | 1138 | } |
1122 | 1139 | ||
@@ -1142,6 +1159,27 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) | @@ -1142,6 +1159,27 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) | ||
1142 | return chr; | 1159 | return chr; |
1143 | } | 1160 | } |
1144 | 1161 | ||
1162 | +CharDriverState *qemu_chr_open_file_out(const char *file_out) | ||
1163 | +{ | ||
1164 | + int fd_out; | ||
1165 | + | ||
1166 | + fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY); | ||
1167 | + if (fd_out < 0) | ||
1168 | + return NULL; | ||
1169 | + return qemu_chr_open_fd(-1, fd_out); | ||
1170 | +} | ||
1171 | + | ||
1172 | +CharDriverState *qemu_chr_open_pipe(const char *filename) | ||
1173 | +{ | ||
1174 | + int fd; | ||
1175 | + | ||
1176 | + fd = open(filename, O_RDWR | O_BINARY); | ||
1177 | + if (fd < 0) | ||
1178 | + return NULL; | ||
1179 | + return qemu_chr_open_fd(fd, fd); | ||
1180 | +} | ||
1181 | + | ||
1182 | + | ||
1145 | /* for STDIO, we handle the case where several clients use it | 1183 | /* for STDIO, we handle the case where several clients use it |
1146 | (nographic mode) */ | 1184 | (nographic mode) */ |
1147 | 1185 | ||
@@ -1334,6 +1372,127 @@ CharDriverState *qemu_chr_open_pty(void) | @@ -1334,6 +1372,127 @@ CharDriverState *qemu_chr_open_pty(void) | ||
1334 | fprintf(stderr, "char device redirected to %s\n", slave_name); | 1372 | fprintf(stderr, "char device redirected to %s\n", slave_name); |
1335 | return qemu_chr_open_fd(master_fd, master_fd); | 1373 | return qemu_chr_open_fd(master_fd, master_fd); |
1336 | } | 1374 | } |
1375 | + | ||
1376 | +static void tty_serial_init(int fd, int speed, | ||
1377 | + int parity, int data_bits, int stop_bits) | ||
1378 | +{ | ||
1379 | + struct termios tty; | ||
1380 | + speed_t spd; | ||
1381 | + | ||
1382 | + tcgetattr (0, &tty); | ||
1383 | + | ||
1384 | + switch(speed) { | ||
1385 | + case 50: | ||
1386 | + spd = B50; | ||
1387 | + break; | ||
1388 | + case 75: | ||
1389 | + spd = B75; | ||
1390 | + break; | ||
1391 | + case 300: | ||
1392 | + spd = B300; | ||
1393 | + break; | ||
1394 | + case 600: | ||
1395 | + spd = B600; | ||
1396 | + break; | ||
1397 | + case 1200: | ||
1398 | + spd = B1200; | ||
1399 | + break; | ||
1400 | + case 2400: | ||
1401 | + spd = B2400; | ||
1402 | + break; | ||
1403 | + case 4800: | ||
1404 | + spd = B4800; | ||
1405 | + break; | ||
1406 | + case 9600: | ||
1407 | + spd = B9600; | ||
1408 | + break; | ||
1409 | + case 19200: | ||
1410 | + spd = B19200; | ||
1411 | + break; | ||
1412 | + case 38400: | ||
1413 | + spd = B38400; | ||
1414 | + break; | ||
1415 | + case 57600: | ||
1416 | + spd = B57600; | ||
1417 | + break; | ||
1418 | + default: | ||
1419 | + case 115200: | ||
1420 | + spd = B115200; | ||
1421 | + break; | ||
1422 | + } | ||
1423 | + | ||
1424 | + cfsetispeed(&tty, spd); | ||
1425 | + cfsetospeed(&tty, spd); | ||
1426 | + | ||
1427 | + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | ||
1428 | + |INLCR|IGNCR|ICRNL|IXON); | ||
1429 | + tty.c_oflag |= OPOST; | ||
1430 | + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); | ||
1431 | + tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS); | ||
1432 | + switch(data_bits) { | ||
1433 | + default: | ||
1434 | + case 8: | ||
1435 | + tty.c_cflag |= CS8; | ||
1436 | + break; | ||
1437 | + case 7: | ||
1438 | + tty.c_cflag |= CS7; | ||
1439 | + break; | ||
1440 | + case 6: | ||
1441 | + tty.c_cflag |= CS6; | ||
1442 | + break; | ||
1443 | + case 5: | ||
1444 | + tty.c_cflag |= CS5; | ||
1445 | + break; | ||
1446 | + } | ||
1447 | + switch(parity) { | ||
1448 | + default: | ||
1449 | + case 'N': | ||
1450 | + break; | ||
1451 | + case 'E': | ||
1452 | + tty.c_cflag |= PARENB; | ||
1453 | + break; | ||
1454 | + case 'O': | ||
1455 | + tty.c_cflag |= PARENB | PARODD; | ||
1456 | + break; | ||
1457 | + } | ||
1458 | + | ||
1459 | + tcsetattr (fd, TCSANOW, &tty); | ||
1460 | +} | ||
1461 | + | ||
1462 | +static void tty_set_serial_parameters(CharDriverState *chr, | ||
1463 | + int speed, int parity, | ||
1464 | + int data_bits, int stop_bits) | ||
1465 | +{ | ||
1466 | + FDCharDriver *s = chr->opaque; | ||
1467 | + tty_serial_init(s->fd_in, speed, parity, data_bits, stop_bits); | ||
1468 | +} | ||
1469 | + | ||
1470 | +static void tty_set_serial_break(CharDriverState *chr, int enable) | ||
1471 | +{ | ||
1472 | + FDCharDriver *s = chr->opaque; | ||
1473 | + /* XXX: find a better solution */ | ||
1474 | + if (enable) | ||
1475 | + tcsendbreak(s->fd_in, 1); | ||
1476 | +} | ||
1477 | + | ||
1478 | +CharDriverState *qemu_chr_open_tty(const char *filename) | ||
1479 | +{ | ||
1480 | + CharDriverState *chr; | ||
1481 | + int fd; | ||
1482 | + | ||
1483 | + fd = open(filename, O_RDWR); | ||
1484 | + if (fd < 0) | ||
1485 | + return NULL; | ||
1486 | + fcntl(fd, F_SETFL, O_NONBLOCK); | ||
1487 | + tty_serial_init(fd, 115200, 'N', 8, 1); | ||
1488 | + chr = qemu_chr_open_fd(fd, fd); | ||
1489 | + if (!chr) | ||
1490 | + return NULL; | ||
1491 | + chr->chr_set_serial_parameters = tty_set_serial_parameters; | ||
1492 | + chr->chr_set_serial_break = tty_set_serial_break; | ||
1493 | + return chr; | ||
1494 | +} | ||
1495 | + | ||
1337 | #else | 1496 | #else |
1338 | CharDriverState *qemu_chr_open_pty(void) | 1497 | CharDriverState *qemu_chr_open_pty(void) |
1339 | { | 1498 | { |
@@ -1345,10 +1504,15 @@ CharDriverState *qemu_chr_open_pty(void) | @@ -1345,10 +1504,15 @@ CharDriverState *qemu_chr_open_pty(void) | ||
1345 | 1504 | ||
1346 | CharDriverState *qemu_chr_open(const char *filename) | 1505 | CharDriverState *qemu_chr_open(const char *filename) |
1347 | { | 1506 | { |
1507 | + const char *p; | ||
1348 | if (!strcmp(filename, "vc")) { | 1508 | if (!strcmp(filename, "vc")) { |
1349 | return text_console_init(&display_state); | 1509 | return text_console_init(&display_state); |
1350 | } else if (!strcmp(filename, "null")) { | 1510 | } else if (!strcmp(filename, "null")) { |
1351 | return qemu_chr_open_null(); | 1511 | return qemu_chr_open_null(); |
1512 | + } else if (strstart(filename, "file:", &p)) { | ||
1513 | + return qemu_chr_open_file_out(p); | ||
1514 | + } else if (strstart(filename, "pipe:", &p)) { | ||
1515 | + return qemu_chr_open_pipe(p); | ||
1352 | } else | 1516 | } else |
1353 | #ifndef _WIN32 | 1517 | #ifndef _WIN32 |
1354 | if (!strcmp(filename, "pty")) { | 1518 | if (!strcmp(filename, "pty")) { |
@@ -1357,6 +1521,11 @@ CharDriverState *qemu_chr_open(const char *filename) | @@ -1357,6 +1521,11 @@ CharDriverState *qemu_chr_open(const char *filename) | ||
1357 | return qemu_chr_open_stdio(); | 1521 | return qemu_chr_open_stdio(); |
1358 | } else | 1522 | } else |
1359 | #endif | 1523 | #endif |
1524 | +#if defined(__linux__) | ||
1525 | + if (strstart(filename, "/dev/", NULL)) { | ||
1526 | + return qemu_chr_open_tty(filename); | ||
1527 | + } else | ||
1528 | +#endif | ||
1360 | { | 1529 | { |
1361 | return NULL; | 1530 | return NULL; |
1362 | } | 1531 | } |
@@ -3010,7 +3179,6 @@ void help(void) | @@ -3010,7 +3179,6 @@ void help(void) | ||
3010 | "-no-code-copy disable code copy acceleration\n" | 3179 | "-no-code-copy disable code copy acceleration\n" |
3011 | #endif | 3180 | #endif |
3012 | #ifdef TARGET_I386 | 3181 | #ifdef TARGET_I386 |
3013 | - "-isa simulate an ISA-only system (default is PCI system)\n" | ||
3014 | "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" | 3182 | "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" |
3015 | " (default is CL-GD5446 PCI VGA)\n" | 3183 | " (default is CL-GD5446 PCI VGA)\n" |
3016 | #endif | 3184 | #endif |
vl.h
@@ -207,6 +207,10 @@ typedef struct CharDriverState { | @@ -207,6 +207,10 @@ typedef struct CharDriverState { | ||
207 | void (*chr_add_read_handler)(struct CharDriverState *s, | 207 | void (*chr_add_read_handler)(struct CharDriverState *s, |
208 | IOCanRWHandler *fd_can_read, | 208 | IOCanRWHandler *fd_can_read, |
209 | IOReadHandler *fd_read, void *opaque); | 209 | IOReadHandler *fd_read, void *opaque); |
210 | + void (*chr_set_serial_parameters)(struct CharDriverState *s, | ||
211 | + int speed, int parity, | ||
212 | + int data_bits, int stop_bits); | ||
213 | + void (*chr_set_serial_break)(struct CharDriverState *s, int enable); | ||
210 | IOEventHandler *chr_event; | 214 | IOEventHandler *chr_event; |
211 | void (*chr_send_event)(struct CharDriverState *chr, int event); | 215 | void (*chr_send_event)(struct CharDriverState *chr, int event); |
212 | void *opaque; | 216 | void *opaque; |
@@ -219,7 +223,11 @@ void qemu_chr_add_read_handler(CharDriverState *s, | @@ -219,7 +223,11 @@ void qemu_chr_add_read_handler(CharDriverState *s, | ||
219 | IOCanRWHandler *fd_can_read, | 223 | IOCanRWHandler *fd_can_read, |
220 | IOReadHandler *fd_read, void *opaque); | 224 | IOReadHandler *fd_read, void *opaque); |
221 | void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); | 225 | void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); |
222 | - | 226 | +void qemu_chr_set_serial_parameters(CharDriverState *s, |
227 | + int speed, int parity, | ||
228 | + int data_bits, int stop_bits); | ||
229 | +void qemu_chr_set_serial_break(CharDriverState *s, int enable); | ||
230 | + | ||
223 | /* consoles */ | 231 | /* consoles */ |
224 | 232 | ||
225 | typedef struct DisplayState DisplayState; | 233 | typedef struct DisplayState DisplayState; |