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; | ... | ... |