int thr_ipending;
int irq;
CharDriverState *chr;
+ int last_break_enable;
};
static void serial_update_irq(SerialState *s)
}
}
+static void serial_update_parameters(SerialState *s)
+{
+ int speed, parity, data_bits, stop_bits;
+
+ if (s->lcr & 0x08) {
+ if (s->lcr & 0x10)
+ parity = 'E';
+ else
+ parity = 'O';
+ } else {
+ parity = 'N';
+ }
+ if (s->lcr & 0x04)
+ stop_bits = 2;
+ else
+ stop_bits = 1;
+ data_bits = (s->lcr & 0x03) + 5;
+ if (s->divider == 0)
+ return;
+ speed = 115200 / s->divider;
+#if 0
+ printf("speed=%d parity=%c data=%d stop=%d\n",
+ speed, parity, data_bits, stop_bits);
+#endif
+}
+
static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
SerialState *s = opaque;
case 0:
if (s->lcr & UART_LCR_DLAB) {
s->divider = (s->divider & 0xff00) | val;
+ serial_update_parameters(s);
} else {
s->thr_ipending = 0;
s->lsr &= ~UART_LSR_THRE;
case 1:
if (s->lcr & UART_LCR_DLAB) {
s->divider = (s->divider & 0x00ff) | (val << 8);
+ serial_update_parameters(s);
} else {
s->ier = val & 0x0f;
if (s->lsr & UART_LSR_THRE) {
case 2:
break;
case 3:
- s->lcr = val;
+ {
+ int break_enable;
+ s->lcr = val;
+ serial_update_parameters(s);
+ break_enable = (val >> 6) & 1;
+ if (break_enable != s->last_break_enable) {
+ s->last_break_enable = break_enable;
+ qemu_chr_set_serial_break(s, break_enable);
+ }
+ }
break;
case 4:
s->mcr = val & 0x1f;
return s->chr_write(s, buf, len);
}
+void qemu_chr_set_serial_parameters(CharDriverState *s,
+ int speed, int parity,
+ int data_bits, int stop_bits)
+{
+ if (s->chr_set_serial_parameters)
+ s->chr_set_serial_parameters(s, speed, parity, data_bits, stop_bits);
+}
+
+void qemu_chr_set_serial_break(CharDriverState *s, int enable)
+{
+ if (s->chr_set_serial_break)
+ s->chr_set_serial_break(s, enable);
+}
+
+
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
{
char buf[4096];
{
FDCharDriver *s = chr->opaque;
- if (nographic && s->fd_in == 0) {
- s->fd_can_read = fd_can_read;
- s->fd_read = fd_read;
- s->fd_opaque = opaque;
- } else {
- qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque);
+ if (s->fd_in >= 0) {
+ if (nographic && s->fd_in == 0) {
+ s->fd_can_read = fd_can_read;
+ s->fd_read = fd_read;
+ s->fd_opaque = opaque;
+ } else {
+ qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque);
+ }
}
}
return chr;
}
+CharDriverState *qemu_chr_open_file_out(const char *file_out)
+{
+ int fd_out;
+
+ fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY);
+ if (fd_out < 0)
+ return NULL;
+ return qemu_chr_open_fd(-1, fd_out);
+}
+
+CharDriverState *qemu_chr_open_pipe(const char *filename)
+{
+ int fd;
+
+ fd = open(filename, O_RDWR | O_BINARY);
+ if (fd < 0)
+ return NULL;
+ return qemu_chr_open_fd(fd, fd);
+}
+
+
/* for STDIO, we handle the case where several clients use it
(nographic mode) */
fprintf(stderr, "char device redirected to %s\n", slave_name);
return qemu_chr_open_fd(master_fd, master_fd);
}
+
+static void tty_serial_init(int fd, int speed,
+ int parity, int data_bits, int stop_bits)
+{
+ struct termios tty;
+ speed_t spd;
+
+ tcgetattr (0, &tty);
+
+ switch(speed) {
+ case 50:
+ spd = B50;
+ break;
+ case 75:
+ spd = B75;
+ break;
+ case 300:
+ spd = B300;
+ break;
+ case 600:
+ spd = B600;
+ break;
+ case 1200:
+ spd = B1200;
+ break;
+ case 2400:
+ spd = B2400;
+ break;
+ case 4800:
+ spd = B4800;
+ break;
+ case 9600:
+ spd = B9600;
+ break;
+ case 19200:
+ spd = B19200;
+ break;
+ case 38400:
+ spd = B38400;
+ break;
+ case 57600:
+ spd = B57600;
+ break;
+ default:
+ case 115200:
+ spd = B115200;
+ break;
+ }
+
+ cfsetispeed(&tty, spd);
+ cfsetospeed(&tty, spd);
+
+ tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+ |INLCR|IGNCR|ICRNL|IXON);
+ tty.c_oflag |= OPOST;
+ tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
+ tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS);
+ switch(data_bits) {
+ default:
+ case 8:
+ tty.c_cflag |= CS8;
+ break;
+ case 7:
+ tty.c_cflag |= CS7;
+ break;
+ case 6:
+ tty.c_cflag |= CS6;
+ break;
+ case 5:
+ tty.c_cflag |= CS5;
+ break;
+ }
+ switch(parity) {
+ default:
+ case 'N':
+ break;
+ case 'E':
+ tty.c_cflag |= PARENB;
+ break;
+ case 'O':
+ tty.c_cflag |= PARENB | PARODD;
+ break;
+ }
+
+ tcsetattr (fd, TCSANOW, &tty);
+}
+
+static void tty_set_serial_parameters(CharDriverState *chr,
+ int speed, int parity,
+ int data_bits, int stop_bits)
+{
+ FDCharDriver *s = chr->opaque;
+ tty_serial_init(s->fd_in, speed, parity, data_bits, stop_bits);
+}
+
+static void tty_set_serial_break(CharDriverState *chr, int enable)
+{
+ FDCharDriver *s = chr->opaque;
+ /* XXX: find a better solution */
+ if (enable)
+ tcsendbreak(s->fd_in, 1);
+}
+
+CharDriverState *qemu_chr_open_tty(const char *filename)
+{
+ CharDriverState *chr;
+ int fd;
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0)
+ return NULL;
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ tty_serial_init(fd, 115200, 'N', 8, 1);
+ chr = qemu_chr_open_fd(fd, fd);
+ if (!chr)
+ return NULL;
+ chr->chr_set_serial_parameters = tty_set_serial_parameters;
+ chr->chr_set_serial_break = tty_set_serial_break;
+ return chr;
+}
+
#else
CharDriverState *qemu_chr_open_pty(void)
{
CharDriverState *qemu_chr_open(const char *filename)
{
+ const char *p;
if (!strcmp(filename, "vc")) {
return text_console_init(&display_state);
} else if (!strcmp(filename, "null")) {
return qemu_chr_open_null();
+ } else if (strstart(filename, "file:", &p)) {
+ return qemu_chr_open_file_out(p);
+ } else if (strstart(filename, "pipe:", &p)) {
+ return qemu_chr_open_pipe(p);
} else
#ifndef _WIN32
if (!strcmp(filename, "pty")) {
return qemu_chr_open_stdio();
} else
#endif
+#if defined(__linux__)
+ if (strstart(filename, "/dev/", NULL)) {
+ return qemu_chr_open_tty(filename);
+ } else
+#endif
{
return NULL;
}
"-no-code-copy disable code copy acceleration\n"
#endif
#ifdef TARGET_I386
- "-isa simulate an ISA-only system (default is PCI system)\n"
"-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
" (default is CL-GD5446 PCI VGA)\n"
#endif
void (*chr_add_read_handler)(struct CharDriverState *s,
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque);
+ void (*chr_set_serial_parameters)(struct CharDriverState *s,
+ int speed, int parity,
+ int data_bits, int stop_bits);
+ void (*chr_set_serial_break)(struct CharDriverState *s, int enable);
IOEventHandler *chr_event;
void (*chr_send_event)(struct CharDriverState *chr, int event);
void *opaque;
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque);
void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event);
-
+void qemu_chr_set_serial_parameters(CharDriverState *s,
+ int speed, int parity,
+ int data_bits, int stop_bits);
+void qemu_chr_set_serial_break(CharDriverState *s, int enable);
+
/* consoles */
typedef struct DisplayState DisplayState;