Source files under "tizen/src/hw/" moved into each parent bus directory.
Change-Id: I32d4cd527583a5cacf43cb4e2bc490212b849ee4
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
# maru skin
obj-y += skin/
-# sdb noti server
-obj-y += sdb_noti_server.o
-
# debug channel
obj-y += debug_ch.o
#include <SDL.h>
#include "maru_finger.h"
#include "emul_state.h"
-#include "hw/maru_virtio_touchscreen.h"
+#include "hw/virtio/maru_virtio_touchscreen.h"
#include "debug_ch.h"
MULTI_DEBUG_CHANNEL(qemu, maru_finger);
#include "maru_display.h"
#include "maru_sdl.h"
#include "maru_sdl_processing.h"
-#include "hw/maru_brightness.h"
+#include "hw/pci/maru_brightness.h"
#include "debug_ch.h"
MULTI_DEBUG_CHANNEL(tizen, maru_sdl);
#include "maru_sdl_processing.h"
-#include "hw/maru_brightness.h"
+#include "hw/pci/maru_brightness.h"
#include "debug_ch.h"
MULTI_DEBUG_CHANNEL(tizen, sdl_processing);
#include "qapi/qmp/json-parser.h"
#include "ecs.h"
-#include "hw/maru_virtio_evdi.h"
-#include "hw/maru_virtio_sensor.h"
-#include "hw/maru_virtio_nfc.h"
+#include "hw/virtio/maru_virtio_evdi.h"
+#include "hw/virtio/maru_virtio_sensor.h"
+#include "hw/virtio/maru_virtio_nfc.h"
#include "debug_ch.h"
MULTI_DEBUG_CHANNEL(qemu, ecs);
#include "display/maru_finger.h"
#endif
-#include "hw/maru_virtio_evdi.h"
-#include "hw/maru_virtio_sensor.h"
-#include "hw/maru_virtio_jack.h"
-#include "hw/maru_virtio_power.h"
-#include "hw/maru_virtio_nfc.h"
-#include "hw/maru_virtio_vmodem.h"
+#include "hw/virtio/maru_virtio_evdi.h"
+#include "hw/virtio/maru_virtio_sensor.h"
+#include "hw/virtio/maru_virtio_jack.h"
+#include "hw/virtio/maru_virtio_power.h"
+#include "hw/virtio/maru_virtio_nfc.h"
+#include "hw/virtio/maru_virtio_vmodem.h"
#include "skin/maruskin_operation.h"
#include "skin/maruskin_server.h"
#include "util/maru_device_hotplug.h"
//#include "qemu-timer.h"
#include "ecs.h"
-#include "hw/maru_virtio_sensor.h"
-#include "hw/maru_virtio_power.h"
-#include "hw/maru_virtio_jack.h"
+#include "hw/virtio/maru_virtio_sensor.h"
+#include "hw/virtio/maru_virtio_power.h"
+#include "hw/virtio/maru_virtio_jack.h"
#define TEMP_BUF_SIZE 255
#define MAX_VAL_LENGTH 40
#include "ecs.h"
#include "ecs_tethering.h"
#include "tethering/app_tethering.h"
-#include "hw/maru_virtio_touchscreen.h"
+#include "hw/virtio/maru_virtio_touchscreen.h"
#include "debug_ch.h"
MULTI_DEBUG_CHANNEL(tizen, ecs_tethering);
#include "build_info.h"
#include "emulator.h"
#include "emul_state.h"
-#include "sdb_noti_server.h"
#include "emulator_options.h"
+#include "util/sdb_noti_server.h"
#include "util/check_gl.h"
#include "maru_err_table.h"
#include "util/osutil.h"
#include "emulator.h"
#include "emul_state.h"
#include "guest_debug.h"
-#include "hw/maru_virtio_touchscreen.h"
+#include "hw/virtio/maru_virtio_touchscreen.h"
#include "util/check_gl.h"
#include "maru_err_table.h"
#include "display/maru_display.h"
obj-y += maru_board.o maru_pm.o
-obj-y += maru_brill_codec.o
-obj-y += maru_brightness.o
+obj-y += pci/
+obj-y += virtio/
-obj-y += maru_virtio_pci.o
-obj-y += maru_virtio_touchscreen.o
-obj-y += maru_virtio_esm.o
-obj-y += maru_virtio_evdi.o
-obj-y += maru_virtio_hwkey.o
-obj-y += maru_virtio_jack.o
-obj-y += maru_virtio_keyboard.o
-obj-y += maru_virtio_nfc.o
-obj-y += maru_virtio_power.o
-obj-y += maru_virtio_sensor.o
-obj-y += maru_virtio_vmodem.o
-
-obj-y += maru_camera_common_pci.o
-ifdef CONFIG_LINUX
-obj-y += maru_camera_linux_pci.o
-LIBS += -lv4l2 -lv4lconvert
-endif
-ifdef CONFIG_WIN32
-obj-y += maru_camera_win32_pci.o
-LIBS += -lole32 -loleaut32 -luuid -lstrmiids
-endif
-ifdef CONFIG_DARWIN
-obj-y += maru_camera_darwin_converter.o
-obj-y += maru_camera_darwin_pci.o
-LIBS += -framework Foundation -framework SystemConfiguration
-LIBS += -framework Cocoa -framework QTKit -framework CoreVideo
-LIBS += -framework AppKit
-endif
-
-#obj-y += maru_codec.o
-#obj-y += maru_usb_touchscreen.o
+#obj-y += usb/
+#obj-y += arm/
+++ /dev/null
-obj-y += maru_arm_soc.o
-
-ifndef CONFIG_DARWIN
-obj-y += maru_arm_board.o
-endif
-
-obj-y += maru_arm_vpci.o
-obj-y += maru_arm_pmu.o
--- /dev/null
+obj-y += maru_arm_soc.o
+
+ifndef CONFIG_DARWIN
+obj-y += maru_arm_board.o
+endif
+
+obj-y += maru_arm_vpci.o
+obj-y += maru_arm_pmu.o
--- /dev/null
+/*
+ * Samsung Maru ARM SoC emulation
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MARU_ARM_H_
+#define MARU_ARM_H_
+
+#include "qemu-common.h"
+#include "memory.h"
+#include "exynos4210.h"
+
+void maru_arm_write_secondary(ARMCPU *cpu,
+ const struct arm_boot_info *info);
+
+Exynos4210State *maru_arm_soc_init(MemoryRegion *system_mem,
+ unsigned long ram_size);
+
+int codec_init(PCIBus *bus);
+int maru_camera_pci_init(PCIBus *bus);
+
+#endif /* MARU_ARM_H_ */
--- /dev/null
+/*
+ * TIZEN ARM base board
+ *
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * Based on maru_board.c, exynos4210.c and exynos4210_boards.c
+ *
+ * Author:
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License; 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include "boards.h"
+#include "arm-misc.h"
+#include "sysbus.h"
+#include "pci.h"
+#include "maru_arm.h"
+#include "i2c.h"
+#include "exec-memory.h"
+#include "hw/maru_brightness.h"
+#include "arch_init.h"
+
+#include "xen.h"
+#ifdef CONFIG_XEN
+# include <xen/hvm/hvm_info_table.h>
+#endif
+#include "maru_common.h"
+#if defined(__linux__)
+#include <X11/Xlib.h>
+#endif
+#include "vigs_device.h"
+extern int enable_yagl;
+extern const char *yagl_backend;
+extern int enable_vigs;
+extern const char *vigs_backend;
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+ #undef PRINT_DEBUG
+ #define PRINT_DEBUG(fmt, args...) \
+ do { \
+ fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
+ } while (0)
+#else
+ #define PRINT_DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifndef DEBUG_LOG_PATH
+#define DEBUG_LOG_PATH "./debug.log"
+#endif
+
+#define EXYNOS4210_WM8994_ADDR 0x1A
+#define MARU_ARM_BOARD_ID 0xF3B
+#define MARU_ARM_BOARD_SMP_BOOTREG_ADDR EXYNOS4210_SECOND_CPU_BOOTREG
+#define MARU_ARM_BOARD_RAMSIZE_MIN 0x20000000
+#define MARU_ARM_BOARD_RAMSIZE_DEFAULT 0x40000000
+
+static struct arm_boot_info maru_arm_board_binfo = {
+ .loader_start = EXYNOS4210_BASE_BOOT_ADDR,
+ .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
+ .nb_cpus = EXYNOS4210_NCPUS,
+ .write_secondary_boot = maru_arm_write_secondary,
+};
+
+static void maru_arm_machine_init(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)
+{
+ Exynos4210State *s;
+ DeviceState *dev;
+ PCIBus *pci_bus;
+#if defined(__linux__)
+ Display *display = XOpenDisplay(0);
+ if (!display) {
+ fprintf(stderr, "Cannot open X display\n");
+ exit(1);
+ }
+#else
+ void *display = NULL;
+#endif
+ struct winsys_interface *vigs_wsi = NULL;
+
+ /*
+ * W/A for allocate larger continuous heap. From maru_board.c
+ */
+ if (!xen_enabled()) {
+ if(preallocated_ptr != NULL) {
+ qemu_vfree(preallocated_ptr);
+ }
+ }
+
+ if (ram_size < MARU_ARM_BOARD_RAMSIZE_MIN) {
+ ram_size = MARU_ARM_BOARD_RAMSIZE_DEFAULT;
+ fprintf(stderr, "RAM size is too small, setting to default value 0x%lx",
+ (long unsigned int)ram_size);
+ }
+
+ maru_arm_board_binfo.ram_size = ram_size;
+ maru_arm_board_binfo.board_id = MARU_ARM_BOARD_ID;
+ maru_arm_board_binfo.smp_bootreg_addr = MARU_ARM_BOARD_SMP_BOOTREG_ADDR;
+ maru_arm_board_binfo.kernel_filename = kernel_filename;
+ maru_arm_board_binfo.initrd_filename = initrd_filename;
+ maru_arm_board_binfo.kernel_cmdline = kernel_cmdline;
+ maru_arm_board_binfo.gic_cpu_if_addr =
+ EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
+
+ PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
+ " kernel_filename: %s\n"
+ " kernel_cmdline: %s\n"
+ " initrd_filename: %s\n",
+ (long unsigned int)ram_size / 1048576,
+ (long unsigned int)ram_size,
+ kernel_filename,
+ kernel_cmdline,
+ initrd_filename);
+ s = maru_arm_soc_init(get_system_memory(), ram_size);
+
+ /* PCI config */
+ dev = qdev_create(NULL, "tizen_vpci");
+ s->vpci_bus = sysbus_from_qdev(dev);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(s->vpci_bus, 0, EXYNOS4210_VPCI_CFG_BASE_ADDR);
+ sysbus_connect_irq(s->vpci_bus, 0, s->irq_table[exynos4210_get_irq(38, 0)]);
+ sysbus_connect_irq(s->vpci_bus, 1, s->irq_table[exynos4210_get_irq(38, 1)]);
+ sysbus_connect_irq(s->vpci_bus, 2, s->irq_table[exynos4210_get_irq(38, 2)]);
+ sysbus_connect_irq(s->vpci_bus, 3, s->irq_table[exynos4210_get_irq(38, 3)]);
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+
+ pci_create_simple(pci_bus, -1, "pci-ohci");
+ maru_camera_pci_init(pci_bus);
+ maru_brill_codec_pci_device_init(pci_bus);
+ pci_maru_brightness_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);
+ }
+
+ audio_init(NULL, pci_bus);
+
+ arm_load_kernel(arm_env_get_cpu(first_cpu), &maru_arm_board_binfo);
+}
+
+static QEMUMachine maru_arm_machine = {
+ .name = "maru-arm-machine",
+ .desc = "maru board(ARM)",
+ .init = maru_arm_machine_init,
+ .max_cpus = 255,
+};
+
+static void maru_machine_init(void)
+{
+ qemu_register_machine(&maru_arm_machine);
+}
+
+machine_init(maru_machine_init);
--- /dev/null
+/*
+ * Tizen Power Management Unit (PMU) Emulation
+ *
+ * Based on exynos4210_pmu.c
+ * Copyright (C) 2011 Samsung Electronics Co Ltd.
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This model implements PMU registers just as a bulk of memory.
+ * Able to shutdown and restart only.
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+#include "ptimer.h"
+
+#ifndef DEBUG_PMU
+#define DEBUG_PMU 0
+#endif
+
+#ifndef DEBUG_PMU_EXTEND
+#define DEBUG_PMU_EXTEND 0
+#endif
+
+#if DEBUG_PMU
+#define PRINT_DEBUG(fmt, args...) \
+ do { \
+ fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
+ } while (0)
+
+#if DEBUG_PMU_EXTEND
+#define PRINT_DEBUG_EXTEND(fmt, args...) \
+ do { \
+ fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0)
+#endif /* EXTEND */
+
+#else
+#define PRINT_DEBUG(fmt, args...) do {} while (0)
+#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0)
+#endif
+
+#define POWER_OFF_TIMER_FREQ 24000000
+
+/*
+ * Offsets for PMU registers
+ */
+#define OM_STAT 0x0000 /* OM status register */
+#define RTC_CLKO_SEL 0x000C /* Controls RTCCLKOUT */
+#define GNSS_RTC_OUT_CTRL 0x0010 /* Controls GNSS_RTC_OUT */
+/* Decides whether system-level low-power mode is used. */
+#define SYSTEM_POWER_DOWN_CTRL 0x0200
+/* Sets control options for CENTRAL_SEQ */
+#define SYSTEM_POWER_DOWN_OPTION 0x0208
+#define SWRESET 0x0400 /* Generate software reset */
+#define RST_STAT 0x0404 /* Reset status register */
+#define WAKEUP_STAT 0x0600 /* Wakeup status register */
+#define EINT_WAKEUP_MASK 0x0604 /* Configure External INTerrupt mask */
+#define WAKEUP_MASK 0x0608 /* Configure wakeup source mask */
+#define HDMI_PHY_CONTROL 0x0700 /* HDMI PHY control register */
+#define USBDEVICE_PHY_CONTROL 0x0704 /* USB Device PHY control register */
+#define USBHOST_PHY_CONTROL 0x0708 /* USB HOST PHY control register */
+#define DAC_PHY_CONTROL 0x070C /* DAC control register */
+#define MIPI_PHY0_CONTROL 0x0710 /* MIPI PHY control register */
+#define MIPI_PHY1_CONTROL 0x0714 /* MIPI PHY control register */
+#define ADC_PHY_CONTROL 0x0718 /* TS-ADC control register */
+#define PCIe_PHY_CONTROL 0x071C /* TS-PCIe control register */
+#define SATA_PHY_CONTROL 0x0720 /* TS-SATA control register */
+#define INFORM0 0x0800 /* Information register 0 */
+#define INFORM1 0x0804 /* Information register 1 */
+#define INFORM2 0x0808 /* Information register 2 */
+#define INFORM3 0x080C /* Information register 3 */
+#define INFORM4 0x0810 /* Information register 4 */
+#define INFORM5 0x0814 /* Information register 5 */
+#define INFORM6 0x0818 /* Information register 6 */
+#define INFORM7 0x081C /* Information register 7 */
+#define PMU_DEBUG 0x0A00 /* PMU debug register */
+/* Registers to set system-level low-power option */
+#define ARM_CORE0_SYS_PWR_REG 0x1000
+#define ARM_CORE1_SYS_PWR_REG 0x1010
+#define ARM_COMMON_SYS_PWR_REG 0x1080
+#define ARM_CPU_L2_0_SYS_PWR_REG 0x10C0
+#define ARM_CPU_L2_1_SYS_PWR_REG 0x10C4
+#define CMU_ACLKSTOP_SYS_PWR_REG 0x1100
+#define CMU_SCLKSTOP_SYS_PWR_REG 0x1104
+#define CMU_RESET_SYS_PWR_REG 0x110C
+#define APLL_SYSCLK_SYS_PWR_REG 0x1120
+#define MPLL_SYSCLK_SYS_PWR_REG 0x1124
+#define VPLL_SYSCLK_SYS_PWR_REG 0x1128
+#define EPLL_SYSCLK_SYS_PWR_REG 0x112C
+#define CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG 0x1138
+#define CMU_RESET_GPS_ALIVE_SYS_PWR_REG 0x113C
+#define CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140
+#define CMU_CLKSTOP_TV_SYS_PWR_REG 0x1144
+#define CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148
+#define CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C
+#define CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150
+#define CMU_CLKSTOP_LCD1_SYS_PWR_REG 0x1154
+#define CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158
+#define CMU_CLKSTOP_GPS_SYS_PWR_REG 0x115C
+#define CMU_RESET_CAM_SYS_PWR_REG 0x1160
+#define CMU_RESET_TV_SYS_PWR_REG 0x1164
+#define CMU_RESET_MFC_SYS_PWR_REG 0x1168
+#define CMU_RESET_G3D_SYS_PWR_REG 0x116C
+#define CMU_RESET_LCD0_SYS_PWR_REG 0x1170
+#define CMU_RESET_LCD1_SYS_PWR_REG 0x1174
+#define CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178
+#define CMU_RESET_GPS_SYS_PWR_REG 0x117C
+#define TOP_BUS_SYS_PWR_REG 0x1180
+#define TOP_RETENTION_SYS_PWR_REG 0x1184
+#define TOP_PWR_SYS_PWR_REG 0x1188
+#define LOGIC_RESET_SYS_PWR_REG 0x11A0
+#define OneNANDXL_MEM_SYS_PWR_REG 0x11C0
+#define MODEMIF_MEM_SYS_PWR_REG 0x11C4
+#define USBDEVICE_MEM_SYS_PWR_REG 0x11CC
+#define SDMMC_MEM_SYS_PWR_REG 0x11D0
+#define CSSYS_MEM_SYS_PWR_REG 0x11D4
+#define SECSS_MEM_SYS_PWR_REG 0x11D8
+#define PCIe_MEM_SYS_PWR_REG 0x11E0
+#define SATA_MEM_SYS_PWR_REG 0x11E4
+#define PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200
+#define PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204
+#define PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220
+#define PAD_RETENTION_UART_SYS_PWR_REG 0x1224
+#define PAD_RETENTION_MMCA_SYS_PWR_REG 0x1228
+#define PAD_RETENTION_MMCB_SYS_PWR_REG 0x122C
+#define PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230
+#define PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234
+#define PAD_ISOLATION_SYS_PWR_REG 0x1240
+#define PAD_ALV_SEL_SYS_PWR_REG 0x1260
+#define XUSBXTI_SYS_PWR_REG 0x1280
+#define XXTI_SYS_PWR_REG 0x1284
+#define EXT_REGULATOR_SYS_PWR_REG 0x12C0
+#define GPIO_MODE_SYS_PWR_REG 0x1300
+#define GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340
+#define CAM_SYS_PWR_REG 0x1380
+#define TV_SYS_PWR_REG 0x1384
+#define MFC_SYS_PWR_REG 0x1388
+#define G3D_SYS_PWR_REG 0x138C
+#define LCD0_SYS_PWR_REG 0x1390
+#define LCD1_SYS_PWR_REG 0x1394
+#define MAUDIO_SYS_PWR_REG 0x1398
+#define GPS_SYS_PWR_REG 0x139C
+#define GPS_ALIVE_SYS_PWR_REG 0x13A0
+#define ARM_CORE0_CONFIGURATION 0x2000 /* Configure power mode of ARM_CORE0 */
+#define ARM_CORE0_STATUS 0x2004 /* Check power mode of ARM_CORE0 */
+#define ARM_CORE0_OPTION 0x2008 /* Sets control options for ARM_CORE0 */
+#define ARM_CORE1_CONFIGURATION 0x2080 /* Configure power mode of ARM_CORE1 */
+#define ARM_CORE1_STATUS 0x2084 /* Check power mode of ARM_CORE1 */
+#define ARM_CORE1_OPTION 0x2088 /* Sets control options for ARM_CORE0 */
+#define ARM_COMMON_OPTION 0x2408 /* Sets control options for ARM_COMMON */
+/* Configure power mode of ARM_CPU_L2_0 */
+#define ARM_CPU_L2_0_CONFIGURATION 0x2600
+#define ARM_CPU_L2_0_STATUS 0x2604 /* Check power mode of ARM_CPU_L2_0 */
+/* Configure power mode of ARM_CPU_L2_1 */
+#define ARM_CPU_L2_1_CONFIGURATION 0x2620
+#define ARM_CPU_L2_1_STATUS 0x2624 /* Check power mode of ARM_CPU_L2_1 */
+/* Sets control options for PAD_RETENTION_MAUDIO */
+#define PAD_RETENTION_MAUDIO_OPTION 0x3028
+/* Sets control options for PAD_RETENTION_GPIO */
+#define PAD_RETENTION_GPIO_OPTION 0x3108
+/* Sets control options for PAD_RETENTION_UART */
+#define PAD_RETENTION_UART_OPTION 0x3128
+/* Sets control options for PAD_RETENTION_MMCA */
+#define PAD_RETENTION_MMCA_OPTION 0x3148
+/* Sets control options for PAD_RETENTION_MMCB */
+#define PAD_RETENTION_MMCB_OPTION 0x3168
+/* Sets control options for PAD_RETENTION_EBIA */
+#define PAD_RETENTION_EBIA_OPTION 0x3188
+/* Sets control options for PAD_RETENTION_EBIB */
+#define PAD_RETENTION_EBIB_OPTION 0x31A8
+#define PS_HOLD_CONTROL 0x330C /* PS_HOLD control register */
+#define XUSBXTI_CONFIGURATION 0x3400 /* Configure the pad of XUSBXTI */
+#define XUSBXTI_STATUS 0x3404 /* Check the pad of XUSBXTI */
+/* Sets time required for XUSBXTI to be stabilized */
+#define XUSBXTI_DURATION 0x341C
+#define XXTI_CONFIGURATION 0x3420 /* Configure the pad of XXTI */
+#define XXTI_STATUS 0x3424 /* Check the pad of XXTI */
+/* Sets time required for XXTI to be stabilized */
+#define XXTI_DURATION 0x343C
+/* Sets time required for EXT_REGULATOR to be stabilized */
+#define EXT_REGULATOR_DURATION 0x361C
+#define CAM_CONFIGURATION 0x3C00 /* Configure power mode of CAM */
+#define CAM_STATUS 0x3C04 /* Check power mode of CAM */
+#define CAM_OPTION 0x3C08 /* Sets control options for CAM */
+#define TV_CONFIGURATION 0x3C20 /* Configure power mode of TV */
+#define TV_STATUS 0x3C24 /* Check power mode of TV */
+#define TV_OPTION 0x3C28 /* Sets control options for TV */
+#define MFC_CONFIGURATION 0x3C40 /* Configure power mode of MFC */
+#define MFC_STATUS 0x3C44 /* Check power mode of MFC */
+#define MFC_OPTION 0x3C48 /* Sets control options for MFC */
+#define G3D_CONFIGURATION 0x3C60 /* Configure power mode of G3D */
+#define G3D_STATUS 0x3C64 /* Check power mode of G3D */
+#define G3D_OPTION 0x3C68 /* Sets control options for G3D */
+#define LCD0_CONFIGURATION 0x3C80 /* Configure power mode of LCD0 */
+#define LCD0_STATUS 0x3C84 /* Check power mode of LCD0 */
+#define LCD0_OPTION 0x3C88 /* Sets control options for LCD0 */
+#define LCD1_CONFIGURATION 0x3CA0 /* Configure power mode of LCD1 */
+#define LCD1_STATUS 0x3CA4 /* Check power mode of LCD1 */
+#define LCD1_OPTION 0x3CA8 /* Sets control options for LCD1 */
+#define GPS_CONFIGURATION 0x3CE0 /* Configure power mode of GPS */
+#define GPS_STATUS 0x3CE4 /* Check power mode of GPS */
+#define GPS_OPTION 0x3CE8 /* Sets control options for GPS */
+#define GPS_ALIVE_CONFIGURATION 0x3D00 /* Configure power mode of GPS */
+#define GPS_ALIVE_STATUS 0x3D04 /* Check power mode of GPS */
+#define GPS_ALIVE_OPTION 0x3D08 /* Sets control options for GPS */
+
+#define EXYNOS4210_PMU_REGS_MEM_SIZE 0x3d0c
+
+typedef struct Exynos4210PmuReg {
+ const char *name; /* for debug only */
+ uint32_t offset;
+ uint32_t reset_value;
+} Exynos4210PmuReg;
+
+static const Exynos4210PmuReg exynos4210_pmu_regs[] = {
+ {"OM_STAT", OM_STAT, 0x00000000},
+ {"RTC_CLKO_SEL", RTC_CLKO_SEL, 0x00000000},
+ {"GNSS_RTC_OUT_CTRL", GNSS_RTC_OUT_CTRL, 0x00000001},
+ {"SYSTEM_POWER_DOWN_CTRL", SYSTEM_POWER_DOWN_CTRL, 0x00010000},
+ {"SYSTEM_POWER_DOWN_OPTION", SYSTEM_POWER_DOWN_OPTION, 0x03030000},
+ {"SWRESET", SWRESET, 0x00000000},
+ {"RST_STAT", RST_STAT, 0x00000000},
+ {"WAKEUP_STAT", WAKEUP_STAT, 0x00000000},
+ {"EINT_WAKEUP_MASK", EINT_WAKEUP_MASK, 0x00000000},
+ {"WAKEUP_MASK", WAKEUP_MASK, 0x00000000},
+ {"HDMI_PHY_CONTROL", HDMI_PHY_CONTROL, 0x00960000},
+ {"USBDEVICE_PHY_CONTROL", USBDEVICE_PHY_CONTROL, 0x00000000},
+ {"USBHOST_PHY_CONTROL", USBHOST_PHY_CONTROL, 0x00000000},
+ {"DAC_PHY_CONTROL", DAC_PHY_CONTROL, 0x00000000},
+ {"MIPI_PHY0_CONTROL", MIPI_PHY0_CONTROL, 0x00000000},
+ {"MIPI_PHY1_CONTROL", MIPI_PHY1_CONTROL, 0x00000000},
+ {"ADC_PHY_CONTROL", ADC_PHY_CONTROL, 0x00000001},
+ {"PCIe_PHY_CONTROL", PCIe_PHY_CONTROL, 0x00000000},
+ {"SATA_PHY_CONTROL", SATA_PHY_CONTROL, 0x00000000},
+ {"INFORM0", INFORM0, 0x00000000},
+ {"INFORM1", INFORM1, 0x00000000},
+ {"INFORM2", INFORM2, 0x00000000},
+ {"INFORM3", INFORM3, 0x00000000},
+ {"INFORM4", INFORM4, 0x00000000},
+ {"INFORM5", INFORM5, 0x00000000},
+ {"INFORM6", INFORM6, 0x00000000},
+ {"INFORM7", INFORM7, 0x00000000},
+ {"PMU_DEBUG", PMU_DEBUG, 0x00000000},
+ {"ARM_CORE0_SYS_PWR_REG", ARM_CORE0_SYS_PWR_REG, 0xFFFFFFFF},
+ {"ARM_CORE1_SYS_PWR_REG", ARM_CORE1_SYS_PWR_REG, 0xFFFFFFFF},
+ {"ARM_COMMON_SYS_PWR_REG", ARM_COMMON_SYS_PWR_REG, 0xFFFFFFFF},
+ {"ARM_CPU_L2_0_SYS_PWR_REG", ARM_CPU_L2_0_SYS_PWR_REG, 0xFFFFFFFF},
+ {"ARM_CPU_L2_1_SYS_PWR_REG", ARM_CPU_L2_1_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_ACLKSTOP_SYS_PWR_REG", CMU_ACLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_SCLKSTOP_SYS_PWR_REG", CMU_SCLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_SYS_PWR_REG", CMU_RESET_SYS_PWR_REG, 0xFFFFFFFF},
+ {"APLL_SYSCLK_SYS_PWR_REG", APLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+ {"MPLL_SYSCLK_SYS_PWR_REG", MPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+ {"VPLL_SYSCLK_SYS_PWR_REG", VPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+ {"EPLL_SYSCLK_SYS_PWR_REG", EPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG", CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"CMU_RESET_GPS_ALIVE_SYS_PWR_REG", CMU_RESET_GPS_ALIVE_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"CMU_CLKSTOP_CAM_SYS_PWR_REG", CMU_CLKSTOP_CAM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_TV_SYS_PWR_REG", CMU_CLKSTOP_TV_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_MFC_SYS_PWR_REG", CMU_CLKSTOP_MFC_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_G3D_SYS_PWR_REG", CMU_CLKSTOP_G3D_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_LCD0_SYS_PWR_REG", CMU_CLKSTOP_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_LCD1_SYS_PWR_REG", CMU_CLKSTOP_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_CLKSTOP_MAUDIO_SYS_PWR_REG", CMU_CLKSTOP_MAUDIO_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"CMU_CLKSTOP_GPS_SYS_PWR_REG", CMU_CLKSTOP_GPS_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_CAM_SYS_PWR_REG", CMU_RESET_CAM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_TV_SYS_PWR_REG", CMU_RESET_TV_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_MFC_SYS_PWR_REG", CMU_RESET_MFC_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_G3D_SYS_PWR_REG", CMU_RESET_G3D_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_LCD0_SYS_PWR_REG", CMU_RESET_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_LCD1_SYS_PWR_REG", CMU_RESET_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_MAUDIO_SYS_PWR_REG", CMU_RESET_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CMU_RESET_GPS_SYS_PWR_REG", CMU_RESET_GPS_SYS_PWR_REG, 0xFFFFFFFF},
+ {"TOP_BUS_SYS_PWR_REG", TOP_BUS_SYS_PWR_REG, 0xFFFFFFFF},
+ {"TOP_RETENTION_SYS_PWR_REG", TOP_RETENTION_SYS_PWR_REG, 0xFFFFFFFF},
+ {"TOP_PWR_SYS_PWR_REG", TOP_PWR_SYS_PWR_REG, 0xFFFFFFFF},
+ {"LOGIC_RESET_SYS_PWR_REG", LOGIC_RESET_SYS_PWR_REG, 0xFFFFFFFF},
+ {"OneNANDXL_MEM_SYS_PWR_REG", OneNANDXL_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"MODEMIF_MEM_SYS_PWR_REG", MODEMIF_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"USBDEVICE_MEM_SYS_PWR_REG", USBDEVICE_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"SDMMC_MEM_SYS_PWR_REG", SDMMC_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CSSYS_MEM_SYS_PWR_REG", CSSYS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"SECSS_MEM_SYS_PWR_REG", SECSS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"PCIe_MEM_SYS_PWR_REG", PCIe_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"SATA_MEM_SYS_PWR_REG", SATA_MEM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"PAD_RETENTION_DRAM_SYS_PWR_REG", PAD_RETENTION_DRAM_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_MAUDIO_SYS_PWR_REG", PAD_RETENTION_MAUDIO_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_GPIO_SYS_PWR_REG", PAD_RETENTION_GPIO_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_UART_SYS_PWR_REG", PAD_RETENTION_UART_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_MMCA_SYS_PWR_REG", PAD_RETENTION_MMCA_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_MMCB_SYS_PWR_REG", PAD_RETENTION_MMCB_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_EBIA_SYS_PWR_REG", PAD_RETENTION_EBIA_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_RETENTION_EBIB_SYS_PWR_REG", PAD_RETENTION_EBIB_SYS_PWR_REG,
+ 0xFFFFFFFF},
+ {"PAD_ISOLATION_SYS_PWR_REG", PAD_ISOLATION_SYS_PWR_REG, 0xFFFFFFFF},
+ {"PAD_ALV_SEL_SYS_PWR_REG", PAD_ALV_SEL_SYS_PWR_REG, 0xFFFFFFFF},
+ {"XUSBXTI_SYS_PWR_REG", XUSBXTI_SYS_PWR_REG, 0xFFFFFFFF},
+ {"XXTI_SYS_PWR_REG", XXTI_SYS_PWR_REG, 0xFFFFFFFF},
+ {"EXT_REGULATOR_SYS_PWR_REG", EXT_REGULATOR_SYS_PWR_REG, 0xFFFFFFFF},
+ {"GPIO_MODE_SYS_PWR_REG", GPIO_MODE_SYS_PWR_REG, 0xFFFFFFFF},
+ {"GPIO_MODE_MAUDIO_SYS_PWR_REG", GPIO_MODE_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
+ {"CAM_SYS_PWR_REG", CAM_SYS_PWR_REG, 0xFFFFFFFF},
+ {"TV_SYS_PWR_REG", TV_SYS_PWR_REG, 0xFFFFFFFF},
+ {"MFC_SYS_PWR_REG", MFC_SYS_PWR_REG, 0xFFFFFFFF},
+ {"G3D_SYS_PWR_REG", G3D_SYS_PWR_REG, 0xFFFFFFFF},
+ {"LCD0_SYS_PWR_REG", LCD0_SYS_PWR_REG, 0xFFFFFFFF},
+ {"LCD1_SYS_PWR_REG", LCD1_SYS_PWR_REG, 0xFFFFFFFF},
+ {"MAUDIO_SYS_PWR_REG", MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
+ {"GPS_SYS_PWR_REG", GPS_SYS_PWR_REG, 0xFFFFFFFF},
+ {"GPS_ALIVE_SYS_PWR_REG", GPS_ALIVE_SYS_PWR_REG, 0xFFFFFFFF},
+ {"ARM_CORE0_CONFIGURATION", ARM_CORE0_CONFIGURATION, 0x00000003},
+ {"ARM_CORE0_STATUS", ARM_CORE0_STATUS, 0x00030003},
+ {"ARM_CORE0_OPTION", ARM_CORE0_OPTION, 0x01010001},
+ {"ARM_CORE1_CONFIGURATION", ARM_CORE1_CONFIGURATION, 0x00000003},
+ {"ARM_CORE1_STATUS", ARM_CORE1_STATUS, 0x00030003},
+ {"ARM_CORE1_OPTION", ARM_CORE1_OPTION, 0x01010001},
+ {"ARM_COMMON_OPTION", ARM_COMMON_OPTION, 0x00000001},
+ {"ARM_CPU_L2_0_CONFIGURATION", ARM_CPU_L2_0_CONFIGURATION, 0x00000003},
+ {"ARM_CPU_L2_0_STATUS", ARM_CPU_L2_0_STATUS, 0x00000003},
+ {"ARM_CPU_L2_1_CONFIGURATION", ARM_CPU_L2_1_CONFIGURATION, 0x00000003},
+ {"ARM_CPU_L2_1_STATUS", ARM_CPU_L2_1_STATUS, 0x00000003},
+ {"PAD_RETENTION_MAUDIO_OPTION", PAD_RETENTION_MAUDIO_OPTION, 0x00000000},
+ {"PAD_RETENTION_GPIO_OPTION", PAD_RETENTION_GPIO_OPTION, 0x00000000},
+ {"PAD_RETENTION_UART_OPTION", PAD_RETENTION_UART_OPTION, 0x00000000},
+ {"PAD_RETENTION_MMCA_OPTION", PAD_RETENTION_MMCA_OPTION, 0x00000000},
+ {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000},
+ {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000},
+ {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000},
+ {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200},
+ {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001},
+ {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001},
+ {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000},
+ {"XXTI_CONFIGURATION", XXTI_CONFIGURATION, 0x00000001},
+ {"XXTI_STATUS", XXTI_STATUS, 0x00000001},
+ {"XXTI_DURATION", XXTI_DURATION, 0xFFF00000},
+ {"EXT_REGULATOR_DURATION", EXT_REGULATOR_DURATION, 0xFFF03FFF},
+ {"CAM_CONFIGURATION", CAM_CONFIGURATION, 0x00000007},
+ {"CAM_STATUS", CAM_STATUS, 0x00060007},
+ {"CAM_OPTION", CAM_OPTION, 0x00000001},
+ {"TV_CONFIGURATION", TV_CONFIGURATION, 0x00000007},
+ {"TV_STATUS", TV_STATUS, 0x00060007},
+ {"TV_OPTION", TV_OPTION, 0x00000001},
+ {"MFC_CONFIGURATION", MFC_CONFIGURATION, 0x00000007},
+ {"MFC_STATUS", MFC_STATUS, 0x00060007},
+ {"MFC_OPTION", MFC_OPTION, 0x00000001},
+ {"G3D_CONFIGURATION", G3D_CONFIGURATION, 0x00000007},
+ {"G3D_STATUS", G3D_STATUS, 0x00060007},
+ {"G3D_OPTION", G3D_OPTION, 0x00000001},
+ {"LCD0_CONFIGURATION", LCD0_CONFIGURATION, 0x00000007},
+ {"LCD0_STATUS", LCD0_STATUS, 0x00060007},
+ {"LCD0_OPTION", LCD0_OPTION, 0x00000001},
+ {"LCD1_CONFIGURATION", LCD1_CONFIGURATION, 0x00000007},
+ {"LCD1_STATUS", LCD1_STATUS, 0x00060007},
+ {"LCD1_OPTION", LCD1_OPTION, 0x00000001},
+ {"GPS_CONFIGURATION", GPS_CONFIGURATION, 0x00000007},
+ {"GPS_STATUS", GPS_STATUS, 0x00060007},
+ {"GPS_OPTION", GPS_OPTION, 0x00000001},
+ {"GPS_ALIVE_CONFIGURATION", GPS_ALIVE_CONFIGURATION, 0x00000007},
+ {"GPS_ALIVE_STATUS", GPS_ALIVE_STATUS, 0x00060007},
+ {"GPS_ALIVE_OPTION", GPS_ALIVE_OPTION, 0x00000001},
+};
+
+#define PMU_NUM_OF_REGISTERS \
+ (sizeof(exynos4210_pmu_regs) / sizeof(Exynos4210PmuReg))
+
+typedef struct Exynos4210PmuState {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ uint32_t reg[PMU_NUM_OF_REGISTERS];
+
+ ptimer_state *ptimer;
+} Exynos4210PmuState;
+
+static uint64_t exynos4210_pmu_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
+ unsigned i;
+ const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
+
+ for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
+ if (reg_p->offset == offset) {
+ PRINT_DEBUG_EXTEND("%s [0x%04x] -> 0x%04x\n", reg_p->name,
+ (uint32_t)offset, s->reg[i]);
+ return s->reg[i];
+ }
+ reg_p++;
+ }
+ PRINT_DEBUG("QEMU PMU ERROR: bad read offset 0x%04x\n", (uint32_t)offset);
+ return 0;
+}
+
+static void exynos4210_pmu_write(void *opaque, target_phys_addr_t offset,
+ uint64_t val, unsigned size)
+{
+ Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
+ unsigned i;
+ const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
+
+ for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
+ if (reg_p->offset == offset) {
+ PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name,
+ (uint32_t)offset, (uint32_t)val);
+ s->reg[i] = val;
+ break;
+ }
+ reg_p++;
+ }
+
+ switch (offset) {
+ case SYSTEM_POWER_DOWN_CTRL:
+ if (!(val & (1 << 16))) {
+ qemu_system_shutdown_request();
+ return;
+ }
+ case SWRESET:
+ if (val & 1) {
+ qemu_system_reset_request();
+ return;
+ }
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps exynos4210_pmu_ops = {
+ .read = exynos4210_pmu_read,
+ .write = exynos4210_pmu_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false
+ }
+};
+
+static void exynos4210_pmu_reset(DeviceState *dev)
+{
+ Exynos4210PmuState *s =
+ container_of(dev, Exynos4210PmuState, busdev.qdev);
+ unsigned i;
+
+ /* Set default values for registers */
+ for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
+ s->reg[i] = exynos4210_pmu_regs[i].reset_value;
+ }
+}
+
+static int exynos4210_pmu_init(SysBusDevice *dev)
+{
+ Exynos4210PmuState *s = FROM_SYSBUS(Exynos4210PmuState, dev);
+
+ /* memory mapping */
+ memory_region_init_io(&s->iomem, &exynos4210_pmu_ops, s, "maru_arm.pmu",
+ EXYNOS4210_PMU_REGS_MEM_SIZE);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static const VMStateDescription exynos4210_pmu_vmstate = {
+ .name = "maru_arm.pmu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = exynos4210_pmu_init;
+ dc->reset = exynos4210_pmu_reset;
+ dc->vmsd = &exynos4210_pmu_vmstate;
+}
+
+static TypeInfo exynos4210_pmu_info = {
+ .name = "maru_arm.pmu",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Exynos4210PmuState),
+ .class_init = exynos4210_pmu_class_init,
+};
+
+static void exynos4210_pmu_register(void)
+{
+ type_register_static(&exynos4210_pmu_info);
+}
+
+type_init(exynos4210_pmu_register)
--- /dev/null
+/*
+ * Samsung Maru ARM SoC emulation
+ *
+ * Based on exynos4210.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Maksim Kozlov <m.kozlov@samsung.com>
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ * Igor Mitsyanko <i.mitsyanko@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "boards.h"
+#include "arm-misc.h"
+#include "sysbus.h"
+#include "pci.h"
+#include "maru_arm.h"
+#include "i2c.h"
+#include "exec-memory.h"
+
+#include "loader.h"
+#include "exynos4210_i2s.h"
+extern int enable_vigs;
+
+#define EXYNOS4210_CHIPID_ADDR 0x10000000
+
+/* CMUs */
+#define EXYNOS4210_CMU_LEFTBUS_BASE_ADDR 0x10034000
+#define EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR 0x10038000
+#define EXYNOS4210_CMU_TOP_BASE_ADDR 0x1003C000
+#define EXYNOS4210_CMU_DMC_BASE_ADDR 0x10040000
+#define EXYNOS4210_CMU_CPU_BASE_ADDR 0x10044000
+
+/* PWM */
+#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000
+
+/* RTC */
+#define EXYNOS4210_RTC_BASE_ADDR 0x10070000
+
+/* MCT */
+#define EXYNOS4210_MCT_BASE_ADDR 0x10050000
+
+/* DMA */
+#define EXYNOS4210_DMAMEM_BASE_ADDR 0x12840000
+#define EXYNOS4210_DMAPERI0_BASE_ADDR 0x12680000
+#define EXYNOS4210_DMAPERI1_BASE_ADDR 0x12690000
+
+/* I2C */
+#define EXYNOS4210_I2C_SHIFT 0x00010000
+#define EXYNOS4210_I2C_BASE_ADDR 0x13860000
+/* Interrupt Group of External Interrupt Combiner for I2C */
+#define EXYNOS4210_I2C_INTG 27
+#define EXYNOS4210_HDMI_INTG 16
+
+/* There are two set of touch screen interfaces, which share one ADC */
+#define EXYNOS4210_TS0_BASE_ADDR 0x13910000
+#define EXYNOS4210_TS1_BASE_ADDR 0x13911000
+#define EXYNOS4210_TS_INTG 19
+
+/* UART's definitions */
+#define EXYNOS4210_UART0_BASE_ADDR 0x13800000
+#define EXYNOS4210_UART1_BASE_ADDR 0x13810000
+#define EXYNOS4210_UART2_BASE_ADDR 0x13820000
+#define EXYNOS4210_UART3_BASE_ADDR 0x13830000
+#define EXYNOS4210_UART0_FIFO_SIZE 256
+#define EXYNOS4210_UART1_FIFO_SIZE 64
+#define EXYNOS4210_UART2_FIFO_SIZE 16
+#define EXYNOS4210_UART3_FIFO_SIZE 16
+/* Interrupt Group of External Interrupt Combiner for UART */
+#define EXYNOS4210_UART_INT_GRP 26
+
+/* External GIC */
+#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000
+#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000
+
+/* Combiner */
+#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000
+#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000
+
+/* SD/MMC host controllers SFR base addresses */
+#define EXYNOS4210_SDHC0_BASE_ADDR 0x12510000
+#define EXYNOS4210_SDHC1_BASE_ADDR 0x12520000
+#define EXYNOS4210_SDHC2_BASE_ADDR 0x12530000
+#define EXYNOS4210_SDHC3_BASE_ADDR 0x12540000
+
+/* PMU SFR base address */
+#define EXYNOS4210_PMU_BASE_ADDR 0x10020000
+
+/* Display controllers (FIMD) */
+#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
+#define EXYNOS4210_FIMD1_BASE_ADDR 0x12000000
+
+/* MALI400 (G3D) */
+#define EXYNOS4210_G3D_BASE_ADDR 0x13000000
+#define EXYNOS4210_G3D_PIXEL_PROC_0_IRQ 0
+#define EXYNOS4210_G3D_PIXEL_PROC_1_IRQ 1
+#define EXYNOS4210_G3D_PIXEL_PROC_2_IRQ 2
+#define EXYNOS4210_G3D_PIXEL_PROC_3_IRQ 3
+#define EXYNOS4210_G3D_GEOM_PROC_IRQ 4
+#define EXYNOS4210_G3D_PMU_IRQ 5
+#define EXYNOS4210_G3D_PPMMU0_IRQ 0
+#define EXYNOS4210_G3D_PPMMU1_IRQ 1
+#define EXYNOS4210_G3D_PPMMU2_IRQ 2
+#define EXYNOS4210_G3D_PPMMU3_IRQ 3
+#define EXYNOS4210_G3D_GPMMU_IRQ 4
+
+/* PPMU */
+#define EXYNOS4210_PPMU_CPU_BASE_ADDR 0x106C0000
+/* DMC */
+#define EXYNOS4210_DMC0_BASE_ADDR 0x10400000
+#define EXYNOS4210_DMC1_BASE_ADDR 0x10410000
+
+/* I2S */
+#define EXYNOS4210_I2S0_BASE_ADDR 0x03830000
+
+/* pl050 ps/2 interface */
+#define EXYNOS4210_PL050_BASE_ADDR 0x12E30000
+
+static uint8_t chipid_and_omr[TARGET_PAGE_SIZE] = { 0x11, 0x02, 0x21, 0x43,
+ 0x09, 0x00, 0x00, 0x00 };
+
+void maru_arm_write_secondary(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t smpboot[] = {
+ 0xe59f3024, /* ldr r3, External gic_cpu_if */
+ 0xe59f2024, /* ldr r2, Internal gic_cpu_if */
+ 0xe59f0024, /* ldr r0, startaddr */
+ 0xe3a01001, /* mov r1, #1 */
+ 0xe5821000, /* str r1, [r2] */
+ 0xe5831000, /* str r1, [r3] */
+ 0xe320f003, /* wfi */
+ 0xe5901000, /* ldr r1, [r0] */
+ 0xe1110001, /* tst r1, r1 */
+ 0x0afffffb, /* beq <wfi> */
+ 0xe12fff11, /* bx r1 */
+ EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
+ 0, /* gic_cpu_if: base address of Internal GIC CPU interface */
+ 0 /* bootreg: Boot register address is held here */
+ };
+ smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+ smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start);
+}
+
+Exynos4210State *maru_arm_soc_init(MemoryRegion *system_mem,
+ unsigned long ram_size)
+{
+ qemu_irq cpu_irq[EXYNOS4210_NCPUS];
+ int i, n;
+ Exynos4210State *s = g_new(Exynos4210State, 1);
+ qemu_irq *irqp;
+ qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
+ unsigned long mem_size;
+ DeviceState *dev;
+ SysBusDevice *busdev;
+
+ for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+ s->cpu[n] = cpu_arm_init("cortex-a9");
+ if (!s->cpu[n]) {
+ fprintf(stderr, "Unable to find CPU %d definition\n", n);
+ exit(1);
+ }
+
+ /* Create PIC controller for each processor instance */
+ irqp = arm_pic_init_cpu(s->cpu[n]);
+
+ /*
+ * Get GICs gpio_in cpu_irq to connect a combiner to them later.
+ * Use only IRQ for a while.
+ */
+ cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+ }
+
+ /*** IRQs ***/
+
+ s->irq_table = exynos4210_init_irq(&s->irqs);
+
+ /* IRQ Gate */
+ for (i = 0; i < EXYNOS4210_NCPUS; i++) {
+ dev = qdev_create(NULL, "exynos4210.irq_gate");
+ qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
+ qdev_init_nofail(dev);
+ /* Get IRQ Gate input in gate_irq */
+ for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
+ gate_irq[i][n] = qdev_get_gpio_in(dev, n);
+ }
+ busdev = sysbus_from_qdev(dev);
+
+ /* Connect IRQ Gate output to cpu_irq */
+ sysbus_connect_irq(busdev, 0, cpu_irq[i]);
+ }
+
+ /* Private memory region and Internal GIC */
+ dev = qdev_create(NULL, "a9mpcore_priv");
+ qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
+ for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+ sysbus_connect_irq(busdev, n, gate_irq[n][0]);
+ }
+ for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
+ s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
+ }
+
+ /* Cache controller */
+ sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
+
+ /* External GIC */
+ dev = qdev_create(NULL, "exynos4210.gic");
+ qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ /* Map CPU interface */
+ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
+ /* Map Distributer interface */
+ sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
+ for (n = 0; n < EXYNOS4210_NCPUS; n++) {
+ sysbus_connect_irq(busdev, n, gate_irq[n][1]);
+ }
+ for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
+ s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
+ }
+
+ /* Internal Interrupt Combiner */
+ dev = qdev_create(NULL, "exynos4210.combiner");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
+ sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
+ }
+ exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
+ sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
+
+ /* External Interrupt Combiner */
+ dev = qdev_create(NULL, "exynos4210.combiner");
+ qdev_prop_set_uint32(dev, "external", 1);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
+ sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
+ }
+ exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
+ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
+
+ /* Initialize board IRQs. */
+ exynos4210_init_board_irqs(&s->irqs);
+
+ /*** Memory ***/
+
+ /* Chip-ID and OMR */
+ memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid",
+ sizeof(chipid_and_omr), chipid_and_omr);
+ memory_region_set_readonly(&s->chipid_mem, true);
+ memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
+ &s->chipid_mem);
+
+ /* Internal ROM */
+ memory_region_init_ram(&s->irom_mem, "exynos4210.irom",
+ EXYNOS4210_IROM_SIZE);
+ memory_region_set_readonly(&s->irom_mem, true);
+ memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
+ &s->irom_mem);
+ /* mirror of iROM */
+ memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias",
+ &s->irom_mem,
+ 0,
+ EXYNOS4210_IROM_SIZE);
+ memory_region_set_readonly(&s->irom_alias_mem, true);
+ memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
+ &s->irom_alias_mem);
+
+ /* Internal RAM */
+ memory_region_init_ram(&s->iram_mem, "exynos4210.iram",
+ EXYNOS4210_IRAM_SIZE);
+ vmstate_register_ram_global(&s->iram_mem);
+ memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
+ &s->iram_mem);
+
+ /* DRAM */
+ mem_size = ram_size;
+ if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
+ memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1",
+ mem_size - EXYNOS4210_DRAM_MAX_SIZE);
+ vmstate_register_ram_global(&s->dram1_mem);
+ memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
+ &s->dram1_mem);
+ mem_size = EXYNOS4210_DRAM_MAX_SIZE;
+ }
+ memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size);
+ vmstate_register_ram_global(&s->dram0_mem);
+ memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
+ &s->dram0_mem);
+
+ /* Audio Subsystem Internal Memory */
+ memory_region_init_ram(&s->audss_intmem, "exynos4210.audss",
+ EXYNOS4210_AUDSS_INTMEM_SIZE);
+ vmstate_register_ram_global(&s->audss_intmem);
+ memory_region_add_subregion(system_mem, EXYNOS4210_AUDSS_INTMEM_BASE_ADDR,
+ &s->audss_intmem);
+
+ /* PMU.
+ * The only reason of existence at the moment is that secondary CPU boot
+ * loader uses PMU INFORM5 register as a holding pen.
+ */
+ sysbus_create_simple("maru_arm.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
+
+ /* CMUs */
+ exynos4210_cmu_create(EXYNOS4210_CMU_LEFTBUS_BASE_ADDR,
+ EXYNOS4210_CMU_LEFTBUS);
+ exynos4210_cmu_create(EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR,
+ EXYNOS4210_CMU_RIGHTBUS);
+ exynos4210_cmu_create(EXYNOS4210_CMU_TOP_BASE_ADDR, EXYNOS4210_CMU_TOP);
+ exynos4210_cmu_create(EXYNOS4210_CMU_DMC_BASE_ADDR, EXYNOS4210_CMU_DMC);
+ exynos4210_cmu_create(EXYNOS4210_CMU_CPU_BASE_ADDR, EXYNOS4210_CMU_CPU);
+
+ /* PWM */
+ sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
+ s->irq_table[exynos4210_get_irq(22, 0)],
+ s->irq_table[exynos4210_get_irq(22, 1)],
+ s->irq_table[exynos4210_get_irq(22, 2)],
+ s->irq_table[exynos4210_get_irq(22, 3)],
+ s->irq_table[exynos4210_get_irq(22, 4)],
+ NULL);
+ /* RTC */
+ sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
+ s->irq_table[exynos4210_get_irq(23, 0)],
+ s->irq_table[exynos4210_get_irq(23, 1)],
+ NULL);
+
+ /* Multi Core Timer */
+ dev = qdev_create(NULL, "exynos4210.mct");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ for (n = 0; n < 4; n++) {
+ /* Connect global timer interrupts to Combiner gpio_in */
+ sysbus_connect_irq(busdev, n,
+ s->irq_table[exynos4210_get_irq(1, 4 + n)]);
+ }
+ /* Connect local timer interrupts to Combiner gpio_in */
+ sysbus_connect_irq(busdev, 4,
+ s->irq_table[exynos4210_get_irq(51, 0)]);
+ sysbus_connect_irq(busdev, 5,
+ s->irq_table[exynos4210_get_irq(35, 3)]);
+ sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
+
+ /*** I2C ***/
+ for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
+ uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
+ qemu_irq i2c_irq;
+
+ if (n < 8) {
+ i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
+ } else {
+ i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
+ }
+
+ dev = qdev_create(NULL, "exynos4210.i2c");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_connect_irq(busdev, 0, i2c_irq);
+ sysbus_mmio_map(busdev, 0, addr);
+ s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+ }
+
+
+ /*** UARTs ***/
+ exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
+ EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
+ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
+
+ exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
+ EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
+ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
+
+ exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
+ EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
+ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
+
+ exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
+ EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
+ s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
+
+ if (!enable_vigs) {
+ /*** Display controller (FIMD) ***/
+ sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
+ s->irq_table[exynos4210_get_irq(11, 0)],
+ s->irq_table[exynos4210_get_irq(11, 1)],
+ s->irq_table[exynos4210_get_irq(11, 2)],
+ NULL);
+ }
+
+ /* I2S0 */
+ s->i2s_bus[0] = exynos4210_i2s_bus_new("exynos4210.i2s",
+ EXYNOS4210_I2S0_BASE_ADDR,
+ s->irqs.ext_gic_irq[97]);
+
+ /* PL050 PS/2 if keyboard */
+ sysbus_create_simple("pl050_keyboard", EXYNOS4210_PL050_BASE_ADDR,
+ s->irq_table[exynos4210_get_irq(28, 2)]);
+
+ return s;
+}
--- /dev/null
+/*
+ * Samsung Tizen Virtual PCI driver
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Vorobiov Stanislav <s.vorobiov@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysbus.h"
+#include "pci.h"
+#include "pci_host.h"
+#include "exec-memory.h"
+
+#define TIZEN_VPCI_VENDOR_ID 0x10ee
+#define TIZEN_VPCI_DEVICE_ID 0x0300
+#define TIZEN_VPCI_CLASS_ID PCI_CLASS_PROCESSOR_CO
+
+#define TIZEN_VPCI_IO_ADDR 0xC3000000
+#define TIZEN_VPCI_IO_SIZE 0xFFFF
+
+typedef struct {
+ SysBusDevice busdev;
+ qemu_irq irq[4];
+ MemoryRegion mem_config;
+ MemoryRegion iospace_alias_mem;
+} TizenVPCIState;
+
+static uint64_t tizen_vpci_io_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ switch (size) {
+ case 1:
+ return cpu_inb(addr);
+ case 2:
+ return cpu_inw(addr);
+ case 4:
+ return cpu_inl(addr);
+ default:
+ break;
+ }
+ assert(0);
+}
+
+static void tizen_vpci_io_write(void *opaque, target_phys_addr_t addr,
+ uint64_t data, unsigned size)
+{
+ switch (size) {
+ case 1:
+ cpu_outb(addr, data);
+ return;
+ case 2:
+ cpu_outw(addr, data);
+ return;
+ case 4:
+ cpu_outl(addr, data);
+ return;
+ }
+ assert(0);
+}
+
+static const MemoryRegionOps tizen_vpci_io_ops = {
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .read = tizen_vpci_io_read,
+ .write = tizen_vpci_io_write
+};
+
+static inline uint32_t tizen_vpci_config_addr(target_phys_addr_t addr)
+{
+ return addr & 0xffffff;
+}
+
+static void tizen_vpci_config_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
+{
+ pci_data_write(opaque, tizen_vpci_config_addr(addr), val, size);
+}
+
+static uint64_t tizen_vpci_config_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, tizen_vpci_config_addr(addr), size);
+ return val;
+}
+
+static const MemoryRegionOps tizen_vpci_config_ops = {
+ .read = tizen_vpci_config_read,
+ .write = tizen_vpci_config_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int tizen_vpci_map_irq(PCIDevice *d, int irq_num)
+{
+ return irq_num;
+}
+
+static void tizen_vpci_set_irq(void *opaque, int irq_num, int level)
+{
+ qemu_irq *pic = opaque;
+
+ qemu_set_irq(pic[irq_num], level);
+}
+
+static int tizen_vpci_init(SysBusDevice *dev)
+{
+ TizenVPCIState *s = FROM_SYSBUS(TizenVPCIState, dev);
+ PCIBus *bus;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
+
+ /* On ARM, we only have MMIO no specific IO space from the CPU
+ * perspective. In theory we ought to be able to embed the PCI IO
+ * memory region direction in the system memory space. However,
+ * if any of the IO BAR subregions use the old_portio mechanism,
+ * that won't be processed properly unless accessed from the
+ * system io address space. This hack to bounce things via
+ * system_io works around the problem until all the users of
+ * old_portion are updated */
+
+ memory_region_init_io(&s->iospace_alias_mem, &tizen_vpci_io_ops, s,
+ "tizen_vpci.io-alias", TIZEN_VPCI_IO_SIZE);
+ memory_region_add_subregion(get_system_memory(), TIZEN_VPCI_IO_ADDR,
+ &s->iospace_alias_mem);
+
+ bus = pci_register_bus(&dev->qdev, "pci",
+ tizen_vpci_set_irq, tizen_vpci_map_irq, s->irq,
+ get_system_memory(), get_system_io(),
+ 0, 4);
+
+ memory_region_init_io(&s->mem_config, &tizen_vpci_config_ops, bus,
+ "tizen-vpci-config", 0x1000000);
+ sysbus_init_mmio(dev, &s->mem_config);
+
+ pci_create_simple(bus, -1, "tizen_vpci_host");
+
+ return 0;
+}
+
+static int tizen_vpci_host_init(PCIDevice *d)
+{
+ pci_set_word(d->config + PCI_STATUS,
+ PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_FAST);
+ return 0;
+}
+
+static void tizen_vpci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = tizen_vpci_host_init;
+ k->vendor_id = TIZEN_VPCI_VENDOR_ID;
+ k->device_id = TIZEN_VPCI_DEVICE_ID;
+ k->class_id = TIZEN_VPCI_CLASS_ID;
+}
+
+static TypeInfo tizen_vpci_host_info = {
+ .name = "tizen_vpci_host",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = tizen_vpci_host_class_init,
+};
+
+static void tizen_vpci_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = tizen_vpci_init;
+}
+
+static TypeInfo tizen_vpci_info = {
+ .name = "tizen_vpci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TizenVPCIState),
+ .class_init = tizen_vpci_class_init,
+};
+
+static void tizen_vpci_register_types(void)
+{
+ type_register_static(&tizen_vpci_info);
+ type_register_static(&tizen_vpci_host_info);
+}
+
+type_init(tizen_vpci_register_types)
+++ /dev/null
-/*
- * Samsung Maru ARM SoC emulation
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MARU_ARM_H_
-#define MARU_ARM_H_
-
-#include "qemu-common.h"
-#include "memory.h"
-#include "exynos4210.h"
-
-void maru_arm_write_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info);
-
-Exynos4210State *maru_arm_soc_init(MemoryRegion *system_mem,
- unsigned long ram_size);
-
-int codec_init(PCIBus *bus);
-int maru_camera_pci_init(PCIBus *bus);
-
-#endif /* MARU_ARM_H_ */
+++ /dev/null
-/*
- * TIZEN ARM base board
- *
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
- *
- * Based on maru_board.c, exynos4210.c and exynos4210_boards.c
- *
- * Author:
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License; 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-
-#include "boards.h"
-#include "arm-misc.h"
-#include "sysbus.h"
-#include "pci.h"
-#include "maru_arm.h"
-#include "i2c.h"
-#include "exec-memory.h"
-#include "hw/maru_brightness.h"
-#include "arch_init.h"
-
-#include "xen.h"
-#ifdef CONFIG_XEN
-# include <xen/hvm/hvm_info_table.h>
-#endif
-#include "maru_common.h"
-#if defined(__linux__)
-#include <X11/Xlib.h>
-#endif
-#include "vigs_device.h"
-extern int enable_yagl;
-extern const char *yagl_backend;
-extern int enable_vigs;
-extern const char *vigs_backend;
-
-#undef DEBUG
-//#define DEBUG
-#ifdef DEBUG
- #undef PRINT_DEBUG
- #define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
- #define PRINT_DEBUG(fmt, args...) do {} while (0)
-#endif
-
-#ifndef DEBUG_LOG_PATH
-#define DEBUG_LOG_PATH "./debug.log"
-#endif
-
-#define EXYNOS4210_WM8994_ADDR 0x1A
-#define MARU_ARM_BOARD_ID 0xF3B
-#define MARU_ARM_BOARD_SMP_BOOTREG_ADDR EXYNOS4210_SECOND_CPU_BOOTREG
-#define MARU_ARM_BOARD_RAMSIZE_MIN 0x20000000
-#define MARU_ARM_BOARD_RAMSIZE_DEFAULT 0x40000000
-
-static struct arm_boot_info maru_arm_board_binfo = {
- .loader_start = EXYNOS4210_BASE_BOOT_ADDR,
- .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
- .nb_cpus = EXYNOS4210_NCPUS,
- .write_secondary_boot = maru_arm_write_secondary,
-};
-
-static void maru_arm_machine_init(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)
-{
- Exynos4210State *s;
- DeviceState *dev;
- PCIBus *pci_bus;
-#if defined(__linux__)
- Display *display = XOpenDisplay(0);
- if (!display) {
- fprintf(stderr, "Cannot open X display\n");
- exit(1);
- }
-#else
- void *display = NULL;
-#endif
- struct winsys_interface *vigs_wsi = NULL;
-
- /*
- * W/A for allocate larger continuous heap. From maru_board.c
- */
- if (!xen_enabled()) {
- if(preallocated_ptr != NULL) {
- qemu_vfree(preallocated_ptr);
- }
- }
-
- if (ram_size < MARU_ARM_BOARD_RAMSIZE_MIN) {
- ram_size = MARU_ARM_BOARD_RAMSIZE_DEFAULT;
- fprintf(stderr, "RAM size is too small, setting to default value 0x%lx",
- (long unsigned int)ram_size);
- }
-
- maru_arm_board_binfo.ram_size = ram_size;
- maru_arm_board_binfo.board_id = MARU_ARM_BOARD_ID;
- maru_arm_board_binfo.smp_bootreg_addr = MARU_ARM_BOARD_SMP_BOOTREG_ADDR;
- maru_arm_board_binfo.kernel_filename = kernel_filename;
- maru_arm_board_binfo.initrd_filename = initrd_filename;
- maru_arm_board_binfo.kernel_cmdline = kernel_cmdline;
- maru_arm_board_binfo.gic_cpu_if_addr =
- EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
-
- PRINT_DEBUG("\n ram_size: %luMiB [0x%08lx]\n"
- " kernel_filename: %s\n"
- " kernel_cmdline: %s\n"
- " initrd_filename: %s\n",
- (long unsigned int)ram_size / 1048576,
- (long unsigned int)ram_size,
- kernel_filename,
- kernel_cmdline,
- initrd_filename);
- s = maru_arm_soc_init(get_system_memory(), ram_size);
-
- /* PCI config */
- dev = qdev_create(NULL, "tizen_vpci");
- s->vpci_bus = sysbus_from_qdev(dev);
- qdev_init_nofail(dev);
- sysbus_mmio_map(s->vpci_bus, 0, EXYNOS4210_VPCI_CFG_BASE_ADDR);
- sysbus_connect_irq(s->vpci_bus, 0, s->irq_table[exynos4210_get_irq(38, 0)]);
- sysbus_connect_irq(s->vpci_bus, 1, s->irq_table[exynos4210_get_irq(38, 1)]);
- sysbus_connect_irq(s->vpci_bus, 2, s->irq_table[exynos4210_get_irq(38, 2)]);
- sysbus_connect_irq(s->vpci_bus, 3, s->irq_table[exynos4210_get_irq(38, 3)]);
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
-
- pci_create_simple(pci_bus, -1, "pci-ohci");
- maru_camera_pci_init(pci_bus);
- maru_brill_codec_pci_device_init(pci_bus);
- pci_maru_brightness_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);
- }
-
- audio_init(NULL, pci_bus);
-
- arm_load_kernel(arm_env_get_cpu(first_cpu), &maru_arm_board_binfo);
-}
-
-static QEMUMachine maru_arm_machine = {
- .name = "maru-arm-machine",
- .desc = "maru board(ARM)",
- .init = maru_arm_machine_init,
- .max_cpus = 255,
-};
-
-static void maru_machine_init(void)
-{
- qemu_register_machine(&maru_arm_machine);
-}
-
-machine_init(maru_machine_init);
+++ /dev/null
-/*
- * Tizen Power Management Unit (PMU) Emulation
- *
- * Based on exynos4210_pmu.c
- * Copyright (C) 2011 Samsung Electronics Co Ltd.
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * This model implements PMU registers just as a bulk of memory.
- * Able to shutdown and restart only.
- */
-
-#include "sysbus.h"
-#include "sysemu.h"
-#include "ptimer.h"
-
-#ifndef DEBUG_PMU
-#define DEBUG_PMU 0
-#endif
-
-#ifndef DEBUG_PMU_EXTEND
-#define DEBUG_PMU_EXTEND 0
-#endif
-
-#if DEBUG_PMU
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_PMU_EXTEND
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0)
-#endif /* EXTEND */
-
-#else
-#define PRINT_DEBUG(fmt, args...) do {} while (0)
-#define PRINT_DEBUG_EXTEND(fmt, args...) do {} while (0)
-#endif
-
-#define POWER_OFF_TIMER_FREQ 24000000
-
-/*
- * Offsets for PMU registers
- */
-#define OM_STAT 0x0000 /* OM status register */
-#define RTC_CLKO_SEL 0x000C /* Controls RTCCLKOUT */
-#define GNSS_RTC_OUT_CTRL 0x0010 /* Controls GNSS_RTC_OUT */
-/* Decides whether system-level low-power mode is used. */
-#define SYSTEM_POWER_DOWN_CTRL 0x0200
-/* Sets control options for CENTRAL_SEQ */
-#define SYSTEM_POWER_DOWN_OPTION 0x0208
-#define SWRESET 0x0400 /* Generate software reset */
-#define RST_STAT 0x0404 /* Reset status register */
-#define WAKEUP_STAT 0x0600 /* Wakeup status register */
-#define EINT_WAKEUP_MASK 0x0604 /* Configure External INTerrupt mask */
-#define WAKEUP_MASK 0x0608 /* Configure wakeup source mask */
-#define HDMI_PHY_CONTROL 0x0700 /* HDMI PHY control register */
-#define USBDEVICE_PHY_CONTROL 0x0704 /* USB Device PHY control register */
-#define USBHOST_PHY_CONTROL 0x0708 /* USB HOST PHY control register */
-#define DAC_PHY_CONTROL 0x070C /* DAC control register */
-#define MIPI_PHY0_CONTROL 0x0710 /* MIPI PHY control register */
-#define MIPI_PHY1_CONTROL 0x0714 /* MIPI PHY control register */
-#define ADC_PHY_CONTROL 0x0718 /* TS-ADC control register */
-#define PCIe_PHY_CONTROL 0x071C /* TS-PCIe control register */
-#define SATA_PHY_CONTROL 0x0720 /* TS-SATA control register */
-#define INFORM0 0x0800 /* Information register 0 */
-#define INFORM1 0x0804 /* Information register 1 */
-#define INFORM2 0x0808 /* Information register 2 */
-#define INFORM3 0x080C /* Information register 3 */
-#define INFORM4 0x0810 /* Information register 4 */
-#define INFORM5 0x0814 /* Information register 5 */
-#define INFORM6 0x0818 /* Information register 6 */
-#define INFORM7 0x081C /* Information register 7 */
-#define PMU_DEBUG 0x0A00 /* PMU debug register */
-/* Registers to set system-level low-power option */
-#define ARM_CORE0_SYS_PWR_REG 0x1000
-#define ARM_CORE1_SYS_PWR_REG 0x1010
-#define ARM_COMMON_SYS_PWR_REG 0x1080
-#define ARM_CPU_L2_0_SYS_PWR_REG 0x10C0
-#define ARM_CPU_L2_1_SYS_PWR_REG 0x10C4
-#define CMU_ACLKSTOP_SYS_PWR_REG 0x1100
-#define CMU_SCLKSTOP_SYS_PWR_REG 0x1104
-#define CMU_RESET_SYS_PWR_REG 0x110C
-#define APLL_SYSCLK_SYS_PWR_REG 0x1120
-#define MPLL_SYSCLK_SYS_PWR_REG 0x1124
-#define VPLL_SYSCLK_SYS_PWR_REG 0x1128
-#define EPLL_SYSCLK_SYS_PWR_REG 0x112C
-#define CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG 0x1138
-#define CMU_RESET_GPS_ALIVE_SYS_PWR_REG 0x113C
-#define CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140
-#define CMU_CLKSTOP_TV_SYS_PWR_REG 0x1144
-#define CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148
-#define CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C
-#define CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150
-#define CMU_CLKSTOP_LCD1_SYS_PWR_REG 0x1154
-#define CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158
-#define CMU_CLKSTOP_GPS_SYS_PWR_REG 0x115C
-#define CMU_RESET_CAM_SYS_PWR_REG 0x1160
-#define CMU_RESET_TV_SYS_PWR_REG 0x1164
-#define CMU_RESET_MFC_SYS_PWR_REG 0x1168
-#define CMU_RESET_G3D_SYS_PWR_REG 0x116C
-#define CMU_RESET_LCD0_SYS_PWR_REG 0x1170
-#define CMU_RESET_LCD1_SYS_PWR_REG 0x1174
-#define CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178
-#define CMU_RESET_GPS_SYS_PWR_REG 0x117C
-#define TOP_BUS_SYS_PWR_REG 0x1180
-#define TOP_RETENTION_SYS_PWR_REG 0x1184
-#define TOP_PWR_SYS_PWR_REG 0x1188
-#define LOGIC_RESET_SYS_PWR_REG 0x11A0
-#define OneNANDXL_MEM_SYS_PWR_REG 0x11C0
-#define MODEMIF_MEM_SYS_PWR_REG 0x11C4
-#define USBDEVICE_MEM_SYS_PWR_REG 0x11CC
-#define SDMMC_MEM_SYS_PWR_REG 0x11D0
-#define CSSYS_MEM_SYS_PWR_REG 0x11D4
-#define SECSS_MEM_SYS_PWR_REG 0x11D8
-#define PCIe_MEM_SYS_PWR_REG 0x11E0
-#define SATA_MEM_SYS_PWR_REG 0x11E4
-#define PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200
-#define PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204
-#define PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220
-#define PAD_RETENTION_UART_SYS_PWR_REG 0x1224
-#define PAD_RETENTION_MMCA_SYS_PWR_REG 0x1228
-#define PAD_RETENTION_MMCB_SYS_PWR_REG 0x122C
-#define PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230
-#define PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234
-#define PAD_ISOLATION_SYS_PWR_REG 0x1240
-#define PAD_ALV_SEL_SYS_PWR_REG 0x1260
-#define XUSBXTI_SYS_PWR_REG 0x1280
-#define XXTI_SYS_PWR_REG 0x1284
-#define EXT_REGULATOR_SYS_PWR_REG 0x12C0
-#define GPIO_MODE_SYS_PWR_REG 0x1300
-#define GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340
-#define CAM_SYS_PWR_REG 0x1380
-#define TV_SYS_PWR_REG 0x1384
-#define MFC_SYS_PWR_REG 0x1388
-#define G3D_SYS_PWR_REG 0x138C
-#define LCD0_SYS_PWR_REG 0x1390
-#define LCD1_SYS_PWR_REG 0x1394
-#define MAUDIO_SYS_PWR_REG 0x1398
-#define GPS_SYS_PWR_REG 0x139C
-#define GPS_ALIVE_SYS_PWR_REG 0x13A0
-#define ARM_CORE0_CONFIGURATION 0x2000 /* Configure power mode of ARM_CORE0 */
-#define ARM_CORE0_STATUS 0x2004 /* Check power mode of ARM_CORE0 */
-#define ARM_CORE0_OPTION 0x2008 /* Sets control options for ARM_CORE0 */
-#define ARM_CORE1_CONFIGURATION 0x2080 /* Configure power mode of ARM_CORE1 */
-#define ARM_CORE1_STATUS 0x2084 /* Check power mode of ARM_CORE1 */
-#define ARM_CORE1_OPTION 0x2088 /* Sets control options for ARM_CORE0 */
-#define ARM_COMMON_OPTION 0x2408 /* Sets control options for ARM_COMMON */
-/* Configure power mode of ARM_CPU_L2_0 */
-#define ARM_CPU_L2_0_CONFIGURATION 0x2600
-#define ARM_CPU_L2_0_STATUS 0x2604 /* Check power mode of ARM_CPU_L2_0 */
-/* Configure power mode of ARM_CPU_L2_1 */
-#define ARM_CPU_L2_1_CONFIGURATION 0x2620
-#define ARM_CPU_L2_1_STATUS 0x2624 /* Check power mode of ARM_CPU_L2_1 */
-/* Sets control options for PAD_RETENTION_MAUDIO */
-#define PAD_RETENTION_MAUDIO_OPTION 0x3028
-/* Sets control options for PAD_RETENTION_GPIO */
-#define PAD_RETENTION_GPIO_OPTION 0x3108
-/* Sets control options for PAD_RETENTION_UART */
-#define PAD_RETENTION_UART_OPTION 0x3128
-/* Sets control options for PAD_RETENTION_MMCA */
-#define PAD_RETENTION_MMCA_OPTION 0x3148
-/* Sets control options for PAD_RETENTION_MMCB */
-#define PAD_RETENTION_MMCB_OPTION 0x3168
-/* Sets control options for PAD_RETENTION_EBIA */
-#define PAD_RETENTION_EBIA_OPTION 0x3188
-/* Sets control options for PAD_RETENTION_EBIB */
-#define PAD_RETENTION_EBIB_OPTION 0x31A8
-#define PS_HOLD_CONTROL 0x330C /* PS_HOLD control register */
-#define XUSBXTI_CONFIGURATION 0x3400 /* Configure the pad of XUSBXTI */
-#define XUSBXTI_STATUS 0x3404 /* Check the pad of XUSBXTI */
-/* Sets time required for XUSBXTI to be stabilized */
-#define XUSBXTI_DURATION 0x341C
-#define XXTI_CONFIGURATION 0x3420 /* Configure the pad of XXTI */
-#define XXTI_STATUS 0x3424 /* Check the pad of XXTI */
-/* Sets time required for XXTI to be stabilized */
-#define XXTI_DURATION 0x343C
-/* Sets time required for EXT_REGULATOR to be stabilized */
-#define EXT_REGULATOR_DURATION 0x361C
-#define CAM_CONFIGURATION 0x3C00 /* Configure power mode of CAM */
-#define CAM_STATUS 0x3C04 /* Check power mode of CAM */
-#define CAM_OPTION 0x3C08 /* Sets control options for CAM */
-#define TV_CONFIGURATION 0x3C20 /* Configure power mode of TV */
-#define TV_STATUS 0x3C24 /* Check power mode of TV */
-#define TV_OPTION 0x3C28 /* Sets control options for TV */
-#define MFC_CONFIGURATION 0x3C40 /* Configure power mode of MFC */
-#define MFC_STATUS 0x3C44 /* Check power mode of MFC */
-#define MFC_OPTION 0x3C48 /* Sets control options for MFC */
-#define G3D_CONFIGURATION 0x3C60 /* Configure power mode of G3D */
-#define G3D_STATUS 0x3C64 /* Check power mode of G3D */
-#define G3D_OPTION 0x3C68 /* Sets control options for G3D */
-#define LCD0_CONFIGURATION 0x3C80 /* Configure power mode of LCD0 */
-#define LCD0_STATUS 0x3C84 /* Check power mode of LCD0 */
-#define LCD0_OPTION 0x3C88 /* Sets control options for LCD0 */
-#define LCD1_CONFIGURATION 0x3CA0 /* Configure power mode of LCD1 */
-#define LCD1_STATUS 0x3CA4 /* Check power mode of LCD1 */
-#define LCD1_OPTION 0x3CA8 /* Sets control options for LCD1 */
-#define GPS_CONFIGURATION 0x3CE0 /* Configure power mode of GPS */
-#define GPS_STATUS 0x3CE4 /* Check power mode of GPS */
-#define GPS_OPTION 0x3CE8 /* Sets control options for GPS */
-#define GPS_ALIVE_CONFIGURATION 0x3D00 /* Configure power mode of GPS */
-#define GPS_ALIVE_STATUS 0x3D04 /* Check power mode of GPS */
-#define GPS_ALIVE_OPTION 0x3D08 /* Sets control options for GPS */
-
-#define EXYNOS4210_PMU_REGS_MEM_SIZE 0x3d0c
-
-typedef struct Exynos4210PmuReg {
- const char *name; /* for debug only */
- uint32_t offset;
- uint32_t reset_value;
-} Exynos4210PmuReg;
-
-static const Exynos4210PmuReg exynos4210_pmu_regs[] = {
- {"OM_STAT", OM_STAT, 0x00000000},
- {"RTC_CLKO_SEL", RTC_CLKO_SEL, 0x00000000},
- {"GNSS_RTC_OUT_CTRL", GNSS_RTC_OUT_CTRL, 0x00000001},
- {"SYSTEM_POWER_DOWN_CTRL", SYSTEM_POWER_DOWN_CTRL, 0x00010000},
- {"SYSTEM_POWER_DOWN_OPTION", SYSTEM_POWER_DOWN_OPTION, 0x03030000},
- {"SWRESET", SWRESET, 0x00000000},
- {"RST_STAT", RST_STAT, 0x00000000},
- {"WAKEUP_STAT", WAKEUP_STAT, 0x00000000},
- {"EINT_WAKEUP_MASK", EINT_WAKEUP_MASK, 0x00000000},
- {"WAKEUP_MASK", WAKEUP_MASK, 0x00000000},
- {"HDMI_PHY_CONTROL", HDMI_PHY_CONTROL, 0x00960000},
- {"USBDEVICE_PHY_CONTROL", USBDEVICE_PHY_CONTROL, 0x00000000},
- {"USBHOST_PHY_CONTROL", USBHOST_PHY_CONTROL, 0x00000000},
- {"DAC_PHY_CONTROL", DAC_PHY_CONTROL, 0x00000000},
- {"MIPI_PHY0_CONTROL", MIPI_PHY0_CONTROL, 0x00000000},
- {"MIPI_PHY1_CONTROL", MIPI_PHY1_CONTROL, 0x00000000},
- {"ADC_PHY_CONTROL", ADC_PHY_CONTROL, 0x00000001},
- {"PCIe_PHY_CONTROL", PCIe_PHY_CONTROL, 0x00000000},
- {"SATA_PHY_CONTROL", SATA_PHY_CONTROL, 0x00000000},
- {"INFORM0", INFORM0, 0x00000000},
- {"INFORM1", INFORM1, 0x00000000},
- {"INFORM2", INFORM2, 0x00000000},
- {"INFORM3", INFORM3, 0x00000000},
- {"INFORM4", INFORM4, 0x00000000},
- {"INFORM5", INFORM5, 0x00000000},
- {"INFORM6", INFORM6, 0x00000000},
- {"INFORM7", INFORM7, 0x00000000},
- {"PMU_DEBUG", PMU_DEBUG, 0x00000000},
- {"ARM_CORE0_SYS_PWR_REG", ARM_CORE0_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CORE1_SYS_PWR_REG", ARM_CORE1_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_COMMON_SYS_PWR_REG", ARM_COMMON_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CPU_L2_0_SYS_PWR_REG", ARM_CPU_L2_0_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CPU_L2_1_SYS_PWR_REG", ARM_CPU_L2_1_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_ACLKSTOP_SYS_PWR_REG", CMU_ACLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_SCLKSTOP_SYS_PWR_REG", CMU_SCLKSTOP_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_SYS_PWR_REG", CMU_RESET_SYS_PWR_REG, 0xFFFFFFFF},
- {"APLL_SYSCLK_SYS_PWR_REG", APLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"MPLL_SYSCLK_SYS_PWR_REG", MPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"VPLL_SYSCLK_SYS_PWR_REG", VPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"EPLL_SYSCLK_SYS_PWR_REG", EPLL_SYSCLK_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG", CMU_CLKSTOP_GPS_ALIVE_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"CMU_RESET_GPS_ALIVE_SYS_PWR_REG", CMU_RESET_GPS_ALIVE_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"CMU_CLKSTOP_CAM_SYS_PWR_REG", CMU_CLKSTOP_CAM_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_TV_SYS_PWR_REG", CMU_CLKSTOP_TV_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_MFC_SYS_PWR_REG", CMU_CLKSTOP_MFC_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_G3D_SYS_PWR_REG", CMU_CLKSTOP_G3D_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_LCD0_SYS_PWR_REG", CMU_CLKSTOP_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_LCD1_SYS_PWR_REG", CMU_CLKSTOP_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_CLKSTOP_MAUDIO_SYS_PWR_REG", CMU_CLKSTOP_MAUDIO_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"CMU_CLKSTOP_GPS_SYS_PWR_REG", CMU_CLKSTOP_GPS_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_CAM_SYS_PWR_REG", CMU_RESET_CAM_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_TV_SYS_PWR_REG", CMU_RESET_TV_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_MFC_SYS_PWR_REG", CMU_RESET_MFC_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_G3D_SYS_PWR_REG", CMU_RESET_G3D_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_LCD0_SYS_PWR_REG", CMU_RESET_LCD0_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_LCD1_SYS_PWR_REG", CMU_RESET_LCD1_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_MAUDIO_SYS_PWR_REG", CMU_RESET_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
- {"CMU_RESET_GPS_SYS_PWR_REG", CMU_RESET_GPS_SYS_PWR_REG, 0xFFFFFFFF},
- {"TOP_BUS_SYS_PWR_REG", TOP_BUS_SYS_PWR_REG, 0xFFFFFFFF},
- {"TOP_RETENTION_SYS_PWR_REG", TOP_RETENTION_SYS_PWR_REG, 0xFFFFFFFF},
- {"TOP_PWR_SYS_PWR_REG", TOP_PWR_SYS_PWR_REG, 0xFFFFFFFF},
- {"LOGIC_RESET_SYS_PWR_REG", LOGIC_RESET_SYS_PWR_REG, 0xFFFFFFFF},
- {"OneNANDXL_MEM_SYS_PWR_REG", OneNANDXL_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"MODEMIF_MEM_SYS_PWR_REG", MODEMIF_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"USBDEVICE_MEM_SYS_PWR_REG", USBDEVICE_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"SDMMC_MEM_SYS_PWR_REG", SDMMC_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"CSSYS_MEM_SYS_PWR_REG", CSSYS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"SECSS_MEM_SYS_PWR_REG", SECSS_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"PCIe_MEM_SYS_PWR_REG", PCIe_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"SATA_MEM_SYS_PWR_REG", SATA_MEM_SYS_PWR_REG, 0xFFFFFFFF},
- {"PAD_RETENTION_DRAM_SYS_PWR_REG", PAD_RETENTION_DRAM_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_MAUDIO_SYS_PWR_REG", PAD_RETENTION_MAUDIO_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_GPIO_SYS_PWR_REG", PAD_RETENTION_GPIO_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_UART_SYS_PWR_REG", PAD_RETENTION_UART_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_MMCA_SYS_PWR_REG", PAD_RETENTION_MMCA_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_MMCB_SYS_PWR_REG", PAD_RETENTION_MMCB_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_EBIA_SYS_PWR_REG", PAD_RETENTION_EBIA_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_RETENTION_EBIB_SYS_PWR_REG", PAD_RETENTION_EBIB_SYS_PWR_REG,
- 0xFFFFFFFF},
- {"PAD_ISOLATION_SYS_PWR_REG", PAD_ISOLATION_SYS_PWR_REG, 0xFFFFFFFF},
- {"PAD_ALV_SEL_SYS_PWR_REG", PAD_ALV_SEL_SYS_PWR_REG, 0xFFFFFFFF},
- {"XUSBXTI_SYS_PWR_REG", XUSBXTI_SYS_PWR_REG, 0xFFFFFFFF},
- {"XXTI_SYS_PWR_REG", XXTI_SYS_PWR_REG, 0xFFFFFFFF},
- {"EXT_REGULATOR_SYS_PWR_REG", EXT_REGULATOR_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPIO_MODE_SYS_PWR_REG", GPIO_MODE_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPIO_MODE_MAUDIO_SYS_PWR_REG", GPIO_MODE_MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
- {"CAM_SYS_PWR_REG", CAM_SYS_PWR_REG, 0xFFFFFFFF},
- {"TV_SYS_PWR_REG", TV_SYS_PWR_REG, 0xFFFFFFFF},
- {"MFC_SYS_PWR_REG", MFC_SYS_PWR_REG, 0xFFFFFFFF},
- {"G3D_SYS_PWR_REG", G3D_SYS_PWR_REG, 0xFFFFFFFF},
- {"LCD0_SYS_PWR_REG", LCD0_SYS_PWR_REG, 0xFFFFFFFF},
- {"LCD1_SYS_PWR_REG", LCD1_SYS_PWR_REG, 0xFFFFFFFF},
- {"MAUDIO_SYS_PWR_REG", MAUDIO_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPS_SYS_PWR_REG", GPS_SYS_PWR_REG, 0xFFFFFFFF},
- {"GPS_ALIVE_SYS_PWR_REG", GPS_ALIVE_SYS_PWR_REG, 0xFFFFFFFF},
- {"ARM_CORE0_CONFIGURATION", ARM_CORE0_CONFIGURATION, 0x00000003},
- {"ARM_CORE0_STATUS", ARM_CORE0_STATUS, 0x00030003},
- {"ARM_CORE0_OPTION", ARM_CORE0_OPTION, 0x01010001},
- {"ARM_CORE1_CONFIGURATION", ARM_CORE1_CONFIGURATION, 0x00000003},
- {"ARM_CORE1_STATUS", ARM_CORE1_STATUS, 0x00030003},
- {"ARM_CORE1_OPTION", ARM_CORE1_OPTION, 0x01010001},
- {"ARM_COMMON_OPTION", ARM_COMMON_OPTION, 0x00000001},
- {"ARM_CPU_L2_0_CONFIGURATION", ARM_CPU_L2_0_CONFIGURATION, 0x00000003},
- {"ARM_CPU_L2_0_STATUS", ARM_CPU_L2_0_STATUS, 0x00000003},
- {"ARM_CPU_L2_1_CONFIGURATION", ARM_CPU_L2_1_CONFIGURATION, 0x00000003},
- {"ARM_CPU_L2_1_STATUS", ARM_CPU_L2_1_STATUS, 0x00000003},
- {"PAD_RETENTION_MAUDIO_OPTION", PAD_RETENTION_MAUDIO_OPTION, 0x00000000},
- {"PAD_RETENTION_GPIO_OPTION", PAD_RETENTION_GPIO_OPTION, 0x00000000},
- {"PAD_RETENTION_UART_OPTION", PAD_RETENTION_UART_OPTION, 0x00000000},
- {"PAD_RETENTION_MMCA_OPTION", PAD_RETENTION_MMCA_OPTION, 0x00000000},
- {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000},
- {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000},
- {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000},
- {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200},
- {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001},
- {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001},
- {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000},
- {"XXTI_CONFIGURATION", XXTI_CONFIGURATION, 0x00000001},
- {"XXTI_STATUS", XXTI_STATUS, 0x00000001},
- {"XXTI_DURATION", XXTI_DURATION, 0xFFF00000},
- {"EXT_REGULATOR_DURATION", EXT_REGULATOR_DURATION, 0xFFF03FFF},
- {"CAM_CONFIGURATION", CAM_CONFIGURATION, 0x00000007},
- {"CAM_STATUS", CAM_STATUS, 0x00060007},
- {"CAM_OPTION", CAM_OPTION, 0x00000001},
- {"TV_CONFIGURATION", TV_CONFIGURATION, 0x00000007},
- {"TV_STATUS", TV_STATUS, 0x00060007},
- {"TV_OPTION", TV_OPTION, 0x00000001},
- {"MFC_CONFIGURATION", MFC_CONFIGURATION, 0x00000007},
- {"MFC_STATUS", MFC_STATUS, 0x00060007},
- {"MFC_OPTION", MFC_OPTION, 0x00000001},
- {"G3D_CONFIGURATION", G3D_CONFIGURATION, 0x00000007},
- {"G3D_STATUS", G3D_STATUS, 0x00060007},
- {"G3D_OPTION", G3D_OPTION, 0x00000001},
- {"LCD0_CONFIGURATION", LCD0_CONFIGURATION, 0x00000007},
- {"LCD0_STATUS", LCD0_STATUS, 0x00060007},
- {"LCD0_OPTION", LCD0_OPTION, 0x00000001},
- {"LCD1_CONFIGURATION", LCD1_CONFIGURATION, 0x00000007},
- {"LCD1_STATUS", LCD1_STATUS, 0x00060007},
- {"LCD1_OPTION", LCD1_OPTION, 0x00000001},
- {"GPS_CONFIGURATION", GPS_CONFIGURATION, 0x00000007},
- {"GPS_STATUS", GPS_STATUS, 0x00060007},
- {"GPS_OPTION", GPS_OPTION, 0x00000001},
- {"GPS_ALIVE_CONFIGURATION", GPS_ALIVE_CONFIGURATION, 0x00000007},
- {"GPS_ALIVE_STATUS", GPS_ALIVE_STATUS, 0x00060007},
- {"GPS_ALIVE_OPTION", GPS_ALIVE_OPTION, 0x00000001},
-};
-
-#define PMU_NUM_OF_REGISTERS \
- (sizeof(exynos4210_pmu_regs) / sizeof(Exynos4210PmuReg))
-
-typedef struct Exynos4210PmuState {
- SysBusDevice busdev;
- MemoryRegion iomem;
- uint32_t reg[PMU_NUM_OF_REGISTERS];
-
- ptimer_state *ptimer;
-} Exynos4210PmuState;
-
-static uint64_t exynos4210_pmu_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
- unsigned i;
- const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
-
- for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
- if (reg_p->offset == offset) {
- PRINT_DEBUG_EXTEND("%s [0x%04x] -> 0x%04x\n", reg_p->name,
- (uint32_t)offset, s->reg[i]);
- return s->reg[i];
- }
- reg_p++;
- }
- PRINT_DEBUG("QEMU PMU ERROR: bad read offset 0x%04x\n", (uint32_t)offset);
- return 0;
-}
-
-static void exynos4210_pmu_write(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
-{
- Exynos4210PmuState *s = (Exynos4210PmuState *)opaque;
- unsigned i;
- const Exynos4210PmuReg *reg_p = exynos4210_pmu_regs;
-
- for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
- if (reg_p->offset == offset) {
- PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name,
- (uint32_t)offset, (uint32_t)val);
- s->reg[i] = val;
- break;
- }
- reg_p++;
- }
-
- switch (offset) {
- case SYSTEM_POWER_DOWN_CTRL:
- if (!(val & (1 << 16))) {
- qemu_system_shutdown_request();
- return;
- }
- case SWRESET:
- if (val & 1) {
- qemu_system_reset_request();
- return;
- }
- default:
- break;
- }
-}
-
-static const MemoryRegionOps exynos4210_pmu_ops = {
- .read = exynos4210_pmu_read,
- .write = exynos4210_pmu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- }
-};
-
-static void exynos4210_pmu_reset(DeviceState *dev)
-{
- Exynos4210PmuState *s =
- container_of(dev, Exynos4210PmuState, busdev.qdev);
- unsigned i;
-
- /* Set default values for registers */
- for (i = 0; i < PMU_NUM_OF_REGISTERS; i++) {
- s->reg[i] = exynos4210_pmu_regs[i].reset_value;
- }
-}
-
-static int exynos4210_pmu_init(SysBusDevice *dev)
-{
- Exynos4210PmuState *s = FROM_SYSBUS(Exynos4210PmuState, dev);
-
- /* memory mapping */
- memory_region_init_io(&s->iomem, &exynos4210_pmu_ops, s, "maru_arm.pmu",
- EXYNOS4210_PMU_REGS_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static const VMStateDescription exynos4210_pmu_vmstate = {
- .name = "maru_arm.pmu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_pmu_init;
- dc->reset = exynos4210_pmu_reset;
- dc->vmsd = &exynos4210_pmu_vmstate;
-}
-
-static TypeInfo exynos4210_pmu_info = {
- .name = "maru_arm.pmu",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210PmuState),
- .class_init = exynos4210_pmu_class_init,
-};
-
-static void exynos4210_pmu_register(void)
-{
- type_register_static(&exynos4210_pmu_info);
-}
-
-type_init(exynos4210_pmu_register)
+++ /dev/null
-/*
- * Samsung Maru ARM SoC emulation
- *
- * Based on exynos4210.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "boards.h"
-#include "arm-misc.h"
-#include "sysbus.h"
-#include "pci.h"
-#include "maru_arm.h"
-#include "i2c.h"
-#include "exec-memory.h"
-
-#include "loader.h"
-#include "exynos4210_i2s.h"
-extern int enable_vigs;
-
-#define EXYNOS4210_CHIPID_ADDR 0x10000000
-
-/* CMUs */
-#define EXYNOS4210_CMU_LEFTBUS_BASE_ADDR 0x10034000
-#define EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR 0x10038000
-#define EXYNOS4210_CMU_TOP_BASE_ADDR 0x1003C000
-#define EXYNOS4210_CMU_DMC_BASE_ADDR 0x10040000
-#define EXYNOS4210_CMU_CPU_BASE_ADDR 0x10044000
-
-/* PWM */
-#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000
-
-/* RTC */
-#define EXYNOS4210_RTC_BASE_ADDR 0x10070000
-
-/* MCT */
-#define EXYNOS4210_MCT_BASE_ADDR 0x10050000
-
-/* DMA */
-#define EXYNOS4210_DMAMEM_BASE_ADDR 0x12840000
-#define EXYNOS4210_DMAPERI0_BASE_ADDR 0x12680000
-#define EXYNOS4210_DMAPERI1_BASE_ADDR 0x12690000
-
-/* I2C */
-#define EXYNOS4210_I2C_SHIFT 0x00010000
-#define EXYNOS4210_I2C_BASE_ADDR 0x13860000
-/* Interrupt Group of External Interrupt Combiner for I2C */
-#define EXYNOS4210_I2C_INTG 27
-#define EXYNOS4210_HDMI_INTG 16
-
-/* There are two set of touch screen interfaces, which share one ADC */
-#define EXYNOS4210_TS0_BASE_ADDR 0x13910000
-#define EXYNOS4210_TS1_BASE_ADDR 0x13911000
-#define EXYNOS4210_TS_INTG 19
-
-/* UART's definitions */
-#define EXYNOS4210_UART0_BASE_ADDR 0x13800000
-#define EXYNOS4210_UART1_BASE_ADDR 0x13810000
-#define EXYNOS4210_UART2_BASE_ADDR 0x13820000
-#define EXYNOS4210_UART3_BASE_ADDR 0x13830000
-#define EXYNOS4210_UART0_FIFO_SIZE 256
-#define EXYNOS4210_UART1_FIFO_SIZE 64
-#define EXYNOS4210_UART2_FIFO_SIZE 16
-#define EXYNOS4210_UART3_FIFO_SIZE 16
-/* Interrupt Group of External Interrupt Combiner for UART */
-#define EXYNOS4210_UART_INT_GRP 26
-
-/* External GIC */
-#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000
-#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000
-
-/* Combiner */
-#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000
-#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000
-
-/* SD/MMC host controllers SFR base addresses */
-#define EXYNOS4210_SDHC0_BASE_ADDR 0x12510000
-#define EXYNOS4210_SDHC1_BASE_ADDR 0x12520000
-#define EXYNOS4210_SDHC2_BASE_ADDR 0x12530000
-#define EXYNOS4210_SDHC3_BASE_ADDR 0x12540000
-
-/* PMU SFR base address */
-#define EXYNOS4210_PMU_BASE_ADDR 0x10020000
-
-/* Display controllers (FIMD) */
-#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
-#define EXYNOS4210_FIMD1_BASE_ADDR 0x12000000
-
-/* MALI400 (G3D) */
-#define EXYNOS4210_G3D_BASE_ADDR 0x13000000
-#define EXYNOS4210_G3D_PIXEL_PROC_0_IRQ 0
-#define EXYNOS4210_G3D_PIXEL_PROC_1_IRQ 1
-#define EXYNOS4210_G3D_PIXEL_PROC_2_IRQ 2
-#define EXYNOS4210_G3D_PIXEL_PROC_3_IRQ 3
-#define EXYNOS4210_G3D_GEOM_PROC_IRQ 4
-#define EXYNOS4210_G3D_PMU_IRQ 5
-#define EXYNOS4210_G3D_PPMMU0_IRQ 0
-#define EXYNOS4210_G3D_PPMMU1_IRQ 1
-#define EXYNOS4210_G3D_PPMMU2_IRQ 2
-#define EXYNOS4210_G3D_PPMMU3_IRQ 3
-#define EXYNOS4210_G3D_GPMMU_IRQ 4
-
-/* PPMU */
-#define EXYNOS4210_PPMU_CPU_BASE_ADDR 0x106C0000
-/* DMC */
-#define EXYNOS4210_DMC0_BASE_ADDR 0x10400000
-#define EXYNOS4210_DMC1_BASE_ADDR 0x10410000
-
-/* I2S */
-#define EXYNOS4210_I2S0_BASE_ADDR 0x03830000
-
-/* pl050 ps/2 interface */
-#define EXYNOS4210_PL050_BASE_ADDR 0x12E30000
-
-static uint8_t chipid_and_omr[TARGET_PAGE_SIZE] = { 0x11, 0x02, 0x21, 0x43,
- 0x09, 0x00, 0x00, 0x00 };
-
-void maru_arm_write_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- int n;
- uint32_t smpboot[] = {
- 0xe59f3024, /* ldr r3, External gic_cpu_if */
- 0xe59f2024, /* ldr r2, Internal gic_cpu_if */
- 0xe59f0024, /* ldr r0, startaddr */
- 0xe3a01001, /* mov r1, #1 */
- 0xe5821000, /* str r1, [r2] */
- 0xe5831000, /* str r1, [r3] */
- 0xe320f003, /* wfi */
- 0xe5901000, /* ldr r1, [r0] */
- 0xe1110001, /* tst r1, r1 */
- 0x0afffffb, /* beq <wfi> */
- 0xe12fff11, /* bx r1 */
- EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
- 0, /* gic_cpu_if: base address of Internal GIC CPU interface */
- 0 /* bootreg: Boot register address is held here */
- };
- smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
- smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- smpboot[n] = tswap32(smpboot[n]);
- }
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
-}
-
-Exynos4210State *maru_arm_soc_init(MemoryRegion *system_mem,
- unsigned long ram_size)
-{
- qemu_irq cpu_irq[EXYNOS4210_NCPUS];
- int i, n;
- Exynos4210State *s = g_new(Exynos4210State, 1);
- qemu_irq *irqp;
- qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
- unsigned long mem_size;
- DeviceState *dev;
- SysBusDevice *busdev;
-
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- s->cpu[n] = cpu_arm_init("cortex-a9");
- if (!s->cpu[n]) {
- fprintf(stderr, "Unable to find CPU %d definition\n", n);
- exit(1);
- }
-
- /* Create PIC controller for each processor instance */
- irqp = arm_pic_init_cpu(s->cpu[n]);
-
- /*
- * Get GICs gpio_in cpu_irq to connect a combiner to them later.
- * Use only IRQ for a while.
- */
- cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
- }
-
- /*** IRQs ***/
-
- s->irq_table = exynos4210_init_irq(&s->irqs);
-
- /* IRQ Gate */
- for (i = 0; i < EXYNOS4210_NCPUS; i++) {
- dev = qdev_create(NULL, "exynos4210.irq_gate");
- qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
- qdev_init_nofail(dev);
- /* Get IRQ Gate input in gate_irq */
- for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
- gate_irq[i][n] = qdev_get_gpio_in(dev, n);
- }
- busdev = sysbus_from_qdev(dev);
-
- /* Connect IRQ Gate output to cpu_irq */
- sysbus_connect_irq(busdev, 0, cpu_irq[i]);
- }
-
- /* Private memory region and Internal GIC */
- dev = qdev_create(NULL, "a9mpcore_priv");
- qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- sysbus_connect_irq(busdev, n, gate_irq[n][0]);
- }
- for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
- s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Cache controller */
- sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
-
- /* External GIC */
- dev = qdev_create(NULL, "exynos4210.gic");
- qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- /* Map CPU interface */
- sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
- /* Map Distributer interface */
- sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- sysbus_connect_irq(busdev, n, gate_irq[n][1]);
- }
- for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
- s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Internal Interrupt Combiner */
- dev = qdev_create(NULL, "exynos4210.combiner");
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
- sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
- }
- exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
-
- /* External Interrupt Combiner */
- dev = qdev_create(NULL, "exynos4210.combiner");
- qdev_prop_set_uint32(dev, "external", 1);
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
- sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
- }
- exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
-
- /* Initialize board IRQs. */
- exynos4210_init_board_irqs(&s->irqs);
-
- /*** Memory ***/
-
- /* Chip-ID and OMR */
- memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid",
- sizeof(chipid_and_omr), chipid_and_omr);
- memory_region_set_readonly(&s->chipid_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
- &s->chipid_mem);
-
- /* Internal ROM */
- memory_region_init_ram(&s->irom_mem, "exynos4210.irom",
- EXYNOS4210_IROM_SIZE);
- memory_region_set_readonly(&s->irom_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
- &s->irom_mem);
- /* mirror of iROM */
- memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias",
- &s->irom_mem,
- 0,
- EXYNOS4210_IROM_SIZE);
- memory_region_set_readonly(&s->irom_alias_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
- &s->irom_alias_mem);
-
- /* Internal RAM */
- memory_region_init_ram(&s->iram_mem, "exynos4210.iram",
- EXYNOS4210_IRAM_SIZE);
- vmstate_register_ram_global(&s->iram_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
- &s->iram_mem);
-
- /* DRAM */
- mem_size = ram_size;
- if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
- memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1",
- mem_size - EXYNOS4210_DRAM_MAX_SIZE);
- vmstate_register_ram_global(&s->dram1_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
- &s->dram1_mem);
- mem_size = EXYNOS4210_DRAM_MAX_SIZE;
- }
- memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size);
- vmstate_register_ram_global(&s->dram0_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
- &s->dram0_mem);
-
- /* Audio Subsystem Internal Memory */
- memory_region_init_ram(&s->audss_intmem, "exynos4210.audss",
- EXYNOS4210_AUDSS_INTMEM_SIZE);
- vmstate_register_ram_global(&s->audss_intmem);
- memory_region_add_subregion(system_mem, EXYNOS4210_AUDSS_INTMEM_BASE_ADDR,
- &s->audss_intmem);
-
- /* PMU.
- * The only reason of existence at the moment is that secondary CPU boot
- * loader uses PMU INFORM5 register as a holding pen.
- */
- sysbus_create_simple("maru_arm.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
-
- /* CMUs */
- exynos4210_cmu_create(EXYNOS4210_CMU_LEFTBUS_BASE_ADDR,
- EXYNOS4210_CMU_LEFTBUS);
- exynos4210_cmu_create(EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR,
- EXYNOS4210_CMU_RIGHTBUS);
- exynos4210_cmu_create(EXYNOS4210_CMU_TOP_BASE_ADDR, EXYNOS4210_CMU_TOP);
- exynos4210_cmu_create(EXYNOS4210_CMU_DMC_BASE_ADDR, EXYNOS4210_CMU_DMC);
- exynos4210_cmu_create(EXYNOS4210_CMU_CPU_BASE_ADDR, EXYNOS4210_CMU_CPU);
-
- /* PWM */
- sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(22, 0)],
- s->irq_table[exynos4210_get_irq(22, 1)],
- s->irq_table[exynos4210_get_irq(22, 2)],
- s->irq_table[exynos4210_get_irq(22, 3)],
- s->irq_table[exynos4210_get_irq(22, 4)],
- NULL);
- /* RTC */
- sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(23, 0)],
- s->irq_table[exynos4210_get_irq(23, 1)],
- NULL);
-
- /* Multi Core Timer */
- dev = qdev_create(NULL, "exynos4210.mct");
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- for (n = 0; n < 4; n++) {
- /* Connect global timer interrupts to Combiner gpio_in */
- sysbus_connect_irq(busdev, n,
- s->irq_table[exynos4210_get_irq(1, 4 + n)]);
- }
- /* Connect local timer interrupts to Combiner gpio_in */
- sysbus_connect_irq(busdev, 4,
- s->irq_table[exynos4210_get_irq(51, 0)]);
- sysbus_connect_irq(busdev, 5,
- s->irq_table[exynos4210_get_irq(35, 3)]);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
-
- /*** I2C ***/
- for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
- uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
- qemu_irq i2c_irq;
-
- if (n < 8) {
- i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
- } else {
- i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
- }
-
- dev = qdev_create(NULL, "exynos4210.i2c");
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- sysbus_connect_irq(busdev, 0, i2c_irq);
- sysbus_mmio_map(busdev, 0, addr);
- s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
- }
-
-
- /*** UARTs ***/
- exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
- EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
-
- exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
- EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
-
- exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
- EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
-
- exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
- EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
-
- if (!enable_vigs) {
- /*** Display controller (FIMD) ***/
- sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(11, 0)],
- s->irq_table[exynos4210_get_irq(11, 1)],
- s->irq_table[exynos4210_get_irq(11, 2)],
- NULL);
- }
-
- /* I2S0 */
- s->i2s_bus[0] = exynos4210_i2s_bus_new("exynos4210.i2s",
- EXYNOS4210_I2S0_BASE_ADDR,
- s->irqs.ext_gic_irq[97]);
-
- /* PL050 PS/2 if keyboard */
- sysbus_create_simple("pl050_keyboard", EXYNOS4210_PL050_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(28, 2)]);
-
- return s;
-}
+++ /dev/null
-/*
- * Samsung Tizen Virtual PCI driver
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Vorobiov Stanislav <s.vorobiov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sysbus.h"
-#include "pci.h"
-#include "pci_host.h"
-#include "exec-memory.h"
-
-#define TIZEN_VPCI_VENDOR_ID 0x10ee
-#define TIZEN_VPCI_DEVICE_ID 0x0300
-#define TIZEN_VPCI_CLASS_ID PCI_CLASS_PROCESSOR_CO
-
-#define TIZEN_VPCI_IO_ADDR 0xC3000000
-#define TIZEN_VPCI_IO_SIZE 0xFFFF
-
-typedef struct {
- SysBusDevice busdev;
- qemu_irq irq[4];
- MemoryRegion mem_config;
- MemoryRegion iospace_alias_mem;
-} TizenVPCIState;
-
-static uint64_t tizen_vpci_io_read(void *opaque, target_phys_addr_t addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return cpu_inb(addr);
- case 2:
- return cpu_inw(addr);
- case 4:
- return cpu_inl(addr);
- default:
- break;
- }
- assert(0);
-}
-
-static void tizen_vpci_io_write(void *opaque, target_phys_addr_t addr,
- uint64_t data, unsigned size)
-{
- switch (size) {
- case 1:
- cpu_outb(addr, data);
- return;
- case 2:
- cpu_outw(addr, data);
- return;
- case 4:
- cpu_outl(addr, data);
- return;
- }
- assert(0);
-}
-
-static const MemoryRegionOps tizen_vpci_io_ops = {
- .endianness = DEVICE_LITTLE_ENDIAN,
- .read = tizen_vpci_io_read,
- .write = tizen_vpci_io_write
-};
-
-static inline uint32_t tizen_vpci_config_addr(target_phys_addr_t addr)
-{
- return addr & 0xffffff;
-}
-
-static void tizen_vpci_config_write(void *opaque, target_phys_addr_t addr,
- uint64_t val, unsigned size)
-{
- pci_data_write(opaque, tizen_vpci_config_addr(addr), val, size);
-}
-
-static uint64_t tizen_vpci_config_read(void *opaque, target_phys_addr_t addr,
- unsigned size)
-{
- uint32_t val;
- val = pci_data_read(opaque, tizen_vpci_config_addr(addr), size);
- return val;
-}
-
-static const MemoryRegionOps tizen_vpci_config_ops = {
- .read = tizen_vpci_config_read,
- .write = tizen_vpci_config_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int tizen_vpci_map_irq(PCIDevice *d, int irq_num)
-{
- return irq_num;
-}
-
-static void tizen_vpci_set_irq(void *opaque, int irq_num, int level)
-{
- qemu_irq *pic = opaque;
-
- qemu_set_irq(pic[irq_num], level);
-}
-
-static int tizen_vpci_init(SysBusDevice *dev)
-{
- TizenVPCIState *s = FROM_SYSBUS(TizenVPCIState, dev);
- PCIBus *bus;
- int i;
-
- for (i = 0; i < 4; i++) {
- sysbus_init_irq(dev, &s->irq[i]);
- }
-
- /* On ARM, we only have MMIO no specific IO space from the CPU
- * perspective. In theory we ought to be able to embed the PCI IO
- * memory region direction in the system memory space. However,
- * if any of the IO BAR subregions use the old_portio mechanism,
- * that won't be processed properly unless accessed from the
- * system io address space. This hack to bounce things via
- * system_io works around the problem until all the users of
- * old_portion are updated */
-
- memory_region_init_io(&s->iospace_alias_mem, &tizen_vpci_io_ops, s,
- "tizen_vpci.io-alias", TIZEN_VPCI_IO_SIZE);
- memory_region_add_subregion(get_system_memory(), TIZEN_VPCI_IO_ADDR,
- &s->iospace_alias_mem);
-
- bus = pci_register_bus(&dev->qdev, "pci",
- tizen_vpci_set_irq, tizen_vpci_map_irq, s->irq,
- get_system_memory(), get_system_io(),
- 0, 4);
-
- memory_region_init_io(&s->mem_config, &tizen_vpci_config_ops, bus,
- "tizen-vpci-config", 0x1000000);
- sysbus_init_mmio(dev, &s->mem_config);
-
- pci_create_simple(bus, -1, "tizen_vpci_host");
-
- return 0;
-}
-
-static int tizen_vpci_host_init(PCIDevice *d)
-{
- pci_set_word(d->config + PCI_STATUS,
- PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_FAST);
- return 0;
-}
-
-static void tizen_vpci_host_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = tizen_vpci_host_init;
- k->vendor_id = TIZEN_VPCI_VENDOR_ID;
- k->device_id = TIZEN_VPCI_DEVICE_ID;
- k->class_id = TIZEN_VPCI_CLASS_ID;
-}
-
-static TypeInfo tizen_vpci_host_info = {
- .name = "tizen_vpci_host",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(PCIDevice),
- .class_init = tizen_vpci_host_class_init,
-};
-
-static void tizen_vpci_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = tizen_vpci_init;
-}
-
-static TypeInfo tizen_vpci_info = {
- .name = "tizen_vpci",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TizenVPCIState),
- .class_init = tizen_vpci_class_init,
-};
-
-static void tizen_vpci_register_types(void)
-{
- type_register_static(&tizen_vpci_info);
- type_register_static(&tizen_vpci_host_info);
-}
-
-type_init(tizen_vpci_register_types)
+++ /dev/null
-/*
- * Maru brightness device for VGA
- *
- * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact:
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * DongKyun Yun
- * DoHyung Hong
- * Hyunjun Son
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#include "hw/i386/pc.h"
-#include "ui/console.h"
-#include "hw/pci/pci.h"
-#include "maru_device_ids.h"
-#include "maru_brightness.h"
-#include "skin/maruskin_server.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(tizen, maru-brightness);
-
-#define QEMU_DEV_NAME "maru-brightness"
-
-#define BRIGHTNESS_MEM_SIZE (4 * 1024) /* 4KB */
-#define BRIGHTNESS_REG_SIZE 256
-
-typedef struct BrightnessState {
- PCIDevice dev;
- MemoryRegion mmio_addr;
-} BrightnessState;
-
-enum {
- BRIGHTNESS_LEVEL = 0x00,
- BRIGHTNESS_OFF = 0x04,
-};
-
-uint32_t brightness_level = BRIGHTNESS_MAX;
-bool display_off;
-pixman_color_t level_color;
-pixman_image_t *brightness_image;
-
-/* level : 1 ~ 100, interval : 1 or 2 */
-uint8_t brightness_tbl[] = {155, /* level 0 : for dimming */
-/* level 01 ~ 10 */ 149, 147, 146, 144, 143, 141, 140, 138, 137, 135,
-/* level 11 ~ 20 */ 134, 132, 131, 129, 128, 126, 125, 123, 122, 120,
-/* level 21 ~ 30 */ 119, 117, 116, 114, 113, 111, 110, 108, 107, 105,
-/* level 31 ~ 40 */ 104, 102, 101, 99, 98, 96, 95, 93, 92, 90,
-/* level 41 ~ 50 */ 89, 87, 86, 84, 83, 81, 80, 78, 77, 75,
-/* level 51 ~ 60 */ 74, 72, 71, 69, 68, 66, 65, 63, 62, 60,
-/* level 61 ~ 70 */ 59, 57, 56, 54, 53, 51, 50, 48, 47, 45,
-/* level 71 ~ 80 */ 44, 42, 41, 39, 38, 36, 35, 33, 32, 30,
-/* level 81 ~ 90 */ 29, 27, 26, 24, 23, 21, 20, 18, 17, 15,
-/* level 91 ~ 99 */ 14, 12, 11, 9, 8, 6, 5, 3, 2, 0};
-
-QEMUBH *display_bh;
-
-static uint64_t brightness_reg_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- switch (addr & 0xFF) {
- case BRIGHTNESS_LEVEL:
- INFO("current brightness level = %lu\n", brightness_level);
- return brightness_level;
- case BRIGHTNESS_OFF:
- INFO("device is turned %s\n", display_off ? "off" : "on");
- return display_off;
- default:
- ERR("wrong brightness register read - addr : %d\n", (int)addr);
- break;
- }
-
- return 0;
-}
-
-static void maru_pixman_image_set_alpha(uint8_t value)
-{
- if (brightness_image) {
- pixman_image_unref(brightness_image);
- }
- level_color.alpha = value << 8;
- brightness_image = pixman_image_create_solid_fill(&level_color);
-
- graphic_hw_invalidate(NULL);
-}
-
-static void brightness_reg_write(void *opaque,
- hwaddr addr,
- uint64_t val,
- unsigned size)
-{
- switch (addr & 0xFF) {
- case BRIGHTNESS_LEVEL:
- if (brightness_level == val) {
- return;
- }
-#if BRIGHTNESS_MIN > 0
- if (val < BRIGHTNESS_MIN || val > BRIGHTNESS_MAX) {
-#else
- if (val > BRIGHTNESS_MAX) {
-#endif
- ERR("input value is out of range(%llu)\n", val);
- } else {
- INFO("level changes: %lu -> %llu\n", brightness_level, val);
- brightness_level = val;
- maru_pixman_image_set_alpha(brightness_tbl[brightness_level]);
- }
- return;
- case BRIGHTNESS_OFF:
- if (display_off == val) {
- return;
- }
-
- INFO("status changes: %s\n", val ? "OFF" : "ON");
-
- display_off = val;
- if (display_off) {
- maru_pixman_image_set_alpha(0xFF); /* set black */
- } else {
- maru_pixman_image_set_alpha(brightness_tbl[brightness_level]);
- }
-
- /* notify to skin process */
- qemu_bh_schedule(display_bh);
-
- return;
- default:
- ERR("wrong brightness register write - addr : %d\n", (int)addr);
- break;
- }
-}
-
-static const MemoryRegionOps brightness_mmio_ops = {
- .read = brightness_reg_read,
- .write = brightness_reg_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void brightness_exitfn(PCIDevice *dev)
-{
- BrightnessState *s = DO_UPCAST(BrightnessState, dev, dev);
-
- if (display_bh) {
- qemu_bh_delete(display_bh);
- }
- if (brightness_image) {
- pixman_image_unref(brightness_image);
- brightness_image = NULL;
- }
-
- memory_region_destroy(&s->mmio_addr);
- INFO("finalize maru-brightness device\n");
-}
-
-static void maru_display_bh(void *opaque)
-{
- notify_display_power(!display_off);
-}
-
-static int brightness_initfn(PCIDevice *dev)
-{
- BrightnessState *s = DO_UPCAST(BrightnessState, dev, dev);
- uint8_t *pci_conf = s->dev.config;
-
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_TIZEN);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIRTUAL_BRIGHTNESS);
- pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_OTHER);
-
- memory_region_init_io(&s->mmio_addr, OBJECT(s), &brightness_mmio_ops, s,
- "maru-brightness-mmio", BRIGHTNESS_REG_SIZE);
- pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_addr);
-
- display_bh = qemu_bh_new(maru_display_bh, s);
- brightness_level = BRIGHTNESS_MAX;
- level_color.alpha = 0x0000;
- level_color.red = 0x0000;
- level_color.green = 0x0000;
- level_color.blue = 0x0000;
- brightness_image = pixman_image_create_solid_fill(&level_color);
- INFO("initialize maru-brightness device\n");
-
- return 0;
-}
-
-static void brightness_classinit(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = brightness_initfn;
- k->exit = brightness_exitfn;
-}
-
-static TypeInfo brightness_info = {
- .name = QEMU_DEV_NAME,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(BrightnessState),
- .class_init = brightness_classinit,
-};
-
-static void brightness_register_types(void)
-{
- type_register_static(&brightness_info);
-}
-
-type_init(brightness_register_types);
+++ /dev/null
-/*
- * Maru brightness device for VGA
- *
- * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact:
- * Jinhyung Jo <jinhyung.jo@samsung.com>
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * Hyunjun Son
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef MARU_BRIGHTNESS_H_
-#define MARU_BRIGHTNESS_H_
-
-#include "qemu-common.h"
-#include "ui/qemu-pixman.h"
-
-#define BRIGHTNESS_MIN (0)
-#define BRIGHTNESS_MAX (100)
-
-extern uint32_t brightness_level;
-extern bool display_off;
-extern uint8_t brightness_tbl[];
-extern pixman_image_t *brightness_image;
-
-#endif /* MARU_BRIGHTNESS_H_ */
+++ /dev/null
-/*
- * Virtual Codec Device
- *
- * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Kitae Kim <kt920.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "maru_brill_codec.h"
-
-/* define debug channel */
-MULTI_DEBUG_CHANNEL(qemu, brillcodec);
-
-// device
-#define CODEC_DEVICE_NAME "codec-pci"
-#define CODEC_DEVICE_THREAD "codec-workthread"
-#define CODEC_VERSION 2
-
-// 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
-#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);
-
-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, 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;
-
- qemu_mutex_lock(&s->context_mutex);
- s->idle_thread_cnt = 0;
- qemu_mutex_unlock(&s->context_mutex);
-
- for (index = 0; index < s->worker_thread_cnt; index++) {
- qemu_thread_create(&pthread[index], CODEC_DEVICE_THREAD,
- 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);
-
- qemu_mutex_lock(&s->context_mutex);
-
- if (ioparam->api_index != CODEC_INIT) {
- if (!s->context[ioparam->ctx_index].opened_context) {
- INFO("abandon api %d for context %d\n",
- ioparam->api_index, ioparam->ctx_index);
- qemu_mutex_unlock(&s->context_mutex);
- return;
- }
- }
-
- qemu_mutex_unlock(&s->context_mutex);
-
- 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;
- bool ret = false;
-
- TRACE("enter: %s\n", __func__);
-
- while (s->is_thread_running) {
- int ctx_id = 0, api_id = 0;
- 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);
-
- qemu_mutex_lock(&s->context_mutex);
- s->context[ctx_id].occupied_thread = true;
- qemu_mutex_unlock(&s->context_mutex);
-
- ret = codec_func_handler[api_id](s, ctx_id, indata_buf);
- if (!ret) {
- ERR("fail api %d for context %d\n", api_id, ctx_id);
- g_free(elem->param_buf);
- continue;
- }
-
- TRACE("release a buffer of CodecParam\n");
- g_free(elem->param_buf);
- elem->param_buf = NULL;
-
- if (elem->data_buf) {
- if (elem->data_buf->buf) {
- TRACE("release inbuf\n");
- g_free(elem->data_buf->buf);
- elem->data_buf->buf = NULL;
- }
-
- TRACE("release a buffer indata_buf\n");
- g_free(elem->data_buf);
- elem->data_buf = NULL;
- }
-
- TRACE("release an element of CodecDataStg\n");
- g_free(elem);
-
- qemu_mutex_lock(&s->context_mutex);
- if (s->context[ctx_id].requested_close) {
- INFO("make worker thread to handle deinit\n");
- // codec_deinit(s, ctx_id, NULL);
- maru_brill_codec_release_context(s, ctx_id);
- s->context[ctx_id].requested_close = false;
- }
- qemu_mutex_unlock(&s->context_mutex);
-
- TRACE("switch context to raise interrupt.\n");
- qemu_bh_schedule(s->codec_bh);
-
- qemu_mutex_lock(&s->context_mutex);
- s->context[ctx_id].occupied_thread = false;
- qemu_mutex_unlock(&s->context_mutex);
- }
-
- 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_INIT ... 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,
- CodecParam *ioparam)
-{
- DeviceMemEntry *elem = NULL;
- int readbuf_size, size = 0;
- uint8_t *readbuf = NULL;
- uint8_t *device_mem = mem_base + 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 0. api_id %d, ctx_id %d, mem_offset %x\n",
- 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;
- }
-
- INFO("codec_init. video, resolution: %dx%d, framerate: %d/%d "
- "pixel_fmt: %d sample_aspect_ratio: %d/%d bpp %d\n",
- avctx->width, avctx->height, avctx->time_base.num,
- avctx->time_base.den, avctx->pix_fmt, avctx->sample_aspect_ratio.num,
- avctx->sample_aspect_ratio.den, avctx->bits_per_coded_sample);
-}
-
-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;
- }
-
- INFO("codec_init. audio, channel %d sample_rate %d sample_fmt %d ch_layout %lld\n",
- avctx->channels, avctx->sample_rate, avctx->sample_fmt, avctx->channel_layout);
-}
-
-#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);
-
- qemu_mutex_lock(&s->threadpool.mutex);
- if (s->context[context_id].opened_context) {
- // qemu_mutex_unlock(&s->threadpool.mutex);
- codec_deinit(s, context_id, NULL);
- // qemu_mutex_lock(&s->threadpool.mutex);
- }
- s->context[context_id].occupied_context = false;
- qemu_mutex_unlock(&s->threadpool.mutex);
-
- // 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__);
-
- // requires mutex_lock? its function is protected by critical section.
- qemu_mutex_lock(&s->threadpool.mutex);
- for (index = 1; index < CODEC_CONTEXT_MAX; index++) {
- if (s->context[index].occupied_context == false) {
- TRACE("get %d of codec context successfully.\n", index);
- s->context[index].occupied_context = true;
- break;
- }
- }
- qemu_mutex_unlock(&s->threadpool.mutex);
-
- 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_context3(NULL);
- s->context[index].frame = avcodec_alloc_frame();
- s->context[index].opened_context = false;
-
-#if 0
- s->context[index].parser_buf = NULL;
- s->context[index].parser_use = false;
-#endif
- 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);
-
-#if 0
- memcpy(&audio, mem_buf + size, sizeof(int32_t) * 7);
- size += (sizeof(int32_t) * 7);
- memcpy(&audio.channel_layout, mem_buf + size, sizeof(audio.channel_layout));
- size += sizeof(audio.channel_layout);
-#endif
- memcpy(&audio, mem_buf + size, sizeof(audio));
- size += sizeof(audio);
- 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);
- INFO("extradata size: %d.\n", avctx->extradata_size);
-
- if (avctx->extradata_size > 0) {
- 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 int write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
-{
- int size = 0;
-
- if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
- int osize = av_get_bytes_per_sample(avctx->sample_fmt);
-
- memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
- size = sizeof(avctx->sample_fmt);
-
- // frame_size: samples per packet, initialized when calling 'init'
- memcpy(mem_buf + size, &avctx->frame_size, sizeof(avctx->frame_size));
- size += sizeof(avctx->frame_size);
-
- memcpy(mem_buf + size, &osize, sizeof(osize));
- size += sizeof(osize);
- }
-
- return size;
-}
-
-static uint8_t *resample_audio(AVCodecContext * avctx, AVFrame *samples, int *out_size)
-{
- AVAudioResampleContext *avr = NULL;
- uint8_t *resample_audio = NULL;
- int buffer_size = 0, out_linesize = 0;
- int nb_samples = samples->nb_samples;
- int out_sample_fmt = avctx->sample_fmt - 5;
-
- avr = avresample_alloc_context();
- if (!avr) {
- ERR("failed to allocate avresample context\n");
- return NULL;
- }
-
- av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
- av_opt_set_int(avr, "in_sample_fmt", avctx->sample_fmt, 0);
- av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
- av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
- av_opt_set_int(avr, "out_sample_fmt", out_sample_fmt, 0);
- av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
-
- TRACE("open avresample context\n");
- if (avresample_open(avr) < 0) {
- ERR("failed to open avresample context\n");
- avresample_free(&avr);
- return NULL;
- }
-
- *out_size =
- av_samples_get_buffer_size(&out_linesize, avctx->channels,
- nb_samples, out_sample_fmt, 0);
-
- resample_audio = av_mallocz(*out_size);
- if (!resample_audio) {
- ERR("failed to allocate resample buffer\n");
- avresample_close(avr);
- avresample_free(&avr);
- return NULL;
- }
-
- buffer_size = avresample_convert(avr, &resample_audio,
- out_linesize, nb_samples,
- samples->data, samples->linesize[0],
- samples->nb_samples);
-
- TRACE("resample_audio out_size %d buffer_size %d\n", *out_size, buffer_size);
-
- avresample_close(avr);
- avresample_free(&avr);
-
- return resample_audio;
-}
-
-
-// codec functions
-static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
- AVCodecContext *avctx = NULL;
- AVCodec *codec = NULL;
- int size = 0, ret = -1;
- DeviceMemEntry *elem = NULL;
- uint8_t *tempbuf = NULL;
- int tempbuf_size = 0;
-
- TRACE("enter: %s\n", __func__);
-
- elem = (DeviceMemEntry *)data_buf;
-
- // allocate AVCodecContext
- avctx = maru_brill_codec_alloc_context(s, ctx_id);
- if (!avctx) {
- ERR("[%d] failed to allocate context.\n", __LINE__);
- ret = -1;
- } else {
-#if 0
- avcodec_get_context_defaults(avctx);
-
- avctx->rc_strategy = 2;
- avctx->b_frame_strategy = 0;
- avctx->coder_type = 0;
- avctx->context_model = 0;
- avctx->scenechange_threshold = 0;
- avctx->inter_threshold = 0;
-
- avctx->gop_size = DEFAULT_VIDEO_GOP_SIZE;
- avctx->lmin = (2 * FF_QP2LAMBDA + 0.5);
- avctx->lmax = (31 * FF_QP2LAMBDA + 0.5);
-#endif
-
- codec = maru_brill_codec_find_avcodec(elem->buf);
- if (codec) {
- size = sizeof(int32_t) + 32; // buffer size of codec_name
- read_codec_init_data(avctx, elem->buf + size);
-
- ret = avcodec_open2(avctx, codec, NULL);
- INFO("avcodec_open success! ret %d ctx_id %d\n", ret, ctx_id);
-
- TRACE("channels %d sample_rate %d sample_fmt %d ch_layout %lld\n",
- avctx->channels, avctx->sample_rate,
- avctx->sample_fmt, avctx->channel_layout);
-
- tempbuf_size = (sizeof(avctx->sample_fmt) + sizeof(avctx->frame_size)
- + sizeof(avctx->extradata_size) + avctx->extradata_size)
- + sizeof(int);
-
- s->context[ctx_id].opened_context = 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);
- ret = -1;
- }
- }
-
- tempbuf_size += sizeof(ret);
-
- tempbuf = g_malloc(tempbuf_size);
- if (!tempbuf) {
- ERR("failed to allocate a buffer\n");
- tempbuf_size = 0;
- } else {
- memcpy(tempbuf, &ret, sizeof(ret));
- size = sizeof(ret);
- if (ret < 0) {
- ERR("failed to open codec contex.\n");
- } else {
- size += write_codec_init_data(avctx, tempbuf + size);
- TRACE("codec_init. copyback!! size %d\n", size);
- {
- memcpy(tempbuf + size, &avctx->extradata_size, sizeof(avctx->extradata_size));
- size += sizeof(avctx->extradata_size);
- if (avctx->extradata) {
- memcpy(tempbuf + size, avctx->extradata, avctx->extradata_size);
- size += avctx->extradata_size;
- }
- }
- }
- }
-
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, 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;
- }
-
- INFO("close avcontext of %d\n", ctx_id);
- // qemu_mutex_lock(&s->threadpool.mutex);
- avcodec_close(avctx);
- s->context[ctx_id].opened_context = 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 (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;
- }
-
- maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
-
- TRACE("leave: %s\n", __func__);
-
- return true;
-}
-
-static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
- AVCodecContext *avctx = NULL;
- bool ret = true;
-
- TRACE("enter: %s\n", __func__);
-
- avctx = s->context[ctx_id].avctx;
- if (!avctx) {
- ERR("%d of AVCodecContext is NULL.\n", ctx_id);
- ret = false;
- } else if (!avctx->codec) {
- ERR("%d of AVCodec is NULL.\n", ctx_id);
- ret = false;
- } else {
- TRACE("flush %d context of buffers.\n", ctx_id);
- avcodec_flush_buffers(avctx);
- }
-
- maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
-
- TRACE("leave: %s\n", __func__);
-
- return ret;
-}
-
-static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
- AVCodecContext *avctx = NULL;
- AVFrame *picture = NULL;
- AVPacket avpkt;
- int got_picture = 0, len = -1;
- uint8_t *inbuf = NULL;
- int inbuf_size = 0, idx, size = 0;
- int64_t in_offset;
- DeviceMemEntry *elem = NULL;
- uint8_t *tempbuf = NULL;
- int tempbuf_size = 0;
-
- TRACE("enter: %s\n", __func__);
-
- elem = (DeviceMemEntry *)data_buf;
- if (elem && elem->buf) {
- memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
- size += sizeof(inbuf_size);
- memcpy(&idx, elem->buf + size, sizeof(idx));
- size += sizeof(idx);
- memcpy(&in_offset, elem->buf + size, sizeof(in_offset));
- size += sizeof(in_offset);
- TRACE("decode_video. inbuf_size %d\n", inbuf_size);
-
- if (inbuf_size > 0) {
- inbuf = elem->buf + size;
- }
- } else {
- TRACE("decode_video. no input buffer\n");
- // FIXME: improve error handling
- // 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) {
- ERR("decode_video. %d of AVCodecContext is NULL.\n", ctx_id);
- } else if (!avctx->codec) {
- ERR("decode_video. %d of AVCodec is NULL.\n", ctx_id);
- } else if (!picture) {
- ERR("decode_video. %d of AVFrame is NULL.\n", ctx_id);
- } else {
- // in case of skipping frames
- // picture->pict_type = -1;
-
- TRACE("decode_video. bitrate %d\n", avctx->bit_rate);
- // avctx->reordered_opaque = idx;
- // picture->reordered_opaque = idx;
-
- len =
- avcodec_decode_video2(avctx, picture, &got_picture, &avpkt);
- TRACE("decode_video. in_size %d len %d, frame_size %d\n", avpkt.size, len, got_picture);
- }
-
- tempbuf_size =
- sizeof(len) + sizeof(got_picture) + sizeof(struct video_data);
-
- if (len < 0) {
- ERR("failed to decode video. ctx_id: %d, len: %d\n", ctx_id, len);
- got_picture = 0;
- }
-
- tempbuf = g_malloc(tempbuf_size);
- if (!tempbuf) {
- ERR("failed to allocate decoded audio buffer\n");
- // FIXME: how to handle this case?
- } else {
- struct video_data video;
-
- memcpy(tempbuf, &len, sizeof(len));
- size = sizeof(len);
- memcpy(tempbuf + size, &got_picture, sizeof(got_picture));
- size += sizeof(got_picture);
- if (avctx) {
- deserialize_video_data(avctx, &video);
- memcpy(tempbuf + size, &video, sizeof(struct video_data));
- }
- }
-
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id);
-
- TRACE("leave: %s\n", __func__);
-
- return true;
-}
-
-static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
-{
- AVCodecContext *avctx = NULL;
- AVPicture *src = NULL;
- AVPicture dst;
- uint8_t *out_buffer = NULL, *tempbuf = NULL;
- int pict_size = 0;
- bool ret = true;
-
- 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) {
- ERR("picture_copy. %d of AVCodecContext is NULL.\n", ctx_id);
- ret = false;
- } else if (!avctx->codec) {
- ERR("picture_copy. %d of AVCodec is NULL.\n", ctx_id);
- ret = false;
- } else if (!src) {
- ERR("picture_copy. %d of AVFrame is NULL.\n", ctx_id);
- ret = false;
- } 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);
- ret = false;
- } 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 ret;
-}
-
-static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
- AVCodecContext *avctx;
- AVPacket avpkt;
- AVFrame *samples = NULL;
- uint8_t *inbuf = NULL;
- int inbuf_size = 0, size = 0;
- int len = -1, got_frame = 0;
-
- DeviceMemEntry *elem = NULL;
- uint8_t *tempbuf = NULL;
- int tempbuf_size = 0;
-
- uint8_t *outbuf = NULL;
- int buffer_size = 0;
- int out_sample_fmt = -1;
-
- TRACE("enter: %s\n", __func__);
-
- elem = (DeviceMemEntry *)data_buf;
- if (elem && elem->buf) {
- memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
- size = sizeof(inbuf_size);
- TRACE("decode_audio. inbuf_size %d\n", inbuf_size);
-
- if (inbuf_size > 0) {
- inbuf = elem->buf + size;
- }
- } else {
- ERR("decode_audio. no input buffer\n");
- // FIXME: improve error handling
- // return false;
- }
-
- av_init_packet(&avpkt);
- avpkt.data = inbuf;
- avpkt.size = inbuf_size;
-
- avctx = s->context[ctx_id].avctx;
- samples = s->context[ctx_id].frame;
- if (!avctx) {
- ERR("decode_audio. %d of AVCodecContext is NULL\n", ctx_id);
- } else if (!avctx->codec) {
- ERR("decode_audio. %d of AVCodec is NULL\n", ctx_id);
- } else if (!samples) {
- ERR("decode_audio. %d of AVFrame is NULL\n", ctx_id);
- } else {
- avcodec_get_frame_defaults(samples);
-
- len = avcodec_decode_audio4(avctx, samples, &got_frame, &avpkt);
- TRACE("decode_audio. len %d, channel_layout %lld, frame_size %d\n",
- len, avctx->channel_layout, got_frame);
- if (got_frame) {
- if (av_sample_fmt_is_planar(avctx->sample_fmt)) {
- out_sample_fmt = avctx->sample_fmt - 5;
-
- outbuf = resample_audio (avctx, samples, &buffer_size);
- } else {
- // TODO: not planar format
- }
- }
- }
-
- tempbuf_size = (sizeof(len) + sizeof(got_frame));
- if (len < 0) {
- ERR("failed to decode audio. ctx_id: %d len: %d got_frame: %d\n",
- ctx_id, len, got_frame);
- got_frame = 0;
- } else {
- tempbuf_size += (sizeof(out_sample_fmt) + sizeof(avctx->sample_rate)
- + sizeof(avctx->channels) + sizeof(avctx->channel_layout)
- + sizeof(buffer_size) + buffer_size);
- }
-
- tempbuf = g_malloc(tempbuf_size);
- if (!tempbuf) {
- ERR("failed to allocate decoded audio buffer\n");
- } else {
- memcpy(tempbuf, &len, sizeof(len));
- size = sizeof(len);
- memcpy(tempbuf + size, &got_frame, sizeof(got_frame));
- size += sizeof(got_frame);
- if (got_frame) {
- memcpy(tempbuf + size, &out_sample_fmt, sizeof(out_sample_fmt));
- size += sizeof(out_sample_fmt);
- memcpy(tempbuf + size, &avctx->sample_rate, sizeof(avctx->sample_rate));
- size += sizeof(avctx->sample_rate);
- memcpy(tempbuf + size, &avctx->channels, sizeof(avctx->channels));
- size += sizeof(avctx->channels);
- memcpy(tempbuf + size, &avctx->channel_layout, sizeof(avctx->channel_layout));
- size += sizeof(avctx->channel_layout);
-
- memcpy(tempbuf + size, &buffer_size, sizeof(buffer_size));
- size += sizeof(buffer_size);
-
- if (outbuf) {
- memcpy(tempbuf + size, outbuf, buffer_size);
- av_free(outbuf);
- }
- }
- }
-
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, 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;
- AVPacket avpkt;
- uint8_t *inbuf = NULL, *outbuf = NULL;
- int inbuf_size = 0, outbuf_size = 0;
- int got_frame = 0, ret = 0, size = 0;
- int64_t in_timestamp = 0;
- int coded_frame = 0, key_frame = 0;
-
- DeviceMemEntry *elem = NULL;
- uint8_t *tempbuf = NULL;
- int tempbuf_size = 0;
-
- TRACE("enter: %s\n", __func__);
-
- elem = (DeviceMemEntry *)data_buf;
- if (elem && elem->buf) {
- memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
- size += sizeof(inbuf_size);
- memcpy(&in_timestamp, elem->buf + size, sizeof(in_timestamp));
- size += sizeof(in_timestamp);
- TRACE("encode video. inbuf_size %d\n", inbuf_size);
-
- if (inbuf_size > 0) {
- inbuf = elem->buf + size;
- }
- } else {
- TRACE("encode video. no input buffer.\n");
- // FIXME: improve error handling
- // return false;
- }
-
- av_init_packet(&avpkt);
- avpkt.data = NULL;
- avpkt.size = 0;
-
- 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);
- } else if (!avctx->codec) {
- ERR("%d of AVCodec is NULL.\n", ctx_id);
- } 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);
- } 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("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);
-
- avpkt.data = outbuf;
- avpkt.size = outbuf_size;
-
- if (!outbuf) {
- ERR("failed to allocate a buffer of encoding video.\n");
- } else {
- ret = avcodec_encode_video2(avctx, &avpkt, pict, &got_frame);
-
- TRACE("encode video. ret %d got_picture %d outbuf_size %d\n", ret, got_frame, avpkt.size);
- if (avctx->coded_frame) {
- TRACE("encode video. keyframe %d\n", avctx->coded_frame->key_frame);
- }
- }
- }
- }
-
- tempbuf_size = sizeof(ret);
- if (ret < 0) {
- ERR("failed to encode video. ctx_id %d ret %d\n", ctx_id, ret);
- } else {
- tempbuf_size += avpkt.size + sizeof(coded_frame) + sizeof(key_frame);
- }
-
- // write encoded video data
- tempbuf = g_malloc0(tempbuf_size);
- if (!tempbuf) {
- ERR("encode video. failed to allocate encoded out buffer.\n");
- } else {
- memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
- size = sizeof(avpkt.size);
-
- if ((got_frame) && outbuf) {
- // inform gstreamer plugin about the status of encoded frames
- // A flag for output buffer in gstreamer is depending on the status.
- if (avctx->coded_frame) {
- coded_frame = 1;
- // if key_frame is 0, this frame cannot be decoded independently.
- key_frame = avctx->coded_frame->key_frame;
- }
- memcpy(tempbuf + size, &coded_frame, sizeof(coded_frame));
- size += sizeof(coded_frame);
- memcpy(tempbuf + size, &key_frame, sizeof(key_frame));
- size += sizeof(key_frame);
- memcpy(tempbuf + size, outbuf, avpkt.size);
- }
- }
-
- if (outbuf) {
- TRACE("release encoded output buffer. %p\n", outbuf);
- g_free(outbuf);
- }
-
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id);
-
- TRACE("leave: %s\n", __func__);
- return true;
-}
-
-static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
-{
- AVCodecContext *avctx;
- AVPacket avpkt;
- uint8_t *inbuf = NULL, *outbuf = NULL;
- int32_t inbuf_size = 0, max_size = 0;
- int ret = 0, got_pkt = 0, size = 0;
-
- DeviceMemEntry *elem = NULL;
- uint8_t *tempbuf = NULL;
- int tempbuf_size = 0;
-
- TRACE("enter: %s\n", __func__);
-
- elem = (DeviceMemEntry *)data_buf;
- if (elem && elem->buf) {
- memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
- size += sizeof(inbuf_size);
- // memcpy(&max_size, elem->buf + size, sizeof(max_size));
- // size += sizeof(max_size);
- max_size = inbuf_size * 4; // + FF_MIN_BUFFER_SIZE;
- TRACE("encode_video. inbuf_size %d max_size %d\n", inbuf_size, max_size);
-
- if (inbuf_size > 0) {
- // inbuf = g_malloc(inbuf_size);
- // memcpy(inbuf, elem->buf + size, inbuf_size);
- inbuf = elem->buf + size;
- }
- } else {
- TRACE("encode_audio. no input buffer\n");
- // FIXME: improve error handling
- // return false;
- }
-
- av_init_packet(&avpkt);
- avpkt.data = NULL;
- avpkt.size = 0;
-
- 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);
- // outbuf = g_malloc0(max_size);
-
- avpkt.data = outbuf;
- avpkt.size = max_size;
-
- if (!outbuf) {
- ERR("failed to allocate a buffer of encoding audio.\n");
- } else {
- ret = avcodec_encode_audio2(avctx, &avpkt, (const AVFrame *)inbuf, &got_pkt);
- TRACE("encode audio. ret %d got_pkt %d outbuf_size %d\n", ret, got_pkt, avpkt.size);
- }
- }
-
- tempbuf_size = sizeof(ret);
- if (ret < 0) {
- ERR("failed to encode audio. ctx_id %d ret %d\n", ctx_id, ret);
- } else {
- // tempbuf_size += (max_size); // len;
- tempbuf_size += avpkt.size;
- }
-
- // write encoded audio data
- tempbuf = g_malloc0(tempbuf_size);
- if (!tempbuf) {
- ERR("encode audio. failed to allocate encoded out buffer.\n");
- } else {
- memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
- size = sizeof(avpkt.size);
- if (got_pkt && outbuf) {
- // memcpy(tempbuf + size, outbuf, max_size); // len);
- memcpy(tempbuf + size, outbuf, avpkt.size);
- }
- }
-
- if (outbuf) {
- av_free(outbuf);
- }
-
- maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, 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");
- pci_set_irq(&s->dev, 1);
- s->irq_raised = 1;
- } else {
- qemu_mutex_unlock(&s->context_queue_mutex);
- TRACE("codec_wq is empty!!\n");
- }
-
- TRACE("leave: %s\n", __func__);
-}
-
-/*
- * Codec Device APIs
- */
-static uint64_t maru_brill_codec_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
- uint64_t ret = 0;
-
- switch (addr) {
- case CODEC_CMD_GET_THREAD_STATE:
- qemu_mutex_lock(&s->context_queue_mutex);
- if (s->irq_raised) {
- ret = CODEC_TASK_END;
- pci_set_irq(&s->dev, 0);
- s->irq_raised = 0;
- }
- qemu_mutex_unlock(&s->context_queue_mutex);
-
- TRACE("get thread_state. ret: %d\n", ret);
- break;
-
- case CODEC_CMD_GET_CTX_FROM_QUEUE:
- {
- DeviceMemEntry *head = NULL;
-
- qemu_mutex_lock(&s->context_queue_mutex);
- head = QTAILQ_FIRST(&codec_wq);
- if (head) {
- ret = head->ctx_id;
- QTAILQ_REMOVE(&codec_wq, head, node);
- entry[ret] = head;
- TRACE("get a elem from codec_wq. 0x%x\n", head);
- } else {
- ret = 0;
- }
- qemu_mutex_unlock(&s->context_queue_mutex);
-
- TRACE("get a head from a writequeue. head: %x\n", ret);
- }
- break;
-
- case CODEC_CMD_GET_VERSION:
- ret = CODEC_VERSION;
- TRACE("codec version: %d\n", ret);
- break;
-
- case CODEC_CMD_GET_ELEMENT:
- ret = maru_brill_codec_query_list(s);
- break;
-
- case CODEC_CMD_GET_CONTEXT_INDEX:
- ret = maru_brill_codec_get_context_index(s);
- TRACE("get context index: %d\n", ret);
- break;
-
- default:
- ERR("no avaiable command for read. %d\n", addr);
- }
-
- return ret;
-}
-
-static void maru_brill_codec_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
-
- switch (addr) {
- case CODEC_CMD_API_INDEX:
- TRACE("set codec_cmd value: %d\n", value);
- s->ioparam.api_index = value;
- maru_brill_codec_wakeup_threads(s, value);
- break;
-
- case CODEC_CMD_CONTEXT_INDEX:
- TRACE("set context_index value: %d\n", value);
- s->ioparam.ctx_index = value;
- break;
-
- case CODEC_CMD_DEVICE_MEM_OFFSET:
- TRACE("set mem_offset value: 0x%x\n", value);
- s->ioparam.mem_offset = value;
- break;
-
- case CODEC_CMD_RELEASE_CONTEXT:
- {
- int ctx_index = (int32_t)value;
-
- if (s->context[ctx_index].occupied_thread) {
- s->context[ctx_index].requested_close = true;
- INFO("make running thread to handle deinit\n");
- } else {
- maru_brill_codec_release_context(s, ctx_index);
- }
- }
- 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);
-
- 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)
+++ /dev/null
-/*
- * Virtual Codec device
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Kitae Kim <kt920.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "hw/hw.h"
-#include "sysemu/kvm.h"
-#include "qemu/main-loop.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_ids.h"
-#include "qemu-common.h"
-#include "qemu/thread.h"
-
-#include "util/osutil.h"
-#include "debug_ch.h"
-#include "maru_device_ids.h"
-
-#include "libavformat/avformat.h"
-#include "libavresample/avresample.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.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;
- int32_t reserved;
- int64_t channel_layout;
-};
-
-typedef struct CodecContext {
- AVCodecContext *avctx;
- AVFrame *frame;
- AVCodecParserContext *parser_ctx;
- uint8_t *parser_buf;
- uint16_t parser_use;
- bool occupied_context;
- bool occupied_thread;
- bool opened_context;
- bool requested_close;
-} CodecContext;
-
-typedef struct CodecThreadPool {
- QemuThread *threads;
- QemuMutex mutex;
- QemuCond cond;
-} CodecThreadPool;
-
-typedef struct MaruBrillCodecState {
- PCIDevice dev;
-
- uint8_t *vaddr;
- MemoryRegion vram;
- MemoryRegion mmio;
-
- QEMUBH *codec_bh;
- QemuMutex context_mutex;
- QemuMutex context_queue_mutex;
- QemuMutex ioparam_queue_mutex;
-
- CodecThreadPool threadpool;
- bool is_thread_running;
- uint32_t worker_thread_cnt;
- uint32_t idle_thread_cnt;
-
- int irq_raised;
-
- CodecContext context[CODEC_CONTEXT_MAX];
- CodecParam ioparam;
-} MaruBrillCodecState;
-
-enum codec_io_cmd {
- CODEC_CMD_API_INDEX = 0x28,
- CODEC_CMD_CONTEXT_INDEX = 0x2C,
- CODEC_CMD_DEVICE_MEM_OFFSET = 0x34,
- CODEC_CMD_GET_THREAD_STATE = 0x38,
- CODEC_CMD_GET_CTX_FROM_QUEUE = 0x3C,
- CODEC_CMD_GET_DATA_FROM_QUEUE = 0x40,
- CODEC_CMD_RELEASE_CONTEXT = 0x44,
- CODEC_CMD_GET_VERSION = 0x50,
- CODEC_CMD_GET_ELEMENT = 0x54,
- CODEC_CMD_GET_CONTEXT_INDEX = 0x58,
-};
-
-enum codec_api_type {
- CODEC_INIT = 0,
- CODEC_DECODE_VIDEO,
- CODEC_ENCODE_VIDEO,
- CODEC_DECODE_AUDIO,
- CODEC_ENCODE_AUDIO,
- CODEC_PICTURE_COPY,
- CODEC_DEINIT,
- CODEC_FLUSH_BUFFERS,
- };
-
-enum codec_type {
- CODEC_TYPE_UNKNOWN = -1,
- CODEC_TYPE_DECODE,
- CODEC_TYPE_ENCODE,
-};
-
-enum thread_state {
- CODEC_TASK_START = 0,
- CODEC_TASK_END = 0x1f,
-};
-
-/*
- * Codec Device Functions
- */
-int maru_brill_codec_pci_device_init(PCIBus *bus);
+++ /dev/null
-/*
- * Common header of MARU Virtual Camera device.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef _MARU_CAMERA_COMMON_H_
-#define _MARU_CAMERA_COMMON_H_
-
-#include "hw/pci/pci.h"
-#include "qemu/thread.h"
-
-#define MARUCAM_MAX_PARAM 20
-#define MARUCAM_SKIPFRAMES 2
-
-/* must sync with GUEST camera_driver */
-#define MARUCAM_CMD_INIT 0x00
-#define MARUCAM_CMD_OPEN 0x04
-#define MARUCAM_CMD_CLOSE 0x08
-#define MARUCAM_CMD_ISR 0x0C
-#define MARUCAM_CMD_START_PREVIEW 0x10
-#define MARUCAM_CMD_STOP_PREVIEW 0x14
-#define MARUCAM_CMD_S_PARAM 0x18
-#define MARUCAM_CMD_G_PARAM 0x1C
-#define MARUCAM_CMD_ENUM_FMT 0x20
-#define MARUCAM_CMD_TRY_FMT 0x24
-#define MARUCAM_CMD_S_FMT 0x28
-#define MARUCAM_CMD_G_FMT 0x2C
-#define MARUCAM_CMD_QCTRL 0x30
-#define MARUCAM_CMD_S_CTRL 0x34
-#define MARUCAM_CMD_G_CTRL 0x38
-#define MARUCAM_CMD_ENUM_FSIZES 0x3C
-#define MARUCAM_CMD_ENUM_FINTV 0x40
-#define MARUCAM_CMD_S_DATA 0x44
-#define MARUCAM_CMD_G_DATA 0x48
-#define MARUCAM_CMD_DATACLR 0x50
-#define MARUCAM_CMD_REQFRAME 0x54
-
-typedef struct MaruCamState MaruCamState;
-typedef struct MaruCamParam MaruCamParam;
-
-struct MaruCamParam {
- uint32_t top;
- uint32_t retVal;
- uint32_t errCode;
- uint32_t stack[MARUCAM_MAX_PARAM];
-};
-
-struct MaruCamState {
- PCIDevice dev;
- MaruCamParam *param;
- QemuThread thread_id;
- QemuMutex thread_mutex;;
- QemuCond thread_cond;
- QEMUBH *tx_bh;
-
- bool initialized;
- bool destroying;
- void *vaddr; /* vram ptr */
- uint32_t isr;
- uint32_t streamon;
- uint32_t buf_size;
- uint32_t req_frame;
-
- MemoryRegion vram;
- MemoryRegion mmio;
-};
-
-/* ------------------------------------------------------------------------- */
-/* Fucntion prototype */
-/* ------------------------------------------------------------------------- */
-int marucam_device_check(int log_flag);
-void marucam_device_init(MaruCamState *state);
-void marucam_device_exit(MaruCamState *state);
-void marucam_device_open(MaruCamState *state);
-void marucam_device_close(MaruCamState *state);
-void marucam_device_start_preview(MaruCamState *state);
-void marucam_device_stop_preview(MaruCamState *state);
-void marucam_device_s_param(MaruCamState *state);
-void marucam_device_g_param(MaruCamState *state);
-void marucam_device_s_fmt(MaruCamState *state);
-void marucam_device_g_fmt(MaruCamState *state);
-void marucam_device_try_fmt(MaruCamState *state);
-void marucam_device_enum_fmt(MaruCamState *state);
-void marucam_device_qctrl(MaruCamState *state);
-void marucam_device_s_ctrl(MaruCamState *state);
-void marucam_device_g_ctrl(MaruCamState *state);
-void marucam_device_enum_fsizes(MaruCamState *state);
-void marucam_device_enum_fintv(MaruCamState *state);
-
-int maru_camera_pci_init(PCIBus *bus);
-
-#endif /* _MARU_CAMERA_COMMON_H_ */
+++ /dev/null
-/*
- * Common implementation of MARU Virtual Camera device by PCI bus.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-
-#include "qemu-common.h"
-#include "qemu/main-loop.h"
-#include "exec/cpu-common.h"
-
-#include "maru_camera_common.h"
-#include "maru_device_ids.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(tizen, maru-camera);
-
-#define MARU_PCI_CAMERA_DEVICE_NAME "maru-camera"
-
-#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) {
- pci_set_irq(&state->dev, 0);
- state->isr = 0;
- }
- qemu_mutex_unlock(&state->thread_mutex);
- break;
- case MARUCAM_CMD_G_DATA:
- ret = state->param->stack[state->param->top++];
- break;
- case MARUCAM_CMD_OPEN:
- case MARUCAM_CMD_CLOSE:
- case MARUCAM_CMD_START_PREVIEW:
- case MARUCAM_CMD_STOP_PREVIEW:
- case MARUCAM_CMD_S_PARAM:
- case MARUCAM_CMD_G_PARAM:
- case MARUCAM_CMD_ENUM_FMT:
- case MARUCAM_CMD_TRY_FMT:
- case MARUCAM_CMD_S_FMT:
- case MARUCAM_CMD_G_FMT:
- case MARUCAM_CMD_QCTRL:
- case MARUCAM_CMD_S_CTRL:
- case MARUCAM_CMD_G_CTRL:
- case MARUCAM_CMD_ENUM_FSIZES:
- case MARUCAM_CMD_ENUM_FINTV:
- ret = state->param->errCode;
- state->param->errCode = 0;
- break;
- default:
- ERR("Not supported command: 0x%x\n", offset);
- ret = EINVAL;
- break;
- }
- return ret;
-}
-
-static inline void
-marucam_mmio_write(void *opaque, hwaddr offset, uint32_t value)
-{
- MaruCamState *state = (MaruCamState *)opaque;
-
- switch (offset & 0xFF) {
- case MARUCAM_CMD_OPEN:
- marucam_device_open(state);
- break;
- case MARUCAM_CMD_CLOSE:
- marucam_device_close(state);
- break;
- case MARUCAM_CMD_START_PREVIEW:
- marucam_device_start_preview(state);
- break;
- case MARUCAM_CMD_STOP_PREVIEW:
- marucam_device_stop_preview(state);
- memset(state->vaddr, 0, MARUCAM_MEM_SIZE);
- break;
- case MARUCAM_CMD_S_PARAM:
- marucam_device_s_param(state);
- break;
- case MARUCAM_CMD_G_PARAM:
- marucam_device_g_param(state);
- break;
- case MARUCAM_CMD_ENUM_FMT:
- marucam_device_enum_fmt(state);
- break;
- case MARUCAM_CMD_TRY_FMT:
- marucam_device_try_fmt(state);
- break;
- case MARUCAM_CMD_S_FMT:
- marucam_device_s_fmt(state);
- break;
- case MARUCAM_CMD_G_FMT:
- marucam_device_g_fmt(state);
- break;
- case MARUCAM_CMD_QCTRL:
- marucam_device_qctrl(state);
- break;
- case MARUCAM_CMD_S_CTRL:
- marucam_device_s_ctrl(state);
- break;
- case MARUCAM_CMD_G_CTRL:
- marucam_device_g_ctrl(state);
- break;
- case MARUCAM_CMD_ENUM_FSIZES:
- marucam_device_enum_fsizes(state);
- break;
- case MARUCAM_CMD_ENUM_FINTV:
- marucam_device_enum_fintv(state);
- break;
- case MARUCAM_CMD_S_DATA:
- state->param->stack[state->param->top++] = value;
- break;
- case MARUCAM_CMD_DATACLR:
- memset(state->param, 0, sizeof(MaruCamParam));
- break;
- case MARUCAM_CMD_REQFRAME:
- qemu_mutex_lock(&state->thread_mutex);
- state->req_frame = value + 1;
- qemu_mutex_unlock(&state->thread_mutex);
- break;
- default:
- ERR("Not supported command: 0x%x\n", offset);
- break;
- }
-}
-
-static const MemoryRegionOps maru_camera_mmio_ops = {
- .old_mmio = {
- .read = {
- marucam_mmio_read,
- marucam_mmio_read,
- marucam_mmio_read,
- },
- .write = {
- marucam_mmio_write,
- marucam_mmio_write,
- marucam_mmio_write,
- },
- },
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/*
- * QEMU bottom half funtion
- */
-static void marucam_tx_bh(void *opaque)
-{
- MaruCamState *state = (MaruCamState *)opaque;
-
- qemu_mutex_lock(&state->thread_mutex);
- if (state->isr) {
- pci_set_irq(&state->dev, 1);
- }
- qemu_mutex_unlock(&state->thread_mutex);
-}
-
-/*
- * Initialization function
- */
-
-static int marucam_initfn(PCIDevice *dev)
-{
- MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);
- uint8_t *pci_conf = s->dev.config;
-
- /* Check available webcam
- * If there is not one, you can't use the camera.
- */
- if (!marucam_device_check(1)) {
- s->initialized = false;
- ERR("Failed to check the camera device, "
- "You can *not* use the camera\n");
- return 0;
- }
-
- 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);
- s->initialized = true;
- INFO("initialize maru-camera device\n");
-
- return 0;
-}
-
-/*
- * Termination function
- */
-static void marucam_exitfn(PCIDevice *pci_dev)
-{
- MaruCamState *s =
- OBJECT_CHECK(MaruCamState, pci_dev, MARU_PCI_CAMERA_DEVICE_NAME);
-
- if (s->initialized) {
- 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("finalize maru-camera device\n");
-}
-
-static void marucam_resetfn(DeviceState *d)
-{
- MaruCamState *s = (MaruCamState *)d;
-
- if (s->initialized) {
- marucam_device_close(s);
- qemu_mutex_lock(&s->thread_mutex);
- s->isr = s->streamon = s->req_frame = s->buf_size = 0;
- qemu_mutex_unlock(&s->thread_mutex);
- memset(s->vaddr, 0, MARUCAM_MEM_SIZE);
- memset(s->param, 0x00, sizeof(MaruCamParam));
- INFO("reset maru-camera device\n");
- }
-}
-
-int maru_camera_pci_init(PCIBus *bus)
-{
- 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->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->reset = marucam_resetfn;
- dc->desc = "MARU Virtual Camera device for Tizen emulator";
-}
-
-static TypeInfo maru_camera_info = {
- .name = MARU_PCI_CAMERA_DEVICE_NAME,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(MaruCamState),
- .class_init = maru_camera_pci_class_init,
-};
-
-static void maru_camera_pci_register_types(void)
-{
- type_register_static(&maru_camera_info);
-}
-
-type_init(maru_camera_pci_register_types)
+++ /dev/null
-/*
- * Header of MARU Virtual Camera device for MacOS.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jun Tian <jun.j.tian@intel.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef _MARU_CAMERA_DARWIN_H_
-#define _MARU_CAMERA_DARWIN_H_
-
-#define MAKEFOURCC(a, b, c, d) \
- (((uint32_t)(a) << 0) | \
- ((uint32_t)(b) << 8) | \
- ((uint32_t)(c) << 16) | \
- ((uint32_t)(d) << 24))
-
-/* 16 RGB-5-5-5 */
-#define V4L2_PIX_FMT_RGB555 MAKEFOURCC('R', 'G', 'B', 'O')
-/* 16 RGB-5-6-5 */
-#define V4L2_PIX_FMT_RGB565 MAKEFOURCC('R', 'G', 'B', 'P')
-/* 16 RGB-5-5-5 BE */
-#define V4L2_PIX_FMT_RGB555X MAKEFOURCC('R', 'G', 'B', 'Q')
-/* 16 RGB-5-6-5 BE */
-#define V4L2_PIX_FMT_RGB565X MAKEFOURCC('R', 'G', 'B', 'R')
-/* 24 BGR-8-8-8 */
-#define V4L2_PIX_FMT_BGR24 MAKEFOURCC('B', 'G', 'R', '3')
-/* 24 RGB-8-8-8 */
-#define V4L2_PIX_FMT_RGB24 MAKEFOURCC('R', 'G', 'B', '3')
-/* 32 BGR-8-8-8-8 */
-#define V4L2_PIX_FMT_BGR32 MAKEFOURCC('B', 'G', 'R', '4')
-/* 32 RGB-8-8-8-8 */
-#define V4L2_PIX_FMT_RGB32 MAKEFOURCC('R', 'G', 'B', '4')
-/* 9 YVU 4:1:0 */
-#define V4L2_PIX_FMT_YVU410 MAKEFOURCC('Y', 'V', 'U', '9')
-/* 12 YVU 4:2:0 */
-#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2')
-/* 16 YUV 4:2:2 */
-#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V')
-/* 16 YUV 4:2:2 */
-#define V4L2_PIX_FMT_UYVY MAKEFOURCC('U', 'Y', 'V', 'Y')
-/* 16 YVU422 planar */
-#define V4L2_PIX_FMT_YUV422P MAKEFOURCC('4', '2', '2', 'P')
-/* 16 YVU411 planar */
-#define V4L2_PIX_FMT_YUV411P MAKEFOURCC('4', '1', '1', 'P')
-/* 12 YUV 4:1:1 */
-#define V4L2_PIX_FMT_Y41P MAKEFOURCC('Y', '4', '1', 'P')
-/* 16 xxxxyyyy uuuuvvvv */
-#define V4L2_PIX_FMT_YUV444 MAKEFOURCC('Y', '4', '4', '4')
-/* 16 YUV-5-5-5 */
-#define V4L2_PIX_FMT_YUV555 MAKEFOURCC('Y', 'U', 'V', 'O')
-/* 16 YUV-5-6-5 */
-#define V4L2_PIX_FMT_YUV565 MAKEFOURCC('Y', 'U', 'V', 'P')
-/* 32 YUV-8-8-8-8 */
-#define V4L2_PIX_FMT_YUV32 MAKEFOURCC('Y', 'U', 'V', '4')
-/* 9 YUV 4:1:0 */
-#define V4L2_PIX_FMT_YUV410 MAKEFOURCC('Y', 'U', 'V', '9')
-/* 12 YUV 4:2:0 */
-#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2')
-/* 16 YUV 4:2:2 */
-#define V4L2_PIX_FMT_YYUV MAKEFOURCC('Y', 'Y', 'U', 'V')
-
-void convert_frame(uint32_t pixel_format, int frame_width, int frame_height,
- size_t frame_size, void *frame_pixels, void *video_buf);
-
-#endif /* _MARU_CAMERA_DARWIN_H_ */
+++ /dev/null
-/*
- * Implementation of color conversion for MARU Virtual Camera device on MacOS.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jun Tian <jun.j.tian@intel.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "qemu-common.h"
-#include "maru_camera_darwin.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(tizen, camera_darwin);
-
-static void UYVYToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
- int width, int height);
-static void YVU420ToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
- int width, int height);
-static void YUYVToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
- int width, int height);
-
-/* Convert pixel format to YUV420 */
-void convert_frame(uint32_t pixel_format, int frame_width, int frame_height,
- size_t frame_size, void *frame_pixels, void *video_buf)
-{
- switch (pixel_format) {
- case V4L2_PIX_FMT_YUV420:
- memcpy(video_buf, (void *)frame_pixels, (size_t)frame_size);
- break;
- case V4L2_PIX_FMT_YVU420:
- YVU420ToYUV420(frame_pixels, video_buf, frame_width, frame_height);
- break;
- case V4L2_PIX_FMT_YUYV:
- YUYVToYUV420(frame_pixels, video_buf, frame_width, frame_height);
- break;
- case V4L2_PIX_FMT_UYVY: /* Mac default format */
- UYVYToYUV420(frame_pixels, video_buf, frame_width, frame_height);
- break;
- default:
- ERR("Cannot convert the pixel format (%.4s)...\n",
- (const char *)&pixel_format);
- break;
- }
-}
-
-static void UYVYToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
- int width, int height)
-{
- int i, j;
-
- /* Source */
- unsigned char *ptrsrcy1, *ptrsrcy2;
- unsigned char *ptrsrcy3, *ptrsrcy4;
- unsigned char *ptrsrccb1;
- unsigned char *ptrsrccb3;
- unsigned char *ptrsrccr1;
- unsigned char *ptrsrccr3;
- int srcystride, srcccstride;
-
- ptrsrcy1 = bufsrc + 1;
- ptrsrcy2 = bufsrc + (width << 1) + 1;
- ptrsrcy3 = bufsrc + (width << 1) * 2 + 1;
- ptrsrcy4 = bufsrc + (width << 1) * 3 + 1;
-
- ptrsrccb1 = bufsrc;
- ptrsrccb3 = bufsrc + (width << 1) * 2;
-
- ptrsrccr1 = bufsrc + 2;
- ptrsrccr3 = bufsrc + (width << 1) * 2 + 2;
-
- srcystride = (width << 1) * 3;
- srcccstride = (width << 1) * 3;
-
- /* Destination */
- unsigned char *ptrdesty1, *ptrdesty2;
- unsigned char *ptrdesty3, *ptrdesty4;
- unsigned char *ptrdestcb1, *ptrdestcb2;
- unsigned char *ptrdestcr1, *ptrdestcr2;
- int destystride, destccstride;
-
- ptrdesty1 = bufdest;
- ptrdesty2 = bufdest + width;
- ptrdesty3 = bufdest + width * 2;
- ptrdesty4 = bufdest + width * 3;
-
- ptrdestcb1 = bufdest + width * height;
- ptrdestcb2 = bufdest + width * height + (width >> 1);
-
- ptrdestcr1 = bufdest + width * height + ((width*height) >> 2);
- ptrdestcr2 = bufdest + width * height + ((width*height) >> 2)
- + (width >> 1);
-
- destystride = (width)*3;
- destccstride = (width>>1);
-
- for (j = 0; j < (height / 4); j++) {
- for (i = 0; i < (width / 2); i++) {
- (*ptrdesty1++) = (*ptrsrcy1);
- (*ptrdesty2++) = (*ptrsrcy2);
- (*ptrdesty3++) = (*ptrsrcy3);
- (*ptrdesty4++) = (*ptrsrcy4);
-
- ptrsrcy1 += 2;
- ptrsrcy2 += 2;
- ptrsrcy3 += 2;
- ptrsrcy4 += 2;
-
- (*ptrdesty1++) = (*ptrsrcy1);
- (*ptrdesty2++) = (*ptrsrcy2);
- (*ptrdesty3++) = (*ptrsrcy3);
- (*ptrdesty4++) = (*ptrsrcy4);
-
- ptrsrcy1 += 2;
- ptrsrcy2 += 2;
- ptrsrcy3 += 2;
- ptrsrcy4 += 2;
-
- (*ptrdestcb1++) = (*ptrsrccb1);
- (*ptrdestcb2++) = (*ptrsrccb3);
-
- ptrsrccb1 += 4;
- ptrsrccb3 += 4;
-
- (*ptrdestcr1++) = (*ptrsrccr1);
- (*ptrdestcr2++) = (*ptrsrccr3);
-
- ptrsrccr1 += 4;
- ptrsrccr3 += 4;
-
- }
-
- /* Update src pointers */
- ptrsrcy1 += srcystride;
- ptrsrcy2 += srcystride;
- ptrsrcy3 += srcystride;
- ptrsrcy4 += srcystride;
-
- ptrsrccb1 += srcccstride;
- ptrsrccb3 += srcccstride;
-
- ptrsrccr1 += srcccstride;
- ptrsrccr3 += srcccstride;
-
- /* Update dest pointers */
- ptrdesty1 += destystride;
- ptrdesty2 += destystride;
- ptrdesty3 += destystride;
- ptrdesty4 += destystride;
-
- ptrdestcb1 += destccstride;
- ptrdestcb2 += destccstride;
-
- ptrdestcr1 += destccstride;
- ptrdestcr2 += destccstride;
- }
-}
-
-static void YVU420ToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
- int width, int height)
-{
- int i, j;
-
- /* Source*/
- unsigned char *ptrsrcy1, *ptrsrcy2;
- unsigned char *ptrsrcy3, *ptrsrcy4;
- unsigned char *ptrsrccb1, *ptrsrccb2;
- unsigned char *ptrsrccr1, *ptrsrccr2;
- int srcystride, srcccstride;
-
- ptrsrcy1 = bufsrc;
- ptrsrcy2 = bufsrc + width;
- ptrsrcy3 = bufsrc + width*2;
- ptrsrcy4 = bufsrc + width*3;
-
- ptrsrccr1 = bufsrc + width*height;
- ptrsrccr2 = bufsrc + width*height + (width>>1);
-
- ptrsrccb1 = bufsrc + width*height + ((width*height) >> 2);
- ptrsrccb2 = bufsrc + width*height + ((width*height) >> 2) + (width>>1);
-
- srcystride = (width)*3;
- srcccstride = (width>>1);
-
- /* Destination */
- unsigned char *ptrdesty1, *ptrdesty2;
- unsigned char *ptrdesty3, *ptrdesty4;
- unsigned char *ptrdestcb1, *ptrdestcb2;
- unsigned char *ptrdestcr1, *ptrdestcr2;
- int destystride, destccstride;
-
- ptrdesty1 = bufdest;
- ptrdesty2 = bufdest + width;
- ptrdesty3 = bufdest + width * 2;
- ptrdesty4 = bufdest + width * 3;
-
- ptrdestcb1 = bufdest + width * height;
- ptrdestcb2 = bufdest + width * height + (width >> 1);
-
- ptrdestcr1 = bufdest + width * height + ((width*height) >> 2);
- ptrdestcr2 = bufdest + width * height + ((width*height) >> 2)
- + (width >> 1);
-
- destystride = (width)*3;
- destccstride = (width>>1);
-
- for (j = 0; j < (height / 4); j++) {
- for (i = 0; i < (width / 2); i++) {
-
- (*ptrdesty1++) = (*ptrsrcy1++);
- (*ptrdesty2++) = (*ptrsrcy2++);
- (*ptrdesty3++) = (*ptrsrcy3++);
- (*ptrdesty4++) = (*ptrsrcy4++);
- (*ptrdesty1++) = (*ptrsrcy1++);
- (*ptrdesty2++) = (*ptrsrcy2++);
- (*ptrdesty3++) = (*ptrsrcy3++);
- (*ptrdesty4++) = (*ptrsrcy4++);
-
- (*ptrdestcb1++) = (*ptrsrccb1++);
- (*ptrdestcr1++) = (*ptrsrccr1++);
- (*ptrdestcb2++) = (*ptrsrccb2++);
- (*ptrdestcr2++) = (*ptrsrccr2++);
-
- }
-
- /* Update src pointers */
- ptrsrcy1 += srcystride;
- ptrsrcy2 += srcystride;
- ptrsrcy3 += srcystride;
- ptrsrcy4 += srcystride;
-
- ptrsrccb1 += srcccstride;
- ptrsrccb2 += srcccstride;
-
- ptrsrccr1 += srcccstride;
- ptrsrccr2 += srcccstride;
-
- /* Update dest pointers */
- ptrdesty1 += destystride;
- ptrdesty2 += destystride;
- ptrdesty3 += destystride;
- ptrdesty4 += destystride;
-
- ptrdestcb1 += destccstride;
- ptrdestcb2 += destccstride;
-
- ptrdestcr1 += destccstride;
- ptrdestcr2 += destccstride;
-
- }
-
-}
-
-static void YUYVToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
- int width, int height)
-{
- int i, j;
-
- /* Source*/
- unsigned char *ptrsrcy1, *ptrsrcy2;
- unsigned char *ptrsrcy3, *ptrsrcy4;
- unsigned char *ptrsrccb1;
- unsigned char *ptrsrccb3;
- unsigned char *ptrsrccr1;
- unsigned char *ptrsrccr3;
- int srcystride, srcccstride;
-
- ptrsrcy1 = bufsrc ;
- ptrsrcy2 = bufsrc + (width << 1);
- ptrsrcy3 = bufsrc + (width << 1) * 2;
- ptrsrcy4 = bufsrc + (width << 1) * 3;
-
- ptrsrccb1 = bufsrc + 1;
- ptrsrccb3 = bufsrc + (width << 1) * 2 + 1;
-
- ptrsrccr1 = bufsrc + 3;
- ptrsrccr3 = bufsrc + (width << 1) * 2 + 3;
-
- srcystride = (width << 1) * 3;
- srcccstride = (width << 1) * 3;
-
- /* Destination */
- unsigned char *ptrdesty1, *ptrdesty2;
- unsigned char *ptrdesty3, *ptrdesty4;
- unsigned char *ptrdestcb1, *ptrdestcb2;
- unsigned char *ptrdestcr1, *ptrdestcr2;
- int destystride, destccstride;
-
- ptrdesty1 = bufdest;
- ptrdesty2 = bufdest + width;
- ptrdesty3 = bufdest + width * 2;
- ptrdesty4 = bufdest + width * 3;
-
- ptrdestcb1 = bufdest + width * height;
- ptrdestcb2 = bufdest + width * height + (width >> 1);
-
- ptrdestcr1 = bufdest + width * height + ((width * height) >> 2);
- ptrdestcr2 = bufdest + width * height + ((width * height) >> 2)
- + (width >> 1);
-
- destystride = width * 3;
- destccstride = (width >> 1);
-
- for (j = 0; j < (height / 4); j++) {
- for (i = 0; i < (width / 2); i++) {
- (*ptrdesty1++) = (*ptrsrcy1);
- (*ptrdesty2++) = (*ptrsrcy2);
- (*ptrdesty3++) = (*ptrsrcy3);
- (*ptrdesty4++) = (*ptrsrcy4);
-
- ptrsrcy1 += 2;
- ptrsrcy2 += 2;
- ptrsrcy3 += 2;
- ptrsrcy4 += 2;
-
- (*ptrdesty1++) = (*ptrsrcy1);
- (*ptrdesty2++) = (*ptrsrcy2);
- (*ptrdesty3++) = (*ptrsrcy3);
- (*ptrdesty4++) = (*ptrsrcy4);
-
- ptrsrcy1 += 2;
- ptrsrcy2 += 2;
- ptrsrcy3 += 2;
- ptrsrcy4 += 2;
-
- (*ptrdestcb1++) = (*ptrsrccb1);
- (*ptrdestcb2++) = (*ptrsrccb3);
-
- ptrsrccb1 += 4;
- ptrsrccb3 += 4;
-
- (*ptrdestcr1++) = (*ptrsrccr1);
- (*ptrdestcr2++) = (*ptrsrccr3);
-
- ptrsrccr1 += 4;
- ptrsrccr3 += 4;
-
- }
-
- /* Update src pointers */
- ptrsrcy1 += srcystride;
- ptrsrcy2 += srcystride;
- ptrsrcy3 += srcystride;
- ptrsrcy4 += srcystride;
-
- ptrsrccb1 += srcccstride;
- ptrsrccb3 += srcccstride;
-
- ptrsrccr1 += srcccstride;
- ptrsrccr3 += srcccstride;
-
- /* Update dest pointers */
- ptrdesty1 += destystride;
- ptrdesty2 += destystride;
- ptrdesty3 += destystride;
- ptrdesty4 += destystride;
-
- ptrdestcb1 += destccstride;
- ptrdestcb2 += destccstride;
-
- ptrdestcr1 += destccstride;
- ptrdestcr2 += destccstride;
- }
-}
+++ /dev/null
-/*
- * Implementation of MARU Virtual Camera device by PCI bus on MacOS.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jun Tian <jun.j.tian@intel.com>
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#import <Cocoa/Cocoa.h>
-#import <QTKit/QTKit.h>
-#import <CoreAudio/CoreAudio.h>
-
-#include <pthread.h>
-#include "qemu-common.h"
-#include "maru_camera_common.h"
-#include "maru_camera_darwin.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(tizen, maru-camera);
-
-#define MARUCAM_THREAD_NAME "marucam_worker_thread"
-
-/* V4L2 defines copy from videodev2.h */
-#define V4L2_CTRL_FLAG_SLIDER 0x0020
-
-#define V4L2_CTRL_CLASS_USER 0x00980000
-#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
-#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE + 0)
-#define V4L2_CID_CONTRAST (V4L2_CID_BASE + 1)
-#define V4L2_CID_SATURATION (V4L2_CID_BASE + 2)
-#define V4L2_CID_SHARPNESS (V4L2_CID_BASE + 27)
-
-typedef struct tagMaruCamConvertPixfmt {
- uint32_t fmt; /* fourcc */
- uint32_t bpp; /* bits per pixel, 0 for compressed formats */
- uint32_t needs_conversion;
-} MaruCamConvertPixfmt;
-
-
-static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
- { V4L2_PIX_FMT_YUYV, 16, 0 },
- { V4L2_PIX_FMT_UYVY, 16, 0 },
- { V4L2_PIX_FMT_YUV420, 12, 0 },
- { V4L2_PIX_FMT_YVU420, 12, 0 },
-};
-
-typedef struct tagMaruCamConvertFrameInfo {
- uint32_t width;
- uint32_t height;
-} MaruCamConvertFrameInfo;
-
-static MaruCamConvertFrameInfo supported_dst_frames[] = {
- { 640, 480 },
- { 352, 288 },
- { 320, 240 },
- { 176, 144 },
- { 160, 120 },
-};
-
-#define MARUCAM_CTRL_VALUE_MAX 20
-#define MARUCAM_CTRL_VALUE_MIN 1
-#define MARUCAM_CTRL_VALUE_MID 10
-#define MARUCAM_CTRL_VALUE_STEP 1
-
-enum {
- _MC_THREAD_PAUSED,
- _MC_THREAD_STREAMON,
- _MC_THREAD_STREAMOFF,
-};
-
-#if 0
-struct marucam_qctrl {
- uint32_t id;
- uint32_t hit;
- long min;
- long max;
- long step;
- long init_val;
-};
-
-static struct marucam_qctrl qctrl_tbl[] = {
- { V4L2_CID_BRIGHTNESS, 0, },
- { V4L2_CID_CONTRAST, 0, },
- { V4L2_CID_SATURATION, 0, },
- { V4L2_CID_SHARPNESS, 0, },
-};
-#endif
-
-static MaruCamState *g_state;
-
-static uint32_t ready_count;
-static uint32_t cur_fmt_idx;
-static uint32_t cur_frame_idx;
-
-/***********************************
- * Mac camera helper functions
- ***********************************/
-
-/* Convert Core Video format to FOURCC */
-static uint32_t corevideo_to_fourcc(uint32_t cv_pix_fmt)
-{
- switch (cv_pix_fmt) {
- case kCVPixelFormatType_420YpCbCr8Planar:
- return V4L2_PIX_FMT_YVU420;
- case kCVPixelFormatType_422YpCbCr8:
- return V4L2_PIX_FMT_UYVY;
- case kCVPixelFormatType_422YpCbCr8_yuvs:
- return V4L2_PIX_FMT_YUYV;
- case kCVPixelFormatType_32ARGB:
- case kCVPixelFormatType_32RGBA:
- return V4L2_PIX_FMT_RGB32;
- case kCVPixelFormatType_32BGRA:
- case kCVPixelFormatType_32ABGR:
- return V4L2_PIX_FMT_BGR32;
- case kCVPixelFormatType_24RGB:
- return V4L2_PIX_FMT_RGB24;
- case kCVPixelFormatType_24BGR:
- return V4L2_PIX_FMT_BGR32;
- default:
- ERR("Unknown pixel format '%.4s'", (const char *)&cv_pix_fmt);
- return 0;
- }
-}
-
-static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
-{
- uint32_t bytesperline;
-
- switch (pixfmt) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- bytesperline = (width * 12) >> 3;
- break;
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_UYVY:
- default:
- bytesperline = width * 2;
- break;
- }
-
- return bytesperline;
-}
-
-static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
-{
- return get_bytesperline(pixfmt, width) * height;
-}
-
-/******************************************************************
- ** Maru Camera Implementation
- *****************************************************************/
-
-@interface MaruCameraDriver : NSObject {
- QTCaptureSession *mCaptureSession;
- QTCaptureDeviceInput *mCaptureVideoDeviceInput;
- QTCaptureVideoPreviewOutput *mCaptureVideoPreviewOutput;
-
- CVImageBufferRef mCurrentImageBuffer;
- BOOL mDeviceIsOpened;
- BOOL mCaptureIsStarted;
-}
-
-- (MaruCameraDriver *)init;
-- (int)startCapture:(int)width:(int)height;
-- (void)stopCapture;
-- (int)readFrame:(void *)video_buf;
-- (int)setCaptureFormat:(int)width:(int)height:(int)pix_format;
-- (int)getCaptureFormat:(int)width:(int)height:(int)pix_format;
-- (BOOL)deviceStatus;
-
-@end
-
-@implementation MaruCameraDriver
-
-- (MaruCameraDriver *)init
-{
- BOOL success = NO;
- NSError *error;
- mDeviceIsOpened = NO;
- mCaptureIsStarted = NO;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- /* Create the capture session */
- mCaptureSession = [[QTCaptureSession alloc] init];
-
- /* Find a video device */
- QTCaptureDevice *videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
- success = [videoDevice open:&error];
-
- /* If a video input device can't be found or opened, try to find and open a muxed input device */
- if (!success) {
- videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeMuxed];
- success = [videoDevice open:&error];
- [pool release];
- return nil;
- }
-
- if (!success) {
- videoDevice = nil;
- [pool release];
- return nil;
- }
-
- if (videoDevice) {
- /* Add the video device to the session as a device input */
- mCaptureVideoDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:videoDevice];
- success = [mCaptureSession addInput:mCaptureVideoDeviceInput error:&error];
-
- if (!success) {
- [pool release];
- return nil;
- }
-
- mCaptureVideoPreviewOutput = [[QTCaptureVideoPreviewOutput alloc] init];
- success = [mCaptureSession addOutput:mCaptureVideoPreviewOutput error:&error];
- if (!success) {
- [pool release];
- return nil;
- }
-
- mDeviceIsOpened = YES;
- [mCaptureVideoPreviewOutput setDelegate:self];
- INFO("Camera session bundling successfully!\n");
- [pool release];
- return self;
- } else {
- [pool release];
- return nil;
- }
-}
-
-- (int)startCapture:(int)width:(int)height
-{
- int ret = -1;
-
- if (![mCaptureSession isRunning]) {
- /* Set width & height, using default pixel format to capture */
- NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
- [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
- nil];
- [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
- [mCaptureSession startRunning];
- } else {
- ERR("Capture session is already running, exit\n");
- return ret;
- }
-
- if ([mCaptureSession isRunning]) {
- while(!mCaptureIsStarted) {
- /* Wait Until Capture is started */
- [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.5]];
- }
- ret = 0;
- }
- return ret;
-}
-
-- (void)stopCapture
-{
- if ([mCaptureSession isRunning]) {
- [mCaptureSession stopRunning];
- while([mCaptureSession isRunning]) {
- /* Wait Until Capture is stopped */
- [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
- }
-
- }
- mCaptureIsStarted = NO;
-}
-
-- (int)readFrame:(void *)video_buf
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- @synchronized (self) {
- if (mCaptureIsStarted == NO) {
- [pool release];
- return 0;
- }
- if (mCurrentImageBuffer != nil) {
- CVPixelBufferLockBaseAddress(mCurrentImageBuffer, 0);
- const uint32_t pixel_format = corevideo_to_fourcc(CVPixelBufferGetPixelFormatType(mCurrentImageBuffer));
- const int frame_width = CVPixelBufferGetWidth(mCurrentImageBuffer);
- const int frame_height = CVPixelBufferGetHeight(mCurrentImageBuffer);
- const size_t frame_size = CVPixelBufferGetBytesPerRow(mCurrentImageBuffer) * frame_height;
- const void *frame_pixels = CVPixelBufferGetBaseAddress(mCurrentImageBuffer);
-
- TRACE("buffer(%p), pixel_format(%d,%.4s), frame_width(%d), "
- "frame_height(%d), frame_size(%d)\n",
- mCurrentImageBuffer, (int)pixel_format,
- (const char *)&pixel_format, frame_width,
- frame_height, (int)frame_size);
-
- /* convert frame to v4l2 format */
- convert_frame(pixel_format, frame_width, frame_height,
- frame_size, (void *)frame_pixels, video_buf);
- CVPixelBufferUnlockBaseAddress(mCurrentImageBuffer, 0);
- [pool release];
- return 1;
- }
- }
-
- [pool release];
- return -1;
-}
-
-- (int)setCaptureFormat:(int)width:(int)height:(int)pix_format
-{
- int ret = -1;
- NSDictionary *attributes;
-
- if (mCaptureSession == nil || mCaptureVideoPreviewOutput == nil) {
- ERR("Capture session is not initiated.\n");
- return ret;
- }
-
- /* Set the pixel buffer attributes before running the capture session */
- if (![mCaptureSession isRunning]) {
- if (pix_format) {
- attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
- [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
- [NSNumber numberWithInt: pix_format], (id)kCVPixelBufferPixelFormatTypeKey,
- nil];
- } else {
- attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
- [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
- nil];
- }
- [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
- ret = 0;
- } else {
- ERR("Cannot set pixel buffer attributes when it's running.\n");
- return ret;
- }
-
- return ret;
-}
-
-- (int)getCaptureFormat:(int)width:(int)height:(int)pix_format
-{
- return 0;
-}
-
-/* Get the device bundling status */
-- (BOOL)deviceStatus
-{
- return mDeviceIsOpened;
-}
-
-/* Handle deallocation of memory for your capture objects */
-
-- (void)dealloc
-{
- [mCaptureSession release];
- [mCaptureVideoDeviceInput release];
- [mCaptureVideoPreviewOutput release];
- [super dealloc];
-}
-
-/* Receive this method whenever the output decompresses and outputs a new video frame */
-- (void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame
- withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
-{
- CVImageBufferRef imageBufferToRelease;
- CVBufferRetain(videoFrame);
-
- @synchronized (self)
- {
- imageBufferToRelease = mCurrentImageBuffer;
- mCurrentImageBuffer = videoFrame;
- mCaptureIsStarted = YES;
- }
- CVBufferRelease(imageBufferToRelease);
-}
-
-@end
-
-/******************************************************************
- ** Maru Camera APIs
- *****************************************************************/
-
-typedef struct MaruCameraDevice MaruCameraDevice;
-struct MaruCameraDevice {
- /* Maru camera device object. */
- MaruCameraDriver *driver;
-};
-
-/* Golbal representation of the Maru camera */
-MaruCameraDevice *mcd = NULL;
-
-static int is_streamon()
-{
- int st;
- qemu_mutex_lock(&g_state->thread_mutex);
- st = g_state->streamon;
- qemu_mutex_unlock(&g_state->thread_mutex);
- return (st == _MC_THREAD_STREAMON);
-}
-
-static void __raise_err_intr()
-{
- qemu_mutex_lock(&g_state->thread_mutex);
- if (g_state->streamon == _MC_THREAD_STREAMON) {
- g_state->req_frame = 0; /* clear request */
- g_state->isr = 0x08; /* set a error flag of rasing a interrupt */
- qemu_bh_schedule(g_state->tx_bh);
- }
- qemu_mutex_unlock(&g_state->thread_mutex);
-}
-
-static int marucam_device_read_frame()
-{
- int ret;
- void *tmp_buf;
-
- qemu_mutex_lock(&g_state->thread_mutex);
- if (g_state->streamon == _MC_THREAD_STREAMON) {
-#if 0
- if (ready_count < MARUCAM_SKIPFRAMES) {
- /* skip a frame cause first some frame are distorted */
- ++ready_count;
- TRACE("Skip %d frame\n", ready_count);
- qemu_mutex_unlock(&g_state->thread_mutex);
- return 0;
- }
-#endif
- if (g_state->req_frame == 0) {
- TRACE("There is no request\n");
- qemu_mutex_unlock(&g_state->thread_mutex);
- return 0;
- }
-
- /* Grab the camera frame into temp buffer */
- tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
- ret = [mcd->driver readFrame: tmp_buf];
- if (ret < 0) {
- ERR("%s, Capture error\n", __func__);
- qemu_mutex_unlock(&g_state->thread_mutex);
- __raise_err_intr();
- return -1;
- } else if (!ret) {
- qemu_mutex_unlock(&g_state->thread_mutex);
- return 0;
- }
-
- g_state->req_frame = 0; /* clear request */
- g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
- qemu_bh_schedule(g_state->tx_bh);
- } else {
- qemu_mutex_unlock(&g_state->thread_mutex);
- return -1;
- }
- qemu_mutex_unlock(&g_state->thread_mutex);
- return 0;
-}
-
-/* Worker thread to grab frames to the preview window */
-static void *marucam_worker_thread(void *thread_param)
-{
- while (1) {
- qemu_mutex_lock(&g_state->thread_mutex);
- g_state->streamon = _MC_THREAD_PAUSED;
- qemu_cond_wait(&g_state->thread_cond, &g_state->thread_mutex);
- qemu_mutex_unlock(&g_state->thread_mutex);
-
- if (g_state->destroying) {
- break;
- }
-
- ready_count = 0;
- qemu_mutex_lock(&g_state->thread_mutex);
- g_state->streamon = _MC_THREAD_STREAMON;
- qemu_mutex_unlock(&g_state->thread_mutex);
- INFO("Streaming on ......\n");
-
- /* Loop: capture frame -> convert format -> render to screen */
- while (1) {
- if (is_streamon()) {
- if (marucam_device_read_frame() < 0) {
- INFO("Streaming is off ...\n");
- break;
- } else {
- /* wait until next frame is avalilable */
- usleep(22000);
- }
- } else {
- INFO("Streaming is off ...\n");
- break;
- }
- }
- }
-
- return NULL;
-}
-
-int marucam_device_check(int log_flag)
-{
- /* FIXME: check the device parameters */
- INFO("Checking camera device\n");
- return 1;
-}
-
-/**********************************************
- * MARU camera routines
- **********************************************/
-void marucam_device_init(MaruCamState *state)
-{
- g_state = state;
- g_state->destroying = false;
- qemu_thread_create(&state->thread_id,
- MARUCAM_THREAD_NAME,
- marucam_worker_thread,
- NULL,
- QEMU_THREAD_JOINABLE);
-}
-
-void marucam_device_exit(MaruCamState *state)
-{
- state->destroying = true;
- qemu_mutex_lock(&state->thread_mutex);
- qemu_cond_signal(&state->thread_cond);
- qemu_mutex_unlock(&state->thread_mutex);
- qemu_thread_join(&state->thread_id);
-}
-
-/* MARUCAM_CMD_OPEN */
-void marucam_device_open(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- param->top = 0;
-
- mcd = (MaruCameraDevice *)malloc(sizeof(MaruCameraDevice));
- if (mcd == NULL) {
- ERR("%s: MaruCameraDevice allocate failed\n", __func__);
- param->errCode = EINVAL;
- return;
- }
- memset(mcd, 0, sizeof(MaruCameraDevice));
- mcd->driver = [[MaruCameraDriver alloc] init];
- if (mcd->driver == nil) {
- ERR("Camera device open failed\n");
- [mcd->driver dealloc];
- free(mcd);
- param->errCode = EINVAL;
- return;
- }
- INFO("Camera opened!\n");
-}
-
-/* MARUCAM_CMD_CLOSE */
-void marucam_device_close(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- param->top = 0;
-
- if (mcd != NULL) {
- if (is_streamon()) {
- marucam_device_stop_preview(state);
- }
- [mcd->driver dealloc];
- free(mcd);
- mcd = NULL;
- }
-
- /* marucam_reset_controls(); */
- INFO("Camera closed\n");
-}
-
-/* MARUCAM_CMD_START_PREVIEW */
-void marucam_device_start_preview(MaruCamState *state)
-{
- uint32_t width, height, pixfmt;
- MaruCamParam *param = state->param;
- param->top = 0;
-
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
- pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- state->buf_size = get_sizeimage(pixfmt, width, height);
-
- INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u), frame idx(%d), fmt idx(%d)\n",
- (char)(pixfmt), (char)(pixfmt >> 8),
- (char)(pixfmt >> 16), (char)(pixfmt >> 24),
- width, height, state->buf_size,
- cur_frame_idx, cur_fmt_idx);
-
- if (mcd->driver == nil) {
- ERR("%s: Start capture failed: vaild device", __func__);
- param->errCode = EINVAL;
- return;
- }
-
- INFO("Starting preview ...\n");
- [mcd->driver startCapture: width: height];
-
- /* Enable the condition to capture frames now */
- qemu_mutex_lock(&state->thread_mutex);
- qemu_cond_signal(&state->thread_cond);
- qemu_mutex_unlock(&state->thread_mutex);
-
- while (!is_streamon()) {
- usleep(10000);
- }
-}
-
-/* MARUCAM_CMD_STOP_PREVIEW */
-void marucam_device_stop_preview(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- param->top = 0;
-
- if (is_streamon()) {
- qemu_mutex_lock(&state->thread_mutex);
- state->streamon = _MC_THREAD_STREAMOFF;
- qemu_mutex_unlock(&state->thread_mutex);
-
- while (is_streamon()) {
- usleep(10000);
- }
- }
-
- if (mcd->driver != nil) {
- [mcd->driver stopCapture];
- }
-
- state->buf_size = 0;
- INFO("Stopping preview ...\n");
-}
-
-/* MARUCAM_CMD_S_PARAM */
-void marucam_device_s_param(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- /* We use default FPS of the webcam */
- param->top = 0;
-}
-
-/* MARUCAM_CMD_G_PARAM */
-void marucam_device_g_param(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- /* We use default FPS of the webcam
- * return a fixed value on guest ini file (1/30).
- */
- param->top = 0;
- param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
- param->stack[1] = 1; /* numerator */
- param->stack[2] = 30; /* denominator */
-}
-
-/* MARUCAM_CMD_S_FMT */
-void marucam_device_s_fmt(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- uint32_t width, height, pixfmt, pidx, fidx;
-
- param->top = 0;
- width = param->stack[0];
- height = param->stack[1];
- pixfmt = param->stack[2];
-
- TRACE("Set format: width(%d), height(%d), pixfmt(%d, %.4s)\n",
- width, height, pixfmt, (const char*)&pixfmt);
-
- for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
- if ((supported_dst_frames[fidx].width == width) &&
- (supported_dst_frames[fidx].height == height)) {
- break;
- }
- }
- if (fidx == ARRAY_SIZE(supported_dst_frames)) {
- param->errCode = EINVAL;
- return;
- }
-
- for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
- if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
- TRACE("pixfmt index is match: %d\n", pidx);
- break;
- }
- }
- if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
-
- if ((supported_dst_frames[cur_frame_idx].width != width) &&
- (supported_dst_frames[cur_frame_idx].height != height)) {
- if (mcd->driver == nil || [mcd->driver setCaptureFormat: width: height: 0] < 0) {
- ERR("Set pixel format failed\n");
- param->errCode = EINVAL;
- return;
- }
-
- TRACE("cur_frame_idx:%d, supported_dst_frames[cur_frame_idx].width:%d\n",
- cur_frame_idx, supported_dst_frames[cur_frame_idx].width);
- }
-
- cur_frame_idx = fidx;
- cur_fmt_idx = pidx;
-
- pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
-
- param->stack[0] = width;
- param->stack[1] = height;
- param->stack[2] = 1; /* V4L2_FIELD_NONE */
- param->stack[3] = pixfmt;
- param->stack[4] = get_bytesperline(pixfmt, width);
- param->stack[5] = get_sizeimage(pixfmt, width, height);
- param->stack[6] = 0;
- param->stack[7] = 0;
-
- TRACE("Set device pixel format ...\n");
-}
-
-/* MARUCAM_CMD_G_FMT */
-void marucam_device_g_fmt(MaruCamState *state)
-{
- uint32_t width, height, pixfmt;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
-
- param->stack[0] = width;
- param->stack[1] = height;
- param->stack[2] = 1; /* V4L2_FIELD_NONE */
- param->stack[3] = pixfmt;
- param->stack[4] = get_bytesperline(pixfmt, width);
- param->stack[5] = get_sizeimage(pixfmt, width, height);
- param->stack[6] = 0;
- param->stack[7] = 0;
-
- TRACE("Get device frame format ...\n");
-}
-
-void marucam_device_try_fmt(MaruCamState *state)
-{
- TRACE("Try device frame format, use default setting ...\n");
-}
-
-/* Get specific pixelformat description */
-void marucam_device_enum_fmt(MaruCamState *state)
-{
- uint32_t index;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- index = param->stack[0];
-
- if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
- param->stack[1] = 0; /* flags = NONE */
- param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
- switch (supported_dst_pixfmts[index].fmt) {
- case V4L2_PIX_FMT_YUYV:
- memcpy(¶m->stack[3], "YUYV", 32);
- break;
- case V4L2_PIX_FMT_UYVY:
- memcpy(¶m->stack[3], "UYVY", 32);
- break;
- case V4L2_PIX_FMT_YUV420:
- memcpy(¶m->stack[3], "YU12", 32);
- break;
- case V4L2_PIX_FMT_YVU420:
- memcpy(¶m->stack[3], "YV12", 32);
- break;
- default:
- param->errCode = EINVAL;
- break;
- }
-}
-
-/*
- * QTKit don't support setting brightness, contrast, saturation & sharpness
- */
-void marucam_device_qctrl(MaruCamState *state)
-{
- uint32_t id, i;
- /* long property, min, max, step, def_val, set_val; */
- char name[32] = {0,};
- MaruCamParam *param = state->param;
-
- param->top = 0;
- id = param->stack[0];
-
- switch (id) {
- case V4L2_CID_BRIGHTNESS:
- TRACE("V4L2_CID_BRIGHTNESS\n");
- memcpy((void *)name, (void *)"brightness", 32);
- i = 0;
- break;
- case V4L2_CID_CONTRAST:
- TRACE("V4L2_CID_CONTRAST\n");
- memcpy((void *)name, (void *)"contrast", 32);
- i = 1;
- break;
- case V4L2_CID_SATURATION:
- TRACE("V4L2_CID_SATURATION\n");
- memcpy((void *)name, (void *)"saturation", 32);
- i = 2;
- break;
- case V4L2_CID_SHARPNESS:
- TRACE("V4L2_CID_SHARPNESS\n");
- memcpy((void *)name, (void *)"sharpness", 32);
- i = 3;
- break;
- default:
- param->errCode = EINVAL;
- return;
- }
-
- param->stack[0] = id;
- param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
- param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
- param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
- param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
- param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
- /* name field setting */
- memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
-}
-
-void marucam_device_s_ctrl(MaruCamState *state)
-{
- INFO("Set control\n");
-}
-
-void marucam_device_g_ctrl(MaruCamState *state)
-{
- INFO("Get control\n");
-}
-
-/* Get frame width & height */
-void marucam_device_enum_fsizes(MaruCamState *state)
-{
- uint32_t index, pixfmt, i;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- index = param->stack[0];
- pixfmt = param->stack[1];
-
- if (index >= ARRAY_SIZE(supported_dst_frames)) {
- param->errCode = EINVAL;
- return;
- }
- for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
- if (supported_dst_pixfmts[i].fmt == pixfmt) {
- break;
- }
- }
-
- if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
-
- param->stack[0] = supported_dst_frames[index].width;
- param->stack[1] = supported_dst_frames[index].height;
-}
-
-void marucam_device_enum_fintv(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- param->top = 0;
-
- /* switch by index(param->stack[0]) */
- switch (param->stack[0]) {
- case 0:
- param->stack[1] = 30; /* denominator */
- break;
- default:
- param->errCode = EINVAL;
- return;
- }
- param->stack[0] = 1; /* numerator */
-}
+++ /dev/null
-/*
- * Implementation of MARU Virtual Camera device by PCI bus on Linux.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "qemu-common.h"
-#include "sysemu/kvm.h"
-#include "maru_camera_common.h"
-#include "debug_ch.h"
-
-#include <linux/videodev2.h>
-
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-
-#include <libv4l2.h>
-#include <libv4lconvert.h>
-
-MULTI_DEBUG_CHANNEL(tizen, maru-camera);
-
-#define MARUCAM_THREAD_NAME "marucam_worker_thread"
-
-#define CLEAR(x) memset(&(x), 0, sizeof(x))
-
-#define MARUCAM_DEFAULT_BUFFER_COUNT 4
-
-#define MARUCAM_CTRL_VALUE_MAX 20
-#define MARUCAM_CTRL_VALUE_MIN 1
-#define MARUCAM_CTRL_VALUE_MID 10
-#define MARUCAM_CTRL_VALUE_STEP 1
-
-enum {
- _MC_THREAD_PAUSED,
- _MC_THREAD_STREAMON,
- _MC_THREAD_STREAMOFF,
-};
-
-typedef struct marucam_framebuffer {
- void *data;
- size_t size;
-} marucam_framebuffer;
-
-struct marucam_saved_frame {
- void *data;
- uint32_t pixelformat;
- uint32_t width;
- uint32_t height;
- uint32_t size;
-};
-
-static struct marucam_saved_frame saved_frame;
-static char has_success_frame;
-static int n_framebuffer;
-static int previous_frame_index = -1;
-static struct marucam_framebuffer *framebuffer;
-
-static const char *dev_name = "/dev/video0";
-static int v4l2_fd;
-static int convert_trial;
-static int ready_count;
-static int timeout_n;
-
-static struct v4l2_format dst_fmt;
-
-static void ScalePlaneSimple(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8_t *src_ptr, uint8_t *dst_ptr) {
- int i, j;
- int dx = (src_width << 16) / dst_width;
- int dy = (src_height << 16) / dst_height;
- int y = (dy >= 65536) ? ((dy >> 1) - 32768) : (dy >> 1);
- for (j = 0; j < dst_height; ++j) {
- int x = (dx >= 65536) ? ((dx >> 1) - 32768) : (dx >> 1);
- int yi = y >> 16;
- const uint8_t *src = src_ptr + yi * src_stride;
- uint8_t *dst = dst_ptr;
- for (i = 0; i < dst_width; ++i) {
- *dst++ = src[x >> 16];
- x += dx;
- }
- dst_ptr += dst_stride;
- y += dy;
- }
-}
-
-static void make_yu12_black(unsigned char *dest, uint32_t width, uint32_t height)
-{
- uint32_t x, y;
- unsigned char *udest, *vdest;
-
- /* Y */
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- *dest++ = 16;
- }
- }
-
- /* U + V */
- udest = dest;
- vdest = dest + width * height / 4;
-
- for (y = 0; y < height / 2; y++) {
- for (x = 0; x < width / 2; x++) {
- *udest++ = *vdest++ = 128;
- }
- }
-}
-
-static void marucam_scale_yuv420(void *src,
- uint32_t src_width, uint32_t src_height,
- void *dst, uint32_t dst_width, uint32_t dst_height)
-{
- uint32_t src_halfwidth = (src_width + 1) >> 1;
- uint32_t src_halfheight = (src_height + 1) >> 1;
- uint32_t dst_halfwidth = (dst_width + 1) >> 1;
- uint32_t dst_halfheight = (dst_height + 1) >> 1;
-
- uint8_t *src_u = src + (src_width * src_height);
- uint8_t *src_v = src_u + (src_width * src_height / 4);
-
- uint8_t *dst_u = dst + (dst_width * dst_height);
- uint8_t *dst_v = dst_u + (dst_width * dst_height /4);
-
- ScalePlaneSimple(src_width, src_height,
- dst_width, dst_height,
- src_width, dst_width,
- src, dst);
- ScalePlaneSimple(src_halfwidth, src_halfheight,
- dst_halfwidth, dst_halfheight,
- src_halfwidth, dst_halfwidth,
- src_u, dst_u);
- ScalePlaneSimple(src_halfwidth, src_halfheight,
- dst_halfwidth, dst_halfheight,
- src_halfwidth, dst_halfwidth,
- src_v, dst_v);
-}
-
-static int yioctl(int fd, int req, void *arg)
-{
- int r;
-
- do {
- r = ioctl(fd, req, arg);
- } while (r < 0 && errno == EINTR);
-
- return r;
-}
-
-static int xioctl(int fd, int req, void *arg)
-{
- int r;
-
- do {
- r = v4l2_ioctl(fd, req, arg);
- } while (r < 0 && errno == EINTR);
-
- return r;
-}
-
-typedef struct tagMaruCamConvertPixfmt {
- uint32_t fmt; /* fourcc */
-} MaruCamConvertPixfmt;
-
-static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
- { V4L2_PIX_FMT_YUYV },
- { V4L2_PIX_FMT_YUV420 },
- { V4L2_PIX_FMT_YVU420 },
-};
-
-typedef struct tagMaruCamConvertFrameInfo {
- uint32_t width;
- uint32_t height;
-} MaruCamConvertFrameInfo;
-
-static MaruCamConvertFrameInfo supported_dst_frames[] = {
- { 640, 480 },
- { 352, 288 },
- { 320, 240 },
- { 176, 144 },
- { 160, 120 },
-};
-
-struct marucam_qctrl {
- uint32_t id;
- uint32_t hit;
- int32_t min;
- int32_t max;
- int32_t step;
- int32_t init_val;
-};
-
-static struct marucam_qctrl qctrl_tbl[] = {
- { V4L2_CID_BRIGHTNESS, 0, },
- { V4L2_CID_CONTRAST, 0, },
- { V4L2_CID_SATURATION, 0, },
- { V4L2_CID_SHARPNESS, 0, },
-};
-
-static void marucam_reset_controls(void)
-{
- uint32_t i;
- for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) {
- if (qctrl_tbl[i].hit) {
- struct v4l2_control ctrl = {0,};
- qctrl_tbl[i].hit = 0;
- ctrl.id = qctrl_tbl[i].id;
- ctrl.value = qctrl_tbl[i].init_val;
- if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
- ERR("Failed to reset control value: id(0x%x), errstr(%s)\n",
- ctrl.id, strerror(errno));
- }
- }
- }
-}
-
-static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value)
-{
- double rate = 0.0;
- int32_t dist = 0, ret = 0;
-
- dist = max - min;
-
- if (dist < MARUCAM_CTRL_VALUE_MAX) {
- rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
- ret = min + (int32_t)(value / rate);
- } else {
- rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
- ret = min + (int32_t)(rate * value);
- }
- return ret;
-}
-
-static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value)
-{
- double rate = 0.0;
- int32_t dist = 0, ret = 0;
-
- dist = max - min;
-
- if (dist < MARUCAM_CTRL_VALUE_MAX) {
- rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
- ret = (int32_t)((double)(value - min) * rate);
- } else {
- rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
- ret = (int32_t)((double)(value - min) / rate);
- }
-
- return ret;
-}
-
-static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format,
- uint32_t width, uint32_t height)
-{
- struct v4l2_frmivalenum fival;
- struct v4l2_streamparm sp;
- uint32_t min_num = 0, min_denom = 0;
-
- CLEAR(fival);
- fival.pixel_format = pixel_format;
- fival.width = width;
- fival.height = height;
-
- if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) {
- ERR("Unable to enumerate intervals for pixelformat(0x%x), (%d:%d)\n",
- pixel_format, width, height);
- return;
- }
-
- if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
- float max_ival = -1.0;
- do {
- float cur_ival = (float)fival.discrete.numerator
- / (float)fival.discrete.denominator;
- if (cur_ival > max_ival) {
- max_ival = cur_ival;
- min_num = fival.discrete.numerator;
- min_denom = fival.discrete.denominator;
- }
- TRACE("Discrete frame interval %u/%u supported\n",
- fival.discrete.numerator, fival.discrete.denominator);
- fival.index++;
- } while (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0);
- } else if ((fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) ||
- (fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) {
- TRACE("Frame intervals from %u/%u to %u/%u supported",
- fival.stepwise.min.numerator, fival.stepwise.min.denominator,
- fival.stepwise.max.numerator, fival.stepwise.max.denominator);
- if (fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
- TRACE("with %u/%u step", fival.stepwise.step.numerator,
- fival.stepwise.step.denominator);
- }
- if (((float)fival.stepwise.max.denominator /
- (float)fival.stepwise.max.numerator) >
- ((float)fival.stepwise.min.denominator /
- (float)fival.stepwise.min.numerator)) {
- min_num = fival.stepwise.max.numerator;
- min_denom = fival.stepwise.max.denominator;
- } else {
- min_num = fival.stepwise.min.numerator;
- min_denom = fival.stepwise.min.denominator;
- }
- }
- TRACE("The actual min values: %u/%u\n", min_num, min_denom);
-
- CLEAR(sp);
- sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- sp.parm.capture.timeperframe.numerator = min_num;
- sp.parm.capture.timeperframe.denominator = min_denom;
-
- if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {
- ERR("Failed to set to minimum FPS(%u/%u)\n", min_num, min_denom);
- }
-}
-
-static uint32_t stop_capturing(void)
-{
- enum v4l2_buf_type type;
-
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (xioctl(v4l2_fd, VIDIOC_STREAMOFF, &type) < 0) {
- ERR("Failed to ioctl() with VIDIOC_STREAMOFF: %s\n", strerror(errno));
- return errno;
- }
- return 0;
-}
-
-static uint32_t start_capturing(void)
-{
- enum v4l2_buf_type type;
-
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (xioctl(v4l2_fd, VIDIOC_STREAMON, &type) < 0) {
- ERR("Failed to ioctl() with VIDIOC_STREAMON: %s\n", strerror(errno));
- return errno;
- }
- return 0;
-}
-
-static void free_framebuffers(marucam_framebuffer *fb, int buf_num)
-{
- int i;
-
- if (fb == NULL) {
- ERR("The framebuffer is NULL. Failed to release the framebuffer\n");
- return;
- } else if (buf_num == 0) {
- ERR("The buffer count is 0. Failed to release the framebuffer\n");
- return;
- } else {
- TRACE("[%s]:fb(0x%p), buf_num(%d)\n", __func__, fb, buf_num);
- }
-
- /* Unmap framebuffers. */
- for (i = 0; i < buf_num; i++) {
- if (fb[i].data != NULL) {
- v4l2_munmap(fb[i].data, fb[i].size);
- fb[i].data = NULL;
- fb[i].size = 0;
- } else {
- ERR("framebuffer[%d].data is NULL.\n", i);
- }
- }
- previous_frame_index = -1;
-}
-
-static uint32_t
-mmap_framebuffers(marucam_framebuffer **fb, int *buf_num)
-{
- struct v4l2_requestbuffers req;
-
- CLEAR(req);
- req.count = MARUCAM_DEFAULT_BUFFER_COUNT;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_MMAP;
- if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &req) < 0) {
- if (errno == EINVAL) {
- ERR("%s does not support memory mapping: %s\n",
- dev_name, strerror(errno));
- } else {
- ERR("Failed to request bufs: %s\n", strerror(errno));
- }
- return errno;
- }
- if (req.count == 0) {
- ERR("Insufficient buffer memory on %s\n", dev_name);
- return EINVAL;
- }
-
- *fb = g_new0(marucam_framebuffer, req.count);
- if (*fb == NULL) {
- ERR("Not enough memory to allocate framebuffers\n");
- return ENOMEM;
- }
-
- for (*buf_num = 0; *buf_num < req.count; ++*buf_num) {
- struct v4l2_buffer buf;
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = *buf_num;
- if (xioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf) < 0) {
- ERR("Failed to ioctl() with VIDIOC_QUERYBUF: %s\n",
- strerror(errno));
- return errno;
- }
-
- (*fb)[*buf_num].size = buf.length;
- (*fb)[*buf_num].data = v4l2_mmap(NULL,
- buf.length,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- v4l2_fd, buf.m.offset);
- if (MAP_FAILED == (*fb)[*buf_num].data) {
- ERR("Failed to mmap: %s\n", strerror(errno));
- return errno;
- }
-
- /* Queue the mapped buffer. */
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = *buf_num;
- if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) {
- ERR("Failed to ioctl() with VIDIOC_QBUF: %s\n", strerror(errno));
- return errno;
- }
- }
- return 0;
-}
-
-static int is_streamon(MaruCamState *state)
-{
- int st;
- qemu_mutex_lock(&state->thread_mutex);
- st = state->streamon;
- qemu_mutex_unlock(&state->thread_mutex);
- return (st == _MC_THREAD_STREAMON);
-}
-
-static int is_stream_paused(MaruCamState *state)
-{
- int st;
- qemu_mutex_lock(&state->thread_mutex);
- st = state->streamon;
- qemu_mutex_unlock(&state->thread_mutex);
- return (st == _MC_THREAD_PAUSED);
-}
-
-/* sends a frame, YU12/black color */
-/* TODO: add other pixel format method */
-static void __raise_dummy_intr(MaruCamState *state)
-{
- void *buf = NULL;
- qemu_mutex_lock(&state->thread_mutex);
- if (state->streamon == _MC_THREAD_STREAMON && state->req_frame) {
- buf = state->vaddr + state->buf_size * (state->req_frame - 1);
- if (saved_frame.data) {
- if (saved_frame.width == dst_fmt.fmt.pix.width &&
- saved_frame.height == dst_fmt.fmt.pix.height) {
- TRACE("Copies the previuos frame\n");
- memcpy(buf, saved_frame.data, state->buf_size);
- } else {
- TRACE("Resizes the previous frame\n");
- marucam_scale_yuv420(saved_frame.data, saved_frame.width,
- saved_frame.height,
- buf, dst_fmt.fmt.pix.width,
- dst_fmt.fmt.pix.height);
- }
- } else {
- TRACE("Sends a black frame\n");
- make_yu12_black(buf,
- dst_fmt.fmt.pix.width,
- dst_fmt.fmt.pix.height);
- }
- state->req_frame = 0; /* clear request */
- state->isr |= 0x01; /* set a flag of raising a interrupt */
- qemu_bh_schedule(state->tx_bh);
- }
- qemu_mutex_unlock(&state->thread_mutex);
-}
-
-static void __raise_err_intr(MaruCamState *state)
-{
- qemu_mutex_lock(&state->thread_mutex);
- if (state->streamon == _MC_THREAD_STREAMON) {
- state->req_frame = 0; /* clear request */
- state->isr = 0x08; /* set a error flag of raising a interrupt */
- qemu_bh_schedule(state->tx_bh);
- }
- qemu_mutex_unlock(&state->thread_mutex);
-}
-
-static void
-notify_buffer_ready(MaruCamState *state, uint32_t buf_index)
-{
- void *buf = NULL;
-
- qemu_mutex_lock(&state->thread_mutex);
- if (state->streamon == _MC_THREAD_STREAMON) {
- if (ready_count < MARUCAM_SKIPFRAMES) {
- /* skip a frame cause first some frame are distorted */
- ++ready_count;
- TRACE("Skip %d frame\n", ready_count);
- qemu_mutex_unlock(&state->thread_mutex);
- return;
- }
- if (state->req_frame == 0) {
- TRACE("There is no request\n");
- qemu_mutex_unlock(&state->thread_mutex);
- return;
- }
- buf = state->vaddr + state->buf_size * (state->req_frame - 1);
- memcpy(buf, framebuffer[buf_index].data, state->buf_size);
- previous_frame_index = buf_index;
- has_success_frame = 1;
- state->req_frame = 0; /* clear request */
- state->isr |= 0x01; /* set a flag of rasing a interrupt */
- qemu_bh_schedule(state->tx_bh);
- }
- qemu_mutex_unlock(&state->thread_mutex);
-}
-
-static int read_frame(MaruCamState *state)
-{
- struct v4l2_buffer buf;
-
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- if (xioctl(v4l2_fd, VIDIOC_DQBUF, &buf) < 0) {
- switch (errno) {
- case EAGAIN:
- case EINTR:
- ERR("DQBUF error, try again: %s\n", strerror(errno));
- return 0;
- case EIO:
- ERR("The v4l2_read() met the EIO\n");
- if (convert_trial-- == -1) {
- ERR("Try count for v4l2_read is exceeded: %s\n",
- strerror(errno));
- return -1;
- }
- return 0;
- default:
- ERR("DQBUF error: %s\n", strerror(errno));
- return -1;
- }
- }
-
- notify_buffer_ready(state, buf.index);
-
- if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) {
- ERR("QBUF error: %s\n", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-static int __v4l2_streaming(MaruCamState *state)
-{
- fd_set fds;
- struct timeval tv;
- int ret;
-
- FD_ZERO(&fds);
- FD_SET(v4l2_fd, &fds);
-
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- ERR("Select again: %s\n", strerror(errno));
- return 0;
- }
- ERR("Failed to select: %s\n", strerror(errno));
- __raise_err_intr(state);
- return -1;
- } else if (!ret) {
- timeout_n++;
- ERR("Select timed out: count(%u)\n", timeout_n);
- if (ready_count <= MARUCAM_SKIPFRAMES) {
- switch (timeout_n) {
- case 1:
- ERR("Waiting for reading a frame data\n");
- return 0;
- case 2:
- case 3:
- case 4:
- ERR("Sends dummy data to initialize the camera\n");
- __raise_dummy_intr(state);
- return 0;
- default:
- ERR("Webcam is busy, failed to a read frame."
- " Raises an error\n");
- __raise_err_intr(state);
- return -1;
- }
- }
- if (timeout_n >= 5) {
- ERR("Webcam is busy, failed to a read frame. Raises an error\n");
- __raise_err_intr(state);
- return -1;
- }
- if (previous_frame_index != -1) {
- ERR("Sends previous frame data\n");
- notify_buffer_ready(state, previous_frame_index);
- }
- return 0;
- }
-
- if (!v4l2_fd || (v4l2_fd == -1)) {
- ERR("The file descriptor is closed or not opened\n");
- __raise_err_intr(state);
- return -1;
- }
-
- ret = read_frame(state);
- if (ret < 0) {
- ERR("Failed to operate the read_frame()\n");
- __raise_err_intr(state);
- return -1;
- }
-
- /* clear the skip count for select time-out */
- if (timeout_n > 0) {
- timeout_n = 0;
- }
-
- return 0;
-}
-
-/* Worker thread */
-static void *marucam_worker_thread(void *thread_param)
-{
- MaruCamState *state = (MaruCamState *)thread_param;
-
- while (1) {
- qemu_mutex_lock(&state->thread_mutex);
- state->streamon = _MC_THREAD_PAUSED;
- qemu_cond_wait(&state->thread_cond, &state->thread_mutex);
- qemu_mutex_unlock(&state->thread_mutex);
-
- if (state->destroying) {
- break;
- }
-
- convert_trial = 10;
- ready_count = 0;
- timeout_n = 0;
- has_success_frame = 0;
- qemu_mutex_lock(&state->thread_mutex);
- state->streamon = _MC_THREAD_STREAMON;
- qemu_mutex_unlock(&state->thread_mutex);
- INFO("Streaming on ......\n");
-
- while (1) {
- if (is_streamon(state)) {
- if (__v4l2_streaming(state) < 0) {
- INFO("...... Streaming off\n");
- break;
- }
- } else {
- INFO("...... Streaming off\n");
- break;
- }
- }
- }
-
- return NULL;
-}
-
-int marucam_device_check(int log_flag)
-{
- int tmp_fd;
- struct timeval t1, t2;
- struct stat st;
- struct v4l2_fmtdesc format;
- struct v4l2_frmsizeenum size;
- struct v4l2_capability cap;
- int ret = 0;
-
- gettimeofday(&t1, NULL);
- if (stat(dev_name, &st) < 0) {
- INFO("<WARNING> Cannot identify '%s': %s\n",
- dev_name, strerror(errno));
- } else {
- if (!S_ISCHR(st.st_mode)) {
- INFO("<WARNING>%s is no character device\n",
- dev_name);
- }
- }
-
- tmp_fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
- if (tmp_fd < 0) {
- ERR("Camera device open failed: %s\n", dev_name);
- gettimeofday(&t2, NULL);
- ERR("Elapsed time: %lu:%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
- if (ioctl(tmp_fd, VIDIOC_QUERYCAP, &cap) < 0) {
- ERR("Could not qeury video capabilities\n");
- close(tmp_fd);
- gettimeofday(&t2, NULL);
- ERR("Elapsed time: %lu:%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
- if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
- !(cap.capabilities & V4L2_CAP_STREAMING)) {
- ERR("Not supported video driver\n");
- close(tmp_fd);
- gettimeofday(&t2, NULL);
- ERR("Elapsed time: %lu:%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
- ret = 1;
-
- if (log_flag) {
- INFO("Driver: %s\n", cap.driver);
- INFO("Card: %s\n", cap.card);
- INFO("Bus info: %s\n", cap.bus_info);
-
- CLEAR(format);
- format.index = 0;
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) < 0) {
- close(tmp_fd);
- gettimeofday(&t2, NULL);
- ERR("Elapsed time: %lu:%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- do {
- CLEAR(size);
- size.index = 0;
- size.pixel_format = format.pixelformat;
-
- INFO("PixelFormat: %c%c%c%c\n",
- (char)(format.pixelformat),
- (char)(format.pixelformat >> 8),
- (char)(format.pixelformat >> 16),
- (char)(format.pixelformat >> 24));
-
- if (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) {
- close(tmp_fd);
- gettimeofday(&t2, NULL);
- ERR("Elapsed time: %lu:%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
- do {
- INFO("\tGot a discrete frame size %dx%d\n",
- size.discrete.width, size.discrete.height);
- size.index++;
- } while (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
- } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
- INFO("We have stepwise frame sizes:\n");
- INFO("\tmin width: %d, min height: %d\n",
- size.stepwise.min_width, size.stepwise.min_height);
- INFO("\tmax width: %d, max height: %d\n",
- size.stepwise.max_width, size.stepwise.max_height);
- INFO("\tstep width: %d, step height: %d\n",
- size.stepwise.step_width, size.stepwise.step_height);
- } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
- INFO("We have continuous frame sizes:\n");
- INFO("\tmin width: %d, min height: %d\n",
- size.stepwise.min_width, size.stepwise.min_height);
- INFO("\tmax width: %d, max height: %d\n",
- size.stepwise.max_width, size.stepwise.max_height);
-
- }
- format.index++;
- } while (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) >= 0);
- }
-
- close(tmp_fd);
- gettimeofday(&t2, NULL);
- INFO("Elapsed time: %lu:%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
-}
-
-void marucam_device_init(MaruCamState *state)
-{
- state->destroying = false;
- qemu_thread_create(&state->thread_id,
- MARUCAM_THREAD_NAME,
- marucam_worker_thread,
- (void *)state,
- QEMU_THREAD_JOINABLE);
-}
-
-void marucam_device_exit(MaruCamState *state)
-{
- state->destroying = true;
- qemu_mutex_lock(&state->thread_mutex);
- qemu_cond_signal(&state->thread_cond);
- qemu_mutex_unlock(&state->thread_mutex);
- qemu_thread_join(&state->thread_id);
-}
-
-void marucam_device_open(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- param->top = 0;
- v4l2_fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
- if (v4l2_fd < 0) {
- ERR("The v4l2 device open failed: %s\n", dev_name);
- param->errCode = EINVAL;
- return;
- }
- INFO("Opened\n");
-
- /* FIXME : Do not use fixed values */
- CLEAR(dst_fmt);
- dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_fmt.fmt.pix.width = 640;
- dst_fmt.fmt.pix.height = 480;
- dst_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- dst_fmt.fmt.pix.field = V4L2_FIELD_ANY;
-
- if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) {
- ERR("Failed to set video format: format(0x%x), width:height(%d:%d), "
- "errstr(%s)\n", dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.width,
- dst_fmt.fmt.pix.height, strerror(errno));
- param->errCode = errno;
- return;
- }
- TRACE("Set the default format: w:h(%dx%d), fmt(0x%x), size(%d), "
- "color(%d), field(%d)\n",
- dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height,
- dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage,
- dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field);
-}
-
-void marucam_device_start_preview(MaruCamState *state)
-{
- struct timespec req;
- MaruCamParam *param = state->param;
- param->top = 0;
- req.tv_sec = 0;
- req.tv_nsec = 10000000;
-
- INFO("Pixfmt(%c%c%c%C), W:H(%d:%d), buf size(%u)\n",
- (char)(dst_fmt.fmt.pix.pixelformat),
- (char)(dst_fmt.fmt.pix.pixelformat >> 8),
- (char)(dst_fmt.fmt.pix.pixelformat >> 16),
- (char)(dst_fmt.fmt.pix.pixelformat >> 24),
- dst_fmt.fmt.pix.width,
- dst_fmt.fmt.pix.height,
- dst_fmt.fmt.pix.sizeimage);
-
- param->errCode = mmap_framebuffers(&framebuffer, &n_framebuffer);
- if (param->errCode) {
- ERR("Failed to mmap framebuffers\n");
- if (framebuffer != NULL) {
- free_framebuffers(framebuffer, n_framebuffer);
- g_free(framebuffer);
- framebuffer = NULL;
- n_framebuffer = 0;
- }
- return;
- }
-
- param->errCode = start_capturing();
- if (param->errCode) {
- if (framebuffer != NULL) {
- free_framebuffers(framebuffer, n_framebuffer);
- g_free(framebuffer);
- framebuffer = NULL;
- n_framebuffer = 0;
- }
- return;
- }
-
- INFO("Starting preview\n");
- state->buf_size = dst_fmt.fmt.pix.sizeimage;
- qemu_mutex_lock(&state->thread_mutex);
- qemu_cond_signal(&state->thread_cond);
- qemu_mutex_unlock(&state->thread_mutex);
-
- /* nanosleep until thread is streamon */
- while (!is_streamon(state)) {
- nanosleep(&req, NULL);
- }
-}
-
-void marucam_device_stop_preview(MaruCamState *state)
-{
- struct timespec req;
- struct v4l2_requestbuffers reqbuf;
- MaruCamParam *param = state->param;
- param->top = 0;
- req.tv_sec = 0;
- req.tv_nsec = 50000000;
-
- if (is_streamon(state)) {
- qemu_mutex_lock(&state->thread_mutex);
- state->streamon = _MC_THREAD_STREAMOFF;
- qemu_mutex_unlock(&state->thread_mutex);
-
- /* nanosleep until thread is paused */
- while (!is_stream_paused(state)) {
- nanosleep(&req, NULL);
- }
- }
-
- if (has_success_frame) {
- saved_frame.width = dst_fmt.fmt.pix.width;
- saved_frame.height = dst_fmt.fmt.pix.height;
- saved_frame.size = dst_fmt.fmt.pix.sizeimage;
- if (saved_frame.data) {
- g_free(saved_frame.data);
- saved_frame.data = NULL;
- }
- saved_frame.data = (void *)g_malloc0(saved_frame.size);
- memcpy(saved_frame.data,
- framebuffer[previous_frame_index].data,
- saved_frame.size);
- TRACE("Saves a frame data\n");
- }
-
- param->errCode = stop_capturing();
- if (framebuffer != NULL) {
- free_framebuffers(framebuffer, n_framebuffer);
- g_free(framebuffer);
- framebuffer = NULL;
- n_framebuffer = 0;
- }
- state->buf_size = 0;
-
- reqbuf.count = 0;
- reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- reqbuf.memory = V4L2_MEMORY_MMAP;
- if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
- ERR("Failed to ioctl() with VIDIOC_REQBUF in stop_preview: %s\n",
- strerror(errno));
- }
- INFO("Stopping preview\n");
-}
-
-void marucam_device_s_param(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- param->top = 0;
-
- /* If KVM enabled, We use default FPS of the webcam.
- * If KVM disabled, we use mininum FPS of the webcam */
- if (!kvm_enabled()) {
- set_maxframeinterval(state, dst_fmt.fmt.pix.pixelformat,
- dst_fmt.fmt.pix.width,
- dst_fmt.fmt.pix.height);
- }
-}
-
-void marucam_device_g_param(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- /* We use default FPS of the webcam
- * return a fixed value on guest ini file (1/30).
- */
- param->top = 0;
- param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
- param->stack[1] = 1; /* numerator */
- param->stack[2] = 30; /* denominator */
-}
-
-void marucam_device_s_fmt(MaruCamState *state)
-{
- struct v4l2_format format;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- CLEAR(format);
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- format.fmt.pix.width = param->stack[0];
- format.fmt.pix.height = param->stack[1];
- format.fmt.pix.pixelformat = param->stack[2];
- format.fmt.pix.field = V4L2_FIELD_ANY;
-
- if (xioctl(v4l2_fd, VIDIOC_S_FMT, &format) < 0) {
- ERR("Failed to set video format: format(0x%x), width:height(%d:%d), "
- "errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,
- format.fmt.pix.height, strerror(errno));
- param->errCode = errno;
- return;
- }
-
- memcpy(&dst_fmt, &format, sizeof(format));
- param->stack[0] = dst_fmt.fmt.pix.width;
- param->stack[1] = dst_fmt.fmt.pix.height;
- param->stack[2] = dst_fmt.fmt.pix.field;
- param->stack[3] = dst_fmt.fmt.pix.pixelformat;
- param->stack[4] = dst_fmt.fmt.pix.bytesperline;
- param->stack[5] = dst_fmt.fmt.pix.sizeimage;
- param->stack[6] = dst_fmt.fmt.pix.colorspace;
- param->stack[7] = dst_fmt.fmt.pix.priv;
- TRACE("Set the format: w:h(%dx%d), fmt(0x%x), size(%d), "
- "color(%d), field(%d)\n",
- dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height,
- dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage,
- dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field);
-}
-
-void marucam_device_g_fmt(MaruCamState *state)
-{
- struct v4l2_format format;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- CLEAR(format);
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) {
- ERR("Failed to get video format: %s\n", strerror(errno));
- param->errCode = errno;
- } else {
- param->stack[0] = format.fmt.pix.width;
- param->stack[1] = format.fmt.pix.height;
- param->stack[2] = format.fmt.pix.field;
- param->stack[3] = format.fmt.pix.pixelformat;
- param->stack[4] = format.fmt.pix.bytesperline;
- param->stack[5] = format.fmt.pix.sizeimage;
- param->stack[6] = format.fmt.pix.colorspace;
- param->stack[7] = format.fmt.pix.priv;
- TRACE("Get the format: w:h(%dx%d), fmt(0x%x), size(%d), "
- "color(%d), field(%d)\n",
- format.fmt.pix.width, format.fmt.pix.height,
- format.fmt.pix.pixelformat, format.fmt.pix.sizeimage,
- format.fmt.pix.colorspace, format.fmt.pix.field);
- }
-}
-
-void marucam_device_try_fmt(MaruCamState *state)
-{
- struct v4l2_format format;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- CLEAR(format);
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- format.fmt.pix.width = param->stack[0];
- format.fmt.pix.height = param->stack[1];
- format.fmt.pix.pixelformat = param->stack[2];
- format.fmt.pix.field = V4L2_FIELD_ANY;
-
- if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) {
- ERR("Failed to check video format: format(0x%x), width:height(%d:%d),"
- " errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,
- format.fmt.pix.height, strerror(errno));
- param->errCode = errno;
- return;
- }
- param->stack[0] = format.fmt.pix.width;
- param->stack[1] = format.fmt.pix.height;
- param->stack[2] = format.fmt.pix.field;
- param->stack[3] = format.fmt.pix.pixelformat;
- param->stack[4] = format.fmt.pix.bytesperline;
- param->stack[5] = format.fmt.pix.sizeimage;
- param->stack[6] = format.fmt.pix.colorspace;
- param->stack[7] = format.fmt.pix.priv;
- TRACE("Check the format: w:h(%dx%d), fmt(0x%x), size(%d), "
- "color(%d), field(%d)\n",
- format.fmt.pix.width, format.fmt.pix.height,
- format.fmt.pix.pixelformat, format.fmt.pix.sizeimage,
- format.fmt.pix.colorspace, format.fmt.pix.field);
-}
-
-void marucam_device_enum_fmt(MaruCamState *state)
-{
- uint32_t index;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- index = param->stack[0];
-
- if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
- param->stack[1] = 0; /* flags = NONE */
- param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
- /* set description */
- switch (supported_dst_pixfmts[index].fmt) {
- case V4L2_PIX_FMT_YUYV:
- strcpy((char *)¶m->stack[3], "YUYV");
- break;
- case V4L2_PIX_FMT_YUV420:
- strcpy((char *)¶m->stack[3], "YU12");
- break;
- case V4L2_PIX_FMT_YVU420:
- strcpy((char *)¶m->stack[3], "YV12");
- break;
- default:
- ERR("Invalid fixel format\n");
- param->errCode = EINVAL;
- break;
- }
-}
-
-void marucam_device_qctrl(MaruCamState *state)
-{
- uint32_t i;
- char name[32] = {0,};
- struct v4l2_queryctrl ctrl;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- CLEAR(ctrl);
- ctrl.id = param->stack[0];
-
- switch (ctrl.id) {
- case V4L2_CID_BRIGHTNESS:
- TRACE("Query : BRIGHTNESS\n");
- strcpy(name, "brightness");
- i = 0;
- break;
- case V4L2_CID_CONTRAST:
- TRACE("Query : CONTRAST\n");
- strcpy(name, "contrast");
- i = 1;
- break;
- case V4L2_CID_SATURATION:
- TRACE("Query : SATURATION\n");
- strcpy(name, "saturation");
- i = 2;
- break;
- case V4L2_CID_SHARPNESS:
- TRACE("Query : SHARPNESS\n");
- strcpy(name, "sharpness");
- i = 3;
- break;
- default:
- ERR("Invalid control ID\n");
- param->errCode = EINVAL;
- return;
- }
-
- if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) {
- if (errno != EINVAL) {
- ERR("Failed to query video controls: %s\n", strerror(errno));
- }
- param->errCode = errno;
- return;
- } else {
- struct v4l2_control sctrl;
- CLEAR(sctrl);
- sctrl.id = ctrl.id;
- if ((ctrl.maximum + ctrl.minimum) == 0) {
- sctrl.value = 0;
- } else {
- sctrl.value = (ctrl.maximum + ctrl.minimum) / 2;
- }
- if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) {
- ERR("Failed to set control value: id(0x%x), value(%d), "
- "errstr(%s)\n", sctrl.id, sctrl.value, strerror(errno));
- param->errCode = errno;
- return;
- }
- qctrl_tbl[i].hit = 1;
- qctrl_tbl[i].min = ctrl.minimum;
- qctrl_tbl[i].max = ctrl.maximum;
- qctrl_tbl[i].step = ctrl.step;
- qctrl_tbl[i].init_val = ctrl.default_value;
- }
-
- /* set fixed values by FW configuration file */
- param->stack[0] = ctrl.id;
- param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
- param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
- param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
- param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
- param->stack[5] = ctrl.flags;
- /* name field setting */
- memcpy(¶m->stack[6], (void *)name, sizeof(ctrl.name));
-}
-
-void marucam_device_s_ctrl(MaruCamState *state)
-{
- uint32_t i;
- struct v4l2_control ctrl;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- CLEAR(ctrl);
- ctrl.id = param->stack[0];
-
- switch (ctrl.id) {
- case V4L2_CID_BRIGHTNESS:
- i = 0;
- TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]);
- break;
- case V4L2_CID_CONTRAST:
- i = 1;
- TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]);
- break;
- case V4L2_CID_SATURATION:
- i = 2;
- TRACE("%d is set to the value of the SATURATION\n", param->stack[1]);
- break;
- case V4L2_CID_SHARPNESS:
- i = 3;
- TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]);
- break;
- default:
- ERR("Our emulator does not support this control: 0x%x\n", ctrl.id);
- param->errCode = EINVAL;
- return;
- }
-
- ctrl.value = value_convert_from_guest(qctrl_tbl[i].min,
- qctrl_tbl[i].max, param->stack[1]);
- if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
- ERR("Failed to set control value: id(0x%x), value(r:%d, c:%d), "
- "errstr(%s)\n", ctrl.id, param->stack[1], ctrl.value,
- strerror(errno));
- param->errCode = errno;
- return;
- }
-}
-
-void marucam_device_g_ctrl(MaruCamState *state)
-{
- uint32_t i;
- struct v4l2_control ctrl;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- CLEAR(ctrl);
- ctrl.id = param->stack[0];
-
- switch (ctrl.id) {
- case V4L2_CID_BRIGHTNESS:
- TRACE("Gets the value of the BRIGHTNESS\n");
- i = 0;
- break;
- case V4L2_CID_CONTRAST:
- TRACE("Gets the value of the CONTRAST\n");
- i = 1;
- break;
- case V4L2_CID_SATURATION:
- TRACE("Gets the value of the SATURATION\n");
- i = 2;
- break;
- case V4L2_CID_SHARPNESS:
- TRACE("Gets the value of the SHARPNESS\n");
- i = 3;
- break;
- default:
- ERR("Our emulator does not support this control: 0x%x\n", ctrl.id);
- param->errCode = EINVAL;
- return;
- }
-
- if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) {
- ERR("Failed to get video control value: %s\n", strerror(errno));
- param->errCode = errno;
- return;
- }
- param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min,
- qctrl_tbl[i].max, ctrl.value);
- TRACE("Value: %d\n", param->stack[0]);
-}
-
-void marucam_device_enum_fsizes(MaruCamState *state)
-{
- uint32_t index, pixfmt, i;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- index = param->stack[0];
- pixfmt = param->stack[1];
-
- if (index >= ARRAY_SIZE(supported_dst_frames)) {
- param->errCode = EINVAL;
- return;
- }
- for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
- if (supported_dst_pixfmts[i].fmt == pixfmt) {
- break;
- }
- }
-
- if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
-
- param->stack[0] = supported_dst_frames[index].width;
- param->stack[1] = supported_dst_frames[index].height;
-}
-
-void marucam_device_enum_fintv(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- param->top = 0;
-
- /* switch by index(param->stack[0]) */
- switch (param->stack[0]) {
- case 0:
- /* we only use 1/30 frame interval */
- param->stack[1] = 30; /* denominator */
- break;
- default:
- param->errCode = EINVAL;
- return;
- }
- param->stack[0] = 1; /* numerator */
-}
-
-void marucam_device_close(MaruCamState *state)
-{
- if (!is_stream_paused(state)) {
- marucam_device_stop_preview(state);
- }
-
- marucam_reset_controls();
-
- if (saved_frame.data) {
- g_free(saved_frame.data);
- saved_frame.data = NULL;
- }
- memset(&saved_frame, 0x00, sizeof(saved_frame));
-
- v4l2_close(v4l2_fd);
- v4l2_fd = 0;
- INFO("Closed\n");
-}
+++ /dev/null
-/*
- * Interface definition header for Windows host.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef _MARU_CAMERA_INTERFACE_H_
-#define _MARU_CAMERA_INTERFACE_H_
-
-extern int hax_enabled(void);
-
-static const WCHAR HWCPinName[] = L"HWCInputPin\0";
-static const WCHAR HWCFilterName[] = L"HWCFilter\0";
-
-/* Forward Declarations */
-FWD_DECL(IBaseFilter);
-FWD_DECL(IFilterGraph);
-
-/* defines */
-#define MAX_PIN_NAME 128
-#define MAX_FILTER_NAME 128
-
-#define DECLARE_INTERFACE2(i) \
- _COM_interface i { CONST_VTABLE struct i##Vtbl *lpVtbl; }; \
- typedef CONST_VTABLE struct i##Vtbl i##Vtbl; \
- CONST_VTABLE struct i##Vtbl
-#define DECLARE_INTERFACE2_(i, b) DECLARE_INTERFACE2(i)
-
-typedef LONGLONG REFERENCE_TIME;
-typedef long OAFilterState;
-typedef DWORD_PTR HSEMAPHORE;
-typedef DWORD_PTR HEVENT;
-
-typedef enum _FilterState {
- State_Stopped,
- State_Paused,
- State_Running
-} FILTER_STATE;
-
-typedef struct _FilterInfo {
- WCHAR achName[MAX_FILTER_NAME];
- IFilterGraph *pGraph;
-} FILTER_INFO;
-
-typedef enum _PinDirection {
- PINDIR_INPUT = 0,
- PINDIR_OUTPUT = (PINDIR_INPUT + 1)
-} PIN_DIRECTION;
-
-typedef struct _PinInfo {
- IBaseFilter *pFilter;
- PIN_DIRECTION dir;
- WCHAR achName[MAX_PIN_NAME];
-} PIN_INFO;
-
-typedef struct _AllocatorProperties {
- long cBuffers;
- long cbBuffer;
- long cbAlign;
- long cbPrefix;
-} ALLOCATOR_PROPERTIES;
-
-typedef struct _AMMediaType {
- GUID majortype;
- GUID subtype;
- BOOL bFixedSizeSamples;
- BOOL bTemporalCompression;
- ULONG lSampleSize;
- GUID formattype;
- IUnknown *pUnk;
- ULONG cbFormat;
- BYTE *pbFormat;
-} AM_MEDIA_TYPE;
-
-typedef enum tagVideoProcAmpFlags {
- VideoProcAmp_Flags_Auto = 0x0001,
- VideoProcAmp_Flags_Manual = 0x0002
-} VideoProcAmpFlags;
-
-typedef enum tagVideoProcAmpProperty {
- VideoProcAmp_Brightness,
- VideoProcAmp_Contrast,
- VideoProcAmp_Hue,
- VideoProcAmp_Saturation,
- VideoProcAmp_Sharpness,
- VideoProcAmp_Gamma,
- VideoProcAmp_ColorEnable,
- VideoProcAmp_WhiteBalance,
- VideoProcAmp_BacklightCompensation,
- VideoProcAmp_Gain
-} VideoProcAmpProperty;
-
-typedef struct tagVIDEOINFOHEADER {
- RECT rcSource;
- RECT rcTarget;
- DWORD dwBitRate;
- DWORD dwBitErrorRate;
- REFERENCE_TIME AvgTimePerFrame;
- BITMAPINFOHEADER bmiHeader;
-} VIDEOINFOHEADER;
-
-typedef struct _VIDEO_STREAM_CONFIG_CAPS {
- GUID guid;
- ULONG VideoStandard;
- SIZE InputSize;
- SIZE MinCroppingSize;
- SIZE MaxCroppingSize;
- int CropGranularityX;
- int CropGranularityY;
- int CropAlignX;
- int CropAlignY;
- SIZE MinOutputSize;
- SIZE MaxOutputSize;
- int OutputGranularityX;
- int OutputGranularityY;
- int StretchTapsX;
- int StretchTapsY;
- int ShrinkTapsX;
- int ShrinkTapsY;
- LONGLONG MinFrameInterval;
- LONGLONG MaxFrameInterval;
- LONG MinBitsPerSecond;
- LONG MaxBitsPerSecond;
-} VIDEO_STREAM_CONFIG_CAPS;
-
-
-/* Interface & Class GUIDs */
-static const IID IID_IGrabCallback = {0x4C337035,0xC89E,0x4B42,{0x9B,0x0C,0x36,0x74,0x44,0xDD,0x70,0xDD}};
-
-EXTERN_C const IID IID_IBaseFilter;
-EXTERN_C const IID IID_ICreateDevEnum;
-EXTERN_C const IID IID_IGraphBuilder;
-EXTERN_C const IID IID_IMediaSeeking;
-EXTERN_C const IID IID_IMediaEventSink;
-EXTERN_C const IID IID_IMemInputPin;
-EXTERN_C const IID IID_IEnumPins;
-EXTERN_C const IID IID_IMediaFilter;
-EXTERN_C const IID IID_IEnumMediaTypes;
-EXTERN_C const IID IID_IMemAllocator;
-EXTERN_C const IID IID_IPin;
-EXTERN_C const IID IID_ICaptureGraphBuilder2;
-EXTERN_C const IID IID_IFileSinkFilter;
-EXTERN_C const IID IID_IAMCopyCaptureFileProgress;
-EXTERN_C const IID IID_IEnumFilters;
-EXTERN_C const IID IID_IMediaSample;
-EXTERN_C const IID IID_IMediaControl;
-EXTERN_C const IID IID_IAMStreamConfig;
-EXTERN_C const IID IID_IAMVideoProcAmp;
-
-EXTERN_C const IID CLSID_CaptureGraphBuilder2;
-EXTERN_C const IID CLSID_VideoInputDeviceCategory;
-EXTERN_C const IID CLSID_AudioRender;
-EXTERN_C const IID CLSID_SystemDeviceEnum;
-EXTERN_C const IID CLSID_AudioRendererCategory;
-EXTERN_C const IID CLSID_FilterGraph;
-EXTERN_C const IID CLSID_InfTee;
-EXTERN_C const IID CLSID_VideoMixingRenderer9;
-EXTERN_C const IID CLSID_MemoryAllocator;
-
-
-/* other types GUIDs*/
-EXTERN_C const IID MEDIATYPE_Audio;
-EXTERN_C const IID MEDIATYPE_Video;
-EXTERN_C const IID MEDIATYPE_Stream;
-EXTERN_C const IID MEDIASUBTYPE_PCM;
-EXTERN_C const IID MEDIASUBTYPE_WAVE;
-EXTERN_C const IID MEDIASUBTYPE_Avi;
-EXTERN_C const IID MEDIASUBTYPE_RGB32;
-EXTERN_C const IID MEDIASUBTYPE_YV12;
-EXTERN_C const IID MEDIASUBTYPE_YUY2;
-EXTERN_C const IID MEDIASUBTYPE_I420;
-EXTERN_C const IID MEDIASUBTYPE_YUYV;
-EXTERN_C const IID FORMAT_WaveFormatEx;
-EXTERN_C const IID FORMAT_VideoInfo;
-EXTERN_C const IID FORMAT_VideoInfo2;
-EXTERN_C const IID PIN_CATEGORY_CAPTURE;
-EXTERN_C const IID PIN_CATEGORY_PREVIEW;
-
-
-#define MEDIATYPE_NULL GUID_NULL
-#define MEDIASUBTYPE_NULL GUID_NULL
-
-#define INTERFACE IGrabCallback
-DECLARE_INTERFACE_(IGrabCallback, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(Grab)(THIS_ ULONG,BYTE*) PURE;
-};
-#undef INTERFACE
-
-#ifdef COBJMACROS
-#define IGrabCallback_QueryInterface(T,a,b) (T)->lpVtbl->QueryInterface(T,a,b)
-#define IGrabCallback_AddRef(T) (T)->lpVtbl->AddRef(T)
-#define IGrabCallback_Release(T) (T)->lpVtbl->Release(T)
-#define IGrabCallback_Grab(T,a,b) (T)->lpVtbl->Grab(T,a,b)
-#endif /* COBJMACROS */
-
-#define INTERFACE IAMCopyCaptureFileProgress
-DECLARE_INTERFACE_(IAMCopyCaptureFileProgress, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(Progress)(THIS_ int) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IReferenceClock
-DECLARE_INTERFACE_(IReferenceClock, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *) PURE;
- STDMETHOD(AdviseTime)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HEVENT, DWORD_PTR *) PURE;
- STDMETHOD(AdvisePeriodic)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HSEMAPHORE, DWORD_PTR *) PURE;
- STDMETHOD(Unadvise)(THIS_ DWORD_PTR) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IEnumFilters
-DECLARE_INTERFACE_(IEnumFilters, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(Next)(THIS_ ULONG, IBaseFilter **, ULONG *) PURE;
- STDMETHOD(Skip)(THIS_ ULONG) PURE;
- STDMETHOD(Reset)(THIS) PURE;
- STDMETHOD(Clone)(THIS_ IEnumFilters **) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IEnumMediaTypes
-DECLARE_INTERFACE_(IEnumMediaTypes, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(Next)(THIS_ ULONG, AM_MEDIA_TYPE **, ULONG *) PURE;
- STDMETHOD(Skip)(THIS_ ULONG) PURE;
- STDMETHOD(Reset)(THIS) PURE;
- STDMETHOD(Clone)(THIS_ IEnumMediaTypes **) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IPin
-DECLARE_INTERFACE_(IPin, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(Connect)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;
- STDMETHOD(ReceiveConnection)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;
- STDMETHOD(Disconnect)(THIS) PURE;
- STDMETHOD(ConnectedTo)(THIS_ IPin **) PURE;
- STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;
- STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO *) PURE;
- STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION *) PURE;
- STDMETHOD(QueryId)(THIS_ LPWSTR *) PURE;
- STDMETHOD(QueryAccept)(THIS_ const AM_MEDIA_TYPE *) PURE;
- STDMETHOD(EnumMediaTypes)(THIS_ IEnumMediaTypes **) PURE;
- STDMETHOD(QueryInternalConnections)(THIS_ IPin **, ULONG *) PURE;
- STDMETHOD(EndOfStream)(THIS) PURE;
- STDMETHOD(BeginFlush)(THIS) PURE;
- STDMETHOD(EndFlush)(THIS) PURE;
- STDMETHOD(NewSegment)(THIS_ REFERENCE_TIME, REFERENCE_TIME, double) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IEnumPins
-DECLARE_INTERFACE_(IEnumPins, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(Next)(THIS_ ULONG, IPin **, ULONG *) PURE;
- STDMETHOD(Skip)(THIS_ ULONG) PURE;
- STDMETHOD(Reset)(THIS) PURE;
- STDMETHOD(Clone)(THIS_ IEnumPins **) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IMediaFilter
-DECLARE_INTERFACE_(IMediaFilter, IPersist)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetClassID)(THIS_ CLSID*) PURE;
- STDMETHOD(Stop)(THIS) PURE;
- STDMETHOD(Pause)(THIS) PURE;
- STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;
- STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE;
- STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE;
- STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IBaseFilter
-DECLARE_INTERFACE2_(IBaseFilter, IMediaFilter)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetClassID)(THIS_ CLSID*) PURE;
- STDMETHOD(Stop)(THIS) PURE;
- STDMETHOD(Pause)(THIS) PURE;
- STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;
- STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE;
- STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE;
- STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE;
- STDMETHOD(EnumPins)(THIS_ IEnumPins **) PURE;
- STDMETHOD(FindPin)(THIS_ LPCWSTR, IPin **) PURE;
- STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO *) PURE;
- STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph *, LPCWSTR) PURE;
- STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR *) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IFilterGraph
-DECLARE_INTERFACE2_(IFilterGraph, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE;
- STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE;
- STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE;
- STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE;
- STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;
- STDMETHOD(Reconnect)(THIS_ IPin *) PURE;
- STDMETHOD(Disconnect)(THIS_ IPin *) PURE;
- STDMETHOD(SetDefaultSyncSource)(THIS) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IGraphBuilder
-DECLARE_INTERFACE_(IGraphBuilder ,IFilterGraph)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE;
- STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE;
- STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE;
- STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE;
- STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;
- STDMETHOD(Reconnect)(THIS_ IPin *) PURE;
- STDMETHOD(Disconnect)(THIS_ IPin *) PURE;
- STDMETHOD(SetDefaultSyncSource)(THIS) PURE;
- STDMETHOD(Connect)(THIS_ IPin *, IPin *) PURE;
- STDMETHOD(Render)(THIS_ IPin *) PURE;
- STDMETHOD(RenderFile)(THIS_ LPCWSTR, LPCWSTR) PURE;
- STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR, LPCWSTR, IBaseFilter **) PURE;
- STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE;
- STDMETHOD(Abort)(THIS) PURE;
- STDMETHOD(ShouldOperationContinue)(THIS) PURE;
-};
-#undef INTERFACE
-#define INTERFACE ICreateDevEnum
-DECLARE_INTERFACE_(ICreateDevEnum, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(CreateClassEnumerator)(THIS_ REFCLSID, IEnumMoniker **, DWORD) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IMediaSample
-DECLARE_INTERFACE_(IMediaSample, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;
- STDMETHOD_(long, GetSize)(THIS) PURE;
- STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
- STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
- STDMETHOD(IsSyncPoint)(THIS) PURE;
- STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE;
- STDMETHOD(IsPreroll)(THIS) PURE;
- STDMETHOD(SetPreroll)(THIS_ BOOL) PURE;
- STDMETHOD_(long, GetActualDataLength)(THIS) PURE;
- STDMETHOD(SetActualDataLength)(THIS_ long) PURE;
- STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE;
- STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;
- STDMETHOD(IsDiscontinuity)(THIS) PURE;
- STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE;
- STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
- STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IMemAllocator
-DECLARE_INTERFACE_(IMemAllocator, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES *, ALLOCATOR_PROPERTIES *) PURE;
- STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES *) PURE;
- STDMETHOD(Commit)(THIS) PURE;
- STDMETHOD(Decommit)(THIS) PURE;
- STDMETHOD(GetBuffer)(THIS_ IMediaSample **, REFERENCE_TIME *, REFERENCE_TIME *, DWORD) PURE;
- STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample *) PURE;
-
-};
-#undef INTERFACE
-#define INTERFACE IMemInputPin
-DECLARE_INTERFACE_(IMemInputPin, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetAllocator)(THIS_ IMemAllocator **) PURE;
- STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator *, BOOL) PURE;
- STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES *) PURE;
- STDMETHOD(Receive)(THIS_ IMediaSample *) PURE;
- STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample **, long, long *) PURE;
- STDMETHOD(ReceiveCanBlock)(THIS) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IFileSinkFilter
-DECLARE_INTERFACE_(IFileSinkFilter, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(SetFileName)(THIS_ LPCOLESTR,const AM_MEDIA_TYPE *) PURE;
- STDMETHOD(GetCurFile)(THIS_ LPOLESTR *,AM_MEDIA_TYPE*) PURE;
-};
-#undef INTERFACE
-#define INTERFACE ICaptureGraphBuilder2
-DECLARE_INTERFACE_(ICaptureGraphBuilder2, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(SetFiltergraph)(THIS_ IGraphBuilder*) PURE;
- STDMETHOD(GetFiltergraph)(THIS_ IGraphBuilder**) PURE;
- STDMETHOD(SetOutputFileName)(THIS_ const GUID*,LPCOLESTR,IBaseFilter**,IFileSinkFilter**) PURE;
- STDMETHOD(FindInterface)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFIID,void**) PURE;
- STDMETHOD(RenderStream)(THIS_ const GUID*,const GUID*,IUnknown*,IBaseFilter*,IBaseFilter*) PURE;
- STDMETHOD(ControlStream)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFERENCE_TIME*,REFERENCE_TIME*,WORD,WORD) PURE;
- STDMETHOD(AllocCapFile)(THIS_ LPCOLESTR,DWORDLONG) PURE;
- STDMETHOD(CopyCaptureFile)(THIS_ LPOLESTR,LPOLESTR,int,IAMCopyCaptureFileProgress*) PURE;
- STDMETHOD(FindPin)(THIS_ IUnknown*,PIN_DIRECTION,const GUID*,const GUID*,BOOL,int,IPin**) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IAMStreamConfig
-DECLARE_INTERFACE_(IAMStreamConfig, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE;
- STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE;
- STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE;
- STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IAMVideoProcAmp
-DECLARE_INTERFACE_(IAMVideoProcAmp, IUnknown)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetRange)(THIS_ long,long*,long*,long*,long*,long*) PURE;
- STDMETHOD(Set)(THIS_ long,long,long) PURE;
- STDMETHOD(Get)(THIS_ long,long*,long*) PURE;
-};
-#undef INTERFACE
-#define INTERFACE IMediaControl
-DECLARE_INTERFACE_(IMediaControl, IDispatch)
-{
- STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
- STDMETHOD_(ULONG, AddRef)(THIS) PURE;
- STDMETHOD_(ULONG, Release)(THIS) PURE;
- STDMETHOD(GetTypeInfoCount)(THIS_ UINT*);
- STDMETHOD(GetTypeInfo)(THIS_ UINT,LCID,ITypeInfo**);
- STDMETHOD(GetIDsOfNames)(THIS_ REFIID,LPOLESTR*,UINT,LCID,DISPID*);
- STDMETHOD(Invoke)(THIS_ DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
- STDMETHOD(Run)(THIS);
- STDMETHOD(Pause)(THIS);
- STDMETHOD(Stop)(THIS);
- STDMETHOD(GetState)(THIS_ LONG, OAFilterState*);
- STDMETHOD(RenderFile)(THIS_ BSTR);
- STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**);
- STDMETHOD(get_FilterCollection)(THIS_ IDispatch**);
- STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**);
- STDMETHOD(StopWhenReady)(THIS);
-};
-#undef INTERFACE
-
-#ifdef COBJMACROS
-#define ICreateDevEnum_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define ICreateDevEnum_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define ICreateDevEnum_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define ICreateDevEnum_CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags) \
- ((This)->lpVtbl->CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IPin_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IPin_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IPin_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IPin_Connect(This,pReceivePin,pmt) \
- ((This)->lpVtbl->Connect(This,pReceivePin,pmt))
-#define IPin_ReceiveConnection(This,pConnector,pmt) \
- ((This)->lpVtbl->ReceiveConnection(This,pConnector,pmt))
-#define IPin_Disconnect(This) \
- ((This)->lpVtbl->Disconnect(This))
-#define IPin_ConnectedTo(This,pPin) \
- ((This)->lpVtbl->ConnectedTo(This,pPin))
-#define IPin_ConnectionMediaType(This,pmt) \
- ((This)->lpVtbl->ConnectionMediaType(This,pmt))
-#define IPin_QueryPinInfo(This,pInfo) \
- ((This)->lpVtbl->QueryPinInfo(This,pInfo))
-#define IPin_QueryDirection(This,pPinDir) \
- ((This)->lpVtbl->QueryDirection(This,pPinDir))
-#define IPin_QueryId(This,Id) \
- ((This)->lpVtbl->QueryId(This,Id))
-#define IPin_QueryAccept(This,pmt) \
- ((This)->lpVtbl->QueryAccept(This,pmt))
-#define IPin_EnumMediaTypes(This,ppEnum) \
- ((This)->lpVtbl->EnumMediaTypes(This,ppEnum))
-#define IPin_QueryInternalConnections(This,apPin,nPin) \
- ((This)->lpVtbl->QueryInternalConnections(This,apPin,nPin))
-#define IPin_EndOfStream(This) \
- ((This)->lpVtbl->EndOfStream(This))
-#define IPin_BeginFlush(This) \
- ((This)->lpVtbl->BeginFlush(This))
-#define IPin_EndFlush(This) \
- ((This)->lpVtbl->EndFlush(This))
-#define IPin_NewSegment(This,tStart,tStop,dRate) \
- ((This)->lpVtbl->NewSegment(This,tStart,tStop,dRate))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IEnumPins_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IEnumPins_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IEnumPins_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IEnumPins_Next(This,cPins,ppPins,pcFetched) \
- ((This)->lpVtbl->Next(This,cPins,ppPins,pcFetched))
-#define IEnumPins_Skip(This,cPins) \
- ((This)->lpVtbl->Skip(This,cPins))
-#define IEnumPins_Reset(This) \
- ((This)->lpVtbl->Reset(This))
-#define IEnumPins_Clone(This,ppEnum) \
- ((This)->lpVtbl->Clone(This,ppEnum))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IAMStreamConfig_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IAMStreamConfig_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IAMStreamConfig_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IAMStreamConfig_SetFormat(This,pmt) \
- ((This)->lpVtbl->SetFormat(This,pmt))
-#define IAMStreamConfig_GetFormat(This,ppmt) \
- ((This)->lpVtbl->GetFormat(This,ppmt))
-#define IAMStreamConfig_GetNumberOfCapabilities(This,piCount,piSize) \
- ((This)->lpVtbl->GetNumberOfCapabilities(This,piCount,piSize))
-#define IAMStreamConfig_GetStreamCaps(This,iIndex,ppmt,pSCC) \
- ((This)->lpVtbl->GetStreamCaps(This,iIndex,ppmt,pSCC))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IFilterGraph_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IFilterGraph_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IFilterGraph_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IFilterGraph_AddFilter(This,pFilter,pName) \
- ((This)->lpVtbl->AddFilter(This,pFilter,pName))
-#define IFilterGraph_RemoveFilter(This,pFilter) \
- ((This)->lpVtbl->RemoveFilter(This,pFilter))
-#define IFilterGraph_EnumFilters(This,ppEnum) \
- ((This)->lpVtbl->EnumFilters(This,ppEnum))
-#define IFilterGraph_FindFilterByName(This,pName,ppFilter) \
- ((This)->lpVtbl->FindFilterByName(This,pName,ppFilter))
-#define IFilterGraph_ConnectDirect(This,ppinOut,ppinIn,pmt) \
- ((This)->lpVtbl->ConnectDirect(This,ppinOut,ppinIn,pmt))
-#define IFilterGraph_Reconnect(This,ppin) \
- ((This)->lpVtbl->Reconnect(This,ppin))
-#define IFilterGraph_Disconnect(This,ppin) \
- ((This)->lpVtbl->Disconnect(This,ppin))
-#define IFilterGraph_SetDefaultSyncSource(This) \
- ((This)->lpVtbl->SetDefaultSyncSource(This))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IMediaFilter_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IMediaFilter_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IMediaFilter_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IMediaFilter_GetClassID(This,pClassID) \
- ((This)->lpVtbl->GetClassID(This,pClassID))
-#define IMediaFilter_Stop(This) \
- ((This)->lpVtbl->Stop(This))
-#define IMediaFilter_Pause(This) \
- ((This)->lpVtbl->Pause(This))
-#define IMediaFilter_Run(This,tStart) \
- ((This)->lpVtbl->Run(This,tStart))
-#define IMediaFilter_GetState(This,dwMilliSecsTimeout,State) \
- ((This)->lpVtbl->GetState(This,dwMilliSecsTimeout,State))
-#define IMediaFilter_SetSyncSource(This,pClock) \
- ((This)->lpVtbl->SetSyncSource(This,pClock))
-#define IMediaFilter_GetSyncSource(This,pClock) \
- ((This)->lpVtbl->GetSyncSource(This,pClock))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IBaseFilter_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IBaseFilter_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IBaseFilter_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IBaseFilter_GetClassID(This,pClassID) \
- ((This)->lpVtbl->GetClassID(This,pClassID))
-#define IBaseFilter_Stop(This) \
- ((This)->lpVtbl->Stop(This))
-#define IBaseFilter_Pause(This) \
- ((This)->lpVtbl->Pause(This))
-#define IBaseFilter_Run(This,tStart) \
- ((This)->lpVtbl->Run(This,tStart))
-#define IBaseFilter_GetState(This,dwMilliSecsTimeout,State) \
- ((This)->lpVtbl->GetState(This,dwMilliSecsTimeout,State))
-#define IBaseFilter_SetSyncSource(This,pClock) \
- ((This)->lpVtbl->SetSyncSource(This,pClock))
-#define IBaseFilter_GetSyncSource(This,pClock) \
- ((This)->lpVtbl->GetSyncSource(This,pClock))
-#define IBaseFilter_EnumPins(This,ppEnum) \
- ((This)->lpVtbl->EnumPins(This,ppEnum))
-#define IBaseFilter_FindPin(This,Id,ppPin) \
- ((This)->lpVtbl->FindPin(This,Id,ppPin))
-#define IBaseFilter_QueryFilterInfo(This,pInfo) \
- ((This)->lpVtbl->QueryFilterInfo(This,pInfo))
-#define IBaseFilter_JoinFilterGraph(This,pGraph,pName) \
- ((This)->lpVtbl->JoinFilterGraph(This,pGraph,pName))
-#define IBaseFilter_QueryVendorInfo(This,pVendorInfo) \
- ((This)->lpVtbl->QueryVendorInfo(This,pVendorInfo))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IMediaSample_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IMediaSample_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IMediaSample_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IMediaSample_GetPointer(This,ppBuffer) \
- ((This)->lpVtbl->GetPointer(This,ppBuffer))
-#define IMediaSample_GetSize(This) \
- ((This)->lpVtbl->GetSize(This))
-#define IMediaSample_GetTime(This,pTimeStart,pTimeEnd) \
- ((This)->lpVtbl->GetTime(This,pTimeStart,pTimeEnd))
-#define IMediaSample_SetTime(This,pTimeStart,pTimeEnd) \
- ((This)->lpVtbl->SetTime(This,pTimeStart,pTimeEnd))
-#define IMediaSample_IsSyncPoint(This) \
- ((This)->lpVtbl->IsSyncPoint(This))
-#define IMediaSample_SetSyncPoint(This,bIsSyncPoint) \
- ((This)->lpVtbl->SetSyncPoint(This,bIsSyncPoint))
-#define IMediaSample_IsPreroll(This) \
- ((This)->lpVtbl->IsPreroll(This))
-#define IMediaSample_SetPreroll(This,bIsPreroll) \
- ((This)->lpVtbl->SetPreroll(This,bIsPreroll))
-#define IMediaSample_GetActualDataLength(This) \
- ((This)->lpVtbl->GetActualDataLength(This))
-#define IMediaSample_SetActualDataLength(This,length) \
- ((This)->lpVtbl->SetActualDataLength(This,length))
-#define IMediaSample_GetMediaType(This,ppMediaType) \
- ((This)->lpVtbl->GetMediaType(This,ppMediaType))
-#define IMediaSample_SetMediaType(This,pMediaType) \
- ((This)->lpVtbl->SetMediaType(This,pMediaType))
-#define IMediaSample_IsDiscontinuity(This) \
- ((This)->lpVtbl->IsDiscontinuity(This))
-#define IMediaSample_SetDiscontinuity(This,bDiscontinuity) \
- ((This)->lpVtbl->SetDiscontinuity(This,bDiscontinuity))
-#define IMediaSample_GetMediaTime(This,pTimeStart,pTimeEnd) \
- ((This)->lpVtbl->GetMediaTime(This,pTimeStart,pTimeEnd))
-#define IMediaSample_SetMediaTime(This,pTimeStart,pTimeEnd) \
- ((This)->lpVtbl->SetMediaTime(This,pTimeStart,pTimeEnd))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IEnumFilters_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IEnumFilters_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IEnumFilters_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IEnumFilters_Next(This,cFilters,ppFilter,pcFetched) \
- ((This)->lpVtbl->Next(This,cFilters,ppFilter,pcFetched))
-#define IEnumFilters_Skip(This,cFilters) \
- ((This)->lpVtbl->Skip(This,cFilters))
-#define IEnumFilters_Reset(This) \
- ((This)->lpVtbl->Reset(This))
-#define IEnumFilters_Clone(This,ppEnum) \
- ((This)->lpVtbl->Clone(This,ppEnum))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IMemAllocator_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IMemAllocator_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IMemAllocator_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IMemAllocator_SetProperties(This,pRequest,pActual) \
- ((This)->lpVtbl->SetProperties(This,pRequest,pActual))
-#define IMemAllocator_GetProperties(This,pProps) \
- ((This)->lpVtbl->GetProperties(This,pProps))
-#define IMemAllocator_Commit(This) \
- ((This)->lpVtbl->Commit(This))
-#define IMemAllocator_Decommit(This) \
- ((This)->lpVtbl->Decommit(This))
-#define IMemAllocator_GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags) \
- ((This)->lpVtbl->GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags))
-#define IMemAllocator_ReleaseBuffer(This,pBuffer) \
- ((This)->lpVtbl->ReleaseBuffer(This,pBuffer))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IMemInputPin_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IMemInputPin_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IMemInputPin_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IMemInputPin_GetAllocator(This,ppAllocator) \
- ((This)->lpVtbl->GetAllocator(This,ppAllocator))
-#define IMemInputPin_NotifyAllocator(This,pAllocator,bReadOnly) \
- ((This)->lpVtbl->NotifyAllocator(This,pAllocator,bReadOnly))
-#define IMemInputPin_GetAllocatorRequirements(This,pProps) \
- ((This)->lpVtbl->GetAllocatorRequirements(This,pProps))
-#define IMemInputPin_Receive(This,pSample) \
- ((This)->lpVtbl->Receive(This,pSample))
-#define IMemInputPin_ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed) \
- ((This)->lpVtbl->ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed))
-#define IMemInputPin_ReceiveCanBlock(This) \
- ((This)->lpVtbl->ReceiveCanBlock(This))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IGraphBuilder_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IGraphBuilder_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IGraphBuilder_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IGraphBuilder_AddFilter(This,pFilter,pName) \
- ((This)->lpVtbl->AddFilter(This,pFilter,pName))
-#define IGraphBuilder_RemoveFilter(This,pFilter) \
- ((This)->lpVtbl->RemoveFilter(This,pFilter))
-#define IGraphBuilder_EnumFilters(This,ppEnum) \
- ((This)->lpVtbl->EnumFilters(This,ppEnum))
-#define IGraphBuilder_FindFilterByName(This,pName,ppFilter) \
- ((This)->lpVtbl->FindFilterByName(This,pName,ppFilter))
-#define IGraphBuilder_ConnectDirect(This,ppinOut,ppinIn,pmt) \
- ((This)->lpVtbl->ConnectDirect(This,ppinOut,ppinIn,pmt))
-#define IGraphBuilder_Reconnect(This,ppin) \
- ((This)->lpVtbl->Reconnect(This,ppin))
-#define IGraphBuilder_Disconnect(This,ppin) \
- ((This)->lpVtbl->Disconnect(This,ppin))
-#define IGraphBuilder_SetDefaultSyncSource(This) \
- ((This)->lpVtbl->SetDefaultSyncSource(This))
-#define IGraphBuilder_Connect(This,ppinOut,ppinIn) \
- ((This)->lpVtbl->Connect(This,ppinOut,ppinIn))
-#define IGraphBuilder_Render(This,ppinOut) \
- ((This)->lpVtbl->Render(This,ppinOut))
-#define IGraphBuilder_RenderFile(This,lpcwstrFile,lpcwstrPlayList) \
- ((This)->lpVtbl->RenderFile(This,lpcwstrFile,lpcwstrPlayList))
-#define IGraphBuilder_AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) \
- ((This)->lpVtbl->AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter))
-#define IGraphBuilder_SetLogFile(This,hFile) \
- ((This)->lpVtbl->SetLogFile(This,hFile))
-#define IGraphBuilder_Abort(This) \
- ((This)->lpVtbl->Abort(This))
-#define IGraphBuilder_ShouldOperationContinue(This) \
- ((This)->lpVtbl->ShouldOperationContinue(This))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IEnumMediaTypes_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IEnumMediaTypes_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IEnumMediaTypes_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IEnumMediaTypes_Next(This,cMediaTypes,ppMediaTypes,pcFetched) \
- ((This)->lpVtbl->Next(This,cMediaTypes,ppMediaTypes,pcFetched))
-#define IEnumMediaTypes_Skip(This,cMediaTypes) \
- ((This)->lpVtbl->Skip(This,cMediaTypes))
-#define IEnumMediaTypes_Reset(This) \
- ((This)->lpVtbl->Reset(This))
-#define IEnumMediaTypes_Clone(This,ppEnum) \
- ((This)->lpVtbl->Clone(This,ppEnum))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IMediaControl_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IMediaControl_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IMediaControl_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IMediaControl_GetTypeInfoCount(This,pctinfo) \
- ((This)->lpVtbl->GetTypeInfoCount(This,pctinfo))
-#define IMediaControl_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
- ((This)->lpVtbl->GetTypeInfo(This,iTInfo,lcid,ppTInfo))
-#define IMediaControl_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
- ((This)->lpVtbl->GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId))
-#define IMediaControl_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
- ((This)->lpVtbl->Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr))
-#define IMediaControl_Run(This) \
- ((This)->lpVtbl->Run(This))
-#define IMediaControl_Pause(This) \
- ((This)->lpVtbl->Pause(This))
-#define IMediaControl_Stop(This) \
- ((This)->lpVtbl->Stop(This))
-#define IMediaControl_GetState(This,msTimeout,pfs) \
- ((This)->lpVtbl->GetState(This,msTimeout,pfs))
-#define IMediaControl_RenderFile(This,strFilename) \
- ((This)->lpVtbl->RenderFile(This,strFilename))
-#define IMediaControl_AddSourceFilter(This,strFilename,ppUnk) \
- ((This)->lpVtbl->AddSourceFilter(This,strFilename,ppUnk))
-#define IMediaControl_get_FilterCollection(This,ppUnk) \
- ((This)->lpVtbl->get_FilterCollection(This,ppUnk))
-#define IMediaControl_get_RegFilterCollection(This,ppUnk) \
- ((This)->lpVtbl->get_RegFilterCollection(This,ppUnk))
-#define IMediaControl_StopWhenReady(This) \
- ((This)->lpVtbl->StopWhenReady(This))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IAMVideoProcAmp_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IAMVideoProcAmp_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IAMVideoProcAmp_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IAMVideoProcAmp_GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags) \
- ((This)->lpVtbl->GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags))
-#define IAMVideoProcAmp_Set(This,Property,lValue,Flags) \
- ((This)->lpVtbl->Set(This,Property,lValue,Flags))
-#define IAMVideoProcAmp_Get(This,Property,lValue,Flags) \
- ((This)->lpVtbl->Get(This,Property,lValue,Flags))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IFileSinkFilter_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IFileSinkFilter_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IFileSinkFilter_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IFileSinkFilter_SetFileName(This,pszFileName,pmt) \
- ((This)->lpVtbl->SetFileName(This,pszFileName,pmt))
-#define IFileSinkFilter_GetCurFile(This,ppszFileName,pmt) \
- ((This)->lpVtbl->GetCurFile(This,ppszFileName,pmt))
-#endif /* COBJMACROS */
-
-#ifdef COBJMACROS
-#define IAMCopyCaptureFileProgress_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define IAMCopyCaptureFileProgress_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define IAMCopyCaptureFileProgress_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define IAMCopyCaptureFileProgress_Progress(This,iProgress) \
- ((This)->lpVtbl->Progress(This,iProgress))
-#endif /* COBJMACROS */
-
-
-#ifdef COBJMACROS
-#define ICaptureGraphBuilder2_QueryInterface(This,riid,ppvObject) \
- ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
-#define ICaptureGraphBuilder2_AddRef(This) \
- ((This)->lpVtbl->AddRef(This))
-#define ICaptureGraphBuilder2_Release(This) \
- ((This)->lpVtbl->Release(This))
-#define ICaptureGraphBuilder2_SetFiltergraph(This,pfg) \
- ((This)->lpVtbl->SetFiltergraph(This,pfg))
-#define ICaptureGraphBuilder2_GetFiltergraph(This,ppfg) \
- ((This)->lpVtbl->GetFiltergraph(This,ppfg))
-#define ICaptureGraphBuilder2_SetOutputFileName(This,pType,lpstrFile,ppf,ppSink) \
- ((This)->lpVtbl->SetOutputFileName(This,pType,lpstrFile,ppf,ppSink))
-#define ICaptureGraphBuilder2_FindInterface(This,pCategory,pType,pf,riid,ppint) \
- ((This)->lpVtbl->FindInterface(This,pCategory,pType,pf,riid,ppint))
-#define ICaptureGraphBuilder2_RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer) \
- ((This)->lpVtbl->RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer))
-#define ICaptureGraphBuilder2_ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie) \
- ((This)->lpVtbl->ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie))
-#define ICaptureGraphBuilder2_AllocCapFile(This,lpstr,dwlSize) \
- ((This)->lpVtbl->AllocCapFile(This,lpstr,dwlSize))
-#define ICaptureGraphBuilder2_CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback) \
- ((This)->lpVtbl->CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback))
-#define ICaptureGraphBuilder2_FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin) \
- ((This)->lpVtbl->FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin))
-#endif /* COBJMACROS */
-
-#endif /* _MARU_CAMERA_INTERFACE_H_ */
+++ /dev/null
-/*
- * Implementation of MARU Virtual Camera device by PCI bus on Windows.
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * JinHyung Jo <jinhyung.jo@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#include "qemu-common.h"
-#include "maru_camera_common.h"
-#include "debug_ch.h"
-
-#define CINTERFACE
-#define COBJMACROS
-#include "ocidl.h"
-#include "errors.h" /* for VFW_E_XXXX */
-#include "mmsystem.h" /* for MAKEFOURCC macro */
-#include "maru_camera_win32_interface.h"
-
-MULTI_DEBUG_CHANNEL(tizen, maru-camera);
-
-/*
- * COM Interface implementations
- *
- */
-
-#define SAFE_RELEASE(x) \
- do { \
- if (x) { \
- (x)->lpVtbl->Release(x); \
- x = NULL; \
- } \
- } while (0)
-
-typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
-
-/*
- * HWCGrabCallback
- */
-
-typedef struct HWCGrabCallback {
- IGrabCallback IGrabCallback_iface;
- long m_cRef;
- CallbackFn m_pCallback;
- STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);
-} HWCGrabCallback;
-
-static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)
-{
- return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);
-}
-
-static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,
- REFIID riid, void **ppv)
-{
- if (IsEqualIID(riid, &IID_IUnknown)) {
- *ppv = (IUnknown *)iface;
- } else if (IsEqualIID(riid, &IID_IGrabCallback)) {
- *ppv = (IGrabCallback *)iface;
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- IGrabCallback_AddRef(iface);
- return S_OK;
-}
-
-static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)
-{
- HWCGrabCallback *This = impl_from_IGrabCallback(iface);
-
- return InterlockedIncrement(&This->m_cRef);
-}
-
-static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)
-{
- HWCGrabCallback *This = impl_from_IGrabCallback(iface);
-
- if (InterlockedDecrement(&This->m_cRef) == 0) {
- This->m_pCallback = NULL;
- g_free((void *)This);
- This = NULL;
- return 0;
- }
-
- return This->m_cRef;
-}
-
-static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,
- ULONG dwSize, BYTE *pBuffer)
-{
- HWCGrabCallback *This = impl_from_IGrabCallback(iface);
-
- if (This->m_pCallback) {
- HRESULT hr = This->m_pCallback(dwSize, pBuffer);
- if (FAILED(hr)) {
- return E_FAIL;
- } else {
- return S_OK;
- }
- }
-
- return E_FAIL;
-}
-
-static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,
- CallbackFn pCallbackFn)
-{
- HWCGrabCallback *This = impl_from_IGrabCallback(iface);
-
- This->m_pCallback = pCallbackFn;
- return S_OK;
-}
-
-static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {
- HWCGrabCallback_QueryInterface,
- HWCGrabCallback_AddRef,
- HWCGrabCallback_Release,
- HWCGrabCallback_Grab
-};
-
-static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)
-{
- HWCGrabCallback *This =
- (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));
-
- if (!This) {
- ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");
- return E_OUTOFMEMORY;
- }
-
- This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;
- This->m_cRef = 1;
- This->m_pCallback = NULL;
- This->SetCallback = HWCGrabCallback_SetCallback;
- *ppv = &This->IGrabCallback_iface;
- return S_OK;
-}
-
-/*
- * HWCPin
- */
-
-typedef struct HWCInPin {
- IPin IPin_iface;
- IMemInputPin IMemInputPin_iface;
- IBaseFilter *m_pCFilter;
- IPin *m_pConnectedPin;
- IGrabCallback *m_pCallback;
- IMemAllocator *m_pAllocator;
- BOOL m_bReadOnly;
- long m_cRef;
- STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);
-} HWCInPin;
-
-static inline HWCInPin *impl_from_IPin(IPin *iface)
-{
- return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);
-}
-
-static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)
-{
- return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);
-}
-
-static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- if (IsEqualIID(riid, &IID_IUnknown)) {
- *ppv = (IUnknown *)(&This->IPin_iface);
- IPin_AddRef((IPin *)*ppv);
- } else if (IsEqualIID(riid, &IID_IPin)) {
- *ppv = (IPin *)(&This->IPin_iface);
- IPin_AddRef((IPin *)*ppv);
- } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
- *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
- IPin_AddRef((IMemInputPin *)*ppv);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- return S_OK;
-}
-
-static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- return InterlockedIncrement(&This->m_cRef);
-}
-
-static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- if (InterlockedDecrement(&This->m_cRef) == 0) {
- if (This->m_pCallback) {
- SAFE_RELEASE(This->m_pCallback);
- }
- if (This->m_pConnectedPin) {
- SAFE_RELEASE(This->m_pConnectedPin);
- }
- if (This->m_pAllocator) {
- IMemAllocator_Decommit(This->m_pAllocator);
- SAFE_RELEASE(This->m_pAllocator);
- }
- g_free((void *)This);
- This = NULL;
- return 0;
- }
- return This->m_cRef;
-}
-
-static STDMETHODIMP HWCPin_Connect(IPin *iface,
- IPin *pReceivePin,
- const AM_MEDIA_TYPE *pmt)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- if (!pReceivePin) {
- return E_POINTER;
- }
-
- if (This->m_pConnectedPin) {
- return VFW_E_ALREADY_CONNECTED;
- }
-
- if (!pmt) {
- return S_OK;
- }
- return S_FALSE;
-}
-
-static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,
- const AM_MEDIA_TYPE *pmt)
-{
- PIN_DIRECTION pd;
- FILTER_STATE fs;
- HWCInPin *This = impl_from_IPin(iface);
-
- if (pConnector == NULL || pmt == NULL) {
- return E_POINTER;
- }
-
- if (This->m_pConnectedPin) {
- return VFW_E_ALREADY_CONNECTED;
- }
- IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
- if (fs != State_Stopped) {
- return VFW_E_NOT_STOPPED;
- }
- IPin_QueryDirection(pConnector, &pd);
- if (pd == PINDIR_INPUT) {
- return VFW_E_INVALID_DIRECTION;
- }
-
- This->m_pConnectedPin = pConnector;
- IPin_AddRef(This->m_pConnectedPin);
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_Disconnect(IPin *iface)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- HRESULT hr;
- FILTER_STATE fs;
- IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
- if (fs != State_Stopped) {
- return VFW_E_NOT_STOPPED;
- }
- if (This->m_pConnectedPin == NULL) {
- hr = S_FALSE;
- } else {
- if (This->m_pAllocator) {
- hr = IMemAllocator_Decommit(This->m_pAllocator);
- if (FAILED(hr)) {
- return hr;
- }
- SAFE_RELEASE(This->m_pAllocator);
- }
- SAFE_RELEASE(This->m_pConnectedPin);
- hr = S_OK;
- }
- return hr;
-}
-
-static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- if (ppPin == NULL) {
- return E_POINTER;
- }
-
- if (This->m_pConnectedPin == NULL) {
- *ppPin = NULL;
- return VFW_E_NOT_CONNECTED;
- } else {
- *ppPin = This->m_pConnectedPin;
- IPin_AddRef(This->m_pConnectedPin);
- }
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
-{
- if (pmt == NULL) {
- return E_POINTER;
- }
- return VFW_E_NOT_CONNECTED;
-}
-
-static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- if (pInfo == NULL) {
- return E_POINTER;
- }
-
- pInfo->pFilter = This->m_pCFilter;
- if (This->m_pCFilter) {
- IBaseFilter_AddRef(This->m_pCFilter);
- }
- memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));
- pInfo->dir = PINDIR_INPUT;
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
-{
- if (pPinDir == NULL) {
- return E_POINTER;
- }
- *pPinDir = PINDIR_INPUT;
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)
-{
- PVOID pId;
- if (Id == NULL) {
- return E_POINTER;
- }
- pId = CoTaskMemAlloc(sizeof(HWCPinName));
- memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));
- *Id = (LPWSTR)pId;
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
-{
- if (pmt == NULL) {
- return E_POINTER;
- }
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,
- IEnumMediaTypes **ppEnum)
-{
- if (ppEnum == NULL) {
- return E_POINTER;
- }
- return E_NOTIMPL;
-}
-
-static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,
- IPin **ppPin,
- ULONG *nPin)
-{
- return E_NOTIMPL;
-}
-
-static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)
-{
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)
-{
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_EndFlush(IPin *iface)
-{
- return S_OK;
-}
-
-static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,
- REFERENCE_TIME tStop, double dRate)
-{
- return S_OK;
-}
-
-static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,
- REFIID riid, void **ppv)
-{
- HWCInPin *This = impl_from_IMemInputPin(iface);
-
- if (IsEqualIID(riid, &IID_IUnknown)) {
- *ppv = (IUnknown *)(&This->IMemInputPin_iface);
- IPin_AddRef((IPin *)*ppv);
- } else if (IsEqualIID(riid, &IID_IPin)) {
- *ppv = (IPin *)(&This->IPin_iface);
- IPin_AddRef((IPin *)*ppv);
- } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
- *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
- IPin_AddRef((IMemInputPin *)*ppv);
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- return S_OK;
-}
-
-static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)
-{
- HWCInPin *This = impl_from_IMemInputPin(iface);
-
- return InterlockedIncrement(&This->m_cRef);
-}
-
-static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)
-{
- HWCInPin *This = impl_from_IMemInputPin(iface);
-
- if (InterlockedDecrement(&This->m_cRef) == 0) {
- if (This->m_pCallback) {
- SAFE_RELEASE(This->m_pCallback);
- }
- if (This->m_pConnectedPin) {
- SAFE_RELEASE(This->m_pConnectedPin);
- }
- if (This->m_pAllocator) {
- IMemAllocator_Decommit(This->m_pAllocator);
- SAFE_RELEASE(This->m_pAllocator);
- }
- g_free((void *)This);
- This = NULL;
- return 0;
- }
- return This->m_cRef;
-}
-
-static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,
- IMemAllocator **ppAllocator)
-{
- HWCInPin *This = impl_from_IMemInputPin(iface);
-
- if (ppAllocator == NULL) {
- return E_POINTER;
- }
-
- if (This->m_pAllocator == NULL) {
- HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
- CLSCTX_INPROC_SERVER,
- &IID_IMemAllocator,
- (void **)&(This->m_pAllocator));
- if (FAILED(hr)) {
- ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");
- return hr;
- }
- }
- ASSERT(This->m_pAllocator != NULL);
- *ppAllocator = This->m_pAllocator;
- IMemAllocator_AddRef(This->m_pAllocator);
-
- return S_OK;
-}
-
-static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,
- IMemAllocator *pAllocator,
- BOOL bReadOnly)
-{
- HWCInPin *This = impl_from_IMemInputPin(iface);
-
- if (pAllocator == NULL) {
- return E_POINTER;
- }
-
- IMemAllocator *pOldAllocator = This->m_pAllocator;
- IMemAllocator_AddRef(pAllocator);
- This->m_pAllocator = pAllocator;
-
- if (pOldAllocator != NULL) {
- SAFE_RELEASE(pOldAllocator);
- }
-
- This->m_bReadOnly = bReadOnly;
-
- return S_OK;
-}
-
-static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(
- IMemInputPin *iface,
- ALLOCATOR_PROPERTIES *pProps)
-{
- return E_NOTIMPL;
-}
-
-static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,
- IMediaSample *pSample)
-{
- HWCInPin *This = impl_from_IMemInputPin(iface);
-
- if (pSample == NULL) {
- ERR("pSample is NULL\n");
- return E_POINTER;
- }
- if (This->m_pCallback != NULL) {
- HRESULT hr;
- BYTE *pBuffer = NULL;
- DWORD dwSize = 0;
- dwSize = IMediaSample_GetSize(pSample);
- hr = IMediaSample_GetPointer(pSample, &pBuffer);
- if (FAILED(hr)) {
- ERR("Receive function : "
- "failed to IMediaSample_GetPointer, 0x%ld\n", hr);
- return hr;
- }
- hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);
- if (FAILED(hr)) {
- ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",
- hr);
- return hr;
- }
- }
- return S_OK;
-}
-
-static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,
- IMediaSample **pSamples,
- long nSamples,
- long *nSamplesProcessed)
-{
- HRESULT hr = S_OK;
-
- if (pSamples == NULL) {
- return E_POINTER;
- }
-
- *nSamplesProcessed = 0;
-
- while (nSamples-- > 0) {
- hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
- if (hr != S_OK) {
- break;
- }
- (*nSamplesProcessed)++;
- }
- return hr;
-}
-
-static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
-{
- return S_FALSE;
-}
-
-static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)
-{
- HWCInPin *This = impl_from_IPin(iface);
-
- if (pCaptureCB == NULL) {
- SAFE_RELEASE(This->m_pCallback);
- } else {
- This->m_pCallback = pCaptureCB;
- IGrabCallback_AddRef(This->m_pCallback);
- }
-
- return S_OK;
-}
-
-
-static IPinVtbl HWCPin_Vtbl = {
- HWCPin_QueryInterface,
- HWCPin_AddRef,
- HWCPin_Release,
- HWCPin_Connect,
- HWCPin_ReceiveConnection,
- HWCPin_Disconnect,
- HWCPin_ConnectedTo,
- HWCPin_ConnectionMediaType,
- HWCPin_QueryPinInfo,
- HWCPin_QueryDirection,
- HWCPin_QueryId,
- HWCPin_QueryAccept,
- HWCPin_EnumMediaTypes,
- HWCPin_QueryInternalConnections,
- HWCPin_EndOfStream,
- HWCPin_BeginFlush,
- HWCPin_EndFlush,
- HWCPin_NewSegment
-};
-
-static IMemInputPinVtbl HWCMemInputPin_Vtbl = {
- HWCMemInputPin_QueryInterface,
- HWCMemInputPin_AddRef,
- HWCMemInputPin_Release,
- HWCMemInputPin_GetAllocator,
- HWCMemInputPin_NotifyAllocator,
- HWCMemInputPin_GetAllocatorRequirements,
- HWCMemInputPin_Receive,
- HWCMemInputPin_ReceiveMultiple,
- HWCMemInputPin_ReceiveCanBlock
-};
-
-static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)
-{
- HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));
-
- if (!This) {
- ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");
- return E_OUTOFMEMORY;
- }
-
- This->IPin_iface.lpVtbl = &HWCPin_Vtbl;
- This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;
- This->m_bReadOnly = FALSE;
- This->m_pCFilter = pFilter;
- This->m_pConnectedPin = NULL;
- This->m_pCallback = NULL;
- This->m_pAllocator = NULL;
- This->m_cRef = 1;
- This->SetGrabCallbackIF = HWCPin_SetCallback;
- *ppv = &This->IPin_iface;
-
- return S_OK;
-}
-
-/*
- * HWCEnumPins
- */
-
-typedef struct HWCEnumPins {
- IEnumPins IEnumPins_iface;
- IBaseFilter *m_pFilter;
- int m_nPos;
- long m_cRef;
-} HWCEnumPins;
-
-static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)
-{
- return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);
-}
-
-static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,
- REFIID riid, void **ppv)
-{
- if (ppv == NULL) {
- return E_POINTER;
- }
-
- if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {
- *ppv = iface;
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- IEnumPins_AddRef(iface);
- return S_OK;
-}
-
-static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)
-{
- HWCEnumPins *This = impl_from_IEnumPins(iface);
-
- return InterlockedIncrement(&This->m_cRef);
-}
-
-static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)
-{
- HWCEnumPins *This = impl_from_IEnumPins(iface);
-
- if (InterlockedDecrement(&This->m_cRef) == 0) {
- if (This->m_pFilter) {
- SAFE_RELEASE(This->m_pFilter);
- }
- This->m_nPos = 0;
- g_free((void *)This);
- This = NULL;
- return 0;
- }
- return This->m_cRef;
-}
-
-static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,
- IPin **ppPins, ULONG *pcFetched)
-{
- ULONG fetched;
- HWCEnumPins *This = impl_from_IEnumPins(iface);
-
- if (ppPins == NULL) {
- return E_POINTER;
- }
-
- if (This->m_nPos < 1 && cPins > 0) {
- IPin *pPin;
- IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);
- *ppPins = pPin;
- fetched = 1;
- This->m_nPos++;
- } else {
- fetched = 0;
- }
-
- if (pcFetched != NULL) {
- *pcFetched = fetched;
- }
-
- return (fetched == cPins) ? S_OK : S_FALSE;
-}
-
-static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)
-{
- HWCEnumPins *This = impl_from_IEnumPins(iface);
- This->m_nPos += cPins;
- return (This->m_nPos >= 1) ? S_FALSE : S_OK;
-}
-
-static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)
-{
- HWCEnumPins *This = impl_from_IEnumPins(iface);
- This->m_nPos = 0;
- return S_OK;
-}
-
-static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
- int nPos, IEnumPins **ppv);
-
-static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)
-{
- HWCEnumPins *This = impl_from_IEnumPins(iface);
-
- if (ppEnum == NULL) {
- return E_POINTER;
- }
-
- HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);
- if (*ppEnum == NULL) {
- ERR("failed to HWCEnumPins_Construct in clone, E_OUTOFMEMORY\n");
- return E_OUTOFMEMORY;
- }
-
- return S_OK;
-}
-
-static IEnumPinsVtbl HWCEnumPins_Vtbl = {
- HWCEnumPins_QueryInterface,
- HWCEnumPins_AddRef,
- HWCEnumPins_Release,
- HWCEnumPins_Next,
- HWCEnumPins_Skip,
- HWCEnumPins_Reset,
- HWCEnumPins_Clone
-};
-
-
-static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
- int nPos, IEnumPins **ppv)
-{
- HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));
-
- if (!This) {
- ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");
- return E_OUTOFMEMORY;
- }
-
- This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;
- This->m_pFilter = pFilter;
- if (This->m_pFilter) {
- IBaseFilter_AddRef(This->m_pFilter);
- }
- This->m_cRef = 1;
- This->m_nPos = nPos;
- *ppv = &This->IEnumPins_iface;
-
- return S_OK;
-}
-
-/*
- * HWCFilter
- */
-
-typedef struct HWCFilter {
- IBaseFilter IBaseFilter_iface;
- IPin *m_pPin;
- IFilterGraph *m_pFilterGraph;
- FILTER_STATE m_state;
- long m_cRef;
-} HWCFilter;
-
-static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)
-{
- return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);
-}
-
-static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,
- REFIID riid, void **ppv)
-{
- if (IsEqualIID(riid, &IID_IUnknown)) {
- *ppv = (IUnknown *)iface;
- } else if (IsEqualIID(riid, &IID_IPersist)) {
- *ppv = (IPersist *)iface;
- } else if (IsEqualIID(riid, &IID_IMediaFilter)) {
- *ppv = (IMediaFilter *)iface;
- } else if (IsEqualIID(riid, &IID_IBaseFilter)) {
- *ppv = (IBaseFilter *)iface;
- } else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- IBaseFilter_AddRef(iface);
- return S_OK;
-}
-
-static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- return InterlockedIncrement(&This->m_cRef);
-}
-
-static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- if (InterlockedDecrement(&This->m_cRef) == 0) {
- if (This->m_pPin) {
- SAFE_RELEASE(This->m_pPin);
- }
- g_free((void *)This);
- This = NULL;
- return 0;
- }
- return This->m_cRef;
-}
-
-static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)
-{
- if (pClsID == NULL) {
- return E_POINTER;
- }
- return E_NOTIMPL;
-}
-
-static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,
- FILTER_STATE *State)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
- *State = This->m_state;
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,
- IReferenceClock *pClock)
-{
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,
- IReferenceClock **pClock)
-{
- *pClock = NULL;
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- IPin_EndFlush(This->m_pPin);
- This->m_state = State_Stopped;
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
- This->m_state = State_Paused;
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- if (This->m_state == State_Stopped) {
- HRESULT hr;
- hr = IBaseFilter_Pause(iface);
- if (FAILED(hr)) {
- ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);
- return hr;
- }
- }
-
- This->m_state = State_Running;
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
-{
- if (ppEnum == NULL) {
- return E_POINTER;
- }
-
- HWCEnumPins_Construct(iface, 0, ppEnum);
- return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;
-}
-
-static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,
- IPin **ppPin)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- if (ppPin == NULL) {
- return E_POINTER;
- }
-
- if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {
- return VFW_E_NOT_FOUND;
- }
-
- if (!This->m_pPin) {
- HWCInPin_Construct(iface, &This->m_pPin);
- }
- *ppPin = This->m_pPin;
-
- IPin_AddRef(This->m_pPin);
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,
- FILTER_INFO *pInfo)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- if (pInfo == NULL) {
- return E_POINTER;
- }
-
- memcpy((void *)pInfo->achName,
- (void *)HWCFilterName,
- sizeof(HWCFilterName));
- pInfo->pGraph = This->m_pFilterGraph;
- if (This->m_pFilterGraph) {
- IFilterGraph_AddRef(This->m_pFilterGraph);
- }
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,
- IFilterGraph *pGraph,
- LPCWSTR pName)
-{
- HWCFilter *This = impl_from_IBaseFilter(iface);
-
- This->m_pFilterGraph = pGraph;
- return S_OK;
-}
-
-static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,
- LPWSTR *pVendorInfo)
-{
- return E_NOTIMPL;
-}
-
-static IBaseFilterVtbl HWCFilter_Vtbl = {
- HWCFilter_QueryInterface,
- HWCFilter_AddRef,
- HWCFilter_Release,
- HWCFilter_GetClassID,
- HWCFilter_Stop,
- HWCFilter_Pause,
- HWCFilter_Run,
- HWCFilter_GetState,
- HWCFilter_SetSyncSource,
- HWCFilter_GetSyncSource,
- HWCFilter_EnumPins,
- HWCFilter_FindPin,
- HWCFilter_QueryFilterInfo,
- HWCFilter_JoinFilterGraph,
- HWCFilter_QueryVendorInfo
-};
-
-static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)
-{
- HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));
-
- if (!This) {
- ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");
- return E_OUTOFMEMORY;
- }
-
- This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;
- This->m_pFilterGraph = NULL;
- This->m_state = State_Stopped;
- This->m_cRef = 1;
- HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);
- *ppv = &This->IBaseFilter_iface;
-
- return S_OK;
-}
-
-/**********************************************************
- *
- * Virtual device implementations
- *
- **********************************************************/
-
-
-/*
- * Declaration global variables for Win32 COM Interfaces
- */
-IGraphBuilder *g_pGB ;
-ICaptureGraphBuilder2 *g_pCGB;
-IMediaControl *g_pMediaControl;
-
-IPin *g_pOutputPin;
-IPin *g_pInputPin;
-IBaseFilter *g_pDstFilter;
-IBaseFilter *g_pSrcFilter;
-
-IGrabCallback *g_pCallback;
-
-/* V4L2 defines copy from videodev2.h */
-#define V4L2_CTRL_FLAG_SLIDER 0x0020
-
-#define V4L2_CTRL_CLASS_USER 0x00980000
-#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
-#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
-#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
-#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
-#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
-
-#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
-#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
-#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
-#define V4L2_PIX_FMT_RGB24 MAKEFOURCC('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
-
-typedef struct tagMaruCamConvertPixfmt {
- uint32_t fmt; /* fourcc */
- uint32_t bpp; /* bits per pixel, 0 for compressed formats */
- uint32_t needs_conversion;
-} MaruCamConvertPixfmt;
-
-static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
- { V4L2_PIX_FMT_YUYV, 16, 0 },
- { V4L2_PIX_FMT_YUV420, 12, 0 },
- { V4L2_PIX_FMT_YVU420, 12, 0 },
-};
-
-typedef struct tagMaruCamConvertFrameInfo {
- uint32_t width;
- uint32_t height;
-} MaruCamConvertFrameInfo;
-
-static MaruCamConvertFrameInfo supported_dst_frames[] = {
- { 640, 480 },
- { 352, 288 },
- { 320, 240 },
- { 176, 144 },
- { 160, 120 },
-};
-
-#define MARUCAM_CTRL_VALUE_MAX 20
-#define MARUCAM_CTRL_VALUE_MIN 1
-#define MARUCAM_CTRL_VALUE_MID 10
-#define MARUCAM_CTRL_VALUE_STEP 1
-
-struct marucam_qctrl {
- uint32_t id;
- uint32_t hit;
- long min;
- long max;
- long step;
- long init_val;
-};
-
-static struct marucam_qctrl qctrl_tbl[] = {
- { V4L2_CID_BRIGHTNESS, 0, },
- { V4L2_CID_CONTRAST, 0, },
- { V4L2_CID_SATURATION, 0, },
- { V4L2_CID_SHARPNESS, 0, },
-};
-
-static MaruCamState *g_state;
-
-static uint32_t ready_count;
-static uint32_t cur_fmt_idx;
-static uint32_t cur_frame_idx;
-static void *grab_buf;
-static uint32_t g_dwSrcFmt;
-
-
-/*
- * Helper functions - converting image formats, converting values
- */
-
-static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
-{
- uint32_t bytesperline;
-
- switch (pixfmt) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- bytesperline = (width * 12) >> 3;
- break;
- case V4L2_PIX_FMT_YUYV:
- default:
- bytesperline = width * 2;
- break;
- }
-
- return bytesperline;
-}
-
-static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
-{
- return get_bytesperline(pixfmt, width) * height;
-}
-
-void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height, uint32_t yvu);
-void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height, uint32_t yvu);
-void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height);
-void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height);
-void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height);
-
-static long value_convert_from_guest(long min, long max, long value)
-{
- double rate = 0.0;
- long dist = 0, ret = 0;
-
- dist = max - min;
-
- if (dist < MARUCAM_CTRL_VALUE_MAX) {
- rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
- ret = min + (int32_t)(value / rate);
- } else {
- rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
- ret = min + (int32_t)(rate * value);
- }
- return ret;
-}
-
-static long value_convert_to_guest(long min, long max, long value)
-{
- double rate = 0.0;
- long dist = 0, ret = 0;
-
- dist = max - min;
-
- if (dist < MARUCAM_CTRL_VALUE_MAX) {
- rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
- ret = (int32_t)((double)(value - min) * rate);
- } else {
- rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
- ret = (int32_t)((double)(value - min) / rate);
- }
-
- return ret;
-}
-
-/*
- * Callback function for grab frames
- */
-static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
-{
- void *tmp_buf;
- uint32_t width, height, fmt, imgsize;
-
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
- fmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- imgsize = get_sizeimage(fmt, width, height);
-
- if (imgsize > (uint32_t)dwSize) {
- ERR("Image size is mismatched\n");
- return E_FAIL;
- }
-
- switch (g_dwSrcFmt) {
- case V4L2_PIX_FMT_YUYV:
- switch (fmt) {
- case V4L2_PIX_FMT_YUV420:
- yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);
- break;
- case V4L2_PIX_FMT_YVU420:
- yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);
- break;
- case V4L2_PIX_FMT_YUYV:
- memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
- break;
- default:
- ERR("Invalid pixel format\n");
- return E_FAIL;
- }
- break;
- case V4L2_PIX_FMT_RGB24:
- switch (fmt) {
- case V4L2_PIX_FMT_YUV420:
- rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);
- break;
- case V4L2_PIX_FMT_YVU420:
- rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);
- break;
- case V4L2_PIX_FMT_YUYV:
- rgb24_to_yuyv(pBuffer, grab_buf, width, height);
- break;
- default:
- ERR("Invalid pixel format\n");
- return E_FAIL;
- }
- break;
- case V4L2_PIX_FMT_YUV420:
- switch (fmt) {
- case V4L2_PIX_FMT_YUV420:
- memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
- break;
- case V4L2_PIX_FMT_YVU420:
- yuv420_to_yvu420(pBuffer, grab_buf, width, height);
- break;
- case V4L2_PIX_FMT_YUYV:
- yuv420_to_yuyv(pBuffer, grab_buf, width, height);
- break;
- default:
- ERR("Invalid pixel format\n");
- return E_FAIL;
- }
- break;
- default:
- ERR("Invalid pixel format\n");
- return E_FAIL;
- }
-
- qemu_mutex_lock(&g_state->thread_mutex);
- if (g_state->streamon) {
- if (ready_count < MARUCAM_SKIPFRAMES) {
- /* skip a frame cause first some frame are distorted */
- ++ready_count;
- TRACE("skip %d frame\n", ready_count);
- qemu_mutex_unlock(&g_state->thread_mutex);
- return S_OK;
- }
- if (g_state->req_frame == 0) {
- TRACE("there is no request\n");
- qemu_mutex_unlock(&g_state->thread_mutex);
- return S_OK;
- }
- tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
- memcpy(tmp_buf, grab_buf, g_state->buf_size);
- g_state->req_frame = 0; /* clear request */
- g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
- qemu_bh_schedule(g_state->tx_bh);
- }
- qemu_mutex_unlock(&g_state->thread_mutex);
- return S_OK;
-}
-
-/*
- * Internal functions for manipulate interfaces
- */
-
-static STDMETHODIMP_(void) CloseInterfaces(void)
-{
- if (g_pMediaControl) {
- g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
- }
-
- if (g_pOutputPin) {
- g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);
- }
-
- SAFE_RELEASE(g_pGB);
- SAFE_RELEASE(g_pCGB);
- SAFE_RELEASE(g_pMediaControl);
- SAFE_RELEASE(g_pOutputPin);
- SAFE_RELEASE(g_pInputPin);
- SAFE_RELEASE(g_pDstFilter);
- SAFE_RELEASE(g_pSrcFilter);
- SAFE_RELEASE(g_pCallback);
-}
-
-static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)
-{
- if (pmt == NULL) {
- return;
- }
-
- if (pmt->cbFormat != 0) {
- CoTaskMemFree((PVOID)pmt->pbFormat);
- pmt->cbFormat = 0;
- pmt->pbFormat = NULL;
- }
- if (pmt->pUnk != NULL) {
- pmt->pUnk->lpVtbl->Release(pmt->pUnk);
- pmt->pUnk = NULL;
- }
-
- CoTaskMemFree((PVOID)pmt);
-}
-
-static STDMETHODIMP GetPin(IBaseFilter *pFilter,
- PIN_DIRECTION PinDir, IPin **ppPin)
-{
- HRESULT hr;
- IEnumPins *pEnum = NULL;
- IPin *pPin = NULL;
-
- if (ppPin == NULL) {
- return E_POINTER;
- }
-
- hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
- if (FAILED(hr)) {
- return hr;
- }
-
- while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {
- PIN_DIRECTION PinDirThis;
- hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);
- if (FAILED(hr)) {
- SAFE_RELEASE(pPin);
- SAFE_RELEASE(pEnum);
- return hr;
- }
- if (PinDir == PinDirThis) {
- *ppPin = pPin;
- SAFE_RELEASE(pEnum);
- return S_OK;
- }
- SAFE_RELEASE(pPin);
- }
-
- SAFE_RELEASE(pEnum);
- return S_FALSE;
-}
-
-static STDMETHODIMP GraphBuilder_Init(void)
-{
- HRESULT hr;
-
- hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
- &IID_IGraphBuilder, (void **)&g_pGB);
- if (FAILED(hr)) {
- ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);
- return hr;
- }
-
- hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
- &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);
- if (FAILED(hr)) {
- ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);
- return hr;
- }
-
- hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);
- if (FAILED(hr)) {
- ERR("Failed to SetFiltergraph, 0x%x\n", hr);
- return hr;
- }
-
- hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,
- (void **)&g_pMediaControl);
- if (FAILED(hr)) {
- ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);
- return hr;
- }
-
- hr = HWCGrabCallback_Construct(&g_pCallback);
- if (g_pCallback == NULL) {
- hr = E_OUTOFMEMORY;
- }
-
- hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,
- (CallbackFn)marucam_device_callbackfn);
-
- return hr;
-}
-
-static STDMETHODIMP BindSourceFilter(void)
-{
- HRESULT hr;
- ICreateDevEnum *pCreateDevEnum = NULL;
- IEnumMoniker *pEnumMK = NULL;
- IMoniker *pMoniKer;
-
- hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
- &IID_ICreateDevEnum,
- (void **)&pCreateDevEnum);
- if (FAILED(hr)) {
- ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);
- return hr;
- }
-
- hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
- &CLSID_VideoInputDeviceCategory,
- &pEnumMK, 0);
- if (FAILED(hr)) {
- ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);
- SAFE_RELEASE(pCreateDevEnum);
- return hr;
- }
-
- if (!pEnumMK) {
- ERR("ClassEnumerator moniker is NULL\n");
- SAFE_RELEASE(pCreateDevEnum);
- return E_FAIL;
- }
- pEnumMK->lpVtbl->Reset(pEnumMK);
-
- hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
- if (hr == S_FALSE) {
- hr = E_FAIL;
- }
- if (SUCCEEDED(hr)) {
- IPropertyBag *pBag = NULL;
- hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
- &IID_IPropertyBag,
- (void **)&pBag);
- if (SUCCEEDED(hr)) {
- VARIANT var;
- var.vt = VT_BSTR;
- hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
- if (hr == NOERROR) {
- hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
- &IID_IBaseFilter,
- (void **)&g_pSrcFilter);
- if (FAILED(hr)) {
- ERR("Counldn't bind moniker to filter object!!\n");
- } else {
- g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);
- }
- SysFreeString(var.bstrVal);
- }
- SAFE_RELEASE(pBag);
- }
- SAFE_RELEASE(pMoniKer);
- }
-
- if (SUCCEEDED(hr)) {
- hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");
- if (hr != S_OK && hr != S_FALSE) {
- ERR("Counldn't add Video Capture filter to our graph!\n");
- SAFE_RELEASE(g_pSrcFilter);
- }
- }
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
-
- return hr;
-}
-
-static STDMETHODIMP BindTargetFilter(void)
-{
- HRESULT hr;
- hr = HWCFilter_Construct(&g_pDstFilter);
-
- if (SUCCEEDED(hr) && g_pDstFilter) {
- hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");
- if (FAILED(hr)) {
- ERR("Counldn't add HWCFilterr to our graph!\n");
- SAFE_RELEASE(g_pDstFilter);
- }
- }
- return hr;
-}
-
-static STDMETHODIMP ConnectFilters(void)
-{
- HRESULT hr;
-
- hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);
- if (FAILED(hr)) {
- ERR("Failed to get output pin. 0x%x\n", hr);
- return hr;
- }
-
- hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);
- if (FAILED(hr)) {
- ERR("Failed to get input pin. 0x%x\n", hr);
- return hr;
- }
-
- hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);
- if (FAILED(hr)) {
- ERR("Failed to connect pins. 0x%x\n", hr);
- }
- return hr;
-}
-
-static STDMETHODIMP DisconnectPins(void)
-{
- HRESULT hr;
-
- hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);
- if (FAILED(hr)) {
- ERR("Failed to disconnect output pin. 0x%x\n", hr);
- return hr;
- }
-
- hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);
- if (FAILED(hr)) {
- ERR("Failed to disconnect input pin. 0x%x\n", hr);
- }
-
- return hr;
-}
-
-static STDMETHODIMP RemoveFilters(void)
-{
- HRESULT hr;
-
- hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);
- if (FAILED(hr)) {
- ERR("Failed to remove source filer. 0x%x\n", hr);
- return hr;
- }
-
- hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);
- if (FAILED(hr)) {
- ERR("Failed to remove destination filer. 0x%x\n", hr);
- }
-
- return hr;
-}
-
-/* default fps is 15 */
-#define MARUCAM_DEFAULT_FRAMEINTERVAL 666666
-
-static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,
- uint32_t dwDstFmt, uint32_t *dwSrcFmt)
-{
- HRESULT hr;
- IAMStreamConfig *pSConfig;
- int iCount = 0, iSize = 0;
- DWORD dwYUY2 = MAKEFOURCC('Y', 'U', 'Y', '2');
- DWORD dwI420 = MAKEFOURCC('I', '4', '2', '0');
-
- if (dwSrcFmt == NULL) {
- ERR("invalid the source format pointer\n");
- return E_FAIL;
- }
-
- hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,
- g_pSrcFilter, &IID_IAMStreamConfig,
- (void **)&pSConfig);
- if (FAILED(hr)) {
- ERR("failed to FindInterface method\n");
- return hr;
- }
-
- hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
- if (FAILED(hr)) {
- ERR("failed to GetNumberOfCapabilities method\n");
- SAFE_RELEASE(pSConfig);
- return hr;
- }
-
- if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
- int iFormat = 0;
- for (iFormat = 0; iFormat < iCount; iFormat++) {
- VIDEO_STREAM_CONFIG_CAPS scc;
- AM_MEDIA_TYPE *pmtConfig;
-
- hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,
- &pmtConfig, (BYTE *)&scc);
- if (hr == S_OK) {
- if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
- VIDEOINFOHEADER *pvi =
- (VIDEOINFOHEADER *)pmtConfig->pbFormat;
- if ((pvi->bmiHeader.biWidth == (LONG)dwWidth) &&
- (pvi->bmiHeader.biHeight == (LONG)dwHeight)) {
- if (pvi->bmiHeader.biCompression == dwYUY2) {
- *dwSrcFmt = V4L2_PIX_FMT_YUYV;
- } else if ((pvi->bmiHeader.biCompression == BI_RGB) &&
- (pvi->bmiHeader.biBitCount == 24)) {
- *dwSrcFmt = V4L2_PIX_FMT_RGB24;
- } else if (pvi->bmiHeader.biCompression == dwI420) {
- *dwSrcFmt = V4L2_PIX_FMT_YUV420;
- } else { /* not support format */
- DeleteMediaType(pmtConfig);
- continue;
- }
- /* use minimum FPS(maximum frameinterval)
- with non-VT system */
-#ifdef CONFIG_HAX
- if (!hax_enabled()) {
- pvi->AvgTimePerFrame =
- (REFERENCE_TIME)scc.MaxFrameInterval;
- } else {
- pvi->AvgTimePerFrame =
- (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;
- }
-#else
- pvi->AvgTimePerFrame =
- (REFERENCE_TIME)scc.MaxFrameInterval;
-#endif
- hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);
- DeleteMediaType(pmtConfig);
- break;
- }
- }
- DeleteMediaType(pmtConfig);
- }
- }
- if (iFormat >= iCount) {
- ERR("Failed to Set format. "
- "Maybe connected webcam does not support the (%ldx%ld) "
- "resolution or image formats(YUY2, RGB24, I420).\n",
- dwWidth, dwHeight);
- hr = E_FAIL;
- }
- }
- SAFE_RELEASE(pSConfig);
- return hr;
-}
-
-static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,
- long *pStep, long *pDefault)
-{
- HRESULT hr;
- long Flags;
- IAMVideoProcAmp *pProcAmp = NULL;
-
- hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
- &IID_IAMVideoProcAmp,
- (void **)&pProcAmp);
- if (FAILED(hr)) {
- return hr;
- }
-
- hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,
- pStep, pDefault, &Flags);
-
- SAFE_RELEASE(pProcAmp);
- return hr;
-}
-
-static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)
-{
- HRESULT hr;
- long Flags;
- IAMVideoProcAmp *pProcAmp = NULL;
-
- hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
- &IID_IAMVideoProcAmp,
- (void **)&pProcAmp);
- if (FAILED(hr)) {
- return hr;
- }
-
- hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);
- if (FAILED(hr)) {
- ERR("Failed to get property for video\n");
- }
-
- SAFE_RELEASE(pProcAmp);
- return hr;
-}
-
-static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)
-{
- HRESULT hr;
-
- IAMVideoProcAmp *pProcAmp = NULL;
- hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
- &IID_IAMVideoProcAmp,
- (void **)&pProcAmp);
- if (FAILED(hr)) {
- return hr;
- }
-
- hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,
- VideoProcAmp_Flags_Manual);
- if (FAILED(hr)) {
- ERR("Failed to set property for video\n");
- }
- SAFE_RELEASE(pProcAmp);
- return hr;
-}
-
-static char *__wchar_to_char(const WCHAR *pwstr)
-{
- char *pstr = NULL;
- int len = 0;
-
- len = wcslen(pwstr) + 1;
- pstr = (char *)g_malloc0(sizeof(char) * len);
- wcstombs(pstr, pwstr, len + 1);
-
- return pstr;
-}
-
-int marucam_device_check(int log_flag)
-{
- struct timeval t1, t2;
- int ret = 0;
- char *device_name = NULL;
- HRESULT hr = E_FAIL;
- ICreateDevEnum *pCreateDevEnum = NULL;
- IGraphBuilder *pGB = NULL;
- ICaptureGraphBuilder2 *pCGB = NULL;
- IBaseFilter *pSrcFilter = NULL;
- IEnumMoniker *pEnumMK = NULL;
- IMoniker *pMoniKer = NULL;
- IAMStreamConfig *pSConfig = NULL;
- int iCount = 0, iSize = 0;
-
- gettimeofday(&t1, NULL);
- hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- if (FAILED(hr)) {
- ERR("Failed to CoInitailizeEx\n");
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
- CLSCTX_INPROC,
- &IID_IGraphBuilder,
- (void **)&pGB);
- if (FAILED(hr)) {
- ERR("Failed to create GraphBuilder, 0x%x\n", hr);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
- CLSCTX_INPROC,
- &IID_ICaptureGraphBuilder2,
- (void **)&pCGB);
- if (FAILED(hr)) {
- ERR("Failed to create CaptureGraphBuilder2, 0x%x\n", hr);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);
- if (FAILED(hr)) {
- ERR("Failed to SetFiltergraph, 0x%x\n", hr);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
- CLSCTX_INPROC,
- &IID_ICreateDevEnum,
- (void **)&pCreateDevEnum);
- if (FAILED(hr)) {
- ERR("Failed to create instance of CLSID_SystemDeviceEnum\n");
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
- &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);
- if (FAILED(hr)) {
- ERR("Failed to create class enumerator\n");
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- if (!pEnumMK) {
- ERR("Class enumerator is NULL!!\n");
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
- pEnumMK->lpVtbl->Reset(pEnumMK);
-
- hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
- if (FAILED(hr) || (hr == S_FALSE)) {
- ERR("Enum moniker returns a invalid value.\n");
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- IPropertyBag *pBag = NULL;
- hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
- &IID_IPropertyBag,
- (void **)&pBag);
- if (FAILED(hr)) {
- ERR("Failed to bind to storage.\n");
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- } else {
- VARIANT var;
- var.vt = VT_BSTR;
- hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
- if (hr == S_OK) {
- ret = 1;
- if (!log_flag) {
- SysFreeString(var.bstrVal);
- SAFE_RELEASE(pBag);
- SAFE_RELEASE(pMoniKer);
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
- device_name = __wchar_to_char(var.bstrVal);
- INFO("Device name : %s\n", device_name);
- g_free(device_name);
- hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
- &IID_IBaseFilter,
- (void **)&pSrcFilter);
- if (FAILED(hr)) {
- ERR("Counldn't bind moniker to filter object!!\n");
- SysFreeString(var.bstrVal);
- SAFE_RELEASE(pBag);
- SAFE_RELEASE(pMoniKer);
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- } else {
- pSrcFilter->lpVtbl->AddRef(pSrcFilter);
- }
- SysFreeString(var.bstrVal);
- }
- SAFE_RELEASE(pBag);
- }
- SAFE_RELEASE(pMoniKer);
-
- hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");
- if (hr != S_OK && hr != S_FALSE) {
- ERR("Counldn't add Video Capture filter to our graph!\n");
- SAFE_RELEASE(pSrcFilter);
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,
- pSrcFilter, &IID_IAMStreamConfig,
- (void **)&pSConfig);
- if (FAILED(hr)) {
- ERR("Failed to FindInterface method\n");
- SAFE_RELEASE(pSrcFilter);
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
- if (FAILED(hr)) {
- ERR("Failed to GetNumberOfCapabilities method\n");
- SAFE_RELEASE(pSConfig);
- SAFE_RELEASE(pSrcFilter);
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
- return ret;
- }
-
- if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
- int iFormat = 0;
- for (iFormat = 0; iFormat < iCount; iFormat++) {
- VIDEO_STREAM_CONFIG_CAPS scc;
- AM_MEDIA_TYPE *pmtConfig;
-
- hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,
- (BYTE *)&scc);
- if (hr == S_OK) {
- if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
- VIDEOINFOHEADER *pvi =
- (VIDEOINFOHEADER *)pmtConfig->pbFormat;
- if (pvi->bmiHeader.biCompression == BI_RGB) {
- INFO("RGB BitCount: %d, Frame size: %ux%u\n",
- pvi->bmiHeader.biBitCount,
- pvi->bmiHeader.biWidth,
- pvi->bmiHeader.biHeight);
- } else {
- INFO("PixelFormat: %c%c%c%c, Frame size: %ux%u\n",
- (char)(pvi->bmiHeader.biCompression),
- (char)(pvi->bmiHeader.biCompression >> 8),
- (char)(pvi->bmiHeader.biCompression >> 16),
- (char)(pvi->bmiHeader.biCompression >> 24),
- pvi->bmiHeader.biWidth,
- pvi->bmiHeader.biHeight);
- }
- }
- DeleteMediaType(pmtConfig);
- }
- }
- }
-
- hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);
- if (FAILED(hr)) {
- ERR("Failed to remove source filer. 0x%x\n", hr);
- }
-
- SAFE_RELEASE(pSConfig);
- SAFE_RELEASE(pSrcFilter);
- SAFE_RELEASE(pCGB);
- SAFE_RELEASE(pGB);
- SAFE_RELEASE(pEnumMK);
- SAFE_RELEASE(pCreateDevEnum);
- CoUninitialize();
- gettimeofday(&t2, NULL);
- ERR("Elapsed time : %lu.%06lu\n",
- t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
-
- return ret;
-}
-
-/* MARUCAM_CMD_INIT */
-void marucam_device_init(MaruCamState *state)
-{
- g_state = state;
-}
-
-void marucam_device_exit(MaruCamState *state)
-{
-}
-
-/* MARUCAM_CMD_OPEN */
-void marucam_device_open(MaruCamState *state)
-{
- HRESULT hr;
- uint32_t dwHeight, dwWidth, dwDstFmt;
- MaruCamParam *param = state->param;
- param->top = 0;
-
- hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- if (FAILED(hr)) {
- ERR("CoInitailizeEx\n");
- ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
- param->errCode = EINVAL;
- return;
- }
-
- hr = GraphBuilder_Init();
- if (FAILED(hr)) {
- ERR("GraphBuilder_Init\n");
- DisconnectPins();
- RemoveFilters();
- CloseInterfaces();
- CoUninitialize();
- param->errCode = EINVAL;
- ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
- return;
- }
-
- hr = BindSourceFilter();
- if (FAILED(hr)) {
- ERR("BindSourceFilter\n");
- DisconnectPins();
- RemoveFilters();
- CloseInterfaces();
- CoUninitialize();
- param->errCode = EINVAL;
- ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
- return;
- }
-
- hr = BindTargetFilter();
- if (FAILED(hr)) {
- ERR("BindTargetFilter\n");
- DisconnectPins();
- RemoveFilters();
- CloseInterfaces();
- CoUninitialize();
- param->errCode = EINVAL;
- ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
- return;
- }
-
- hr = ConnectFilters();
- if (FAILED(hr)) {
- ERR("ConnectFilters\n");
- DisconnectPins();
- RemoveFilters();
- CloseInterfaces();
- CoUninitialize();
- param->errCode = EINVAL;
- ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
- return;
- }
-
- cur_frame_idx = 0;
- cur_fmt_idx = 0;
-
- dwHeight = supported_dst_frames[cur_frame_idx].height;
- dwWidth = supported_dst_frames[cur_frame_idx].width;
- dwDstFmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- hr = SetFormat(dwWidth, dwHeight, dwDstFmt, &g_dwSrcFmt);
- if (hr != S_OK) {
- ERR("failed to Set default values\n");
- DisconnectPins();
- RemoveFilters();
- CloseInterfaces();
- CoUninitialize();
- param->errCode = EINVAL;
- ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
- return;
- }
-
- INFO("Opened\n");
- return;
-}
-
-/* MARUCAM_CMD_CLOSE */
-void marucam_device_close(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
- int ret = 0;
- param->top = 0;
-
- qemu_mutex_lock(&state->thread_mutex);
- ret = state->streamon;
- qemu_mutex_unlock(&state->thread_mutex);
- if (ret) {
- marucam_device_stop_preview(state);
- }
-
- if (g_pGB) {
- DisconnectPins();
- RemoveFilters();
- }
- CloseInterfaces();
- CoUninitialize();
- INFO("Closed\n");
-}
-
-/* MARUCAM_CMD_START_PREVIEW */
-void marucam_device_start_preview(MaruCamState *state)
-{
- HRESULT hr;
- uint32_t pixfmt, width, height;
- MaruCamParam *param = state->param;
- param->top = 0;
-
- ready_count = 0;
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
- pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- state->buf_size = get_sizeimage(pixfmt, width, height);
-
- INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n",
- (char)(pixfmt), (char)(pixfmt >> 8),
- (char)(pixfmt >> 16), (char)(pixfmt >> 24),
- width, height, state->buf_size);
- INFO("Starting preview\n");
-
- assert(g_pCallback != NULL);
- hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,
- g_pCallback);
- if (FAILED(hr)) {
- ERR("Failed to set IGrabCallback interface.\n");
- param->errCode = EINVAL;
- return;
- }
-
- if (grab_buf) {
- g_free(grab_buf);
- grab_buf = NULL;
- }
- grab_buf = (void *)g_malloc0(state->buf_size);
- if (grab_buf == NULL) {
- param->errCode = ENOMEM;
- return;
- }
-
- hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);
- if (FAILED(hr)) {
- ERR("Failed to run media control. hr=0x%x\n", hr);
- param->errCode = EINVAL;
- return;
- }
-
- qemu_mutex_lock(&state->thread_mutex);
- state->streamon = 1;
- qemu_mutex_unlock(&state->thread_mutex);
-
- INFO("Streaming on ......\n");
-}
-
-/* MARUCAM_CMD_STOP_PREVIEW */
-void marucam_device_stop_preview(MaruCamState *state)
-{
- HRESULT hr;
- MaruCamParam *param = state->param;
- param->top = 0;
-
- INFO("...... Streaming off\n");
- qemu_mutex_lock(&state->thread_mutex);
- state->streamon = 0;
- qemu_mutex_unlock(&state->thread_mutex);
-
- hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);
- if (FAILED(hr)) {
- ERR("Failed to set IGrabCallback interface.\n");
- param->errCode = EINVAL;
- return;
- }
-
- hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
- if (FAILED(hr)) {
- ERR("Failed to stop media control.\n");
- param->errCode = EINVAL;
- return;
- }
-
- if (grab_buf) {
- g_free(grab_buf);
- grab_buf = NULL;
- }
- state->buf_size = 0;
-
- INFO("Stopping preview\n");
-}
-
-/* MARUCAM_CMD_S_PARAM */
-void marucam_device_s_param(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- /* We use default FPS of the webcam */
- param->top = 0;
-}
-
-/* MARUCAM_CMD_G_PARAM */
-void marucam_device_g_param(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- /* We use default FPS of the webcam
- * return a fixed value on guest ini file (1/30).
- */
- param->top = 0;
- param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
- param->stack[1] = 1; /* numerator */
- param->stack[2] = 30; /* denominator */
-}
-
-/* MARUCAM_CMD_S_FMT */
-void marucam_device_s_fmt(MaruCamState *state)
-{
- uint32_t width, height, pixfmt, pidx, fidx;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- width = param->stack[0];
- height = param->stack[1];
- pixfmt = param->stack[2];
-
- for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
- if ((supported_dst_frames[fidx].width == width) &&
- (supported_dst_frames[fidx].height == height)) {
- break;
- }
- }
- if (fidx == ARRAY_SIZE(supported_dst_frames)) {
- param->errCode = EINVAL;
- return;
- }
- for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
- if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
- break;
- }
- }
- if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
-
- if ((supported_dst_frames[cur_frame_idx].width != width) &&
- (supported_dst_frames[cur_frame_idx].height != height)) {
- HRESULT hr = SetFormat(width, height, pixfmt, &g_dwSrcFmt);
- if (FAILED(hr)) {
- param->errCode = EINVAL;
- return;
- }
- }
-
- cur_frame_idx = fidx;
- cur_fmt_idx = pidx;
-
- pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
-
- param->stack[0] = width;
- param->stack[1] = height;
- param->stack[2] = 1; /* V4L2_FIELD_NONE */
- param->stack[3] = pixfmt;
- param->stack[4] = get_bytesperline(pixfmt, width);
- param->stack[5] = get_sizeimage(pixfmt, width, height);
- param->stack[6] = 0;
- param->stack[7] = 0;
-
- TRACE("Set format...\n");
-}
-
-/* MARUCAM_CMD_G_FMT */
-void marucam_device_g_fmt(MaruCamState *state)
-{
- uint32_t width, height, pixfmt;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
- width = supported_dst_frames[cur_frame_idx].width;
- height = supported_dst_frames[cur_frame_idx].height;
-
- param->stack[0] = width;
- param->stack[1] = height;
- param->stack[2] = 1; /* V4L2_FIELD_NONE */
- param->stack[3] = pixfmt;
- param->stack[4] = get_bytesperline(pixfmt, width);
- param->stack[5] = get_sizeimage(pixfmt, width, height);
- param->stack[6] = 0;
- param->stack[7] = 0;
-
- TRACE("Get format...\n");
-}
-
-void marucam_device_try_fmt(MaruCamState *state)
-{
- uint32_t width, height, pixfmt, i;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- width = param->stack[0];
- height = param->stack[1];
- pixfmt = param->stack[2];
-
- for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
- if ((supported_dst_frames[i].width == width) &&
- (supported_dst_frames[i].height == height)) {
- break;
- }
- }
- if (i == ARRAY_SIZE(supported_dst_frames)) {
- param->errCode = EINVAL;
- return;
- }
- for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
- if (supported_dst_pixfmts[i].fmt == pixfmt) {
- break;
- }
- }
- if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
-
- param->stack[0] = width;
- param->stack[1] = height;
- param->stack[2] = 1; /* V4L2_FIELD_NONE */
- param->stack[3] = pixfmt;
- param->stack[4] = get_bytesperline(pixfmt, width);
- param->stack[5] = get_sizeimage(pixfmt, width, height);
- param->stack[6] = 0;
- param->stack[7] = 0;
-}
-
-void marucam_device_enum_fmt(MaruCamState *state)
-{
- uint32_t index;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- index = param->stack[0];
-
- if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
- param->stack[1] = 0; /* flags = NONE */
- param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
- /* set description */
- switch (supported_dst_pixfmts[index].fmt) {
- case V4L2_PIX_FMT_YUYV:
- memcpy(¶m->stack[3], "YUYV", 32);
- break;
- case V4L2_PIX_FMT_YUV420:
- memcpy(¶m->stack[3], "YU12", 32);
- break;
- case V4L2_PIX_FMT_YVU420:
- memcpy(¶m->stack[3], "YV12", 32);
- break;
- default:
- ERR("Invalid pixel format\n");
- param->errCode = EINVAL;
- break;
- }
-}
-
-void marucam_device_qctrl(MaruCamState *state)
-{
- HRESULT hr;
- uint32_t id, i;
- long property, min, max, step, def_val, set_val;
- char name[32] = {0,};
- MaruCamParam *param = state->param;
-
- param->top = 0;
- id = param->stack[0];
-
- switch (id) {
- case V4L2_CID_BRIGHTNESS:
- TRACE("V4L2_CID_BRIGHTNESS\n");
- property = VideoProcAmp_Brightness;
- memcpy((void *)name, (void *)"brightness", 32);
- i = 0;
- break;
- case V4L2_CID_CONTRAST:
- TRACE("V4L2_CID_CONTRAST\n");
- property = VideoProcAmp_Contrast;
- memcpy((void *)name, (void *)"contrast", 32);
- i = 1;
- break;
- case V4L2_CID_SATURATION:
- TRACE("V4L2_CID_SATURATION\n");
- property = VideoProcAmp_Saturation;
- memcpy((void *)name, (void *)"saturation", 32);
- i = 2;
- break;
- case V4L2_CID_SHARPNESS:
- TRACE("V4L2_CID_SHARPNESS\n");
- property = VideoProcAmp_Sharpness;
- memcpy((void *)name, (void *)"sharpness", 32);
- i = 3;
- break;
- default:
- ERR("Invalid control ID\n");
- param->errCode = EINVAL;
- return;
- }
- hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);
- if (FAILED(hr)) {
- param->errCode = EINVAL;
- ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
- return;
- } else {
- qctrl_tbl[i].hit = 1;
- qctrl_tbl[i].min = min;
- qctrl_tbl[i].max = max;
- qctrl_tbl[i].step = step;
- qctrl_tbl[i].init_val = def_val;
-
- if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
- set_val = 0;
- } else {
- set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
- }
- hr = SetVideoProcAmp(property, set_val);
- if (FAILED(hr)) {
- param->errCode = EINVAL;
- ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
- return;
- }
- }
-
- param->stack[0] = id;
- param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
- param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
- param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
- param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
- param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
- /* name field setting */
- memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
-}
-
-void marucam_device_s_ctrl(MaruCamState *state)
-{
- HRESULT hr;
- uint32_t i;
- long property, set_val;
- MaruCamParam *param = state->param;
-
- param->top = 0;
-
- switch (param->stack[0]) {
- case V4L2_CID_BRIGHTNESS:
- i = 0;
- property = VideoProcAmp_Brightness;
- break;
- case V4L2_CID_CONTRAST:
- i = 1;
- property = VideoProcAmp_Contrast;
- break;
- case V4L2_CID_SATURATION:
- i = 2;
- property = VideoProcAmp_Saturation;
- break;
- case V4L2_CID_SHARPNESS:
- i = 3;
- property = VideoProcAmp_Sharpness;
- break;
- default:
- param->errCode = EINVAL;
- return;
- }
- set_val = value_convert_from_guest(qctrl_tbl[i].min,
- qctrl_tbl[i].max, (long)param->stack[1]);
- hr = SetVideoProcAmp(property, set_val);
- if (FAILED(hr)) {
- param->errCode = EINVAL;
- ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
- return;
- }
-}
-
-void marucam_device_g_ctrl(MaruCamState *state)
-{
- HRESULT hr;
- uint32_t i;
- long property, get_val;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- switch (param->stack[0]) {
- case V4L2_CID_BRIGHTNESS:
- i = 0;
- property = VideoProcAmp_Brightness;
- break;
- case V4L2_CID_CONTRAST:
- i = 1;
- property = VideoProcAmp_Contrast;
- break;
- case V4L2_CID_SATURATION:
- i = 2;
- property = VideoProcAmp_Saturation;
- break;
- case V4L2_CID_SHARPNESS:
- i = 3;
- property = VideoProcAmp_Sharpness;
- break;
- default:
- param->errCode = EINVAL;
- return;
- }
-
- hr = GetVideoProcAmp(property, &get_val);
- if (FAILED(hr)) {
- param->errCode = EINVAL;
- ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
- return;
- }
- param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
- qctrl_tbl[i].max, get_val);
-}
-
-void marucam_device_enum_fsizes(MaruCamState *state)
-{
- uint32_t index, pixfmt, i;
- MaruCamParam *param = state->param;
-
- param->top = 0;
- index = param->stack[0];
- pixfmt = param->stack[1];
-
- if (index >= ARRAY_SIZE(supported_dst_frames)) {
- param->errCode = EINVAL;
- return;
- }
- for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
- if (supported_dst_pixfmts[i].fmt == pixfmt) {
- break;
- }
- }
-
- if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
- param->errCode = EINVAL;
- return;
- }
-
- param->stack[0] = supported_dst_frames[index].width;
- param->stack[1] = supported_dst_frames[index].height;
-}
-
-void marucam_device_enum_fintv(MaruCamState *state)
-{
- MaruCamParam *param = state->param;
-
- param->top = 0;
-
- /* switch by index(param->stack[0]) */
- switch (param->stack[0]) {
- case 0:
- param->stack[1] = 30; /* denominator */
- break;
- default:
- param->errCode = EINVAL;
- return;
- }
- param->stack[0] = 1; /* numerator */
-}
-
-void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height, uint32_t yvu)
-{
- uint32_t i, j;
- const unsigned char *src1;
- unsigned char *udest, *vdest;
-
- /* copy the Y values */
- src1 = src;
- for (i = 0; i < height; i++) {
- for (j = 0; j < width; j += 2) {
- *dest++ = src1[0];
- *dest++ = src1[2];
- src1 += 4;
- }
- }
-
- /* copy the U and V values */
- src++; /* point to V */
- src1 = src + width * 2; /* next line */
- if (yvu) {
- vdest = dest;
- udest = dest + width * height / 4;
- } else {
- udest = dest;
- vdest = dest + width * height / 4;
- }
- for (i = 0; i < height; i += 2) {
- for (j = 0; j < width; j += 2) {
- *udest++ = ((int) src[0] + src1[0]) / 2; /* U */
- *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
- src += 4;
- src1 += 4;
- }
- src = src1;
- src1 += width * 2;
- }
-}
-
-#define RGB2Y(r, g, b, y) \
- (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
-
-#define RGB2UV(r, g, b, u, v) \
- do { \
- (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15); \
- (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15); \
- } while (0)
-
-#define CLIP(color) \
- (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
-
-void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height, uint32_t yvu)
-{
- uint32_t x, y;
- uint32_t halfWidth;
- uint8_t *yplane, *uplane, *vplane;
- uint8_t *yline, *uline, *vline;
- const uint8_t *rgbIndex;
-
- halfWidth = width >> 1;
- yplane = dest;
-
- if (yvu) {
- vplane = dest + width * height;
- uplane = vplane + ((width * height) >> 2);
- } else {
- uplane = dest + width * height;
- vplane = uplane + ((width * height) >> 2);
- }
-
- for (y = 0; y < height; y++) {
- yline = yplane + (y * width);
- uline = uplane + ((y >> 1) * halfWidth);
- vline = vplane + ((y >> 1) * halfWidth);
-
- rgbIndex = src + (width * (height - 1 - y) * 3);
- for (x = 0; x < (int)width; x+=2) {
- RGB2Y(rgbIndex[2], rgbIndex[1], rgbIndex[0], *yline++);
- rgbIndex += 3;
- RGB2Y(rgbIndex[2], rgbIndex[1], rgbIndex[0], *yline++);
- RGB2UV(rgbIndex[2], rgbIndex[1], rgbIndex[0], *uline++, *vline++);
- rgbIndex += 3;
- }
- }
-}
-
-void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height)
-{
- uint32_t i, j;
- uint8_t *ptr;
-
- for (i = 0; i < height; i++) {
- ptr = src + (width * (height - 1 - i) * 3);
- for (j = 0; j < width; j += 2) {
- /* y */
- *dest++ = CLIP(0.299 * (ptr[2] - 128) +
- 0.587 * (ptr[1] - 128) +
- 0.114 * (ptr[0] - 128) + 128);
- /* u */
- *dest++ = CLIP(((-0.147 * (ptr[2] - 128) -
- 0.289 * (ptr[1] - 128) +
- 0.436 * (ptr[0] - 128) + 128) +
- (-0.147 * (ptr[5] - 128) -
- 0.289 * (ptr[4] - 128) +
- 0.436 * (ptr[3] - 128) + 128)) / 2);
- /* y1 */
- *dest++ = CLIP(0.299 * (ptr[5] - 128) +
- 0.587 * (ptr[4] - 128) +
- 0.114 * (ptr[3] - 128) + 128);
- /* v */
- *dest++ = CLIP(((0.615 * (ptr[2] - 128) -
- 0.515 * (ptr[1] - 128) -
- 0.100 * (ptr[0] - 128) + 128) +
- (0.615 * (ptr[5] - 128) -
- 0.515 * (ptr[4] - 128) -
- 0.100 * (ptr[3] - 128) + 128)) / 2);
- ptr += 6;
- }
- }
-}
-
-void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height)
-{
- unsigned char *psrc_y, *pdst_y;
- unsigned char *psrc_u, *pdst_u;
- unsigned char *psrc_v, *pdst_v;
-
- psrc_y = src;
- psrc_u = psrc_y + (width * height);
- psrc_v = psrc_u + (width * height / 4);
-
- pdst_y = dest;
- pdst_v = pdst_y + (width * height);
- pdst_u = pdst_v + (width * height / 4);
-
- memcpy(pdst_y, psrc_y, width * height);
- memcpy(pdst_v, psrc_v, width * height / 4);
- memcpy(pdst_u, psrc_u, width * height / 4);
-}
-
-void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
- uint32_t width, uint32_t height)
-{
- unsigned char *py;
- unsigned char *pu;
- unsigned char *pv;
-
- uint32_t linesize = width * 2;
- uint32_t uvlinesize = width / 2;
- uint32_t offset = 0;
- uint32_t offset1 = 0;
- uint32_t offsety = 0;
- uint32_t offsety1 = 0;
- uint32_t offsetuv = 0;
- uint32_t h = 0;
- uint32_t w = 0;
- uint32_t wy = 0;
- uint32_t huv = 0;
- uint32_t wuv = 0;
-
- py = src;
- pu = py + (width * height);
- pv = pu + (width * height / 4);
-
- for (h = 0; h < height; h += 2) {
- wy = 0;
- wuv = 0;
- offset = h * linesize;
- offset1 = (h + 1) * linesize;
- offsety = h * width;
- offsety1 = (h + 1) * width;
- offsetuv = huv * uvlinesize;
-
- for (w = 0; w < linesize; w += 4) {
- /* y00 */
- dest[w + offset] = py[wy + offsety];
- /* u0 */
- dest[(w + 1) + offset] = pu[wuv + offsetuv];
- /* y01 */
- dest[(w + 2) + offset] = py[(wy + 1) + offsety];
- /* v0 */
- dest[(w + 3) + offset] = pv[wuv + offsetuv];
-
- /* y10 */
- dest[w + offset1] = py[wy + offsety1];
- /* u0 */
- dest[(w + 1) + offset1] = pu[wuv + offsetuv];
- /* y11 */
- dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];
- /* v0 */
- dest[(w + 3) + offset1] = pv[wuv + offsetuv];
-
- wuv++;
- wy += 2;
- }
- huv++;
- }
-}
+++ /dev/null
-/*
- * Virtual Codec device
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Kitae Kim <kt920.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * DongKyun Yun
- *
- * 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_codec.h"
-#include "qemu-common.h"
-
-#define MARU_CODEC_DEV_NAME "codec"
-#define MARU_CODEC_VERSION 14
-
-/* Needs 16M to support 1920x1080 video resolution.
- * Output size for encoding has to be greater than (width * height * 6)
- */
-#define MARU_CODEC_MEM_SIZE (2 * 16 * 1024 * 1024)
-#define MARU_CODEC_REG_SIZE (256)
-#define MARU_CODEC_IRQ 0x7f
-
-#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))
-
-typedef struct PixFmtInfo {
- uint8_t x_chroma_shift;
- uint8_t y_chroma_shift;
-} PixFmtInfo;
-
-static PixFmtInfo pix_fmt_info[PIX_FMT_NB];
-
-/* define debug channel */
-MULTI_DEBUG_CHANNEL(qemu, marucodec);
-
-void codec_thread_init(SVCodecState *s)
-{
- int index = 0;
- QemuThread *pthread = NULL;
- TRACE("Enter, %s\n", __func__);
-
- pthread = g_malloc0(sizeof(QemuThread) * CODEC_MAX_THREAD);
- if (!pthread) {
- ERR("Failed to allocate wrk_thread memory.\n");
- return;
- }
- qemu_cond_init(&s->codec_thread.cond);
- qemu_mutex_init(&s->codec_thread.mutex);
-
- qemu_mutex_lock(&s->thread_mutex);
- s->isrunning = 1;
- qemu_mutex_unlock(&s->thread_mutex);
-
- for (; index < CODEC_MAX_THREAD; index++) {
- qemu_thread_create(&pthread[index], codec_worker_thread, (void *)s,
- QEMU_THREAD_JOINABLE);
- }
-
- s->codec_thread.wrk_thread = pthread;
- TRACE("Leave, %s\n", __func__);
-}
-
-void codec_thread_exit(SVCodecState *s)
-{
- TRACE("Enter, %s\n", __func__);
- int index;
-
- /* stop to run dedicated threads. */
- s->isrunning = 0;
-
- for (index = 0; index < CODEC_MAX_THREAD; index++) {
- qemu_thread_join(&s->codec_thread.wrk_thread[index]);
- }
-
- TRACE("destroy mutex and conditional.\n");
- qemu_mutex_destroy(&s->codec_thread.mutex);
- qemu_cond_destroy(&s->codec_thread.cond);
-
- TRACE("Leave, %s\n", __func__);
-}
-
-void wake_codec_worker_thread(SVCodecState *s)
-{
- TRACE("Enter, %s\n", __func__);
-
- qemu_cond_signal(&s->codec_thread.cond);
- TRACE("sent a conditional signal to a worker thread.\n");
-
- TRACE("Leave, %s\n", __func__);
-}
-
-void *codec_worker_thread(void *opaque)
-{
- SVCodecState *s = (SVCodecState *)opaque;
- QemuThread thread;
- AVCodecContext *avctx;
-
- TRACE("Enter, %s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- while (s->isrunning) {
- TRACE("wait for conditional signal.\n");
- qemu_cond_wait(&s->codec_thread.cond, &s->thread_mutex);
-
- qemu_thread_get_self(&thread);
-#ifdef CONFIG_LINUX
- TRACE("wake up a worker thread. :%x\n", thread.thread);
-#endif
- avctx = s->codec_ctx[s->codec_param.ctx_index].avctx;
- if (avctx) {
- if (avctx->codec->decode) {
- decode_codec(s);
- } else {
- encode_codec(s);
- }
- } else {
- ERR("there is a synchrous problem "
- "between each context.\n");
- continue;
- }
-
- s->codec_thread.state = MARU_CODEC_IRQ;
- qemu_bh_schedule(s->tx_bh);
- }
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("Leave, %s\n", __func__);
-
- return NULL;
-}
-
-int decode_codec(SVCodecState *s)
-{
- AVCodecContext *avctx;
- uint32_t len = 0, ctx_index;
-
- TRACE("Enter, %s\n", __func__);
-
- qemu_mutex_lock(&s->codec_thread.mutex);
- ctx_index = s->codec_param.ctx_index;
- qemu_mutex_unlock(&s->codec_thread.mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
- len = qemu_avcodec_decode_video(s, ctx_index);
- } else {
- len = qemu_avcodec_decode_audio(s, ctx_index);
- }
-
- TRACE("Leave, %s\n", __func__);
- return len;
-}
-
-int encode_codec(SVCodecState *s)
-{
- AVCodecContext *avctx;
- uint32_t len = 0, ctx_index;
-
- TRACE("Enter, %s\n", __func__);
-
- qemu_mutex_unlock(&s->thread_mutex);
-
- ctx_index = s->codec_param.ctx_index;
- avctx = s->codec_ctx[ctx_index].avctx;
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
- len = qemu_avcodec_encode_video(s, ctx_index);
- } else {
- len = qemu_avcodec_encode_audio(s, ctx_index);
- }
-
- qemu_mutex_lock(&s->thread_mutex);
-
- TRACE("Leave, %s\n", __func__);
- return len;
-}
-
-static int qemu_serialize_rational(const AVRational *elem, uint8_t *buff)
-{
- int size = 0;
-
- memcpy(buff + size, &elem->num, sizeof(elem->num));
- size += sizeof(elem->num);
- memcpy(buff + size, &elem->den, sizeof(elem->den));
- size += sizeof(elem->den);
-
- return size;
-}
-
-static int qemu_deserialize_rational(const uint8_t *buff, AVRational *elem)
-{
- int size = 0;
-
- memset(elem, 0, sizeof(*elem));
-
- memcpy(&elem->num, buff + size, sizeof(elem->num));
- size += sizeof(elem->num);
- memcpy(&elem->den, buff + size, sizeof(elem->den));
- size += sizeof(elem->den);
-
- return size;
-}
-
-static int qemu_serialize_frame(const AVFrame *elem, uint8_t *buff)
-{
- int size = 0;
-
- memcpy(buff + size, &elem->key_frame, sizeof(elem->key_frame));
- size += sizeof(elem->key_frame);
- memcpy(buff + size, &elem->pict_type, sizeof(elem->pict_type));
- size += sizeof(elem->pict_type);
- memcpy(buff + size, &elem->pts, sizeof(elem->pts));
- size += sizeof(elem->pts);
- memcpy(buff + size, &elem->coded_picture_number,
- sizeof(elem->coded_picture_number));
- size += sizeof(elem->coded_picture_number);
- memcpy(buff + size, &elem->display_picture_number,
- sizeof(elem->display_picture_number));
- size += sizeof(elem->display_picture_number);
- memcpy(buff + size, &elem->quality, sizeof(elem->quality));
- size += sizeof(elem->quality);
- memcpy(buff + size, &elem->age, sizeof(elem->age));
- size += sizeof(elem->age);
- memcpy(buff + size, &elem->reference, sizeof(elem->reference));
- size += sizeof(elem->reference);
- memcpy(buff + size, &elem->reordered_opaque,
- sizeof(elem->reordered_opaque));
- size += sizeof(elem->reordered_opaque);
- memcpy(buff + size, &elem->repeat_pict, sizeof(elem->repeat_pict));
- size += sizeof(elem->repeat_pict);
- memcpy(buff + size, &elem->interlaced_frame,
- sizeof(elem->interlaced_frame));
- size += sizeof(elem->interlaced_frame);
-
- return size;
-}
-
-static int qemu_deserialize_frame(const uint8_t *buff, AVFrame *elem)
-{
- int size = 0;
-
- memset(elem, 0, sizeof(*elem));
-
- memcpy(&elem->linesize, buff + size, sizeof(elem->linesize));
- size += sizeof(elem->linesize);
- memcpy(&elem->key_frame, buff + size, sizeof(elem->key_frame));
- size += sizeof(elem->key_frame);
- memcpy(&elem->pict_type, buff + size, sizeof(elem->pict_type));
- size += sizeof(elem->pict_type);
- memcpy(&elem->pts, buff + size, sizeof(elem->pts));
- size += sizeof(elem->pts);
- memcpy(&elem->coded_picture_number, buff + size,
- sizeof(elem->coded_picture_number));
- size += sizeof(elem->coded_picture_number);
- memcpy(&elem->display_picture_number, buff + size,
- sizeof(elem->display_picture_number));
- size += sizeof(elem->display_picture_number);
- memcpy(&elem->quality, buff + size, sizeof(elem->quality));
- size += sizeof(elem->quality);
- memcpy(&elem->age, buff + size, sizeof(elem->age));
- size += sizeof(elem->age);
- memcpy(&elem->reference, buff + size, sizeof(elem->reference));
- size += sizeof(elem->reference);
- memcpy(&elem->qstride, buff + size, sizeof(elem->qstride));
- size += sizeof(elem->qstride);
- memcpy(&elem->motion_subsample_log2, buff + size,
- sizeof(elem->motion_subsample_log2));
- size += sizeof(elem->motion_subsample_log2);
- memcpy(&elem->error, buff + size, sizeof(elem->error));
- size += sizeof(elem->error);
- memcpy(&elem->type, buff + size, sizeof(elem->type));
- size += sizeof(elem->type);
- memcpy(&elem->repeat_pict, buff + size, sizeof(elem->repeat_pict));
- size += sizeof(elem->repeat_pict);
- memcpy(&elem->qscale_type, buff + size, sizeof(elem->qscale_type));
- size += sizeof(elem->qscale_type);
- memcpy(&elem->interlaced_frame, buff + size,
- sizeof(elem->interlaced_frame));
- size += sizeof(elem->interlaced_frame);
- memcpy(&elem->top_field_first, buff + size, sizeof(elem->top_field_first));
- size += sizeof(elem->top_field_first);
- memcpy(&elem->palette_has_changed, buff + size,
- sizeof(elem->palette_has_changed));
- size += sizeof(elem->palette_has_changed);
- memcpy(&elem->buffer_hints, buff + size, sizeof(elem->buffer_hints));
- size += sizeof(elem->buffer_hints);
- memcpy(&elem->reordered_opaque, buff + size,
- sizeof(elem->reordered_opaque));
- size += sizeof(elem->reordered_opaque);
-
- return size;
-}
-
-void qemu_parser_init(SVCodecState *s, int ctx_index)
-{
- TRACE("[%s] Enter\n", __func__);
-
- s->codec_ctx[ctx_index].parser_buf = NULL;
- s->codec_ctx[ctx_index].parser_use = false;
-
- TRACE("[%s] Leave\n", __func__);
-}
-
-void qemu_reset_codec_info(SVCodecState *s, uint32_t value)
-{
- int ctx_idx;
-
- TRACE("[%s] Enter\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- for (ctx_idx = 0; ctx_idx < CODEC_CONTEXT_MAX; ctx_idx++) {
- if (s->codec_ctx[ctx_idx].file_index == value) {
- TRACE("reset %d context\n", ctx_idx);
- qemu_mutex_unlock(&s->thread_mutex);
- qemu_av_free(s, ctx_idx);
- qemu_mutex_lock(&s->thread_mutex);
- s->codec_ctx[ctx_idx].avctx_use = false;
- break;
- }
- }
- qemu_parser_init(s, ctx_idx);
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("[%s] Leave\n", __func__);
-}
-
-/* void av_register_all() */
-void qemu_av_register_all(void)
-{
- av_register_all();
- TRACE("av_register_all\n");
-}
-
-/* int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic) */
-int qemu_avcodec_get_buffer(AVCodecContext *context, AVFrame *picture)
-{
- int ret;
- TRACE("avcodec_default_get_buffer\n");
-
- picture->reordered_opaque = context->reordered_opaque;
- picture->opaque = NULL;
-
- ret = avcodec_default_get_buffer(context, picture);
-
- return ret;
-}
-
-/* void avcodec_default_release_buffer(AVCodecContext *ctx, AVFrame *frame) */
-void qemu_avcodec_release_buffer(AVCodecContext *context, AVFrame *picture)
-{
- TRACE("avcodec_default_release_buffer\n");
- avcodec_default_release_buffer(context, picture);
-}
-
-static void qemu_init_pix_fmt_info(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 = 1;
- 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;
-
- /* JPEG YUV */
- 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 uint8_t *qemu_malloc_avpicture (int picture_size)
-{
- uint8_t *ptr = NULL;
-
- ptr = av_mallocz(picture_size);
- if (!ptr) {
- ERR("failed to allocate memory.\n");
- return NULL;
- }
-
- return ptr;
-}
-
-static int qemu_avpicture_fill(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) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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", 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;
- TRACE("stride %d, stride2 %d, size %d, size2 %d, fsize %d\n",
- stride, stride2, size, size2, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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 %d\n", 0, size, size + size2, size + 2 * size2);
- TRACE("strides %d %d %d %d\n", stride, stride2, stride2, stride);
- break;
- case PIX_FMT_RGB24:
- case PIX_FMT_BGR24:
- stride = ROUND_UP_4 (width * 3);
- fsize = stride * height;
- TRACE("stride: %d, fsize: %d\n", stride, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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, fsize: %d\n", stride, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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:
- case PIX_FMT_YUYV422:
- case PIX_FMT_UYVY422:
- stride = ROUND_UP_4 (width * 2);
- fsize = stride * height;
- TRACE("stride: %d, fsize: %d\n", stride, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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_UYYVYY411:
- /* FIXME, probably not the right stride */
- stride = ROUND_UP_4 (width);
- size = stride * height;
- fsize = size + size / 2;
- TRACE("stride %d, size %d, fsize %d\n", stride, size, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- picture->data[0] = ptr;
- picture->data[1] = NULL;
- picture->data[2] = NULL;
- picture->data[3] = NULL;
- picture->linesize[0] = width + width / 2;
- picture->linesize[1] = 0;
- picture->linesize[2] = 0;
- picture->linesize[3] = 0;
- break;
- case PIX_FMT_GRAY8:
- stride = ROUND_UP_4 (width);
- fsize = stride * height;
- TRACE("stride %d, fsize %d\n", stride, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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_MONOWHITE:
- case PIX_FMT_MONOBLACK:
- stride = ROUND_UP_4 ((width + 7) >> 3);
- fsize = stride * height;
- TRACE("stride %d, fsize %d\n", stride, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- 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:
- /* already forced to be with stride, so same result as other function */
- stride = ROUND_UP_4 (width);
- size = stride * height;
- fsize = size + 256 * 4;
- TRACE("stride %d, size %d, fsize %d\n", stride, size, fsize);
- if (!encode && !ptr) {
- ptr = qemu_malloc_avpicture(fsize);
- }
- picture->data[0] = ptr;
- picture->data[1] = ptr + size; /* palette is stored here as 256 32 bit words */
- 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;
-}
-
-/* int avcodec_open(AVCodecContext *avctx, AVCodec *codec) */
-int qemu_avcodec_open(SVCodecState *s)
-{
- AVCodecContext *avctx;
- AVCodec *codec;
- enum CodecID codec_id;
- off_t offset;
- int ret = -1;
- int bEncode = 0;
- int size = 0;
- int ctx_index = 0;
-
- av_register_all();
- TRACE("av_register_all\n");
-
- ctx_index = qemu_avcodec_alloc_context(s);
- if (ctx_index < 0) {
- return ret;
- }
-
- qemu_mutex_lock(&s->thread_mutex);
- offset = s->codec_param.mmap_offset;
- qemu_mutex_unlock(&s->thread_mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- if (!avctx) {
- ERR("[%s] %d of AVCodecContext is NULL!\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->thread_mutex);
- return ret;
- }
-
- TRACE("[%s] Context Index:%d, offset:%d\n", __func__, ctx_index, offset);
- memcpy(&avctx->bit_rate, (uint8_t *)s->vaddr + offset, sizeof(int));
- size = sizeof(int);
- memcpy(&avctx->bit_rate_tolerance,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->flags, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- size += qemu_deserialize_rational((uint8_t *)s->vaddr + offset + size,
- &avctx->time_base);
- memcpy(&avctx->width, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->height, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->gop_size, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->pix_fmt, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->sample_rate,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->channels, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->codec_tag, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->block_align,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->rc_strategy,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->strict_std_compliance,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->rc_qsquish,
- (uint8_t *)s->vaddr + offset + size, sizeof(float));
- size += sizeof(float);
- size += qemu_deserialize_rational((uint8_t *)s->vaddr + offset + size,
- &avctx->sample_aspect_ratio);
- memcpy(&avctx->qmin, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->qmax, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->pre_me, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->trellis, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&avctx->extradata_size,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&codec_id, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&bEncode, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- TRACE("Context Index:%d, width:%d, height:%d\n",
- ctx_index, avctx->width, avctx->height);
-
- if (avctx->extradata_size > 0) {
- avctx->extradata = (uint8_t *)av_mallocz(avctx->extradata_size +
- ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
- memcpy(avctx->extradata,
- (uint8_t *)s->vaddr + offset + size, avctx->extradata_size);
- size += avctx->extradata_size;
- } else {
- TRACE("[%s] allocate dummy extradata\n", __func__);
- avctx->extradata =
- av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
- }
-
- if (bEncode) {
- TRACE("[%s] find encoder :%d\n", __func__, codec_id);
- codec = avcodec_find_encoder(codec_id);
- } else {
- TRACE("[%s] find decoder :%d\n", __func__, codec_id);
- codec = avcodec_find_decoder(codec_id);
- }
-
- if (!codec) {
- ERR("[%s] failed to find codec of %d\n", __func__, codec_id);
- }
-
- if (codec->type == AVMEDIA_TYPE_AUDIO) {
- s->codec_ctx[ctx_index].mem_index = s->codec_param.mem_index;
- TRACE("set mem_index: %d into ctx_index: %d.\n",
- s->codec_ctx[ctx_index].mem_index, ctx_index);
- }
-
-#if 0
- avctx->get_buffer = qemu_avcodec_get_buffer;
- avctx->release_buffer = qemu_avcodec_release_buffer;
-#endif
-
- ret = avcodec_open(avctx, codec);
- if (ret != 0) {
- ERR("[%s] avcodec_open failure, %d\n", __func__, ret);
- }
-
- memcpy((uint8_t *)s->vaddr + offset, &ctx_index, sizeof(int));
- size = sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->pix_fmt, sizeof(int));
- size += sizeof(int);
- size += qemu_serialize_rational(&avctx->time_base,
- (uint8_t *)s->vaddr + offset + size);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->channels, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->sample_fmt, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->codec_type, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->codec_id, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->coded_width, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->coded_height, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->ticks_per_frame, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->chroma_sample_location, sizeof(int));
- size += sizeof(int);
-#if 0
- memcpy((uint8_t *)s->vaddr + offset + size,
- avctx->priv_data, codec->priv_data_size);
- size += codec->priv_data_size;
-#endif
- memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
- size += sizeof(int);
-
- TRACE("Leave, %s\n", __func__);
- return ret;
-}
-
-/* int avcodec_close(AVCodecContext *avctx) */
-int qemu_avcodec_close(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx;
- off_t offset;
- int ret = -1;
-
- TRACE("Enter, %s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- offset = s->codec_param.mmap_offset;
-
- avctx = s->codec_ctx[ctx_index].avctx;
- if (!avctx) {
- ERR("[%s] %d of AVCodecContext is NULL\n", __func__, ctx_index);
- memcpy((uint8_t *)s->vaddr + offset, &ret, sizeof(int));
- qemu_mutex_unlock(&s->thread_mutex);
- return ret;
- }
-
- ret = avcodec_close(avctx);
- TRACE("after avcodec_close. ret:%d\n", ret);
-
- memcpy((uint8_t *)s->vaddr + offset, &ret, sizeof(int));
-
- qemu_mutex_unlock(&s->thread_mutex);
-
- TRACE("[%s] Leave\n", __func__);
- return ret;
-}
-
-/* AVCodecContext* avcodec_alloc_context (void) */
-int qemu_avcodec_alloc_context(SVCodecState *s)
-{
- int index;
-
- TRACE("[%s] Enter\n", __func__);
-
- for (index = 0; index < CODEC_CONTEXT_MAX; index++) {
- if (s->codec_ctx[index].avctx_use == false) {
- TRACE("Succeeded to get %d of context.\n", index);
- s->codec_ctx[index].avctx_use = true;
- break;
- }
- TRACE("Failed to get context.\n");
- }
-
- if (index == CODEC_CONTEXT_MAX) {
- ERR("Failed to get available codec context.");
- ERR(" Try to run codec again.\n");
- return -1;
- }
-
- TRACE("allocate %d of context and frame.\n", index);
- s->codec_ctx[index].avctx = avcodec_alloc_context();
- s->codec_ctx[index].frame = avcodec_alloc_frame();
-
- s->codec_ctx[index].file_index = s->codec_param.file_index;
- qemu_parser_init(s, index);
- qemu_init_pix_fmt_info();
-
- TRACE("[%s] Leave\n", __func__);
-
- return index;
-}
-
-/* void av_free(void *ptr) */
-void qemu_av_free(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx;
- AVFrame *avframe;
-
- TRACE("enter %s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- avframe = s->codec_ctx[ctx_index].frame;
-
- if (avctx && avctx->palctrl) {
- av_free(avctx->palctrl);
- avctx->palctrl = NULL;
- }
-
- if (avctx && avctx->extradata) {
- TRACE("free extradata\n");
- av_free(avctx->extradata);
- avctx->extradata = NULL;
- }
-
- if (avctx && avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
- int audio_idx = s->codec_ctx[ctx_index].mem_index;
- TRACE("reset audio mem_idex: %d\n", __LINE__, audio_idx);
- s->audio_codec_offset[audio_idx] = 0;
- }
-
- if (avctx) {
- TRACE("free codec context of %d.\n", ctx_index);
- av_free(avctx);
- s->codec_ctx[ctx_index].avctx = NULL;
- }
-
- if (avframe) {
- TRACE("free codec frame of %d.\n", ctx_index);
- av_free(avframe);
- s->codec_ctx[ctx_index].frame = NULL;
- }
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("leave %s\n", __func__);
-}
-
-/* void avcodec_flush_buffers(AVCodecContext *avctx) */
-void qemu_avcodec_flush_buffers(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx;
-
- TRACE("Enter\n");
- qemu_mutex_lock(&s->thread_mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- if (avctx) {
- avcodec_flush_buffers(avctx);
- } else {
- ERR("[%s] %d of AVCodecContext is NULL\n", __func__, ctx_index);
- }
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("[%s] Leave\n", __func__);
-}
-
-/* int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture,
- * int *got_picture_ptr, const uint8_t *buf,
- * int buf_size)
- */
-int qemu_avcodec_decode_video(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx;
- AVFrame *picture;
- AVPacket avpkt;
- int got_picture_ptr;
- uint8_t *buf;
- uint8_t *parser_buf;
- bool parser_use;
- int buf_size;
- int size = 0;
- int ret = -1;
- off_t offset;
-
- TRACE("Enter, %s\n", __func__);
- qemu_mutex_lock(&s->codec_thread.mutex);
-
- TRACE("[%s] Video Context Index : %d\n", __func__, ctx_index);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- picture = s->codec_ctx[ctx_index].frame;
- if (!avctx || !picture) {
- ERR("[%s] %d of Context or Frame is NULL!\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->codec_thread.mutex);
- return ret;
- }
-
- offset = s->codec_param.mmap_offset;
-
- parser_buf = s->codec_ctx[ctx_index].parser_buf;
- parser_use = s->codec_ctx[ctx_index].parser_use;
- TRACE("[%s] Parser Buffer : %p, Parser:%d\n", __func__,
- parser_buf, parser_use);
-
- memcpy(&avctx->reordered_opaque,
- (uint8_t *)s->vaddr + offset, sizeof(int64_t));
- size = sizeof(int64_t);
- memcpy(&avctx->skip_frame,
- (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
- memcpy(&buf_size, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
-
- picture->reordered_opaque = avctx->reordered_opaque;
-
- if (parser_buf && parser_use) {
- buf = parser_buf;
- } else if (buf_size > 0) {
- TRACE("[%s] not use parser, codec_id:%x\n", __func__, avctx->codec_id);
- buf = (uint8_t *)s->vaddr + offset + size;
- size += buf_size;
- } else {
- TRACE("There is no input buffer\n");
- buf = NULL;
- }
-
- memset(&avpkt, 0, sizeof(AVPacket));
- avpkt.data = buf;
- avpkt.size = buf_size;
- TRACE("packet buf:%p, size:%d\n", buf, buf_size);
-
- ret = avcodec_decode_video2(avctx, picture, &got_picture_ptr, &avpkt);
-
- TRACE("[%s] after decoding video, ret:%d\n", __func__, ret);
- if (ret < 0) {
- ERR("[%s] failed to decode video!!, ret:%d\n", __func__, ret);
- } else {
- if (ret == 0) {
- TRACE("[%s] no frame. packet size:%d\n", __func__, avpkt.size);
- }
- TRACE("decoded frame number:%d\n", avctx->frame_number);
- }
-
- memcpy((uint8_t *)s->vaddr + offset, &avctx->pix_fmt, sizeof(int));
- size = sizeof(int);
- size += qemu_serialize_rational(&avctx->time_base,
- (uint8_t *)s->vaddr + offset + size);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->width, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->height, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->has_b_frames, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->frame_number, sizeof(int));
- size += sizeof(int);
- size += qemu_serialize_rational(&avctx->sample_aspect_ratio,
- (uint8_t *)s->vaddr + offset + size);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->internal_buffer_count, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->profile, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->level, sizeof(int));
- size += sizeof(int);
- size += qemu_serialize_frame(picture, (uint8_t *)s->vaddr + offset + size);
-
- memcpy((uint8_t *)s->vaddr + offset + size, &got_picture_ptr, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
- size += sizeof(int);
-
-#if 0
- memcpy((uint8_t *)s->vaddr + offset + size, dst.data[0], numbytes);
- av_free(buffer);
-
- if (parser_buf && parser_use) {
- TRACE("[%s] Free input buffer after decoding video\n", __func__);
- TRACE("[%s] input buffer : %p, %p\n",
- __func__, avpkt.data, parser_buf);
- av_free(avpkt.data);
- s->codec_ctx[ctx_index].parser_buf = NULL;
- }
-#endif
-
- qemu_mutex_unlock(&s->codec_thread.mutex);
- TRACE("Leave, %s\n", __func__);
-
- return ret;
-}
-
-/* int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf,
- * int buf_size, const AVFrame *pict)
- */
-int qemu_avcodec_encode_video(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx = NULL;
- AVFrame *pict = NULL;
- uint8_t *inputBuf = NULL;
- int outbufSize = 0;
- int bPict = -1;
- int size = 0;
- int ret = -1;
- off_t offset;
-
- TRACE("Enter, %s\n", __func__);
- qemu_mutex_lock(&s->codec_thread.mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- pict = s->codec_ctx[ctx_index].frame;
- if (!avctx || !pict) {
- ERR("[%s] %d of Context or Frame is NULL\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->thread_mutex);
- return ret;
- }
-
- offset = s->codec_param.mmap_offset;
-
- size = sizeof(int);
- memcpy(&bPict, (uint8_t *)s->vaddr + offset, size);
- TRACE("[%s] avframe is :%d\n", __func__, bPict);
-
- if (bPict == 0) {
- memcpy(&outbufSize, (uint8_t *)s->vaddr + offset + size, size);
- size += sizeof(int);
- size +=
- qemu_deserialize_frame((uint8_t *)s->vaddr + offset + size, pict);
-
- inputBuf = (uint8_t *)s->vaddr + offset + size;
- if (!inputBuf) {
- ERR("[%s] failed to get input buffer\n", __func__);
- return ret;
- }
-
- ret = qemu_avpicture_fill((AVPicture *)pict, inputBuf, avctx->pix_fmt,
- avctx->width, avctx->height, true);
-
- if (ret < 0) {
- ERR("after avpicture_fill, ret:%d\n", ret);
- }
- TRACE("before encode video, ticks_per_frame:%d, pts:%lld\n",
- avctx->ticks_per_frame, pict->pts);
- } else {
- TRACE("flush encoded buffers\n");
- pict = NULL;
- }
-
- ret = avcodec_encode_video(avctx, (uint8_t *)s->vaddr + offset,
- outbufSize, pict);
- TRACE("encode video, ret:%d, pts:%lld, outbuf size:%d\n",
- ret, pict->pts, outbufSize);
-
- if (ret < 0) {
- ERR("failed to encode video.\n");
- }
-
- memcpy((uint8_t *)s->vaddr + offset + outbufSize, &ret, sizeof(int));
-
- qemu_mutex_unlock(&s->codec_thread.mutex);
- TRACE("Leave, %s\n", __func__);
-
- return ret;
-}
-
-/*
- * int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
- * int *frame_size_ptr, AVPacket *avpkt)
- */
-int qemu_avcodec_decode_audio(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx;
- AVPacket avpkt;
- int16_t *samples;
- int frame_size_ptr;
- uint8_t *buf;
- uint8_t *parser_buf;
- bool parser_use;
- int buf_size, outbuf_size;
- int size;
- int ret = -1;
- off_t offset;
-
- TRACE("Enter, %s\n", __func__);
-
- TRACE("Audio Context Index : %d\n", ctx_index);
- avctx = s->codec_ctx[ctx_index].avctx;
- if (!avctx) {
- ERR("[%s] %d of Context is NULL!\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->codec_thread.mutex);
- return ret;
- }
-
- if (!avctx->codec) {
- ERR("[%s] %d of Codec is NULL\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->codec_thread.mutex);
- return ret;
- }
-
- offset = s->codec_param.mmap_offset;
-
- parser_buf = s->codec_ctx[ctx_index].parser_buf;
- parser_use = s->codec_ctx[ctx_index].parser_use;
-
- memcpy(&buf_size, (uint8_t *)s->vaddr + offset, sizeof(int));
- size = sizeof(int);
- if (parser_buf && parser_use) {
- TRACE("[%s] use parser, buf:%p codec_id:%x\n",
- __func__, parser_buf, avctx->codec_id);
- buf = parser_buf;
- } else if (buf_size > 0) {
- TRACE("[%s] not use parser, codec_id:%x\n", __func__, avctx->codec_id);
- buf = (uint8_t *)s->vaddr + offset + size;
- size += buf_size;
- } else {
- TRACE("no input buffer\n");
- buf = NULL;
- }
-
- av_init_packet(&avpkt);
- avpkt.data = buf;
- avpkt.size = buf_size;
-
- frame_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
- outbuf_size = frame_size_ptr;
- samples = av_malloc(frame_size_ptr);
-
- ret = avcodec_decode_audio3(avctx, samples, &frame_size_ptr, &avpkt);
- TRACE("after decoding audio!, ret:%d\n", ret);
-
- memcpy((uint8_t *)s->vaddr + offset, &avctx->bit_rate, sizeof(int));
- size = sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->sample_rate, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->channels, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->channel_layout, sizeof(int64_t));
- size += sizeof(int64_t);
- memcpy((uint8_t *)s->vaddr + offset + size, &avctx->sub_id, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->frame_size, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size,
- &avctx->frame_number, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, samples, outbuf_size);
- size += outbuf_size;
- memcpy((uint8_t *)s->vaddr + offset + size, &frame_size_ptr, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
- size += sizeof(int);
-
- TRACE("before free input buffer and output buffer!\n");
- if (samples) {
- TRACE("release allocated audio buffer.\n");
- av_free(samples);
- samples = NULL;
- }
-
- if (parser_buf && parser_use) {
- TRACE("[%s] free parser buf\n", __func__);
- av_free(avpkt.data);
- s->codec_ctx[ctx_index].parser_buf = NULL;
- }
-
- TRACE("[%s] Leave\n", __func__);
-
- return ret;
-}
-
-int qemu_avcodec_encode_audio(SVCodecState *s, int ctx_index)
-{
- WARN("[%s] Does not support audio encoder using FFmpeg\n", __func__);
- return 0;
-}
-
-/* void av_picture_copy(AVPicture *dst, const AVPicture *src,
- * enum PixelFormat pix_fmt, int width, int height)
- */
-void qemu_av_picture_copy(SVCodecState *s, int ctx_index)
-{
- AVCodecContext *avctx = NULL;
- AVPicture dst;
- AVPicture *src = NULL;
- int numBytes = 0;
- uint8_t *buffer = NULL;
- off_t offset = 0;
-
- TRACE("Enter :%s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- src = (AVPicture *)s->codec_ctx[ctx_index].frame;
- if (!avctx && !src) {
- ERR("[%s] %d of context or frame is NULL\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->thread_mutex);
- return;
- }
-
- offset = s->codec_param.mmap_offset;
-
- numBytes = qemu_avpicture_fill(&dst, NULL, avctx->pix_fmt,
- avctx->width, avctx->height, false);
- TRACE("after avpicture_fill: %d\n", numBytes);
- if (numBytes < 0) {
- ERR("picture size:%d is wrong.\n", numBytes);
- qemu_mutex_unlock(&s->thread_mutex);
- return;
- }
-
- av_picture_copy(&dst, src, avctx->pix_fmt, avctx->width, avctx->height);
- buffer = dst.data[0];
- memcpy((uint8_t *)s->vaddr + offset, buffer, numBytes);
- TRACE("after copy image buffer from host to guest.\n");
-
- if (buffer) {
- TRACE("release allocated video frame.\n");
- av_free(buffer);
- }
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("Leave :%s\n", __func__);
-}
-
-/* AVCodecParserContext *av_parser_init(int codec_id) */
-void qemu_av_parser_init(SVCodecState *s, int ctx_index)
-{
- AVCodecParserContext *parser_ctx = NULL;
- AVCodecContext *avctx;
-
- TRACE("Enter :%s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- avctx = s->codec_ctx[ctx_index].avctx;
- if (!avctx) {
- ERR("[%s] %d of AVCodecContext is NULL!!\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->thread_mutex);
- return;
- }
-
- TRACE("before av_parser_init, codec_type:%d codec_id:%x\n",
- avctx->codec_type, avctx->codec_id);
-
- parser_ctx = av_parser_init(avctx->codec_id);
- if (parser_ctx) {
- TRACE("[%s] using parser\n", __func__);
- s->codec_ctx[ctx_index].parser_use = true;
- } else {
- TRACE("[%s] no parser\n", __func__);
- s->codec_ctx[ctx_index].parser_use = false;
- }
- s->codec_ctx[ctx_index].parser_ctx = parser_ctx;
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("[%s] Leave\n", __func__);
-}
-
-/* int av_parser_parse(AVCodecParserContext *s, AVCodecContext *avctx,
- * uint8_t **poutbuf, int *poutbuf_size,
- * const uint8_t *buf, int buf_size,
- * int64_t pts, int64_t dts)
- */
-int qemu_av_parser_parse(SVCodecState *s, int ctx_index)
-{
- AVCodecParserContext *parser_ctx = NULL;
- AVCodecContext *avctx = NULL;
- uint8_t *poutbuf;
- int poutbuf_size = 0;
- uint8_t *inbuf = NULL;
- int inbuf_size;
- int64_t pts;
- int64_t dts;
- int64_t pos;
- int size, ret = -1;
- off_t offset;
-
- TRACE("Enter %s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- parser_ctx = s->codec_ctx[ctx_index].parser_ctx;
- avctx = s->codec_ctx[ctx_index].avctx;
- if (!avctx) {
- ERR("[%s] %d of AVCodecContext is NULL\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->thread_mutex);
- return ret;
- }
-
- if (!parser_ctx) {
- ERR("[%s] %d of AVCodecParserContext is NULL\n", __func__, ctx_index);
- qemu_mutex_unlock(&s->thread_mutex);
- return ret;
- }
-
- offset = s->codec_param.mmap_offset;
-
- memcpy(&parser_ctx->pts,
- (uint8_t *)s->vaddr + offset, sizeof(int64_t));
- size = sizeof(int64_t);
- memcpy(&parser_ctx->dts,
- (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
- size += sizeof(int64_t);
- memcpy(&parser_ctx->pos,
- (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
- size += sizeof(int64_t);
- memcpy(&pts, (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
- size += sizeof(int64_t);
- memcpy(&dts, (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
- size += sizeof(int64_t);
- memcpy(&pos, (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
- size += sizeof(int64_t);
- memcpy(&inbuf_size, (uint8_t *)s->vaddr + offset + size, sizeof(int));
- size += sizeof(int);
-
- if (inbuf_size > 0) {
- inbuf = av_mallocz(inbuf_size);
- memcpy(inbuf, (uint8_t *)s->vaddr + offset + size, inbuf_size);
- } else {
- inbuf = NULL;
- INFO("input buffer size for parser is zero.\n");
- }
-
- TRACE("[%s] inbuf:%p inbuf_size :%d\n", __func__, inbuf, inbuf_size);
- ret = av_parser_parse2(parser_ctx, avctx, &poutbuf, &poutbuf_size,
- inbuf, inbuf_size, pts, dts, pos);
- TRACE("after parsing, outbuf size :%d, ret:%d\n", poutbuf_size, ret);
-
- if (poutbuf) {
- s->codec_ctx[ctx_index].parser_buf = poutbuf;
- }
-
- TRACE("[%s] inbuf : %p, outbuf : %p\n", __func__, inbuf, poutbuf);
- memcpy((uint8_t *)s->vaddr + offset, &parser_ctx->pts, sizeof(int64_t));
- size = sizeof(int64_t);
- memcpy((uint8_t *)s->vaddr + offset + size, &poutbuf_size, sizeof(int));
- size += sizeof(int);
- memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
- size += sizeof(int);
- if (poutbuf && poutbuf_size > 0) {
- memcpy((uint8_t *)s->vaddr + offset + size, poutbuf, poutbuf_size);
- } else {
- av_free(inbuf);
- }
-
-#if 0
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
- TRACE("[%s] free parser inbuf\n", __func__);
- av_free(inbuf);
- }
-#endif
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("Leave, %s\n", __func__);
-
- return ret;
-}
-
-/* void av_parser_close(AVCodecParserContext *s) */
-void qemu_av_parser_close(SVCodecState *s, int ctx_index)
-{
- AVCodecParserContext *parser_ctx;
-
- TRACE("Enter, %s\n", __func__);
- qemu_mutex_lock(&s->thread_mutex);
-
- parser_ctx = s->codec_ctx[ctx_index].parser_ctx;
- if (!parser_ctx) {
- ERR("AVCodecParserContext is NULL\n");
- qemu_mutex_unlock(&s->thread_mutex);
- return;
- }
- av_parser_close(parser_ctx);
-
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("Leave, %s\n", __func__);
-}
-
-int codec_operate(uint32_t api_index, uint32_t ctx_index, SVCodecState *s)
-{
- int ret = -1;
-
- TRACE("[%s] context : %d\n", __func__, ctx_index);
- switch (api_index) {
- /* FFMPEG API */
- case EMUL_AV_REGISTER_ALL:
- qemu_av_register_all();
- break;
- case EMUL_AVCODEC_OPEN:
- ret = qemu_avcodec_open(s);
- break;
- case EMUL_AVCODEC_CLOSE:
- ret = qemu_avcodec_close(s, ctx_index);
- qemu_av_free(s, ctx_index);
- break;
- case EMUL_AVCODEC_FLUSH_BUFFERS:
- qemu_avcodec_flush_buffers(s, ctx_index);
- break;
- case EMUL_AVCODEC_DECODE_VIDEO:
- case EMUL_AVCODEC_ENCODE_VIDEO:
- case EMUL_AVCODEC_DECODE_AUDIO:
- case EMUL_AVCODEC_ENCODE_AUDIO:
- wake_codec_worker_thread(s);
- break;
- case EMUL_AV_PICTURE_COPY:
- qemu_av_picture_copy(s, ctx_index);
- break;
- case EMUL_AV_PARSER_INIT:
- qemu_av_parser_init(s, ctx_index);
- break;
- case EMUL_AV_PARSER_PARSE:
- ret = qemu_av_parser_parse(s, ctx_index);
- break;
- case EMUL_AV_PARSER_CLOSE:
- qemu_av_parser_close(s, ctx_index);
- break;
- default:
- WARN("api index %d does not exist!.\n", api_index);
- }
- return ret;
-}
-
-static uint32_t qemu_get_mmap_offset(SVCodecState *s)
-{
- int index = 0;
-
- for (; index < AUDIO_CODEC_MEM_OFFSET_MAX; index++) {
- if (s->audio_codec_offset[index] == 0) {
- s->audio_codec_offset[index] = 1;
- break;
- }
- }
- TRACE("return mmap offset: %d\n", index);
-
- return index;
-}
-
-/*
- * Codec Device APIs
- */
-uint64_t codec_read(void *opaque, hwaddr addr, unsigned size)
-{
- SVCodecState *s = (SVCodecState *)opaque;
- uint64_t ret = 0;
-
- switch (addr) {
- case CODEC_CMD_GET_THREAD_STATE:
- qemu_mutex_lock(&s->thread_mutex);
- ret = s->codec_thread.state;
- s->codec_thread.state = 0;
- qemu_mutex_unlock(&s->thread_mutex);
- TRACE("ret: %d, thread state: %d\n", ret, s->codec_thread.state);
- qemu_irq_lower(s->dev.irq[0]);
- break;
- case CODEC_CMD_GET_VERSION:
- ret = MARU_CODEC_VERSION;
- TRACE("codec version: %d\n", ret);
- break;
- case CODEC_CMD_GET_DEVICE_MEM:
- qemu_mutex_lock(&s->thread_mutex);
- ret = s->device_mem_avail;
- if (s->device_mem_avail != 1) {
- s->device_mem_avail = 1;
- }
- qemu_mutex_unlock(&s->thread_mutex);
- break;
- case CODEC_CMD_GET_MMAP_OFFSET:
- ret = qemu_get_mmap_offset(s);
- TRACE("mem index: %d\n", ret);
- break;
- default:
- ERR("no avaiable command for read. %d\n", addr);
- }
-
- return ret;
-}
-
-void codec_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SVCodecState *s = (SVCodecState *)opaque;
-
- switch (addr) {
- case CODEC_CMD_API_INDEX:
- codec_operate(value, s->codec_param.ctx_index, s);
- break;
- case CODEC_CMD_CONTEXT_INDEX:
- s->codec_param.ctx_index = value;
- TRACE("Context Index: %d\n", s->codec_param.ctx_index);
- break;
- case CODEC_CMD_FILE_INDEX:
- s->codec_param.file_index = value;
- break;
- case CODEC_CMD_DEVICE_MEM_OFFSET:
- s->codec_param.mmap_offset = value;
- TRACE("MMAP Offset: %d\n", s->codec_param.mmap_offset);
- break;
- case CODEC_CMD_RESET_CODEC_INFO:
- qemu_reset_codec_info(s, value);
- break;
- case CODEC_CMD_SET_DEVICE_MEM:
- qemu_mutex_lock(&s->thread_mutex);
- s->device_mem_avail = value;
- qemu_mutex_unlock(&s->thread_mutex);
- break;
- case CODEC_CMD_SET_MMAP_OFFSET:
- s->codec_param.mem_index = value;
- break;
- default:
- ERR("no avaiable command for write. %d\n", addr);
- }
-}
-
-static const MemoryRegionOps codec_mmio_ops = {
- .read = codec_read,
- .write = codec_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void codec_tx_bh(void *opaque)
-{
- SVCodecState *s = (SVCodecState *)opaque;
-
- int ctx_index;
- AVCodecContext *ctx;
-
- ctx_index = s->codec_param.ctx_index;
- ctx = s->codec_ctx[ctx_index].avctx;
-
- TRACE("Enter, %s\n", __func__);
-
- /* raise irq as soon as a worker thread had finished a job*/
- if (s->codec_thread.state) {
- TRACE("raise codec irq. state:%d, codec:%d\n",
- s->codec_thread.state, ctx->codec_type);
- qemu_irq_raise(s->dev.irq[0]);
- }
-
- TRACE("Leave, %s\n", __func__);
-}
-
-static int codec_initfn(PCIDevice *dev)
-{
- SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
- uint8_t *pci_conf = s->dev.config;
-
- INFO("[%s] device init\n", __func__);
-
- memset(&s->codec_param, 0, sizeof(SVCodecParam));
-
- qemu_mutex_init(&s->thread_mutex);
- codec_thread_init(s);
- s->tx_bh = qemu_bh_new(codec_tx_bh, s);
-
- pci_config_set_interrupt_pin(pci_conf, 1);
-
- memory_region_init_ram(&s->vram, OBJECT(s), "codec.ram", MARU_CODEC_MEM_SIZE);
- s->vaddr = memory_region_get_ram_ptr(&s->vram);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &codec_mmio_ops, s,
- "codec-mmio", MARU_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);
-
- return 0;
-}
-
-static void codec_exitfn(PCIDevice *dev)
-{
- SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
- INFO("[%s] device exit\n", __func__);
-
- qemu_bh_delete(s->tx_bh);
-
- memory_region_destroy(&s->vram);
- memory_region_destroy(&s->mmio);
-}
-
-int codec_init(PCIBus *bus)
-{
- INFO("[%s] device create\n", __func__);
- pci_create_simple(bus, -1, MARU_CODEC_DEV_NAME);
- return 0;
-}
-
-static void codec_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = codec_initfn;
- k->exit = codec_exitfn;
- k->vendor_id = PCI_VENDOR_ID_TIZEN;
- k->device_id = PCI_DEVICE_ID_VIRTUAL_CODEC;
- k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
- dc->desc = "Virtual Codec device for Tizen emulator";
-}
-
-static TypeInfo codec_info = {
- .name = MARU_CODEC_DEV_NAME,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(SVCodecState),
- .class_init = codec_class_init,
-};
-
-static void codec_register_types(void)
-{
- type_register_static(&codec_info);
-}
-
-type_init(codec_register_types)
+++ /dev/null
-/*
- * Virtual Codec device
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Kitae Kim <kt920.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include "hw/hw.h"
-#include "sysemu/kvm.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_ids.h"
-#include "qemu/thread.h"
-#include "debug_ch.h"
-#include "maru_device_ids.h"
-
-#include <libavformat/avformat.h>
-
-#define CODEC_CONTEXT_MAX 1024
-#define VIDEO_CODEC_MEM_OFFSET_MAX 16
-#define AUDIO_CODEC_MEM_OFFSET_MAX 64
-
-#define CODEC_MAX_THREAD 10
-
-/*
- * Codec Device Structures
- */
-typedef struct _SVCodecParam {
- uint32_t api_index;
- uint32_t ctx_index;
- uint32_t file_index;
- uint32_t mem_index;
- uint32_t mmap_offset;
-} SVCodecParam;
-
-typedef struct _SVCodecContext {
- AVCodecContext *avctx;
- AVFrame *frame;
- AVCodecParserContext *parser_ctx;
- uint8_t *parser_buf;
- uint8_t parser_use;
- uint8_t avctx_use;
- uint32_t file_index;
- uint32_t mem_index;
-} SVCodecContext;
-
-typedef struct _SVCodecThreadPool {
- QemuThread *wrk_thread;
- QemuMutex mutex;
- QemuCond cond;
- uint32_t state;
- uint8_t isrunning;
-} SVCodecThreadPool;
-
-typedef struct _SVCodecState {
- PCIDevice dev;
-
- uint8_t *vaddr;
- MemoryRegion vram;
- MemoryRegion mmio;
-
- QEMUBH *tx_bh;
- QemuMutex thread_mutex;
-
- SVCodecContext codec_ctx[CODEC_CONTEXT_MAX];
- SVCodecParam codec_param;
- SVCodecThreadPool codec_thread;
- uint8_t audio_codec_offset[AUDIO_CODEC_MEM_OFFSET_MAX];
- uint8_t device_mem_avail;
- uint8_t isrunning;
-} SVCodecState;
-
-enum codec_io_cmd {
- CODEC_CMD_API_INDEX = 0x00,
- CODEC_CMD_CONTEXT_INDEX = 0x04,
- CODEC_CMD_FILE_INDEX = 0x08,
- CODEC_CMD_DEVICE_MEM_OFFSET = 0x0c,
- CODEC_CMD_GET_THREAD_STATE = 0x10,
- CODEC_CMD_GET_VERSION = 0x14,
- CODEC_CMD_GET_DEVICE_MEM = 0x18,
- CODEC_CMD_SET_DEVICE_MEM = 0x1C,
- CODEC_CMD_GET_MMAP_OFFSET = 0x20,
- CODEC_CMD_SET_MMAP_OFFSET = 0x24,
- CODEC_CMD_RESET_CODEC_INFO = 0x28,
-};
-
-enum {
- EMUL_AV_REGISTER_ALL = 1,
- EMUL_AVCODEC_OPEN,
- EMUL_AVCODEC_CLOSE,
- EMUL_AVCODEC_FLUSH_BUFFERS,
- EMUL_AVCODEC_DECODE_VIDEO,
- EMUL_AVCODEC_ENCODE_VIDEO,
- EMUL_AVCODEC_DECODE_AUDIO,
- EMUL_AVCODEC_ENCODE_AUDIO,
- EMUL_AV_PICTURE_COPY,
- EMUL_AV_PARSER_INIT,
- EMUL_AV_PARSER_PARSE,
- EMUL_AV_PARSER_CLOSE,
-};
-
-
-/*
- * Codec Thread Functions
- */
-void codec_thread_init(SVCodecState *s);
-void codec_thread_exit(SVCodecState *s);
-void *codec_worker_thread(void *opaque);
-void wake_codec_worker_thread(SVCodecState *s);
-int decode_codec(SVCodecState *s);
-int encode_codec(SVCodecState *s);
-
-/*
- * Codec Device Functions
- */
-int codec_init(PCIBus *bus);
-uint64_t codec_read(void *opaque, hwaddr addr,
- unsigned size);
-void codec_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size);
-int codec_operate(uint32_t api_index, uint32_t ctx_index,
- SVCodecState *state);
-
-/*
- * Codec Helper Functions
- */
-void qemu_parser_init(SVCodecState *s, int ctx_index);
-void qemu_codec_close(SVCodecState *s, uint32_t value);
-void qemu_get_codec_ver(SVCodecState *s);
-void qemu_reset_codec_info(SVCodecState *s, uint32_t value);
-
-/*
- * FFMPEG Functions
- */
-void qemu_av_register_all(void);
-int qemu_avcodec_open(SVCodecState *s);
-int qemu_avcodec_close(SVCodecState *s, int ctx_index);
-int qemu_avcodec_alloc_context(SVCodecState *s);
-void qemu_avcodec_flush_buffers(SVCodecState *s, int ctx_index);
-int qemu_avcodec_decode_video(SVCodecState *s, int ctx_index);
-int qemu_avcodec_encode_video(SVCodecState *s, int ctx_index);
-int qemu_avcodec_decode_audio(SVCodecState *s, int ctx_index);
-int qemu_avcodec_encode_audio(SVCodecState *s, int ctx_index);
-void qemu_av_picture_copy(SVCodecState *s, int ctx_index);
-void qemu_av_parser_init(SVCodecState *s, int ctx_index);
-int qemu_av_parser_parse(SVCodecState *s, int ctx_index);
-void qemu_av_parser_close(SVCodecState *s, int ctx_index);
-int qemu_avcodec_get_buffer(AVCodecContext *context, AVFrame *picture);
-void qemu_avcodec_release_buffer(AVCodecContext *context, AVFrame *picture);
-void qemu_av_free(SVCodecState *s, int ctx_index);
#include "sysemu/sysemu.h"
#include "debug_ch.h"
-#include "sdb_noti_server.h"
+#include "util/sdb_noti_server.h"
/* define debug channel */
MULTI_DEBUG_CHANNEL(tizen, maru_pm);
+++ /dev/null
-/*
- * Maru USB Touchscreen Device
- * Based on hw/usb-wacom.c:
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * HyunJun Son
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#include "maru_usb_touchscreen.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(qemu, usb_touchscreen);
-
-
-#define MAX_TOUCH_EVENT_CNT 128
-
-//lock for between communication thread and main thread
-static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static QTAILQ_HEAD(, TouchEventEntry) events_queue =
- QTAILQ_HEAD_INITIALIZER(events_queue);
-
-static unsigned int event_cnt = 0;
-static unsigned int _processed_buf_cnt = 0;
-static TouchEventEntry _event_buf[MAX_TOUCH_EVENT_CNT];
-
-/**
- * @brief : qemu touch(host mouse) event handler
- * @param opaque : state of device
- * @param x : X-axis value
- * @param y : Y-axis value
- * @param z : event id for multiple touch
- */
-static void usb_touchscreen_event(void *opaque, int x, int y, int z, int buttons_state)
-{
- TouchEventEntry *te;
- USBTouchscreenState *s = opaque;
-
- pthread_mutex_lock(&event_mutex);
- if (event_cnt >= MAX_TOUCH_EVENT_CNT) {
- pthread_mutex_unlock(&event_mutex);
- INFO("full touch event queue, lose event\n", event_cnt);
- return;
- }
-
- //using prepared memory
- te = &(_event_buf[_processed_buf_cnt % MAX_TOUCH_EVENT_CNT]);
- _processed_buf_cnt++;
-
- /* mouse event is copied into the queue */
- te->index = ++event_cnt;
- te->queue_packet.x = x;
- te->queue_packet.y = y;
- te->queue_packet.z = z;
- te->queue_packet.state = buttons_state;
-
- QTAILQ_INSERT_TAIL(&events_queue, te, node);
- s->changed = 1;
- pthread_mutex_unlock(&event_mutex);
-
- TRACE("touch event (%d) : x=%d, y=%d, z=%d, state=%d\n", te->index, x, y, z, buttons_state);
-}
-
-/**
- * @brief : fill the usb packet
- * @param s : state of device
- * @param buf : usb packet
- * @param len : size of packet
- */
-static int usb_touchscreen_poll(USBTouchscreenState *s, uint8_t *buf, int len)
-{
- USBEmulTouchscreenPacket *packet = (USBEmulTouchscreenPacket *)buf;
-
- if (s->mouse_grabbed == 0) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_touchscreen_event, s, 1, "QEMU USB touchscreen");
- qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
- }
-
- if (len < EMUL_TOUCHSCREEN_PACKET_LEN) {
- return 0;
- }
-
- packet->x = s->dx & 0xffff;
- packet->y = s->dy & 0xffff;
- packet->z = s->dz & 0xffff;
-
- if (s->buttons_state == 0) {
- packet->state = 0;
- } else {
- packet->state = 1;
- }
-
- return EMUL_TOUCHSCREEN_PACKET_LEN;
-}
-
-static void usb_touchscreen_handle_reset(USBDevice *dev)
-{
- USBTouchscreenState *s = (USBTouchscreenState *) dev;
-
- pthread_mutex_lock(&event_mutex);
-
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- s->buttons_state = 0;
-
- event_cnt = 0;
- _processed_buf_cnt = 0;
-
- pthread_mutex_unlock(&event_mutex);
-}
-
-static void usb_touchscreen_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- usb_desc_handle_control(dev, p, request, value, index, length, data);
-}
-
-/**
- * @brief : call by uhci frame timer
- * @param dev : state of device
- * @param p : usb packet
- */
-static void usb_touchscreen_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBTouchscreenState *s = (USBTouchscreenState *) dev;
- uint8_t buf[p->iov.size];
- int len = 0;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- pthread_mutex_lock(&event_mutex);
-
- if (s->changed == 0) {
- pthread_mutex_unlock(&event_mutex);
- TRACE("USB_RET_NAK\n");
- }
-
- if (event_cnt != 0) {
- if (!QTAILQ_EMPTY(&events_queue)) {
- TouchEventEntry *te = QTAILQ_FIRST(&events_queue);
-
- s->dx = te->queue_packet.x;
- s->dy = te->queue_packet.y;
- s->dz = te->queue_packet.z;
- s->buttons_state = te->queue_packet.state;
-
- QTAILQ_REMOVE(&events_queue, te, node);
- event_cnt--;
- TRACE("processed touch event (%d) : x=%d, y=%d, z=%d, state=%d\n",
- te->index, s->dx, s->dy, s->dz, s->buttons_state);
-
- if (QTAILQ_EMPTY(&events_queue)) {
- s->changed = 0;
- TRACE("processed all touch events (%d)\n", event_cnt);
- }
- }
- } else {
- s->changed = 0;
- }
-
- pthread_mutex_unlock(&event_mutex);
-
- memset(buf, 0, sizeof(buf));
- len = usb_touchscreen_poll(s, buf, p->iov.size); //write event to packet
- usb_packet_copy(p, buf, len);
- break;
- }
- /* Fall through */
- case USB_TOKEN_OUT:
- default:
- TRACE("USB_RET_STALL\n");
- break;
- }
-}
-
-static void usb_touchscreen_handle_destroy(USBDevice *dev)
-{
- USBTouchscreenState *s = (USBTouchscreenState *) dev;
-
- if (s->mouse_grabbed == 1) {
- qemu_remove_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 0;
- }
-}
-
-/**
- * @brief : initialize a touchscreen device
- * @param opaque : state of device
- */
-static int usb_touchscreen_initfn(USBDevice *dev)
-{
- USBTouchscreenState *s = DO_UPCAST(USBTouchscreenState, dev, dev);
- usb_desc_init(dev);
-
- pthread_mutex_lock(&event_mutex);
- s->changed = 1;
- pthread_mutex_unlock(&event_mutex);
-
- return 0;
-}
-
-/**
- * @brief : remove mouse handlers before loading
- * @param opaque : state of device
- */
-static int touchscreen_pre_load(void *opaque)
-{
- USBTouchscreenState *s = (USBTouchscreenState *)opaque;
-
- if (s->eh_entry) {
- qemu_remove_mouse_event_handler(s->eh_entry);
- }
-
- return 0;
-}
-
-static int touchscreen_post_load(void *opaque, int version_id)
-{
- USBTouchscreenState *s = (USBTouchscreenState *)opaque;
-
- pthread_mutex_lock(&event_mutex);
- s->changed = 1;
- pthread_mutex_unlock(&event_mutex);
-
- if (s->mouse_grabbed == 1) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_touchscreen_event, s, 1, "QEMU USB touchscreen");
- qemu_activate_mouse_event_handler(s->eh_entry);
- }
-
- return 0;
-}
-
-static VMStateDescription vmsd_usbdevice = {
- .name = "maru-touchscreen-usbdevice",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField []) {
- VMSTATE_UINT8(addr, USBDevice),
- VMSTATE_INT32(state, USBDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription vmsd = {
- .name = "maru-touchscreen",
- .version_id = 2,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .pre_load = touchscreen_pre_load,
- .post_load = touchscreen_post_load,
- .fields = (VMStateField []) {
- VMSTATE_STRUCT(dev, USBTouchscreenState, 1, vmsd_usbdevice, USBDevice),
- VMSTATE_INT32(dx, USBTouchscreenState),
- VMSTATE_INT32(dy, USBTouchscreenState),
- VMSTATE_INT32(dz, USBTouchscreenState),
- VMSTATE_INT32(buttons_state, USBTouchscreenState),
- VMSTATE_INT8(mouse_grabbed, USBTouchscreenState),
- VMSTATE_INT8(changed, USBTouchscreenState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void usb_touchscreen_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->handle_reset = usb_touchscreen_handle_reset;
- uc->handle_control = usb_touchscreen_handle_control;
- uc->handle_data = usb_touchscreen_handle_data;
- uc->handle_destroy = usb_touchscreen_handle_destroy;
- uc->init = usb_touchscreen_initfn;
- uc->product_desc = "Maru USB Touchscreen";
- uc->usb_desc = &desc_touchscreen;
- dc->vmsd = &vmsd;
- dc->desc = "Maru USB Touchscreen";
-}
-
-static TypeInfo touchscreen_info = {
- .name = "usb-maru-touchscreen",
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBTouchscreenState),
- .class_init = usb_touchscreen_class_initfn,
-};
-
-/**
- * @brief : register a touchscreen device
- */
-static void usb_touchscreen_register_types(void)
-{
- type_register_static(&touchscreen_info);
- usb_legacy_register("usb-maru-touchscreen", "maru-touchscreen", NULL);
-}
-
-type_init(usb_touchscreen_register_types)
+++ /dev/null
-/*
- * Maru USB Touchscreen Device
- * Based on hw/usb-wacom.c:
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- * HyunJun Son
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#ifndef MARU_TOUCH_H_
-#define MARU_TOUCH_H_
-
-#include <pthread.h>
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-
-typedef struct USBTouchscreenState {
- USBDevice dev;
- QEMUPutMouseEntry *eh_entry;
-
- int32_t dx, dy, dz, buttons_state;
- int8_t mouse_grabbed;
- int8_t changed;
-} USBTouchscreenState;
-
-/* This structure must match the kernel definitions */
-typedef struct USBEmulTouchscreenPacket {
- uint16_t x, y, z;
- uint8_t state;
-} USBEmulTouchscreenPacket;
-
-
-#define EMUL_TOUCHSCREEN_PACKET_LEN 7
-#define TOUCHSCREEN_RESOLUTION_X 5040
-#define TOUCHSCREEN_RESOLUTION_Y 3780
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
- [STR_PRODUCT] = "Maru USB Touchscreen",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_touchscreen = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- 0x21, /* u8 bDescriptorType */
- 0x01, 0x10, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- 0x22, /* u8 type: Report */
- 0x6e, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescDevice desc_device_touchscreen = {
- .bcdUSB = 0x0110,
- .bMaxPacketSize0 = EMUL_TOUCHSCREEN_PACKET_LEN + 1,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = 0x80,
- .bMaxPower = 40,
- .nif = 1,
- .ifs = &desc_iface_touchscreen,
- },
- },
-};
-
-static const USBDesc desc_touchscreen = {
- .id = {
- .idVendor = 0x056a,
- .idProduct = 0x0000,
- .bcdDevice = 0x0010,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_touchscreen,
- .str = desc_strings,
-};
-
-typedef struct TouchEventEntry {
- USBEmulTouchscreenPacket queue_packet;
- int index;
-
- /* used internally by qemu for handling mice */
- QTAILQ_ENTRY(TouchEventEntry) node;
-} TouchEventEntry;
-
-#endif /* MARU_TOUCH_H_ */
+++ /dev/null
-/*
- * Virtio EmulatorStatusMedium Device
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "maru_device_ids.h"
-#include "maru_virtio_esm.h"
-#include "skin/maruskin_server.h"
-#include "emul_state.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-esm);
-
-
-#define SYSTEM_MODE_LAYER 1
-#define USER_MODE_LAYER 0
-static uint8_t boot_complete;
-
-struct progress_info {
- char mode;
- uint16_t percentage;
-};
-
-static VirtQueueElement elem;
-struct progress_info progress;
-
-static void virtio_esm_handle(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOESM *vesm = VIRTIO_ESM(vdev);
- int index = 0;
-
- TRACE("virtqueue handler.\n");
- if (virtio_queue_empty(vesm->vq)) {
- INFO("virtqueue is empty.\n");
- return;
- }
-
- // Get a queue buffer.
- index = virtqueue_pop(vq, &elem);
- TRACE("virtqueue pop. index: %d\n", index);
-
- TRACE("virtio element out number : %d\n", elem.out_num);
- if (elem.out_num != 1) {
- ERR("virtio element out number is wierd.\n");
- }
- else {
- TRACE("caramis elem.out_sg[0].iov_len : %x\n", elem.out_sg[0].iov_len);
- TRACE("caramis elem.out_sg[0].iov_base : %x\n", elem.out_sg[0].iov_base);
- if (elem.out_sg[0].iov_len != 4) {
- ERR("out lenth is wierd.\n");
- }
- else {
- progress = *((struct progress_info*)elem.out_sg[0].iov_base);
- TRACE("Boot up progress is [%u] percent done at %s.\n",
- progress.percentage,
- progress.mode == 's' || progress.mode == 'S' ? "system mode" : "user mode");
-
- /* notify to skin */
- if (progress.mode == 's' || progress.mode == 'S') {
- if (progress.percentage >= 100) {
- boot_complete |= (1 << SYSTEM_MODE_LAYER);
- }
-
- notify_booting_progress(SYSTEM_MODE_LAYER, progress.percentage);
- } else {
- if (progress.percentage >= 100) {
- boot_complete |= (1 << USER_MODE_LAYER);
- }
-
- notify_booting_progress(USER_MODE_LAYER, progress.percentage);
- }
-
- /* booting complete check */
- if ((boot_complete & (1 << SYSTEM_MODE_LAYER)) &&
- (boot_complete & (1 << USER_MODE_LAYER))) {
- set_emulator_condition(BOOT_COMPLETED);
- }
- }
- }
-
- // There is no data to copy into guest.
- virtqueue_push(vesm->vq, &elem, 0);
- virtio_notify(&vesm->vdev, vesm->vq);
-}
-
-static uint32_t virtio_esm_get_features(VirtIODevice *vdev, uint32_t feature)
-{
- TRACE("virtio_esm_get_features.\n");
- return feature;
-}
-
-static void virtio_esm_reset(VirtIODevice* vdev)
-{
- TRACE("virtio_esm_reset.\n");
-
- progress.mode = '\0';
- progress.percentage = 0;
-}
-
-
-static void virtio_esm_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOESM *vesm = VIRTIO_ESM(dev);
-
- INFO("initialize virtio-esm device\n");
- virtio_init(vdev, "virtio-esm", VIRTIO_ID_ESM, 0);
-
- vesm->vq = virtio_add_queue(vdev, 1, virtio_esm_handle);
-
- virtio_esm_reset(vdev);
-}
-
-static void virtio_esm_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- INFO("destroy device\n");
- virtio_cleanup(vdev);
-}
-
-static void virtio_esm_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->realize = virtio_esm_device_realize;
- vdc->unrealize = virtio_esm_device_unrealize;
- vdc->get_features = virtio_esm_get_features;
- // This device is no need to reset.
- //vdc->reset = virtio_esm_reset;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_ESM,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOESM),
- .class_init = virtio_esm_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
+++ /dev/null
-/*
- * Virtio EmulatorStatusMedium Device
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef MARU_VIRTIO_ESM_H_
-#define MARU_VIRTIO_ESM_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "hw/virtio/virtio.h"
-
-#define TYPE_VIRTIO_ESM "virtio-esm-device"
-#define VIRTIO_ESM(obj) \
- OBJECT_CHECK(VirtIOESM, (obj), TYPE_VIRTIO_ESM)
-
-typedef struct VirtIOEmulatorStatusMedium {
- VirtIODevice vdev;
- VirtQueue *vq;
- DeviceState *qdev;
-} VirtIOESM;
-
-VirtIODevice *virtio_esm_init(DeviceState *dev);
-
-void virtio_esm_exit(VirtIODevice *vdev);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MARU_VIRTIO_ESM_H_ */
+++ /dev/null
-/*
- * Virtio EmulatorVirtualDeviceInterface Device
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * DaiYoung Kim <daiyoung777.kim.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <pthread.h>
-
-#include "maru_device_ids.h"
-#include "maru_virtio_evdi.h"
-#include "debug_ch.h"
-#include "ecs/ecs.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-evdi);
-
-#define EVDI_DEVICE_NAME "virtio-evdi"
-
-enum {
- IOTYPE_INPUT = 0,
- IOTYPE_OUTPUT = 1
-};
-
-
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif
-
-
-VirtIOEVDI* vio_evdi;
-
-//
-
-typedef struct MsgInfo
-{
- msg_info info;
- QTAILQ_ENTRY(MsgInfo) next;
-}MsgInfo;
-
-static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) evdi_recv_msg_queue =
- QTAILQ_HEAD_INITIALIZER(evdi_recv_msg_queue);
-
-//
-
-typedef struct EvdiBuf {
- VirtQueueElement elem;
-
- QTAILQ_ENTRY(EvdiBuf) next;
-} EvdiBuf;
-
-static QTAILQ_HEAD(EvdiMsgHead , EvdiBuf) evdi_in_queue =
- QTAILQ_HEAD_INITIALIZER(evdi_in_queue);
-
-
-static pthread_mutex_t recv_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-bool send_to_evdi(const uint32_t route, char* data, const uint32_t len)
-{
- int size;
- int left = len;
- int count = 0;
- char* readptr = data;
-
- if(vio_evdi == NULL) {
- ERR("EVDI is not initialized\n");
- return false;
- }
-
- if (unlikely(!virtio_queue_ready(vio_evdi->rvq))) {
- ERR("virtio queue is not ready\n");
- return false;
- }
-
- while (left > 0)
- {
- MsgInfo* _msg = (MsgInfo*) malloc(sizeof(MsgInfo));
- if (!_msg)
- return false;
-
- memset(&_msg->info, 0, sizeof(msg_info));
-
- size = min(left, __MAX_BUF_SIZE);
- memcpy(_msg->info.buf, readptr, size);
- readptr += size;
- _msg->info.use = size;
- _msg->info.index = count;
-
- pthread_mutex_lock(&recv_buf_mutex);
-
- QTAILQ_INSERT_TAIL(&evdi_recv_msg_queue, _msg, next);
-
- pthread_mutex_unlock(&recv_buf_mutex);
-
- left -= size;
- count ++;
- }
-
- qemu_bh_schedule(vio_evdi->bh);
-
- return true;
-}
-
-
-static void flush_evdi_recv_queue(void)
-{
- int index;
-
- if (unlikely(!virtio_queue_ready(vio_evdi->rvq))) {
- INFO("virtio queue is not ready\n");
- return;
- }
-
- if (unlikely(virtio_queue_empty(vio_evdi->rvq))) {
- TRACE("virtqueue is empty\n");
- return;
- }
-
-
- pthread_mutex_lock(&recv_buf_mutex);
-
- while (!QTAILQ_EMPTY(&evdi_recv_msg_queue))
- {
- MsgInfo* msginfo = QTAILQ_FIRST(&evdi_recv_msg_queue);
- if (!msginfo)
- break;
-
- VirtQueueElement elem;
- index = virtqueue_pop(vio_evdi->rvq, &elem);
- if (index == 0)
- {
- //ERR("unexpected empty queue");
- break;
- }
-
- //INFO(">> virtqueue_pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
-
- memset(elem.in_sg[0].iov_base, 0, elem.in_sg[0].iov_len);
- memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct msg_info));
-
- //INFO(">> send to guest count = %d, use = %d, msg = %s, iov_len = %d \n",
- // ++g_cnt, msginfo->info.use, msginfo->info.buf, elem.in_sg[0].iov_len);
-
- virtqueue_push(vio_evdi->rvq, &elem, sizeof(msg_info));
- virtio_notify(&vio_evdi->vdev, vio_evdi->rvq);
-
- QTAILQ_REMOVE(&evdi_recv_msg_queue, msginfo, next);
- if (msginfo)
- free(msginfo);
- }
-
- pthread_mutex_unlock(&recv_buf_mutex);
-
-}
-
-
-static void virtio_evdi_recv(VirtIODevice *vdev, VirtQueue *vq)
-{
- flush_evdi_recv_queue();
-}
-
-static void virtio_evdi_send(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOEVDI *vevdi = (VirtIOEVDI *)vdev;
- int index = 0;
- struct msg_info _msg;
-
- if (virtio_queue_empty(vevdi->svq)) {
- INFO("<< virtqueue is empty.\n");
- return;
- }
-
- VirtQueueElement elem;
-
- while ((index = virtqueue_pop(vq, &elem))) {
-
- //INFO("<< virtqueue pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
-
- //INFO("<< use=%d, iov_len = %d\n", _msg.use, elem.out_sg[0].iov_len);
-
- memset(&_msg, 0x00, sizeof(_msg));
- memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
-
- //INFO("<< recv from guest len = %d, msg = %s \n", _msg.use, _msg.buf);
-
- send_injector_ntf(_msg.buf, _msg.use);
- }
-
- virtqueue_push(vq, &elem, sizeof(VirtIOEVDI));
- virtio_notify(&vio_evdi->vdev, vq);
-}
-
-static uint32_t virtio_evdi_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_evdi_get_features.\n");
- return 0;
-}
-
-static void maru_evdi_bh(void *opaque)
-{
- flush_evdi_recv_queue();
-}
-
-static void virtio_evdi_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vio_evdi = VIRTIO_EVDI(dev);
- if (vio_evdi == NULL) {
- ERR("failed to initialize evdi device\n");
- return;
- }
-
- INFO("initialize evdi device\n");
-
- virtio_init(vdev, TYPE_VIRTIO_EVDI, VIRTIO_ID_EVDI, 0); //EVDI_DEVICE_NAME
-
- vio_evdi->rvq = virtio_add_queue(&vio_evdi->vdev, 256, virtio_evdi_recv);
- vio_evdi->svq = virtio_add_queue(&vio_evdi->vdev, 256, virtio_evdi_send);
-
- vio_evdi->bh = qemu_bh_new(maru_evdi_bh, vio_evdi);
-
-}
-
-static void virtio_evdi_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- INFO("destroy evdi device\n");
-
- if (vio_evdi->bh) {
- qemu_bh_delete(vio_evdi->bh);
- }
-
- virtio_cleanup(vdev);
-}
-
-static void virtio_evdi_reset(VirtIODevice *vdev)
-{
- TRACE("virtio_evdi_reset.\n");
-}
-
-
-static void virtio_evdi_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->realize = virtio_evdi_realize;
- vdc->unrealize = virtio_evdi_unrealize;
- vdc->get_features = virtio_evdi_get_features;
- vdc->reset = virtio_evdi_reset;
-}
-
-
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_EVDI,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOEVDI),
- .class_init = virtio_evdi_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
+++ /dev/null
-/*
- * maru_virtio_evdi.h
- *
- * Created on: 2013. 3. 30.
- * Author: dykim
- */
-
-#ifndef MARU_VIRTIO_EVDI_H_
-#define MARU_VIRTIO_EVDI_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "hw/virtio/virtio.h"
-
-/* device protocol */
-
-#define __MAX_BUF_SIZE 1024
-
-enum
-{
- route_qemu = 0,
- route_control_server = 1,
- route_monitor = 2,
- route_ij = 3
-};
-
-typedef unsigned int CSCliSN;
-
-typedef struct msg_info {
- char buf[__MAX_BUF_SIZE];
-
- uint32_t route;
- uint32_t use;
- uint16_t count;
- uint16_t index;
-
- CSCliSN cclisn;
-}msg_info;
-
-/* device protocol */
-
-typedef struct VirtIOEVDI{
- VirtIODevice vdev;
- VirtQueue *rvq;
- VirtQueue *svq;
- DeviceState *qdev;
-
- QEMUBH *bh;
-} VirtIOEVDI;
-
-
-
-#define TYPE_VIRTIO_EVDI "virtio-evdi-device"
-#define VIRTIO_EVDI(obj) \
- OBJECT_CHECK(VirtIOEVDI, (obj), TYPE_VIRTIO_EVDI)
-
-//VirtIODevice *virtio_evdi_init(DeviceState *dev);
-
-//void virtio_evdi_exit(VirtIODevice *vdev);
-bool send_to_evdi(const uint32_t route, char* data, const uint32_t len);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* MARU_VIRTIO_EVDI_H_ */
+++ /dev/null
-/*
- * Maru Virtio HW Key Device
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#include <pthread.h>
-#include "emul_state.h"
-#include "maru_virtio_hwkey.h"
-#include "maru_device_ids.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(qemu, hwkey);
-
-#define DEVICE_NAME "virtio-hwkey"
-#define MAX_BUF_COUNT 64
-static int vqidx;
-/*
- * HW key event queue
- */
-typedef struct HwKeyEventEntry {
- unsigned int index;
- EmulHWKeyEvent hwkey;
-
- QTAILQ_ENTRY(HwKeyEventEntry) node;
-} HwKeyEventEntry;
-
-/* the maximum number of HW key event that can be put into a queue */
-#define MAX_HWKEY_EVENT_CNT 64
-
-static HwKeyEventEntry _events_buf[MAX_HWKEY_EVENT_CNT];
-static QTAILQ_HEAD(, HwKeyEventEntry) events_queue =
- QTAILQ_HEAD_INITIALIZER(events_queue);
-
-static unsigned int event_ringbuf_cnt; /* _events_buf */
-static unsigned int event_queue_cnt; /* events_queue */
-
-/*
- * VirtQueueElement queue
- */
-typedef struct ElementEntry {
- unsigned int el_index;
- unsigned int sg_index;
- VirtQueueElement elem;
-
- QTAILQ_ENTRY(ElementEntry) node;
-} ElementEntry;
-
-static QTAILQ_HEAD(, ElementEntry) elem_queue =
- QTAILQ_HEAD_INITIALIZER(elem_queue);
-
-static unsigned int elem_ringbuf_cnt; /* _elem_buf */
-static unsigned int elem_queue_cnt; /* elem_queue */
-
-VirtIOHWKey *vhk;
-VirtQueueElement elem_vhk;
-
-/* lock for between communication thread and IO thread */
-static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void maru_hwkey_event(int event_type, int keycode)
-{
- HwKeyEventEntry *entry = NULL;
-
- if (!vhk) {
- INFO("Hwkey device can not be used.\n");
- return;
- }
-
- if (unlikely(event_queue_cnt >= MAX_HWKEY_EVENT_CNT)) {
- INFO("full hwkey event queue, lose event\n", event_queue_cnt);
-
- qemu_bh_schedule(vhk->bh);
- return;
- }
-
- entry = &(_events_buf[event_ringbuf_cnt % MAX_HWKEY_EVENT_CNT]);
-
- /* hwkey event is copied into the queue */
- entry->hwkey.keycode = keycode;
- entry->hwkey.event_type = event_type;
-
- pthread_mutex_lock(&event_mutex);
-
- event_ringbuf_cnt++;
-
- /* 1 ~ */
- entry->index = ++event_queue_cnt;
-
- QTAILQ_INSERT_TAIL(&events_queue, entry, node);
-
- pthread_mutex_unlock(&event_mutex);
-
- /* call maru_virtio_hwkey_notify */
- qemu_bh_schedule(vhk->bh);
-
- TRACE("hwkey event (%d) : keycode=%d, event_type=%d\n",
- entry->index, entry->hwkey.keycode, entry->hwkey.event_type);
-}
-
-static void maru_virtio_hwkey_handle(VirtIODevice *vdev, VirtQueue *vq)
-{
- int virt_sg_index = 0;
-
- TRACE("maru_virtio_hwkey_handle\n");
-
- if (unlikely(virtio_queue_empty(vhk->vq))) {
- TRACE("virtqueue is empty\n");
- return;
- }
- /* Get a queue buffer which is written by guest side. */
- do {
- virt_sg_index = virtqueue_pop(vq, &elem_vhk);
- TRACE("virtqueue pop.\n");
- } while (virt_sg_index < MAX_BUF_COUNT);
-}
-
-void maru_virtio_hwkey_notify(void)
-{
- HwKeyEventEntry *event_entry = NULL;
-
- TRACE("maru_virtio_hwkey_notify\n");
-
- if (unlikely(!virtio_queue_ready(vhk->vq))) {
- ERR("virtio queue is not ready\n");
- return;
- }
-
- while (true) {
- if (event_queue_cnt == 0) {
- TRACE("no event\n");
- break;
- }
-
- /* get hwkey event from host queue */
- event_entry = QTAILQ_FIRST(&events_queue);
-
- printf("keycode=%d, event_type=%d, event_queue_cnt=%d, vqidx=%d\n",
- event_entry->hwkey.keycode, event_entry->hwkey.event_type,
- event_queue_cnt, vqidx);
-
- /* copy event into virtio buffer */
- memcpy(elem_vhk.in_sg[vqidx++].iov_base, &(event_entry->hwkey),
- sizeof(EmulHWKeyEvent));
- if (vqidx == MAX_BUF_COUNT) {
- vqidx = 0;
- }
-
- virtqueue_push(vhk->vq, &elem_vhk, sizeof(EmulHWKeyEvent));
- virtio_notify(&vhk->vdev, vhk->vq);
-
- pthread_mutex_lock(&event_mutex);
-
- /* remove host event */
- QTAILQ_REMOVE(&events_queue, event_entry, node);
- event_queue_cnt--;
-
- pthread_mutex_unlock(&event_mutex);
- }
-}
-
-static uint32_t virtio_hwkey_get_features(
- VirtIODevice *vdev, uint32_t request_features)
-{
- return request_features;
-}
-
-static void maru_hwkey_bh(void *opaque)
-{
- maru_virtio_hwkey_notify();
-}
-
-static void virtio_hwkey_device_realize(DeviceState *dev, Error **errp)
-{
- INFO("initialize the hwkey device\n");
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vhk = VIRTIO_HWKEY(dev);
-
- if (vdev == NULL) {
- ERR("failed to initialize the hwkey device\n");
- return;
- }
-
- virtio_init(vdev, TYPE_VIRTIO_HWKEY, VIRTIO_ID_HWKEY, 0);
-
- vhk->vq = virtio_add_queue(vdev, MAX_BUF_COUNT, maru_virtio_hwkey_handle);
-
- vhk->qdev = dev;
-
- /* reset the counters */
- pthread_mutex_lock(&event_mutex);
- event_queue_cnt = event_ringbuf_cnt = 0;
- pthread_mutex_unlock(&event_mutex);
-
- elem_queue_cnt = elem_ringbuf_cnt = 0;
-
- /* bottom-half */
- vhk->bh = qemu_bh_new(maru_hwkey_bh, vhk);
-}
-
-static void virtio_hwkey_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- INFO("exit the hwkey device\n");
-
- if (vhk->bh) {
- qemu_bh_delete(vhk->bh);
- }
-
- virtio_cleanup(vdev);
-
- pthread_mutex_destroy(&event_mutex);
-}
-
-static void virtio_hwkey_device_reset(VirtIODevice *vdev)
-{
- INFO("reset hwkey device\n");
- vqidx = 0;
-}
-
-static void virtio_hwkey_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->unrealize = virtio_hwkey_device_unrealize;
- vdc->realize = virtio_hwkey_device_realize;
- vdc->reset = virtio_hwkey_device_reset;
- vdc->get_features = virtio_hwkey_get_features;
-}
-
-static const TypeInfo virtio_hwkey_info = {
- .name = TYPE_VIRTIO_HWKEY,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOHWKey),
- .class_init = virtio_hwkey_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_hwkey_info);
-}
-
-type_init(virtio_register_types)
-
+++ /dev/null
-/*
- * Maru Virtio HW Key Device
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#ifndef MARU_HWKEY_H_
-#define MARU_HWKEY_H_
-
-#include "ui/console.h"
-#include "hw/virtio/virtio.h"
-
-#define TYPE_VIRTIO_HWKEY "virtio-hwkey-device"
-#define VIRTIO_HWKEY(obj) \
- OBJECT_CHECK(VirtIOHWKey, (obj), TYPE_VIRTIO_HWKEY)
-
-
-typedef struct VirtIOHWKey
-{
- VirtIODevice vdev;
- /* simply a queue into which buffers are posted
- by the guest for consumption by the host */
- VirtQueue *vq;
-
- QEMUBH *bh;
- DeviceState *qdev;
-} VirtIOHWKey;
-
-/* This structure must match the kernel definitions */
-typedef struct EmulHWKeyEvent {
- uint8_t event_type;
- uint32_t keycode;
-} EmulHWKeyEvent;
-
-
-VirtIODevice *maru_virtio_hwkey_init(DeviceState *dev);
-void maru_virtio_hwkey_exit(VirtIODevice *vdev);
-
-void maru_hwkey_event(int event_type, int keycode);
-void maru_virtio_hwkey_notify(void);
-
-#endif /* MARU_HWKEY_H_ */
+++ /dev/null
-/*
- * Virtio Jack Device
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung Choi <jinhyung2.choi@samsung.com>
- * Daiyoung Kim <daiyoung777.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <pthread.h>
-
-#include "hw/pci/pci.h"
-
-#include "maru_device_ids.h"
-#include "debug_ch.h"
-
-#include "maru_virtio_jack.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-jack);
-
-#define JACK_DEVICE_NAME "jack"
-#define _MAX_BUF 1024
-#define __MAX_BUF_JACK 32
-
-static int charger_online = 0;
-static int earjack_online = 0;
-static int earkey_online = 0;
-static int hdmi_online = 0;
-static int usb_online = 0;
-
-VirtIOJACK* vjack;
-static int jack_capability = 0;
-
-typedef struct msg_info {
- char buf[_MAX_BUF];
-
- uint16_t type;
- uint16_t req;
-} msg_info;
-
-enum request_cmd {
- request_get = 0,
- request_set,
- request_answer
-};
-
-void set_jack_charger(int online){
- charger_online = online;
-}
-
-int get_jack_charger(void) {
- return charger_online;
-}
-
-void set_jack_usb(int online){
- usb_online = online;
-}
-
-int get_jack_usb(void) {
- return usb_online;
-}
-
-static void set_jack_data (enum jack_types type, char* data, int len)
-{
- if (len < 0 || len > __MAX_BUF_JACK) {
- ERR("jack data size is wrong.\n");
- return;
- }
-
- if (data == NULL) {
- ERR("jack data is NULL.\n");
- return;
- }
-
- switch (type) {
- case jack_type_charger:
- sscanf(data, "%d", &charger_online);
- break;
- case jack_type_earjack:
- sscanf(data, "%d", &earjack_online);
- break;
- case jack_type_earkey:
- sscanf(data, "%d", &earkey_online);
- break;
- case jack_type_hdmi:
- sscanf(data, "%d", &hdmi_online);
- break;
- case jack_type_usb:
- sscanf(data, "%d", &usb_online);
- break;
- default:
- return;
- }
-}
-
-static void get_jack_data(enum jack_types type, char* msg_info)
-{
- if (msg_info == NULL) {
- return;
- }
-
- switch (type) {
- case jack_type_list:
- sprintf(msg_info, "%d", jack_capability);
- break;
- case jack_type_charger:
- sprintf(msg_info, "%d", charger_online);
- break;
- case jack_type_earjack:
- sprintf(msg_info, "%d", earjack_online);
- break;
- case jack_type_earkey:
- sprintf(msg_info, "%d", earkey_online);
- break;
- case jack_type_hdmi:
- sprintf(msg_info, "%d", hdmi_online);
- break;
- case jack_type_usb:
- sprintf(msg_info, "%d", usb_online);
- break;
- default:
- return;
- }
-}
-
-static void answer_jack_data_request(int type, char* data, VirtQueueElement *elem)
-{
- msg_info* msginfo = (msg_info*) malloc(sizeof(msg_info));
- if (!msginfo) {
- ERR("msginfo is NULL!\n");
- return;
- }
-
- msginfo->req = request_answer;
- msginfo->type = type;
- get_jack_data(type, msginfo->buf);
-
- TRACE("sending message: %s, type: %d, req: %d\n", msginfo->buf, msginfo->type, msginfo->req);
-
- memset(elem->in_sg[0].iov_base, 0, elem->in_sg[0].iov_len);
- memcpy(elem->in_sg[0].iov_base, msginfo, sizeof(struct msg_info));
-
- if (msginfo)
- free(msginfo);
-}
-
-static void handle_msg(struct msg_info *msg, VirtQueueElement *elem)
-{
- unsigned int len = 0;
-
- if (msg == NULL) {
- ERR("msg info structure is NULL.\n");
- return;
- }
-
- if (msg->req == request_set) {
- set_jack_data (msg->type, msg->buf, strlen(msg->buf));
- } else if (msg->req == request_get) {
- answer_jack_data_request(msg->type, msg->buf, elem);
- len = sizeof(msg_info);
- }
-
- virtqueue_push(vjack->vq, elem, len);
- virtio_notify(&vjack->vdev, vjack->vq);
-}
-
-static void virtio_jack_vq(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOJACK *vjack = (VirtIOJACK*)vdev;
- struct msg_info msg;
- VirtQueueElement elem;
- int index = 0;
-
- if (vjack->vq == NULL) {
- ERR("virt queue is not ready.\n");
- return;
- }
-
- if (!virtio_queue_ready(vjack->vq)) {
- ERR("virtqueue is not ready.");
- return;
- }
-
- if (virtio_queue_empty(vjack->vq)) {
- ERR("<< virtqueue is empty.\n");
- return;
- }
-
- while ((index = virtqueue_pop(vq, &elem))) {
- memset(&msg, 0x00, sizeof(msg));
- memcpy(&msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
-
- TRACE("handling msg from driver: %s, len: %d, type: %d, req: %d, index: %d\n", msg.buf, strlen(msg.buf), msg.type, msg.req, index);
-
- handle_msg(&msg, &elem);
- }
-}
-
-static int set_capability(char* jack)
-{
- if (!strncmp(jack, JACK_NAME_CHARGER, 7)) {
- return jack_cap_charger;
- } else if (!strncmp(jack, JACK_NAME_EARJACK, 7)) {
- return jack_cap_earjack;
- } else if (!strncmp(jack, JACK_NAME_EARKEY, 6)) {
- return jack_cap_earkey;
- } else if (!strncmp(jack, JACK_NAME_HDMI, 4)) {
- return jack_cap_hdmi;
- } else if (!strncmp(jack, JACK_NAME_USB, 3)) {
- return jack_cap_usb;
- }
-
- return 0;
-}
-
-static void parse_jack_capability(char* lists)
-{
- char token[] = JACK_CAP_TOKEN;
- char* data = NULL;
-
- if (lists == NULL)
- return;
-
- data = strtok(lists, token);
- if (data != NULL) {
- jack_capability |= set_capability(data);
- while ((data = strtok(NULL, token)) != NULL) {
- jack_capability |= set_capability(data);
- }
- }
-
- INFO("jack device capabilty enabled with %02x\n", jack_capability);
-}
-
-static void virtio_jack_realize(DeviceState *dev, Error **errp)
-{
- INFO("initialize virtio-jack device\n");
-
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vjack = VIRTIO_JACK(vdev);
-
- virtio_init(vdev, JACK_DEVICE_NAME, VIRTIO_ID_JACK, 0);
-
- if (vjack == NULL) {
- ERR("failed to initialize jack device\n");
- return;
- }
-
- vjack->vq = virtio_add_queue(&vjack->vdev, 64, virtio_jack_vq);
-
- INFO("initialized jack type: %s\n", vjack->jacks);
-
- if (vjack->jacks) {
- parse_jack_capability(vjack->jacks);
- }
-}
-
-static void virtio_jack_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- INFO("destroy jack device\n");
-
- virtio_cleanup(vdev);
-}
-
-
-static void virtio_jack_reset(VirtIODevice *vdev)
-{
- TRACE("virtio_jack_reset.\n");
-}
-
-static uint32_t virtio_jack_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_jack_get_features.\n");
- return 0;
-}
-
-static Property virtio_jack_properties[] = {
- DEFINE_PROP_STRING(ATTRIBUTE_NAME_JACKS, VirtIOJACK, jacks),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_jack_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- dc->props = virtio_jack_properties;
- vdc->realize = virtio_jack_realize;
- vdc->unrealize = virtio_jack_unrealize;
- vdc->get_features = virtio_jack_get_features;
- vdc->reset = virtio_jack_reset;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_JACK,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOJACK),
- .class_init = virtio_jack_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
-
+++ /dev/null
-/*
- * Virtio Jack Device
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung choi <jinhyung2.choi@samsung.com>
- * Daiyoung Kim <daiyoung777.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef MARU_VIRTIO_JACK_H_
-#define MARU_VIRTIO_JACK_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "hw/virtio/virtio.h"
-
-#define TYPE_VIRTIO_JACK "virtio-jack-device"
-#define VIRTIO_JACK(obj) \
- OBJECT_CHECK(VirtIOJACK, (obj), TYPE_VIRTIO_JACK)
-
-enum jack_types {
- jack_type_list = 0,
- jack_type_charger,
- jack_type_earjack,
- jack_type_earkey,
- jack_type_hdmi,
- jack_type_usb,
- jack_type_max
-};
-
-enum jack_capabilities {
- jack_cap_charger = 0x01,
- jack_cap_earjack = 0x02,
- jack_cap_earkey = 0x04,
- jack_cap_hdmi = 0x08,
- jack_cap_usb = 0x10
-};
-
-typedef struct VirtIOJACK {
- VirtIODevice vdev;
- VirtQueue *vq;
- DeviceState *qdev;
-
- char *jacks;
-} VirtIOJACK;
-
-#define ATTRIBUTE_NAME_JACKS "jacks"
-
-#define JACK_NAME_CHARGER "charger"
-#define JACK_NAME_EARJACK "earjack"
-#define JACK_NAME_EARKEY "earkey"
-#define JACK_NAME_HDMI "hdmi"
-#define JACK_NAME_USB "usb"
-
-#define JACK_CAP_TOKEN "&"
-
-void set_jack_charger(int online);
-int get_jack_charger(void);
-
-void set_jack_usb(int online);
-int get_jack_usb(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-/*
- * Virtio Keyboard Device
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Kitae Kim <kt920.kim@samsung.com>
- * GiWoong Kim <giwoong.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "maru_device_ids.h"
-#include "maru_virtio_keyboard.h"
-#include "debug_ch.h"
-
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-kbd);
-
-VirtIOKeyboard *vkbd;
-VirtQueueElement elem;
-
-static void virtio_keyboard_handle(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
- int index = 0;
-
- if (virtio_queue_empty(vkbd->vq)) {
- INFO("virtqueue is empty.\n");
- return;
- }
-
- /* Get a queue buffer which is written by guest side. */
- do {
- index = virtqueue_pop(vq, &elem);
- TRACE("virtqueue pop.\n");
- } while (index < VIRTIO_KBD_QUEUE_SIZE);
-}
-
-void virtio_keyboard_notify(void *opaque)
-{
- VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
- EmulKbdEvent *kbdevt;
- int written_cnt = 0;
-
- if (!vkbd) {
- ERR("VirtIOKeyboard is NULL.\n");
- return;
- }
-
- TRACE("[Enter] virtqueue notifier.\n");
-
- if (!virtio_queue_ready(vkbd->vq)) {
- INFO("virtqueue is not ready.\n");
- return;
- }
-
- if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
- vkbd->kbdqueue.rptr = 0;
- }
-
- qemu_mutex_lock(&vkbd->event_mutex);
- written_cnt = vkbd->kbdqueue.wptr;
-
- while ((written_cnt--)) {
- kbdevt = &vkbd->kbdqueue.kbdevent[vkbd->kbdqueue.rptr];
-
- if (((EmulKbdEvent*)(elem.in_sg[vkbd->kbdqueue.rptr].iov_base))->code != 0) {
- TRACE("FIXME: virtio queue is full.\n");
- }
-
- /* Copy keyboard data into guest side. */
- TRACE("copy: keycode %d, type %d, elem_index %d\n",
- kbdevt->code, kbdevt->type, vkbd->kbdqueue.rptr);
- memcpy(elem.in_sg[vkbd->kbdqueue.rptr].iov_base, kbdevt, sizeof(EmulKbdEvent));
- memset(kbdevt, 0x00, sizeof(EmulKbdEvent));
-
- if (vkbd->kbdqueue.wptr > 0) {
- vkbd->kbdqueue.wptr--;
- TRACE("written_cnt: %d, wptr: %d, qemu_index: %d\n",
- written_cnt, vkbd->kbdqueue.wptr, vkbd->kbdqueue.rptr);
- }
-
- vkbd->kbdqueue.rptr++;
- if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
- vkbd->kbdqueue.rptr = 0;
- }
- }
- qemu_mutex_unlock(&vkbd->event_mutex);
-
- virtqueue_push(vkbd->vq, &elem, sizeof(EmulKbdEvent));
- virtio_notify(&vkbd->vdev, vkbd->vq);
-
- TRACE("[Leave] virtqueue notifier.\n");
-}
-
-void virtio_keyboard_event(int keycode)
-{
- EmulKbdEvent kbdevt = {0};
- int *index = NULL;
-
- if (!vkbd) {
- ERR("VirtIOKeyboard is NULL.\n");
- return;
- }
-
- if (!virtio_queue_ready(vkbd->vq)) {
- INFO("virtqueue is not ready.\n");
- return;
- }
-
- index = &(vkbd->kbdqueue.index);
- TRACE("[Enter] input_event handler. cnt %d\n", vkbd->kbdqueue.wptr);
-
- if (*index < 0) {
- ERR("keyboard queue is overflow.\n");
- return;
- }
-
- if (*index == VIRTIO_KBD_QUEUE_SIZE) {
- *index = 0;
- }
-
- if (keycode < 0xe0) {
- if (vkbd->extension_key) {
- switch (keycode & 0x7f) {
- case 28: /* KP_Enter */
- kbdevt.code = 96;
- break;
- case 29: /* Right Ctrl */
- kbdevt.code = 97;
- break;
- case 56: /* Right Alt */
- kbdevt.code = 100;
- break;
- case 71: /* Home */
- kbdevt.code = 102;
- break;
- case 72: /* Up */
- kbdevt.code = 103;
- break;
- case 73: /* Page Up */
- kbdevt.code = 104;
- break;
- case 75: /* Left */
- kbdevt.code = 105;
- break;
- case 77: /* Right */
- kbdevt.code = 106;
- break;
- case 79: /* End */
- kbdevt.code = 107;
- break;
- case 80: /* Down */
- kbdevt.code = 108;
- break;
- case 81: /* Page Down */
- kbdevt.code = 109;
- break;
- case 82: /* Insert */
- kbdevt.code = 110;
- break;
- case 83: /* Delete */
- kbdevt.code = 111;
- break;
- default:
- WARN("There is no keymap for this keycode %d.\n", keycode);
- }
- vkbd->extension_key = 0;
- } else {
- kbdevt.code = keycode & 0x7f;
- }
-
- if (!(keycode & 0x80)) {
- kbdevt.type = 1; /* KEY_PRESSED */
- } else {
- kbdevt.type = 0; /* KEY_RELEASED */
- }
- } else {
- TRACE("Extension key.\n");
- kbdevt.code = keycode;
- vkbd->extension_key = 1;
- }
-
- qemu_mutex_lock(&vkbd->event_mutex);
- memcpy(&vkbd->kbdqueue.kbdevent[(*index)++], &kbdevt, sizeof(kbdevt));
- TRACE("event: keycode %d, type %d, index %d.\n",
- kbdevt.code, kbdevt.type, ((*index) - 1));
-
- vkbd->kbdqueue.wptr++;
- qemu_mutex_unlock(&vkbd->event_mutex);
-
- TRACE("[Leave] input_event handler. cnt:%d\n", vkbd->kbdqueue.wptr);
-
- qemu_bh_schedule(vkbd->bh);
-}
-
-static uint32_t virtio_keyboard_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_keyboard_get_features.\n");
- return 0;
-}
-
-static void virtio_keyboard_bh(void *opaque)
-{
- virtio_keyboard_notify(opaque);
-}
-
-static void virtio_keyboard_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vkbd = VIRTIO_KEYBOARD(vdev);
-
- INFO("initialize virtio-keyboard device\n");
-
- if (vdev == NULL) {
- ERR("failed to initialize virtio-keyboard device\n");
- return;
- }
-
- virtio_init(vdev, TYPE_VIRTIO_KEYBOARD, VIRTIO_ID_KEYBOARD, 0);
-
- memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
- vkbd->extension_key = 0;
- qemu_mutex_init(&vkbd->event_mutex);
-
- vkbd->vq = virtio_add_queue(vdev, 128, virtio_keyboard_handle);
- vkbd->qdev = dev;
-
- /* bottom half */
- vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
-}
-
-static void virtio_keyboard_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
-
- INFO("destroy device\n");
-
- if (vkbd->bh) {
- qemu_bh_delete(vkbd->bh);
- }
-
- qemu_mutex_destroy(&vkbd->event_mutex);
-
- virtio_cleanup(vdev);
-}
-
-static void virtio_keyboard_device_reset(VirtIODevice *vdev)
-{
- vkbd = VIRTIO_KEYBOARD(vdev);
-
- INFO("reset keyboard device\n");
- vkbd->kbdqueue.rptr = 0;
- vkbd->kbdqueue.index = 0;
-}
-
-static void virtio_keyboard_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->unrealize = virtio_keyboard_device_unrealize;
- vdc->realize = virtio_keyboard_device_realize;
- vdc->reset = virtio_keyboard_device_reset;
- vdc->get_features = virtio_keyboard_get_features;
-}
-
-static const TypeInfo virtio_keyboard_info = {
- .name = TYPE_VIRTIO_KEYBOARD,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOKeyboard),
- .class_init = virtio_keyboard_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_keyboard_info);
-}
-
-type_init(virtio_register_types)
-
+++ /dev/null
-/*
- * Virtio Keyboard Device
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Kitae Kim <kt920.kim@samsung.com>
- * GiWoong Kim <giwoong.kim@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef VIRTIO_KEYBOARD_H_
-#define VIRTIO_KEYBOARD_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "qemu/thread.h"
-#include "hw/virtio/virtio.h"
-
-#define TYPE_VIRTIO_KEYBOARD "virtio-keyboard-device"
-#define VIRTIO_KEYBOARD(obj) \
- OBJECT_CHECK(VirtIOKeyboard, (obj), TYPE_VIRTIO_KEYBOARD)
-#define VIRTIO_KBD_QUEUE_SIZE 100
-
-typedef struct EmulKbdEvent {
- uint16_t code;
- uint16_t type;
-} EmulKbdEvent;
-
-typedef struct VirtIOKbdQueue {
- EmulKbdEvent kbdevent[VIRTIO_KBD_QUEUE_SIZE];
- int index;
- int rptr, wptr;
-} VirtIOKbdQueue;
-
-typedef struct VirtIOKeyboard {
- VirtIODevice vdev;
- VirtQueue *vq;
- DeviceState *qdev;
- uint16_t extension_key;
-
- VirtIOKbdQueue kbdqueue;
- QemuMutex event_mutex;
- QEMUBH *bh;
-} VirtIOKeyboard;
-
-VirtIODevice *virtio_keyboard_init(DeviceState *dev);
-void virtio_keyboard_exit(VirtIODevice *vdev);
-
-void virtio_keyboard_event(int keycode);
-void virtio_keyboard_notify(void *opaque);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* VIRTIO_KEYBOARD_H_ */
+++ /dev/null
-/*
- * Virtio NFC Device
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Munkyu Im <munkyu.im@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <pthread.h>
-
-#include "maru_device_ids.h"
-#include "maru_virtio_nfc.h"
-#include "debug_ch.h"
-#include "ecs/ecs.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-nfc);
-
-#define NFC_DEVICE_NAME "virtio-nfc"
-
-enum {
- IOTYPE_INPUT = 0,
- IOTYPE_OUTPUT = 1
-};
-
-
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif
-
-VirtIONFC* vio_nfc;
-
-typedef struct MsgInfo
-{
- nfc_msg_info info;
- QTAILQ_ENTRY(MsgInfo) next;
-}MsgInfo;
-
-static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) nfc_recv_msg_queue =
-QTAILQ_HEAD_INITIALIZER(nfc_recv_msg_queue);
-
-typedef struct NFCBuf {
- VirtQueueElement elem;
- QTAILQ_ENTRY(NFCBuf) next;
-} NFCBuf;
-
-static pthread_mutex_t recv_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-bool send_to_nfc(unsigned char id, unsigned char type, const char* data, const uint32_t len)
-{
- if(vio_nfc == NULL) {
- ERR("NFC is not initialized\n");
- return false;
- }
-
- if (unlikely(!virtio_queue_ready(vio_nfc->rvq))) {
- ERR("virtio queue is not ready\n");
- return false;
- }
-
- MsgInfo* _msg = (MsgInfo*) malloc(sizeof(MsgInfo));
- if (!_msg) {
- return false;
- }
-
- if(len > NFC_MAX_BUF_SIZE) {
- ERR("the length of data is longer than max buffer size");
- free(_msg);
- return false;
- }
-
- memset(&_msg->info, 0, sizeof(nfc_msg_info));
-
- memcpy(_msg->info.buf, data, len);
- _msg->info.use = len;
- _msg->info.client_id = id;
- _msg->info.client_type = type;
-
- pthread_mutex_lock(&recv_buf_mutex);
-
- QTAILQ_INSERT_TAIL(&nfc_recv_msg_queue, _msg, next);
-
- pthread_mutex_unlock(&recv_buf_mutex);
-
- qemu_bh_schedule(vio_nfc->bh);
-
- return true;
-}
-
-static void flush_nfc_recv_queue(void)
-{
- int index;
-
- if (unlikely(!virtio_queue_ready(vio_nfc->rvq))) {
- INFO("virtio queue is not ready\n");
- return;
- }
-
- if (unlikely(virtio_queue_empty(vio_nfc->rvq))) {
- TRACE("virtqueue is empty\n");
- return;
- }
-
-
- pthread_mutex_lock(&recv_buf_mutex);
-
- while (!QTAILQ_EMPTY(&nfc_recv_msg_queue))
- {
- MsgInfo* msginfo = QTAILQ_FIRST(&nfc_recv_msg_queue);
- if (!msginfo) {
- break;
- }
-
- VirtQueueElement elem;
- index = virtqueue_pop(vio_nfc->rvq, &elem);
- if (index == 0)
- {
- //ERR("unexpected empty queue");
- break;
- }
-
- INFO(">> virtqueue_pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
-
- memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct nfc_msg_info));
-
- INFO(">> send to guest use = %d, msg = %s, iov_len = %d \n",
- msginfo->info.use, msginfo->info.buf, elem.in_sg[0].iov_len);
-
- virtqueue_push(vio_nfc->rvq, &elem, sizeof(nfc_msg_info));
- virtio_notify(&vio_nfc->vdev, vio_nfc->rvq);
-
- QTAILQ_REMOVE(&nfc_recv_msg_queue, msginfo, next);
- if (msginfo)
- free(msginfo);
- }
-
- pthread_mutex_unlock(&recv_buf_mutex);
-
-}
-
-
-static void virtio_nfc_recv(VirtIODevice *vdev, VirtQueue *vq)
-{
- flush_nfc_recv_queue();
-}
-
-static void virtio_nfc_send(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIONFC *vnfc = (VirtIONFC *)vdev;
- int index = 0;
- struct nfc_msg_info _msg;
-
- if (virtio_queue_empty(vnfc->svq)) {
- INFO("<< virtqueue is empty.\n");
- return;
- }
-
- VirtQueueElement elem;
-
- while ((index = virtqueue_pop(vq, &elem))) {
-
- INFO("<< virtqueue pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
-
- INFO("<< iov_len = %d\n", elem.out_sg[0].iov_len);
-
- memset(&_msg, 0x00, sizeof(_msg));
- memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
-
- INFO("<< recv from guest len = %d, msg = %s \n", _msg.use, _msg.buf);
- send_nfc_ntf(&_msg);
-
- }
-
- virtqueue_push(vq, &elem, sizeof(VirtIONFC));
- virtio_notify(&vio_nfc->vdev, vq);
-}
-
-static uint32_t virtio_nfc_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_nfc_get_features.\n");
- return 0;
-}
-
-static void maru_nfc_bh(void *opaque)
-{
- flush_nfc_recv_queue();
-}
-
-static void virtio_nfc_realize(DeviceState* dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vio_nfc = VIRTIO_NFC(vdev);
- if (vio_nfc == NULL) {
- ERR("failed to initialize nfc device\n");
- return;
- }
-
- INFO("initialize nfc device\n");
-
- virtio_init(vdev, NFC_DEVICE_NAME, VIRTIO_ID_NFC, 0);
-
- vio_nfc->rvq = virtio_add_queue(&vio_nfc->vdev, 256, virtio_nfc_recv);
- vio_nfc->svq = virtio_add_queue(&vio_nfc->vdev, 256, virtio_nfc_send);
-
- vio_nfc->bh = qemu_bh_new(maru_nfc_bh, vio_nfc);
-}
-
-static void virtio_nfc_unrealize(DeviceState* dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- INFO("destroy nfc device\n");
-
- if (vio_nfc->bh) {
- qemu_bh_delete(vio_nfc->bh);
- }
-
- virtio_cleanup(vdev);
-}
-
-static void virtio_nfc_reset(VirtIODevice *vdev)
-{
- TRACE("virtio_sensor_reset.\n");
-}
-
-
-static void virtio_nfc_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->realize = virtio_nfc_realize;
- vdc->unrealize = virtio_nfc_unrealize;
- vdc->get_features = virtio_nfc_get_features;
- vdc->reset = virtio_nfc_reset;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_NFC,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIONFC),
- .class_init = virtio_nfc_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
-
+++ /dev/null
-/*\r
- * Virtio NFC Device\r
- *\r
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved\r
- *\r
- * Contact:\r
- * Munkyu Im <munkyu.im@samsung.com>\r
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
- *\r
- * Contributors:\r
- * - S-Core Co., Ltd\r
- *\r
- */\r
-\r
-#ifndef MARU_VIRTIO_NFC_H_\r
-#define MARU_VIRTIO_NFC_H_\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-#include "hw/virtio/virtio.h"\r
-\r
-enum request_cmd_nfc {\r
- request_nfc_get = 0,\r
- request_nfc_set,\r
- request_nfc_answer\r
-};\r
-\r
-\r
-/* device protocol */\r
-\r
-#define __MAX_BUF_SIZE 1024\r
-\r
-\r
-typedef struct VirtIONFC{\r
- VirtIODevice vdev;\r
- VirtQueue *rvq;\r
- VirtQueue *svq;\r
- DeviceState *qdev;\r
-\r
- QEMUBH *bh;\r
-} VirtIONFC;\r
-\r
-\r
-#define TYPE_VIRTIO_NFC "virtio-nfc-device"\r
-#define VIRTIO_NFC(obj) \\r
- OBJECT_CHECK(VirtIONFC, (obj), TYPE_VIRTIO_NFC)\r
-\r
-\r
-bool send_to_nfc(unsigned char id, unsigned char type, const char* data, const uint32_t len);\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-\r
-#endif /* MARU_VIRTIO_NFC_H_ */\r
+++ /dev/null
-/*
- * Maru virtio pci
- *
- * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact:
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- * refer to hw/virtio/virtio-pci.c
- */
-
-#include "hw/virtio/virtio-pci.h"
-
-#include "tizen/src/hw/maru_device_ids.h"
-#include "tizen/src/hw/maru_virtio_evdi.h"
-#include "tizen/src/hw/maru_virtio_esm.h"
-#include "tizen/src/hw/maru_virtio_hwkey.h"
-#include "tizen/src/hw/maru_virtio_keyboard.h"
-#include "tizen/src/hw/maru_virtio_touchscreen.h"
-#include "tizen/src/hw/maru_virtio_sensor.h"
-#include "tizen/src/hw/maru_virtio_jack.h"
-#include "tizen/src/hw/maru_virtio_power.h"
-#include "tizen/src/hw/maru_virtio_nfc.h"
-#include "tizen/src/hw/maru_virtio_vmodem.h"
-
-typedef struct VirtIOTouchscreenPCI VirtIOTouchscreenPCI;
-typedef struct VirtIOEVDIPCI VirtIOEVDIPCI;
-typedef struct VirtIOESMPCI VirtIOESMPCI;
-typedef struct VirtIOHWKeyPCI VirtIOHWKeyPCI;
-typedef struct VirtIOKeyboardPCI VirtIOKeyboardPCI;
-typedef struct VirtIOSENSORPCI VirtIOSENSORPCI;
-typedef struct VirtIONFCPCI VirtIONFCPCI;
-typedef struct VirtIOPOWERPCI VirtIOPOWERPCI;
-typedef struct VirtIOJACKPCI VirtIOJACKPCI;
-typedef struct VirtIOVModemPCI VirtIOVModemPCI;
-
-/*
- * virtio-touchscreen-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_TOUCHSCREEN_PCI "virtio-touchscreen-pci"
-#define VIRTIO_TOUCHSCREEN_PCI(obj) \
- OBJECT_CHECK(VirtIOTouchscreenPCI, (obj), TYPE_VIRTIO_TOUCHSCREEN_PCI)
-
-struct VirtIOTouchscreenPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOTouchscreen vdev;
-};
-
-/*
- * virtio-keyboard-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
-#define VIRTIO_KEYBOARD_PCI(obj) \
- OBJECT_CHECK(VirtIOKeyboardPCI, (obj), TYPE_VIRTIO_KEYBOARD_PCI)
-
-struct VirtIOKeyboardPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOKeyboard vdev;
-};
-
-/*
- * virtio-evdi-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_EVDI_PCI "virtio-evdi-pci"
-#define VIRTIO_EVDI_PCI(obj) \
- OBJECT_CHECK(VirtIOEVDIPCI, (obj), TYPE_VIRTIO_EVDI_PCI)
-
-struct VirtIOEVDIPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOEVDI vdev;
-};
-
-/*
- * virtio-esm-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_ESM_PCI "virtio-esm-pci"
-#define VIRTIO_ESM_PCI(obj) \
- OBJECT_CHECK(VirtIOESMPCI, (obj), TYPE_VIRTIO_ESM_PCI)
-struct VirtIOESMPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOESM vdev;
-};
-
-/*
- * virtio-hwkey-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_HWKEY_PCI "virtio-hwkey-pci"
-#define VIRTIO_HWKEY_PCI(obj) \
- OBJECT_CHECK(VirtIOHWKeyPCI, (obj), TYPE_VIRTIO_HWKEY_PCI)
-struct VirtIOHWKeyPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOHWKey vdev;
-};
-
-/*
- * virtio-sensor-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_SENSOR_PCI "virtio-sensor-pci"
-#define VIRTIO_SENSOR_PCI(obj) \
- OBJECT_CHECK(VirtIOSENSORPCI, (obj), TYPE_VIRTIO_SENSOR_PCI)
-
-struct VirtIOSENSORPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOSENSOR vdev;
-};
-
-/*
- * virtio-nfc-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_NFC_PCI "virtio-nfc-pci"
-#define VIRTIO_NFC_PCI(obj) \
- OBJECT_CHECK(VirtIONFCPCI, (obj), TYPE_VIRTIO_NFC_PCI)
-
-struct VirtIONFCPCI {
- VirtIOPCIProxy parent_obj;
- VirtIONFC vdev;
-};
-
-/*
- * virtio-jack-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_JACK_PCI "virtio-jack-pci"
-#define VIRTIO_JACK_PCI(obj) \
- OBJECT_CHECK(VirtIOJACKPCI, (obj), TYPE_VIRTIO_JACK_PCI)
-
-struct VirtIOJACKPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOJACK vdev;
-};
-
-/*
- * virtio-power-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_POWER_PCI "virtio-power-pci"
-#define VIRTIO_POWER_PCI(obj) \
- OBJECT_CHECK(VirtIOPOWERPCI, (obj), TYPE_VIRTIO_POWER_PCI)
-
-struct VirtIOPOWERPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOPOWER vdev;
-};
-
-/*
- * virtio-vmodem-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_VMODEM_PCI "virtio-vmodem-pci"
-#define VIRTIO_VMODEM_PCI(obj) \
- OBJECT_CHECK(VirtIOVModemPCI, (obj), TYPE_VIRTIO_VMODEM_PCI)
-struct VirtIOVModemPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOVModem vdev;
-};
-
-
-/* virtio-touchscreen-pci */
-
-static Property virtio_touchscreen_pci_properties[] = {
- DEFINE_PROP_UINT32(TOUCHSCREEN_OPTION_NAME,
- VirtIOTouchscreenPCI,vdev.max_finger, DEFAULT_MAX_FINGER),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-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);
-
- dc->props = virtio_touchscreen_pci_properties;
- 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(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TOUCHSCREEN);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-
- dev->vdev.max_finger = DEFAULT_MAX_FINGER;
-}
-
-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)
-{
- 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(&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)
-{
- 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(&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(&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(&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 Property virtio_sensor_pci_properties[] = {
- DEFINE_PROP_STRING(ATTRIBUTE_NAME_SENSORS, VirtIOSENSORPCI, vdev.sensors),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_sensor_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_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;
- dc->props = virtio_sensor_pci_properties;
-}
-
-static void virtio_sensor_pci_instance_init(Object *obj)
-{
- VirtIOSENSORPCI *dev = VIRTIO_SENSOR_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SENSOR);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static TypeInfo virtio_sensor_pci_info = {
- .name = TYPE_VIRTIO_SENSOR_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOSENSORPCI),
- .instance_init = virtio_sensor_pci_instance_init,
- .class_init = virtio_sensor_pci_class_init,
-};
-
-/* virtio NFC */
-
-static int virtio_nfc_pci_init(VirtIOPCIProxy *vpci_dev)
-{
- VirtIONFCPCI *dev = VIRTIO_NFC_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
- }
- return 0;
-}
-
-static void virtio_nfc_pci_class_init(ObjectClass *klass, void *data)
-{
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->init = virtio_nfc_pci_init;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_NFC;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_nfc_pci_instance_init(Object *obj)
-{
- VirtIONFCPCI *dev = VIRTIO_NFC_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NFC);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static TypeInfo virtio_nfc_pci_info = {
- .name = TYPE_VIRTIO_NFC_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIONFCPCI),
- .instance_init = virtio_nfc_pci_instance_init,
- .class_init = virtio_nfc_pci_class_init,
-};
-
-/* virtio-jack-pci */
-
-static int virtio_jack_pci_init(VirtIOPCIProxy *vpci_dev)
-{
- VirtIOJACKPCI *dev = VIRTIO_JACK_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 Property virtio_jack_pci_properties[] = {
- DEFINE_PROP_STRING(ATTRIBUTE_NAME_JACKS, VirtIOJACKPCI, vdev.jacks),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_jack_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_jack_pci_init;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_JACK;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
- dc->props = virtio_jack_pci_properties;
-}
-
-static void virtio_jack_pci_instance_init(Object *obj)
-{
- VirtIOJACKPCI *dev = VIRTIO_JACK_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_JACK);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static TypeInfo virtio_jack_pci_info = {
- .name = TYPE_VIRTIO_JACK_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOJACKPCI),
- .instance_init = virtio_jack_pci_instance_init,
- .class_init = virtio_jack_pci_class_init,
-};
-
-/* virtio-power-pci */
-
-static int virtio_power_pci_init(VirtIOPCIProxy *vpci_dev)
-{
- VirtIOPOWERPCI *dev = VIRTIO_POWER_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_power_pci_class_init(ObjectClass *klass, void *data)
-{
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->init = virtio_power_pci_init;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_POWER;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_power_pci_instance_init(Object *obj)
-{
- VirtIOPOWERPCI *dev = VIRTIO_POWER_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_POWER);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static TypeInfo virtio_power_pci_info = {
- .name = TYPE_VIRTIO_POWER_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOPOWERPCI),
- .instance_init = virtio_power_pci_instance_init,
- .class_init = virtio_power_pci_class_init,
-};
-
-/* virtio-vmodem-pci */
-
-static int virtio_vmodem_pci_init(VirtIOPCIProxy *vpci_dev)
-{
- VirtIOVModemPCI *dev = VIRTIO_VMODEM_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_vmodem_pci_class_init(ObjectClass *klass, void *data)
-{
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->init = virtio_vmodem_pci_init;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VMODEM;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_vmodem_pci_instance_init(Object *obj)
-{
- VirtIOVModemPCI *dev = VIRTIO_VMODEM_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_VMODEM);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static TypeInfo virtio_vmodem_pci_info = {
- .name = TYPE_VIRTIO_VMODEM_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOVModemPCI),
- .instance_init = virtio_vmodem_pci_instance_init,
- .class_init = virtio_vmodem_pci_class_init,
-};
-
-static void maru_virtio_pci_register_types(void)
-{
- type_register_static(&virtio_evdi_pci_info);
- type_register_static(&virtio_esm_pci_info);
- type_register_static(&virtio_hwkey_pci_info);
- type_register_static(&virtio_keyboard_pci_info);
- type_register_static(&virtio_touchscreen_pci_info);
- type_register_static(&virtio_sensor_pci_info);
- type_register_static(&virtio_nfc_pci_info);
- type_register_static(&virtio_jack_pci_info);
- type_register_static(&virtio_power_pci_info);
- type_register_static(&virtio_vmodem_pci_info);
-}
-
-type_init(maru_virtio_pci_register_types)
+++ /dev/null
-/*
- * Virtio Power Device
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung Choi <jinhyung2.choi@samsung.com>
- * Daiyoung Kim <daiyoung777.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <pthread.h>
-
-#include "hw/pci/pci.h"
-
-#include "maru_device_ids.h"
-#include "debug_ch.h"
-
-#include "maru_virtio_power.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-power);
-
-#define POWER_DEVICE_NAME "power_supply"
-#define _MAX_BUF 1024
-#define __MAX_BUF_POWER 32
-
-static int capacity = 50;
-static int charge_full = 0;
-static int charge_now = 0;
-
-VirtIOPOWER* vpower;
-
-typedef struct msg_info {
- char buf[_MAX_BUF];
-
- uint16_t type;
- uint16_t req;
-} msg_info;
-
-enum request_cmd {
- request_get = 0,
- request_set,
- request_answer
-};
-
-static void set_power_data (enum power_types type, char* data, int len)
-{
- if (len < 0 || len > __MAX_BUF_POWER) {
- ERR("power data size is wrong.\n");
- return;
- }
-
- if (data == NULL) {
- ERR("power data is NULL.\n");
- return;
- }
-
- switch (type) {
- case power_type_capacity:
- sscanf(data, "%d", &capacity);
- break;
- case power_type_charge_full:
- sscanf(data, "%d", &charge_full);
- break;
- case power_type_charge_now:
- sscanf(data, "%d", &charge_now);
- break;
- default:
- return;
- }
-}
-
-static void get_power_data(enum power_types type, char* msg_info)
-{
- if (msg_info == NULL) {
- return;
- }
-
- switch (type) {
- case power_type_capacity:
- sprintf(msg_info, "%d", capacity);
- break;
- case power_type_charge_full:
- sprintf(msg_info, "%d", charge_full);
- break;
- case power_type_charge_now:
- sprintf(msg_info, "%d", charge_now);
- break;
- default:
- return;
- }
-}
-
-void set_power_capacity(int level) {
- capacity = level;
-}
-
-int get_power_capacity(void) {
- return capacity;
-}
-
-void set_power_charge_full(int full){
- charge_full = full;
-}
-
-int get_power_charge_full(void){
- return charge_full;
-}
-
-void set_power_charge_now(int now){
- charge_now = now;
-}
-
-int get_power_charge_now(void){
- return charge_now;
-}
-
-static void answer_power_data_request(int type, char* data, VirtQueueElement *elem)
-{
- msg_info* msginfo = (msg_info*) malloc(sizeof(msg_info));
- if (!msginfo) {
- ERR("msginfo is NULL!\n");
- return;
- }
-
- msginfo->req = request_answer;
- msginfo->type = type;
- get_power_data(type, msginfo->buf);
-
- TRACE("sending message: %s, type: %d, req: %d\n", msginfo->buf, msginfo->type, msginfo->req);
-
- memset(elem->in_sg[0].iov_base, 0, elem->in_sg[0].iov_len);
- memcpy(elem->in_sg[0].iov_base, msginfo, sizeof(struct msg_info));
-
- if (msginfo)
- free(msginfo);
-}
-
-static void handle_msg(struct msg_info *msg, VirtQueueElement *elem)
-{
- unsigned int len = 0;
-
- if (msg == NULL) {
- ERR("msg info structure is NULL.\n");
- return;
- }
-
- if (msg->req == request_set) {
- set_power_data (msg->type, msg->buf, strlen(msg->buf));
- } else if (msg->req == request_get) {
- answer_power_data_request(msg->type, msg->buf, elem);
- len = sizeof(msg_info);
- }
-
- virtqueue_push(vpower->vq, elem, len);
- virtio_notify(&vpower->vdev, vpower->vq);
-}
-
-static void virtio_power_vq(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOPOWER *vpower = (VirtIOPOWER*)vdev;
- struct msg_info msg;
- VirtQueueElement elem;
- int index = 0;
-
- if (vpower->vq == NULL) {
- ERR("virt queue is not ready.\n");
- return;
- }
-
- if (!virtio_queue_ready(vpower->vq)) {
- ERR("virtqueue is not ready.");
- return;
- }
-
- if (virtio_queue_empty(vpower->vq)) {
- ERR("<< virtqueue is empty.\n");
- return;
- }
-
- while ((index = virtqueue_pop(vq, &elem))) {
- memset(&msg, 0x00, sizeof(msg));
- memcpy(&msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
-
- TRACE("handling msg from driver: %s, len: %d, type: %d, req: %d, index: %d\n", msg.buf, strlen(msg.buf), msg.type, msg.req, index);
-
- handle_msg(&msg, &elem);
- }
-}
-
-static void virtio_power_realize(DeviceState *dev, Error **errp)
-{
- INFO("initialize virtio-power device\n");
-
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vpower = VIRTIO_POWER(vdev);
-
- virtio_init(vdev, POWER_DEVICE_NAME, VIRTIO_ID_POWER, 0);
-
- if (vpower == NULL) {
- ERR("failed to initialize power device\n");
- return;
- }
-
- vpower->vq = virtio_add_queue(&vpower->vdev, 64, virtio_power_vq);
-}
-
-static void virtio_power_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- INFO("destroy power device\n");
-
- virtio_cleanup(vdev);
-}
-
-
-static void virtio_power_reset(VirtIODevice *vdev)
-{
- TRACE("virtio_power_reset.\n");
-}
-
-static uint32_t virtio_power_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_power_get_features.\n");
- return 0;
-}
-
-static void virtio_power_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->realize = virtio_power_realize;
- vdc->unrealize = virtio_power_unrealize;
- vdc->get_features = virtio_power_get_features;
- vdc->reset = virtio_power_reset;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_POWER,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOPOWER),
- .class_init = virtio_power_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
-
+++ /dev/null
-/*
- * Virtio Power Device
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung choi <jinhyung2.choi@samsung.com>
- * Daiyoung Kim <daiyoung777.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef MARU_VIRTIO_POWER_H_
-#define MARU_VIRTIO_POWER_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "hw/virtio/virtio.h"
-
-#define TYPE_VIRTIO_POWER "virtio-power-device"
-#define VIRTIO_POWER(obj) \
- OBJECT_CHECK(VirtIOPOWER, (obj), TYPE_VIRTIO_POWER)
-
-enum power_types {
- power_type_capacity = 0,
- power_type_charge_full,
- power_type_charge_now,
- power_type_max
-};
-
-typedef struct VirtIOPOWER {
- VirtIODevice vdev;
- VirtQueue *vq;
- DeviceState *qdev;
-
- QEMUBH *bh;
-} VirtIOPOWER;
-
-void set_power_capacity(int capacity);
-int get_power_capacity(void);
-void set_power_charge_full(int full);
-int get_power_charge_full(void);
-void set_power_charge_now(int now);
-int get_power_charge_now(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-/*
- * Virtio Sensor Device
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung Choi <jinhyung2.choi@samsung.com>
- * Daiyoung Kim <daiyoung777.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <pthread.h>
-
-#include "hw/pci/pci.h"
-
-#include "maru_device_ids.h"
-#include "maru_virtio_sensor.h"
-#include "debug_ch.h"
-#include "ecs/ecs.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-sensor);
-
-#define SENSOR_DEVICE_NAME "sensor"
-#define _MAX_BUF 1024
-#define __MAX_BUF_SENSOR 32
-
-static QemuMutex accel_mutex;
-static QemuMutex geo_mutex;
-static QemuMutex gyro_mutex;
-static QemuMutex light_mutex;
-static QemuMutex proxi_mutex;
-
-static char accel_xyz [__MAX_BUF_SENSOR] = {'0',',','9','8','0','6','6','5',',','0'};
-static int accel_enable = 0;
-static int accel_delay = 200000000;
-
-static char geo_raw [__MAX_BUF_SENSOR] = {'0',' ','-','9','0',' ','0',' ','3'};
-static char geo_tesla [__MAX_BUF_SENSOR] = {'1',' ','0',' ','-','1','0'};
-static int geo_enable = 0;
-static int geo_delay = 200000000;
-
-static int gyro_x_raw = 0;
-static int gyro_y_raw = 0;
-static int gyro_z_raw = 0;
-static int gyro_enable = 0;
-static int gyro_delay = 200000000;
-
-static int light_adc = 65535;
-static int light_level = 10;
-static int light_enable = 0;
-static int light_delay = 200000000;
-
-static int proxi_vo = 8;
-static int proxi_enable = 0;
-static int proxi_delay = 200000000;
-
-VirtIOSENSOR* vsensor;
-static int sensor_capability = 0;
-
-typedef struct msg_info {
- char buf[_MAX_BUF];
-
- uint16_t type;
- uint16_t req;
-} msg_info;
-
-static type_action get_action(enum sensor_types type)
-{
- type_action action = 0;
-
- switch (type) {
- case sensor_type_accel:
- action = ACTION_ACCEL;
- break;
- case sensor_type_gyro:
- action = ACTION_GYRO;
- break;
- case sensor_type_mag:
- action = ACTION_MAG;
- break;
- case sensor_type_light:
- action = ACTION_LIGHT;
- break;
- case sensor_type_proxi:
- action = ACTION_PROXI;
- break;
- default:
- break;
- }
-
- return action;
-}
-
-static void send_sensor_to_ecs(const char* data, enum sensor_types type)
-{
- type_length length = 0;
- type_group group = GROUP_STATUS;
- type_action action = 0;
- int buf_len = strlen(data);
- int message_len = buf_len + 14;
-
- char* ecs_message = (char*) malloc(message_len + 1);
- if (!ecs_message)
- return;
-
- memset(ecs_message, 0, message_len + 1);
-
- length = (unsigned short) buf_len;
- action = get_action(type);
-
- memcpy(ecs_message, MESSAGE_TYPE_SENSOR, 6);
- memcpy(ecs_message + 10, &length, sizeof(unsigned short));
- memcpy(ecs_message + 12, &group, sizeof(unsigned char));
- memcpy(ecs_message + 13, &action, sizeof(unsigned char));
- memcpy(ecs_message + 14, data, buf_len);
-
- TRACE("ntf_to_injector- len: %d, group: %d, action: %d, data: %s\n", length, group, action, data);
-
- send_device_ntf(ecs_message, message_len);
-
- if (ecs_message)
- free(ecs_message);
-}
-
-static void __set_sensor_data (enum sensor_types type, char* data, int len)
-{
- if (len < 0 || len > __MAX_BUF_SENSOR) {
- ERR("sensor data size is wrong.\n");
- return;
- }
-
- if (data == NULL) {
- ERR("sensor data is NULL.\n");
- return;
- }
-
- TRACE("set_sensor_data with type '%d' with data '%s'", type, data);
-
- switch (type) {
- case sensor_type_accel:
- qemu_mutex_lock(&accel_mutex);
- strcpy(accel_xyz, data);
- qemu_mutex_unlock(&accel_mutex);
- break;
- case sensor_type_accel_enable:
- qemu_mutex_lock(&accel_mutex);
- sscanf(data, "%d", &accel_enable);
- qemu_mutex_unlock(&accel_mutex);
- break;
- case sensor_type_accel_delay:
- qemu_mutex_lock(&accel_mutex);
- sscanf(data, "%d", &accel_delay);
- qemu_mutex_unlock(&accel_mutex);
- break;
- case sensor_type_gyro_enable:
- qemu_mutex_lock(&gyro_mutex);
- sscanf(data, "%d", &gyro_enable);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_delay:
- qemu_mutex_lock(&gyro_mutex);
- sscanf(data, "%d", &gyro_delay);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_x:
- qemu_mutex_lock(&gyro_mutex);
- sscanf(data, "%d", &gyro_x_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_y:
- qemu_mutex_lock(&gyro_mutex);
- sscanf(data, "%d", &gyro_y_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_z:
- qemu_mutex_lock(&gyro_mutex);
- sscanf(data, "%d", &gyro_z_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro:
- qemu_mutex_lock(&gyro_mutex);
- sscanf(data, "%d %d %d", &gyro_x_raw, &gyro_y_raw, &gyro_z_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_light_adc:
- qemu_mutex_lock(&light_mutex);
- sscanf(data, "%d", &light_adc);
- light_level = (light_adc / 6554) % 10 + 1;
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_light_level:
- qemu_mutex_lock(&light_mutex);
- sscanf(data, "%d", &light_level);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_light_enable:
- qemu_mutex_lock(&light_mutex);
- sscanf(data, "%d", &light_enable);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_light_delay:
- qemu_mutex_lock(&light_mutex);
- sscanf(data, "%d", &light_delay);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_proxi:
- qemu_mutex_lock(&proxi_mutex);
- sscanf(data, "%d", &proxi_vo);
- qemu_mutex_unlock(&proxi_mutex);
- break;
- case sensor_type_proxi_enable:
- qemu_mutex_lock(&proxi_mutex);
- sscanf(data, "%d", &proxi_enable);
- qemu_mutex_unlock(&proxi_mutex);
- break;
- case sensor_type_proxi_delay:
- qemu_mutex_lock(&proxi_mutex);
- sscanf(data, "%d", &proxi_delay);
- qemu_mutex_unlock(&proxi_mutex);
- break;
- case sensor_type_mag:
- qemu_mutex_lock(&geo_mutex);
- strcpy(geo_tesla, data);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_tilt:
- qemu_mutex_lock(&geo_mutex);
- strcpy(geo_raw, data);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_geo_enable:
- qemu_mutex_lock(&geo_mutex);
- sscanf(data, "%d", &geo_enable);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_geo_delay:
- qemu_mutex_lock(&geo_mutex);
- sscanf(data, "%d", &geo_delay);
- qemu_mutex_unlock(&geo_mutex);
- break;
- default:
- return;
- }
-}
-
-static void __get_sensor_data(enum sensor_types type, char* msg_info)
-{
- if (msg_info == NULL) {
- return;
- }
-
- switch (type) {
- case sensor_type_list:
- sprintf(msg_info, "%d", sensor_capability);
- break;
- case sensor_type_accel:
- qemu_mutex_lock(&accel_mutex);
- strcpy(msg_info, accel_xyz);
- qemu_mutex_unlock(&accel_mutex);
- break;
- case sensor_type_accel_enable:
- qemu_mutex_lock(&accel_mutex);
- sprintf(msg_info, "%d", accel_enable);
- qemu_mutex_unlock(&accel_mutex);
- break;
- case sensor_type_accel_delay:
- qemu_mutex_lock(&accel_mutex);
- sprintf(msg_info, "%d", accel_delay);
- qemu_mutex_unlock(&accel_mutex);
- break;
- case sensor_type_mag:
- qemu_mutex_lock(&geo_mutex);
- strcpy(msg_info, geo_tesla);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_tilt:
- qemu_mutex_lock(&geo_mutex);
- strcpy(msg_info, geo_raw);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_geo_enable:
- qemu_mutex_lock(&geo_mutex);
- sprintf(msg_info, "%d", geo_enable);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_geo_delay:
- qemu_mutex_lock(&geo_mutex);
- sprintf(msg_info, "%d", geo_delay);
- qemu_mutex_unlock(&geo_mutex);
- break;
- case sensor_type_gyro:
- qemu_mutex_lock(&gyro_mutex);
- sprintf(msg_info, "%d,%d,%d", gyro_x_raw, gyro_y_raw, gyro_z_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_enable:
- qemu_mutex_lock(&gyro_mutex);
- sprintf(msg_info, "%d", gyro_enable);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_delay:
- qemu_mutex_lock(&gyro_mutex);
- sprintf(msg_info, "%d", gyro_delay);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_x:
- qemu_mutex_lock(&gyro_mutex);
- sprintf(msg_info, "%d", gyro_x_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_y:
- qemu_mutex_lock(&gyro_mutex);
- sprintf(msg_info, "%d", gyro_y_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_gyro_z:
- qemu_mutex_lock(&gyro_mutex);
- sprintf(msg_info, "%d", gyro_z_raw);
- qemu_mutex_unlock(&gyro_mutex);
- break;
- case sensor_type_light:
- case sensor_type_light_adc:
- qemu_mutex_lock(&light_mutex);
- sprintf(msg_info, "%d", light_adc);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_light_level:
- qemu_mutex_lock(&light_mutex);
- sprintf(msg_info, "%d", light_level);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_light_enable:
- qemu_mutex_lock(&light_mutex);
- sprintf(msg_info, "%d", light_enable);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_light_delay:
- qemu_mutex_lock(&light_mutex);
- sprintf(msg_info, "%d", light_delay);
- qemu_mutex_unlock(&light_mutex);
- break;
- case sensor_type_proxi:
- qemu_mutex_lock(&proxi_mutex);
- sprintf(msg_info, "%d", proxi_vo);
- qemu_mutex_unlock(&proxi_mutex);
- break;
- case sensor_type_proxi_enable:
- qemu_mutex_lock(&proxi_mutex);
- sprintf(msg_info, "%d", proxi_enable);
- qemu_mutex_unlock(&proxi_mutex);
- break;
- case sensor_type_proxi_delay:
- qemu_mutex_lock(&proxi_mutex);
- sprintf(msg_info, "%d", proxi_delay);
- qemu_mutex_unlock(&proxi_mutex);
- break;
- default:
- return;
- }
-}
-
-void req_sensor_data (enum sensor_types type, enum request_cmd req, char* data, int len)
-{
- char msg_info [__MAX_BUF_SENSOR];
- memset(msg_info, 0, __MAX_BUF_SENSOR);
-
- if (type >= sensor_type_max || (req != request_get && req != request_set)) {
- ERR("unavailable sensor type request.\n");
- return;
- }
-
- if (req == request_set) {
- __set_sensor_data (type, data, len);
- } else if (req == request_get) {
- __get_sensor_data(type, msg_info);
- send_sensor_to_ecs(msg_info, type);
- }
-}
-
-static void answer_sensor_data_request(int type, char* data, VirtQueueElement *elem)
-{
- msg_info* msginfo = (msg_info*) malloc(sizeof(msg_info));
- if (!msginfo) {
- ERR("msginfo is NULL!\n");
- return;
- }
-
- msginfo->req = request_answer;
- msginfo->type = type;
- __get_sensor_data(type, msginfo->buf);
-
- TRACE("sending message: %s, type: %d, req: %d\n", msginfo->buf, msginfo->type, msginfo->req);
-
- memset(elem->in_sg[0].iov_base, 0, elem->in_sg[0].iov_len);
- memcpy(elem->in_sg[0].iov_base, msginfo, sizeof(struct msg_info));
-
- if (msginfo)
- free(msginfo);
-}
-
-static void handle_msg(struct msg_info *msg, VirtQueueElement *elem)
-{
- unsigned int len = 0;
-
- if (msg == NULL) {
- ERR("msg info structure is NULL.\n");
- return;
- }
-
- if (msg->req == request_set) {
- __set_sensor_data (msg->type, msg->buf, strlen(msg->buf));
- } else if (msg->req == request_get) {
- answer_sensor_data_request(msg->type, msg->buf, elem);
- len = sizeof(msg_info);
- }
-
- virtqueue_push(vsensor->vq, elem, len);
- virtio_notify(&vsensor->vdev, vsensor->vq);
-}
-
-static void virtio_sensor_vq(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOSENSOR *vsensor = (VirtIOSENSOR*)vdev;
- struct msg_info msg;
- VirtQueueElement elem;
- int index = 0;
-
- if (vsensor->vq == NULL) {
- ERR("virt queue is not ready.\n");
- return;
- }
-
- if (!virtio_queue_ready(vsensor->vq)) {
- ERR("virtqueue is not ready.");
- return;
- }
-
- if (virtio_queue_empty(vsensor->vq)) {
- ERR("<< virtqueue is empty.\n");
- return;
- }
-
- while ((index = virtqueue_pop(vq, &elem))) {
- memset(&msg, 0x00, sizeof(msg));
- memcpy(&msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
-
- TRACE("handling msg from driver: %s, len: %d, type: %d, req: %d, index: %d\n", msg.buf, strlen(msg.buf), msg.type, msg.req, index);
-
- handle_msg(&msg, &elem);
- }
-}
-
-static int set_capability(char* sensor)
-{
- if (!strncmp(sensor, SENSOR_NAME_ACCEL, 5)) {
- return sensor_cap_accel;
- } else if (!strncmp(sensor, SENSOR_NAME_GEO, 3)) {
- return sensor_cap_geo;
- } else if (!strncmp(sensor, SENSOR_NAME_GYRO, 4)) {
- return sensor_cap_gyro;
- } else if (!strncmp(sensor, SENSOR_NAME_LIGHT, 5)) {
- return sensor_cap_light;
- } else if (!strncmp(sensor, SENSOR_NAME_PROXI, 5)) {
- return sensor_cap_proxi;
- } else if (!strncmp(sensor, SENSOR_NAME_HAPTIC, 6)) {
- return sensor_cap_haptic;
- } else {
- ERR("unknown sensor request: %s", sensor);
- }
-
- return 0;
-}
-
-static void parse_sensor_capability(char* lists)
-{
- char token[] = SENSOR_CAP_TOKEN;
- char* data = NULL;
-
- if (lists == NULL)
- return;
-
- data = strtok(lists, token);
- if (data != NULL) {
- sensor_capability |= set_capability(data);
- while ((data = strtok(NULL, token)) != NULL) {
- sensor_capability |= set_capability(data);
- }
- }
-
- INFO("sensor device capabilty enabled with %02x\n", sensor_capability);
-}
-
-static void virtio_sensor_realize(DeviceState *dev, Error **errp)
-{
- INFO("initialize virtio-sensor device\n");
-
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- vsensor = VIRTIO_SENSOR(vdev);
-
- virtio_init(vdev, SENSOR_DEVICE_NAME, VIRTIO_ID_SENSOR, 0);
-
- if (vsensor == NULL) {
- ERR("failed to initialize sensor device\n");
- error_set(errp, QERR_DEVICE_INIT_FAILED, SENSOR_DEVICE_NAME);
- return;
- }
-
- qemu_mutex_init(&accel_mutex);
- qemu_mutex_init(&gyro_mutex);
- qemu_mutex_init(&geo_mutex);
- qemu_mutex_init(&light_mutex);
- qemu_mutex_init(&proxi_mutex);
-
- vsensor->vq = virtio_add_queue(&vsensor->vdev, 64, virtio_sensor_vq);
-
- INFO("initialized sensor type: %s\n", vsensor->sensors);
-
- if (vsensor->sensors) {
- parse_sensor_capability(vsensor->sensors);
- }
-}
-
-static void virtio_sensor_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- INFO("destroy sensor device\n");
-
- qemu_mutex_destroy(&accel_mutex);
- qemu_mutex_destroy(&gyro_mutex);
- qemu_mutex_destroy(&geo_mutex);
- qemu_mutex_destroy(&light_mutex);
- qemu_mutex_destroy(&proxi_mutex);
-
- virtio_cleanup(vdev);
-}
-
-
-static void virtio_sensor_reset(VirtIODevice *vdev)
-{
- TRACE("virtio_sensor_reset.\n");
-}
-
-static uint32_t virtio_sensor_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_sensor_get_features.\n");
- return 0;
-}
-
-static Property virtio_sensor_properties[] = {
- DEFINE_PROP_STRING(ATTRIBUTE_NAME_SENSORS, VirtIOSENSOR, sensors),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_sensor_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- dc->props = virtio_sensor_properties;
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->unrealize= virtio_sensor_unrealize;
- vdc->realize = virtio_sensor_realize;
- vdc->get_features = virtio_sensor_get_features;
- vdc->reset = virtio_sensor_reset;
-}
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_SENSOR,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOSENSOR),
- .class_init = virtio_sensor_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
-
+++ /dev/null
-/*
- * Virtio Sensor Device
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung choi <jinhyung2.choi@samsung.com>
- * Daiyoung Kim <daiyoung777.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef MARU_VIRTIO_SENSOR_H_
-#define MARU_VIRTIO_SENSOR_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "hw/virtio/virtio.h"
-
-enum request_cmd {
- request_get = 0,
- request_set,
- request_answer
-};
-
-enum sensor_types {
- sensor_type_list = 0,
- sensor_type_accel,
- sensor_type_accel_enable,
- sensor_type_accel_delay,
- sensor_type_geo,
- sensor_type_geo_enable,
- sensor_type_geo_delay,
- sensor_type_gyro,
- sensor_type_gyro_enable,
- sensor_type_gyro_delay,
- sensor_type_gyro_x,
- sensor_type_gyro_y,
- sensor_type_gyro_z,
- sensor_type_light,
- sensor_type_light_enable,
- sensor_type_light_delay,
- sensor_type_light_adc,
- sensor_type_light_level,
- sensor_type_proxi,
- sensor_type_proxi_enable,
- sensor_type_proxi_delay,
- sensor_type_mag,
- sensor_type_tilt,
- sensor_type_max
-};
-
-enum sensor_capabilities {
- sensor_cap_accel = 0x01,
- sensor_cap_geo = 0x02,
- sensor_cap_gyro = 0x04,
- sensor_cap_light = 0x08,
- sensor_cap_proxi = 0x10,
- sensor_cap_haptic = 0x20
-};
-
-#define MESSAGE_TYPE_SENSOR "sensor"
-
-#define GROUP_STATUS 15
-
-#define ACTION_ACCEL 110
-#define ACTION_GYRO 111
-#define ACTION_MAG 112
-#define ACTION_LIGHT 113
-#define ACTION_PROXI 114
-
-#define ATTRIBUTE_NAME_SENSORS "sensors"
-
-#define SENSOR_NAME_ACCEL "accel"
-#define SENSOR_NAME_GYRO "gyro"
-#define SENSOR_NAME_GEO "geo"
-#define SENSOR_NAME_LIGHT "light"
-#define SENSOR_NAME_PROXI "proxi"
-#define SENSOR_NAME_HAPTIC "haptic"
-
-#define SENSOR_CAP_TOKEN "&"
-
-#define TYPE_VIRTIO_SENSOR "virtio-sensor-device"
-#define VIRTIO_SENSOR(obj) \
- OBJECT_CHECK(VirtIOSENSOR, (obj), TYPE_VIRTIO_SENSOR)
-
-typedef struct VirtIOSENSOR {
- VirtIODevice vdev;
- VirtQueue *vq;
- DeviceState *qdev;
-
- char *sensors;
-} VirtIOSENSOR;
-
-void req_sensor_data(enum sensor_types type, enum request_cmd req, char* data, int len);
-
-#define get_sensor_accel() \
- req_sensor_data(sensor_type_accel, request_get, NULL, 0);
-
-#define get_sensor_gyro() \
- req_sensor_data(sensor_type_gyro, request_get, NULL, 0);
-
-#define get_sensor_mag() \
- req_sensor_data(sensor_type_mag, request_get, NULL, 0);
-
-#define get_sensor_light() \
- req_sensor_data(sensor_type_light_adc, request_get, NULL, 0);
-
-#define get_sensor_proxi() \
- req_sensor_data(sensor_type_proxi, request_get, NULL, 0);
-
-#define set_sensor_accel(data, len) \
- req_sensor_data(sensor_type_accel, request_set, data, len);
-
-#define set_sensor_proxi(data, len) \
- req_sensor_data(sensor_type_proxi, request_set, data, len);
-
-#define set_sensor_light(data, len) \
- req_sensor_data(sensor_type_light_adc, request_set, data, len);
-
-#define set_sensor_gyro(data, len) \
- req_sensor_data(sensor_type_gyro, request_set, data, len);
-
-#define set_sensor_tilt(data, len) \
- req_sensor_data(sensor_type_tilt, request_set, data, len);
-
-#define set_sensor_mag(data, len) \
- req_sensor_data(sensor_type_mag, request_set, data, len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+++ /dev/null
-/*
- * Maru Virtio Touchscreen Device
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#include <pthread.h>
-#include "maru_virtio_touchscreen.h"
-#include "maru_device_ids.h"
-#include "emul_state.h"
-#include "debug_ch.h"
-
-MULTI_DEBUG_CHANNEL(qemu, touchscreen);
-
-
-#define DEVICE_NAME "virtio-touchscreen"
-
-/*
- * touch event queue
- */
-typedef struct TouchEventEntry {
- unsigned int index;
- EmulTouchEvent touch;
-
- QTAILQ_ENTRY(TouchEventEntry) node;
-} TouchEventEntry;
-
-/* the maximum number of touch event that can be put into a queue */
-#define MAX_TOUCH_EVENT_CNT 256
-
-static TouchEventEntry _events_buf[MAX_TOUCH_EVENT_CNT];
-static QTAILQ_HEAD(, TouchEventEntry) events_queue =
- QTAILQ_HEAD_INITIALIZER(events_queue);
-
-static unsigned int event_ringbuf_cnt; /* _events_buf */
-static unsigned int event_queue_cnt; /* events_queue */
-
-/*
- * VirtQueueElement queue
- */
-typedef struct ElementEntry {
- unsigned int el_index;
- unsigned int sg_index;
- VirtQueueElement elem;
-
- QTAILQ_ENTRY(ElementEntry) node;
-} ElementEntry;
-
-static ElementEntry _elem_buf[10];
-static QTAILQ_HEAD(, ElementEntry) elem_queue =
- QTAILQ_HEAD_INITIALIZER(elem_queue);
-
-static unsigned int elem_ringbuf_cnt; /* _elem_buf */
-static unsigned int elem_queue_cnt; /* elem_queue */
-
-
-VirtIOTouchscreen *ts;
-
-/* lock for between communication thread and IO thread */
-static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t elem_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
-void virtio_touchscreen_event(int x, int y, int z, int buttons_state)
-{
- TouchEventEntry *entry = NULL;
-
- if (unlikely(!virtio_queue_ready(ts->vq))) {
- ERR("virtio queue is not ready\n");
- return;
- }
-
- if (unlikely(event_queue_cnt >= MAX_TOUCH_EVENT_CNT)) {
- INFO("full touch event queue, lose event\n", event_queue_cnt);
-
- qemu_bh_schedule(ts->bh);
- return;
- }
-
- entry = &(_events_buf[event_ringbuf_cnt % MAX_TOUCH_EVENT_CNT]);
- event_ringbuf_cnt++;
-
- /* mouse event is copied into the queue */
- entry->touch.x = x;
- entry->touch.y = y;
- entry->touch.z = z;
- entry->touch.state = buttons_state;
-
- pthread_mutex_lock(&event_mutex);
-
- entry->index = ++event_queue_cnt; /* 1 ~ */
-
- QTAILQ_INSERT_TAIL(&events_queue, entry, node);
-
- pthread_mutex_unlock(&event_mutex);
-
- /* call maru_virtio_touchscreen_notify */
- qemu_bh_schedule(ts->bh);
-
- TRACE("touch event (%d) : x=%d, y=%d, z=%d, state=%d\n",
- entry->index, entry->touch.x, entry->touch.y,
- entry->touch.z, entry->touch.state);
-}
-
-static void maru_virtio_touchscreen_handle(VirtIODevice *vdev, VirtQueue *vq)
-{
-#if 0 /* not used yet */
- if (ts->eh_entry == NULL) {
- void *vbuf = NULL;
- VirtQueueElement elem;
- int max_trkid = 0;
-
- virtqueue_pop(ts->vq, &elem);
- vbuf = elem.in_sg[0].iov_base;
- memcpy(&max_trkid, vbuf, sizeof(max_trkid));
-
- if (max_trkid > 0) {
- INFO("virtio touchscreen's maximum of tracking id = %d\n", max_trkid);
-
- /* register a event handler */
- ts->eh_entry = qemu_add_mouse_event_handler(
- virtio_touchscreen_event, ts, 1, "QEMU Virtio Touchscreen");
- qemu_activate_mouse_event_handler(ts->eh_entry);
-
- //TODO:
- virtqueue_push(ts->vq, &elem, 0);
- virtio_notify(&(ts->vdev), ts->vq);
- } else {
- INFO("virtio touchscreen is not added to qemu mouse event handler\n");
- }
- }
-#endif
-
- int virt_sg_index = 0;
- ElementEntry *elem_entry = NULL;
-
- TRACE("maru_virtio_touchscreen_handle\n");
-
- if (unlikely(virtio_queue_empty(ts->vq))) {
- TRACE("virtqueue is empty\n");
- return;
- }
-
- while (true) {
- elem_entry = &(_elem_buf[elem_ringbuf_cnt % 10]);
- elem_ringbuf_cnt++;
-
- virt_sg_index = virtqueue_pop(ts->vq, &elem_entry->elem);
- if (virt_sg_index == 0) {
- elem_ringbuf_cnt--;
- break;
- } else if (virt_sg_index < 0) {
- ERR("virtqueue is broken\n");
- elem_ringbuf_cnt--;
- return;
- }
-
- pthread_mutex_lock(&elem_mutex);
-
- elem_entry->el_index = ++elem_queue_cnt;
- elem_entry->sg_index = (unsigned int)virt_sg_index;
-
- /* save VirtQueueElement */
- QTAILQ_INSERT_TAIL(&elem_queue, elem_entry, node);
-
- if (ts->waitBuf == true) {
- ts->waitBuf = false;
-
- /* call maru_virtio_touchscreen_notify */
- qemu_bh_schedule(ts->bh);
- }
-
- pthread_mutex_unlock(&elem_mutex);
- }
-}
-
-void maru_virtio_touchscreen_notify(void)
-{
- ElementEntry *elem_entry = NULL;
- unsigned int ii = 0;
-
- TRACE("maru_virtio_touchscreen_notify\n");
-
- if (unlikely(!virtio_queue_ready(ts->vq))) {
- ERR("virtio queue is not ready\n");
- return;
- }
-
- while (true) {
- if (event_queue_cnt == 0) {
- TRACE("no event\n");
- break;
- } else if (elem_queue_cnt == 0) {
- TRACE("no buffer\n");
-
- pthread_mutex_lock(&elem_mutex);
- /* maybe next time */
- ts->waitBuf = true;
- pthread_mutex_unlock(&elem_mutex);
- break;
- }
-
- elem_entry = QTAILQ_FIRST(&elem_queue);
-
- if (elem_entry->sg_index > 0) {
- TouchEventEntry *event_entry = NULL;
- VirtQueueElement *element = NULL;
- void *vbuf = NULL;
-
- element = &elem_entry->elem;
- vbuf = element->in_sg[elem_entry->sg_index - 1].iov_base;
-
- /* get touch event from host queue */
- event_entry = QTAILQ_FIRST(&events_queue);
-
- TRACE("touch(%d) : x=%d, y=%d, z=%d, state=%d | \
- event_queue_cnt=%d, elem.index=%d, elem.in_num=%d, sg_index=%d\n",
- event_entry->index, event_entry->touch.x, event_entry->touch.y,
- event_entry->touch.z, event_entry->touch.state,
- event_queue_cnt, element->index, element->in_num,
- elem_entry->sg_index);
-
- /* copy event into virtio buffer */
- memcpy(vbuf, &(event_entry->touch), sizeof(event_entry->touch));
-
- pthread_mutex_lock(&event_mutex);
-
- /* remove host event */
- QTAILQ_REMOVE(&events_queue, event_entry, node);
- event_queue_cnt--;
-
- pthread_mutex_unlock(&event_mutex);
-
- /* put buffer into virtio queue */
- virtqueue_fill(ts->vq, element, sizeof(EmulTouchEvent), ii++);
- }
-
- pthread_mutex_lock(&elem_mutex);
-
- QTAILQ_REMOVE(&elem_queue, elem_entry, node);
- elem_queue_cnt--;
-
- pthread_mutex_unlock(&elem_mutex);
- }
-
- if (ii != 0) {
- /* signal other side */
- virtqueue_flush(ts->vq, ii);
- /* notify to guest */
- virtio_notify(&(ts->vdev), ts->vq);
- }
-}
-
-static void virtio_touchscreen_get_config(
- VirtIODevice *vdev, uint8_t *config_data)
-{
- int max_trkid = 10;
- INFO("virtio_touchscreen_get_config\n");
-
- max_trkid = get_emul_max_touch_point();
- memcpy(config_data, &max_trkid, 4);
-}
-
-static void virtio_touchscreen_set_config(
- VirtIODevice *vdev, const uint8_t *config_data)
-{
- /* do nothing */
-}
-
-static uint32_t virtio_touchscreen_get_features(
- VirtIODevice *vdev, uint32_t request_features)
-{
- /* do nothing */
-
- return request_features;
-}
-
-static void maru_touchscreen_bh(void *opaque)
-{
- //TouchscreenState *ts = (TouchscreenState *)opaque;
-
- maru_virtio_touchscreen_notify();
-}
-
-static void virtio_touchscreen_device_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
- ts = VIRTIO_TOUCHSCREEN(dev);
-
- INFO("initialize touchscreen device : %d\n", ts->max_finger);
-
- virtio_init(vdev, DEVICE_NAME, VIRTIO_ID_TOUCHSCREEN, 4);
- /*if (ts == NULL) {
- ERR("failed to initialize the touchscreen device\n");
- return NULL;
- }*/
-
- // TODO: reduce size
- ts->vq = virtio_add_queue(&ts->vdev, 64, maru_virtio_touchscreen_handle);
- ts->qdev = dev;
-
- /* bottom halves */
- ts->bh = qemu_bh_new(maru_touchscreen_bh, ts);
-}
-
-static void virtio_touchscreen_device_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- INFO("exit the touchscreen device\n");
-
- if (ts->bh) {
- qemu_bh_delete(ts->bh);
- }
-
- virtio_cleanup(vdev);
-
- pthread_mutex_destroy(&event_mutex);
- pthread_mutex_destroy(&elem_mutex);
-}
-
-static Property virtio_touchscreen_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_touchscreen_device_reset(VirtIODevice *vdev)
-{
- TouchEventEntry *event_entry = NULL;
- ElementEntry *elem_entry = NULL;
-
- INFO("reset the touchscreen device\n");
-
- /* reset the counters */
- event_ringbuf_cnt = 0;
- elem_ringbuf_cnt = 0;
-
- /* reset queue */
- pthread_mutex_lock(&event_mutex);
- while (event_queue_cnt > 0) {
- event_entry = QTAILQ_FIRST(&events_queue);
- QTAILQ_REMOVE(&events_queue, event_entry, node);
-
- event_queue_cnt--;
- }
- pthread_mutex_unlock(&event_mutex);
-
- pthread_mutex_lock(&elem_mutex);
- while (elem_queue_cnt > 0) {
- elem_entry = QTAILQ_FIRST(&elem_queue);
- QTAILQ_REMOVE(&elem_queue, elem_entry, node);
-
- elem_queue_cnt--;
- }
-
- ts->waitBuf = false;
- pthread_mutex_unlock(&elem_mutex);
-}
-
-static void virtio_touchscreen_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-
- dc->props = virtio_touchscreen_properties;
- vdc->realize = virtio_touchscreen_device_realize;
- vdc->unrealize = virtio_touchscreen_device_unrealize;
- vdc->reset = virtio_touchscreen_device_reset;
- vdc->get_config = virtio_touchscreen_get_config;
- vdc->set_config = virtio_touchscreen_set_config;
- vdc->get_features = virtio_touchscreen_get_features;
-}
-
-static const TypeInfo virtio_touchscreen_info = {
- .name = TYPE_VIRTIO_TOUCHSCREEN,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOTouchscreen),
- .class_init = virtio_touchscreen_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_touchscreen_info);
-}
-
-type_init(virtio_register_types)
+++ /dev/null
-/*
- * Maru Virtio Touchscreen Device
- *
- * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * GiWoong Kim <giwoong.kim@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-
-#ifndef MARU_TOUCHSCREEN_H_
-#define MARU_TOUCHSCREEN_H_
-
-#include "hw/virtio/virtio.h"
-
-#define TYPE_VIRTIO_TOUCHSCREEN "virtio-touchscreen-device"
-#define VIRTIO_TOUCHSCREEN(obj) \
- OBJECT_CHECK(VirtIOTouchscreen, (obj), TYPE_VIRTIO_TOUCHSCREEN)
-
-#define TOUCHSCREEN_OPTION_NAME "max_point"
-#define DEFAULT_MAX_FINGER (1)
-
-typedef struct VirtIOTouchscreen {
- VirtIODevice vdev;
- /* simply a queue into which buffers are posted
- by the guest for consumption by the host */
- VirtQueue *vq;
- bool waitBuf;
-
- QEMUBH *bh;
- DeviceState *qdev;
-
- unsigned int max_finger;
-} VirtIOTouchscreen;
-
-/* This structure must match the kernel definitions */
-typedef struct EmulTouchEvent {
- uint16_t x, y, z;
- uint8_t state;
-} EmulTouchEvent;
-
-void virtio_touchscreen_event(int x, int y, int z, int buttons_state);
-void maru_virtio_touchscreen_notify(void);
-
-#endif /* MARU_TOUCHSCREEN_H_ */
+++ /dev/null
-/*
- * Virtio Virtual Modem Device
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Sooyoung Ha <yoosah.ha@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * Sangho Park <sangho1206.park@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "maru_device_ids.h"
-#include "maru_virtio_vmodem.h"
-#include "maru_virtio_evdi.h"
-#include "debug_ch.h"
-#include "ecs/ecs.h"
-
-MULTI_DEBUG_CHANNEL(qemu, virtio-vmodem);
-
-#define VMODEM_DEVICE_NAME "virtio-vmodem"
-
-enum {
- IOTYPE_INPUT = 0,
- IOTYPE_OUTPUT = 1
-};
-
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif
-
-VirtIOVModem *vio_vmodem;
-
-typedef struct MsgInfo
-{
- msg_info info;
- QTAILQ_ENTRY(MsgInfo) next;
-}MsgInfo;
-
-static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) vmodem_recv_msg_queue =
- QTAILQ_HEAD_INITIALIZER(vmodem_recv_msg_queue);
-
-typedef struct EvdiBuf {
- VirtQueueElement elem;
-
- QTAILQ_ENTRY(EvdiBuf) next;
-} EvdiBuf;
-
-static QTAILQ_HEAD(EvdiMsgHead , EvdiBuf) vmodem_in_queue =
- QTAILQ_HEAD_INITIALIZER(vmodem_in_queue);
-
-bool send_to_vmodem(const uint32_t route, char *data, const uint32_t len)
-{
- int size;
- int left = len;
- int count = 0;
- char *readptr = data;
-
- while (left > 0) {
- MsgInfo *_msg = (MsgInfo*) malloc(sizeof(MsgInfo));
- if (!_msg) {
- ERR("malloc failed\n");
- return false;
- }
-
- memset(&_msg->info, 0, sizeof(msg_info));
-
- size = min(left, __MAX_BUF_SIZE);
- memcpy(_msg->info.buf, readptr, size);
- readptr += size;
- _msg->info.use = size;
- _msg->info.index = count;
-
- qemu_mutex_lock(&vio_vmodem->mutex);
-
- QTAILQ_INSERT_TAIL(&vmodem_recv_msg_queue, _msg, next);
-
- qemu_mutex_unlock(&vio_vmodem->mutex);
-
- left -= size;
- count ++;
- }
-
- qemu_bh_schedule(vio_vmodem->bh);
-
- return true;
-}
-
-static void flush_vmodem_recv_queue(void)
-{
- int index;
-
- if (unlikely(!virtio_queue_ready(vio_vmodem->rvq))) {
- ERR("virtio queue is not ready\n");
- return;
- }
-
- if (unlikely(virtio_queue_empty(vio_vmodem->rvq))) {
- ERR("virtqueue is empty\n");
- return;
- }
-
- qemu_mutex_lock(&vio_vmodem->mutex);
-
- while (!QTAILQ_EMPTY(&vmodem_recv_msg_queue))
- {
- MsgInfo *msginfo = QTAILQ_FIRST(&vmodem_recv_msg_queue);
- if (!msginfo)
- break;
-
- VirtQueueElement elem;
- index = virtqueue_pop(vio_vmodem->rvq, &elem);
- if (index == 0) {
- break;
- }
-
- memset(elem.in_sg[0].iov_base, 0, elem.in_sg[0].iov_len);
- memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct msg_info));
-
- virtqueue_push(vio_vmodem->rvq, &elem, sizeof(msg_info));
- virtio_notify(&vio_vmodem->vdev, vio_vmodem->rvq);
-
- QTAILQ_REMOVE(&vmodem_recv_msg_queue, msginfo, next);
- if (msginfo)
- free(msginfo);
- }
- qemu_mutex_unlock(&vio_vmodem->mutex);
-}
-
-
-static void virtio_vmodem_recv(VirtIODevice *vdev, VirtQueue *vq)
-{
- flush_vmodem_recv_queue();
-}
-
-static void virtio_vmodem_send(VirtIODevice *vdev, VirtQueue *vq)
-{
- VirtIOVModem *vvmodem = (VirtIOVModem *)vdev;
- int index = 0;
- struct msg_info _msg;
-
- if (virtio_queue_empty(vvmodem->svq)) {
- ERR("virtqueue is empty.\n");
- return;
- }
-
- VirtQueueElement elem;
-
- while ((index = virtqueue_pop(vq, &elem))) {
- memset(&_msg, 0x00, sizeof(_msg));
- memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
-
- TRACE("vmodem send to ecp.\n");
- send_injector_ntf(_msg.buf, _msg.use);
- }
-
- virtqueue_push(vq, &elem, sizeof(VirtIOVModem));
- virtio_notify(&vio_vmodem->vdev, vq);
-}
-
-static uint32_t virtio_vmodem_get_features(VirtIODevice *vdev,
- uint32_t request_feature)
-{
- TRACE("virtio_vmodem_get_features.\n");
- return 0;
-}
-
-static void maru_vmodem_bh(void *opaque)
-{
- flush_vmodem_recv_queue();
-}
-
-static void virtio_vmodem_realize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- vio_vmodem = VIRTIO_VMODEM(vdev);
-
- if (vio_vmodem == NULL) {
- ERR("failed to initialize vmodem device\n");
- return;
- }
-
- virtio_init(vdev, TYPE_VIRTIO_VMODEM, VIRTIO_ID_VMODEM, 0); //VMODEM_DEVICE_NAME
- qemu_mutex_init(&vio_vmodem->mutex);
-
- vio_vmodem->rvq = virtio_add_queue(&vio_vmodem->vdev, 256, virtio_vmodem_recv);
- vio_vmodem->svq = virtio_add_queue(&vio_vmodem->vdev, 256, virtio_vmodem_send);
- vio_vmodem->qdev = dev;
-
- vio_vmodem->bh = qemu_bh_new(maru_vmodem_bh, vio_vmodem);
-
- INFO("finish the vmodem device initialization.\n");
-}
-
-static void virtio_vmodem_unrealize(DeviceState *dev, Error **errp)
-{
- VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
- INFO("destroy vmodem device\n");
-
- if (vio_vmodem->bh) {
- qemu_bh_delete(vio_vmodem->bh);
- }
-
- qemu_mutex_destroy(&vio_vmodem->mutex);
- virtio_cleanup(vdev);
-}
-
-static void virtio_vmodem_reset(VirtIODevice *vdev)
-{
- INFO("virtio_vmodem_reset.\n");
-}
-
-
-static void virtio_vmodem_class_init(ObjectClass *klass, void *data)
-{
- VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- vdc->realize = virtio_vmodem_realize;
- vdc->unrealize = virtio_vmodem_unrealize;
- vdc->get_features = virtio_vmodem_get_features;
- vdc->reset = virtio_vmodem_reset;
-}
-
-
-
-static const TypeInfo virtio_device_info = {
- .name = TYPE_VIRTIO_VMODEM,
- .parent = TYPE_VIRTIO_DEVICE,
- .instance_size = sizeof(VirtIOVModem),
- .class_init = virtio_vmodem_class_init,
-};
-
-static void virtio_register_types(void)
-{
- type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
+++ /dev/null
-/*
- * Virtio Virtual Modem Device
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Sooyoung Ha <yoosah.ha@samsung.com>
- * SeokYeon Hwang <syeon.hwang@samsung.com>
- * Sangho Park <sangho1206.park@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef MARU_VIRTIO_VMODEM_H_
-#define MARU_VIRTIO_VMODEM_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "hw/virtio/virtio.h"
-
-typedef struct VirtIOVirtualModem{
- VirtIODevice vdev;
- VirtQueue *rvq;
- VirtQueue *svq;
- DeviceState *qdev;
-
- QemuMutex mutex;
- QEMUBH *bh;
-} VirtIOVModem;
-
-#define TYPE_VIRTIO_VMODEM "virtio-vmodem-device"
-#define VIRTIO_VMODEM(obj) \
- OBJECT_CHECK(VirtIOVModem, (obj), TYPE_VIRTIO_VMODEM)
-
-bool send_to_vmodem(const uint32_t route, char *data, const uint32_t len);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* MARU_VIRTIO_VMODEM_H_ */
--- /dev/null
+obj-y += maru_brill_codec.o
+obj-y += maru_brightness.o
+
+obj-y += maru_camera_common_pci.o
+ifdef CONFIG_LINUX
+obj-y += maru_camera_linux_pci.o
+LIBS += -lv4l2 -lv4lconvert
+endif
+ifdef CONFIG_WIN32
+obj-y += maru_camera_win32_pci.o
+LIBS += -lole32 -loleaut32 -luuid -lstrmiids
+endif
+ifdef CONFIG_DARWIN
+obj-y += maru_camera_darwin_converter.o
+obj-y += maru_camera_darwin_pci.o
+LIBS += -framework Foundation -framework SystemConfiguration
+LIBS += -framework Cocoa -framework QTKit -framework CoreVideo
+LIBS += -framework AppKit
+endif
--- /dev/null
+/*
+ * Maru brightness device for VGA
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun
+ * DoHyung Hong
+ * Hyunjun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "hw/i386/pc.h"
+#include "ui/console.h"
+#include "hw/pci/pci.h"
+#include "hw/maru_device_ids.h"
+#include "maru_brightness.h"
+#include "skin/maruskin_server.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru-brightness);
+
+#define QEMU_DEV_NAME "maru-brightness"
+
+#define BRIGHTNESS_MEM_SIZE (4 * 1024) /* 4KB */
+#define BRIGHTNESS_REG_SIZE 256
+
+typedef struct BrightnessState {
+ PCIDevice dev;
+ MemoryRegion mmio_addr;
+} BrightnessState;
+
+enum {
+ BRIGHTNESS_LEVEL = 0x00,
+ BRIGHTNESS_OFF = 0x04,
+};
+
+uint32_t brightness_level = BRIGHTNESS_MAX;
+bool display_off;
+pixman_color_t level_color;
+pixman_image_t *brightness_image;
+
+/* level : 1 ~ 100, interval : 1 or 2 */
+uint8_t brightness_tbl[] = {155, /* level 0 : for dimming */
+/* level 01 ~ 10 */ 149, 147, 146, 144, 143, 141, 140, 138, 137, 135,
+/* level 11 ~ 20 */ 134, 132, 131, 129, 128, 126, 125, 123, 122, 120,
+/* level 21 ~ 30 */ 119, 117, 116, 114, 113, 111, 110, 108, 107, 105,
+/* level 31 ~ 40 */ 104, 102, 101, 99, 98, 96, 95, 93, 92, 90,
+/* level 41 ~ 50 */ 89, 87, 86, 84, 83, 81, 80, 78, 77, 75,
+/* level 51 ~ 60 */ 74, 72, 71, 69, 68, 66, 65, 63, 62, 60,
+/* level 61 ~ 70 */ 59, 57, 56, 54, 53, 51, 50, 48, 47, 45,
+/* level 71 ~ 80 */ 44, 42, 41, 39, 38, 36, 35, 33, 32, 30,
+/* level 81 ~ 90 */ 29, 27, 26, 24, 23, 21, 20, 18, 17, 15,
+/* level 91 ~ 99 */ 14, 12, 11, 9, 8, 6, 5, 3, 2, 0};
+
+QEMUBH *display_bh;
+
+static uint64_t brightness_reg_read(void *opaque,
+ hwaddr addr,
+ unsigned size)
+{
+ switch (addr & 0xFF) {
+ case BRIGHTNESS_LEVEL:
+ INFO("current brightness level = %lu\n", brightness_level);
+ return brightness_level;
+ case BRIGHTNESS_OFF:
+ INFO("device is turned %s\n", display_off ? "off" : "on");
+ return display_off;
+ default:
+ ERR("wrong brightness register read - addr : %d\n", (int)addr);
+ break;
+ }
+
+ return 0;
+}
+
+static void maru_pixman_image_set_alpha(uint8_t value)
+{
+ if (brightness_image) {
+ pixman_image_unref(brightness_image);
+ }
+ level_color.alpha = value << 8;
+ brightness_image = pixman_image_create_solid_fill(&level_color);
+
+ graphic_hw_invalidate(NULL);
+}
+
+static void brightness_reg_write(void *opaque,
+ hwaddr addr,
+ uint64_t val,
+ unsigned size)
+{
+ switch (addr & 0xFF) {
+ case BRIGHTNESS_LEVEL:
+ if (brightness_level == val) {
+ return;
+ }
+#if BRIGHTNESS_MIN > 0
+ if (val < BRIGHTNESS_MIN || val > BRIGHTNESS_MAX) {
+#else
+ if (val > BRIGHTNESS_MAX) {
+#endif
+ ERR("input value is out of range(%llu)\n", val);
+ } else {
+ INFO("level changes: %lu -> %llu\n", brightness_level, val);
+ brightness_level = val;
+ maru_pixman_image_set_alpha(brightness_tbl[brightness_level]);
+ }
+ return;
+ case BRIGHTNESS_OFF:
+ if (display_off == val) {
+ return;
+ }
+
+ INFO("status changes: %s\n", val ? "OFF" : "ON");
+
+ display_off = val;
+ if (display_off) {
+ maru_pixman_image_set_alpha(0xFF); /* set black */
+ } else {
+ maru_pixman_image_set_alpha(brightness_tbl[brightness_level]);
+ }
+
+ /* notify to skin process */
+ qemu_bh_schedule(display_bh);
+
+ return;
+ default:
+ ERR("wrong brightness register write - addr : %d\n", (int)addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps brightness_mmio_ops = {
+ .read = brightness_reg_read,
+ .write = brightness_reg_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void brightness_exitfn(PCIDevice *dev)
+{
+ BrightnessState *s = DO_UPCAST(BrightnessState, dev, dev);
+
+ if (display_bh) {
+ qemu_bh_delete(display_bh);
+ }
+ if (brightness_image) {
+ pixman_image_unref(brightness_image);
+ brightness_image = NULL;
+ }
+
+ memory_region_destroy(&s->mmio_addr);
+ INFO("finalize maru-brightness device\n");
+}
+
+static void maru_display_bh(void *opaque)
+{
+ notify_display_power(!display_off);
+}
+
+static int brightness_initfn(PCIDevice *dev)
+{
+ BrightnessState *s = DO_UPCAST(BrightnessState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_TIZEN);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIRTUAL_BRIGHTNESS);
+ pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_OTHER);
+
+ memory_region_init_io(&s->mmio_addr, OBJECT(s), &brightness_mmio_ops, s,
+ "maru-brightness-mmio", BRIGHTNESS_REG_SIZE);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_addr);
+
+ display_bh = qemu_bh_new(maru_display_bh, s);
+ brightness_level = BRIGHTNESS_MAX;
+ level_color.alpha = 0x0000;
+ level_color.red = 0x0000;
+ level_color.green = 0x0000;
+ level_color.blue = 0x0000;
+ brightness_image = pixman_image_create_solid_fill(&level_color);
+ INFO("initialize maru-brightness device\n");
+
+ return 0;
+}
+
+static void brightness_classinit(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = brightness_initfn;
+ k->exit = brightness_exitfn;
+}
+
+static TypeInfo brightness_info = {
+ .name = QEMU_DEV_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(BrightnessState),
+ .class_init = brightness_classinit,
+};
+
+static void brightness_register_types(void)
+{
+ type_register_static(&brightness_info);
+}
+
+type_init(brightness_register_types);
--- /dev/null
+/*
+ * Maru brightness device for VGA
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * Hyunjun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_BRIGHTNESS_H_
+#define MARU_BRIGHTNESS_H_
+
+#include "qemu-common.h"
+#include "ui/qemu-pixman.h"
+
+#define BRIGHTNESS_MIN (0)
+#define BRIGHTNESS_MAX (100)
+
+extern uint32_t brightness_level;
+extern bool display_off;
+extern uint8_t brightness_tbl[];
+extern pixman_image_t *brightness_image;
+
+#endif /* MARU_BRIGHTNESS_H_ */
--- /dev/null
+/*
+ * Virtual Codec Device
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "maru_brill_codec.h"
+
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, brillcodec);
+
+// device
+#define CODEC_DEVICE_NAME "codec-pci"
+#define CODEC_DEVICE_THREAD "codec-workthread"
+#define CODEC_VERSION 2
+
+// 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
+#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);
+
+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, 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;
+
+ qemu_mutex_lock(&s->context_mutex);
+ s->idle_thread_cnt = 0;
+ qemu_mutex_unlock(&s->context_mutex);
+
+ for (index = 0; index < s->worker_thread_cnt; index++) {
+ qemu_thread_create(&pthread[index], CODEC_DEVICE_THREAD,
+ 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);
+
+ qemu_mutex_lock(&s->context_mutex);
+
+ if (ioparam->api_index != CODEC_INIT) {
+ if (!s->context[ioparam->ctx_index].opened_context) {
+ INFO("abandon api %d for context %d\n",
+ ioparam->api_index, ioparam->ctx_index);
+ qemu_mutex_unlock(&s->context_mutex);
+ return;
+ }
+ }
+
+ qemu_mutex_unlock(&s->context_mutex);
+
+ 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;
+ bool ret = false;
+
+ TRACE("enter: %s\n", __func__);
+
+ while (s->is_thread_running) {
+ int ctx_id = 0, api_id = 0;
+ 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);
+
+ qemu_mutex_lock(&s->context_mutex);
+ s->context[ctx_id].occupied_thread = true;
+ qemu_mutex_unlock(&s->context_mutex);
+
+ ret = codec_func_handler[api_id](s, ctx_id, indata_buf);
+ if (!ret) {
+ ERR("fail api %d for context %d\n", api_id, ctx_id);
+ g_free(elem->param_buf);
+ continue;
+ }
+
+ TRACE("release a buffer of CodecParam\n");
+ g_free(elem->param_buf);
+ elem->param_buf = NULL;
+
+ if (elem->data_buf) {
+ if (elem->data_buf->buf) {
+ TRACE("release inbuf\n");
+ g_free(elem->data_buf->buf);
+ elem->data_buf->buf = NULL;
+ }
+
+ TRACE("release a buffer indata_buf\n");
+ g_free(elem->data_buf);
+ elem->data_buf = NULL;
+ }
+
+ TRACE("release an element of CodecDataStg\n");
+ g_free(elem);
+
+ qemu_mutex_lock(&s->context_mutex);
+ if (s->context[ctx_id].requested_close) {
+ INFO("make worker thread to handle deinit\n");
+ // codec_deinit(s, ctx_id, NULL);
+ maru_brill_codec_release_context(s, ctx_id);
+ s->context[ctx_id].requested_close = false;
+ }
+ qemu_mutex_unlock(&s->context_mutex);
+
+ TRACE("switch context to raise interrupt.\n");
+ qemu_bh_schedule(s->codec_bh);
+
+ qemu_mutex_lock(&s->context_mutex);
+ s->context[ctx_id].occupied_thread = false;
+ qemu_mutex_unlock(&s->context_mutex);
+ }
+
+ 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_INIT ... 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,
+ CodecParam *ioparam)
+{
+ DeviceMemEntry *elem = NULL;
+ int readbuf_size, size = 0;
+ uint8_t *readbuf = NULL;
+ uint8_t *device_mem = mem_base + 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 0. api_id %d, ctx_id %d, mem_offset %x\n",
+ 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;
+ }
+
+ INFO("codec_init. video, resolution: %dx%d, framerate: %d/%d "
+ "pixel_fmt: %d sample_aspect_ratio: %d/%d bpp %d\n",
+ avctx->width, avctx->height, avctx->time_base.num,
+ avctx->time_base.den, avctx->pix_fmt, avctx->sample_aspect_ratio.num,
+ avctx->sample_aspect_ratio.den, avctx->bits_per_coded_sample);
+}
+
+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;
+ }
+
+ INFO("codec_init. audio, channel %d sample_rate %d sample_fmt %d ch_layout %lld\n",
+ avctx->channels, avctx->sample_rate, avctx->sample_fmt, avctx->channel_layout);
+}
+
+#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);
+
+ qemu_mutex_lock(&s->threadpool.mutex);
+ if (s->context[context_id].opened_context) {
+ // qemu_mutex_unlock(&s->threadpool.mutex);
+ codec_deinit(s, context_id, NULL);
+ // qemu_mutex_lock(&s->threadpool.mutex);
+ }
+ s->context[context_id].occupied_context = false;
+ qemu_mutex_unlock(&s->threadpool.mutex);
+
+ // 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__);
+
+ // requires mutex_lock? its function is protected by critical section.
+ qemu_mutex_lock(&s->threadpool.mutex);
+ for (index = 1; index < CODEC_CONTEXT_MAX; index++) {
+ if (s->context[index].occupied_context == false) {
+ TRACE("get %d of codec context successfully.\n", index);
+ s->context[index].occupied_context = true;
+ break;
+ }
+ }
+ qemu_mutex_unlock(&s->threadpool.mutex);
+
+ 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_context3(NULL);
+ s->context[index].frame = avcodec_alloc_frame();
+ s->context[index].opened_context = false;
+
+#if 0
+ s->context[index].parser_buf = NULL;
+ s->context[index].parser_use = false;
+#endif
+ 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);
+
+#if 0
+ memcpy(&audio, mem_buf + size, sizeof(int32_t) * 7);
+ size += (sizeof(int32_t) * 7);
+ memcpy(&audio.channel_layout, mem_buf + size, sizeof(audio.channel_layout));
+ size += sizeof(audio.channel_layout);
+#endif
+ memcpy(&audio, mem_buf + size, sizeof(audio));
+ size += sizeof(audio);
+ 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);
+ INFO("extradata size: %d.\n", avctx->extradata_size);
+
+ if (avctx->extradata_size > 0) {
+ 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 int write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+{
+ int size = 0;
+
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ int osize = av_get_bytes_per_sample(avctx->sample_fmt);
+
+ memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
+ size = sizeof(avctx->sample_fmt);
+
+ // frame_size: samples per packet, initialized when calling 'init'
+ memcpy(mem_buf + size, &avctx->frame_size, sizeof(avctx->frame_size));
+ size += sizeof(avctx->frame_size);
+
+ memcpy(mem_buf + size, &osize, sizeof(osize));
+ size += sizeof(osize);
+ }
+
+ return size;
+}
+
+static uint8_t *resample_audio(AVCodecContext * avctx, AVFrame *samples, int *out_size)
+{
+ AVAudioResampleContext *avr = NULL;
+ uint8_t *resample_audio = NULL;
+ int buffer_size = 0, out_linesize = 0;
+ int nb_samples = samples->nb_samples;
+ int out_sample_fmt = avctx->sample_fmt - 5;
+
+ avr = avresample_alloc_context();
+ if (!avr) {
+ ERR("failed to allocate avresample context\n");
+ return NULL;
+ }
+
+ av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
+ av_opt_set_int(avr, "in_sample_fmt", avctx->sample_fmt, 0);
+ av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
+ av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
+ av_opt_set_int(avr, "out_sample_fmt", out_sample_fmt, 0);
+ av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
+
+ TRACE("open avresample context\n");
+ if (avresample_open(avr) < 0) {
+ ERR("failed to open avresample context\n");
+ avresample_free(&avr);
+ return NULL;
+ }
+
+ *out_size =
+ av_samples_get_buffer_size(&out_linesize, avctx->channels,
+ nb_samples, out_sample_fmt, 0);
+
+ resample_audio = av_mallocz(*out_size);
+ if (!resample_audio) {
+ ERR("failed to allocate resample buffer\n");
+ avresample_close(avr);
+ avresample_free(&avr);
+ return NULL;
+ }
+
+ buffer_size = avresample_convert(avr, &resample_audio,
+ out_linesize, nb_samples,
+ samples->data, samples->linesize[0],
+ samples->nb_samples);
+
+ TRACE("resample_audio out_size %d buffer_size %d\n", *out_size, buffer_size);
+
+ avresample_close(avr);
+ avresample_free(&avr);
+
+ return resample_audio;
+}
+
+
+// codec functions
+static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVCodec *codec = NULL;
+ int size = 0, ret = -1;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+
+ // allocate AVCodecContext
+ avctx = maru_brill_codec_alloc_context(s, ctx_id);
+ if (!avctx) {
+ ERR("[%d] failed to allocate context.\n", __LINE__);
+ ret = -1;
+ } else {
+#if 0
+ avcodec_get_context_defaults(avctx);
+
+ avctx->rc_strategy = 2;
+ avctx->b_frame_strategy = 0;
+ avctx->coder_type = 0;
+ avctx->context_model = 0;
+ avctx->scenechange_threshold = 0;
+ avctx->inter_threshold = 0;
+
+ avctx->gop_size = DEFAULT_VIDEO_GOP_SIZE;
+ avctx->lmin = (2 * FF_QP2LAMBDA + 0.5);
+ avctx->lmax = (31 * FF_QP2LAMBDA + 0.5);
+#endif
+
+ codec = maru_brill_codec_find_avcodec(elem->buf);
+ if (codec) {
+ size = sizeof(int32_t) + 32; // buffer size of codec_name
+ read_codec_init_data(avctx, elem->buf + size);
+
+ ret = avcodec_open2(avctx, codec, NULL);
+ INFO("avcodec_open success! ret %d ctx_id %d\n", ret, ctx_id);
+
+ TRACE("channels %d sample_rate %d sample_fmt %d ch_layout %lld\n",
+ avctx->channels, avctx->sample_rate,
+ avctx->sample_fmt, avctx->channel_layout);
+
+ tempbuf_size = (sizeof(avctx->sample_fmt) + sizeof(avctx->frame_size)
+ + sizeof(avctx->extradata_size) + avctx->extradata_size)
+ + sizeof(int);
+
+ s->context[ctx_id].opened_context = 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);
+ ret = -1;
+ }
+ }
+
+ tempbuf_size += sizeof(ret);
+
+ tempbuf = g_malloc(tempbuf_size);
+ if (!tempbuf) {
+ ERR("failed to allocate a buffer\n");
+ tempbuf_size = 0;
+ } else {
+ memcpy(tempbuf, &ret, sizeof(ret));
+ size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to open codec contex.\n");
+ } else {
+ size += write_codec_init_data(avctx, tempbuf + size);
+ TRACE("codec_init. copyback!! size %d\n", size);
+ {
+ memcpy(tempbuf + size, &avctx->extradata_size, sizeof(avctx->extradata_size));
+ size += sizeof(avctx->extradata_size);
+ if (avctx->extradata) {
+ memcpy(tempbuf + size, avctx->extradata, avctx->extradata_size);
+ size += avctx->extradata_size;
+ }
+ }
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, 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;
+ }
+
+ INFO("close avcontext of %d\n", ctx_id);
+ // qemu_mutex_lock(&s->threadpool.mutex);
+ avcodec_close(avctx);
+ s->context[ctx_id].opened_context = 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 (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;
+ }
+
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ bool ret = true;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = s->context[ctx_id].avctx;
+ if (!avctx) {
+ ERR("%d of AVCodecContext is NULL.\n", ctx_id);
+ ret = false;
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ ret = false;
+ } else {
+ TRACE("flush %d context of buffers.\n", ctx_id);
+ avcodec_flush_buffers(avctx);
+ }
+
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return ret;
+}
+
+static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *picture = NULL;
+ AVPacket avpkt;
+ int got_picture = 0, len = -1;
+ uint8_t *inbuf = NULL;
+ int inbuf_size = 0, idx, size = 0;
+ int64_t in_offset;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
+ size += sizeof(inbuf_size);
+ memcpy(&idx, elem->buf + size, sizeof(idx));
+ size += sizeof(idx);
+ memcpy(&in_offset, elem->buf + size, sizeof(in_offset));
+ size += sizeof(in_offset);
+ TRACE("decode_video. inbuf_size %d\n", inbuf_size);
+
+ if (inbuf_size > 0) {
+ inbuf = elem->buf + size;
+ }
+ } else {
+ TRACE("decode_video. no input buffer\n");
+ // FIXME: improve error handling
+ // 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) {
+ ERR("decode_video. %d of AVCodecContext is NULL.\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("decode_video. %d of AVCodec is NULL.\n", ctx_id);
+ } else if (!picture) {
+ ERR("decode_video. %d of AVFrame is NULL.\n", ctx_id);
+ } else {
+ // in case of skipping frames
+ // picture->pict_type = -1;
+
+ TRACE("decode_video. bitrate %d\n", avctx->bit_rate);
+ // avctx->reordered_opaque = idx;
+ // picture->reordered_opaque = idx;
+
+ len =
+ avcodec_decode_video2(avctx, picture, &got_picture, &avpkt);
+ TRACE("decode_video. in_size %d len %d, frame_size %d\n", avpkt.size, len, got_picture);
+ }
+
+ tempbuf_size =
+ sizeof(len) + sizeof(got_picture) + sizeof(struct video_data);
+
+ if (len < 0) {
+ ERR("failed to decode video. ctx_id: %d, len: %d\n", ctx_id, len);
+ got_picture = 0;
+ }
+
+ tempbuf = g_malloc(tempbuf_size);
+ if (!tempbuf) {
+ ERR("failed to allocate decoded audio buffer\n");
+ // FIXME: how to handle this case?
+ } else {
+ struct video_data video;
+
+ memcpy(tempbuf, &len, sizeof(len));
+ size = sizeof(len);
+ memcpy(tempbuf + size, &got_picture, sizeof(got_picture));
+ size += sizeof(got_picture);
+ if (avctx) {
+ deserialize_video_data(avctx, &video);
+ memcpy(tempbuf + size, &video, sizeof(struct video_data));
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+}
+
+static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
+{
+ AVCodecContext *avctx = NULL;
+ AVPicture *src = NULL;
+ AVPicture dst;
+ uint8_t *out_buffer = NULL, *tempbuf = NULL;
+ int pict_size = 0;
+ bool ret = true;
+
+ 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) {
+ ERR("picture_copy. %d of AVCodecContext is NULL.\n", ctx_id);
+ ret = false;
+ } else if (!avctx->codec) {
+ ERR("picture_copy. %d of AVCodec is NULL.\n", ctx_id);
+ ret = false;
+ } else if (!src) {
+ ERR("picture_copy. %d of AVFrame is NULL.\n", ctx_id);
+ ret = false;
+ } 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);
+ ret = false;
+ } 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 ret;
+}
+
+static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx;
+ AVPacket avpkt;
+ AVFrame *samples = NULL;
+ uint8_t *inbuf = NULL;
+ int inbuf_size = 0, size = 0;
+ int len = -1, got_frame = 0;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ uint8_t *outbuf = NULL;
+ int buffer_size = 0;
+ int out_sample_fmt = -1;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
+ size = sizeof(inbuf_size);
+ TRACE("decode_audio. inbuf_size %d\n", inbuf_size);
+
+ if (inbuf_size > 0) {
+ inbuf = elem->buf + size;
+ }
+ } else {
+ ERR("decode_audio. no input buffer\n");
+ // FIXME: improve error handling
+ // return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+ avctx = s->context[ctx_id].avctx;
+ samples = s->context[ctx_id].frame;
+ if (!avctx) {
+ ERR("decode_audio. %d of AVCodecContext is NULL\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("decode_audio. %d of AVCodec is NULL\n", ctx_id);
+ } else if (!samples) {
+ ERR("decode_audio. %d of AVFrame is NULL\n", ctx_id);
+ } else {
+ avcodec_get_frame_defaults(samples);
+
+ len = avcodec_decode_audio4(avctx, samples, &got_frame, &avpkt);
+ TRACE("decode_audio. len %d, channel_layout %lld, frame_size %d\n",
+ len, avctx->channel_layout, got_frame);
+ if (got_frame) {
+ if (av_sample_fmt_is_planar(avctx->sample_fmt)) {
+ out_sample_fmt = avctx->sample_fmt - 5;
+
+ outbuf = resample_audio (avctx, samples, &buffer_size);
+ } else {
+ // TODO: not planar format
+ }
+ }
+ }
+
+ tempbuf_size = (sizeof(len) + sizeof(got_frame));
+ if (len < 0) {
+ ERR("failed to decode audio. ctx_id: %d len: %d got_frame: %d\n",
+ ctx_id, len, got_frame);
+ got_frame = 0;
+ } else {
+ tempbuf_size += (sizeof(out_sample_fmt) + sizeof(avctx->sample_rate)
+ + sizeof(avctx->channels) + sizeof(avctx->channel_layout)
+ + sizeof(buffer_size) + buffer_size);
+ }
+
+ tempbuf = g_malloc(tempbuf_size);
+ if (!tempbuf) {
+ ERR("failed to allocate decoded audio buffer\n");
+ } else {
+ memcpy(tempbuf, &len, sizeof(len));
+ size = sizeof(len);
+ memcpy(tempbuf + size, &got_frame, sizeof(got_frame));
+ size += sizeof(got_frame);
+ if (got_frame) {
+ memcpy(tempbuf + size, &out_sample_fmt, sizeof(out_sample_fmt));
+ size += sizeof(out_sample_fmt);
+ memcpy(tempbuf + size, &avctx->sample_rate, sizeof(avctx->sample_rate));
+ size += sizeof(avctx->sample_rate);
+ memcpy(tempbuf + size, &avctx->channels, sizeof(avctx->channels));
+ size += sizeof(avctx->channels);
+ memcpy(tempbuf + size, &avctx->channel_layout, sizeof(avctx->channel_layout));
+ size += sizeof(avctx->channel_layout);
+
+ memcpy(tempbuf + size, &buffer_size, sizeof(buffer_size));
+ size += sizeof(buffer_size);
+
+ if (outbuf) {
+ memcpy(tempbuf + size, outbuf, buffer_size);
+ av_free(outbuf);
+ }
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, 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;
+ AVPacket avpkt;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int inbuf_size = 0, outbuf_size = 0;
+ int got_frame = 0, ret = 0, size = 0;
+ int64_t in_timestamp = 0;
+ int coded_frame = 0, key_frame = 0;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
+ size += sizeof(inbuf_size);
+ memcpy(&in_timestamp, elem->buf + size, sizeof(in_timestamp));
+ size += sizeof(in_timestamp);
+ TRACE("encode video. inbuf_size %d\n", inbuf_size);
+
+ if (inbuf_size > 0) {
+ inbuf = elem->buf + size;
+ }
+ } else {
+ TRACE("encode video. no input buffer.\n");
+ // FIXME: improve error handling
+ // return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = NULL;
+ avpkt.size = 0;
+
+ 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);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ } 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);
+ } 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("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);
+
+ avpkt.data = outbuf;
+ avpkt.size = outbuf_size;
+
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding video.\n");
+ } else {
+ ret = avcodec_encode_video2(avctx, &avpkt, pict, &got_frame);
+
+ TRACE("encode video. ret %d got_picture %d outbuf_size %d\n", ret, got_frame, avpkt.size);
+ if (avctx->coded_frame) {
+ TRACE("encode video. keyframe %d\n", avctx->coded_frame->key_frame);
+ }
+ }
+ }
+ }
+
+ tempbuf_size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to encode video. ctx_id %d ret %d\n", ctx_id, ret);
+ } else {
+ tempbuf_size += avpkt.size + sizeof(coded_frame) + sizeof(key_frame);
+ }
+
+ // write encoded video data
+ tempbuf = g_malloc0(tempbuf_size);
+ if (!tempbuf) {
+ ERR("encode video. failed to allocate encoded out buffer.\n");
+ } else {
+ memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
+ size = sizeof(avpkt.size);
+
+ if ((got_frame) && outbuf) {
+ // inform gstreamer plugin about the status of encoded frames
+ // A flag for output buffer in gstreamer is depending on the status.
+ if (avctx->coded_frame) {
+ coded_frame = 1;
+ // if key_frame is 0, this frame cannot be decoded independently.
+ key_frame = avctx->coded_frame->key_frame;
+ }
+ memcpy(tempbuf + size, &coded_frame, sizeof(coded_frame));
+ size += sizeof(coded_frame);
+ memcpy(tempbuf + size, &key_frame, sizeof(key_frame));
+ size += sizeof(key_frame);
+ memcpy(tempbuf + size, outbuf, avpkt.size);
+ }
+ }
+
+ if (outbuf) {
+ TRACE("release encoded output buffer. %p\n", outbuf);
+ g_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id);
+
+ TRACE("leave: %s\n", __func__);
+ return true;
+}
+
+static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+{
+ AVCodecContext *avctx;
+ AVPacket avpkt;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int32_t inbuf_size = 0, max_size = 0;
+ int ret = 0, got_pkt = 0, size = 0;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->buf) {
+ memcpy(&inbuf_size, elem->buf, sizeof(inbuf_size));
+ size += sizeof(inbuf_size);
+ // memcpy(&max_size, elem->buf + size, sizeof(max_size));
+ // size += sizeof(max_size);
+ max_size = inbuf_size * 4; // + FF_MIN_BUFFER_SIZE;
+ TRACE("encode_video. inbuf_size %d max_size %d\n", inbuf_size, max_size);
+
+ if (inbuf_size > 0) {
+ // inbuf = g_malloc(inbuf_size);
+ // memcpy(inbuf, elem->buf + size, inbuf_size);
+ inbuf = elem->buf + size;
+ }
+ } else {
+ TRACE("encode_audio. no input buffer\n");
+ // FIXME: improve error handling
+ // return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = NULL;
+ avpkt.size = 0;
+
+ 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);
+ // outbuf = g_malloc0(max_size);
+
+ avpkt.data = outbuf;
+ avpkt.size = max_size;
+
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding audio.\n");
+ } else {
+ ret = avcodec_encode_audio2(avctx, &avpkt, (const AVFrame *)inbuf, &got_pkt);
+ TRACE("encode audio. ret %d got_pkt %d outbuf_size %d\n", ret, got_pkt, avpkt.size);
+ }
+ }
+
+ tempbuf_size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to encode audio. ctx_id %d ret %d\n", ctx_id, ret);
+ } else {
+ // tempbuf_size += (max_size); // len;
+ tempbuf_size += avpkt.size;
+ }
+
+ // write encoded audio data
+ tempbuf = g_malloc0(tempbuf_size);
+ if (!tempbuf) {
+ ERR("encode audio. failed to allocate encoded out buffer.\n");
+ } else {
+ memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
+ size = sizeof(avpkt.size);
+ if (got_pkt && outbuf) {
+ // memcpy(tempbuf + size, outbuf, max_size); // len);
+ memcpy(tempbuf + size, outbuf, avpkt.size);
+ }
+ }
+
+ if (outbuf) {
+ av_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, 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");
+ pci_set_irq(&s->dev, 1);
+ s->irq_raised = 1;
+ } else {
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ TRACE("codec_wq is empty!!\n");
+ }
+
+ TRACE("leave: %s\n", __func__);
+}
+
+/*
+ * Codec Device APIs
+ */
+static uint64_t maru_brill_codec_read(void *opaque,
+ hwaddr addr,
+ unsigned size)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+ uint64_t ret = 0;
+
+ switch (addr) {
+ case CODEC_CMD_GET_THREAD_STATE:
+ qemu_mutex_lock(&s->context_queue_mutex);
+ if (s->irq_raised) {
+ ret = CODEC_TASK_END;
+ pci_set_irq(&s->dev, 0);
+ s->irq_raised = 0;
+ }
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("get thread_state. ret: %d\n", ret);
+ break;
+
+ case CODEC_CMD_GET_CTX_FROM_QUEUE:
+ {
+ DeviceMemEntry *head = NULL;
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ head = QTAILQ_FIRST(&codec_wq);
+ if (head) {
+ ret = head->ctx_id;
+ QTAILQ_REMOVE(&codec_wq, head, node);
+ entry[ret] = head;
+ TRACE("get a elem from codec_wq. 0x%x\n", head);
+ } else {
+ ret = 0;
+ }
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ TRACE("get a head from a writequeue. head: %x\n", ret);
+ }
+ break;
+
+ case CODEC_CMD_GET_VERSION:
+ ret = CODEC_VERSION;
+ TRACE("codec version: %d\n", ret);
+ break;
+
+ case CODEC_CMD_GET_ELEMENT:
+ ret = maru_brill_codec_query_list(s);
+ break;
+
+ case CODEC_CMD_GET_CONTEXT_INDEX:
+ ret = maru_brill_codec_get_context_index(s);
+ TRACE("get context index: %d\n", ret);
+ break;
+
+ default:
+ ERR("no avaiable command for read. %d\n", addr);
+ }
+
+ return ret;
+}
+
+static void maru_brill_codec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+
+ switch (addr) {
+ case CODEC_CMD_API_INDEX:
+ TRACE("set codec_cmd value: %d\n", value);
+ s->ioparam.api_index = value;
+ maru_brill_codec_wakeup_threads(s, value);
+ break;
+
+ case CODEC_CMD_CONTEXT_INDEX:
+ TRACE("set context_index value: %d\n", value);
+ s->ioparam.ctx_index = value;
+ break;
+
+ case CODEC_CMD_DEVICE_MEM_OFFSET:
+ TRACE("set mem_offset value: 0x%x\n", value);
+ s->ioparam.mem_offset = value;
+ break;
+
+ case CODEC_CMD_RELEASE_CONTEXT:
+ {
+ int ctx_index = (int32_t)value;
+
+ if (s->context[ctx_index].occupied_thread) {
+ s->context[ctx_index].requested_close = true;
+ INFO("make running thread to handle deinit\n");
+ } else {
+ maru_brill_codec_release_context(s, ctx_index);
+ }
+ }
+ 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);
+
+ 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)
--- /dev/null
+/*
+ * Virtual Codec device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "hw/hw.h"
+#include "sysemu/kvm.h"
+#include "qemu/main-loop.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "qemu-common.h"
+#include "qemu/thread.h"
+
+#include "util/osutil.h"
+#include "debug_ch.h"
+#include "hw/maru_device_ids.h"
+
+#include "libavformat/avformat.h"
+#include "libavresample/avresample.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.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;
+ int32_t reserved;
+ int64_t channel_layout;
+};
+
+typedef struct CodecContext {
+ AVCodecContext *avctx;
+ AVFrame *frame;
+ AVCodecParserContext *parser_ctx;
+ uint8_t *parser_buf;
+ uint16_t parser_use;
+ bool occupied_context;
+ bool occupied_thread;
+ bool opened_context;
+ bool requested_close;
+} CodecContext;
+
+typedef struct CodecThreadPool {
+ QemuThread *threads;
+ QemuMutex mutex;
+ QemuCond cond;
+} CodecThreadPool;
+
+typedef struct MaruBrillCodecState {
+ PCIDevice dev;
+
+ uint8_t *vaddr;
+ MemoryRegion vram;
+ MemoryRegion mmio;
+
+ QEMUBH *codec_bh;
+ QemuMutex context_mutex;
+ QemuMutex context_queue_mutex;
+ QemuMutex ioparam_queue_mutex;
+
+ CodecThreadPool threadpool;
+ bool is_thread_running;
+ uint32_t worker_thread_cnt;
+ uint32_t idle_thread_cnt;
+
+ int irq_raised;
+
+ CodecContext context[CODEC_CONTEXT_MAX];
+ CodecParam ioparam;
+} MaruBrillCodecState;
+
+enum codec_io_cmd {
+ CODEC_CMD_API_INDEX = 0x28,
+ CODEC_CMD_CONTEXT_INDEX = 0x2C,
+ CODEC_CMD_DEVICE_MEM_OFFSET = 0x34,
+ CODEC_CMD_GET_THREAD_STATE = 0x38,
+ CODEC_CMD_GET_CTX_FROM_QUEUE = 0x3C,
+ CODEC_CMD_GET_DATA_FROM_QUEUE = 0x40,
+ CODEC_CMD_RELEASE_CONTEXT = 0x44,
+ CODEC_CMD_GET_VERSION = 0x50,
+ CODEC_CMD_GET_ELEMENT = 0x54,
+ CODEC_CMD_GET_CONTEXT_INDEX = 0x58,
+};
+
+enum codec_api_type {
+ CODEC_INIT = 0,
+ CODEC_DECODE_VIDEO,
+ CODEC_ENCODE_VIDEO,
+ CODEC_DECODE_AUDIO,
+ CODEC_ENCODE_AUDIO,
+ CODEC_PICTURE_COPY,
+ CODEC_DEINIT,
+ CODEC_FLUSH_BUFFERS,
+ };
+
+enum codec_type {
+ CODEC_TYPE_UNKNOWN = -1,
+ CODEC_TYPE_DECODE,
+ CODEC_TYPE_ENCODE,
+};
+
+enum thread_state {
+ CODEC_TASK_START = 0,
+ CODEC_TASK_END = 0x1f,
+};
+
+/*
+ * Codec Device Functions
+ */
+int maru_brill_codec_pci_device_init(PCIBus *bus);
--- /dev/null
+/*
+ * Common header of MARU Virtual Camera device.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _MARU_CAMERA_COMMON_H_
+#define _MARU_CAMERA_COMMON_H_
+
+#include "hw/pci/pci.h"
+#include "qemu/thread.h"
+
+#define MARUCAM_MAX_PARAM 20
+#define MARUCAM_SKIPFRAMES 2
+
+/* must sync with GUEST camera_driver */
+#define MARUCAM_CMD_INIT 0x00
+#define MARUCAM_CMD_OPEN 0x04
+#define MARUCAM_CMD_CLOSE 0x08
+#define MARUCAM_CMD_ISR 0x0C
+#define MARUCAM_CMD_START_PREVIEW 0x10
+#define MARUCAM_CMD_STOP_PREVIEW 0x14
+#define MARUCAM_CMD_S_PARAM 0x18
+#define MARUCAM_CMD_G_PARAM 0x1C
+#define MARUCAM_CMD_ENUM_FMT 0x20
+#define MARUCAM_CMD_TRY_FMT 0x24
+#define MARUCAM_CMD_S_FMT 0x28
+#define MARUCAM_CMD_G_FMT 0x2C
+#define MARUCAM_CMD_QCTRL 0x30
+#define MARUCAM_CMD_S_CTRL 0x34
+#define MARUCAM_CMD_G_CTRL 0x38
+#define MARUCAM_CMD_ENUM_FSIZES 0x3C
+#define MARUCAM_CMD_ENUM_FINTV 0x40
+#define MARUCAM_CMD_S_DATA 0x44
+#define MARUCAM_CMD_G_DATA 0x48
+#define MARUCAM_CMD_DATACLR 0x50
+#define MARUCAM_CMD_REQFRAME 0x54
+
+typedef struct MaruCamState MaruCamState;
+typedef struct MaruCamParam MaruCamParam;
+
+struct MaruCamParam {
+ uint32_t top;
+ uint32_t retVal;
+ uint32_t errCode;
+ uint32_t stack[MARUCAM_MAX_PARAM];
+};
+
+struct MaruCamState {
+ PCIDevice dev;
+ MaruCamParam *param;
+ QemuThread thread_id;
+ QemuMutex thread_mutex;;
+ QemuCond thread_cond;
+ QEMUBH *tx_bh;
+
+ bool initialized;
+ bool destroying;
+ void *vaddr; /* vram ptr */
+ uint32_t isr;
+ uint32_t streamon;
+ uint32_t buf_size;
+ uint32_t req_frame;
+
+ MemoryRegion vram;
+ MemoryRegion mmio;
+};
+
+/* ------------------------------------------------------------------------- */
+/* Fucntion prototype */
+/* ------------------------------------------------------------------------- */
+int marucam_device_check(int log_flag);
+void marucam_device_init(MaruCamState *state);
+void marucam_device_exit(MaruCamState *state);
+void marucam_device_open(MaruCamState *state);
+void marucam_device_close(MaruCamState *state);
+void marucam_device_start_preview(MaruCamState *state);
+void marucam_device_stop_preview(MaruCamState *state);
+void marucam_device_s_param(MaruCamState *state);
+void marucam_device_g_param(MaruCamState *state);
+void marucam_device_s_fmt(MaruCamState *state);
+void marucam_device_g_fmt(MaruCamState *state);
+void marucam_device_try_fmt(MaruCamState *state);
+void marucam_device_enum_fmt(MaruCamState *state);
+void marucam_device_qctrl(MaruCamState *state);
+void marucam_device_s_ctrl(MaruCamState *state);
+void marucam_device_g_ctrl(MaruCamState *state);
+void marucam_device_enum_fsizes(MaruCamState *state);
+void marucam_device_enum_fintv(MaruCamState *state);
+
+int maru_camera_pci_init(PCIBus *bus);
+
+#endif /* _MARU_CAMERA_COMMON_H_ */
--- /dev/null
+/*
+ * Common implementation of MARU Virtual Camera device by PCI bus.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "qemu-common.h"
+#include "qemu/main-loop.h"
+#include "exec/cpu-common.h"
+
+#include "maru_camera_common.h"
+#include "hw/maru_device_ids.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru-camera);
+
+#define MARU_PCI_CAMERA_DEVICE_NAME "maru-camera"
+
+#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) {
+ pci_set_irq(&state->dev, 0);
+ state->isr = 0;
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+ break;
+ case MARUCAM_CMD_G_DATA:
+ ret = state->param->stack[state->param->top++];
+ break;
+ case MARUCAM_CMD_OPEN:
+ case MARUCAM_CMD_CLOSE:
+ case MARUCAM_CMD_START_PREVIEW:
+ case MARUCAM_CMD_STOP_PREVIEW:
+ case MARUCAM_CMD_S_PARAM:
+ case MARUCAM_CMD_G_PARAM:
+ case MARUCAM_CMD_ENUM_FMT:
+ case MARUCAM_CMD_TRY_FMT:
+ case MARUCAM_CMD_S_FMT:
+ case MARUCAM_CMD_G_FMT:
+ case MARUCAM_CMD_QCTRL:
+ case MARUCAM_CMD_S_CTRL:
+ case MARUCAM_CMD_G_CTRL:
+ case MARUCAM_CMD_ENUM_FSIZES:
+ case MARUCAM_CMD_ENUM_FINTV:
+ ret = state->param->errCode;
+ state->param->errCode = 0;
+ break;
+ default:
+ ERR("Not supported command: 0x%x\n", offset);
+ ret = EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static inline void
+marucam_mmio_write(void *opaque, hwaddr offset, uint32_t value)
+{
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ switch (offset & 0xFF) {
+ case MARUCAM_CMD_OPEN:
+ marucam_device_open(state);
+ break;
+ case MARUCAM_CMD_CLOSE:
+ marucam_device_close(state);
+ break;
+ case MARUCAM_CMD_START_PREVIEW:
+ marucam_device_start_preview(state);
+ break;
+ case MARUCAM_CMD_STOP_PREVIEW:
+ marucam_device_stop_preview(state);
+ memset(state->vaddr, 0, MARUCAM_MEM_SIZE);
+ break;
+ case MARUCAM_CMD_S_PARAM:
+ marucam_device_s_param(state);
+ break;
+ case MARUCAM_CMD_G_PARAM:
+ marucam_device_g_param(state);
+ break;
+ case MARUCAM_CMD_ENUM_FMT:
+ marucam_device_enum_fmt(state);
+ break;
+ case MARUCAM_CMD_TRY_FMT:
+ marucam_device_try_fmt(state);
+ break;
+ case MARUCAM_CMD_S_FMT:
+ marucam_device_s_fmt(state);
+ break;
+ case MARUCAM_CMD_G_FMT:
+ marucam_device_g_fmt(state);
+ break;
+ case MARUCAM_CMD_QCTRL:
+ marucam_device_qctrl(state);
+ break;
+ case MARUCAM_CMD_S_CTRL:
+ marucam_device_s_ctrl(state);
+ break;
+ case MARUCAM_CMD_G_CTRL:
+ marucam_device_g_ctrl(state);
+ break;
+ case MARUCAM_CMD_ENUM_FSIZES:
+ marucam_device_enum_fsizes(state);
+ break;
+ case MARUCAM_CMD_ENUM_FINTV:
+ marucam_device_enum_fintv(state);
+ break;
+ case MARUCAM_CMD_S_DATA:
+ state->param->stack[state->param->top++] = value;
+ break;
+ case MARUCAM_CMD_DATACLR:
+ memset(state->param, 0, sizeof(MaruCamParam));
+ break;
+ case MARUCAM_CMD_REQFRAME:
+ qemu_mutex_lock(&state->thread_mutex);
+ state->req_frame = value + 1;
+ qemu_mutex_unlock(&state->thread_mutex);
+ break;
+ default:
+ ERR("Not supported command: 0x%x\n", offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps maru_camera_mmio_ops = {
+ .old_mmio = {
+ .read = {
+ marucam_mmio_read,
+ marucam_mmio_read,
+ marucam_mmio_read,
+ },
+ .write = {
+ marucam_mmio_write,
+ marucam_mmio_write,
+ marucam_mmio_write,
+ },
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/*
+ * QEMU bottom half funtion
+ */
+static void marucam_tx_bh(void *opaque)
+{
+ MaruCamState *state = (MaruCamState *)opaque;
+
+ qemu_mutex_lock(&state->thread_mutex);
+ if (state->isr) {
+ pci_set_irq(&state->dev, 1);
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+}
+
+/*
+ * Initialization function
+ */
+
+static int marucam_initfn(PCIDevice *dev)
+{
+ MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ /* Check available webcam
+ * If there is not one, you can't use the camera.
+ */
+ if (!marucam_device_check(1)) {
+ s->initialized = false;
+ ERR("Failed to check the camera device, "
+ "You can *not* use the camera\n");
+ return 0;
+ }
+
+ 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);
+ s->initialized = true;
+ INFO("initialize maru-camera device\n");
+
+ return 0;
+}
+
+/*
+ * Termination function
+ */
+static void marucam_exitfn(PCIDevice *pci_dev)
+{
+ MaruCamState *s =
+ OBJECT_CHECK(MaruCamState, pci_dev, MARU_PCI_CAMERA_DEVICE_NAME);
+
+ if (s->initialized) {
+ 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("finalize maru-camera device\n");
+}
+
+static void marucam_resetfn(DeviceState *d)
+{
+ MaruCamState *s = (MaruCamState *)d;
+
+ if (s->initialized) {
+ marucam_device_close(s);
+ qemu_mutex_lock(&s->thread_mutex);
+ s->isr = s->streamon = s->req_frame = s->buf_size = 0;
+ qemu_mutex_unlock(&s->thread_mutex);
+ memset(s->vaddr, 0, MARUCAM_MEM_SIZE);
+ memset(s->param, 0x00, sizeof(MaruCamParam));
+ INFO("reset maru-camera device\n");
+ }
+}
+
+int maru_camera_pci_init(PCIBus *bus)
+{
+ 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->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->reset = marucam_resetfn;
+ dc->desc = "MARU Virtual Camera device for Tizen emulator";
+}
+
+static TypeInfo maru_camera_info = {
+ .name = MARU_PCI_CAMERA_DEVICE_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MaruCamState),
+ .class_init = maru_camera_pci_class_init,
+};
+
+static void maru_camera_pci_register_types(void)
+{
+ type_register_static(&maru_camera_info);
+}
+
+type_init(maru_camera_pci_register_types)
--- /dev/null
+/*
+ * Header of MARU Virtual Camera device for MacOS.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jun Tian <jun.j.tian@intel.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _MARU_CAMERA_DARWIN_H_
+#define _MARU_CAMERA_DARWIN_H_
+
+#define MAKEFOURCC(a, b, c, d) \
+ (((uint32_t)(a) << 0) | \
+ ((uint32_t)(b) << 8) | \
+ ((uint32_t)(c) << 16) | \
+ ((uint32_t)(d) << 24))
+
+/* 16 RGB-5-5-5 */
+#define V4L2_PIX_FMT_RGB555 MAKEFOURCC('R', 'G', 'B', 'O')
+/* 16 RGB-5-6-5 */
+#define V4L2_PIX_FMT_RGB565 MAKEFOURCC('R', 'G', 'B', 'P')
+/* 16 RGB-5-5-5 BE */
+#define V4L2_PIX_FMT_RGB555X MAKEFOURCC('R', 'G', 'B', 'Q')
+/* 16 RGB-5-6-5 BE */
+#define V4L2_PIX_FMT_RGB565X MAKEFOURCC('R', 'G', 'B', 'R')
+/* 24 BGR-8-8-8 */
+#define V4L2_PIX_FMT_BGR24 MAKEFOURCC('B', 'G', 'R', '3')
+/* 24 RGB-8-8-8 */
+#define V4L2_PIX_FMT_RGB24 MAKEFOURCC('R', 'G', 'B', '3')
+/* 32 BGR-8-8-8-8 */
+#define V4L2_PIX_FMT_BGR32 MAKEFOURCC('B', 'G', 'R', '4')
+/* 32 RGB-8-8-8-8 */
+#define V4L2_PIX_FMT_RGB32 MAKEFOURCC('R', 'G', 'B', '4')
+/* 9 YVU 4:1:0 */
+#define V4L2_PIX_FMT_YVU410 MAKEFOURCC('Y', 'V', 'U', '9')
+/* 12 YVU 4:2:0 */
+#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2')
+/* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V')
+/* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_UYVY MAKEFOURCC('U', 'Y', 'V', 'Y')
+/* 16 YVU422 planar */
+#define V4L2_PIX_FMT_YUV422P MAKEFOURCC('4', '2', '2', 'P')
+/* 16 YVU411 planar */
+#define V4L2_PIX_FMT_YUV411P MAKEFOURCC('4', '1', '1', 'P')
+/* 12 YUV 4:1:1 */
+#define V4L2_PIX_FMT_Y41P MAKEFOURCC('Y', '4', '1', 'P')
+/* 16 xxxxyyyy uuuuvvvv */
+#define V4L2_PIX_FMT_YUV444 MAKEFOURCC('Y', '4', '4', '4')
+/* 16 YUV-5-5-5 */
+#define V4L2_PIX_FMT_YUV555 MAKEFOURCC('Y', 'U', 'V', 'O')
+/* 16 YUV-5-6-5 */
+#define V4L2_PIX_FMT_YUV565 MAKEFOURCC('Y', 'U', 'V', 'P')
+/* 32 YUV-8-8-8-8 */
+#define V4L2_PIX_FMT_YUV32 MAKEFOURCC('Y', 'U', 'V', '4')
+/* 9 YUV 4:1:0 */
+#define V4L2_PIX_FMT_YUV410 MAKEFOURCC('Y', 'U', 'V', '9')
+/* 12 YUV 4:2:0 */
+#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2')
+/* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YYUV MAKEFOURCC('Y', 'Y', 'U', 'V')
+
+void convert_frame(uint32_t pixel_format, int frame_width, int frame_height,
+ size_t frame_size, void *frame_pixels, void *video_buf);
+
+#endif /* _MARU_CAMERA_DARWIN_H_ */
--- /dev/null
+/*
+ * Implementation of color conversion for MARU Virtual Camera device on MacOS.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jun Tian <jun.j.tian@intel.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu-common.h"
+#include "maru_camera_darwin.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, camera_darwin);
+
+static void UYVYToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
+ int width, int height);
+static void YVU420ToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
+ int width, int height);
+static void YUYVToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
+ int width, int height);
+
+/* Convert pixel format to YUV420 */
+void convert_frame(uint32_t pixel_format, int frame_width, int frame_height,
+ size_t frame_size, void *frame_pixels, void *video_buf)
+{
+ switch (pixel_format) {
+ case V4L2_PIX_FMT_YUV420:
+ memcpy(video_buf, (void *)frame_pixels, (size_t)frame_size);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ YVU420ToYUV420(frame_pixels, video_buf, frame_width, frame_height);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ YUYVToYUV420(frame_pixels, video_buf, frame_width, frame_height);
+ break;
+ case V4L2_PIX_FMT_UYVY: /* Mac default format */
+ UYVYToYUV420(frame_pixels, video_buf, frame_width, frame_height);
+ break;
+ default:
+ ERR("Cannot convert the pixel format (%.4s)...\n",
+ (const char *)&pixel_format);
+ break;
+ }
+}
+
+static void UYVYToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
+ int width, int height)
+{
+ int i, j;
+
+ /* Source */
+ unsigned char *ptrsrcy1, *ptrsrcy2;
+ unsigned char *ptrsrcy3, *ptrsrcy4;
+ unsigned char *ptrsrccb1;
+ unsigned char *ptrsrccb3;
+ unsigned char *ptrsrccr1;
+ unsigned char *ptrsrccr3;
+ int srcystride, srcccstride;
+
+ ptrsrcy1 = bufsrc + 1;
+ ptrsrcy2 = bufsrc + (width << 1) + 1;
+ ptrsrcy3 = bufsrc + (width << 1) * 2 + 1;
+ ptrsrcy4 = bufsrc + (width << 1) * 3 + 1;
+
+ ptrsrccb1 = bufsrc;
+ ptrsrccb3 = bufsrc + (width << 1) * 2;
+
+ ptrsrccr1 = bufsrc + 2;
+ ptrsrccr3 = bufsrc + (width << 1) * 2 + 2;
+
+ srcystride = (width << 1) * 3;
+ srcccstride = (width << 1) * 3;
+
+ /* Destination */
+ unsigned char *ptrdesty1, *ptrdesty2;
+ unsigned char *ptrdesty3, *ptrdesty4;
+ unsigned char *ptrdestcb1, *ptrdestcb2;
+ unsigned char *ptrdestcr1, *ptrdestcr2;
+ int destystride, destccstride;
+
+ ptrdesty1 = bufdest;
+ ptrdesty2 = bufdest + width;
+ ptrdesty3 = bufdest + width * 2;
+ ptrdesty4 = bufdest + width * 3;
+
+ ptrdestcb1 = bufdest + width * height;
+ ptrdestcb2 = bufdest + width * height + (width >> 1);
+
+ ptrdestcr1 = bufdest + width * height + ((width*height) >> 2);
+ ptrdestcr2 = bufdest + width * height + ((width*height) >> 2)
+ + (width >> 1);
+
+ destystride = (width)*3;
+ destccstride = (width>>1);
+
+ for (j = 0; j < (height / 4); j++) {
+ for (i = 0; i < (width / 2); i++) {
+ (*ptrdesty1++) = (*ptrsrcy1);
+ (*ptrdesty2++) = (*ptrsrcy2);
+ (*ptrdesty3++) = (*ptrsrcy3);
+ (*ptrdesty4++) = (*ptrsrcy4);
+
+ ptrsrcy1 += 2;
+ ptrsrcy2 += 2;
+ ptrsrcy3 += 2;
+ ptrsrcy4 += 2;
+
+ (*ptrdesty1++) = (*ptrsrcy1);
+ (*ptrdesty2++) = (*ptrsrcy2);
+ (*ptrdesty3++) = (*ptrsrcy3);
+ (*ptrdesty4++) = (*ptrsrcy4);
+
+ ptrsrcy1 += 2;
+ ptrsrcy2 += 2;
+ ptrsrcy3 += 2;
+ ptrsrcy4 += 2;
+
+ (*ptrdestcb1++) = (*ptrsrccb1);
+ (*ptrdestcb2++) = (*ptrsrccb3);
+
+ ptrsrccb1 += 4;
+ ptrsrccb3 += 4;
+
+ (*ptrdestcr1++) = (*ptrsrccr1);
+ (*ptrdestcr2++) = (*ptrsrccr3);
+
+ ptrsrccr1 += 4;
+ ptrsrccr3 += 4;
+
+ }
+
+ /* Update src pointers */
+ ptrsrcy1 += srcystride;
+ ptrsrcy2 += srcystride;
+ ptrsrcy3 += srcystride;
+ ptrsrcy4 += srcystride;
+
+ ptrsrccb1 += srcccstride;
+ ptrsrccb3 += srcccstride;
+
+ ptrsrccr1 += srcccstride;
+ ptrsrccr3 += srcccstride;
+
+ /* Update dest pointers */
+ ptrdesty1 += destystride;
+ ptrdesty2 += destystride;
+ ptrdesty3 += destystride;
+ ptrdesty4 += destystride;
+
+ ptrdestcb1 += destccstride;
+ ptrdestcb2 += destccstride;
+
+ ptrdestcr1 += destccstride;
+ ptrdestcr2 += destccstride;
+ }
+}
+
+static void YVU420ToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
+ int width, int height)
+{
+ int i, j;
+
+ /* Source*/
+ unsigned char *ptrsrcy1, *ptrsrcy2;
+ unsigned char *ptrsrcy3, *ptrsrcy4;
+ unsigned char *ptrsrccb1, *ptrsrccb2;
+ unsigned char *ptrsrccr1, *ptrsrccr2;
+ int srcystride, srcccstride;
+
+ ptrsrcy1 = bufsrc;
+ ptrsrcy2 = bufsrc + width;
+ ptrsrcy3 = bufsrc + width*2;
+ ptrsrcy4 = bufsrc + width*3;
+
+ ptrsrccr1 = bufsrc + width*height;
+ ptrsrccr2 = bufsrc + width*height + (width>>1);
+
+ ptrsrccb1 = bufsrc + width*height + ((width*height) >> 2);
+ ptrsrccb2 = bufsrc + width*height + ((width*height) >> 2) + (width>>1);
+
+ srcystride = (width)*3;
+ srcccstride = (width>>1);
+
+ /* Destination */
+ unsigned char *ptrdesty1, *ptrdesty2;
+ unsigned char *ptrdesty3, *ptrdesty4;
+ unsigned char *ptrdestcb1, *ptrdestcb2;
+ unsigned char *ptrdestcr1, *ptrdestcr2;
+ int destystride, destccstride;
+
+ ptrdesty1 = bufdest;
+ ptrdesty2 = bufdest + width;
+ ptrdesty3 = bufdest + width * 2;
+ ptrdesty4 = bufdest + width * 3;
+
+ ptrdestcb1 = bufdest + width * height;
+ ptrdestcb2 = bufdest + width * height + (width >> 1);
+
+ ptrdestcr1 = bufdest + width * height + ((width*height) >> 2);
+ ptrdestcr2 = bufdest + width * height + ((width*height) >> 2)
+ + (width >> 1);
+
+ destystride = (width)*3;
+ destccstride = (width>>1);
+
+ for (j = 0; j < (height / 4); j++) {
+ for (i = 0; i < (width / 2); i++) {
+
+ (*ptrdesty1++) = (*ptrsrcy1++);
+ (*ptrdesty2++) = (*ptrsrcy2++);
+ (*ptrdesty3++) = (*ptrsrcy3++);
+ (*ptrdesty4++) = (*ptrsrcy4++);
+ (*ptrdesty1++) = (*ptrsrcy1++);
+ (*ptrdesty2++) = (*ptrsrcy2++);
+ (*ptrdesty3++) = (*ptrsrcy3++);
+ (*ptrdesty4++) = (*ptrsrcy4++);
+
+ (*ptrdestcb1++) = (*ptrsrccb1++);
+ (*ptrdestcr1++) = (*ptrsrccr1++);
+ (*ptrdestcb2++) = (*ptrsrccb2++);
+ (*ptrdestcr2++) = (*ptrsrccr2++);
+
+ }
+
+ /* Update src pointers */
+ ptrsrcy1 += srcystride;
+ ptrsrcy2 += srcystride;
+ ptrsrcy3 += srcystride;
+ ptrsrcy4 += srcystride;
+
+ ptrsrccb1 += srcccstride;
+ ptrsrccb2 += srcccstride;
+
+ ptrsrccr1 += srcccstride;
+ ptrsrccr2 += srcccstride;
+
+ /* Update dest pointers */
+ ptrdesty1 += destystride;
+ ptrdesty2 += destystride;
+ ptrdesty3 += destystride;
+ ptrdesty4 += destystride;
+
+ ptrdestcb1 += destccstride;
+ ptrdestcb2 += destccstride;
+
+ ptrdestcr1 += destccstride;
+ ptrdestcr2 += destccstride;
+
+ }
+
+}
+
+static void YUYVToYUV420(unsigned char *bufsrc, unsigned char *bufdest,
+ int width, int height)
+{
+ int i, j;
+
+ /* Source*/
+ unsigned char *ptrsrcy1, *ptrsrcy2;
+ unsigned char *ptrsrcy3, *ptrsrcy4;
+ unsigned char *ptrsrccb1;
+ unsigned char *ptrsrccb3;
+ unsigned char *ptrsrccr1;
+ unsigned char *ptrsrccr3;
+ int srcystride, srcccstride;
+
+ ptrsrcy1 = bufsrc ;
+ ptrsrcy2 = bufsrc + (width << 1);
+ ptrsrcy3 = bufsrc + (width << 1) * 2;
+ ptrsrcy4 = bufsrc + (width << 1) * 3;
+
+ ptrsrccb1 = bufsrc + 1;
+ ptrsrccb3 = bufsrc + (width << 1) * 2 + 1;
+
+ ptrsrccr1 = bufsrc + 3;
+ ptrsrccr3 = bufsrc + (width << 1) * 2 + 3;
+
+ srcystride = (width << 1) * 3;
+ srcccstride = (width << 1) * 3;
+
+ /* Destination */
+ unsigned char *ptrdesty1, *ptrdesty2;
+ unsigned char *ptrdesty3, *ptrdesty4;
+ unsigned char *ptrdestcb1, *ptrdestcb2;
+ unsigned char *ptrdestcr1, *ptrdestcr2;
+ int destystride, destccstride;
+
+ ptrdesty1 = bufdest;
+ ptrdesty2 = bufdest + width;
+ ptrdesty3 = bufdest + width * 2;
+ ptrdesty4 = bufdest + width * 3;
+
+ ptrdestcb1 = bufdest + width * height;
+ ptrdestcb2 = bufdest + width * height + (width >> 1);
+
+ ptrdestcr1 = bufdest + width * height + ((width * height) >> 2);
+ ptrdestcr2 = bufdest + width * height + ((width * height) >> 2)
+ + (width >> 1);
+
+ destystride = width * 3;
+ destccstride = (width >> 1);
+
+ for (j = 0; j < (height / 4); j++) {
+ for (i = 0; i < (width / 2); i++) {
+ (*ptrdesty1++) = (*ptrsrcy1);
+ (*ptrdesty2++) = (*ptrsrcy2);
+ (*ptrdesty3++) = (*ptrsrcy3);
+ (*ptrdesty4++) = (*ptrsrcy4);
+
+ ptrsrcy1 += 2;
+ ptrsrcy2 += 2;
+ ptrsrcy3 += 2;
+ ptrsrcy4 += 2;
+
+ (*ptrdesty1++) = (*ptrsrcy1);
+ (*ptrdesty2++) = (*ptrsrcy2);
+ (*ptrdesty3++) = (*ptrsrcy3);
+ (*ptrdesty4++) = (*ptrsrcy4);
+
+ ptrsrcy1 += 2;
+ ptrsrcy2 += 2;
+ ptrsrcy3 += 2;
+ ptrsrcy4 += 2;
+
+ (*ptrdestcb1++) = (*ptrsrccb1);
+ (*ptrdestcb2++) = (*ptrsrccb3);
+
+ ptrsrccb1 += 4;
+ ptrsrccb3 += 4;
+
+ (*ptrdestcr1++) = (*ptrsrccr1);
+ (*ptrdestcr2++) = (*ptrsrccr3);
+
+ ptrsrccr1 += 4;
+ ptrsrccr3 += 4;
+
+ }
+
+ /* Update src pointers */
+ ptrsrcy1 += srcystride;
+ ptrsrcy2 += srcystride;
+ ptrsrcy3 += srcystride;
+ ptrsrcy4 += srcystride;
+
+ ptrsrccb1 += srcccstride;
+ ptrsrccb3 += srcccstride;
+
+ ptrsrccr1 += srcccstride;
+ ptrsrccr3 += srcccstride;
+
+ /* Update dest pointers */
+ ptrdesty1 += destystride;
+ ptrdesty2 += destystride;
+ ptrdesty3 += destystride;
+ ptrdesty4 += destystride;
+
+ ptrdestcb1 += destccstride;
+ ptrdestcb2 += destccstride;
+
+ ptrdestcr1 += destccstride;
+ ptrdestcr2 += destccstride;
+ }
+}
--- /dev/null
+/*
+ * Implementation of MARU Virtual Camera device by PCI bus on MacOS.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jun Tian <jun.j.tian@intel.com>
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <QTKit/QTKit.h>
+#import <CoreAudio/CoreAudio.h>
+
+#include <pthread.h>
+#include "qemu-common.h"
+#include "maru_camera_common.h"
+#include "maru_camera_darwin.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru-camera);
+
+#define MARUCAM_THREAD_NAME "marucam_worker_thread"
+
+/* V4L2 defines copy from videodev2.h */
+#define V4L2_CTRL_FLAG_SLIDER 0x0020
+
+#define V4L2_CTRL_CLASS_USER 0x00980000
+#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE + 0)
+#define V4L2_CID_CONTRAST (V4L2_CID_BASE + 1)
+#define V4L2_CID_SATURATION (V4L2_CID_BASE + 2)
+#define V4L2_CID_SHARPNESS (V4L2_CID_BASE + 27)
+
+typedef struct tagMaruCamConvertPixfmt {
+ uint32_t fmt; /* fourcc */
+ uint32_t bpp; /* bits per pixel, 0 for compressed formats */
+ uint32_t needs_conversion;
+} MaruCamConvertPixfmt;
+
+
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
+ { V4L2_PIX_FMT_YUYV, 16, 0 },
+ { V4L2_PIX_FMT_UYVY, 16, 0 },
+ { V4L2_PIX_FMT_YUV420, 12, 0 },
+ { V4L2_PIX_FMT_YVU420, 12, 0 },
+};
+
+typedef struct tagMaruCamConvertFrameInfo {
+ uint32_t width;
+ uint32_t height;
+} MaruCamConvertFrameInfo;
+
+static MaruCamConvertFrameInfo supported_dst_frames[] = {
+ { 640, 480 },
+ { 352, 288 },
+ { 320, 240 },
+ { 176, 144 },
+ { 160, 120 },
+};
+
+#define MARUCAM_CTRL_VALUE_MAX 20
+#define MARUCAM_CTRL_VALUE_MIN 1
+#define MARUCAM_CTRL_VALUE_MID 10
+#define MARUCAM_CTRL_VALUE_STEP 1
+
+enum {
+ _MC_THREAD_PAUSED,
+ _MC_THREAD_STREAMON,
+ _MC_THREAD_STREAMOFF,
+};
+
+#if 0
+struct marucam_qctrl {
+ uint32_t id;
+ uint32_t hit;
+ long min;
+ long max;
+ long step;
+ long init_val;
+};
+
+static struct marucam_qctrl qctrl_tbl[] = {
+ { V4L2_CID_BRIGHTNESS, 0, },
+ { V4L2_CID_CONTRAST, 0, },
+ { V4L2_CID_SATURATION, 0, },
+ { V4L2_CID_SHARPNESS, 0, },
+};
+#endif
+
+static MaruCamState *g_state;
+
+static uint32_t ready_count;
+static uint32_t cur_fmt_idx;
+static uint32_t cur_frame_idx;
+
+/***********************************
+ * Mac camera helper functions
+ ***********************************/
+
+/* Convert Core Video format to FOURCC */
+static uint32_t corevideo_to_fourcc(uint32_t cv_pix_fmt)
+{
+ switch (cv_pix_fmt) {
+ case kCVPixelFormatType_420YpCbCr8Planar:
+ return V4L2_PIX_FMT_YVU420;
+ case kCVPixelFormatType_422YpCbCr8:
+ return V4L2_PIX_FMT_UYVY;
+ case kCVPixelFormatType_422YpCbCr8_yuvs:
+ return V4L2_PIX_FMT_YUYV;
+ case kCVPixelFormatType_32ARGB:
+ case kCVPixelFormatType_32RGBA:
+ return V4L2_PIX_FMT_RGB32;
+ case kCVPixelFormatType_32BGRA:
+ case kCVPixelFormatType_32ABGR:
+ return V4L2_PIX_FMT_BGR32;
+ case kCVPixelFormatType_24RGB:
+ return V4L2_PIX_FMT_RGB24;
+ case kCVPixelFormatType_24BGR:
+ return V4L2_PIX_FMT_BGR32;
+ default:
+ ERR("Unknown pixel format '%.4s'", (const char *)&cv_pix_fmt);
+ return 0;
+ }
+}
+
+static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
+{
+ uint32_t bytesperline;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ bytesperline = (width * 12) >> 3;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ bytesperline = width * 2;
+ break;
+ }
+
+ return bytesperline;
+}
+
+static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
+{
+ return get_bytesperline(pixfmt, width) * height;
+}
+
+/******************************************************************
+ ** Maru Camera Implementation
+ *****************************************************************/
+
+@interface MaruCameraDriver : NSObject {
+ QTCaptureSession *mCaptureSession;
+ QTCaptureDeviceInput *mCaptureVideoDeviceInput;
+ QTCaptureVideoPreviewOutput *mCaptureVideoPreviewOutput;
+
+ CVImageBufferRef mCurrentImageBuffer;
+ BOOL mDeviceIsOpened;
+ BOOL mCaptureIsStarted;
+}
+
+- (MaruCameraDriver *)init;
+- (int)startCapture:(int)width:(int)height;
+- (void)stopCapture;
+- (int)readFrame:(void *)video_buf;
+- (int)setCaptureFormat:(int)width:(int)height:(int)pix_format;
+- (int)getCaptureFormat:(int)width:(int)height:(int)pix_format;
+- (BOOL)deviceStatus;
+
+@end
+
+@implementation MaruCameraDriver
+
+- (MaruCameraDriver *)init
+{
+ BOOL success = NO;
+ NSError *error;
+ mDeviceIsOpened = NO;
+ mCaptureIsStarted = NO;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ /* Create the capture session */
+ mCaptureSession = [[QTCaptureSession alloc] init];
+
+ /* Find a video device */
+ QTCaptureDevice *videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
+ success = [videoDevice open:&error];
+
+ /* If a video input device can't be found or opened, try to find and open a muxed input device */
+ if (!success) {
+ videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeMuxed];
+ success = [videoDevice open:&error];
+ [pool release];
+ return nil;
+ }
+
+ if (!success) {
+ videoDevice = nil;
+ [pool release];
+ return nil;
+ }
+
+ if (videoDevice) {
+ /* Add the video device to the session as a device input */
+ mCaptureVideoDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:videoDevice];
+ success = [mCaptureSession addInput:mCaptureVideoDeviceInput error:&error];
+
+ if (!success) {
+ [pool release];
+ return nil;
+ }
+
+ mCaptureVideoPreviewOutput = [[QTCaptureVideoPreviewOutput alloc] init];
+ success = [mCaptureSession addOutput:mCaptureVideoPreviewOutput error:&error];
+ if (!success) {
+ [pool release];
+ return nil;
+ }
+
+ mDeviceIsOpened = YES;
+ [mCaptureVideoPreviewOutput setDelegate:self];
+ INFO("Camera session bundling successfully!\n");
+ [pool release];
+ return self;
+ } else {
+ [pool release];
+ return nil;
+ }
+}
+
+- (int)startCapture:(int)width:(int)height
+{
+ int ret = -1;
+
+ if (![mCaptureSession isRunning]) {
+ /* Set width & height, using default pixel format to capture */
+ NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
+ [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
+ nil];
+ [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
+ [mCaptureSession startRunning];
+ } else {
+ ERR("Capture session is already running, exit\n");
+ return ret;
+ }
+
+ if ([mCaptureSession isRunning]) {
+ while(!mCaptureIsStarted) {
+ /* Wait Until Capture is started */
+ [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.5]];
+ }
+ ret = 0;
+ }
+ return ret;
+}
+
+- (void)stopCapture
+{
+ if ([mCaptureSession isRunning]) {
+ [mCaptureSession stopRunning];
+ while([mCaptureSession isRunning]) {
+ /* Wait Until Capture is stopped */
+ [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
+ }
+
+ }
+ mCaptureIsStarted = NO;
+}
+
+- (int)readFrame:(void *)video_buf
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ @synchronized (self) {
+ if (mCaptureIsStarted == NO) {
+ [pool release];
+ return 0;
+ }
+ if (mCurrentImageBuffer != nil) {
+ CVPixelBufferLockBaseAddress(mCurrentImageBuffer, 0);
+ const uint32_t pixel_format = corevideo_to_fourcc(CVPixelBufferGetPixelFormatType(mCurrentImageBuffer));
+ const int frame_width = CVPixelBufferGetWidth(mCurrentImageBuffer);
+ const int frame_height = CVPixelBufferGetHeight(mCurrentImageBuffer);
+ const size_t frame_size = CVPixelBufferGetBytesPerRow(mCurrentImageBuffer) * frame_height;
+ const void *frame_pixels = CVPixelBufferGetBaseAddress(mCurrentImageBuffer);
+
+ TRACE("buffer(%p), pixel_format(%d,%.4s), frame_width(%d), "
+ "frame_height(%d), frame_size(%d)\n",
+ mCurrentImageBuffer, (int)pixel_format,
+ (const char *)&pixel_format, frame_width,
+ frame_height, (int)frame_size);
+
+ /* convert frame to v4l2 format */
+ convert_frame(pixel_format, frame_width, frame_height,
+ frame_size, (void *)frame_pixels, video_buf);
+ CVPixelBufferUnlockBaseAddress(mCurrentImageBuffer, 0);
+ [pool release];
+ return 1;
+ }
+ }
+
+ [pool release];
+ return -1;
+}
+
+- (int)setCaptureFormat:(int)width:(int)height:(int)pix_format
+{
+ int ret = -1;
+ NSDictionary *attributes;
+
+ if (mCaptureSession == nil || mCaptureVideoPreviewOutput == nil) {
+ ERR("Capture session is not initiated.\n");
+ return ret;
+ }
+
+ /* Set the pixel buffer attributes before running the capture session */
+ if (![mCaptureSession isRunning]) {
+ if (pix_format) {
+ attributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
+ [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
+ [NSNumber numberWithInt: pix_format], (id)kCVPixelBufferPixelFormatTypeKey,
+ nil];
+ } else {
+ attributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
+ [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
+ nil];
+ }
+ [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
+ ret = 0;
+ } else {
+ ERR("Cannot set pixel buffer attributes when it's running.\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+- (int)getCaptureFormat:(int)width:(int)height:(int)pix_format
+{
+ return 0;
+}
+
+/* Get the device bundling status */
+- (BOOL)deviceStatus
+{
+ return mDeviceIsOpened;
+}
+
+/* Handle deallocation of memory for your capture objects */
+
+- (void)dealloc
+{
+ [mCaptureSession release];
+ [mCaptureVideoDeviceInput release];
+ [mCaptureVideoPreviewOutput release];
+ [super dealloc];
+}
+
+/* Receive this method whenever the output decompresses and outputs a new video frame */
+- (void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame
+ withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
+{
+ CVImageBufferRef imageBufferToRelease;
+ CVBufferRetain(videoFrame);
+
+ @synchronized (self)
+ {
+ imageBufferToRelease = mCurrentImageBuffer;
+ mCurrentImageBuffer = videoFrame;
+ mCaptureIsStarted = YES;
+ }
+ CVBufferRelease(imageBufferToRelease);
+}
+
+@end
+
+/******************************************************************
+ ** Maru Camera APIs
+ *****************************************************************/
+
+typedef struct MaruCameraDevice MaruCameraDevice;
+struct MaruCameraDevice {
+ /* Maru camera device object. */
+ MaruCameraDriver *driver;
+};
+
+/* Golbal representation of the Maru camera */
+MaruCameraDevice *mcd = NULL;
+
+static int is_streamon()
+{
+ int st;
+ qemu_mutex_lock(&g_state->thread_mutex);
+ st = g_state->streamon;
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return (st == _MC_THREAD_STREAMON);
+}
+
+static void __raise_err_intr()
+{
+ qemu_mutex_lock(&g_state->thread_mutex);
+ if (g_state->streamon == _MC_THREAD_STREAMON) {
+ g_state->req_frame = 0; /* clear request */
+ g_state->isr = 0x08; /* set a error flag of rasing a interrupt */
+ qemu_bh_schedule(g_state->tx_bh);
+ }
+ qemu_mutex_unlock(&g_state->thread_mutex);
+}
+
+static int marucam_device_read_frame()
+{
+ int ret;
+ void *tmp_buf;
+
+ qemu_mutex_lock(&g_state->thread_mutex);
+ if (g_state->streamon == _MC_THREAD_STREAMON) {
+#if 0
+ if (ready_count < MARUCAM_SKIPFRAMES) {
+ /* skip a frame cause first some frame are distorted */
+ ++ready_count;
+ TRACE("Skip %d frame\n", ready_count);
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return 0;
+ }
+#endif
+ if (g_state->req_frame == 0) {
+ TRACE("There is no request\n");
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return 0;
+ }
+
+ /* Grab the camera frame into temp buffer */
+ tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
+ ret = [mcd->driver readFrame: tmp_buf];
+ if (ret < 0) {
+ ERR("%s, Capture error\n", __func__);
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ __raise_err_intr();
+ return -1;
+ } else if (!ret) {
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return 0;
+ }
+
+ g_state->req_frame = 0; /* clear request */
+ g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
+ qemu_bh_schedule(g_state->tx_bh);
+ } else {
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return -1;
+ }
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return 0;
+}
+
+/* Worker thread to grab frames to the preview window */
+static void *marucam_worker_thread(void *thread_param)
+{
+ while (1) {
+ qemu_mutex_lock(&g_state->thread_mutex);
+ g_state->streamon = _MC_THREAD_PAUSED;
+ qemu_cond_wait(&g_state->thread_cond, &g_state->thread_mutex);
+ qemu_mutex_unlock(&g_state->thread_mutex);
+
+ if (g_state->destroying) {
+ break;
+ }
+
+ ready_count = 0;
+ qemu_mutex_lock(&g_state->thread_mutex);
+ g_state->streamon = _MC_THREAD_STREAMON;
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ INFO("Streaming on ......\n");
+
+ /* Loop: capture frame -> convert format -> render to screen */
+ while (1) {
+ if (is_streamon()) {
+ if (marucam_device_read_frame() < 0) {
+ INFO("Streaming is off ...\n");
+ break;
+ } else {
+ /* wait until next frame is avalilable */
+ usleep(22000);
+ }
+ } else {
+ INFO("Streaming is off ...\n");
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int marucam_device_check(int log_flag)
+{
+ /* FIXME: check the device parameters */
+ INFO("Checking camera device\n");
+ return 1;
+}
+
+/**********************************************
+ * MARU camera routines
+ **********************************************/
+void marucam_device_init(MaruCamState *state)
+{
+ g_state = state;
+ g_state->destroying = false;
+ qemu_thread_create(&state->thread_id,
+ MARUCAM_THREAD_NAME,
+ marucam_worker_thread,
+ NULL,
+ QEMU_THREAD_JOINABLE);
+}
+
+void marucam_device_exit(MaruCamState *state)
+{
+ state->destroying = true;
+ qemu_mutex_lock(&state->thread_mutex);
+ qemu_cond_signal(&state->thread_cond);
+ qemu_mutex_unlock(&state->thread_mutex);
+ qemu_thread_join(&state->thread_id);
+}
+
+/* MARUCAM_CMD_OPEN */
+void marucam_device_open(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ mcd = (MaruCameraDevice *)malloc(sizeof(MaruCameraDevice));
+ if (mcd == NULL) {
+ ERR("%s: MaruCameraDevice allocate failed\n", __func__);
+ param->errCode = EINVAL;
+ return;
+ }
+ memset(mcd, 0, sizeof(MaruCameraDevice));
+ mcd->driver = [[MaruCameraDriver alloc] init];
+ if (mcd->driver == nil) {
+ ERR("Camera device open failed\n");
+ [mcd->driver dealloc];
+ free(mcd);
+ param->errCode = EINVAL;
+ return;
+ }
+ INFO("Camera opened!\n");
+}
+
+/* MARUCAM_CMD_CLOSE */
+void marucam_device_close(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ if (mcd != NULL) {
+ if (is_streamon()) {
+ marucam_device_stop_preview(state);
+ }
+ [mcd->driver dealloc];
+ free(mcd);
+ mcd = NULL;
+ }
+
+ /* marucam_reset_controls(); */
+ INFO("Camera closed\n");
+}
+
+/* MARUCAM_CMD_START_PREVIEW */
+void marucam_device_start_preview(MaruCamState *state)
+{
+ uint32_t width, height, pixfmt;
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+ pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ state->buf_size = get_sizeimage(pixfmt, width, height);
+
+ INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u), frame idx(%d), fmt idx(%d)\n",
+ (char)(pixfmt), (char)(pixfmt >> 8),
+ (char)(pixfmt >> 16), (char)(pixfmt >> 24),
+ width, height, state->buf_size,
+ cur_frame_idx, cur_fmt_idx);
+
+ if (mcd->driver == nil) {
+ ERR("%s: Start capture failed: vaild device", __func__);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ INFO("Starting preview ...\n");
+ [mcd->driver startCapture: width: height];
+
+ /* Enable the condition to capture frames now */
+ qemu_mutex_lock(&state->thread_mutex);
+ qemu_cond_signal(&state->thread_cond);
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ while (!is_streamon()) {
+ usleep(10000);
+ }
+}
+
+/* MARUCAM_CMD_STOP_PREVIEW */
+void marucam_device_stop_preview(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ if (is_streamon()) {
+ qemu_mutex_lock(&state->thread_mutex);
+ state->streamon = _MC_THREAD_STREAMOFF;
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ while (is_streamon()) {
+ usleep(10000);
+ }
+ }
+
+ if (mcd->driver != nil) {
+ [mcd->driver stopCapture];
+ }
+
+ state->buf_size = 0;
+ INFO("Stopping preview ...\n");
+}
+
+/* MARUCAM_CMD_S_PARAM */
+void marucam_device_s_param(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ /* We use default FPS of the webcam */
+ param->top = 0;
+}
+
+/* MARUCAM_CMD_G_PARAM */
+void marucam_device_g_param(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ /* We use default FPS of the webcam
+ * return a fixed value on guest ini file (1/30).
+ */
+ param->top = 0;
+ param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
+ param->stack[1] = 1; /* numerator */
+ param->stack[2] = 30; /* denominator */
+}
+
+/* MARUCAM_CMD_S_FMT */
+void marucam_device_s_fmt(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ uint32_t width, height, pixfmt, pidx, fidx;
+
+ param->top = 0;
+ width = param->stack[0];
+ height = param->stack[1];
+ pixfmt = param->stack[2];
+
+ TRACE("Set format: width(%d), height(%d), pixfmt(%d, %.4s)\n",
+ width, height, pixfmt, (const char*)&pixfmt);
+
+ for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
+ if ((supported_dst_frames[fidx].width == width) &&
+ (supported_dst_frames[fidx].height == height)) {
+ break;
+ }
+ }
+ if (fidx == ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
+ if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
+ TRACE("pixfmt index is match: %d\n", pidx);
+ break;
+ }
+ }
+ if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if ((supported_dst_frames[cur_frame_idx].width != width) &&
+ (supported_dst_frames[cur_frame_idx].height != height)) {
+ if (mcd->driver == nil || [mcd->driver setCaptureFormat: width: height: 0] < 0) {
+ ERR("Set pixel format failed\n");
+ param->errCode = EINVAL;
+ return;
+ }
+
+ TRACE("cur_frame_idx:%d, supported_dst_frames[cur_frame_idx].width:%d\n",
+ cur_frame_idx, supported_dst_frames[cur_frame_idx].width);
+ }
+
+ cur_frame_idx = fidx;
+ cur_fmt_idx = pidx;
+
+ pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; /* V4L2_FIELD_NONE */
+ param->stack[3] = pixfmt;
+ param->stack[4] = get_bytesperline(pixfmt, width);
+ param->stack[5] = get_sizeimage(pixfmt, width, height);
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+
+ TRACE("Set device pixel format ...\n");
+}
+
+/* MARUCAM_CMD_G_FMT */
+void marucam_device_g_fmt(MaruCamState *state)
+{
+ uint32_t width, height, pixfmt;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; /* V4L2_FIELD_NONE */
+ param->stack[3] = pixfmt;
+ param->stack[4] = get_bytesperline(pixfmt, width);
+ param->stack[5] = get_sizeimage(pixfmt, width, height);
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+
+ TRACE("Get device frame format ...\n");
+}
+
+void marucam_device_try_fmt(MaruCamState *state)
+{
+ TRACE("Try device frame format, use default setting ...\n");
+}
+
+/* Get specific pixelformat description */
+void marucam_device_enum_fmt(MaruCamState *state)
+{
+ uint32_t index;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ index = param->stack[0];
+
+ if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[1] = 0; /* flags = NONE */
+ param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
+ switch (supported_dst_pixfmts[index].fmt) {
+ case V4L2_PIX_FMT_YUYV:
+ memcpy(¶m->stack[3], "YUYV", 32);
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ memcpy(¶m->stack[3], "UYVY", 32);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ memcpy(¶m->stack[3], "YU12", 32);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ memcpy(¶m->stack[3], "YV12", 32);
+ break;
+ default:
+ param->errCode = EINVAL;
+ break;
+ }
+}
+
+/*
+ * QTKit don't support setting brightness, contrast, saturation & sharpness
+ */
+void marucam_device_qctrl(MaruCamState *state)
+{
+ uint32_t id, i;
+ /* long property, min, max, step, def_val, set_val; */
+ char name[32] = {0,};
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ id = param->stack[0];
+
+ switch (id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("V4L2_CID_BRIGHTNESS\n");
+ memcpy((void *)name, (void *)"brightness", 32);
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("V4L2_CID_CONTRAST\n");
+ memcpy((void *)name, (void *)"contrast", 32);
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("V4L2_CID_SATURATION\n");
+ memcpy((void *)name, (void *)"saturation", 32);
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("V4L2_CID_SHARPNESS\n");
+ memcpy((void *)name, (void *)"sharpness", 32);
+ i = 3;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = id;
+ param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
+ param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
+ param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
+ param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
+ param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
+ /* name field setting */
+ memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
+}
+
+void marucam_device_s_ctrl(MaruCamState *state)
+{
+ INFO("Set control\n");
+}
+
+void marucam_device_g_ctrl(MaruCamState *state)
+{
+ INFO("Get control\n");
+}
+
+/* Get frame width & height */
+void marucam_device_enum_fsizes(MaruCamState *state)
+{
+ uint32_t index, pixfmt, i;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ index = param->stack[0];
+ pixfmt = param->stack[1];
+
+ if (index >= ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+ if (supported_dst_pixfmts[i].fmt == pixfmt) {
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = supported_dst_frames[index].width;
+ param->stack[1] = supported_dst_frames[index].height;
+}
+
+void marucam_device_enum_fintv(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ /* switch by index(param->stack[0]) */
+ switch (param->stack[0]) {
+ case 0:
+ param->stack[1] = 30; /* denominator */
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[0] = 1; /* numerator */
+}
--- /dev/null
+/*
+ * Implementation of MARU Virtual Camera device by PCI bus on Linux.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu-common.h"
+#include "sysemu/kvm.h"
+#include "maru_camera_common.h"
+#include "debug_ch.h"
+
+#include <linux/videodev2.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <libv4l2.h>
+#include <libv4lconvert.h>
+
+MULTI_DEBUG_CHANNEL(tizen, maru-camera);
+
+#define MARUCAM_THREAD_NAME "marucam_worker_thread"
+
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+
+#define MARUCAM_DEFAULT_BUFFER_COUNT 4
+
+#define MARUCAM_CTRL_VALUE_MAX 20
+#define MARUCAM_CTRL_VALUE_MIN 1
+#define MARUCAM_CTRL_VALUE_MID 10
+#define MARUCAM_CTRL_VALUE_STEP 1
+
+enum {
+ _MC_THREAD_PAUSED,
+ _MC_THREAD_STREAMON,
+ _MC_THREAD_STREAMOFF,
+};
+
+typedef struct marucam_framebuffer {
+ void *data;
+ size_t size;
+} marucam_framebuffer;
+
+struct marucam_saved_frame {
+ void *data;
+ uint32_t pixelformat;
+ uint32_t width;
+ uint32_t height;
+ uint32_t size;
+};
+
+static struct marucam_saved_frame saved_frame;
+static char has_success_frame;
+static int n_framebuffer;
+static int previous_frame_index = -1;
+static struct marucam_framebuffer *framebuffer;
+
+static const char *dev_name = "/dev/video0";
+static int v4l2_fd;
+static int convert_trial;
+static int ready_count;
+static int timeout_n;
+
+static struct v4l2_format dst_fmt;
+
+static void ScalePlaneSimple(int src_width, int src_height,
+ int dst_width, int dst_height,
+ int src_stride, int dst_stride,
+ const uint8_t *src_ptr, uint8_t *dst_ptr) {
+ int i, j;
+ int dx = (src_width << 16) / dst_width;
+ int dy = (src_height << 16) / dst_height;
+ int y = (dy >= 65536) ? ((dy >> 1) - 32768) : (dy >> 1);
+ for (j = 0; j < dst_height; ++j) {
+ int x = (dx >= 65536) ? ((dx >> 1) - 32768) : (dx >> 1);
+ int yi = y >> 16;
+ const uint8_t *src = src_ptr + yi * src_stride;
+ uint8_t *dst = dst_ptr;
+ for (i = 0; i < dst_width; ++i) {
+ *dst++ = src[x >> 16];
+ x += dx;
+ }
+ dst_ptr += dst_stride;
+ y += dy;
+ }
+}
+
+static void make_yu12_black(unsigned char *dest, uint32_t width, uint32_t height)
+{
+ uint32_t x, y;
+ unsigned char *udest, *vdest;
+
+ /* Y */
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ *dest++ = 16;
+ }
+ }
+
+ /* U + V */
+ udest = dest;
+ vdest = dest + width * height / 4;
+
+ for (y = 0; y < height / 2; y++) {
+ for (x = 0; x < width / 2; x++) {
+ *udest++ = *vdest++ = 128;
+ }
+ }
+}
+
+static void marucam_scale_yuv420(void *src,
+ uint32_t src_width, uint32_t src_height,
+ void *dst, uint32_t dst_width, uint32_t dst_height)
+{
+ uint32_t src_halfwidth = (src_width + 1) >> 1;
+ uint32_t src_halfheight = (src_height + 1) >> 1;
+ uint32_t dst_halfwidth = (dst_width + 1) >> 1;
+ uint32_t dst_halfheight = (dst_height + 1) >> 1;
+
+ uint8_t *src_u = src + (src_width * src_height);
+ uint8_t *src_v = src_u + (src_width * src_height / 4);
+
+ uint8_t *dst_u = dst + (dst_width * dst_height);
+ uint8_t *dst_v = dst_u + (dst_width * dst_height /4);
+
+ ScalePlaneSimple(src_width, src_height,
+ dst_width, dst_height,
+ src_width, dst_width,
+ src, dst);
+ ScalePlaneSimple(src_halfwidth, src_halfheight,
+ dst_halfwidth, dst_halfheight,
+ src_halfwidth, dst_halfwidth,
+ src_u, dst_u);
+ ScalePlaneSimple(src_halfwidth, src_halfheight,
+ dst_halfwidth, dst_halfheight,
+ src_halfwidth, dst_halfwidth,
+ src_v, dst_v);
+}
+
+static int yioctl(int fd, int req, void *arg)
+{
+ int r;
+
+ do {
+ r = ioctl(fd, req, arg);
+ } while (r < 0 && errno == EINTR);
+
+ return r;
+}
+
+static int xioctl(int fd, int req, void *arg)
+{
+ int r;
+
+ do {
+ r = v4l2_ioctl(fd, req, arg);
+ } while (r < 0 && errno == EINTR);
+
+ return r;
+}
+
+typedef struct tagMaruCamConvertPixfmt {
+ uint32_t fmt; /* fourcc */
+} MaruCamConvertPixfmt;
+
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
+ { V4L2_PIX_FMT_YUYV },
+ { V4L2_PIX_FMT_YUV420 },
+ { V4L2_PIX_FMT_YVU420 },
+};
+
+typedef struct tagMaruCamConvertFrameInfo {
+ uint32_t width;
+ uint32_t height;
+} MaruCamConvertFrameInfo;
+
+static MaruCamConvertFrameInfo supported_dst_frames[] = {
+ { 640, 480 },
+ { 352, 288 },
+ { 320, 240 },
+ { 176, 144 },
+ { 160, 120 },
+};
+
+struct marucam_qctrl {
+ uint32_t id;
+ uint32_t hit;
+ int32_t min;
+ int32_t max;
+ int32_t step;
+ int32_t init_val;
+};
+
+static struct marucam_qctrl qctrl_tbl[] = {
+ { V4L2_CID_BRIGHTNESS, 0, },
+ { V4L2_CID_CONTRAST, 0, },
+ { V4L2_CID_SATURATION, 0, },
+ { V4L2_CID_SHARPNESS, 0, },
+};
+
+static void marucam_reset_controls(void)
+{
+ uint32_t i;
+ for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) {
+ if (qctrl_tbl[i].hit) {
+ struct v4l2_control ctrl = {0,};
+ qctrl_tbl[i].hit = 0;
+ ctrl.id = qctrl_tbl[i].id;
+ ctrl.value = qctrl_tbl[i].init_val;
+ if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
+ ERR("Failed to reset control value: id(0x%x), errstr(%s)\n",
+ ctrl.id, strerror(errno));
+ }
+ }
+ }
+}
+
+static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value)
+{
+ double rate = 0.0;
+ int32_t dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = min + (int32_t)(value / rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = min + (int32_t)(rate * value);
+ }
+ return ret;
+}
+
+static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value)
+{
+ double rate = 0.0;
+ int32_t dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = (int32_t)((double)(value - min) * rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = (int32_t)((double)(value - min) / rate);
+ }
+
+ return ret;
+}
+
+static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format,
+ uint32_t width, uint32_t height)
+{
+ struct v4l2_frmivalenum fival;
+ struct v4l2_streamparm sp;
+ uint32_t min_num = 0, min_denom = 0;
+
+ CLEAR(fival);
+ fival.pixel_format = pixel_format;
+ fival.width = width;
+ fival.height = height;
+
+ if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) {
+ ERR("Unable to enumerate intervals for pixelformat(0x%x), (%d:%d)\n",
+ pixel_format, width, height);
+ return;
+ }
+
+ if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+ float max_ival = -1.0;
+ do {
+ float cur_ival = (float)fival.discrete.numerator
+ / (float)fival.discrete.denominator;
+ if (cur_ival > max_ival) {
+ max_ival = cur_ival;
+ min_num = fival.discrete.numerator;
+ min_denom = fival.discrete.denominator;
+ }
+ TRACE("Discrete frame interval %u/%u supported\n",
+ fival.discrete.numerator, fival.discrete.denominator);
+ fival.index++;
+ } while (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0);
+ } else if ((fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) ||
+ (fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) {
+ TRACE("Frame intervals from %u/%u to %u/%u supported",
+ fival.stepwise.min.numerator, fival.stepwise.min.denominator,
+ fival.stepwise.max.numerator, fival.stepwise.max.denominator);
+ if (fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
+ TRACE("with %u/%u step", fival.stepwise.step.numerator,
+ fival.stepwise.step.denominator);
+ }
+ if (((float)fival.stepwise.max.denominator /
+ (float)fival.stepwise.max.numerator) >
+ ((float)fival.stepwise.min.denominator /
+ (float)fival.stepwise.min.numerator)) {
+ min_num = fival.stepwise.max.numerator;
+ min_denom = fival.stepwise.max.denominator;
+ } else {
+ min_num = fival.stepwise.min.numerator;
+ min_denom = fival.stepwise.min.denominator;
+ }
+ }
+ TRACE("The actual min values: %u/%u\n", min_num, min_denom);
+
+ CLEAR(sp);
+ sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ sp.parm.capture.timeperframe.numerator = min_num;
+ sp.parm.capture.timeperframe.denominator = min_denom;
+
+ if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {
+ ERR("Failed to set to minimum FPS(%u/%u)\n", min_num, min_denom);
+ }
+}
+
+static uint32_t stop_capturing(void)
+{
+ enum v4l2_buf_type type;
+
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (xioctl(v4l2_fd, VIDIOC_STREAMOFF, &type) < 0) {
+ ERR("Failed to ioctl() with VIDIOC_STREAMOFF: %s\n", strerror(errno));
+ return errno;
+ }
+ return 0;
+}
+
+static uint32_t start_capturing(void)
+{
+ enum v4l2_buf_type type;
+
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (xioctl(v4l2_fd, VIDIOC_STREAMON, &type) < 0) {
+ ERR("Failed to ioctl() with VIDIOC_STREAMON: %s\n", strerror(errno));
+ return errno;
+ }
+ return 0;
+}
+
+static void free_framebuffers(marucam_framebuffer *fb, int buf_num)
+{
+ int i;
+
+ if (fb == NULL) {
+ ERR("The framebuffer is NULL. Failed to release the framebuffer\n");
+ return;
+ } else if (buf_num == 0) {
+ ERR("The buffer count is 0. Failed to release the framebuffer\n");
+ return;
+ } else {
+ TRACE("[%s]:fb(0x%p), buf_num(%d)\n", __func__, fb, buf_num);
+ }
+
+ /* Unmap framebuffers. */
+ for (i = 0; i < buf_num; i++) {
+ if (fb[i].data != NULL) {
+ v4l2_munmap(fb[i].data, fb[i].size);
+ fb[i].data = NULL;
+ fb[i].size = 0;
+ } else {
+ ERR("framebuffer[%d].data is NULL.\n", i);
+ }
+ }
+ previous_frame_index = -1;
+}
+
+static uint32_t
+mmap_framebuffers(marucam_framebuffer **fb, int *buf_num)
+{
+ struct v4l2_requestbuffers req;
+
+ CLEAR(req);
+ req.count = MARUCAM_DEFAULT_BUFFER_COUNT;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+ if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &req) < 0) {
+ if (errno == EINVAL) {
+ ERR("%s does not support memory mapping: %s\n",
+ dev_name, strerror(errno));
+ } else {
+ ERR("Failed to request bufs: %s\n", strerror(errno));
+ }
+ return errno;
+ }
+ if (req.count == 0) {
+ ERR("Insufficient buffer memory on %s\n", dev_name);
+ return EINVAL;
+ }
+
+ *fb = g_new0(marucam_framebuffer, req.count);
+ if (*fb == NULL) {
+ ERR("Not enough memory to allocate framebuffers\n");
+ return ENOMEM;
+ }
+
+ for (*buf_num = 0; *buf_num < req.count; ++*buf_num) {
+ struct v4l2_buffer buf;
+ CLEAR(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = *buf_num;
+ if (xioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf) < 0) {
+ ERR("Failed to ioctl() with VIDIOC_QUERYBUF: %s\n",
+ strerror(errno));
+ return errno;
+ }
+
+ (*fb)[*buf_num].size = buf.length;
+ (*fb)[*buf_num].data = v4l2_mmap(NULL,
+ buf.length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ v4l2_fd, buf.m.offset);
+ if (MAP_FAILED == (*fb)[*buf_num].data) {
+ ERR("Failed to mmap: %s\n", strerror(errno));
+ return errno;
+ }
+
+ /* Queue the mapped buffer. */
+ CLEAR(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = *buf_num;
+ if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) {
+ ERR("Failed to ioctl() with VIDIOC_QBUF: %s\n", strerror(errno));
+ return errno;
+ }
+ }
+ return 0;
+}
+
+static int is_streamon(MaruCamState *state)
+{
+ int st;
+ qemu_mutex_lock(&state->thread_mutex);
+ st = state->streamon;
+ qemu_mutex_unlock(&state->thread_mutex);
+ return (st == _MC_THREAD_STREAMON);
+}
+
+static int is_stream_paused(MaruCamState *state)
+{
+ int st;
+ qemu_mutex_lock(&state->thread_mutex);
+ st = state->streamon;
+ qemu_mutex_unlock(&state->thread_mutex);
+ return (st == _MC_THREAD_PAUSED);
+}
+
+/* sends a frame, YU12/black color */
+/* TODO: add other pixel format method */
+static void __raise_dummy_intr(MaruCamState *state)
+{
+ void *buf = NULL;
+ qemu_mutex_lock(&state->thread_mutex);
+ if (state->streamon == _MC_THREAD_STREAMON && state->req_frame) {
+ buf = state->vaddr + state->buf_size * (state->req_frame - 1);
+ if (saved_frame.data) {
+ if (saved_frame.width == dst_fmt.fmt.pix.width &&
+ saved_frame.height == dst_fmt.fmt.pix.height) {
+ TRACE("Copies the previuos frame\n");
+ memcpy(buf, saved_frame.data, state->buf_size);
+ } else {
+ TRACE("Resizes the previous frame\n");
+ marucam_scale_yuv420(saved_frame.data, saved_frame.width,
+ saved_frame.height,
+ buf, dst_fmt.fmt.pix.width,
+ dst_fmt.fmt.pix.height);
+ }
+ } else {
+ TRACE("Sends a black frame\n");
+ make_yu12_black(buf,
+ dst_fmt.fmt.pix.width,
+ dst_fmt.fmt.pix.height);
+ }
+ state->req_frame = 0; /* clear request */
+ state->isr |= 0x01; /* set a flag of raising a interrupt */
+ qemu_bh_schedule(state->tx_bh);
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+}
+
+static void __raise_err_intr(MaruCamState *state)
+{
+ qemu_mutex_lock(&state->thread_mutex);
+ if (state->streamon == _MC_THREAD_STREAMON) {
+ state->req_frame = 0; /* clear request */
+ state->isr = 0x08; /* set a error flag of raising a interrupt */
+ qemu_bh_schedule(state->tx_bh);
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+}
+
+static void
+notify_buffer_ready(MaruCamState *state, uint32_t buf_index)
+{
+ void *buf = NULL;
+
+ qemu_mutex_lock(&state->thread_mutex);
+ if (state->streamon == _MC_THREAD_STREAMON) {
+ if (ready_count < MARUCAM_SKIPFRAMES) {
+ /* skip a frame cause first some frame are distorted */
+ ++ready_count;
+ TRACE("Skip %d frame\n", ready_count);
+ qemu_mutex_unlock(&state->thread_mutex);
+ return;
+ }
+ if (state->req_frame == 0) {
+ TRACE("There is no request\n");
+ qemu_mutex_unlock(&state->thread_mutex);
+ return;
+ }
+ buf = state->vaddr + state->buf_size * (state->req_frame - 1);
+ memcpy(buf, framebuffer[buf_index].data, state->buf_size);
+ previous_frame_index = buf_index;
+ has_success_frame = 1;
+ state->req_frame = 0; /* clear request */
+ state->isr |= 0x01; /* set a flag of rasing a interrupt */
+ qemu_bh_schedule(state->tx_bh);
+ }
+ qemu_mutex_unlock(&state->thread_mutex);
+}
+
+static int read_frame(MaruCamState *state)
+{
+ struct v4l2_buffer buf;
+
+ CLEAR(buf);
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ if (xioctl(v4l2_fd, VIDIOC_DQBUF, &buf) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ ERR("DQBUF error, try again: %s\n", strerror(errno));
+ return 0;
+ case EIO:
+ ERR("The v4l2_read() met the EIO\n");
+ if (convert_trial-- == -1) {
+ ERR("Try count for v4l2_read is exceeded: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ return 0;
+ default:
+ ERR("DQBUF error: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ notify_buffer_ready(state, buf.index);
+
+ if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) {
+ ERR("QBUF error: %s\n", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int __v4l2_streaming(MaruCamState *state)
+{
+ fd_set fds;
+ struct timeval tv;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(v4l2_fd, &fds);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv);
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ ERR("Select again: %s\n", strerror(errno));
+ return 0;
+ }
+ ERR("Failed to select: %s\n", strerror(errno));
+ __raise_err_intr(state);
+ return -1;
+ } else if (!ret) {
+ timeout_n++;
+ ERR("Select timed out: count(%u)\n", timeout_n);
+ if (ready_count <= MARUCAM_SKIPFRAMES) {
+ switch (timeout_n) {
+ case 1:
+ ERR("Waiting for reading a frame data\n");
+ return 0;
+ case 2:
+ case 3:
+ case 4:
+ ERR("Sends dummy data to initialize the camera\n");
+ __raise_dummy_intr(state);
+ return 0;
+ default:
+ ERR("Webcam is busy, failed to a read frame."
+ " Raises an error\n");
+ __raise_err_intr(state);
+ return -1;
+ }
+ }
+ if (timeout_n >= 5) {
+ ERR("Webcam is busy, failed to a read frame. Raises an error\n");
+ __raise_err_intr(state);
+ return -1;
+ }
+ if (previous_frame_index != -1) {
+ ERR("Sends previous frame data\n");
+ notify_buffer_ready(state, previous_frame_index);
+ }
+ return 0;
+ }
+
+ if (!v4l2_fd || (v4l2_fd == -1)) {
+ ERR("The file descriptor is closed or not opened\n");
+ __raise_err_intr(state);
+ return -1;
+ }
+
+ ret = read_frame(state);
+ if (ret < 0) {
+ ERR("Failed to operate the read_frame()\n");
+ __raise_err_intr(state);
+ return -1;
+ }
+
+ /* clear the skip count for select time-out */
+ if (timeout_n > 0) {
+ timeout_n = 0;
+ }
+
+ return 0;
+}
+
+/* Worker thread */
+static void *marucam_worker_thread(void *thread_param)
+{
+ MaruCamState *state = (MaruCamState *)thread_param;
+
+ while (1) {
+ qemu_mutex_lock(&state->thread_mutex);
+ state->streamon = _MC_THREAD_PAUSED;
+ qemu_cond_wait(&state->thread_cond, &state->thread_mutex);
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ if (state->destroying) {
+ break;
+ }
+
+ convert_trial = 10;
+ ready_count = 0;
+ timeout_n = 0;
+ has_success_frame = 0;
+ qemu_mutex_lock(&state->thread_mutex);
+ state->streamon = _MC_THREAD_STREAMON;
+ qemu_mutex_unlock(&state->thread_mutex);
+ INFO("Streaming on ......\n");
+
+ while (1) {
+ if (is_streamon(state)) {
+ if (__v4l2_streaming(state) < 0) {
+ INFO("...... Streaming off\n");
+ break;
+ }
+ } else {
+ INFO("...... Streaming off\n");
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int marucam_device_check(int log_flag)
+{
+ int tmp_fd;
+ struct timeval t1, t2;
+ struct stat st;
+ struct v4l2_fmtdesc format;
+ struct v4l2_frmsizeenum size;
+ struct v4l2_capability cap;
+ int ret = 0;
+
+ gettimeofday(&t1, NULL);
+ if (stat(dev_name, &st) < 0) {
+ INFO("<WARNING> Cannot identify '%s': %s\n",
+ dev_name, strerror(errno));
+ } else {
+ if (!S_ISCHR(st.st_mode)) {
+ INFO("<WARNING>%s is no character device\n",
+ dev_name);
+ }
+ }
+
+ tmp_fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
+ if (tmp_fd < 0) {
+ ERR("Camera device open failed: %s\n", dev_name);
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time: %lu:%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+ if (ioctl(tmp_fd, VIDIOC_QUERYCAP, &cap) < 0) {
+ ERR("Could not qeury video capabilities\n");
+ close(tmp_fd);
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time: %lu:%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
+ !(cap.capabilities & V4L2_CAP_STREAMING)) {
+ ERR("Not supported video driver\n");
+ close(tmp_fd);
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time: %lu:%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+ ret = 1;
+
+ if (log_flag) {
+ INFO("Driver: %s\n", cap.driver);
+ INFO("Card: %s\n", cap.card);
+ INFO("Bus info: %s\n", cap.bus_info);
+
+ CLEAR(format);
+ format.index = 0;
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) < 0) {
+ close(tmp_fd);
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time: %lu:%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ do {
+ CLEAR(size);
+ size.index = 0;
+ size.pixel_format = format.pixelformat;
+
+ INFO("PixelFormat: %c%c%c%c\n",
+ (char)(format.pixelformat),
+ (char)(format.pixelformat >> 8),
+ (char)(format.pixelformat >> 16),
+ (char)(format.pixelformat >> 24));
+
+ if (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) {
+ close(tmp_fd);
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time: %lu:%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ do {
+ INFO("\tGot a discrete frame size %dx%d\n",
+ size.discrete.width, size.discrete.height);
+ size.index++;
+ } while (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
+ } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
+ INFO("We have stepwise frame sizes:\n");
+ INFO("\tmin width: %d, min height: %d\n",
+ size.stepwise.min_width, size.stepwise.min_height);
+ INFO("\tmax width: %d, max height: %d\n",
+ size.stepwise.max_width, size.stepwise.max_height);
+ INFO("\tstep width: %d, step height: %d\n",
+ size.stepwise.step_width, size.stepwise.step_height);
+ } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
+ INFO("We have continuous frame sizes:\n");
+ INFO("\tmin width: %d, min height: %d\n",
+ size.stepwise.min_width, size.stepwise.min_height);
+ INFO("\tmax width: %d, max height: %d\n",
+ size.stepwise.max_width, size.stepwise.max_height);
+
+ }
+ format.index++;
+ } while (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) >= 0);
+ }
+
+ close(tmp_fd);
+ gettimeofday(&t2, NULL);
+ INFO("Elapsed time: %lu:%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+}
+
+void marucam_device_init(MaruCamState *state)
+{
+ state->destroying = false;
+ qemu_thread_create(&state->thread_id,
+ MARUCAM_THREAD_NAME,
+ marucam_worker_thread,
+ (void *)state,
+ QEMU_THREAD_JOINABLE);
+}
+
+void marucam_device_exit(MaruCamState *state)
+{
+ state->destroying = true;
+ qemu_mutex_lock(&state->thread_mutex);
+ qemu_cond_signal(&state->thread_cond);
+ qemu_mutex_unlock(&state->thread_mutex);
+ qemu_thread_join(&state->thread_id);
+}
+
+void marucam_device_open(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ v4l2_fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
+ if (v4l2_fd < 0) {
+ ERR("The v4l2 device open failed: %s\n", dev_name);
+ param->errCode = EINVAL;
+ return;
+ }
+ INFO("Opened\n");
+
+ /* FIXME : Do not use fixed values */
+ CLEAR(dst_fmt);
+ dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_fmt.fmt.pix.width = 640;
+ dst_fmt.fmt.pix.height = 480;
+ dst_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ dst_fmt.fmt.pix.field = V4L2_FIELD_ANY;
+
+ if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) {
+ ERR("Failed to set video format: format(0x%x), width:height(%d:%d), "
+ "errstr(%s)\n", dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.width,
+ dst_fmt.fmt.pix.height, strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ TRACE("Set the default format: w:h(%dx%d), fmt(0x%x), size(%d), "
+ "color(%d), field(%d)\n",
+ dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height,
+ dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage,
+ dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field);
+}
+
+void marucam_device_start_preview(MaruCamState *state)
+{
+ struct timespec req;
+ MaruCamParam *param = state->param;
+ param->top = 0;
+ req.tv_sec = 0;
+ req.tv_nsec = 10000000;
+
+ INFO("Pixfmt(%c%c%c%C), W:H(%d:%d), buf size(%u)\n",
+ (char)(dst_fmt.fmt.pix.pixelformat),
+ (char)(dst_fmt.fmt.pix.pixelformat >> 8),
+ (char)(dst_fmt.fmt.pix.pixelformat >> 16),
+ (char)(dst_fmt.fmt.pix.pixelformat >> 24),
+ dst_fmt.fmt.pix.width,
+ dst_fmt.fmt.pix.height,
+ dst_fmt.fmt.pix.sizeimage);
+
+ param->errCode = mmap_framebuffers(&framebuffer, &n_framebuffer);
+ if (param->errCode) {
+ ERR("Failed to mmap framebuffers\n");
+ if (framebuffer != NULL) {
+ free_framebuffers(framebuffer, n_framebuffer);
+ g_free(framebuffer);
+ framebuffer = NULL;
+ n_framebuffer = 0;
+ }
+ return;
+ }
+
+ param->errCode = start_capturing();
+ if (param->errCode) {
+ if (framebuffer != NULL) {
+ free_framebuffers(framebuffer, n_framebuffer);
+ g_free(framebuffer);
+ framebuffer = NULL;
+ n_framebuffer = 0;
+ }
+ return;
+ }
+
+ INFO("Starting preview\n");
+ state->buf_size = dst_fmt.fmt.pix.sizeimage;
+ qemu_mutex_lock(&state->thread_mutex);
+ qemu_cond_signal(&state->thread_cond);
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ /* nanosleep until thread is streamon */
+ while (!is_streamon(state)) {
+ nanosleep(&req, NULL);
+ }
+}
+
+void marucam_device_stop_preview(MaruCamState *state)
+{
+ struct timespec req;
+ struct v4l2_requestbuffers reqbuf;
+ MaruCamParam *param = state->param;
+ param->top = 0;
+ req.tv_sec = 0;
+ req.tv_nsec = 50000000;
+
+ if (is_streamon(state)) {
+ qemu_mutex_lock(&state->thread_mutex);
+ state->streamon = _MC_THREAD_STREAMOFF;
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ /* nanosleep until thread is paused */
+ while (!is_stream_paused(state)) {
+ nanosleep(&req, NULL);
+ }
+ }
+
+ if (has_success_frame) {
+ saved_frame.width = dst_fmt.fmt.pix.width;
+ saved_frame.height = dst_fmt.fmt.pix.height;
+ saved_frame.size = dst_fmt.fmt.pix.sizeimage;
+ if (saved_frame.data) {
+ g_free(saved_frame.data);
+ saved_frame.data = NULL;
+ }
+ saved_frame.data = (void *)g_malloc0(saved_frame.size);
+ memcpy(saved_frame.data,
+ framebuffer[previous_frame_index].data,
+ saved_frame.size);
+ TRACE("Saves a frame data\n");
+ }
+
+ param->errCode = stop_capturing();
+ if (framebuffer != NULL) {
+ free_framebuffers(framebuffer, n_framebuffer);
+ g_free(framebuffer);
+ framebuffer = NULL;
+ n_framebuffer = 0;
+ }
+ state->buf_size = 0;
+
+ reqbuf.count = 0;
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+ if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
+ ERR("Failed to ioctl() with VIDIOC_REQBUF in stop_preview: %s\n",
+ strerror(errno));
+ }
+ INFO("Stopping preview\n");
+}
+
+void marucam_device_s_param(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+
+ /* If KVM enabled, We use default FPS of the webcam.
+ * If KVM disabled, we use mininum FPS of the webcam */
+ if (!kvm_enabled()) {
+ set_maxframeinterval(state, dst_fmt.fmt.pix.pixelformat,
+ dst_fmt.fmt.pix.width,
+ dst_fmt.fmt.pix.height);
+ }
+}
+
+void marucam_device_g_param(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ /* We use default FPS of the webcam
+ * return a fixed value on guest ini file (1/30).
+ */
+ param->top = 0;
+ param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
+ param->stack[1] = 1; /* numerator */
+ param->stack[2] = 30; /* denominator */
+}
+
+void marucam_device_s_fmt(MaruCamState *state)
+{
+ struct v4l2_format format;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ CLEAR(format);
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = param->stack[0];
+ format.fmt.pix.height = param->stack[1];
+ format.fmt.pix.pixelformat = param->stack[2];
+ format.fmt.pix.field = V4L2_FIELD_ANY;
+
+ if (xioctl(v4l2_fd, VIDIOC_S_FMT, &format) < 0) {
+ ERR("Failed to set video format: format(0x%x), width:height(%d:%d), "
+ "errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,
+ format.fmt.pix.height, strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+
+ memcpy(&dst_fmt, &format, sizeof(format));
+ param->stack[0] = dst_fmt.fmt.pix.width;
+ param->stack[1] = dst_fmt.fmt.pix.height;
+ param->stack[2] = dst_fmt.fmt.pix.field;
+ param->stack[3] = dst_fmt.fmt.pix.pixelformat;
+ param->stack[4] = dst_fmt.fmt.pix.bytesperline;
+ param->stack[5] = dst_fmt.fmt.pix.sizeimage;
+ param->stack[6] = dst_fmt.fmt.pix.colorspace;
+ param->stack[7] = dst_fmt.fmt.pix.priv;
+ TRACE("Set the format: w:h(%dx%d), fmt(0x%x), size(%d), "
+ "color(%d), field(%d)\n",
+ dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height,
+ dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage,
+ dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field);
+}
+
+void marucam_device_g_fmt(MaruCamState *state)
+{
+ struct v4l2_format format;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ CLEAR(format);
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) {
+ ERR("Failed to get video format: %s\n", strerror(errno));
+ param->errCode = errno;
+ } else {
+ param->stack[0] = format.fmt.pix.width;
+ param->stack[1] = format.fmt.pix.height;
+ param->stack[2] = format.fmt.pix.field;
+ param->stack[3] = format.fmt.pix.pixelformat;
+ param->stack[4] = format.fmt.pix.bytesperline;
+ param->stack[5] = format.fmt.pix.sizeimage;
+ param->stack[6] = format.fmt.pix.colorspace;
+ param->stack[7] = format.fmt.pix.priv;
+ TRACE("Get the format: w:h(%dx%d), fmt(0x%x), size(%d), "
+ "color(%d), field(%d)\n",
+ format.fmt.pix.width, format.fmt.pix.height,
+ format.fmt.pix.pixelformat, format.fmt.pix.sizeimage,
+ format.fmt.pix.colorspace, format.fmt.pix.field);
+ }
+}
+
+void marucam_device_try_fmt(MaruCamState *state)
+{
+ struct v4l2_format format;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ CLEAR(format);
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = param->stack[0];
+ format.fmt.pix.height = param->stack[1];
+ format.fmt.pix.pixelformat = param->stack[2];
+ format.fmt.pix.field = V4L2_FIELD_ANY;
+
+ if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) {
+ ERR("Failed to check video format: format(0x%x), width:height(%d:%d),"
+ " errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,
+ format.fmt.pix.height, strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ param->stack[0] = format.fmt.pix.width;
+ param->stack[1] = format.fmt.pix.height;
+ param->stack[2] = format.fmt.pix.field;
+ param->stack[3] = format.fmt.pix.pixelformat;
+ param->stack[4] = format.fmt.pix.bytesperline;
+ param->stack[5] = format.fmt.pix.sizeimage;
+ param->stack[6] = format.fmt.pix.colorspace;
+ param->stack[7] = format.fmt.pix.priv;
+ TRACE("Check the format: w:h(%dx%d), fmt(0x%x), size(%d), "
+ "color(%d), field(%d)\n",
+ format.fmt.pix.width, format.fmt.pix.height,
+ format.fmt.pix.pixelformat, format.fmt.pix.sizeimage,
+ format.fmt.pix.colorspace, format.fmt.pix.field);
+}
+
+void marucam_device_enum_fmt(MaruCamState *state)
+{
+ uint32_t index;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ index = param->stack[0];
+
+ if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[1] = 0; /* flags = NONE */
+ param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
+ /* set description */
+ switch (supported_dst_pixfmts[index].fmt) {
+ case V4L2_PIX_FMT_YUYV:
+ strcpy((char *)¶m->stack[3], "YUYV");
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ strcpy((char *)¶m->stack[3], "YU12");
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ strcpy((char *)¶m->stack[3], "YV12");
+ break;
+ default:
+ ERR("Invalid fixel format\n");
+ param->errCode = EINVAL;
+ break;
+ }
+}
+
+void marucam_device_qctrl(MaruCamState *state)
+{
+ uint32_t i;
+ char name[32] = {0,};
+ struct v4l2_queryctrl ctrl;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ CLEAR(ctrl);
+ ctrl.id = param->stack[0];
+
+ switch (ctrl.id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("Query : BRIGHTNESS\n");
+ strcpy(name, "brightness");
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("Query : CONTRAST\n");
+ strcpy(name, "contrast");
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("Query : SATURATION\n");
+ strcpy(name, "saturation");
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("Query : SHARPNESS\n");
+ strcpy(name, "sharpness");
+ i = 3;
+ break;
+ default:
+ ERR("Invalid control ID\n");
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) {
+ if (errno != EINVAL) {
+ ERR("Failed to query video controls: %s\n", strerror(errno));
+ }
+ param->errCode = errno;
+ return;
+ } else {
+ struct v4l2_control sctrl;
+ CLEAR(sctrl);
+ sctrl.id = ctrl.id;
+ if ((ctrl.maximum + ctrl.minimum) == 0) {
+ sctrl.value = 0;
+ } else {
+ sctrl.value = (ctrl.maximum + ctrl.minimum) / 2;
+ }
+ if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) {
+ ERR("Failed to set control value: id(0x%x), value(%d), "
+ "errstr(%s)\n", sctrl.id, sctrl.value, strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ qctrl_tbl[i].hit = 1;
+ qctrl_tbl[i].min = ctrl.minimum;
+ qctrl_tbl[i].max = ctrl.maximum;
+ qctrl_tbl[i].step = ctrl.step;
+ qctrl_tbl[i].init_val = ctrl.default_value;
+ }
+
+ /* set fixed values by FW configuration file */
+ param->stack[0] = ctrl.id;
+ param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
+ param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
+ param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
+ param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
+ param->stack[5] = ctrl.flags;
+ /* name field setting */
+ memcpy(¶m->stack[6], (void *)name, sizeof(ctrl.name));
+}
+
+void marucam_device_s_ctrl(MaruCamState *state)
+{
+ uint32_t i;
+ struct v4l2_control ctrl;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ CLEAR(ctrl);
+ ctrl.id = param->stack[0];
+
+ switch (ctrl.id) {
+ case V4L2_CID_BRIGHTNESS:
+ i = 0;
+ TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]);
+ break;
+ case V4L2_CID_CONTRAST:
+ i = 1;
+ TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]);
+ break;
+ case V4L2_CID_SATURATION:
+ i = 2;
+ TRACE("%d is set to the value of the SATURATION\n", param->stack[1]);
+ break;
+ case V4L2_CID_SHARPNESS:
+ i = 3;
+ TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]);
+ break;
+ default:
+ ERR("Our emulator does not support this control: 0x%x\n", ctrl.id);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ ctrl.value = value_convert_from_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, param->stack[1]);
+ if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
+ ERR("Failed to set control value: id(0x%x), value(r:%d, c:%d), "
+ "errstr(%s)\n", ctrl.id, param->stack[1], ctrl.value,
+ strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+}
+
+void marucam_device_g_ctrl(MaruCamState *state)
+{
+ uint32_t i;
+ struct v4l2_control ctrl;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ CLEAR(ctrl);
+ ctrl.id = param->stack[0];
+
+ switch (ctrl.id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("Gets the value of the BRIGHTNESS\n");
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("Gets the value of the CONTRAST\n");
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("Gets the value of the SATURATION\n");
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("Gets the value of the SHARPNESS\n");
+ i = 3;
+ break;
+ default:
+ ERR("Our emulator does not support this control: 0x%x\n", ctrl.id);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) {
+ ERR("Failed to get video control value: %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, ctrl.value);
+ TRACE("Value: %d\n", param->stack[0]);
+}
+
+void marucam_device_enum_fsizes(MaruCamState *state)
+{
+ uint32_t index, pixfmt, i;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ index = param->stack[0];
+ pixfmt = param->stack[1];
+
+ if (index >= ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+ if (supported_dst_pixfmts[i].fmt == pixfmt) {
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = supported_dst_frames[index].width;
+ param->stack[1] = supported_dst_frames[index].height;
+}
+
+void marucam_device_enum_fintv(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+
+ /* switch by index(param->stack[0]) */
+ switch (param->stack[0]) {
+ case 0:
+ /* we only use 1/30 frame interval */
+ param->stack[1] = 30; /* denominator */
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[0] = 1; /* numerator */
+}
+
+void marucam_device_close(MaruCamState *state)
+{
+ if (!is_stream_paused(state)) {
+ marucam_device_stop_preview(state);
+ }
+
+ marucam_reset_controls();
+
+ if (saved_frame.data) {
+ g_free(saved_frame.data);
+ saved_frame.data = NULL;
+ }
+ memset(&saved_frame, 0x00, sizeof(saved_frame));
+
+ v4l2_close(v4l2_fd);
+ v4l2_fd = 0;
+ INFO("Closed\n");
+}
--- /dev/null
+/*
+ * Interface definition header for Windows host.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _MARU_CAMERA_INTERFACE_H_
+#define _MARU_CAMERA_INTERFACE_H_
+
+extern int hax_enabled(void);
+
+static const WCHAR HWCPinName[] = L"HWCInputPin\0";
+static const WCHAR HWCFilterName[] = L"HWCFilter\0";
+
+/* Forward Declarations */
+FWD_DECL(IBaseFilter);
+FWD_DECL(IFilterGraph);
+
+/* defines */
+#define MAX_PIN_NAME 128
+#define MAX_FILTER_NAME 128
+
+#define DECLARE_INTERFACE2(i) \
+ _COM_interface i { CONST_VTABLE struct i##Vtbl *lpVtbl; }; \
+ typedef CONST_VTABLE struct i##Vtbl i##Vtbl; \
+ CONST_VTABLE struct i##Vtbl
+#define DECLARE_INTERFACE2_(i, b) DECLARE_INTERFACE2(i)
+
+typedef LONGLONG REFERENCE_TIME;
+typedef long OAFilterState;
+typedef DWORD_PTR HSEMAPHORE;
+typedef DWORD_PTR HEVENT;
+
+typedef enum _FilterState {
+ State_Stopped,
+ State_Paused,
+ State_Running
+} FILTER_STATE;
+
+typedef struct _FilterInfo {
+ WCHAR achName[MAX_FILTER_NAME];
+ IFilterGraph *pGraph;
+} FILTER_INFO;
+
+typedef enum _PinDirection {
+ PINDIR_INPUT = 0,
+ PINDIR_OUTPUT = (PINDIR_INPUT + 1)
+} PIN_DIRECTION;
+
+typedef struct _PinInfo {
+ IBaseFilter *pFilter;
+ PIN_DIRECTION dir;
+ WCHAR achName[MAX_PIN_NAME];
+} PIN_INFO;
+
+typedef struct _AllocatorProperties {
+ long cBuffers;
+ long cbBuffer;
+ long cbAlign;
+ long cbPrefix;
+} ALLOCATOR_PROPERTIES;
+
+typedef struct _AMMediaType {
+ GUID majortype;
+ GUID subtype;
+ BOOL bFixedSizeSamples;
+ BOOL bTemporalCompression;
+ ULONG lSampleSize;
+ GUID formattype;
+ IUnknown *pUnk;
+ ULONG cbFormat;
+ BYTE *pbFormat;
+} AM_MEDIA_TYPE;
+
+typedef enum tagVideoProcAmpFlags {
+ VideoProcAmp_Flags_Auto = 0x0001,
+ VideoProcAmp_Flags_Manual = 0x0002
+} VideoProcAmpFlags;
+
+typedef enum tagVideoProcAmpProperty {
+ VideoProcAmp_Brightness,
+ VideoProcAmp_Contrast,
+ VideoProcAmp_Hue,
+ VideoProcAmp_Saturation,
+ VideoProcAmp_Sharpness,
+ VideoProcAmp_Gamma,
+ VideoProcAmp_ColorEnable,
+ VideoProcAmp_WhiteBalance,
+ VideoProcAmp_BacklightCompensation,
+ VideoProcAmp_Gain
+} VideoProcAmpProperty;
+
+typedef struct tagVIDEOINFOHEADER {
+ RECT rcSource;
+ RECT rcTarget;
+ DWORD dwBitRate;
+ DWORD dwBitErrorRate;
+ REFERENCE_TIME AvgTimePerFrame;
+ BITMAPINFOHEADER bmiHeader;
+} VIDEOINFOHEADER;
+
+typedef struct _VIDEO_STREAM_CONFIG_CAPS {
+ GUID guid;
+ ULONG VideoStandard;
+ SIZE InputSize;
+ SIZE MinCroppingSize;
+ SIZE MaxCroppingSize;
+ int CropGranularityX;
+ int CropGranularityY;
+ int CropAlignX;
+ int CropAlignY;
+ SIZE MinOutputSize;
+ SIZE MaxOutputSize;
+ int OutputGranularityX;
+ int OutputGranularityY;
+ int StretchTapsX;
+ int StretchTapsY;
+ int ShrinkTapsX;
+ int ShrinkTapsY;
+ LONGLONG MinFrameInterval;
+ LONGLONG MaxFrameInterval;
+ LONG MinBitsPerSecond;
+ LONG MaxBitsPerSecond;
+} VIDEO_STREAM_CONFIG_CAPS;
+
+
+/* Interface & Class GUIDs */
+static const IID IID_IGrabCallback = {0x4C337035,0xC89E,0x4B42,{0x9B,0x0C,0x36,0x74,0x44,0xDD,0x70,0xDD}};
+
+EXTERN_C const IID IID_IBaseFilter;
+EXTERN_C const IID IID_ICreateDevEnum;
+EXTERN_C const IID IID_IGraphBuilder;
+EXTERN_C const IID IID_IMediaSeeking;
+EXTERN_C const IID IID_IMediaEventSink;
+EXTERN_C const IID IID_IMemInputPin;
+EXTERN_C const IID IID_IEnumPins;
+EXTERN_C const IID IID_IMediaFilter;
+EXTERN_C const IID IID_IEnumMediaTypes;
+EXTERN_C const IID IID_IMemAllocator;
+EXTERN_C const IID IID_IPin;
+EXTERN_C const IID IID_ICaptureGraphBuilder2;
+EXTERN_C const IID IID_IFileSinkFilter;
+EXTERN_C const IID IID_IAMCopyCaptureFileProgress;
+EXTERN_C const IID IID_IEnumFilters;
+EXTERN_C const IID IID_IMediaSample;
+EXTERN_C const IID IID_IMediaControl;
+EXTERN_C const IID IID_IAMStreamConfig;
+EXTERN_C const IID IID_IAMVideoProcAmp;
+
+EXTERN_C const IID CLSID_CaptureGraphBuilder2;
+EXTERN_C const IID CLSID_VideoInputDeviceCategory;
+EXTERN_C const IID CLSID_AudioRender;
+EXTERN_C const IID CLSID_SystemDeviceEnum;
+EXTERN_C const IID CLSID_AudioRendererCategory;
+EXTERN_C const IID CLSID_FilterGraph;
+EXTERN_C const IID CLSID_InfTee;
+EXTERN_C const IID CLSID_VideoMixingRenderer9;
+EXTERN_C const IID CLSID_MemoryAllocator;
+
+
+/* other types GUIDs*/
+EXTERN_C const IID MEDIATYPE_Audio;
+EXTERN_C const IID MEDIATYPE_Video;
+EXTERN_C const IID MEDIATYPE_Stream;
+EXTERN_C const IID MEDIASUBTYPE_PCM;
+EXTERN_C const IID MEDIASUBTYPE_WAVE;
+EXTERN_C const IID MEDIASUBTYPE_Avi;
+EXTERN_C const IID MEDIASUBTYPE_RGB32;
+EXTERN_C const IID MEDIASUBTYPE_YV12;
+EXTERN_C const IID MEDIASUBTYPE_YUY2;
+EXTERN_C const IID MEDIASUBTYPE_I420;
+EXTERN_C const IID MEDIASUBTYPE_YUYV;
+EXTERN_C const IID FORMAT_WaveFormatEx;
+EXTERN_C const IID FORMAT_VideoInfo;
+EXTERN_C const IID FORMAT_VideoInfo2;
+EXTERN_C const IID PIN_CATEGORY_CAPTURE;
+EXTERN_C const IID PIN_CATEGORY_PREVIEW;
+
+
+#define MEDIATYPE_NULL GUID_NULL
+#define MEDIASUBTYPE_NULL GUID_NULL
+
+#define INTERFACE IGrabCallback
+DECLARE_INTERFACE_(IGrabCallback, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(Grab)(THIS_ ULONG,BYTE*) PURE;
+};
+#undef INTERFACE
+
+#ifdef COBJMACROS
+#define IGrabCallback_QueryInterface(T,a,b) (T)->lpVtbl->QueryInterface(T,a,b)
+#define IGrabCallback_AddRef(T) (T)->lpVtbl->AddRef(T)
+#define IGrabCallback_Release(T) (T)->lpVtbl->Release(T)
+#define IGrabCallback_Grab(T,a,b) (T)->lpVtbl->Grab(T,a,b)
+#endif /* COBJMACROS */
+
+#define INTERFACE IAMCopyCaptureFileProgress
+DECLARE_INTERFACE_(IAMCopyCaptureFileProgress, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(Progress)(THIS_ int) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IReferenceClock
+DECLARE_INTERFACE_(IReferenceClock, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *) PURE;
+ STDMETHOD(AdviseTime)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HEVENT, DWORD_PTR *) PURE;
+ STDMETHOD(AdvisePeriodic)(THIS_ REFERENCE_TIME, REFERENCE_TIME, HSEMAPHORE, DWORD_PTR *) PURE;
+ STDMETHOD(Unadvise)(THIS_ DWORD_PTR) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IEnumFilters
+DECLARE_INTERFACE_(IEnumFilters, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(Next)(THIS_ ULONG, IBaseFilter **, ULONG *) PURE;
+ STDMETHOD(Skip)(THIS_ ULONG) PURE;
+ STDMETHOD(Reset)(THIS) PURE;
+ STDMETHOD(Clone)(THIS_ IEnumFilters **) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IEnumMediaTypes
+DECLARE_INTERFACE_(IEnumMediaTypes, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(Next)(THIS_ ULONG, AM_MEDIA_TYPE **, ULONG *) PURE;
+ STDMETHOD(Skip)(THIS_ ULONG) PURE;
+ STDMETHOD(Reset)(THIS) PURE;
+ STDMETHOD(Clone)(THIS_ IEnumMediaTypes **) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IPin
+DECLARE_INTERFACE_(IPin, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(Connect)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(ReceiveConnection)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(Disconnect)(THIS) PURE;
+ STDMETHOD(ConnectedTo)(THIS_ IPin **) PURE;
+ STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO *) PURE;
+ STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION *) PURE;
+ STDMETHOD(QueryId)(THIS_ LPWSTR *) PURE;
+ STDMETHOD(QueryAccept)(THIS_ const AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(EnumMediaTypes)(THIS_ IEnumMediaTypes **) PURE;
+ STDMETHOD(QueryInternalConnections)(THIS_ IPin **, ULONG *) PURE;
+ STDMETHOD(EndOfStream)(THIS) PURE;
+ STDMETHOD(BeginFlush)(THIS) PURE;
+ STDMETHOD(EndFlush)(THIS) PURE;
+ STDMETHOD(NewSegment)(THIS_ REFERENCE_TIME, REFERENCE_TIME, double) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IEnumPins
+DECLARE_INTERFACE_(IEnumPins, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(Next)(THIS_ ULONG, IPin **, ULONG *) PURE;
+ STDMETHOD(Skip)(THIS_ ULONG) PURE;
+ STDMETHOD(Reset)(THIS) PURE;
+ STDMETHOD(Clone)(THIS_ IEnumPins **) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IMediaFilter
+DECLARE_INTERFACE_(IMediaFilter, IPersist)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetClassID)(THIS_ CLSID*) PURE;
+ STDMETHOD(Stop)(THIS) PURE;
+ STDMETHOD(Pause)(THIS) PURE;
+ STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;
+ STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE;
+ STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE;
+ STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IBaseFilter
+DECLARE_INTERFACE2_(IBaseFilter, IMediaFilter)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetClassID)(THIS_ CLSID*) PURE;
+ STDMETHOD(Stop)(THIS) PURE;
+ STDMETHOD(Pause)(THIS) PURE;
+ STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;
+ STDMETHOD(GetState)(THIS_ DWORD, FILTER_STATE *) PURE;
+ STDMETHOD(SetSyncSource)(THIS_ IReferenceClock *) PURE;
+ STDMETHOD(GetSyncSource)(THIS_ IReferenceClock **) PURE;
+ STDMETHOD(EnumPins)(THIS_ IEnumPins **) PURE;
+ STDMETHOD(FindPin)(THIS_ LPCWSTR, IPin **) PURE;
+ STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO *) PURE;
+ STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph *, LPCWSTR) PURE;
+ STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR *) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IFilterGraph
+DECLARE_INTERFACE2_(IFilterGraph, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE;
+ STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE;
+ STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE;
+ STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE;
+ STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(Reconnect)(THIS_ IPin *) PURE;
+ STDMETHOD(Disconnect)(THIS_ IPin *) PURE;
+ STDMETHOD(SetDefaultSyncSource)(THIS) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IGraphBuilder
+DECLARE_INTERFACE_(IGraphBuilder ,IFilterGraph)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(AddFilter)(THIS_ IBaseFilter *, LPCWSTR) PURE;
+ STDMETHOD(RemoveFilter)(THIS_ IBaseFilter *) PURE;
+ STDMETHOD(EnumFilters)(THIS_ IEnumFilters **) PURE;
+ STDMETHOD(FindFilterByName)(THIS_ LPCWSTR, IBaseFilter **) PURE;
+ STDMETHOD(ConnectDirect)(THIS_ IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(Reconnect)(THIS_ IPin *) PURE;
+ STDMETHOD(Disconnect)(THIS_ IPin *) PURE;
+ STDMETHOD(SetDefaultSyncSource)(THIS) PURE;
+ STDMETHOD(Connect)(THIS_ IPin *, IPin *) PURE;
+ STDMETHOD(Render)(THIS_ IPin *) PURE;
+ STDMETHOD(RenderFile)(THIS_ LPCWSTR, LPCWSTR) PURE;
+ STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR, LPCWSTR, IBaseFilter **) PURE;
+ STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE;
+ STDMETHOD(Abort)(THIS) PURE;
+ STDMETHOD(ShouldOperationContinue)(THIS) PURE;
+};
+#undef INTERFACE
+#define INTERFACE ICreateDevEnum
+DECLARE_INTERFACE_(ICreateDevEnum, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(CreateClassEnumerator)(THIS_ REFCLSID, IEnumMoniker **, DWORD) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IMediaSample
+DECLARE_INTERFACE_(IMediaSample, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;
+ STDMETHOD_(long, GetSize)(THIS) PURE;
+ STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
+ STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
+ STDMETHOD(IsSyncPoint)(THIS) PURE;
+ STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE;
+ STDMETHOD(IsPreroll)(THIS) PURE;
+ STDMETHOD(SetPreroll)(THIS_ BOOL) PURE;
+ STDMETHOD_(long, GetActualDataLength)(THIS) PURE;
+ STDMETHOD(SetActualDataLength)(THIS_ long) PURE;
+ STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE;
+ STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(IsDiscontinuity)(THIS) PURE;
+ STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE;
+ STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
+ STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IMemAllocator
+DECLARE_INTERFACE_(IMemAllocator, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES *, ALLOCATOR_PROPERTIES *) PURE;
+ STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES *) PURE;
+ STDMETHOD(Commit)(THIS) PURE;
+ STDMETHOD(Decommit)(THIS) PURE;
+ STDMETHOD(GetBuffer)(THIS_ IMediaSample **, REFERENCE_TIME *, REFERENCE_TIME *, DWORD) PURE;
+ STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample *) PURE;
+
+};
+#undef INTERFACE
+#define INTERFACE IMemInputPin
+DECLARE_INTERFACE_(IMemInputPin, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetAllocator)(THIS_ IMemAllocator **) PURE;
+ STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator *, BOOL) PURE;
+ STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES *) PURE;
+ STDMETHOD(Receive)(THIS_ IMediaSample *) PURE;
+ STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample **, long, long *) PURE;
+ STDMETHOD(ReceiveCanBlock)(THIS) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IFileSinkFilter
+DECLARE_INTERFACE_(IFileSinkFilter, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(SetFileName)(THIS_ LPCOLESTR,const AM_MEDIA_TYPE *) PURE;
+ STDMETHOD(GetCurFile)(THIS_ LPOLESTR *,AM_MEDIA_TYPE*) PURE;
+};
+#undef INTERFACE
+#define INTERFACE ICaptureGraphBuilder2
+DECLARE_INTERFACE_(ICaptureGraphBuilder2, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(SetFiltergraph)(THIS_ IGraphBuilder*) PURE;
+ STDMETHOD(GetFiltergraph)(THIS_ IGraphBuilder**) PURE;
+ STDMETHOD(SetOutputFileName)(THIS_ const GUID*,LPCOLESTR,IBaseFilter**,IFileSinkFilter**) PURE;
+ STDMETHOD(FindInterface)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFIID,void**) PURE;
+ STDMETHOD(RenderStream)(THIS_ const GUID*,const GUID*,IUnknown*,IBaseFilter*,IBaseFilter*) PURE;
+ STDMETHOD(ControlStream)(THIS_ const GUID*,const GUID*,IBaseFilter*,REFERENCE_TIME*,REFERENCE_TIME*,WORD,WORD) PURE;
+ STDMETHOD(AllocCapFile)(THIS_ LPCOLESTR,DWORDLONG) PURE;
+ STDMETHOD(CopyCaptureFile)(THIS_ LPOLESTR,LPOLESTR,int,IAMCopyCaptureFileProgress*) PURE;
+ STDMETHOD(FindPin)(THIS_ IUnknown*,PIN_DIRECTION,const GUID*,const GUID*,BOOL,int,IPin**) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IAMStreamConfig
+DECLARE_INTERFACE_(IAMStreamConfig, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE;
+ STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE;
+ STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE;
+ STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IAMVideoProcAmp
+DECLARE_INTERFACE_(IAMVideoProcAmp, IUnknown)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetRange)(THIS_ long,long*,long*,long*,long*,long*) PURE;
+ STDMETHOD(Set)(THIS_ long,long,long) PURE;
+ STDMETHOD(Get)(THIS_ long,long*,long*) PURE;
+};
+#undef INTERFACE
+#define INTERFACE IMediaControl
+DECLARE_INTERFACE_(IMediaControl, IDispatch)
+{
+ STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID *) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+ STDMETHOD(GetTypeInfoCount)(THIS_ UINT*);
+ STDMETHOD(GetTypeInfo)(THIS_ UINT,LCID,ITypeInfo**);
+ STDMETHOD(GetIDsOfNames)(THIS_ REFIID,LPOLESTR*,UINT,LCID,DISPID*);
+ STDMETHOD(Invoke)(THIS_ DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
+ STDMETHOD(Run)(THIS);
+ STDMETHOD(Pause)(THIS);
+ STDMETHOD(Stop)(THIS);
+ STDMETHOD(GetState)(THIS_ LONG, OAFilterState*);
+ STDMETHOD(RenderFile)(THIS_ BSTR);
+ STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**);
+ STDMETHOD(get_FilterCollection)(THIS_ IDispatch**);
+ STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**);
+ STDMETHOD(StopWhenReady)(THIS);
+};
+#undef INTERFACE
+
+#ifdef COBJMACROS
+#define ICreateDevEnum_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define ICreateDevEnum_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define ICreateDevEnum_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define ICreateDevEnum_CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags) \
+ ((This)->lpVtbl->CreateClassEnumerator(This,clsidDeviceClass,ppEnumMoniker,dwFlags))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IPin_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IPin_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IPin_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IPin_Connect(This,pReceivePin,pmt) \
+ ((This)->lpVtbl->Connect(This,pReceivePin,pmt))
+#define IPin_ReceiveConnection(This,pConnector,pmt) \
+ ((This)->lpVtbl->ReceiveConnection(This,pConnector,pmt))
+#define IPin_Disconnect(This) \
+ ((This)->lpVtbl->Disconnect(This))
+#define IPin_ConnectedTo(This,pPin) \
+ ((This)->lpVtbl->ConnectedTo(This,pPin))
+#define IPin_ConnectionMediaType(This,pmt) \
+ ((This)->lpVtbl->ConnectionMediaType(This,pmt))
+#define IPin_QueryPinInfo(This,pInfo) \
+ ((This)->lpVtbl->QueryPinInfo(This,pInfo))
+#define IPin_QueryDirection(This,pPinDir) \
+ ((This)->lpVtbl->QueryDirection(This,pPinDir))
+#define IPin_QueryId(This,Id) \
+ ((This)->lpVtbl->QueryId(This,Id))
+#define IPin_QueryAccept(This,pmt) \
+ ((This)->lpVtbl->QueryAccept(This,pmt))
+#define IPin_EnumMediaTypes(This,ppEnum) \
+ ((This)->lpVtbl->EnumMediaTypes(This,ppEnum))
+#define IPin_QueryInternalConnections(This,apPin,nPin) \
+ ((This)->lpVtbl->QueryInternalConnections(This,apPin,nPin))
+#define IPin_EndOfStream(This) \
+ ((This)->lpVtbl->EndOfStream(This))
+#define IPin_BeginFlush(This) \
+ ((This)->lpVtbl->BeginFlush(This))
+#define IPin_EndFlush(This) \
+ ((This)->lpVtbl->EndFlush(This))
+#define IPin_NewSegment(This,tStart,tStop,dRate) \
+ ((This)->lpVtbl->NewSegment(This,tStart,tStop,dRate))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IEnumPins_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IEnumPins_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IEnumPins_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IEnumPins_Next(This,cPins,ppPins,pcFetched) \
+ ((This)->lpVtbl->Next(This,cPins,ppPins,pcFetched))
+#define IEnumPins_Skip(This,cPins) \
+ ((This)->lpVtbl->Skip(This,cPins))
+#define IEnumPins_Reset(This) \
+ ((This)->lpVtbl->Reset(This))
+#define IEnumPins_Clone(This,ppEnum) \
+ ((This)->lpVtbl->Clone(This,ppEnum))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IAMStreamConfig_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IAMStreamConfig_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IAMStreamConfig_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IAMStreamConfig_SetFormat(This,pmt) \
+ ((This)->lpVtbl->SetFormat(This,pmt))
+#define IAMStreamConfig_GetFormat(This,ppmt) \
+ ((This)->lpVtbl->GetFormat(This,ppmt))
+#define IAMStreamConfig_GetNumberOfCapabilities(This,piCount,piSize) \
+ ((This)->lpVtbl->GetNumberOfCapabilities(This,piCount,piSize))
+#define IAMStreamConfig_GetStreamCaps(This,iIndex,ppmt,pSCC) \
+ ((This)->lpVtbl->GetStreamCaps(This,iIndex,ppmt,pSCC))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IFilterGraph_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IFilterGraph_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IFilterGraph_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IFilterGraph_AddFilter(This,pFilter,pName) \
+ ((This)->lpVtbl->AddFilter(This,pFilter,pName))
+#define IFilterGraph_RemoveFilter(This,pFilter) \
+ ((This)->lpVtbl->RemoveFilter(This,pFilter))
+#define IFilterGraph_EnumFilters(This,ppEnum) \
+ ((This)->lpVtbl->EnumFilters(This,ppEnum))
+#define IFilterGraph_FindFilterByName(This,pName,ppFilter) \
+ ((This)->lpVtbl->FindFilterByName(This,pName,ppFilter))
+#define IFilterGraph_ConnectDirect(This,ppinOut,ppinIn,pmt) \
+ ((This)->lpVtbl->ConnectDirect(This,ppinOut,ppinIn,pmt))
+#define IFilterGraph_Reconnect(This,ppin) \
+ ((This)->lpVtbl->Reconnect(This,ppin))
+#define IFilterGraph_Disconnect(This,ppin) \
+ ((This)->lpVtbl->Disconnect(This,ppin))
+#define IFilterGraph_SetDefaultSyncSource(This) \
+ ((This)->lpVtbl->SetDefaultSyncSource(This))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IMediaFilter_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IMediaFilter_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IMediaFilter_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IMediaFilter_GetClassID(This,pClassID) \
+ ((This)->lpVtbl->GetClassID(This,pClassID))
+#define IMediaFilter_Stop(This) \
+ ((This)->lpVtbl->Stop(This))
+#define IMediaFilter_Pause(This) \
+ ((This)->lpVtbl->Pause(This))
+#define IMediaFilter_Run(This,tStart) \
+ ((This)->lpVtbl->Run(This,tStart))
+#define IMediaFilter_GetState(This,dwMilliSecsTimeout,State) \
+ ((This)->lpVtbl->GetState(This,dwMilliSecsTimeout,State))
+#define IMediaFilter_SetSyncSource(This,pClock) \
+ ((This)->lpVtbl->SetSyncSource(This,pClock))
+#define IMediaFilter_GetSyncSource(This,pClock) \
+ ((This)->lpVtbl->GetSyncSource(This,pClock))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IBaseFilter_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IBaseFilter_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IBaseFilter_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IBaseFilter_GetClassID(This,pClassID) \
+ ((This)->lpVtbl->GetClassID(This,pClassID))
+#define IBaseFilter_Stop(This) \
+ ((This)->lpVtbl->Stop(This))
+#define IBaseFilter_Pause(This) \
+ ((This)->lpVtbl->Pause(This))
+#define IBaseFilter_Run(This,tStart) \
+ ((This)->lpVtbl->Run(This,tStart))
+#define IBaseFilter_GetState(This,dwMilliSecsTimeout,State) \
+ ((This)->lpVtbl->GetState(This,dwMilliSecsTimeout,State))
+#define IBaseFilter_SetSyncSource(This,pClock) \
+ ((This)->lpVtbl->SetSyncSource(This,pClock))
+#define IBaseFilter_GetSyncSource(This,pClock) \
+ ((This)->lpVtbl->GetSyncSource(This,pClock))
+#define IBaseFilter_EnumPins(This,ppEnum) \
+ ((This)->lpVtbl->EnumPins(This,ppEnum))
+#define IBaseFilter_FindPin(This,Id,ppPin) \
+ ((This)->lpVtbl->FindPin(This,Id,ppPin))
+#define IBaseFilter_QueryFilterInfo(This,pInfo) \
+ ((This)->lpVtbl->QueryFilterInfo(This,pInfo))
+#define IBaseFilter_JoinFilterGraph(This,pGraph,pName) \
+ ((This)->lpVtbl->JoinFilterGraph(This,pGraph,pName))
+#define IBaseFilter_QueryVendorInfo(This,pVendorInfo) \
+ ((This)->lpVtbl->QueryVendorInfo(This,pVendorInfo))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IMediaSample_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IMediaSample_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IMediaSample_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IMediaSample_GetPointer(This,ppBuffer) \
+ ((This)->lpVtbl->GetPointer(This,ppBuffer))
+#define IMediaSample_GetSize(This) \
+ ((This)->lpVtbl->GetSize(This))
+#define IMediaSample_GetTime(This,pTimeStart,pTimeEnd) \
+ ((This)->lpVtbl->GetTime(This,pTimeStart,pTimeEnd))
+#define IMediaSample_SetTime(This,pTimeStart,pTimeEnd) \
+ ((This)->lpVtbl->SetTime(This,pTimeStart,pTimeEnd))
+#define IMediaSample_IsSyncPoint(This) \
+ ((This)->lpVtbl->IsSyncPoint(This))
+#define IMediaSample_SetSyncPoint(This,bIsSyncPoint) \
+ ((This)->lpVtbl->SetSyncPoint(This,bIsSyncPoint))
+#define IMediaSample_IsPreroll(This) \
+ ((This)->lpVtbl->IsPreroll(This))
+#define IMediaSample_SetPreroll(This,bIsPreroll) \
+ ((This)->lpVtbl->SetPreroll(This,bIsPreroll))
+#define IMediaSample_GetActualDataLength(This) \
+ ((This)->lpVtbl->GetActualDataLength(This))
+#define IMediaSample_SetActualDataLength(This,length) \
+ ((This)->lpVtbl->SetActualDataLength(This,length))
+#define IMediaSample_GetMediaType(This,ppMediaType) \
+ ((This)->lpVtbl->GetMediaType(This,ppMediaType))
+#define IMediaSample_SetMediaType(This,pMediaType) \
+ ((This)->lpVtbl->SetMediaType(This,pMediaType))
+#define IMediaSample_IsDiscontinuity(This) \
+ ((This)->lpVtbl->IsDiscontinuity(This))
+#define IMediaSample_SetDiscontinuity(This,bDiscontinuity) \
+ ((This)->lpVtbl->SetDiscontinuity(This,bDiscontinuity))
+#define IMediaSample_GetMediaTime(This,pTimeStart,pTimeEnd) \
+ ((This)->lpVtbl->GetMediaTime(This,pTimeStart,pTimeEnd))
+#define IMediaSample_SetMediaTime(This,pTimeStart,pTimeEnd) \
+ ((This)->lpVtbl->SetMediaTime(This,pTimeStart,pTimeEnd))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IEnumFilters_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IEnumFilters_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IEnumFilters_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IEnumFilters_Next(This,cFilters,ppFilter,pcFetched) \
+ ((This)->lpVtbl->Next(This,cFilters,ppFilter,pcFetched))
+#define IEnumFilters_Skip(This,cFilters) \
+ ((This)->lpVtbl->Skip(This,cFilters))
+#define IEnumFilters_Reset(This) \
+ ((This)->lpVtbl->Reset(This))
+#define IEnumFilters_Clone(This,ppEnum) \
+ ((This)->lpVtbl->Clone(This,ppEnum))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IMemAllocator_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IMemAllocator_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IMemAllocator_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IMemAllocator_SetProperties(This,pRequest,pActual) \
+ ((This)->lpVtbl->SetProperties(This,pRequest,pActual))
+#define IMemAllocator_GetProperties(This,pProps) \
+ ((This)->lpVtbl->GetProperties(This,pProps))
+#define IMemAllocator_Commit(This) \
+ ((This)->lpVtbl->Commit(This))
+#define IMemAllocator_Decommit(This) \
+ ((This)->lpVtbl->Decommit(This))
+#define IMemAllocator_GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags) \
+ ((This)->lpVtbl->GetBuffer(This,ppBuffer,pStartTime,pEndTime,dwFlags))
+#define IMemAllocator_ReleaseBuffer(This,pBuffer) \
+ ((This)->lpVtbl->ReleaseBuffer(This,pBuffer))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IMemInputPin_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IMemInputPin_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IMemInputPin_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IMemInputPin_GetAllocator(This,ppAllocator) \
+ ((This)->lpVtbl->GetAllocator(This,ppAllocator))
+#define IMemInputPin_NotifyAllocator(This,pAllocator,bReadOnly) \
+ ((This)->lpVtbl->NotifyAllocator(This,pAllocator,bReadOnly))
+#define IMemInputPin_GetAllocatorRequirements(This,pProps) \
+ ((This)->lpVtbl->GetAllocatorRequirements(This,pProps))
+#define IMemInputPin_Receive(This,pSample) \
+ ((This)->lpVtbl->Receive(This,pSample))
+#define IMemInputPin_ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed) \
+ ((This)->lpVtbl->ReceiveMultiple(This,pSamples,nSamples,nSamplesProcessed))
+#define IMemInputPin_ReceiveCanBlock(This) \
+ ((This)->lpVtbl->ReceiveCanBlock(This))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IGraphBuilder_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IGraphBuilder_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IGraphBuilder_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IGraphBuilder_AddFilter(This,pFilter,pName) \
+ ((This)->lpVtbl->AddFilter(This,pFilter,pName))
+#define IGraphBuilder_RemoveFilter(This,pFilter) \
+ ((This)->lpVtbl->RemoveFilter(This,pFilter))
+#define IGraphBuilder_EnumFilters(This,ppEnum) \
+ ((This)->lpVtbl->EnumFilters(This,ppEnum))
+#define IGraphBuilder_FindFilterByName(This,pName,ppFilter) \
+ ((This)->lpVtbl->FindFilterByName(This,pName,ppFilter))
+#define IGraphBuilder_ConnectDirect(This,ppinOut,ppinIn,pmt) \
+ ((This)->lpVtbl->ConnectDirect(This,ppinOut,ppinIn,pmt))
+#define IGraphBuilder_Reconnect(This,ppin) \
+ ((This)->lpVtbl->Reconnect(This,ppin))
+#define IGraphBuilder_Disconnect(This,ppin) \
+ ((This)->lpVtbl->Disconnect(This,ppin))
+#define IGraphBuilder_SetDefaultSyncSource(This) \
+ ((This)->lpVtbl->SetDefaultSyncSource(This))
+#define IGraphBuilder_Connect(This,ppinOut,ppinIn) \
+ ((This)->lpVtbl->Connect(This,ppinOut,ppinIn))
+#define IGraphBuilder_Render(This,ppinOut) \
+ ((This)->lpVtbl->Render(This,ppinOut))
+#define IGraphBuilder_RenderFile(This,lpcwstrFile,lpcwstrPlayList) \
+ ((This)->lpVtbl->RenderFile(This,lpcwstrFile,lpcwstrPlayList))
+#define IGraphBuilder_AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) \
+ ((This)->lpVtbl->AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter))
+#define IGraphBuilder_SetLogFile(This,hFile) \
+ ((This)->lpVtbl->SetLogFile(This,hFile))
+#define IGraphBuilder_Abort(This) \
+ ((This)->lpVtbl->Abort(This))
+#define IGraphBuilder_ShouldOperationContinue(This) \
+ ((This)->lpVtbl->ShouldOperationContinue(This))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IEnumMediaTypes_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IEnumMediaTypes_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IEnumMediaTypes_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IEnumMediaTypes_Next(This,cMediaTypes,ppMediaTypes,pcFetched) \
+ ((This)->lpVtbl->Next(This,cMediaTypes,ppMediaTypes,pcFetched))
+#define IEnumMediaTypes_Skip(This,cMediaTypes) \
+ ((This)->lpVtbl->Skip(This,cMediaTypes))
+#define IEnumMediaTypes_Reset(This) \
+ ((This)->lpVtbl->Reset(This))
+#define IEnumMediaTypes_Clone(This,ppEnum) \
+ ((This)->lpVtbl->Clone(This,ppEnum))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IMediaControl_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IMediaControl_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IMediaControl_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IMediaControl_GetTypeInfoCount(This,pctinfo) \
+ ((This)->lpVtbl->GetTypeInfoCount(This,pctinfo))
+#define IMediaControl_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
+ ((This)->lpVtbl->GetTypeInfo(This,iTInfo,lcid,ppTInfo))
+#define IMediaControl_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
+ ((This)->lpVtbl->GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId))
+#define IMediaControl_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
+ ((This)->lpVtbl->Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr))
+#define IMediaControl_Run(This) \
+ ((This)->lpVtbl->Run(This))
+#define IMediaControl_Pause(This) \
+ ((This)->lpVtbl->Pause(This))
+#define IMediaControl_Stop(This) \
+ ((This)->lpVtbl->Stop(This))
+#define IMediaControl_GetState(This,msTimeout,pfs) \
+ ((This)->lpVtbl->GetState(This,msTimeout,pfs))
+#define IMediaControl_RenderFile(This,strFilename) \
+ ((This)->lpVtbl->RenderFile(This,strFilename))
+#define IMediaControl_AddSourceFilter(This,strFilename,ppUnk) \
+ ((This)->lpVtbl->AddSourceFilter(This,strFilename,ppUnk))
+#define IMediaControl_get_FilterCollection(This,ppUnk) \
+ ((This)->lpVtbl->get_FilterCollection(This,ppUnk))
+#define IMediaControl_get_RegFilterCollection(This,ppUnk) \
+ ((This)->lpVtbl->get_RegFilterCollection(This,ppUnk))
+#define IMediaControl_StopWhenReady(This) \
+ ((This)->lpVtbl->StopWhenReady(This))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IAMVideoProcAmp_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IAMVideoProcAmp_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IAMVideoProcAmp_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IAMVideoProcAmp_GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags) \
+ ((This)->lpVtbl->GetRange(This,Property,pMin,pMax,pSteppingDelta,pDefault,pCapsFlags))
+#define IAMVideoProcAmp_Set(This,Property,lValue,Flags) \
+ ((This)->lpVtbl->Set(This,Property,lValue,Flags))
+#define IAMVideoProcAmp_Get(This,Property,lValue,Flags) \
+ ((This)->lpVtbl->Get(This,Property,lValue,Flags))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IFileSinkFilter_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IFileSinkFilter_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IFileSinkFilter_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IFileSinkFilter_SetFileName(This,pszFileName,pmt) \
+ ((This)->lpVtbl->SetFileName(This,pszFileName,pmt))
+#define IFileSinkFilter_GetCurFile(This,ppszFileName,pmt) \
+ ((This)->lpVtbl->GetCurFile(This,ppszFileName,pmt))
+#endif /* COBJMACROS */
+
+#ifdef COBJMACROS
+#define IAMCopyCaptureFileProgress_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define IAMCopyCaptureFileProgress_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define IAMCopyCaptureFileProgress_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define IAMCopyCaptureFileProgress_Progress(This,iProgress) \
+ ((This)->lpVtbl->Progress(This,iProgress))
+#endif /* COBJMACROS */
+
+
+#ifdef COBJMACROS
+#define ICaptureGraphBuilder2_QueryInterface(This,riid,ppvObject) \
+ ((This)->lpVtbl->QueryInterface(This,riid,ppvObject))
+#define ICaptureGraphBuilder2_AddRef(This) \
+ ((This)->lpVtbl->AddRef(This))
+#define ICaptureGraphBuilder2_Release(This) \
+ ((This)->lpVtbl->Release(This))
+#define ICaptureGraphBuilder2_SetFiltergraph(This,pfg) \
+ ((This)->lpVtbl->SetFiltergraph(This,pfg))
+#define ICaptureGraphBuilder2_GetFiltergraph(This,ppfg) \
+ ((This)->lpVtbl->GetFiltergraph(This,ppfg))
+#define ICaptureGraphBuilder2_SetOutputFileName(This,pType,lpstrFile,ppf,ppSink) \
+ ((This)->lpVtbl->SetOutputFileName(This,pType,lpstrFile,ppf,ppSink))
+#define ICaptureGraphBuilder2_FindInterface(This,pCategory,pType,pf,riid,ppint) \
+ ((This)->lpVtbl->FindInterface(This,pCategory,pType,pf,riid,ppint))
+#define ICaptureGraphBuilder2_RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer) \
+ ((This)->lpVtbl->RenderStream(This,pCategory,pType,pSource,pfCompressor,pfRenderer))
+#define ICaptureGraphBuilder2_ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie) \
+ ((This)->lpVtbl->ControlStream(This,pCategory,pType,pFilter,pstart,pstop,wStartCookie,wStopCookie))
+#define ICaptureGraphBuilder2_AllocCapFile(This,lpstr,dwlSize) \
+ ((This)->lpVtbl->AllocCapFile(This,lpstr,dwlSize))
+#define ICaptureGraphBuilder2_CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback) \
+ ((This)->lpVtbl->CopyCaptureFile(This,lpwstrOld,lpwstrNew,fAllowEscAbort,pCallback))
+#define ICaptureGraphBuilder2_FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin) \
+ ((This)->lpVtbl->FindPin(This,pSource,pindir,pCategory,pType,fUnconnected,num,ppPin))
+#endif /* COBJMACROS */
+
+#endif /* _MARU_CAMERA_INTERFACE_H_ */
--- /dev/null
+/*
+ * Implementation of MARU Virtual Camera device by PCI bus on Windows.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "qemu-common.h"
+#include "maru_camera_common.h"
+#include "debug_ch.h"
+
+#define CINTERFACE
+#define COBJMACROS
+#include "ocidl.h"
+#include "errors.h" /* for VFW_E_XXXX */
+#include "mmsystem.h" /* for MAKEFOURCC macro */
+#include "maru_camera_win32_interface.h"
+
+MULTI_DEBUG_CHANNEL(tizen, maru-camera);
+
+/*
+ * COM Interface implementations
+ *
+ */
+
+#define SAFE_RELEASE(x) \
+ do { \
+ if (x) { \
+ (x)->lpVtbl->Release(x); \
+ x = NULL; \
+ } \
+ } while (0)
+
+typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
+
+/*
+ * HWCGrabCallback
+ */
+
+typedef struct HWCGrabCallback {
+ IGrabCallback IGrabCallback_iface;
+ long m_cRef;
+ CallbackFn m_pCallback;
+ STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);
+} HWCGrabCallback;
+
+static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)
+{
+ return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);
+}
+
+static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,
+ REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, &IID_IUnknown)) {
+ *ppv = (IUnknown *)iface;
+ } else if (IsEqualIID(riid, &IID_IGrabCallback)) {
+ *ppv = (IGrabCallback *)iface;
+ } else {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IGrabCallback_AddRef(iface);
+ return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)
+{
+ HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+ return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)
+{
+ HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+ if (InterlockedDecrement(&This->m_cRef) == 0) {
+ This->m_pCallback = NULL;
+ g_free((void *)This);
+ This = NULL;
+ return 0;
+ }
+
+ return This->m_cRef;
+}
+
+static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,
+ ULONG dwSize, BYTE *pBuffer)
+{
+ HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+ if (This->m_pCallback) {
+ HRESULT hr = This->m_pCallback(dwSize, pBuffer);
+ if (FAILED(hr)) {
+ return E_FAIL;
+ } else {
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,
+ CallbackFn pCallbackFn)
+{
+ HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+ This->m_pCallback = pCallbackFn;
+ return S_OK;
+}
+
+static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {
+ HWCGrabCallback_QueryInterface,
+ HWCGrabCallback_AddRef,
+ HWCGrabCallback_Release,
+ HWCGrabCallback_Grab
+};
+
+static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)
+{
+ HWCGrabCallback *This =
+ (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));
+
+ if (!This) {
+ ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");
+ return E_OUTOFMEMORY;
+ }
+
+ This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;
+ This->m_cRef = 1;
+ This->m_pCallback = NULL;
+ This->SetCallback = HWCGrabCallback_SetCallback;
+ *ppv = &This->IGrabCallback_iface;
+ return S_OK;
+}
+
+/*
+ * HWCPin
+ */
+
+typedef struct HWCInPin {
+ IPin IPin_iface;
+ IMemInputPin IMemInputPin_iface;
+ IBaseFilter *m_pCFilter;
+ IPin *m_pConnectedPin;
+ IGrabCallback *m_pCallback;
+ IMemAllocator *m_pAllocator;
+ BOOL m_bReadOnly;
+ long m_cRef;
+ STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);
+} HWCInPin;
+
+static inline HWCInPin *impl_from_IPin(IPin *iface)
+{
+ return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);
+}
+
+static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)
+{
+ return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);
+}
+
+static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (IsEqualIID(riid, &IID_IUnknown)) {
+ *ppv = (IUnknown *)(&This->IPin_iface);
+ IPin_AddRef((IPin *)*ppv);
+ } else if (IsEqualIID(riid, &IID_IPin)) {
+ *ppv = (IPin *)(&This->IPin_iface);
+ IPin_AddRef((IPin *)*ppv);
+ } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
+ *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
+ IPin_AddRef((IMemInputPin *)*ppv);
+ } else {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (InterlockedDecrement(&This->m_cRef) == 0) {
+ if (This->m_pCallback) {
+ SAFE_RELEASE(This->m_pCallback);
+ }
+ if (This->m_pConnectedPin) {
+ SAFE_RELEASE(This->m_pConnectedPin);
+ }
+ if (This->m_pAllocator) {
+ IMemAllocator_Decommit(This->m_pAllocator);
+ SAFE_RELEASE(This->m_pAllocator);
+ }
+ g_free((void *)This);
+ This = NULL;
+ return 0;
+ }
+ return This->m_cRef;
+}
+
+static STDMETHODIMP HWCPin_Connect(IPin *iface,
+ IPin *pReceivePin,
+ const AM_MEDIA_TYPE *pmt)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (!pReceivePin) {
+ return E_POINTER;
+ }
+
+ if (This->m_pConnectedPin) {
+ return VFW_E_ALREADY_CONNECTED;
+ }
+
+ if (!pmt) {
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,
+ const AM_MEDIA_TYPE *pmt)
+{
+ PIN_DIRECTION pd;
+ FILTER_STATE fs;
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (pConnector == NULL || pmt == NULL) {
+ return E_POINTER;
+ }
+
+ if (This->m_pConnectedPin) {
+ return VFW_E_ALREADY_CONNECTED;
+ }
+ IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
+ if (fs != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ }
+ IPin_QueryDirection(pConnector, &pd);
+ if (pd == PINDIR_INPUT) {
+ return VFW_E_INVALID_DIRECTION;
+ }
+
+ This->m_pConnectedPin = pConnector;
+ IPin_AddRef(This->m_pConnectedPin);
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_Disconnect(IPin *iface)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ HRESULT hr;
+ FILTER_STATE fs;
+ IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
+ if (fs != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ }
+ if (This->m_pConnectedPin == NULL) {
+ hr = S_FALSE;
+ } else {
+ if (This->m_pAllocator) {
+ hr = IMemAllocator_Decommit(This->m_pAllocator);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ SAFE_RELEASE(This->m_pAllocator);
+ }
+ SAFE_RELEASE(This->m_pConnectedPin);
+ hr = S_OK;
+ }
+ return hr;
+}
+
+static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (ppPin == NULL) {
+ return E_POINTER;
+ }
+
+ if (This->m_pConnectedPin == NULL) {
+ *ppPin = NULL;
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ *ppPin = This->m_pConnectedPin;
+ IPin_AddRef(This->m_pConnectedPin);
+ }
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
+{
+ if (pmt == NULL) {
+ return E_POINTER;
+ }
+ return VFW_E_NOT_CONNECTED;
+}
+
+static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (pInfo == NULL) {
+ return E_POINTER;
+ }
+
+ pInfo->pFilter = This->m_pCFilter;
+ if (This->m_pCFilter) {
+ IBaseFilter_AddRef(This->m_pCFilter);
+ }
+ memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));
+ pInfo->dir = PINDIR_INPUT;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
+{
+ if (pPinDir == NULL) {
+ return E_POINTER;
+ }
+ *pPinDir = PINDIR_INPUT;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)
+{
+ PVOID pId;
+ if (Id == NULL) {
+ return E_POINTER;
+ }
+ pId = CoTaskMemAlloc(sizeof(HWCPinName));
+ memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));
+ *Id = (LPWSTR)pId;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
+{
+ if (pmt == NULL) {
+ return E_POINTER;
+ }
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,
+ IEnumMediaTypes **ppEnum)
+{
+ if (ppEnum == NULL) {
+ return E_POINTER;
+ }
+ return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,
+ IPin **ppPin,
+ ULONG *nPin)
+{
+ return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_EndFlush(IPin *iface)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,
+ REFERENCE_TIME tStop, double dRate)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,
+ REFIID riid, void **ppv)
+{
+ HWCInPin *This = impl_from_IMemInputPin(iface);
+
+ if (IsEqualIID(riid, &IID_IUnknown)) {
+ *ppv = (IUnknown *)(&This->IMemInputPin_iface);
+ IPin_AddRef((IPin *)*ppv);
+ } else if (IsEqualIID(riid, &IID_IPin)) {
+ *ppv = (IPin *)(&This->IPin_iface);
+ IPin_AddRef((IPin *)*ppv);
+ } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
+ *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
+ IPin_AddRef((IMemInputPin *)*ppv);
+ } else {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)
+{
+ HWCInPin *This = impl_from_IMemInputPin(iface);
+
+ return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)
+{
+ HWCInPin *This = impl_from_IMemInputPin(iface);
+
+ if (InterlockedDecrement(&This->m_cRef) == 0) {
+ if (This->m_pCallback) {
+ SAFE_RELEASE(This->m_pCallback);
+ }
+ if (This->m_pConnectedPin) {
+ SAFE_RELEASE(This->m_pConnectedPin);
+ }
+ if (This->m_pAllocator) {
+ IMemAllocator_Decommit(This->m_pAllocator);
+ SAFE_RELEASE(This->m_pAllocator);
+ }
+ g_free((void *)This);
+ This = NULL;
+ return 0;
+ }
+ return This->m_cRef;
+}
+
+static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,
+ IMemAllocator **ppAllocator)
+{
+ HWCInPin *This = impl_from_IMemInputPin(iface);
+
+ if (ppAllocator == NULL) {
+ return E_POINTER;
+ }
+
+ if (This->m_pAllocator == NULL) {
+ HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
+ CLSCTX_INPROC_SERVER,
+ &IID_IMemAllocator,
+ (void **)&(This->m_pAllocator));
+ if (FAILED(hr)) {
+ ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");
+ return hr;
+ }
+ }
+ ASSERT(This->m_pAllocator != NULL);
+ *ppAllocator = This->m_pAllocator;
+ IMemAllocator_AddRef(This->m_pAllocator);
+
+ return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,
+ IMemAllocator *pAllocator,
+ BOOL bReadOnly)
+{
+ HWCInPin *This = impl_from_IMemInputPin(iface);
+
+ if (pAllocator == NULL) {
+ return E_POINTER;
+ }
+
+ IMemAllocator *pOldAllocator = This->m_pAllocator;
+ IMemAllocator_AddRef(pAllocator);
+ This->m_pAllocator = pAllocator;
+
+ if (pOldAllocator != NULL) {
+ SAFE_RELEASE(pOldAllocator);
+ }
+
+ This->m_bReadOnly = bReadOnly;
+
+ return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(
+ IMemInputPin *iface,
+ ALLOCATOR_PROPERTIES *pProps)
+{
+ return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,
+ IMediaSample *pSample)
+{
+ HWCInPin *This = impl_from_IMemInputPin(iface);
+
+ if (pSample == NULL) {
+ ERR("pSample is NULL\n");
+ return E_POINTER;
+ }
+ if (This->m_pCallback != NULL) {
+ HRESULT hr;
+ BYTE *pBuffer = NULL;
+ DWORD dwSize = 0;
+ dwSize = IMediaSample_GetSize(pSample);
+ hr = IMediaSample_GetPointer(pSample, &pBuffer);
+ if (FAILED(hr)) {
+ ERR("Receive function : "
+ "failed to IMediaSample_GetPointer, 0x%ld\n", hr);
+ return hr;
+ }
+ hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);
+ if (FAILED(hr)) {
+ ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",
+ hr);
+ return hr;
+ }
+ }
+ return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,
+ IMediaSample **pSamples,
+ long nSamples,
+ long *nSamplesProcessed)
+{
+ HRESULT hr = S_OK;
+
+ if (pSamples == NULL) {
+ return E_POINTER;
+ }
+
+ *nSamplesProcessed = 0;
+
+ while (nSamples-- > 0) {
+ hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
+ if (hr != S_OK) {
+ break;
+ }
+ (*nSamplesProcessed)++;
+ }
+ return hr;
+}
+
+static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
+{
+ return S_FALSE;
+}
+
+static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)
+{
+ HWCInPin *This = impl_from_IPin(iface);
+
+ if (pCaptureCB == NULL) {
+ SAFE_RELEASE(This->m_pCallback);
+ } else {
+ This->m_pCallback = pCaptureCB;
+ IGrabCallback_AddRef(This->m_pCallback);
+ }
+
+ return S_OK;
+}
+
+
+static IPinVtbl HWCPin_Vtbl = {
+ HWCPin_QueryInterface,
+ HWCPin_AddRef,
+ HWCPin_Release,
+ HWCPin_Connect,
+ HWCPin_ReceiveConnection,
+ HWCPin_Disconnect,
+ HWCPin_ConnectedTo,
+ HWCPin_ConnectionMediaType,
+ HWCPin_QueryPinInfo,
+ HWCPin_QueryDirection,
+ HWCPin_QueryId,
+ HWCPin_QueryAccept,
+ HWCPin_EnumMediaTypes,
+ HWCPin_QueryInternalConnections,
+ HWCPin_EndOfStream,
+ HWCPin_BeginFlush,
+ HWCPin_EndFlush,
+ HWCPin_NewSegment
+};
+
+static IMemInputPinVtbl HWCMemInputPin_Vtbl = {
+ HWCMemInputPin_QueryInterface,
+ HWCMemInputPin_AddRef,
+ HWCMemInputPin_Release,
+ HWCMemInputPin_GetAllocator,
+ HWCMemInputPin_NotifyAllocator,
+ HWCMemInputPin_GetAllocatorRequirements,
+ HWCMemInputPin_Receive,
+ HWCMemInputPin_ReceiveMultiple,
+ HWCMemInputPin_ReceiveCanBlock
+};
+
+static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)
+{
+ HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));
+
+ if (!This) {
+ ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");
+ return E_OUTOFMEMORY;
+ }
+
+ This->IPin_iface.lpVtbl = &HWCPin_Vtbl;
+ This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;
+ This->m_bReadOnly = FALSE;
+ This->m_pCFilter = pFilter;
+ This->m_pConnectedPin = NULL;
+ This->m_pCallback = NULL;
+ This->m_pAllocator = NULL;
+ This->m_cRef = 1;
+ This->SetGrabCallbackIF = HWCPin_SetCallback;
+ *ppv = &This->IPin_iface;
+
+ return S_OK;
+}
+
+/*
+ * HWCEnumPins
+ */
+
+typedef struct HWCEnumPins {
+ IEnumPins IEnumPins_iface;
+ IBaseFilter *m_pFilter;
+ int m_nPos;
+ long m_cRef;
+} HWCEnumPins;
+
+static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)
+{
+ return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);
+}
+
+static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,
+ REFIID riid, void **ppv)
+{
+ if (ppv == NULL) {
+ return E_POINTER;
+ }
+
+ if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {
+ *ppv = iface;
+ } else {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IEnumPins_AddRef(iface);
+ return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)
+{
+ HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+ return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)
+{
+ HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+ if (InterlockedDecrement(&This->m_cRef) == 0) {
+ if (This->m_pFilter) {
+ SAFE_RELEASE(This->m_pFilter);
+ }
+ This->m_nPos = 0;
+ g_free((void *)This);
+ This = NULL;
+ return 0;
+ }
+ return This->m_cRef;
+}
+
+static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,
+ IPin **ppPins, ULONG *pcFetched)
+{
+ ULONG fetched;
+ HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+ if (ppPins == NULL) {
+ return E_POINTER;
+ }
+
+ if (This->m_nPos < 1 && cPins > 0) {
+ IPin *pPin;
+ IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);
+ *ppPins = pPin;
+ fetched = 1;
+ This->m_nPos++;
+ } else {
+ fetched = 0;
+ }
+
+ if (pcFetched != NULL) {
+ *pcFetched = fetched;
+ }
+
+ return (fetched == cPins) ? S_OK : S_FALSE;
+}
+
+static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)
+{
+ HWCEnumPins *This = impl_from_IEnumPins(iface);
+ This->m_nPos += cPins;
+ return (This->m_nPos >= 1) ? S_FALSE : S_OK;
+}
+
+static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)
+{
+ HWCEnumPins *This = impl_from_IEnumPins(iface);
+ This->m_nPos = 0;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
+ int nPos, IEnumPins **ppv);
+
+static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)
+{
+ HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+ if (ppEnum == NULL) {
+ return E_POINTER;
+ }
+
+ HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);
+ if (*ppEnum == NULL) {
+ ERR("failed to HWCEnumPins_Construct in clone, E_OUTOFMEMORY\n");
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+static IEnumPinsVtbl HWCEnumPins_Vtbl = {
+ HWCEnumPins_QueryInterface,
+ HWCEnumPins_AddRef,
+ HWCEnumPins_Release,
+ HWCEnumPins_Next,
+ HWCEnumPins_Skip,
+ HWCEnumPins_Reset,
+ HWCEnumPins_Clone
+};
+
+
+static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
+ int nPos, IEnumPins **ppv)
+{
+ HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));
+
+ if (!This) {
+ ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");
+ return E_OUTOFMEMORY;
+ }
+
+ This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;
+ This->m_pFilter = pFilter;
+ if (This->m_pFilter) {
+ IBaseFilter_AddRef(This->m_pFilter);
+ }
+ This->m_cRef = 1;
+ This->m_nPos = nPos;
+ *ppv = &This->IEnumPins_iface;
+
+ return S_OK;
+}
+
+/*
+ * HWCFilter
+ */
+
+typedef struct HWCFilter {
+ IBaseFilter IBaseFilter_iface;
+ IPin *m_pPin;
+ IFilterGraph *m_pFilterGraph;
+ FILTER_STATE m_state;
+ long m_cRef;
+} HWCFilter;
+
+static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)
+{
+ return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);
+}
+
+static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,
+ REFIID riid, void **ppv)
+{
+ if (IsEqualIID(riid, &IID_IUnknown)) {
+ *ppv = (IUnknown *)iface;
+ } else if (IsEqualIID(riid, &IID_IPersist)) {
+ *ppv = (IPersist *)iface;
+ } else if (IsEqualIID(riid, &IID_IMediaFilter)) {
+ *ppv = (IMediaFilter *)iface;
+ } else if (IsEqualIID(riid, &IID_IBaseFilter)) {
+ *ppv = (IBaseFilter *)iface;
+ } else {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IBaseFilter_AddRef(iface);
+ return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ if (InterlockedDecrement(&This->m_cRef) == 0) {
+ if (This->m_pPin) {
+ SAFE_RELEASE(This->m_pPin);
+ }
+ g_free((void *)This);
+ This = NULL;
+ return 0;
+ }
+ return This->m_cRef;
+}
+
+static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)
+{
+ if (pClsID == NULL) {
+ return E_POINTER;
+ }
+ return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,
+ FILTER_STATE *State)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+ *State = This->m_state;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,
+ IReferenceClock *pClock)
+{
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,
+ IReferenceClock **pClock)
+{
+ *pClock = NULL;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ IPin_EndFlush(This->m_pPin);
+ This->m_state = State_Stopped;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+ This->m_state = State_Paused;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ if (This->m_state == State_Stopped) {
+ HRESULT hr;
+ hr = IBaseFilter_Pause(iface);
+ if (FAILED(hr)) {
+ ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);
+ return hr;
+ }
+ }
+
+ This->m_state = State_Running;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
+{
+ if (ppEnum == NULL) {
+ return E_POINTER;
+ }
+
+ HWCEnumPins_Construct(iface, 0, ppEnum);
+ return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;
+}
+
+static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,
+ IPin **ppPin)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ if (ppPin == NULL) {
+ return E_POINTER;
+ }
+
+ if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {
+ return VFW_E_NOT_FOUND;
+ }
+
+ if (!This->m_pPin) {
+ HWCInPin_Construct(iface, &This->m_pPin);
+ }
+ *ppPin = This->m_pPin;
+
+ IPin_AddRef(This->m_pPin);
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,
+ FILTER_INFO *pInfo)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ if (pInfo == NULL) {
+ return E_POINTER;
+ }
+
+ memcpy((void *)pInfo->achName,
+ (void *)HWCFilterName,
+ sizeof(HWCFilterName));
+ pInfo->pGraph = This->m_pFilterGraph;
+ if (This->m_pFilterGraph) {
+ IFilterGraph_AddRef(This->m_pFilterGraph);
+ }
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,
+ IFilterGraph *pGraph,
+ LPCWSTR pName)
+{
+ HWCFilter *This = impl_from_IBaseFilter(iface);
+
+ This->m_pFilterGraph = pGraph;
+ return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,
+ LPWSTR *pVendorInfo)
+{
+ return E_NOTIMPL;
+}
+
+static IBaseFilterVtbl HWCFilter_Vtbl = {
+ HWCFilter_QueryInterface,
+ HWCFilter_AddRef,
+ HWCFilter_Release,
+ HWCFilter_GetClassID,
+ HWCFilter_Stop,
+ HWCFilter_Pause,
+ HWCFilter_Run,
+ HWCFilter_GetState,
+ HWCFilter_SetSyncSource,
+ HWCFilter_GetSyncSource,
+ HWCFilter_EnumPins,
+ HWCFilter_FindPin,
+ HWCFilter_QueryFilterInfo,
+ HWCFilter_JoinFilterGraph,
+ HWCFilter_QueryVendorInfo
+};
+
+static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)
+{
+ HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));
+
+ if (!This) {
+ ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");
+ return E_OUTOFMEMORY;
+ }
+
+ This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;
+ This->m_pFilterGraph = NULL;
+ This->m_state = State_Stopped;
+ This->m_cRef = 1;
+ HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);
+ *ppv = &This->IBaseFilter_iface;
+
+ return S_OK;
+}
+
+/**********************************************************
+ *
+ * Virtual device implementations
+ *
+ **********************************************************/
+
+
+/*
+ * Declaration global variables for Win32 COM Interfaces
+ */
+IGraphBuilder *g_pGB ;
+ICaptureGraphBuilder2 *g_pCGB;
+IMediaControl *g_pMediaControl;
+
+IPin *g_pOutputPin;
+IPin *g_pInputPin;
+IBaseFilter *g_pDstFilter;
+IBaseFilter *g_pSrcFilter;
+
+IGrabCallback *g_pCallback;
+
+/* V4L2 defines copy from videodev2.h */
+#define V4L2_CTRL_FLAG_SLIDER 0x0020
+
+#define V4L2_CTRL_CLASS_USER 0x00980000
+#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
+#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
+
+#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
+#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
+#define V4L2_PIX_FMT_RGB24 MAKEFOURCC('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
+
+typedef struct tagMaruCamConvertPixfmt {
+ uint32_t fmt; /* fourcc */
+ uint32_t bpp; /* bits per pixel, 0 for compressed formats */
+ uint32_t needs_conversion;
+} MaruCamConvertPixfmt;
+
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
+ { V4L2_PIX_FMT_YUYV, 16, 0 },
+ { V4L2_PIX_FMT_YUV420, 12, 0 },
+ { V4L2_PIX_FMT_YVU420, 12, 0 },
+};
+
+typedef struct tagMaruCamConvertFrameInfo {
+ uint32_t width;
+ uint32_t height;
+} MaruCamConvertFrameInfo;
+
+static MaruCamConvertFrameInfo supported_dst_frames[] = {
+ { 640, 480 },
+ { 352, 288 },
+ { 320, 240 },
+ { 176, 144 },
+ { 160, 120 },
+};
+
+#define MARUCAM_CTRL_VALUE_MAX 20
+#define MARUCAM_CTRL_VALUE_MIN 1
+#define MARUCAM_CTRL_VALUE_MID 10
+#define MARUCAM_CTRL_VALUE_STEP 1
+
+struct marucam_qctrl {
+ uint32_t id;
+ uint32_t hit;
+ long min;
+ long max;
+ long step;
+ long init_val;
+};
+
+static struct marucam_qctrl qctrl_tbl[] = {
+ { V4L2_CID_BRIGHTNESS, 0, },
+ { V4L2_CID_CONTRAST, 0, },
+ { V4L2_CID_SATURATION, 0, },
+ { V4L2_CID_SHARPNESS, 0, },
+};
+
+static MaruCamState *g_state;
+
+static uint32_t ready_count;
+static uint32_t cur_fmt_idx;
+static uint32_t cur_frame_idx;
+static void *grab_buf;
+static uint32_t g_dwSrcFmt;
+
+
+/*
+ * Helper functions - converting image formats, converting values
+ */
+
+static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
+{
+ uint32_t bytesperline;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ bytesperline = (width * 12) >> 3;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ default:
+ bytesperline = width * 2;
+ break;
+ }
+
+ return bytesperline;
+}
+
+static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
+{
+ return get_bytesperline(pixfmt, width) * height;
+}
+
+void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height, uint32_t yvu);
+void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height, uint32_t yvu);
+void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height);
+void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height);
+void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height);
+
+static long value_convert_from_guest(long min, long max, long value)
+{
+ double rate = 0.0;
+ long dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = min + (int32_t)(value / rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = min + (int32_t)(rate * value);
+ }
+ return ret;
+}
+
+static long value_convert_to_guest(long min, long max, long value)
+{
+ double rate = 0.0;
+ long dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = (int32_t)((double)(value - min) * rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = (int32_t)((double)(value - min) / rate);
+ }
+
+ return ret;
+}
+
+/*
+ * Callback function for grab frames
+ */
+static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
+{
+ void *tmp_buf;
+ uint32_t width, height, fmt, imgsize;
+
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+ fmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ imgsize = get_sizeimage(fmt, width, height);
+
+ if (imgsize > (uint32_t)dwSize) {
+ ERR("Image size is mismatched\n");
+ return E_FAIL;
+ }
+
+ switch (g_dwSrcFmt) {
+ case V4L2_PIX_FMT_YUYV:
+ switch (fmt) {
+ case V4L2_PIX_FMT_YUV420:
+ yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
+ break;
+ default:
+ ERR("Invalid pixel format\n");
+ return E_FAIL;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ switch (fmt) {
+ case V4L2_PIX_FMT_YUV420:
+ rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ rgb24_to_yuyv(pBuffer, grab_buf, width, height);
+ break;
+ default:
+ ERR("Invalid pixel format\n");
+ return E_FAIL;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ switch (fmt) {
+ case V4L2_PIX_FMT_YUV420:
+ memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ yuv420_to_yvu420(pBuffer, grab_buf, width, height);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ yuv420_to_yuyv(pBuffer, grab_buf, width, height);
+ break;
+ default:
+ ERR("Invalid pixel format\n");
+ return E_FAIL;
+ }
+ break;
+ default:
+ ERR("Invalid pixel format\n");
+ return E_FAIL;
+ }
+
+ qemu_mutex_lock(&g_state->thread_mutex);
+ if (g_state->streamon) {
+ if (ready_count < MARUCAM_SKIPFRAMES) {
+ /* skip a frame cause first some frame are distorted */
+ ++ready_count;
+ TRACE("skip %d frame\n", ready_count);
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return S_OK;
+ }
+ if (g_state->req_frame == 0) {
+ TRACE("there is no request\n");
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return S_OK;
+ }
+ tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
+ memcpy(tmp_buf, grab_buf, g_state->buf_size);
+ g_state->req_frame = 0; /* clear request */
+ g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
+ qemu_bh_schedule(g_state->tx_bh);
+ }
+ qemu_mutex_unlock(&g_state->thread_mutex);
+ return S_OK;
+}
+
+/*
+ * Internal functions for manipulate interfaces
+ */
+
+static STDMETHODIMP_(void) CloseInterfaces(void)
+{
+ if (g_pMediaControl) {
+ g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
+ }
+
+ if (g_pOutputPin) {
+ g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);
+ }
+
+ SAFE_RELEASE(g_pGB);
+ SAFE_RELEASE(g_pCGB);
+ SAFE_RELEASE(g_pMediaControl);
+ SAFE_RELEASE(g_pOutputPin);
+ SAFE_RELEASE(g_pInputPin);
+ SAFE_RELEASE(g_pDstFilter);
+ SAFE_RELEASE(g_pSrcFilter);
+ SAFE_RELEASE(g_pCallback);
+}
+
+static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)
+{
+ if (pmt == NULL) {
+ return;
+ }
+
+ if (pmt->cbFormat != 0) {
+ CoTaskMemFree((PVOID)pmt->pbFormat);
+ pmt->cbFormat = 0;
+ pmt->pbFormat = NULL;
+ }
+ if (pmt->pUnk != NULL) {
+ pmt->pUnk->lpVtbl->Release(pmt->pUnk);
+ pmt->pUnk = NULL;
+ }
+
+ CoTaskMemFree((PVOID)pmt);
+}
+
+static STDMETHODIMP GetPin(IBaseFilter *pFilter,
+ PIN_DIRECTION PinDir, IPin **ppPin)
+{
+ HRESULT hr;
+ IEnumPins *pEnum = NULL;
+ IPin *pPin = NULL;
+
+ if (ppPin == NULL) {
+ return E_POINTER;
+ }
+
+ hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {
+ PIN_DIRECTION PinDirThis;
+ hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);
+ if (FAILED(hr)) {
+ SAFE_RELEASE(pPin);
+ SAFE_RELEASE(pEnum);
+ return hr;
+ }
+ if (PinDir == PinDirThis) {
+ *ppPin = pPin;
+ SAFE_RELEASE(pEnum);
+ return S_OK;
+ }
+ SAFE_RELEASE(pPin);
+ }
+
+ SAFE_RELEASE(pEnum);
+ return S_FALSE;
+}
+
+static STDMETHODIMP GraphBuilder_Init(void)
+{
+ HRESULT hr;
+
+ hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
+ &IID_IGraphBuilder, (void **)&g_pGB);
+ if (FAILED(hr)) {
+ ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
+ &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);
+ if (FAILED(hr)) {
+ ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);
+ if (FAILED(hr)) {
+ ERR("Failed to SetFiltergraph, 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,
+ (void **)&g_pMediaControl);
+ if (FAILED(hr)) {
+ ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = HWCGrabCallback_Construct(&g_pCallback);
+ if (g_pCallback == NULL) {
+ hr = E_OUTOFMEMORY;
+ }
+
+ hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,
+ (CallbackFn)marucam_device_callbackfn);
+
+ return hr;
+}
+
+static STDMETHODIMP BindSourceFilter(void)
+{
+ HRESULT hr;
+ ICreateDevEnum *pCreateDevEnum = NULL;
+ IEnumMoniker *pEnumMK = NULL;
+ IMoniker *pMoniKer;
+
+ hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
+ &IID_ICreateDevEnum,
+ (void **)&pCreateDevEnum);
+ if (FAILED(hr)) {
+ ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
+ &CLSID_VideoInputDeviceCategory,
+ &pEnumMK, 0);
+ if (FAILED(hr)) {
+ ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);
+ SAFE_RELEASE(pCreateDevEnum);
+ return hr;
+ }
+
+ if (!pEnumMK) {
+ ERR("ClassEnumerator moniker is NULL\n");
+ SAFE_RELEASE(pCreateDevEnum);
+ return E_FAIL;
+ }
+ pEnumMK->lpVtbl->Reset(pEnumMK);
+
+ hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
+ if (hr == S_FALSE) {
+ hr = E_FAIL;
+ }
+ if (SUCCEEDED(hr)) {
+ IPropertyBag *pBag = NULL;
+ hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
+ &IID_IPropertyBag,
+ (void **)&pBag);
+ if (SUCCEEDED(hr)) {
+ VARIANT var;
+ var.vt = VT_BSTR;
+ hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
+ if (hr == NOERROR) {
+ hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
+ &IID_IBaseFilter,
+ (void **)&g_pSrcFilter);
+ if (FAILED(hr)) {
+ ERR("Counldn't bind moniker to filter object!!\n");
+ } else {
+ g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);
+ }
+ SysFreeString(var.bstrVal);
+ }
+ SAFE_RELEASE(pBag);
+ }
+ SAFE_RELEASE(pMoniKer);
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");
+ if (hr != S_OK && hr != S_FALSE) {
+ ERR("Counldn't add Video Capture filter to our graph!\n");
+ SAFE_RELEASE(g_pSrcFilter);
+ }
+ }
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+
+ return hr;
+}
+
+static STDMETHODIMP BindTargetFilter(void)
+{
+ HRESULT hr;
+ hr = HWCFilter_Construct(&g_pDstFilter);
+
+ if (SUCCEEDED(hr) && g_pDstFilter) {
+ hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");
+ if (FAILED(hr)) {
+ ERR("Counldn't add HWCFilterr to our graph!\n");
+ SAFE_RELEASE(g_pDstFilter);
+ }
+ }
+ return hr;
+}
+
+static STDMETHODIMP ConnectFilters(void)
+{
+ HRESULT hr;
+
+ hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);
+ if (FAILED(hr)) {
+ ERR("Failed to get output pin. 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);
+ if (FAILED(hr)) {
+ ERR("Failed to get input pin. 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);
+ if (FAILED(hr)) {
+ ERR("Failed to connect pins. 0x%x\n", hr);
+ }
+ return hr;
+}
+
+static STDMETHODIMP DisconnectPins(void)
+{
+ HRESULT hr;
+
+ hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);
+ if (FAILED(hr)) {
+ ERR("Failed to disconnect output pin. 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);
+ if (FAILED(hr)) {
+ ERR("Failed to disconnect input pin. 0x%x\n", hr);
+ }
+
+ return hr;
+}
+
+static STDMETHODIMP RemoveFilters(void)
+{
+ HRESULT hr;
+
+ hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);
+ if (FAILED(hr)) {
+ ERR("Failed to remove source filer. 0x%x\n", hr);
+ return hr;
+ }
+
+ hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);
+ if (FAILED(hr)) {
+ ERR("Failed to remove destination filer. 0x%x\n", hr);
+ }
+
+ return hr;
+}
+
+/* default fps is 15 */
+#define MARUCAM_DEFAULT_FRAMEINTERVAL 666666
+
+static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,
+ uint32_t dwDstFmt, uint32_t *dwSrcFmt)
+{
+ HRESULT hr;
+ IAMStreamConfig *pSConfig;
+ int iCount = 0, iSize = 0;
+ DWORD dwYUY2 = MAKEFOURCC('Y', 'U', 'Y', '2');
+ DWORD dwI420 = MAKEFOURCC('I', '4', '2', '0');
+
+ if (dwSrcFmt == NULL) {
+ ERR("invalid the source format pointer\n");
+ return E_FAIL;
+ }
+
+ hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,
+ g_pSrcFilter, &IID_IAMStreamConfig,
+ (void **)&pSConfig);
+ if (FAILED(hr)) {
+ ERR("failed to FindInterface method\n");
+ return hr;
+ }
+
+ hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
+ if (FAILED(hr)) {
+ ERR("failed to GetNumberOfCapabilities method\n");
+ SAFE_RELEASE(pSConfig);
+ return hr;
+ }
+
+ if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
+ int iFormat = 0;
+ for (iFormat = 0; iFormat < iCount; iFormat++) {
+ VIDEO_STREAM_CONFIG_CAPS scc;
+ AM_MEDIA_TYPE *pmtConfig;
+
+ hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,
+ &pmtConfig, (BYTE *)&scc);
+ if (hr == S_OK) {
+ if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *pvi =
+ (VIDEOINFOHEADER *)pmtConfig->pbFormat;
+ if ((pvi->bmiHeader.biWidth == (LONG)dwWidth) &&
+ (pvi->bmiHeader.biHeight == (LONG)dwHeight)) {
+ if (pvi->bmiHeader.biCompression == dwYUY2) {
+ *dwSrcFmt = V4L2_PIX_FMT_YUYV;
+ } else if ((pvi->bmiHeader.biCompression == BI_RGB) &&
+ (pvi->bmiHeader.biBitCount == 24)) {
+ *dwSrcFmt = V4L2_PIX_FMT_RGB24;
+ } else if (pvi->bmiHeader.biCompression == dwI420) {
+ *dwSrcFmt = V4L2_PIX_FMT_YUV420;
+ } else { /* not support format */
+ DeleteMediaType(pmtConfig);
+ continue;
+ }
+ /* use minimum FPS(maximum frameinterval)
+ with non-VT system */
+#ifdef CONFIG_HAX
+ if (!hax_enabled()) {
+ pvi->AvgTimePerFrame =
+ (REFERENCE_TIME)scc.MaxFrameInterval;
+ } else {
+ pvi->AvgTimePerFrame =
+ (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;
+ }
+#else
+ pvi->AvgTimePerFrame =
+ (REFERENCE_TIME)scc.MaxFrameInterval;
+#endif
+ hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);
+ DeleteMediaType(pmtConfig);
+ break;
+ }
+ }
+ DeleteMediaType(pmtConfig);
+ }
+ }
+ if (iFormat >= iCount) {
+ ERR("Failed to Set format. "
+ "Maybe connected webcam does not support the (%ldx%ld) "
+ "resolution or image formats(YUY2, RGB24, I420).\n",
+ dwWidth, dwHeight);
+ hr = E_FAIL;
+ }
+ }
+ SAFE_RELEASE(pSConfig);
+ return hr;
+}
+
+static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,
+ long *pStep, long *pDefault)
+{
+ HRESULT hr;
+ long Flags;
+ IAMVideoProcAmp *pProcAmp = NULL;
+
+ hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
+ &IID_IAMVideoProcAmp,
+ (void **)&pProcAmp);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,
+ pStep, pDefault, &Flags);
+
+ SAFE_RELEASE(pProcAmp);
+ return hr;
+}
+
+static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)
+{
+ HRESULT hr;
+ long Flags;
+ IAMVideoProcAmp *pProcAmp = NULL;
+
+ hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
+ &IID_IAMVideoProcAmp,
+ (void **)&pProcAmp);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);
+ if (FAILED(hr)) {
+ ERR("Failed to get property for video\n");
+ }
+
+ SAFE_RELEASE(pProcAmp);
+ return hr;
+}
+
+static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)
+{
+ HRESULT hr;
+
+ IAMVideoProcAmp *pProcAmp = NULL;
+ hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
+ &IID_IAMVideoProcAmp,
+ (void **)&pProcAmp);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,
+ VideoProcAmp_Flags_Manual);
+ if (FAILED(hr)) {
+ ERR("Failed to set property for video\n");
+ }
+ SAFE_RELEASE(pProcAmp);
+ return hr;
+}
+
+static char *__wchar_to_char(const WCHAR *pwstr)
+{
+ char *pstr = NULL;
+ int len = 0;
+
+ len = wcslen(pwstr) + 1;
+ pstr = (char *)g_malloc0(sizeof(char) * len);
+ wcstombs(pstr, pwstr, len + 1);
+
+ return pstr;
+}
+
+int marucam_device_check(int log_flag)
+{
+ struct timeval t1, t2;
+ int ret = 0;
+ char *device_name = NULL;
+ HRESULT hr = E_FAIL;
+ ICreateDevEnum *pCreateDevEnum = NULL;
+ IGraphBuilder *pGB = NULL;
+ ICaptureGraphBuilder2 *pCGB = NULL;
+ IBaseFilter *pSrcFilter = NULL;
+ IEnumMoniker *pEnumMK = NULL;
+ IMoniker *pMoniKer = NULL;
+ IAMStreamConfig *pSConfig = NULL;
+ int iCount = 0, iSize = 0;
+
+ gettimeofday(&t1, NULL);
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ if (FAILED(hr)) {
+ ERR("Failed to CoInitailizeEx\n");
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
+ CLSCTX_INPROC,
+ &IID_IGraphBuilder,
+ (void **)&pGB);
+ if (FAILED(hr)) {
+ ERR("Failed to create GraphBuilder, 0x%x\n", hr);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
+ CLSCTX_INPROC,
+ &IID_ICaptureGraphBuilder2,
+ (void **)&pCGB);
+ if (FAILED(hr)) {
+ ERR("Failed to create CaptureGraphBuilder2, 0x%x\n", hr);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);
+ if (FAILED(hr)) {
+ ERR("Failed to SetFiltergraph, 0x%x\n", hr);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
+ CLSCTX_INPROC,
+ &IID_ICreateDevEnum,
+ (void **)&pCreateDevEnum);
+ if (FAILED(hr)) {
+ ERR("Failed to create instance of CLSID_SystemDeviceEnum\n");
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
+ &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);
+ if (FAILED(hr)) {
+ ERR("Failed to create class enumerator\n");
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ if (!pEnumMK) {
+ ERR("Class enumerator is NULL!!\n");
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+ pEnumMK->lpVtbl->Reset(pEnumMK);
+
+ hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
+ if (FAILED(hr) || (hr == S_FALSE)) {
+ ERR("Enum moniker returns a invalid value.\n");
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ IPropertyBag *pBag = NULL;
+ hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
+ &IID_IPropertyBag,
+ (void **)&pBag);
+ if (FAILED(hr)) {
+ ERR("Failed to bind to storage.\n");
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ } else {
+ VARIANT var;
+ var.vt = VT_BSTR;
+ hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
+ if (hr == S_OK) {
+ ret = 1;
+ if (!log_flag) {
+ SysFreeString(var.bstrVal);
+ SAFE_RELEASE(pBag);
+ SAFE_RELEASE(pMoniKer);
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+ device_name = __wchar_to_char(var.bstrVal);
+ INFO("Device name : %s\n", device_name);
+ g_free(device_name);
+ hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
+ &IID_IBaseFilter,
+ (void **)&pSrcFilter);
+ if (FAILED(hr)) {
+ ERR("Counldn't bind moniker to filter object!!\n");
+ SysFreeString(var.bstrVal);
+ SAFE_RELEASE(pBag);
+ SAFE_RELEASE(pMoniKer);
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ } else {
+ pSrcFilter->lpVtbl->AddRef(pSrcFilter);
+ }
+ SysFreeString(var.bstrVal);
+ }
+ SAFE_RELEASE(pBag);
+ }
+ SAFE_RELEASE(pMoniKer);
+
+ hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");
+ if (hr != S_OK && hr != S_FALSE) {
+ ERR("Counldn't add Video Capture filter to our graph!\n");
+ SAFE_RELEASE(pSrcFilter);
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,
+ pSrcFilter, &IID_IAMStreamConfig,
+ (void **)&pSConfig);
+ if (FAILED(hr)) {
+ ERR("Failed to FindInterface method\n");
+ SAFE_RELEASE(pSrcFilter);
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
+ if (FAILED(hr)) {
+ ERR("Failed to GetNumberOfCapabilities method\n");
+ SAFE_RELEASE(pSConfig);
+ SAFE_RELEASE(pSrcFilter);
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+ return ret;
+ }
+
+ if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
+ int iFormat = 0;
+ for (iFormat = 0; iFormat < iCount; iFormat++) {
+ VIDEO_STREAM_CONFIG_CAPS scc;
+ AM_MEDIA_TYPE *pmtConfig;
+
+ hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,
+ (BYTE *)&scc);
+ if (hr == S_OK) {
+ if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *pvi =
+ (VIDEOINFOHEADER *)pmtConfig->pbFormat;
+ if (pvi->bmiHeader.biCompression == BI_RGB) {
+ INFO("RGB BitCount: %d, Frame size: %ux%u\n",
+ pvi->bmiHeader.biBitCount,
+ pvi->bmiHeader.biWidth,
+ pvi->bmiHeader.biHeight);
+ } else {
+ INFO("PixelFormat: %c%c%c%c, Frame size: %ux%u\n",
+ (char)(pvi->bmiHeader.biCompression),
+ (char)(pvi->bmiHeader.biCompression >> 8),
+ (char)(pvi->bmiHeader.biCompression >> 16),
+ (char)(pvi->bmiHeader.biCompression >> 24),
+ pvi->bmiHeader.biWidth,
+ pvi->bmiHeader.biHeight);
+ }
+ }
+ DeleteMediaType(pmtConfig);
+ }
+ }
+ }
+
+ hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);
+ if (FAILED(hr)) {
+ ERR("Failed to remove source filer. 0x%x\n", hr);
+ }
+
+ SAFE_RELEASE(pSConfig);
+ SAFE_RELEASE(pSrcFilter);
+ SAFE_RELEASE(pCGB);
+ SAFE_RELEASE(pGB);
+ SAFE_RELEASE(pEnumMK);
+ SAFE_RELEASE(pCreateDevEnum);
+ CoUninitialize();
+ gettimeofday(&t2, NULL);
+ ERR("Elapsed time : %lu.%06lu\n",
+ t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+
+ return ret;
+}
+
+/* MARUCAM_CMD_INIT */
+void marucam_device_init(MaruCamState *state)
+{
+ g_state = state;
+}
+
+void marucam_device_exit(MaruCamState *state)
+{
+}
+
+/* MARUCAM_CMD_OPEN */
+void marucam_device_open(MaruCamState *state)
+{
+ HRESULT hr;
+ uint32_t dwHeight, dwWidth, dwDstFmt;
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ if (FAILED(hr)) {
+ ERR("CoInitailizeEx\n");
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ hr = GraphBuilder_Init();
+ if (FAILED(hr)) {
+ ERR("GraphBuilder_Init\n");
+ DisconnectPins();
+ RemoveFilters();
+ CloseInterfaces();
+ CoUninitialize();
+ param->errCode = EINVAL;
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+
+ hr = BindSourceFilter();
+ if (FAILED(hr)) {
+ ERR("BindSourceFilter\n");
+ DisconnectPins();
+ RemoveFilters();
+ CloseInterfaces();
+ CoUninitialize();
+ param->errCode = EINVAL;
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+
+ hr = BindTargetFilter();
+ if (FAILED(hr)) {
+ ERR("BindTargetFilter\n");
+ DisconnectPins();
+ RemoveFilters();
+ CloseInterfaces();
+ CoUninitialize();
+ param->errCode = EINVAL;
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+
+ hr = ConnectFilters();
+ if (FAILED(hr)) {
+ ERR("ConnectFilters\n");
+ DisconnectPins();
+ RemoveFilters();
+ CloseInterfaces();
+ CoUninitialize();
+ param->errCode = EINVAL;
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+
+ cur_frame_idx = 0;
+ cur_fmt_idx = 0;
+
+ dwHeight = supported_dst_frames[cur_frame_idx].height;
+ dwWidth = supported_dst_frames[cur_frame_idx].width;
+ dwDstFmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ hr = SetFormat(dwWidth, dwHeight, dwDstFmt, &g_dwSrcFmt);
+ if (hr != S_OK) {
+ ERR("failed to Set default values\n");
+ DisconnectPins();
+ RemoveFilters();
+ CloseInterfaces();
+ CoUninitialize();
+ param->errCode = EINVAL;
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+
+ INFO("Opened\n");
+ return;
+}
+
+/* MARUCAM_CMD_CLOSE */
+void marucam_device_close(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+ int ret = 0;
+ param->top = 0;
+
+ qemu_mutex_lock(&state->thread_mutex);
+ ret = state->streamon;
+ qemu_mutex_unlock(&state->thread_mutex);
+ if (ret) {
+ marucam_device_stop_preview(state);
+ }
+
+ if (g_pGB) {
+ DisconnectPins();
+ RemoveFilters();
+ }
+ CloseInterfaces();
+ CoUninitialize();
+ INFO("Closed\n");
+}
+
+/* MARUCAM_CMD_START_PREVIEW */
+void marucam_device_start_preview(MaruCamState *state)
+{
+ HRESULT hr;
+ uint32_t pixfmt, width, height;
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ ready_count = 0;
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+ pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ state->buf_size = get_sizeimage(pixfmt, width, height);
+
+ INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n",
+ (char)(pixfmt), (char)(pixfmt >> 8),
+ (char)(pixfmt >> 16), (char)(pixfmt >> 24),
+ width, height, state->buf_size);
+ INFO("Starting preview\n");
+
+ assert(g_pCallback != NULL);
+ hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,
+ g_pCallback);
+ if (FAILED(hr)) {
+ ERR("Failed to set IGrabCallback interface.\n");
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if (grab_buf) {
+ g_free(grab_buf);
+ grab_buf = NULL;
+ }
+ grab_buf = (void *)g_malloc0(state->buf_size);
+ if (grab_buf == NULL) {
+ param->errCode = ENOMEM;
+ return;
+ }
+
+ hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);
+ if (FAILED(hr)) {
+ ERR("Failed to run media control. hr=0x%x\n", hr);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ qemu_mutex_lock(&state->thread_mutex);
+ state->streamon = 1;
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ INFO("Streaming on ......\n");
+}
+
+/* MARUCAM_CMD_STOP_PREVIEW */
+void marucam_device_stop_preview(MaruCamState *state)
+{
+ HRESULT hr;
+ MaruCamParam *param = state->param;
+ param->top = 0;
+
+ INFO("...... Streaming off\n");
+ qemu_mutex_lock(&state->thread_mutex);
+ state->streamon = 0;
+ qemu_mutex_unlock(&state->thread_mutex);
+
+ hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);
+ if (FAILED(hr)) {
+ ERR("Failed to set IGrabCallback interface.\n");
+ param->errCode = EINVAL;
+ return;
+ }
+
+ hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
+ if (FAILED(hr)) {
+ ERR("Failed to stop media control.\n");
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if (grab_buf) {
+ g_free(grab_buf);
+ grab_buf = NULL;
+ }
+ state->buf_size = 0;
+
+ INFO("Stopping preview\n");
+}
+
+/* MARUCAM_CMD_S_PARAM */
+void marucam_device_s_param(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ /* We use default FPS of the webcam */
+ param->top = 0;
+}
+
+/* MARUCAM_CMD_G_PARAM */
+void marucam_device_g_param(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ /* We use default FPS of the webcam
+ * return a fixed value on guest ini file (1/30).
+ */
+ param->top = 0;
+ param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
+ param->stack[1] = 1; /* numerator */
+ param->stack[2] = 30; /* denominator */
+}
+
+/* MARUCAM_CMD_S_FMT */
+void marucam_device_s_fmt(MaruCamState *state)
+{
+ uint32_t width, height, pixfmt, pidx, fidx;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ width = param->stack[0];
+ height = param->stack[1];
+ pixfmt = param->stack[2];
+
+ for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
+ if ((supported_dst_frames[fidx].width == width) &&
+ (supported_dst_frames[fidx].height == height)) {
+ break;
+ }
+ }
+ if (fidx == ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
+ if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
+ break;
+ }
+ }
+ if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if ((supported_dst_frames[cur_frame_idx].width != width) &&
+ (supported_dst_frames[cur_frame_idx].height != height)) {
+ HRESULT hr = SetFormat(width, height, pixfmt, &g_dwSrcFmt);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ }
+
+ cur_frame_idx = fidx;
+ cur_fmt_idx = pidx;
+
+ pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; /* V4L2_FIELD_NONE */
+ param->stack[3] = pixfmt;
+ param->stack[4] = get_bytesperline(pixfmt, width);
+ param->stack[5] = get_sizeimage(pixfmt, width, height);
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+
+ TRACE("Set format...\n");
+}
+
+/* MARUCAM_CMD_G_FMT */
+void marucam_device_g_fmt(MaruCamState *state)
+{
+ uint32_t width, height, pixfmt;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; /* V4L2_FIELD_NONE */
+ param->stack[3] = pixfmt;
+ param->stack[4] = get_bytesperline(pixfmt, width);
+ param->stack[5] = get_sizeimage(pixfmt, width, height);
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+
+ TRACE("Get format...\n");
+}
+
+void marucam_device_try_fmt(MaruCamState *state)
+{
+ uint32_t width, height, pixfmt, i;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ width = param->stack[0];
+ height = param->stack[1];
+ pixfmt = param->stack[2];
+
+ for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
+ if ((supported_dst_frames[i].width == width) &&
+ (supported_dst_frames[i].height == height)) {
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+ if (supported_dst_pixfmts[i].fmt == pixfmt) {
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; /* V4L2_FIELD_NONE */
+ param->stack[3] = pixfmt;
+ param->stack[4] = get_bytesperline(pixfmt, width);
+ param->stack[5] = get_sizeimage(pixfmt, width, height);
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+}
+
+void marucam_device_enum_fmt(MaruCamState *state)
+{
+ uint32_t index;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ index = param->stack[0];
+
+ if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[1] = 0; /* flags = NONE */
+ param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
+ /* set description */
+ switch (supported_dst_pixfmts[index].fmt) {
+ case V4L2_PIX_FMT_YUYV:
+ memcpy(¶m->stack[3], "YUYV", 32);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ memcpy(¶m->stack[3], "YU12", 32);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ memcpy(¶m->stack[3], "YV12", 32);
+ break;
+ default:
+ ERR("Invalid pixel format\n");
+ param->errCode = EINVAL;
+ break;
+ }
+}
+
+void marucam_device_qctrl(MaruCamState *state)
+{
+ HRESULT hr;
+ uint32_t id, i;
+ long property, min, max, step, def_val, set_val;
+ char name[32] = {0,};
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ id = param->stack[0];
+
+ switch (id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("V4L2_CID_BRIGHTNESS\n");
+ property = VideoProcAmp_Brightness;
+ memcpy((void *)name, (void *)"brightness", 32);
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("V4L2_CID_CONTRAST\n");
+ property = VideoProcAmp_Contrast;
+ memcpy((void *)name, (void *)"contrast", 32);
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("V4L2_CID_SATURATION\n");
+ property = VideoProcAmp_Saturation;
+ memcpy((void *)name, (void *)"saturation", 32);
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("V4L2_CID_SHARPNESS\n");
+ property = VideoProcAmp_Sharpness;
+ memcpy((void *)name, (void *)"sharpness", 32);
+ i = 3;
+ break;
+ default:
+ ERR("Invalid control ID\n");
+ param->errCode = EINVAL;
+ return;
+ }
+ hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
+ return;
+ } else {
+ qctrl_tbl[i].hit = 1;
+ qctrl_tbl[i].min = min;
+ qctrl_tbl[i].max = max;
+ qctrl_tbl[i].step = step;
+ qctrl_tbl[i].init_val = def_val;
+
+ if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
+ set_val = 0;
+ } else {
+ set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
+ }
+ hr = SetVideoProcAmp(property, set_val);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+ }
+
+ param->stack[0] = id;
+ param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
+ param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
+ param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
+ param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
+ param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
+ /* name field setting */
+ memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
+}
+
+void marucam_device_s_ctrl(MaruCamState *state)
+{
+ HRESULT hr;
+ uint32_t i;
+ long property, set_val;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+
+ switch (param->stack[0]) {
+ case V4L2_CID_BRIGHTNESS:
+ i = 0;
+ property = VideoProcAmp_Brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ i = 1;
+ property = VideoProcAmp_Contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ i = 2;
+ property = VideoProcAmp_Saturation;
+ break;
+ case V4L2_CID_SHARPNESS:
+ i = 3;
+ property = VideoProcAmp_Sharpness;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ set_val = value_convert_from_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, (long)param->stack[1]);
+ hr = SetVideoProcAmp(property, set_val);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+}
+
+void marucam_device_g_ctrl(MaruCamState *state)
+{
+ HRESULT hr;
+ uint32_t i;
+ long property, get_val;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ switch (param->stack[0]) {
+ case V4L2_CID_BRIGHTNESS:
+ i = 0;
+ property = VideoProcAmp_Brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ i = 1;
+ property = VideoProcAmp_Contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ i = 2;
+ property = VideoProcAmp_Saturation;
+ break;
+ case V4L2_CID_SHARPNESS:
+ i = 3;
+ property = VideoProcAmp_Sharpness;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+
+ hr = GetVideoProcAmp(property, &get_val);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+ param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, get_val);
+}
+
+void marucam_device_enum_fsizes(MaruCamState *state)
+{
+ uint32_t index, pixfmt, i;
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+ index = param->stack[0];
+ pixfmt = param->stack[1];
+
+ if (index >= ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+ if (supported_dst_pixfmts[i].fmt == pixfmt) {
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = supported_dst_frames[index].width;
+ param->stack[1] = supported_dst_frames[index].height;
+}
+
+void marucam_device_enum_fintv(MaruCamState *state)
+{
+ MaruCamParam *param = state->param;
+
+ param->top = 0;
+
+ /* switch by index(param->stack[0]) */
+ switch (param->stack[0]) {
+ case 0:
+ param->stack[1] = 30; /* denominator */
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[0] = 1; /* numerator */
+}
+
+void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height, uint32_t yvu)
+{
+ uint32_t i, j;
+ const unsigned char *src1;
+ unsigned char *udest, *vdest;
+
+ /* copy the Y values */
+ src1 = src;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = src1[0];
+ *dest++ = src1[2];
+ src1 += 4;
+ }
+ }
+
+ /* copy the U and V values */
+ src++; /* point to V */
+ src1 = src + width * 2; /* next line */
+ if (yvu) {
+ vdest = dest;
+ udest = dest + width * height / 4;
+ } else {
+ udest = dest;
+ vdest = dest + width * height / 4;
+ }
+ for (i = 0; i < height; i += 2) {
+ for (j = 0; j < width; j += 2) {
+ *udest++ = ((int) src[0] + src1[0]) / 2; /* U */
+ *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
+ src += 4;
+ src1 += 4;
+ }
+ src = src1;
+ src1 += width * 2;
+ }
+}
+
+#define RGB2Y(r, g, b, y) \
+ (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
+
+#define RGB2UV(r, g, b, u, v) \
+ do { \
+ (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15); \
+ (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15); \
+ } while (0)
+
+#define CLIP(color) \
+ (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
+
+void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height, uint32_t yvu)
+{
+ uint32_t x, y;
+ uint32_t halfWidth;
+ uint8_t *yplane, *uplane, *vplane;
+ uint8_t *yline, *uline, *vline;
+ const uint8_t *rgbIndex;
+
+ halfWidth = width >> 1;
+ yplane = dest;
+
+ if (yvu) {
+ vplane = dest + width * height;
+ uplane = vplane + ((width * height) >> 2);
+ } else {
+ uplane = dest + width * height;
+ vplane = uplane + ((width * height) >> 2);
+ }
+
+ for (y = 0; y < height; y++) {
+ yline = yplane + (y * width);
+ uline = uplane + ((y >> 1) * halfWidth);
+ vline = vplane + ((y >> 1) * halfWidth);
+
+ rgbIndex = src + (width * (height - 1 - y) * 3);
+ for (x = 0; x < (int)width; x+=2) {
+ RGB2Y(rgbIndex[2], rgbIndex[1], rgbIndex[0], *yline++);
+ rgbIndex += 3;
+ RGB2Y(rgbIndex[2], rgbIndex[1], rgbIndex[0], *yline++);
+ RGB2UV(rgbIndex[2], rgbIndex[1], rgbIndex[0], *uline++, *vline++);
+ rgbIndex += 3;
+ }
+ }
+}
+
+void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height)
+{
+ uint32_t i, j;
+ uint8_t *ptr;
+
+ for (i = 0; i < height; i++) {
+ ptr = src + (width * (height - 1 - i) * 3);
+ for (j = 0; j < width; j += 2) {
+ /* y */
+ *dest++ = CLIP(0.299 * (ptr[2] - 128) +
+ 0.587 * (ptr[1] - 128) +
+ 0.114 * (ptr[0] - 128) + 128);
+ /* u */
+ *dest++ = CLIP(((-0.147 * (ptr[2] - 128) -
+ 0.289 * (ptr[1] - 128) +
+ 0.436 * (ptr[0] - 128) + 128) +
+ (-0.147 * (ptr[5] - 128) -
+ 0.289 * (ptr[4] - 128) +
+ 0.436 * (ptr[3] - 128) + 128)) / 2);
+ /* y1 */
+ *dest++ = CLIP(0.299 * (ptr[5] - 128) +
+ 0.587 * (ptr[4] - 128) +
+ 0.114 * (ptr[3] - 128) + 128);
+ /* v */
+ *dest++ = CLIP(((0.615 * (ptr[2] - 128) -
+ 0.515 * (ptr[1] - 128) -
+ 0.100 * (ptr[0] - 128) + 128) +
+ (0.615 * (ptr[5] - 128) -
+ 0.515 * (ptr[4] - 128) -
+ 0.100 * (ptr[3] - 128) + 128)) / 2);
+ ptr += 6;
+ }
+ }
+}
+
+void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height)
+{
+ unsigned char *psrc_y, *pdst_y;
+ unsigned char *psrc_u, *pdst_u;
+ unsigned char *psrc_v, *pdst_v;
+
+ psrc_y = src;
+ psrc_u = psrc_y + (width * height);
+ psrc_v = psrc_u + (width * height / 4);
+
+ pdst_y = dest;
+ pdst_v = pdst_y + (width * height);
+ pdst_u = pdst_v + (width * height / 4);
+
+ memcpy(pdst_y, psrc_y, width * height);
+ memcpy(pdst_v, psrc_v, width * height / 4);
+ memcpy(pdst_u, psrc_u, width * height / 4);
+}
+
+void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height)
+{
+ unsigned char *py;
+ unsigned char *pu;
+ unsigned char *pv;
+
+ uint32_t linesize = width * 2;
+ uint32_t uvlinesize = width / 2;
+ uint32_t offset = 0;
+ uint32_t offset1 = 0;
+ uint32_t offsety = 0;
+ uint32_t offsety1 = 0;
+ uint32_t offsetuv = 0;
+ uint32_t h = 0;
+ uint32_t w = 0;
+ uint32_t wy = 0;
+ uint32_t huv = 0;
+ uint32_t wuv = 0;
+
+ py = src;
+ pu = py + (width * height);
+ pv = pu + (width * height / 4);
+
+ for (h = 0; h < height; h += 2) {
+ wy = 0;
+ wuv = 0;
+ offset = h * linesize;
+ offset1 = (h + 1) * linesize;
+ offsety = h * width;
+ offsety1 = (h + 1) * width;
+ offsetuv = huv * uvlinesize;
+
+ for (w = 0; w < linesize; w += 4) {
+ /* y00 */
+ dest[w + offset] = py[wy + offsety];
+ /* u0 */
+ dest[(w + 1) + offset] = pu[wuv + offsetuv];
+ /* y01 */
+ dest[(w + 2) + offset] = py[(wy + 1) + offsety];
+ /* v0 */
+ dest[(w + 3) + offset] = pv[wuv + offsetuv];
+
+ /* y10 */
+ dest[w + offset1] = py[wy + offsety1];
+ /* u0 */
+ dest[(w + 1) + offset1] = pu[wuv + offsetuv];
+ /* y11 */
+ dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];
+ /* v0 */
+ dest[(w + 3) + offset1] = pv[wuv + offsetuv];
+
+ wuv++;
+ wy += 2;
+ }
+ huv++;
+ }
+}
--- /dev/null
+/*
+ * Virtual Codec device
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * DongKyun Yun
+ *
+ * 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_codec.h"
+#include "qemu-common.h"
+
+#define MARU_CODEC_DEV_NAME "codec"
+#define MARU_CODEC_VERSION 14
+
+/* Needs 16M to support 1920x1080 video resolution.
+ * Output size for encoding has to be greater than (width * height * 6)
+ */
+#define MARU_CODEC_MEM_SIZE (2 * 16 * 1024 * 1024)
+#define MARU_CODEC_REG_SIZE (256)
+#define MARU_CODEC_IRQ 0x7f
+
+#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))
+
+typedef struct PixFmtInfo {
+ uint8_t x_chroma_shift;
+ uint8_t y_chroma_shift;
+} PixFmtInfo;
+
+static PixFmtInfo pix_fmt_info[PIX_FMT_NB];
+
+/* define debug channel */
+MULTI_DEBUG_CHANNEL(qemu, marucodec);
+
+void codec_thread_init(SVCodecState *s)
+{
+ int index = 0;
+ QemuThread *pthread = NULL;
+ TRACE("Enter, %s\n", __func__);
+
+ pthread = g_malloc0(sizeof(QemuThread) * CODEC_MAX_THREAD);
+ if (!pthread) {
+ ERR("Failed to allocate wrk_thread memory.\n");
+ return;
+ }
+ qemu_cond_init(&s->codec_thread.cond);
+ qemu_mutex_init(&s->codec_thread.mutex);
+
+ qemu_mutex_lock(&s->thread_mutex);
+ s->isrunning = 1;
+ qemu_mutex_unlock(&s->thread_mutex);
+
+ for (; index < CODEC_MAX_THREAD; index++) {
+ qemu_thread_create(&pthread[index], codec_worker_thread, (void *)s,
+ QEMU_THREAD_JOINABLE);
+ }
+
+ s->codec_thread.wrk_thread = pthread;
+ TRACE("Leave, %s\n", __func__);
+}
+
+void codec_thread_exit(SVCodecState *s)
+{
+ TRACE("Enter, %s\n", __func__);
+ int index;
+
+ /* stop to run dedicated threads. */
+ s->isrunning = 0;
+
+ for (index = 0; index < CODEC_MAX_THREAD; index++) {
+ qemu_thread_join(&s->codec_thread.wrk_thread[index]);
+ }
+
+ TRACE("destroy mutex and conditional.\n");
+ qemu_mutex_destroy(&s->codec_thread.mutex);
+ qemu_cond_destroy(&s->codec_thread.cond);
+
+ TRACE("Leave, %s\n", __func__);
+}
+
+void wake_codec_worker_thread(SVCodecState *s)
+{
+ TRACE("Enter, %s\n", __func__);
+
+ qemu_cond_signal(&s->codec_thread.cond);
+ TRACE("sent a conditional signal to a worker thread.\n");
+
+ TRACE("Leave, %s\n", __func__);
+}
+
+void *codec_worker_thread(void *opaque)
+{
+ SVCodecState *s = (SVCodecState *)opaque;
+ QemuThread thread;
+ AVCodecContext *avctx;
+
+ TRACE("Enter, %s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ while (s->isrunning) {
+ TRACE("wait for conditional signal.\n");
+ qemu_cond_wait(&s->codec_thread.cond, &s->thread_mutex);
+
+ qemu_thread_get_self(&thread);
+#ifdef CONFIG_LINUX
+ TRACE("wake up a worker thread. :%x\n", thread.thread);
+#endif
+ avctx = s->codec_ctx[s->codec_param.ctx_index].avctx;
+ if (avctx) {
+ if (avctx->codec->decode) {
+ decode_codec(s);
+ } else {
+ encode_codec(s);
+ }
+ } else {
+ ERR("there is a synchrous problem "
+ "between each context.\n");
+ continue;
+ }
+
+ s->codec_thread.state = MARU_CODEC_IRQ;
+ qemu_bh_schedule(s->tx_bh);
+ }
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("Leave, %s\n", __func__);
+
+ return NULL;
+}
+
+int decode_codec(SVCodecState *s)
+{
+ AVCodecContext *avctx;
+ uint32_t len = 0, ctx_index;
+
+ TRACE("Enter, %s\n", __func__);
+
+ qemu_mutex_lock(&s->codec_thread.mutex);
+ ctx_index = s->codec_param.ctx_index;
+ qemu_mutex_unlock(&s->codec_thread.mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ len = qemu_avcodec_decode_video(s, ctx_index);
+ } else {
+ len = qemu_avcodec_decode_audio(s, ctx_index);
+ }
+
+ TRACE("Leave, %s\n", __func__);
+ return len;
+}
+
+int encode_codec(SVCodecState *s)
+{
+ AVCodecContext *avctx;
+ uint32_t len = 0, ctx_index;
+
+ TRACE("Enter, %s\n", __func__);
+
+ qemu_mutex_unlock(&s->thread_mutex);
+
+ ctx_index = s->codec_param.ctx_index;
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ len = qemu_avcodec_encode_video(s, ctx_index);
+ } else {
+ len = qemu_avcodec_encode_audio(s, ctx_index);
+ }
+
+ qemu_mutex_lock(&s->thread_mutex);
+
+ TRACE("Leave, %s\n", __func__);
+ return len;
+}
+
+static int qemu_serialize_rational(const AVRational *elem, uint8_t *buff)
+{
+ int size = 0;
+
+ memcpy(buff + size, &elem->num, sizeof(elem->num));
+ size += sizeof(elem->num);
+ memcpy(buff + size, &elem->den, sizeof(elem->den));
+ size += sizeof(elem->den);
+
+ return size;
+}
+
+static int qemu_deserialize_rational(const uint8_t *buff, AVRational *elem)
+{
+ int size = 0;
+
+ memset(elem, 0, sizeof(*elem));
+
+ memcpy(&elem->num, buff + size, sizeof(elem->num));
+ size += sizeof(elem->num);
+ memcpy(&elem->den, buff + size, sizeof(elem->den));
+ size += sizeof(elem->den);
+
+ return size;
+}
+
+static int qemu_serialize_frame(const AVFrame *elem, uint8_t *buff)
+{
+ int size = 0;
+
+ memcpy(buff + size, &elem->key_frame, sizeof(elem->key_frame));
+ size += sizeof(elem->key_frame);
+ memcpy(buff + size, &elem->pict_type, sizeof(elem->pict_type));
+ size += sizeof(elem->pict_type);
+ memcpy(buff + size, &elem->pts, sizeof(elem->pts));
+ size += sizeof(elem->pts);
+ memcpy(buff + size, &elem->coded_picture_number,
+ sizeof(elem->coded_picture_number));
+ size += sizeof(elem->coded_picture_number);
+ memcpy(buff + size, &elem->display_picture_number,
+ sizeof(elem->display_picture_number));
+ size += sizeof(elem->display_picture_number);
+ memcpy(buff + size, &elem->quality, sizeof(elem->quality));
+ size += sizeof(elem->quality);
+ memcpy(buff + size, &elem->age, sizeof(elem->age));
+ size += sizeof(elem->age);
+ memcpy(buff + size, &elem->reference, sizeof(elem->reference));
+ size += sizeof(elem->reference);
+ memcpy(buff + size, &elem->reordered_opaque,
+ sizeof(elem->reordered_opaque));
+ size += sizeof(elem->reordered_opaque);
+ memcpy(buff + size, &elem->repeat_pict, sizeof(elem->repeat_pict));
+ size += sizeof(elem->repeat_pict);
+ memcpy(buff + size, &elem->interlaced_frame,
+ sizeof(elem->interlaced_frame));
+ size += sizeof(elem->interlaced_frame);
+
+ return size;
+}
+
+static int qemu_deserialize_frame(const uint8_t *buff, AVFrame *elem)
+{
+ int size = 0;
+
+ memset(elem, 0, sizeof(*elem));
+
+ memcpy(&elem->linesize, buff + size, sizeof(elem->linesize));
+ size += sizeof(elem->linesize);
+ memcpy(&elem->key_frame, buff + size, sizeof(elem->key_frame));
+ size += sizeof(elem->key_frame);
+ memcpy(&elem->pict_type, buff + size, sizeof(elem->pict_type));
+ size += sizeof(elem->pict_type);
+ memcpy(&elem->pts, buff + size, sizeof(elem->pts));
+ size += sizeof(elem->pts);
+ memcpy(&elem->coded_picture_number, buff + size,
+ sizeof(elem->coded_picture_number));
+ size += sizeof(elem->coded_picture_number);
+ memcpy(&elem->display_picture_number, buff + size,
+ sizeof(elem->display_picture_number));
+ size += sizeof(elem->display_picture_number);
+ memcpy(&elem->quality, buff + size, sizeof(elem->quality));
+ size += sizeof(elem->quality);
+ memcpy(&elem->age, buff + size, sizeof(elem->age));
+ size += sizeof(elem->age);
+ memcpy(&elem->reference, buff + size, sizeof(elem->reference));
+ size += sizeof(elem->reference);
+ memcpy(&elem->qstride, buff + size, sizeof(elem->qstride));
+ size += sizeof(elem->qstride);
+ memcpy(&elem->motion_subsample_log2, buff + size,
+ sizeof(elem->motion_subsample_log2));
+ size += sizeof(elem->motion_subsample_log2);
+ memcpy(&elem->error, buff + size, sizeof(elem->error));
+ size += sizeof(elem->error);
+ memcpy(&elem->type, buff + size, sizeof(elem->type));
+ size += sizeof(elem->type);
+ memcpy(&elem->repeat_pict, buff + size, sizeof(elem->repeat_pict));
+ size += sizeof(elem->repeat_pict);
+ memcpy(&elem->qscale_type, buff + size, sizeof(elem->qscale_type));
+ size += sizeof(elem->qscale_type);
+ memcpy(&elem->interlaced_frame, buff + size,
+ sizeof(elem->interlaced_frame));
+ size += sizeof(elem->interlaced_frame);
+ memcpy(&elem->top_field_first, buff + size, sizeof(elem->top_field_first));
+ size += sizeof(elem->top_field_first);
+ memcpy(&elem->palette_has_changed, buff + size,
+ sizeof(elem->palette_has_changed));
+ size += sizeof(elem->palette_has_changed);
+ memcpy(&elem->buffer_hints, buff + size, sizeof(elem->buffer_hints));
+ size += sizeof(elem->buffer_hints);
+ memcpy(&elem->reordered_opaque, buff + size,
+ sizeof(elem->reordered_opaque));
+ size += sizeof(elem->reordered_opaque);
+
+ return size;
+}
+
+void qemu_parser_init(SVCodecState *s, int ctx_index)
+{
+ TRACE("[%s] Enter\n", __func__);
+
+ s->codec_ctx[ctx_index].parser_buf = NULL;
+ s->codec_ctx[ctx_index].parser_use = false;
+
+ TRACE("[%s] Leave\n", __func__);
+}
+
+void qemu_reset_codec_info(SVCodecState *s, uint32_t value)
+{
+ int ctx_idx;
+
+ TRACE("[%s] Enter\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ for (ctx_idx = 0; ctx_idx < CODEC_CONTEXT_MAX; ctx_idx++) {
+ if (s->codec_ctx[ctx_idx].file_index == value) {
+ TRACE("reset %d context\n", ctx_idx);
+ qemu_mutex_unlock(&s->thread_mutex);
+ qemu_av_free(s, ctx_idx);
+ qemu_mutex_lock(&s->thread_mutex);
+ s->codec_ctx[ctx_idx].avctx_use = false;
+ break;
+ }
+ }
+ qemu_parser_init(s, ctx_idx);
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("[%s] Leave\n", __func__);
+}
+
+/* void av_register_all() */
+void qemu_av_register_all(void)
+{
+ av_register_all();
+ TRACE("av_register_all\n");
+}
+
+/* int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic) */
+int qemu_avcodec_get_buffer(AVCodecContext *context, AVFrame *picture)
+{
+ int ret;
+ TRACE("avcodec_default_get_buffer\n");
+
+ picture->reordered_opaque = context->reordered_opaque;
+ picture->opaque = NULL;
+
+ ret = avcodec_default_get_buffer(context, picture);
+
+ return ret;
+}
+
+/* void avcodec_default_release_buffer(AVCodecContext *ctx, AVFrame *frame) */
+void qemu_avcodec_release_buffer(AVCodecContext *context, AVFrame *picture)
+{
+ TRACE("avcodec_default_release_buffer\n");
+ avcodec_default_release_buffer(context, picture);
+}
+
+static void qemu_init_pix_fmt_info(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 = 1;
+ 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;
+
+ /* JPEG YUV */
+ 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 uint8_t *qemu_malloc_avpicture (int picture_size)
+{
+ uint8_t *ptr = NULL;
+
+ ptr = av_mallocz(picture_size);
+ if (!ptr) {
+ ERR("failed to allocate memory.\n");
+ return NULL;
+ }
+
+ return ptr;
+}
+
+static int qemu_avpicture_fill(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) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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", 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;
+ TRACE("stride %d, stride2 %d, size %d, size2 %d, fsize %d\n",
+ stride, stride2, size, size2, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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 %d\n", 0, size, size + size2, size + 2 * size2);
+ TRACE("strides %d %d %d %d\n", stride, stride2, stride2, stride);
+ break;
+ case PIX_FMT_RGB24:
+ case PIX_FMT_BGR24:
+ stride = ROUND_UP_4 (width * 3);
+ fsize = stride * height;
+ TRACE("stride: %d, fsize: %d\n", stride, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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, fsize: %d\n", stride, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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:
+ case PIX_FMT_YUYV422:
+ case PIX_FMT_UYVY422:
+ stride = ROUND_UP_4 (width * 2);
+ fsize = stride * height;
+ TRACE("stride: %d, fsize: %d\n", stride, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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_UYYVYY411:
+ /* FIXME, probably not the right stride */
+ stride = ROUND_UP_4 (width);
+ size = stride * height;
+ fsize = size + size / 2;
+ TRACE("stride %d, size %d, fsize %d\n", stride, size, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = NULL;
+ picture->data[2] = NULL;
+ picture->data[3] = NULL;
+ picture->linesize[0] = width + width / 2;
+ picture->linesize[1] = 0;
+ picture->linesize[2] = 0;
+ picture->linesize[3] = 0;
+ break;
+ case PIX_FMT_GRAY8:
+ stride = ROUND_UP_4 (width);
+ fsize = stride * height;
+ TRACE("stride %d, fsize %d\n", stride, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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_MONOWHITE:
+ case PIX_FMT_MONOBLACK:
+ stride = ROUND_UP_4 ((width + 7) >> 3);
+ fsize = stride * height;
+ TRACE("stride %d, fsize %d\n", stride, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ 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:
+ /* already forced to be with stride, so same result as other function */
+ stride = ROUND_UP_4 (width);
+ size = stride * height;
+ fsize = size + 256 * 4;
+ TRACE("stride %d, size %d, fsize %d\n", stride, size, fsize);
+ if (!encode && !ptr) {
+ ptr = qemu_malloc_avpicture(fsize);
+ }
+ picture->data[0] = ptr;
+ picture->data[1] = ptr + size; /* palette is stored here as 256 32 bit words */
+ 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;
+}
+
+/* int avcodec_open(AVCodecContext *avctx, AVCodec *codec) */
+int qemu_avcodec_open(SVCodecState *s)
+{
+ AVCodecContext *avctx;
+ AVCodec *codec;
+ enum CodecID codec_id;
+ off_t offset;
+ int ret = -1;
+ int bEncode = 0;
+ int size = 0;
+ int ctx_index = 0;
+
+ av_register_all();
+ TRACE("av_register_all\n");
+
+ ctx_index = qemu_avcodec_alloc_context(s);
+ if (ctx_index < 0) {
+ return ret;
+ }
+
+ qemu_mutex_lock(&s->thread_mutex);
+ offset = s->codec_param.mmap_offset;
+ qemu_mutex_unlock(&s->thread_mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of AVCodecContext is NULL!\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return ret;
+ }
+
+ TRACE("[%s] Context Index:%d, offset:%d\n", __func__, ctx_index, offset);
+ memcpy(&avctx->bit_rate, (uint8_t *)s->vaddr + offset, sizeof(int));
+ size = sizeof(int);
+ memcpy(&avctx->bit_rate_tolerance,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->flags, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ size += qemu_deserialize_rational((uint8_t *)s->vaddr + offset + size,
+ &avctx->time_base);
+ memcpy(&avctx->width, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->height, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->gop_size, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->pix_fmt, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->sample_rate,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->channels, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->codec_tag, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->block_align,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->rc_strategy,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->strict_std_compliance,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->rc_qsquish,
+ (uint8_t *)s->vaddr + offset + size, sizeof(float));
+ size += sizeof(float);
+ size += qemu_deserialize_rational((uint8_t *)s->vaddr + offset + size,
+ &avctx->sample_aspect_ratio);
+ memcpy(&avctx->qmin, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->qmax, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->pre_me, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->trellis, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&avctx->extradata_size,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&codec_id, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&bEncode, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ TRACE("Context Index:%d, width:%d, height:%d\n",
+ ctx_index, avctx->width, avctx->height);
+
+ if (avctx->extradata_size > 0) {
+ avctx->extradata = (uint8_t *)av_mallocz(avctx->extradata_size +
+ ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ memcpy(avctx->extradata,
+ (uint8_t *)s->vaddr + offset + size, avctx->extradata_size);
+ size += avctx->extradata_size;
+ } else {
+ TRACE("[%s] allocate dummy extradata\n", __func__);
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ }
+
+ if (bEncode) {
+ TRACE("[%s] find encoder :%d\n", __func__, codec_id);
+ codec = avcodec_find_encoder(codec_id);
+ } else {
+ TRACE("[%s] find decoder :%d\n", __func__, codec_id);
+ codec = avcodec_find_decoder(codec_id);
+ }
+
+ if (!codec) {
+ ERR("[%s] failed to find codec of %d\n", __func__, codec_id);
+ }
+
+ if (codec->type == AVMEDIA_TYPE_AUDIO) {
+ s->codec_ctx[ctx_index].mem_index = s->codec_param.mem_index;
+ TRACE("set mem_index: %d into ctx_index: %d.\n",
+ s->codec_ctx[ctx_index].mem_index, ctx_index);
+ }
+
+#if 0
+ avctx->get_buffer = qemu_avcodec_get_buffer;
+ avctx->release_buffer = qemu_avcodec_release_buffer;
+#endif
+
+ ret = avcodec_open(avctx, codec);
+ if (ret != 0) {
+ ERR("[%s] avcodec_open failure, %d\n", __func__, ret);
+ }
+
+ memcpy((uint8_t *)s->vaddr + offset, &ctx_index, sizeof(int));
+ size = sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->pix_fmt, sizeof(int));
+ size += sizeof(int);
+ size += qemu_serialize_rational(&avctx->time_base,
+ (uint8_t *)s->vaddr + offset + size);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->channels, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->sample_fmt, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->codec_type, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->codec_id, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->coded_width, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->coded_height, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->ticks_per_frame, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->chroma_sample_location, sizeof(int));
+ size += sizeof(int);
+#if 0
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ avctx->priv_data, codec->priv_data_size);
+ size += codec->priv_data_size;
+#endif
+ memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
+ size += sizeof(int);
+
+ TRACE("Leave, %s\n", __func__);
+ return ret;
+}
+
+/* int avcodec_close(AVCodecContext *avctx) */
+int qemu_avcodec_close(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx;
+ off_t offset;
+ int ret = -1;
+
+ TRACE("Enter, %s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ offset = s->codec_param.mmap_offset;
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of AVCodecContext is NULL\n", __func__, ctx_index);
+ memcpy((uint8_t *)s->vaddr + offset, &ret, sizeof(int));
+ qemu_mutex_unlock(&s->thread_mutex);
+ return ret;
+ }
+
+ ret = avcodec_close(avctx);
+ TRACE("after avcodec_close. ret:%d\n", ret);
+
+ memcpy((uint8_t *)s->vaddr + offset, &ret, sizeof(int));
+
+ qemu_mutex_unlock(&s->thread_mutex);
+
+ TRACE("[%s] Leave\n", __func__);
+ return ret;
+}
+
+/* AVCodecContext* avcodec_alloc_context (void) */
+int qemu_avcodec_alloc_context(SVCodecState *s)
+{
+ int index;
+
+ TRACE("[%s] Enter\n", __func__);
+
+ for (index = 0; index < CODEC_CONTEXT_MAX; index++) {
+ if (s->codec_ctx[index].avctx_use == false) {
+ TRACE("Succeeded to get %d of context.\n", index);
+ s->codec_ctx[index].avctx_use = true;
+ break;
+ }
+ TRACE("Failed to get context.\n");
+ }
+
+ if (index == CODEC_CONTEXT_MAX) {
+ ERR("Failed to get available codec context.");
+ ERR(" Try to run codec again.\n");
+ return -1;
+ }
+
+ TRACE("allocate %d of context and frame.\n", index);
+ s->codec_ctx[index].avctx = avcodec_alloc_context();
+ s->codec_ctx[index].frame = avcodec_alloc_frame();
+
+ s->codec_ctx[index].file_index = s->codec_param.file_index;
+ qemu_parser_init(s, index);
+ qemu_init_pix_fmt_info();
+
+ TRACE("[%s] Leave\n", __func__);
+
+ return index;
+}
+
+/* void av_free(void *ptr) */
+void qemu_av_free(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx;
+ AVFrame *avframe;
+
+ TRACE("enter %s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ avframe = s->codec_ctx[ctx_index].frame;
+
+ if (avctx && avctx->palctrl) {
+ av_free(avctx->palctrl);
+ avctx->palctrl = NULL;
+ }
+
+ if (avctx && avctx->extradata) {
+ TRACE("free extradata\n");
+ av_free(avctx->extradata);
+ avctx->extradata = NULL;
+ }
+
+ if (avctx && avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ int audio_idx = s->codec_ctx[ctx_index].mem_index;
+ TRACE("reset audio mem_idex: %d\n", __LINE__, audio_idx);
+ s->audio_codec_offset[audio_idx] = 0;
+ }
+
+ if (avctx) {
+ TRACE("free codec context of %d.\n", ctx_index);
+ av_free(avctx);
+ s->codec_ctx[ctx_index].avctx = NULL;
+ }
+
+ if (avframe) {
+ TRACE("free codec frame of %d.\n", ctx_index);
+ av_free(avframe);
+ s->codec_ctx[ctx_index].frame = NULL;
+ }
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("leave %s\n", __func__);
+}
+
+/* void avcodec_flush_buffers(AVCodecContext *avctx) */
+void qemu_avcodec_flush_buffers(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx;
+
+ TRACE("Enter\n");
+ qemu_mutex_lock(&s->thread_mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (avctx) {
+ avcodec_flush_buffers(avctx);
+ } else {
+ ERR("[%s] %d of AVCodecContext is NULL\n", __func__, ctx_index);
+ }
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("[%s] Leave\n", __func__);
+}
+
+/* int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture,
+ * int *got_picture_ptr, const uint8_t *buf,
+ * int buf_size)
+ */
+int qemu_avcodec_decode_video(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx;
+ AVFrame *picture;
+ AVPacket avpkt;
+ int got_picture_ptr;
+ uint8_t *buf;
+ uint8_t *parser_buf;
+ bool parser_use;
+ int buf_size;
+ int size = 0;
+ int ret = -1;
+ off_t offset;
+
+ TRACE("Enter, %s\n", __func__);
+ qemu_mutex_lock(&s->codec_thread.mutex);
+
+ TRACE("[%s] Video Context Index : %d\n", __func__, ctx_index);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ picture = s->codec_ctx[ctx_index].frame;
+ if (!avctx || !picture) {
+ ERR("[%s] %d of Context or Frame is NULL!\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->codec_thread.mutex);
+ return ret;
+ }
+
+ offset = s->codec_param.mmap_offset;
+
+ parser_buf = s->codec_ctx[ctx_index].parser_buf;
+ parser_use = s->codec_ctx[ctx_index].parser_use;
+ TRACE("[%s] Parser Buffer : %p, Parser:%d\n", __func__,
+ parser_buf, parser_use);
+
+ memcpy(&avctx->reordered_opaque,
+ (uint8_t *)s->vaddr + offset, sizeof(int64_t));
+ size = sizeof(int64_t);
+ memcpy(&avctx->skip_frame,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+ memcpy(&buf_size, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+
+ picture->reordered_opaque = avctx->reordered_opaque;
+
+ if (parser_buf && parser_use) {
+ buf = parser_buf;
+ } else if (buf_size > 0) {
+ TRACE("[%s] not use parser, codec_id:%x\n", __func__, avctx->codec_id);
+ buf = (uint8_t *)s->vaddr + offset + size;
+ size += buf_size;
+ } else {
+ TRACE("There is no input buffer\n");
+ buf = NULL;
+ }
+
+ memset(&avpkt, 0, sizeof(AVPacket));
+ avpkt.data = buf;
+ avpkt.size = buf_size;
+ TRACE("packet buf:%p, size:%d\n", buf, buf_size);
+
+ ret = avcodec_decode_video2(avctx, picture, &got_picture_ptr, &avpkt);
+
+ TRACE("[%s] after decoding video, ret:%d\n", __func__, ret);
+ if (ret < 0) {
+ ERR("[%s] failed to decode video!!, ret:%d\n", __func__, ret);
+ } else {
+ if (ret == 0) {
+ TRACE("[%s] no frame. packet size:%d\n", __func__, avpkt.size);
+ }
+ TRACE("decoded frame number:%d\n", avctx->frame_number);
+ }
+
+ memcpy((uint8_t *)s->vaddr + offset, &avctx->pix_fmt, sizeof(int));
+ size = sizeof(int);
+ size += qemu_serialize_rational(&avctx->time_base,
+ (uint8_t *)s->vaddr + offset + size);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->width, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->height, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->has_b_frames, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->frame_number, sizeof(int));
+ size += sizeof(int);
+ size += qemu_serialize_rational(&avctx->sample_aspect_ratio,
+ (uint8_t *)s->vaddr + offset + size);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->internal_buffer_count, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->profile, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->level, sizeof(int));
+ size += sizeof(int);
+ size += qemu_serialize_frame(picture, (uint8_t *)s->vaddr + offset + size);
+
+ memcpy((uint8_t *)s->vaddr + offset + size, &got_picture_ptr, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
+ size += sizeof(int);
+
+#if 0
+ memcpy((uint8_t *)s->vaddr + offset + size, dst.data[0], numbytes);
+ av_free(buffer);
+
+ if (parser_buf && parser_use) {
+ TRACE("[%s] Free input buffer after decoding video\n", __func__);
+ TRACE("[%s] input buffer : %p, %p\n",
+ __func__, avpkt.data, parser_buf);
+ av_free(avpkt.data);
+ s->codec_ctx[ctx_index].parser_buf = NULL;
+ }
+#endif
+
+ qemu_mutex_unlock(&s->codec_thread.mutex);
+ TRACE("Leave, %s\n", __func__);
+
+ return ret;
+}
+
+/* int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf,
+ * int buf_size, const AVFrame *pict)
+ */
+int qemu_avcodec_encode_video(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx = NULL;
+ AVFrame *pict = NULL;
+ uint8_t *inputBuf = NULL;
+ int outbufSize = 0;
+ int bPict = -1;
+ int size = 0;
+ int ret = -1;
+ off_t offset;
+
+ TRACE("Enter, %s\n", __func__);
+ qemu_mutex_lock(&s->codec_thread.mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ pict = s->codec_ctx[ctx_index].frame;
+ if (!avctx || !pict) {
+ ERR("[%s] %d of Context or Frame is NULL\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return ret;
+ }
+
+ offset = s->codec_param.mmap_offset;
+
+ size = sizeof(int);
+ memcpy(&bPict, (uint8_t *)s->vaddr + offset, size);
+ TRACE("[%s] avframe is :%d\n", __func__, bPict);
+
+ if (bPict == 0) {
+ memcpy(&outbufSize, (uint8_t *)s->vaddr + offset + size, size);
+ size += sizeof(int);
+ size +=
+ qemu_deserialize_frame((uint8_t *)s->vaddr + offset + size, pict);
+
+ inputBuf = (uint8_t *)s->vaddr + offset + size;
+ if (!inputBuf) {
+ ERR("[%s] failed to get input buffer\n", __func__);
+ return ret;
+ }
+
+ ret = qemu_avpicture_fill((AVPicture *)pict, inputBuf, avctx->pix_fmt,
+ avctx->width, avctx->height, true);
+
+ if (ret < 0) {
+ ERR("after avpicture_fill, ret:%d\n", ret);
+ }
+ TRACE("before encode video, ticks_per_frame:%d, pts:%lld\n",
+ avctx->ticks_per_frame, pict->pts);
+ } else {
+ TRACE("flush encoded buffers\n");
+ pict = NULL;
+ }
+
+ ret = avcodec_encode_video(avctx, (uint8_t *)s->vaddr + offset,
+ outbufSize, pict);
+ TRACE("encode video, ret:%d, pts:%lld, outbuf size:%d\n",
+ ret, pict->pts, outbufSize);
+
+ if (ret < 0) {
+ ERR("failed to encode video.\n");
+ }
+
+ memcpy((uint8_t *)s->vaddr + offset + outbufSize, &ret, sizeof(int));
+
+ qemu_mutex_unlock(&s->codec_thread.mutex);
+ TRACE("Leave, %s\n", __func__);
+
+ return ret;
+}
+
+/*
+ * int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
+ * int *frame_size_ptr, AVPacket *avpkt)
+ */
+int qemu_avcodec_decode_audio(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx;
+ AVPacket avpkt;
+ int16_t *samples;
+ int frame_size_ptr;
+ uint8_t *buf;
+ uint8_t *parser_buf;
+ bool parser_use;
+ int buf_size, outbuf_size;
+ int size;
+ int ret = -1;
+ off_t offset;
+
+ TRACE("Enter, %s\n", __func__);
+
+ TRACE("Audio Context Index : %d\n", ctx_index);
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of Context is NULL!\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->codec_thread.mutex);
+ return ret;
+ }
+
+ if (!avctx->codec) {
+ ERR("[%s] %d of Codec is NULL\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->codec_thread.mutex);
+ return ret;
+ }
+
+ offset = s->codec_param.mmap_offset;
+
+ parser_buf = s->codec_ctx[ctx_index].parser_buf;
+ parser_use = s->codec_ctx[ctx_index].parser_use;
+
+ memcpy(&buf_size, (uint8_t *)s->vaddr + offset, sizeof(int));
+ size = sizeof(int);
+ if (parser_buf && parser_use) {
+ TRACE("[%s] use parser, buf:%p codec_id:%x\n",
+ __func__, parser_buf, avctx->codec_id);
+ buf = parser_buf;
+ } else if (buf_size > 0) {
+ TRACE("[%s] not use parser, codec_id:%x\n", __func__, avctx->codec_id);
+ buf = (uint8_t *)s->vaddr + offset + size;
+ size += buf_size;
+ } else {
+ TRACE("no input buffer\n");
+ buf = NULL;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = buf;
+ avpkt.size = buf_size;
+
+ frame_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ outbuf_size = frame_size_ptr;
+ samples = av_malloc(frame_size_ptr);
+
+ ret = avcodec_decode_audio3(avctx, samples, &frame_size_ptr, &avpkt);
+ TRACE("after decoding audio!, ret:%d\n", ret);
+
+ memcpy((uint8_t *)s->vaddr + offset, &avctx->bit_rate, sizeof(int));
+ size = sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->sample_rate, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->channels, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->channel_layout, sizeof(int64_t));
+ size += sizeof(int64_t);
+ memcpy((uint8_t *)s->vaddr + offset + size, &avctx->sub_id, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->frame_size, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size,
+ &avctx->frame_number, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, samples, outbuf_size);
+ size += outbuf_size;
+ memcpy((uint8_t *)s->vaddr + offset + size, &frame_size_ptr, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
+ size += sizeof(int);
+
+ TRACE("before free input buffer and output buffer!\n");
+ if (samples) {
+ TRACE("release allocated audio buffer.\n");
+ av_free(samples);
+ samples = NULL;
+ }
+
+ if (parser_buf && parser_use) {
+ TRACE("[%s] free parser buf\n", __func__);
+ av_free(avpkt.data);
+ s->codec_ctx[ctx_index].parser_buf = NULL;
+ }
+
+ TRACE("[%s] Leave\n", __func__);
+
+ return ret;
+}
+
+int qemu_avcodec_encode_audio(SVCodecState *s, int ctx_index)
+{
+ WARN("[%s] Does not support audio encoder using FFmpeg\n", __func__);
+ return 0;
+}
+
+/* void av_picture_copy(AVPicture *dst, const AVPicture *src,
+ * enum PixelFormat pix_fmt, int width, int height)
+ */
+void qemu_av_picture_copy(SVCodecState *s, int ctx_index)
+{
+ AVCodecContext *avctx = NULL;
+ AVPicture dst;
+ AVPicture *src = NULL;
+ int numBytes = 0;
+ uint8_t *buffer = NULL;
+ off_t offset = 0;
+
+ TRACE("Enter :%s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ src = (AVPicture *)s->codec_ctx[ctx_index].frame;
+ if (!avctx && !src) {
+ ERR("[%s] %d of context or frame is NULL\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return;
+ }
+
+ offset = s->codec_param.mmap_offset;
+
+ numBytes = qemu_avpicture_fill(&dst, NULL, avctx->pix_fmt,
+ avctx->width, avctx->height, false);
+ TRACE("after avpicture_fill: %d\n", numBytes);
+ if (numBytes < 0) {
+ ERR("picture size:%d is wrong.\n", numBytes);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return;
+ }
+
+ av_picture_copy(&dst, src, avctx->pix_fmt, avctx->width, avctx->height);
+ buffer = dst.data[0];
+ memcpy((uint8_t *)s->vaddr + offset, buffer, numBytes);
+ TRACE("after copy image buffer from host to guest.\n");
+
+ if (buffer) {
+ TRACE("release allocated video frame.\n");
+ av_free(buffer);
+ }
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("Leave :%s\n", __func__);
+}
+
+/* AVCodecParserContext *av_parser_init(int codec_id) */
+void qemu_av_parser_init(SVCodecState *s, int ctx_index)
+{
+ AVCodecParserContext *parser_ctx = NULL;
+ AVCodecContext *avctx;
+
+ TRACE("Enter :%s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of AVCodecContext is NULL!!\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return;
+ }
+
+ TRACE("before av_parser_init, codec_type:%d codec_id:%x\n",
+ avctx->codec_type, avctx->codec_id);
+
+ parser_ctx = av_parser_init(avctx->codec_id);
+ if (parser_ctx) {
+ TRACE("[%s] using parser\n", __func__);
+ s->codec_ctx[ctx_index].parser_use = true;
+ } else {
+ TRACE("[%s] no parser\n", __func__);
+ s->codec_ctx[ctx_index].parser_use = false;
+ }
+ s->codec_ctx[ctx_index].parser_ctx = parser_ctx;
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("[%s] Leave\n", __func__);
+}
+
+/* int av_parser_parse(AVCodecParserContext *s, AVCodecContext *avctx,
+ * uint8_t **poutbuf, int *poutbuf_size,
+ * const uint8_t *buf, int buf_size,
+ * int64_t pts, int64_t dts)
+ */
+int qemu_av_parser_parse(SVCodecState *s, int ctx_index)
+{
+ AVCodecParserContext *parser_ctx = NULL;
+ AVCodecContext *avctx = NULL;
+ uint8_t *poutbuf;
+ int poutbuf_size = 0;
+ uint8_t *inbuf = NULL;
+ int inbuf_size;
+ int64_t pts;
+ int64_t dts;
+ int64_t pos;
+ int size, ret = -1;
+ off_t offset;
+
+ TRACE("Enter %s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ parser_ctx = s->codec_ctx[ctx_index].parser_ctx;
+ avctx = s->codec_ctx[ctx_index].avctx;
+ if (!avctx) {
+ ERR("[%s] %d of AVCodecContext is NULL\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return ret;
+ }
+
+ if (!parser_ctx) {
+ ERR("[%s] %d of AVCodecParserContext is NULL\n", __func__, ctx_index);
+ qemu_mutex_unlock(&s->thread_mutex);
+ return ret;
+ }
+
+ offset = s->codec_param.mmap_offset;
+
+ memcpy(&parser_ctx->pts,
+ (uint8_t *)s->vaddr + offset, sizeof(int64_t));
+ size = sizeof(int64_t);
+ memcpy(&parser_ctx->dts,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ memcpy(&parser_ctx->pos,
+ (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ memcpy(&pts, (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ memcpy(&dts, (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ memcpy(&pos, (uint8_t *)s->vaddr + offset + size, sizeof(int64_t));
+ size += sizeof(int64_t);
+ memcpy(&inbuf_size, (uint8_t *)s->vaddr + offset + size, sizeof(int));
+ size += sizeof(int);
+
+ if (inbuf_size > 0) {
+ inbuf = av_mallocz(inbuf_size);
+ memcpy(inbuf, (uint8_t *)s->vaddr + offset + size, inbuf_size);
+ } else {
+ inbuf = NULL;
+ INFO("input buffer size for parser is zero.\n");
+ }
+
+ TRACE("[%s] inbuf:%p inbuf_size :%d\n", __func__, inbuf, inbuf_size);
+ ret = av_parser_parse2(parser_ctx, avctx, &poutbuf, &poutbuf_size,
+ inbuf, inbuf_size, pts, dts, pos);
+ TRACE("after parsing, outbuf size :%d, ret:%d\n", poutbuf_size, ret);
+
+ if (poutbuf) {
+ s->codec_ctx[ctx_index].parser_buf = poutbuf;
+ }
+
+ TRACE("[%s] inbuf : %p, outbuf : %p\n", __func__, inbuf, poutbuf);
+ memcpy((uint8_t *)s->vaddr + offset, &parser_ctx->pts, sizeof(int64_t));
+ size = sizeof(int64_t);
+ memcpy((uint8_t *)s->vaddr + offset + size, &poutbuf_size, sizeof(int));
+ size += sizeof(int);
+ memcpy((uint8_t *)s->vaddr + offset + size, &ret, sizeof(int));
+ size += sizeof(int);
+ if (poutbuf && poutbuf_size > 0) {
+ memcpy((uint8_t *)s->vaddr + offset + size, poutbuf, poutbuf_size);
+ } else {
+ av_free(inbuf);
+ }
+
+#if 0
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ TRACE("[%s] free parser inbuf\n", __func__);
+ av_free(inbuf);
+ }
+#endif
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("Leave, %s\n", __func__);
+
+ return ret;
+}
+
+/* void av_parser_close(AVCodecParserContext *s) */
+void qemu_av_parser_close(SVCodecState *s, int ctx_index)
+{
+ AVCodecParserContext *parser_ctx;
+
+ TRACE("Enter, %s\n", __func__);
+ qemu_mutex_lock(&s->thread_mutex);
+
+ parser_ctx = s->codec_ctx[ctx_index].parser_ctx;
+ if (!parser_ctx) {
+ ERR("AVCodecParserContext is NULL\n");
+ qemu_mutex_unlock(&s->thread_mutex);
+ return;
+ }
+ av_parser_close(parser_ctx);
+
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("Leave, %s\n", __func__);
+}
+
+int codec_operate(uint32_t api_index, uint32_t ctx_index, SVCodecState *s)
+{
+ int ret = -1;
+
+ TRACE("[%s] context : %d\n", __func__, ctx_index);
+ switch (api_index) {
+ /* FFMPEG API */
+ case EMUL_AV_REGISTER_ALL:
+ qemu_av_register_all();
+ break;
+ case EMUL_AVCODEC_OPEN:
+ ret = qemu_avcodec_open(s);
+ break;
+ case EMUL_AVCODEC_CLOSE:
+ ret = qemu_avcodec_close(s, ctx_index);
+ qemu_av_free(s, ctx_index);
+ break;
+ case EMUL_AVCODEC_FLUSH_BUFFERS:
+ qemu_avcodec_flush_buffers(s, ctx_index);
+ break;
+ case EMUL_AVCODEC_DECODE_VIDEO:
+ case EMUL_AVCODEC_ENCODE_VIDEO:
+ case EMUL_AVCODEC_DECODE_AUDIO:
+ case EMUL_AVCODEC_ENCODE_AUDIO:
+ wake_codec_worker_thread(s);
+ break;
+ case EMUL_AV_PICTURE_COPY:
+ qemu_av_picture_copy(s, ctx_index);
+ break;
+ case EMUL_AV_PARSER_INIT:
+ qemu_av_parser_init(s, ctx_index);
+ break;
+ case EMUL_AV_PARSER_PARSE:
+ ret = qemu_av_parser_parse(s, ctx_index);
+ break;
+ case EMUL_AV_PARSER_CLOSE:
+ qemu_av_parser_close(s, ctx_index);
+ break;
+ default:
+ WARN("api index %d does not exist!.\n", api_index);
+ }
+ return ret;
+}
+
+static uint32_t qemu_get_mmap_offset(SVCodecState *s)
+{
+ int index = 0;
+
+ for (; index < AUDIO_CODEC_MEM_OFFSET_MAX; index++) {
+ if (s->audio_codec_offset[index] == 0) {
+ s->audio_codec_offset[index] = 1;
+ break;
+ }
+ }
+ TRACE("return mmap offset: %d\n", index);
+
+ return index;
+}
+
+/*
+ * Codec Device APIs
+ */
+uint64_t codec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ SVCodecState *s = (SVCodecState *)opaque;
+ uint64_t ret = 0;
+
+ switch (addr) {
+ case CODEC_CMD_GET_THREAD_STATE:
+ qemu_mutex_lock(&s->thread_mutex);
+ ret = s->codec_thread.state;
+ s->codec_thread.state = 0;
+ qemu_mutex_unlock(&s->thread_mutex);
+ TRACE("ret: %d, thread state: %d\n", ret, s->codec_thread.state);
+ qemu_irq_lower(s->dev.irq[0]);
+ break;
+ case CODEC_CMD_GET_VERSION:
+ ret = MARU_CODEC_VERSION;
+ TRACE("codec version: %d\n", ret);
+ break;
+ case CODEC_CMD_GET_DEVICE_MEM:
+ qemu_mutex_lock(&s->thread_mutex);
+ ret = s->device_mem_avail;
+ if (s->device_mem_avail != 1) {
+ s->device_mem_avail = 1;
+ }
+ qemu_mutex_unlock(&s->thread_mutex);
+ break;
+ case CODEC_CMD_GET_MMAP_OFFSET:
+ ret = qemu_get_mmap_offset(s);
+ TRACE("mem index: %d\n", ret);
+ break;
+ default:
+ ERR("no avaiable command for read. %d\n", addr);
+ }
+
+ return ret;
+}
+
+void codec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ SVCodecState *s = (SVCodecState *)opaque;
+
+ switch (addr) {
+ case CODEC_CMD_API_INDEX:
+ codec_operate(value, s->codec_param.ctx_index, s);
+ break;
+ case CODEC_CMD_CONTEXT_INDEX:
+ s->codec_param.ctx_index = value;
+ TRACE("Context Index: %d\n", s->codec_param.ctx_index);
+ break;
+ case CODEC_CMD_FILE_INDEX:
+ s->codec_param.file_index = value;
+ break;
+ case CODEC_CMD_DEVICE_MEM_OFFSET:
+ s->codec_param.mmap_offset = value;
+ TRACE("MMAP Offset: %d\n", s->codec_param.mmap_offset);
+ break;
+ case CODEC_CMD_RESET_CODEC_INFO:
+ qemu_reset_codec_info(s, value);
+ break;
+ case CODEC_CMD_SET_DEVICE_MEM:
+ qemu_mutex_lock(&s->thread_mutex);
+ s->device_mem_avail = value;
+ qemu_mutex_unlock(&s->thread_mutex);
+ break;
+ case CODEC_CMD_SET_MMAP_OFFSET:
+ s->codec_param.mem_index = value;
+ break;
+ default:
+ ERR("no avaiable command for write. %d\n", addr);
+ }
+}
+
+static const MemoryRegionOps codec_mmio_ops = {
+ .read = codec_read,
+ .write = codec_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void codec_tx_bh(void *opaque)
+{
+ SVCodecState *s = (SVCodecState *)opaque;
+
+ int ctx_index;
+ AVCodecContext *ctx;
+
+ ctx_index = s->codec_param.ctx_index;
+ ctx = s->codec_ctx[ctx_index].avctx;
+
+ TRACE("Enter, %s\n", __func__);
+
+ /* raise irq as soon as a worker thread had finished a job*/
+ if (s->codec_thread.state) {
+ TRACE("raise codec irq. state:%d, codec:%d\n",
+ s->codec_thread.state, ctx->codec_type);
+ qemu_irq_raise(s->dev.irq[0]);
+ }
+
+ TRACE("Leave, %s\n", __func__);
+}
+
+static int codec_initfn(PCIDevice *dev)
+{
+ SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+
+ INFO("[%s] device init\n", __func__);
+
+ memset(&s->codec_param, 0, sizeof(SVCodecParam));
+
+ qemu_mutex_init(&s->thread_mutex);
+ codec_thread_init(s);
+ s->tx_bh = qemu_bh_new(codec_tx_bh, s);
+
+ pci_config_set_interrupt_pin(pci_conf, 1);
+
+ memory_region_init_ram(&s->vram, OBJECT(s), "codec.ram", MARU_CODEC_MEM_SIZE);
+ s->vaddr = memory_region_get_ram_ptr(&s->vram);
+
+ memory_region_init_io(&s->mmio, OBJECT(s), &codec_mmio_ops, s,
+ "codec-mmio", MARU_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);
+
+ return 0;
+}
+
+static void codec_exitfn(PCIDevice *dev)
+{
+ SVCodecState *s = DO_UPCAST(SVCodecState, dev, dev);
+ INFO("[%s] device exit\n", __func__);
+
+ qemu_bh_delete(s->tx_bh);
+
+ memory_region_destroy(&s->vram);
+ memory_region_destroy(&s->mmio);
+}
+
+int codec_init(PCIBus *bus)
+{
+ INFO("[%s] device create\n", __func__);
+ pci_create_simple(bus, -1, MARU_CODEC_DEV_NAME);
+ return 0;
+}
+
+static void codec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = codec_initfn;
+ k->exit = codec_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TIZEN;
+ k->device_id = PCI_DEVICE_ID_VIRTUAL_CODEC;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ dc->desc = "Virtual Codec device for Tizen emulator";
+}
+
+static TypeInfo codec_info = {
+ .name = MARU_CODEC_DEV_NAME,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(SVCodecState),
+ .class_init = codec_class_init,
+};
+
+static void codec_register_types(void)
+{
+ type_register_static(&codec_info);
+}
+
+type_init(codec_register_types)
--- /dev/null
+/*
+ * Virtual Codec device
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "hw/hw.h"
+#include "sysemu/kvm.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_ids.h"
+#include "qemu/thread.h"
+#include "debug_ch.h"
+#include "maru_device_ids.h"
+
+#include <libavformat/avformat.h>
+
+#define CODEC_CONTEXT_MAX 1024
+#define VIDEO_CODEC_MEM_OFFSET_MAX 16
+#define AUDIO_CODEC_MEM_OFFSET_MAX 64
+
+#define CODEC_MAX_THREAD 10
+
+/*
+ * Codec Device Structures
+ */
+typedef struct _SVCodecParam {
+ uint32_t api_index;
+ uint32_t ctx_index;
+ uint32_t file_index;
+ uint32_t mem_index;
+ uint32_t mmap_offset;
+} SVCodecParam;
+
+typedef struct _SVCodecContext {
+ AVCodecContext *avctx;
+ AVFrame *frame;
+ AVCodecParserContext *parser_ctx;
+ uint8_t *parser_buf;
+ uint8_t parser_use;
+ uint8_t avctx_use;
+ uint32_t file_index;
+ uint32_t mem_index;
+} SVCodecContext;
+
+typedef struct _SVCodecThreadPool {
+ QemuThread *wrk_thread;
+ QemuMutex mutex;
+ QemuCond cond;
+ uint32_t state;
+ uint8_t isrunning;
+} SVCodecThreadPool;
+
+typedef struct _SVCodecState {
+ PCIDevice dev;
+
+ uint8_t *vaddr;
+ MemoryRegion vram;
+ MemoryRegion mmio;
+
+ QEMUBH *tx_bh;
+ QemuMutex thread_mutex;
+
+ SVCodecContext codec_ctx[CODEC_CONTEXT_MAX];
+ SVCodecParam codec_param;
+ SVCodecThreadPool codec_thread;
+ uint8_t audio_codec_offset[AUDIO_CODEC_MEM_OFFSET_MAX];
+ uint8_t device_mem_avail;
+ uint8_t isrunning;
+} SVCodecState;
+
+enum codec_io_cmd {
+ CODEC_CMD_API_INDEX = 0x00,
+ CODEC_CMD_CONTEXT_INDEX = 0x04,
+ CODEC_CMD_FILE_INDEX = 0x08,
+ CODEC_CMD_DEVICE_MEM_OFFSET = 0x0c,
+ CODEC_CMD_GET_THREAD_STATE = 0x10,
+ CODEC_CMD_GET_VERSION = 0x14,
+ CODEC_CMD_GET_DEVICE_MEM = 0x18,
+ CODEC_CMD_SET_DEVICE_MEM = 0x1C,
+ CODEC_CMD_GET_MMAP_OFFSET = 0x20,
+ CODEC_CMD_SET_MMAP_OFFSET = 0x24,
+ CODEC_CMD_RESET_CODEC_INFO = 0x28,
+};
+
+enum {
+ EMUL_AV_REGISTER_ALL = 1,
+ EMUL_AVCODEC_OPEN,
+ EMUL_AVCODEC_CLOSE,
+ EMUL_AVCODEC_FLUSH_BUFFERS,
+ EMUL_AVCODEC_DECODE_VIDEO,
+ EMUL_AVCODEC_ENCODE_VIDEO,
+ EMUL_AVCODEC_DECODE_AUDIO,
+ EMUL_AVCODEC_ENCODE_AUDIO,
+ EMUL_AV_PICTURE_COPY,
+ EMUL_AV_PARSER_INIT,
+ EMUL_AV_PARSER_PARSE,
+ EMUL_AV_PARSER_CLOSE,
+};
+
+
+/*
+ * Codec Thread Functions
+ */
+void codec_thread_init(SVCodecState *s);
+void codec_thread_exit(SVCodecState *s);
+void *codec_worker_thread(void *opaque);
+void wake_codec_worker_thread(SVCodecState *s);
+int decode_codec(SVCodecState *s);
+int encode_codec(SVCodecState *s);
+
+/*
+ * Codec Device Functions
+ */
+int codec_init(PCIBus *bus);
+uint64_t codec_read(void *opaque, hwaddr addr,
+ unsigned size);
+void codec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size);
+int codec_operate(uint32_t api_index, uint32_t ctx_index,
+ SVCodecState *state);
+
+/*
+ * Codec Helper Functions
+ */
+void qemu_parser_init(SVCodecState *s, int ctx_index);
+void qemu_codec_close(SVCodecState *s, uint32_t value);
+void qemu_get_codec_ver(SVCodecState *s);
+void qemu_reset_codec_info(SVCodecState *s, uint32_t value);
+
+/*
+ * FFMPEG Functions
+ */
+void qemu_av_register_all(void);
+int qemu_avcodec_open(SVCodecState *s);
+int qemu_avcodec_close(SVCodecState *s, int ctx_index);
+int qemu_avcodec_alloc_context(SVCodecState *s);
+void qemu_avcodec_flush_buffers(SVCodecState *s, int ctx_index);
+int qemu_avcodec_decode_video(SVCodecState *s, int ctx_index);
+int qemu_avcodec_encode_video(SVCodecState *s, int ctx_index);
+int qemu_avcodec_decode_audio(SVCodecState *s, int ctx_index);
+int qemu_avcodec_encode_audio(SVCodecState *s, int ctx_index);
+void qemu_av_picture_copy(SVCodecState *s, int ctx_index);
+void qemu_av_parser_init(SVCodecState *s, int ctx_index);
+int qemu_av_parser_parse(SVCodecState *s, int ctx_index);
+void qemu_av_parser_close(SVCodecState *s, int ctx_index);
+int qemu_avcodec_get_buffer(AVCodecContext *context, AVFrame *picture);
+void qemu_avcodec_release_buffer(AVCodecContext *context, AVFrame *picture);
+void qemu_av_free(SVCodecState *s, int ctx_index);
--- /dev/null
+obj-y += maru_usb_touchscreen.o
--- /dev/null
+/*
+ * Maru USB Touchscreen Device
+ * Based on hw/usb-wacom.c:
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "maru_usb_touchscreen.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, usb_touchscreen);
+
+
+#define MAX_TOUCH_EVENT_CNT 128
+
+//lock for between communication thread and main thread
+static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static QTAILQ_HEAD(, TouchEventEntry) events_queue =
+ QTAILQ_HEAD_INITIALIZER(events_queue);
+
+static unsigned int event_cnt = 0;
+static unsigned int _processed_buf_cnt = 0;
+static TouchEventEntry _event_buf[MAX_TOUCH_EVENT_CNT];
+
+/**
+ * @brief : qemu touch(host mouse) event handler
+ * @param opaque : state of device
+ * @param x : X-axis value
+ * @param y : Y-axis value
+ * @param z : event id for multiple touch
+ */
+static void usb_touchscreen_event(void *opaque, int x, int y, int z, int buttons_state)
+{
+ TouchEventEntry *te;
+ USBTouchscreenState *s = opaque;
+
+ pthread_mutex_lock(&event_mutex);
+ if (event_cnt >= MAX_TOUCH_EVENT_CNT) {
+ pthread_mutex_unlock(&event_mutex);
+ INFO("full touch event queue, lose event\n", event_cnt);
+ return;
+ }
+
+ //using prepared memory
+ te = &(_event_buf[_processed_buf_cnt % MAX_TOUCH_EVENT_CNT]);
+ _processed_buf_cnt++;
+
+ /* mouse event is copied into the queue */
+ te->index = ++event_cnt;
+ te->queue_packet.x = x;
+ te->queue_packet.y = y;
+ te->queue_packet.z = z;
+ te->queue_packet.state = buttons_state;
+
+ QTAILQ_INSERT_TAIL(&events_queue, te, node);
+ s->changed = 1;
+ pthread_mutex_unlock(&event_mutex);
+
+ TRACE("touch event (%d) : x=%d, y=%d, z=%d, state=%d\n", te->index, x, y, z, buttons_state);
+}
+
+/**
+ * @brief : fill the usb packet
+ * @param s : state of device
+ * @param buf : usb packet
+ * @param len : size of packet
+ */
+static int usb_touchscreen_poll(USBTouchscreenState *s, uint8_t *buf, int len)
+{
+ USBEmulTouchscreenPacket *packet = (USBEmulTouchscreenPacket *)buf;
+
+ if (s->mouse_grabbed == 0) {
+ s->eh_entry = qemu_add_mouse_event_handler(usb_touchscreen_event, s, 1, "QEMU USB touchscreen");
+ qemu_activate_mouse_event_handler(s->eh_entry);
+ s->mouse_grabbed = 1;
+ }
+
+ if (len < EMUL_TOUCHSCREEN_PACKET_LEN) {
+ return 0;
+ }
+
+ packet->x = s->dx & 0xffff;
+ packet->y = s->dy & 0xffff;
+ packet->z = s->dz & 0xffff;
+
+ if (s->buttons_state == 0) {
+ packet->state = 0;
+ } else {
+ packet->state = 1;
+ }
+
+ return EMUL_TOUCHSCREEN_PACKET_LEN;
+}
+
+static void usb_touchscreen_handle_reset(USBDevice *dev)
+{
+ USBTouchscreenState *s = (USBTouchscreenState *) dev;
+
+ pthread_mutex_lock(&event_mutex);
+
+ s->dx = 0;
+ s->dy = 0;
+ s->dz = 0;
+ s->buttons_state = 0;
+
+ event_cnt = 0;
+ _processed_buf_cnt = 0;
+
+ pthread_mutex_unlock(&event_mutex);
+}
+
+static void usb_touchscreen_handle_control(USBDevice *dev, USBPacket *p,
+ int request, int value, int index, int length, uint8_t *data)
+{
+ usb_desc_handle_control(dev, p, request, value, index, length, data);
+}
+
+/**
+ * @brief : call by uhci frame timer
+ * @param dev : state of device
+ * @param p : usb packet
+ */
+static void usb_touchscreen_handle_data(USBDevice *dev, USBPacket *p)
+{
+ USBTouchscreenState *s = (USBTouchscreenState *) dev;
+ uint8_t buf[p->iov.size];
+ int len = 0;
+
+ switch (p->pid) {
+ case USB_TOKEN_IN:
+ if (p->ep->nr == 1) {
+ pthread_mutex_lock(&event_mutex);
+
+ if (s->changed == 0) {
+ pthread_mutex_unlock(&event_mutex);
+ TRACE("USB_RET_NAK\n");
+ }
+
+ if (event_cnt != 0) {
+ if (!QTAILQ_EMPTY(&events_queue)) {
+ TouchEventEntry *te = QTAILQ_FIRST(&events_queue);
+
+ s->dx = te->queue_packet.x;
+ s->dy = te->queue_packet.y;
+ s->dz = te->queue_packet.z;
+ s->buttons_state = te->queue_packet.state;
+
+ QTAILQ_REMOVE(&events_queue, te, node);
+ event_cnt--;
+ TRACE("processed touch event (%d) : x=%d, y=%d, z=%d, state=%d\n",
+ te->index, s->dx, s->dy, s->dz, s->buttons_state);
+
+ if (QTAILQ_EMPTY(&events_queue)) {
+ s->changed = 0;
+ TRACE("processed all touch events (%d)\n", event_cnt);
+ }
+ }
+ } else {
+ s->changed = 0;
+ }
+
+ pthread_mutex_unlock(&event_mutex);
+
+ memset(buf, 0, sizeof(buf));
+ len = usb_touchscreen_poll(s, buf, p->iov.size); //write event to packet
+ usb_packet_copy(p, buf, len);
+ break;
+ }
+ /* Fall through */
+ case USB_TOKEN_OUT:
+ default:
+ TRACE("USB_RET_STALL\n");
+ break;
+ }
+}
+
+static void usb_touchscreen_handle_destroy(USBDevice *dev)
+{
+ USBTouchscreenState *s = (USBTouchscreenState *) dev;
+
+ if (s->mouse_grabbed == 1) {
+ qemu_remove_mouse_event_handler(s->eh_entry);
+ s->mouse_grabbed = 0;
+ }
+}
+
+/**
+ * @brief : initialize a touchscreen device
+ * @param opaque : state of device
+ */
+static int usb_touchscreen_initfn(USBDevice *dev)
+{
+ USBTouchscreenState *s = DO_UPCAST(USBTouchscreenState, dev, dev);
+ usb_desc_init(dev);
+
+ pthread_mutex_lock(&event_mutex);
+ s->changed = 1;
+ pthread_mutex_unlock(&event_mutex);
+
+ return 0;
+}
+
+/**
+ * @brief : remove mouse handlers before loading
+ * @param opaque : state of device
+ */
+static int touchscreen_pre_load(void *opaque)
+{
+ USBTouchscreenState *s = (USBTouchscreenState *)opaque;
+
+ if (s->eh_entry) {
+ qemu_remove_mouse_event_handler(s->eh_entry);
+ }
+
+ return 0;
+}
+
+static int touchscreen_post_load(void *opaque, int version_id)
+{
+ USBTouchscreenState *s = (USBTouchscreenState *)opaque;
+
+ pthread_mutex_lock(&event_mutex);
+ s->changed = 1;
+ pthread_mutex_unlock(&event_mutex);
+
+ if (s->mouse_grabbed == 1) {
+ s->eh_entry = qemu_add_mouse_event_handler(usb_touchscreen_event, s, 1, "QEMU USB touchscreen");
+ qemu_activate_mouse_event_handler(s->eh_entry);
+ }
+
+ return 0;
+}
+
+static VMStateDescription vmsd_usbdevice = {
+ .name = "maru-touchscreen-usbdevice",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(addr, USBDevice),
+ VMSTATE_INT32(state, USBDevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static VMStateDescription vmsd = {
+ .name = "maru-touchscreen",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_load = touchscreen_pre_load,
+ .post_load = touchscreen_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT(dev, USBTouchscreenState, 1, vmsd_usbdevice, USBDevice),
+ VMSTATE_INT32(dx, USBTouchscreenState),
+ VMSTATE_INT32(dy, USBTouchscreenState),
+ VMSTATE_INT32(dz, USBTouchscreenState),
+ VMSTATE_INT32(buttons_state, USBTouchscreenState),
+ VMSTATE_INT8(mouse_grabbed, USBTouchscreenState),
+ VMSTATE_INT8(changed, USBTouchscreenState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void usb_touchscreen_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->handle_reset = usb_touchscreen_handle_reset;
+ uc->handle_control = usb_touchscreen_handle_control;
+ uc->handle_data = usb_touchscreen_handle_data;
+ uc->handle_destroy = usb_touchscreen_handle_destroy;
+ uc->init = usb_touchscreen_initfn;
+ uc->product_desc = "Maru USB Touchscreen";
+ uc->usb_desc = &desc_touchscreen;
+ dc->vmsd = &vmsd;
+ dc->desc = "Maru USB Touchscreen";
+}
+
+static TypeInfo touchscreen_info = {
+ .name = "usb-maru-touchscreen",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBTouchscreenState),
+ .class_init = usb_touchscreen_class_initfn,
+};
+
+/**
+ * @brief : register a touchscreen device
+ */
+static void usb_touchscreen_register_types(void)
+{
+ type_register_static(&touchscreen_info);
+ usb_legacy_register("usb-maru-touchscreen", "maru-touchscreen", NULL);
+}
+
+type_init(usb_touchscreen_register_types)
--- /dev/null
+/*
+ * Maru USB Touchscreen Device
+ * Based on hw/usb-wacom.c:
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_TOUCH_H_
+#define MARU_TOUCH_H_
+
+#include <pthread.h>
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/usb.h"
+#include "hw/usb/desc.h"
+
+
+typedef struct USBTouchscreenState {
+ USBDevice dev;
+ QEMUPutMouseEntry *eh_entry;
+
+ int32_t dx, dy, dz, buttons_state;
+ int8_t mouse_grabbed;
+ int8_t changed;
+} USBTouchscreenState;
+
+/* This structure must match the kernel definitions */
+typedef struct USBEmulTouchscreenPacket {
+ uint16_t x, y, z;
+ uint8_t state;
+} USBEmulTouchscreenPacket;
+
+
+#define EMUL_TOUCHSCREEN_PACKET_LEN 7
+#define TOUCHSCREEN_RESOLUTION_X 5040
+#define TOUCHSCREEN_RESOLUTION_Y 3780
+
+enum {
+ STR_MANUFACTURER = 1,
+ STR_PRODUCT,
+ STR_SERIALNUMBER,
+};
+
+static const USBDescStrings desc_strings = {
+ [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+ [STR_PRODUCT] = "Maru USB Touchscreen",
+ [STR_SERIALNUMBER] = "1",
+};
+
+static const USBDescIface desc_iface_touchscreen = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 0x01, /* boot */
+ .bInterfaceProtocol = 0x02,
+ .ndesc = 1,
+ .descs = (USBDescOther[]) {
+ {
+ /* HID descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ 0x21, /* u8 bDescriptorType */
+ 0x01, 0x10, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ 0x22, /* u8 type: Report */
+ 0x6e, 0, /* u16 len */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 8,
+ .bInterval = 0x0a,
+ },
+ },
+};
+
+static const USBDescDevice desc_device_touchscreen = {
+ .bcdUSB = 0x0110,
+ .bMaxPacketSize0 = EMUL_TOUCHSCREEN_PACKET_LEN + 1,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .bmAttributes = 0x80,
+ .bMaxPower = 40,
+ .nif = 1,
+ .ifs = &desc_iface_touchscreen,
+ },
+ },
+};
+
+static const USBDesc desc_touchscreen = {
+ .id = {
+ .idVendor = 0x056a,
+ .idProduct = 0x0000,
+ .bcdDevice = 0x0010,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_touchscreen,
+ .str = desc_strings,
+};
+
+typedef struct TouchEventEntry {
+ USBEmulTouchscreenPacket queue_packet;
+ int index;
+
+ /* used internally by qemu for handling mice */
+ QTAILQ_ENTRY(TouchEventEntry) node;
+} TouchEventEntry;
+
+#endif /* MARU_TOUCH_H_ */
--- /dev/null
+obj-y += maru_virtio_pci.o
+obj-y += maru_virtio_touchscreen.o
+obj-y += maru_virtio_esm.o
+obj-y += maru_virtio_evdi.o
+obj-y += maru_virtio_hwkey.o
+obj-y += maru_virtio_jack.o
+obj-y += maru_virtio_keyboard.o
+obj-y += maru_virtio_nfc.o
+obj-y += maru_virtio_power.o
+obj-y += maru_virtio_sensor.o
+obj-y += maru_virtio_vmodem.o
--- /dev/null
+/*
+ * Virtio EmulatorStatusMedium Device
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_esm.h"
+#include "skin/maruskin_server.h"
+#include "emul_state.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-esm);
+
+
+#define SYSTEM_MODE_LAYER 1
+#define USER_MODE_LAYER 0
+static uint8_t boot_complete;
+
+struct progress_info {
+ char mode;
+ uint16_t percentage;
+};
+
+static VirtQueueElement elem;
+struct progress_info progress;
+
+static void virtio_esm_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOESM *vesm = VIRTIO_ESM(vdev);
+ int index = 0;
+
+ TRACE("virtqueue handler.\n");
+ if (virtio_queue_empty(vesm->vq)) {
+ INFO("virtqueue is empty.\n");
+ return;
+ }
+
+ // Get a queue buffer.
+ index = virtqueue_pop(vq, &elem);
+ TRACE("virtqueue pop. index: %d\n", index);
+
+ TRACE("virtio element out number : %d\n", elem.out_num);
+ if (elem.out_num != 1) {
+ ERR("virtio element out number is wierd.\n");
+ }
+ else {
+ TRACE("caramis elem.out_sg[0].iov_len : %x\n", elem.out_sg[0].iov_len);
+ TRACE("caramis elem.out_sg[0].iov_base : %x\n", elem.out_sg[0].iov_base);
+ if (elem.out_sg[0].iov_len != 4) {
+ ERR("out lenth is wierd.\n");
+ }
+ else {
+ progress = *((struct progress_info*)elem.out_sg[0].iov_base);
+ TRACE("Boot up progress is [%u] percent done at %s.\n",
+ progress.percentage,
+ progress.mode == 's' || progress.mode == 'S' ? "system mode" : "user mode");
+
+ /* notify to skin */
+ if (progress.mode == 's' || progress.mode == 'S') {
+ if (progress.percentage >= 100) {
+ boot_complete |= (1 << SYSTEM_MODE_LAYER);
+ }
+
+ notify_booting_progress(SYSTEM_MODE_LAYER, progress.percentage);
+ } else {
+ if (progress.percentage >= 100) {
+ boot_complete |= (1 << USER_MODE_LAYER);
+ }
+
+ notify_booting_progress(USER_MODE_LAYER, progress.percentage);
+ }
+
+ /* booting complete check */
+ if ((boot_complete & (1 << SYSTEM_MODE_LAYER)) &&
+ (boot_complete & (1 << USER_MODE_LAYER))) {
+ set_emulator_condition(BOOT_COMPLETED);
+ }
+ }
+ }
+
+ // There is no data to copy into guest.
+ virtqueue_push(vesm->vq, &elem, 0);
+ virtio_notify(&vesm->vdev, vesm->vq);
+}
+
+static uint32_t virtio_esm_get_features(VirtIODevice *vdev, uint32_t feature)
+{
+ TRACE("virtio_esm_get_features.\n");
+ return feature;
+}
+
+static void virtio_esm_reset(VirtIODevice* vdev)
+{
+ TRACE("virtio_esm_reset.\n");
+
+ progress.mode = '\0';
+ progress.percentage = 0;
+}
+
+
+static void virtio_esm_device_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIOESM *vesm = VIRTIO_ESM(dev);
+
+ INFO("initialize virtio-esm device\n");
+ virtio_init(vdev, "virtio-esm", VIRTIO_ID_ESM, 0);
+
+ vesm->vq = virtio_add_queue(vdev, 1, virtio_esm_handle);
+
+ virtio_esm_reset(vdev);
+}
+
+static void virtio_esm_device_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ INFO("destroy device\n");
+ virtio_cleanup(vdev);
+}
+
+static void virtio_esm_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->realize = virtio_esm_device_realize;
+ vdc->unrealize = virtio_esm_device_unrealize;
+ vdc->get_features = virtio_esm_get_features;
+ // This device is no need to reset.
+ //vdc->reset = virtio_esm_reset;
+}
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_ESM,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOESM),
+ .class_init = virtio_esm_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
--- /dev/null
+/*
+ * Virtio EmulatorStatusMedium Device
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_VIRTIO_ESM_H_
+#define MARU_VIRTIO_ESM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_ESM "virtio-esm-device"
+#define VIRTIO_ESM(obj) \
+ OBJECT_CHECK(VirtIOESM, (obj), TYPE_VIRTIO_ESM)
+
+typedef struct VirtIOEmulatorStatusMedium {
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ DeviceState *qdev;
+} VirtIOESM;
+
+VirtIODevice *virtio_esm_init(DeviceState *dev);
+
+void virtio_esm_exit(VirtIODevice *vdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MARU_VIRTIO_ESM_H_ */
--- /dev/null
+/*
+ * Virtio EmulatorVirtualDeviceInterface Device
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * DaiYoung Kim <daiyoung777.kim.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <pthread.h>
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_evdi.h"
+#include "debug_ch.h"
+#include "ecs/ecs.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-evdi);
+
+#define EVDI_DEVICE_NAME "virtio-evdi"
+
+enum {
+ IOTYPE_INPUT = 0,
+ IOTYPE_OUTPUT = 1
+};
+
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+
+VirtIOEVDI* vio_evdi;
+
+//
+
+typedef struct MsgInfo
+{
+ msg_info info;
+ QTAILQ_ENTRY(MsgInfo) next;
+}MsgInfo;
+
+static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) evdi_recv_msg_queue =
+ QTAILQ_HEAD_INITIALIZER(evdi_recv_msg_queue);
+
+//
+
+typedef struct EvdiBuf {
+ VirtQueueElement elem;
+
+ QTAILQ_ENTRY(EvdiBuf) next;
+} EvdiBuf;
+
+static QTAILQ_HEAD(EvdiMsgHead , EvdiBuf) evdi_in_queue =
+ QTAILQ_HEAD_INITIALIZER(evdi_in_queue);
+
+
+static pthread_mutex_t recv_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+bool send_to_evdi(const uint32_t route, char* data, const uint32_t len)
+{
+ int size;
+ int left = len;
+ int count = 0;
+ char* readptr = data;
+
+ if(vio_evdi == NULL) {
+ ERR("EVDI is not initialized\n");
+ return false;
+ }
+
+ if (unlikely(!virtio_queue_ready(vio_evdi->rvq))) {
+ ERR("virtio queue is not ready\n");
+ return false;
+ }
+
+ while (left > 0)
+ {
+ MsgInfo* _msg = (MsgInfo*) malloc(sizeof(MsgInfo));
+ if (!_msg)
+ return false;
+
+ memset(&_msg->info, 0, sizeof(msg_info));
+
+ size = min(left, __MAX_BUF_SIZE);
+ memcpy(_msg->info.buf, readptr, size);
+ readptr += size;
+ _msg->info.use = size;
+ _msg->info.index = count;
+
+ pthread_mutex_lock(&recv_buf_mutex);
+
+ QTAILQ_INSERT_TAIL(&evdi_recv_msg_queue, _msg, next);
+
+ pthread_mutex_unlock(&recv_buf_mutex);
+
+ left -= size;
+ count ++;
+ }
+
+ qemu_bh_schedule(vio_evdi->bh);
+
+ return true;
+}
+
+
+static void flush_evdi_recv_queue(void)
+{
+ int index;
+
+ if (unlikely(!virtio_queue_ready(vio_evdi->rvq))) {
+ INFO("virtio queue is not ready\n");
+ return;
+ }
+
+ if (unlikely(virtio_queue_empty(vio_evdi->rvq))) {
+ TRACE("virtqueue is empty\n");
+ return;
+ }
+
+
+ pthread_mutex_lock(&recv_buf_mutex);
+
+ while (!QTAILQ_EMPTY(&evdi_recv_msg_queue))
+ {
+ MsgInfo* msginfo = QTAILQ_FIRST(&evdi_recv_msg_queue);
+ if (!msginfo)
+ break;
+
+ VirtQueueElement elem;
+ index = virtqueue_pop(vio_evdi->rvq, &elem);
+ if (index == 0)
+ {
+ //ERR("unexpected empty queue");
+ break;
+ }
+
+ //INFO(">> virtqueue_pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
+
+ memset(elem.in_sg[0].iov_base, 0, elem.in_sg[0].iov_len);
+ memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct msg_info));
+
+ //INFO(">> send to guest count = %d, use = %d, msg = %s, iov_len = %d \n",
+ // ++g_cnt, msginfo->info.use, msginfo->info.buf, elem.in_sg[0].iov_len);
+
+ virtqueue_push(vio_evdi->rvq, &elem, sizeof(msg_info));
+ virtio_notify(&vio_evdi->vdev, vio_evdi->rvq);
+
+ QTAILQ_REMOVE(&evdi_recv_msg_queue, msginfo, next);
+ if (msginfo)
+ free(msginfo);
+ }
+
+ pthread_mutex_unlock(&recv_buf_mutex);
+
+}
+
+
+static void virtio_evdi_recv(VirtIODevice *vdev, VirtQueue *vq)
+{
+ flush_evdi_recv_queue();
+}
+
+static void virtio_evdi_send(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOEVDI *vevdi = (VirtIOEVDI *)vdev;
+ int index = 0;
+ struct msg_info _msg;
+
+ if (virtio_queue_empty(vevdi->svq)) {
+ INFO("<< virtqueue is empty.\n");
+ return;
+ }
+
+ VirtQueueElement elem;
+
+ while ((index = virtqueue_pop(vq, &elem))) {
+
+ //INFO("<< virtqueue pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
+
+ //INFO("<< use=%d, iov_len = %d\n", _msg.use, elem.out_sg[0].iov_len);
+
+ memset(&_msg, 0x00, sizeof(_msg));
+ memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
+
+ //INFO("<< recv from guest len = %d, msg = %s \n", _msg.use, _msg.buf);
+
+ send_injector_ntf(_msg.buf, _msg.use);
+ }
+
+ virtqueue_push(vq, &elem, sizeof(VirtIOEVDI));
+ virtio_notify(&vio_evdi->vdev, vq);
+}
+
+static uint32_t virtio_evdi_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_evdi_get_features.\n");
+ return 0;
+}
+
+static void maru_evdi_bh(void *opaque)
+{
+ flush_evdi_recv_queue();
+}
+
+static void virtio_evdi_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vio_evdi = VIRTIO_EVDI(dev);
+ if (vio_evdi == NULL) {
+ ERR("failed to initialize evdi device\n");
+ return;
+ }
+
+ INFO("initialize evdi device\n");
+
+ virtio_init(vdev, TYPE_VIRTIO_EVDI, VIRTIO_ID_EVDI, 0); //EVDI_DEVICE_NAME
+
+ vio_evdi->rvq = virtio_add_queue(&vio_evdi->vdev, 256, virtio_evdi_recv);
+ vio_evdi->svq = virtio_add_queue(&vio_evdi->vdev, 256, virtio_evdi_send);
+
+ vio_evdi->bh = qemu_bh_new(maru_evdi_bh, vio_evdi);
+
+}
+
+static void virtio_evdi_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ INFO("destroy evdi device\n");
+
+ if (vio_evdi->bh) {
+ qemu_bh_delete(vio_evdi->bh);
+ }
+
+ virtio_cleanup(vdev);
+}
+
+static void virtio_evdi_reset(VirtIODevice *vdev)
+{
+ TRACE("virtio_evdi_reset.\n");
+}
+
+
+static void virtio_evdi_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->realize = virtio_evdi_realize;
+ vdc->unrealize = virtio_evdi_unrealize;
+ vdc->get_features = virtio_evdi_get_features;
+ vdc->reset = virtio_evdi_reset;
+}
+
+
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_EVDI,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOEVDI),
+ .class_init = virtio_evdi_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
--- /dev/null
+/*
+ * maru_virtio_evdi.h
+ *
+ * Created on: 2013. 3. 30.
+ * Author: dykim
+ */
+
+#ifndef MARU_VIRTIO_EVDI_H_
+#define MARU_VIRTIO_EVDI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+/* device protocol */
+
+#define __MAX_BUF_SIZE 1024
+
+enum
+{
+ route_qemu = 0,
+ route_control_server = 1,
+ route_monitor = 2,
+ route_ij = 3
+};
+
+typedef unsigned int CSCliSN;
+
+typedef struct msg_info {
+ char buf[__MAX_BUF_SIZE];
+
+ uint32_t route;
+ uint32_t use;
+ uint16_t count;
+ uint16_t index;
+
+ CSCliSN cclisn;
+}msg_info;
+
+/* device protocol */
+
+typedef struct VirtIOEVDI{
+ VirtIODevice vdev;
+ VirtQueue *rvq;
+ VirtQueue *svq;
+ DeviceState *qdev;
+
+ QEMUBH *bh;
+} VirtIOEVDI;
+
+
+
+#define TYPE_VIRTIO_EVDI "virtio-evdi-device"
+#define VIRTIO_EVDI(obj) \
+ OBJECT_CHECK(VirtIOEVDI, (obj), TYPE_VIRTIO_EVDI)
+
+//VirtIODevice *virtio_evdi_init(DeviceState *dev);
+
+//void virtio_evdi_exit(VirtIODevice *vdev);
+bool send_to_evdi(const uint32_t route, char* data, const uint32_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* MARU_VIRTIO_EVDI_H_ */
--- /dev/null
+/*
+ * Maru Virtio HW Key Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <pthread.h>
+#include "emul_state.h"
+#include "maru_virtio_hwkey.h"
+#include "hw/maru_device_ids.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, hwkey);
+
+#define DEVICE_NAME "virtio-hwkey"
+#define MAX_BUF_COUNT 64
+static int vqidx;
+/*
+ * HW key event queue
+ */
+typedef struct HwKeyEventEntry {
+ unsigned int index;
+ EmulHWKeyEvent hwkey;
+
+ QTAILQ_ENTRY(HwKeyEventEntry) node;
+} HwKeyEventEntry;
+
+/* the maximum number of HW key event that can be put into a queue */
+#define MAX_HWKEY_EVENT_CNT 64
+
+static HwKeyEventEntry _events_buf[MAX_HWKEY_EVENT_CNT];
+static QTAILQ_HEAD(, HwKeyEventEntry) events_queue =
+ QTAILQ_HEAD_INITIALIZER(events_queue);
+
+static unsigned int event_ringbuf_cnt; /* _events_buf */
+static unsigned int event_queue_cnt; /* events_queue */
+
+/*
+ * VirtQueueElement queue
+ */
+typedef struct ElementEntry {
+ unsigned int el_index;
+ unsigned int sg_index;
+ VirtQueueElement elem;
+
+ QTAILQ_ENTRY(ElementEntry) node;
+} ElementEntry;
+
+static QTAILQ_HEAD(, ElementEntry) elem_queue =
+ QTAILQ_HEAD_INITIALIZER(elem_queue);
+
+static unsigned int elem_ringbuf_cnt; /* _elem_buf */
+static unsigned int elem_queue_cnt; /* elem_queue */
+
+VirtIOHWKey *vhk;
+VirtQueueElement elem_vhk;
+
+/* lock for between communication thread and IO thread */
+static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void maru_hwkey_event(int event_type, int keycode)
+{
+ HwKeyEventEntry *entry = NULL;
+
+ if (!vhk) {
+ INFO("Hwkey device can not be used.\n");
+ return;
+ }
+
+ if (unlikely(event_queue_cnt >= MAX_HWKEY_EVENT_CNT)) {
+ INFO("full hwkey event queue, lose event\n", event_queue_cnt);
+
+ qemu_bh_schedule(vhk->bh);
+ return;
+ }
+
+ entry = &(_events_buf[event_ringbuf_cnt % MAX_HWKEY_EVENT_CNT]);
+
+ /* hwkey event is copied into the queue */
+ entry->hwkey.keycode = keycode;
+ entry->hwkey.event_type = event_type;
+
+ pthread_mutex_lock(&event_mutex);
+
+ event_ringbuf_cnt++;
+
+ /* 1 ~ */
+ entry->index = ++event_queue_cnt;
+
+ QTAILQ_INSERT_TAIL(&events_queue, entry, node);
+
+ pthread_mutex_unlock(&event_mutex);
+
+ /* call maru_virtio_hwkey_notify */
+ qemu_bh_schedule(vhk->bh);
+
+ TRACE("hwkey event (%d) : keycode=%d, event_type=%d\n",
+ entry->index, entry->hwkey.keycode, entry->hwkey.event_type);
+}
+
+static void maru_virtio_hwkey_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+ int virt_sg_index = 0;
+
+ TRACE("maru_virtio_hwkey_handle\n");
+
+ if (unlikely(virtio_queue_empty(vhk->vq))) {
+ TRACE("virtqueue is empty\n");
+ return;
+ }
+ /* Get a queue buffer which is written by guest side. */
+ do {
+ virt_sg_index = virtqueue_pop(vq, &elem_vhk);
+ TRACE("virtqueue pop.\n");
+ } while (virt_sg_index < MAX_BUF_COUNT);
+}
+
+void maru_virtio_hwkey_notify(void)
+{
+ HwKeyEventEntry *event_entry = NULL;
+
+ TRACE("maru_virtio_hwkey_notify\n");
+
+ if (unlikely(!virtio_queue_ready(vhk->vq))) {
+ ERR("virtio queue is not ready\n");
+ return;
+ }
+
+ while (true) {
+ if (event_queue_cnt == 0) {
+ TRACE("no event\n");
+ break;
+ }
+
+ /* get hwkey event from host queue */
+ event_entry = QTAILQ_FIRST(&events_queue);
+
+ printf("keycode=%d, event_type=%d, event_queue_cnt=%d, vqidx=%d\n",
+ event_entry->hwkey.keycode, event_entry->hwkey.event_type,
+ event_queue_cnt, vqidx);
+
+ /* copy event into virtio buffer */
+ memcpy(elem_vhk.in_sg[vqidx++].iov_base, &(event_entry->hwkey),
+ sizeof(EmulHWKeyEvent));
+ if (vqidx == MAX_BUF_COUNT) {
+ vqidx = 0;
+ }
+
+ virtqueue_push(vhk->vq, &elem_vhk, sizeof(EmulHWKeyEvent));
+ virtio_notify(&vhk->vdev, vhk->vq);
+
+ pthread_mutex_lock(&event_mutex);
+
+ /* remove host event */
+ QTAILQ_REMOVE(&events_queue, event_entry, node);
+ event_queue_cnt--;
+
+ pthread_mutex_unlock(&event_mutex);
+ }
+}
+
+static uint32_t virtio_hwkey_get_features(
+ VirtIODevice *vdev, uint32_t request_features)
+{
+ return request_features;
+}
+
+static void maru_hwkey_bh(void *opaque)
+{
+ maru_virtio_hwkey_notify();
+}
+
+static void virtio_hwkey_device_realize(DeviceState *dev, Error **errp)
+{
+ INFO("initialize the hwkey device\n");
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vhk = VIRTIO_HWKEY(dev);
+
+ if (vdev == NULL) {
+ ERR("failed to initialize the hwkey device\n");
+ return;
+ }
+
+ virtio_init(vdev, TYPE_VIRTIO_HWKEY, VIRTIO_ID_HWKEY, 0);
+
+ vhk->vq = virtio_add_queue(vdev, MAX_BUF_COUNT, maru_virtio_hwkey_handle);
+
+ vhk->qdev = dev;
+
+ /* reset the counters */
+ pthread_mutex_lock(&event_mutex);
+ event_queue_cnt = event_ringbuf_cnt = 0;
+ pthread_mutex_unlock(&event_mutex);
+
+ elem_queue_cnt = elem_ringbuf_cnt = 0;
+
+ /* bottom-half */
+ vhk->bh = qemu_bh_new(maru_hwkey_bh, vhk);
+}
+
+static void virtio_hwkey_device_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ INFO("exit the hwkey device\n");
+
+ if (vhk->bh) {
+ qemu_bh_delete(vhk->bh);
+ }
+
+ virtio_cleanup(vdev);
+
+ pthread_mutex_destroy(&event_mutex);
+}
+
+static void virtio_hwkey_device_reset(VirtIODevice *vdev)
+{
+ INFO("reset hwkey device\n");
+ vqidx = 0;
+}
+
+static void virtio_hwkey_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->unrealize = virtio_hwkey_device_unrealize;
+ vdc->realize = virtio_hwkey_device_realize;
+ vdc->reset = virtio_hwkey_device_reset;
+ vdc->get_features = virtio_hwkey_get_features;
+}
+
+static const TypeInfo virtio_hwkey_info = {
+ .name = TYPE_VIRTIO_HWKEY,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOHWKey),
+ .class_init = virtio_hwkey_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_hwkey_info);
+}
+
+type_init(virtio_register_types)
+
--- /dev/null
+/*
+ * Maru Virtio HW Key Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_HWKEY_H_
+#define MARU_HWKEY_H_
+
+#include "ui/console.h"
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_HWKEY "virtio-hwkey-device"
+#define VIRTIO_HWKEY(obj) \
+ OBJECT_CHECK(VirtIOHWKey, (obj), TYPE_VIRTIO_HWKEY)
+
+
+typedef struct VirtIOHWKey
+{
+ VirtIODevice vdev;
+ /* simply a queue into which buffers are posted
+ by the guest for consumption by the host */
+ VirtQueue *vq;
+
+ QEMUBH *bh;
+ DeviceState *qdev;
+} VirtIOHWKey;
+
+/* This structure must match the kernel definitions */
+typedef struct EmulHWKeyEvent {
+ uint8_t event_type;
+ uint32_t keycode;
+} EmulHWKeyEvent;
+
+
+VirtIODevice *maru_virtio_hwkey_init(DeviceState *dev);
+void maru_virtio_hwkey_exit(VirtIODevice *vdev);
+
+void maru_hwkey_event(int event_type, int keycode);
+void maru_virtio_hwkey_notify(void);
+
+#endif /* MARU_HWKEY_H_ */
--- /dev/null
+/*
+ * Virtio Jack Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung Choi <jinhyung2.choi@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <pthread.h>
+
+#include "hw/pci/pci.h"
+
+#include "hw/maru_device_ids.h"
+#include "debug_ch.h"
+
+#include "maru_virtio_jack.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-jack);
+
+#define JACK_DEVICE_NAME "jack"
+#define _MAX_BUF 1024
+#define __MAX_BUF_JACK 32
+
+static int charger_online = 0;
+static int earjack_online = 0;
+static int earkey_online = 0;
+static int hdmi_online = 0;
+static int usb_online = 0;
+
+VirtIOJACK* vjack;
+static int jack_capability = 0;
+
+typedef struct msg_info {
+ char buf[_MAX_BUF];
+
+ uint16_t type;
+ uint16_t req;
+} msg_info;
+
+enum request_cmd {
+ request_get = 0,
+ request_set,
+ request_answer
+};
+
+void set_jack_charger(int online){
+ charger_online = online;
+}
+
+int get_jack_charger(void) {
+ return charger_online;
+}
+
+void set_jack_usb(int online){
+ usb_online = online;
+}
+
+int get_jack_usb(void) {
+ return usb_online;
+}
+
+static void set_jack_data (enum jack_types type, char* data, int len)
+{
+ if (len < 0 || len > __MAX_BUF_JACK) {
+ ERR("jack data size is wrong.\n");
+ return;
+ }
+
+ if (data == NULL) {
+ ERR("jack data is NULL.\n");
+ return;
+ }
+
+ switch (type) {
+ case jack_type_charger:
+ sscanf(data, "%d", &charger_online);
+ break;
+ case jack_type_earjack:
+ sscanf(data, "%d", &earjack_online);
+ break;
+ case jack_type_earkey:
+ sscanf(data, "%d", &earkey_online);
+ break;
+ case jack_type_hdmi:
+ sscanf(data, "%d", &hdmi_online);
+ break;
+ case jack_type_usb:
+ sscanf(data, "%d", &usb_online);
+ break;
+ default:
+ return;
+ }
+}
+
+static void get_jack_data(enum jack_types type, char* msg_info)
+{
+ if (msg_info == NULL) {
+ return;
+ }
+
+ switch (type) {
+ case jack_type_list:
+ sprintf(msg_info, "%d", jack_capability);
+ break;
+ case jack_type_charger:
+ sprintf(msg_info, "%d", charger_online);
+ break;
+ case jack_type_earjack:
+ sprintf(msg_info, "%d", earjack_online);
+ break;
+ case jack_type_earkey:
+ sprintf(msg_info, "%d", earkey_online);
+ break;
+ case jack_type_hdmi:
+ sprintf(msg_info, "%d", hdmi_online);
+ break;
+ case jack_type_usb:
+ sprintf(msg_info, "%d", usb_online);
+ break;
+ default:
+ return;
+ }
+}
+
+static void answer_jack_data_request(int type, char* data, VirtQueueElement *elem)
+{
+ msg_info* msginfo = (msg_info*) malloc(sizeof(msg_info));
+ if (!msginfo) {
+ ERR("msginfo is NULL!\n");
+ return;
+ }
+
+ msginfo->req = request_answer;
+ msginfo->type = type;
+ get_jack_data(type, msginfo->buf);
+
+ TRACE("sending message: %s, type: %d, req: %d\n", msginfo->buf, msginfo->type, msginfo->req);
+
+ memset(elem->in_sg[0].iov_base, 0, elem->in_sg[0].iov_len);
+ memcpy(elem->in_sg[0].iov_base, msginfo, sizeof(struct msg_info));
+
+ if (msginfo)
+ free(msginfo);
+}
+
+static void handle_msg(struct msg_info *msg, VirtQueueElement *elem)
+{
+ unsigned int len = 0;
+
+ if (msg == NULL) {
+ ERR("msg info structure is NULL.\n");
+ return;
+ }
+
+ if (msg->req == request_set) {
+ set_jack_data (msg->type, msg->buf, strlen(msg->buf));
+ } else if (msg->req == request_get) {
+ answer_jack_data_request(msg->type, msg->buf, elem);
+ len = sizeof(msg_info);
+ }
+
+ virtqueue_push(vjack->vq, elem, len);
+ virtio_notify(&vjack->vdev, vjack->vq);
+}
+
+static void virtio_jack_vq(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOJACK *vjack = (VirtIOJACK*)vdev;
+ struct msg_info msg;
+ VirtQueueElement elem;
+ int index = 0;
+
+ if (vjack->vq == NULL) {
+ ERR("virt queue is not ready.\n");
+ return;
+ }
+
+ if (!virtio_queue_ready(vjack->vq)) {
+ ERR("virtqueue is not ready.");
+ return;
+ }
+
+ if (virtio_queue_empty(vjack->vq)) {
+ ERR("<< virtqueue is empty.\n");
+ return;
+ }
+
+ while ((index = virtqueue_pop(vq, &elem))) {
+ memset(&msg, 0x00, sizeof(msg));
+ memcpy(&msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
+
+ TRACE("handling msg from driver: %s, len: %d, type: %d, req: %d, index: %d\n", msg.buf, strlen(msg.buf), msg.type, msg.req, index);
+
+ handle_msg(&msg, &elem);
+ }
+}
+
+static int set_capability(char* jack)
+{
+ if (!strncmp(jack, JACK_NAME_CHARGER, 7)) {
+ return jack_cap_charger;
+ } else if (!strncmp(jack, JACK_NAME_EARJACK, 7)) {
+ return jack_cap_earjack;
+ } else if (!strncmp(jack, JACK_NAME_EARKEY, 6)) {
+ return jack_cap_earkey;
+ } else if (!strncmp(jack, JACK_NAME_HDMI, 4)) {
+ return jack_cap_hdmi;
+ } else if (!strncmp(jack, JACK_NAME_USB, 3)) {
+ return jack_cap_usb;
+ }
+
+ return 0;
+}
+
+static void parse_jack_capability(char* lists)
+{
+ char token[] = JACK_CAP_TOKEN;
+ char* data = NULL;
+
+ if (lists == NULL)
+ return;
+
+ data = strtok(lists, token);
+ if (data != NULL) {
+ jack_capability |= set_capability(data);
+ while ((data = strtok(NULL, token)) != NULL) {
+ jack_capability |= set_capability(data);
+ }
+ }
+
+ INFO("jack device capabilty enabled with %02x\n", jack_capability);
+}
+
+static void virtio_jack_realize(DeviceState *dev, Error **errp)
+{
+ INFO("initialize virtio-jack device\n");
+
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vjack = VIRTIO_JACK(vdev);
+
+ virtio_init(vdev, JACK_DEVICE_NAME, VIRTIO_ID_JACK, 0);
+
+ if (vjack == NULL) {
+ ERR("failed to initialize jack device\n");
+ return;
+ }
+
+ vjack->vq = virtio_add_queue(&vjack->vdev, 64, virtio_jack_vq);
+
+ INFO("initialized jack type: %s\n", vjack->jacks);
+
+ if (vjack->jacks) {
+ parse_jack_capability(vjack->jacks);
+ }
+}
+
+static void virtio_jack_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ INFO("destroy jack device\n");
+
+ virtio_cleanup(vdev);
+}
+
+
+static void virtio_jack_reset(VirtIODevice *vdev)
+{
+ TRACE("virtio_jack_reset.\n");
+}
+
+static uint32_t virtio_jack_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_jack_get_features.\n");
+ return 0;
+}
+
+static Property virtio_jack_properties[] = {
+ DEFINE_PROP_STRING(ATTRIBUTE_NAME_JACKS, VirtIOJACK, jacks),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_jack_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ dc->props = virtio_jack_properties;
+ vdc->realize = virtio_jack_realize;
+ vdc->unrealize = virtio_jack_unrealize;
+ vdc->get_features = virtio_jack_get_features;
+ vdc->reset = virtio_jack_reset;
+}
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_JACK,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOJACK),
+ .class_init = virtio_jack_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
+
--- /dev/null
+/*
+ * Virtio Jack Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_VIRTIO_JACK_H_
+#define MARU_VIRTIO_JACK_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_JACK "virtio-jack-device"
+#define VIRTIO_JACK(obj) \
+ OBJECT_CHECK(VirtIOJACK, (obj), TYPE_VIRTIO_JACK)
+
+enum jack_types {
+ jack_type_list = 0,
+ jack_type_charger,
+ jack_type_earjack,
+ jack_type_earkey,
+ jack_type_hdmi,
+ jack_type_usb,
+ jack_type_max
+};
+
+enum jack_capabilities {
+ jack_cap_charger = 0x01,
+ jack_cap_earjack = 0x02,
+ jack_cap_earkey = 0x04,
+ jack_cap_hdmi = 0x08,
+ jack_cap_usb = 0x10
+};
+
+typedef struct VirtIOJACK {
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ DeviceState *qdev;
+
+ char *jacks;
+} VirtIOJACK;
+
+#define ATTRIBUTE_NAME_JACKS "jacks"
+
+#define JACK_NAME_CHARGER "charger"
+#define JACK_NAME_EARJACK "earjack"
+#define JACK_NAME_EARKEY "earkey"
+#define JACK_NAME_HDMI "hdmi"
+#define JACK_NAME_USB "usb"
+
+#define JACK_CAP_TOKEN "&"
+
+void set_jack_charger(int online);
+int get_jack_charger(void);
+
+void set_jack_usb(int online);
+int get_jack_usb(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Virtio Keyboard Device
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_keyboard.h"
+#include "debug_ch.h"
+
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-kbd);
+
+VirtIOKeyboard *vkbd;
+VirtQueueElement elem;
+
+static void virtio_keyboard_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
+ int index = 0;
+
+ if (virtio_queue_empty(vkbd->vq)) {
+ INFO("virtqueue is empty.\n");
+ return;
+ }
+
+ /* Get a queue buffer which is written by guest side. */
+ do {
+ index = virtqueue_pop(vq, &elem);
+ TRACE("virtqueue pop.\n");
+ } while (index < VIRTIO_KBD_QUEUE_SIZE);
+}
+
+void virtio_keyboard_notify(void *opaque)
+{
+ VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
+ EmulKbdEvent *kbdevt;
+ int written_cnt = 0;
+
+ if (!vkbd) {
+ ERR("VirtIOKeyboard is NULL.\n");
+ return;
+ }
+
+ TRACE("[Enter] virtqueue notifier.\n");
+
+ if (!virtio_queue_ready(vkbd->vq)) {
+ INFO("virtqueue is not ready.\n");
+ return;
+ }
+
+ if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
+ vkbd->kbdqueue.rptr = 0;
+ }
+
+ qemu_mutex_lock(&vkbd->event_mutex);
+ written_cnt = vkbd->kbdqueue.wptr;
+
+ while ((written_cnt--)) {
+ kbdevt = &vkbd->kbdqueue.kbdevent[vkbd->kbdqueue.rptr];
+
+ if (((EmulKbdEvent*)(elem.in_sg[vkbd->kbdqueue.rptr].iov_base))->code != 0) {
+ TRACE("FIXME: virtio queue is full.\n");
+ }
+
+ /* Copy keyboard data into guest side. */
+ TRACE("copy: keycode %d, type %d, elem_index %d\n",
+ kbdevt->code, kbdevt->type, vkbd->kbdqueue.rptr);
+ memcpy(elem.in_sg[vkbd->kbdqueue.rptr].iov_base, kbdevt, sizeof(EmulKbdEvent));
+ memset(kbdevt, 0x00, sizeof(EmulKbdEvent));
+
+ if (vkbd->kbdqueue.wptr > 0) {
+ vkbd->kbdqueue.wptr--;
+ TRACE("written_cnt: %d, wptr: %d, qemu_index: %d\n",
+ written_cnt, vkbd->kbdqueue.wptr, vkbd->kbdqueue.rptr);
+ }
+
+ vkbd->kbdqueue.rptr++;
+ if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
+ vkbd->kbdqueue.rptr = 0;
+ }
+ }
+ qemu_mutex_unlock(&vkbd->event_mutex);
+
+ virtqueue_push(vkbd->vq, &elem, sizeof(EmulKbdEvent));
+ virtio_notify(&vkbd->vdev, vkbd->vq);
+
+ TRACE("[Leave] virtqueue notifier.\n");
+}
+
+void virtio_keyboard_event(int keycode)
+{
+ EmulKbdEvent kbdevt = {0};
+ int *index = NULL;
+
+ if (!vkbd) {
+ ERR("VirtIOKeyboard is NULL.\n");
+ return;
+ }
+
+ if (!virtio_queue_ready(vkbd->vq)) {
+ INFO("virtqueue is not ready.\n");
+ return;
+ }
+
+ index = &(vkbd->kbdqueue.index);
+ TRACE("[Enter] input_event handler. cnt %d\n", vkbd->kbdqueue.wptr);
+
+ if (*index < 0) {
+ ERR("keyboard queue is overflow.\n");
+ return;
+ }
+
+ if (*index == VIRTIO_KBD_QUEUE_SIZE) {
+ *index = 0;
+ }
+
+ if (keycode < 0xe0) {
+ if (vkbd->extension_key) {
+ switch (keycode & 0x7f) {
+ case 28: /* KP_Enter */
+ kbdevt.code = 96;
+ break;
+ case 29: /* Right Ctrl */
+ kbdevt.code = 97;
+ break;
+ case 56: /* Right Alt */
+ kbdevt.code = 100;
+ break;
+ case 71: /* Home */
+ kbdevt.code = 102;
+ break;
+ case 72: /* Up */
+ kbdevt.code = 103;
+ break;
+ case 73: /* Page Up */
+ kbdevt.code = 104;
+ break;
+ case 75: /* Left */
+ kbdevt.code = 105;
+ break;
+ case 77: /* Right */
+ kbdevt.code = 106;
+ break;
+ case 79: /* End */
+ kbdevt.code = 107;
+ break;
+ case 80: /* Down */
+ kbdevt.code = 108;
+ break;
+ case 81: /* Page Down */
+ kbdevt.code = 109;
+ break;
+ case 82: /* Insert */
+ kbdevt.code = 110;
+ break;
+ case 83: /* Delete */
+ kbdevt.code = 111;
+ break;
+ default:
+ WARN("There is no keymap for this keycode %d.\n", keycode);
+ }
+ vkbd->extension_key = 0;
+ } else {
+ kbdevt.code = keycode & 0x7f;
+ }
+
+ if (!(keycode & 0x80)) {
+ kbdevt.type = 1; /* KEY_PRESSED */
+ } else {
+ kbdevt.type = 0; /* KEY_RELEASED */
+ }
+ } else {
+ TRACE("Extension key.\n");
+ kbdevt.code = keycode;
+ vkbd->extension_key = 1;
+ }
+
+ qemu_mutex_lock(&vkbd->event_mutex);
+ memcpy(&vkbd->kbdqueue.kbdevent[(*index)++], &kbdevt, sizeof(kbdevt));
+ TRACE("event: keycode %d, type %d, index %d.\n",
+ kbdevt.code, kbdevt.type, ((*index) - 1));
+
+ vkbd->kbdqueue.wptr++;
+ qemu_mutex_unlock(&vkbd->event_mutex);
+
+ TRACE("[Leave] input_event handler. cnt:%d\n", vkbd->kbdqueue.wptr);
+
+ qemu_bh_schedule(vkbd->bh);
+}
+
+static uint32_t virtio_keyboard_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_keyboard_get_features.\n");
+ return 0;
+}
+
+static void virtio_keyboard_bh(void *opaque)
+{
+ virtio_keyboard_notify(opaque);
+}
+
+static void virtio_keyboard_device_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vkbd = VIRTIO_KEYBOARD(vdev);
+
+ INFO("initialize virtio-keyboard device\n");
+
+ if (vdev == NULL) {
+ ERR("failed to initialize virtio-keyboard device\n");
+ return;
+ }
+
+ virtio_init(vdev, TYPE_VIRTIO_KEYBOARD, VIRTIO_ID_KEYBOARD, 0);
+
+ memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
+ vkbd->extension_key = 0;
+ qemu_mutex_init(&vkbd->event_mutex);
+
+ vkbd->vq = virtio_add_queue(vdev, 128, virtio_keyboard_handle);
+ vkbd->qdev = dev;
+
+ /* bottom half */
+ vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
+}
+
+static void virtio_keyboard_device_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
+
+ INFO("destroy device\n");
+
+ if (vkbd->bh) {
+ qemu_bh_delete(vkbd->bh);
+ }
+
+ qemu_mutex_destroy(&vkbd->event_mutex);
+
+ virtio_cleanup(vdev);
+}
+
+static void virtio_keyboard_device_reset(VirtIODevice *vdev)
+{
+ vkbd = VIRTIO_KEYBOARD(vdev);
+
+ INFO("reset keyboard device\n");
+ vkbd->kbdqueue.rptr = 0;
+ vkbd->kbdqueue.index = 0;
+}
+
+static void virtio_keyboard_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->unrealize = virtio_keyboard_device_unrealize;
+ vdc->realize = virtio_keyboard_device_realize;
+ vdc->reset = virtio_keyboard_device_reset;
+ vdc->get_features = virtio_keyboard_get_features;
+}
+
+static const TypeInfo virtio_keyboard_info = {
+ .name = TYPE_VIRTIO_KEYBOARD,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOKeyboard),
+ .class_init = virtio_keyboard_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_keyboard_info);
+}
+
+type_init(virtio_register_types)
+
--- /dev/null
+/*
+ * Virtio Keyboard Device
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef VIRTIO_KEYBOARD_H_
+#define VIRTIO_KEYBOARD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "qemu/thread.h"
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_KEYBOARD "virtio-keyboard-device"
+#define VIRTIO_KEYBOARD(obj) \
+ OBJECT_CHECK(VirtIOKeyboard, (obj), TYPE_VIRTIO_KEYBOARD)
+#define VIRTIO_KBD_QUEUE_SIZE 100
+
+typedef struct EmulKbdEvent {
+ uint16_t code;
+ uint16_t type;
+} EmulKbdEvent;
+
+typedef struct VirtIOKbdQueue {
+ EmulKbdEvent kbdevent[VIRTIO_KBD_QUEUE_SIZE];
+ int index;
+ int rptr, wptr;
+} VirtIOKbdQueue;
+
+typedef struct VirtIOKeyboard {
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ DeviceState *qdev;
+ uint16_t extension_key;
+
+ VirtIOKbdQueue kbdqueue;
+ QemuMutex event_mutex;
+ QEMUBH *bh;
+} VirtIOKeyboard;
+
+VirtIODevice *virtio_keyboard_init(DeviceState *dev);
+void virtio_keyboard_exit(VirtIODevice *vdev);
+
+void virtio_keyboard_event(int keycode);
+void virtio_keyboard_notify(void *opaque);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VIRTIO_KEYBOARD_H_ */
--- /dev/null
+/*
+ * Virtio NFC Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Munkyu Im <munkyu.im@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <pthread.h>
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_nfc.h"
+#include "debug_ch.h"
+#include "ecs/ecs.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-nfc);
+
+#define NFC_DEVICE_NAME "virtio-nfc"
+
+enum {
+ IOTYPE_INPUT = 0,
+ IOTYPE_OUTPUT = 1
+};
+
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+VirtIONFC* vio_nfc;
+
+typedef struct MsgInfo
+{
+ nfc_msg_info info;
+ QTAILQ_ENTRY(MsgInfo) next;
+}MsgInfo;
+
+static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) nfc_recv_msg_queue =
+QTAILQ_HEAD_INITIALIZER(nfc_recv_msg_queue);
+
+typedef struct NFCBuf {
+ VirtQueueElement elem;
+ QTAILQ_ENTRY(NFCBuf) next;
+} NFCBuf;
+
+static pthread_mutex_t recv_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+bool send_to_nfc(unsigned char id, unsigned char type, const char* data, const uint32_t len)
+{
+ if(vio_nfc == NULL) {
+ ERR("NFC is not initialized\n");
+ return false;
+ }
+
+ if (unlikely(!virtio_queue_ready(vio_nfc->rvq))) {
+ ERR("virtio queue is not ready\n");
+ return false;
+ }
+
+ MsgInfo* _msg = (MsgInfo*) malloc(sizeof(MsgInfo));
+ if (!_msg) {
+ return false;
+ }
+
+ if(len > NFC_MAX_BUF_SIZE) {
+ ERR("the length of data is longer than max buffer size");
+ free(_msg);
+ return false;
+ }
+
+ memset(&_msg->info, 0, sizeof(nfc_msg_info));
+
+ memcpy(_msg->info.buf, data, len);
+ _msg->info.use = len;
+ _msg->info.client_id = id;
+ _msg->info.client_type = type;
+
+ pthread_mutex_lock(&recv_buf_mutex);
+
+ QTAILQ_INSERT_TAIL(&nfc_recv_msg_queue, _msg, next);
+
+ pthread_mutex_unlock(&recv_buf_mutex);
+
+ qemu_bh_schedule(vio_nfc->bh);
+
+ return true;
+}
+
+static void flush_nfc_recv_queue(void)
+{
+ int index;
+
+ if (unlikely(!virtio_queue_ready(vio_nfc->rvq))) {
+ INFO("virtio queue is not ready\n");
+ return;
+ }
+
+ if (unlikely(virtio_queue_empty(vio_nfc->rvq))) {
+ TRACE("virtqueue is empty\n");
+ return;
+ }
+
+
+ pthread_mutex_lock(&recv_buf_mutex);
+
+ while (!QTAILQ_EMPTY(&nfc_recv_msg_queue))
+ {
+ MsgInfo* msginfo = QTAILQ_FIRST(&nfc_recv_msg_queue);
+ if (!msginfo) {
+ break;
+ }
+
+ VirtQueueElement elem;
+ index = virtqueue_pop(vio_nfc->rvq, &elem);
+ if (index == 0)
+ {
+ //ERR("unexpected empty queue");
+ break;
+ }
+
+ INFO(">> virtqueue_pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
+
+ memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct nfc_msg_info));
+
+ INFO(">> send to guest use = %d, msg = %s, iov_len = %d \n",
+ msginfo->info.use, msginfo->info.buf, elem.in_sg[0].iov_len);
+
+ virtqueue_push(vio_nfc->rvq, &elem, sizeof(nfc_msg_info));
+ virtio_notify(&vio_nfc->vdev, vio_nfc->rvq);
+
+ QTAILQ_REMOVE(&nfc_recv_msg_queue, msginfo, next);
+ if (msginfo)
+ free(msginfo);
+ }
+
+ pthread_mutex_unlock(&recv_buf_mutex);
+
+}
+
+
+static void virtio_nfc_recv(VirtIODevice *vdev, VirtQueue *vq)
+{
+ flush_nfc_recv_queue();
+}
+
+static void virtio_nfc_send(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIONFC *vnfc = (VirtIONFC *)vdev;
+ int index = 0;
+ struct nfc_msg_info _msg;
+
+ if (virtio_queue_empty(vnfc->svq)) {
+ INFO("<< virtqueue is empty.\n");
+ return;
+ }
+
+ VirtQueueElement elem;
+
+ while ((index = virtqueue_pop(vq, &elem))) {
+
+ INFO("<< virtqueue pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
+
+ INFO("<< iov_len = %d\n", elem.out_sg[0].iov_len);
+
+ memset(&_msg, 0x00, sizeof(_msg));
+ memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
+
+ INFO("<< recv from guest len = %d, msg = %s \n", _msg.use, _msg.buf);
+ send_nfc_ntf(&_msg);
+
+ }
+
+ virtqueue_push(vq, &elem, sizeof(VirtIONFC));
+ virtio_notify(&vio_nfc->vdev, vq);
+}
+
+static uint32_t virtio_nfc_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_nfc_get_features.\n");
+ return 0;
+}
+
+static void maru_nfc_bh(void *opaque)
+{
+ flush_nfc_recv_queue();
+}
+
+static void virtio_nfc_realize(DeviceState* dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vio_nfc = VIRTIO_NFC(vdev);
+ if (vio_nfc == NULL) {
+ ERR("failed to initialize nfc device\n");
+ return;
+ }
+
+ INFO("initialize nfc device\n");
+
+ virtio_init(vdev, NFC_DEVICE_NAME, VIRTIO_ID_NFC, 0);
+
+ vio_nfc->rvq = virtio_add_queue(&vio_nfc->vdev, 256, virtio_nfc_recv);
+ vio_nfc->svq = virtio_add_queue(&vio_nfc->vdev, 256, virtio_nfc_send);
+
+ vio_nfc->bh = qemu_bh_new(maru_nfc_bh, vio_nfc);
+}
+
+static void virtio_nfc_unrealize(DeviceState* dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ INFO("destroy nfc device\n");
+
+ if (vio_nfc->bh) {
+ qemu_bh_delete(vio_nfc->bh);
+ }
+
+ virtio_cleanup(vdev);
+}
+
+static void virtio_nfc_reset(VirtIODevice *vdev)
+{
+ TRACE("virtio_sensor_reset.\n");
+}
+
+
+static void virtio_nfc_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->realize = virtio_nfc_realize;
+ vdc->unrealize = virtio_nfc_unrealize;
+ vdc->get_features = virtio_nfc_get_features;
+ vdc->reset = virtio_nfc_reset;
+}
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_NFC,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIONFC),
+ .class_init = virtio_nfc_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
+
--- /dev/null
+/*\r
+ * Virtio NFC Device\r
+ *\r
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Contact:\r
+ * Munkyu Im <munkyu.im@samsung.com>\r
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+#ifndef MARU_VIRTIO_NFC_H_\r
+#define MARU_VIRTIO_NFC_H_\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#include "hw/virtio/virtio.h"\r
+\r
+enum request_cmd_nfc {\r
+ request_nfc_get = 0,\r
+ request_nfc_set,\r
+ request_nfc_answer\r
+};\r
+\r
+\r
+/* device protocol */\r
+\r
+#define __MAX_BUF_SIZE 1024\r
+\r
+\r
+typedef struct VirtIONFC{\r
+ VirtIODevice vdev;\r
+ VirtQueue *rvq;\r
+ VirtQueue *svq;\r
+ DeviceState *qdev;\r
+\r
+ QEMUBH *bh;\r
+} VirtIONFC;\r
+\r
+\r
+#define TYPE_VIRTIO_NFC "virtio-nfc-device"\r
+#define VIRTIO_NFC(obj) \\r
+ OBJECT_CHECK(VirtIONFC, (obj), TYPE_VIRTIO_NFC)\r
+\r
+\r
+bool send_to_nfc(unsigned char id, unsigned char type, const char* data, const uint32_t len);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+\r
+#endif /* MARU_VIRTIO_NFC_H_ */\r
--- /dev/null
+/*
+ * Maru virtio pci
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ * refer to hw/virtio/virtio-pci.c
+ */
+
+#include "hw/virtio/virtio-pci.h"
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_evdi.h"
+#include "maru_virtio_esm.h"
+#include "maru_virtio_hwkey.h"
+#include "maru_virtio_keyboard.h"
+#include "maru_virtio_touchscreen.h"
+#include "maru_virtio_sensor.h"
+#include "maru_virtio_jack.h"
+#include "maru_virtio_power.h"
+#include "maru_virtio_nfc.h"
+#include "maru_virtio_vmodem.h"
+
+typedef struct VirtIOTouchscreenPCI VirtIOTouchscreenPCI;
+typedef struct VirtIOEVDIPCI VirtIOEVDIPCI;
+typedef struct VirtIOESMPCI VirtIOESMPCI;
+typedef struct VirtIOHWKeyPCI VirtIOHWKeyPCI;
+typedef struct VirtIOKeyboardPCI VirtIOKeyboardPCI;
+typedef struct VirtIOSENSORPCI VirtIOSENSORPCI;
+typedef struct VirtIONFCPCI VirtIONFCPCI;
+typedef struct VirtIOPOWERPCI VirtIOPOWERPCI;
+typedef struct VirtIOJACKPCI VirtIOJACKPCI;
+typedef struct VirtIOVModemPCI VirtIOVModemPCI;
+
+/*
+ * virtio-touchscreen-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_TOUCHSCREEN_PCI "virtio-touchscreen-pci"
+#define VIRTIO_TOUCHSCREEN_PCI(obj) \
+ OBJECT_CHECK(VirtIOTouchscreenPCI, (obj), TYPE_VIRTIO_TOUCHSCREEN_PCI)
+
+struct VirtIOTouchscreenPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOTouchscreen vdev;
+};
+
+/*
+ * virtio-keyboard-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
+#define VIRTIO_KEYBOARD_PCI(obj) \
+ OBJECT_CHECK(VirtIOKeyboardPCI, (obj), TYPE_VIRTIO_KEYBOARD_PCI)
+
+struct VirtIOKeyboardPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOKeyboard vdev;
+};
+
+/*
+ * virtio-evdi-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_EVDI_PCI "virtio-evdi-pci"
+#define VIRTIO_EVDI_PCI(obj) \
+ OBJECT_CHECK(VirtIOEVDIPCI, (obj), TYPE_VIRTIO_EVDI_PCI)
+
+struct VirtIOEVDIPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOEVDI vdev;
+};
+
+/*
+ * virtio-esm-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_ESM_PCI "virtio-esm-pci"
+#define VIRTIO_ESM_PCI(obj) \
+ OBJECT_CHECK(VirtIOESMPCI, (obj), TYPE_VIRTIO_ESM_PCI)
+struct VirtIOESMPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOESM vdev;
+};
+
+/*
+ * virtio-hwkey-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_HWKEY_PCI "virtio-hwkey-pci"
+#define VIRTIO_HWKEY_PCI(obj) \
+ OBJECT_CHECK(VirtIOHWKeyPCI, (obj), TYPE_VIRTIO_HWKEY_PCI)
+struct VirtIOHWKeyPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOHWKey vdev;
+};
+
+/*
+ * virtio-sensor-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_SENSOR_PCI "virtio-sensor-pci"
+#define VIRTIO_SENSOR_PCI(obj) \
+ OBJECT_CHECK(VirtIOSENSORPCI, (obj), TYPE_VIRTIO_SENSOR_PCI)
+
+struct VirtIOSENSORPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOSENSOR vdev;
+};
+
+/*
+ * virtio-nfc-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_NFC_PCI "virtio-nfc-pci"
+#define VIRTIO_NFC_PCI(obj) \
+ OBJECT_CHECK(VirtIONFCPCI, (obj), TYPE_VIRTIO_NFC_PCI)
+
+struct VirtIONFCPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIONFC vdev;
+};
+
+/*
+ * virtio-jack-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_JACK_PCI "virtio-jack-pci"
+#define VIRTIO_JACK_PCI(obj) \
+ OBJECT_CHECK(VirtIOJACKPCI, (obj), TYPE_VIRTIO_JACK_PCI)
+
+struct VirtIOJACKPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOJACK vdev;
+};
+
+/*
+ * virtio-power-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_POWER_PCI "virtio-power-pci"
+#define VIRTIO_POWER_PCI(obj) \
+ OBJECT_CHECK(VirtIOPOWERPCI, (obj), TYPE_VIRTIO_POWER_PCI)
+
+struct VirtIOPOWERPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOPOWER vdev;
+};
+
+/*
+ * virtio-vmodem-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_VMODEM_PCI "virtio-vmodem-pci"
+#define VIRTIO_VMODEM_PCI(obj) \
+ OBJECT_CHECK(VirtIOVModemPCI, (obj), TYPE_VIRTIO_VMODEM_PCI)
+struct VirtIOVModemPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOVModem vdev;
+};
+
+
+/* virtio-touchscreen-pci */
+
+static Property virtio_touchscreen_pci_properties[] = {
+ DEFINE_PROP_UINT32(TOUCHSCREEN_OPTION_NAME,
+ VirtIOTouchscreenPCI,vdev.max_finger, DEFAULT_MAX_FINGER),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+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);
+
+ dc->props = virtio_touchscreen_pci_properties;
+ 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(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TOUCHSCREEN);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ dev->vdev.max_finger = DEFAULT_MAX_FINGER;
+}
+
+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)
+{
+ 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(&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)
+{
+ 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(&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(&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(&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 Property virtio_sensor_pci_properties[] = {
+ DEFINE_PROP_STRING(ATTRIBUTE_NAME_SENSORS, VirtIOSENSORPCI, vdev.sensors),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_sensor_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_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;
+ dc->props = virtio_sensor_pci_properties;
+}
+
+static void virtio_sensor_pci_instance_init(Object *obj)
+{
+ VirtIOSENSORPCI *dev = VIRTIO_SENSOR_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SENSOR);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_sensor_pci_info = {
+ .name = TYPE_VIRTIO_SENSOR_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOSENSORPCI),
+ .instance_init = virtio_sensor_pci_instance_init,
+ .class_init = virtio_sensor_pci_class_init,
+};
+
+/* virtio NFC */
+
+static int virtio_nfc_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIONFCPCI *dev = VIRTIO_NFC_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_nfc_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_nfc_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_NFC;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_nfc_pci_instance_init(Object *obj)
+{
+ VirtIONFCPCI *dev = VIRTIO_NFC_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NFC);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_nfc_pci_info = {
+ .name = TYPE_VIRTIO_NFC_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIONFCPCI),
+ .instance_init = virtio_nfc_pci_instance_init,
+ .class_init = virtio_nfc_pci_class_init,
+};
+
+/* virtio-jack-pci */
+
+static int virtio_jack_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOJACKPCI *dev = VIRTIO_JACK_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 Property virtio_jack_pci_properties[] = {
+ DEFINE_PROP_STRING(ATTRIBUTE_NAME_JACKS, VirtIOJACKPCI, vdev.jacks),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_jack_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_jack_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_JACK;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+ dc->props = virtio_jack_pci_properties;
+}
+
+static void virtio_jack_pci_instance_init(Object *obj)
+{
+ VirtIOJACKPCI *dev = VIRTIO_JACK_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_JACK);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_jack_pci_info = {
+ .name = TYPE_VIRTIO_JACK_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOJACKPCI),
+ .instance_init = virtio_jack_pci_instance_init,
+ .class_init = virtio_jack_pci_class_init,
+};
+
+/* virtio-power-pci */
+
+static int virtio_power_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOPOWERPCI *dev = VIRTIO_POWER_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_power_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_power_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_POWER;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_power_pci_instance_init(Object *obj)
+{
+ VirtIOPOWERPCI *dev = VIRTIO_POWER_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_POWER);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_power_pci_info = {
+ .name = TYPE_VIRTIO_POWER_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOPOWERPCI),
+ .instance_init = virtio_power_pci_instance_init,
+ .class_init = virtio_power_pci_class_init,
+};
+
+/* virtio-vmodem-pci */
+
+static int virtio_vmodem_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIOVModemPCI *dev = VIRTIO_VMODEM_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_vmodem_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_vmodem_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VMODEM;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_vmodem_pci_instance_init(Object *obj)
+{
+ VirtIOVModemPCI *dev = VIRTIO_VMODEM_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_VMODEM);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_vmodem_pci_info = {
+ .name = TYPE_VIRTIO_VMODEM_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOVModemPCI),
+ .instance_init = virtio_vmodem_pci_instance_init,
+ .class_init = virtio_vmodem_pci_class_init,
+};
+
+static void maru_virtio_pci_register_types(void)
+{
+ type_register_static(&virtio_evdi_pci_info);
+ type_register_static(&virtio_esm_pci_info);
+ type_register_static(&virtio_hwkey_pci_info);
+ type_register_static(&virtio_keyboard_pci_info);
+ type_register_static(&virtio_touchscreen_pci_info);
+ type_register_static(&virtio_sensor_pci_info);
+ type_register_static(&virtio_nfc_pci_info);
+ type_register_static(&virtio_jack_pci_info);
+ type_register_static(&virtio_power_pci_info);
+ type_register_static(&virtio_vmodem_pci_info);
+}
+
+type_init(maru_virtio_pci_register_types)
--- /dev/null
+/*
+ * Virtio Power Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung Choi <jinhyung2.choi@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <pthread.h>
+
+#include "hw/pci/pci.h"
+
+#include "hw/maru_device_ids.h"
+#include "debug_ch.h"
+
+#include "maru_virtio_power.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-power);
+
+#define POWER_DEVICE_NAME "power_supply"
+#define _MAX_BUF 1024
+#define __MAX_BUF_POWER 32
+
+static int capacity = 50;
+static int charge_full = 0;
+static int charge_now = 0;
+
+VirtIOPOWER* vpower;
+
+typedef struct msg_info {
+ char buf[_MAX_BUF];
+
+ uint16_t type;
+ uint16_t req;
+} msg_info;
+
+enum request_cmd {
+ request_get = 0,
+ request_set,
+ request_answer
+};
+
+static void set_power_data (enum power_types type, char* data, int len)
+{
+ if (len < 0 || len > __MAX_BUF_POWER) {
+ ERR("power data size is wrong.\n");
+ return;
+ }
+
+ if (data == NULL) {
+ ERR("power data is NULL.\n");
+ return;
+ }
+
+ switch (type) {
+ case power_type_capacity:
+ sscanf(data, "%d", &capacity);
+ break;
+ case power_type_charge_full:
+ sscanf(data, "%d", &charge_full);
+ break;
+ case power_type_charge_now:
+ sscanf(data, "%d", &charge_now);
+ break;
+ default:
+ return;
+ }
+}
+
+static void get_power_data(enum power_types type, char* msg_info)
+{
+ if (msg_info == NULL) {
+ return;
+ }
+
+ switch (type) {
+ case power_type_capacity:
+ sprintf(msg_info, "%d", capacity);
+ break;
+ case power_type_charge_full:
+ sprintf(msg_info, "%d", charge_full);
+ break;
+ case power_type_charge_now:
+ sprintf(msg_info, "%d", charge_now);
+ break;
+ default:
+ return;
+ }
+}
+
+void set_power_capacity(int level) {
+ capacity = level;
+}
+
+int get_power_capacity(void) {
+ return capacity;
+}
+
+void set_power_charge_full(int full){
+ charge_full = full;
+}
+
+int get_power_charge_full(void){
+ return charge_full;
+}
+
+void set_power_charge_now(int now){
+ charge_now = now;
+}
+
+int get_power_charge_now(void){
+ return charge_now;
+}
+
+static void answer_power_data_request(int type, char* data, VirtQueueElement *elem)
+{
+ msg_info* msginfo = (msg_info*) malloc(sizeof(msg_info));
+ if (!msginfo) {
+ ERR("msginfo is NULL!\n");
+ return;
+ }
+
+ msginfo->req = request_answer;
+ msginfo->type = type;
+ get_power_data(type, msginfo->buf);
+
+ TRACE("sending message: %s, type: %d, req: %d\n", msginfo->buf, msginfo->type, msginfo->req);
+
+ memset(elem->in_sg[0].iov_base, 0, elem->in_sg[0].iov_len);
+ memcpy(elem->in_sg[0].iov_base, msginfo, sizeof(struct msg_info));
+
+ if (msginfo)
+ free(msginfo);
+}
+
+static void handle_msg(struct msg_info *msg, VirtQueueElement *elem)
+{
+ unsigned int len = 0;
+
+ if (msg == NULL) {
+ ERR("msg info structure is NULL.\n");
+ return;
+ }
+
+ if (msg->req == request_set) {
+ set_power_data (msg->type, msg->buf, strlen(msg->buf));
+ } else if (msg->req == request_get) {
+ answer_power_data_request(msg->type, msg->buf, elem);
+ len = sizeof(msg_info);
+ }
+
+ virtqueue_push(vpower->vq, elem, len);
+ virtio_notify(&vpower->vdev, vpower->vq);
+}
+
+static void virtio_power_vq(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOPOWER *vpower = (VirtIOPOWER*)vdev;
+ struct msg_info msg;
+ VirtQueueElement elem;
+ int index = 0;
+
+ if (vpower->vq == NULL) {
+ ERR("virt queue is not ready.\n");
+ return;
+ }
+
+ if (!virtio_queue_ready(vpower->vq)) {
+ ERR("virtqueue is not ready.");
+ return;
+ }
+
+ if (virtio_queue_empty(vpower->vq)) {
+ ERR("<< virtqueue is empty.\n");
+ return;
+ }
+
+ while ((index = virtqueue_pop(vq, &elem))) {
+ memset(&msg, 0x00, sizeof(msg));
+ memcpy(&msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
+
+ TRACE("handling msg from driver: %s, len: %d, type: %d, req: %d, index: %d\n", msg.buf, strlen(msg.buf), msg.type, msg.req, index);
+
+ handle_msg(&msg, &elem);
+ }
+}
+
+static void virtio_power_realize(DeviceState *dev, Error **errp)
+{
+ INFO("initialize virtio-power device\n");
+
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vpower = VIRTIO_POWER(vdev);
+
+ virtio_init(vdev, POWER_DEVICE_NAME, VIRTIO_ID_POWER, 0);
+
+ if (vpower == NULL) {
+ ERR("failed to initialize power device\n");
+ return;
+ }
+
+ vpower->vq = virtio_add_queue(&vpower->vdev, 64, virtio_power_vq);
+}
+
+static void virtio_power_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ INFO("destroy power device\n");
+
+ virtio_cleanup(vdev);
+}
+
+
+static void virtio_power_reset(VirtIODevice *vdev)
+{
+ TRACE("virtio_power_reset.\n");
+}
+
+static uint32_t virtio_power_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_power_get_features.\n");
+ return 0;
+}
+
+static void virtio_power_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->realize = virtio_power_realize;
+ vdc->unrealize = virtio_power_unrealize;
+ vdc->get_features = virtio_power_get_features;
+ vdc->reset = virtio_power_reset;
+}
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_POWER,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOPOWER),
+ .class_init = virtio_power_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
+
--- /dev/null
+/*
+ * Virtio Power Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_VIRTIO_POWER_H_
+#define MARU_VIRTIO_POWER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_POWER "virtio-power-device"
+#define VIRTIO_POWER(obj) \
+ OBJECT_CHECK(VirtIOPOWER, (obj), TYPE_VIRTIO_POWER)
+
+enum power_types {
+ power_type_capacity = 0,
+ power_type_charge_full,
+ power_type_charge_now,
+ power_type_max
+};
+
+typedef struct VirtIOPOWER {
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ DeviceState *qdev;
+
+ QEMUBH *bh;
+} VirtIOPOWER;
+
+void set_power_capacity(int capacity);
+int get_power_capacity(void);
+void set_power_charge_full(int full);
+int get_power_charge_full(void);
+void set_power_charge_now(int now);
+int get_power_charge_now(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Virtio Sensor Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung Choi <jinhyung2.choi@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <pthread.h>
+
+#include "hw/pci/pci.h"
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_sensor.h"
+#include "debug_ch.h"
+#include "ecs/ecs.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-sensor);
+
+#define SENSOR_DEVICE_NAME "sensor"
+#define _MAX_BUF 1024
+#define __MAX_BUF_SENSOR 32
+
+static QemuMutex accel_mutex;
+static QemuMutex geo_mutex;
+static QemuMutex gyro_mutex;
+static QemuMutex light_mutex;
+static QemuMutex proxi_mutex;
+
+static char accel_xyz [__MAX_BUF_SENSOR] = {'0',',','9','8','0','6','6','5',',','0'};
+static int accel_enable = 0;
+static int accel_delay = 200000000;
+
+static char geo_raw [__MAX_BUF_SENSOR] = {'0',' ','-','9','0',' ','0',' ','3'};
+static char geo_tesla [__MAX_BUF_SENSOR] = {'1',' ','0',' ','-','1','0'};
+static int geo_enable = 0;
+static int geo_delay = 200000000;
+
+static int gyro_x_raw = 0;
+static int gyro_y_raw = 0;
+static int gyro_z_raw = 0;
+static int gyro_enable = 0;
+static int gyro_delay = 200000000;
+
+static int light_adc = 65535;
+static int light_level = 10;
+static int light_enable = 0;
+static int light_delay = 200000000;
+
+static int proxi_vo = 8;
+static int proxi_enable = 0;
+static int proxi_delay = 200000000;
+
+VirtIOSENSOR* vsensor;
+static int sensor_capability = 0;
+
+typedef struct msg_info {
+ char buf[_MAX_BUF];
+
+ uint16_t type;
+ uint16_t req;
+} msg_info;
+
+static type_action get_action(enum sensor_types type)
+{
+ type_action action = 0;
+
+ switch (type) {
+ case sensor_type_accel:
+ action = ACTION_ACCEL;
+ break;
+ case sensor_type_gyro:
+ action = ACTION_GYRO;
+ break;
+ case sensor_type_mag:
+ action = ACTION_MAG;
+ break;
+ case sensor_type_light:
+ action = ACTION_LIGHT;
+ break;
+ case sensor_type_proxi:
+ action = ACTION_PROXI;
+ break;
+ default:
+ break;
+ }
+
+ return action;
+}
+
+static void send_sensor_to_ecs(const char* data, enum sensor_types type)
+{
+ type_length length = 0;
+ type_group group = GROUP_STATUS;
+ type_action action = 0;
+ int buf_len = strlen(data);
+ int message_len = buf_len + 14;
+
+ char* ecs_message = (char*) malloc(message_len + 1);
+ if (!ecs_message)
+ return;
+
+ memset(ecs_message, 0, message_len + 1);
+
+ length = (unsigned short) buf_len;
+ action = get_action(type);
+
+ memcpy(ecs_message, MESSAGE_TYPE_SENSOR, 6);
+ memcpy(ecs_message + 10, &length, sizeof(unsigned short));
+ memcpy(ecs_message + 12, &group, sizeof(unsigned char));
+ memcpy(ecs_message + 13, &action, sizeof(unsigned char));
+ memcpy(ecs_message + 14, data, buf_len);
+
+ TRACE("ntf_to_injector- len: %d, group: %d, action: %d, data: %s\n", length, group, action, data);
+
+ send_device_ntf(ecs_message, message_len);
+
+ if (ecs_message)
+ free(ecs_message);
+}
+
+static void __set_sensor_data (enum sensor_types type, char* data, int len)
+{
+ if (len < 0 || len > __MAX_BUF_SENSOR) {
+ ERR("sensor data size is wrong.\n");
+ return;
+ }
+
+ if (data == NULL) {
+ ERR("sensor data is NULL.\n");
+ return;
+ }
+
+ TRACE("set_sensor_data with type '%d' with data '%s'", type, data);
+
+ switch (type) {
+ case sensor_type_accel:
+ qemu_mutex_lock(&accel_mutex);
+ strcpy(accel_xyz, data);
+ qemu_mutex_unlock(&accel_mutex);
+ break;
+ case sensor_type_accel_enable:
+ qemu_mutex_lock(&accel_mutex);
+ sscanf(data, "%d", &accel_enable);
+ qemu_mutex_unlock(&accel_mutex);
+ break;
+ case sensor_type_accel_delay:
+ qemu_mutex_lock(&accel_mutex);
+ sscanf(data, "%d", &accel_delay);
+ qemu_mutex_unlock(&accel_mutex);
+ break;
+ case sensor_type_gyro_enable:
+ qemu_mutex_lock(&gyro_mutex);
+ sscanf(data, "%d", &gyro_enable);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_delay:
+ qemu_mutex_lock(&gyro_mutex);
+ sscanf(data, "%d", &gyro_delay);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_x:
+ qemu_mutex_lock(&gyro_mutex);
+ sscanf(data, "%d", &gyro_x_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_y:
+ qemu_mutex_lock(&gyro_mutex);
+ sscanf(data, "%d", &gyro_y_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_z:
+ qemu_mutex_lock(&gyro_mutex);
+ sscanf(data, "%d", &gyro_z_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro:
+ qemu_mutex_lock(&gyro_mutex);
+ sscanf(data, "%d %d %d", &gyro_x_raw, &gyro_y_raw, &gyro_z_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_light_adc:
+ qemu_mutex_lock(&light_mutex);
+ sscanf(data, "%d", &light_adc);
+ light_level = (light_adc / 6554) % 10 + 1;
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_light_level:
+ qemu_mutex_lock(&light_mutex);
+ sscanf(data, "%d", &light_level);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_light_enable:
+ qemu_mutex_lock(&light_mutex);
+ sscanf(data, "%d", &light_enable);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_light_delay:
+ qemu_mutex_lock(&light_mutex);
+ sscanf(data, "%d", &light_delay);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_proxi:
+ qemu_mutex_lock(&proxi_mutex);
+ sscanf(data, "%d", &proxi_vo);
+ qemu_mutex_unlock(&proxi_mutex);
+ break;
+ case sensor_type_proxi_enable:
+ qemu_mutex_lock(&proxi_mutex);
+ sscanf(data, "%d", &proxi_enable);
+ qemu_mutex_unlock(&proxi_mutex);
+ break;
+ case sensor_type_proxi_delay:
+ qemu_mutex_lock(&proxi_mutex);
+ sscanf(data, "%d", &proxi_delay);
+ qemu_mutex_unlock(&proxi_mutex);
+ break;
+ case sensor_type_mag:
+ qemu_mutex_lock(&geo_mutex);
+ strcpy(geo_tesla, data);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_tilt:
+ qemu_mutex_lock(&geo_mutex);
+ strcpy(geo_raw, data);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_geo_enable:
+ qemu_mutex_lock(&geo_mutex);
+ sscanf(data, "%d", &geo_enable);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_geo_delay:
+ qemu_mutex_lock(&geo_mutex);
+ sscanf(data, "%d", &geo_delay);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ default:
+ return;
+ }
+}
+
+static void __get_sensor_data(enum sensor_types type, char* msg_info)
+{
+ if (msg_info == NULL) {
+ return;
+ }
+
+ switch (type) {
+ case sensor_type_list:
+ sprintf(msg_info, "%d", sensor_capability);
+ break;
+ case sensor_type_accel:
+ qemu_mutex_lock(&accel_mutex);
+ strcpy(msg_info, accel_xyz);
+ qemu_mutex_unlock(&accel_mutex);
+ break;
+ case sensor_type_accel_enable:
+ qemu_mutex_lock(&accel_mutex);
+ sprintf(msg_info, "%d", accel_enable);
+ qemu_mutex_unlock(&accel_mutex);
+ break;
+ case sensor_type_accel_delay:
+ qemu_mutex_lock(&accel_mutex);
+ sprintf(msg_info, "%d", accel_delay);
+ qemu_mutex_unlock(&accel_mutex);
+ break;
+ case sensor_type_mag:
+ qemu_mutex_lock(&geo_mutex);
+ strcpy(msg_info, geo_tesla);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_tilt:
+ qemu_mutex_lock(&geo_mutex);
+ strcpy(msg_info, geo_raw);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_geo_enable:
+ qemu_mutex_lock(&geo_mutex);
+ sprintf(msg_info, "%d", geo_enable);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_geo_delay:
+ qemu_mutex_lock(&geo_mutex);
+ sprintf(msg_info, "%d", geo_delay);
+ qemu_mutex_unlock(&geo_mutex);
+ break;
+ case sensor_type_gyro:
+ qemu_mutex_lock(&gyro_mutex);
+ sprintf(msg_info, "%d,%d,%d", gyro_x_raw, gyro_y_raw, gyro_z_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_enable:
+ qemu_mutex_lock(&gyro_mutex);
+ sprintf(msg_info, "%d", gyro_enable);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_delay:
+ qemu_mutex_lock(&gyro_mutex);
+ sprintf(msg_info, "%d", gyro_delay);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_x:
+ qemu_mutex_lock(&gyro_mutex);
+ sprintf(msg_info, "%d", gyro_x_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_y:
+ qemu_mutex_lock(&gyro_mutex);
+ sprintf(msg_info, "%d", gyro_y_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_gyro_z:
+ qemu_mutex_lock(&gyro_mutex);
+ sprintf(msg_info, "%d", gyro_z_raw);
+ qemu_mutex_unlock(&gyro_mutex);
+ break;
+ case sensor_type_light:
+ case sensor_type_light_adc:
+ qemu_mutex_lock(&light_mutex);
+ sprintf(msg_info, "%d", light_adc);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_light_level:
+ qemu_mutex_lock(&light_mutex);
+ sprintf(msg_info, "%d", light_level);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_light_enable:
+ qemu_mutex_lock(&light_mutex);
+ sprintf(msg_info, "%d", light_enable);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_light_delay:
+ qemu_mutex_lock(&light_mutex);
+ sprintf(msg_info, "%d", light_delay);
+ qemu_mutex_unlock(&light_mutex);
+ break;
+ case sensor_type_proxi:
+ qemu_mutex_lock(&proxi_mutex);
+ sprintf(msg_info, "%d", proxi_vo);
+ qemu_mutex_unlock(&proxi_mutex);
+ break;
+ case sensor_type_proxi_enable:
+ qemu_mutex_lock(&proxi_mutex);
+ sprintf(msg_info, "%d", proxi_enable);
+ qemu_mutex_unlock(&proxi_mutex);
+ break;
+ case sensor_type_proxi_delay:
+ qemu_mutex_lock(&proxi_mutex);
+ sprintf(msg_info, "%d", proxi_delay);
+ qemu_mutex_unlock(&proxi_mutex);
+ break;
+ default:
+ return;
+ }
+}
+
+void req_sensor_data (enum sensor_types type, enum request_cmd req, char* data, int len)
+{
+ char msg_info [__MAX_BUF_SENSOR];
+ memset(msg_info, 0, __MAX_BUF_SENSOR);
+
+ if (type >= sensor_type_max || (req != request_get && req != request_set)) {
+ ERR("unavailable sensor type request.\n");
+ return;
+ }
+
+ if (req == request_set) {
+ __set_sensor_data (type, data, len);
+ } else if (req == request_get) {
+ __get_sensor_data(type, msg_info);
+ send_sensor_to_ecs(msg_info, type);
+ }
+}
+
+static void answer_sensor_data_request(int type, char* data, VirtQueueElement *elem)
+{
+ msg_info* msginfo = (msg_info*) malloc(sizeof(msg_info));
+ if (!msginfo) {
+ ERR("msginfo is NULL!\n");
+ return;
+ }
+
+ msginfo->req = request_answer;
+ msginfo->type = type;
+ __get_sensor_data(type, msginfo->buf);
+
+ TRACE("sending message: %s, type: %d, req: %d\n", msginfo->buf, msginfo->type, msginfo->req);
+
+ memset(elem->in_sg[0].iov_base, 0, elem->in_sg[0].iov_len);
+ memcpy(elem->in_sg[0].iov_base, msginfo, sizeof(struct msg_info));
+
+ if (msginfo)
+ free(msginfo);
+}
+
+static void handle_msg(struct msg_info *msg, VirtQueueElement *elem)
+{
+ unsigned int len = 0;
+
+ if (msg == NULL) {
+ ERR("msg info structure is NULL.\n");
+ return;
+ }
+
+ if (msg->req == request_set) {
+ __set_sensor_data (msg->type, msg->buf, strlen(msg->buf));
+ } else if (msg->req == request_get) {
+ answer_sensor_data_request(msg->type, msg->buf, elem);
+ len = sizeof(msg_info);
+ }
+
+ virtqueue_push(vsensor->vq, elem, len);
+ virtio_notify(&vsensor->vdev, vsensor->vq);
+}
+
+static void virtio_sensor_vq(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOSENSOR *vsensor = (VirtIOSENSOR*)vdev;
+ struct msg_info msg;
+ VirtQueueElement elem;
+ int index = 0;
+
+ if (vsensor->vq == NULL) {
+ ERR("virt queue is not ready.\n");
+ return;
+ }
+
+ if (!virtio_queue_ready(vsensor->vq)) {
+ ERR("virtqueue is not ready.");
+ return;
+ }
+
+ if (virtio_queue_empty(vsensor->vq)) {
+ ERR("<< virtqueue is empty.\n");
+ return;
+ }
+
+ while ((index = virtqueue_pop(vq, &elem))) {
+ memset(&msg, 0x00, sizeof(msg));
+ memcpy(&msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
+
+ TRACE("handling msg from driver: %s, len: %d, type: %d, req: %d, index: %d\n", msg.buf, strlen(msg.buf), msg.type, msg.req, index);
+
+ handle_msg(&msg, &elem);
+ }
+}
+
+static int set_capability(char* sensor)
+{
+ if (!strncmp(sensor, SENSOR_NAME_ACCEL, 5)) {
+ return sensor_cap_accel;
+ } else if (!strncmp(sensor, SENSOR_NAME_GEO, 3)) {
+ return sensor_cap_geo;
+ } else if (!strncmp(sensor, SENSOR_NAME_GYRO, 4)) {
+ return sensor_cap_gyro;
+ } else if (!strncmp(sensor, SENSOR_NAME_LIGHT, 5)) {
+ return sensor_cap_light;
+ } else if (!strncmp(sensor, SENSOR_NAME_PROXI, 5)) {
+ return sensor_cap_proxi;
+ } else if (!strncmp(sensor, SENSOR_NAME_HAPTIC, 6)) {
+ return sensor_cap_haptic;
+ } else {
+ ERR("unknown sensor request: %s", sensor);
+ }
+
+ return 0;
+}
+
+static void parse_sensor_capability(char* lists)
+{
+ char token[] = SENSOR_CAP_TOKEN;
+ char* data = NULL;
+
+ if (lists == NULL)
+ return;
+
+ data = strtok(lists, token);
+ if (data != NULL) {
+ sensor_capability |= set_capability(data);
+ while ((data = strtok(NULL, token)) != NULL) {
+ sensor_capability |= set_capability(data);
+ }
+ }
+
+ INFO("sensor device capabilty enabled with %02x\n", sensor_capability);
+}
+
+static void virtio_sensor_realize(DeviceState *dev, Error **errp)
+{
+ INFO("initialize virtio-sensor device\n");
+
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ vsensor = VIRTIO_SENSOR(vdev);
+
+ virtio_init(vdev, SENSOR_DEVICE_NAME, VIRTIO_ID_SENSOR, 0);
+
+ if (vsensor == NULL) {
+ ERR("failed to initialize sensor device\n");
+ error_set(errp, QERR_DEVICE_INIT_FAILED, SENSOR_DEVICE_NAME);
+ return;
+ }
+
+ qemu_mutex_init(&accel_mutex);
+ qemu_mutex_init(&gyro_mutex);
+ qemu_mutex_init(&geo_mutex);
+ qemu_mutex_init(&light_mutex);
+ qemu_mutex_init(&proxi_mutex);
+
+ vsensor->vq = virtio_add_queue(&vsensor->vdev, 64, virtio_sensor_vq);
+
+ INFO("initialized sensor type: %s\n", vsensor->sensors);
+
+ if (vsensor->sensors) {
+ parse_sensor_capability(vsensor->sensors);
+ }
+}
+
+static void virtio_sensor_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ INFO("destroy sensor device\n");
+
+ qemu_mutex_destroy(&accel_mutex);
+ qemu_mutex_destroy(&gyro_mutex);
+ qemu_mutex_destroy(&geo_mutex);
+ qemu_mutex_destroy(&light_mutex);
+ qemu_mutex_destroy(&proxi_mutex);
+
+ virtio_cleanup(vdev);
+}
+
+
+static void virtio_sensor_reset(VirtIODevice *vdev)
+{
+ TRACE("virtio_sensor_reset.\n");
+}
+
+static uint32_t virtio_sensor_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_sensor_get_features.\n");
+ return 0;
+}
+
+static Property virtio_sensor_properties[] = {
+ DEFINE_PROP_STRING(ATTRIBUTE_NAME_SENSORS, VirtIOSENSOR, sensors),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_sensor_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->props = virtio_sensor_properties;
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->unrealize= virtio_sensor_unrealize;
+ vdc->realize = virtio_sensor_realize;
+ vdc->get_features = virtio_sensor_get_features;
+ vdc->reset = virtio_sensor_reset;
+}
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_SENSOR,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOSENSOR),
+ .class_init = virtio_sensor_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
+
--- /dev/null
+/*
+ * Virtio Sensor Device
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_VIRTIO_SENSOR_H_
+#define MARU_VIRTIO_SENSOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+enum request_cmd {
+ request_get = 0,
+ request_set,
+ request_answer
+};
+
+enum sensor_types {
+ sensor_type_list = 0,
+ sensor_type_accel,
+ sensor_type_accel_enable,
+ sensor_type_accel_delay,
+ sensor_type_geo,
+ sensor_type_geo_enable,
+ sensor_type_geo_delay,
+ sensor_type_gyro,
+ sensor_type_gyro_enable,
+ sensor_type_gyro_delay,
+ sensor_type_gyro_x,
+ sensor_type_gyro_y,
+ sensor_type_gyro_z,
+ sensor_type_light,
+ sensor_type_light_enable,
+ sensor_type_light_delay,
+ sensor_type_light_adc,
+ sensor_type_light_level,
+ sensor_type_proxi,
+ sensor_type_proxi_enable,
+ sensor_type_proxi_delay,
+ sensor_type_mag,
+ sensor_type_tilt,
+ sensor_type_max
+};
+
+enum sensor_capabilities {
+ sensor_cap_accel = 0x01,
+ sensor_cap_geo = 0x02,
+ sensor_cap_gyro = 0x04,
+ sensor_cap_light = 0x08,
+ sensor_cap_proxi = 0x10,
+ sensor_cap_haptic = 0x20
+};
+
+#define MESSAGE_TYPE_SENSOR "sensor"
+
+#define GROUP_STATUS 15
+
+#define ACTION_ACCEL 110
+#define ACTION_GYRO 111
+#define ACTION_MAG 112
+#define ACTION_LIGHT 113
+#define ACTION_PROXI 114
+
+#define ATTRIBUTE_NAME_SENSORS "sensors"
+
+#define SENSOR_NAME_ACCEL "accel"
+#define SENSOR_NAME_GYRO "gyro"
+#define SENSOR_NAME_GEO "geo"
+#define SENSOR_NAME_LIGHT "light"
+#define SENSOR_NAME_PROXI "proxi"
+#define SENSOR_NAME_HAPTIC "haptic"
+
+#define SENSOR_CAP_TOKEN "&"
+
+#define TYPE_VIRTIO_SENSOR "virtio-sensor-device"
+#define VIRTIO_SENSOR(obj) \
+ OBJECT_CHECK(VirtIOSENSOR, (obj), TYPE_VIRTIO_SENSOR)
+
+typedef struct VirtIOSENSOR {
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ DeviceState *qdev;
+
+ char *sensors;
+} VirtIOSENSOR;
+
+void req_sensor_data(enum sensor_types type, enum request_cmd req, char* data, int len);
+
+#define get_sensor_accel() \
+ req_sensor_data(sensor_type_accel, request_get, NULL, 0);
+
+#define get_sensor_gyro() \
+ req_sensor_data(sensor_type_gyro, request_get, NULL, 0);
+
+#define get_sensor_mag() \
+ req_sensor_data(sensor_type_mag, request_get, NULL, 0);
+
+#define get_sensor_light() \
+ req_sensor_data(sensor_type_light_adc, request_get, NULL, 0);
+
+#define get_sensor_proxi() \
+ req_sensor_data(sensor_type_proxi, request_get, NULL, 0);
+
+#define set_sensor_accel(data, len) \
+ req_sensor_data(sensor_type_accel, request_set, data, len);
+
+#define set_sensor_proxi(data, len) \
+ req_sensor_data(sensor_type_proxi, request_set, data, len);
+
+#define set_sensor_light(data, len) \
+ req_sensor_data(sensor_type_light_adc, request_set, data, len);
+
+#define set_sensor_gyro(data, len) \
+ req_sensor_data(sensor_type_gyro, request_set, data, len);
+
+#define set_sensor_tilt(data, len) \
+ req_sensor_data(sensor_type_tilt, request_set, data, len);
+
+#define set_sensor_mag(data, len) \
+ req_sensor_data(sensor_type_mag, request_set, data, len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Maru Virtio Touchscreen Device
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <pthread.h>
+#include "maru_virtio_touchscreen.h"
+#include "hw/maru_device_ids.h"
+#include "emul_state.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, touchscreen);
+
+
+#define DEVICE_NAME "virtio-touchscreen"
+
+/*
+ * touch event queue
+ */
+typedef struct TouchEventEntry {
+ unsigned int index;
+ EmulTouchEvent touch;
+
+ QTAILQ_ENTRY(TouchEventEntry) node;
+} TouchEventEntry;
+
+/* the maximum number of touch event that can be put into a queue */
+#define MAX_TOUCH_EVENT_CNT 256
+
+static TouchEventEntry _events_buf[MAX_TOUCH_EVENT_CNT];
+static QTAILQ_HEAD(, TouchEventEntry) events_queue =
+ QTAILQ_HEAD_INITIALIZER(events_queue);
+
+static unsigned int event_ringbuf_cnt; /* _events_buf */
+static unsigned int event_queue_cnt; /* events_queue */
+
+/*
+ * VirtQueueElement queue
+ */
+typedef struct ElementEntry {
+ unsigned int el_index;
+ unsigned int sg_index;
+ VirtQueueElement elem;
+
+ QTAILQ_ENTRY(ElementEntry) node;
+} ElementEntry;
+
+static ElementEntry _elem_buf[10];
+static QTAILQ_HEAD(, ElementEntry) elem_queue =
+ QTAILQ_HEAD_INITIALIZER(elem_queue);
+
+static unsigned int elem_ringbuf_cnt; /* _elem_buf */
+static unsigned int elem_queue_cnt; /* elem_queue */
+
+
+VirtIOTouchscreen *ts;
+
+/* lock for between communication thread and IO thread */
+static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t elem_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+void virtio_touchscreen_event(int x, int y, int z, int buttons_state)
+{
+ TouchEventEntry *entry = NULL;
+
+ if (unlikely(!virtio_queue_ready(ts->vq))) {
+ ERR("virtio queue is not ready\n");
+ return;
+ }
+
+ if (unlikely(event_queue_cnt >= MAX_TOUCH_EVENT_CNT)) {
+ INFO("full touch event queue, lose event\n", event_queue_cnt);
+
+ qemu_bh_schedule(ts->bh);
+ return;
+ }
+
+ entry = &(_events_buf[event_ringbuf_cnt % MAX_TOUCH_EVENT_CNT]);
+ event_ringbuf_cnt++;
+
+ /* mouse event is copied into the queue */
+ entry->touch.x = x;
+ entry->touch.y = y;
+ entry->touch.z = z;
+ entry->touch.state = buttons_state;
+
+ pthread_mutex_lock(&event_mutex);
+
+ entry->index = ++event_queue_cnt; /* 1 ~ */
+
+ QTAILQ_INSERT_TAIL(&events_queue, entry, node);
+
+ pthread_mutex_unlock(&event_mutex);
+
+ /* call maru_virtio_touchscreen_notify */
+ qemu_bh_schedule(ts->bh);
+
+ TRACE("touch event (%d) : x=%d, y=%d, z=%d, state=%d\n",
+ entry->index, entry->touch.x, entry->touch.y,
+ entry->touch.z, entry->touch.state);
+}
+
+static void maru_virtio_touchscreen_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+#if 0 /* not used yet */
+ if (ts->eh_entry == NULL) {
+ void *vbuf = NULL;
+ VirtQueueElement elem;
+ int max_trkid = 0;
+
+ virtqueue_pop(ts->vq, &elem);
+ vbuf = elem.in_sg[0].iov_base;
+ memcpy(&max_trkid, vbuf, sizeof(max_trkid));
+
+ if (max_trkid > 0) {
+ INFO("virtio touchscreen's maximum of tracking id = %d\n", max_trkid);
+
+ /* register a event handler */
+ ts->eh_entry = qemu_add_mouse_event_handler(
+ virtio_touchscreen_event, ts, 1, "QEMU Virtio Touchscreen");
+ qemu_activate_mouse_event_handler(ts->eh_entry);
+
+ //TODO:
+ virtqueue_push(ts->vq, &elem, 0);
+ virtio_notify(&(ts->vdev), ts->vq);
+ } else {
+ INFO("virtio touchscreen is not added to qemu mouse event handler\n");
+ }
+ }
+#endif
+
+ int virt_sg_index = 0;
+ ElementEntry *elem_entry = NULL;
+
+ TRACE("maru_virtio_touchscreen_handle\n");
+
+ if (unlikely(virtio_queue_empty(ts->vq))) {
+ TRACE("virtqueue is empty\n");
+ return;
+ }
+
+ while (true) {
+ elem_entry = &(_elem_buf[elem_ringbuf_cnt % 10]);
+ elem_ringbuf_cnt++;
+
+ virt_sg_index = virtqueue_pop(ts->vq, &elem_entry->elem);
+ if (virt_sg_index == 0) {
+ elem_ringbuf_cnt--;
+ break;
+ } else if (virt_sg_index < 0) {
+ ERR("virtqueue is broken\n");
+ elem_ringbuf_cnt--;
+ return;
+ }
+
+ pthread_mutex_lock(&elem_mutex);
+
+ elem_entry->el_index = ++elem_queue_cnt;
+ elem_entry->sg_index = (unsigned int)virt_sg_index;
+
+ /* save VirtQueueElement */
+ QTAILQ_INSERT_TAIL(&elem_queue, elem_entry, node);
+
+ if (ts->waitBuf == true) {
+ ts->waitBuf = false;
+
+ /* call maru_virtio_touchscreen_notify */
+ qemu_bh_schedule(ts->bh);
+ }
+
+ pthread_mutex_unlock(&elem_mutex);
+ }
+}
+
+void maru_virtio_touchscreen_notify(void)
+{
+ ElementEntry *elem_entry = NULL;
+ unsigned int ii = 0;
+
+ TRACE("maru_virtio_touchscreen_notify\n");
+
+ if (unlikely(!virtio_queue_ready(ts->vq))) {
+ ERR("virtio queue is not ready\n");
+ return;
+ }
+
+ while (true) {
+ if (event_queue_cnt == 0) {
+ TRACE("no event\n");
+ break;
+ } else if (elem_queue_cnt == 0) {
+ TRACE("no buffer\n");
+
+ pthread_mutex_lock(&elem_mutex);
+ /* maybe next time */
+ ts->waitBuf = true;
+ pthread_mutex_unlock(&elem_mutex);
+ break;
+ }
+
+ elem_entry = QTAILQ_FIRST(&elem_queue);
+
+ if (elem_entry->sg_index > 0) {
+ TouchEventEntry *event_entry = NULL;
+ VirtQueueElement *element = NULL;
+ void *vbuf = NULL;
+
+ element = &elem_entry->elem;
+ vbuf = element->in_sg[elem_entry->sg_index - 1].iov_base;
+
+ /* get touch event from host queue */
+ event_entry = QTAILQ_FIRST(&events_queue);
+
+ TRACE("touch(%d) : x=%d, y=%d, z=%d, state=%d | \
+ event_queue_cnt=%d, elem.index=%d, elem.in_num=%d, sg_index=%d\n",
+ event_entry->index, event_entry->touch.x, event_entry->touch.y,
+ event_entry->touch.z, event_entry->touch.state,
+ event_queue_cnt, element->index, element->in_num,
+ elem_entry->sg_index);
+
+ /* copy event into virtio buffer */
+ memcpy(vbuf, &(event_entry->touch), sizeof(event_entry->touch));
+
+ pthread_mutex_lock(&event_mutex);
+
+ /* remove host event */
+ QTAILQ_REMOVE(&events_queue, event_entry, node);
+ event_queue_cnt--;
+
+ pthread_mutex_unlock(&event_mutex);
+
+ /* put buffer into virtio queue */
+ virtqueue_fill(ts->vq, element, sizeof(EmulTouchEvent), ii++);
+ }
+
+ pthread_mutex_lock(&elem_mutex);
+
+ QTAILQ_REMOVE(&elem_queue, elem_entry, node);
+ elem_queue_cnt--;
+
+ pthread_mutex_unlock(&elem_mutex);
+ }
+
+ if (ii != 0) {
+ /* signal other side */
+ virtqueue_flush(ts->vq, ii);
+ /* notify to guest */
+ virtio_notify(&(ts->vdev), ts->vq);
+ }
+}
+
+static void virtio_touchscreen_get_config(
+ VirtIODevice *vdev, uint8_t *config_data)
+{
+ int max_trkid = 10;
+ INFO("virtio_touchscreen_get_config\n");
+
+ max_trkid = get_emul_max_touch_point();
+ memcpy(config_data, &max_trkid, 4);
+}
+
+static void virtio_touchscreen_set_config(
+ VirtIODevice *vdev, const uint8_t *config_data)
+{
+ /* do nothing */
+}
+
+static uint32_t virtio_touchscreen_get_features(
+ VirtIODevice *vdev, uint32_t request_features)
+{
+ /* do nothing */
+
+ return request_features;
+}
+
+static void maru_touchscreen_bh(void *opaque)
+{
+ //TouchscreenState *ts = (TouchscreenState *)opaque;
+
+ maru_virtio_touchscreen_notify();
+}
+
+static void virtio_touchscreen_device_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ ts = VIRTIO_TOUCHSCREEN(dev);
+
+ INFO("initialize touchscreen device : %d\n", ts->max_finger);
+
+ virtio_init(vdev, DEVICE_NAME, VIRTIO_ID_TOUCHSCREEN, 4);
+ /*if (ts == NULL) {
+ ERR("failed to initialize the touchscreen device\n");
+ return NULL;
+ }*/
+
+ // TODO: reduce size
+ ts->vq = virtio_add_queue(&ts->vdev, 64, maru_virtio_touchscreen_handle);
+ ts->qdev = dev;
+
+ /* bottom halves */
+ ts->bh = qemu_bh_new(maru_touchscreen_bh, ts);
+}
+
+static void virtio_touchscreen_device_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ INFO("exit the touchscreen device\n");
+
+ if (ts->bh) {
+ qemu_bh_delete(ts->bh);
+ }
+
+ virtio_cleanup(vdev);
+
+ pthread_mutex_destroy(&event_mutex);
+ pthread_mutex_destroy(&elem_mutex);
+}
+
+static Property virtio_touchscreen_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_touchscreen_device_reset(VirtIODevice *vdev)
+{
+ TouchEventEntry *event_entry = NULL;
+ ElementEntry *elem_entry = NULL;
+
+ INFO("reset the touchscreen device\n");
+
+ /* reset the counters */
+ event_ringbuf_cnt = 0;
+ elem_ringbuf_cnt = 0;
+
+ /* reset queue */
+ pthread_mutex_lock(&event_mutex);
+ while (event_queue_cnt > 0) {
+ event_entry = QTAILQ_FIRST(&events_queue);
+ QTAILQ_REMOVE(&events_queue, event_entry, node);
+
+ event_queue_cnt--;
+ }
+ pthread_mutex_unlock(&event_mutex);
+
+ pthread_mutex_lock(&elem_mutex);
+ while (elem_queue_cnt > 0) {
+ elem_entry = QTAILQ_FIRST(&elem_queue);
+ QTAILQ_REMOVE(&elem_queue, elem_entry, node);
+
+ elem_queue_cnt--;
+ }
+
+ ts->waitBuf = false;
+ pthread_mutex_unlock(&elem_mutex);
+}
+
+static void virtio_touchscreen_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+ dc->props = virtio_touchscreen_properties;
+ vdc->realize = virtio_touchscreen_device_realize;
+ vdc->unrealize = virtio_touchscreen_device_unrealize;
+ vdc->reset = virtio_touchscreen_device_reset;
+ vdc->get_config = virtio_touchscreen_get_config;
+ vdc->set_config = virtio_touchscreen_set_config;
+ vdc->get_features = virtio_touchscreen_get_features;
+}
+
+static const TypeInfo virtio_touchscreen_info = {
+ .name = TYPE_VIRTIO_TOUCHSCREEN,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOTouchscreen),
+ .class_init = virtio_touchscreen_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_touchscreen_info);
+}
+
+type_init(virtio_register_types)
--- /dev/null
+/*
+ * Maru Virtio Touchscreen Device
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_TOUCHSCREEN_H_
+#define MARU_TOUCHSCREEN_H_
+
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_TOUCHSCREEN "virtio-touchscreen-device"
+#define VIRTIO_TOUCHSCREEN(obj) \
+ OBJECT_CHECK(VirtIOTouchscreen, (obj), TYPE_VIRTIO_TOUCHSCREEN)
+
+#define TOUCHSCREEN_OPTION_NAME "max_point"
+#define DEFAULT_MAX_FINGER (1)
+
+typedef struct VirtIOTouchscreen {
+ VirtIODevice vdev;
+ /* simply a queue into which buffers are posted
+ by the guest for consumption by the host */
+ VirtQueue *vq;
+ bool waitBuf;
+
+ QEMUBH *bh;
+ DeviceState *qdev;
+
+ unsigned int max_finger;
+} VirtIOTouchscreen;
+
+/* This structure must match the kernel definitions */
+typedef struct EmulTouchEvent {
+ uint16_t x, y, z;
+ uint8_t state;
+} EmulTouchEvent;
+
+void virtio_touchscreen_event(int x, int y, int z, int buttons_state);
+void maru_virtio_touchscreen_notify(void);
+
+#endif /* MARU_TOUCHSCREEN_H_ */
--- /dev/null
+/*
+ * Virtio Virtual Modem Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Sooyoung Ha <yoosah.ha@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_vmodem.h"
+#include "maru_virtio_evdi.h"
+#include "debug_ch.h"
+#include "ecs/ecs.h"
+
+MULTI_DEBUG_CHANNEL(qemu, virtio-vmodem);
+
+#define VMODEM_DEVICE_NAME "virtio-vmodem"
+
+enum {
+ IOTYPE_INPUT = 0,
+ IOTYPE_OUTPUT = 1
+};
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+VirtIOVModem *vio_vmodem;
+
+typedef struct MsgInfo
+{
+ msg_info info;
+ QTAILQ_ENTRY(MsgInfo) next;
+}MsgInfo;
+
+static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) vmodem_recv_msg_queue =
+ QTAILQ_HEAD_INITIALIZER(vmodem_recv_msg_queue);
+
+typedef struct EvdiBuf {
+ VirtQueueElement elem;
+
+ QTAILQ_ENTRY(EvdiBuf) next;
+} EvdiBuf;
+
+static QTAILQ_HEAD(EvdiMsgHead , EvdiBuf) vmodem_in_queue =
+ QTAILQ_HEAD_INITIALIZER(vmodem_in_queue);
+
+bool send_to_vmodem(const uint32_t route, char *data, const uint32_t len)
+{
+ int size;
+ int left = len;
+ int count = 0;
+ char *readptr = data;
+
+ while (left > 0) {
+ MsgInfo *_msg = (MsgInfo*) malloc(sizeof(MsgInfo));
+ if (!_msg) {
+ ERR("malloc failed\n");
+ return false;
+ }
+
+ memset(&_msg->info, 0, sizeof(msg_info));
+
+ size = min(left, __MAX_BUF_SIZE);
+ memcpy(_msg->info.buf, readptr, size);
+ readptr += size;
+ _msg->info.use = size;
+ _msg->info.index = count;
+
+ qemu_mutex_lock(&vio_vmodem->mutex);
+
+ QTAILQ_INSERT_TAIL(&vmodem_recv_msg_queue, _msg, next);
+
+ qemu_mutex_unlock(&vio_vmodem->mutex);
+
+ left -= size;
+ count ++;
+ }
+
+ qemu_bh_schedule(vio_vmodem->bh);
+
+ return true;
+}
+
+static void flush_vmodem_recv_queue(void)
+{
+ int index;
+
+ if (unlikely(!virtio_queue_ready(vio_vmodem->rvq))) {
+ ERR("virtio queue is not ready\n");
+ return;
+ }
+
+ if (unlikely(virtio_queue_empty(vio_vmodem->rvq))) {
+ ERR("virtqueue is empty\n");
+ return;
+ }
+
+ qemu_mutex_lock(&vio_vmodem->mutex);
+
+ while (!QTAILQ_EMPTY(&vmodem_recv_msg_queue))
+ {
+ MsgInfo *msginfo = QTAILQ_FIRST(&vmodem_recv_msg_queue);
+ if (!msginfo)
+ break;
+
+ VirtQueueElement elem;
+ index = virtqueue_pop(vio_vmodem->rvq, &elem);
+ if (index == 0) {
+ break;
+ }
+
+ memset(elem.in_sg[0].iov_base, 0, elem.in_sg[0].iov_len);
+ memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct msg_info));
+
+ virtqueue_push(vio_vmodem->rvq, &elem, sizeof(msg_info));
+ virtio_notify(&vio_vmodem->vdev, vio_vmodem->rvq);
+
+ QTAILQ_REMOVE(&vmodem_recv_msg_queue, msginfo, next);
+ if (msginfo)
+ free(msginfo);
+ }
+ qemu_mutex_unlock(&vio_vmodem->mutex);
+}
+
+
+static void virtio_vmodem_recv(VirtIODevice *vdev, VirtQueue *vq)
+{
+ flush_vmodem_recv_queue();
+}
+
+static void virtio_vmodem_send(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOVModem *vvmodem = (VirtIOVModem *)vdev;
+ int index = 0;
+ struct msg_info _msg;
+
+ if (virtio_queue_empty(vvmodem->svq)) {
+ ERR("virtqueue is empty.\n");
+ return;
+ }
+
+ VirtQueueElement elem;
+
+ while ((index = virtqueue_pop(vq, &elem))) {
+ memset(&_msg, 0x00, sizeof(_msg));
+ memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
+
+ TRACE("vmodem send to ecp.\n");
+ send_injector_ntf(_msg.buf, _msg.use);
+ }
+
+ virtqueue_push(vq, &elem, sizeof(VirtIOVModem));
+ virtio_notify(&vio_vmodem->vdev, vq);
+}
+
+static uint32_t virtio_vmodem_get_features(VirtIODevice *vdev,
+ uint32_t request_feature)
+{
+ TRACE("virtio_vmodem_get_features.\n");
+ return 0;
+}
+
+static void maru_vmodem_bh(void *opaque)
+{
+ flush_vmodem_recv_queue();
+}
+
+static void virtio_vmodem_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ vio_vmodem = VIRTIO_VMODEM(vdev);
+
+ if (vio_vmodem == NULL) {
+ ERR("failed to initialize vmodem device\n");
+ return;
+ }
+
+ virtio_init(vdev, TYPE_VIRTIO_VMODEM, VIRTIO_ID_VMODEM, 0); //VMODEM_DEVICE_NAME
+ qemu_mutex_init(&vio_vmodem->mutex);
+
+ vio_vmodem->rvq = virtio_add_queue(&vio_vmodem->vdev, 256, virtio_vmodem_recv);
+ vio_vmodem->svq = virtio_add_queue(&vio_vmodem->vdev, 256, virtio_vmodem_send);
+ vio_vmodem->qdev = dev;
+
+ vio_vmodem->bh = qemu_bh_new(maru_vmodem_bh, vio_vmodem);
+
+ INFO("finish the vmodem device initialization.\n");
+}
+
+static void virtio_vmodem_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+ INFO("destroy vmodem device\n");
+
+ if (vio_vmodem->bh) {
+ qemu_bh_delete(vio_vmodem->bh);
+ }
+
+ qemu_mutex_destroy(&vio_vmodem->mutex);
+ virtio_cleanup(vdev);
+}
+
+static void virtio_vmodem_reset(VirtIODevice *vdev)
+{
+ INFO("virtio_vmodem_reset.\n");
+}
+
+
+static void virtio_vmodem_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->realize = virtio_vmodem_realize;
+ vdc->unrealize = virtio_vmodem_unrealize;
+ vdc->get_features = virtio_vmodem_get_features;
+ vdc->reset = virtio_vmodem_reset;
+}
+
+
+
+static const TypeInfo virtio_device_info = {
+ .name = TYPE_VIRTIO_VMODEM,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIOVModem),
+ .class_init = virtio_vmodem_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
--- /dev/null
+/*
+ * Virtio Virtual Modem Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Sooyoung Ha <yoosah.ha@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_VIRTIO_VMODEM_H_
+#define MARU_VIRTIO_VMODEM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+typedef struct VirtIOVirtualModem{
+ VirtIODevice vdev;
+ VirtQueue *rvq;
+ VirtQueue *svq;
+ DeviceState *qdev;
+
+ QemuMutex mutex;
+ QEMUBH *bh;
+} VirtIOVModem;
+
+#define TYPE_VIRTIO_VMODEM "virtio-vmodem-device"
+#define VIRTIO_VMODEM(obj) \
+ OBJECT_CHECK(VirtIOVModem, (obj), TYPE_VIRTIO_VMODEM)
+
+bool send_to_vmodem(const uint32_t route, char *data, const uint32_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* MARU_VIRTIO_VMODEM_H_ */
+++ /dev/null
-/*
- * Emulator SDB Notification Server
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung choi <jinhyung2.choi@samsung.com>
- * MunKyu Im <munkyu.im@samsung.com>
- * Sangho Park <sangho1206.park@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include "qemu/sockets.h"
-
-#include "hw/maru_virtio_hwkey.h"
-#include "hw/maru_pm.h"
-#include "skin/maruskin_server.h"
-#include "ecs/ecs.h"
-
-#include "emulator.h"
-#include "debug_ch.h"
-#include "sdb_noti_server.h"
-
-MULTI_DEBUG_CHANNEL(qemu, sdb_noti);
-
-#define RECV_BUF_SIZE 32
-
-typedef struct SDB_Noti_Server {
- int server_fd;
- GIOChannel *server_chan;
- guint server_tag;
-} SDB_Noti_Server;
-
-typedef struct SDB_Client {
- int port;
- struct sockaddr_in addr;
- char serial[RECV_BUF_SIZE];
-
- QTAILQ_ENTRY(SDB_Client) next;
-} SDB_Client;
-
-static QTAILQ_HEAD(SDB_ClientHead, SDB_Client)
-clients = QTAILQ_HEAD_INITIALIZER(clients);
-
-static SDB_Noti_Server *current_server;
-static QemuMutex mutex_clients;
-
-static void remove_sdb_client(SDB_Client* client)
-{
- if (client == NULL) {
- return;
- }
-
- qemu_mutex_lock(&mutex_clients);
-
- QTAILQ_REMOVE(&clients, client, next);
-
- qemu_mutex_unlock(&mutex_clients);
-
- g_free(client);
-}
-
-static void send_to_sdb_client(SDB_Client* client, int state)
-{
- struct sockaddr_in sock_addr;
- int s, slen = sizeof(sock_addr);
- int serial_len = 0;
- char buf [32];
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
- INFO("socket creation error! %d\n", errno);
- return;
- }
-
- memset(&sock_addr, 0, sizeof(sock_addr));
-
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_port = htons(client->port);
- sock_addr.sin_addr = (client->addr).sin_addr;
-
- if (connect(s, (struct sockaddr*)&sock_addr, slen) == -1) {
- INFO("connect error! remove this client.\n");
- remove_sdb_client(client);
- close(s);
- return;
- }
-
- memset(buf, 0, sizeof(buf));
-
- serial_len = strlen(client->serial);
-
- // send message "[4 digit message length]host:sync:emulator-26101:[0|1]"
- sprintf(buf, "%04xhost:sync:%s:%01d", (serial_len + 12), client->serial, state);
-
- INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr));
-
- if (send(s, buf, sizeof(buf), 0) == -1)
- {
- INFO("send error! remove this client.\n");
- remove_sdb_client(client);
- }
-
- close(s);
-}
-
-void notify_all_sdb_clients(int state)
-{
- qemu_mutex_lock(&mutex_clients);
- SDB_Client *client, *next;
-
- QTAILQ_FOREACH_SAFE(client, &clients, next, next)
- {
- send_to_sdb_client(client, state);
- }
- qemu_mutex_unlock(&mutex_clients);
-
-}
-
-static void add_sdb_client(struct sockaddr_in* addr, int port, const char* serial)
-{
- SDB_Client *cli = NULL;
- SDB_Client *client = NULL, *next;
-
- if (addr == NULL) {
- INFO("SDB_Client client's address is EMPTY.\n");
- return;
- } else if (serial == NULL || strlen(serial) <= 0) {
- INFO("SDB_Client client's serial is EMPTY.\n");
- return;
- } else if (strlen(serial) > RECV_BUF_SIZE) {
- INFO("SDB_Client client's serial is too long. %s\n", serial);
- return;
- }
-
- qemu_mutex_lock(&mutex_clients);
- QTAILQ_FOREACH_SAFE(cli, &clients, next, next)
- {
- if (!strcmp(serial, cli->serial) && !strcmp(inet_ntoa(addr->sin_addr), inet_ntoa((cli->addr).sin_addr))) {
- INFO("Client cannot be duplicated.\n");
- qemu_mutex_unlock(&mutex_clients);
- return;
- }
- }
- qemu_mutex_unlock(&mutex_clients);
-
- client = g_malloc0(sizeof(SDB_Client));
- if (NULL == client) {
- INFO("SDB_Client allocation failed.\n");
- return;
- }
-
- memcpy(&client->addr, addr, sizeof(struct sockaddr_in));
- client->port = port;
- strcpy(client->serial, serial);
-
- qemu_mutex_lock(&mutex_clients);
-
- QTAILQ_INSERT_TAIL(&clients, client, next);
-
- qemu_mutex_unlock(&mutex_clients);
-
- INFO("Added new sdb client. ip: %s, port: %d, serial: %s\n", inet_ntoa((client->addr).sin_addr), client->port, client->serial);
-
- send_to_sdb_client(client, runstate_check(RUN_STATE_SUSPENDED));
-}
-
-static int parse_val(char* buff, unsigned char data, char* parsbuf)
-{
- int count = 0;
-
- while (1) {
- if (count > 12) {
- return -1;
- }
-
- if (buff[count] == data) {
- count++;
- strncpy(parsbuf, buff, count);
- return count;
- }
-
- count++;
- }
-
- return 0;
-}
-
-#define SDB_SERVER_PORT 26097
-static void register_sdb_server(char* readbuf, struct sockaddr_in* client_addr)
-{
- int port = 0;
- char token[] = "\n";
- char* ret = NULL;
- char* serial = NULL;
-
- ret = strtok(readbuf, token);
- if (ret == NULL) {
- INFO("command is not found.");
- return;
- }
-
- serial = strtok(NULL, token);
- if (serial == NULL) {
- INFO("serial is not found.");
- return;
- }
-
- port = SDB_SERVER_PORT;
-
- add_sdb_client(client_addr, port, serial);
-}
-
-#define PRESS 1
-#define RELEASE 2
-#define POWER_KEY 116
-static void wakeup_guest(void)
-{
- // FIXME: Temporarily working model.
- // It must be fixed as the way it works.
- maru_hwkey_event(PRESS, POWER_KEY);
- maru_hwkey_event(RELEASE, POWER_KEY);
-}
-
-static void suspend_lock_state(int state)
-{
- ecs_suspend_lock_state(state);
-}
-
-static void command_handler(char* readbuf, struct sockaddr_in* client_addr)
-{
- char command[RECV_BUF_SIZE];
- memset(command, '\0', sizeof(command));
-
- parse_val(readbuf, 0x0a, command);
-
- TRACE("----------------------------------------\n");
- TRACE("command:%s\n", command);
- if (strcmp(command, "2\n" ) == 0) {
- notify_sdb_daemon_start();
- } else if (strcmp(command, "5\n") == 0) {
- register_sdb_server(readbuf, client_addr);
- } else if (strcmp(command, "6\n") == 0) {
- wakeup_guest();
- } else if (strcmp(command, "7\n") == 0) {
- suspend_lock_state(SUSPEND_LOCK);
- } else if (strcmp(command, "8\n") == 0) {
- suspend_lock_state(SUSPEND_UNLOCK);
- } else {
- INFO("!!! unknown command : %s\n", command);
- }
- TRACE("========================================\n");
-}
-
-static void close_clients(void)
-{
- qemu_mutex_lock(&mutex_clients);
- SDB_Client * client, *next;
-
- QTAILQ_FOREACH_SAFE(client, &clients, next, next)
- {
- QTAILQ_REMOVE(&clients, client, next);
-
- if (NULL != client)
- {
- g_free(client);
- }
- }
-
- qemu_mutex_unlock(&mutex_clients);
-}
-
-static void close_server(void)
-{
- if (current_server == NULL) {
- return;
- }
-
- close_clients();
-
- if (current_server->server_fd > 0) {
- if (current_server->server_tag) {
- g_source_remove(current_server->server_tag);
- current_server->server_tag = 0;
- }
- if (current_server->server_chan) {
- g_io_channel_unref(current_server->server_chan);
- }
- closesocket(current_server->server_fd);
- }
-
- g_free(current_server);
-
- qemu_mutex_destroy(&mutex_clients);
-}
-
-static gboolean sdb_noti_read(GIOChannel *channel, GIOCondition cond, void *opaque)
-{
- int recv_cnt = 0;
- struct sockaddr_in client_addr;
- socklen_t client_len;
- char readbuf[RECV_BUF_SIZE + 1];
- SDB_Noti_Server *server = opaque;
-
- memset(&readbuf, 0, sizeof(readbuf));
-
- recv_cnt = recvfrom(server->server_fd, readbuf, RECV_BUF_SIZE, 0,
- (struct sockaddr*) &client_addr, &client_len);
-
- if (recv_cnt > 0) {
- command_handler((char*)readbuf, &client_addr);
- } else if (recv_cnt == 0) {
- INFO("noti server recvfrom returned 0.\n");
- } else {
-#ifdef _WIN32
- errno = WSAGetLastError();
-#endif
- TRACE("recvfrom error case (it can be from non-blocking socket): %d", errno);
- }
-
- return TRUE;
-}
-
-static int create_UDP_server(SDB_Noti_Server *server, int port)
-{
- struct sockaddr_in server_addr;
- int opt = 1;
-
- if ((server->server_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
- INFO("create listen socket error:%d\n", errno);
- return -1;
- }
-
- memset(&server_addr, '\0', sizeof(server_addr));
- server_addr.sin_family = PF_INET;
- server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- server_addr.sin_port = htons(port);
-
- qemu_set_nonblock(server->server_fd);
-
- if (qemu_setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
- INFO("setsockopt SO_REUSEADDR is failed.: %d\n", errno);
- return -1;
- }
-
- if (bind(server->server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
- INFO("sdb noti server bind error: %d", errno);
- return -1;
- }
-
- return 0;
-}
-
-static GIOChannel *io_channel_from_socket(int fd)
-{
- GIOChannel *chan;
-
- if (fd == -1) {
- return NULL;
- }
-
-#ifdef _WIN32
- chan = g_io_channel_win32_new_socket(fd);
-#else
- chan = g_io_channel_unix_new(fd);
-#endif
-
- g_io_channel_set_encoding(chan, NULL, NULL);
- g_io_channel_set_buffered(chan, FALSE);
-
- return chan;
-}
-
-static void sdb_noti_server_notify_exit(Notifier *notifier, void *data)
-{
- INFO("shutdown sdb notification server.\n");
- close_server();
-}
-
-static Notifier sdb_noti_server_exit = { .notify = sdb_noti_server_notify_exit };
-
-void start_sdb_noti_server(int server_port)
-{
- SDB_Noti_Server *server;
- int ret;
-
- INFO("start sdb noti server thread.\n");
-
- server = g_malloc0(sizeof(SDB_Noti_Server));
- if (server == NULL) {
- INFO("SDB Notification server allocation is failed.\n");
- return;
- }
-
- ret = create_UDP_server(server, server_port);
- if (ret < 0) {
- INFO("failed to create UDP server\n");
- close_server();
- return;
- }
-
- server->server_chan = io_channel_from_socket(server->server_fd);
- server->server_tag = g_io_add_watch(server->server_chan, G_IO_IN, sdb_noti_read, server);
-
- current_server = server;
-
- qemu_mutex_init(&mutex_clients);
-
- INFO("success to bind port[127.0.0.1:%d/udp] for sdb noti server in host \n", server_port);
-
- emulator_add_exit_notifier(&sdb_noti_server_exit);
-}
-
+++ /dev/null
-/*
- * Emulator SDB Notification Server
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact:
- * Jinhyung choi <jinhyung2.choi@samsung.com>
- * MunKyu Im <munkyu.im@samsung.com>
- * Sangho Park <sangho1206.park@samsung.com>
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#ifndef SDB_NOTI_SERVER_H_
-#define SDB_NOTI_SERVER_H_
-
-void start_sdb_noti_server(int server_port);
-
-#define STATE_RUNNING 0
-#define STATE_SUSPEND 1
-void notify_all_sdb_clients(int state);
-
-#endif
#ifndef MARUSKIN_KEYMAP_H_
#define MARUSKIN_KEYMAP_H_
-#include "hw/maru_virtio_keyboard.h"
+#include "hw/virtio/maru_virtio_keyboard.h"
/* keep it consistent with emulator-skin(swt) virtual keycode */
#define JAVA_KEYCODE_BIT (1 << 24)
#include "maru_common.h"
#include "maruskin_operation.h"
-#include "hw/maru_brightness.h"
-#include "hw/maru_virtio_hwkey.h"
-#include "hw/maru_virtio_touchscreen.h"
+#include "hw/pci/maru_brightness.h"
+#include "hw/virtio/maru_virtio_hwkey.h"
+#include "hw/virtio/maru_virtio_touchscreen.h"
#include "display/maru_display.h"
#include "emulator.h"
#include "debug_ch.h"
#sdb
obj-y += sdb.o
+# sdb noti server
+obj-y += sdb_noti_server.o
+
# check gl
obj-y += check_gl_core.o
obj-$(CONFIG_LINUX) += check_gl_glx.o
--- /dev/null
+/*
+ * Emulator SDB Notification Server
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu/sockets.h"
+
+#include "hw/maru_pm.h"
+#include "hw/virtio/maru_virtio_hwkey.h"
+#include "skin/maruskin_server.h"
+#include "ecs/ecs.h"
+
+#include "emulator.h"
+#include "debug_ch.h"
+#include "sdb_noti_server.h"
+
+MULTI_DEBUG_CHANNEL(qemu, sdb_noti);
+
+#define RECV_BUF_SIZE 32
+
+typedef struct SDB_Noti_Server {
+ int server_fd;
+ GIOChannel *server_chan;
+ guint server_tag;
+} SDB_Noti_Server;
+
+typedef struct SDB_Client {
+ int port;
+ struct sockaddr_in addr;
+ char serial[RECV_BUF_SIZE];
+
+ QTAILQ_ENTRY(SDB_Client) next;
+} SDB_Client;
+
+static QTAILQ_HEAD(SDB_ClientHead, SDB_Client)
+clients = QTAILQ_HEAD_INITIALIZER(clients);
+
+static SDB_Noti_Server *current_server;
+static QemuMutex mutex_clients;
+
+static void remove_sdb_client(SDB_Client* client)
+{
+ if (client == NULL) {
+ return;
+ }
+
+ qemu_mutex_lock(&mutex_clients);
+
+ QTAILQ_REMOVE(&clients, client, next);
+
+ qemu_mutex_unlock(&mutex_clients);
+
+ g_free(client);
+}
+
+static void send_to_sdb_client(SDB_Client* client, int state)
+{
+ struct sockaddr_in sock_addr;
+ int s, slen = sizeof(sock_addr);
+ int serial_len = 0;
+ char buf [32];
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
+ INFO("socket creation error! %d\n", errno);
+ return;
+ }
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_port = htons(client->port);
+ sock_addr.sin_addr = (client->addr).sin_addr;
+
+ if (connect(s, (struct sockaddr*)&sock_addr, slen) == -1) {
+ INFO("connect error! remove this client.\n");
+ remove_sdb_client(client);
+ close(s);
+ return;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ serial_len = strlen(client->serial);
+
+ // send message "[4 digit message length]host:sync:emulator-26101:[0|1]"
+ sprintf(buf, "%04xhost:sync:%s:%01d", (serial_len + 12), client->serial, state);
+
+ INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr));
+
+ if (send(s, buf, sizeof(buf), 0) == -1)
+ {
+ INFO("send error! remove this client.\n");
+ remove_sdb_client(client);
+ }
+
+ close(s);
+}
+
+void notify_all_sdb_clients(int state)
+{
+ qemu_mutex_lock(&mutex_clients);
+ SDB_Client *client, *next;
+
+ QTAILQ_FOREACH_SAFE(client, &clients, next, next)
+ {
+ send_to_sdb_client(client, state);
+ }
+ qemu_mutex_unlock(&mutex_clients);
+
+}
+
+static void add_sdb_client(struct sockaddr_in* addr, int port, const char* serial)
+{
+ SDB_Client *cli = NULL;
+ SDB_Client *client = NULL, *next;
+
+ if (addr == NULL) {
+ INFO("SDB_Client client's address is EMPTY.\n");
+ return;
+ } else if (serial == NULL || strlen(serial) <= 0) {
+ INFO("SDB_Client client's serial is EMPTY.\n");
+ return;
+ } else if (strlen(serial) > RECV_BUF_SIZE) {
+ INFO("SDB_Client client's serial is too long. %s\n", serial);
+ return;
+ }
+
+ qemu_mutex_lock(&mutex_clients);
+ QTAILQ_FOREACH_SAFE(cli, &clients, next, next)
+ {
+ if (!strcmp(serial, cli->serial) && !strcmp(inet_ntoa(addr->sin_addr), inet_ntoa((cli->addr).sin_addr))) {
+ INFO("Client cannot be duplicated.\n");
+ qemu_mutex_unlock(&mutex_clients);
+ return;
+ }
+ }
+ qemu_mutex_unlock(&mutex_clients);
+
+ client = g_malloc0(sizeof(SDB_Client));
+ if (NULL == client) {
+ INFO("SDB_Client allocation failed.\n");
+ return;
+ }
+
+ memcpy(&client->addr, addr, sizeof(struct sockaddr_in));
+ client->port = port;
+ strcpy(client->serial, serial);
+
+ qemu_mutex_lock(&mutex_clients);
+
+ QTAILQ_INSERT_TAIL(&clients, client, next);
+
+ qemu_mutex_unlock(&mutex_clients);
+
+ INFO("Added new sdb client. ip: %s, port: %d, serial: %s\n", inet_ntoa((client->addr).sin_addr), client->port, client->serial);
+
+ send_to_sdb_client(client, runstate_check(RUN_STATE_SUSPENDED));
+}
+
+static int parse_val(char* buff, unsigned char data, char* parsbuf)
+{
+ int count = 0;
+
+ while (1) {
+ if (count > 12) {
+ return -1;
+ }
+
+ if (buff[count] == data) {
+ count++;
+ strncpy(parsbuf, buff, count);
+ return count;
+ }
+
+ count++;
+ }
+
+ return 0;
+}
+
+#define SDB_SERVER_PORT 26097
+static void register_sdb_server(char* readbuf, struct sockaddr_in* client_addr)
+{
+ int port = 0;
+ char token[] = "\n";
+ char* ret = NULL;
+ char* serial = NULL;
+
+ ret = strtok(readbuf, token);
+ if (ret == NULL) {
+ INFO("command is not found.");
+ return;
+ }
+
+ serial = strtok(NULL, token);
+ if (serial == NULL) {
+ INFO("serial is not found.");
+ return;
+ }
+
+ port = SDB_SERVER_PORT;
+
+ add_sdb_client(client_addr, port, serial);
+}
+
+#define PRESS 1
+#define RELEASE 2
+#define POWER_KEY 116
+static void wakeup_guest(void)
+{
+ // FIXME: Temporarily working model.
+ // It must be fixed as the way it works.
+ maru_hwkey_event(PRESS, POWER_KEY);
+ maru_hwkey_event(RELEASE, POWER_KEY);
+}
+
+static void suspend_lock_state(int state)
+{
+ ecs_suspend_lock_state(state);
+}
+
+static void command_handler(char* readbuf, struct sockaddr_in* client_addr)
+{
+ char command[RECV_BUF_SIZE];
+ memset(command, '\0', sizeof(command));
+
+ parse_val(readbuf, 0x0a, command);
+
+ TRACE("----------------------------------------\n");
+ TRACE("command:%s\n", command);
+ if (strcmp(command, "2\n" ) == 0) {
+ notify_sdb_daemon_start();
+ } else if (strcmp(command, "5\n") == 0) {
+ register_sdb_server(readbuf, client_addr);
+ } else if (strcmp(command, "6\n") == 0) {
+ wakeup_guest();
+ } else if (strcmp(command, "7\n") == 0) {
+ suspend_lock_state(SUSPEND_LOCK);
+ } else if (strcmp(command, "8\n") == 0) {
+ suspend_lock_state(SUSPEND_UNLOCK);
+ } else {
+ INFO("!!! unknown command : %s\n", command);
+ }
+ TRACE("========================================\n");
+}
+
+static void close_clients(void)
+{
+ qemu_mutex_lock(&mutex_clients);
+ SDB_Client * client, *next;
+
+ QTAILQ_FOREACH_SAFE(client, &clients, next, next)
+ {
+ QTAILQ_REMOVE(&clients, client, next);
+
+ if (NULL != client)
+ {
+ g_free(client);
+ }
+ }
+
+ qemu_mutex_unlock(&mutex_clients);
+}
+
+static void close_server(void)
+{
+ if (current_server == NULL) {
+ return;
+ }
+
+ close_clients();
+
+ if (current_server->server_fd > 0) {
+ if (current_server->server_tag) {
+ g_source_remove(current_server->server_tag);
+ current_server->server_tag = 0;
+ }
+ if (current_server->server_chan) {
+ g_io_channel_unref(current_server->server_chan);
+ }
+ closesocket(current_server->server_fd);
+ }
+
+ g_free(current_server);
+
+ qemu_mutex_destroy(&mutex_clients);
+}
+
+static gboolean sdb_noti_read(GIOChannel *channel, GIOCondition cond, void *opaque)
+{
+ int recv_cnt = 0;
+ struct sockaddr_in client_addr;
+ socklen_t client_len;
+ char readbuf[RECV_BUF_SIZE + 1];
+ SDB_Noti_Server *server = opaque;
+
+ memset(&readbuf, 0, sizeof(readbuf));
+
+ recv_cnt = recvfrom(server->server_fd, readbuf, RECV_BUF_SIZE, 0,
+ (struct sockaddr*) &client_addr, &client_len);
+
+ if (recv_cnt > 0) {
+ command_handler((char*)readbuf, &client_addr);
+ } else if (recv_cnt == 0) {
+ INFO("noti server recvfrom returned 0.\n");
+ } else {
+#ifdef _WIN32
+ errno = WSAGetLastError();
+#endif
+ TRACE("recvfrom error case (it can be from non-blocking socket): %d", errno);
+ }
+
+ return TRUE;
+}
+
+static int create_UDP_server(SDB_Noti_Server *server, int port)
+{
+ struct sockaddr_in server_addr;
+ int opt = 1;
+
+ if ((server->server_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ INFO("create listen socket error:%d\n", errno);
+ return -1;
+ }
+
+ memset(&server_addr, '\0', sizeof(server_addr));
+ server_addr.sin_family = PF_INET;
+ server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ server_addr.sin_port = htons(port);
+
+ qemu_set_nonblock(server->server_fd);
+
+ if (qemu_setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
+ INFO("setsockopt SO_REUSEADDR is failed.: %d\n", errno);
+ return -1;
+ }
+
+ if (bind(server->server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
+ INFO("sdb noti server bind error: %d", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static GIOChannel *io_channel_from_socket(int fd)
+{
+ GIOChannel *chan;
+
+ if (fd == -1) {
+ return NULL;
+ }
+
+#ifdef _WIN32
+ chan = g_io_channel_win32_new_socket(fd);
+#else
+ chan = g_io_channel_unix_new(fd);
+#endif
+
+ g_io_channel_set_encoding(chan, NULL, NULL);
+ g_io_channel_set_buffered(chan, FALSE);
+
+ return chan;
+}
+
+static void sdb_noti_server_notify_exit(Notifier *notifier, void *data)
+{
+ INFO("shutdown sdb notification server.\n");
+ close_server();
+}
+
+static Notifier sdb_noti_server_exit = { .notify = sdb_noti_server_notify_exit };
+
+void start_sdb_noti_server(int server_port)
+{
+ SDB_Noti_Server *server;
+ int ret;
+
+ INFO("start sdb noti server thread.\n");
+
+ server = g_malloc0(sizeof(SDB_Noti_Server));
+ if (server == NULL) {
+ INFO("SDB Notification server allocation is failed.\n");
+ return;
+ }
+
+ ret = create_UDP_server(server, server_port);
+ if (ret < 0) {
+ INFO("failed to create UDP server\n");
+ close_server();
+ return;
+ }
+
+ server->server_chan = io_channel_from_socket(server->server_fd);
+ server->server_tag = g_io_add_watch(server->server_chan, G_IO_IN, sdb_noti_read, server);
+
+ current_server = server;
+
+ qemu_mutex_init(&mutex_clients);
+
+ INFO("success to bind port[127.0.0.1:%d/udp] for sdb noti server in host \n", server_port);
+
+ emulator_add_exit_notifier(&sdb_noti_server_exit);
+}
+
--- /dev/null
+/*
+ * Emulator SDB Notification Server
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef SDB_NOTI_SERVER_H_
+#define SDB_NOTI_SERVER_H_
+
+void start_sdb_noti_server(int server_port);
+
+#define STATE_RUNNING 0
+#define STATE_SUSPEND 1
+void notify_all_sdb_clients(int state);
+
+#endif