use host serial port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1609 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									3f87bf6959
								
							
						
					
					
						commit
						f8d179e33d
					
				| 
						 | 
				
			
			@ -7,7 +7,8 @@ version 0.7.3:
 | 
			
		|||
  - new audio options: '-soundhw' and '-audio-help' (malc)
 | 
			
		||||
  - ES1370 PCI audio device (malc)
 | 
			
		||||
  - Initial USB support
 | 
			
		||||
   
 | 
			
		||||
  - Linux host serial port access
 | 
			
		||||
 | 
			
		||||
version 0.7.2:
 | 
			
		||||
  
 | 
			
		||||
  - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										40
									
								
								hw/serial.c
								
								
								
								
							
							
						
						
									
										40
									
								
								hw/serial.c
								
								
								
								
							| 
						 | 
				
			
			@ -85,6 +85,7 @@ struct SerialState {
 | 
			
		|||
    int thr_ipending;
 | 
			
		||||
    int irq;
 | 
			
		||||
    CharDriverState *chr;
 | 
			
		||||
    int last_break_enable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void serial_update_irq(SerialState *s)
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +104,32 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +144,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
			
		|||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -132,6 +160,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
			
		|||
    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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +172,16 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 | 
			
		|||
    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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -363,8 +363,15 @@ Virtual console
 | 
			
		|||
[Linux only] Pseudo TTY (a new PTY is automatically allocated)
 | 
			
		||||
@item null
 | 
			
		||||
void device
 | 
			
		||||
@item /dev/XXX
 | 
			
		||||
[Linux only]Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
 | 
			
		||||
parameters are set according to the emulated ones.
 | 
			
		||||
@item file:filename
 | 
			
		||||
Write output to filename. No character can be read.
 | 
			
		||||
@item stdio
 | 
			
		||||
[Unix only] standard input/output
 | 
			
		||||
@item pipe:filename
 | 
			
		||||
[Unix only] name pipe @var{filename}
 | 
			
		||||
@end table
 | 
			
		||||
The default device is @code{vc} in graphical mode and @code{stdio} in
 | 
			
		||||
non graphical mode.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										182
									
								
								vl.c
								
								
								
								
							
							
						
						
									
										182
									
								
								vl.c
								
								
								
								
							| 
						 | 
				
			
			@ -1013,6 +1013,21 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
 | 
			
		|||
    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];
 | 
			
		||||
| 
						 | 
				
			
			@ -1111,12 +1126,14 @@ static void fd_chr_add_read_handler(CharDriverState *chr,
 | 
			
		|||
{
 | 
			
		||||
    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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1142,6 +1159,27 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
 | 
			
		|||
    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) */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1334,6 +1372,127 @@ CharDriverState *qemu_chr_open_pty(void)
 | 
			
		|||
    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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1345,10 +1504,15 @@ 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")) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1356,6 +1520,11 @@ CharDriverState *qemu_chr_open(const char *filename)
 | 
			
		|||
    } else if (!strcmp(filename, "stdio")) {
 | 
			
		||||
        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;
 | 
			
		||||
| 
						 | 
				
			
			@ -3010,7 +3179,6 @@ void help(void)
 | 
			
		|||
           "-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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								vl.h
								
								
								
								
							
							
						
						
									
										10
									
								
								vl.h
								
								
								
								
							| 
						 | 
				
			
			@ -207,6 +207,10 @@ typedef struct CharDriverState {
 | 
			
		|||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +223,11 @@ void qemu_chr_add_read_handler(CharDriverState *s,
 | 
			
		|||
                               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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue