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 | - new audio options: '-soundhw' and '-audio-help' (malc) |
| 8 | 8 | - ES1370 PCI audio device (malc) |
| 9 | 9 | - Initial USB support |
| 10 | - | |
| 10 | + - Linux host serial port access | |
| 11 | + | |
| 11 | 12 | version 0.7.2: |
| 12 | 13 | |
| 13 | 14 | - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit) | ... | ... |
hw/serial.c
| ... | ... | @@ -85,6 +85,7 @@ struct SerialState { |
| 85 | 85 | int thr_ipending; |
| 86 | 86 | int irq; |
| 87 | 87 | CharDriverState *chr; |
| 88 | + int last_break_enable; | |
| 88 | 89 | }; |
| 89 | 90 | |
| 90 | 91 | 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 | 133 | static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 107 | 134 | { |
| 108 | 135 | SerialState *s = opaque; |
| ... | ... | @@ -117,6 +144,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 117 | 144 | case 0: |
| 118 | 145 | if (s->lcr & UART_LCR_DLAB) { |
| 119 | 146 | s->divider = (s->divider & 0xff00) | val; |
| 147 | + serial_update_parameters(s); | |
| 120 | 148 | } else { |
| 121 | 149 | s->thr_ipending = 0; |
| 122 | 150 | s->lsr &= ~UART_LSR_THRE; |
| ... | ... | @@ -132,6 +160,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 132 | 160 | case 1: |
| 133 | 161 | if (s->lcr & UART_LCR_DLAB) { |
| 134 | 162 | s->divider = (s->divider & 0x00ff) | (val << 8); |
| 163 | + serial_update_parameters(s); | |
| 135 | 164 | } else { |
| 136 | 165 | s->ier = val & 0x0f; |
| 137 | 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 | 172 | case 2: |
| 144 | 173 | break; |
| 145 | 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 | 185 | break; |
| 148 | 186 | case 4: |
| 149 | 187 | s->mcr = val & 0x1f; | ... | ... |
qemu-doc.texi
| ... | ... | @@ -363,8 +363,15 @@ Virtual console |
| 363 | 363 | [Linux only] Pseudo TTY (a new PTY is automatically allocated) |
| 364 | 364 | @item null |
| 365 | 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 | 371 | @item stdio |
| 367 | 372 | [Unix only] standard input/output |
| 373 | +@item pipe:filename | |
| 374 | +[Unix only] name pipe @var{filename} | |
| 368 | 375 | @end table |
| 369 | 376 | The default device is @code{vc} in graphical mode and @code{stdio} in |
| 370 | 377 | non graphical mode. | ... | ... |
vl.c
| ... | ... | @@ -1013,6 +1013,21 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) |
| 1013 | 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 | 1031 | void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) |
| 1017 | 1032 | { |
| 1018 | 1033 | char buf[4096]; |
| ... | ... | @@ -1111,12 +1126,14 @@ static void fd_chr_add_read_handler(CharDriverState *chr, |
| 1111 | 1126 | { |
| 1112 | 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 | 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 | 1183 | /* for STDIO, we handle the case where several clients use it |
| 1146 | 1184 | (nographic mode) */ |
| 1147 | 1185 | |
| ... | ... | @@ -1334,6 +1372,127 @@ CharDriverState *qemu_chr_open_pty(void) |
| 1334 | 1372 | fprintf(stderr, "char device redirected to %s\n", slave_name); |
| 1335 | 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 | 1496 | #else |
| 1338 | 1497 | CharDriverState *qemu_chr_open_pty(void) |
| 1339 | 1498 | { |
| ... | ... | @@ -1345,10 +1504,15 @@ CharDriverState *qemu_chr_open_pty(void) |
| 1345 | 1504 | |
| 1346 | 1505 | CharDriverState *qemu_chr_open(const char *filename) |
| 1347 | 1506 | { |
| 1507 | + const char *p; | |
| 1348 | 1508 | if (!strcmp(filename, "vc")) { |
| 1349 | 1509 | return text_console_init(&display_state); |
| 1350 | 1510 | } else if (!strcmp(filename, "null")) { |
| 1351 | 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 | 1516 | } else |
| 1353 | 1517 | #ifndef _WIN32 |
| 1354 | 1518 | if (!strcmp(filename, "pty")) { |
| ... | ... | @@ -1357,6 +1521,11 @@ CharDriverState *qemu_chr_open(const char *filename) |
| 1357 | 1521 | return qemu_chr_open_stdio(); |
| 1358 | 1522 | } else |
| 1359 | 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 | 1530 | return NULL; |
| 1362 | 1531 | } |
| ... | ... | @@ -3010,7 +3179,6 @@ void help(void) |
| 3010 | 3179 | "-no-code-copy disable code copy acceleration\n" |
| 3011 | 3180 | #endif |
| 3012 | 3181 | #ifdef TARGET_I386 |
| 3013 | - "-isa simulate an ISA-only system (default is PCI system)\n" | |
| 3014 | 3182 | "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" |
| 3015 | 3183 | " (default is CL-GD5446 PCI VGA)\n" |
| 3016 | 3184 | #endif | ... | ... |
vl.h
| ... | ... | @@ -207,6 +207,10 @@ typedef struct CharDriverState { |
| 207 | 207 | void (*chr_add_read_handler)(struct CharDriverState *s, |
| 208 | 208 | IOCanRWHandler *fd_can_read, |
| 209 | 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 | 214 | IOEventHandler *chr_event; |
| 211 | 215 | void (*chr_send_event)(struct CharDriverState *chr, int event); |
| 212 | 216 | void *opaque; |
| ... | ... | @@ -219,7 +223,11 @@ void qemu_chr_add_read_handler(CharDriverState *s, |
| 219 | 223 | IOCanRWHandler *fd_can_read, |
| 220 | 224 | IOReadHandler *fd_read, void *opaque); |
| 221 | 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 | 231 | /* consoles */ |
| 224 | 232 | |
| 225 | 233 | typedef struct DisplayState DisplayState; | ... | ... |