++config.status
config-devices.*
config-all-devices.*
config-all-disas.*
# xen support
obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o
- obj-$(CONFIG_NO_XEN) += xen-stub.o
+ obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o
+# HAX support
+ifdef CONFIG_WIN32
+obj-$(CONFIG_HAX) += target-i386/hax-all.o target-i386/hax-windows.o
+obj-$(CONFIG_NO_HAX) += hax-stub.o
+endif
+ifdef CONFIG_DARWIN
+obj-$(CONFIG_HAX) += target-i386/hax-all.o target-i386/hax-darwin.o
+obj-$(CONFIG_NO_HAX) += hax-stub.o
+endif
+
# Hardware support
ifeq ($(TARGET_NAME), sparc64)
obj-y += hw/sparc64/
assert(!bs->dev);
assert(!bs->job);
assert(!bs->in_use);
+ assert(!bs->refcnt);
+
+ bdrv_close(bs);
+ bdrv_close(bs);
+
/* remove from list, if necessary */
bdrv_make_anon(bs);
},
};
- static int raw_open(BlockDriverState *bs, QDict *options, int flags)
+ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
{
BDRVRawState *s = bs->opaque;
- int access_flags;
- DWORD overlapped;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
return 0;
}
- static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
+ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
{
BDRVRawState *s = bs->opaque;
+#ifndef CONFIG_MARU
int access_flags, create_flags;
+ int ret = 0;
DWORD overlapped;
+#else
+ int open_flags;
+#endif
+ int ret = 0;
char device_name[64];
Error *local_err = NULL;
if (err == ERROR_ACCESS_DENIED) {
ret = -EACCES;
} else {
- ret = -1;
+ ret = -EINVAL;
}
+ error_setg_errno(errp, -ret, "Could not open device");
goto done;
}
+#else
+ /*
+ s->hfile = CreateFile(g_win32_locale_filename_from_utf8(filename),
+ access_flags,
+ FILE_SHARE_READ, NULL,
+ create_flags, overlapped, NULL);
+ */
+ open_flags = (O_BINARY & ~O_ACCMODE);
+ if (flags & BDRV_O_RDWR) {
+ open_flags |= O_RDWR;
+ } else {
+ open_flags |= O_RDONLY;
+ }
+
+ /* Use O_DSYNC for write-through caching, no flags for write-back caching,
+ * and O_DIRECT for no caching. */
+ /*
+ if ((flags & BDRV_O_NOCACHE)) {
+ open_flags |= O_DIRECT;
+ }
+ if (!(flags & BDRV_O_CACHE_WB)) {
+ open_flags |= O_DSYNC;
+ }
+ */
+
+ ret = qemu_open(filename, open_flags, 0644);
+ if (ret < 0) {
+ error_report("raw_open failed(%d) \n", ret);
+ return -errno;
+ }
+ s->hfile = (HANDLE)_get_osfhandle(ret);
+#endif
+ return 0;
done:
qemu_opts_del(opts);
}
}
- static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp)
+#ifdef CONFIG_MARU
+extern int start_simple_client(char* msg);
+extern char* maru_convert_path(char* msg, const char *path);
+#endif
+
+ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
{
- bool bps_flag;
- bool iops_flag;
-
- assert(io_limits);
-
- bps_flag = (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] != 0)
- && ((io_limits->bps[BLOCK_IO_LIMIT_READ] != 0)
- || (io_limits->bps[BLOCK_IO_LIMIT_WRITE] != 0));
- iops_flag = (io_limits->iops[BLOCK_IO_LIMIT_TOTAL] != 0)
- && ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0)
- || (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0));
- if (bps_flag || iops_flag) {
- error_setg(errp, "bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) "
- "cannot be used at the same time");
+ if (throttle_conflicting(cfg)) {
+ error_setg(errp, "bps/iops/max total values and read/write values"
+ " cannot be used at the same time");
return false;
}
bdrv_flags |= BDRV_O_INCOMING;
}
- if (media == MEDIA_CDROM) {
- /* CDROM is fine for any interface, don't check. */
- ro = 1;
- } else if (ro == 1) {
- if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY &&
- type != IF_NONE && type != IF_PFLASH) {
- error_report("read-only not supported by this bus type");
- goto err;
- }
- }
-
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
- if (ro && copy_on_read) {
- error_report("warning: disabling copy_on_read on read-only drive");
- }
-
QINCREF(bs_opts);
- ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv);
+ ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv, &error);
if (ret < 0) {
- if (ret == -EMEDIUMTYPE) {
- error_report("could not open disk image %s: not in %s format",
- file ?: dinfo->id, drv ? drv->format_name :
- qdict_get_str(bs_opts, "driver"));
- } else {
- error_report("could not open disk image %s: %s",
- file ?: dinfo->id, strerror(-ret));
- }
+#ifdef CONFIG_MARU
+ const char _msg[] = "Failed to load disk file from the following path. Check if the file is corrupted or missing.\n\n";
+ char* err_msg = NULL;
+ err_msg = maru_convert_path((char*)_msg, file);
+ start_simple_client(err_msg);
+ if (err_msg) {
+ g_free(err_msg);
+ }
+#endif
+
+ error_setg(errp, "could not open disk image %s: %s",
+ file ?: dinfo->id, error_get_pretty(error));
+ error_free(error);
goto err;
}
smartcard_nss=""
libusb=""
usb_redir=""
+opengl=""
+efence="no"
+yagl="no"
+yagl_stats="no"
glx=""
+vigs="no"
zlib="yes"
guest_agent=""
+ guest_agent_with_vss="no"
+ vss_win32_sdk=""
+ win_sdk="no"
want_tools="yes"
libiscsi=""
coroutine=""
kvm="yes"
vhost_net="yes"
vhost_scsi="yes"
- if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+ if [ "$cpu" = "i386" -o "$cpu" = "x86_64" -o "$cpu" = "x32" ] ; then
audio_possible_drivers="$audio_possible_drivers fmod"
fi
+
+# fix linking error on Ubuntu 13.04
+# libs_qga="-lrt $libs_qga"
+# QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers $QEMU_INCLUDES"
QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES"
;;
esac
echo " --enable-tpm enable TPM support"
echo " --disable-libssh2 disable ssh block device support"
echo " --enable-libssh2 enable ssh block device support"
+ echo " --disable-vhdx disables support for the Microsoft VHDX image format"
+ echo " --enable-vhdx enable support for the Microsoft VHDX image format"
echo ""
+# for TIZEN-maru
+echo "TIZEN-maru options:"
+echo " --enable-maru enable maru board"
+echo " --enable-shm enable shared memory for framebuffer"
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
fi
echo "nss used $smartcard_nss"
echo "libusb $libusb"
echo "usb net redir $usb_redir"
+echo "OpenGL support $opengl"
+echo "EFence support $efence"
+echo "YaGL support $yagl"
+echo "YaGL stats $yagl_stats"
echo "GLX support $glx"
+echo "VIGS support $vigs"
echo "libiscsi support $libiscsi"
echo "build guest agent $guest_agent"
+ echo "QGA VSS support $guest_agent_with_vss"
echo "seccomp support $seccomp"
echo "coroutine backend $coroutine"
echo "coroutine pool $coroutine_pool"
echo "libssh2 support $libssh2"
echo "TPM passthrough $tpm_passthrough"
echo "QOM debugging $qom_cast_debug"
+ echo "vhdx $vhdx"
+# for TIZEN-maru
+echo "TIZEN-maru support $maru"
+echo "TIZEN-maru shared framebuffer support $shm"
+#
+
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
fi
echo 'CONFIG_VIRTIO_BLK_DATA_PLANE=$(CONFIG_VIRTIO)' >> $config_host_mak
fi
+ if test "$vhdx" = "yes" ; then
+ echo "CONFIG_VHDX=y" >> $config_host_mak
+ fi
+
# USB host support
- case "$usb" in
- linux)
- echo "HOST_USB=linux legacy" >> $config_host_mak
- ;;
- bsd)
- echo "HOST_USB=bsd" >> $config_host_mak
- ;;
- libusb)
- if test "$linux" = "yes"; then
- echo "HOST_USB=libusb linux legacy" >> $config_host_mak
- else
- echo "HOST_USB=libusb legacy" >> $config_host_mak
- fi
- ;;
- *)
+ if test "$libusb" = "yes"; then
+ echo "HOST_USB=libusb legacy" >> $config_host_mak
+ else
echo "HOST_USB=stub" >> $config_host_mak
- ;;
- esac
+ fi
+# for TIZEN-maru
+if test "$maru" = "yes" ; then
+ echo "CONFIG_MARU=y" >> $config_host_mak
+fi
+if test "$shm" = "yes" ; then
+ echo "CONFIG_USE_SHM=y" >> $config_host_mak
+fi
+if test "$gl" = "yes" ; then
+ echo "CONFIG_GL_BACKEND=y" >> $config_host_mak
+fi
# TPM passthrough support?
if test "$tpm" = "yes"; then
echo 'CONFIG_TPM=$(CONFIG_SOFTMMU)' >> $config_host_mak
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
+CONFIG_SOUND=y
CONFIG_SDHCI=y
+ CONFIG_INTEGRATOR_DEBUG=y
if (host) {
new_block->host = host;
new_block->flags |= RAM_PREALLOC_MASK;
- } else {
+ } else if (xen_enabled()) {
if (mem_path) {
- #if defined (__linux__) && !defined(TARGET_S390X)
- new_block->host = file_ram_alloc(new_block, size, mem_path);
- if (!new_block->host) {
- new_block->host = qemu_anon_ram_alloc(size);
- memory_try_enable_merging(new_block->host, size);
- }
- #else
- fprintf(stderr, "-mem-path option unsupported\n");
+ fprintf(stderr, "-mem-path not supported with Xen\n");
exit(1);
- #endif
- } else {
- if (xen_enabled()) {
- xen_ram_alloc(new_block->offset, size, mr);
- } else if (kvm_enabled()) {
- /* some s390/kvm configurations have special constraints */
- new_block->host = kvm_ram_alloc(size);
- } else {
- new_block->host = qemu_anon_ram_alloc(size);
- #ifdef CONFIG_HAX
+ }
+ xen_ram_alloc(new_block->offset, size, mr);
+ } else {
+ if (mem_path) {
+ if (phys_mem_alloc != qemu_anon_ram_alloc) {
/*
- * In Hax, the qemu allocate the virtual address, and HAX kernel
- * populate the memory with physical memory. Currently we have no
- * paging, so user should make sure enough free memory in advance
+ * file_ram_alloc() needs to allocate just like
+ * phys_mem_alloc, but we haven't bothered to provide
+ * a hook there.
*/
- if (hax_enabled()) {
- int ret;
- ret = hax_populate_ram((uint64_t)new_block->host, size);
- if (ret < 0) {
- fprintf(stderr, "Hax failed to populate ram\n");
- exit(-1);
- }
+ fprintf(stderr,
+ "-mem-path not supported with this accelerator\n");
+ exit(1);
+ }
+ new_block->host = file_ram_alloc(new_block, size, mem_path);
+ }
+ if (!new_block->host) {
+ new_block->host = phys_mem_alloc(size);
++#ifdef CONFIG_HAX
++ /*
++ * In Hax, the qemu allocate the virtual address, and HAX kernel
++ * populate the memory with physical memory. Currently we have no
++ * paging, so user should make sure enough free memory in advance
++ */
++ if (hax_enabled()) {
++ int ret;
++ ret = hax_populate_ram((uint64_t)new_block->host, size);
++ if (ret < 0) {
++ fprintf(stderr, "Hax failed to populate ram\n");
++ exit(-1);
+ }
++ }
+#endif
+ if (!new_block->host) {
+ fprintf(stderr, "Cannot set up guest memory '%s': %s\n",
+ new_block->mr->name, strerror(errno));
+ exit(1);
}
memory_try_enable_merging(new_block->host, size);
}
#include "exec/ioport.h"
#include "hw/nvram/fw_cfg.h"
#include "exec/address-spaces.h"
+ #include "hw/acpi/piix4.h"
+#ifdef CONFIG_MARU
+#include "tizen/src/hw/maru_pm.h"
+#endif
+
//#define DEBUG
#ifdef DEBUG
+obj-y = arm_pic.o
+obj-y += arm_boot.o
+obj-y += zynq_slcr.o
+obj-y += arm_gic.o arm_gic_common.o
+obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
+obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
+obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
+obj-y += exynos4210_rtc.o exynos4210_i2c.o
+obj-y += exynos4210_cmu.o exynos4210_g3d.o
+obj-y += exynos4210_i2s.o exynos4210_audio.o
+obj-y += arm_mptimer.o a15mpcore.o
+obj-y += armv7m.o armv7m_nvic.o stellaris_enet.o
+obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
+obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
+obj-y += zaurus.o ide/microdrive.o tc6393xb.o
+obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
+ omap_gpio.o omap_intc.o omap_uart.o
+obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
+ omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
+obj-y += tsc210x.o
+obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
+obj-y += mst_fpga.o
+obj-y += bitbang_i2c.o marvell_88w8618_audio.o
+obj-y += framebuffer.o
+obj-y += strongarm.o
+obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
+obj-$(CONFIG_FDT) += ../device_tree.o
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
- obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o
+ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
#include "hw/cpu/icc_bus.h"
#include "hw/boards.h"
#include "hw/pci/pci_host.h"
+ #include "acpi-build.h"
+#ifdef CONFIG_MARU
+#include "../../tizen/src/maru_err_table.h"
+#endif
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
#define MAX_IDE_BUS 2
++#ifdef CONFIG_MARU
++void pc_init_pci(QEMUMachineInitArgs *args);
++
++extern MemoryRegion *global_ram_memory;
++extern void *preallocated_ptr;
++#endif
++
static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
guest_info->has_pci_info = has_pci_info;
guest_info->isapc_ram_fw = !pci_enabled;
++#ifdef CONFIG_MARU
++ // for ramdump...
++ global_ram_memory = ram_memory;
++#endif
++
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
++#ifdef CONFIG_MARU
++ // W/A for allocate larger continuous heap.
++ // see vl.c
++ if(preallocated_ptr != NULL) {
++ g_free(preallocated_ptr);
++ }
++#endif
fw_cfg = pc_memory_init(system_memory,
- kernel_filename, kernel_cmdline, initrd_filename,
- args->kernel_filename, args->kernel_cmdline,
- args->initrd_filename,
-- below_4g_mem_size, above_4g_mem_size,
-- rom_memory, &ram_memory, guest_info);
++ args->kernel_filename, args->kernel_cmdline,
++ args->initrd_filename,
++ below_4g_mem_size, above_4g_mem_size,
++ rom_memory, &ram_memory, guest_info);
}
gsi_state = g_malloc0(sizeof(*gsi_state));
if (kvm_irqchip_in_kernel()) {
kvm_pc_setup_irq_routing(pci_enabled);
gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
-- GSI_NUM_PINS);
++ GSI_NUM_PINS);
} else {
gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
}
if (pci_enabled) {
pc_pci_device_init(pci_bus);
}
-
- if (has_pvpanic) {
- pvpanic_init(isa_bus);
- }
}
++#ifdef CONFIG_MARU
++void pc_init_pci(QEMUMachineInitArgs *args)
++#else
static void pc_init_pci(QEMUMachineInitArgs *args)
++#endif
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 1);
+ pc_init1(args, 1, 1);
}
- static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
+ static void pc_compat_1_6(QEMUMachineInitArgs *args)
{
has_pci_info = false;
- pc_init_pci(args);
+ rom_file_in_ram = false;
+ has_acpi_build = false;
}
- static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+ static void pc_compat_1_5(QEMUMachineInitArgs *args)
{
- has_pvpanic = true;
- pc_init_pci_1_6(args);
+ pc_compat_1_6(args);
}
- static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+ static void pc_compat_1_4(QEMUMachineInitArgs *args)
{
+ pc_compat_1_5(args);
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
- has_pci_info = false;
- pc_init_pci(args);
}
- static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
+ static void pc_compat_1_3(QEMUMachineInitArgs *args)
{
+ pc_compat_1_4(args);
enable_compat_apic_id_mode();
- pc_init_pci_1_4(args);
}
- /* PC machine init function for pc-1.1 to pc-1.2 */
- static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+ /* PC compat function for pc-0.14 to pc-1.2 */
+ static void pc_compat_1_2(QEMUMachineInitArgs *args)
{
+ pc_compat_1_3(args);
disable_kvm_pv_eoi();
- pc_init_pci_1_3(args);
}
- /* PC machine init function for pc-0.14 to pc-1.0 */
- static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
+ static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_6(args);
+ pc_init_pci(args);
+ }
+
+ static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_5(args);
+ pc_init_pci(args);
+ }
+
+ static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_4(args);
+ pc_init_pci(args);
+ }
+
+ static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
{
- pc_init_pci_1_2(args);
+ pc_compat_1_3(args);
+ pc_init_pci(args);
+ }
+
+ /* PC machine init function for pc-0.14 to pc-1.2 */
+ static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+ {
+ pc_compat_1_2(args);
+ pc_init_pci(args);
}
/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
--- /dev/null
- qemu_irq_lower(s->dev.pci_dev.irq[0]);
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "vigs_device.h"
+#include "vigs_log.h"
+#include "vigs_server.h"
+#include "vigs_backend.h"
+#include "vigs_regs.h"
+#include "hw/hw.h"
+#include "ui/console.h"
+
+#define PCI_VENDOR_ID_VIGS 0x19B2
+#define PCI_DEVICE_ID_VIGS 0x1011
+
+#define VIGS_IO_SIZE 0x1000
+
+typedef struct VIGSState
+{
+ VIGSDevice dev;
+
+ void *display;
+
+ MemoryRegion vram_bar;
+ uint32_t vram_size;
+
+ MemoryRegion ram_bar;
+ uint32_t ram_size;
+
+ MemoryRegion io_bar;
+
+ struct vigs_server *server;
+
+ /*
+ * Our console.
+ */
+ QemuConsole *con;
+
+ uint32_t reg_int;
+} VIGSState;
+
+#define TYPE_VIGS_DEVICE "vigs"
+
+extern const char *vigs_backend;
+
+static void vigs_update_irq(VIGSState *s)
+{
+ if ((s->reg_int & VIGS_REG_INT_VBLANK_ENABLE) == 0) {
- qemu_irq_raise(s->dev.pci_dev.irq[0]);
++ pci_set_irq(&s->dev.pci_dev, 0);
+ return;
+ }
+
+ if (s->reg_int & VIGS_REG_INT_VBLANK_PENDING) {
- qemu_irq_lower(s->dev.pci_dev.irq[0]);
++ pci_set_irq(&s->dev.pci_dev, 1);
+ } else {
++ pci_set_irq(&s->dev.pci_dev, 0);
+ }
+}
+
+static void vigs_hw_update(void *opaque)
+{
+ VIGSState *s = opaque;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ if (!surface_data(ds)) {
+ return;
+ }
+
+ vigs_server_update_display(s->server);
+
+ dpy_gfx_update(s->con, 0, 0, surface_width(ds), surface_height(ds));
+
+ if (s->reg_int & VIGS_REG_INT_VBLANK_ENABLE) {
+ s->reg_int |= VIGS_REG_INT_VBLANK_PENDING;
+ vigs_update_irq(s);
+ }
+}
+
+static void vigs_hw_invalidate(void *opaque)
+{
+}
+
+static void vigs_dpy_resize(void *user_data,
+ uint32_t width,
+ uint32_t height)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ if ((width != surface_width(ds)) ||
+ (height != surface_height(ds)))
+ {
+ qemu_console_resize(s->con, width, height);
+ }
+}
+
+static uint32_t vigs_dpy_get_stride(void *user_data)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ return surface_stride(ds);
+}
+
+static uint32_t vigs_dpy_get_bpp(void *user_data)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ return surface_bytes_per_pixel(ds);
+}
+
+static uint8_t *vigs_dpy_get_data(void *user_data)
+{
+ VIGSState *s = user_data;
+ DisplaySurface *ds = qemu_console_surface(s->con);
+
+ return surface_data(ds);
+}
+
+static uint64_t vigs_io_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ VIGSState *s = opaque;
+
+ switch (offset) {
+ case VIGS_REG_INT:
+ return s->reg_int;
+ default:
+ VIGS_LOG_CRITICAL("Bad register 0x%X read", (uint32_t)offset);
+ break;
+ }
+
+ return 0;
+}
+
+static void vigs_io_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ VIGSState *s = opaque;
+
+ switch (offset) {
+ case VIGS_REG_EXEC:
+ vigs_server_dispatch(s->server, value);
+ break;
+ case VIGS_REG_INT:
+ if (((s->reg_int & VIGS_REG_INT_VBLANK_PENDING) == 0) &&
+ (value & VIGS_REG_INT_VBLANK_PENDING)) {
+ VIGS_LOG_CRITICAL("Attempt to set VBLANK_PENDING");
+ value &= ~VIGS_REG_INT_VBLANK_PENDING;
+ }
+
+ if (((s->reg_int & VIGS_REG_INT_VBLANK_ENABLE) == 0) &&
+ (value & VIGS_REG_INT_VBLANK_ENABLE)) {
+ VIGS_LOG_DEBUG("VBLANK On");
+ } else if (((value & VIGS_REG_INT_VBLANK_ENABLE) == 0) &&
+ (s->reg_int & VIGS_REG_INT_VBLANK_ENABLE)) {
+ VIGS_LOG_DEBUG("VBLANK Off");
+ }
+
+ s->reg_int = value & VIGS_REG_INT_MASK;
+ if ((value & VIGS_REG_INT_VBLANK_ENABLE) == 0) {
+ s->reg_int &= ~VIGS_REG_INT_VBLANK_PENDING;
+ }
+ vigs_update_irq(s);
+ break;
+ default:
+ VIGS_LOG_CRITICAL("Bad register 0x%X write", (uint32_t)offset);
+ break;
+ }
+}
+
+static struct GraphicHwOps vigs_hw_ops =
+{
+ .invalidate = vigs_hw_invalidate,
+ .gfx_update = vigs_hw_update
+};
+
+static const MemoryRegionOps vigs_io_ops =
+{
+ .read = vigs_io_read,
+ .write = vigs_io_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static struct vigs_display_ops vigs_dpy_ops =
+{
+ .resize = vigs_dpy_resize,
+ .get_stride = vigs_dpy_get_stride,
+ .get_bpp = vigs_dpy_get_bpp,
+ .get_data = vigs_dpy_get_data,
+};
+
+static int vigs_device_init(PCIDevice *dev)
+{
+ VIGSState *s = DO_UPCAST(VIGSState, dev.pci_dev, dev);
+ struct vigs_backend *backend = NULL;
+
+ vigs_log_init();
+
+ if (s->vram_size < 16 * 1024 * 1024) {
+ VIGS_LOG_WARN("\"vram_size\" is too small, defaulting to 16mb");
+ s->vram_size = 16 * 1024 * 1024;
+ }
+
+ if (s->ram_size < 1 * 1024 * 1024) {
+ VIGS_LOG_WARN("\"ram_size\" is too small, defaulting to 1mb");
+ s->ram_size = 1 * 1024 * 1024;
+ }
+
+ pci_config_set_interrupt_pin(dev->config, 1);
+
+ memory_region_init_ram(&s->vram_bar, OBJECT(s),
+ TYPE_VIGS_DEVICE ".vram",
+ s->vram_size);
+
+ memory_region_init_ram(&s->ram_bar, OBJECT(s),
+ TYPE_VIGS_DEVICE ".ram",
+ s->ram_size);
+
+ memory_region_init_io(&s->io_bar, OBJECT(s),
+ &vigs_io_ops,
+ s,
+ TYPE_VIGS_DEVICE ".io",
+ VIGS_IO_SIZE);
+
+ pci_register_bar(&s->dev.pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->vram_bar);
+ pci_register_bar(&s->dev.pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_bar);
+ pci_register_bar(&s->dev.pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_bar);
+
+ if (!strcmp(vigs_backend, "gl")) {
+ backend = vigs_gl_backend_create(s->display);
+ } else if (!strcmp(vigs_backend, "sw")) {
+ backend = vigs_sw_backend_create();
+ }
+
+ if (!backend) {
+ goto fail;
+ }
+
+ s->con = graphic_console_init(DEVICE(dev), &vigs_hw_ops, s);
+
+ if (!s->con) {
+ goto fail;
+ }
+
+ s->server = vigs_server_create(memory_region_get_ram_ptr(&s->vram_bar),
+ memory_region_get_ram_ptr(&s->ram_bar),
+ &vigs_dpy_ops,
+ s,
+ backend);
+
+ if (!s->server) {
+ goto fail;
+ }
+
+ s->dev.wsi = &s->server->wsi;
+
+ VIGS_LOG_INFO("VIGS initialized");
+
+ VIGS_LOG_DEBUG("vram_size = %u", s->vram_size);
+ VIGS_LOG_DEBUG("ram_size = %u", s->ram_size);
+
+ return 0;
+
+fail:
+ if (backend) {
+ backend->destroy(backend);
+ }
+
+ memory_region_destroy(&s->io_bar);
+ memory_region_destroy(&s->ram_bar);
+ memory_region_destroy(&s->vram_bar);
+
+ vigs_log_cleanup();
+
+ return -1;
+}
+
+static void vigs_device_reset(DeviceState *d)
+{
+ VIGSState *s = container_of(d, VIGSState, dev.pci_dev.qdev);
+
+ vigs_server_reset(s->server);
+
+ s->reg_int = 0;
+
+ VIGS_LOG_INFO("VIGS reset");
+}
+
+static void vigs_device_exit(PCIDevice *dev)
+{
+ VIGSState *s = DO_UPCAST(VIGSState, dev.pci_dev, dev);
+
+ vigs_server_destroy(s->server);
+
+ memory_region_destroy(&s->io_bar);
+ memory_region_destroy(&s->ram_bar);
+ memory_region_destroy(&s->vram_bar);
+
+ VIGS_LOG_INFO("VIGS deinitialized");
+
+ vigs_log_cleanup();
+}
+
+static Property vigs_properties[] = {
+ {
+ .name = "display",
+ .info = &qdev_prop_ptr,
+ .offset = offsetof(VIGSState, display),
+ },
+ DEFINE_PROP_UINT32("vram_size", VIGSState, vram_size,
+ 32 * 1024 * 1024),
+ DEFINE_PROP_UINT32("ram_size", VIGSState, ram_size,
+ 1 * 1024 * 1024),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vigs_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vigs_device_init;
+ k->exit = vigs_device_exit;
+ k->vendor_id = PCI_VENDOR_ID_VIGS;
+ k->device_id = PCI_DEVICE_ID_VIGS;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->reset = vigs_device_reset;
+ dc->props = vigs_properties;
+ dc->desc = "VIGS device";
+}
+
+static TypeInfo vigs_device_info =
+{
+ .name = TYPE_VIGS_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VIGSState),
+ .class_init = vigs_class_init,
+};
+
+static void vigs_register_types(void)
+{
+ type_register_static(&vigs_device_info);
+}
+
+type_init(vigs_register_types)
.class_init = virtio_rng_pci_class_init,
};
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_GL);
+#ifdef CONFIG_MARU
+/* virtio-gl-pci */
+
+static int virtio_gl_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOGLPCI *dev = VIRTIO_GL_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void virtio_gl_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_gl_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GL;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_gl_pci_instance_init(Object *obj)
+{
+ VirtIOGLPCI *dev = VIRTIO_GL_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_TOUCHSCREEN);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GL);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_gl_pci_info = {
+ .name = TYPE_VIRTIO_GL_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOGLPCI),
+ .instance_init = virtio_gl_pci_instance_init,
+ .class_init = virtio_gl_pci_class_init,
+};
+
+/* virtio-touchscreen-pci */
+
+static int virtio_touchscreen_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOTouchscreenPCI *dev = VIRTIO_TOUCHSCREEN_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_touchscreen_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_touchscreen_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_TOUCHSCREEN;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_touchscreen_pci_instance_init(Object *obj)
+{
+ VirtIOTouchscreenPCI *dev = VIRTIO_TOUCHSCREEN_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_KEYBOARD);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TOUCHSCREEN);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_touchscreen_pci_info = {
+ .name = TYPE_VIRTIO_TOUCHSCREEN_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOTouchscreenPCI),
+ .instance_init = virtio_touchscreen_pci_instance_init,
+ .class_init = virtio_touchscreen_pci_class_init,
+};
+
+/* virtio-keyboard-pci */
+
+static int virtio_keyboard_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOKeyboardPCI *dev = VIRTIO_KEYBOARD_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_keyboard_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_keyboard_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_KEYBOARD;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_keyboard_pci_instance_init(Object *obj)
+{
+ VirtIOKeyboardPCI *dev = VIRTIO_KEYBOARD_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_ESM);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_keyboard_pci_info = {
+ .name = TYPE_VIRTIO_KEYBOARD_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOKeyboardPCI),
+ .instance_init = virtio_keyboard_pci_instance_init,
+ .class_init = virtio_keyboard_pci_class_init,
+};
+
+/* virtio-esm-pci */
+
+static int virtio_esm_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOESMPCI *dev = VIRTIO_ESM_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_esm_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_esm_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_ESM;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_esm_pci_instance_init(Object *obj)
+{
+ VirtIOESMPCI *dev = VIRTIO_ESM_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_HWKEY);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_ESM);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_esm_pci_info = {
+ .name = TYPE_VIRTIO_ESM_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOESMPCI),
+ .instance_init = virtio_esm_pci_instance_init,
+ .class_init = virtio_esm_pci_class_init,
+};
+
+/* virtio-hwkey-pci */
+
+static int virtio_hwkey_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOHWKeyPCI *dev = VIRTIO_HWKEY_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_hwkey_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_hwkey_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_HWKEY;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_hwkey_pci_instance_init(Object *obj)
+{
+ VirtIOHWKeyPCI *dev = VIRTIO_HWKEY_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_EVDI);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_HWKEY);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_hwkey_pci_info = {
+ .name = TYPE_VIRTIO_HWKEY_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOHWKeyPCI),
+ .instance_init = virtio_hwkey_pci_instance_init,
+ .class_init = virtio_hwkey_pci_class_init,
+};
+
+/* virtio-evdi-pci */
+
+static int virtio_evdi_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOEVDIPCI *dev = VIRTIO_EVDI_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_evdi_pci_class_init(ObjectClass *klass, void *data)
+{
+// DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_evdi_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_EVDI;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_evdi_pci_instance_init(Object *obj)
+{
+ VirtIOEVDIPCI *dev = VIRTIO_EVDI_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SENSOR);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_EVDI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_evdi_pci_info = {
+ .name = TYPE_VIRTIO_EVDI_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOEVDIPCI),
+ .instance_init = virtio_evdi_pci_instance_init,
+ .class_init = virtio_evdi_pci_class_init,
+};
+
+/* virtio-sensor-pci */
+
+static int virtio_sensor_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOSENSORPCI *dev = VIRTIO_SENSOR_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_sensor_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_sensor_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SENSOR;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_sensor_pci_instance_init(Object *obj)
+{
+ VirtIOSENSORPCI *dev = VIRTIO_SENSOR_PCI(obj);
- object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_NFC);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SENSOR);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_sensor_pci_info = {
+ .name = TYPE_VIRTIO_SENSOR_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOSENSORPCI),
+ .instance_init = virtio_sensor_pci_instance_init,
+ .class_init = virtio_sensor_pci_class_init,
+};
+
+/* virtio NFC */
+
+static int virtio_nfc_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIONFCPCI *dev = VIRTIO_NFC_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_nfc_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_nfc_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_NFC;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_nfc_pci_instance_init(Object *obj)
+{
+ VirtIONFCPCI *dev = VIRTIO_NFC_PCI(obj);
++ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NFC);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_nfc_pci_info = {
+ .name = TYPE_VIRTIO_NFC_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIONFCPCI),
+ .instance_init = virtio_nfc_pci_instance_init,
+ .class_init = virtio_nfc_pci_class_init,
+};
+
+
+#endif
+
/* virtio-pci-bus */
- static void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
+ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
+ VirtIOPCIProxy *dev)
{
DeviceState *qdev = DEVICE(dev);
BusState *qbus;
sigjmp_buf jmp_env; \
int exception_index; \
\
+ /* for hax */ \
+ int hax_vcpu_dirty; \
+ struct hax_vcpu_state *hax_vcpu; \
+ \
/* user data */ \
void *opaque; \
- \
- const char *cpu_model_str;
#endif
#endif /* NEED_CPU_H */
+ void kvm_cpu_synchronize_state(CPUState *cpu);
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
void kvm_cpu_synchronize_post_init(CPUState *cpu);
+#ifdef CONFIG_HAX
+void hax_cpu_synchronize_post_reset(CPUArchState *env);
+void hax_cpu_synchronize_post_init(CPUArchState *env);
+#endif
+ /* generic hooks - to be moved/refactored once there are more users */
+
+ static inline void cpu_synchronize_state(CPUState *cpu)
+ {
+ if (kvm_enabled()) {
+ kvm_cpu_synchronize_state(cpu);
+ }
+ }
+
static inline void cpu_synchronize_post_reset(CPUState *cpu)
{
if (kvm_enabled()) {
--- /dev/null
- qemu_del_timer(cs->alive_timer);
+/*
+ * Emulator Control Server
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdbool.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "hw/qdev.h"
+#include "net/net.h"
+#include "ui/console.h"
+
+#include "qemu-common.h"
+#include "qemu/queue.h"
+#include "qemu/sockets.h"
+#include "qemu/option.h"
+#include "qemu/timer.h"
+#include "qemu/main-loop.h"
+#include "sysemu/char.h"
+#include "config.h"
+#include "qapi/qmp/qint.h"
+
+#include "sdb.h"
+#include "ecs.h"
+#include "guest_server.h"
+#include "emul_state.h"
+
+#include "genmsg/ecs.pb-c.h"
+
+#define DEBUG
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static QTAILQ_HEAD(ECS_ClientHead, ECS_Client)
+clients = QTAILQ_HEAD_INITIALIZER(clients);
+
+static ECS_State *current_ecs;
+
+static void* keepalive_buf;
+static int payloadsize;
+
+static int port;
+static int port_setting = -1;
+
+static int log_fd = -1;
+static int g_client_id = 1;
+
+static pthread_mutex_t mutex_clilist = PTHREAD_MUTEX_INITIALIZER;
+
+static int suspend_state = 1;
+
+void ecs_set_suspend_state(int state)
+{
+ suspend_state = state;
+}
+
+int ecs_get_suspend_state(void)
+{
+ return suspend_state;
+}
+
+static char* get_emulator_ecs_log_path(void)
+{
+ gchar *emulator_ecs_log_path = NULL;
+ gchar *tizen_sdk_data = NULL;
+#ifndef CONFIG_WIN32
+ char emulator_ecs[] = "/emulator/vms/ecs.log";
+#else
+ char emulator_ecs[] = "\\emulator\\vms\\ecs.log";
+#endif
+
+ tizen_sdk_data = get_tizen_sdk_data_path();
+ if (!tizen_sdk_data) {
+ LOG("failed to get tizen-sdk-data path.\n");
+ return NULL;
+ }
+
+ emulator_ecs_log_path =
+ g_malloc(strlen(tizen_sdk_data) + sizeof(emulator_ecs) + 1);
+ if (!emulator_ecs_log_path) {
+ LOG("failed to allocate memory.\n");
+ return NULL;
+ }
+
+ g_snprintf(emulator_ecs_log_path, strlen(tizen_sdk_data) + sizeof(emulator_ecs),
+ "%s%s", tizen_sdk_data, emulator_ecs);
+
+ g_free(tizen_sdk_data);
+
+ LOG("ecs log path: %s\n", emulator_ecs_log_path);
+ return emulator_ecs_log_path;
+}
+
+static char* get_emulator_ecs_prop_path(void)
+{
+ int path_len = 0;
+ gchar *ecs_property_path = NULL;
+ gchar *tizen_sdk_data = NULL;
+#ifndef CONFIG_WIN32
+ char emulator_vms[] = "/emulator/vms/";
+ char ecs_prop[] = "/.ecs.properties";
+#else
+ char emulator_vms[] = "\\emulator\\vms\\";
+ char ecs_prop[] = "\\.ecs.properties";
+#endif
+ char* emul_name = get_emul_vm_name();
+
+ tizen_sdk_data = get_tizen_sdk_data_path();
+ if (!tizen_sdk_data) {
+ LOG("failed to get tizen-sdk-data path.\n");
+ return NULL;
+ }
+
+ path_len = strlen(tizen_sdk_data) + sizeof(emulator_vms) + sizeof(ecs_prop) + strlen(emul_name);
+ ecs_property_path = g_malloc(path_len + 1);
+ g_snprintf(ecs_property_path, path_len, "%s%s%s%s", tizen_sdk_data, emulator_vms, emul_name, ecs_prop);
+
+ g_free(tizen_sdk_data);
+ LOG("ecs property path: %s", ecs_property_path);
+
+ return ecs_property_path;
+}
+
+static inline void start_logging(void) {
+ char* path = get_emulator_ecs_log_path();
+ if (!path)
+ return;
+
+#ifdef _WIN32
+ FILE* fnul;
+ FILE* flog;
+
+ fnul = fopen("NUL", "rt");
+ if (fnul != NULL)
+ stdin[0] = fnul[0];
+
+ flog = fopen(path, "wt+");
+ if (flog == NULL)
+ flog = fnul;
+
+ setvbuf(flog, NULL, _IONBF, 0);
+
+ stdout[0] = flog[0];
+ stderr[0] = flog[0];
+#else
+ log_fd = open("/dev/null", O_RDONLY);
+ dup2(log_fd, 0);
+
+ log_fd = creat(path, 0640);
+ if (log_fd < 0) {
+ log_fd = open("/dev/null", O_WRONLY);
+ }
+ dup2(log_fd, 1);
+ dup2(log_fd, 2);
+#endif
+}
+
+static inline void stop_logging(void) {
+ int ret = -1;
+ if (log_fd >= 0) {
+ ret = close(log_fd);
+ if (ret != 0) {
+ LOG("failed to close log fd.");
+ }
+ }
+}
+
+int ecs_write(int fd, const uint8_t *buf, int len) {
+ LOG("write buflen : %d, buf : %s", len, (char*)buf);
+ if (fd < 0) {
+ return -1;
+ }
+
+ return send_all(fd, buf, len);
+}
+
+void ecs_client_close(ECS_Client* clii) {
+ if (clii == NULL)
+ return;
+
+ pthread_mutex_lock(&mutex_clilist);
+
+ if (clii->client_fd > 0) {
+ LOG("ecs client closed with fd: %d", clii->client_fd);
+ closesocket(clii->client_fd);
+#ifndef CONFIG_LINUX
+ FD_CLR(clii->client_fd, &clii->cs->reads);
+#endif
+ clii->client_fd = -1;
+ }
+
+ QTAILQ_REMOVE(&clients, clii, next);
+
+ g_free(clii);
+ clii = NULL;
+
+ pthread_mutex_unlock(&mutex_clilist);
+}
+
+bool send_to_all_client(const char* data, const int len) {
+ LOG("data len: %d, data: %s", len, data);
+ pthread_mutex_lock(&mutex_clilist);
+
+ ECS_Client *clii;
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ send_to_client(clii->client_fd, data, len);
+ }
+ pthread_mutex_unlock(&mutex_clilist);
+
+ return true;
+}
+
+void send_to_single_client(ECS_Client *clii, const char* data, const int len)
+{
+ pthread_mutex_lock(&mutex_clilist);
+ send_to_client(clii->client_fd, data, len);
+ pthread_mutex_unlock(&mutex_clilist);
+}
+
+void send_to_client(int fd, const char* data, const int len)
+{
+ ecs_write(fd, (const uint8_t*) data, len);
+}
+
+void read_val_short(const char* data, unsigned short* ret_val) {
+ memcpy(ret_val, data, sizeof(unsigned short));
+}
+
+void read_val_char(const char* data, unsigned char* ret_val) {
+ memcpy(ret_val, data, sizeof(unsigned char));
+}
+
+void read_val_str(const char* data, char* ret_val, int len) {
+ memcpy(ret_val, data, len);
+}
+
+bool ntf_to_control(const char* data, const int len) {
+ return true;
+}
+
+bool ntf_to_monitor(const char* data, const int len) {
+ return true;
+}
+
+void print_binary(const char* data, const int len) {
+ int i;
+ printf("[DATA: ");
+ for(i = 0; i < len; i++) {
+ if(i == len - 1) {
+ printf("%02x]\n", data[i]);
+ } else {
+ printf("%02x,", data[i]);
+ }
+ }
+}
+
+void ecs_make_header(QDict* obj, type_length length, type_group group,
+ type_action action) {
+ qdict_put(obj, "length", qint_from_int((int64_t )length));
+ qdict_put(obj, "group", qint_from_int((int64_t )group));
+ qdict_put(obj, "action", qint_from_int((int64_t )action));
+}
+
+static Monitor *monitor_create(void) {
+ Monitor *mon;
+
+ mon = g_malloc0(sizeof(*mon));
+ if (NULL == mon) {
+ LOG("monitor allocation failed.");
+ return NULL;
+ }
+
+ return mon;
+}
+
+static void ecs_close(ECS_State *cs) {
+ ECS_Client *clii;
+ LOG("### Good bye! ECS ###");
+
+ if (cs == NULL)
+ return;
+
+ if (0 <= cs->listen_fd) {
+ LOG("close listen_fd: %d", cs->listen_fd);
+ closesocket(cs->listen_fd);
+ cs->listen_fd = -1;
+ }
+
+ if (cs->mon != NULL) {
+ g_free(cs->mon);
+ cs->mon = NULL;
+ }
+
+ if (keepalive_buf) {
+ g_free(keepalive_buf);
+ }
+
+ if (cs->alive_timer != NULL) {
- qemu_mod_timer(current_ecs->alive_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * TIMER_ALIVE_S);
++ timer_del(cs->alive_timer);
+ cs->alive_timer = NULL;
+ }
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ ecs_client_close(clii);
+ }
+
+ g_free(cs);
+ cs = NULL;
+ current_ecs = NULL;
+
+ stop_logging();
+}
+
+#ifndef _WIN32
+static ssize_t ecs_recv(int fd, char *buf, size_t len) {
+ struct msghdr msg = { NULL, };
+ struct iovec iov[1];
+ union {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(int))];
+ } msg_control;
+ int flags = 0;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = len;
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+#ifdef MSG_CMSG_CLOEXEC
+ flags |= MSG_CMSG_CLOEXEC;
+#endif
+ return recvmsg(fd, &msg, flags);
+}
+
+#else
+static ssize_t ecs_recv(int fd, char *buf, size_t len)
+{
+ return qemu_recv(fd, buf, len, 0);
+}
+#endif
+
+
+static void reset_sbuf(sbuf* sbuf)
+{
+ memset(sbuf->_buf, 0, 4096);
+ sbuf->_use = 0;
+ sbuf->_netlen = 0;
+}
+
+static void ecs_read(ECS_Client *cli) {
+
+ int read = 0;
+ int to_read_bytes = 0;
+
+#ifndef __WIN32
+ if (ioctl(cli->client_fd, FIONREAD, &to_read_bytes) < 0)
+ {
+ LOG("ioctl failed");
+ return;
+ }
+#else
+ unsigned long to_read_bytes_long = 0;
+ if (ioctlsocket(cli->client_fd, FIONREAD, &to_read_bytes_long) < 0)
+ {
+ LOG("ioctl failed");
+ return;
+ }
+ to_read_bytes = (int)to_read_bytes_long;
+#endif
+
+ if (to_read_bytes == 0) {
+ LOG("ioctl FIONREAD: 0");
+ goto fail;
+ }
+
+ if (cli->sbuf._netlen == 0)
+ {
+ if (to_read_bytes < 4)
+ {
+ //LOG("insufficient data size to read");
+ return;
+ }
+
+ long payloadsize = 0;
+ read = ecs_recv(cli->client_fd, (char*) &payloadsize, 4);
+
+ if (read < 4)
+ {
+ LOG("insufficient header size");
+ goto fail;
+ }
+
+ payloadsize = ntohl(payloadsize);
+
+ cli->sbuf._netlen = payloadsize;
+
+ LOG("payload size: %ld\n", payloadsize);
+
+ to_read_bytes -= 4;
+ }
+
+ if (to_read_bytes == 0)
+ return;
+
+
+ to_read_bytes = min(to_read_bytes, cli->sbuf._netlen - cli->sbuf._use);
+
+ read = ecs_recv(cli->client_fd, (char*)(cli->sbuf._buf + cli->sbuf._use), to_read_bytes);
+ if (read == 0)
+ goto fail;
+
+
+ cli->sbuf._use += read;
+
+
+ if (cli->sbuf._netlen == cli->sbuf._use)
+ {
+ handle_protobuf_msg(cli, (char*)cli->sbuf._buf, cli->sbuf._use);
+ reset_sbuf(&cli->sbuf);
+ }
+
+ return;
+fail:
+ ecs_client_close(cli);
+}
+
+#ifdef CONFIG_LINUX
+static void epoll_cli_add(ECS_State *cs, int fd) {
+ struct epoll_event events;
+
+ /* event control set for read event */
+ events.events = EPOLLIN;
+ events.data.fd = fd;
+
+ if (epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, fd, &events) < 0) {
+ LOG("Epoll control fails.in epoll_cli_add.");
+ }
+}
+#endif
+
+static ECS_Client *ecs_find_client(int fd) {
+ ECS_Client *clii;
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ if (clii->client_fd == fd)
+ return clii;
+ }
+ return NULL;
+}
+
+ECS_Client *find_client(unsigned char id, unsigned char type) {
+ ECS_Client *clii;
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ if (clii->client_id == id && clii->client_type == type)
+ return clii;
+ }
+ return NULL;
+}
+
+static int ecs_add_client(ECS_State *cs, int fd) {
+
+ ECS_Client *clii = g_malloc0(sizeof(ECS_Client));
+ if (NULL == clii) {
+ LOG("ECS_Client allocation failed.");
+ return -1;
+ }
+
+ reset_sbuf(&clii->sbuf);
+
+ qemu_set_nonblock(fd);
+
+ clii->client_fd = fd;
+ clii->cs = cs;
+ clii->client_type = TYPE_NONE;
+
+ ecs_json_message_parser_init(&clii->parser, handle_qmp_command, clii);
+
+#ifdef CONFIG_LINUX
+ epoll_cli_add(cs, fd);
+#else
+ FD_SET(fd, &cs->reads);
+#endif
+
+ pthread_mutex_lock(&mutex_clilist);
+
+ QTAILQ_INSERT_TAIL(&clients, clii, next);
+
+ LOG("Add an ecs client. fd: %d", fd);
+
+ pthread_mutex_unlock(&mutex_clilist);
+
+// send_ecs_version_check(clii);
+
+ return 0;
+}
+
+static void ecs_accept(ECS_State *cs) {
+ struct sockaddr_in saddr;
+#ifndef _WIN32
+ struct sockaddr_un uaddr;
+#endif
+ struct sockaddr *addr;
+ socklen_t len;
+ int fd;
+
+ for (;;) {
+#ifndef _WIN32
+ if (cs->is_unix) {
+ len = sizeof(uaddr);
+ addr = (struct sockaddr *) &uaddr;
+ } else
+#endif
+ {
+ len = sizeof(saddr);
+ addr = (struct sockaddr *) &saddr;
+ }
+ fd = qemu_accept(cs->listen_fd, addr, &len);
+ if (0 > fd && EINTR != errno) {
+ return;
+ } else if (0 <= fd) {
+ break;
+ }
+ }
+ if (0 > ecs_add_client(cs, fd)) {
+ LOG("failed to add client.");
+ }
+}
+
+#ifdef CONFIG_LINUX
+static void epoll_init(ECS_State *cs) {
+ struct epoll_event events;
+
+ cs->epoll_fd = epoll_create(MAX_EVENTS);
+ if (cs->epoll_fd < 0) {
+ closesocket(cs->listen_fd);
+ }
+
+ events.events = EPOLLIN;
+ events.data.fd = cs->listen_fd;
+
+ if (epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, cs->listen_fd, &events) < 0) {
+ close(cs->listen_fd);
+ close(cs->epoll_fd);
+ }
+}
+#endif
+
+static void send_keep_alive_msg(ECS_Client *clii) {
+ send_to_single_client(clii, keepalive_buf, payloadsize);
+}
+
+static void make_keep_alive_msg(void) {
+ int len_pack = 0;
+ char msg [5] = {'s','e','l','f'};
+
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__KeepAliveReq req = ECS__KEEP_ALIVE_REQ__INIT;
+
+ req.time_str = (char*) g_malloc(5);
+
+ strncpy(req.time_str, msg, 4);
+
+ master.type = ECS__MASTER__TYPE__KEEPALIVE_REQ;
+ master.keepalive_req = &req;
+
+ len_pack = ecs__master__get_packed_size(&master);
+ payloadsize = len_pack + 4;
+
+ keepalive_buf = g_malloc(len_pack + 4);
+ if (!keepalive_buf) {
+ LOG("keep alive message creation is failed.");
+ return;
+ }
+
+ ecs__master__pack(&master, keepalive_buf + 4);
+
+ len_pack = htonl(len_pack);
+ memcpy(keepalive_buf, &len_pack, 4);
+}
+
+static void alive_checker(void *opaque) {
+
+ ECS_Client *clii;
+
+ if (NULL != current_ecs && !current_ecs->ecs_running) {
+ return;
+ }
+
+ QTAILQ_FOREACH(clii, &clients, next)
+ {
+ if (1 == clii->keep_alive) {
+ LOG("get client fd %d - keep alive fail", clii->client_fd);
+ ecs_client_close(clii);
+ continue;
+ }
+ LOG("set client fd %d - keep alive 1", clii->client_fd);
+ clii->keep_alive = 1;
+ send_keep_alive_msg(clii);
+ }
+
+ if (current_ecs == NULL) {
+ LOG("alive checking is failed because current ecs is null.");
+ return;
+ }
+
- cs->alive_timer = qemu_new_timer_ns(vm_clock, alive_checker, cs);
++ timer_mod(current_ecs->alive_timer,
++ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
+
+}
+
+static int socket_initialize(ECS_State *cs, QemuOpts *opts) {
+ int fd = -1;
+ Error *local_err = NULL;
+
+ fd = inet_listen_opts(opts, 0, &local_err);
+ if (0 > fd || error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+
+ LOG("Listen fd is %d", fd);
+
+ qemu_set_nonblock(fd);
+
+ cs->listen_fd = fd;
+
+#ifdef CONFIG_LINUX
+ epoll_init(cs);
+#else
+ FD_ZERO(&cs->reads);
+ FD_SET(fd, &cs->reads);
+#endif
+
+ make_keep_alive_msg();
+
- qemu_mod_timer(cs->alive_timer,
- qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * TIMER_ALIVE_S);
++ cs->alive_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, alive_checker, cs);
+
++ timer_mod(cs->alive_timer,
++ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
+
+ return 0;
+}
+
+#ifdef CONFIG_LINUX
+static int ecs_loop(ECS_State *cs) {
+ int i, nfds;
+
+ nfds = epoll_wait(cs->epoll_fd, cs->events, MAX_EVENTS, 100);
+ if (0 == nfds) {
+ return 0;
+ }
+
+ if (0 > nfds) {
+ if (errno == EINTR)
+ return 0;
+ perror("epoll wait error");
+ return -1;
+ }
+
+ for (i = 0; i < nfds; i++) {
+ if (cs->events[i].data.fd == cs->listen_fd) {
+ ecs_accept(cs);
+ continue;
+ }
+ ecs_read(ecs_find_client(cs->events[i].data.fd));
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_WIN32)
+static int ecs_loop(ECS_State *cs)
+{
+ int index = 0;
+ TIMEVAL timeout;
+ fd_set temps = cs->reads;
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ if (select(0, &temps, 0, 0, &timeout) < 0) {
+ LOG("select error.");
+ return -1;
+ }
+
+ for (index = 0; index < cs->reads.fd_count; index++) {
+ if (FD_ISSET(cs->reads.fd_array[index], &temps)) {
+ if (cs->reads.fd_array[index] == cs->listen_fd) {
+ ecs_accept(cs);
+ continue;
+ }
+
+ ecs_read(ecs_find_client(cs->reads.fd_array[index]));
+ }
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_DARWIN)
+static int ecs_loop(ECS_State *cs)
+{
+ int index = 0;
+ int res = 0;
+ struct timeval timeout;
+ fd_set temps = cs->reads;
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ if ((res = select(MAX_FD_NUM + 1, &temps, NULL, NULL, &timeout)) < 0) {
+ LOG("select failed..");
+ return -1;
+ }
+
+ for (index = 0; index < MAX_FD_NUM; index ++) {
+ if (FD_ISSET(index, &temps)) {
+ if (index == cs->listen_fd) {
+ ecs_accept(cs);
+ continue;
+ }
+
+ ecs_read(ecs_find_client(index));
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
+int get_ecs_port(void) {
+ if (port_setting < 0) {
+ LOG("ecs port is not determined yet.");
+ return 0;
+ }
+ LOG("requests ecs port, and port is %d", port);
+ return port;
+}
+
+static int set_ecs_port(int port) {
+ FILE* fprop;
+ char* path = get_emulator_ecs_prop_path();
+ if (!path)
+ return -1;
+
+ fprop = fopen(path, "wt+");
+ if (fprop == NULL) {
+ return -1;
+ }
+
+ fprintf(fprop, "%d", port);
+ fclose(fprop);
+
+ g_free(path);
+
+ return 0;
+}
+
+static int setting_ecs_port(ECS_State *cs) {
+ struct sockaddr server_addr;
+ socklen_t server_len;
+
+ server_len = sizeof(server_addr);
+ memset(&server_addr, 0, sizeof(server_addr));
+ if (getsockname(cs->listen_fd, (struct sockaddr *) &server_addr, &server_len) < 0) {
+ return -1;
+ }
+
+ port = ntohs( ((struct sockaddr_in *) &server_addr)->sin_port );
+ LOG("listen port is %d", port);
+
+ return set_ecs_port(port);
+}
+
+static void* ecs_initialize(void* args) {
+ int ret = 1;
+ ECS_State *cs = NULL;
+ QemuOpts *opts = NULL;
+ Error *local_err = NULL;
+ Monitor* mon = NULL;
+ char host_port[16];
+
+ start_logging();
+ LOG("ecs starts initializing.");
+
+ opts = qemu_opts_create(qemu_find_opts(ECS_OPTS_NAME), ECS_OPTS_NAME, 1, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return NULL;
+ }
+
+ qemu_opt_set(opts, "host", HOST_LISTEN_ADDR);
+
+ cs = g_malloc0(sizeof(ECS_State));
+ if (NULL == cs) {
+ LOG("ECS_State allocation failed.");
+ return NULL;
+ }
+
+ sprintf(host_port, "%d", port);
+ qemu_opt_set(opts, "port", host_port);
+ ret = socket_initialize(cs, opts);
+ if (ret < 0) {
+ LOG("Socket initialization is failed.");
+ ecs_close(cs);
+ return NULL;
+ }
+
+ if (setting_ecs_port(cs) < 0) {
+ LOG("Failed to get random port.");
+ ecs_close(cs);
+ return NULL;
+ }
+
+ port_setting = 1;
+
+ mon = monitor_create();
+ if (NULL == mon) {
+ LOG("monitor initialization failed.");
+ ecs_close(cs);
+ return NULL;
+ }
+
+ cs->mon = mon;
+ current_ecs = cs;
+ cs->ecs_running = 1;
+
+ LOG("ecs_loop entered.");
+ while (cs->ecs_running) {
+ ret = ecs_loop(cs);
+ if (0 > ret) {
+ ecs_close(cs);
+ break;
+ }
+ }
+ LOG("ecs_loop exited.");
+
+ return NULL;
+}
+
+int stop_ecs(void) {
+ LOG("ecs is closing.");
+ if (NULL != current_ecs) {
+ current_ecs->ecs_running = 0;
+ ecs_close(current_ecs);
+ }
+
+ pthread_mutex_destroy(&mutex_clilist);
+
+ return 0;
+}
+
+int start_ecs(void) {
+ pthread_t thread_id;
+
+ if (0 != pthread_create(&thread_id, NULL, ecs_initialize, NULL)) {
+ LOG("pthread creation failed.");
+ return -1;
+ }
+ return 0;
+}
+
+bool handle_protobuf_msg(ECS_Client* cli, char* data, int len)
+{
+ ECS__Master* master = ecs__master__unpack(NULL, (size_t)len, (const uint8_t*)data);
+ if (!master)
+ return false;
+
+ if (master->type == ECS__MASTER__TYPE__INJECTOR_REQ)
+ {
+ ECS__InjectorReq* msg = master->injector_req;
+ if (!msg)
+ goto fail;
+ msgproc_injector_req(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__MONITOR_REQ)
+ {
+ ECS__MonitorReq* msg = master->monitor_req;
+ if (!msg)
+ goto fail;
+ msgproc_monitor_req(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__DEVICE_REQ)
+ {
+ cli->client_type = TYPE_ECP;
+ ECS__DeviceReq* msg = master->device_req;
+ if (!msg)
+ goto fail;
+ msgproc_device_req(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__NFC_REQ)
+ {
+ ECS__NfcReq* msg = master->nfc_req;
+ if (!msg)
+ goto fail;
+
+ pthread_mutex_lock(&mutex_clilist);
+ if(cli->client_type == TYPE_NONE) {
+ if (!strncmp(msg->category, MSG_TYPE_NFC, 3)) {
+ QTAILQ_REMOVE(&clients, cli, next);
+ cli->client_type = TYPE_ECP;
+ if(g_client_id > 255) {
+ g_client_id = 1;
+ }
+ cli->client_id = g_client_id++;
+
+ QTAILQ_INSERT_TAIL(&clients, cli, next);
+ }
+ else if (!strncmp(msg->category, MSG_TYPE_SIMUL_NFC, 9)) {
+ QTAILQ_REMOVE(&clients, cli, next);
+ cli->client_type = TYPE_SIMUL_NFC;
+ if(g_client_id > 255) {
+ g_client_id = 1;
+ }
+ cli->client_id = g_client_id++;
+ QTAILQ_INSERT_TAIL(&clients, cli, next);
+ }
+ else {
+ LOG("unsupported category is found: %s", msg->category);
+ goto fail;
+ }
+ }
+ pthread_mutex_unlock(&mutex_clilist);
+
+ msgproc_nfc_req(cli, msg);
+ }
+#if 0
+ else if (master->type == ECS__MASTER__TYPE__CHECKVERSION_REQ)
+ {
+ ECS__CheckVersionReq* msg = master->checkversion_req;
+ if (!msg)
+ goto fail;
+ msgproc_checkversion_req(cli, msg);
+ }
+#endif
+ else if (master->type == ECS__MASTER__TYPE__KEEPALIVE_ANS)
+ {
+ ECS__KeepAliveAns* msg = master->keepalive_ans;
+ if (!msg)
+ goto fail;
+ msgproc_keepalive_ans(cli, msg);
+ }
+ else if (master->type == ECS__MASTER__TYPE__TETHERING_REQ)
+ {
+ ECS__TetheringReq* msg = master->tethering_req;
+ if (!msg)
+ goto fail;
+ msgproc_tethering_req(cli, msg);
+ }
+
+ ecs__master__free_unpacked(master, NULL);
+ return true;
+fail:
+ LOG("invalid message type");
+ ecs__master__free_unpacked(master, NULL);
+ return false;
+}
--- /dev/null
- static bool has_pvpanic = true;
+/*
+ * TIZEN base board
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * SangJin Kim <sangjin3.kim@samsung.com>
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * SungMin Ha <sungmin82.ha@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * DongKyun Yun
+ * DoHyung Hong
+ * Hyunjun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ * x86 board from pc_piix.c...
+ * add some TIZEN-speciaized device...
+ */
+
+#include <glib.h>
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/usb.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/ide.h"
+#include "sysemu/kvm.h"
+#include "hw/kvm/clock.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "hw/cpu/icc_bus.h"
+#include "sysemu/arch_init.h"
+#include "sysemu/blockdev.h"
+#include "hw/i2c/smbus.h"
+#include "hw/xen/xen.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "hw/acpi/acpi.h"
+#include "cpu.h"
+#ifdef CONFIG_XEN
+# include <xen/hvm/hvm_info_table.h>
+#endif
+
+#include "maru_common.h"
+#include "guest_debug.h"
+#include "maru_pm.h"
+#include "maru_brightness.h"
+#include "maru_overlay.h"
+#if defined(__linux__)
+#include <X11/Xlib.h>
+#endif
+#include "vigs/vigs_device.h"
+extern int enable_yagl;
+extern const char *yagl_backend;
+extern int enable_vigs;
+extern const char *vigs_backend;
+extern int enable_spice;
+
+#define MAX_IDE_BUS 2
+
+int codec_init(PCIBus *bus);
+int maru_brill_codec_pci_device_init(PCIBus *bus);
+
+static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
+static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
+static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+
- static void maru_x86_machine_init(MemoryRegion *system_memory,
- MemoryRegion *system_io,
- ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *cpu_model,
- int pci_enabled,
- int kvmclock_enabled)
+static bool has_pci_info = true;
+
+MemoryRegion *global_ram_memory;
+
+MemoryRegion *get_ram_memory(void)
+{
+ return global_ram_memory;
+}
+
- int i;
- ram_addr_t below_4g_mem_size, above_4g_mem_size;
- PCIBus *pci_bus;
- ISABus *isa_bus;
- PCII440FXState *i440fx_state;
- int piix3_devfn = -1;
- qemu_irq *cpu_irq;
- qemu_irq *gsi;
- qemu_irq *i8259;
- qemu_irq *smi_irq;
- GSIState *gsi_state;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- BusState *idebus[MAX_IDE_BUS];
- ISADevice *rtc_state;
- ISADevice *floppy;
- MemoryRegion *ram_memory;
- MemoryRegion *pci_memory;
- MemoryRegion *rom_memory;
- DeviceState *icc_bridge;
- void *fw_cfg = NULL;
- PcGuestInfo *guest_info;
++/* maru specialized device init */
++static void maru_device_init(void)
+{
- #if defined(__linux__)
++ PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
+
- if (xen_enabled() && xen_hvm_init(&ram_memory) != 0) {
- fprintf(stderr, "xen hardware virtual machine initialisation failed\n");
- exit(1);
- }
-
- icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
- object_property_add_child(qdev_get_machine(), "icc-bridge",
- OBJECT(icc_bridge), NULL);
-
- pc_cpus_init(cpu_model, icc_bridge);
- pc_acpi_init("acpi-dsdt.aml");
-
- if (kvmclock_enabled) {
- kvmclock_create();
- }
-
- if (ram_size >= QEMU_BELOW_4G_RAM_END ) {
- above_4g_mem_size = ram_size - QEMU_BELOW_4G_RAM_END;
- below_4g_mem_size = QEMU_BELOW_4G_RAM_END;
- } else {
- above_4g_mem_size = 0;
- below_4g_mem_size = ram_size;
- }
-
- if (pci_enabled) {
- pci_memory = g_new(MemoryRegion, 1);
- memory_region_init(pci_memory, NULL, "pci", INT64_MAX);
- rom_memory = pci_memory;
- } else {
- pci_memory = NULL;
- rom_memory = system_memory;
- }
-
- guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
- guest_info->has_pci_info = has_pci_info;
- guest_info->isapc_ram_fw = !pci_enabled;
-
- /* allocate ram and load rom/bios */
- if (!xen_enabled()) {
- // W/A for allocate larger continuous heap.
- // see vl.c
- if(preallocated_ptr != NULL) {
- g_free(preallocated_ptr);
- }
- //
- fw_cfg = pc_memory_init(system_memory,
- kernel_filename, kernel_cmdline, initrd_filename,
- below_4g_mem_size, above_4g_mem_size,
- rom_memory, &ram_memory, guest_info);
- }
-
- // for ramdump...
- global_ram_memory = ram_memory;
-
- gsi_state = g_malloc0(sizeof(*gsi_state));
- if (kvm_irqchip_in_kernel()) {
- kvm_pc_setup_irq_routing(pci_enabled);
- gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
- GSI_NUM_PINS);
- } else {
- gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
- }
-
- if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
- system_memory, system_io, ram_size,
- below_4g_mem_size,
- 0x100000000ULL - below_4g_mem_size,
- above_4g_mem_size,
- pci_memory, ram_memory);
- } else {
- pci_bus = NULL;
- i440fx_state = NULL;
- isa_bus = isa_bus_new(NULL, system_io);
- no_hpet = 1;
- }
- isa_bus_irqs(isa_bus, gsi);
-
- if (kvm_irqchip_in_kernel()) {
- i8259 = kvm_i8259_init(isa_bus);
- } else if (xen_enabled()) {
- i8259 = xen_interrupt_controller_init();
- } else {
- cpu_irq = pc_allocate_cpu_irq();
- i8259 = i8259_init(isa_bus, cpu_irq[0]);
- }
-
- for (i = 0; i < ISA_NUM_IRQS; i++) {
- gsi_state->i8259_irq[i] = i8259[i];
- }
- if (pci_enabled) {
- ioapic_init_gsi(gsi_state, "i440fx");
- }
- qdev_init_nofail(icc_bridge);
-
- pc_register_ferr_irq(gsi[13]);
-
- pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
- if (xen_enabled()) {
- pci_create_simple(pci_bus, -1, "xen-platform");
- }
-
- /* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
-
- pc_nic_init(isa_bus, pci_bus);
-
- ide_drive_get(hd, MAX_IDE_BUS);
- if (pci_enabled) {
- PCIDevice *dev;
- if (xen_enabled()) {
- dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
- } else {
- dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
- }
- idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
- idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
- } else {
- for(i = 0; i < MAX_IDE_BUS; i++) {
- ISADevice *dev;
- dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
- ide_irq[i],
- hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0");
- }
- }
-
- pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
- floppy, idebus[0], idebus[1], rtc_state);
-
- if (pci_enabled && usb_enabled(false)) {
- pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
- }
-
- if (pci_enabled && acpi_enabled) {
- i2c_bus *smbus;
-
- smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
- /* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- gsi[9], *smi_irq,
- kvm_enabled(), fw_cfg);
- smbus_eeprom_init(smbus, 8, NULL, 0);
- }
-
- if (pci_enabled) {
- pc_pci_device_init(pci_bus);
- }
-
- if (has_pvpanic) {
- pvpanic_init(isa_bus);
- }
-
- /* maru specialized device init */
- if (pci_enabled) {
- // codec_init(pci_bus);
- pci_maru_overlay_init(pci_bus);
- pci_maru_brightness_init(pci_bus);
- maru_brill_codec_pci_device_init(pci_bus);
- }
++#if defined(CONFIG_LINUX)
+ Display *display = XOpenDisplay(0);
+ if (!display && !enable_spice) {
+ fprintf(stderr, "Cannot open X display\n");
+ exit(1);
+ }
+#else
+ void *display = NULL;
+#endif
+ struct winsys_interface *vigs_wsi = NULL;
+
- has_pci_info = false;
++ pci_maru_overlay_init(pci_bus);
++ pci_maru_brightness_init(pci_bus);
++ maru_brill_codec_pci_device_init(pci_bus);
+
+ if (enable_vigs) {
+ PCIDevice *pci_dev = pci_create(pci_bus, -1, "vigs");
+ qdev_prop_set_ptr(&pci_dev->qdev, "display", display);
+ qdev_init_nofail(&pci_dev->qdev);
+ vigs_wsi = DO_UPCAST(VIGSDevice, pci_dev, pci_dev)->wsi;
+ }
+
+ if (enable_yagl) {
+ PCIDevice *pci_dev = pci_create(pci_bus, -1, "yagl");
+ qdev_prop_set_ptr(&pci_dev->qdev, "display", display);
+ if (vigs_wsi &&
+ (strcmp(yagl_backend, "vigs") == 0) &&
+ (strcmp(vigs_backend, "gl") == 0)) {
+ qdev_prop_set_ptr(&pci_dev->qdev, "winsys_gl_interface", vigs_wsi);
+ }
+ qdev_init_nofail(&pci_dev->qdev);
+ }
+}
+
++extern void pc_init_pci(QEMUMachineInitArgs *args);
+static void maru_x86_board_init(QEMUMachineInitArgs *args)
+{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- maru_x86_machine_init(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 1);
++ pc_init_pci(args);
+
- .max_cpus = 255,
- DEFAULT_MACHINE_OPTIONS,
++ has_pci_info = false;
++ maru_device_init();
+}
+
+static QEMUMachine maru_x86_machine = {
++ PC_DEFAULT_MACHINE_OPTIONS,
+ .name = "maru-x86-machine",
+ .alias = "maru-x86-machine",
+ .desc = "Maru Board (x86)",
+ .init = maru_x86_board_init,
+ .hot_add_cpu = pc_hot_add_cpu,
+};
+
+static void maru_machine_init(void)
+{
+ qemu_register_machine(&maru_x86_machine);
+}
+
+machine_init(maru_machine_init);
--- /dev/null
- qemu_irq_raise(s->dev.irq[0]);
+/*
+ * Virtual Codec Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "maru_brill_codec.h"
+
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, brillcodec);
+
+// device
+#define CODEC_DEVICE_NAME "brilcodec"
+#define CODEC_VERSION 1
+
+// device memory
+#define CODEC_META_DATA_SIZE (256)
+
+#define CODEC_MEM_SIZE (32 * 1024 * 1024)
+#define CODEC_REG_SIZE (256)
+
+// libav
+#define GEN_MASK(x) ((1 << (x)) - 1)
+#define ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x))
+#define ROUND_UP_2(x) ROUND_UP_X(x, 1)
+#define ROUND_UP_4(x) ROUND_UP_X(x, 2)
+#define ROUND_UP_8(x) ROUND_UP_X(x, 3)
+#define DIV_ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) >> (x))
+
+#define DEFAULT_VIDEO_GOP_SIZE 15
+
+
+// define a queue to manage ioparam, context data
+typedef struct DeviceMemEntry {
+ uint8_t *buf;
+ uint32_t buf_size;
+ uint32_t ctx_id;
+
+ QTAILQ_ENTRY(DeviceMemEntry) node;
+} DeviceMemEntry;
+
+typedef struct CodecDataStg {
+ CodecParam *param_buf;
+ DeviceMemEntry *data_buf;
+
+ QTAILQ_ENTRY(CodecDataStg) node;
+} CodecDataStg;
+
+// define two queue to store input and output buffers.
+static QTAILQ_HEAD(codec_wq, DeviceMemEntry) codec_wq =
+ QTAILQ_HEAD_INITIALIZER(codec_wq);
+
+static QTAILQ_HEAD(codec_rq, CodecDataStg) codec_rq =
+ QTAILQ_HEAD_INITIALIZER(codec_rq);
+
+static DeviceMemEntry *entry[CODEC_CONTEXT_MAX];
+
+// pixel info
+typedef struct PixFmtInfo {
+ uint8_t x_chroma_shift;
+ uint8_t y_chroma_shift;
+} PixFmtInfo;
+
+static PixFmtInfo pix_fmt_info[PIX_FMT_NB];
+
+// thread
+// static int idle_thread_cnt = 0;
+#define DEFAULT_WORKER_THREAD_CNT 8
+
+static void *maru_brill_codec_threads(void *opaque);
+
+// static void maru_brill_codec_reset_parser_info(MaruBrillCodecState *s, int32_t ctx_index);
+static int maru_brill_codec_query_list(MaruBrillCodecState *s);
+static void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t value);
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *, int, void *);
+static bool codec_deinit(MaruBrillCodecState *, int, void *);
+static bool codec_decode_video(MaruBrillCodecState *, int, void *);
+static bool codec_encode_video(MaruBrillCodecState *, int, void *);
+static bool codec_decode_audio(MaruBrillCodecState *, int, void *);
+static bool codec_encode_audio(MaruBrillCodecState *, int, void *);
+static bool codec_picture_copy(MaruBrillCodecState *, int, void *);
+static bool codec_flush_buffers(MaruBrillCodecState *, int, void *);
+
+typedef bool (*CodecFuncEntry)(MaruBrillCodecState *, int, void *);
+static CodecFuncEntry codec_func_handler[] = {
+ codec_init,
+ codec_decode_video,
+ codec_encode_video,
+ codec_decode_audio,
+ codec_encode_audio,
+ codec_picture_copy,
+ codec_deinit,
+ codec_flush_buffers,
+};
+
+static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx);
+#if 0
+static int maru_brill_codec_parser_parse (AVCodecParserContext *pctx, AVCodecContext *avctx,
+ uint8_t *inbuf, int inbuf_size,
+ int64_t pts, int64_t dts, int64_t pos);
+#endif
+
+static void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx);
+static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s, CodecParam *ioparam);
+static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* buf,
+ uint32_t buf_size, int ctx_id);
+
+static void *maru_brill_codec_store_inbuf(uint8_t *mem_base_offset, CodecParam *ioparam);
+
+static void maru_brill_codec_reset(DeviceState *s);
+
+static void maru_brill_codec_get_cpu_cores(MaruBrillCodecState *s)
+{
+ s->worker_thread_cnt = get_number_of_processors();
+ if (s->worker_thread_cnt < DEFAULT_WORKER_THREAD_CNT) {
+ s->worker_thread_cnt = DEFAULT_WORKER_THREAD_CNT;
+ }
+
+ TRACE("number of threads: %d\n", s->worker_thread_cnt);
+}
+
+static void maru_brill_codec_threads_create(MaruBrillCodecState *s)
+{
+ int index;
+ QemuThread *pthread = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ pthread = g_malloc(sizeof(QemuThread) * s->worker_thread_cnt);
+ if (!pthread) {
+ ERR("failed to allocate threadpool memory.\n");
+ return;
+ }
+
+ qemu_cond_init(&s->threadpool.cond);
+ qemu_mutex_init(&s->threadpool.mutex);
+
+ s->is_thread_running = true;
+ s->idle_thread_cnt = 0;
+
+ for (index = 0; index < s->worker_thread_cnt; index++) {
+ qemu_thread_create(&pthread[index],
+ maru_brill_codec_threads, (void *)s, QEMU_THREAD_JOINABLE);
+ }
+
+ s->threadpool.threads = pthread;
+
+ TRACE("leave: %s\n", __func__);
+}
+
+static void maru_brill_codec_thread_exit(MaruBrillCodecState *s)
+{
+ int index;
+
+ TRACE("enter: %s\n", __func__);
+
+ /* stop to run dedicated threads. */
+ s->is_thread_running = false;
+
+ for (index = 0; index < s->worker_thread_cnt; index++) {
+ qemu_thread_join(&s->threadpool.threads[index]);
+ }
+
+ TRACE("destroy mutex and conditional.\n");
+ qemu_mutex_destroy(&s->threadpool.mutex);
+ qemu_cond_destroy(&s->threadpool.cond);
+
+ if (s->threadpool.threads) {
+ g_free(s->threadpool.threads);
+ s->threadpool.threads = NULL;
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+static void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
+{
+ CodecParam *ioparam = NULL;
+
+ ioparam = g_malloc0(sizeof(CodecParam));
+ if (!ioparam) {
+ ERR("failed to allocate ioparam\n");
+ return;
+ }
+
+ memcpy(ioparam, &s->ioparam, sizeof(CodecParam));
+
+ TRACE("wakeup thread. ctx_id: %u, api_id: %u, mem_offset: 0x%x\n",
+ ioparam->ctx_index, ioparam->api_index, ioparam->mem_offset);
+
+ maru_brill_codec_push_readqueue(s, ioparam);
+
+ qemu_mutex_lock(&s->context_mutex);
+ // W/A for threads starvation.
+ while (s->idle_thread_cnt == 0) {
+ qemu_mutex_unlock(&s->context_mutex);
+ TRACE("Worker threads are exhausted\n");
+ usleep(2000); // wait 2ms.
+ qemu_mutex_lock(&s->context_mutex);
+ }
+ qemu_cond_signal(&s->threadpool.cond);
+ qemu_mutex_unlock(&s->context_mutex);
+
+ TRACE("after sending conditional signal\n");
+}
+
+static void *maru_brill_codec_threads(void *opaque)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ TRACE("enter: %s\n", __func__);
+
+ while (s->is_thread_running) {
+ int ctx_id, api_id;
+ CodecDataStg *elem = NULL;
+ DeviceMemEntry *indata_buf = NULL;
+
+ qemu_mutex_lock(&s->context_mutex);
+ ++(s->idle_thread_cnt); // protected under mutex.
+ qemu_cond_wait(&s->threadpool.cond, &s->context_mutex);
+ --(s->idle_thread_cnt); // protected under mutex.
+ qemu_mutex_unlock(&s->context_mutex);
+
+ qemu_mutex_lock(&s->ioparam_queue_mutex);
+ elem = QTAILQ_FIRST(&codec_rq);
+ if (elem) {
+ QTAILQ_REMOVE(&codec_rq, elem, node);
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ } else {
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ continue;
+ }
+
+ if (!elem->param_buf) {
+ continue;
+ }
+
+ api_id = elem->param_buf->api_index;
+ ctx_id = elem->param_buf->ctx_index;
+ indata_buf = elem->data_buf;
+
+ TRACE("api_id: %d ctx_id: %d\n", api_id, ctx_id);
+
+ if (!codec_func_handler[api_id](s, ctx_id, indata_buf)) {
+ ERR("codec_func failure.\n");
+ continue;
+ }
+
+ TRACE("release a buffer of CodecParam\n");
+ g_free(elem->param_buf);
+
+ if (elem->data_buf) {
+
+ if (elem->data_buf->buf) {
+ TRACE("release inbuf\n");
+ g_free(elem->data_buf->buf);
+ }
+
+ TRACE("release a buffer indata_buf\n");
+ g_free(elem->data_buf);
+ }
+
+ TRACE("release an element of CodecDataStg\n");
+ g_free(elem);
+
+ if (api_id == CODEC_DEINIT) {
+ TRACE("deinit doesn't need to raise interrupt.\n");
+ } else {
+ TRACE("switch context to raise interrupt.\n");
+ qemu_bh_schedule(s->codec_bh);
+ }
+ }
+
+ maru_brill_codec_thread_exit(s);
+
+ TRACE("leave: %s\n", __func__);
+ return NULL;
+}
+
+// queue
+static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s,
+ CodecParam *ioparam)
+{
+ CodecDataStg *elem = NULL;
+ DeviceMemEntry *data_buf = NULL;
+
+ elem = g_malloc0(sizeof(CodecDataStg));
+ if (!elem) {
+ ERR("failed to allocate ioparam_queue. %d\n", sizeof(CodecDataStg));
+ return;
+ }
+
+ elem->param_buf = ioparam;
+
+ switch(ioparam->api_index) {
+ case CODEC_DECODE_VIDEO ... CODEC_ENCODE_AUDIO:
+ data_buf = maru_brill_codec_store_inbuf((uint8_t *)s->vaddr, ioparam);
+ break;
+ default:
+ TRACE("no buffer from guest\n");
+ break;
+ }
+
+ elem->data_buf = data_buf;
+
+ qemu_mutex_lock(&s->ioparam_queue_mutex);
+ QTAILQ_INSERT_TAIL(&codec_rq, elem, node);
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+}
+
+static void *maru_brill_codec_store_inbuf(uint8_t *mem_base_offset,
+ CodecParam *ioparam)
+{
+ DeviceMemEntry *elem = NULL;
+ int readbuf_size, size = 0;
+ uint8_t *readbuf = NULL;
+ uint8_t *device_mem = mem_base_offset + ioparam->mem_offset;
+
+ elem = g_malloc0(sizeof(DeviceMemEntry));
+ if (!elem) {
+ ERR("failed to allocate readqueue node. size: %d\n",
+ sizeof(DeviceMemEntry));
+ return NULL;
+ }
+
+ memcpy(&readbuf_size, device_mem, sizeof(readbuf_size));
+ size = sizeof(readbuf_size);
+
+ TRACE("readbuf size: %d\n", readbuf_size);
+ if (readbuf_size <= 0) {
+ TRACE("inbuf size is zero. api_id: %d, ctx_id: %d, mem_offset: %x\n",
+ readbuf_size, ioparam->api_index, ioparam->ctx_index, ioparam->mem_offset);
+ } else {
+ readbuf = g_malloc0(readbuf_size);
+ if (!readbuf) {
+ ERR("failed to allocate a read buffer. size: %d\n", readbuf_size);
+ } else {
+ TRACE("copy input buffer from guest. ctx_id: %d, mem_offset: %x\n",
+ ioparam->ctx_index, ioparam->mem_offset);
+ memcpy(readbuf, device_mem + size, readbuf_size);
+ }
+ }
+ memset(device_mem, 0x00, sizeof(readbuf_size));
+
+ elem->buf = readbuf;
+ elem->buf_size = readbuf_size;
+ elem->ctx_id = ioparam->ctx_index;
+
+ return elem;
+}
+
+static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* buf,
+ uint32_t buf_size, int ctx_id)
+{
+ DeviceMemEntry *elem = NULL;
+ elem = g_malloc0(sizeof(DeviceMemEntry));
+
+ elem->buf = buf;
+ elem->buf_size = buf_size;
+ elem->ctx_id = ctx_id;
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_INSERT_TAIL(&codec_wq, elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+}
+
+static void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
+{
+ DeviceMemEntry *elem = NULL;
+ uint32_t mem_offset = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ if (ctx_idx < 1 || ctx_idx > (CODEC_CONTEXT_MAX - 1)) {
+ ERR("invalid buffer index. %d\n", ctx_idx);
+ return;
+ }
+
+ TRACE("pop_writeqeue. context index: %d\n", ctx_idx);
+ elem = entry[ctx_idx];
+ if (elem) {
+ mem_offset = s->ioparam.mem_offset;
+
+ // check corrupted mem_offset
+ if (mem_offset < CODEC_MEM_SIZE) {
+ if (elem->buf) {
+ TRACE("write data %d to guest. mem_offset: 0x%x\n",
+ elem->buf_size, mem_offset);
+ memcpy(s->vaddr + mem_offset, elem->buf, elem->buf_size);
+
+ TRACE("release output buffer: %p\n", elem->buf);
+ g_free(elem->buf);
+ }
+ } else {
+ TRACE("mem_offset is corrupted!!\n");
+ }
+
+ TRACE("pop_writequeue. release elem: %p\n", elem);
+ g_free(elem);
+
+ entry[ctx_idx] = NULL;
+ } else {
+ TRACE("there is no buffer to copy data to guest\n");
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+static void serialize_video_data(const struct video_data *video,
+ AVCodecContext *avctx)
+{
+ if (video->width) {
+ avctx->width = video->width;
+ }
+ if (video->height) {
+ avctx->height = video->height;
+ }
+ if (video->fps_n) {
+ avctx->time_base.num = video->fps_n;
+ }
+ if (video->fps_d) {
+ avctx->time_base.den = video->fps_d;
+ }
+ if (video->pix_fmt > PIX_FMT_NONE) {
+ avctx->pix_fmt = video->pix_fmt;
+ }
+ if (video->par_n) {
+ avctx->sample_aspect_ratio.num = video->par_n;
+ }
+ if (video->par_d) {
+ avctx->sample_aspect_ratio.den = video->par_d;
+ }
+ if (video->bpp) {
+ avctx->bits_per_coded_sample = video->bpp;
+ }
+ if (video->ticks_per_frame) {
+ avctx->ticks_per_frame = video->ticks_per_frame;
+ }
+}
+
+static void deserialize_video_data (const AVCodecContext *avctx,
+ struct video_data *video)
+{
+ memset(video, 0x00, sizeof(struct video_data));
+
+ video->width = avctx->width;
+ video->height = avctx->height;
+ video->fps_n = avctx->time_base.num;
+ video->fps_d = avctx->time_base.den;
+ video->pix_fmt = avctx->pix_fmt;
+ video->par_n = avctx->sample_aspect_ratio.num;
+ video->par_d = avctx->sample_aspect_ratio.den;
+ video->bpp = avctx->bits_per_coded_sample;
+ video->ticks_per_frame = avctx->ticks_per_frame;
+}
+
+static void serialize_audio_data (const struct audio_data *audio,
+ AVCodecContext *avctx)
+{
+ if (audio->channels) {
+ avctx->channels = audio->channels;
+ }
+ if (audio->sample_rate) {
+ avctx->sample_rate = audio->sample_rate;
+ }
+ if (audio->block_align) {
+ avctx->block_align = audio->block_align;
+ }
+
+ if (audio->sample_fmt > AV_SAMPLE_FMT_NONE) {
+ avctx->sample_fmt = audio->sample_fmt;
+ }
+}
+
+#if 0
+static void maru_brill_codec_reset_parser_info(MaruBrillCodecState *s, int32_t ctx_index)
+{
+ s->context[ctx_index].parser_buf = NULL;
+ s->context[ctx_index].parser_use = false;
+}
+#endif
+
+static void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t context_id)
+{
+ DeviceMemEntry *wq_elem = NULL, *wnext = NULL;
+ CodecDataStg *rq_elem = NULL, *rnext = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("release %d of context\n", context_id);
+ codec_deinit(s, context_id, NULL);
+ s->context[context_id].occupied = false;
+
+ // TODO: check if foreach statment needs lock or not.
+ QTAILQ_FOREACH_SAFE(rq_elem, &codec_rq, node, rnext) {
+ if (rq_elem && rq_elem->data_buf &&
+ (rq_elem->data_buf->ctx_id == context_id)) {
+
+ TRACE("remove unused node from codec_rq. ctx_id: %d\n", context_id);
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_REMOVE(&codec_rq, rq_elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ if (rq_elem && rq_elem->data_buf) {
+ TRACE("release rq_buffer: %p\n", rq_elem->data_buf);
+ g_free(rq_elem->data_buf);
+ }
+
+ TRACE("release rq_elem: %p\n", rq_elem);
+ g_free(rq_elem);
+ } else {
+ TRACE("no elem of %d context in the codec_rq.\n", context_id);
+ }
+ }
+
+ QTAILQ_FOREACH_SAFE(wq_elem, &codec_wq, node, wnext) {
+ if (wq_elem && wq_elem->ctx_id == context_id) {
+ TRACE("remove unused node from codec_wq. ctx_id: %d\n", context_id);
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_REMOVE(&codec_wq, wq_elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ if (wq_elem && wq_elem->buf) {
+ TRACE("release wq_buffer: %p\n", wq_elem->buf);
+ g_free(wq_elem->buf);
+ wq_elem->buf = NULL;
+ }
+
+ TRACE("release wq_elem: %p\n", wq_elem);
+ g_free(wq_elem);
+ } else {
+ TRACE("no elem of %d context in the codec_wq.\n", context_id);
+ }
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+
+// initialize each pixel format.
+static void maru_brill_codec_pixfmt_info_init(void)
+{
+ /* YUV formats */
+ pix_fmt_info[PIX_FMT_YUV420P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUV420P].y_chroma_shift = 1;
+
+ pix_fmt_info[PIX_FMT_YUV422P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUV422P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUV444P].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_YUV444P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUYV422].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUYV422].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUV410P].x_chroma_shift = 2;
+ pix_fmt_info[PIX_FMT_YUV410P].y_chroma_shift = 2;
+
+ pix_fmt_info[PIX_FMT_YUV411P].x_chroma_shift = 2;
+ pix_fmt_info[PIX_FMT_YUV411P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUVJ420P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUVJ420P].y_chroma_shift = 1;
+
+ pix_fmt_info[PIX_FMT_YUVJ422P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUVJ422P].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUVJ444P].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_YUVJ444P].y_chroma_shift = 0;
+
+ /* RGB formats */
+ pix_fmt_info[PIX_FMT_RGB24].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB24].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_BGR24].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_BGR24].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_RGB32].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB32].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_RGB565].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB565].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_RGB555].x_chroma_shift = 0;
+ pix_fmt_info[PIX_FMT_RGB555].y_chroma_shift = 0;
+
+ pix_fmt_info[PIX_FMT_YUVA420P].x_chroma_shift = 1;
+ pix_fmt_info[PIX_FMT_YUVA420P].y_chroma_shift = 1;
+}
+
+static int maru_brill_codec_get_picture_size(AVPicture *picture, uint8_t *ptr,
+ int pix_fmt, int width,
+ int height, bool encode)
+{
+ int size, w2, h2, size2;
+ int stride, stride2;
+ int fsize;
+ PixFmtInfo *pinfo;
+
+ pinfo = &pix_fmt_info[pix_fmt];
+
+ switch (pix_fmt) {
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUV422P:
+ case PIX_FMT_YUV444P:
+ case PIX_FMT_YUV410P:
+ case PIX_FMT_YUV411P:
+ case PIX_FMT_YUVJ420P:
+ case PIX_FMT_YUVJ422P:
+ case PIX_FMT_YUVJ444P:
+ stride = ROUND_UP_4(width);
+ h2 = ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size = stride * h2;
+ w2 = DIV_ROUND_UP_X(width, pinfo->x_chroma_shift);
+ stride2 = ROUND_UP_4(w2);
+ h2 = DIV_ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size2 = stride2 * h2;
+ fsize = size + 2 * size2;
+ TRACE("stride: %d, stride2: %d, size: %d, size2: %d, fsize: %d\n",
+ stride, stride2, size, size2, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = picture->data[0] + size;
+ picture->data[2] = picture->data[1] + size2;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = stride2;
+ picture->linesize[2] = stride2;
+ picture->linesize[3] = 0;
+ TRACE("planes %d %d %d\n", 0, size, size + size2);
+ TRACE("strides %d %d %d\n", 0, stride, stride2, stride2);
+ break;
+ case PIX_FMT_YUVA420P:
+ stride = ROUND_UP_4(width);
+ h2 = ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size = stride * h2;
+ w2 = DIV_ROUND_UP_X(width, pinfo->x_chroma_shift);
+ stride2 = ROUND_UP_4(w2);
+ h2 = DIV_ROUND_UP_X(height, pinfo->y_chroma_shift);
+ size2 = stride2 * h2;
+ fsize = 2 * size + 2 * size2;
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = picture->data[0] + size;
+ picture->data[2] = picture->data[1] + size2;
+ picture->data[3] = picture->data[2] + size2;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = stride2;
+ picture->linesize[2] = stride2;
+ picture->linesize[3] = stride;
+ TRACE("planes %d %d %d\n", 0, size, size + size2);
+ TRACE("strides %d %d %d\n", 0, stride, stride2, stride2);
+ break;
+ case PIX_FMT_RGB24:
+ case PIX_FMT_BGR24:
+ stride = ROUND_UP_4 (width * 3);
+ fsize = stride * height;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_RGB32:
+ stride = width * 4;
+ fsize = stride * height;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_RGB555:
+ case PIX_FMT_RGB565:
+ stride = ROUND_UP_4 (width * 2);
+ fsize = stride * height;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_PAL8:
+ stride = ROUND_UP_4(width);
+ size = stride * height;
+ fsize = size + 256 * 4;
+ TRACE("stride: %d, size: %d\n", stride, fsize);
+
+ if (!encode && !ptr) {
+ TRACE("allocate a buffer for a decoded picture.\n");
+ ptr = av_mallocz(fsize);
+ if (!ptr) {
+ ERR("[%d] failed to allocate memory.\n", __LINE__);
+ return -1;
+ }
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = ptr + size;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = stride;
+ picture->linesize[1] = 4;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ default:
+ picture->data[0] = NULL;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ fsize = -1;
+ ERR("pixel format: %d was wrong.\n", pix_fmt);
+ break;
+ }
+
+ return fsize;
+}
+
+static int maru_brill_codec_query_list (MaruBrillCodecState *s)
+{
+ AVCodec *codec = NULL;
+ uint32_t size = 0, mem_size = 0;
+ uint32_t data_len = 0, length = 0;
+ int32_t codec_type, media_type;
+ int32_t codec_fmts[4], i;
+
+ /* register avcodec */
+ TRACE("register avcodec\n");
+ av_register_all();
+
+ codec = av_codec_next(NULL);
+ if (!codec) {
+ ERR("failed to get codec info.\n");
+ return -1;
+ }
+
+ // a region to store the number of codecs.
+ length = 32 + 64 + 6 * sizeof(int32_t);
+ mem_size = size = sizeof(uint32_t);
+
+ while (codec) {
+ codec_type =
+ codec->decode ? CODEC_TYPE_DECODE : CODEC_TYPE_ENCODE;
+ media_type = codec->type;
+
+ memset(codec_fmts, -1, sizeof(codec_fmts));
+ if (media_type == AVMEDIA_TYPE_VIDEO) {
+ if (codec->pix_fmts) {
+ for (i = 0; codec->pix_fmts[i] != -1; i++) {
+ codec_fmts[i] = codec->pix_fmts[i];
+ }
+ }
+ } else if (media_type == AVMEDIA_TYPE_AUDIO) {
+ if (codec->sample_fmts) {
+ for (i = 0; codec->sample_fmts[i] != -1; i++) {
+ codec_fmts[i] = codec->sample_fmts[i];
+ }
+ }
+ } else {
+ ERR("%s of media type is unknown.\n", codec->name);
+ }
+
+ memset(s->vaddr + mem_size, 0x00, length);
+ mem_size += length;
+
+ data_len += length;
+ memcpy(s->vaddr, &data_len, sizeof(data_len));
+
+ memcpy(s->vaddr + size, &codec_type, sizeof(codec_type));
+ size += sizeof(codec_type);
+ memcpy(s->vaddr + size, &media_type, sizeof(media_type));
+ size += sizeof(media_type);
+ memcpy(s->vaddr + size, codec->name, strlen(codec->name));
+ size += 32;
+ memcpy(s->vaddr + size,
+ codec->long_name, strlen(codec->long_name));
+ size += 64;
+ memcpy(s->vaddr + size, codec_fmts, sizeof(codec_fmts));
+ size += sizeof(codec_fmts);
+
+ codec = av_codec_next(codec);
+ }
+
+ return 0;
+}
+
+static int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
+{
+ int index;
+
+ TRACE("enter: %s\n", __func__);
+
+ for (index = 1; index < CODEC_CONTEXT_MAX; index++) {
+ if (s->context[index].occupied == false) {
+ TRACE("get %d of codec context successfully.\n", index);
+ s->context[index].occupied = true;
+ break;
+ }
+ }
+
+ if (index == CODEC_CONTEXT_MAX) {
+ ERR("failed to get available codec context. ");
+ ERR("try to run codec again.\n");
+ index = -1;
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return index;
+}
+
+// allocate avcontext and avframe struct.
+static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, int index)
+{
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("allocate %d of context and frame.\n", index);
+ s->context[index].avctx = avcodec_alloc_context();
+ s->context[index].frame = avcodec_alloc_frame();
+ s->context[index].opened = false;
+
+ s->context[index].parser_buf = NULL;
+ s->context[index].parser_use = false;
+
+ TRACE("leave: %s\n", __func__);
+
+ return s->context[index].avctx;
+}
+
+static AVCodec *maru_brill_codec_find_avcodec(uint8_t *mem_buf)
+{
+ AVCodec *codec = NULL;
+ int32_t encode, size = 0;
+ char codec_name[32] = {0, };
+
+ memcpy(&encode, mem_buf, sizeof(encode));
+ size = sizeof(encode);
+ memcpy(codec_name, mem_buf + size, sizeof(codec_name));
+ size += sizeof(codec_name);
+
+ TRACE("type: %d, name: %s\n", encode, codec_name);
+
+ if (encode) {
+ codec = avcodec_find_encoder_by_name (codec_name);
+ } else {
+ codec = avcodec_find_decoder_by_name (codec_name);
+ }
+ INFO("%s!! find %s %s\n",
+ codec ? "success" : "failure",
+ codec_name, encode ? "encoder" : "decoder");
+
+ return codec;
+}
+
+static void read_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+ struct video_data video = { 0, };
+ struct audio_data audio = { 0, };
+ int bitrate = 0, size = 0;
+
+ memcpy(&video, mem_buf + size, sizeof(video));
+ size = sizeof(video);
+ serialize_video_data(&video, avctx);
+
+ memcpy(&audio, mem_buf + size, sizeof(int32_t) * 6);
+ size += sizeof(int32_t) * 6;
+ memcpy(&audio.bits_per_smp_fmt, mem_buf + size, sizeof(int32_t));
+ size += sizeof(int32_t);
+ memcpy(&audio.channel_layout, mem_buf + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ serialize_audio_data(&audio, avctx);
+
+ memcpy(&bitrate, mem_buf + size, sizeof(bitrate));
+ size += sizeof(bitrate);
+ if (bitrate) {
+ avctx->bit_rate = bitrate;
+ }
+ memcpy(&avctx->codec_tag, mem_buf + size, sizeof(avctx->codec_tag));
+ size += sizeof(avctx->codec_tag);
+ memcpy(&avctx->extradata_size,
+ mem_buf + size, sizeof(avctx->extradata_size));
+ size += sizeof(avctx->extradata_size);
+ if (avctx->extradata_size > 0) {
+ TRACE("extradata size: %d.\n", avctx->extradata_size);
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ if (avctx->extradata) {
+ memcpy(avctx->extradata, mem_buf + size, avctx->extradata_size);
+ }
+ } else {
+ TRACE("no extra data.\n");
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ }
+}
+
+// write the result of codec_init
+static void write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+ int size = 0;
+
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ int osize = 0;
+
+ TRACE("codec_init. audio sample_fmt: %d\n", avctx->sample_fmt);
+
+ memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
+ size = sizeof(avctx->sample_fmt);
+ memcpy(mem_buf + size,
+ &avctx->frame_size, sizeof(avctx->frame_size));
+ size += sizeof(avctx->frame_size);
+ osize = av_get_bits_per_sample(avctx->codec->id) / 8;
+ memcpy(mem_buf + size, &osize, sizeof(osize));
+ }
+}
+
+// write the result of codec_decode_video
+static void write_codec_decode_video_data(AVCodecContext *avctx, int len,
+ int got_pic_ptr, uint8_t *mem_buf)
+{
+ struct video_data video;
+ int size = 0;
+
+ memcpy(mem_buf, &len, sizeof(len));
+ size = sizeof(len);
+ memcpy(mem_buf + size, &got_pic_ptr, sizeof(got_pic_ptr));
+ size += sizeof(got_pic_ptr);
+ if (avctx) {
+ deserialize_video_data(avctx, &video);
+ memcpy(mem_buf + size, &video, sizeof(struct video_data));
+ }
+}
+
+// write the result of codec_decode_audio
+static void write_codec_decode_audio_data(int sample_rate, int channel,
+ int64_t channel_layout, int len,
+ int frame_size_ptr, uint8_t *mem_buf)
+{
+ int size = 0;
+
+ TRACE("copy decode_audio. len %d, frame_size %d\n", len, frame_size_ptr);
+
+ memcpy(mem_buf, &sample_rate, sizeof(sample_rate));
+ size = sizeof(sample_rate);
+ memcpy(mem_buf + size, &channel, sizeof(channel));
+ size += sizeof(channel);
+ memcpy(mem_buf + size, &channel_layout, sizeof(channel_layout));
+ size += sizeof(channel_layout);
+ memcpy(mem_buf + size, &len, sizeof(len));
+ size += sizeof(len);
+ memcpy(mem_buf + size, &frame_size_ptr, sizeof(frame_size_ptr));
+}
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *elem)
+{
+ AVCodecContext *avctx = NULL;
+ AVCodec *codec = NULL;
+ int size = 0, ret = -1;
+ uint8_t *meta_buf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ // assign meta_buf
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ // allocate AVCodecContext
+ avctx = maru_brill_codec_alloc_context(s, ctx_id);
+ if (!avctx) {
+ ERR("[%d] failed to allocate context.\n", __LINE__);
+ ret = -1;
+ } else {
+ codec = maru_brill_codec_find_avcodec(meta_buf);
+ if (codec) {
+ size = sizeof(int32_t) + 32; // buffer size of codec_name
+ read_codec_init_data(avctx, meta_buf + size);
+
+ ret = avcodec_open(avctx, codec);
+ INFO("avcodec_open done. ctx_id: %d\n", ctx_id);
+
+ s->context[ctx_id].opened = true;
+ s->context[ctx_id].parser_ctx =
+ maru_brill_codec_parser_init(avctx);
+ } else {
+ ERR("failed to find codec. ctx_id: %d\n", ctx_id);
+ }
+ }
+
+ // return the result of avcodec_open
+ memcpy(meta_buf, &ret, sizeof(ret));
+ size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to open codec contex.\n");
+ } else {
+ write_codec_init_data(avctx, meta_buf + size);
+ }
+
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *frame = NULL;
+ AVCodecParserContext *parserctx = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = s->context[ctx_id].avctx;
+ frame = s->context[ctx_id].frame;
+ parserctx = s->context[ctx_id].parser_ctx;
+ if (!avctx || !frame) {
+ TRACE("%d of AVCodecContext or AVFrame is NULL. "
+ " Those resources have been released before.\n", ctx_id);
+ return false;
+ } else {
+ qemu_mutex_lock(&s->threadpool.mutex);
+ if (!s->context[ctx_id].opened) {
+ TRACE("%d of context has already been closed\n", ctx_id);
+ qemu_mutex_unlock(&s->threadpool.mutex);
+ return false;
+ }
+ avcodec_close(avctx);
+ INFO("close avcontext of %d\n", ctx_id);
+ s->context[ctx_id].opened = false;
+ qemu_mutex_unlock(&s->threadpool.mutex);
+
+ if (avctx->extradata) {
+ TRACE("free context extradata\n");
+ av_free(avctx->extradata);
+ s->context[ctx_id].avctx->extradata = NULL;
+ }
+
+ if (avctx->palctrl) {
+ TRACE("free context palctrl \n");
+ av_free(avctx->palctrl);
+ s->context[ctx_id].avctx->palctrl = NULL;
+ }
+
+ if (frame) {
+ TRACE("free frame\n");
+ av_free(frame);
+ s->context[ctx_id].frame = NULL;
+ }
+
+ if (avctx) {
+ TRACE("free codec context\n");
+ av_free(avctx);
+ s->context[ctx_id].avctx = NULL;
+ }
+
+ if (parserctx) {
+ av_parser_close(parserctx);
+ s->context[ctx_id].parser_ctx = NULL;
+ }
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+//
+static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("%d of AVCodecContext is NULL.\n", ctx_id);
+ return false;
+ } else {
+ avcodec_flush_buffers(avctx);
+ TRACE("flush %d context of buffers.\n", ctx_id);
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *picture = NULL;
+ AVPacket avpkt;
+ int got_pic_ptr = 0, len = 0;
+ uint8_t *inbuf = NULL;
+ int inbuf_size, idx, size = 0;
+ int64_t in_offset;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *meta_buf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ size = sizeof(inbuf_size);
+ memcpy(&idx, meta_buf + size, sizeof(idx));
+ size += sizeof(idx);
+ memcpy(&in_offset, meta_buf + size, sizeof(in_offset));
+ size += sizeof(in_offset);
+ TRACE("decode_video. input buffer size: %d\n", inbuf_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ inbuf_size = 0;
+ TRACE("decode_video. no input buffer. ctx_id: %d, %p, %d\n",
+ ctx_id, inbuf, elem->buf_size);
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+ avctx = s->context[ctx_id].avctx;
+ picture = s->context[ctx_id].frame;
+ if (!avctx || !picture) {
+ ERR("%d of AVCodecContext or AVFrame is NULL.\n", ctx_id);
+ len = -1;
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ len = -1;
+ } else {
+ // in case of skipping frames
+ picture->pict_type = -1;
+
+ len = avcodec_decode_video2(avctx, picture, &got_pic_ptr, &avpkt);
+ if (len < 0) {
+ ERR("failed to decode video. ctx index: %d\n", ctx_id);
+ }
+ }
+
+ TRACE("after decoding video. len: %d, have_data: %d\n",
+ len, got_pic_ptr);
+
+ write_codec_decode_video_data(avctx, len, got_pic_ptr, meta_buf);
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
+{
+ AVCodecContext *avctx;
+ AVPicture *src;
+ AVPicture dst;
+ uint8_t *out_buffer = NULL, *tempbuf = NULL;
+ int pict_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("copy decoded image of %d context.\n", ctx_id);
+
+ avctx = s->context[ctx_id].avctx;
+ src = (AVPicture *)s->context[ctx_id].frame;
+ if (!avctx || !src) {
+ ERR("%d of AVCodecContext or AVFrame is NULL.\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ } else {
+ TRACE("decoded image. pix_fmt: %d width: %d, height: %d\n",
+ avctx->pix_fmt, avctx->width, avctx->height);
+
+ pict_size =
+ maru_brill_codec_get_picture_size(&dst, NULL, avctx->pix_fmt,
+ avctx->width, avctx->height, false);
+ if ((pict_size) < 0) {
+ ERR("picture size: %d\n", pict_size);
+ } else {
+ TRACE("picture size: %d\n", pict_size);
+ av_picture_copy(&dst, src, avctx->pix_fmt,
+ avctx->width, avctx->height);
+
+ tempbuf = g_malloc0(pict_size);
+ if (!tempbuf) {
+ ERR("failed to allocate a picture buffer. size: %d\n", pict_size);
+ } else {
+ out_buffer = dst.data[0];
+ memcpy(tempbuf, out_buffer, pict_size);
+ }
+ av_free(out_buffer);
+ }
+ }
+ maru_brill_codec_push_writequeue(s, tempbuf, pict_size, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx;
+ AVPacket avpkt;
+ int16_t *samples = NULL;
+ uint8_t *inbuf = NULL;
+ int inbuf_size = 0;
+ int len = 0, frame_size_ptr = 0;
+ uint8_t *meta_buf = NULL;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ TRACE("before decoding audio. inbuf_size: %d\n", inbuf_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ inbuf_size = 0;
+ TRACE("decode_audio. no input buffer.\n");
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of AVCodecContext is NULL!\n", __func__, ctx_id);
+ write_codec_decode_audio_data(0, 0, 0, -1, 0, meta_buf);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ write_codec_decode_audio_data(0, 0, 0, -1, 0, meta_buf);
+ } else {
+ frame_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ samples = av_mallocz(frame_size_ptr);
+ if (!samples) {
+ ERR("failed to allocate an outbuf of audio.\n");
+ len = -1;
+ } else {
+ len =
+ avcodec_decode_audio3(avctx, samples, &frame_size_ptr, &avpkt);
+
+ TRACE("audio. len %d, channel_layout %lld, frame_size %d\n",
+ len, avctx->channel_layout, frame_size_ptr);
+ }
+
+ write_codec_decode_audio_data(avctx->sample_rate, avctx->channels,
+ avctx->channel_layout, len,
+ frame_size_ptr, meta_buf);
+ }
+
+ if (len < 0) {
+ ERR("failed to decode audio. ctx_id: %d, len: %d\n", ctx_id, len);
+ frame_size_ptr = 0;
+ } else {
+ if (frame_size_ptr > 0) {
+ tempbuf = g_malloc0(frame_size_ptr);
+ if (!tempbuf) {
+ ERR("failed to allocate decoded audio buffer. "
+ "ctx_id: %d, outbuf_size: %d\n", ctx_id, frame_size_ptr);
+ } else {
+ memcpy(tempbuf, samples, frame_size_ptr);
+ }
+ av_free(samples);
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, frame_size_ptr, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_encode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *pict = NULL;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int inbuf_size, outbuf_size, len = 0;
+ int ret;
+ int64_t in_timestamp;
+
+ uint8_t *meta_buf = NULL;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ memcpy(&in_timestamp, meta_buf + sizeof(inbuf_size), sizeof(in_timestamp));
+ TRACE("input buffer size: %d\n", inbuf_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ TRACE("encode_video. no input buffer.\n");
+ inbuf_size = 0;
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ avctx = s->context[ctx_id].avctx;
+ pict = s->context[ctx_id].frame;
+ if (!avctx || !pict) {
+ ERR("%d of context or frame is NULL\n", ctx_id);
+ len = -1;
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ len = -1;
+ } else {
+ TRACE("pixel format: %d inbuf: %p, picture data: %p\n",
+ avctx->pix_fmt, inbuf, pict->data[0]);
+
+ ret =
+ maru_brill_codec_get_picture_size((AVPicture *)pict, inbuf,
+ avctx->pix_fmt, avctx->width,
+ avctx->height, true);
+ if (ret < 0) {
+ ERR("after avpicture_fill, ret:%d\n", ret);
+ len = -1;
+ } else {
+ if (avctx->time_base.num == 0) {
+ pict->pts = AV_NOPTS_VALUE;
+ } else {
+ AVRational bq =
+ {1, (G_USEC_PER_SEC * G_GINT64_CONSTANT(1000))};
+ pict->pts = av_rescale_q(in_timestamp, bq, avctx->time_base);
+ }
+ TRACE("before encode video, ticks_per_frame:%d, pts:%lld\n",
+ avctx->ticks_per_frame, pict->pts);
+
+ outbuf_size =
+ (avctx->width * avctx->height * 6) + FF_MIN_BUFFER_SIZE;
+ outbuf = g_malloc0(outbuf_size);
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding video.\n");
+ len = -1;
+ } else {
+ len = avcodec_encode_video(avctx, outbuf, outbuf_size, pict);
+
+ TRACE("encode video! len:%d pts:%lld outbuf:%p outbuf size: %d\n",
+ len, pict->pts, outbuf, outbuf_size);
+ }
+ }
+ }
+
+ // write encoded video data
+ memcpy(meta_buf, &len, sizeof(len));
+ if (len < 0) {
+ ERR("failed to encode video. len: %d\n", len);
+ } else {
+ tempbuf = g_malloc0(len);
+ if (!tempbuf) {
+ ERR("failed to allocate an element of writequeue.\n");
+ } else {
+ memcpy(tempbuf, outbuf, len);
+ }
+ }
+
+ if (outbuf) {
+ TRACE("release encoded output buffer. %p\n", outbuf);
+ g_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, len, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+ return true;
+}
+
+static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int32_t inbuf_size, max_size;
+ int len = 0;
+ uint8_t *meta_buf = NULL;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ meta_buf = s->vaddr + ((ctx_id - 1) * CODEC_META_DATA_SIZE);
+ meta_buf += 8; // skipped header.
+
+ memcpy(&inbuf_size, meta_buf, sizeof(inbuf_size));
+ memcpy(&max_size, meta_buf + sizeof(inbuf_size), sizeof(max_size));
+ TRACE("encoding audio. in_size: %d, max_size: %d\n", inbuf_size, max_size);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ inbuf = elem->buf;
+ } else if (elem) {
+ TRACE("no input buffer to encode audio.\n");
+ inbuf_size = 0;
+ } else {
+ ERR("wrong input data\n");
+ return false;
+ }
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of Context is NULL!\n", __func__, ctx_id);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ } else {
+ outbuf = g_malloc0(max_size + FF_MIN_BUFFER_SIZE);
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding audio.\n");
+ len = -1;
+ } else {
+ len =
+ avcodec_encode_audio(avctx, outbuf, max_size, (short *)inbuf);
+ TRACE("after encoding audio. len: %d\n", len);
+ }
+ }
+
+ // write encoded audio data
+ memcpy(meta_buf, &len, sizeof(len));
+ if (len < 0) {
+ ERR("failed to encode audio. ctx_id: %d len: %d\n", ctx_id, len);
+ } else {
+ tempbuf = g_malloc0(len);
+ if (!tempbuf) {
+ ERR("encode_audio. failed to allocate temporary buffer.\n");
+ } else {
+ memcpy(tempbuf, outbuf, len);
+ }
+ }
+
+ if (outbuf) {
+ av_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, len, ctx_id);
+
+ TRACE("[%s] leave:\n", __func__);
+ return true;
+}
+
+static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx)
+{
+ AVCodecParserContext *parser = NULL;
+
+ if (!avctx) {
+ ERR("context is NULL\n");
+ return NULL;
+ }
+
+ switch (avctx->codec_id) {
+ case CODEC_ID_MPEG4:
+ case CODEC_ID_VC1:
+ TRACE("not using parser.\n");
+ break;
+ case CODEC_ID_H264:
+ if (avctx->extradata_size == 0) {
+ TRACE("H.264 with no extradata, creating parser.\n");
+ parser = av_parser_init (avctx->codec_id);
+ }
+ break;
+ default:
+ parser = av_parser_init (avctx->codec_id);
+ if (parser) {
+ INFO("using parser. %d\n", avctx->codec_id);
+ }
+ break;
+ }
+
+ return parser;
+}
+
+//
+static void maru_brill_codec_bh_callback(void *opaque)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ TRACE("enter: %s\n", __func__);
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ if (!QTAILQ_EMPTY(&codec_wq)) {
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("raise irq\n");
- qemu_irq_lower(s->dev.irq[0]);
++ pci_set_irq(&s->dev, 1);
+ s->irq_raised = 1;
+ } else {
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ TRACE("codec_wq is empty!!\n");
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+/*
+ * Codec Device APIs
+ */
+static uint64_t maru_brill_codec_read(void *opaque,
+ hwaddr addr,
+ unsigned size)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+ uint64_t ret = 0;
+
+ switch (addr) {
+ case CODEC_CMD_GET_THREAD_STATE:
+ qemu_mutex_lock(&s->context_queue_mutex);
+ if (s->irq_raised) {
+ ret = CODEC_TASK_END;
++ pci_set_irq(&s->dev, 0);
+ s->irq_raised = 0;
+ }
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("get thread_state. ret: %d\n", ret);
+ break;
+
+ case CODEC_CMD_GET_CTX_FROM_QUEUE:
+ {
+ DeviceMemEntry *head = NULL;
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ head = QTAILQ_FIRST(&codec_wq);
+ if (head) {
+ ret = head->ctx_id;
+ QTAILQ_REMOVE(&codec_wq, head, node);
+ entry[ret] = head;
+ TRACE("get a elem from codec_wq. 0x%x\n", head);
+ } else {
+ ret = 0;
+ }
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("get a head from a writequeue. head: %x\n", ret);
+ }
+ break;
+
+ case CODEC_CMD_GET_VERSION:
+ ret = CODEC_VERSION;
+ TRACE("codec version: %d\n", ret);
+ break;
+
+ case CODEC_CMD_GET_ELEMENT:
+ ret = maru_brill_codec_query_list(s);
+ break;
+
+ case CODEC_CMD_GET_CONTEXT_INDEX:
+ ret = maru_brill_codec_get_context_index(s);
+ TRACE("get context index: %d\n", ret);
+ break;
+
+ default:
+ ERR("no avaiable command for read. %d\n", addr);
+ }
+
+ return ret;
+}
+
+static void maru_brill_codec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ switch (addr) {
+ case CODEC_CMD_API_INDEX:
+ TRACE("set codec_cmd value: %d\n", value);
+ s->ioparam.api_index = value;
+ maru_brill_codec_wakeup_threads(s, value);
+ break;
+
+ case CODEC_CMD_CONTEXT_INDEX:
+ TRACE("set context_index value: %d\n", value);
+ s->ioparam.ctx_index = value;
+ break;
+
+ case CODEC_CMD_DEVICE_MEM_OFFSET:
+ TRACE("set mem_offset value: 0x%x\n", value);
+ s->ioparam.mem_offset = value;
+ break;
+
+ case CODEC_CMD_RELEASE_CONTEXT:
+ maru_brill_codec_release_context(s, (int32_t)value);
+ break;
+
+ case CODEC_CMD_GET_DATA_FROM_QUEUE:
+ maru_brill_codec_pop_writequeue(s, (uint32_t)value);
+ break;
+
+ default:
+ ERR("no available command for write. %d\n", addr);
+ }
+}
+
+static const MemoryRegionOps maru_brill_codec_mmio_ops = {
+ .read = maru_brill_codec_read,
+ .write = maru_brill_codec_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int maru_brill_codec_initfn(PCIDevice *dev)
+{
+ MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ INFO("device initialization.\n");
+ pci_config_set_interrupt_pin(pci_conf, 1);
+
+ memory_region_init_ram(&s->vram, OBJECT(s), "maru_brill_codec.vram", CODEC_MEM_SIZE);
+ s->vaddr = (uint8_t *)memory_region_get_ram_ptr(&s->vram);
+
+ memory_region_init_io(&s->mmio, OBJECT(s), &maru_brill_codec_mmio_ops, s,
+ "maru_brill_codec.mmio", CODEC_REG_SIZE);
+
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+// maru_brill_codec_reset(&s->dev.qdev);
+
+ qemu_mutex_init(&s->context_mutex);
+ qemu_mutex_init(&s->context_queue_mutex);
+ qemu_mutex_init(&s->ioparam_queue_mutex);
+
+ maru_brill_codec_get_cpu_cores(s);
+ maru_brill_codec_threads_create(s);
+
+ // register a function to qemu bottom-halves to switch context.
+ s->codec_bh = qemu_bh_new(maru_brill_codec_bh_callback, s);
+
+ return 0;
+}
+
+static void maru_brill_codec_exitfn(PCIDevice *dev)
+{
+ MaruBrillCodecState *s = DO_UPCAST(MaruBrillCodecState, dev, dev);
+ INFO("device exit\n");
+
+ qemu_mutex_destroy(&s->context_mutex);
+ qemu_mutex_destroy(&s->context_queue_mutex);
+ qemu_mutex_destroy(&s->ioparam_queue_mutex);
+
+ qemu_bh_delete(s->codec_bh);
+
+ memory_region_destroy(&s->vram);
+ memory_region_destroy(&s->mmio);
+}
+
+static void maru_brill_codec_reset(DeviceState *d)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)d;
+ INFO("device reset\n");
+
+ s->irq_raised = 0;
+
+ memset(&s->context, 0, sizeof(CodecContext) * CODEC_CONTEXT_MAX);
+ memset(&s->ioparam, 0, sizeof(CodecParam));
+
+ maru_brill_codec_pixfmt_info_init();
+}
+
+static void maru_brill_codec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = maru_brill_codec_initfn;
+ k->exit = maru_brill_codec_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TIZEN;
+ k->device_id = PCI_DEVICE_ID_VIRTUAL_BRILL_CODEC;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->reset = maru_brill_codec_reset;
+ dc->desc = "Virtual new codec device for Tizen emulator";
+}
+
+static TypeInfo codec_device_info = {
+ .name = CODEC_DEVICE_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MaruBrillCodecState),
+ .class_init = maru_brill_codec_class_init,
+};
+
+static void codec_register_types(void)
+{
+ type_register_static(&codec_device_info);
+}
+
+type_init(codec_register_types)
+
+int maru_brill_codec_pci_device_init(PCIBus *bus)
+{
+ INFO("device create.\n");
+ pci_create_simple(bus, -1, CODEC_DEVICE_NAME);
+ return 0;
+}
--- /dev/null
+/*
+ * Virtual Codec device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "hw/hw.h"
+#include "sysemu/kvm.h"
++#include "qemu/main-loop.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "qemu-common.h"
+#include "qemu/thread.h"
+
+#include "osutil.h"
+#include "tizen/src/debug_ch.h"
+#include "maru_device_ids.h"
+#include "libavformat/avformat.h"
+
+#define CODEC_CONTEXT_MAX 1024
+
+/*
+ * Codec Device Structures
+ */
+typedef struct CodecParam {
+ int32_t api_index;
+ int32_t ctx_index;
+ uint32_t mem_offset;
+} CodecParam;
+
+struct video_data {
+ int32_t width;
+ int32_t height;
+ int32_t fps_n;
+ int32_t fps_d;
+ int32_t par_n;
+ int32_t par_d;
+ int32_t pix_fmt;
+ int32_t bpp;
+ int32_t ticks_per_frame;
+};
+
+struct audio_data {
+ int32_t channels;
+ int32_t sample_rate;
+ int32_t block_align;
+ int32_t depth;
+ int32_t sample_fmt;
+ int32_t frame_size;
+ int32_t bits_per_smp_fmt;
+ int64_t channel_layout;
+};
+
+typedef struct CodecContext {
+ AVCodecContext *avctx;
+ AVFrame *frame;
+ AVCodecParserContext *parser_ctx;
+ uint8_t *parser_buf;
+ uint16_t parser_use;
+ bool occupied;
+ bool opened;
+} CodecContext;
+
+typedef struct CodecThreadPool {
+ QemuThread *threads;
+ QemuMutex mutex;
+ QemuCond cond;
+} CodecThreadPool;
+
+typedef struct MaruBrillCodecState {
+ PCIDevice dev;
+
+ uint8_t *vaddr;
+ MemoryRegion vram;
+ MemoryRegion mmio;
+
+ QEMUBH *codec_bh;
+ QemuMutex context_mutex;
+ QemuMutex context_queue_mutex;
+ QemuMutex ioparam_queue_mutex;
+
+ CodecThreadPool threadpool;
+ bool is_thread_running;
+ uint32_t worker_thread_cnt;
+ uint32_t idle_thread_cnt;
+
+ int irq_raised;
+
+ CodecContext context[CODEC_CONTEXT_MAX];
+ CodecParam ioparam;
+} MaruBrillCodecState;
+
+enum codec_io_cmd {
+ CODEC_CMD_API_INDEX = 0x28,
+ CODEC_CMD_CONTEXT_INDEX = 0x2C,
+ CODEC_CMD_DEVICE_MEM_OFFSET = 0x34,
+ CODEC_CMD_GET_THREAD_STATE = 0x38,
+ CODEC_CMD_GET_CTX_FROM_QUEUE = 0x3C,
+ CODEC_CMD_GET_DATA_FROM_QUEUE = 0x40,
+ CODEC_CMD_RELEASE_CONTEXT = 0x44,
+ CODEC_CMD_GET_VERSION = 0x50,
+ CODEC_CMD_GET_ELEMENT = 0x54,
+ CODEC_CMD_GET_CONTEXT_INDEX = 0x58,
+};
+
+enum codec_api_type {
+ CODEC_INIT = 0,
+ CODEC_DECODE_VIDEO,
+ CODEC_ENCODE_VIDEO,
+ CODEC_DECODE_AUDIO,
+ CODEC_ENCODE_AUDIO,
+ CODEC_PICTURE_COPY,
+ CODEC_DEINIT,
+ CODEC_FLUSH_BUFFERS,
+ };
+
+enum codec_type {
+ CODEC_TYPE_UNKNOWN = -1,
+ CODEC_TYPE_DECODE,
+ CODEC_TYPE_ENCODE,
+};
+
+enum thread_state {
+ CODEC_TASK_START = 0,
+ CODEC_TASK_END = 0x1f,
+};
+
+/*
+ * Codec Device Functions
+ */
+int maru_brill_codec_pci_device_init(PCIBus *bus);
--- /dev/null
- qemu_irq_lower(state->dev.irq[2]);
+/*
+ * Common implementation of MARU Virtual Camera device by PCI bus.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "qemu-common.h"
++#include "qemu/main-loop.h"
+#include "exec/cpu-common.h"
+
+#include "maru_camera_common.h"
+#include "maru_device_ids.h"
+#include "tizen/src/debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, camera_pci);
+
+#define MARU_PCI_CAMERA_DEVICE_NAME "maru_camera_pci"
+
+#define MARUCAM_MEM_SIZE (4 * 1024 * 1024) /* 4MB */
+#define MARUCAM_REG_SIZE (256) /* 64 * 4Byte */
+
+/*
+ * I/O functions
+ */
+static inline uint32_t
+marucam_mmio_read(void *opaque, hwaddr offset)
+{
+ uint32_t ret = 0;
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ switch (offset & 0xFF) {
+ case MARUCAM_CMD_ISR:
+ qemu_mutex_lock(&state->thread_mutex);
+ ret = state->isr;
+ if (ret != 0) {
- qemu_irq_raise(state->dev.irq[2]);
++ pci_set_irq(&state->dev, 0);
+ state->isr = 0;
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+ break;
+ case MARUCAM_CMD_G_DATA:
+ ret = state->param->stack[state->param->top++];
+ break;
+ case MARUCAM_CMD_OPEN:
+ case MARUCAM_CMD_CLOSE:
+ case MARUCAM_CMD_START_PREVIEW:
+ case MARUCAM_CMD_STOP_PREVIEW:
+ case MARUCAM_CMD_S_PARAM:
+ case MARUCAM_CMD_G_PARAM:
+ case MARUCAM_CMD_ENUM_FMT:
+ case MARUCAM_CMD_TRY_FMT:
+ case MARUCAM_CMD_S_FMT:
+ case MARUCAM_CMD_G_FMT:
+ case MARUCAM_CMD_QCTRL:
+ case MARUCAM_CMD_S_CTRL:
+ case MARUCAM_CMD_G_CTRL:
+ case MARUCAM_CMD_ENUM_FSIZES:
+ case MARUCAM_CMD_ENUM_FINTV:
+ ret = state->param->errCode;
+ state->param->errCode = 0;
+ break;
+ default:
+ ERR("Not supported command: 0x%x\n", offset);
+ ret = EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static inline void
+marucam_mmio_write(void *opaque, hwaddr offset, uint32_t value)
+{
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ switch (offset & 0xFF) {
+ case MARUCAM_CMD_OPEN:
+ marucam_device_open(state);
+ break;
+ case MARUCAM_CMD_CLOSE:
+ marucam_device_close(state);
+ break;
+ case MARUCAM_CMD_START_PREVIEW:
+ marucam_device_start_preview(state);
+ break;
+ case MARUCAM_CMD_STOP_PREVIEW:
+ marucam_device_stop_preview(state);
+ memset(state->vaddr, 0, MARUCAM_MEM_SIZE);
+ break;
+ case MARUCAM_CMD_S_PARAM:
+ marucam_device_s_param(state);
+ break;
+ case MARUCAM_CMD_G_PARAM:
+ marucam_device_g_param(state);
+ break;
+ case MARUCAM_CMD_ENUM_FMT:
+ marucam_device_enum_fmt(state);
+ break;
+ case MARUCAM_CMD_TRY_FMT:
+ marucam_device_try_fmt(state);
+ break;
+ case MARUCAM_CMD_S_FMT:
+ marucam_device_s_fmt(state);
+ break;
+ case MARUCAM_CMD_G_FMT:
+ marucam_device_g_fmt(state);
+ break;
+ case MARUCAM_CMD_QCTRL:
+ marucam_device_qctrl(state);
+ break;
+ case MARUCAM_CMD_S_CTRL:
+ marucam_device_s_ctrl(state);
+ break;
+ case MARUCAM_CMD_G_CTRL:
+ marucam_device_g_ctrl(state);
+ break;
+ case MARUCAM_CMD_ENUM_FSIZES:
+ marucam_device_enum_fsizes(state);
+ break;
+ case MARUCAM_CMD_ENUM_FINTV:
+ marucam_device_enum_fintv(state);
+ break;
+ case MARUCAM_CMD_S_DATA:
+ state->param->stack[state->param->top++] = value;
+ break;
+ case MARUCAM_CMD_DATACLR:
+ memset(state->param, 0, sizeof(MaruCamParam));
+ break;
+ case MARUCAM_CMD_REQFRAME:
+ qemu_mutex_lock(&state->thread_mutex);
+ state->req_frame = value + 1;
+ qemu_mutex_unlock(&state->thread_mutex);
+ break;
+ default:
+ ERR("Not supported command: 0x%x\n", offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps maru_camera_mmio_ops = {
+ .old_mmio = {
+ .read = {
+ marucam_mmio_read,
+ marucam_mmio_read,
+ marucam_mmio_read,
+ },
+ .write = {
+ marucam_mmio_write,
+ marucam_mmio_write,
+ marucam_mmio_write,
+ },
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/*
+ * QEMU bottom half funtion
+ */
+static void marucam_tx_bh(void *opaque)
+{
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ qemu_mutex_lock(&state->thread_mutex);
+ if (state->isr) {
++ pci_set_irq(&state->dev, 1);
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+}
+
+/*
+ * Initialization function
+ */
+static int marucam_initfn(PCIDevice *dev)
+{
+ MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ pci_config_set_interrupt_pin(pci_conf, 0x03);
+
+ memory_region_init_ram(&s->vram, OBJECT(s), "marucamera.ram", MARUCAM_MEM_SIZE);
+ s->vaddr = memory_region_get_ram_ptr(&s->vram);
+ memset(s->vaddr, 0, MARUCAM_MEM_SIZE);
+
+ memory_region_init_io(&s->mmio, OBJECT(s),
+ &maru_camera_mmio_ops,
+ s,
+ "maru-camera-mmio",
+ MARUCAM_REG_SIZE);
+
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+ /* for worker thread */
+ s->param = (MaruCamParam *)g_malloc0(sizeof(MaruCamParam));
+ qemu_cond_init(&s->thread_cond);
+ qemu_mutex_init(&s->thread_mutex);
+
+ marucam_device_init(s);
+
+ s->tx_bh = qemu_bh_new(marucam_tx_bh, s);
+ INFO("[%s] camera device was initialized.\n", __func__);
+
+ return 0;
+}
+
+/*
+ * Termination function
+ */
+static void marucam_exitfn(PCIDevice *pci_dev)
+{
+ MaruCamState *s =
+ OBJECT_CHECK(MaruCamState, pci_dev, MARU_PCI_CAMERA_DEVICE_NAME);
+
+ marucam_device_exit(s);
+ g_free(s->param);
+ qemu_cond_destroy(&s->thread_cond);
+ qemu_mutex_destroy(&s->thread_mutex);
+
+ memory_region_destroy(&s->vram);
+ memory_region_destroy(&s->mmio);
+
+
+ INFO("[%s] camera device was released.\n", __func__);
+}
+
+int maru_camera_pci_init(PCIBus *bus)
+{
+ INFO("[%s] camera device was initialized.\n", __func__);
+ pci_create_simple(bus, -1, MARU_PCI_CAMERA_DEVICE_NAME);
+ return 0;
+}
+
+static void maru_camera_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = marucam_initfn;
+ k->exit = marucam_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TIZEN;
+ k->device_id = PCI_DEVICE_ID_VIRTUAL_CAMERA;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->desc = "MARU Virtual Camera device for Tizen emulator";
+}
+
+static TypeInfo maru_camera_info = {
+ .name = MARU_PCI_CAMERA_DEVICE_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MaruCamState),
+ .class_init = maru_camera_pci_class_init,
+};
+
+static void maru_camera_pci_register_types(void)
+{
+ type_register_static(&maru_camera_info);
+}
+
+type_init(maru_camera_pci_register_types)
--- /dev/null
- cur_tick = qemu_get_clock_ns(vm_clock);
+/*
+ * Maru vga device
+ * Based on qemu/hw/vga.c
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "hw/hw.h"
+#include "display/vga.h"
+#include "ui/console.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "display/vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+#include "hw/xen/xen.h"
+#include "trace.h"
+
+#include <pthread.h>
+
+#define MARU_VGA
+#include "maru_common.h"
+#include "maru_vga_int.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, maru_vga);
+
+//#define DEBUG_VGA
+//#define DEBUG_VGA_MEM
+//#define DEBUG_VGA_REG
+
+//#define DEBUG_BOCHS_VBE
+
+/* 16 state changes per vertical frame @60 Hz */
+#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) (x)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define BIG 1
+#else
+#define BIG 0
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
+#else
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+#endif
+
+static const uint32_t mask16[16] = {
+ PAT(0x00000000),
+ PAT(0x000000ff),
+ PAT(0x0000ff00),
+ PAT(0x0000ffff),
+ PAT(0x00ff0000),
+ PAT(0x00ff00ff),
+ PAT(0x00ffff00),
+ PAT(0x00ffffff),
+ PAT(0xff000000),
+ PAT(0xff0000ff),
+ PAT(0xff00ff00),
+ PAT(0xff00ffff),
+ PAT(0xffff0000),
+ PAT(0xffff00ff),
+ PAT(0xffffff00),
+ PAT(0xffffffff),
+};
+
+#undef PAT
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) (x)
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+ PAT(0x00000000),
+ PAT(0x000000ff),
+ PAT(0x0000ff00),
+ PAT(0x0000ffff),
+ PAT(0x00ff0000),
+ PAT(0x00ff00ff),
+ PAT(0x00ffff00),
+ PAT(0x00ffffff),
+ PAT(0xff000000),
+ PAT(0xff0000ff),
+ PAT(0xff00ff00),
+ PAT(0xff00ffff),
+ PAT(0xffff0000),
+ PAT(0xffff00ff),
+ PAT(0xffffff00),
+ PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+ PAT(0x00000000),
+ PAT(0x0000ffff),
+ PAT(0xffff0000),
+ PAT(0xffffffff),
+};
+
+static uint32_t expand4[256];
+static uint16_t expand2[256];
+static uint8_t expand4to8[16];
+
+static void vga_dumb_update_retrace_info(VGACommonState *s)
+{
+ (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGACommonState *s)
+{
+ int htotal_chars;
+ int hretr_start_char;
+ int hretr_skew_chars;
+ int hretr_end_char;
+
+ int vtotal_lines;
+ int vretr_start_line;
+ int vretr_end_line;
+
+ int dots;
+#if 0
+ int div2, sldiv2;
+#endif
+ int clocking_mode;
+ int clock_sel;
+ const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+ int64_t chars_per_sec;
+ struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+ htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
+ hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
+ hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
+ hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
+
+ vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
+ (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
+ vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
+ ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
+ vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
+
+ clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
+ clock_sel = (s->msr >> 2) & 3;
+ dots = (s->msr & 1) ? 8 : 9;
+
+ chars_per_sec = clk_hz[clock_sel] / dots;
+
+ htotal_chars <<= clocking_mode;
+
+ r->total_chars = vtotal_lines * htotal_chars;
+ if (r->freq) {
+ r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+ } else {
+ r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+ }
+
+ r->vstart = vretr_start_line;
+ r->vend = r->vstart + vretr_end_line + 1;
+
+ r->hstart = hretr_start_char + hretr_skew_chars;
+ r->hend = r->hstart + hretr_end_char + 1;
+ r->htotal = htotal_chars;
+
+#if 0
+ div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
+ sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
+ printf (
+ "hz=%f\n"
+ "htotal = %d\n"
+ "hretr_start = %d\n"
+ "hretr_skew = %d\n"
+ "hretr_end = %d\n"
+ "vtotal = %d\n"
+ "vretr_start = %d\n"
+ "vretr_end = %d\n"
+ "div2 = %d sldiv2 = %d\n"
+ "clocking_mode = %d\n"
+ "clock_sel = %d %d\n"
+ "dots = %d\n"
+ "ticks/char = %" PRId64 "\n"
+ "\n",
+ (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
+ htotal_chars,
+ hretr_start_char,
+ hretr_skew_chars,
+ hretr_end_char,
+ vtotal_lines,
+ vretr_start_line,
+ vretr_end_line,
+ div2, sldiv2,
+ clocking_mode,
+ clock_sel,
+ clk_hz[clock_sel],
+ dots,
+ r->ticks_per_char
+ );
+#endif
+}
+
+static uint8_t vga_precise_retrace(VGACommonState *s)
+{
+ struct vga_precise_retrace *r = &s->retrace_info.precise;
+ uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
+
+ if (r->total_chars) {
+ int cur_line, cur_line_char, cur_char;
+ int64_t cur_tick;
+
- int64_t now = qemu_get_clock_ms(vm_clock);
++ cur_tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
+ cur_line = cur_char / r->htotal;
+
+ if (cur_line >= r->vstart && cur_line <= r->vend) {
+ val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
+ } else {
+ cur_line_char = cur_char % r->htotal;
+ if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
+ val |= ST01_DISP_ENABLE;
+ }
+ }
+
+ return val;
+ } else {
+ return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+ }
+}
+
+static uint8_t vga_dumb_retrace(VGACommonState *s)
+{
+ return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+}
+
+typedef void maru_vga_draw_glyph8_func(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol);
+typedef void maru_vga_draw_glyph9_func(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol, int dup9);
+typedef void maru_vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width);
+
+#define DEPTH 8
+#include "maru_vga_template.h"
+
+#define DEPTH 15
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "maru_vga_template.h"
+
+#define DEPTH 16
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "maru_vga_template.h"
+
+#define DEPTH 32
+#include "maru_vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "maru_vga_template.h"
+
+static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel8(r, g, b);
+ col |= col << 8;
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel15(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel15bgr(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel16(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel16bgr(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32(r, g, b);
+ return col;
+}
+
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32bgr(r, g, b);
+ return col;
+}
+
+/* return true if the palette was modified */
+static int update_palette16(VGACommonState *s)
+{
+ int full_update, i;
+ uint32_t v, col, *palette;
+
+ full_update = 0;
+ palette = s->last_palette;
+ for(i = 0; i < 16; i++) {
+ v = s->ar[i];
+ if (s->ar[VGA_ATC_MODE] & 0x80) {
+ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
+ } else {
+ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
+ }
+ v = v * 3;
+ col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+ c6_to_8(s->palette[v + 1]),
+ c6_to_8(s->palette[v + 2]));
+ if (col != palette[i]) {
+ full_update = 1;
+ palette[i] = col;
+ }
+ }
+ return full_update;
+}
+
+/* return true if the palette was modified */
+static int update_palette256(VGACommonState *s)
+{
+ int full_update, i;
+ uint32_t v, col, *palette;
+
+ full_update = 0;
+ palette = s->last_palette;
+ v = 0;
+ for(i = 0; i < 256; i++) {
+ if (s->dac_8bit) {
+ col = s->rgb_to_pixel(s->palette[v],
+ s->palette[v + 1],
+ s->palette[v + 2]);
+ } else {
+ col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+ c6_to_8(s->palette[v + 1]),
+ c6_to_8(s->palette[v + 2]));
+ }
+ if (col != palette[i]) {
+ full_update = 1;
+ palette[i] = col;
+ }
+ v += 3;
+ }
+ return full_update;
+}
+
+static void vga_get_offsets(VGACommonState *s,
+ uint32_t *pline_offset,
+ uint32_t *pstart_addr,
+ uint32_t *pline_compare)
+{
+ uint32_t start_addr, line_offset, line_compare;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ line_offset = s->vbe_line_offset;
+ start_addr = s->vbe_start_addr;
+ line_compare = 65535;
+ } else {
+ /* compute line_offset in bytes */
+ line_offset = s->cr[VGA_CRTC_OFFSET];
+ line_offset <<= 3;
+
+ /* starting address */
+ start_addr = s->cr[VGA_CRTC_START_LO] |
+ (s->cr[VGA_CRTC_START_HI] << 8);
+
+ /* line compare */
+ line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
+ ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
+ }
+ *pline_offset = line_offset;
+ *pstart_addr = start_addr;
+ *pline_compare = line_compare;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(VGACommonState *s)
+{
+ int full_update;
+ uint32_t start_addr, line_offset, line_compare;
+
+ full_update = 0;
+
+ s->get_offsets(s, &line_offset, &start_addr, &line_compare);
+
+ if (line_offset != s->line_offset ||
+ start_addr != s->start_addr ||
+ line_compare != s->line_compare) {
+ s->line_offset = line_offset;
+ s->start_addr = start_addr;
+ s->line_compare = line_compare;
+ full_update = 1;
+ }
+ return full_update;
+}
+
+#define NB_DEPTHS 7
+
+static inline int get_depth_index(DisplaySurface *s)
+{
+ switch (surface_bits_per_pixel(s)) {
+ default:
+ case 8:
+ return 0;
+ case 15:
+ return 1;
+ case 16:
+ return 2;
+ case 32:
+ if (is_surface_bgr(s)) {
+ return 4;
+ } else {
+ return 3;
+ }
+ }
+}
+
+static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph8_table[NB_DEPTHS] = {
+ maru_vga_draw_glyph8_8,
+ maru_vga_draw_glyph8_16,
+ maru_vga_draw_glyph8_16,
+ maru_vga_draw_glyph8_32,
+ maru_vga_draw_glyph8_32,
+ maru_vga_draw_glyph8_16,
+ maru_vga_draw_glyph8_16,
+};
+
+static maru_vga_draw_glyph8_func * const maru_vga_draw_glyph16_table[NB_DEPTHS] = {
+ maru_vga_draw_glyph16_8,
+ maru_vga_draw_glyph16_16,
+ maru_vga_draw_glyph16_16,
+ maru_vga_draw_glyph16_32,
+ maru_vga_draw_glyph16_32,
+ maru_vga_draw_glyph16_16,
+ maru_vga_draw_glyph16_16,
+};
+
+static maru_vga_draw_glyph9_func * const maru_vga_draw_glyph9_table[NB_DEPTHS] = {
+ maru_vga_draw_glyph9_8,
+ maru_vga_draw_glyph9_16,
+ maru_vga_draw_glyph9_16,
+ maru_vga_draw_glyph9_32,
+ maru_vga_draw_glyph9_32,
+ maru_vga_draw_glyph9_16,
+ maru_vga_draw_glyph9_16,
+};
+
+static const uint8_t cursor_glyph[32 * 4] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
+ int *pcwidth, int *pcheight)
+{
+ int width, cwidth, height, cheight;
+
+ /* total width & height */
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+ cwidth = 8;
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ cwidth = 9;
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ cwidth = 16; /* NOTE: no 18 pixel wide */
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
+ /* ugly hack for CGA 160x100x16 - explain me the logic */
+ height = 100;
+ } else {
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+ height = (height + 1) / cheight;
+ }
+
+ *pwidth = width;
+ *pheight = height;
+ *pcwidth = cwidth;
+ *pcheight = cheight;
+}
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
+ rgb_to_pixel8_dup,
+ rgb_to_pixel15_dup,
+ rgb_to_pixel16_dup,
+ rgb_to_pixel32_dup,
+ rgb_to_pixel32bgr_dup,
+ rgb_to_pixel15bgr_dup,
+ rgb_to_pixel16bgr_dup,
+};
+
+/*
+ * Text mode update
+ * Missing:
+ * - double scan
+ * - double width
+ * - underline
+ * - flashing
+ */
+static void vga_draw_text(VGACommonState *s, int full_update)
+{
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
+ int cx_min, cx_max, linesize, x_incr, line, line1;
+ uint32_t offset, fgcol, bgcol, v, cursor_offset;
+ uint8_t *d1, *d, *src, *dest, *cursor_ptr;
+ const uint8_t *font_ptr, *font_base[2];
+ int dup9, line_offset, depth_index;
+ uint32_t *palette;
+ uint32_t *ch_attr_ptr;
+ maru_vga_draw_glyph8_func *maru_vga_draw_glyph8;
+ maru_vga_draw_glyph9_func *maru_vga_draw_glyph9;
- s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
++ int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+
+ /* compute font data address (in plane 2) */
+ v = s->sr[VGA_SEQ_CHARACTER_MAP];
+ offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
+ if (offset != s->font_offsets[0]) {
+ s->font_offsets[0] = offset;
+ full_update = 1;
+ }
+ font_base[0] = s->vram_ptr + offset;
+
+ offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+ font_base[1] = s->vram_ptr + offset;
+ if (offset != s->font_offsets[1]) {
+ s->font_offsets[1] = offset;
+ full_update = 1;
+ }
+ if (s->plane_updated & (1 << 2) || s->chain4_alias) {
+ /* if the plane 2 was modified since the last display, it
+ indicates the font may have been modified */
+ s->plane_updated = 0;
+ full_update = 1;
+ }
+ full_update |= update_basic_params(s);
+
+ line_offset = s->line_offset;
+
+ vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+ if ((height * width) <= 1) {
+ /* better than nothing: exit if transient size is too small */
+ return;
+ }
+ if ((height * width) > CH_ATTR_SIZE) {
+ /* better than nothing: exit if transient size is too big */
+ return;
+ }
+
+ if (width != s->last_width || height != s->last_height ||
+ cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
+ s->last_scr_width = width * cw;
+ s->last_scr_height = height * cheight;
+ qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+ surface = qemu_console_surface(s->con);
+ dpy_text_resize(s->con, width, height);
+ s->last_depth = 0;
+ s->last_width = width;
+ s->last_height = height;
+ s->last_ch = cheight;
+ s->last_cw = cw;
+ full_update = 1;
+ }
+ s->rgb_to_pixel =
+ rgb_to_pixel_dup_table[get_depth_index(surface)];
+ full_update |= update_palette16(s);
+ palette = s->last_palette;
+ x_incr = cw * surface_bytes_per_pixel(surface);
+
+ if (full_update) {
+ s->full_update_text = 1;
+ }
+ if (s->full_update_gfx) {
+ s->full_update_gfx = 0;
+ full_update |= 1;
+ }
+
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+ if (cursor_offset != s->cursor_offset ||
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
+ /* if the cursor position changed, we update the old and new
+ chars */
+ if (s->cursor_offset < CH_ATTR_SIZE)
+ s->last_ch_attr[s->cursor_offset] = -1;
+ if (cursor_offset < CH_ATTR_SIZE)
+ s->last_ch_attr[cursor_offset] = -1;
+ s->cursor_offset = cursor_offset;
+ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
+ }
+ cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
+ if (now >= s->cursor_blink_time) {
+ s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
+ s->cursor_visible_phase = !s->cursor_visible_phase;
+ }
+
+ depth_index = get_depth_index(surface);
+ if (cw == 16)
+ maru_vga_draw_glyph8 = maru_vga_draw_glyph16_table[depth_index];
+ else
+ maru_vga_draw_glyph8 = maru_vga_draw_glyph8_table[depth_index];
+ maru_vga_draw_glyph9 = maru_vga_draw_glyph9_table[depth_index];
+
+ dest = surface_data(surface);
+ linesize = surface_stride(surface);
+ ch_attr_ptr = s->last_ch_attr;
+ line = 0;
+ offset = s->start_addr * 4;
+ for(cy = 0; cy < height; cy++) {
+ d1 = dest;
+ src = s->vram_ptr + offset;
+ cx_min = width;
+ cx_max = -1;
+ for(cx = 0; cx < width; cx++) {
+ ch_attr = *(uint16_t *)src;
+ if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
+ if (cx < cx_min)
+ cx_min = cx;
+ if (cx > cx_max)
+ cx_max = cx;
+ *ch_attr_ptr = ch_attr;
+#ifdef HOST_WORDS_BIGENDIAN
+ ch = ch_attr >> 8;
+ cattr = ch_attr & 0xff;
+#else
+ ch = ch_attr & 0xff;
+ cattr = ch_attr >> 8;
+#endif
+ font_ptr = font_base[(cattr >> 3) & 1];
+ font_ptr += 32 * 4 * ch;
+ bgcol = palette[cattr >> 4];
+ fgcol = palette[cattr & 0x0f];
+ if (cw != 9) {
+ maru_vga_draw_glyph8(d1, linesize,
+ font_ptr, cheight, fgcol, bgcol);
+ } else {
+ dup9 = 0;
+ if (ch >= 0xb0 && ch <= 0xdf &&
+ (s->ar[VGA_ATC_MODE] & 0x04)) {
+ dup9 = 1;
+ }
+ maru_vga_draw_glyph9(d1, linesize,
+ font_ptr, cheight, fgcol, bgcol, dup9);
+ }
+ if (src == cursor_ptr &&
+ !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
+ s->cursor_visible_phase) {
+ int line_start, line_last, h;
+ /* draw the cursor */
+ line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
+ line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
+ /* XXX: check that */
+ if (line_last > cheight - 1)
+ line_last = cheight - 1;
+ if (line_last >= line_start && line_start < cheight) {
+ h = line_last - line_start + 1;
+ d = d1 + linesize * line_start;
+ if (cw != 9) {
+ maru_vga_draw_glyph8(d, linesize,
+ cursor_glyph, h, fgcol, bgcol);
+ } else {
+ maru_vga_draw_glyph9(d, linesize,
+ cursor_glyph, h, fgcol, bgcol, 1);
+ }
+ }
+ }
+ }
+ d1 += x_incr;
+ src += 4;
+ ch_attr_ptr++;
+ }
+ if (cx_max != -1) {
+ dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
+ (cx_max - cx_min + 1) * cw, cheight);
+ }
+ dest += linesize * cheight;
+ line1 = line + cheight;
+ offset += line_offset;
+ if (line < s->line_compare && line1 >= s->line_compare) {
+ offset = 0;
+ }
+ line = line1;
+ }
+}
+
+enum {
+ maru_vga_draw_line2,
+ maru_vga_draw_line2D2,
+ maru_vga_draw_line4,
+ maru_vga_draw_line4D2,
+ maru_vga_draw_line8D2,
+ maru_vga_draw_line8,
+ maru_vga_draw_line15,
+ maru_vga_draw_line16,
+ maru_vga_draw_line24,
+ maru_vga_draw_line32,
+ maru_vga_draw_line_NB,
+};
+
+static maru_vga_draw_line_func * const maru_vga_draw_line_table[NB_DEPTHS * maru_vga_draw_line_NB] = {
+ maru_vga_draw_line2_8,
+ maru_vga_draw_line2_16,
+ maru_vga_draw_line2_16,
+ maru_vga_draw_line2_32,
+ maru_vga_draw_line2_32,
+ maru_vga_draw_line2_16,
+ maru_vga_draw_line2_16,
+
+ maru_vga_draw_line2d2_8,
+ maru_vga_draw_line2d2_16,
+ maru_vga_draw_line2d2_16,
+ maru_vga_draw_line2d2_32,
+ maru_vga_draw_line2d2_32,
+ maru_vga_draw_line2d2_16,
+ maru_vga_draw_line2d2_16,
+
+ maru_vga_draw_line4_8,
+ maru_vga_draw_line4_16,
+ maru_vga_draw_line4_16,
+ maru_vga_draw_line4_32,
+ maru_vga_draw_line4_32,
+ maru_vga_draw_line4_16,
+ maru_vga_draw_line4_16,
+
+ maru_vga_draw_line4d2_8,
+ maru_vga_draw_line4d2_16,
+ maru_vga_draw_line4d2_16,
+ maru_vga_draw_line4d2_32,
+ maru_vga_draw_line4d2_32,
+ maru_vga_draw_line4d2_16,
+ maru_vga_draw_line4d2_16,
+
+ maru_vga_draw_line8d2_8,
+ maru_vga_draw_line8d2_16,
+ maru_vga_draw_line8d2_16,
+ maru_vga_draw_line8d2_32,
+ maru_vga_draw_line8d2_32,
+ maru_vga_draw_line8d2_16,
+ maru_vga_draw_line8d2_16,
+
+ maru_vga_draw_line8_8,
+ maru_vga_draw_line8_16,
+ maru_vga_draw_line8_16,
+ maru_vga_draw_line8_32,
+ maru_vga_draw_line8_32,
+ maru_vga_draw_line8_16,
+ maru_vga_draw_line8_16,
+
+ maru_vga_draw_line15_8,
+ maru_vga_draw_line15_15,
+ maru_vga_draw_line15_16,
+ maru_vga_draw_line15_32,
+ maru_vga_draw_line15_32bgr,
+ maru_vga_draw_line15_15bgr,
+ maru_vga_draw_line15_16bgr,
+
+ maru_vga_draw_line16_8,
+ maru_vga_draw_line16_15,
+ maru_vga_draw_line16_16,
+ maru_vga_draw_line16_32,
+ maru_vga_draw_line16_32bgr,
+ maru_vga_draw_line16_15bgr,
+ maru_vga_draw_line16_16bgr,
+
+ maru_vga_draw_line24_8,
+ maru_vga_draw_line24_15,
+ maru_vga_draw_line24_16,
+ maru_vga_draw_line24_32,
+ maru_vga_draw_line24_32bgr,
+ maru_vga_draw_line24_15bgr,
+ maru_vga_draw_line24_16bgr,
+
+ maru_vga_draw_line32_8,
+ maru_vga_draw_line32_15,
+ maru_vga_draw_line32_16,
+ maru_vga_draw_line32_32,
+ maru_vga_draw_line32_32bgr,
+ maru_vga_draw_line32_15bgr,
+ maru_vga_draw_line32_16bgr,
+};
+
+static int vga_get_bpp(VGACommonState *s)
+{
+ int ret;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+ int width, height;
+
+ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
+ height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
+ } else {
+ width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+ height = (height + 1);
+ }
+ *pwidth = width;
+ *pheight = height;
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGACommonState *s, int full_update)
+{
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int y1, y, update, linesize, y_start, double_scan, mask, depth;
+ int width, height, shift_control, line_offset, bwidth, bits;
+ ram_addr_t page0, page1, page_min, page_max;
+ int disp_width, multi_scan, multi_run;
+ uint8_t *d;
+ uint32_t v, addr1, addr;
+ maru_vga_draw_line_func *maru_vga_draw_line;
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ static const bool byteswap = false;
+#else
+ static const bool byteswap = true;
+#endif
+
+ full_update |= update_basic_params(s);
+
+ if (!full_update)
+ vga_sync_dirty_bitmap(s);
+
+ s->get_resolution(s, &width, &height);
+ disp_width = width;
+
+ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
+ double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
+ if (shift_control != 1) {
+ multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+ - 1;
+ } else {
+ /* in CGA modes, multi_scan is ignored */
+ /* XXX: is it correct ? */
+ multi_scan = double_scan;
+ }
+ multi_run = multi_scan;
+ if (shift_control != s->shift_control ||
+ double_scan != s->double_scan) {
+ full_update = 1;
+ s->shift_control = shift_control;
+ s->double_scan = double_scan;
+ }
+
+ if (shift_control == 0) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ disp_width <<= 1;
+ }
+ } else if (shift_control == 1) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ disp_width <<= 1;
+ }
+ }
+
+ depth = s->get_bpp(s);
+ if (s->line_offset != s->last_line_offset ||
+ disp_width != s->last_width ||
+ height != s->last_height ||
+ s->last_depth != depth) {
+ if (depth == 32 || (depth == 16 && !byteswap)) {
+#ifdef MARU_VGA /* create new sufrace by g_new0 in MARU VGA */
+ TRACE("create the display surface\n");
+ surface = qemu_create_displaysurface(disp_width, height);
+#else /* MARU_VGA */
+ surface = qemu_create_displaysurface_from(disp_width,
+ height, depth, s->line_offset,
+ s->vram_ptr + (s->start_addr * 4), byteswap);
+#endif /* MARU_VGA */
+ dpy_gfx_replace_surface(s->con, surface);
+ } else {
+ qemu_console_resize(s->con, disp_width, height);
+ surface = qemu_console_surface(s->con);
+ }
+ s->last_scr_width = disp_width;
+ s->last_scr_height = height;
+ s->last_width = disp_width;
+ s->last_height = height;
+ s->last_line_offset = s->line_offset;
+ s->last_depth = depth;
+ full_update = 1;
+ } else if (is_buffer_shared(surface) &&
+ (full_update || surface_data(surface) != s->vram_ptr
+ + (s->start_addr * 4))) {
+ DisplaySurface *surface;
+ surface = qemu_create_displaysurface_from(disp_width,
+ height, depth, s->line_offset,
+ s->vram_ptr + (s->start_addr * 4), byteswap);
+ dpy_gfx_replace_surface(s->con, surface);
+ }
+
+ s->rgb_to_pixel =
+ rgb_to_pixel_dup_table[get_depth_index(surface)];
+
+ if (shift_control == 0) {
+ full_update |= update_palette16(s);
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ v = maru_vga_draw_line4D2;
+ } else {
+ v = maru_vga_draw_line4;
+ }
+ bits = 4;
+ } else if (shift_control == 1) {
+ full_update |= update_palette16(s);
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ v = maru_vga_draw_line2D2;
+ } else {
+ v = maru_vga_draw_line2;
+ }
+ bits = 4;
+ } else {
+ switch(s->get_bpp(s)) {
+ default:
+ case 0:
+ full_update |= update_palette256(s);
+ v = maru_vga_draw_line8D2;
+ bits = 4;
+ break;
+ case 8:
+ full_update |= update_palette256(s);
+ v = maru_vga_draw_line8;
+ bits = 8;
+ break;
+ case 15:
+ v = maru_vga_draw_line15;
+ bits = 16;
+ break;
+ case 16:
+ v = maru_vga_draw_line16;
+ bits = 16;
+ break;
+ case 24:
+ v = maru_vga_draw_line24;
+ bits = 24;
+ break;
+ case 32:
+ v = maru_vga_draw_line32;
+ bits = 32;
+ break;
+ }
+ }
+ maru_vga_draw_line = maru_vga_draw_line_table[v * NB_DEPTHS +
+ get_depth_index(surface)];
+
+ if (!is_buffer_shared(surface) && s->cursor_invalidate) {
+ s->cursor_invalidate(s);
+ }
+
+ line_offset = s->line_offset;
+#if 0
+ printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
+ width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
+ s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
+#endif
+ addr1 = (s->start_addr * 4);
+ bwidth = (width * bits + 7) / 8;
+ y_start = -1;
+ page_min = -1;
+ page_max = 0;
+ d = surface_data(surface);
+ linesize = surface_stride(surface);
+ y1 = 0;
+ for(y = 0; y < height; y++) {
+ addr = addr1;
+ if (!(s->cr[VGA_CRTC_MODE] & 1)) {
+ int shift;
+ /* CGA compatibility handling */
+ shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
+ addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+ }
+ if (!(s->cr[VGA_CRTC_MODE] & 2)) {
+ addr = (addr & ~0x8000) | ((y1 & 2) << 14);
+ }
+ update = full_update;
+ page0 = addr;
+ page1 = addr + bwidth - 1;
+ update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
+ DIRTY_MEMORY_VGA);
+ /* explicit invalidation for the hardware cursor */
+ update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+#ifdef MARU_VGA /* needs full update */
+ update |= 1;
+#endif
+ if (update) {
+ if (y_start < 0)
+ y_start = y;
+ if (page0 < page_min)
+ page_min = page0;
+ if (page1 > page_max)
+ page_max = page1;
+ if (!(is_buffer_shared(surface))) {
+ maru_vga_draw_line(s, d, s->vram_ptr + addr, width);
+ if (s->cursor_draw_line)
+ s->cursor_draw_line(s, d, y);
+ }
+ } else {
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_gfx_update(s->con, 0, y_start,
+ disp_width, y - y_start);
+ y_start = -1;
+ }
+ }
+ if (!multi_run) {
+ mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
+ if ((y1 & mask) == mask)
+ addr1 += line_offset;
+ y1++;
+ multi_run = multi_scan;
+ } else {
+ multi_run--;
+ }
+ /* line compare acts on the displayed lines */
+ if (y == s->line_compare)
+ addr1 = 0;
+ d += linesize;
+ }
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_gfx_update(s->con, 0, y_start,
+ disp_width, y - y_start);
+ }
+ /* reset modified pages */
+ if (page_max >= page_min) {
+ memory_region_reset_dirty(&s->vram,
+ page_min,
+ page_max - page_min,
+ DIRTY_MEMORY_VGA);
+ }
+ memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void vga_draw_blank(VGACommonState *s, int full_update)
+{
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int i, w, val;
+ uint8_t *d;
+
+ if (!full_update)
+ return;
+ if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+ return;
+
+ s->rgb_to_pixel =
+ rgb_to_pixel_dup_table[get_depth_index(surface)];
+ if (surface_bits_per_pixel(surface) == 8) {
+ val = s->rgb_to_pixel(0, 0, 0);
+ } else {
+ val = 0;
+ }
+ w = s->last_scr_width * surface_bytes_per_pixel(surface);
+ d = surface_data(surface);
+ for(i = 0; i < s->last_scr_height; i++) {
+ memset(d, val, w);
+ d += surface_stride(surface);
+ }
+ dpy_gfx_update(s->con, 0, 0,
+ s->last_scr_width, s->last_scr_height);
+}
+
+#define GMODE_TEXT 0
+#define GMODE_GRAPH 1
+#define GMODE_BLANK 2
+
+static void vga_update_display(void *opaque)
+{
+ VGACommonState *s = opaque;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int full_update, graphic_mode;
+
+ qemu_flush_coalesced_mmio_buffer();
+
+ if (surface_bits_per_pixel(surface) == 0) {
+ /* nothing to do */
+ } else {
+ full_update = 0;
+ if (!(s->ar_index & 0x20)) {
+ graphic_mode = GMODE_BLANK;
+ } else {
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+ }
+ if (graphic_mode != s->graphic_mode) {
+ s->graphic_mode = graphic_mode;
++ s->cursor_blink_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+ full_update = 1;
+ }
+ switch(graphic_mode) {
+ case GMODE_TEXT:
+ vga_draw_text(s, full_update);
+ break;
+ case GMODE_GRAPH:
+ vga_draw_graphic(s, full_update);
+ break;
+ case GMODE_BLANK:
+ default:
+ vga_draw_blank(s, full_update);
+ break;
+ }
+ }
+}
+
+/* force a full display refresh */
+static void vga_invalidate_display(void *opaque)
+{
+ VGACommonState *s = opaque;
+
+ s->last_width = -1;
+ s->last_height = -1;
+}
+
+#define TEXTMODE_X(x) ((x) % width)
+#define TEXTMODE_Y(x) ((x) / width)
+#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
+ ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
+/* relay text rendering to the display driver
+ * instead of doing a full vga_update_display() */
+static void vga_update_text(void *opaque, console_ch_t *chardata)
+{
+ VGACommonState *s = opaque;
+ int graphic_mode, i, cursor_offset, cursor_visible;
+ int cw, cheight, width, height, size, c_min, c_max;
+ uint32_t *src;
+ console_ch_t *dst, val;
+ char msg_buffer[80];
+ int full_update = 0;
+
+ qemu_flush_coalesced_mmio_buffer();
+
+ if (!(s->ar_index & 0x20)) {
+ graphic_mode = GMODE_BLANK;
+ } else {
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+ }
+ if (graphic_mode != s->graphic_mode) {
+ s->graphic_mode = graphic_mode;
+ full_update = 1;
+ }
+ if (s->last_width == -1) {
+ s->last_width = 0;
+ full_update = 1;
+ }
+
+ switch (graphic_mode) {
+ case GMODE_TEXT:
+ /* TODO: update palette */
+ full_update |= update_basic_params(s);
+
+ /* total width & height */
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+ cw = 8;
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ cw = 9;
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ cw = 16; /* NOTE: no 18 pixel wide */
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
+ /* ugly hack for CGA 160x100x16 - explain me the logic */
+ height = 100;
+ } else {
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+ height = (height + 1) / cheight;
+ }
+
+ size = (height * width);
+ if (size > CH_ATTR_SIZE) {
+ if (!full_update)
+ return;
+
+ snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
+ width, height);
+ break;
+ }
+
+ if (width != s->last_width || height != s->last_height ||
+ cw != s->last_cw || cheight != s->last_ch) {
+ s->last_scr_width = width * cw;
+ s->last_scr_height = height * cheight;
+ qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+ dpy_text_resize(s->con, width, height);
+ s->last_depth = 0;
+ s->last_width = width;
+ s->last_height = height;
+ s->last_ch = cheight;
+ s->last_cw = cw;
+ full_update = 1;
+ }
+
+ if (full_update) {
+ s->full_update_gfx = 1;
+ }
+ if (s->full_update_text) {
+ s->full_update_text = 0;
+ full_update |= 1;
+ }
+
+ /* Update "hardware" cursor */
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+ if (cursor_offset != s->cursor_offset ||
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
+ cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
+ if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
+ dpy_text_cursor(s->con,
+ TEXTMODE_X(cursor_offset),
+ TEXTMODE_Y(cursor_offset));
+ else
+ dpy_text_cursor(s->con, -1, -1);
+ s->cursor_offset = cursor_offset;
+ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
+ }
+
+ src = (uint32_t *) s->vram_ptr + s->start_addr;
+ dst = chardata;
+
+ if (full_update) {
+ for (i = 0; i < size; src ++, dst ++, i ++)
+ console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
+
+ dpy_text_update(s->con, 0, 0, width, height);
+ } else {
+ c_max = 0;
+
+ for (i = 0; i < size; src ++, dst ++, i ++) {
+ console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+ if (*dst != val) {
+ *dst = val;
+ c_max = i;
+ break;
+ }
+ }
+ c_min = i;
+ for (; i < size; src ++, dst ++, i ++) {
+ console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+ if (*dst != val) {
+ *dst = val;
+ c_max = i;
+ }
+ }
+
+ if (c_min <= c_max) {
+ i = TEXTMODE_Y(c_min);
+ dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
+ }
+ }
+
+ return;
+ case GMODE_GRAPH:
+ if (!full_update)
+ return;
+
+ s->get_resolution(s, &width, &height);
+ snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
+ width, height);
+ break;
+ case GMODE_BLANK:
+ default:
+ if (!full_update)
+ return;
+
+ snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
+ break;
+ }
+
+ /* Display a message */
+ s->last_width = 60;
+ s->last_height = height = 3;
+ dpy_text_cursor(s->con, -1, -1);
+ dpy_text_resize(s->con, s->last_width, height);
+
+ for (dst = chardata, i = 0; i < s->last_width * height; i ++)
+ console_write_ch(dst ++, ' ');
+
+ size = strlen(msg_buffer);
+ width = (s->last_width - size) / 2;
+ dst = chardata + s->last_width + width;
+ for (i = 0; i < size; i ++)
+ console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
+
+ dpy_text_update(s->con, 0, 0, s->last_width, height);
+}
+
+static const GraphicHwOps vga_ops = {
+ .invalidate = vga_invalidate_display,
+ .gfx_update = vga_update_display,
+ .text_update = vga_update_text,
+};
+
+void maru_vga_common_init(VGACommonState *s, Object *obj)
+{
+ int i, j, v, b;
+
+ for(i = 0;i < 256; i++) {
+ v = 0;
+ for(j = 0; j < 8; j++) {
+ v |= ((i >> j) & 1) << (j * 4);
+ }
+ expand4[i] = v;
+
+ v = 0;
+ for(j = 0; j < 4; j++) {
+ v |= ((i >> (2 * j)) & 3) << (j * 4);
+ }
+ expand2[i] = v;
+ }
+ for(i = 0; i < 16; i++) {
+ v = 0;
+ for(j = 0; j < 4; j++) {
+ b = ((i >> j) & 1);
+ v |= b << (2 * j);
+ v |= b << (2 * j + 1);
+ }
+ expand4to8[i] = v;
+ }
+
+ /* valid range: 1 MB -> 256 MB */
+ s->vram_size = 1024 * 1024;
+ while (s->vram_size < (s->vram_size_mb << 20) &&
+ s->vram_size < (256 << 20)) {
+ s->vram_size <<= 1;
+ }
+ s->vram_size_mb = s->vram_size >> 20;
+
+ s->is_vbe_vmstate = 1;
+ memory_region_init_ram(&s->vram, obj, "maru_vga.vram", s->vram_size);
+ vmstate_register_ram_global(&s->vram);
+ xen_register_framebuffer(&s->vram);
+ s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+ s->get_bpp = vga_get_bpp;
+ s->get_offsets = vga_get_offsets;
+ s->get_resolution = vga_get_resolution;
+ s->hw_ops = &vga_ops;
+ switch (vga_retrace_method) {
+ case VGA_RETRACE_DUMB:
+ s->retrace = vga_dumb_retrace;
+ s->update_retrace_info = vga_dumb_update_retrace_info;
+ break;
+
+ case VGA_RETRACE_PRECISE:
+ s->retrace = vga_precise_retrace;
+ s->update_retrace_info = vga_precise_update_retrace_info;
+ break;
+ }
+ vga_dirty_log_start(s);
+ TRACE("%s\n", __func__);
+}
+
+void maru_vga_common_fini(void)
+{
+ /* do nothing */
+ TRACE("%s\n", __func__);
+}
--- /dev/null
- cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+/*
+ * vga device
+ * Based on qemu/hw/vga_template.h
+ *
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * Hyunjun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
+
+static inline void glue(maru_vga_draw_glyph_line_, DEPTH)(uint8_t *d,
+ uint32_t font_data,
+ uint32_t xorcol,
+ uint32_t bgcol)
+{
+#if BPP == 1
+ ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+ ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+static void glue(maru_vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol)
+{
+ uint32_t font_data, xorcol;
+
+ xorcol = bgcol ^ fgcol;
+ do {
+ font_data = font_ptr[0];
+ glue(maru_vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
+ font_ptr += 4;
+ d += linesize;
+ } while (--h);
+}
+
+static void glue(maru_vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol)
+{
+ uint32_t font_data, xorcol;
+
+ xorcol = bgcol ^ fgcol;
+ do {
+ font_data = font_ptr[0];
+ glue(maru_vga_draw_glyph_line_, DEPTH)(d,
+ expand4to8[font_data >> 4],
+ xorcol, bgcol);
+ glue(maru_vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+ expand4to8[font_data & 0x0f],
+ xorcol, bgcol);
+ font_ptr += 4;
+ d += linesize;
+ } while (--h);
+}
+
+static void glue(maru_vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
+ const uint8_t *font_ptr, int h,
+ uint32_t fgcol, uint32_t bgcol, int dup9)
+{
+ uint32_t font_data, xorcol, v;
+
+ xorcol = bgcol ^ fgcol;
+ do {
+ font_data = font_ptr[0];
+#if BPP == 1
- cpu_to_32wu(((uint32_t *)d)+1, v);
++ stl_p((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+ v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
- cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
- cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
- cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
++ stl_p(((uint32_t *)d)+1, v);
+ if (dup9)
+ ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
+ else
+ ((uint8_t *)d)[8] = bgcol;
+
+#elif BPP == 2
- cpu_to_32wu(((uint32_t *)d)+3, v);
++ stl_p(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
++ stl_p(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
++ stl_p(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
+ v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
++ stl_p(((uint32_t *)d)+3, v);
+ if (dup9)
+ ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
+ else
+ ((uint16_t *)d)[8] = bgcol;
+#else
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+ v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[7] = v;
+ if (dup9)
+ ((uint32_t *)d)[8] = v;
+ else
+ ((uint32_t *)d)[8] = bgcol;
+#endif
+ font_ptr += 4;
+ d += linesize;
+ } while (--h);
+}
+
+/*
+ * 4 color mode
+ */
+static void glue(maru_vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, *palette, data, v;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand2[GET_PLANE(data, 0)];
+ v |= expand2[GET_PLANE(data, 2)] << 2;
+ ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
+ ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
+ ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
+ ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
+
+ v = expand2[GET_PLANE(data, 1)];
+ v |= expand2[GET_PLANE(data, 3)] << 2;
+ ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
+ ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+ ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+ ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+ d += BPP * 8;
+ s += 4;
+ }
+}
+
+#if BPP == 1
+#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
+#elif BPP == 2
+#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
+#else
+#define PUT_PIXEL2(d, n, v) \
+((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
+#endif
+
+/*
+ * 4 color mode, dup2 horizontal
+ */
+static void glue(maru_vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, *palette, data, v;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand2[GET_PLANE(data, 0)];
+ v |= expand2[GET_PLANE(data, 2)] << 2;
+ PUT_PIXEL2(d, 0, palette[v >> 12]);
+ PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
+ PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
+ PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
+
+ v = expand2[GET_PLANE(data, 1)];
+ v |= expand2[GET_PLANE(data, 3)] << 2;
+ PUT_PIXEL2(d, 4, palette[v >> 12]);
+ PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+ PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+ PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+ d += BPP * 16;
+ s += 4;
+ }
+}
+
+/*
+ * 16 color mode
+ */
+static void glue(maru_vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, data, v, *palette;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand4[GET_PLANE(data, 0)];
+ v |= expand4[GET_PLANE(data, 1)] << 1;
+ v |= expand4[GET_PLANE(data, 2)] << 2;
+ v |= expand4[GET_PLANE(data, 3)] << 3;
+ ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
+ ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
+ ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
+ ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
+ ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
+ ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+ ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+ ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+ d += BPP * 8;
+ s += 4;
+ }
+}
+
+/*
+ * 16 color mode, dup2 horizontal
+ */
+static void glue(maru_vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t plane_mask, data, v, *palette;
+ int x;
+
+ palette = s1->last_palette;
+ plane_mask = mask16[s1->ar[0x12] & 0xf];
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ data = ((uint32_t *)s)[0];
+ data &= plane_mask;
+ v = expand4[GET_PLANE(data, 0)];
+ v |= expand4[GET_PLANE(data, 1)] << 1;
+ v |= expand4[GET_PLANE(data, 2)] << 2;
+ v |= expand4[GET_PLANE(data, 3)] << 3;
+ PUT_PIXEL2(d, 0, palette[v >> 28]);
+ PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
+ PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
+ PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
+ PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
+ PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+ PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+ PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+ d += BPP * 16;
+ s += 4;
+ }
+}
+
+/*
+ * 256 color mode, double pixels
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(maru_vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t *palette;
+ int x;
+
+ palette = s1->last_palette;
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ PUT_PIXEL2(d, 0, palette[s[0]]);
+ PUT_PIXEL2(d, 1, palette[s[1]]);
+ PUT_PIXEL2(d, 2, palette[s[2]]);
+ PUT_PIXEL2(d, 3, palette[s[3]]);
+ d += BPP * 8;
+ s += 4;
+ }
+}
+
+/*
+ * standard 256 color mode
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(maru_vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ uint32_t *palette;
+ int x;
+
+ palette = s1->last_palette;
+ width >>= 3;
+ for(x = 0; x < width; x++) {
+ ((PIXEL_TYPE *)d)[0] = palette[s[0]];
+ ((PIXEL_TYPE *)d)[1] = palette[s[1]];
+ ((PIXEL_TYPE *)d)[2] = palette[s[2]];
+ ((PIXEL_TYPE *)d)[3] = palette[s[3]];
+ ((PIXEL_TYPE *)d)[4] = palette[s[4]];
+ ((PIXEL_TYPE *)d)[5] = palette[s[5]];
+ ((PIXEL_TYPE *)d)[6] = palette[s[6]];
+ ((PIXEL_TYPE *)d)[7] = palette[s[7]];
+ d += BPP * 8;
+ s += 8;
+ }
+}
+
+#endif /* DEPTH != 15 */
+
+
+/* XXX: optimize */
+
+/*
+ * 15 bit color
+ */
+static void glue(maru_vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ memcpy(d, s, width * 2);
+#else
+ int w;
+ uint32_t v, r, g, b;
+
+ w = width;
+ do {
+ v = lduw_raw((void *)s);
+ r = (v >> 7) & 0xf8;
+ g = (v >> 2) & 0xf8;
+ b = (v << 3) & 0xf8;
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 2;
+ d += BPP;
+ } while (--w != 0);
+#endif
+}
+
+/*
+ * 16 bit color
+ */
+static void glue(maru_vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+ memcpy(d, s, width * 2);
+#else
+ int w;
+ uint32_t v, r, g, b;
+
+ w = width;
+ do {
+ v = lduw_raw((void *)s);
+ r = (v >> 8) & 0xf8;
+ g = (v >> 3) & 0xfc;
+ b = (v << 3) & 0xf8;
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 2;
+ d += BPP;
+ } while (--w != 0);
+#endif
+}
+
+/*
+ * 24 bit color
+ */
+static void glue(maru_vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ int w;
+ uint32_t r, g, b;
+
+ w = width;
+ do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+ r = s[0];
+ g = s[1];
+ b = s[2];
+#else
+ b = s[0];
+ g = s[1];
+ r = s[2];
+#endif
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 3;
+ d += BPP;
+ } while (--w != 0);
+}
+
+/*
+ * 32 bit color
+ */
+static void glue(maru_vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
+ memcpy(d, s, width * 4);
+#else
+ int w;
+ uint32_t r, g, b;
+
+ w = width;
+ do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+ r = s[1];
+ g = s[2];
+ b = s[3];
+#else
+ b = s[0];
+ g = s[1];
+ r = s[2];
+#endif
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+ s += 4;
+ d += BPP;
+ } while (--w != 0);
+#endif
+}
+
+#undef PUT_PIXEL2
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
--- /dev/null
+/*
+ * SDL_WINDOWID hack
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <pthread.h>
+#include <math.h>
+#include <png.h>
+#include "ui/console.h"
++#include "qemu/main-loop.h"
+#include "maru_sdl.h"
+#include "maru_display.h"
+#include "emul_state.h"
+#include "emulator.h"
+#include "maru_finger.h"
+#include "hw/maru_pm.h"
+#include "hw/maru_brightness.h"
+#include "hw/maru_overlay.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru_sdl);
+
+static QEMUBH *sdl_init_bh;
+static QEMUBH *sdl_resize_bh;
+static DisplaySurface *dpy_surface;
+
+static SDL_Surface *surface_screen;
+static SDL_Surface *surface_qemu;
+static SDL_Surface *scaled_screen;
+static SDL_Surface *rotated_screen;
+static SDL_Surface *surface_guide; /* blank guide image */
+
+static double current_scale_factor = 1.0;
+static double current_screen_degree;
+static pixman_filter_t sdl_pixman_filter;
+
+static int sdl_alteration;
+
+static unsigned int sdl_skip_update;
+static unsigned int sdl_skip_count;
+
+static bool blank_guide_enable;
+static unsigned int blank_cnt;
+#define MAX_BLANK_FRAME_CNT 10
+#define BLANK_GUIDE_IMAGE_PATH "../images/"
+#define BLANK_GUIDE_IMAGE_NAME "blank-guide.png"
+
+
+#define SDL_THREAD
+
+static pthread_mutex_t sdl_mutex = PTHREAD_MUTEX_INITIALIZER;
+#ifdef SDL_THREAD
+static pthread_cond_t sdl_cond = PTHREAD_COND_INITIALIZER;
+static int sdl_thread_initialized;
+#endif
+
+#define SDL_FLAGS (SDL_SWSURFACE | SDL_ASYNCBLIT | SDL_NOFRAME)
+#define SDL_BPP 32
+
+/* Image processing functions using the pixman library */
+static void maru_do_pixman_dpy_surface(pixman_image_t *dst_image)
+{
+ /* overlay0 */
+ if (overlay0_power) {
+ pixman_image_composite(PIXMAN_OP_OVER,
+ overlay0_image, NULL, dst_image,
+ 0, 0, 0, 0, overlay0_left, overlay0_top,
+ overlay0_width, overlay0_height);
+ }
+ /* overlay1 */
+ if (overlay1_power) {
+ pixman_image_composite(PIXMAN_OP_OVER,
+ overlay1_image, NULL, dst_image,
+ 0, 0, 0, 0, overlay1_left, overlay1_top,
+ overlay1_width, overlay1_height);
+ }
+ /* apply the brightness level */
+ if (brightness_level < BRIGHTNESS_MAX) {
+ pixman_image_composite(PIXMAN_OP_OVER,
+ brightness_image, NULL, dst_image,
+ 0, 0, 0, 0, 0, 0,
+ pixman_image_get_width(dst_image),
+ pixman_image_get_height(dst_image));
+ }
+}
+
+static SDL_Surface *maru_do_pixman_scale(SDL_Surface *rz_src,
+ SDL_Surface *rz_dst,
+ pixman_filter_t filter)
+{
+ pixman_image_t *src = NULL;
+ pixman_image_t *dst = NULL;
+ double sx = 0;
+ double sy = 0;
+ pixman_transform_t matrix;
+ struct pixman_f_transform matrix_f;
+
+ SDL_LockSurface(rz_src);
+ SDL_LockSurface(rz_dst);
+
+ src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_src->w, rz_src->h, rz_src->pixels, rz_src->w * 4);
+ dst = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_dst->w, rz_dst->h, rz_dst->pixels, rz_dst->w * 4);
+
+ sx = (double)rz_src->w / (double)rz_dst->w;
+ sy = (double)rz_src->h / (double)rz_dst->h;
+ pixman_f_transform_init_identity(&matrix_f);
+ pixman_f_transform_scale(&matrix_f, NULL, sx, sy);
+ pixman_transform_from_pixman_f_transform(&matrix, &matrix_f);
+ pixman_image_set_transform(src, &matrix);
+ pixman_image_set_filter(src, filter, NULL, 0);
+ pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dst,
+ 0, 0, 0, 0, 0, 0,
+ rz_dst->w, rz_dst->h);
+
+ pixman_image_unref(src);
+ pixman_image_unref(dst);
+
+ SDL_UnlockSurface(rz_src);
+ SDL_UnlockSurface(rz_dst);
+
+ return rz_dst;
+}
+
+static SDL_Surface *maru_do_pixman_rotate(SDL_Surface *rz_src,
+ SDL_Surface *rz_dst,
+ int angle)
+{
+ pixman_image_t *src = NULL;
+ pixman_image_t *dst = NULL;
+ pixman_transform_t matrix;
+ struct pixman_f_transform matrix_f;
+
+ SDL_LockSurface(rz_src);
+ SDL_LockSurface(rz_dst);
+
+ src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_src->w, rz_src->h, rz_src->pixels, rz_src->w * 4);
+ dst = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ rz_dst->w, rz_dst->h, rz_dst->pixels, rz_dst->w * 4);
+
+ pixman_f_transform_init_identity(&matrix_f);
+ switch(angle) {
+ case 0:
+ pixman_f_transform_rotate(&matrix_f, NULL, 1.0, 0.0);
+ pixman_f_transform_translate(&matrix_f, NULL, 0.0, 0.0);
+ break;
+ case 90:
+ pixman_f_transform_rotate(&matrix_f, NULL, 0.0, 1.0);
+ pixman_f_transform_translate(&matrix_f, NULL,
+ (double)rz_dst->h, 0.0);
+ break;
+ case 180:
+ pixman_f_transform_rotate(&matrix_f, NULL, -1.0, 0.0);
+ pixman_f_transform_translate(&matrix_f, NULL,
+ (double)rz_dst->w, (double)rz_dst->h);
+ break;
+ case 270:
+ pixman_f_transform_rotate(&matrix_f, NULL, 0.0, -1.0);
+ pixman_f_transform_translate(&matrix_f, NULL,
+ 0.0, (double)rz_dst->w);
+ break;
+ default:
+ fprintf(stdout, "not supported angle factor (angle=%d)\n", angle);
+ break;
+ }
+ pixman_transform_from_pixman_f_transform(&matrix, &matrix_f);
+ pixman_image_set_transform(src, &matrix);
+ //pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, NULL, 0);
+ pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dst,
+ 0, 0, 0, 0, 0, 0,
+ rz_dst->w, rz_dst->h);
+
+ pixman_image_unref(src);
+ pixman_image_unref(dst);
+
+ SDL_UnlockSurface(rz_src);
+ SDL_UnlockSurface(rz_dst);
+
+ return rz_dst;
+}
+
+static void qemu_ds_sdl_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ /* call sdl update */
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+
+ pthread_cond_signal(&sdl_cond);
+
+ pthread_mutex_unlock(&sdl_mutex);
+#else
+ qemu_update();
+#endif
+}
+
+static void qemu_ds_sdl_switch(DisplayChangeListener *dcl,
+ struct DisplaySurface *new_surface)
+{
+ int console_width = 0, console_height = 0;
+
+ sdl_skip_update = 0;
+ sdl_skip_count = 0;
+
+ if (!new_surface) {
+ ERR("qemu_ds_sdl_switch : new_surface is NULL\n");
+ return;
+ }
+
+ dpy_surface = new_surface;
+ console_width = surface_width(new_surface);
+ console_height = surface_height(new_surface);
+
+ INFO("qemu_ds_sdl_switch : (%d, %d)\n",
+ console_width, console_height);
+
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ if (surface_qemu != NULL) {
+ SDL_FreeSurface(surface_qemu);
+ surface_qemu = NULL;
+ }
+
+ /* create surface_qemu */
+ if (console_width == get_emul_resolution_width() &&
+ console_height == get_emul_resolution_height()) {
+ INFO("create SDL screen : (%d, %d)\n",
+ console_width, console_height);
+
+ surface_qemu = SDL_CreateRGBSurfaceFrom(
+ surface_data(dpy_surface),
+ console_width, console_height,
+ surface_bits_per_pixel(dpy_surface),
+ surface_stride(dpy_surface),
+ dpy_surface->pf.rmask,
+ dpy_surface->pf.gmask,
+ dpy_surface->pf.bmask,
+ dpy_surface->pf.amask);
+ } else {
+ INFO("create blank screen : (%d, %d)\n",
+ get_emul_resolution_width(), get_emul_resolution_height());
+
+ surface_qemu = SDL_CreateRGBSurface(
+ SDL_SWSURFACE,
+ console_width, console_height,
+ surface_bits_per_pixel(dpy_surface),
+ 0, 0, 0, 0);
+ }
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+
+ if (surface_qemu == NULL) {
+ ERR("Unable to set the RGBSurface: %s\n", SDL_GetError());
+ return;
+ }
+}
+
+static png_bytep read_png_file(const char *file_name,
+ unsigned int *width_out, unsigned int *height_out)
+{
+#define PNG_HEADER_SIZE 8
+
+ FILE *fp = NULL;
+ png_byte header[PNG_HEADER_SIZE] = { 0, };
+ png_structp png_ptr = NULL;
+
+ png_infop info_ptr = NULL;
+ png_uint_32 width = 0;
+ png_uint_32 height = 0;
+ png_byte channels = 0;
+ unsigned int stride = 0;
+ int bit_depth = 0;
+ int color_type = 0;
+ int i = 0;
+
+ png_bytep pixel_data = NULL;
+ png_bytepp row_ptr_data = NULL;
+
+ if (file_name == NULL) {
+ ERR("file name is empty\n");
+ return NULL;
+ }
+
+ fp = fopen(file_name, "rb");
+ if (fp == NULL) {
+ ERR("file %s could not be opened\n", file_name);
+ return NULL;
+ }
+
+ if (fread(header, sizeof(png_byte), PNG_HEADER_SIZE, fp) != PNG_HEADER_SIZE) {
+ ERR("failed to read header from png file\n");
+ fclose(fp);
+ return NULL;
+ }
+
+ if (png_sig_cmp(header, 0, PNG_HEADER_SIZE) != 0) {
+ ERR("file %s is not recognized as a PNG image\n", file_name);
+ fclose(fp);
+ return NULL;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL) {
+ ERR("failed to allocate png read struct\n");
+ fclose(fp);
+ return NULL;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ ERR("failed to allocate png info struct\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ fclose(fp);
+ return NULL;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)) != 0) {
+ ERR("error during init_io\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+ return NULL;
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, PNG_HEADER_SIZE);
+
+ /* read the PNG image information */
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr,
+ &width, &height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ stride = width * bit_depth * channels / 8;
+
+ pixel_data = (png_bytep) g_malloc0(stride * height);
+ if (pixel_data == NULL) {
+ ERR("could not allocate data buffer for pixels\n");
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+ return NULL;
+ }
+
+ row_ptr_data = (png_bytepp) g_malloc0(sizeof(png_bytep) * height);
+ if (row_ptr_data == NULL) {
+ ERR("could not allocate data buffer for row_ptr\n");
+
+ g_free(pixel_data);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+ return NULL;
+ }
+
+ switch(color_type) {
+ case PNG_COLOR_TYPE_PALETTE :
+ png_set_palette_to_rgb(png_ptr);
+ break;
+ case PNG_COLOR_TYPE_RGB :
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ /* transparency data for image */
+ png_set_tRNS_to_alpha(png_ptr);
+ } else {
+ png_set_filter(png_ptr, 0xff, PNG_FILLER_AFTER);
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA :
+ break;
+ default :
+ INFO("png file has an unsupported color type\n");
+ break;
+ }
+
+ for (i = 0; i < height; i++) {
+ row_ptr_data[i] = pixel_data + (stride * i);
+ }
+
+ /* read the entire image into memory */
+ png_read_image(png_ptr, row_ptr_data);
+
+ /* image information */
+ INFO("=== blank guide image was loaded ===============\n");
+ INFO("file path : %s\n", file_name);
+ INFO("width : %d, height : %d, stride : %d\n",
+ width, height, stride);
+ INFO("color type : %d, channels : %d, bit depth : %d\n",
+ color_type, channels, bit_depth);
+ INFO("================================================\n");
+
+ if (width_out != NULL) {
+ *width_out = (unsigned int) width;
+ }
+ if (height_out != NULL) {
+ *height_out = (unsigned int) height;
+ }
+
+ g_free(row_ptr_data);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ png_destroy_info_struct(png_ptr, &info_ptr);
+ fclose(fp);
+
+ return pixel_data;
+}
+
+static SDL_Surface *get_blank_guide_image(void)
+{
+ if (surface_guide == NULL) {
+ unsigned int width = 0;
+ unsigned int height = 0;
+ char *guide_image_path = NULL;
+ void *guide_image_data = NULL;
+
+ /* load png image */
+ int path_len = strlen(get_bin_path()) +
+ strlen(BLANK_GUIDE_IMAGE_PATH) +
+ strlen(BLANK_GUIDE_IMAGE_NAME) + 1;
+ guide_image_path = g_malloc0(sizeof(char) * path_len);
+ snprintf(guide_image_path, path_len, "%s%s%s",
+ get_bin_path(), BLANK_GUIDE_IMAGE_PATH,
+ BLANK_GUIDE_IMAGE_NAME);
+
+ guide_image_data = (void *) read_png_file(
+ guide_image_path, &width, &height);
+
+ if (guide_image_data != NULL) {
+ surface_guide = SDL_CreateRGBSurfaceFrom(
+ guide_image_data, width, height,
+ get_emul_sdl_bpp(), width * 4,
+ dpy_surface->pf.bmask,
+ dpy_surface->pf.gmask,
+ dpy_surface->pf.rmask,
+ dpy_surface->pf.amask);
+ } else {
+ ERR("failed to draw a blank guide image\n");
+ }
+
+ g_free(guide_image_path);
+ }
+
+ return surface_guide;
+}
+
+static void qemu_ds_sdl_refresh(DisplayChangeListener *dcl)
+{
+ if (sdl_alteration == 1) {
+ sdl_alteration = 0;
+ sdl_skip_update = 0;
+ sdl_skip_count = 0;
+ }
+
+ /* If the display is turned off,
+ the screen does not update until the display is turned on */
+ if (sdl_skip_update && brightness_off) {
+ if (blank_cnt > MAX_BLANK_FRAME_CNT) {
+ /* do nothing */
+ return;
+ } else if (blank_cnt == MAX_BLANK_FRAME_CNT) {
+ if (blank_guide_enable == true) {
+ INFO("draw a blank guide image\n");
+
+ SDL_Surface *guide = get_blank_guide_image();
+ if (guide != NULL && get_emul_skin_enable() == 1) {
+ /* draw guide image */
+ int dst_x = 0; int dst_y = 0;
+ int dst_w = 0; int dst_h = 0;
+
+ unsigned int screen_width =
+ get_emul_resolution_width() * current_scale_factor;
+ unsigned int screen_height =
+ get_emul_resolution_height() * current_scale_factor;
+
+ int margin_w = screen_width - guide->w;
+ int margin_h = screen_height - guide->h;
+
+ if (margin_w < 0 || margin_h < 0) {
+ /* guide image scaling */
+ int margin = (margin_w < margin_h)? margin_w : margin_h;
+ dst_w = guide->w + margin;
+ dst_h = guide->h + margin;
+
+ SDL_Surface *scaled_guide = SDL_CreateRGBSurface(
+ SDL_SWSURFACE, dst_w, dst_h, get_emul_sdl_bpp(),
+ guide->format->Rmask, guide->format->Gmask,
+ guide->format->Bmask, guide->format->Amask);
+
+ scaled_guide = maru_do_pixman_scale(
+ guide, scaled_guide, PIXMAN_FILTER_BEST);
+
+ dst_x = (surface_screen->w - dst_w) / 2;
+ dst_y = (surface_screen->h - dst_h) / 2;
+ SDL_Rect dst_rect = { dst_x, dst_y, dst_w, dst_h };
+
+ SDL_BlitSurface(scaled_guide, NULL,
+ surface_screen, &dst_rect);
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+
+ SDL_FreeSurface(scaled_guide);
+ } else {
+ dst_w = guide->w;
+ dst_h = guide->h;
+ dst_x = (surface_screen->w - dst_w) / 2;
+ dst_y = (surface_screen->h - dst_h) / 2;
+ SDL_Rect dst_rect = { dst_x, dst_y, dst_w, dst_h };
+
+ SDL_BlitSurface(guide, NULL,
+ surface_screen, &dst_rect);
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+ }
+ }
+ }
+ } else if (blank_cnt == 0) {
+ INFO("skipping of the display updating is started\n");
+ }
+
+ blank_cnt++;
+
+ return;
+ } else {
+ if (blank_cnt != 0) {
+ INFO("skipping of the display updating is ended\n");
+ blank_cnt = 0;
+ }
+ }
+
+ graphic_hw_update(NULL);
+
+ /* Usually, continuously updated.
+ When the display is turned off,
+ ten more updates the screen for a black screen. */
+ if (brightness_off) {
+ if (++sdl_skip_count > 10) {
+ sdl_skip_update = 1;
+ } else {
+ sdl_skip_update = 0;
+ }
+ } else {
+ sdl_skip_count = 0;
+ sdl_skip_update = 0;
+ }
+
+#ifdef TARGET_ARM
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ /*
+ * It is necessary only for exynos4210 FIMD in connection with
+ * some WM (xfwm4, for example)
+ */
+
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+#endif
+}
+
+DisplayChangeListenerOps maru_dcl_ops = {
+ .dpy_name = "maru_sdl",
+ .dpy_gfx_update = qemu_ds_sdl_update,
+ .dpy_gfx_switch = qemu_ds_sdl_switch,
+ .dpy_refresh = qemu_ds_sdl_refresh,
+};
+
+void maruskin_sdl_interpolation(bool on)
+{
+ if (on == true) {
+ INFO("set PIXMAN_FILTER_BEST filter for image processing\n");
+
+ /* PIXMAN_FILTER_BILINEAR */
+ sdl_pixman_filter = PIXMAN_FILTER_BEST;
+ } else {
+ INFO("set PIXMAN_FILTER_FAST filter for image processing\n");
+
+ /* PIXMAN_FILTER_NEAREST */
+ sdl_pixman_filter = PIXMAN_FILTER_FAST;
+ }
+}
+
+static void qemu_update(void)
+{
+ if (sdl_alteration == -1) {
+ SDL_FreeSurface(scaled_screen);
+ SDL_FreeSurface(rotated_screen);
+ SDL_FreeSurface(surface_qemu);
+ surface_qemu = NULL;
+
+ return;
+ }
+
+ if (surface_qemu != NULL) {
+ int i = 0;
+
+ maru_do_pixman_dpy_surface(dpy_surface->image);
+ set_maru_screenshot(dpy_surface);
+
+ if (current_scale_factor != 1.0) {
+ rotated_screen = maru_do_pixman_rotate(
+ surface_qemu, rotated_screen,
+ (int)current_screen_degree);
+ scaled_screen = maru_do_pixman_scale(
+ rotated_screen, scaled_screen, sdl_pixman_filter);
+
+ SDL_BlitSurface(scaled_screen, NULL, surface_screen, NULL);
+ }
+ else {/* current_scale_factor == 1.0 */
+ if (current_screen_degree != 0.0) {
+ rotated_screen = maru_do_pixman_rotate(
+ surface_qemu, rotated_screen,
+ (int)current_screen_degree);
+
+ SDL_BlitSurface(rotated_screen, NULL, surface_screen, NULL);
+ } else {
+ /* as-is */
+ SDL_BlitSurface(surface_qemu, NULL, surface_screen, NULL);
+ }
+ }
+
+ /* draw multi-touch finger points */
+ MultiTouchState *mts = get_emul_multi_touch_state();
+ if (mts->multitouch_enable != 0 && mts->finger_point_surface != NULL) {
+ FingerPoint *finger = NULL;
+ int finger_point_size_half = mts->finger_point_size / 2;
+ SDL_Rect rect;
+
+ for (i = 0; i < mts->finger_cnt; i++) {
+ finger = get_finger_point_from_slot(i);
+ if (finger != NULL && finger->id != 0) {
+ rect.x = finger->origin_x - finger_point_size_half;
+ rect.y = finger->origin_y - finger_point_size_half;
+ rect.w = rect.h = mts->finger_point_size;
+
+ SDL_BlitSurface(
+ (SDL_Surface *)mts->finger_point_surface,
+ NULL, surface_screen, &rect);
+ }
+ }
+ } /* end of draw multi-touch */
+ }
+
+ SDL_UpdateRect(surface_screen, 0, 0, 0, 0);
+}
+
+
+#ifdef SDL_THREAD
+static void *run_qemu_update(void *arg)
+{
+ while(1) {
+ pthread_mutex_lock(&sdl_mutex);
+
+ pthread_cond_wait(&sdl_cond, &sdl_mutex);
+
+ qemu_update();
+
+ pthread_mutex_unlock(&sdl_mutex);
+ }
+
+ return NULL;
+}
+#endif
+
+static void maru_sdl_resize_bh(void *opaque)
+{
+ int surface_width = 0, surface_height = 0;
+ int display_width = 0, display_height = 0;
+ int temp = 0;
+
+ INFO("Set up a video mode with the specified width, "
+ "height and bits-per-pixel\n");
+
+ sdl_alteration = 1;
+ sdl_skip_update = 0;
+
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ /* get current setting information and calculate screen size */
+ display_width = get_emul_resolution_width();
+ display_height = get_emul_resolution_height();
+ current_scale_factor = get_emul_win_scale();
+
+ short rotaton_type = get_emul_rotation();
+ if (rotaton_type == ROTATION_PORTRAIT) {
+ current_screen_degree = 0.0;
+ } else if (rotaton_type == ROTATION_LANDSCAPE) {
+ current_screen_degree = 90.0;
+ temp = display_width;
+ display_width = display_height;
+ display_height = temp;
+ } else if (rotaton_type == ROTATION_REVERSE_PORTRAIT) {
+ current_screen_degree = 180.0;
+ } else if (rotaton_type == ROTATION_REVERSE_LANDSCAPE) {
+ current_screen_degree = 270.0;
+ temp = display_width;
+ display_width = display_height;
+ display_height = temp;
+ }
+
+ surface_width = display_width * current_scale_factor;
+ surface_height = display_height * current_scale_factor;
+
+ surface_screen = SDL_SetVideoMode(
+ surface_width, surface_height,
+ get_emul_sdl_bpp(), SDL_FLAGS);
+
+ INFO("SDL_SetVideoMode\n");
+
+ if (surface_screen == NULL) {
+ ERR("Could not open SDL display (%dx%dx%d) : %s\n",
+ surface_width, surface_height,
+ get_emul_sdl_bpp(), SDL_GetError());
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+
+ return;
+ }
+
+ /* create buffer for image processing */
+ SDL_FreeSurface(scaled_screen);
+ scaled_screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ surface_width, surface_height,
+ get_emul_sdl_bpp(),
+ surface_qemu->format->Rmask,
+ surface_qemu->format->Gmask,
+ surface_qemu->format->Bmask,
+ surface_qemu->format->Amask);
+
+ SDL_FreeSurface(rotated_screen);
+ rotated_screen = SDL_CreateRGBSurface(SDL_SWSURFACE,
+ display_width, display_height,
+ get_emul_sdl_bpp(),
+ surface_qemu->format->Rmask,
+ surface_qemu->format->Gmask,
+ surface_qemu->format->Bmask,
+ surface_qemu->format->Amask);
+
+ /* rearrange multi-touch finger points */
+ if (get_emul_multi_touch_state()->multitouch_enable == 1 ||
+ get_emul_multi_touch_state()->multitouch_enable == 2) {
+ rearrange_finger_points(get_emul_resolution_width(), get_emul_resolution_height(),
+ current_scale_factor, rotaton_type);
+ }
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+#endif
+}
+
+static void maru_sdl_init_bh(void *opaque)
+{
+ SDL_SysWMinfo info;
+
+ INFO("SDL_Init\n");
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ ERR("unable to init SDL: %s\n", SDL_GetError());
+ // TODO:
+ }
+
+#ifndef _WIN32
+ SDL_VERSION(&info.version);
+ SDL_GetWMInfo(&info);
+#endif
+
+ qemu_bh_schedule(sdl_resize_bh);
+
+#ifdef SDL_THREAD
+ if (sdl_thread_initialized == 0) {
+ sdl_thread_initialized = 1;
+
+ INFO("sdl update thread create\n");
+
+ pthread_t thread_id;
+ if (pthread_create(
+ &thread_id, NULL, run_qemu_update, NULL) != 0) {
+ ERR("pthread_create fail\n");
+ return;
+ }
+ }
+#endif
+}
+
+void maruskin_sdl_init(uint64 swt_handle,
+ unsigned int display_width, unsigned int display_height,
+ bool blank_guide)
+{
+ gchar SDL_windowhack[32] = { 0, };
+ long window_id = swt_handle;
+ blank_guide_enable = blank_guide;
+
+ INFO("maru sdl init\n");
+
+ sdl_init_bh = qemu_bh_new(maru_sdl_init_bh, NULL);
+ sdl_resize_bh = qemu_bh_new(maru_sdl_resize_bh, NULL);
+
+ sprintf(SDL_windowhack, "%ld", window_id);
+ g_setenv("SDL_WINDOWID", SDL_windowhack, 1);
+
+ INFO("register SDL environment variable. "
+ "(SDL_WINDOWID = %s)\n", SDL_windowhack);
+
+ set_emul_resolution(display_width, display_height);
+ set_emul_sdl_bpp(SDL_BPP);
+ maruskin_sdl_interpolation(false);
+ init_multi_touch_state();
+
+ if (blank_guide_enable == true) {
+ INFO("blank guide is on\n");
+ }
+
+ qemu_bh_schedule(sdl_init_bh);
+}
+
+void maruskin_sdl_quit(void)
+{
+ INFO("maru sdl quit\n");
+
+ if (surface_guide != NULL) {
+ g_free(surface_guide->pixels);
+ SDL_FreeSurface(surface_guide);
+ }
+
+ /* remove multi-touch finger points */
+ cleanup_multi_touch_state();
+
+ if (sdl_init_bh != NULL) {
+ qemu_bh_delete(sdl_init_bh);
+ }
+ if (sdl_resize_bh != NULL) {
+ qemu_bh_delete(sdl_resize_bh);
+ }
+
+ sdl_alteration = -1;
+
+#ifdef SDL_THREAD
+ pthread_mutex_lock(&sdl_mutex);
+#endif
+
+ SDL_Quit();
+
+#ifdef SDL_THREAD
+ pthread_mutex_unlock(&sdl_mutex);
+ pthread_cond_destroy(&sdl_cond);
+#endif
+
+ pthread_mutex_destroy(&sdl_mutex);
+}
+
+void maruskin_sdl_resize(void)
+{
+ INFO("maru sdl resize\n");
+
+ qemu_bh_schedule(sdl_resize_bh);
+}
--- /dev/null
- qdev_free(&usbdisk->qdev);
+/*
+ * mainloop_evhandle.c
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * DoHyung Hong
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifdef _WIN32
+#include <winsock.h>
+#define socklen_t int
+#else
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#endif
+
+//#include "qobject.h"
+#include "qemu-common.h"
+#include "hw/usb.h"
+#include "hw/irq.h"
+#include "mloop_event.h"
+#include "ui/console.h"
+#include "emul_state.h"
+#include "debug_ch.h"
+#include "monitor/monitor.h"
+#include "hw/pci/pci.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory-internal.h"
+
+#include "emulator.h"
+#include "guest_debug.h"
+#include "skin/maruskin_server.h"
+#include "hw/maru_virtio_touchscreen.h"
+#include "hw/maru_virtio_keyboard.h"
+
+MULTI_DEBUG_CHANNEL(qemu, mloop_event);
+
+struct mloop_evsock {
+ int sockno;
+ unsigned short portno;
+ unsigned char status;
+};
+
+#define MLOOP_EVSOCK_NULL 0
+#define MLOOP_EVSOCK_CREATED 1
+#define MLOOP_EVSOCK_NOTBOUND 2
+#define MLOOP_EVSOCK_BOUND 3
+#define MLOOP_EVSOCK_CONNECTED 4
+
+#define PACKET_LEN 512
+struct mloop_evpack {
+ short type;
+ short size;
+ char data[PACKET_LEN-4];
+};
+
+#define MLOOP_EVTYPE_USB_ADD 1
+#define MLOOP_EVTYPE_USB_DEL 2
+#define MLOOP_EVTYPE_INTR_UP 3
+#define MLOOP_EVTYPE_INTR_DOWN 4
+#define MLOOP_EVTYPE_TOUCH 6
+#define MLOOP_EVTYPE_KEYBOARD 7
+#define MLOOP_EVTYPE_KBD_ADD 8
+#define MLOOP_EVTYPE_KBD_DEL 9
+#define MLOOP_EVTYPE_RAMDUMP 10
+#define MLOOP_EVTYPE_SDCARD_ATTACH 11
+#define MLOOP_EVTYPE_SDCARD_DETACH 12
+
+
+static struct mloop_evsock mloop = {-1, 0, 0};
+
+static int mloop_evsock_create(struct mloop_evsock *ev)
+{
+ struct sockaddr sa;
+ socklen_t sa_size;
+ int ret;
+ unsigned long nonblock = 1;
+
+ if (ev == NULL) {
+ ERR("null pointer\n");
+ return -1;
+ }
+
+ ev->sockno = socket(AF_INET, SOCK_DGRAM, 0);
+ if ( ev->sockno == -1 ) {
+ ERR("socket() failed\n");
+ return -1;
+ }
+
+#ifdef _WIN32
+ ioctlsocket(ev->sockno, FIONBIO, &nonblock );
+#else
+ ioctl(ev->sockno, FIONBIO, &nonblock);
+#endif // _WIN32
+
+ nonblock = 1 ;
+ setsockopt( ev->sockno, SOL_SOCKET, SO_REUSEADDR, (char *)&nonblock, sizeof(nonblock) ) ;
+
+ memset(&sa, '\0', sizeof(sa));
+ ((struct sockaddr_in *) &sa)->sin_family = AF_INET;
+ memcpy(&((struct sockaddr_in *) &sa)->sin_addr, "\177\000\000\001", 4); // 127.0.0.1
+ ((struct sockaddr_in *) &sa)->sin_port = htons(ev->portno);
+ sa_size = sizeof(struct sockaddr_in);
+
+ ret = bind(ev->sockno, &sa, sa_size);
+ if (ret) {
+ ERR("bind() failed\n");
+#ifdef _WIN32
+ closesocket(ev->sockno);
+#else
+ close(ev->sockno);
+#endif
+ ev->sockno = -1;
+ ev->status = 0;
+ return ret;
+ }
+
+ if (ev->portno == 0) {
+ memset(&sa, '\0', sizeof(sa));
+ getsockname(ev->sockno, (struct sockaddr *) &sa, &sa_size);
+ ev->portno = ntohs(((struct sockaddr_in *) &sa)->sin_port);
+ }
+
+ ret = connect(ev->sockno, (struct sockaddr *) &sa, sa_size);
+ if (ret) {
+ ERR("connect() failed\n");
+#ifdef _WIN32
+ closesocket(ev->sockno);
+#else
+ close(ev->sockno);
+#endif
+ ev->sockno = -1;
+ ev->status = 0;
+ return ret;
+ }
+
+ ev->status = MLOOP_EVSOCK_CONNECTED;
+ return 0;
+}
+
+static void mloop_evsock_remove(struct mloop_evsock *ev)
+{
+ if (!ev) {
+ return ;
+ }
+
+ if (ev->sockno > 0) {
+#ifdef _WIN32
+ shutdown(ev->sockno, SD_BOTH);
+ closesocket(ev->sockno);
+#else
+ shutdown(ev->sockno, SHUT_RDWR);
+ close(ev->sockno);
+#endif
+ ev->sockno = -1;
+ ev->status = 0;
+ }
+}
+
+static int mloop_evsock_send(struct mloop_evsock *ev, struct mloop_evpack *p)
+{
+ int ret;
+
+ if (ev == NULL || ev->sockno == -1) {
+ ERR("invalid mloop_evsock\n");
+ return -1;
+ }
+
+ if (p == NULL || p->size <= 0) {
+ ERR("invalid mloop_evpack\n");
+ return -1;
+ }
+
+ do {
+ ret = send(ev->sockno, p, p->size, 0);
+#ifdef _WIN32
+ } while (ret == -1 && (WSAGetLastError() == WSAEWOULDBLOCK));
+#else
+ } while (ret == -1 && (errno == EWOULDBLOCK || errno == EINTR));
+#endif // _WIN32
+
+ return ret;
+}
+
+static USBDevice *usbkbd = NULL;
+static USBDevice *usbdisk = NULL;
+#ifdef TARGET_I386
+static PCIDevice *hostkbd = NULL;
+static PCIDevice *virtio_sdcard = NULL;
+#endif
+
+static void mloop_evhandle_usb_add(char *name)
+{
+ if (name == NULL) {
+ ERR("Packet data for usb device is NULL\n");
+ return;
+ }
+
+ if (strcmp(name, "keyboard") == 0) {
+ if (usbkbd == NULL) {
+ usbkbd = usbdevice_create(name);
+ } else if (usbkbd->attached == 0) {
+ usb_device_attach(usbkbd);
+ }
+ } else if (strncmp(name, "disk:", 5) == 0) {
+ if (usbdisk == NULL) {
+ usbdisk = usbdevice_create(name);
+ }
+ } else {
+ WARN("There is no usb-device for %s.\n", name);
+ }
+}
+
+static void mloop_evhandle_usb_del(char *name)
+{
+ if (name == NULL) {
+ ERR("Packet data for usb device is NULL\n");
+ return;
+ }
+
+ if (strcmp(name, "keyboard") == 0) {
+ if (usbkbd && usbkbd->attached != 0) {
+ usb_device_detach(usbkbd);
+ }
+ } else if (strncmp(name, "disk:", 5) == 0) {
+ if (usbdisk) {
++// qdev_free(&usbdisk->qdev);
+ }
+ } else {
+ WARN("There is no usb-device for %s.\n", name);
+ }
+}
+
+static void mloop_evhandle_intr_up(long data)
+{
+ if (data == 0) {
+ return;
+ }
+
+ qemu_irq_raise((qemu_irq)data);
+}
+
+static void mloop_evhandle_intr_down(long data)
+{
+ if (data == 0) {
+ return;
+ }
+
+ qemu_irq_lower((qemu_irq)data);
+}
+
+static void mloop_evhandle_touch(struct mloop_evpack* pack)
+{
+ maru_virtio_touchscreen_notify();
+}
+
+static void mloop_evhandle_keyboard(long data)
+{
+ virtio_keyboard_notify((void*)data);
+}
+
+#ifdef TARGET_I386
+static void mloop_evhandle_kbd_add(char *name)
+{
+ QDict *qdict;
+
+ TRACE("try to add a keyboard device.\n");
+
+ if (name == NULL) {
+ ERR("packet data is NULL.\n");
+ return;
+ }
+
+ if (hostkbd) {
+ INFO("virtio-keyboard has already been added.\n");
+ return;
+ }
+
+ qdict = qdict_new();
+ qdict_put(qdict, "pci_addr", qstring_from_str("auto"));
+ qdict_put(qdict, "type", qstring_from_str(name));
+
+ hostkbd = do_pci_device_hot_add(cur_mon, qdict);
+ if (hostkbd) {
+ TRACE("virtio-keyboard device: root_bus_path %s, bus %d, slot %d, function %d\n",
+ pci_root_bus_path(hostkbd), pci_bus_num(hostkbd->bus),
+ PCI_SLOT(hostkbd->devfn), PCI_FUNC(hostkbd->devfn));
+ } else {
+ ERR("failed to hot_add keyboard device.\n");
+ }
+
+ QDECREF(qdict);
+}
+
+static void mloop_evhandle_kbd_del(void)
+{
+ QDict *qdict;
+ int slot = 0;
+ char slotbuf[4] = {0,};
+
+ TRACE("try to remove a keyboard device.\n");
+
+ if (!hostkbd) {
+ ERR("Failed to remove a keyboard device "
+ "because the device has not been created yet.\n");
+ return;
+ }
+
+ slot = PCI_SLOT(hostkbd->devfn);
+ snprintf(slotbuf, sizeof(slotbuf), "%x", slot);
+ TRACE("virtio-keyboard slot %s.\n", slotbuf);
+
+ qdict = qdict_new();
+ qdict_put(qdict, "pci_addr", qstring_from_str(slotbuf));
+
+ do_pci_device_hot_remove(cur_mon, qdict);
+ INFO("hot_remove keyboard.\n");
+
+ hostkbd = NULL;
+
+ QDECREF(qdict);
+}
+
+static void mloop_evhandle_sdcard_attach(char *name)
+{
+ char opts[PATH_MAX];
+
+ INFO("try to attach sdcard.\n");
+
+ if (name == NULL) {
+ ERR("Packet data is NULL.\n");
+ return;
+ }
+
+ if (virtio_sdcard) {
+ ERR("sdcard is already attached.\n");
+ return;
+ }
+
+ QDict *qdict = qdict_new();
+
+ qdict_put(qdict, "pci_addr", qstring_from_str("auto"));
+ qdict_put(qdict, "type", qstring_from_str("storage"));
+ snprintf(opts, sizeof(opts), "file=%s,if=virtio", name);
+ qdict_put(qdict, "opts", qstring_from_str(opts));
+
+ virtio_sdcard = do_pci_device_hot_add(cur_mon, qdict);
+ if (virtio_sdcard) {
+ INFO("hot add virtio storage device with [%s]\n", opts);
+ INFO("virtio-sdcard device: root_bus_path %s, bus %d, slot %d, function %d\n",
+ pci_root_bus_path(virtio_sdcard), pci_bus_num(virtio_sdcard->bus),
+ PCI_SLOT(virtio_sdcard->devfn), PCI_FUNC(virtio_sdcard->devfn));
+ } else {
+ ERR("failed to create a sdcard device.\n");
+ }
+
+ QDECREF(qdict);
+}
+
+static void mloop_evhandle_sdcard_detach(void)
+{
+ INFO("try to detach sdcard.\n");
+
+ if (!virtio_sdcard) {
+ ERR("sdcard is not attached yet.\n");
+ return;
+ }
+
+ QDict *qdict = qdict_new();
+ int slot = 0;
+ char slotbuf[4] = {0,};
+
+ slot = PCI_SLOT(virtio_sdcard->devfn);
+ snprintf(slotbuf, sizeof(slotbuf), "%x", slot);
+ INFO("virtio-sdcard slot [%d].\n", slot);
+ qdict_put(qdict, "pci_addr", qstring_from_str(slotbuf));
+
+ do_pci_device_hot_remove(cur_mon, qdict);
+
+ virtio_sdcard = NULL;
+
+ INFO("hot remove virtio storage device.\n");
+
+ QDECREF(qdict);
+}
+
+int mloop_evcmd_get_hostkbd_status(void)
+{
+ return hostkbd ? 1 : 0;
+}
+#endif
+
+static void mloop_evhandle_ramdump(struct mloop_evpack* pack)
+{
+#define MAX_PATH 256
+ INFO("dumping...\n");
+
+#if defined(CONFIG_LINUX) && !defined(TARGET_ARM) /* FIXME: Handle ARM ram as list */
+ MemoryRegion* mr = get_ram_memory();
+ size_t size = mr->size.lo;
+ char dump_fullpath[MAX_PATH];
+ char dump_filename[MAX_PATH];
+
+ char* dump_path = g_path_get_dirname(get_log_path());
+
+ sprintf(dump_filename, "0x%08x%s0x%08x%s", (unsigned int)mr->ram_addr, "-",
+ (unsigned int)(mr->ram_addr + size), "_RAM.dump");
+ sprintf(dump_fullpath, "%s/%s", dump_path, dump_filename);
+ free(dump_path);
+
+ FILE *dump_file = fopen(dump_fullpath, "w+");
+ if(!dump_file) {
+ fprintf(stderr, "Dump file create failed [%s]\n", dump_fullpath);
+
+ return;
+ }
+
+ size_t written;
+ written = fwrite(qemu_get_ram_ptr(mr->ram_addr), sizeof(char), size, dump_file);
+ fprintf(stdout, "Dump file written [%08x][%zu bytes]\n", (unsigned int)mr->ram_addr, written);
+ if(written != size) {
+ fprintf(stderr, "Dump file size error [%zu, %zu, %d]\n", written, size, errno);
+ }
+
+ fprintf(stdout, "Dump file create success [%s, %zu bytes]\n", dump_fullpath, size);
+
+ fclose(dump_file);
+#endif
+
+ /* notify to skin process */
+ notify_ramdump_completed();
+}
+
+static void mloop_evcb_recv(struct mloop_evsock *ev)
+{
+ struct mloop_evpack pack;
+ int ret;
+
+ do {
+ ret = recv(ev->sockno, (void *)&pack, sizeof(pack), 0);
+#ifdef _WIN32
+ } while (ret == -1 && WSAGetLastError() == WSAEINTR);
+#else
+ } while (ret == -1 && errno == EINTR);
+#endif // _WIN32
+
+ if (ret == -1) {
+ return;
+ }
+
+ if (ret == 0) {
+ return;
+ }
+
+ switch (pack.type) {
+ case MLOOP_EVTYPE_USB_ADD:
+ mloop_evhandle_usb_add(pack.data);
+ break;
+ case MLOOP_EVTYPE_USB_DEL:
+ mloop_evhandle_usb_del(pack.data);
+ break;
+ case MLOOP_EVTYPE_INTR_UP:
+ mloop_evhandle_intr_up(*(long*)&pack.data[0]);
+ break;
+ case MLOOP_EVTYPE_INTR_DOWN:
+ mloop_evhandle_intr_down(*(long*)&pack.data[0]);
+ break;
+ case MLOOP_EVTYPE_TOUCH:
+ mloop_evhandle_touch(&pack);
+ break;
+ case MLOOP_EVTYPE_KEYBOARD:
+ mloop_evhandle_keyboard(*(uint64_t*)&pack.data[0]);
+ break;
+#ifdef TARGET_I386
+ case MLOOP_EVTYPE_KBD_ADD:
+ mloop_evhandle_kbd_add(pack.data);
+ break;
+ case MLOOP_EVTYPE_KBD_DEL:
+ mloop_evhandle_kbd_del();
+ break;
+#endif
+ case MLOOP_EVTYPE_RAMDUMP:
+ mloop_evhandle_ramdump(&pack);
+ break;
+#ifdef TARGET_I386
+ case MLOOP_EVTYPE_SDCARD_ATTACH:
+ mloop_evhandle_sdcard_attach(pack.data);
+ break;
+ case MLOOP_EVTYPE_SDCARD_DETACH:
+ mloop_evhandle_sdcard_detach();
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void mloop_ev_init(void)
+{
+ int ret = mloop_evsock_create(&mloop);
+ if (ret == 0) {
+ qemu_set_fd_handler(mloop.sockno, (IOHandler *)mloop_evcb_recv, NULL, &mloop);
+ }
+}
+
+void mloop_ev_stop(void)
+{
+ qemu_set_fd_handler(mloop.sockno, NULL, NULL, NULL);
+ mloop_evsock_remove(&mloop);
+}
+
+void mloop_evcmd_raise_intr(void *irq)
+{
+ struct mloop_evpack pack;
+ memset((void*)&pack, 0, sizeof(struct mloop_evpack));
+ pack.type = MLOOP_EVTYPE_INTR_UP;
+ pack.size = 8;
+ *(long*)&pack.data[0] = (long)irq;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_lower_intr(void *irq)
+{
+ struct mloop_evpack pack;
+ memset((void*)&pack, 0, sizeof(struct mloop_evpack));
+ pack.type = MLOOP_EVTYPE_INTR_DOWN;
+ pack.size = 8;
+ *(long*)&pack.data[0] = (long)irq;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_usbkbd(int on)
+{
+ struct mloop_evpack pack = { MLOOP_EVTYPE_USB_ADD, 13, "keyboard" };
+ if (on == 0) {
+ pack.type = MLOOP_EVTYPE_USB_DEL;
+ }
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_hostkbd(int on)
+{
+ struct mloop_evpack pack
+ = {MLOOP_EVTYPE_KBD_ADD, 13, "keyboard"};
+ if (on == 0) {
+ pack.type = MLOOP_EVTYPE_KBD_DEL;
+ }
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_usbdisk(char *img)
+{
+ struct mloop_evpack pack;
+
+ if (img) {
+ if (strlen(img) > PACKET_LEN-5) {
+ ERR("The length of disk image path is greater than "
+ "lenth of maximum packet.\n");
+ return;
+ }
+
+ pack.type = MLOOP_EVTYPE_USB_ADD;
+ pack.size = 5 + sprintf(pack.data, "disk:%s", img);
+ } else {
+ pack.type = MLOOP_EVTYPE_USB_DEL;
+ pack.size = 5 + sprintf(pack.data, "disk:");
+ }
+
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_sdcard(char *img)
+{
+ struct mloop_evpack pack;
+
+ if (img) {
+ if (strlen(img) > PACKET_LEN-5) {
+ ERR("The length of disk image path is greater than "
+ "lenth of maximum packet.\n");
+ return;
+ }
+
+ pack.type = MLOOP_EVTYPE_SDCARD_ATTACH;
+ pack.size = 5 + sprintf(pack.data, "%s", img);
+ } else {
+ pack.type = MLOOP_EVTYPE_SDCARD_DETACH;
+ pack.size = 5;
+ }
+
+ mloop_evsock_send(&mloop, &pack);
+}
+
+int mloop_evcmd_get_usbkbd_status(void)
+{
+ return (usbkbd && usbkbd->attached ? 1 : 0);
+}
+
+void mloop_evcmd_set_usbkbd(void *dev)
+{
+ usbkbd = (USBDevice *)dev;
+}
+
+void mloop_evcmd_set_usbdisk(void *dev)
+{
+ usbdisk = (USBDevice *)dev;
+}
+
+void mloop_evcmd_touch(void)
+{
+ struct mloop_evpack pack;
+ memset(&pack, 0, sizeof(struct mloop_evpack));
+
+ pack.type = MLOOP_EVTYPE_TOUCH;
+ pack.size = 5;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_keyboard(void *data)
+{
+ struct mloop_evpack pack;
+ memset(&pack, 0, sizeof(struct mloop_evpack));
+
+ pack.type = MLOOP_EVTYPE_KEYBOARD;
+ pack.size = 4 + 8;
+ *((VirtIOKeyboard **)pack.data) = (VirtIOKeyboard *)data;
+ mloop_evsock_send(&mloop, &pack);
+}
+
+void mloop_evcmd_ramdump(void)
+{
+ struct mloop_evpack pack;
+ memset(&pack, 0, sizeof(struct mloop_evpack));
+
+ pack.type = MLOOP_EVTYPE_RAMDUMP;
+ pack.size = 5;
+ mloop_evsock_send(&mloop, &pack);
+}
qdev_machine_init();
+#ifdef CONFIG_MARU
+ // Returned variable points different address from input variable.
+ kernel_cmdline = prepare_maru_devices(kernel_cmdline);
+#endif
QEMUMachineInitArgs args = { .ram_size = ram_size,
- .boot_device = boot_order,
+ .boot_order = boot_order,
.kernel_filename = kernel_filename,
.kernel_cmdline = kernel_cmdline,
.initrd_filename = initrd_filename,