qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] patch for serial port support(linux host only)


From: Cai Qiang
Subject: [Qemu-devel] patch for serial port support(linux host only)
Date: Mon, 9 May 2005 10:01:07 +0000
User-agent: KMail/1.6.1

Hi,
        Here are patch for serial port support(partial; linux host only). You 
can 
invoke it by adding sth like "-serial /dev/ttyS0" in arguments to let qemu 
using host's serial port as its serial port. qemu will change host's serial 
port setting(baudrate, databits, stopbits, parity) when guest os change them. 
In my test, I use minicom's zmodem to send file. When sending file to qemu, 
things works fine. When sending file from qemu, file can be sent completely, 
but qemu gives many warning saying "serial8250: too much work for irq4".
        I has also worked on serial port support for windows host, but my build 
of 
qemu always crash, althrough I have tried different method: cross-compile 
using i386-mingw32msvc;  mingw/msys. If anyone who has build qemu windows 
port can teach me about it, I will try to finish my windows support when I 
get time.

        Any comments/tests are welcome.

Best Regards

        Cai Qiang


--- qemu-0.7.0/vl.c     2005-04-27 20:52:05.000000000 +0000
+++ qemu-0.7.0-serialport/vl.c  2005-05-09 09:24:43.000000000 +0000
@@ -1226,13 +1226,13 @@
     fcntl(0, F_SETFL, old_fd0_flags);
 }
 
-static void term_init(void)
+static void term_init(int in)
 {
     struct termios tty;
 
-    tcgetattr (0, &tty);
+    tcgetattr (in, &tty);
     oldtty = tty;
-    old_fd0_flags = fcntl(0, F_GETFL);
+    old_fd0_flags = fcntl(in, F_GETFL);
 
     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                           |INLCR|IGNCR|ICRNL|IXON);
@@ -1246,11 +1246,11 @@
     tty.c_cc[VMIN] = 1;
     tty.c_cc[VTIME] = 0;
     
-    tcsetattr (0, TCSANOW, &tty);
+    tcsetattr (in, TCSANOW, &tty);
 
     atexit(term_exit);
 
-    fcntl(0, F_SETFL, O_NONBLOCK);
+    fcntl(in, F_SETFL, O_NONBLOCK);
 }
 
 CharDriverState *qemu_chr_open_stdio(void)
@@ -1272,7 +1272,7 @@
     stdio_clients[stdio_nb_clients++] = chr;
     if (stdio_nb_clients == 1) {
         /* set the terminal in raw mode */
-        term_init();
+        term_init(0);
     }
     return chr;
 }
@@ -1290,6 +1290,126 @@
     fprintf(stderr, "char device redirected to %s\n", slave_name);
     return qemu_chr_open_fd(master_fd, master_fd);
 }
+
+#include <termios.h>
+static void set_baudrate(int fd, int v)
+{
+       struct termios newtio;
+       int BaudRate;
+
+  switch (v) {
+    case 600:  BaudRate = B600;        break;
+    case 1200:         BaudRate = B1200;       break;
+    case 2400:         BaudRate = B2400;       break;
+    case 4800:         BaudRate = B4800;       break;
+    case 9600:         BaudRate = B9600;       break;
+    case 19200: BaudRate = B19200;     break;
+    case 38400: BaudRate = B38400;     break;
+    case 57600: BaudRate = B57600;     break;
+    case 115200:BaudRate = B115200; break;
+       default:        BaudRate=B115200;       break;
+  }
+
+    tcgetattr( fd,&newtio);
+       newtio.c_cflag &= ~CBAUD;
+       newtio.c_cflag |= BaudRate;
+    tcflush(fd, TCIFLUSH);
+    tcsetattr(fd,TCSANOW,&newtio);
+}
+
+static void set_databits(int fd, int v)
+{
+       struct termios newtio;
+
+    tcgetattr( fd,&newtio);
+       newtio.c_cflag &= ~CSIZE;
+       const int databits[] = { CS5, CS6, CS7, CS8 };
+       v-=5;
+       newtio.c_cflag |= 
v<sizeof(databits)/sizeof(databits[0])?databits[v]:CS8;
+    tcflush(fd, TCIFLUSH);
+    tcsetattr(fd,TCSANOW,&newtio);
+}
+
+static void set_stopbits(int fd, int v)
+{
+       struct termios newtio;
+
+    tcgetattr( fd,&newtio);
+       if (v==2)
+               newtio.c_cflag |= CSTOPB;
+       else
+               newtio.c_cflag &= ~CSTOPB;
+    tcflush(fd, TCIFLUSH);
+    tcsetattr(fd,TCSANOW,&newtio);
+}
+static void set_parity(int fd, int v)
+{
+       struct termios newtio;
+
+    tcgetattr( fd,&newtio);
+       switch (v) {
+       case 0:
+                       newtio.c_iflag=0;
+               break;
+       case 1:
+               newtio.c_iflag = INPCK;
+                       newtio.c_cflag |= PARENB|PARODD;
+               break;
+       case 2:
+               newtio.c_iflag = INPCK;
+                       newtio.c_cflag |= PARENB;
+                       newtio.c_cflag &= ~PARODD;
+               break;
+               case 3:
+               break;
+       case 4:
+               break;
+       }
+    tcflush(fd, TCIFLUSH);
+    tcsetattr(fd,TCSANOW,&newtio);
+}
+
+static void Notify_serial_param_set( CharDriverState *chr, int msg)
+{
+       if (chr != NULL) {
+               int mode=msg>>16, param=msg&0xffff;
+               int pmode;              
+               switch (mode) {
+                       case 0:
+                       case 1:
+#define  PC_CLOCK_XTL   1843200.0
+                               set_baudrate(((FDCharDriver 
*)(chr->opaque))->fd_in, (int) 
(PC_CLOCK_XTL /(16 * param)));
+                               break;
+                       case 3:         //lcr
+                       set_databits(((FDCharDriver 
*)(chr->opaque))->fd_in,(param&0x03) 
+ 5);
+                       set_stopbits(((FDCharDriver *)(chr->opaque))->fd_in,
(param&(1<<2)) ? 2 : 1);
+                       if ((param&(1<<3)) == 0)
+                               pmode = 0;
+                       else
+                           pmode = ((param & 0x30) >> 4) + 1;
+                       set_parity(((FDCharDriver 
*)(chr->opaque))->fd_in,pmode);
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+static CharDriverState *qemu_chr_open_dev(const char *devname)
+{
+    int fd;
+       CharDriverState *s;
+    
+    if ( (fd=open(devname, O_RDWR|O_NDELAY)) < 0) 
+        return NULL;
+    s = qemu_chr_open_fd(fd, fd);
+       if (s!=NULL) {
+               s->chr_send_event=Notify_serial_param_set;
+           /* set the terminal in raw mode */
+           term_init(fd);
+       }
+    return s;
+}
 #else
 CharDriverState *qemu_chr_open_pty(void)
 {
@@ -1311,6 +1431,8 @@
         return qemu_chr_open_pty();
     } else if (!strcmp(filename, "stdio")) {
         return qemu_chr_open_stdio();
+    } else if (!strncmp(filename, "/dev/", 5)) {
+        return qemu_chr_open_dev(filename);
     } else 
 #endif
     {

--- qemu-0.7.0/hw/serial.c      2005-04-27 20:52:05.000000000 +0000
+++ qemu-0.7.0-serialport/hw/serial.c   2005-05-09 09:14:39.000000000 +0000
@@ -117,6 +117,7 @@
     case 0:
         if (s->lcr & UART_LCR_DLAB) {
             s->divider = (s->divider & 0xff00) | val;
+                       qemu_chr_send_event(s->chr, (addr<<16)|s->divider);
         } else {
             s->thr_ipending = 0;
             s->lsr &= ~UART_LSR_THRE;
@@ -132,6 +133,7 @@
     case 1:
         if (s->lcr & UART_LCR_DLAB) {
             s->divider = (s->divider & 0x00ff) | (val << 8);
+                       qemu_chr_send_event(s->chr, (addr<<16)|s->divider);
         } else {
             s->ier = val & 0x0f;
             if (s->lsr & UART_LSR_THRE) {
@@ -144,6 +146,7 @@
         break;
     case 3:
         s->lcr = val;
+               qemu_chr_send_event(s->chr, (addr<<16)|val);
         break;
     case 4:
         s->mcr = val & 0x1f;








reply via email to

[Prev in Thread] Current Thread [Next in Thread]