qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 05/11] Goldfish: Added a tty device:


From: Patrick Jackson
Subject: [Qemu-devel] [PATCH 05/11] Goldfish: Added a tty device:
Date: Mon, 22 Aug 2011 05:39:00 -0400


This device allows for viewing the kernel output using the command line options below.

-append "console=ttyS0" -serial stdio

Signed-off-by: Patrick Jackson <address@hidden>
---
 Makefile.target      |    1 +
 hw/android_arm.c     |    9 ++
 hw/goldfish_device.h |    1 +
 hw/goldfish_tty.c    |  227 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 238 insertions(+), 0 deletions(-)
 create mode 100644 hw/goldfish_tty.c

diff --git a/Makefile.target b/Makefile.target
index 2c802fa..ec8d189 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -361,6 +361,7 @@ obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
 obj-arm-y += android_arm.o goldfish_device.o goldfish_interrupt.o goldfish_timer.o
+obj-arm-y += goldfish_tty.o
 
 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/android_arm.c b/hw/android_arm.c
index 90c75c5..89b07d1 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -40,6 +40,7 @@ static void android_arm_init_(ram_addr_t ram_size,
     qemu_irq *cpu_pic;
     ram_addr_t ram_offset;
     DeviceState *gf_int;
+    int i;
 
     if (!cpu_model)
         cpu_model = "arm926";
@@ -55,6 +56,14 @@ static void android_arm_init_(ram_addr_t ram_size,
     goldfish_device_init(gf_int, 0xff010000, 10);
     goldfish_timer_create(gbus, 0xff003000, 3);
     goldfish_rtc_create(gbus);
+    goldfish_tty_create(gbus, serial_hds[0], 0, 0xff002000, 4);
+    for(i = 1; i < MAX_SERIAL_PORTS; i++) {
+        //printf("android_arm_init serial %d %x\n", i, serial_hds[i]);
+        if(serial_hds[i]) {
+            printf("serial_hds: %d\n",i);
+            goldfish_tty_create(gbus, serial_hds[i], i, 0, 0);
+        }
+    }
 
     info.ram_size        = ram_size;
     info.kernel_filename = kernel_filename;
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
index 0d5b91e..4a123e5 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -45,6 +45,7 @@ GoldfishBus *goldfish_bus_init(uint32_t base, uint32_t irq);
 DeviceState *goldfish_int_create(GoldfishBus *gbus, uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq);
 DeviceState *goldfish_timer_create(GoldfishBus *gbus, uint32_t base, int irq);
 DeviceState *goldfish_rtc_create(GoldfishBus *gbus);
+DeviceState *goldfish_tty_create(GoldfishBus *gbus, CharDriverState *cs, int id, uint32_t base, int irq);
 
 /* Global functions provided by Goldfish devices */
 void goldfish_bus_register_withprop(GoldfishDeviceInfo *info);
diff --git a/hw/goldfish_tty.c b/hw/goldfish_tty.c
new file mode 100644
index 0000000..9b99013
--- /dev/null
+++ b/hw/goldfish_tty.c
@@ -0,0 +1,227 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#include "goldfish_device.h"
+#include "qemu-char.h"
+
+#ifdef TARGET_I386
+#include "kvm.h"
+#endif
+
+enum {
+    TTY_PUT_CHAR       = 0x00,
+    TTY_BYTES_READY    = 0x04,
+    TTY_CMD            = 0x08,
+
+    TTY_DATA_PTR       = 0x10,
+    TTY_DATA_LEN       = 0x14,
+
+    TTY_CMD_INT_DISABLE    = 0,
+    TTY_CMD_INT_ENABLE     = 1,
+    TTY_CMD_WRITE_BUFFER   = 2,
+    TTY_CMD_READ_BUFFER    = 3,
+};
+
+typedef struct GoldfishTTYDevice {
+    GoldfishDevice dev;
+    CharDriverState *cs;
+    uint32_t ptr;
+    uint32_t ptr_len;
+    uint32_t ready;
+    uint8_t data[128];
+    uint32_t data_count;
+} GoldfishTTYDevice;
+
+static uint32_t goldfish_tty_read(void *opaque, target_phys_addr_t offset)
+{
+    GoldfishTTYDevice *s = (GoldfishTTYDevice *)opaque;
+
+    //printf("goldfish_tty_read %x %x\n", offset, size);
+
+    switch (offset) {
+        case TTY_BYTES_READY:
+            return s->data_count;
+    default:
+        cpu_abort (cpu_single_env, "goldfish_tty_read: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void goldfish_tty_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+    GoldfishTTYDevice *s = (GoldfishTTYDevice *)opaque;
+
+    //printf("goldfish_tty_read %x %x %x\n", offset, value, size);
+
+    switch(offset) {
+        case TTY_PUT_CHAR: {
+            uint8_t ch = value;
+            if(s->cs)
+                qemu_chr_write(s->cs, &ch, 1);
+        } break;
+
+        case TTY_CMD:
+            switch(value) {
+                case TTY_CMD_INT_DISABLE:
+                    if(s->ready) {
+                        if(s->data_count > 0)
+                            goldfish_device_set_irq(&s->dev, 0, 0);
+                        s->ready = 0;
+                    }
+                    break;
+
+                case TTY_CMD_INT_ENABLE:
+                    if(!s->ready) {
+                        if(s->data_count > 0)
+                            goldfish_device_set_irq(&s->dev, 0, 1);
+                        s->ready = 1;
+                    }
+                    break;
+
+                case TTY_CMD_WRITE_BUFFER:
+                    if(s->cs) {
+                        int len;
+                        target_phys_addr_t  buf;
+
+                        buf = s->ptr;
+                        len = s->ptr_len;
+
+                        while (len) {
+                            char   temp[64];
+                            int    to_write = sizeof(temp);
+                            if (to_write > len)
+                                to_write = len;
+
+#ifdef TARGET_I386
+                            if (kvm_enabled())
+                                cpu_synchronize_state(cpu_single_env, 0);
+#endif
+                            cpu_memory_rw_debug(cpu_single_env, buf, (uint8_t*)temp, to_write, 0);
+                            qemu_chr_write(s->cs, (const uint8_t*)temp, to_write);
+                            buf += to_write;
+                            len -= to_write;
+                        }
+                        //printf("goldfish_tty_write: got %d bytes from %x\n", s->ptr_len, s->ptr);
+                    }
+                    break;
+
+                case TTY_CMD_READ_BUFFER:
+                    if(s->ptr_len > s->data_count)
+                        cpu_abort (cpu_single_env, "goldfish_tty_write: reading more data than available %d %d\n", s->ptr_len, s->data_count);
+#ifdef TARGET_I386
+                    if (kvm_enabled())
+                        cpu_synchronize_state(cpu_single_env, 0);
+#endif
+                    cpu_memory_rw_debug(cpu_single_env,s->ptr, s->data, s->ptr_len,1);
+                    //printf("goldfish_tty_write: read %d bytes to %x\n", s->ptr_len, s->ptr);
+                    if(s->data_count > s->ptr_len)
+                        memmove(s->data, s->data + s->ptr_len, s->data_count - s->ptr_len);
+                    s->data_count -= s->ptr_len;
+                    if(s->data_count == 0 && s->ready)
+                        goldfish_device_set_irq(&s->dev, 0, 0);
+                    break;
+
+                default:
+                    cpu_abort (cpu_single_env, "goldfish_tty_write: Bad command %x\n", value);
+            };
+            break;
+
+        case TTY_DATA_PTR:
+            s->ptr = value;
+            break;
+
+        case TTY_DATA_LEN:
+            s->ptr_len = value;
+            break;
+
+        default:
+            cpu_abort (cpu_single_env, "goldfish_tty_write: Bad offset %x\n", offset);
+    }
+}
+
+static int tty_can_receive(void *opaque)
+{
+    GoldfishTTYDevice *s = opaque;
+
+    return (sizeof(s->data) - s->data_count);
+}
+
+static void tty_receive(void *opaque, const uint8_t *buf, int size)
+{
+    GoldfishTTYDevice *s = opaque;
+
+    memcpy(s->data + s->data_count, buf, size);
+    s->data_count += size;
+    if(s->data_count > 0 && s->ready)
+        goldfish_device_set_irq(&s->dev, 0, 1);
+}
+
+static CPUReadMemoryFunc *goldfish_tty_readfn[] = {
+    goldfish_tty_read,
+    goldfish_tty_read,
+    goldfish_tty_read
+};
+
+static CPUWriteMemoryFunc *goldfish_tty_writefn[] = {
+    goldfish_tty_write,
+    goldfish_tty_write,
+    goldfish_tty_write
+};
+
+static int goldfish_tty_init(GoldfishDevice *dev)
+{
+    GoldfishTTYDevice *tdev = (GoldfishTTYDevice *)dev;
+    if(tdev->cs) {
+        qemu_chr_add_handlers(tdev->cs, tty_can_receive, tty_receive, NULL, tdev);
+    }
+
+    return 0;
+}
+
+DeviceState *goldfish_tty_create(GoldfishBus *gbus, CharDriverState *cs, int id, uint32_t base, int irq)
+{
+    DeviceState *dev;
+    char *name = (char *)"goldfish_tty";
+
+    dev = qdev_create(&gbus->bus, name);
+    qdev_prop_set_string(dev, "name", name);
+    qdev_prop_set_uint32(dev, "id", id);
+    qdev_prop_set_uint32(dev, "base", base);
+    qdev_prop_set_uint32(dev, "irq", irq);
+    qdev_prop_set_chr(dev, "chardev", cs);
+    qdev_init_nofail(dev);
+
+    return dev;
+}
+
+static GoldfishDeviceInfo goldfish_tty_info = {
+    .init = goldfish_tty_init,
+    .readfn = goldfish_tty_readfn,
+    .writefn = goldfish_tty_writefn,
+    .qdev.name  = "goldfish_tty",
+    .qdev.size  = sizeof(GoldfishTTYDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("base", GoldfishDevice, base, 0),
+        DEFINE_PROP_UINT32("id", GoldfishDevice, id, -1),
+        DEFINE_PROP_UINT32("size", GoldfishDevice, size, 0x1000),
+        DEFINE_PROP_UINT32("irq", GoldfishDevice, irq, 0),
+        DEFINE_PROP_UINT32("irq_count", GoldfishDevice, irq_count, 1),
+        DEFINE_PROP_CHR("chardev", GoldfishTTYDevice, cs),
+        DEFINE_PROP_STRING("name", GoldfishDevice, name),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void goldfish_tty_register(void)
+{
+    goldfish_bus_register_withprop(&goldfish_tty_info);
+}
+device_init(goldfish_tty_register);
-- 
1.7.4.1


reply via email to

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