allow host serial port usage (Blue Swirl)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 9 Sep 2006 12:17:15 +0000 (12:17 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 9 Sep 2006 12:17:15 +0000 (12:17 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2153 c046a42c-6fe2-441c-8c8c-71466251a162

hw/slavio_serial.c

index 7112bec..404138d 100644 (file)
@@ -74,6 +74,8 @@ typedef enum {
     chn_a, chn_b,
 } chn_id_t;
 
+#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
+
 typedef enum {
     ser, kbd, mouse,
 } chn_type_t;
@@ -113,7 +115,7 @@ static void put_queue(void *opaque, int b)
     ChannelState *s = opaque;
     SERIOQueue *q = &s->queue;
 
-    SER_DPRINTF("put: 0x%02x\n", b);
+    SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
     if (q->count >= SERIO_QUEUE_SIZE)
         return;
     q->data[q->wptr] = b;
@@ -137,7 +139,7 @@ static uint32_t get_queue(void *opaque)
             q->rptr = 0;
         q->count--;
     }
-    KBD_DPRINTF("get 0x%02x\n", val);
+    KBD_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
     if (q->count > 0)
        serial_receive_byte(s, 0);
     return val;
@@ -198,11 +200,10 @@ static inline void clr_rxint(ChannelState *s)
 {
     s->rxint = 0;
     s->rxint_under_svc = 0;
-    if (s->chn == 0)
+    if (s->chn == chn_a)
         s->rregs[3] &= ~0x20;
-    else {
+    else
         s->otherchn->rregs[3] &= ~4;
-    }
     if (s->txint)
         set_txint(s);
     else
@@ -215,11 +216,10 @@ static inline void set_rxint(ChannelState *s)
     s->rxint = 1;
     if (!s->txint_under_svc) {
         s->rxint_under_svc = 1;
-        if (s->chn == 0)
+        if (s->chn == chn_a)
             s->rregs[3] |= 0x20;
-        else {
+        else
             s->otherchn->rregs[3] |= 4;
-        }
         s->rregs[2] = 4;
         slavio_serial_update_irq(s);
     }
@@ -229,11 +229,10 @@ static inline void clr_txint(ChannelState *s)
 {
     s->txint = 0;
     s->txint_under_svc = 0;
-    if (s->chn == 0)
+    if (s->chn == chn_a)
         s->rregs[3] &= ~0x10;
-    else {
+    else
         s->otherchn->rregs[3] &= ~2;
-    }
     if (s->rxint)
         set_rxint(s);
     else
@@ -246,16 +245,74 @@ static inline void set_txint(ChannelState *s)
     s->txint = 1;
     if (!s->rxint_under_svc) {
         s->txint_under_svc = 1;
-        if (s->chn == 0)
+        if (s->chn == chn_a)
             s->rregs[3] |= 0x10;
-        else {
+        else
             s->otherchn->rregs[3] |= 2;
-        }
         s->rregs[2] = 0;
         slavio_serial_update_irq(s);
     }
 }
 
+static void slavio_serial_update_parameters(ChannelState *s)
+{
+    int speed, parity, data_bits, stop_bits;
+    QEMUSerialSetParams ssp;
+
+    if (!s->chr || s->type != ser)
+        return;
+
+    if (s->wregs[4] & 1) {
+        if (s->wregs[4] & 2)
+            parity = 'E';
+        else
+            parity = 'O';
+    } else {
+        parity = 'N';
+    }
+    if ((s->wregs[4] & 0x0c) == 0x0c)
+        stop_bits = 2;
+    else
+        stop_bits = 1;
+    switch (s->wregs[5] & 0x60) {
+    case 0x00:
+        data_bits = 5;
+        break;
+    case 0x20:
+        data_bits = 7;
+        break;
+    case 0x40:
+        data_bits = 6;
+        break;
+    default:
+    case 0x60:
+        data_bits = 8;
+        break;
+    }
+    speed = 2457600 / ((s->wregs[12] | (s->wregs[13] << 8)) + 2);
+    switch (s->wregs[4] & 0xc0) {
+    case 0x00:
+        break;
+    case 0x40:
+        speed /= 16;
+        break;
+    case 0x80:
+        speed /= 32;
+        break;
+    default:
+    case 0xc0:
+        speed /= 64;
+        break;
+    }
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
+                speed, parity, data_bits, stop_bits);
+    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+}
+
 static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     SerialState *ser = opaque;
@@ -269,7 +326,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
     s = &ser->chn[channel];
     switch (saddr) {
     case 0:
-       SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
+       SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff);
        newreg = 0;
        switch (s->reg) {
        case 0:
@@ -292,9 +349,18 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
                break;
            }
            break;
-       case 1 ... 8:
-       case 10 ... 15:
+        case 1 ... 3:
+        case 6 ... 8:
+        case 10 ... 11:
+        case 14 ... 15:
+           s->wregs[s->reg] = val;
+           break;
+        case 4:
+        case 5:
+        case 12:
+        case 13:
            s->wregs[s->reg] = val;
+            slavio_serial_update_parameters(s);
            break;
        case 9:
            switch (val & 0xc0) {
@@ -321,7 +387,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
            s->reg = 0;
        break;
     case 1:
-       SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
+       SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
        if (s->wregs[5] & 8) { // tx enabled
            s->tx = val;
            if (s->chr)
@@ -352,7 +418,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
     s = &ser->chn[channel];
     switch (saddr) {
     case 0:
-       SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
+       SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]);
        ret = s->rregs[s->reg];
        s->reg = 0;
        return ret;
@@ -363,7 +429,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
            ret = get_queue(s);
        else
            ret = s->rx;
-       SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret);
+       SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
        return ret;
     default:
        break;
@@ -381,13 +447,13 @@ static int serial_can_receive(void *opaque)
        ret = 0;
     else
        ret = 1;
-    SER_DPRINTF("can receive %d\n", ret);
+    //SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret);
     return ret;
 }
 
 static void serial_receive_byte(ChannelState *s, int ch)
 {
-    SER_DPRINTF("put ch %d\n", ch);
+    SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
     s->rregs[0] |= 1;
     s->rx = ch;
     set_rxint(s);