From: SeokYeon Hwang Date: Wed, 11 Dec 2013 01:38:35 +0000 (+0900) Subject: Merge branch 'upstream-1.7' into tizen_qemu_1.7 X-Git-Tag: Tizen_Studio_1.3_Release_p2.3.1~524^2~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1a81500c243dfe21a1c348d24b116b6315c66c83;p=sdk%2Femulator%2Fqemu.git Merge branch 'upstream-1.7' into tizen_qemu_1.7 Signed-off-by: SeokYeon Hwang Conflicts: VERSION block/cow.c block/raw-win32.c block/stream.c block/vmdk.c blockdev.c exec.c hw/i386/pc_piix.c hw/scsi/scsi-bus.c include/qom/cpu.h include/sysemu/kvm.h qemu-img.c tcg/tcg.c tcg/tcg.h vl.c Change-Id: Ib8de93ad2c05150934e17e63d7f8e90ffdfccc62 --- 1a81500c243dfe21a1c348d24b116b6315c66c83 diff --cc .gitignore index 81f5f090b3,5584b5fcb0..ab07cfa003 --- a/.gitignore +++ b/.gitignore @@@ -1,3 -1,3 +1,4 @@@ ++config.status config-devices.* config-all-devices.* config-all-disas.* diff --cc Makefile.target index 1bdc34f1a0,af6ac7eaa1..3fa46ab691 --- a/Makefile.target +++ b/Makefile.target @@@ -125,18 -121,8 +121,18 @@@ LIBS+=$(libs_softmmu # 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/ diff --cc block.c index 8ce8b91f00,382ea71f4b..fa8ff23e6e --- a/block.c +++ b/block.c @@@ -1605,9 -1715,10 +1715,12 @@@ static void bdrv_delete(BlockDriverStat 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); diff --cc block/raw-win32.c index 9686afe702,2bad5a39b4..1008cdbe74 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@@ -239,9 -235,12 +240,10 @@@ static QemuOptsList raw_runtime_opts = }, }; - 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; @@@ -575,16 -538,13 +582,18 @@@ static int hdev_probe_device(const cha 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; @@@ -632,43 -591,11 +641,44 @@@ 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); diff --cc blockdev.c index 51f727c598,44755e1a5d..9a4a8fbde2 --- a/blockdev.c +++ b/blockdev.c @@@ -281,27 -288,11 +288,16 @@@ static int parse_block_error_action(con } } +#ifdef CONFIG_MARU +extern int start_simple_client(char* msg); +extern char* maru_convert_path(char* msg, const char *path); +#endif + - static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp) + 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; } @@@ -691,45 -509,15 +514,25 @@@ static DriveInfo *blockdev_init(QDict * 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) { +#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 + - 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)); - } + error_setg(errp, "could not open disk image %s: %s", + file ?: dinfo->id, error_get_pretty(error)); + error_free(error); goto err; } diff --cc configure index d78e2e159d,066622865f..bb41d08129 --- a/configure +++ b/configure @@@ -230,14 -242,12 +243,17 @@@ rbd=" 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="" @@@ -562,14 -579,9 +591,13 @@@ Haiku 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 @@@ -1232,11 -1225,9 +1291,13 @@@ echo " --gcov=GCOV use sp 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 @@@ -3690,14 -3775,10 +3847,15 @@@ echo "xfsctl support $xfs 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" @@@ -3709,12 -3790,8 +3867,13 @@@ echo "TPM support $tpm 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 @@@ -4138,36 -4183,17 +4294,27 @@@ if test "$virtio_blk_data_plane" = "yes 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 diff --cc default-configs/arm-softmmu.mak index b27f5bdb41,a555eefed5..ba47b39a90 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@@ -80,5 -79,5 +80,6 @@@ CONFIG_ZYNQ= CONFIG_VERSATILE_PCI=y CONFIG_VERSATILE_I2C=y +CONFIG_SOUND=y CONFIG_SDHCI=y + CONFIG_INTEGRATOR_DEBUG=y diff --cc exec.c index f78239f1dc,95c4356c65..0e0fa0691a --- a/exec.c +++ b/exec.c @@@ -1123,41 -1114,32 +1115,47 @@@ ram_addr_t qemu_ram_alloc_from_ptr(ram_ 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); } diff --cc hw/acpi/piix4.c index 13dcd20c5a,93849c8d36..2a7f49885c --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@@ -29,11 -29,8 +29,12 @@@ #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 diff --cc hw/arm/Makefile.objs index ad97a15f6b,3671b42738..41d4a3a847 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@@ -1,34 -1,6 +1,34 @@@ +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 diff --cc hw/i386/pc.c index 13bbde3dbc,12c436e7f1..dc2e129142 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@@ -56,10 -56,8 +56,11 @@@ #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 diff --cc hw/i386/pc_piix.c index a0f6115e82,2111f0192c..ef5cab79e0 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@@ -52,6 -53,6 +53,13 @@@ #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 }; @@@ -129,19 -128,20 +135,32 @@@ static void pc_init1(QEMUMachineInitArg 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); } @@@ -228,64 -228,74 +247,78 @@@ 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 */ diff --cc hw/vigs/vigs_device.c index ef8e2d4cfc,0000000000..6cc986d356 mode 100644,000000..100644 --- a/hw/vigs/vigs_device.c +++ b/hw/vigs/vigs_device.c @@@ -1,372 -1,0 +1,372 @@@ +/* + * vigs + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Stanislav Vorobiov + * Jinhyung Jo + * YeongKyoon Lee + * + * 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_lower(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_raise(s->dev.pci_dev.irq[0]); ++ pci_set_irq(&s->dev.pci_dev, 1); + } else { - qemu_irq_lower(s->dev.pci_dev.irq[0]); ++ 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) diff --cc hw/virtio/virtio-pci.c index d6ab60b62a,7647be8a3c..cf6ac0b8e0 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@@ -1501,347 -1502,10 +1502,348 @@@ static const TypeInfo virtio_rng_pci_in .class_init = virtio_rng_pci_class_init, }; +#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_GL); ++ 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_TOUCHSCREEN); ++ 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_KEYBOARD); ++ 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_ESM); ++ 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_HWKEY); ++ 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_EVDI); ++ 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_SENSOR); ++ 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(OBJECT(&dev->vdev), TYPE_VIRTIO_NFC); ++ 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; diff --cc include/exec/cpu-defs.h index a4a527b2a0,01cd8c7a2b..e51e744eb1 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@@ -176,13 -176,7 +176,11 @@@ typedef struct CPUWatchpoint 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 diff --cc include/sysemu/kvm.h index c638866cad,3b25f27a7c..ee783f74c0 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@@ -296,13 -282,19 +282,23 @@@ int kvm_physical_memory_addr_from_host( #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()) { diff --cc tizen/src/ecs/ecs.c index 7bbd271be8,0000000000..67e921d76b mode 100644,000000..100644 --- a/tizen/src/ecs/ecs.c +++ b/tizen/src/ecs/ecs.c @@@ -1,995 -1,0 +1,995 @@@ +/* + * Emulator Control Server + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Jinhyung choi + * MunKyu Im + * Daiyoung Kim + * YeongKyoon Lee + * + * 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 +#include +#include + +#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_del_timer(cs->alive_timer); ++ 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; + } + - qemu_mod_timer(current_ecs->alive_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * TIMER_ALIVE_S); ++ 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(); + - cs->alive_timer = qemu_new_timer_ns(vm_clock, alive_checker, cs); ++ cs->alive_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, alive_checker, cs); + - qemu_mod_timer(cs->alive_timer, - qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * TIMER_ALIVE_S); ++ 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; +} diff --cc tizen/src/hw/maru_board.c index e06ebbb407,0000000000..d0f851844f mode 100644,000000..100644 --- a/tizen/src/hw/maru_board.c +++ b/tizen/src/hw/maru_board.c @@@ -1,359 -1,0 +1,164 @@@ +/* + * TIZEN base board + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * YeongKyoon Lee + * SeokYeon Hwang + * SangJin Kim + * KiTae Kim + * JinHyung Jo + * SungMin Ha + * MunKyu Im + * JiHye Kim + * GiWoong Kim + * 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 + +#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 +#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 +#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 bool has_pvpanic = true; +static bool has_pci_info = true; + +MemoryRegion *global_ram_memory; + +MemoryRegion *get_ram_memory(void) +{ + return global_ram_memory; +} + - 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) ++/* maru specialized device init */ ++static void maru_device_init(void) +{ - 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; ++ PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL); + - #if defined(__linux__) ++#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; + - 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); - } ++ 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) +{ - has_pci_info = false; ++ pc_init_pci(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); ++ 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, - .max_cpus = 255, - DEFAULT_MACHINE_OPTIONS, +}; + +static void maru_machine_init(void) +{ + qemu_register_machine(&maru_x86_machine); +} + +machine_init(maru_machine_init); diff --cc tizen/src/hw/maru_brill_codec.c index fad948f645,0000000000..702fefa84a mode 100644,000000..100644 --- a/tizen/src/hw/maru_brill_codec.c +++ b/tizen/src/hw/maru_brill_codec.c @@@ -1,1802 -1,0 +1,1802 @@@ +/* + * Virtual Codec Device + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Kitae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * 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_raise(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; - qemu_irq_lower(s->dev.irq[0]); ++ 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; +} diff --cc tizen/src/hw/maru_brill_codec.h index 840f4dad55,0000000000..dd6c4fa8e1 mode 100644,000000..100644 --- a/tizen/src/hw/maru_brill_codec.h +++ b/tizen/src/hw/maru_brill_codec.h @@@ -1,157 -1,0 +1,158 @@@ +/* + * Virtual Codec device + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Kitae Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * 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 +#include + +#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); diff --cc tizen/src/hw/maru_camera_common_pci.c index 23f7e667e9,0000000000..7e32e83d8c mode 100644,000000..100644 --- a/tizen/src/hw/maru_camera_common_pci.c +++ b/tizen/src/hw/maru_camera_common_pci.c @@@ -1,288 -1,0 +1,289 @@@ +/* + * Common implementation of MARU Virtual Camera device by PCI bus. + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * JinHyung Jo + * YeongKyoon Lee + * + * 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 +#include +#include +#include +#include +#include + +#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_lower(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) { - qemu_irq_raise(state->dev.irq[2]); ++ 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) diff --cc tizen/src/hw/maru_vga.c index db547c6513,0000000000..e8ea00cf83 mode 100644,000000..100644 --- a/tizen/src/hw/maru_vga.c +++ b/tizen/src/hw/maru_vga.c @@@ -1,1461 -1,0 +1,1461 @@@ +/* + * Maru vga device + * Based on qemu/hw/vga.c + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * JinHyung Jo + * GiWoong Kim + * YeongKyoon Lee + * 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 + +#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; + - cur_tick = qemu_get_clock_ns(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; - int64_t now = 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_get_clock_ms(vm_clock); ++ 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__); +} diff --cc tizen/src/hw/maru_vga_template.h index 126036eba3,0000000000..8772b9e57b mode 100644,000000..100644 --- a/tizen/src/hw/maru_vga_template.h +++ b/tizen/src/hw/maru_vga_template.h @@@ -1,465 -1,0 +1,465 @@@ +/* + * vga device + * Based on qemu/hw/vga_template.h + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * GiWoong Kim + * YeongKyoon Lee + * 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, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol); ++ 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)+1, v); ++ 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)+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)+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; - cpu_to_32wu(((uint32_t *)d)+3, v); ++ 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 diff --cc tizen/src/maru_sdl.c index 5b37ebfc2f,0000000000..b3f1cff21b mode 100644,000000..100644 --- a/tizen/src/maru_sdl.c +++ b/tizen/src/maru_sdl.c @@@ -1,892 -1,0 +1,893 @@@ +/* + * SDL_WINDOWID hack + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Jo + * GiWoong Kim + * SeokYeon Hwang + * YeongKyoon Lee + * + * 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 +#include +#include +#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); +} diff --cc tizen/src/mloop_event.c index 88797e28e9,0000000000..b51436cb81 mode 100644,000000..100644 --- a/tizen/src/mloop_event.c +++ b/tizen/src/mloop_event.c @@@ -1,659 -1,0 +1,659 @@@ +/* + * mainloop_evhandle.c + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Kitae Kim + * GiWoong Kim + * 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 +#define socklen_t int +#else +#include +#include +#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); ++// 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); +} diff --cc vl.c index f3aa79734d,8d5d874e68..7162d514fb --- a/vl.c +++ b/vl.c @@@ -4515,12 -4237,8 +4445,12 @@@ int main(int argc, char **argv, char ** 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,