aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:04:49 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:04:49 -0800
commitdf7881f07f53b041dc0568be8528e9dbb74994cc (patch)
tree1b3e036f7df4241bf0c2d527b73198c50e1d7891
parent55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (diff)
downloadexternal_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.zip
external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.tar.gz
external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.tar.bz2
Code drop from //branches/cupcake/...@124589
-rw-r--r--Android.mk2
-rw-r--r--CHANGES.TXT94
-rw-r--r--INSTALL119
-rw-r--r--Makefile208
-rw-r--r--Makefile.android95
-rw-r--r--Makefile.target587
-rw-r--r--README24
-rw-r--r--README.distrib16
-rw-r--r--TODO55
-rw-r--r--VERSION1
-rwxr-xr-xandroid-configure.sh668
-rwxr-xr-xandroid-rebuild.sh259
-rw-r--r--android.h7
-rw-r--r--android/build/binary.make29
-rw-r--r--android/build/clear_vars.make30
-rw-r--r--android/build/definitions.make88
-rw-r--r--android/build/getdir.make19
-rw-r--r--android/build/host_executable.make36
-rw-r--r--android/build/host_static_library.make35
-rwxr-xr-xandroid/build/mkdeps.sh48
-rw-r--r--android/config/check-alsa.c107
-rw-r--r--android/config/check-esd.c67
-rw-r--r--android/globals.h33
-rwxr-xr-xandroid/tools/gen-hw-config.py141
-rw-r--r--android/utils/debug.h18
-rw-r--r--android/utils/dirscanner.c203
-rw-r--r--android/utils/dirscanner.h25
-rw-r--r--android/utils/ini.c366
-rw-r--r--android/utils/ini.h121
-rw-r--r--android/vm/hardware-properties.ini158
-rw-r--r--android/vm/hw-config-defs.h165
-rw-r--r--android/vm/hw-config.c39
-rw-r--r--android/vm/hw-config.h46
-rw-r--r--android/vm/info.c1534
-rw-r--r--android/vm/info.h161
-rw-r--r--android_console.c12
-rw-r--r--android_debug.h2
-rw-r--r--android_help.c99
-rw-r--r--android_hw_control.c201
-rw-r--r--android_hw_control.h38
-rw-r--r--android_main.c785
-rw-r--r--android_option.c84
-rw-r--r--android_options.h7
-rw-r--r--android_qemud.c42
-rw-r--r--android_qemud.h5
-rw-r--r--android_utils.c268
-rw-r--r--android_utils.h56
-rw-r--r--audio/alsaaudio.c163
-rw-r--r--audio/esdaudio.c46
-rwxr-xr-xconfigure1112
-rwxr-xr-xdistrib/make-distrib.sh2
-rw-r--r--dynlink.h107
-rw-r--r--framebuffer.c2
-rw-r--r--framebuffer.h130
-rw-r--r--hw/android_arm.c5
-rw-r--r--hw/goldfish_audio.c58
-rw-r--r--hw/goldfish_fb.c2
-rw-r--r--osdep.h1
-rw-r--r--proxy/proxy_common.c345
-rw-r--r--proxy/proxy_common.h18
-rw-r--r--proxy/proxy_http.c235
-rw-r--r--proxy/proxy_http_connector.c213
-rw-r--r--proxy/proxy_http_int.h38
-rw-r--r--proxy/proxy_http_rewriter.c1132
-rw-r--r--proxy/proxy_int.h146
-rw-r--r--qemu-binfmt-conf.sh39
-rw-r--r--qemu-doc.texi1875
-rw-r--r--shaper.c2
-rw-r--r--skins/skin_argb.h2
-rw-r--r--skins/skin_keyset.c3
-rw-r--r--skins/skin_keyset.h1
-rw-r--r--skins/skin_trackball.c53
-rw-r--r--skins/skin_trackball.h4
-rw-r--r--skins/skin_window.c406
-rw-r--r--skins/skin_window.h10
-rw-r--r--slirp/if.c2
-rw-r--r--slirp/socket.c4
-rw-r--r--slirp/tcp_subr.c61
-rw-r--r--sockets.c68
-rw-r--r--sockets.h9
-rw-r--r--telephony/sysdeps_qemu.c4
-rwxr-xr-xtexi2pod.pl428
-rw-r--r--translate.make3
-rw-r--r--vl.c4
84 files changed, 8232 insertions, 5704 deletions
diff --git a/Android.mk b/Android.mk
index 5cff342..0b02fdb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -2,7 +2,7 @@
# through the 'm' or 'mm' build commands. if not, we use the
# standard QEMU Makefile
#
-ifeq ($(DEFAULT_TARGET),droid)
+ifeq ($(DEFAULT_GOAL),droid)
LOCAL_PATH:= $(call my-dir)
include $(LOCAL_PATH)/Makefile.android
else
diff --git a/CHANGES.TXT b/CHANGES.TXT
index b6ced26..8f4b87a 100644
--- a/CHANGES.TXT
+++ b/CHANGES.TXT
@@ -10,7 +10,58 @@ Versions:
1.4 => Internal release (build 84853)
1.5 => SDK 0.9_r1
1.6 => SDK 1.0_r1
- 1.7 => SDK 1.0_r2 (planned, unreleased)
+ 1.7 => SDK 1.0_r2
+ 1.8 => (unreleased, planned, named likely to change)
+
+==============================================================================
+Changes between 1.7 and 1.8
+
+IMPORTANT CHANGES:
+
+- The emulator now requires that you specify a virtual machine name when
+ starting the emulator, prefixed with the '@' sign. For example, to start
+ the 'foo' virtual machine, type:
+
+ emulator @foo
+
+ Each VM corresponds to a directory used to store mutable disk images, an
+ optional system image/kernel/sdcard, plus some configuration file(s).
+
+ The command-line tool 'android' that comes with the SDK can be used to
+ create/list/remove virtual machines on your system.
+
+ Note that the '@<name>' form is a convenience shortcut for '-vm <name>'.
+ It is thus possible to place options after the VM name on your command
+ line, as in:
+
+ emulator @foo -verbose -shell
+
+ Finally, when building the Android platform source tree, a VM name is not
+ required and 'emulator' will start a new emulator instance exactly as
+ previously.
+
+- Hardware emulation is now limited to the corresponding Android Virtual
+ Machine's configuration. This means it is now possible to not emulate
+ a touch-screen, trackball, dpad, keyboard, modem, etc...
+
+ Note that in the case of the Android build system, all hardware properties
+ are enabled by default, so this only affects "normal" virtual machines
+ created with the 'android' tool.
+
+OTHER:
+
+- A new console command 'vm name' can be used to query the name of the
+ virtual machine running in the emulator. Note that it will be '<build>'
+ if you run from the Android build system.
+
+ Also, the emulator's window title also displays the VM name now.
+
+- The option '-memory <size>' has been added. <memory> must be an integer
+ specifying the amount of physical RAM in the emulated device in megabytes.
+ The default value is 96.
+
+- The '-skindir <path>' option now requires that you specify a '-skin <name>'
+ option as well.
==============================================================================
Changes between 1.6 and 1.7
@@ -21,11 +72,22 @@ IMPORTANT BUG FIXES:
- Do not leave temporary files in Android app-specific directory on Win32
-- Trackball mode toggle key (Ctrl-T by default) now works after rotating
- your skin once.
+- Support for HTTP/HTTPS proxies has been considerably improved and should now
+ "just work" with a lot more HTTP proxies. In case of problem, use the
+ -debug-proxy option to dump debugging data to stderr.
OTHER:
+- Trackball emulation has changed. First, the awkward "Control-T" keybinding
+ is gone. Instead, you can now:
+
+ - press 'Delete' to show the trackball and have it disappear as soon
+ as your release the key.
+
+ - press 'F6' to perform a persistent trackball mode toggle.
+
+ Also, trackball emulation is fixed in rotated/landscape mode now.
+
- New option '-nand-limits <limits>' allows you to send a signal to a remote
process when a read or write threshold on flash storage is reached. This is
only useful for hardcore Android system hackers.
@@ -34,7 +96,13 @@ OTHER:
tolerate the _GNU_SOURCE macro definition anymore)
- Fix Win32 emulator to support SD Card images larger than 2 GiB
-
+
+- The non-Android build system has been completely rewritten to allow building
+ the emulator on Linux x86_64. Also, there is now a single Makefile that
+ drives the build in both Android and non-Android modes.
+
+- '-qemu <other-options>' works again
+
==============================================================================
Changes between 1.5 and 1.6
@@ -76,7 +144,23 @@ Changes between 1.4 and 1.5
IMPORTANT BUG FIXES:
-- fix spurious discards of SMS messages when using two emulators.
+- Fix spurious discards of SMS messages when using two emulators.
+
+OTHER:
+
+- Get rid of EsounD-related freezes on Linux (again)
+
+- Fix the documentation in -help-audio. '-audio list' doesn't work; one
+ needs to call -help-audio-out and -help-audio-in to get the list of valid
+ audio backends
+
+- Fix scrollwheel Dpad emulation in rotated mode. before that, using the
+ scroll-wheel would always generated Dpad Up/Down events, even when in
+ landscape mode.
+
+- Re-enable CPU fault emulation in case of unaligned data access. This was
+ previously disabled because it crashed the emulated kernel in previous
+ releases.
==============================================================================
Changes between 1.3 and 1.4
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..95b64e1
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,119 @@
+This package contains the sources to the Android emulator program.
+
+Supported Development Platforms:
+--------------------------------
+
+The Android emulator can be built on the following platforms:
+
+ - Linux 32-bits
+ - Linux 64-bits (*only* generates 32-bit emulator binary)
+ - Darwin x86
+ - Darwin ppc (experimental only)
+ - Windows x86 (through Cygwin only)
+
+Note that development on 64-bit versions of Darwin and Windows is
+not supported. The 32-bit emulator binary should run normally on
+these platforms though.
+
+The Windows emulator binary is built using the -no-cygwin option
+and thus doesn't depend on CYGWIN.DLL being installed on your system.
+
+It is possible to hack the android-configure.sh script to build
+a 64-bit emulator binary on Linux. Unfortunately the resulting
+program will crash pretty soon during emulation. This problem is
+due to the way the emulator works and cannot be easily fixed at
+the moment.
+
+Supported Compilers:
+--------------------
+
+The Android emulator is a heavy fork of QEMU 0.8.2, and as such,
+can only be built properly with a small number of compilers. Moreover,
+which compiler can be used depends on your platform.
+
+The following table sums up the compilers that are *known* to produce
+correct output:
+
+ Linux x86: gcc-3.4.6
+ Linux x86 and x86_64: gcc-4.2.3
+ Darwin x86: gcc-4.0.1 (build 5341)
+ Darwin ppc: gcc-3.3 (build 1819)
+
+Use any other compiler at your own risks ! A 'bad binary' usually
+results in the VM crashing either immediately or after a few seconds.
+
+Note that on Darwin, the *build* number of your compiler *is* important.
+Some builds of gcc-4.0.1 are known to generate bad binaries on Darwin x86,
+so your own fails to build an executable that works correctly.
+You can find the sources to the required gcc here:
+
+
+We distribute a file named distrib/build_gcc_qemu_darwin.sh which can be
+used as a replacement for the Apple-provided build_gcc.sh that comes with
+their gcc distribution.
+
+
+Building the emulator with the Android build system:
+----------------------------------------------------
+
+Ensure that you have properly configured your build by running the
+envsetup.sh script and using the appropriate 'lunch' command.
+
+Then type:
+
+ m emulator
+
+This will rebuild the emulator and place it in an adequate location.
+Simply type 'emulator' to start it with the currently built system
+image.
+
+
+Building the emulator without the Android build system:
+-------------------------------------------------------
+
+You can also build the emulator as a stand-alone program, by following
+these simple steps:
+
+ 1/ First, build Android's patched libSDL as a static library,
+ this can be done as:
+
+ cd $TOP/extlibs/libsdl-1.2.12
+ ./android-configure --prefix=<PATH>
+ make
+ make install
+
+ Where $TOP is the path of your open-source Android source tree, and
+ where <PATH> is any path of your chosing where the library will
+ be copied to by the 'make install' command. For example, you
+ can use $HOME/android-sdl
+
+ 2/ Configure the emulator with android-configure.sh, as in:
+
+ cd $TOP/tools/qemu
+ ./android-configure.sh --sdl-config=<PATH>
+ make
+
+ Where <PATH> is the same path you used with the --prefix option
+ when building the SDL library
+
+The emulator binary is located into objs/emulator, you can strip it and
+copy it to any location of your choosing.
+
+
+Creating an emulator source distribution package:
+-------------------------------------------------
+
+We provide a script to build a tar.gz package file that contains all the
+sources required to rebuild the emulator (i.e. it includes the patched SDL
+sources as well) plus a handy script to automate the rebuild.
+
+Simply invoke:
+
+ cd $TOP/tools/qemu
+ distrib/make-distrib.sh
+
+This script will create a tar.gz file under /tmp/android-package and will
+print its location when it completes.
+
+To rebuild the corresponding emulator, un-tar-gz the package, and run
+the 'rebuild.sh' script.
diff --git a/Makefile b/Makefile
index 9731afb..f911c2a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,165 +1,71 @@
-# Makefile for QEMU.
-
-include config-host.mak
-
-.PHONY: all clean distclean dvi info install install-doc tar tarbin \
- speed test test2 html dvi info zlib-lib libgpng-lib
-
-CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. -MMD -MP
-ifdef CONFIG_DARWIN
-CFLAGS+= -mdynamic-no-pic -I/opt/local/include
-endif
-ifeq ($(ARCH),sparc)
-CFLAGS+=-mcpu=ultrasparc
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# this is a set of definitions that allow the usage of Makefile.android
+# even if we're not using the Android build system.
+#
+
+BUILD_SYSTEM := android/build
+OBJS_DIR := objs
+CONFIG_MAKE := $(OBJS_DIR)/config.make
+CONFIG_H := $(OBJS_DIR)/config-host.h
+
+ifeq ($(wildcard $(CONFIG_MAKE)),)
+ $(error "The configuration file '$(CONFIG_MAKE)' doesnt' exist, please run the "rebuilt.sh" script)
endif
-LDFLAGS=-g
-LIBS=
-DEFINES+=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-TOOLS=
-ifdef CONFIG_STATIC
-LDFLAGS+=-static
-endif
-DOCS=
-UNAME=$(shell uname -s)
-ifneq ($(findstring CYGWIN,$(UNAME)),)
-CFLAGS+=-mno-cygwin -D_WIN32
-LDFLAGS+=-mno-cygwin
-endif
+include $(CONFIG_MAKE)
+include $(BUILD_SYSTEM)/definitions.make
-all: $(TOOLS) $(DOCS) recurse-all zlib-lib libgpng-lib
+VPATH := $(OBJS_DIR)
+VPATH += :$(SRC_PATH)/android/config
+VPATH += :$(SRC_PATH):$(SRC_PATH)/target-$(TARGET_ARCH)
-subdir-%: dyngen$(EXESUF)
- $(MAKE) -C $(subst subdir-,,$@) all
+.PHONY: all libraries executables clean clean-config clean-objs-dir \
+ clean-executables clean-libraries
-include $(SRC_PATH)/distrib/Makefile
+CLEAR_VARS := $(BUILD_SYSTEM)/clear_vars.make
+BUILD_HOST_EXECUTABLE := $(BUILD_SYSTEM)/host_executable.make
+BUILD_HOST_STATIC_LIBRARY := $(BUILD_SYSTEM)/host_static_library.make
-recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
+all: libraries executables
+EXECUTABLES :=
+LIBRARIES :=
-libz.a: subdir-distrib
+SDL_CONFIG ?= $(PREBUILT)/sdl/bin/sdl-config
+SDL_LIBS := $(filter %.a,$(shell $(SDL_CONFIG) --static-libs))
+$(foreach lib,$(SDL_LIBS), \
+ $(eval $(call copy-prebuilt-lib,$(lib))) \
+)
-dyngen$(EXESUF): dyngen.c
- $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
+clean: clean-intermediates
-clean: clean-zlib clean-libpng
-# avoid old build problems by removing potentially incorrect old files
- rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
- rm -f *.o *.d *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
- $(MAKE) -C tests clean
- for d in $(TARGET_DIRS); do \
- $(MAKE) -C $$d $@ || exit 1 ; \
- done
+distclean: clean clean-config
-distclean: clean
- rm -f config-host.mak config-host.h $(DOCS)
- rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
- for d in $(TARGET_DIRS); do \
- rm -rf $$d || exit 1 ; \
- done
+# let's roll
+include Makefile.android
-KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
-ar de en-us fi fr-be hr it lv nl pl ru th \
-common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
+libraries: $(LIBRARIES)
+executables: $(EXECUTABLES)
-install-doc: $(DOCS)
- mkdir -p "$(DESTDIR)$(docdir)"
- $(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
-ifndef CONFIG_WIN32
- mkdir -p "$(DESTDIR)$(mandir)/man1"
- $(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
-endif
+clean-intermediates:
+ rm -rf $(OBJS_DIR)/intermediates $(EXECUTABLES) $(LIBRARIES)
-install: all $(if $(BUILD_DOCS),install-doc)
- mkdir -p "$(DESTDIR)$(bindir)"
- $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
- mkdir -p "$(DESTDIR)$(datadir)"
- for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
- video.x openbios-sparc32 linux_boot.bin; do \
- $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
- done
-ifndef CONFIG_WIN32
- mkdir -p "$(DESTDIR)$(datadir)/keymaps"
- for x in $(KEYMAPS); do \
- $(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
- done
-endif
- for d in $(TARGET_DIRS); do \
- $(MAKE) -C $$d $@ || exit 1 ; \
- done
-
-# various test targets
-test speed test2: all
- $(MAKE) -C tests $@
-
-TAGS:
- etags *.[ch] tests/*.[ch]
-
-cscope:
- rm -f ./cscope.*
- find . -name "*.[ch]" -print > ./cscope.files
- cscope -b
-
-# documentation
-%.html: %.texi
- texi2html -monolithic -number $<
-
-%.info: %.texi
- makeinfo $< -o $@
-
-%.dvi: %.texi
- texi2dvi $<
-
-qemu.1: qemu-doc.texi
- $(SRC_PATH)/texi2pod.pl $< qemu.pod
- pod2man --section=1 --center=" " --release=" " qemu.pod > $@
-
-qemu-img.1: qemu-img.texi
- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod
- pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
-
-info: qemu-doc.info qemu-tech.info
-
-dvi: qemu-doc.dvi qemu-tech.dvi
-
-html: qemu-doc.html qemu-tech.html
-
-FILE=qemu-$(shell cat VERSION)
-
-# tar release (use 'make -k tar' on a checkouted tree)
-tar:
- rm -rf /tmp/$(FILE)
- cp -r . /tmp/$(FILE)
- ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
- rm -rf /tmp/$(FILE)
-
-# generate a binary distribution
-tarbin:
- ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
- $(bindir)/qemu \
- $(bindir)/qemu-system-ppc \
- $(bindir)/qemu-system-sparc \
- $(bindir)/qemu-system-x86_64 \
- $(bindir)/qemu-system-mips \
- $(bindir)/qemu-system-mipsel \
- $(bindir)/qemu-system-arm \
- $(bindir)/qemu-i386 \
- $(bindir)/qemu-arm \
- $(bindir)/qemu-armeb \
- $(bindir)/qemu-sparc \
- $(bindir)/qemu-ppc \
- $(bindir)/qemu-mips \
- $(bindir)/qemu-mipsel \
- $(bindir)/qemu-img \
- $(datadir)/bios.bin \
- $(datadir)/vgabios.bin \
- $(datadir)/vgabios-cirrus.bin \
- $(datadir)/ppc_rom.bin \
- $(datadir)/video.x \
- $(datadir)/openbios-sparc32 \
- $(datadir)/linux_boot.bin \
- $(docdir)/qemu-doc.html \
- $(docdir)/qemu-tech.html \
- $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
-
-include $(wildcard *.d)
+clean-config:
+ rm -f $(CONFIG_MAKE) $(CONFIG_H)
+# include dependency information
+CLEAN_OBJS_DIRS := $(sort $(CLEAN_OBJS_DIRS))
+-include $(wildcard $(CLEAN_OBJS_DIRS:%=%/*.d))
diff --git a/Makefile.android b/Makefile.android
index a139f4d..baf8344 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -4,8 +4,9 @@ LOCAL_PATH:= $(call my-dir)
# determine the location of platform-specific directories
#
CONFIG_DIRS := \
- $(LOCAL_PATH)/android/config \
- $(LOCAL_PATH)/android/config/$(HOST_PREBUILT_TAG)
+ $(LOCAL_PATH)/android/config \
+ $(LOCAL_PATH)/android/config/$(HOST_PREBUILT_TAG)
+
CONFIG_INCLUDES := $(CONFIG_DIRS:%=-I%)
MY_CFLAGS := $(CONFIG_INCLUDES)
@@ -20,23 +21,31 @@ ifeq ($(HOST_OS),windows)
MY_CFLAGS += -DWINVER=0x500
endif
-# We're going to use a specific version of gcc (3.4.6) if it is available
-# from the prebuilt directory. This prevents many nasty emulator problems
-# due to the way QEMU works
-#
-MY_CC :=
+MY_CC := $(HOST_CC)
-ifneq ($(strip $(wildcard $(GCCQEMU))),)
- # GCCQEMU is set by the host file under build/core/combo/
- MY_CC := $(GCCQEMU)
-endif
+# BUILD_STANDALONE_EMULATOR is only defined when building with
+# the android-rebuild.sh script. The script will also provide
+# adequate values for HOST_CC
+#
+ifneq ($(BUILD_STANDALONE_EMULATOR),true)
+ # We're going to use a specific version of gcc (3.4.6) if it is available
+ # from the prebuilt directory. This prevents many nasty emulator problems
+ # due to the way QEMU works
+ #
+ ifneq ($(strip $(wildcard $(GCCQEMU))),)
+ # GCCQEMU is set by the host file under build/core/combo/
+ MY_CC := $(GCCQEMU)
+ endif
-ifdef MY_CC
ifneq ($(USE_CCACHE),)
MY_CC := prebuilt/$(HOST_PREBUILT_TAG)/ccache/ccache $(MY_CC)
endif
-else
- MY_CC := $(HOST_CC)
+endif
+
+
+ifneq ($(combo_target)$(TARGET_SIMULATOR),HOST_true)
+my_32bit_cflags += -m32
+my_32bit_ldflags += -m32
endif
include $(CLEAR_VARS)
@@ -49,7 +58,8 @@ include $(CLEAR_VARS)
#
LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
LOCAL_CC := $(MY_CC)
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
+LOCAL_CFLAGS := $(my_32bit_cflags) $(MY_CFLAGS) $(LOCAL_CFLAGS)
+LOCAL_LDFLAGS := $(my_32bit_ldflags)
LOCAL_SRC_FILES := dyngen.c
ifeq ($(HOST_OS),windows)
@@ -127,8 +137,10 @@ include $(CLEAR_VARS)
LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
LOCAL_CC := $(MY_CC)
LOCAL_MODULE := emulator-arm
+LOCAL_LDFLAGS := $(my_32bit_ldflags)
-LOCAL_CFLAGS := -fno-PIC -fomit-frame-pointer -Wno-sign-compare
+LOCAL_CFLAGS := $(my_32bit_cflags) \
+ -fno-PIC -fomit-frame-pointer -Wno-sign-compare
LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
ifeq ($(HOST_OS),darwin)
@@ -184,12 +196,14 @@ LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
LOCAL_CC := $(MY_CC)
LOCAL_MODULE := emulator
LOCAL_STATIC_LIBRARIES := $(EMULATOR_OP_LIBRARIES) emulator-arm
+LOCAL_LDFLAGS := $(my_32bit_ldflags)
# don't remove the -fno-strict-aliasing, or you'll break things
# (e.g. slirp/network support)
#
-LOCAL_CFLAGS := -fno-PIC -fomit-frame-pointer -Wno-sign-compare \
- -fno-strict-aliasing
+LOCAL_CFLAGS := $(my_32bit_cflags) \
+ -fno-PIC -fomit-frame-pointer -Wno-sign-compare \
+ -fno-strict-aliasing -g -W -Wall -Wno-unused-parameter
LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
@@ -275,19 +289,43 @@ ifeq ($(QEMU_AUDIO_LIB),)
AUDIO_SOURCES := audio.c noaudio.c wavaudio.c sdlaudio.c wavcapture.c mixeng.c
ifeq ($(HOST_OS),darwin)
+ CONFIG_COREAUDIO ?= yes
+ endif
+
+ ifeq ($(HOST_OS),windows)
+ CONFIG_WINAUDIO ?= yes
+ endif
+
+ ifeq ($(HOST_OS),linux)
+ CONFIG_OSS ?= yes
+ CONFIG_ALSA ?= yes
+ CONFIG_ESD ?= yes
+ endif
+
+ ifeq ($(CONFIG_COREAUDIO),yes)
AUDIO_SOURCES += coreaudio.c
LOCAL_CFLAGS += -DCONFIG_COREAUDIO
LOCAL_LDLIBS += -Wl,-framework,CoreAudio
endif
- ifeq ($(HOST_OS),windows)
+ ifeq ($(CONFIG_WINAUDIO),yes)
AUDIO_SOURCES += winaudio.c
LOCAL_CFLAGS += -DCONFIG_WINAUDIO
endif
- ifeq ($(HOST_OS),linux)
- AUDIO_SOURCES += esdaudio.c alsaaudio.c audio_pt_int.c
- LOCAL_CFLAGS += -DCONFIG_ESD -DCONFIG_ALSA
+ ifeq ($(CONFIG_ALSA),yes)
+ AUDIO_SOURCES += alsaaudio.c audio_pt_int.c
+ LOCAL_CFLAGS += -DCONFIG_ALSA
+ endif
+
+ ifeq ($(CONFIG_ESD),yes)
+ AUDIO_SOURCES += esdaudio.c
+ LOCAL_CFLAGS += -DCONFIG_ESD
+ endif
+
+ ifeq ($(CONFIG_OSS),yes)
+ AUDIO_SOURCES += ossaudio.c
+ LOCAL_CFLAGS += -DCONFIG_OSS
endif
LOCAL_SRC_FILES += $(AUDIO_SOURCES:%=audio/%)
@@ -323,7 +361,11 @@ LOCAL_CFLAGS += -I$(LOCAL_PATH)/slirp
# socket proxy support
#
-PROXY_SOURCES := proxy_common.c proxy_http.c
+PROXY_SOURCES := \
+ proxy_common.c \
+ proxy_http.c \
+ proxy_http_connector.c \
+ proxy_http_rewriter.c \
LOCAL_SRC_FILES += $(PROXY_SOURCES:%=proxy/%)
LOCAL_CFLAGS += -I$(LOCAL_PATH)/proxy
@@ -381,6 +423,11 @@ VL_SOURCES := vl.c osdep.c \
android_gps.c \
android_qemud.c \
android_kmsg.c \
+ android_hw_control.c \
+ android/utils/ini.c \
+ android/utils/dirscanner.c \
+ android/vm/hw-config.c \
+ android/vm/info.c \
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lX11
@@ -406,7 +453,7 @@ endif
# add SDL-specific flags
#
-SDL_CONFIG := prebuilt/$(HOST_PREBUILT_TAG)/sdl/bin/sdl-config
+SDL_CONFIG ?= prebuilt/$(HOST_PREBUILT_TAG)/sdl/bin/sdl-config
SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
# We need to filter out the _GNU_SOURCE variable because it breaks recent
diff --git a/Makefile.target b/Makefile.target
deleted file mode 100644
index a5964b4..0000000
--- a/Makefile.target
+++ /dev/null
@@ -1,587 +0,0 @@
-include config.mak
-include $(SRC_PATH)/distrib/Makefile
-
-TARGET_BASE_ARCH:=$(TARGET_ARCH)
-TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
-VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio:$(SRC_PATH)/telephony:$(SRC_PATH)/proxy:$(SRC_PATH)/skins
-DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -I$(SRC_PATH)/telephony -I$(SRC_PATH)/proxy -I$(SRC_PATH)/skins
-CFLAGS=-Wall $(OPTIM) -g $(ZLIB_CFLAGS) $(LIBPNG_CFLAGS) -MMD -MP
-ifeq ($(CONFIG_DARWIN),yes)
-CFLAGS+=-mdynamic-no-pic
-endif
-#CFLAGS+=-Werror
-LDFLAGS=-g
-LIBS=
-HELPER_CFLAGS=$(CFLAGS)
-DYNGEN=../dyngen$(EXESUF)
-# user emulator name
-TARGET_ARCH2=$(TARGET_ARCH)
-ifeq ($(TARGET_ARCH),arm)
- ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
- TARGET_ARCH2=armeb
- endif
-endif
-# system emulator name
-ifdef CONFIG_SOFTMMU
-QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(EXESUF)
-else
-QEMU_SYSTEM=qemu-fast
-endif
-
-PROGS+=$(QEMU_SYSTEM)
-ifndef CONFIG_SOFTMMU
-CONFIG_STATIC=y
-endif
-
-ifdef CONFIG_STATIC
-LDFLAGS+=-static
-endif
-
-ifeq ($(ARCH),i386)
-OP_CFLAGS=$(CFLAGS) -O2 -fomit-frame-pointer
-CFLAGS+=-DUSE_MMX -mmmx
-ifneq ($(CONFIG_DARWIN),yes)
-OP_CFLAGS+= -mpreferred-stack-boundary=2
-else
-OP_CFLAGS+= -mpreferred-stack-boundary=4
-endif
-ifeq ($(HAVE_GCC3_OPTIONS),yes)
-OP_CFLAGS+= -falign-functions=0 -fno-gcse
-else
-OP_CFLAGS+= -malign-functions=0
-endif
-
-ifdef TARGET_GPROF
-USE_I386_LD=y
-endif
-ifdef wwCONFIG_STATIC
-USE_I386_LD=y
-endif
-ifdef USE_I386_LD
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
-else
-# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
-# that the kernel ELF loader considers as an executable. I think this
-# is the simplest way to make it self virtualizable!
-LDFLAGS+=-Wl,-shared
-endif
-endif
-
-ifeq ($(ARCH),x86_64)
-OP_CFLAGS=$(CFLAGS) -falign-functions=0
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
-endif
-
-ifeq ($(ARCH),ppc)
-CFLAGS+= -D__powerpc__
-OP_CFLAGS=$(CFLAGS)
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
-endif
-
-ifeq ($(ARCH),s390)
-OP_CFLAGS=$(CFLAGS)
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
-endif
-
-ifeq ($(ARCH),sparc)
-ifeq ($(CONFIG_SOLARIS),yes)
-CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
-LDFLAGS+=-m32
-OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
-else
-CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
-LDFLAGS+=-m32
-OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
-HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
-# -static is used to avoid g1/g3 usage by the dynamic linker
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
-endif
-endif
-
-ifeq ($(ARCH),sparc64)
-CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
-LDFLAGS+=-m64
-OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
-endif
-
-ifeq ($(ARCH),alpha)
-# -msmall-data is not used because we want two-instruction relocations
-# for the constant constructions
-OP_CFLAGS=-Wall -O2 -g
-# Ensure there's only a single GP
-CFLAGS += -msmall-data
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
-endif
-
-ifeq ($(ARCH),ia64)
-CFLAGS += -mno-sdata
-OP_CFLAGS=$(CFLAGS)
-LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
-endif
-
-ifeq ($(ARCH),arm)
-OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
-endif
-
-ifeq ($(ARCH),m68k)
-OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
-LDFLAGS+=-Wl,-T,m68k.ld
-endif
-
-ifeq ($(HAVE_GCC3_OPTIONS),yes)
-# very important to generate a return at the end of every operation
-OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
-endif
-
-ifeq ($(CONFIG_DARWIN),yes)
-CFLAGS+= -I/opt/local/include
-LIBS+=-lmx
-endif
-
-ifeq ($(CONFIG_WIN32),yes)
-UNAME := $(shell uname -s)
-ifneq ($(findstring CYGWIN,$(UNAME)),)
-CFLAGS += -mno-cygwin -D_WIN32
-LDFLAGS += -mno-cygwin -mwindows
-endif
-endif
-
-#########################################################
-
-DEFINES+=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-LIBS+=-lm
-#now using our own zlib static version
-#LIBS+=-L/usr/lib -lz
-ifdef CONFIG_WIN32
-LIBS+=-lwinmm -lws2_32 -liphlpapi
-endif
-ifdef CONFIG_SOLARIS
-LIBS+=-lsocket -lnsl -lresolv
-endif
-
-# profiling code
-ifdef TARGET_GPROF
-LDFLAGS+=-p
-main.o: CFLAGS+=-p
-endif
-
-OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
- elfload.o linuxload.o
-ifdef TARGET_HAS_BFLT
-OBJS+= flatload.o
-endif
-
-ifeq ($(TARGET_ARCH), arm)
-OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
-nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
- nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
-endif
-SRCS:= $(OBJS:.o=.c)
-OBJS+= libqemu.a
-
-# cpu emulator library
-LIBOBJS=exec.o kqemu.o translate-all.o translate-op.o cpu-exec.o\
- translate.o
-ifdef CONFIG_SOFTFLOAT
-LIBOBJS+=fpu/softfloat.o
-else
-LIBOBJS+=fpu/softfloat-native.o
-endif
-DEFINES+=-I$(SRC_PATH)/fpu
-
-ifeq ($(TARGET_BASE_ARCH), arm)
-ifdef CONFIG_TRACE
-LIBOBJS += translate-trace.o translate-all-trace.o translate-op-trace.o
-endif
-LIBOBJS+= op_helper.o helper.o
-endif
-
-# NOTE: the disassembler code is only needed for debugging
-LIBOBJS+=disas.o
-ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
-USE_I386_DIS=y
-endif
-ifeq ($(findstring x86_64, $(TARGET_ARCH) $(ARCH)),x86_64)
-USE_I386_DIS=y
-endif
-ifdef USE_I386_DIS
-LIBOBJS+=i386-dis.o
-endif
-ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
-LIBOBJS+=alpha-dis.o
-endif
-ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
-LIBOBJS+=ppc-dis.o
-endif
-ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
-LIBOBJS+=sparc-dis.o
-endif
-ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
-LIBOBJS+=arm-dis.o
-endif
-ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
-LIBOBJS+=m68k-dis.o
-endif
-
-ifdef CONFIG_GDBSTUB
-OBJS+=gdbstub.o
-endif
-
-OBJS+=android_console.o android_modem.c sim_card.o gsm.o sysdeps_qemu.o charpipe.o modem_driver.o sms.o \
- android_gps.o
-
-all: $(PROGS)
-
-ifeq ($(ARCH),alpha)
-# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
-# the address space (31 bit so sign extending doesn't matter)
- echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
-endif
-
-# must use static linking to avoid leaving stuff in virtual address space
-VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o sockets.o qemu_timers.o
-VL_OBJS+= block-cloop.o block-dmg.o block-qcow.o aes.o
-ifdef CONFIG_TRACE
-VL_OBJS+=trace.o dcache.o varint.o
-endif
-
-vl.o: android.h
-
-ifdef CONFIG_SHAPER
-VL_OBJS+=shaper.o
-vl.o: shaper.h shaper.c
-endif
-ifdef CONFIG_WIN32
-VL_OBJS+=tap-win32.o
-endif
-
-AUDIODRV = audio.o noaudio.o wavaudio.o mixeng.o
-ifdef CONFIG_WINAUDIO
-AUDIODRV += winaudio.o
-endif
-ifdef CONFIG_SDL
-AUDIODRV += sdlaudio.o
-endif
-ifdef CONFIG_OSS
-AUDIODRV += ossaudio.o
-endif
-ifdef CONFIG_COREAUDIO
-AUDIODRV += coreaudio.o
-endif
-ifdef CONFIG_ALSA
-AUDIODRV += alsaaudio.o
-alsaaudio.o: DEFINES := $(CONFIG_ALSA_INC) $(DEFINES)
-#LIBS += -lasound # we use dlopen/dlsym to get ALSA functions when available
-endif
-ifdef CONFIG_ESD
-AUDIODRV += esdaudio.o audio_pt_int.o
-esdaudio.o: DEFINES := $(CONFIG_ESD_INC) $(DEFINES)
-#LIBS += -lesd # we use dlopen/dlsym to get esound function, when available
-endif
-ifdef CONFIG_DSOUND
-AUDIODRV += dsoundaudio.o
-LIBS += -lole32 -ldxguid
-endif
-ifdef CONFIG_FMOD
-AUDIODRV += fmodaudio.o
-audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
-LIBS += $(CONFIG_FMOD_LIB)
-endif
-ifdef CONFIG_ADLIB
-SOUND_HW += fmopl.o adlib.o
-endif
-AUDIODRV+= wavcapture.o
-
-AUDIOLIB := libqemu-audio.a
-$(AUDIOLIB): $(AUDIODRV)
- rm -f $@
- $(AR) rcs $@ $(AUDIODRV)
-
-# DMA
-VL_OBJS+=dma.o
-
-# SCSI layer
-VL_OBJS+= scsi-disk.o cdrom.o
-
-# USB layer
-VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
-
-ifeq ($(TARGET_BASE_ARCH), arm)
-VL_OBJS+= smc91c111.o arm_pic.o arm_boot.o
-VL_OBJS+= android_arm.o goldfish_device.o goldfish_interrupt.o goldfish_timer.o \
- goldfish_fb.o goldfish_tty.o goldfish_switch.o goldfish_mmc.o \
- goldfish_memlog.o \
- goldfish_battery.o \
- irq.o
-
-# platform_audio support
-DEFINES += -DHAS_AUDIO
-VL_OBJS += goldfish_audio.o
-
-ifeq ($(CONFIG_QFB), yes)
-VL_OBJS+= qfb_dev.o qfb_fuse.o qfb_fs.o
-endif
-ifeq ($(CONFIG_TRACE), yes)
-VL_OBJS+= goldfish_trace.o
-endif
-ifeq ($(CONFIG_SKINS), yes)
-VL_OBJS+= goldfish_events_device.o
-endif
-ifeq ($(CONFIG_NAND), yes)
-VL_OBJS+= goldfish_nand.o
-endif
-endif
-ifdef CONFIG_GDBSTUB
-VL_OBJS+=gdbstub.o
-endif
-
-VL_OBJS+=android_console.o android_modem.o sim_card.o gsm.o sysdeps_qemu.o \
- charpipe.o modem_driver.o sms.o remote_call.o \
- cbuffer.o \
- android_gps.o
-
-VL_OBJS+=proxy_common.o proxy_http.o
-
-VL_OBJS+=android_debug.o \
- android_help.o \
- android_option.o \
- android_utils.o \
- android_resource.o \
- android_config.o \
- android_timezone.o \
- android_events.o \
- android_profile.o \
- android_qemud.o \
- android_kmsg.o \
- skin_image.o \
- skin_trackball.o \
- skin_keyboard.o \
- skin_file.o \
- skin_window.o \
- skin_scaler.o \
- skin_keyset.o \
- skin_rect.o \
- skin_region.o \
- skin_composer.o \
- skin_surface.o \
- framebuffer.o
-
-ifdef CONFIG_SDL
-ifdef CONFIG_SKINS
-VL_OBJS += loadpng.o android_main.o android_charmap.o
-else
-VL_OBJS+=sdl.o
-endif
-endif
-VL_OBJS+=vnc.o
-ifdef CONFIG_COCOA
-VL_OBJS+=cocoa.o
-COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
-endif
-ifdef CONFIG_COREAUDIO
-COCOA_LIBS+=-F/System/Library/Frameworks -framework CoreAudio
-endif
-ifdef CONFIG_SLIRP
-DEFINES+=-I$(SRC_PATH)/slirp
-SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
-slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
-tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
-VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
-endif
-
-VL_LDFLAGS=
-ifdef CONFIG_WIN32
-VL_LDFLAGS+=-mno-cygwin -mwindows
-endif
-ifndef CONFIG_WIN32
-ifndef CONFIG_DARWIN
-VL_LDFLAGS+=-lX11
-endif
-endif
-
-android_main.c: android_utils.h android_resource.h android_config.h \
- skin_image.h android_icons.h skin_file.h \
- skin_window.h
-
-# specific flags are needed for non soft mmu emulator
-ifdef CONFIG_SKINS
-VL_LIBS+=$(PNG_LIBS)
-endif
-ifdef CONFIG_STATIC
-VL_LDFLAGS+=-static
-endif
-ifndef CONFIG_SOFTMMU
-VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
-endif
-ifndef CONFIG_DARWIN
-ifndef CONFIG_WIN32
-ifndef CONFIG_SOLARIS
-VL_LIBS+=-lutil -lrt
-endif
-endif
-endif
-ifdef TARGET_GPROF
-vl.o: CFLAGS+=-p
-VL_LDFLAGS+=-p
-endif
-
-# we need to filter out _GNU_SOURCE from the SDL C Flags if any, because
-# this macro is not needed at all and will break recent versions of Cygwin
-# with the -mno-cygwin option (blame it on Cygwin/Mingw)
-#
-SDL_CFLAGS := $(filter-out -D_GNU_SOURCE=1,$(SDL_CFLAGS))
-
-$(info SDL_CFLAGS is $(SDL_CFLAGS))
-
-ifdef CONFIG_DARWIN
-ifdef CONFIG_SDL
-CFLAGS += $(SDL_CFLAGS)
-endif
-endif
-
-#skin_%.o android_main.o: CFLAGS+=-O0 -g -fno-omit-frame-pointer
-
-ifeq ($(ARCH),ia64)
-VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
-endif
-
-ifdef CONFIG_WIN32
-SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
-VL_OBJS+=android_icon.o
-android_icon.o: images/android_icon.rc
- windres $< -o $@
-endif
-
-$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(AUDIOLIB) $(LIBPNG_LIB) $(ZLIB_LIB)
- $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
-
-cocoa.o: cocoa.m
- $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-
-android_main.o: android_main.c android.h android_icons.h android_charmap.h android_utils.h android_resource.h skin_image.h
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-android_console.o: android_console.c # we need SDL_CFLAGS
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-android_resource.o: android_resource.c android_resource.h skin_default.h
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-skin_image.o: skin_image.c skin_image.h android_resource.h
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-skin_%.o: skin_%.c skin_%.h
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-android_charmap.o: android_charmap.c android_charmap.h
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-android_utils.o: android_utils.c android_utils.h
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
- $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-
-sdlaudio.o: sdlaudio.c
- $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-
-esdaudio.o: esdaudio.c
- $(CC) $(CFLAGS) -O0 $(DEFINES) -c -o $@ $<
-
-
-depend: $(SRCS)
- $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
-
-vldepend: $(VL_OBJS:.o=.c)
- $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
-
-# libqemu
-
-libqemu.a: $(LIBOBJS)
- rm -f $@
- $(AR) rcs $@ $(LIBOBJS)
-
-translate.o: translate.c gen-op.h opc.h cpu.h
-
-ifdef CONFIG_TRACE
-translate-trace.o: translate.c gen-op-trace.h opc-trace.h cpu.h
- $(CC) $(CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
-endif
-
-translate-all.o: translate-all.c opc.h cpu.h
-
-translate-op.o: translate-op.c op.h opc.h cpu.h
-
-op.h: op.o $(DYNGEN)
- $(DYNGEN) -o $@ $<
-
-opc.h: op.o $(DYNGEN)
- $(DYNGEN) -c -o $@ $<
-
-gen-op.h: op.o $(DYNGEN)
- $(DYNGEN) -g -o $@ $<
-
-op.o: op.c
- $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
-
-ifdef CONFIG_TRACE
-op-trace.h: op-trace.o $(DYNGEN)
- $(DYNGEN) -o $@ $<
-
-opc-trace.h: op-trace.o $(DYNGEN)
- $(DYNGEN) -c -o $@ $<
-
-gen-op-trace.h: op-trace.o $(DYNGEN)
- $(DYNGEN) -g -o $@ $<
-
-op-trace.o: op.c
- $(CC) $(OP_CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
-
-translate-all-trace.o: translate-all.c op-trace.h opc-trace.h cpu.h
- $(CC) $(OP_CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
-
-translate-op-trace.o: translate-op.c op-trace.h opc-trace.h cpu.h
- $(CC) $(OP_CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
-
-endif
-
-skin_scaler.o: CFLAGS += -O2 -g -fno-omit-frame-pointer
-
-helper.o: helper.c
- $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
-
-ifeq ($(TARGET_ARCH), arm)
-op.o: op.c op_template.h
-ifdef CONFIG_TRACE
-op-trace.o: op.c op_template.h
-endif
-endif
-
-loader.o: loader.c elf_ops.h
-
-$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
-
-%.o: %.c
- $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-
-%.o: %.S
- $(CC) $(DEFINES) -c -o $@ $<
-
-clean:
- rm -f *.o *.d *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
-ifdef CONFIG_TRACE
- rm -f opc-trace.h op-trace.h gen-op-trace.h
-endif
-
-install: all
-ifneq ($(PROGS),)
- $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
-endif
-
-ifneq ($(wildcard .depend),)
-include .depend
-endif
-
-# Include automatically generated dependency files
--include $(wildcard *.d)
diff --git a/README b/README
index c333804..44ddc25 100644
--- a/README
+++ b/README
@@ -1,13 +1,23 @@
This package contains the sources to the Android emulator program.
-Building the emulator:
-----------------------
+This program emulates a virtual ARM board that can be used to run Android
+system images on a typical developer machine. To do so, you'll need additionnal
+files provided with the public Android Software Development Kit (SDK).
-you can build this program either form within the Android build system,
-or as a standalone binary executable.
+To download them, go to http://code.google.com/android/
- + in the former case, simply type "m emulator" to build the emulator
+Emulator-specific documentation is available at the following page:
- + in the second case, read the INSTALL document for details on
- requirement and build/install steps.
+ http://code.google.com/android/reference/emulator.html
+Please read the INSTALL file to see how you can rebuild the emulator, or
+build a source distribution package tarball.
+
+Read the CHANGES.TXT file to see what important changes were added since
+the last release.
+
+Note: This program is distributed under the terms of the GNU General Public
+ License, which exact licensing conditions are available in the COPYING
+ file found within this package.
+
+- Android Emulator Team
diff --git a/README.distrib b/README.distrib
deleted file mode 100644
index a1598a2..0000000
--- a/README.distrib
+++ /dev/null
@@ -1,16 +0,0 @@
-Information about the various packages used to build the current qemu
-x86 binary distribution:
-
-* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
- was used to get most of the binary packages.
-
-* wine-20020411 tarball
-
- ./configure --prefix=/usr/local/wine-i386
-
- All exe and libs were stripped. Some compile time tools and the
- includes were deleted.
-
-* ldconfig was launched to build the library links:
-
- qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
diff --git a/TODO b/TODO
deleted file mode 100644
index 516ea87..0000000
--- a/TODO
+++ /dev/null
@@ -1,55 +0,0 @@
-short term:
-----------
-- cycle counter for all archs
-- cpu_interrupt() win32/SMP fix
-- support variable tsc freq
-- USB host async
-- IDE async
-- debug option in 'configure' script + disable -fomit-frame-pointer
-- Precise VGA timings for old games/demos (malc patch)
-- merge PIC spurious interrupt patch
-- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
-- config file (at least for windows/Mac OS X)
-- update doc: PCI infos.
-- basic VGA optimizations
-- better code fetch (different exception handling + CS.limit support)
-- do not resize vga if invalid size.
-- avoid looping if only exceptions
-- TLB code protection support for PPC
-- see openMosix Doc
-- disable SMC handling for ARM/SPARC/PPC (not finished)
-- see undefined flags for BTx insn
-- user/kernel PUSHL/POPL in helper.c
-- keyboard output buffer filling timing emulation
-- return UD exception if LOCK prefix incorrectly used
-- test ldt limit < 7 ?
-- tests for each target CPU
-- fix CCOP optimisation
-- fix all remaining thread lock issues (must put TBs in a specific invalid
- state, find a solution for tb_flush()).
-
-ppc specific:
-------------
-- TLB invalidate not needed if msr_pr changes
-- enable shift optimizations ?
-
-linux-user specific:
--------------------
-- add IPC syscalls
-- handle rare page fault cases (in particular if page fault in helpers or
- in syscall emulation code).
-- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
- issues, fix 16 bit uid issues)
-- use page_unprotect_range in every suitable syscall to handle all
- cases of self modifying code.
-- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
-- use kernel traps for unaligned accesses on ARM ?
-
-
-lower priority:
---------------
-- int15 ah=86: use better timing
-- suppress shift_mem ops
-- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
-- optimize FPU operations (evaluate x87 stack pointer statically)
-- use -msoft-float on ARM
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 53a48a1..0000000
--- a/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-0.8.2 \ No newline at end of file
diff --git a/android-configure.sh b/android-configure.sh
new file mode 100755
index 0000000..a73b89b
--- /dev/null
+++ b/android-configure.sh
@@ -0,0 +1,668 @@
+#!/bin/bash
+#
+# this script is used to rebuild the Android emulator from sources
+# in the current directory. It also contains logic to speed up the
+# rebuild if it detects that you're using the Android build system
+#
+# in this case, it will use prebuilt binaries for the compiler,
+# the audio library and the SDL library. You can disable this
+# by using the --no-prebuilt-libs and --cc=<compiler> options
+#
+#
+# here's the list of environment variables you can define before
+# calling this script to control it (besides options):
+#
+#
+
+# first, let's see which system we're running this on
+cd `dirname $0`
+PROGNAME=`basename $0`
+
+# this function will be used to execute commands and eventually
+# dump them if VERBOSE is 'yes'
+VERBOSE=yes
+VERBOSE2=no
+
+function log()
+{
+ if [ "$VERBOSE" = "yes" ] ; then
+ echo "$1"
+ fi
+}
+
+function log2()
+{
+ if [ "$VERBOSE2" = "yes" ] ; then
+ echo "$1"
+ fi
+}
+
+function execute()
+{
+ log2 "Running: $*"
+ $*
+}
+
+function compile()
+{
+ log2 "Object : $CC -o $TMPO -c $CFLAGS $TMPC"
+ $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL
+}
+
+function link()
+{
+ log2 "Link : $LD $LDFLAGS -o $TMPE $TMPO"
+ $LD $LDFLAGS -o $TMPE $TMPO 2> $TMPL
+}
+
+function compile-exec-run()
+{
+ log2 "RunExec : $CC -o $TMPE $CFLAGS $TMPC"
+ compile
+ if [ $? != 0 ] ; then
+ echo "Failure to compile test program"
+ cat $TMPL
+ exit 1
+ fi
+ link
+ if [ $? != 0 ] ; then
+ echo "Failure to link test program"
+ cat $TMPL
+ exit 1
+ fi
+ $TMPE
+}
+
+OS=`uname -s`
+CPU=`uname -m`
+EXE=""
+case "$OS" in
+ Darwin)
+ if [ $CPU = "i386" ] ; then
+ OS=darwin-x86
+ else
+ OS=darwin-ppc
+ fi
+ ;;
+ Linux)
+ case "$CPU" in
+ i?86) OS=linux-x86
+ ;;
+ # note that building on x86_64 is handled later
+ *) OS=linux-$CPU
+ esac
+ ;;
+ *_NT-*)
+ OS=windows
+ EXE=.exe
+ ;;
+esac
+
+# Are we running in the Android build system ?
+unset TOP
+if [ -n "$ANDROID_PRODUCT_OUT" ] ; then
+ TOP=`cd $ANDROID_PRODUCT_OUT/../../../.. && pwd`
+ log "TOP found at $TOP"
+ # $TOP/config/envsetup.make is for the old tree layout
+ # $TOP/build/envsetup.sh is for the new one
+ ANDROID_ENVSETUP_MK=$TOP/config/envsetup.make
+ if [ ! -f $ANDROID_ENVSETUP_MK ] ; then
+ ANDROID_ENVSETUP_MK=$TOP/build/core/envsetup.mk
+ fi
+ if [ ! -f $ANDROID_ENVSETUP_MK ] ; then
+ echo "Cannot find build system root (TOP)"
+ echo "defaulting to non-Android build"
+ unset TOP
+ fi
+fi
+
+# normalize the TOP variable, we don't want any trailing /
+IN_ANDROID_BUILD=no
+if [ -n "$TOP" ] ; then
+ TOPDIR=`dirname $TOP`
+ if [ "$TOPDIR" != "." ] ; then
+ TOP=$TOPDIR/`basename $TOP`
+ fi
+ IN_ANDROID_BUILD=yes
+ log "In Android Build"
+fi
+
+# Parse options
+OPTION_TARGETS=""
+OPTION_DEBUG=no
+OPTION_IGNORE_AUDIO=no
+OPTION_NO_PREBUILTS=no
+OPTION_TRY_64=no
+OPTION_HELP=no
+
+for opt do
+ optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+ case "$opt" in
+ --help|-h|-\?) OPTION_HELP=yes
+ ;;
+ --verbose)
+ if [ "$VERBOSE" = "yes" ] ; then
+ VERBOSE2=yes
+ else
+ VERBOSE=yes
+ fi
+ ;;
+ --install=*) OPTION_TARGETS="$TARGETS $optarg";
+ ;;
+ --sdl-config=*) SDL_CONFIG=$optarg
+ ;;
+ --cc=*) CC="$optarg" ; HOSTCC=$CC
+ ;;
+ --no-strip) OPTION_NO_STRIP=yes
+ ;;
+ --debug) OPTION_DEBUG=yes
+ ;;
+ --ignore-audio) OPTION_IGNORE_AUDIO=yes
+ ;;
+ --no-prebuilts) OPTION_NO_PREBUILTS=yes
+ ;;
+ --try-64) OPTION_TRY_64=yes
+ ;;
+ *)
+ echo "unknown option '$opt', use --help"
+ exit 1
+ esac
+done
+
+# Print the help message
+#
+if [ "$OPTION_HELP" = "yes" ] ; then
+ cat << EOF
+
+Usage: rebuild.sh [options]
+Options: [defaults in brackets after descriptions]
+EOF
+ echo "Standard options:"
+ echo " --help print this message"
+ echo " --install=FILEPATH copy emulator executable to FILEPATH [$TARGETS]"
+ echo " --cc=PATH specify C compiler [$CC]"
+ echo " --sdl-config=FILE use specific sdl-config script [$SDL_CONFIG]"
+ echo " --no-strip do not strip emulator executable"
+ echo " --debug enable debug (-O0 -g) build"
+ echo " --ignore-audio ignore audio messages (may build sound-less emulator)"
+ echo " --no-prebuilts do not use prebuilt libraries and compiler"
+ echo " --try-64 try to build a 64-bit executable (may crash)"
+ echo " --verbose verbose configuration"
+ echo ""
+ exit 1
+fi
+
+# Various probes are going to need to run a small C program
+TMPC=/tmp/android-qemu-$$.c
+TMPO=/tmp/android-qemu-$$.o
+TMPE=/tmp/android-qemu-$$$EXE
+TMPL=/tmp/android-qemu-$$.log
+
+function clean-exit ()
+{
+ rm -f $TMPC $TMPO $TMPL $TMPE
+ exit 1
+}
+
+# Adjust a few things when we're building within the Android build
+# system:
+# - locate prebuilt directory
+# - locate and use prebuilt libraries and compiler
+# - copy the new binary to the correct location
+#
+if [ "$OPTION_NO_PREBUILTS" = "yes" ] ; then
+ IN_ANDROID_BUILD=no
+fi
+
+if [ "$IN_ANDROID_BUILD" = "yes" ] ; then
+
+ # Get the value of a build variable as an absolute path.
+ function get_abs_build_var()
+ {
+ (cd "$TOP" &&
+ CALLED_FROM_SETUP=true make -f $ANDROID_ENVSETUP_MK dumpvar-abs-$1)
+ }
+
+ # locate prebuilt directory
+ PREBUILT_HOST_TAG=$OS
+ case $OS in
+ linux-*)
+ # Linux is a special case because in the old tree layout
+ # we simply used 'Linux' as the prebuilt host tag, but
+ # are now using "linux-x86" in the new layout
+ # check which one should be used
+ #
+ if [ -d $TOP/prebuilt/Linux ] ; then
+ PREBUILT_HOST_TAG=Linux
+ fi
+ ;;
+ esac
+ PREBUILT=$TOP/prebuilt/$PREBUILT_HOST_TAG
+ if [ ! -d $PREBUILT ] ; then
+ # this can happen when building on x86_64
+ case $OS in
+ linux-x86_64)
+ PREBUILT_HOST_TAG=linux-x86
+ PREBUILT=$TOP/prebuilt/$PREBUILT_HOST_TAG
+ log "Forcing usage of 32-bit prebuilts"
+ ;;
+ *)
+ esac
+ if [ ! -d $PREBUILT ] ; then
+ echo "Can't find the prebuilt directory $PREBUILT in Android build"
+ exit 1
+ fi
+ fi
+ log "Prebuilt : PREBUILT=$PREBUILT"
+
+ # if CC is unspecified, grab the prebuilt compiler
+ if [ -z "$CC" ] ; then
+ PREBUILT_GCC=$PREBUILT/gcc-qemu/bin/gcc
+ if [ ! -f $PREBUILT_GCC ] ; then
+ # try to find the prebuilt compiler in the new tree layout
+ # this is pretty specific to each OS and hard-coded in the
+ # build system
+ case "$OS" in
+ linux-*)
+ QEMUGCC=i686-linux-gnu-3.4.6
+ ;;
+ darwin-x86)
+ QEMUGCC=i686-apple-darwin8-4.0.1
+ ;;
+ esac
+ PREBUILT_GCC=$PREBUILT/toolchain/$QEMUGCC/bin/gcc
+ fi
+ if [ -f $PREBUILT_GCC ] ; then
+ CC=$PREBUILT_GCC
+ log "Prebuilt : CC=$CC"
+ fi
+ fi
+
+ # use ccache if USE_CCACHE is defined and the corresponding
+ # binary is available.
+ #
+ # note: located in PREBUILT/ccache/ccache in the new tree layout
+ # located in PREBUILT/ccache in the old one
+ #
+ if [ -n "$USE_CCACHE" ] ; then
+ CCACHE="$PREBUILT/ccache/ccache$EXE"
+ if [ ! -f $CCACHE ] ; then
+ CCACHE="$PREBUILT/ccache$EXE"
+ fi
+ if [ -f $CCACHE ] ; then
+ CC="$CCACHE $CC"
+ fi
+ log "Prebuilt : CCACHE=$CCACHE"
+ fi
+
+ # if the user didn't specify a sdl-config script, get the prebuilt one
+ if [ -z "$SDL_CONFIG" -a "$OPTION_NO_PREBUILTS" = "no" ] ; then
+ # always use our own static libSDL by default
+ SDL_CONFIG=$PREBUILT/sdl/bin/sdl-config
+ log "Prebuilt : SDL_CONFIG=$SDL_CONFIG"
+ fi
+
+ # finally ensure that our new binary is copied to the 'out'
+ # subdirectory as 'emulator'
+ HOST_BIN=$(get_abs_build_var HOST_OUT_EXECUTABLES)
+ if [ -n "$HOST_BIN" ] ; then
+ TARGETS="$TARGETS $HOST_BIN/emulator$EXE"
+ log "Targets : TARGETS=$TARGETS"
+ fi
+fi # IN_ANDROID_BUILD = no
+
+
+####
+#### Compiler checks
+####
+####
+if [ -z "$CC" ] ; then
+ CC=gcc
+ if [ $CPU = "powerpc" ] ; then
+ CC=gcc-3.3
+ fi
+fi
+
+cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+if [ -z "$LD" ] ; then
+ LD=$CC
+fi
+
+# we only support generating 32-bit binaris on 64-bit systems.
+# And we may need to add a -Wa,--32 to CFLAGS to let the assembler
+# generate 32-bit binaries on Linux x86_64.
+#
+if [ "$OPTION_TRY_64" != "yes" ] ; then
+ if [ "$CPU" = "x86_64" -o "$CPU" = "amd64" ] ; then
+ log "Check32Bits: Forcing generation of 32-bit binaries (--try-64 to disable)"
+ CPU="i386"
+ case $OS in
+ linux-*)
+ OS=linux-x86
+ ;;
+ darwin-*)
+ OS=darwin-x86
+ ;;
+ esac
+ CFLAGS="$CFLAGS -m32"
+ LDFLAGS="$LDFLAGS -m32"
+ compile
+ if [ $? != 0 ] ; then
+ CFLAGS="$CFLAGS -Wa,--32"
+ fi
+ # check that the compiler can link 32-bit executables
+ # if not, try the host linker
+ link
+ if [ $? != 0 ] ; then
+ OLD_LD=$LD
+ LD=gcc
+ compile
+ link
+ if [ $? != 0 ] ; then
+ log "not using gcc for LD"
+ LD=$OLD_LD
+ fi
+ fi
+ fi
+fi
+
+compile
+if [ $? != 0 ] ; then
+ echo "C compiler doesn't seem to work:"
+ cat $TMPL
+ clean-exit
+fi
+log "CC : compiler check ok ($CC)"
+
+# on 64-bit systems, some of our prebuilt compilers are not
+# capable of linking 32-bit executables properly
+#
+link
+if [ $? != 0 ] ; then
+ echo "Linker doesn't seem to work:"
+ cat $TMPL
+ clean-exit
+fi
+log "LD : linker check ok ($LD)"
+
+###
+### SDL Probe
+###
+
+# For now, we require an external libSDL library, if SDL_CONFIG is not
+# defined, try to grab it from the environment
+#
+if [ -z "$SDL_CONFIG" ] ; then
+ SDL_CONFIG=`which sdl-config`
+ if [ $? != 0 ] ; then
+ echo "Please ensure that you have the emulator's patched libSDL"
+ echo "built somewhere and point to its sdl-config script either"
+ echo "with the SDL_CONFIG env. variable, or the --sdl-config=<script>"
+ echo "option."
+ clean-exit
+ fi
+fi
+
+# check that we can link statically with the library.
+#
+SDL_CFLAGS=`$SDL_CONFIG --cflags`
+SDL_LIBS=`$SDL_CONFIG --static-libs`
+
+# quick hack, remove the -D_GNU_SOURCE=1 of some SDL Cflags
+# since they break recent Mingw releases
+SDL_CFLAGS=`echo $SDL_CFLAGS | sed -e s/-D_GNU_SOURCE=1//g`
+
+log "SDL-probe : SDL_CFLAGS = $SDL_CFLAGS"
+log "SDL-probe : SDL_LIBS = $SDL_LIBS"
+
+OLD_CFLAGS=$CFLAGS
+OLD_LDFLAGS=$LDFLAGS
+
+CFLAGS="$CFLAGS $SDL_CFLAGS"
+LDFLAGS="$LDFLAGS $SDL_LIBS"
+
+cat > $TMPC << EOF
+#include <SDL.h>
+#undef main
+int main( void ) {
+ return SDL_Init (SDL_INIT_VIDEO);
+}
+EOF
+compile
+if [ $? != 0 ] ; then
+ echo "You provided an explicit sdl-config script, but the corresponding library"
+ echo "cannot be statically linked with the Android emulator directly."
+ echo "Error message:"
+ cat $TMPL
+ clean-exit
+fi
+log "SDL-probe : static linking ok"
+
+# now, let's check that the SDL library has the special functions
+# we added to our own sources
+#
+cat > $TMPC << EOF
+#include <SDL.h>
+#undef main
+int main( void ) {
+ int x, y;
+ SDL_WM_GetPos(&x, &y);
+ SDL_WM_SetPos(x, y);
+ return SDL_Init (SDL_INIT_VIDEO);
+}
+EOF
+compile
+if [ $? != 0 ] ; then
+ echo "You provided an explicit sdl-config script in SDL_CONFIG, but the"
+ echo "corresponding library doesn't have the patches required to link"
+ echo "with the Android emulator. Unsetting SDL_CONFIG will use the"
+ echo "sources bundled with the emulator instead"
+ echo "Error:"
+ cat $TMPL
+ clean-exit
+fi
+
+log "SDL-probe : extra features ok"
+rm -f $TMPL $TMPC $TMPE
+
+CFLAGS=$OLD_CFLAGS
+LDFLAGS=$OLD_LDFLAGS
+
+
+###
+### Audio subsystems probes
+###
+PROBE_COREAUDIO=no
+PROBE_ALSA=no
+PROBE_OSS=no
+PROBE_ESD=no
+PROBE_WINAUDIO=no
+
+case "$OS" in
+ darwin*) PROBE_COREAUDIO=yes;
+ ;;
+ linux-*) PROBE_ALSA=yes; PROBE_OSS=yes; PROBE_ESD=yes;
+ ;;
+ windows) PROBE_WINAUDIO=yes
+ ;;
+esac
+
+ORG_CFLAGS=$CFLAGS
+ORG_LDFLAGS=$LDFLAGS
+
+if [ "$PROBE_ESD" = yes ] ; then
+ CFLAGS="$ORG_CFLAGS"
+ LDFLAGS="$ORG_LDFLAGS -ldl"
+ cp -f android/config/check-esd.c $TMPC
+ compile && link && $TMPE
+ if [ $? = 0 ] ; then
+ log "AudioProbe : ESD seems to be usable on this system"
+ else
+ if [ "$OPTION_IGNORE_AUDIO" = no ] ; then
+ echo "the EsounD development files do not seem to be installed on this system"
+ echo "Are you missing the libesd-dev package ?"
+ echo "Correct the errors below and try again:"
+ cat $TMPL
+ clean-exit
+ fi
+ PROBE_ESD=no
+ log "AudioProbe : ESD seems to be UNUSABLE on this system !!"
+ fi
+fi
+
+if [ "$PROBE_ALSA" = yes ] ; then
+ CFLAGS="$ORG_CFLAGS"
+ LDFLAGS="$ORG_CFLAGS -ldl"
+ cp -f android/config/check-alsa.c $TMPC
+ compile && link && $TMPE
+ if [ $? = 0 ] ; then
+ log "AudioProbe : ALSA seems to be usable on this system"
+ else
+ if [ "$OPTION_IGNORE_AUDIO" = no ] ; then
+ echo "the ALSA development files do not seem to be installed on this system"
+ echo "Are you missing the libasound-dev package ?"
+ echo "Correct the erros below and try again"
+ cat $TMPL
+ clean-exit
+ fi
+ PROBE_ALSA=no
+ log "AudioProbe : ALSA seems to be UNUSABLE on this system !!"
+ fi
+fi
+
+CFLAGS=$ORG_CFLAGS
+LDFLAGS=$ORG_LDFLAGS
+
+# create the objs directory that is going to contain all generated files
+# including the configuration ones
+#
+mkdir -p objs
+
+###
+### Compiler probe
+###
+
+####
+#### Host system probe
+####
+
+# because the previous version could be read-only
+rm -f $TMPC
+
+# check host endianess
+#
+HOST_BIGENDIAN=no
+cat > $TMPC << EOF
+#include <inttypes.h>
+int main(int argc, char ** argv){
+ volatile uint32_t i=0x01234567;
+ return (*((uint8_t*)(&i))) == 0x67;
+}
+EOF
+compile-exec-run && HOST_BIGENDIAN=yes
+log "Host : HOST_BIGENDIAN=$HOST_BIGENDIAN"
+
+# check size of host long bits
+HOST_LONGBITS=32
+cat > $TMPC << EOF
+int main(void) {
+ return sizeof(void*)*8;
+}
+EOF
+compile-exec-run
+HOST_LONGBITS=$?
+log "Host : HOST_LONGBITS=$HOST_LONGBITS"
+
+# check whether we have <byteswap.h>
+#
+HAVE_BYTESWAP_H=yes
+cat > $TMPC << EOF
+#include <byteswap.h>
+EOF
+compile
+if [ $? != 0 ] ; then
+ HAVE_BYTESWAP_H=no
+fi
+log "Host : HAVE_BYTESWAP_H=$HAVE_BYTESWAP_H"
+
+# Build the config.make file
+#
+rm -rf objs
+mkdir -p objs
+config_mk=objs/config.make
+echo "# This file was autogenerated by $PROGNAME" > $config_mk
+echo "TARGET_ARCH := arm" >> $config_mk
+case $OS in
+ linux-*) HOST_OS=linux
+ ;;
+ darwin-*) HOST_OS=darwin
+ ;;
+ *) HOST_OS=$OS
+esac
+echo "OS := $OS" >> $config_mk
+echo "HOST_OS := $HOST_OS" >> $config_mk
+case $CPU in
+ i?86) HOST_ARCH=x86
+ ;;
+ amd64) HOST_ARCH=x86_64
+ ;;
+ powerpc) HOST_ARCH=ppc
+ ;;
+ *) HOST_ARCH=$CPU
+esac
+echo "HOST_ARCH := $HOST_ARCH" >> $config_mk
+PWD=`pwd`
+echo "SRC_PATH := $PWD" >> $config_mk
+echo "CC := $CC" >> $config_mk
+echo "HOST_CC := $CC" >> $config_mk
+echo "LD := $LD" >> $config_mk
+echo "NO_PREBUILT := $OPTION_NO_PREBUILTS" >> $config_mk
+echo "PREBUILT := $PREBUILT" >> $config_mk
+echo "CFLAGS := $CFLAGS" >> $config_mk
+echo "LDFLAGS := $LDFLAGS" >> $config_mk
+echo "SDL_CONFIG := $SDL_CONFIG" >> $config_mk
+echo "CONFIG_COREAUDIO := $PROBE_COREAUDIO" >> $config_mk
+echo "CONFIG_WINAUDIO := $PROBE_WINAUDIO" >> $config_mk
+echo "CONFIG_ESD := $PROBE_ESD" >> $config_mk
+echo "CONFIG_ALSA := $PROBE_ALSA" >> $config_mk
+echo "CONFIG_OSS := $PROBE_OSS" >> $config_mk
+echo "" >> $config-mk
+echo "BUILD_STANDALONE_EMULATOR := true" >> $config_mk
+echo "HOST_PREBUILT_TAG := $PREBUILT_HOST_TAG" >> $config_mk
+
+log "Generate : $config_mk"
+
+# Build the config-host.h file
+#
+config_h=objs/config-host.h
+echo "/* This file was autogenerated by '$PROGNAME' */" > $config_h
+echo "#define CONFIG_QEMU_SHAREDIR \"/usr/local/share/qemu\"" >> $config_h
+echo "#define HOST_LONG_BITS $HOST_LONGBITS" >> $config_h
+if [ "$HAVE_BYTESWAP_H" = "yes" ] ; then
+ echo "#define HAVE_BYTESWAP_H 1" >> $config_h
+fi
+echo "#define CONFIG_GDBSTUB 1" >> $config_h
+echo "#define CONFIG_SLIRP 1" >> $config_h
+echo "#define CONFIG_SKINS 1" >> $config_h
+# the -nand-limits options can only work on non-windows systems
+if [ "$OS" != "windows" ] ; then
+ echo "#define CONFIG_NAND_LIMITS 1" >> $config_h
+fi
+echo "#define QEMU_VERSION \"0.8.2\"" >> $config_h
+case "$CPU" in
+ i386) HOST_CPU=I386
+ ;;
+ powerpc) HOST_CPU=PPC
+ ;;
+ x86_64|amd64) HOST_CPU=X86_64
+ ;;
+ *) HOST_CPU=$CPU
+ ;;
+esac
+echo "#define HOST_$HOST_CPU 1" >> $config_h
+log "Generate : $config_h"
+
+echo "Ready to go. Type 'make' to build emulator"
diff --git a/android-rebuild.sh b/android-rebuild.sh
index 443afca..d488f69 100755
--- a/android-rebuild.sh
+++ b/android-rebuild.sh
@@ -7,259 +7,6 @@
#
cd `dirname $0`
-
-OS=`uname -s`
-EXE=""
-case "$OS" in
- Darwin)
- CPU=`uname -p`
- if [ "$CPU" = "i386" ] ; then
- OS=darwin-x86
- else
- OS=darwin-ppc
- fi
- ;;
- *_NT-*)
- OS=windows
- EXE=.exe
- ;;
-esac
-
-# select the compiler: on OS X PPC, we're forced to use gcc-3.3
-# also use ccache if we can
-CC=gcc
-HOSTCC=gcc
-cpu=$(uname -p)
-if [ "$cpu" = "powerpc" ] ; then
- HOSTCC=gcc-3.3
-fi
-
-unset TOP
-# if ANDROID_PRODUCT_OUT is defined we maybe in an Android build
-if [ -n "$ANDROID_PRODUCT_OUT" ] ; then
- TOP=$(cd $ANDROID_PRODUCT_OUT/../../../.. && pwd)
- echo "TOP found at $TOP"
- if [ ! -f "$TOP/config/envsetup.make" ] ; then
- echo "Cannot find build system root (TOP)"
- echo "defaulting to non-Android build"
- unset TOP
- fi
-fi
-
-# normalize the TOP variable, we don't want any trailing /
-IN_ANDROID_BUILD=
-if [ -n "$TOP" ] ; then
- if [ ! "$(dirname $TOP)" = "." ] ; then
- TOP=$(dirname $TOP)/$(basename $TOP)
- fi
- IN_ANDROID_BUILD=1
- echo "In Android Build"
-fi
-
-TARGETS=
-DEBUG=no
-IGNORE_AUDIO=no
-for opt do
- optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
- case "$opt" in
- --help|-h|-\?) show_help=yes
- ;;
- --install=*) TARGETS="$TARGETS $optarg";
- ;;
- --sdl-config=*) SDL_CONFIG=$optarg
- ;;
- --cc=*) CC="$optarg" ; HOSTCC=$CC
- ;;
- --no-strip) NOSTRIP=1
- ;;
- --no-android) IN_ANDROID_BUILD=
- ;;
- --debug) DEBUG=yes
- ;;
- --android-build) IN_ANDROID_BUILD=1
- ;;
- --ignore-audio) IGNORE_AUDIO=yes
- ;;
- esac
-done
-
-if test x"$show_help" = x"yes" ; then
- cat << EOF
-
-Usage: android-rebuild.sh [options]
-Options: [defaults in brackets after descriptions]
-
-EOF
- echo "Standard options:"
- echo " --help print this message"
- echo " --install=FILEPATH copy emulator executable to FILEPATH [$TARGETS]"
- echo " --no-strip do not strip emulator executable"
- echo " --sdl-config=FILE use specific sdl-config script [$SDL_CONFIG]"
- echo " --debug enable debug (-O0 -g) build"
- echo " --no-android perform clean build, without Android build tools & prebuilt"
- echo " --ignore-audio ignore audio messages (may build sound-less emulator)"
- echo " --cc=PATH specify C compiler [$CC]"
- echo ""
- exit 1
-fi
-
-if [ -n "$IN_ANDROID_BUILD" ] ; then
- # Get the value of a build variable as an absolute path.
- function get_abs_build_var()
- {
- (cd "$TOP" &&
- CALLED_FROM_SETUP=true make -f config/envsetup.make dumpvar-abs-$1)
- }
-
- PREBUILT=$TOP/prebuilt/$OS
- if [ ! -d $PREBUILT ] ; then
- echo "Can't find the prebuilt directory $PREBUILT in Android build"
- exit 1
- fi
- if [ -n "$USE_CCACHE" ] ; then
- CCACHE="$TOP/prebuilt/$OS/ccache$EXE"
- if [ -f $CCACHE ] ; then
- CC="$TOP/prebuilt/$OS/ccache$EXE $CC"
- HOSTCC="$CC"
- fi
- fi
-
- if [ -z "$SDL_CONFIG" ] ; then
- # always use our own static libSDL by default
- SDL_CONFIG=$TOP/prebuilt/$OS/sdl/bin/sdl-config
- fi
- HOST_BIN=$(get_abs_build_var HOST_OUT_EXECUTABLES)
- if [ -n "$HOST_BIN" ] ; then
- TARGETS="$TARGETS $HOST_BIN/emulator$EXE"
- fi
-else
- # try to find sdl-config
- if [ -z "$SDL_CONFIG" ] ; then
- SDL_CONFIG=$(which sdl-config)
- fi
- if [ -z "$SDL_CONFIG" ] ; then
- echo "Could not find the 'sdl-config' script"
- echo "You need to have the development version of the SDL library on this machine to build this program"
- echo "See (www.libsdl.org for details)"
- if [ "$OS" = "Linux" ] ; then
- echo "Try to install the 'libsdl-dev' package on this machine"
- fi
- exit 1
- fi
-
- # check that the static version is usable, this is performed by the configure script
- # too, but we can be more informative when checking it here
- TMPC=/tmp/android-qemu-sdl-check.c
- TMPE=/tmp/android-qemu-sdl-check$EXE
- TMPL=/tmp/android-qemu-sdl.log
- cat > $TMPC << EOF
-#include <SDL.h>
-#undef main
-int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
-EOF
- if $HOSTCC -o $TMPE $TMPC `$SDL_CONFIG --cflags` `$SDL_CONFIG --static-libs` 2> $TMPL; then
- rm -f $TMPC $TMPE
- else
- echo "static linking with your installed SDL library doesn't work"
- echo "please correct the following compilation/link error messages, then try again"
- cat $TMPL
- rm -f $TMPL $TMPC $TMPE
- exit 1
- fi
-fi
-
-# if we're in tools/qemu, we output the build commands to the standard outputs
-# if not, we hide them...
-if [ -n "$SHOW_COMMANDS" -o `dirname $0` = "." ] ; then
- STDOUT=/dev/stdout
- STDERR=/dev/stderr
-else
- STDOUT=/dev/null
- STDERR=/dev/null
-fi
-
-if ! [ -f $SDL_CONFIG ] ; then
- echo "SDL_CONFIG is set to '$SDL_CONFIG' which doesn't exist"
- exit 3
-fi
-
-use_sdl_config="--use-sdl-config=$SDL_CONFIG"
-
-# use Makefile.qemu if available
-#
-if [ -f Makefile.qemu ] ; then
- MAKEFILE=Makefile.qemu
-else
- MAKEFILE=Makefile
-fi
-
-# compute options for the 'configure' program
-CONFIGURE_OPTIONS="--disable-user --disable-kqemu --enable-trace --enable-shaper"
-CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --enable-skins --enable-nand --enable-sdl $use_sdl_config"
-
-if [ "$OS" != "windows" ] ; then
- # Windows doesn't have signals, so -nand-limits cannot work on this platform
- CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --enable-nand-limits"
-fi
-
-CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --static-png --static-sdl --target-list=arm-softmmu"
-
-# we don't want to use the SDL audio driver when possible, since it doesn't support
-# audio input. select a platform-specific one instead...
-#
-AUDIO_OPTIONS=""
-case $OS in
- darwin*) AUDIO_OPTIONS=" --enable-coreaudio"
- ;;
- windows) AUDIO_OPTIONS=" --enable-winaudio"
- ;;
- Linux)
- if `pkg-config --exists alsa`; then
- AUDIO_OPTIONS="$AUDIO_OPTIONS --enable-alsa"
- else
- if [ "$IGNORE_AUDIO" = "no" ] ; then
- echo "please install the libasound2-dev package on this machine, or use the --ignore-audio option"
- exit 3
- fi
- fi
- if `pkg-config --exists esound`; then
- AUDIO_OPTIONS="$AUDIO_OPTIONS --enable-esd"
- else
- if [ "$IGNORE_AUDIO" = "no" ] ; then
- echo "please install the libesd0-dev package on this machine, or use the --ignore-audio option"
- exit 3
- fi
- fi
- AUDIO_OPTIONS="$AUDIO_OPTIONS --enable-oss"
- ;;
-esac
-CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS$AUDIO_OPTIONS"
-
-if [ "$DEBUG" = "yes" ] ; then
- CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --debug"
-fi
-
-export CC HOSTCC
-
-echo "rebuilding the emulator binary"
-if ! (
- if [ -f arm-softmmu/Makefile ] ; then
- make -f $MAKEFILE clean
- fi
- echo ./configure $CONFIGURE_OPTIONS &&
- ./configure $CONFIGURE_OPTIONS &&
- make -f $MAKEFILE -j4 ) 2>$STDERR >$STDOUT ; then
- echo "Error while rebuilding the emulator. please check the sources"
- exit 3
-fi
-
-for target in $TARGETS; do
- ( echo "copying binary to $target" &&
- cp -f arm-softmmu/qemu-system-arm$EXE $target &&
- ( if [ -z "$NOSTRIP" ] ; then
- echo "stripping $target"
- strip $target ;
- fi )
- ) ;
-done
-
+./android-configure.sh $* && \
+make -j4 && \
+echo "Done. !!"
diff --git a/android.h b/android.h
index 8d304f5..05b579e 100644
--- a/android.h
+++ b/android.h
@@ -13,12 +13,7 @@
#define _qemu_android_h
#define ANDROID_VERSION_MAJOR 1
-#define ANDROID_VERSION_MINOR 7
-
-// Used to know where to store the user data image.
-// Note: this *must* match the similar-named constant in the ADT plugin,
-// defined in tools/androidprefs/src/com/android/prefs/AndroidLocation.java
-#define ANDROID_SDK_VERSION "SDK-1.0"
+#define ANDROID_VERSION_MINOR 8
#define CONFIG_SHAPER 1
diff --git a/android/build/binary.make b/android/build/binary.make
new file mode 100644
index 0000000..379ef9a
--- /dev/null
+++ b/android/build/binary.make
@@ -0,0 +1,29 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# definitions shared by host_executable.make and host_static_library.make
+#
+
+# the directory where we're going to place our object files
+LOCAL_OBJS_DIR := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE))
+LOCAL_OBJECTS :=
+LOCAL_CC ?= $(CC)
+LOCAL_C_SOURCES := $(filter %.c,$(LOCAL_SRC_FILES))
+
+$(foreach src,$(LOCAL_C_SOURCES), \
+ $(eval $(call compile-c-source,$(src))) \
+)
+
+CLEAN_OBJS_DIRS += $(LOCAL_OBJS_DIR)
diff --git a/android/build/clear_vars.make b/android/build/clear_vars.make
new file mode 100644
index 0000000..a9289b0
--- /dev/null
+++ b/android/build/clear_vars.make
@@ -0,0 +1,30 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# called multiple times to clear variables used to define a given 'module'
+#
+LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
+LOCAL_CC :=
+LOCAL_CXX :=
+LOCAL_CFLAGS :=
+LOCAL_LDFLAGS :=
+LOCAL_LDLIBS :=
+LOCAL_SRC_FILES :=
+LOCAL_MODULE :=
+LOCAL_MODULE_PATH:=
+LOCAL_STATIC_LIBRARIES :=
+LOCAL_BUILT_MODULE :=
+LOCAL_PREBUILT_OBJ_FILES :=
+
diff --git a/android/build/definitions.make b/android/build/definitions.make
new file mode 100644
index 0000000..c4183ea
--- /dev/null
+++ b/android/build/definitions.make
@@ -0,0 +1,88 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# shared definitions
+ifeq ($(strip $(SHOW)),)
+define pretty
+@echo $1
+endef
+hide := @
+else
+define pretty
+endef
+hide :=
+endif
+
+define my-dir
+.
+endef
+
+# return the directory containing the intermediate files for a given
+# kind of executable
+# $1 = type (EXECUTABLES or STATIC_LIBRARIES)
+# $2 = module name
+# $3 = ignored
+#
+define intermediates-dir-for
+$(OBJS_DIR)/intermediates/$(2)
+endef
+
+# Generate the full path of a given static library
+define library-path
+$(OBJS_DIR)/$(1).a
+endef
+
+define executable-path
+$(OBJS_DIR)/$(1)$(EXE)
+endef
+
+# Compile a C source file
+#
+define compile-c-source
+SRC:=$(1)
+OBJ:=$$(LOCAL_OBJS_DIR)/$$(SRC:%.c=%.o)
+LOCAL_OBJECTS += $$(OBJ)
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CC := $$(LOCAL_CC)
+$$(OBJ): PRIVATE_OBJ := $$(OBJ)
+$$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
+$$(OBJ): PRIVATE_SRC := $$(SRC_PATH)/$$(SRC)
+$$(OBJ): PRIVATE_SRC0 := $$(SRC)
+$$(OBJ): $$(SRC_PATH)/$$(SRC)
+ @mkdir -p $$(dir $$(PRIVATE_OBJ))
+ @echo "Compile: $$(PRIVATE_MODULE) <= $$(PRIVATE_SRC0)"
+ $(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) -c -o $$(PRIVATE_OBJ) -MMD -MP -MF $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_SRC)
+ $(hide) $$(SRC_PATH)/android/build/mkdeps.sh $$(PRIVATE_OBJ) $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_OBJ).d
+endef
+
+# for now, we only use prebuilt SDL libraries, so copy them
+define copy-prebuilt-lib
+_SRC := $(1)
+_SRC1 := $$(notdir $$(_SRC))
+_DST := $$(OBJS_DIR)/$$(_SRC1)
+LIBRARIES += $$(_DST)
+$$(_DST): PRIVATE_DST := $$(_DST)
+$$(_DST): PRIVATE_SRC := $$(_SRC)
+$$(_DST): $$(_SRC)
+ @mkdir -p $$(dir $$(PRIVATE_DST))
+ @echo "Prebuilt: $$(PRIVATE_DST)"
+ $(hide) cp -f $$(PRIVATE_SRC) $$(PRIVATE_DST)
+endef
+
+define create-dir
+$(1):
+ mkdir -p $(1)
+endef
+
diff --git a/android/build/getdir.make b/android/build/getdir.make
new file mode 100644
index 0000000..a4dadd3
--- /dev/null
+++ b/android/build/getdir.make
@@ -0,0 +1,19 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# used to return in 'dir' the name of the current operating system
+# we really get the value from the configuration script
+#
+dir := $(HOST_OS)
diff --git a/android/build/host_executable.make b/android/build/host_executable.make
new file mode 100644
index 0000000..a9b51d8
--- /dev/null
+++ b/android/build/host_executable.make
@@ -0,0 +1,36 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# first, call a library containing all object files
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# now, link the executable with it
+LOCAL_BUILT_LIBRARY := $(LOCAL_BUILT_MODULE)
+LOCAL_BUILT_MODULE := $(call executable-path,$(LOCAL_MODULE))
+
+LOCAL_LDLIBS := $(foreach lib,$(LOCAL_STATIC_LIBRARIES),$(call library-path,$(lib))) $(LOCAL_LDLIBS)
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LDFLAGS := $(LDFLAGS) $(LOCAL_LDFLAGS)
+$(LOCAL_BUILT_MODULE): PRIVATE_LDLIBS := $(LOCAL_LDLIBS)
+$(LOCAL_BUILT_MODULE): PRIVATE_LIBRARY := $(LOCAL_BUILT_LIBRARY)
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_BUILT_LIBRARY)
+ @ mkdir -p $(dir $@)
+ @ echo "Executable: $@"
+ $(hide) $(LD) $(PRIVATE_LDFLAGS) -o $@ $(PRIVATE_LIBRARY) $(PRIVATE_LDLIBS)
+
+EXECUTABLES += $(LOCAL_BUILT_MODULE)
+$(LOCAL_BUILT_MODULE): $(foreach lib,$(LOCAL_STATIC_LIBRARIES),$(call library-path,$(lib)))
+
diff --git a/android/build/host_static_library.make b/android/build/host_static_library.make
new file mode 100644
index 0000000..3de5a99
--- /dev/null
+++ b/android/build/host_static_library.make
@@ -0,0 +1,35 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# build a host executable, the name of the final executable should be
+# put in LOCAL_BUILT_MODULE for use by the caller
+#
+
+#$(info STATIC_LIBRARY SRCS=$(LOCAL_SRC_FILES))
+LOCAL_BUILT_MODULE := $(call library-path,$(LOCAL_MODULE))
+LOCAL_CC ?= $(CC)
+include $(BUILD_SYSTEM)/binary.make
+
+LOCAL_AR ?= $(AR)
+ARFLAGS := crs
+
+$(LOCAL_BUILT_MODULE): PRIVATE_AR := $(LOCAL_AR)
+$(LOCAL_BUILT_MODULE): PRIVATE_OBJECTS := $(LOCAL_OBJECTS)
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+ @mkdir -p $(dir $@)
+ @echo "Library: $@"
+ $(hide) $(PRIVATE_AR) $(ARFLAGS) $@ $(PRIVATE_OBJECTS)
+
+LIBRARIES += $(LOCAL_BUILT_MODULE)
diff --git a/android/build/mkdeps.sh b/android/build/mkdeps.sh
new file mode 100755
index 0000000..2d25ca3
--- /dev/null
+++ b/android/build/mkdeps.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is used to transform the dependency files generated by GCC
+# For example, a typical .d file will have a line like:
+#
+# source.o: /full/path/to/source.c other.h headers.h
+# ...
+#
+# the script is used to replace 'source.o' to a full path, as in
+#
+# objs/intermediates/emulator/source.o: /full/path/to/source.c other.h headers.h
+#
+# parameters
+#
+# $1: object file (full path)
+# $2: source dependency file to modify (erased on success)
+# $3: target source dependency file
+#
+
+# quote the object path. we change a single '.' into
+# a '\.' since this will be parsed by sed.
+#
+OBJECT=`echo $1 | sed -e s/\\\\./\\\\\\\\./g`
+#echo OBJECT=$OBJECT
+
+OBJ_NAME=`basename $OBJECT`
+#echo OBJ_NAME=$OBJ_NAME
+
+# we replace $OBJ_NAME with $OBJECT
+#
+cat $2 | sed -e s%$OBJ_NAME%$OBJECT%g > $3 && rm -f $2
+
+
+
diff --git a/android/config/check-alsa.c b/android/config/check-alsa.c
new file mode 100644
index 0000000..4ab2945
--- /dev/null
+++ b/android/config/check-alsa.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <stdio.h>
+#include <alsa/asoundlib.h>
+
+#define D(...) fprintf(stderr,__VA_ARGS__)
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define DYN_SYMBOLS \
+ DYN_FUNCTION(size_t,snd_pcm_sw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(size_t,snd_pcm_hw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_drop,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(const char*,snd_strerror,(int errnum)) \
+ DYN_FUNCTION(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
+ DYN_FUNCTION(int,snd_pcm_close,(snd_pcm_t *pcm)) \
+
+
+
+/* define pointers to library functions we're going to use */
+#define DYN_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+DYN_SYMBOLS
+
+#undef DYN_FUNCTION
+
+#define func_snd_pcm_hw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(func_snd_pcm_hw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_hw_params_sizeof()); } while (0)
+
+#define func_snd_pcm_sw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(func_snd_pcm_sw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_sw_params_sizeof()); } while (0)
+
+static void* alsa_lib;
+
+int main(void)
+{
+ int result = 1;
+
+ alsa_lib = dlopen( "libasound.so", RTLD_NOW );
+ if (alsa_lib == NULL)
+ alsa_lib = dlopen( "libasound.so.2", RTLD_NOW );
+
+ if (alsa_lib == NULL) {
+ D("could not find libasound on this system\n");
+ return 1;
+ }
+
+#undef DYN_FUNCTION
+#define DYN_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( alsa_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libasound\n", STRINGIFY(name)); \
+ goto Fail; \
+ } \
+ } while (0);
+
+ DYN_SYMBOLS
+
+ result = 0;
+ goto Exit;
+
+Fail:
+ D("failed to open library\n");
+
+Exit:
+ dlclose(alsa_lib);
+ return result;
+}
diff --git a/android/config/check-esd.c b/android/config/check-esd.c
new file mode 100644
index 0000000..a8eb11b
--- /dev/null
+++ b/android/config/check-esd.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* this file is used to test that we can use libesd with lazy dynamic linking */
+
+#include <esd.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+#define D(...) fprintf(stderr,__VA_ARGS__)
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define ESD_SYMBOLS \
+ ESD_FUNCTION(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_open_sound,( const char *host )) \
+ ESD_FUNCTION(int,esd_close,(int)) \
+
+/* define pointers to library functions we're going to use */
+#define ESD_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+ESD_SYMBOLS
+
+#undef ESD_FUNCTION
+static void* esd_lib;
+
+int main( void )
+{
+ int fd;
+
+ esd_lib = dlopen( "libesd.so", RTLD_NOW );
+ if (esd_lib == NULL)
+ esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
+
+ if (esd_lib == NULL) {
+ D("could not find libesd on this system");
+ return 1;
+ }
+
+#undef ESD_FUNCTION
+#define ESD_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( esd_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libesd\n", STRINGIFY(name)); \
+ return 1; \
+ } \
+ } while (0);
+
+ ESD_SYMBOLS
+
+ return 0;
+}
diff --git a/android/globals.h b/android/globals.h
new file mode 100644
index 0000000..625c84a
--- /dev/null
+++ b/android/globals.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_GLOBALS_H
+#define _ANDROID_GLOBALS_H
+
+#include "android/vm/info.h"
+#include "android/vm/hw-config.h"
+
+/* this structure is setup when loading the virtual machine
+ * after that, you can read the 'flags' field to determine
+ * wether a data or cache wipe has been in effect.
+ */
+extern AvmInfoParams android_vmParams[1];
+
+/* a pointer to the android virtual machine information
+ * object, which can be queried for the paths of various
+ * image files or the skin
+ */
+extern AvmInfo* android_vmInfo;
+
+/* the hardware configuration for this specific virtual machine */
+extern AndroidHwConfig android_hw[1];
+
+#endif /* _ANDROID_GLOBALS_H */
diff --git a/android/tools/gen-hw-config.py b/android/tools/gen-hw-config.py
new file mode 100755
index 0000000..ae3a8de
--- /dev/null
+++ b/android/tools/gen-hw-config.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# this script is used to generate 'android/vm/hw-config.h' by
+# parsing 'android/vm/hardware-properties.ini'
+#
+#
+import sys, os, string, re
+
+# location of source file, relative to current program directory
+relativeSourcePath = "../vm/hardware-properties.ini"
+
+# location of target file, relative to current program directory
+relativeTargetPath = "../vm/hw-config-defs.h"
+
+def quoteStringForC(str):
+ """quote a string so it can be used in C"""
+ return '\\"'.join('"'+p+'"' for p in str.split('"'))
+
+# a dictionary that maps item types as they appear in the .ini
+# file into macro names in the generated C header
+#
+typesToMacros = {
+ 'integer': 'HWCFG_INT',
+ 'string': 'HWCFG_STRING',
+ 'boolean': 'HWCFG_BOOL',
+ 'diskSize': 'HWCFG_DISKSIZE',
+ 'double': 'HWCFG_DOUBLE'
+ }
+
+# the list of macro names
+macroNames = typesToMacros.values()
+
+# target program header
+targetHeader = """\
+/* this file is automatically generated from 'hardware-properties.ini'
+ * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
+ */"""
+
+# locate source and target
+programDir = os.path.dirname(sys.argv[0])
+sourceFile = os.path.normpath(os.path.join(programDir,relativeSourcePath))
+targetFile = os.path.normpath(os.path.join(programDir,relativeTargetPath))
+
+# parse the source file and record items
+# I would love to use Python's ConfigParser, but it doesn't
+# support files without sections, or multiply defined items
+#
+items = []
+lastItem = None
+
+class Item:
+ def __init__(self,name):
+ self.name = name
+ self.type = type
+ self.default = None
+ self.abstract = ""
+ self.description = ""
+
+ def add(self,key,val):
+ if key == 'type':
+ self.type = val
+ elif key == 'default':
+ self.default = val
+ elif key == 'abstract':
+ self.abstract = val
+ elif key == 'description':
+ self.description = val
+
+for line in open(sourceFile):
+ line = line.strip()
+ # ignore empty lines and comments
+ if len(line) == 0 or line[0] in ";#":
+ continue
+ key, value = line.split('=')
+
+ key = key.strip()
+ value = value.strip()
+
+ if key == 'name':
+ if lastItem: items.append(lastItem)
+ lastItem = Item(value)
+ else:
+ lastItem.add(key, value)
+
+if lastItem:
+ items.append(lastItem)
+
+
+print targetHeader
+
+# write guards to prevent bad compiles
+for m in macroNames:
+ print """\
+#ifndef %(macro)s
+#error %(macro)s not defined
+#endif""" % { 'macro':m }
+print ""
+
+for item in items:
+ if item.type == None:
+ sys.stderr.write("ignoring config item with no type '%s'\n" % item.name)
+ continue
+
+ if not typesToMacros.has_key(item.type):
+ sys.stderr.write("ignoring config item with unknown type '%s': '%s'\n" % \
+ (item.type, item.name))
+ continue
+
+ if item.default == None:
+ sys.stderr.write("ignoring config item with no default '%s' */" % item.name)
+ continue
+
+ # convert dots into underscores
+ varMacro = typesToMacros[item.type]
+ varNameStr = quoteStringForC(item.name)
+ varName = item.name.replace(".","_")
+ varDefault = item.default
+ varAbstract = quoteStringForC(item.abstract)
+ varDesc = quoteStringForC(item.description)
+
+ if item.type in [ 'string', 'boolean', 'diskSize' ]:
+ # quote default value for strings
+ varDefault = quoteStringForC(varDefault)
+
+ print "%s(\n %s,\n %s,\n %s,\n %s,\n %s)\n" % \
+ (varMacro,varName,varNameStr,varDefault,varAbstract,varDesc)
+
+
+for m in macroNames:
+ print "#undef %s" % m
+
+print "/* end of auto-generated file */"
diff --git a/android/utils/debug.h b/android/utils/debug.h
new file mode 100644
index 0000000..28b93ee
--- /dev/null
+++ b/android/utils/debug.h
@@ -0,0 +1,18 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_DEBUG_H
+#define _ANDROID_UTILS_DEBUG_H
+
+/* we'll move android_debug.h here later */
+#include "android_debug.h"
+
+#endif /* _ANDROID_UTILS_DEBUG_H */
diff --git a/android/utils/dirscanner.c b/android/utils/dirscanner.c
new file mode 100644
index 0000000..9f44d2d
--- /dev/null
+++ b/android/utils/dirscanner.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/dirscanner.h"
+#include "android_utils.h"
+#include "vl.h"
+#include <stddef.h>
+
+#define DIRSCANNER_BASE \
+ char root[PATH_MAX]; \
+ int rootLen; \
+ char full[PATH_MAX]; \
+
+
+#if _WIN32
+
+#include <io.h>
+
+struct DirScanner {
+ DIRSCANNER_BASE
+ intptr_t findIndex1;
+ struct _finddata_t findData;
+};
+
+/* note: findIndex1 contains the find index + 1
+ * so a value of 0 means 'invalid'
+ */
+
+static int
+_dirScannerInit( DirScanner* s )
+{
+ char* p = s->root + s->rootLen;
+ char* end = s->root + sizeof s->root;
+ int ret;
+
+ /* create file spec by appending \* to root */
+ p = bufprint(p, end, "\\*");
+ if (p >= end)
+ return -1;
+
+ ret = _findfirst(s->root, &s->findData) + 1;
+
+ s->findIndex1 = ret+1;
+ return ret;
+}
+
+static void
+_dirScanner_done( DirScanner* s )
+{
+ if (s->findIndex1 > 0) {
+ _findclose(s->findIndex1-1);
+ s->findIndex1 = 0;
+ }
+}
+
+const char*
+dirScanner_next( DirScanner* s )
+{
+ char* ret = NULL;
+
+ if (!s || s->findIndex1 <= 0)
+ return NULL;
+
+ while (ret == NULL) {
+ ret = s->findData.name;
+
+ /* ignore special directories */
+ if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
+ ret = NULL;
+ }
+ /* find next one */
+ if (_findnext(s->findIndex1-1, &s->findData) < 0) {
+ _dirScanner_done(s);
+ break;
+ }
+ }
+ return ret;
+}
+
+#else /* !_WIN32 */
+
+#include <dirent.h>
+struct DirScanner {
+ DIRSCANNER_BASE
+ DIR* dir;
+ struct dirent* entry;
+};
+
+static int
+_dirScannerInit( DirScanner* s )
+{
+ s->dir = opendir(s->root);
+
+ if (s->dir == NULL)
+ return -1;
+
+ s->entry = NULL;
+ return 0;
+}
+
+static void
+_dirScanner_done( DirScanner* s )
+{
+ if (s->dir) {
+ closedir(s->dir);
+ s->dir = NULL;
+ }
+}
+
+const char*
+dirScanner_next( DirScanner* s )
+{
+ char* ret = NULL;
+
+ if (!s || s->dir == NULL)
+ return NULL;
+
+ for (;;)
+ {
+ /* read new entry if needed */
+ s->entry = readdir(s->dir);
+ if (s->entry == NULL) {
+ _dirScanner_done(s);
+ break;
+ }
+
+ /* ignore special directories */
+ ret = s->entry->d_name;
+
+ if (!strcmp(ret,".") || !strcmp(ret,"..")) {
+ ret = NULL;
+ continue;
+ }
+ break;
+ }
+ return ret;
+}
+
+#endif /* !_WIN32 */
+
+DirScanner*
+dirScanner_new ( const char* rootPath )
+{
+ DirScanner* s = qemu_mallocz(sizeof *s);
+ char* p = s->root;
+ char* end = p + sizeof s->root;
+
+ p = bufprint(p, end, "%s", rootPath);
+ if (p >= end)
+ goto FAIL;
+
+ s->rootLen = (p - s->root);
+
+ if (_dirScannerInit(s) < 0)
+ goto FAIL;
+
+ return s;
+
+FAIL:
+ dirScanner_free(s);
+ return NULL;
+}
+
+
+void
+dirScanner_free( DirScanner* s )
+{
+ if (!s)
+ return;
+
+ _dirScanner_done(s);
+ qemu_free(s);
+}
+
+
+const char*
+dirScanner_nextFull( DirScanner* s )
+{
+ const char* name = dirScanner_next(s);
+ char* p;
+ char* end;
+
+ if (name == NULL)
+ return NULL;
+
+ p = s->full;
+ end = p + sizeof s->full;
+
+ p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
+ if (p >= end) {
+ /* ignore if the full name is too long */
+ return dirScanner_nextFull(s);
+ }
+ return s->full;
+}
diff --git a/android/utils/dirscanner.h b/android/utils/dirscanner.h
new file mode 100644
index 0000000..9486cfc
--- /dev/null
+++ b/android/utils/dirscanner.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_DIR_H
+#define _ANDROID_UTILS_DIR_H
+
+/* simple utility to parse directories for files */
+/* needed because Unix and Windows don't use the same stuff */
+
+typedef struct DirScanner DirScanner;
+
+DirScanner* dirScanner_new ( const char* rootPath );
+void dirScanner_free( DirScanner* s );
+const char* dirScanner_next( DirScanner* s );
+const char* dirScanner_nextFull( DirScanner* s );
+
+#endif /* _ANDROID_UTILS_DIR_H */
diff --git a/android/utils/ini.c b/android/utils/ini.c
new file mode 100644
index 0000000..d99ecdd
--- /dev/null
+++ b/android/utils/ini.c
@@ -0,0 +1,366 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/utils/ini.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include "android_debug.h"
+#include "osdep.h"
+
+/* W() is used to print warnings, D() to print debugging info */
+#define W(...) dwarning(__VA_ARGS__)
+#define D(...) VERBOSE_PRINT(vm_config,__VA_ARGS__)
+
+/* a simple .ini file parser and container for Android
+ * no sections support. see android/utils/ini.h for
+ * more details on the supported file format.
+ */
+typedef struct {
+ char* key;
+ char* value;
+} IniPair;
+
+struct IniFile {
+ int numPairs;
+ int maxPairs;
+ IniPair* pairs;
+};
+
+void
+iniFile_free( IniFile* i )
+{
+ int nn;
+ for (nn = 0; nn < i->numPairs; nn++) {
+ free(i->pairs[nn].key);
+ i->pairs[nn].key = NULL;
+ i->pairs[nn].value = NULL;
+ }
+ free(i->pairs);
+ free(i);
+}
+
+static IniFile*
+iniFile_alloc( void )
+{
+ IniFile* i = calloc(1, sizeof(*i));
+ return i;
+}
+
+static void
+iniFile_addPair( IniFile* i, const char* key, int keyLen,
+ const char* value, int valueLen )
+{
+ IniPair* pair;
+
+ if (i->numPairs >= i->maxPairs) {
+ int oldMax = i->maxPairs;
+ int newMax = oldMax + (oldMax >> 1) + 4;
+ IniPair* newPairs = realloc(i->pairs, newMax*sizeof(newPairs[0]));
+
+ i->pairs = newPairs;
+ i->maxPairs = newMax;
+ }
+
+ pair = i->pairs + i->numPairs;
+
+ pair->key = malloc(keyLen + valueLen + 2);
+ memcpy(pair->key, key, keyLen);
+ pair->key[keyLen] = 0;
+
+ pair->value = pair->key + keyLen + 1;
+ memcpy(pair->value, value, valueLen);
+ pair->value[valueLen] = 0;
+
+ i->numPairs += 1;
+}
+
+const char*
+iniFile_getValue( IniFile* i, const char* key )
+{
+ if (i && key) {
+ int nn;
+
+ for (nn = 0; nn < i->numPairs; nn++) {
+ if (!strcmp(i->pairs[nn].key,key))
+ return i->pairs[nn].value;
+ }
+ }
+ return NULL;
+}
+
+int
+iniFile_getPairCount( IniFile* i )
+{
+ return i ? i->numPairs : 0;
+}
+
+void
+iniFile_getPair( IniFile* i,
+ int index,
+ const char* *pKey,
+ const char* *pValue )
+{
+ const char* key = NULL;
+ const char* value = NULL;
+
+ if (i && index >= 0 && index < i->numPairs) {
+ key = i->pairs[index].key;
+ value = i->pairs[index].value;
+ }
+ *pKey = key;
+ *pValue = value;
+}
+
+/* NOTE: we avoid using <ctype.h> functions to avoid locale-specific
+ * behaviour that can be the source of strange bugs.
+ */
+
+static const char*
+skipSpaces( const char* p )
+{
+ while (*p == ' ' || *p == '\t')
+ p ++;
+ return p;
+}
+
+static const char*
+skipToEOL( const char* p )
+{
+ while (*p && (*p != '\n' && *p != '\r'))
+ p ++;
+
+ if (*p) {
+ p ++;
+ if (p[-1] == '\r' && p[0] == '\n')
+ p ++;
+ }
+ return p;
+}
+
+static int
+isKeyStartChar( int c )
+{
+ return ((unsigned)(c-'a') < 26 ||
+ (unsigned)(c-'A') < 26 ||
+ c == '_');
+}
+
+static int
+isKeyChar( int c )
+{
+ return isKeyStartChar(c) || ((unsigned)(c-'0') < 10) || (c == '.');
+}
+
+IniFile*
+iniFile_newFromMemory( const char* text, const char* fileName )
+{
+ const char* p = text;
+ IniFile* ini = iniFile_alloc();
+ int lineno = 0;
+
+ if (!fileName)
+ fileName = "<unknownFile>";
+
+ D("%s: parsing as .ini file", fileName);
+
+ while (*p) {
+ const char* key;
+ int keyLen;
+ const char* value;
+ int valueLen;
+
+ lineno += 1;
+
+ /* skip leading whitespace */
+ p = skipSpaces(p);
+
+ /* skip comments and empty lines */
+ if (*p == 0 || *p == ';' || *p == '#' || *p == '\n' || *p == '\r') {
+ p = skipToEOL(p);
+ continue;
+ }
+
+ /* check the key name */
+ key = p++;
+ if (!isKeyStartChar(*key)) {
+ p = skipToEOL(p);
+ W("%s:%d: key name doesn't start with valid character. line ignored",
+ fileName, lineno);
+ continue;
+ }
+
+ while (isKeyChar(*p))
+ p++;
+
+ keyLen = p - key;
+ p = skipSpaces(p);
+
+ /* check the equal */
+ if (*p != '=') {
+ W("%s:%d: missing expected assignment operator (=). line ignored",
+ fileName, lineno);
+ p = skipToEOL(p);
+ continue;
+ }
+ p += 1;
+
+ /* skip spaces before the value */
+ p = skipSpaces(p);
+ value = p;
+
+ /* find the value */
+ while (*p && (*p != '\n' && *p != '\r'))
+ p += 1;
+
+ /* remove trailing spaces */
+ while (p > value && (p[-1] == ' ' || p[-1] == '\t'))
+ p --;
+
+ valueLen = p - value;
+
+ iniFile_addPair(ini, key, keyLen, value, valueLen);
+ D("%s:%d: KEY='%.*s' VALUE='%.*s'", fileName, lineno,
+ keyLen, key, valueLen, value);
+
+ p = skipToEOL(p);
+ }
+
+ return ini;
+}
+
+IniFile*
+iniFile_newFromFile( const char* filepath )
+{
+ FILE* fp = fopen(filepath, "rt");
+ char* text;
+ long size;
+ IniFile* ini = NULL;
+
+ if (fp == NULL) {
+ W("could not open .ini file: %s: %s",
+ filepath, strerror(errno));
+ return NULL;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ /* avoid reading a very large file that was passed by mistake
+ * this threshold is quite liberal.
+ */
+#define MAX_INI_FILE_SIZE 655360
+
+ if (size < 0 || size > MAX_INI_FILE_SIZE) {
+ W("hardware configuration file '%s' too large (%ld bytes)",
+ filepath, size);
+ goto EXIT;
+ }
+
+ /* read the file, add a sentinel at the end of it */
+ text = malloc(size+1);
+ fread(text, 1, size, fp);
+ text[size] = 0;
+
+ ini = iniFile_newFromMemory(text, filepath);
+ free(text);
+
+EXIT:
+ fclose(fp);
+ return ini;
+}
+
+char*
+iniFile_getString( IniFile* f, const char* key )
+{
+ const char* val = iniFile_getValue(f, key);
+
+ if (!val)
+ return NULL;
+
+ return qemu_strdup(val);
+}
+
+int
+iniFile_getInteger( IniFile* f, const char* key, int defaultValue )
+{
+ const char* valueStr = iniFile_getValue(f, key);
+ int value = defaultValue;
+
+ if (valueStr != NULL) {
+ char* end;
+ long l = strtol(valueStr, &end, 10);
+ if (end != NULL && end[0] == 0 && (int)l == l)
+ value = l;
+ }
+ return value;
+}
+
+double
+iniFile_getDouble( IniFile* f, const char* key, double defaultValue )
+{
+ const char* valueStr = iniFile_getValue(f, key);
+ double value = defaultValue;
+
+ if (valueStr != NULL) {
+ char* end;
+ double d = strtod(valueStr, &end);
+ if (end != NULL && end[0] == 0)
+ value = d;
+ }
+ return value;
+}
+
+int
+iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue )
+{
+ const char* value = iniFile_getValue(f, key);
+
+ if (!value)
+ value = defaultValue;
+
+ if (!strcmp(value,"1") ||
+ !strcmp(value,"yes") ||
+ !strcmp(value,"YES") ||
+ !strcmp(value,"true") ||
+ !strcmp(value,"TRUE"))
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int64_t
+iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue )
+{
+ const char* valStr = iniFile_getValue(f, key);
+ int64_t value = 0;
+
+ if (!valStr)
+ valStr = defaultValue;
+
+ if (valStr != NULL) {
+ char* end;
+
+ value = strtoll(valStr, &end, 10);
+ if (*end == 'k' || *end == 'K')
+ value *= 1024ULL;
+ else if (*end == 'm' || *end == 'M')
+ value *= 1024*1024ULL;
+ else if (*end == 'g' || *end == 'G')
+ value *= 1024*1024*1024ULL;
+ }
+ return value;
+}
diff --git a/android/utils/ini.h b/android/utils/ini.h
new file mode 100644
index 0000000..41b369b
--- /dev/null
+++ b/android/utils/ini.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_INI_H
+#define _ANDROID_UTILS_INI_H
+
+#include <stdint.h>
+
+/* the emulator supports a simple .ini file format for its configuration
+ * files. Here's the BNF for it:
+ *
+ * file := <line>*
+ * line := <comment> | <LF> | <assignment>
+ * comment := (';'|'#') <noLF>* <LF>
+ * assignment := <space>* <keyName> <space>* '=' <space>* <valueString> <space>* <LF>
+ * keyName := <keyNameStartChar> <keyNameChar>*
+ * keyNameStartChar := [A-Za-z_]
+ * keyNameChar := [A-Za-z0-9_.]
+ * valueString := <noLF>*
+ * space := ' ' | '\t'
+ * LF := '\r\n' | '\n' | '\r'
+ * noLF := [^<LF>]
+ *
+ * Or, in English:
+ *
+ * - no support for sections
+ * - empty lines are ignored, as well as lines beginning with ';' or '#'
+ * - lines must be of the form: "<keyName> = <value>"
+ * - key names must start with a letter or an underscore
+ * - other key name characters can be letters, digits, underscores or dots
+ *
+ * - leading and trailing space are allowed and ignored before/after the key name
+ * and before/after the value
+ *
+ * - there is no restriction on the value, except that it can't contain
+ * leading/trailing space/tab characters or newline/charfeed characters
+ *
+ * - empty values are possible, and will be stored as an empty string.
+ * - any badly formatted line is discarded (and will print a warning)
+ *
+ */
+
+/* an opaque structure used to model an .ini configuration file */
+typedef struct IniFile IniFile;
+
+/* creates a new IniFile object from a config file loaded in memory.
+ * 'fileName' is only used when writing a warning to stderr in case
+ * of badly formed output
+ */
+IniFile* iniFile_newFromMemory( const char* text, const char* fileName );
+
+/* creates a new IniFile object from a file path,
+ * returns NULL if the file cannot be opened.
+ */
+IniFile* iniFile_newFromFile( const char* filePath);
+
+/* free an IniFile object */
+void iniFile_free( IniFile* f );
+
+/* returns the number of (key.value) pairs in an IniFile */
+int iniFile_getPairCount( IniFile* f );
+
+/* return a specific (key,value) pair from an IniFile.
+ * if the index is not correct, both '*pKey' and '*pValue' will be
+ * set to NULL.
+ *
+ * you should probably use iniFile_getValue() and its variants instead
+ */
+void iniFile_getPair( IniFile* f,
+ int index,
+ const char* *pKey,
+ const char* *pValue );
+
+/* returns the value of a given key from an IniFile.
+ * NULL if the key is not assigned in the corresponding configuration file
+ */
+const char* iniFile_getValue( IniFile* f, const char* key );
+
+/* returns a copy of the value of a given key, or NULL
+ */
+char* iniFile_getString( IniFile* f, const char* key );
+
+/* returns an integer value, or a default in case the value string is
+ * missing or badly formatted
+ */
+int iniFile_getInteger( IniFile* f, const char* key, int defaultValue );
+
+/* returns a double value, or a default in case the value string is
+ * missing or badly formatted
+ */
+double iniFile_getDouble( IniFile* f, const char* key, double defaultValue );
+
+/* returns a copy of a given key's value, if any, or NULL if it is missing
+ * caller must call free() to release it */
+char* iniFile_getString( IniFile* f, const char* key );
+
+/* parses a key value as a boolean. Accepted values are "1", "0", "yes", "YES",
+ * "no" and "NO". Returns either 1 or 0.
+ * note that the default value must be provided as a string too
+ */
+int iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue );
+
+/* parses a key value as a disk size. this means it can be an integer followed
+ * by a suffix that can be one of "mMkKgG" which correspond to KiB, MiB and GiB
+ * multipliers.
+ *
+ * NOTE: we consider that 1K = 1024, not 1000.
+ */
+int64_t iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue );
+
+/* */
+
+#endif /* _ANDROID_UTILS_INI_H */
diff --git a/android/vm/hardware-properties.ini b/android/vm/hardware-properties.ini
new file mode 100644
index 0000000..3589e45
--- /dev/null
+++ b/android/vm/hardware-properties.ini
@@ -0,0 +1,158 @@
+# This file describes the properties of a given virtual device configuration file.
+#
+# Note: Most top-level properties are boolean that control whether a feature is
+# present or not. Sub-features that depend on it are ignored if their
+# parent is set to 'false' or 'no'
+#
+# This file is parsed by 'android/tools/gen-hw-config.py' to generate
+# 'android/vm/hw-config-defs.h'. The latter is a special header containing
+# macro statements that is used several times:
+#
+# - once to define the fields of the AndroidHwConfig structure
+# (see android/vm/hw-config.h)
+#
+# - once to implement the hardware configuration loader
+# (see android/vm/hw-config.h)
+#
+# Hopefully, this file should also be read by a virtual device creation
+# tool/wizard to provide a nice user interface (hence the presence of
+# the 'abstract' and 'description' keys which are not currently used)
+#
+#
+# NOTE: if you remove items from this file, be sure that you do not break
+# the emulator build.
+#
+
+# Ram size
+name = hw.ramSize
+type = integer
+default = 96
+abstract = Device ram size
+description = The amount of physical RAM on the device, in megabytes.
+
+# Touch screen support
+name = hw.touchScreen
+type = boolean
+default = yes
+abstract = Touch-screen support
+description = Whether there is a touch screen or not on the device.
+
+# Trackball support
+name = hw.trackBall
+type = boolean
+default = yes
+abstract = Track-ball support
+description = Whether there is a trackball on the device.
+
+# Keyboard support (qwerty/azerty)
+name = hw.keyboard
+type = boolean
+default = yes
+abstract = Keyboard support
+description = Whether the device has a QWERTY keyboard.
+
+# DPad keys
+name = hw.dPad
+type = boolean
+default = yes
+abstract = DPad support
+description = Whether the device has DPad keys
+
+# GSM Modem support
+name = hw.gsmModem
+type = boolean
+default = yes
+abstract = GSM modem support
+description = Whether there is a GSM modem in the device.
+
+# Wifi support
+name = hw.wifi
+type = boolean
+default = no
+abstract = Wifi support
+description = Whether the device has a Wifi chipset.
+
+# Bluetooth support
+name = hw.bluetooth
+type = boolean
+default = no
+abstract = Bluetooth support
+description = Whether the device has a Bluetooth chipset.
+
+# Camera support
+name = hw.camera
+type = boolean
+default = no
+abstract = Camera support
+description = Whether the device has a camera.
+
+name = hw.camera.maxHorizontalPixels
+type = integer
+default = 640
+abstract = Maximum horizontal camera pixels
+
+name = hw.camera.maxVerticalPixels
+type = integer
+default = 480
+abstract = Maximum vertical camera pixels
+
+# GPS support
+name = hw.gps
+type = boolean
+default = no
+abstract = GPS support
+description = Whether there is a GPS in the device.
+
+# Accelerometer
+name = hw.accelerometer
+type = boolean
+default = no
+abstract = Accelerometer support
+description = Whether there is an accelerometer in the device.
+
+# Battery
+name = hw.battery
+type = boolean
+default = yes
+abstract = Battery support
+description = Whether the device can run on a battery.
+
+# Audio input
+name = hw.audioInput
+type = boolean
+default = yes
+abstract = Audio recording support
+description = Whether the device can record audio
+
+# Audio output
+name = hw.audioOutput
+type = boolean
+default = yes
+abstract = Audio playback support
+description = Whether the device can play audio
+
+# Compass
+name = hw.compass
+type = boolean
+default = no
+abstract = Compass support
+description = Whether there is a compass in the device.
+
+# SDCard support
+name = hw.sdCard
+type = boolean
+default = yes
+abstract = SD Card support
+description = Whether the device supports insertion/removal of virtual SD Cards.
+
+# Cache partition
+name = disk.cachePartition
+type = boolean
+default = yes
+abstract = Cache partition support
+description = Whether we use a /cache partition on the device.
+
+name = disk.cachePartition.size
+type = diskSize
+abstract = Cache partition size
+default = 66MB
diff --git a/android/vm/hw-config-defs.h b/android/vm/hw-config-defs.h
new file mode 100644
index 0000000..5c3b9ab
--- /dev/null
+++ b/android/vm/hw-config-defs.h
@@ -0,0 +1,165 @@
+/* this file is automatically generated from 'hardware-properties.ini'
+ * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
+ */
+#ifndef HWCFG_INT
+#error HWCFG_INT not defined
+#endif
+#ifndef HWCFG_BOOL
+#error HWCFG_BOOL not defined
+#endif
+#ifndef HWCFG_DISKSIZE
+#error HWCFG_DISKSIZE not defined
+#endif
+#ifndef HWCFG_STRING
+#error HWCFG_STRING not defined
+#endif
+#ifndef HWCFG_DOUBLE
+#error HWCFG_DOUBLE not defined
+#endif
+
+HWCFG_INT(
+ hw_ramSize,
+ "hw.ramSize",
+ 96,
+ "Device ram size",
+ "The amount of physical RAM on the device, in megabytes.")
+
+HWCFG_BOOL(
+ hw_touchScreen,
+ "hw.touchScreen",
+ "yes",
+ "Touch-screen support",
+ "Whether there is a touch screen or not on the device.")
+
+HWCFG_BOOL(
+ hw_trackBall,
+ "hw.trackBall",
+ "yes",
+ "Track-ball support",
+ "Whether there is a trackball on the device.")
+
+HWCFG_BOOL(
+ hw_keyboard,
+ "hw.keyboard",
+ "yes",
+ "Keyboard support",
+ "Whether the device has a QWERTY keyboard.")
+
+HWCFG_BOOL(
+ hw_dPad,
+ "hw.dPad",
+ "yes",
+ "DPad support",
+ "Whether the device has DPad keys")
+
+HWCFG_BOOL(
+ hw_gsmModem,
+ "hw.gsmModem",
+ "yes",
+ "GSM modem support",
+ "Whether there is a GSM modem in the device.")
+
+HWCFG_BOOL(
+ hw_wifi,
+ "hw.wifi",
+ "no",
+ "Wifi support",
+ "Whether the device has a Wifi chipset.")
+
+HWCFG_BOOL(
+ hw_bluetooth,
+ "hw.bluetooth",
+ "no",
+ "Bluetooth support",
+ "Whether the device has a Bluetooth chipset.")
+
+HWCFG_BOOL(
+ hw_camera,
+ "hw.camera",
+ "no",
+ "Camera support",
+ "Whether the device has a camera.")
+
+HWCFG_INT(
+ hw_camera_maxHorizontalPixels,
+ "hw.camera.maxHorizontalPixels",
+ 640,
+ "Maximum horizontal camera pixels",
+ "")
+
+HWCFG_INT(
+ hw_camera_maxVerticalPixels,
+ "hw.camera.maxVerticalPixels",
+ 480,
+ "Maximum vertical camera pixels",
+ "")
+
+HWCFG_BOOL(
+ hw_gps,
+ "hw.gps",
+ "no",
+ "GPS support",
+ "Whether there is a GPS in the device.")
+
+HWCFG_BOOL(
+ hw_accelerometer,
+ "hw.accelerometer",
+ "no",
+ "Accelerometer support",
+ "Whether there is an accelerometer in the device.")
+
+HWCFG_BOOL(
+ hw_battery,
+ "hw.battery",
+ "yes",
+ "Battery support",
+ "Whether the device can run on a battery.")
+
+HWCFG_BOOL(
+ hw_audioInput,
+ "hw.audioInput",
+ "yes",
+ "Audio recording support",
+ "Whether the device can record audio")
+
+HWCFG_BOOL(
+ hw_audioOutput,
+ "hw.audioOutput",
+ "yes",
+ "Audio playback support",
+ "Whether the device can play audio")
+
+HWCFG_BOOL(
+ hw_compass,
+ "hw.compass",
+ "no",
+ "Compass support",
+ "Whether there is a compass in the device.")
+
+HWCFG_BOOL(
+ hw_sdCard,
+ "hw.sdCard",
+ "yes",
+ "SD Card support",
+ "Whether the device supports insertion/removal of virtual SD Cards.")
+
+HWCFG_BOOL(
+ disk_cachePartition,
+ "disk.cachePartition",
+ "yes",
+ "Cache partition support",
+ "Whether we use a /cache partition on the device.")
+
+HWCFG_DISKSIZE(
+ disk_cachePartition_size,
+ "disk.cachePartition.size",
+ "66MB",
+ "Cache partition size",
+ "")
+
+#undef HWCFG_INT
+#undef HWCFG_BOOL
+#undef HWCFG_DISKSIZE
+#undef HWCFG_STRING
+#undef HWCFG_DOUBLE
+/* end of auto-generated file */
diff --git a/android/vm/hw-config.c b/android/vm/hw-config.c
new file mode 100644
index 0000000..7018d32
--- /dev/null
+++ b/android/vm/hw-config.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/vm/hw-config.h"
+#include "android/utils/ini.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+/* the global variable containing the hardware config for this device */
+AndroidHwConfig android_hw[1];
+
+int
+androidHwConfig_read( AndroidHwConfig* config,
+ IniFile* ini )
+{
+ if (ini == NULL)
+ return -1;
+
+ /* use the magic of macros to implement the hardware configuration loaded */
+
+#define HWCFG_BOOL(n,s,d,a,t) config->n = iniFile_getBoolean(ini, s, d);
+#define HWCFG_INT(n,s,d,a,t) config->n = iniFile_getInteger(ini, s, d);
+#define HWCFG_STRING(n,s,d,a,t) config->n = iniFile_getString(ini, s, d);
+#define HWCFG_DOUBLE(n,s,d,a,t) config->n = iniFile_getDouble(ini, s, d);
+#define HWCFG_DISKSIZE(n,s,d,a,t) config->n = iniFile_getDiskSize(ini, s, d);
+
+#include "android/vm/hw-config-defs.h"
+
+ return 0;
+}
diff --git a/android/vm/hw-config.h b/android/vm/hw-config.h
new file mode 100644
index 0000000..0ab231d
--- /dev/null
+++ b/android/vm/hw-config.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_VM_HW_CONFIG_H
+#define _ANDROID_VM_HW_CONFIG_H
+
+#include <stdint.h>
+#include "android/utils/ini.h"
+
+typedef char hw_bool_t;
+typedef int hw_int_t;
+typedef int64_t hw_disksize_t;
+typedef char* hw_string_t;
+typedef double hw_double_t;
+
+/* these macros are used to define the fields of AndroidHwConfig
+ * declared below
+ */
+#define HWCFG_BOOL(n,s,d,a,t) hw_bool_t n;
+#define HWCFG_INT(n,s,d,a,t) hw_int_t n;
+#define HWCFG_STRING(n,s,d,a,t) hw_string_t n;
+#define HWCFG_DOUBLE(n,s,d,a,t) hw_double_t n;
+#define HWCFG_DISKSIZE(n,s,d,a,t) hw_disksize_t n;
+
+typedef struct {
+#include "android/vm/hw-config-defs.h"
+} AndroidHwConfig;
+
+/* reads a hardware configuration file from disk.
+ * returns -1 if the file could not be read, or 0 in case of success.
+ *
+ * note that default values are written to hwConfig if the configuration
+ * file doesn't have the corresponding hardware properties.
+ */
+int androidHwConfig_read( AndroidHwConfig* hwConfig,
+ IniFile* configFile );
+
+#endif /* _ANDROID_VM_HW_CONFIG_H */
diff --git a/android/vm/info.c b/android/vm/info.c
new file mode 100644
index 0000000..e3f04ff
--- /dev/null
+++ b/android/vm/info.c
@@ -0,0 +1,1534 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "android/vm/info.h"
+#include "android_utils.h"
+#include "android/utils/debug.h"
+#include "android/utils/dirscanner.h"
+#include "osdep.h"
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* global variables - see android/globals.h */
+AvmInfoParams android_vmParams[1];
+AvmInfo* android_vmInfo;
+
+/* for debugging */
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+#define DD(...) VERBOSE_PRINT(vm_config,__VA_ARGS__)
+
+/* technical note on how all of this is supposed to work:
+ *
+ * we assume the following SDK layout:
+ *
+ * SDK/
+ * tools/
+ * emulator[.exe]
+ * libs/
+ * hardware-properties.ini
+ * ...
+ *
+ * platforms/
+ * <platform1>/
+ * build.prop
+ * images/
+ * <default kernel/disk images>
+ * skins/
+ * default/ --> default skin
+ * layout
+ * <skin bitmaps>
+ * <skin2>/ --> another skin
+ * layout
+ * <skin bitmaps>
+ * <skin3>/ --> skin alias to <skin2>
+ * alias-<skin2>
+ *
+ * <platform2>/
+ * build.prop
+ * images/
+ * <other default kernel/disk images>
+ *
+ * add-ons/
+ * <partner1>/
+ * manifest.ini
+ * images/
+ * <replacement disk images>
+ *
+ * <partner2>/
+ * manifest.ini
+ * <replacement disk images>
+ * hardware.ini
+ * skins/
+ * default/
+ * layout
+ * <skin bitmaps>
+ * <skin2>/
+ * layout
+ * <skin bitmaps>
+ *
+ *
+ * we define a 'platform' as a directory that provides a complete
+ * set of disk/kernel images, some skins, as well as a build.prop
+ * file.
+ *
+ * we define an 'addon' as a directory that provides additionnal
+ * or replacement files related to a given existing platform.
+ * each add-on provides at the minimum a 'manifest.ini' file
+ * that describes it (see below).
+ *
+ * important notes:
+ *
+ * - the build.prop file of a given platform directory contains
+ * a line that reads 'ro.build.version.sdk=<version>' where
+ * <version> is an integer corresponding to the corresponding
+ * official API version number as defined by Android.
+ *
+ * each platform provided with the SDK must have a unique
+ * version number.
+ *
+ * - the manifest.ini of a given addon must contain lines
+ * that include:
+ *
+ * name=<addOnName>
+ * vendor=<vendorName>
+ * api=<version>
+ *
+ * where <version> is used to identify the platform the add-on
+ * refers to. Note that the platform's directory name is
+ * irrelevant to the matching algorithm.
+ *
+ * each addon available must have a unique
+ * <vendor>:<name>:<sdk> triplet
+ *
+ * - an add-on can provide a hardware.ini file. If present, this
+ * is used to force the hardware setting of any virtual machine
+ * built from the add-on.
+ *
+ * - the file in SDK/tools/lib/hardware-properties.ini declares which
+ * hardware properties are supported by the emulator binary.
+ * these can appear in the config.ini file of a given virtual
+ * machine, or the hardware.ini of a given add-on.
+ *
+ * normally, a virtual machine corresponds to:
+ *
+ * - a root configuration file, placed in ~/.android/vm/<foo>.ini
+ * where <foo> is the name of the virtual machine.
+ *
+ * - a "content" directory, which contains disk images for the
+ * virtual machine (e.g. at a minimum, the userdata.img file)
+ * plus some configuration information.
+ *
+ * - the root config file must have at least two lines like:
+ *
+ * path=<pathToContentDirectory>
+ * target=<targetAddonOrPlatform>
+ *
+ * the 'path' value must point to the location of
+ * the virtual machine's content directory. By default, this
+ * should be ~/.android/vm/<foo>/, though the user should be
+ * able to choose an alternative path at creation time.
+ *
+ * the 'target' value can be one of:
+ *
+ * android-<version>
+ * <vendor>:<name>:<version>
+ *
+ * the first form is used to refer to a given platform.
+ * the second form is used to refer to a unique add-on.
+ * in both forms, <version> must be an integer that
+ * matches one of the available platforms.
+ *
+ * <vendor>:<name>:<version> must match the triplet of one
+ * of the available add-ons
+ *
+ * if the target value is incorrect, or if the content path
+ * is invalid, the emulator will abort with an error.
+ *
+ * - the content directory shall contain a 'config.ini' that
+ * contains hardware properties for the virtual machine
+ * (as defined by SDK/tools/lib/hardware-properties.ini), as
+ * well as additional lines like:
+ *
+ * sdcard=<pathToDefaultSDCard>
+ * skin=<defaultSkinName>
+ * options=<additionalEmulatorStartupOptions>
+ *
+ *
+ * Finally, to find the skin to be used with a given virtual
+ * machine, the following logic is used:
+ *
+ * - if no skin name has been manually specified on
+ * the command line, or in the config.ini file,
+ * look in $CONTENT/skin/layout and use it if available.
+ *
+ * - otherwise, set SKINNAME to 'default' if not manually
+ * specified, and look for $ADDON/skins/$SKINNAME/layout
+ * and use it if available
+ *
+ * - otherwise, look for $PLATFORM/skins/$SKINNAME/layout
+ * and use it if available.
+ *
+ * - otherwise, look for $PLATFORM/skins/$SKINNAME/alias-<other>.
+ * if a file exist by that name, look at $PLATFORM/skins/<other>/layout
+ * and use it if available. Aliases are not recursives :-)
+ */
+
+/* now, things get a little bit more complicated when working
+ * within the Android build system. In this mode, which can be
+ * detected by looking at the definition of the ANDROID_PRODUCT_OUT
+ * environment variable, we're going to simply pick the image files
+ * from the out directory, or from $BUILDROOT/prebuilt
+ */
+
+/* the name of the $SDKROOT subdirectory that contains all platforms */
+#define PLATFORMS_SUBDIR "platforms"
+
+/* the name of the $SDKROOT subdirectory that contains add-ons */
+#define ADDONS_SUBDIR "add-ons"
+
+/* this is the subdirectory of $HOME/.android where all
+ * root configuration files (and default content directories)
+ * are located.
+ */
+#define ANDROID_VM_DIR "vm"
+
+/* certain disk image files are mounted read/write by the emulator
+ * to ensure that several emulators referencing the same files
+ * do not corrupt these files, we need to lock them and respond
+ * to collision depending on the image type.
+ *
+ * the enumeration below is used to record information about
+ * each image file path.
+ *
+ * READONLY means that the file will be mounted read-only
+ * and this doesn't need to be locked. must be first in list
+ *
+ * MUSTLOCK means that the file should be locked before
+ * being mounted by the emulator
+ *
+ * TEMPORARY means that the file has been copied to a
+ * temporary image, which can be mounted read/write
+ * but doesn't require locking.
+ */
+typedef enum {
+ IMAGE_STATE_READONLY, /* unlocked */
+ IMAGE_STATE_MUSTLOCK, /* must be locked */
+ IMAGE_STATE_LOCKED, /* locked */
+ IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
+ IMAGE_STATE_TEMPORARY, /* copied to temp file (no lock needed) */
+} AvmImageState;
+
+struct AvmInfo {
+ /* for the Android build system case */
+ char inAndroidBuild;
+ char* androidOut;
+ char* androidBuildRoot;
+
+ /* for the normal virtual machine case */
+ char* machineName;
+ char* sdkRootPath;
+ int platformVersion;
+ char* platformPath;
+ char* addonTarget;
+ char* addonPath;
+ char* contentPath;
+ IniFile* rootIni; /* root <foo>.ini file */
+ IniFile* configIni; /* virtual machine's config.ini */
+
+ /* for both */
+ char* skinName; /* skin name */
+ char* skinDirPath; /* skin directory */
+
+ /* image files */
+ char* imagePath [ AVM_IMAGE_MAX ];
+ char imageState[ AVM_IMAGE_MAX ];
+};
+
+
+void
+avmInfo_free( AvmInfo* i )
+{
+ if (i) {
+ int nn;
+
+ for (nn = 0; nn < AVM_IMAGE_MAX; nn++)
+ qemu_free(i->imagePath[nn]);
+
+ qemu_free(i->skinName);
+ qemu_free(i->skinDirPath);
+
+ if (i->configIni) {
+ iniFile_free(i->configIni);
+ i->configIni = NULL;
+ }
+
+ if (i->rootIni) {
+ iniFile_free(i->rootIni);
+ i->rootIni = NULL;
+ }
+
+ qemu_free(i->contentPath);
+ qemu_free(i->sdkRootPath);
+
+ if (i->inAndroidBuild) {
+ qemu_free(i->androidOut);
+ qemu_free(i->androidBuildRoot);
+ } else {
+ qemu_free(i->platformPath);
+ qemu_free(i->addonTarget);
+ qemu_free(i->addonPath);
+ }
+
+ qemu_free(i->machineName);
+ qemu_free(i);
+ }
+}
+
+/* list of default file names for each supported image file type */
+static const char* const _imageFileNames[ AVM_IMAGE_MAX ] = {
+#define _AVM_IMG(x,y,z) y,
+ AVM_IMAGE_LIST
+#undef _AVM_IMG
+};
+
+/* list of short text description for each supported image file type */
+static const char* const _imageFileText[ AVM_IMAGE_MAX ] = {
+#define _AVM_IMG(x,y,z) z,
+ AVM_IMAGE_LIST
+#undef _AVM_IMG
+};
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** NORMAL VIRTUAL MACHINE SUPPORT
+ *****
+ *****/
+
+/* compute path to the root SDK directory
+ * assume we are in $SDKROOT/tools/emulator[.exe]
+ */
+static int
+_getSdkRoot( AvmInfo* i )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ (void) bufprint_app_dir(temp, end);
+
+ i->sdkRootPath = path_parent(temp, 1);
+ if (i->sdkRootPath == NULL) {
+ derror("can't find root of SDK directory");
+ return -1;
+ }
+ D("found SDK root at %s", i->sdkRootPath);
+ return 0;
+}
+
+/* returns the full path of the platform subdirectory
+ * corresponding to a given API version
+ */
+static char*
+_findPlatformByVersion( const char* sdkRoot, int version )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
+ char* subdir = NULL;
+ DirScanner* scanner;
+
+ DD("> %s(%s,%d)", __FUNCTION__, sdkRoot, version);
+ p = bufprint(temp, end, "%s/%s", sdkRoot, PLATFORMS_SUBDIR);
+ if (p >= end) {
+ DD("! path too long");
+ return NULL;
+ }
+
+ scanner = dirScanner_new(temp);
+ if (scanner == NULL) {
+ DD("! cannot scan path %s: %s", temp, strerror(errno));
+ return NULL;
+ }
+
+ for (;;) {
+ IniFile* ini;
+ int apiVersion;
+
+ subdir = (char*) dirScanner_nextFull(scanner);
+ if (subdir == NULL)
+ break;
+
+ /* look for a file named "build.prop */
+ p = bufprint(temp, end, "%s/build.prop", subdir);
+ if (p >= end)
+ continue;
+
+ if (!path_exists(temp)) {
+ DD("! no file at %s", temp);
+ continue;
+ }
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL)
+ continue;
+
+ apiVersion = iniFile_getInteger(ini, "ro.build.version.sdk", -1);
+ iniFile_free(ini);
+
+ DD("! found %s (version %d)", temp, apiVersion);
+
+ if (apiVersion == version) {
+ /* Bingo */
+ subdir = qemu_strdup(subdir);
+ break;
+ }
+ }
+
+ if (!subdir) {
+ DD("< didn't found anything");
+ }
+
+ dirScanner_free(scanner);
+ return subdir;
+}
+
+/* returns the full path of the addon corresponding to a given target,
+ * or NULL if not found. on success, *pversion will contain the SDK
+ * version number
+ */
+static char*
+_findAddonByTarget( const char* sdkRoot, const char* target, int *pversion )
+{
+ char* targetCopy = qemu_strdup(target);
+ char* targetVendor = NULL;
+ char* targetName = NULL;
+ int targetVersion = -1;
+
+ char temp[PATH_MAX];
+ char* p;
+ char* end;
+ DirScanner* scanner;
+ char* subdir;
+
+ DD("> %s(%s,%s)", __FUNCTION__, sdkRoot, target);
+
+ /* extract triplet from target string */
+ targetVendor = targetCopy;
+
+ p = strchr(targetVendor, ':');
+ if (p == NULL) {
+ DD("< missing first column separator");
+ goto FAIL;
+ }
+ *p = 0;
+ targetName = p + 1;
+ p = strchr(targetName, ':');
+ if (p == NULL) {
+ DD("< missing second column separator");
+ goto FAIL;
+ }
+ *p++ = 0;
+
+ targetVersion = atoi(p);
+
+ if (targetVersion == 0) {
+ DD("< invalid version number");
+ goto FAIL;
+ }
+ /* now scan addons directory */
+ p = temp;
+ end = p + sizeof temp;
+
+ p = bufprint(p, end, "%s/%s", sdkRoot, ADDONS_SUBDIR);
+ if (p >= end) {
+ DD("< add-on path too long");
+ goto FAIL;
+ }
+ scanner = dirScanner_new(temp);
+ if (scanner == NULL) {
+ DD("< cannot scan add-on path %s: %s", temp, strerror(errno));
+ goto FAIL;
+ }
+ for (;;) {
+ IniFile* ini;
+ const char* vendor;
+ const char* name;
+ int version;
+ int matches;
+
+ subdir = (char*) dirScanner_nextFull(scanner);
+ if (subdir == NULL)
+ break;
+
+ /* try to open the manifest.ini file */
+ p = bufprint(temp, end, "%s/manifest.ini", subdir);
+ if (p >= end)
+ continue;
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL)
+ continue;
+
+ DD("! scanning manifest.ini in %s", temp);
+
+ /* find the vendor, name and version */
+ vendor = iniFile_getValue(ini, "vendor");
+ name = iniFile_getValue(ini, "name");
+ version = iniFile_getInteger(ini, "api", -1);
+
+ matches = 0;
+
+ matches += (version == targetVersion);
+ matches += (vendor && !strcmp(vendor, targetVendor));
+ matches += (name && !strcmp(name, targetName));
+
+ DD("! matches=%d vendor=[%s] name=[%s] version=%d",
+ matches,
+ vendor ? vendor : "<NULL>",
+ name ? name : "<NULL>",
+ version);
+
+ iniFile_free(ini);
+
+ if (matches == 3) {
+ /* bingo */
+ *pversion = version;
+ subdir = qemu_strdup(subdir);
+ break;
+ }
+ }
+
+ dirScanner_free(scanner);
+
+ DD("< returning %s", subdir ? subdir : "<NULL>");
+ return subdir;
+
+FAIL:
+ qemu_free(targetCopy);
+ return NULL;
+}
+
+static int
+_checkAvmName( const char* name )
+{
+ int len = strlen(name);
+ int len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789_.-");
+ return (len == len2);
+}
+
+/* parse the root config .ini file. it is located in
+ * ~/.android/vm/<name>.ini or Windows equivalent
+ */
+static int
+_getRootIni( AvmInfo* i )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint_config_path(temp, end);
+ p = bufprint(p, end, "/" ANDROID_VM_DIR "/%s.ini", i->machineName);
+ if (p >= end) {
+ derror("machine name too long");
+ return -1;
+ }
+
+ i->rootIni = iniFile_newFromFile(temp);
+ if (i->rootIni == NULL) {
+ derror("unknown virtual machine name: '%s'", i->machineName);
+ return -1;
+ }
+ D("root virtual machine file at %s", temp);
+ return 0;
+}
+
+/* the .ini variable name that points to the content directory
+ * in a root AVM ini file. This is required */
+# define ROOT_PATH_KEY "path"
+# define ROOT_TARGET_KEY "target"
+
+/* retrieve the content path and target from the root .ini file */
+static int
+_getTarget( AvmInfo* i )
+{
+ i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY);
+ i->addonTarget = iniFile_getString(i->rootIni, ROOT_TARGET_KEY);
+
+ iniFile_free(i->rootIni);
+ i->rootIni = NULL;
+
+ if (i->contentPath == NULL) {
+ derror("bad config: %s",
+ "virtual machine file lacks a "ROOT_PATH_KEY" entry");
+ return -1;
+ }
+
+ if (i->addonTarget == NULL) {
+ derror("bad config: %s",
+ "virtual machine file lacks a "ROOT_TARGET_KEY" entry");
+ return -1;
+ }
+
+ D("virtual machine content at %s", i->contentPath);
+ D("virtual machine target is %s", i->addonTarget);
+
+ if (!strncmp(i->addonTarget, "android-", 8)) { /* target is platform */
+ char* end;
+ const char* versionString = i->addonTarget+8;
+ int version = (int) strtol(versionString, &end, 10);
+ if (*end != 0 || version <= 0) {
+ derror("bad config: invalid platform version: '%s'", versionString);
+ return -1;
+ }
+ i->platformVersion = version;
+ i->platformPath = _findPlatformByVersion(i->sdkRootPath,
+ version);
+ if (i->platformPath == NULL) {
+ derror("bad config: unknown platform version: '%d'", version);
+ return -1;
+ }
+ }
+ else /* target is add-on */
+ {
+ i->addonPath = _findAddonByTarget(i->sdkRootPath, i->addonTarget,
+ &i->platformVersion);
+ if (i->addonPath == NULL) {
+ derror("bad config: %s",
+ "unknown add-on target: '%s'", i->addonTarget);
+ return -1;
+ }
+
+ i->platformPath = _findPlatformByVersion(i->sdkRootPath,
+ i->platformVersion);
+ if (i->platformPath == NULL) {
+ derror("bad config: %s",
+ "unknown add-on platform version: '%d'", i->platformVersion);
+ return -1;
+ }
+ D("virtual machine add-on path: %s", i->addonPath);
+ }
+ D("virtual machine platform path: %s", i->platformPath);
+ D("virtual machine platform version %d", i->platformVersion);
+ return 0;
+}
+
+
+/* find and parse the config.ini file from the content directory */
+static int
+_getConfigIni(AvmInfo* i)
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint(p, end, "%s/config.ini", i->contentPath);
+ if (p >= end) {
+ derror("can't access virtual machine content directory");
+ return -1;
+ }
+
+#if 1 /* XXX: TODO: remove this in the future */
+ /* for now, allow a non-existing config.ini */
+ if (!path_exists(temp)) {
+ D("virtual machine has no config file - no problem");
+ return 0;
+ }
+#endif
+
+ i->configIni = iniFile_newFromFile(temp);
+ if (i->configIni == NULL) {
+ derror("bad config: %s",
+ "virtual machine directory lacks config.ini");
+ return -1;
+ }
+ D("virtual machine config file: %s", temp);
+ return 0;
+}
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** KERNEL/DISK IMAGE LOADER
+ *****
+ *****/
+
+/* a structure used to handle the loading of
+ * kernel/disk images.
+ */
+typedef struct {
+ AvmInfo* info;
+ AvmInfoParams* params;
+ AvmImageType id;
+ const char* imageFile;
+ const char* imageText;
+ char** pPath;
+ char* pState;
+ char temp[PATH_MAX];
+} ImageLoader;
+
+static void
+imageLoader_init( ImageLoader* l, AvmInfo* info, AvmInfoParams* params )
+{
+ memset(l, 0, sizeof(*l));
+ l->info = info;
+ l->params = params;
+}
+
+/* set the type of the image to load */
+static void
+imageLoader_set( ImageLoader* l, AvmImageType id )
+{
+ l->id = id;
+ l->imageFile = _imageFileNames[id];
+ l->imageText = _imageFileText[id];
+ l->pPath = &l->info->imagePath[id];
+ l->pState = &l->info->imageState[id];
+
+ l->pState[0] = IMAGE_STATE_READONLY;
+}
+
+/* change the image path */
+static char*
+imageLoader_setPath( ImageLoader* l, const char* path )
+{
+ path = path ? qemu_strdup(path) : NULL;
+
+ qemu_free(l->pPath[0]);
+ l->pPath[0] = (char*) path;
+
+ return (char*) path;
+}
+
+static char*
+imageLoader_extractPath( ImageLoader* l )
+{
+ char* result = l->pPath[0];
+ l->pPath[0] = NULL;
+ return result;
+}
+
+/* flags used when loading images */
+enum {
+ IMAGE_REQUIRED = (1<<0), /* image is required */
+ IMAGE_SEARCH_SDK = (1<<1), /* search image in SDK */
+ IMAGE_EMPTY_IF_MISSING = (1<<2), /* create empty file if missing */
+ IMAGE_DONT_LOCK = (1<<4), /* don't try to lock image */
+ IMAGE_IGNORE_IF_LOCKED = (1<<5), /* ignore file if it's locked */
+};
+
+#define IMAGE_OPTIONAL 0
+
+/* find an image from the SDK add-on and/or platform
+ * directories. returns the full path or NULL if
+ * the file could not be found.
+ *
+ * note: this stores the result in the image's path as well
+ */
+static char*
+imageLoader_lookupSdk( ImageLoader* l )
+{
+ AvmInfo* i = l->info;
+ char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
+
+ do {
+ /* try the add-on directory, if any */
+ if (i->addonPath != NULL) {
+ DD("searching %s in add-on directory: %s",
+ l->imageFile, i->addonPath);
+
+ p = bufprint(temp, end, "%s/images/%s",
+ i->addonPath, l->imageFile);
+
+ if (p < end && path_exists(temp))
+ break;
+ }
+
+ /* or try the platform directory */
+ DD("searching %s in platform directory: %s",
+ l->imageFile, i->platformPath);
+
+ p = bufprint(temp, end, "%s/images/%s",
+ i->platformPath, l->imageFile);
+ if (p < end && path_exists(temp))
+ break;
+
+ DD("could not find %s in SDK", l->imageFile);
+ return NULL;
+
+ } while (0);
+
+ l->pState[0] = IMAGE_STATE_READONLY;
+
+ return imageLoader_setPath(l, temp);
+}
+
+/* search for a file in the content directory.
+ * returns NULL if the file cannot be found.
+ *
+ * note that this formats l->temp with the file's path
+ * allowing you to retrieve it if the function returns NULL
+ */
+static char*
+imageLoader_lookupContent( ImageLoader* l )
+{
+ AvmInfo* i = l->info;
+ char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
+
+ DD("searching %s in content directory", l->imageFile);
+ p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile);
+ if (p >= end) {
+ derror("content directory path too long");
+ exit(2);
+ }
+ if (!path_exists(temp)) {
+ DD("not found %s in content directory", l->imageFile);
+ return NULL;
+ }
+
+ /* assume content image files must be locked */
+ l->pState[0] = IMAGE_STATE_MUSTLOCK;
+
+ return imageLoader_setPath(l, temp);
+}
+
+/* lock a file image depending on its state and user flags
+ * note that this clears l->pPath[0] if the lock could not
+ * be acquired and that IMAGE_IGNORE_IF_LOCKED is used.
+ */
+static void
+imageLoader_lock( ImageLoader* l, unsigned flags )
+{
+ const char* path = l->pPath[0];
+
+ if (flags & IMAGE_DONT_LOCK)
+ return;
+
+ if (l->pState[0] != IMAGE_STATE_MUSTLOCK)
+ return;
+
+ D("locking %s image at %s", l->imageText, path);
+
+ if (filelock_create(path) != NULL) {
+ /* succesful lock */
+ l->pState[0] = IMAGE_STATE_LOCKED;
+ return;
+ }
+
+ if (flags & IMAGE_IGNORE_IF_LOCKED) {
+ dwarning("ignoring locked %s image at %s", l->imageText, path);
+ imageLoader_setPath(l, NULL);
+ return;
+ }
+
+ derror("the %s image is used by another emulator. aborting",
+ l->imageText);
+ exit(2);
+}
+
+/* make a file image empty, this may require locking */
+static void
+imageLoader_empty( ImageLoader* l, unsigned flags )
+{
+ const char* path;
+
+ imageLoader_lock(l, flags);
+
+ path = l->pPath[0];
+ if (path == NULL) /* failed to lock, caller will handle it */
+ return;
+
+ if (make_empty_file(path) < 0) {
+ derror("could not create %s image at %s: %s",
+ l->imageText, path, strerror(errno));
+ exit(2);
+ }
+ l->pState[0] = IMAGE_STATE_LOCKED_EMPTY;
+}
+
+
+/* copy image file from a given source
+ * assumes locking is needed.
+ */
+static void
+imageLoader_copyFrom( ImageLoader* l, const char* srcPath )
+{
+ const char* dstPath = NULL;
+
+ /* find destination file */
+ if (l->params) {
+ dstPath = l->params->forcePaths[l->id];
+ }
+ if (!dstPath) {
+ imageLoader_lookupContent(l);
+ dstPath = l->temp;
+ }
+
+ /* lock destination */
+ imageLoader_setPath(l, dstPath);
+ l->pState[0] = IMAGE_STATE_MUSTLOCK;
+ imageLoader_lock(l, 0);
+
+ /* make the copy */
+ if (copy_file(dstPath, srcPath) < 0) {
+ derror("can't initialize %s image from SDK: %s: %s",
+ l->imageText, dstPath, strerror(errno));
+ exit(2);
+ }
+}
+
+/* this will load and eventually lock and image file, depending
+ * on the flags being used. on exit, this function udpates
+ * l->pState[0] and l->pPath[0]
+ *
+ * returns the path to the file. Note that it returns NULL
+ * only if the file was optional and could not be found.
+ *
+ * if the file is required and missing, the function aborts
+ * the program.
+ */
+static char*
+imageLoader_load( ImageLoader* l,
+ unsigned flags )
+{
+ const char* path = NULL;
+
+ DD("looking for %s image (%s)", l->imageText, l->imageFile);
+
+ /* first, check user-provided path */
+ path = l->params->forcePaths[l->id];
+ if (path != NULL) {
+ imageLoader_setPath(l, path);
+ if (path_exists(path))
+ goto EXIT;
+
+ D("user-provided %s image does not exist: %s",
+ l->imageText, path);
+
+ /* if the file is required, abort */
+ if (flags & IMAGE_REQUIRED) {
+ derror("user-provided %s image at %s doesn't exist",
+ l->imageText, path);
+ exit(2);
+ }
+ }
+ else {
+ const char* contentFile;
+
+ /* second, look in the content directory */
+ path = imageLoader_lookupContent(l);
+ if (path) goto EXIT;
+
+ contentFile = qemu_strdup(l->temp);
+
+ /* it's not there */
+ if (flags & IMAGE_SEARCH_SDK) {
+ /* third, look in the SDK directory */
+ path = imageLoader_lookupSdk(l);
+ if (path) {
+ qemu_free((char*)contentFile);
+ goto EXIT;
+ }
+ }
+ DD("found no %s image (%s)", l->imageText, l->imageFile);
+
+ /* if the file is required, abort */
+ if (flags & IMAGE_REQUIRED) {
+ derror("could not find required %s image (%s)",
+ l->imageText, l->imageFile);
+ exit(2);
+ }
+
+ path = imageLoader_setPath(l, contentFile);
+ qemu_free((char*)contentFile);
+ }
+
+ /* otherwise, do we need to create it ? */
+ if (flags & IMAGE_EMPTY_IF_MISSING) {
+ imageLoader_empty(l, flags);
+ return l->pPath[0];
+ }
+ return NULL;
+
+EXIT:
+ imageLoader_lock(l, flags);
+ return l->pPath[0];
+}
+
+
+
+/* find the correct path of all image files we're going to need
+ * and lock the files that need it.
+ */
+static int
+_getImagePaths(AvmInfo* i, AvmInfoParams* params )
+{
+ int wipeData = (params->flags & AVMINFO_WIPE_DATA) != 0;
+ int wipeCache = (params->flags & AVMINFO_WIPE_CACHE) != 0;
+ int noCache = (params->flags & AVMINFO_NO_CACHE) != 0;
+ int noSdCard = (params->flags & AVMINFO_NO_SDCARD) != 0;
+
+ ImageLoader l[1];
+
+ imageLoader_init(l, i, params);
+
+ /* pick up the kernel and ramdisk image files - these don't
+ * need a specific handling.
+ */
+ imageLoader_set ( l, AVM_IMAGE_KERNEL );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
+
+ imageLoader_set ( l, AVM_IMAGE_RAMDISK );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
+
+ /* the system image
+ *
+ * if there is one in the content directory just lock
+ * and use it.
+ */
+ imageLoader_set ( l, AVM_IMAGE_SYSTEM );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK );
+
+ /* the data partition - this one is special because if it
+ * is missing, we need to copy the initial image file into it.
+ *
+ * first, try to see if it is in the content directory
+ * (or the user-provided path)
+ */
+ imageLoader_set( l, AVM_IMAGE_USERDATA );
+ if ( !imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING |
+ IMAGE_DONT_LOCK ) )
+ {
+ /* it's not, we're going to initialize it. simply
+ * forcing a data wipe should be enough */
+ D("initializing new data partition image: %s", l->pPath[0]);
+ wipeData = 1;
+ }
+
+ if (wipeData) {
+ /* find SDK source file */
+ const char* srcPath;
+
+ if (imageLoader_lookupSdk(l)) {
+ derror("can't locate initial %s image in SDK",
+ l->imageText);
+ exit(2);
+ }
+ srcPath = imageLoader_extractPath(l);
+
+ imageLoader_copyFrom( l, srcPath );
+ qemu_free((char*) srcPath);
+ }
+ else
+ {
+ /* lock the data partition image */
+ l->pState[0] = IMAGE_STATE_MUSTLOCK;
+ imageLoader_lock( l, 0 );
+ }
+
+ /* the cache partition: unless the user doesn't want one,
+ * we're going to create it in the content directory
+ */
+ if (!noCache) {
+ imageLoader_set (l, AVM_IMAGE_CACHE);
+ imageLoader_load(l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING );
+
+ if (wipeCache) {
+ if (make_empty_file(l->pPath[0]) < 0) {
+ derror("cannot wipe %s image at %s: %s",
+ l->imageText, l->pPath[0],
+ strerror(errno));
+ exit(2);
+ }
+ }
+ }
+
+ /* the SD Card image. unless the user doesn't want to, we're
+ * going to mount it if available. Note that if the image is
+ * already used, we must ignore it.
+ */
+ if (!noSdCard) {
+ imageLoader_set (l, AVM_IMAGE_SDCARD);
+ imageLoader_load(l, IMAGE_OPTIONAL |
+ IMAGE_IGNORE_IF_LOCKED);
+
+ /* if the file was not found, ignore it */
+ if (l->pPath[0] && !path_exists(l->pPath[0]))
+ {
+ D("ignoring non-existing %s at %s: %s",
+ l->imageText, l->pPath[0], strerror(errno));
+
+ /* if the user provided the SD Card path by hand,
+ * warn him. */
+ if (params->forcePaths[AVM_IMAGE_SDCARD] != NULL)
+ dwarning("ignoring non-existing SD Card image");
+
+ imageLoader_setPath(l, NULL);
+ }
+ }
+
+ return 0;
+}
+
+/* check that there is a skin named 'skinName' listed from 'skinDirRoot'
+ * this returns 1 on success, 0 on failure
+ * on success, the 'temp' buffer will get the path of the real skin
+ * directory (after alias expansion, if needed)
+ */
+static int
+_checkSkinDir( char* temp, char* end, const char* skinDirRoot, const char* skinName )
+{
+ DirScanner* scanner;
+ char *p, *q;
+
+ p = bufprint(temp, end, "%s/skins/%s",
+ skinDirRoot, skinName);
+
+ if (p >= end || !path_exists(temp))
+ return -1;
+
+ /* first, is this a normal skin directory ? */
+ q = bufprint(q, end, "/layout");
+ if (q < end && path_exists(temp)) {
+ /* yes */
+ *p = 0;
+ return 1;
+ }
+
+ /* second, is it an alias to another skin ? */
+ *p = 0;
+ scanner = dirScanner_new(temp);
+ if (scanner != NULL) {
+ for (;;) {
+ const char* file = dirScanner_next(scanner);
+
+ if (file == NULL)
+ break;
+
+ if (strncmp(file, "alias-", 6) || file[6] == 0)
+ continue;
+
+ p = bufprint(temp, end, "%s/skins/%s",
+ skinDirRoot, file+6);
+
+ q = bufprint(p, end, "/layout");
+ if (q < end && path_exists(temp)) {
+ /* yes, it's an alias */
+ *p = 0;
+ return 1;
+ }
+ }
+ dirScanner_free(scanner);
+ }
+ return 0;
+}
+
+static int
+_getSkin( AvmInfo* i, AvmInfoParams* params )
+{
+ char* skinName;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ char explicitSkin = 1;
+
+ /* determine the skin name, the default is "default"
+ * unless specified by the caller or in config.ini
+ */
+ if (params->skinName) {
+ skinName = qemu_strdup(params->skinName);
+ } else {
+ skinName = iniFile_getString( i->configIni, "skin" );
+ if (skinName == NULL) {
+ skinName = qemu_strdup("default");
+ explicitSkin = 0;
+ }
+ }
+
+ i->skinName = skinName;
+
+ /* now try to find the skin directory for that name -
+ * first try the content directory */
+ do {
+ /* if there is a single 'skin' directory in
+ * the content directory, assume that's what the
+ * user wants, unless an explicit name was given
+ */
+ if (!explicitSkin) {
+ p = bufprint(temp, end, "%s/skin/layout", i->contentPath);
+ if (p < end && path_exists(temp)) {
+ /* use this one - cheat a little */
+ qemu_free(i->skinName);
+ i->skinName = qemu_strdup("skin");
+ i->skinDirPath = qemu_strdup(i->contentPath);
+ return 0;
+ }
+ }
+
+ /* look in content directory */
+ if (_checkSkinDir(temp, end, i->contentPath, skinName))
+ break;
+
+ /* look in the add-on directory, if any */
+ if (i->addonPath &&
+ _checkSkinDir(temp, end, i->addonPath, skinName))
+ break;
+
+ /* look in the platforms directory */
+ if (_checkSkinDir(temp, end, i->platformPath, skinName))
+ break;
+
+ /* didn't find it */
+ if (explicitSkin)
+ dwarning("could not find directory for skin '%s'", skinName);
+
+ return -1;
+
+ } while (0);
+
+ i->skinDirPath = qemu_strdup(temp);
+ return 0;
+}
+
+
+AvmInfo*
+avmInfo_new( const char* name, AvmInfoParams* params )
+{
+ AvmInfo* i;
+
+ if (name == NULL)
+ return NULL;
+
+ if (!_checkAvmName(name)) {
+ derror("virtual machine name contains invalid characters");
+ exit(1);
+ }
+
+ i = qemu_mallocz(sizeof *i);
+ i->machineName = qemu_strdup(name);
+
+ if ( _getSdkRoot(i) < 0 ||
+ _getRootIni(i) < 0 ||
+ _getTarget(i) < 0 ||
+ _getConfigIni(i) < 0 )
+ goto FAIL;
+
+ if ( _getImagePaths(i, params) < 0 ||
+ _getSkin (i, params) < 0 )
+ goto FAIL;
+
+ return i;
+
+FAIL:
+ avmInfo_free(i);
+ return NULL;
+}
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** ANDROID BUILD SUPPORT
+ *****
+ ***** The code below corresponds to the case where we're
+ ***** starting the emulator inside the Android build
+ ***** system. The main differences are that:
+ *****
+ ***** - the $ANDROID_PRODUCT_OUT directory is used as the
+ ***** content file.
+ *****
+ ***** - built images must not be modified by the emulator,
+ ***** so system.img must be copied to a temporary file
+ ***** and userdata.img must be copied to userdata-qemu.img
+ ***** if the latter doesn't exist.
+ *****
+ ***** - the kernel and default skin directory are taken from
+ ***** prebuilt
+ *****
+ ***** - there is no root .ini file, or any config.ini in
+ ***** the content directory, no SDK platform version
+ ***** and no add-on to consider.
+ *****/
+
+/* used to fake a config.ini located in the content directory */
+static int
+_getBuildConfigIni( AvmInfo* i )
+{
+ /* a blank file is ok at the moment */
+ i->configIni = iniFile_newFromMemory( "", 0 );
+ return 0;
+}
+
+static int
+_getBuildImagePaths( AvmInfo* i, AvmInfoParams* params )
+{
+ int wipeData = (params->flags & AVMINFO_WIPE_DATA) != 0;
+ int noCache = (params->flags & AVMINFO_NO_CACHE) != 0;
+ int noSdCard = (params->flags & AVMINFO_NO_SDCARD) != 0;
+
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
+ char* srcData;
+ ImageLoader l[1];
+
+ imageLoader_init(l, i, params);
+
+ /** load the kernel image
+ **/
+
+ /* if it is not in the out directory, get it from prebuilt
+ */
+ imageLoader_set ( l, AVM_IMAGE_KERNEL );
+
+ if ( !imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_DONT_LOCK ) )
+ {
+#define PREBUILT_KERNEL_PATH "prebuilt/android-arm/kernel/kernel-qemu"
+ p = bufprint(temp, end, "%s/%s", i->androidBuildRoot,
+ PREBUILT_KERNEL_PATH);
+ if (p >= end || !path_exists(temp)) {
+ derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
+ exit(1);
+ }
+ imageLoader_setPath(l, temp);
+ }
+
+ /** load the data partition. note that we use userdata-qemu.img
+ ** since we don't want to modify userdata.img at all
+ **/
+ imageLoader_set ( l, AVM_IMAGE_USERDATA );
+ imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK );
+
+ /* get the path of the source file, and check that it actually exists
+ * if the user didn't provide an explicit data file
+ */
+ srcData = imageLoader_extractPath(l);
+ if (srcData == NULL && params->forcePaths[AVM_IMAGE_USERDATA] == NULL) {
+ derror("There is no %s image in your build directory. Please make a full build",
+ l->imageText, l->imageFile);
+ exit(2);
+ }
+
+ /* get the path of the target file */
+ l->imageFile = "userdata-qemu.img";
+ imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING |
+ IMAGE_IGNORE_IF_LOCKED );
+
+ /* force a data wipe if we just created the image */
+ if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY)
+ wipeData = 1;
+
+ /* if the image was already locked, create a temp file
+ * then force a data wipe.
+ */
+ if (l->pPath[0] == NULL) {
+ TempFile* temp = tempfile_create();
+ imageLoader_setPath(l, tempfile_path(temp));
+ dwarning( "Another emulator is running. user data changes will *NOT* be saved");
+ wipeData = 1;
+ }
+
+ /* in the case of a data wipe, copy userdata.img into
+ * the destination */
+ if (wipeData) {
+ if (srcData == NULL || !path_exists(srcData)) {
+ derror("There is no %s image in your build directory. Please make a full build",
+ l->imageText, _imageFileNames[l->id]);
+ exit(2);
+ }
+ if (copy_file( l->pPath[0], srcData ) < 0) {
+ derror("could not initialize %s image from %s: %s",
+ l->imageText, temp, strerror(errno));
+ exit(2);
+ }
+ }
+
+ qemu_free(srcData);
+
+ /** load the ramdisk image
+ **/
+ imageLoader_set ( l, AVM_IMAGE_RAMDISK );
+ imageLoader_load( l, IMAGE_REQUIRED |
+ IMAGE_DONT_LOCK );
+
+ /** load the system image. read-only. the caller must
+ ** take care of checking the state
+ **/
+ imageLoader_set ( l, AVM_IMAGE_SYSTEM );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
+
+ /* force the system image to read-only status */
+ l->pState[0] = IMAGE_STATE_READONLY;
+
+ /** cache partition handling
+ **/
+ if (!noCache) {
+ imageLoader_set (l, AVM_IMAGE_CACHE);
+
+ /* if the user provided one cache image, lock & use it */
+ if ( params->forcePaths[l->id] != NULL ) {
+ imageLoader_load(l, IMAGE_REQUIRED |
+ IMAGE_IGNORE_IF_LOCKED);
+ }
+ }
+
+ /** SD Card image
+ **/
+ if (!noSdCard) {
+ imageLoader_set (l, AVM_IMAGE_SDCARD);
+ imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
+ }
+
+ return 0;
+}
+
+static int
+_getBuildSkin( AvmInfo* i, AvmInfoParams* params )
+{
+ /* the (current) default skin name for our build system */
+ const char* skinName = params->skinName;
+ const char* skinDir = params->skinRootPath;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ char* q;
+
+ if (!skinName) {
+ /* the (current) default skin name for the build system */
+ skinName = "HVGA";
+ DD("selecting default skin name '%s'", skinName);
+ }
+
+ i->skinName = qemu_strdup(skinName);
+
+ if (!skinDir) {
+
+#define PREBUILT_SKINS_DIR "development/emulator/skins"
+
+ /* the (current) default skin directory */
+ p = bufprint( temp, end, "%s/%s",
+ i->androidBuildRoot, PREBUILT_SKINS_DIR );
+ } else {
+ p = bufprint( temp, end, "%s", skinDir );
+ }
+
+ q = bufprint(p, end, "/%s/layout", skinName);
+ if (q >= end || !path_exists(temp)) {
+ if (skinDir)
+ dwarning("could not find valid skin '%s' in %s:\n",
+ skinName, skinDir);
+ else
+ DD("could not find directory for skin '%s'",
+ skinName);
+ return -1;
+ }
+ *p = 0;
+ DD("found skin path: %s", temp);
+ i->skinDirPath = qemu_strdup(temp);
+
+ return 0;
+}
+
+AvmInfo*
+avmInfo_newForAndroidBuild( const char* androidBuildRoot,
+ const char* androidOut,
+ AvmInfoParams* params )
+{
+ AvmInfo* i;
+
+ i = qemu_mallocz(sizeof *i);
+
+ i->inAndroidBuild = 1;
+ i->androidBuildRoot = qemu_strdup(androidBuildRoot);
+ i->androidOut = qemu_strdup(androidOut);
+ i->contentPath = qemu_strdup(androidOut);
+
+ /* TODO: find a way to provide better information from the build files */
+ i->machineName = qemu_strdup("<build>");
+
+ if (_getBuildConfigIni(i) < 0 ||
+ _getBuildImagePaths(i, params) < 0 )
+ goto FAIL;
+
+ /* we don't need to fail if there is no valid skin */
+ _getBuildSkin(i, params);
+
+ return i;
+
+FAIL:
+ avmInfo_free(i);
+ return NULL;
+}
+
+const char*
+avmInfo_getName( AvmInfo* i )
+{
+ return i ? i->machineName : NULL;
+}
+
+const char*
+avmInfo_getImageFile( AvmInfo* i, AvmImageType imageType )
+{
+ if (i == NULL || (unsigned)imageType >= AVM_IMAGE_MAX)
+ return NULL;
+
+ return i->imagePath[imageType];
+}
+
+int
+avmInfo_isImageReadOnly( AvmInfo* i, AvmImageType imageType )
+{
+ if (i == NULL || (unsigned)imageType >= AVM_IMAGE_MAX)
+ return 1;
+
+ return (i->imageState[imageType] == IMAGE_STATE_READONLY);
+}
+
+const char*
+avmInfo_getSkinName( AvmInfo* i )
+{
+ return i->skinName;
+}
+
+const char*
+avmInfo_getSkinDir ( AvmInfo* i )
+{
+ return i->skinDirPath;
+}
+
+int
+avmInfo_getHwConfig( AvmInfo* i, AndroidHwConfig* hw )
+{
+ IniFile* ini = i->configIni;
+ int ret;
+
+ if (ini == NULL)
+ ini = iniFile_newFromMemory("", 0);
+
+ ret = androidHwConfig_read(hw, ini);
+
+ if (ini != i->configIni)
+ iniFile_free(ini);
+
+ return ret;
+}
+
+
+char*
+avmInfo_getTracePath( AvmInfo* i, const char* traceName )
+{
+ char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
+
+ if (i == NULL || traceName == NULL || traceName[0] == 0)
+ return NULL;
+
+ if (i->inAndroidBuild) {
+ p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
+ i->androidOut, traceName );
+ } else {
+ p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
+ i->contentPath, traceName );
+ }
+ return qemu_strdup(tmp);
+}
diff --git a/android/vm/info.h b/android/vm/info.h
new file mode 100644
index 0000000..cdad34f
--- /dev/null
+++ b/android/vm/info.h
@@ -0,0 +1,161 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef ANDROID_VM_INFO_H
+#define ANDROID_VM_INFO_H
+
+#include "android/utils/ini.h"
+#include "android/vm/hw-config.h"
+
+/* An Android Virtual Machine (AVM for short) corresponds to a
+ * directory containing all kernel/disk images for a given virtual
+ * device, as well as information about its hardware capabilities,
+ * SDK version number, skin, etc...
+ *
+ * Each AVM has a human-readable name and is backed by a root
+ * configuration file and a content directory. For example, an
+ * AVM named 'foo' will correspond to the following:
+ *
+ * - a root configuration file named ~/.android/vm/foo.ini
+ * describing where the AVM's content can be found
+ *
+ * - a content directory like ~/.android/vm/foo/ containing all
+ * disk image and configuration files for the virtual device.
+ *
+ * the 'foo.ini' file should contain at least one line of the form:
+ *
+ * rootPath=<content-path>
+ *
+ * it may also contain other lines that cache stuff found in the
+ * content directory, like hardware properties or SDK version number.
+ *
+ * it is possible to move the content directory by updating the foo.ini
+ * file to point to the new location. This can be interesting when your
+ * $HOME directory is located on a network share or in a roaming profile
+ * (Windows), given that the content directory of a single virtual device
+ * can easily use more than 100MB of data.
+ *
+ */
+
+/* a macro used to define the list of disk images managed by the
+ * implementation. This macro will be expanded several times with
+ * varying definitions of _AVM_IMG
+ */
+#define AVM_IMAGE_LIST \
+ _AVM_IMG(KERNEL,"kernel-qemu","kernel") \
+ _AVM_IMG(RAMDISK,"ramdisk.img","ramdisk") \
+ _AVM_IMG(SYSTEM,"system.img","system") \
+ _AVM_IMG(USERDATA,"userdata.img","user data") \
+ _AVM_IMG(CACHE,"cache.img","cache") \
+ _AVM_IMG(SDCARD,"sdcard.img","SD Card") \
+
+/* define the enumared values corresponding to each AVM image type
+ * examples are: AVM_IMAGE_KERNEL, AVM_IMAGE_SYSTEM, etc..
+ */
+#define _AVM_IMG(x,y,z) AVM_IMAGE_##x ,
+typedef enum {
+ AVM_IMAGE_LIST
+ AVM_IMAGE_MAX /* do not remove */
+} AvmImageType;
+#undef _AVM_IMG
+
+/* AvmInfo is an opaque structure used to model the information
+ * corresponding to a given AVM instance
+ */
+typedef struct AvmInfo AvmInfo;
+
+/* various flags used when creating an AvmInfo object */
+typedef enum {
+ /* use to force a data wipe */
+ AVMINFO_WIPE_DATA = (1 << 0),
+ /* use to ignore the cache partition */
+ AVMINFO_NO_CACHE = (1 << 1),
+ /* use to wipe cache partition, ignored if NO_CACHE is set */
+ AVMINFO_WIPE_CACHE = (1 << 2),
+ /* use to ignore ignore SDCard image (default or provided) */
+ AVMINFO_NO_SDCARD = (1 << 3),
+} AvmFlags;
+
+typedef struct {
+ unsigned flags;
+ const char* skinName;
+ const char* skinRootPath;
+ const char* forcePaths[AVM_IMAGE_MAX];
+} AvmInfoParams;
+
+/* Creates a new AvmInfo object from a name. Returns NULL if name is NULL
+ * or contains characters that are not part of the following list:
+ * letters, digits, underscores, dashes and periods
+ */
+AvmInfo* avmInfo_new( const char* name, AvmInfoParams* params );
+
+/* A special function used to setup an AvmInfo for use when starting
+ * the emulator from the Android build system. In this specific instance
+ * we're going to create temporary files to hold all writable image
+ * files, and activate all hardware features by default
+ *
+ * 'androidBuildRoot' must be the absolute path to the root of the
+ * Android build system (i.e. the 'android' directory)
+ *
+ * 'androidOut' must be the target-specific out directory where
+ * disk images will be looked for.
+ */
+AvmInfo* avmInfo_newForAndroidBuild( const char* androidBuildRoot,
+ const char* androidOut,
+ AvmInfoParams* params );
+
+/* Frees an AvmInfo object and the corresponding strings that may be
+ * returned by its getXXX() methods
+ */
+void avmInfo_free( AvmInfo* i );
+
+/* Return the name of the Android Virtual Machine
+ */
+const char* avmInfo_getName( AvmInfo* i );
+
+/* Try to find the path of a given image file, returns NULL
+ * if the corresponding file could not be found. the string
+ * belongs to the AvmInfo object.
+ */
+const char* avmInfo_getImageFile( AvmInfo* i, AvmImageType imageType );
+
+/* Returns 1 if the corresponding image file is read-only
+ */
+int avmInfo_isImageReadOnly( AvmInfo* i, AvmImageType imageType );
+
+/* lock an image file if it is writable. returns 0 on success, or -1
+ * otherwise. note that if the file is read-only, it doesn't need to
+ * be locked and the function will return success.
+ */
+int avmInfo_lockImageFile( AvmInfo* i, AvmImageType imageType, int abortOnError);
+
+/* Manually set the path of a given image file. */
+void avmInfo_setImageFile( AvmInfo* i, AvmImageType imageType, const char* imagePath );
+
+/* Returns the path of the skin directory */
+/* the string belongs to the AvmInfo object */
+const char* avmInfo_getSkinPath( AvmInfo* i );
+
+/* Returns the name of the virtual machine's skin */
+const char* avmInfo_getSkinName( AvmInfo* i );
+
+/* Returns the root skin directory for this machine */
+const char* avmInfo_getSkinDir ( AvmInfo* i );
+
+/* Reads the AVM's hardware configuration into 'hw'. returns -1 on error, 0 otherwise */
+int avmInfo_getHwConfig( AvmInfo* i, AndroidHwConfig* hw );
+
+/* Returns a *copy* of the path used to store trace 'foo'. result must be freed by caller */
+char* avmInfo_getTracePath( AvmInfo* i, const char* traceName );
+
+/* */
+
+#endif /* ANDROID_VM_INFO_H */
diff --git a/android_console.c b/android_console.c
index 50af155..a83bb85 100644
--- a/android_console.c
+++ b/android_console.c
@@ -30,6 +30,7 @@
#include "shaper.h"
#include "modem_driver.h"
#include "android_gps.h"
+#include "android/globals.h"
#include <stdlib.h>
#include <stdio.h>
@@ -1853,6 +1854,13 @@ do_vm_status( ControlClient client, char* args )
return 0;
}
+static int
+do_vm_name( ControlClient client, char* args )
+{
+ control_write( client, "%s\r\n", avmInfo_getName(android_vmInfo) );
+ return 0;
+}
+
static const CommandDefRec vm_commands[] =
{
{ "stop", "stop the virtual machine",
@@ -1867,6 +1875,10 @@ static const CommandDefRec vm_commands[] =
"'vm status' will indicate wether the virtual machine is running or not\r\n",
NULL, do_vm_status, NULL },
+ { "name", "query virtual machine name",
+ "'vm name' will return the name of this virtual machine\r\n",
+ NULL, do_vm_name, NULL },
+
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
diff --git a/android_debug.h b/android_debug.h
index 14e962f..9dc4f40 100644
--- a/android_debug.h
+++ b/android_debug.h
@@ -31,6 +31,8 @@
_VERBOSE_TAG(qemud, "qemud multiplexer daemon") \
_VERBOSE_TAG(gps, "emulated GPS") \
_VERBOSE_TAG(nand_limits, "nand/flash read/write thresholding") \
+ _VERBOSE_TAG(hw_control, "emulated power/flashlight/led/vibrator") \
+ _VERBOSE_TAG(vm_config, "virtual device configuration") \
#define _VERBOSE_TAG(x,y) VERBOSE_##x,
typedef enum {
diff --git a/android_help.c b/android_help.c
index 25ff36a..b4c4f8e 100644
--- a/android_help.c
+++ b/android_help.c
@@ -13,6 +13,23 @@
#define PRINTF(...) stralloc_add_format(out,__VA_ARGS__)
static void
+help_virtual_machine( stralloc_t* out )
+{
+ PRINTF(
+ " An Android Virtual Machine (avm) models a single virtual\n"
+ " device running the Android platform that has its own kernel,\n"
+ " system image and data partition.\n\n"
+
+ " Only one emulator process can run a given AVM at a time, but\n"
+ " you can create several AVMs and run them concurrently.\n\n"
+
+ " TODO TODO TODO: ADD INFORMATION ABOUT AVM CONTENT DIRECTORIES,\n"
+ " AVM MANAGEMENT, ETC...\n"
+ );
+}
+
+
+static void
help_disk_images( stralloc_t* out )
{
char datadir[256];
@@ -313,17 +330,33 @@ help_char_devices(stralloc_t* out)
static const struct { const char* name; const char* descr; void (*help_func)(stralloc_t* out); } help_topics[] =
{
- { "disk-images", "about disk images", help_disk_images },
- { "keys", "supported key bindings", help_keys },
- { "debug-tags", "debug tags for -debug <tags>", help_debug_tags },
- { "char-devices", "character <device> specification", help_char_devices },
- { "environment", "environment variables", help_environment },
- { "keyset-file", "key bindings configuration file", help_keyset_file },
- { NULL, NULL }
+ { "disk-images", "about disk images", help_disk_images },
+ { "keys", "supported key bindings", help_keys },
+ { "debug-tags", "debug tags for -debug <tags>", help_debug_tags },
+ { "char-devices", "character <device> specification", help_char_devices },
+ { "environment", "environment variables", help_environment },
+ { "keyset-file", "key bindings configuration file", help_keyset_file },
+ { "virtual-machine", "virtual machine management", help_virtual_machine },
+ { NULL, NULL, NULL }
};
static void
+help_vm(stralloc_t* out)
+{
+ PRINTF(
+ " use '-vm <name>' to start the emulator program with a given vm,\n"
+ " where <name> must correspond to the name of one of the\n"
+ " Android virtual machines available on your host.\n\n"
+
+ " As a special convenience, using '@<name>' is equivalent to using\n"
+ " '-vm <name>'.\n\n"
+
+ " For more information about virtual machines, see -help-virtual-machine.\n"
+ );
+}
+
+static void
help_system(stralloc_t* out)
{
char systemdir[MAX_PATH];
@@ -480,7 +513,10 @@ help_skindir(stralloc_t* out)
PRINTF(
" use '-skindir <dir>' to specify a directory that will be used to search\n"
" for emulator skins. each skin must be a subdirectory of <dir>. by default\n"
- " the emulator will look in the 'skins' sub-directory of the system directory\n\n" );
+ " the emulator will look in the 'skins' sub-directory of the system directory\n\n"
+
+ " the '-skin <name>' option is required when -skindir is used.\n"
+ );
}
static void
@@ -880,6 +916,26 @@ help_port(stralloc_t* out)
}
static void
+help_ports(stralloc_t* out)
+{
+ PRINTF(
+ " the '-ports <consoleport>,<adbport>' option allows you to explicitely set\n"
+ " the TCP ports used by the emulator to implement its control console and\n"
+ " communicate with the ADB tool.\n\n"
+
+ " This is a very special option that should probably *not* be used by typical\n"
+ " developers using the Android SDK (use '-port <port>' instead), because the\n"
+ " corresponding instance is probably not going to be seen from adb/DDMS. Its\n"
+ " purpose is to use the emulator in very specific network configurations.\n\n"
+
+ " <consoleport> is the TCP port used to bind the control console\n"
+ " <adbport> is the TCP port used to bind the ADB local transport/tunnel.\n\n"
+
+ " If both ports aren't available on startup, the emulator will exit.\n\n");
+}
+
+
+static void
help_onion(stralloc_t* out)
{
PRINTF(
@@ -1079,15 +1135,30 @@ help_nand_limits(stralloc_t* out)
}
#endif /* CONFIG_NAND_LIMITS */
+static void
+help_bootchart(stralloc_t *out)
+{
+ PRINTF(
+ " some Android system images have a modified 'init' system that integrates\n"
+ " a bootcharting facility (see http://www.bootchart.org/). You can pass a\n"
+ " bootcharting period to the system with the following:\n\n"
+
+ " -bootchart <timeout>\n\n"
+
+ " where 'timeout' is a period expressed in seconds. Note that this won't do\n"
+ " anything if your init doesn't have bootcharting activated.\n\n"
+ );
+}
+
#define help_noskin NULL
#define help_netspeed help_shaper
#define help_netdelay help_shaper
#define help_netfast help_shaper
#define help_nojni NULL
-#define help_no_window NULL
-#define help_version NULL
-
+#define help_no_window NULL
+#define help_version NULL
+#define help_memory NULL
typedef struct {
const char* name;
@@ -1130,8 +1201,7 @@ android_help_for_option( const char* option, stralloc_t* out )
* of dashes, so create a tranlated copy of the option name
* before scanning the table for matches
*/
- pstrcpy(temp, sizeof temp, option);
- buffer_translate_char( temp, sizeof temp, '-', '_' );
+ buffer_translate_char( temp, sizeof temp, option, '-', '_' );
for ( oo = option_help; oo->name != NULL; oo++ ) {
if ( !strcmp(oo->name, temp) ) {
@@ -1181,8 +1251,7 @@ android_help_list_options( stralloc_t* out )
/* the names in the option_help table use underscores instead
* of dashes, so create a translated copy of the option's name
*/
- pstrcpy(temp, sizeof temp, oo->name);
- buffer_translate_char(temp, sizeof temp, '_', '-');
+ buffer_translate_char(temp, sizeof temp, oo->name, '_', '-');
stralloc_add_format( out, " -%s %-*s %s\n",
temp,
diff --git a/android_hw_control.c b/android_hw_control.c
new file mode 100644
index 0000000..ffd5509
--- /dev/null
+++ b/android_hw_control.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+/* this file implements the support of the new 'hardware control'
+ * qemud communication channel, which is used by libs/hardware on
+ * the system image to communicate with the emulator program for
+ * emulating the following:
+ *
+ * - power management
+ * - led(s) brightness
+ * - vibrator
+ * - flashlight
+ */
+#include "android_hw_control.h"
+#include "cbuffer.h"
+#include "android_qemud.h"
+#include "android_utils.h"
+#include <stdio.h>
+
+#define D(...) VERBOSE_PRINT(hw_control,__VA_ARGS__)
+
+/* define T_ACTIVE to 1 to debug transport communications */
+#define T_ACTIVE 0
+
+#if T_ACTIVE
+#define T(...) VERBOSE_PRINT(hw_control,__VA_ARGS__)
+#else
+#define T(...) ((void)0)
+#endif
+
+static void* hw_control_client;
+static AndroidHwControlFuncs hw_control_funcs;
+
+#define BUFFER_SIZE 512
+
+typedef struct {
+ CharDriverState* cs;
+ int overflow;
+ int wanted;
+ CBuffer input[1];
+ char input_0[ BUFFER_SIZE ];
+ /* note: 1 more byte to zero-terminate the query */
+ char query[ BUFFER_SIZE+1 ];
+} HwControl;
+
+/* forward */
+static void hw_control_do_query( HwControl* h,
+ uint8_t* query,
+ int querylen );
+
+static void
+hw_control_init( HwControl* h, CharDriverState* cs )
+{
+ h->cs = cs;
+ h->overflow = 0;
+ h->wanted = 0;
+ cbuffer_reset( h->input, h->input_0, sizeof h->input_0 );
+}
+
+static int
+hw_control_can_read( void* _hw )
+{
+ HwControl* h = _hw;
+ return cbuffer_write_avail( h->input );
+}
+
+static void
+hw_control_read( void* _hw, const uint8_t* data, int len )
+{
+ HwControl* h = _hw;
+ CBuffer* input = h->input;
+
+ T("%s: %4d '%.*s'", __FUNCTION__, len, len, data);
+
+ cbuffer_write( input, data, len );
+
+ while ( input->count > 0 )
+ {
+ /* skip over unwanted data, if any */
+ while (h->overflow > 0) {
+ uint8_t* dummy;
+ int avail = cbuffer_read_peek( input, &dummy );
+
+ if (avail == 0)
+ return;
+
+ if (avail > h->overflow)
+ avail = h->overflow;
+
+ cbuffer_read_step( input, avail );
+ h->overflow -= avail;
+ }
+
+ /* all incoming messages are made of a 4-byte hexchar sequence giving */
+ /* the length of the following payload */
+ if (h->wanted == 0)
+ {
+ char header[4];
+ int len;
+
+ if (input->count < 4)
+ return;
+
+ cbuffer_read( input, header, 4 );
+ len = hex2int( header, 4 );
+ if (len >= 0) {
+ /* if the message is too long, skip it */
+ if (len > input->size) {
+ T("%s: skipping oversized message (%d > %d)",
+ __FUNCTION__, len, input->size);
+ h->overflow = len;
+ } else {
+ T("%s: waiting for %d bytes", __FUNCTION__, len);
+ h->wanted = len;
+ }
+ }
+ }
+ else
+ {
+ if (input->count < h->wanted)
+ break;
+
+ cbuffer_read( input, h->query, h->wanted );
+ h->query[h->wanted] = 0;
+ hw_control_do_query( h, h->query, h->wanted );
+ h->wanted = 0;
+ }
+ }
+}
+
+
+static char*
+if_starts_with( uint8_t* buf, int buflen, const char* prefix )
+{
+ int prefixlen = strlen(prefix);
+
+ if (buflen < prefixlen || memcmp(buf, prefix, prefixlen))
+ return NULL;
+
+ return (char*)buf + prefixlen;
+}
+
+
+static void
+hw_control_do_query( HwControl* h,
+ uint8_t* query,
+ int querylen )
+{
+ uint8_t* q;
+
+ D("%s: query %4d '%.*s'", __FUNCTION__, querylen, querylen, query );
+
+ q = if_starts_with( query, querylen, "power:light:brightness:" );
+ if (q != NULL) {
+ if (hw_control_funcs.light_brightness) {
+ char* qq = strchr(q, ':');
+ int value;
+ if (qq == NULL) {
+ D("%s: badly formatted", __FUNCTION__ );
+ return;
+ }
+ *qq++ = 0;
+ value = atoi(qq);
+ hw_control_funcs.light_brightness( hw_control_client, q, value );
+ }
+ return;
+ }
+}
+
+
+void
+android_hw_control_init( void* opaque, const AndroidHwControlFuncs* funcs )
+{
+ static CharDriverState* hw_control_cs;
+ static HwControl hwstate[1];
+
+ if (hw_control_cs == NULL) {
+ CharDriverState* cs;
+ if ( android_qemud_get_channel( ANDROID_QEMUD_CONTROL, &cs ) < 0 ) {
+ derror( "could not create hardware control charpipe" );
+ exit(1);
+ }
+
+ hw_control_cs = cs;
+ hw_control_init( hwstate, cs );
+ qemu_chr_add_read_handler( cs, hw_control_can_read, hw_control_read, hwstate );
+
+ D("%s: hw-control char pipe initialized", __FUNCTION__);
+ }
+ hw_control_client = opaque;
+ hw_control_funcs = funcs[0];
+}
diff --git a/android_hw_control.h b/android_hw_control.h
new file mode 100644
index 0000000..9933819
--- /dev/null
+++ b/android_hw_control.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_hw_control_h
+#define _android_hw_control_h
+
+#include "vl.h"
+
+/* a callback function called when the system wants to change the brightness
+ * of a given light. 'light' is a string which can be one of:
+ * 'lcd_backlight', 'button_backlight' or 'Keyboard_backlight'
+ *
+ * brightness is an integer (acceptable range are 0..255), however the
+ * default is around 105, and we probably don't want to dim the emulator's
+ * output at that level.
+ */
+typedef void (*AndroidHwLightBrightnessFunc)( void* opaque,
+ const char* light,
+ int brightness );
+
+/* used to record a hw control 'client' */
+typedef struct {
+ AndroidHwLightBrightnessFunc light_brightness;
+} AndroidHwControlFuncs;
+
+/* used to initialize the hardware control support */
+extern void android_hw_control_init( void* opaque,
+ const AndroidHwControlFuncs* funcs );
+
+#endif /* _android_hw_control_h */
diff --git a/android_main.c b/android_main.c
index 72c9ef6..75d52c7 100644
--- a/android_main.c
+++ b/android_main.c
@@ -54,11 +54,15 @@
#include "android_gps.h"
#include "android_qemud.h"
#include "android_kmsg.h"
+#include "android_hw_control.h"
+#include "android/utils/dirscanner.h"
#include "android_option.h"
#include "android_help.h"
#include "hw/goldfish_nand.h"
+#include "android/globals.h"
+
#include "framebuffer.h"
AndroidRotation android_framebuffer_rotation;
@@ -351,6 +355,7 @@ typedef struct {
int win_y;
int show_trackball;
SkinTrackBall* trackball;
+ int lcd_brightness;
SkinImage* onion;
SkinRotation onion_rotation;
int onion_alpha;
@@ -576,7 +581,10 @@ qemulator_set_title( QEmulator* emulator )
if (emulator->window == NULL)
return;
- snprintf( temp, sizeof(temp), "Android Emulator (%d)", android_base_port );
+ snprintf( temp, sizeof(temp), "Android Emulator (%s:%d)",
+ avmInfo_getName( android_vmInfo ),
+ android_base_port );
+
skin_window_set_title( emulator->window, temp );
}
@@ -599,6 +607,21 @@ sdl_update(DisplayState *ds, int x, int y, int w, int h)
static void
+qemulator_light_brightness( void* opaque, const char* light, int value )
+{
+ QEmulator* emulator = opaque;
+
+ D("%s: light='%s' value=%d window=%p", __FUNCTION__, light, value, emulator->window);
+ if ( !strcmp(light, "lcd_backlight") ) {
+ emulator->lcd_brightness = value;
+ if (emulator->window)
+ skin_window_set_lcd_brightness( emulator->window, value );
+ return;
+ }
+}
+
+
+static void
qemulator_setup( QEmulator* emulator )
{
AndroidOptions* opts = emulator->opts;
@@ -624,6 +647,9 @@ qemulator_setup( QEmulator* emulator )
ball = skin_trackball_create( &params );
emulator->trackball = ball;
skin_window_set_trackball( emulator->window, ball );
+
+ emulator->lcd_brightness = 128; /* 50% */
+ skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
}
if ( emulator->onion != NULL )
@@ -633,6 +659,19 @@ qemulator_setup( QEmulator* emulator )
emulator->onion_alpha );
qemulator_set_title( emulator );
+
+ skin_window_enable_touch ( emulator->window, android_hw->hw_touchScreen != 0 );
+ skin_window_enable_dpad ( emulator->window, android_hw->hw_dPad != 0 );
+ skin_window_enable_qwerty( emulator->window, android_hw->hw_keyboard != 0 );
+ skin_window_enable_trackball( emulator->window, android_hw->hw_trackBall != 0 );
+ }
+
+ /* initialize hardware control support */
+ {
+ AndroidHwControlFuncs funcs;
+
+ funcs.light_brightness = qemulator_light_brightness;
+ android_hw_control_init( emulator, &funcs );
}
}
@@ -779,11 +818,11 @@ handle_key_command( void* opaque, SkinKeyCommand command, int down )
}
}
- // for the trackball command, handle down events to enable, and
+ // for the show-trackball command, handle down events to enable, and
// up events to disable
- if (command == SKIN_KEY_COMMAND_TOGGLE_TRACKBALL) {
- skin_window_toggle_trackball( emulator->window );
- emulator->show_trackball = !emulator->show_trackball;
+ if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
+ emulator->show_trackball = (down != 0);
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
//qemulator_set_title( emulator );
return;
}
@@ -825,6 +864,11 @@ handle_key_command( void* opaque, SkinKeyCommand command, int down )
}
break;
+ case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
+ emulator->show_trackball = !emulator->show_trackball;
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ break;
+
case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
if (emulator->onion)
@@ -864,14 +908,23 @@ handle_key_command( void* opaque, SkinKeyCommand command, int down )
layout = layout->next;
}
if (layout != NULL) {
+ SkinRotation rotation;
+
emulator->layout = layout;
skin_window_reset( emulator->window, layout );
+ rotation = skin_layout_get_dpad_rotation( layout );
+
if (emulator->keyboard)
- skin_keyboard_set_rotation( emulator->keyboard,
- skin_layout_get_dpad_rotation( layout ) );
- if (emulator->trackball)
+ skin_keyboard_set_rotation( emulator->keyboard, rotation );
+
+ if (emulator->trackball) {
+ skin_trackball_set_rotation( emulator->trackball, rotation );
skin_window_set_trackball( emulator->window, emulator->trackball );
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ }
+
+ skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
qframebuffer_invalidate_all();
qframebuffer_check_updates();
@@ -993,11 +1046,22 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts)
if(name) {
/* Support skin aliases like QVGA-H QVGA-P, etc...
- But first we check if it's a directory that exist before applyin the alias */
- sprintf(tmp, "%s/%s", path, name);
- if (!path_exists(tmp)) {
- /* directory is invalid, apply alias */
+ But first we check if it's a directory that exist before applying
+ the alias */
+ int checkAlias = 1;
+
+ if (path != NULL) {
+ bufprint(tmp, tmp+sizeof(tmp), "%s/%s", path, name);
+ if (path_exists(tmp)) {
+ checkAlias = 0;
+ } else {
+ D("there is no '%s' skin in '%s'", name, path);
+ }
+ }
+
+ if (checkAlias) {
int nn;
+
for (nn = 0; ; nn++ ) {
const char* skin_name = skin_aliases[nn].name;
const char* skin_alias = skin_aliases[nn].alias;
@@ -1006,6 +1070,7 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts)
break;
if ( !strcasecmp( skin_name, name ) ) {
+ D("skin name '%s' aliased to '%s'", name, skin_alias);
name = skin_alias;
break;
}
@@ -1018,13 +1083,19 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts)
if(x && isdigit(x[1])) {
int width = atoi(name);
int height = atoi(x + 1);
- sprintf(tmp,"display {\n width %d\n height %d\n}\n", width, height);
+ sprintf(tmp,"display {\n width %d\n height %d\n}\n",
+ width, height);
aconfig_load(root, strdup(tmp));
path = ":";
goto found_a_skin;
}
}
+ if (path == NULL) {
+ derror("unknown skin name '%s'", name);
+ exit(1);
+ }
+
sprintf(tmp, "%s/%s/layout", path, name);
D("trying to load skin file '%s'", tmp);
@@ -1033,7 +1104,8 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts)
path = tmp;
goto found_a_skin;
} else {
- fprintf(stderr, "### WARNING: could not load skin file '%s', using built-in one\n", tmp);
+ dwarning("could not load skin file '%s', using built-in one\n",
+ tmp);
}
}
@@ -1128,15 +1200,6 @@ found_a_skin:
}
}
-/* where to look relative to appdir for system.img and friends */
-const char *sysdir_paths[] = {
- "%s/lib/images/%s", /* emulator in <sdk>, images in <sdk>/lib/images */
- "%s/%s", /* emulator and images in the same directory */
- "%s/../%s",
- "%s/../../%s", /* emulator in <build>/host/bin, images in <build> */
- 0
-};
-
int qemu_main(int argc, char **argv);
/* this function dumps the QEMU help */
@@ -1418,41 +1481,6 @@ parse_nand_limits(char* limits)
}
#endif /* CONFIG_NAND_LIMITS */
-/* If *arg isn't already set, and <dir>/<file> exists, use it. */
-static void default_file(char **arg, const char* option, const char *dir, const char *file) {
- if (*arg == NULL || (*arg)[0] == '\0') {
- *arg = malloc(strlen(dir) + strlen(PATH_SEP) + strlen(file) + 1);
- sprintf(*arg, "%s%s%s", dir, PATH_SEP, file);
- if (option)
- D("autoconfig: -%s %s", option, *arg);
- }
-}
-
-
-/* Call default_file() and also exit if the file doesn't exist. */
-static void require_file(char **arg, const char* option, const char *dir, const char *file) {
- default_file(arg, option, dir, file);
- if (!path_exists(*arg)) {
- fprintf(stderr, "Cannot find file: %s\n", *arg);
- if (option != NULL)
- fprintf(stderr, "Please specify a valid -%s file\n", option);
- exit(1);
- }
-}
-
-
-/* If *arg is set, require it to exist, else use the default if it exists. */
-static void optional_file(char **arg, const char* option, const char *dir, const char *file) {
- if (*arg == NULL) {
- default_file(arg, option, dir, file);
- if (!path_exists(*arg))
- *arg = NULL;
- } else {
- /* If it's supplied explciitly, it better be there. */
- require_file(arg, option, dir, file);
- }
-}
-
void emulator_help( void )
{
STRALLOC_DEFINE(out);
@@ -1642,6 +1670,120 @@ report_console( const char* proto_port, int console_port )
restore_sigalrm (&sigstate);
}
+/* this function is used to perform auto-detection of the
+ * system directory in the case of a SDK installation.
+ *
+ * we want to deal with several historical usages, hence
+ * the slightly complicated logic.
+ *
+ * NOTE: the function returns the path to the directory
+ * containing 'fileName'. this is *not* the full
+ * path to 'fileName'.
+ */
+static char*
+_getSdkImagePath( const char* fileName )
+{
+ char temp[MAX_PATH];
+ char* p = temp;
+ char* end = p + sizeof(temp);
+ char* q;
+ char* app;
+
+ static const char* const searchPaths[] = {
+ "", /* program's directory */
+ "/lib/images", /* this is for SDK 1.0 */
+ "/../platforms/android-1.1/images", /* this is for SDK 1.1 */
+ NULL
+ };
+
+ app = bufprint_app_dir(temp, end);
+ if (app >= end)
+ return NULL;
+
+ do {
+ int nn;
+
+ /* first search a few well-known paths */
+ for (nn = 0; searchPaths[nn] != NULL; nn++) {
+ p = bufprint(app, end, "%s", searchPaths[nn]);
+ q = bufprint(p, end, "/%s", fileName);
+ if (q < end && path_exists(temp)) {
+ *p = 0;
+ goto FOUND_IT;
+ }
+ }
+
+ /* hmmm. let's assume that we are in a post-1.1 SDK
+ * scan ../platforms if it exists
+ */
+ p = bufprint(app, end, "/../platforms");
+ if (p < end) {
+ DirScanner* scanner = dirScanner_new(temp);
+ if (scanner != NULL) {
+ int found = 0;
+ const char* subdir;
+
+ for (;;) {
+ subdir = dirScanner_next(scanner);
+ if (!subdir) break;
+
+ q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
+ if (q >= end || !path_exists(temp))
+ continue;
+
+ found = 1;
+ q = bufprint(p, end, "/%s/images", subdir);
+ break;
+ }
+ dirScanner_free(scanner);
+ if (found)
+ break;
+ }
+ }
+
+ /* I'm out of ideas */
+ return NULL;
+
+ } while (0);
+
+FOUND_IT:
+ //D("image auto-detection: %s/%s", temp, fileName);
+ return qemu_strdup(temp);
+}
+
+static char*
+_getSdkImage( const char* path, const char* pathText, const char* file )
+{
+ char temp[MAX_PATH];
+ char *p = temp, *end = p + sizeof(temp);
+
+ p = bufprint(temp, end, "%s/%s", path, file);
+ if (p >= end || !path_exists(temp)) {
+ derror("you %s directory is missing the '%s' image file.",
+ pathText, file);
+ exit(2);
+ }
+
+ return qemu_strdup(temp);
+}
+
+
+static void
+_forceVmImagePath( AvmImageType imageType,
+ const char* path,
+ const char* description,
+ int required )
+{
+ if (path == NULL)
+ return;
+
+ if (required && !path_exists(path)) {
+ derror("cannot find %s image file: %s", description, path);
+ exit(1);
+ }
+ android_vmParams->forcePaths[imageType] = path;
+}
+
#ifdef _WIN32
#undef main /* we don't want SDL to define main */
#endif
@@ -1660,8 +1802,11 @@ int main(int argc, char **argv)
int qemud_serial = 0;
int shell_serial = 0;
int dns_count = 0;
+ unsigned cachePartitionSize = 0;
+
+ AndroidHwConfig* hw;
- const char *appdir = get_app_dir();
+ //const char *appdir = get_app_dir();
char* android_build_root = NULL;
char* android_build_out = NULL;
@@ -1677,6 +1822,8 @@ int main(int argc, char **argv)
opt = (++argv)[0];
if(!strcmp(opt, "-qemu")) {
+ argc--;
+ argv++;
break;
}
@@ -1702,17 +1849,21 @@ int main(int argc, char **argv)
exit(0);
}
- fprintf(stderr, "unknown option: -%s\n", opt);
- emulator_help();
+ fprintf(stderr, "unknown option: -help-%s\n", opt);
+ fprintf(stderr, "please use -help for a list of valid topics\n");
+ exit(1);
}
if (opt[0] == '-') {
fprintf(stderr, "unknown option: %s\n", opt);
- emulator_help();
+ fprintf(stderr, "please use -help for a list of valid options\n");
+ exit(1);
}
- fprintf(stderr, "invalid command-line parameter: %s\n", opt);
- emulator_help();
+ fprintf(stderr, "invalid command-line parameter: %s.\n", opt);
+ fprintf(stderr, "Hint: use '@foo' to launch a virtual machine named 'foo'.\n");
+ fprintf(stderr, "please use -help for more information\n");
+ exit(1);
}
android_charmap = android_charmaps[0];
@@ -1743,9 +1894,9 @@ int main(int argc, char **argv)
}
}
- //if(opts->nopoll) qemu_milli_needed = 0;
-
- /* try to find the top of the Android build tree */
+ /* try to find the top of the Android build tree
+ * unless we have been given a virtual machine name
+ */
do {
char* out = getenv("ANDROID_PRODUCT_OUT");
@@ -1772,149 +1923,164 @@ int main(int argc, char **argv)
D( "found Android build out: %s", android_build_out );
} while (0);
- /* if no opts->system was specified, try to find one */
- if (opts->system == NULL) {
- for (n = 0; sysdir_paths[n]; n++) {
- sprintf(tmp, sysdir_paths[n], appdir, "system.img");
- if (path_exists(tmp)) {
- sprintf(tmp, sysdir_paths[n], appdir, "");
- opts->system = strdup(tmp);
- break;
+ /* if no virtual machine name is given, and we're not in the
+ * Android build system, we'll need to perform some auto-detection
+ * magic :-)
+ */
+ if (opts->vm == NULL && !android_build_out) {
+ if (!opts->system) {
+ opts->system = _getSdkImagePath("system.img");
+ if (!opts->system) {
+ NO_VM_NAME:
+ derror( "you must provide the name of a virtual machine to start the emulator.\n"
+ "please see -help-vm for details." );
+ exit(2);
}
+ D("autoconfig: -system %s", opts->system);
}
- if (opts->system == NULL && android_build_out) {
- sprintf(tmp, "%s/%s", android_build_out, "system.img");
- if (path_exists(tmp))
- opts->system = android_build_out;
+ if (!opts->image) {
+ opts->image = _getSdkImage(opts->system, "-system", "system.img");
+ D("autoconfig: -image %s", opts->image);
}
- if (opts->system == NULL) {
- fprintf(stderr,
- "Cannot locate system directory, which "
- "contains 'system.img' and other\n"
- "system files. Please specify one by "
- "using '-system <directory>' or by\n"
- "defining the environment variable ANDROID_PRODUCT_OUT.\n");
- exit(1);
+ if (!opts->kernel) {
+ opts->kernel = _getSdkImage(opts->system, "-system", "kernel-qemu");
+ D("autoconfig: -kernel %s", opts->kernel);
}
- D("autoconfig: -system %s", opts->system);
- }
+ if (!opts->ramdisk) {
+ opts->ramdisk = _getSdkImage(opts->system, "-ramdisk", "ramdisk.img");
+ D("autoconfig: -ramdisk %s", opts->ramdisk);
+ }
- if (opts->datadir == NULL) {
- if (android_build_out)
- opts->datadir = android_build_out;
- else {
- bufprint_config_path( tmp, tmpend );
- opts->datadir = strdup(tmp);
+ if (!opts->data) {
+ /* we don't want new SDK users to keep using their
+ * obsolete data images. unless they specifically
+ * use -data or -datadir with an existing file,
+ * we're going to complain.
+ */
+ if (!opts->datadir) {
+ goto NO_VM_NAME;
+ }
+
+ /* here the user used -datadir, so check that there is a
+ * valid data partition file here, if not abort.
+ */
+ bufprint(tmp, tmpend, opts->datadir, "/userdata-qemu.img");
+ if (!path_exists(tmp))
+ goto NO_VM_NAME;
+
+ opts->data = qemu_strdup(tmp);
+ D("autoconfig: -data %s", opts->data);
}
- D("autoconfig: -datadir %s", opts->datadir);
- }
- sprintf(tmp, "%s%s.", opts->datadir, PATH_SEP);
- if (!path_can_write(tmp)) {
- if (path_mkdir_if_needed(opts->datadir, 0755) != 0) {
- fprintf(stderr,
- "Cannot create data directory: %s\n"
- "Please specify a writable directory with -datadir.\n", opts->datadir);
- exit(1);
+ if (!opts->sdcard && opts->datadir) {
+ bufprint(tmp, tmpend, opts->datadir, "/sdcard.img");
+ if (path_exists(tmp)) {
+ opts->sdcard = qemu_strdup(tmp);
+ D("autoconfig: -sdcard %s", opts->sdcard);
+ }
}
}
- /* try to find the qemu kernel in the system directory,
- * otherwise, try to get it in the prebuilt directory */
- optional_file(&opts->kernel, "kernel", opts->system, "kernel-qemu");
- if (!opts->kernel && android_build_root) {
- sprintf(tmp, "%s/prebuilt/android-arm/kernel", android_build_root);
- optional_file(&opts->kernel, "kernel", tmp, "kernel-qemu");
+ /* setup the virtual machine parameters from our options
+ */
+ if (opts->nocache) {
+ android_vmParams->flags |= AVMINFO_NO_CACHE;
}
-
- /* similar hack for emulator skins */
- if (!opts->noskin && opts->skindir == NULL) {
- if (android_build_root) {
- sprintf(tmp, "%s/development/emulator", android_build_root);
- optional_file(&opts->skindir, "skindir", tmp, "skins");
- }
+ if (opts->wipe_data) {
+ android_vmParams->flags |= AVMINFO_WIPE_DATA | AVMINFO_WIPE_CACHE;
}
- require_file(&opts->kernel, "kernel", opts->system, "kernel-qemu");
- require_file(&opts->ramdisk, "ramdisk", opts->system, "ramdisk.img");
- require_file(&opts->image, "image", opts->system, "system.img");
- require_file(&opts->initdata, "initdata", opts->system, "userdata.img");
-
- if (!opts->skindir)
- optional_file(&opts->skindir, "skindir", opts->system, "skins");
-
- optional_file(&opts->sdcard, "sdcard", opts->datadir, "sdcard.img");
+ /* if certain options are set, we can force the path of
+ * certain kernel/disk image files
+ */
+ _forceVmImagePath(AVM_IMAGE_KERNEL, opts->kernel, "kernel", 1);
+ _forceVmImagePath(AVM_IMAGE_SYSTEM, opts->image, "system", 1);
+ _forceVmImagePath(AVM_IMAGE_RAMDISK, opts->ramdisk,"ramdisk", 1);
+ _forceVmImagePath(AVM_IMAGE_USERDATA,opts->data, "user data", 0);
+ _forceVmImagePath(AVM_IMAGE_CACHE, opts->cache, "cache", 0);
+ _forceVmImagePath(AVM_IMAGE_SDCARD, opts->sdcard, "SD Card", 0);
+
+ /* we don't accept -skindir without -skin now
+ * to simplify the autoconfig stuff with virtual devices
+ */
+ if (opts->noskin) {
+ opts->skin = "320x480";
+ opts->skindir = NULL;
+ }
- if (opts->data == NULL) {
- if (strcmp(opts->datadir, opts->system) != 0) {
- /* in the past, the writable image was called "userdata.img" */
- optional_file(&opts->data, "data", opts->datadir, "userdata.img");
+ if (opts->skindir) {
+ if (!opts->skin) {
+ derror( "the -skindir <path> option requires a -skin <name> option");
+ exit(1);
}
- default_file(&opts->data, "data", opts->datadir, "userdata-qemu.img");
-
- if ( !path_exists(opts->data) ) {
- /* if the file does not exist, imply a -wipe-data */
- opts->wipe_data = 1;
+ }
+ else {
+ if (!opts->skin && android_build_out) {
+ /* select default skin based on product type */
+ const char* p = strrchr(android_build_out,'/');
+ if (p) {
+ if (p[1] == 's') {
+ opts->skin = "QVGA-L";
+ } else if (p[1] == 'd') {
+ opts->skin = "HVGA";
+ }
+ }
+ D("autoconfig: -skin %s", opts->skin);
}
- } else if ( !path_exists(opts->data) ) {
- /* if -data is used with a non-existent data file */
- opts->wipe_data = 1;
+ android_vmParams->skinName = opts->skin;
}
-
+ /* setup the virtual machine differently depending on whether
+ * we are in the Android build system or not
+ */
+ if (opts->vm != NULL)
{
- FileLock* data_lock = filelock_create(opts->data);
- if (data_lock == NULL) {
- fprintf(stderr, "Cannot create /data image file lock\n");
- exit(2);
- }
- /* if the file is already used, use a temporary file instead */
- if (filelock_lock(data_lock) < 0) {
- TempFile* data_tmp;
- fprintf(stderr,
- "### WARNING: Another emulator is running with our data file\n");
-
- data_tmp = tempfile_create();
- if (data_tmp == NULL) {
- fprintf(stderr, "annot create a new temporary user data file.\n" );
- exit(2);
- }
- fprintf(stderr, "### WARNING: User data changes will NOT be saved!\n");
- opts->data = (char*) tempfile_path(data_tmp);
- opts->wipe_data = 1;
+ android_vmInfo = avmInfo_new( opts->vm, android_vmParams );
+ if (android_vmInfo == NULL) {
+ /* an error message has already been printed */
+ D("could not find virtual machine named '%s'", opts->vm);
+ exit(1);
}
}
+ else
+ {
+ if (!android_build_out) {
+ android_build_root = android_build_out = opts->system;
+ }
+ android_vmInfo = avmInfo_newForAndroidBuild(
+ android_build_root,
+ android_build_out,
+ android_vmParams );
- /* wipe the data file if necessary */
- if (opts->wipe_data || !path_exists(opts->data)) {
- if (copy_file(opts->data, opts->initdata) >= 0) {
- D("copied file '%s' from '%s'", opts->data, opts->initdata);
- } else {
- fprintf(stderr,
- "### WARNING: Cannot write user data file '%s': %s\n",
- opts->data, strerror(errno));
- exit(3);
+ if(android_vmInfo == NULL) {
+ D("could not start virtual machine\n");
+ exit(1);
}
}
- /* lock the SD card image file */
- if (opts->sdcard != NULL) {
- FileLock* sdcard_lock = filelock_create( opts->sdcard );
- int free_sdcard = (sdcard_lock == NULL);
+ if (!opts->skindir) {
+ /* get the skin from the virtual machine configuration */
+ opts->skin = (char*) avmInfo_getSkinName( android_vmInfo );
+ opts->skindir = (char*) avmInfo_getSkinDir( android_vmInfo );
- if (sdcard_lock && filelock_lock(sdcard_lock) < 0) {
- fprintf( stderr, "#### WARNING: SD Card emulation disabled. '%s' already in use\n", opts->sdcard );
- free_sdcard = 1;
+ if (opts->skin) {
+ D("autoconfig: -skin %s", opts->skin);
}
-
- if (free_sdcard) {
- opts->sdcard = NULL;
+ if (opts->skindir) {
+ D("autoconfig: -skindir %s", opts->skindir);
}
}
+ /* Read hardware configuration */
+ hw = android_hw;
+ if (avmInfo_getHwConfig(android_vmInfo, hw) < 0) {
+ derror("could not read hardware configuration ?");
+ exit(1);
+ }
+
#ifdef CONFIG_NAND_LIMITS
if (opts->nand_limits)
parse_nand_limits(opts->nand_limits);
@@ -1924,7 +2090,8 @@ int main(int argc, char **argv)
parse_keyset(opts->keyset, opts);
if (!android_keyset) {
fprintf(stderr,
- "emulator: WARNING: could not find keyset file named '%s', using defaults instead\n",
+ "emulator: WARNING: could not find keyset file named '%s',"
+ " using defaults instead\n",
opts->keyset);
}
}
@@ -1969,6 +2136,10 @@ int main(int argc, char **argv)
}
bufprint( env, env+sizeof(env), "QEMU_AUDIO_IN_DRV=%s", opts->audio_in );
putenv( env );
+
+ if (!hw->hw_audioInput) {
+ dwarning( "Emulated hardware doesn't have audio input.");
+ }
}
if (opts->audio_out) {
static char env[64]; /* note: putenv needs a static unique string buffer */
@@ -1979,26 +2150,8 @@ int main(int argc, char **argv)
}
bufprint( env, env+sizeof(env), "QEMU_AUDIO_OUT_DRV=%s", opts->audio_out );
putenv( env );
- }
-
- if (opts->noskin) {
- opts->skin = "320x240";
- opts->skindir = NULL;
- } else if (opts->skin == NULL) {
- /* select default skin based on product type */
- const char* env = getenv("ANDROID_PRODUCT_OUT");
- if (env) {
- const char* p = strrchr(env,'/');
- if (p) {
- if (p[1] == 's') {
- opts->skin = "QVGA-L";
- } else if (p[1] == 'd') {
- opts->skin = "HVGA";
- }
- }
- }
- if (opts->skin) {
- D("autoconfig: -skin %s", opts->skin);
+ if (!hw->hw_audioOutput) {
+ dwarning( "Emulated hardware doesn't have audio output");
}
}
@@ -2047,41 +2200,24 @@ int main(int argc, char **argv)
}
if (opts->trace) {
- int ret;
- sprintf(tmp, "%s/traces", opts->system);
- ret = path_mkdir_if_needed( tmp, 0755 );
+ char* tracePath = avmInfo_getTracePath(android_vmInfo, opts->trace);
+ int ret;
+
+ if (tracePath == NULL) {
+ derror( "bad -trace parameter" );
+ exit(1);
+ }
+ ret = path_mkdir_if_needed( tracePath, 0755 );
if (ret < 0) {
fprintf(stderr, "could not create directory '%s'\n", tmp);
exit(2);
}
- sprintf(tmp, "%s/traces/%s", opts->system, opts->trace);
- opts->trace = strdup(tmp);
+ opts->trace = tracePath;
}
if (opts->nocache)
opts->cache = 0;
- if (opts->cache) {
- FileLock* cache_lock = filelock_create(opts->cache);
- if (cache_lock == NULL) {
- fprintf(stderr, "Could not create cache image file lock\n" );
- exit(2);
- }
- if ( filelock_lock( cache_lock ) < 0 ) {
- fprintf(stderr, "### WARNING: Another emulator instance is using our cache file. using temp file\n");
- opts->cache = NULL;
- }
- else if ( !path_exists(opts->cache) ) {
- /* -cache <file> where <file> does not exit, we simply */
- /* create an empty file then */
- if ( make_empty_file( opts->cache ) < 0 ) {
- fprintf(stderr, "could not create cache file '%s'\n", opts->cache);
- exit(2);
- }
- D( "created non-existent cache image file: %s\n", opts->cache );
- }
- }
-
if (opts->dns_server) {
char* x = strchr(opts->dns_server, ',');
dns_count = 0;
@@ -2119,33 +2255,63 @@ int main(int argc, char **argv)
n = 1;
/* generate arguments for the underlying qemu main() */
- if(opts->kernel) {
- args[n++] = "-kernel";
- args[n++] = opts->kernel;
- }
- if(opts->ramdisk) {
- args[n++] = "-initrd";
- args[n++] = opts->ramdisk;
- }
- if(opts->image) {
- sprintf(tmp, "system,size=0x4200000,initfile=%s", opts->image);
+ args[n++] = "-kernel";
+ args[n++] = (char*) avmInfo_getImageFile(android_vmInfo, AVM_IMAGE_KERNEL);
+
+ args[n++] = "-initrd";
+ args[n++] = (char*) avmInfo_getImageFile(android_vmInfo, AVM_IMAGE_RAMDISK);
+
+ {
+ const char* filetype = "file";
+
+ if (avmInfo_isImageReadOnly(android_vmInfo, AVM_IMAGE_SYSTEM))
+ filetype = "initfile";
+
+ bufprint(tmp, tmpend,
+ "system,size=0x4200000,%s=%s", filetype,
+ avmInfo_getImageFile(android_vmInfo, AVM_IMAGE_SYSTEM));
+
args[n++] = "-nand";
args[n++] = strdup(tmp);
}
- if(opts->data) {
- sprintf(tmp, "userdata,size=0x4200000,file=%s", opts->data);
- args[n++] = "-nand";
- args[n++] = strdup(tmp);
+
+ bufprint(tmp, tmpend,
+ "userdata,size=0x4200000,file=%s",
+ avmInfo_getImageFile(android_vmInfo, AVM_IMAGE_USERDATA));
+
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+
+ if (hw->disk_cachePartition) {
+ opts->cache = (char*) avmInfo_getImageFile(android_vmInfo, AVM_IMAGE_CACHE);
+ cachePartitionSize = hw->disk_cachePartition_size;
+ }
+ else if (opts->cache) {
+ dwarning( "Emulated hardware doesn't support a cache partition" );
+ opts->cache = NULL;
+ opts->nocache = 1;
}
+
if (opts->cache) {
- sprintf(tmp, "cache,size=0x4200000,file=%s", opts->cache);
+ /* use a specific cache file */
+ sprintf(tmp, "cache,size=0x%0x,file=%s", cachePartitionSize, opts->cache);
args[n++] = "-nand";
args[n++] = strdup(tmp);
- } else if(!opts->nocache) {
- sprintf(tmp, "cache,size=0x4200000");
+ }
+ else if (!opts->nocache) {
+ /* create a temporary cache partition file */
+ sprintf(tmp, "cache,size=0x%0x", cachePartitionSize);
args[n++] = "-nand";
args[n++] = strdup(tmp);
}
+
+ if (hw->hw_sdCard != 0)
+ opts->sdcard = (char*) avmInfo_getImageFile(android_vmInfo, AVM_IMAGE_SDCARD);
+ else if (opts->sdcard) {
+ dwarning( "Emulated hardware doesn't support SD Cards" );
+ opts->sdcard = NULL;
+ }
+
if(opts->sdcard) {
uint64_t size;
if (path_get_size(opts->sdcard, &size) == 0) {
@@ -2158,7 +2324,7 @@ int main(int argc, char **argv)
use_sdcard_img = 1;
}
} else {
- dprint("could not find or access sdcard image at '%s'", opts->sdcard);
+ D("no SD Card image at '%s'", opts->sdcard);
}
}
@@ -2233,7 +2399,7 @@ int main(int argc, char **argv)
}
android_qemud_set_channel( ANDROID_QEMUD_GSM, cs);
}
- else {
+ else if ( hw->hw_gsmModem != 0 ) {
if ( android_qemud_get_channel( ANDROID_QEMUD_GSM, &android_modem_cs ) < 0 ) {
derror( "could not initialize qemud 'gsm' channel" );
exit(1);
@@ -2249,7 +2415,7 @@ int main(int argc, char **argv)
}
android_qemud_set_channel( ANDROID_QEMUD_GPS, cs);
}
- else {
+ else if ( hw->hw_gps != 0 ) {
if ( android_qemud_get_channel( "gps", &android_gps_cs ) < 0 ) {
derror( "could not initialize qemud 'gps' channel" );
exit(1);
@@ -2257,6 +2423,23 @@ int main(int argc, char **argv)
}
}
+ if (opts->memory) {
+ char* end;
+ long ramSize = strtol(opts->memory, &end, 0);
+ if (ramSize < 0 || *end != 0) {
+ derror( "-memory must be followed by a positive integer" );
+ exit(1);
+ }
+ if (ramSize < 32 || ramSize > 4096) {
+ derror( "physical memory size must be between 32 and 4096 MB" );
+ exit(1);
+ }
+ }
+ if (!opts->memory) {
+ bufprint(tmp, tmpend, "%d", hw->hw_ramSize);
+ opts->memory = qemu_strdup(tmp);
+ }
+
if (opts->noaudio) {
args[n++] = "-noaudio";
}
@@ -2281,6 +2464,18 @@ int main(int argc, char **argv)
args[n++] = "-append";
+ if (opts->bootchart) {
+ char* end;
+ int timeout = strtol(opts->bootchart, &end, 10);
+ if (timeout == 0)
+ opts->bootchart = NULL;
+ else if (timeout < 0 || timeout > 15*60) {
+ derror( "timeout specified for -bootchart option is invalid.\n"
+ "please use integers between 1 and 900\n");
+ exit(1);
+ }
+ }
+
{
static char params[1024];
char *p = params, *end = p + sizeof(params);
@@ -2336,6 +2531,10 @@ int main(int argc, char **argv)
p = bufprint(p, end, " android.ndns=%d", dns_count);
}
+ if (opts->bootchart) {
+ p = bufprint(p, end, " androidboot.bootchart=%s", opts->bootchart);
+ }
+
if (p >= end) {
fprintf(stderr, "### ERROR: kernel parameters too long\n");
exit(1);
@@ -2344,6 +2543,10 @@ int main(int argc, char **argv)
args[n++] = strdup(params);
}
+ /* physical memory */
+ args[n++] = "-m";
+ args[n++] = opts->memory;
+
while(argc-- > 0) {
args[n++] = *argv++;
}
@@ -2380,45 +2583,79 @@ void android_emulation_setup( void )
}
#endif
- if (opts->port) {
- char* end;
- int port = strtol( opts->port, &end, 0 );
- if ( end == NULL || *end ||
- (unsigned)((port - base_port) >> 1) >= (unsigned)tries )
- {
- derror( "option -port must be followed by an even integer number between %d and %d\n",
- base_port, base_port + (tries-1)*2 );
+ if (opts->port && opts->ports) {
+ fprintf( stderr, "options -port and -ports cannot be used together.\n");
+ exit(1);
+ }
+
+ if (opts->ports) {
+ char* comma_location;
+ char* end;
+ int console_port = strtol( opts->ports, &comma_location, 0 );
+
+ if ( comma_location == NULL || *comma_location != ',' ) {
+ derror( "option -ports must be followed by two comma separated positive integer numbers" );
exit(1);
}
- if ( (port & 1) != 0 ) {
- port &= ~1;
- dwarning( "option -port must be followed by an even integer, using port number %d\n",
- port );
+
+ int adb_port = strtol( comma_location+1, &end, 0 );
+
+ if ( end == NULL || *end ) {
+ derror( "option -ports must be followed by two comma separated positive integer numbers" );
+ exit(1);
}
- base_port = port;
- tries = 1;
- }
- for ( ; tries > 0; tries--, base_port += 2 ) {
+ if ( console_port == adb_port ) {
+ derror( "option -ports must be followed by two different integer numbers" );
+ exit(1);
+ }
- /* setup first redirection for ADB, the Android Debug Bridge */
- if ( slirp_redir( 0, base_port+1, guest_addr, 5555 ) < 0 )
- continue;
+ slirp_redir( 0, adb_port, guest_addr, 5555 );
+ if ( control_console_start( console_port ) < 0 ) {
+ slirp_unredir( 0, adb_port );
+ }
- /* setup second redirection for the emulator console */
- if ( control_console_start( base_port ) < 0 ) {
- slirp_unredir( 0, base_port+1 );
- continue;
+ base_port = console_port;
+ } else {
+ if (opts->port) {
+ char* end;
+ int port = strtol( opts->port, &end, 0 );
+ if ( end == NULL || *end ||
+ (unsigned)((port - base_port) >> 1) >= (unsigned)tries ) {
+ derror( "option -port must be followed by an even integer number between %d and %d\n",
+ base_port, base_port + (tries-1)*2 );
+ exit(1);
+ }
+ if ( (port & 1) != 0 ) {
+ port &= ~1;
+ dwarning( "option -port must be followed by an even integer, using port number %d\n",
+ port );
+ }
+ base_port = port;
+ tries = 1;
}
- D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
- success = 1;
- break;
- }
+ for ( ; tries > 0; tries--, base_port += 2 ) {
- if (!success) {
- fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
- exit(1);
+ /* setup first redirection for ADB, the Android Debug Bridge */
+ if ( slirp_redir( 0, base_port+1, guest_addr, 5555 ) < 0 )
+ continue;
+
+ /* setup second redirection for the emulator console */
+ if ( control_console_start( base_port ) < 0 ) {
+ slirp_unredir( 0, base_port+1 );
+ continue;
+ }
+
+ D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
+ success = 1;
+ break;
+ }
+
+ if (!success) {
+ fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
+ exit(1);
+ }
}
if (opts->report_console) {
diff --git a/android_option.c b/android_option.c
index 1a8506e..7f97b64 100644
--- a/android_option.c
+++ b/android_option.c
@@ -45,10 +45,30 @@ android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
memset( opt, 0, sizeof *opt );
- while (nargs > 0 && aread[0][0] == '-') {
- char* arg = aread[0]+1;
+ while (nargs > 0) {
+ char* arg;
+ char arg2_tab[64], *arg2 = arg2_tab;
int nn;
+ /* process @<name> as a special exception meaning
+ * '-vm <name>'
+ */
+ if (aread[0][0] == '@') {
+ opt->vm = aread[0]+1;
+ nargs--;
+ aread++;
+ continue;
+ }
+
+ /* anything that isn't an option past this points
+ * exits the loop
+ */
+ if (aread[0][0] != '-') {
+ break;
+ }
+
+ arg = aread[0]+1;
+
/* an option cannot contain an underscore */
if (strchr(arg, '_') != NULL) {
break;
@@ -73,21 +93,38 @@ android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
continue;
}
+ /* NOTE: variable tables map option names to values
+ * (e.g. field offsets into the AndroidOptions structure).
+ *
+ * however, the names stored in the table used underscores
+ * instead of dashes. this means that the command-line option
+ * '-foo-bar' will be associated to the name 'foo_bar' in
+ * this table, and will point to the field 'foo_bar' or
+ * AndroidOptions.
+ *
+ * as such, before comparing the current option to the
+ * content of the table, we're going to translate dashes
+ * into underscores.
+ */
+ arg2 = arg2_tab;
+ buffer_translate_char( arg2_tab, sizeof(arg2_tab),
+ arg, '-', '_');
+
/* special handling for -debug-<tag> and -debug-no-<tag> */
- if (!strncmp(arg, "debug-", 6)) {
+ if (!memcmp(arg2, "debug_", 6)) {
int remove = 0;
unsigned long mask = 0;
- arg += 6;
- if (!strncmp(arg, "no-", 3)) {
- arg += 3;
+ arg2 += 6;
+ if (!memcmp(arg2, "no_", 3)) {
+ arg2 += 3;
remove = 1;
}
- if (!strcmp(arg, "all")) {
+ if (!strcmp(arg2, "all")) {
mask = ~0;
}
for (nn = 0; debug_tags[nn].name; nn++) {
- if (!strcmp(arg, debug_tags[nn].name)) {
- mask = (1 << debug_tags[nn].flag);
+ if (!strcmp(arg2, debug_tags[nn].name)) {
+ mask = (1UL << debug_tags[nn].flag);
break;
}
}
@@ -100,33 +137,9 @@ android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
/* look into our table of options
*
- * NOTE: the 'option_keys' table maps option names
- * to field offsets into the AndroidOptions structure.
- *
- * however, the names stored in the table used underscores
- * instead of dashes. this means that the command-line option
- * '-foo-bar' will be associated to the name 'foo_bar' in
- * this table, and will point to the field 'foo_bar' or
- * AndroidOptions.
- *
- * as such, before comparing the current option to the
- * content of the table, we're going to translate dashes
- * into underscores.
*/
{
const OptionInfo* oo = option_keys;
- char arg2[64];
- int len = strlen(arg);
-
- /* copy into 'arg2' buffer, translating dashes
- * to underscores. note that we truncate to 63
- * characters, which should be enough in practice
- */
- if (len > sizeof(arg2)-1)
- len = sizeof(arg2)-1;
-
- memcpy(arg2, arg, len+1);
- buffer_translate_char(arg2, len, '-', '_');
for ( ; oo->name; oo++ ) {
if ( !strcmp( oo->name, arg2 ) ) {
@@ -207,8 +220,11 @@ parse_debug_tags( const char* tags )
if (!strcmp( "all", x ))
mask = ~0;
else {
+ char temp[32];
+ buffer_translate_char(temp, sizeof temp, x, '-', '_');
+
for (nn = 0; debug_tags[nn].name != NULL; nn++) {
- if ( !strcmp( debug_tags[nn].name, x ) ) {
+ if ( !strcmp( debug_tags[nn].name, temp ) ) {
mask |= (1 << debug_tags[nn].flag);
break;
}
diff --git a/android_options.h b/android_options.h
index 695e17b..89a44db 100644
--- a/android_options.h
+++ b/android_options.h
@@ -70,10 +70,11 @@ CFG_PARAM( cache, "<file>", "cache partition image (default is temporary file
CFG_FLAG ( nocache, "disable the cache partition" )
OPT_PARAM( sdcard, "<file>", "SD card image (default <system>/sdcard.img")
OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" )
-
+CFG_PARAM( vm, "<name>", "use a specific virtual machine" )
CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" )
CFG_PARAM( skin, "<file>", "select a given skin" )
CFG_FLAG ( noskin, "don't use any emulator skin" )
+CFG_PARAM( memory, "<size>", "physical RAM size in MBs" )
OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" )
OPT_PARAM( netdelay, "<delay>", "network latency emulation" )
@@ -93,6 +94,7 @@ OPT_PARAM( audio_out,"<backend>", "use specific audio output backend" )
OPT_FLAG ( raw_keys, "disable Unicode keyboard reverse-mapping" )
OPT_PARAM( radio, "<device>", "redirect radio modem interface to character device" )
OPT_PARAM( port, "<port>", "TCP port that will be used for the console" )
+OPT_PARAM( ports, "<consoleport>,<adbport>", "TCP ports used for the console and adb bridge" )
OPT_PARAM( onion, "<image>", "use overlay PNG image over screen" )
OPT_PARAM( onion_alpha, "<%age>", "specify onion-skin translucency" )
OPT_PARAM( onion_rotation, "0|1|2|3", "specify onion-skin rotation" )
@@ -116,10 +118,13 @@ OPT_PARAM( keyset, "<name>", "specify keyset file name" )
OPT_PARAM( shell_serial, "<device>", "specific character device for root shell" )
OPT_FLAG ( old_system, "support old (pre 1.4) system images" )
+
#ifdef CONFIG_NAND_LIMITS
OPT_PARAM( nand_limits, "<nlimits>", "enforce NAND/Flash read/write thresholds" )
#endif
+OPT_PARAM( bootchart, "<timeout>", "enable bootcharting")
+
#undef CFG_FLAG
#undef CFG_PARAM
#undef OPT_FLAG
diff --git a/android_qemud.c b/android_qemud.c
index cfbd540..02563a4 100644
--- a/android_qemud.c
+++ b/android_qemud.c
@@ -32,48 +32,6 @@
#define CHANNEL_CONTROL_INDEX 0
-/** utilities
- **/
-static int
-hexdigit( int c )
-{
- unsigned d;
-
- d = (unsigned)(c - '0');
- if (d < 10) return d;
-
- d = (unsigned)(c - 'a');
- if (d < 6) return d+10;
-
- d = (unsigned)(c - 'A');
- if (d < 6) return d+10;
-
- return -1;
-}
-
-static int
-hex2int( const uint8_t* hex, int len )
-{
- int result = 0;
- while (len > 0) {
- int c = hexdigit(*hex++);
- if (c < 0)
- return -1;
-
- result = (result << 4) | c;
- len --;
- }
- return result;
-}
-
-static void
-int2hex( uint8_t* hex, int len, int val )
-{
- static const uint8_t hexchars[16] = "0123456789abcdef";
- while ( --len >= 0 )
- *hex++ = hexchars[(val >> (len*4)) & 15];
-}
-
/** packets
**/
#define HEADER_SIZE 6
diff --git a/android_qemud.h b/android_qemud.h
index 1e9fad5..dfd6ba1 100644
--- a/android_qemud.h
+++ b/android_qemud.h
@@ -63,8 +63,9 @@ extern int android_qemud_get_channel( const char* name, CharDriverState* *pcs
extern int android_qemud_set_channel( const char* name, CharDriverState* peer_cs );
/* list of known qemud channel names */
-#define ANDROID_QEMUD_GSM "gsm"
-#define ANDROID_QEMUD_GPS "gps"
+#define ANDROID_QEMUD_GSM "gsm"
+#define ANDROID_QEMUD_GPS "gps"
+#define ANDROID_QEMUD_CONTROL "control"
/* add new channel names here when you need them */
diff --git a/android_utils.c b/android_utils.c
index 26518cd..58f2a88 100644
--- a/android_utils.c
+++ b/android_utils.c
@@ -36,6 +36,39 @@
#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+#ifdef _WIN32
+char*
+win32_strsep(char** pline, const char* delim)
+{
+ char* line = *pline;
+ char* p = line;
+
+ if (p == NULL)
+ return NULL;
+
+ for (;;) {
+ int c = *p++;
+ const char* q = delim;
+
+ if (c == 0) {
+ p = NULL;
+ break;
+ }
+
+ while (*q) {
+ if (*q == c) {
+ p[-1] = 0;
+ goto Exit;
+ }
+ q++;
+ }
+ }
+Exit:
+ *pline = p;
+ return line;
+}
+#endif
+
/** PATH HANDLING ROUTINES
**
** path_parent() can be used to return the n-level parent of a given directory
@@ -419,12 +452,12 @@ bufprint_config_path(char* buff, char* end)
SHGetFolderPath( NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
NULL, 0, path);
- return bufprint(buff, end, "%s\\%s\\%s", path, _ANDROID_PATH, ANDROID_SDK_VERSION);
+ return bufprint(buff, end, "%s\\%s", path, _ANDROID_PATH );
#else
const char* home = getenv("HOME");
if (home == NULL)
home = "/tmp";
- return bufprint(buff, end, "%s/%s/%s", home, _ANDROID_PATH, ANDROID_SDK_VERSION);
+ return bufprint(buff, end, "%s/%s", home, _ANDROID_PATH );
#endif
}
@@ -477,11 +510,7 @@ bufprint_temp_file(char* buff, char* end, const char* suffix)
** writable file (e.g. the userdata.img disk images).
**
** create a FileLock object with filelock_create(), ithis function should return NULL
- ** only if thee file doesn't exist, or if you don't have enough memory.
- *
- * then call filelock_lock() to try to acquire a lock for the corresponding file.
- ** returns 0 on success, or -1 in case of error, which means that another program
- ** is using the file or that the directory containing the file is read-only.
+ ** only if the corresponding file path could not be locked.
**
** all file locks are automatically released and destroyed when the program exits.
** the filelock_lock() function can also detect stale file locks that can linger
@@ -516,6 +545,10 @@ struct FileLock
FileLock* next;
};
+/* used to cleanup all locks at emulator exit */
+static FileLock* _all_filelocks;
+
+
#define LOCK_NAME ".lock"
#define TEMP_NAME ".tmp-XXXXXX"
@@ -524,7 +557,7 @@ struct FileLock
#endif
/* returns 0 on success, -1 on failure */
-int
+static int
filelock_lock( FileLock* lock )
{
int ret;
@@ -780,32 +813,26 @@ Fail:
}
void
-filelock_unlock( FileLock* lock )
+filelock_release( FileLock* lock )
{
+ if (lock->locked) {
#ifdef _WIN32
- unlink_file( (char*)lock->temp );
- rmdir( (char*)lock->lock );
- lock->locked = 0;
+ unlink_file( (char*)lock->temp );
+ rmdir( (char*)lock->lock );
#else
- unlink( (char*)lock->lock );
- lock->locked = 0;
+ unlink( (char*)lock->lock );
#endif
+ lock->locked = 0;
+ }
}
-
-/* used to cleanup all locks at emulator exit */
-static FileLock* _all_filelocks;
-
static void
filelock_atexit( void )
{
FileLock* lock;
for (lock = _all_filelocks; lock != NULL; lock = lock->next)
- {
- if (lock->locked)
- filelock_unlock( lock );
- }
+ filelock_release( lock );
}
/* create a file lock */
@@ -822,8 +849,6 @@ filelock_create( const char* file )
int total_len = sizeof(FileLock) + file_len + lock_len + temp_len + 3;
FileLock* lock = malloc(total_len);
- if (lock == NULL)
- goto Exit;
lock->file = (const char*)(lock + 1);
memcpy( (char*)lock->file, file, file_len+1 );
@@ -834,18 +859,23 @@ filelock_create( const char* file )
lock->temp = (char*)lock->lock + lock_len + 1;
#ifdef _WIN32
- sprintf( (char*)lock->temp, "%s\\" PIDFILE_NAME, lock->lock );
+ snprintf( (char*)lock->temp, temp_len, "%s\\" PIDFILE_NAME, lock->lock );
#else
lock->temp[0] = 0;
#endif
lock->locked = 0;
+ if (filelock_lock(lock) < 0) {
+ free(lock);
+ return NULL;
+ }
+
lock->next = _all_filelocks;
_all_filelocks = lock;
if (lock->next == NULL)
atexit( filelock_atexit );
-Exit:
+
return lock;
}
@@ -1189,9 +1219,53 @@ get_monitor_resolution( int *px_dpi, int *py_dpi )
#else /* Linux and others */
#include <SDL.h>
#include <SDL_syswm.h>
+#include <dlfcn.h>
#include <X11/Xlib.h>
#define MM_PER_INCH 25.4
+#define DYNLINK_FUNCTIONS \
+ DYNLINK_FUNC(int,XDefaultScreen,(Display*)) \
+ DYNLINK_FUNC(int,XDisplayWidth,(Display*,int)) \
+ DYNLINK_FUNC(int,XDisplayWidthMM,(Display*,int)) \
+ DYNLINK_FUNC(int,XDisplayHeight,(Display*,int)) \
+ DYNLINK_FUNC(int,XDisplayHeightMM,(Display*,int)) \
+
+#define DYNLINK_FUNCTIONS_INIT \
+ x11_dynlink_init
+
+#include "dynlink.h"
+
+static int x11_lib_inited;
+static void* x11_lib;
+
+int
+x11_lib_init( void )
+{
+ if (!x11_lib_inited) {
+ x11_lib_inited = 1;
+
+ x11_lib = dlopen( "libX11.so", RTLD_NOW );
+
+ if (x11_lib == NULL) {
+ x11_lib = dlopen( "libX11.so.6", RTLD_NOW );
+ }
+ if (x11_lib == NULL) {
+ D("%s: Could not find libX11.so on this machine",
+ __FUNCTION__);
+ return -1;
+ }
+
+ if (x11_dynlink_init(x11_lib) < 0) {
+ D("%s: didn't find necessary symbols in libX11.so",
+ __FUNCTION__);
+ dlclose(x11_lib);
+ x11_lib = NULL;
+ }
+ }
+ return x11_lib ? 0 : -1;
+}
+
+
int
get_monitor_resolution( int *px_dpi, int *py_dpi )
{
@@ -1207,13 +1281,16 @@ get_monitor_resolution( int *px_dpi, int *py_dpi )
return -1;
}
+ if (x11_lib_init() < 0)
+ return -1;
+
display = info.info.x11.display;
- screen = XDefaultScreen(display);
+ screen = FF(XDefaultScreen)(display);
- width = XDisplayWidth(display, screen);
- width_mm = XDisplayWidthMM(display, screen);
- height = XDisplayHeight(display, screen);
- height_mm = XDisplayHeightMM(display, screen);
+ width = FF(XDisplayWidth)(display, screen);
+ width_mm = FF(XDisplayWidthMM)(display, screen);
+ height = FF(XDisplayHeight)(display, screen);
+ height_mm = FF(XDisplayHeightMM)(display, screen);
if (width_mm <= 0 || height_mm <= 0) {
D( "%s: bad screen dimensions: width_mm = %d, height_mm = %d",
@@ -1343,24 +1420,32 @@ stralloc_tabular( stralloc_t* out,
}
extern void
-buffer_translate_char( char* buff, unsigned len,
- char from, char to )
+string_translate_char( char* str, char from, char to )
{
- char* p = buff;
- char* end = p + len;
-
- while (p != NULL && (p = memchr(p, from, (size_t)(end - p))) != NULL)
+ char* p = str;
+ while (p != NULL && (p = strchr(p, from)) != NULL)
*p++ = to;
}
extern void
-string_translate_char( char* str, char from, char to )
+buffer_translate_char( char* buff,
+ unsigned buffLen,
+ const char* src,
+ char fromChar,
+ char toChar )
{
- char* p = str;
- while (p != NULL && (p = strchr(p, from)) != NULL)
- *p++ = to;
+ int len = strlen(src);
+
+ if (len >= buffLen)
+ len = buffLen-1;
+
+ memcpy(buff, src, len);
+ buff[len] = 0;
+
+ string_translate_char( buff, fromChar, toChar );
}
+
/** DYNAMIC STRINGS
**/
@@ -1547,6 +1632,64 @@ stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len )
}
}
+extern void
+stralloc_add_hex( stralloc_t* s, unsigned value, int num_digits )
+{
+ const char hexdigits[16] = "0123456789abcdef";
+ int nn;
+
+ if (num_digits <= 0)
+ return;
+
+ stralloc_readyplus(s, num_digits);
+ for (nn = num_digits-1; nn >= 0; nn--) {
+ s->s[s->n+nn] = hexdigits[value & 15];
+ value >>= 4;
+ }
+ s->n += num_digits;
+}
+
+extern void
+stralloc_add_hexdump( stralloc_t* s, void* base, int size, const char* prefix )
+{
+ uint8_t* p = (uint8_t*)base;
+ const int max_count = 16;
+ int prefix_len = strlen(prefix);
+
+ while (size > 0) {
+ int count = size > max_count ? max_count : size;
+ int count2;
+ int n;
+
+ stralloc_add_bytes( s, prefix, prefix_len );
+ stralloc_add_hex( s, p[0], 2 );
+
+ for (n = 1; n < count; n++) {
+ stralloc_add_c( s, ' ' );
+ stralloc_add_hex( s, p[n], 2 );
+ }
+
+ count2 = 4 + 3*(max_count - count);
+ stralloc_readyplus( s, count2 );
+ memset( s->s + s->n, ' ', count2 );
+ s->n += count2;
+
+ stralloc_readyplus(s, count+1);
+ for (n = 0; n < count; n++) {
+ int c = p[n];
+
+ if (c < 32 || c > 127)
+ c = '.';
+
+ s->s[s->n++] = c;
+ }
+ s->s[s->n++] = '\n';
+
+ size -= count;
+ p += count;
+ }
+}
+
/** TEMP CHAR STRINGS
**
** implement a circular ring of temporary string buffers
@@ -1762,3 +1905,46 @@ qvector_remove_n( qvector_t* v, int index, int count )
v->n -= count;
}
+
+/** HEXADECIMAL CHARACTER SEQUENCES
+ **/
+
+static int
+hexdigit( int c )
+{
+ unsigned d;
+
+ d = (unsigned)(c - '0');
+ if (d < 10) return d;
+
+ d = (unsigned)(c - 'a');
+ if (d < 6) return d+10;
+
+ d = (unsigned)(c - 'A');
+ if (d < 6) return d+10;
+
+ return -1;
+}
+
+int
+hex2int( const uint8_t* hex, int len )
+{
+ int result = 0;
+ while (len > 0) {
+ int c = hexdigit(*hex++);
+ if (c < 0)
+ return -1;
+
+ result = (result << 4) | c;
+ len --;
+ }
+ return result;
+}
+
+void
+int2hex( uint8_t* hex, int len, int val )
+{
+ static const uint8_t hexchars[16] = "0123456789abcdef";
+ while ( --len >= 0 )
+ *hex++ = hexchars[(val >> (len*4)) & 15];
+}
diff --git a/android_utils.h b/android_utils.h
index 56dbc9a..43546c0 100644
--- a/android_utils.h
+++ b/android_utils.h
@@ -49,11 +49,23 @@
#ifdef _WIN32
# undef MAX_PATH
# define MAX_PATH 1024
+# define PATH_MAX MAX_PATH
#else
# include <limits.h>
# define MAX_PATH PATH_MAX
#endif
+#ifdef _WIN32
+# define strcasecmp stricmp
+#endif
+
+
+#ifdef _WIN32
+# undef strsep
+# define strsep win32_strsep
+extern char* win32_strsep(char** pline, const char* delim);
+#endif
+
/** NON-GRAPHIC USAGE
**
** this variable is TRUE if the -no-window argument was used.
@@ -173,23 +185,22 @@ extern char* bufprint_temp_file (char* buffer, char* buffend, const char* s
** a FileLock is useful to prevent several emulator instances from using the same
** writable file (e.g. the userdata.img disk images).
**
- ** create a FileLock object with filelock_create(), note that the function will *not*
- ** return NULL if the file doesn't exist.
- *
- * then call filelock_lock() to try to acquire a lock for the corresponding file.
- ** returns 0 on success, or -1 in case of error, which means that another program
- ** is using the file or that the directory containing the file is read-only.
+ ** create a FileLock object with filelock_create(), the function will return
+ ** NULL only if the corresponding path is already locked by another emulator
+ ** of if the path is read-only.
**
- ** all file locks are automatically released and destroyed when the program exits.
- ** the filelock_lock() function can also detect stale file locks that can linger
- ** when the emulator crashes unexpectedly, and will happily clean them for you
+ ** note that 'path' can designate a non-existing path and that the lock creation
+ ** function can detect stale file locks that can longer when the emulator
+ ** crashes unexpectedly, and will happily clean them for you.
+ **
+ ** you can call filelock_release() to release a file lock explicitely. otherwise
+ ** all file locks are automatically released when the program exits.
**/
typedef struct FileLock FileLock;
-extern FileLock* filelock_create( const char* path );
-extern int filelock_lock( FileLock* lock );
-extern void filelock_unlock( FileLock* lock );
+extern FileLock* filelock_create ( const char* path );
+extern void filelock_release( FileLock* lock );
/** TEMP FILE SUPPORT
**
@@ -317,8 +328,11 @@ extern void print_tabular( const char** strings, int count,
** converts one character into another in strings
**/
-extern void buffer_translate_char( char* buff, unsigned len,
- char from, char to );
+extern void buffer_translate_char( char* buff,
+ unsigned buffLen,
+ const char* src,
+ char fromChar,
+ char toChar );
extern void string_translate_char( char* str, char from, char to );
@@ -354,6 +368,9 @@ extern void stralloc_add_quote_c( stralloc_t* s, int c );
extern void stralloc_add_quote_str( stralloc_t* s, const char* str );
extern void stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len );
+extern void stralloc_add_hex( stralloc_t* s, unsigned value, int num_digits );
+extern void stralloc_add_hexdump( stralloc_t* s, void* base, int size, const char* prefix );
+
extern void stralloc_tabular( stralloc_t* s, const char** strings, int count,
const char* prefix, int width );
@@ -401,4 +418,15 @@ extern void qvector_insert( qvector_t* v, int index, void* item );
extern void qvector_remove( qvector_t* v, int index );
extern void qvector_remove_n( qvector_t* v, int index, int count );
+/** DECIMAL AND HEXADECIMAL CHARACTER SEQUENCES
+ **/
+
+/* decodes a sequence of 'len' hexadecimal chars from 'hex' into
+ * an integer. returns -1 in case of error (i.e. badly formed chars)
+ */
+extern int hex2int( const uint8_t* hex, int len );
+
+/* encodes an integer 'val' into 'len' hexadecimal charaters into 'hex' */
+extern void int2hex( uint8_t* hex, int len, int val );
+
#endif /* _ANDROID_UTILS_H */
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index d18705b..21aae59 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -50,52 +50,48 @@
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
-#define DYN_SYMBOLS \
- DYN_FUNCTION(size_t,snd_pcm_sw_params_sizeof,(void)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
- DYN_FUNCTION(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \
- DYN_FUNCTION(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
- DYN_FUNCTION(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
- DYN_FUNCTION(size_t,snd_pcm_hw_params_sizeof,(void)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
- DYN_FUNCTION(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
- DYN_FUNCTION(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \
- DYN_FUNCTION(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
- DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
- DYN_FUNCTION(int,snd_pcm_drop,(snd_pcm_t *pcm)) \
- DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \
- DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \
- DYN_FUNCTION(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \
- DYN_FUNCTION(const char*,snd_strerror,(int errnum)) \
- DYN_FUNCTION(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
- DYN_FUNCTION(int,snd_pcm_close,(snd_pcm_t *pcm)) \
-
-
-
-/* define pointers to library functions we're going to use */
-#define DYN_FUNCTION(ret,name,sig) \
- static ret (*func_ ## name)sig;
-
-DYN_SYMBOLS
-
-#undef DYN_FUNCTION
-
-#define func_snd_pcm_hw_params_alloca(ptr) \
- do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(func_snd_pcm_hw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_hw_params_sizeof()); } while (0)
-
-#define func_snd_pcm_sw_params_alloca(ptr) \
- do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(func_snd_pcm_sw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_sw_params_sizeof()); } while (0)
+#define DYNLINK_FUNCTIONS \
+ DYNLINK_FUNC(size_t,snd_pcm_sw_params_sizeof,(void)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYNLINK_FUNC(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \
+ DYNLINK_FUNC(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYNLINK_FUNC(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYNLINK_FUNC(size_t,snd_pcm_hw_params_sizeof,(void)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYNLINK_FUNC(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \
+ DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(int,snd_pcm_drop,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \
+ DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \
+ DYNLINK_FUNC(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \
+ DYNLINK_FUNC(const char*,snd_strerror,(int errnum)) \
+ DYNLINK_FUNC(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
+ DYNLINK_FUNC(int,snd_pcm_close,(snd_pcm_t *pcm)) \
+
+#define DYNLINK_FUNCTIONS_INIT \
+ alsa_dynlink_init
+
+#include "dynlink.h"
+
+/* these are inlined functions in the original headers */
+#define FF_snd_pcm_hw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(FF(snd_pcm_hw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_hw_params_sizeof)()); } while (0)
+
+#define FF_snd_pcm_sw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(FF(snd_pcm_sw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_sw_params_sizeof)()); } while (0)
static void* alsa_lib;
@@ -179,7 +175,7 @@ static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
- AUD_log (AUDIO_CAP, "Reason: %s\n", func_snd_strerror (err));
+ AUD_log (AUDIO_CAP, "Reason: %s\n", FF(snd_strerror) (err));
}
static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
@@ -197,12 +193,12 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
- AUD_log (AUDIO_CAP, "Reason: %s\n", func_snd_strerror (err));
+ AUD_log (AUDIO_CAP, "Reason: %s\n", FF(snd_strerror) (err));
}
static void alsa_anal_close (snd_pcm_t **handlep)
{
- int err = func_snd_pcm_close (*handlep);
+ int err = FF(snd_pcm_close) (*handlep);
if (err) {
alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
}
@@ -300,16 +296,16 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
int err;
snd_pcm_sw_params_t *sw_params;
- func_snd_pcm_sw_params_alloca (&sw_params);
+ FF_snd_pcm_sw_params_alloca (&sw_params);
- err = func_snd_pcm_sw_params_current (handle, sw_params);
+ err = FF(snd_pcm_sw_params_current) (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to get current software parameters\n");
return;
}
- err = func_snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
+ err = FF(snd_pcm_sw_params_set_start_threshold) (handle, sw_params, threshold);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software threshold to %ld\n",
@@ -317,7 +313,7 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
return;
}
- err = func_snd_pcm_sw_params (handle, sw_params);
+ err = FF(snd_pcm_sw_params) (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software parameters\n");
@@ -341,9 +337,9 @@ static int alsa_open (int in, struct alsa_params_req *req,
buffer_size = req->buffer_size;
nchannels = req->nchannels;
- func_snd_pcm_hw_params_alloca (&hw_params);
+ FF_snd_pcm_hw_params_alloca (&hw_params);
- err = func_snd_pcm_open (
+ err = FF(snd_pcm_open) (
&handle,
pcm_name,
in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
@@ -354,13 +350,13 @@ static int alsa_open (int in, struct alsa_params_req *req,
return -1;
}
- err = func_snd_pcm_hw_params_any (handle, hw_params);
+ err = FF(snd_pcm_hw_params_any) (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
goto err;
}
- err = func_snd_pcm_hw_params_set_access (
+ err = FF(snd_pcm_hw_params_set_access) (
handle,
hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED
@@ -370,19 +366,19 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- err = func_snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
+ err = FF(snd_pcm_hw_params_set_format) (handle, hw_params, req->fmt);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
goto err;
}
- err = func_snd_pcm_hw_params_set_rate_near (handle, hw_params, (unsigned*)&freq, 0);
+ err = FF(snd_pcm_hw_params_set_rate_near) (handle, hw_params, (unsigned*)&freq, 0);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
goto err;
}
- err = func_snd_pcm_hw_params_set_channels_near (
+ err = FF(snd_pcm_hw_params_set_channels_near) (
handle,
hw_params,
(unsigned*)&nchannels
@@ -410,7 +406,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
if (buffer_size) {
if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
if (period_size) {
- err = func_snd_pcm_hw_params_set_period_time_near (
+ err = FF(snd_pcm_hw_params_set_period_time_near) (
handle,
hw_params,
&period_size,
@@ -424,7 +420,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
- err = func_snd_pcm_hw_params_set_buffer_time_near (
+ err = FF(snd_pcm_hw_params_set_buffer_time_near) (
handle,
hw_params,
&buffer_size,
@@ -446,7 +442,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
minval = period_size;
dir = 0;
- err = func_snd_pcm_hw_params_get_period_size_min (
+ err = FF(snd_pcm_hw_params_get_period_size_min) (
hw_params,
&minval,
&dir
@@ -472,7 +468,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
- err = func_snd_pcm_hw_params_set_period_size (
+ err = FF(snd_pcm_hw_params_set_period_size) (
handle,
hw_params,
period_size,
@@ -486,7 +482,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
minval = buffer_size;
- err = func_snd_pcm_hw_params_get_buffer_size_min (
+ err = FF(snd_pcm_hw_params_get_buffer_size_min) (
hw_params,
&minval
);
@@ -510,7 +506,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
- err = func_snd_pcm_hw_params_set_buffer_size (
+ err = FF(snd_pcm_hw_params_set_buffer_size) (
handle,
hw_params,
buffer_size
@@ -526,19 +522,19 @@ static int alsa_open (int in, struct alsa_params_req *req,
dolog ("warning: Buffer size is not set\n");
}
- err = func_snd_pcm_hw_params (handle, hw_params);
+ err = FF(snd_pcm_hw_params) (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
goto err;
}
- err = func_snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
+ err = FF(snd_pcm_hw_params_get_buffer_size) (hw_params, &obt_buffer_size);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get buffer size\n");
goto err;
}
- err = func_snd_pcm_prepare (handle);
+ err = FF(snd_pcm_prepare) (handle);
if (err < 0) {
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
goto err;
@@ -583,7 +579,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
static int alsa_recover (snd_pcm_t *handle)
{
- int err = func_snd_pcm_prepare (handle);
+ int err = FF(snd_pcm_prepare) (handle);
if (err < 0) {
alsa_logerr (err, "Failed to prepare handle %p\n", handle);
return -1;
@@ -595,11 +591,11 @@ static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
{
snd_pcm_sframes_t avail;
- avail = func_snd_pcm_avail_update (handle);
+ avail = FF(snd_pcm_avail_update) (handle);
if (avail < 0) {
if (avail == -EPIPE) {
if (!alsa_recover (handle)) {
- avail = func_snd_pcm_avail_update (handle);
+ avail = FF(snd_pcm_avail_update) (handle);
}
}
@@ -647,7 +643,7 @@ static int alsa_run_out (HWVoiceOut *hw)
hw->clip (dst, src, len);
while (len) {
- written = func_snd_pcm_writei (alsa->handle, dst, len);
+ written = FF(snd_pcm_writei) (alsa->handle, dst, len);
if (written <= 0) {
switch (written) {
@@ -766,14 +762,14 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
int err;
if (pause) {
- err = func_snd_pcm_drop (handle);
+ err = FF(snd_pcm_drop) (handle);
if (err < 0) {
alsa_logerr (err, "Could not stop %s\n", typ);
return -1;
}
}
else {
- err = func_snd_pcm_prepare (handle);
+ err = FF(snd_pcm_prepare) (handle);
if (err < 0) {
alsa_logerr (err, "Could not prepare handle for %s\n", typ);
return -1;
@@ -897,7 +893,7 @@ static int alsa_run_in (HWVoiceIn *hw)
return 0;
}
- if (!avail && (func_snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
+ if (!avail && (FF(snd_pcm_state) (alsa->handle) == SND_PCM_STATE_PREPARED)) {
avail = hw->samples;
}
@@ -926,7 +922,7 @@ static int alsa_run_in (HWVoiceIn *hw)
dst = hw->conv_buf + bufs[i].add;
while (len) {
- nread = func_snd_pcm_readi (alsa->handle, src, len);
+ nread = FF(snd_pcm_readi) (alsa->handle, src, len);
if (nread <= 0) {
switch (nread) {
@@ -1010,17 +1006,8 @@ static void *alsa_audio_init (void)
goto Exit;
}
-#undef DYN_FUNCTION
-#define DYN_FUNCTION(ret,name,sig) \
- do { \
- (func_ ##name) = dlsym( alsa_lib, STRINGIFY(name) ); \
- if ((func_##name) == NULL) { \
- ldebug("could not find %s in libasound\n", STRINGIFY(name)); \
- goto Fail; \
- } \
- } while (0);
-
- DYN_SYMBOLS
+ if (alsa_dynlink_init(alsa_lib) < 0)
+ goto Fail;
result = &conf;
goto Exit;
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
index 9aeb8a5..636bbaf 100644
--- a/audio/esdaudio.c
+++ b/audio/esdaudio.c
@@ -89,19 +89,16 @@ static struct {
/* link dynamically to the libesd.so */
-#define ESD_SYMBOLS \
- ESD_FUNCTION(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
- ESD_FUNCTION(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
- ESD_FUNCTION(int,esd_open_sound,( const char *host )) \
- ESD_FUNCTION(int,esd_close,(int)) \
+#define DYNLINK_FUNCTIONS \
+ DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
+ DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
+ DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \
+ DYNLINK_FUNC(int,esd_close,(int)) \
-/* define pointers to library functions we're going to use */
-#define ESD_FUNCTION(ret,name,sig) \
- static ret (*func_ ## name)sig;
+#define DYNLINK_FUNCTIONS_INIT \
+ esd_dynlink_init
-ESD_SYMBOLS
-
-#undef ESD_FUNCTION
+#include "dynlink.h"
static void* esd_lib;
@@ -292,10 +289,10 @@ static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
goto exit;
}
- esd->fd = func_esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
+ esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL);
if (esd->fd < 0) {
if (conf.dac_host == NULL) {
- esd->fd = func_esd_play_stream (esdfmt, as->freq, "localhost", NULL);
+ esd->fd = FF(esd_play_stream) (esdfmt, as->freq, "localhost", NULL);
}
if (esd->fd < 0) {
qesd_logerr (errno, "esd_play_stream failed\n");
@@ -513,10 +510,10 @@ static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
goto exit;
}
- esd->fd = func_esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
+ esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL);
if (esd->fd < 0) {
if (conf.adc_host == NULL) {
- esd->fd = func_esd_record_stream (esdfmt, as->freq, "localhost", NULL);
+ esd->fd = FF(esd_record_stream) (esdfmt, as->freq, "localhost", NULL);
}
if (esd->fd < 0) {
qesd_logerr (errno, "esd_record_stream failed\n");
@@ -598,23 +595,14 @@ static void *qesd_audio_init (void)
goto Exit;
}
- #undef ESD_FUNCTION
- #define ESD_FUNCTION(ret,name,sig) \
- do { \
- (func_ ##name) = dlsym( esd_lib, STRINGIFY(name) ); \
- if ((func_##name) == NULL) { \
- D("could not find %s in libesd\n", STRINGIFY(name)); \
- goto Fail; \
- } \
- } while (0);
-
- ESD_SYMBOLS
+ if (esd_dynlink_init(esd_lib) < 0)
+ goto Fail;
- fd = func_esd_open_sound(conf.dac_host);
+ fd = FF(esd_open_sound)(conf.dac_host);
if (fd < 0) {
D("%s: could not open direct sound server connection, trying localhost",
__FUNCTION__);
- fd = func_esd_open_sound("localhost");
+ fd = FF(esd_open_sound)("localhost");
if (fd < 0) {
D("%s: could not open localhost sound server connection", __FUNCTION__);
goto Fail;
@@ -622,7 +610,7 @@ static void *qesd_audio_init (void)
}
D("%s: EsounD server connection succeeded", __FUNCTION__);
- /* func_esd_close(fd); */
+ /* FF(esd_close)(fd); */
}
result = &conf;
goto Exit;
diff --git a/configure b/configure
deleted file mode 100755
index 6a420b4..0000000
--- a/configure
+++ /dev/null
@@ -1,1112 +0,0 @@
-#!/bin/sh
-#
-# qemu configure script (c) 2003 Fabrice Bellard
-#
-# set temporary file name
-if test ! -z "$TMPDIR" ; then
- TMPDIR1="${TMPDIR}"
-elif test ! -z "$TEMPDIR" ; then
- TMPDIR1="${TEMPDIR}"
-else
- TMPDIR1="/tmp"
-fi
-
-TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
-TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
-TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
-TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
-TMPL="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.log"
-
-# default parameters
-prefix=""
-interp_prefix="/usr/gnemul/qemu-%M"
-static="no"
-cross_prefix=""
-cc="gcc"
-host_cc="gcc"
-if [ -n "$CC" ] ; then
- cc="$CC"
-fi
-if [ -n "$HOSTCC" ] ; then
- host_cc="$HOSTCC"
-fi
-ar="ar"
-make="make"
-install="install"
-strip="strip"
-cpu=`uname -m`
-target_list=""
-case "$cpu" in
- i386|i486|i586|i686|i86pc|BePC)
- cpu="i386"
- ;;
- armv*b)
- cpu="armv4b"
- ;;
- armv*l)
- cpu="armv4l"
- ;;
- alpha)
- cpu="alpha"
- ;;
- "Power Macintosh"|ppc|ppc64)
- cpu="powerpc"
- ;;
- mips)
- cpu="mips"
- ;;
- s390)
- cpu="s390"
- ;;
- sparc|sun4[muv])
- cpu="sparc"
- ;;
- sparc64)
- cpu="sparc64"
- ;;
- ia64)
- cpu="ia64"
- ;;
- m68k)
- cpu="m68k"
- ;;
- x86_64|amd64)
- cpu="x86_64"
- # if the kernel release contains mixed64, we have a 64-bit kernel with
- # a 32-bit environment. We should generate i386 binaries then or things
- # will go very wrong
- kernel_mixed=`uname -r | grep mixed64`
- if test ! -z "$kernel_mixed" ; then
- cpu="i386"
- fi
- # another specific case
- kernel_uXen=`uname -r | grep "gg.*-xenU"`
- if test ! -z "$kernel_uXen" ; then
- cpu="i386"
- fi
- ;;
- *)
- cpu="unknown"
- ;;
-esac
-gprof="no"
-bigendian="no"
-mingw32="no"
-EXESUF=""
-gdbstub="yes"
-slirp="yes"
-adlib="no"
-oss="no"
-dsound="no"
-coreaudio="no"
-winaudio="no"
-alsa="no"
-esd="no"
-fmod="no"
-fmod_lib=""
-fmod_inc=""
-bsd="no"
-linux="no"
-kqemu="no"
-profiler="no"
-kernel_path=""
-cocoa="no"
-check_gfx="yes"
-check_gcc="no" # 2006-10-10; digit: no check required anymore
-softmmu="yes"
-user="no"
-build_docs="no"
-build_acpi_tables="no"
-uname_release=""
-shaper="no"
-debug="no"
-android_nand_limits="no"
-
-# OS specific
-targetos=`uname -s`
-case $targetos in
-CYGWIN*)
-mingw32="yes"
-CFLAGS="-O2 -mno-cygwin"
-LDFLAGS="-mno-cygwin -mwindows"
-;;
-MINGW32*)
-mingw32="yes"
-;;
-FreeBSD)
-bsd="yes"
-oss="yes"
-if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
- kqemu="yes"
-fi
-;;
-NetBSD)
-bsd="yes"
-oss="yes"
-;;
-OpenBSD)
-bsd="yes"
-oss="yes"
-;;
-Darwin)
-bsd="yes"
-darwin="yes"
-;;
-SunOS)
-solaris="yes"
-;;
-*)
-linux="yes"
-user="yes"
-if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
- kqemu="yes"
-fi
-;;
-esac
-
-if [ "$bsd" = "yes" ] ; then
- if [ "$darwin" != "yes" ] ; then
- make="gmake"
- fi
-fi
-
-if [ "$solaris" = "yes" ] ; then
- make="gmake"
- install="ginstall"
- solarisrev=`uname -r | cut -f2 -d.`
-fi
-
-# find source path
-source_path=`dirname "$0"`
-if [ -z "$source_path" ]; then
- source_path=`pwd`
-else
- source_path=`cd "$source_path"; pwd`
-fi
-if test "$source_path" = `pwd` ; then
- source_path_used="no"
-else
- source_path_used="yes"
-fi
-
-for opt do
- optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
- case "$opt" in
- --help|-h) show_help=yes
- ;;
- --prefix=*) prefix="$optarg"
- ;;
- --interp-prefix=*) interp_prefix="$optarg"
- ;;
- --source-path=*) source_path="$optarg"
- source_path_used="yes"
- ;;
- --cross-prefix=*) cross_prefix="$optarg"
- ;;
- --cc=*) cc="$optarg"
- ;;
- --debug) debug="yes"
- ;;
- --host-cc=*) host_cc="$optarg"
- ;;
- --make=*) make="$optarg"
- ;;
- --install=*) install="$optarg"
- ;;
- --extra-cflags=*) CFLAGS="$optarg"
- ;;
- --extra-ldflags=*) LDFLAGS="$optarg"
- ;;
- --cpu=*) cpu="$optarg"
- ;;
- --target-list=*) target_list="$optarg"
- ;;
- --enable-gprof) gprof="yes"
- ;;
- --static) static="yes"
- ;;
- --disable-sdl) sdl="no"
- ;;
- --static-sdl) force_static_sdl="yes"
- ;;
- --enable-coreaudio) coreaudio="yes"
- ;;
- --enable-winaudio) winaudio="yes"
- ;;
- --enable-alsa) alsa="yes"
- ;;
- --enable-esd) esd="yes"
- ;;
- --enable-oss) oss="yes"
- ;;
- --enable-dsound) dsound="yes"
- ;;
- --enable-fmod) fmod="yes"
- ;;
- --fmod-lib=*) fmod_lib="$optarg"
- ;;
- --fmod-inc=*) fmod_inc="$optarg"
- ;;
- --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
- ;;
- --disable-slirp) slirp="no"
- ;;
- --enable-adlib) adlib="yes"
- ;;
- --disable-kqemu) kqemu="no"
- ;;
- --enable-profiler) profiler="yes"
- ;;
- --kernel-path=*) kernel_path="$optarg"
- ;;
- --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
- ;;
- --disable-gfx-check) check_gfx="no"
- ;;
- --disable-gcc-check) check_gcc="no"
- ;;
- --disable-system) softmmu="no"
- ;;
- --enable-system) softmmu="yes"
- ;;
- --disable-user) user="no"
- ;;
- --enable-user) user="yes"
- ;;
- --enable-uname-release=*) uname_release="$optarg"
- ;;
- --enable-iasl) build_acpi_tables="yes"
- ;;
-## Added functions for Android ##
- --enable-qfb) qfb="yes"
- ;;
- --enable-trace) trace="yes"
- ;;
- --enable-skins) skins="yes"
- ;;
- --enable-nand) nand="yes"
- ;;
- --enable-shaper) shaper="yes"
- ;;
- --use-sdl-config=*) sdl_config="$optarg"
- ;;
- --enable-nand-limits) android_nand_limits="yes"
- ;;
-#################################
- esac
-done
-
-# Checking for CFLAGS
-if test -z "$CFLAGS"; then
- CFLAGS="-O2"
-fi
-
-if test x"$show_help" = x"yes" ; then
-cat << EOF
-
-Usage: configure [options]
-Options: [defaults in brackets after descriptions]
-
-EOF
-echo "Standard options:"
-echo " --help print this message"
-echo " --prefix=PREFIX install in PREFIX [$prefix]"
-echo " --interp-prefix=PREFIX where to find shared libraries, etc."
-echo " use %M for cpu name [$interp_prefix]"
-echo " --target-list=LIST set target list [$target_list]"
-echo ""
-echo "kqemu kernel acceleration support:"
-echo " --disable-kqemu disable kqemu support"
-echo " --kernel-path=PATH set the kernel path (configure probes it)"
-echo ""
-echo "Advanced options (experts only):"
-echo " --source-path=PATH path of source code [$source_path]"
-echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
-echo " --cc=CC use C compiler CC [$cc]"
-echo " --host-cc=CC use C compiler CC [$host_cc] for dyngen etc."
-echo " --make=MAKE use specified make [$make]"
-echo " --install=INSTALL use specified install [$install]"
-echo " --static enable static build [$static]"
-echo " --enable-cocoa enable COCOA (Mac OS X only)"
-echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
-echo " --enable-adlib enable Adlib emulation"
-echo " --enable-coreaudio enable Coreaudio audio driver"
-echo " --enable-winaudio enable Windows Wave audio driver"
-echo " --enable-alsa enable ALSA audio driver"
-echo " --enable-esd enable ESD audio driver"
-echo " --enable-oss enable OSS audio driver"
-echo " --enable-fmod enable FMOD audio driver"
-echo " --enabled-dsound enable DirectSound audio driver"
-echo " --enable-system enable all system emulation targets"
-echo " --disable-system disable all system emulation targets"
-echo " --enable-user enable all linux usermode emulation targets"
-echo " --disable-user disable all linux usermode emulation targets"
-echo " --fmod-lib path to FMOD library"
-echo " --fmod-inc path to FMOD includes"
-echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
-echo " --enable-iasl compilation of ACPI tables with the IASL compiler"
-## Added functions for Android ##
-echo " --static-sdl force static linking of libSDL"
-echo " --enable-qfb enable QEMU FUSE Bridge support"
-echo " --enable-trace enable ARM trace support"
-echo " --enable-skins enable device skin feature (requires SDL)"
-echo " --enable-nand enable NAND image support"
-echo " --enable-shaper enable network shaping support"
-echo " --use-sdl-config=FILE use a specific sdl-config script"
-echo " --enable-nand-limits enable NAND read/write thresholding support"
-#################################
-echo ""
-echo "NOTE: The object files are build at the place where configure is launched"
-exit 1
-fi
-
-cc="${cross_prefix}${cc}"
-ar="${cross_prefix}${ar}"
-strip="${cross_prefix}${strip}"
-
-# check that the C compiler works.
-cat > $TMPC <<EOF
-int main(void) {}
-EOF
-
-if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
- : C compiler works ok
-else
- echo "ERROR: \"$cc\" either does not exist or does not work"
- exit 1
-fi
-
-if test "$mingw32" = "yes" ; then
- linux="no"
- EXESUF=".exe"
- oss="no"
- TMPE="$TMPE$EXESUF"
- if [ "$cpu" = "i386" ] ; then
- kqemu="yes"
- fi
-fi
-
-#
-# Solaris specific configure tool chain decisions
-#
-if test "$solaris" = "yes" ; then
- #
- # gcc for solaris 10/fcs in /usr/sfw/bin doesn't compile qemu correctly
- # override the check with --disable-gcc-check
- #
- if test "$solarisrev" -eq 10 -a "$check_gcc" = "yes" ; then
- solgcc=`which $cc`
- if test "$solgcc" = "/usr/sfw/bin/gcc" ; then
- echo "Solaris 10/FCS gcc in /usr/sfw/bin will not compiled qemu correctly."
- echo "please get gcc-3.4.3 or later, from www.blastwave.org using pkg-get -i gcc3"
- echo "or get the latest patch from SunSolve for gcc"
- exit 1
- fi
- fi
- solinst=`which $install 2> /dev/null | /usr/bin/grep -v "no $install in"`
- if test -z "$solinst" ; then
- echo "Solaris install program not found. Use --install=/usr/ucb/install or"
- echo "install fileutils from www.blastwave.org using pkg-get -i fileutils"
- echo "to get ginstall which is used by default (which lives in /opt/csw/bin)"
- exit 1
- fi
- if test "$solinst" = "/usr/sbin/install" ; then
- echo "Error: Solaris /usr/sbin/install is not an appropriate install program."
- echo "try ginstall from the GNU fileutils available from www.blastwave.org"
- echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install"
- exit 1
- fi
- sol_ar=`which ar 2> /dev/null | /usr/bin/grep -v "no ar in"`
- if test -z "$sol_ar" ; then
- echo "Error: No path includes ar"
- if test -f /usr/ccs/bin/ar ; then
- echo "Add /usr/ccs/bin to your path and rerun configure"
- fi
- exit 1
- fi
-fi
-
-
-if test -z "$target_list" ; then
-# these targets are portable
- if [ "$softmmu" = "yes" ] ; then
- # x86_64-softmmu has been removed from the default list because it doesn't build on Intel MAC
- # 2006-10-10; digit
- target_list="i386-softmmu ppc-softmmu sparc-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
- fi
-# the following are Linux specific
- if [ "$user" = "yes" ] ; then
- target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
- fi
-else
- target_list=`echo "$target_list" | sed -e 's/,/ /g'`
-fi
-if test -z "$target_list" ; then
- echo "No targets enabled"
- exit 1
-fi
-
-if test -z "$cross_prefix" ; then
-
-# ---
-# big/little endian test
-cat > $TMPC << EOF
-#include <inttypes.h>
-int main(int argc, char ** argv){
- volatile uint32_t i=0x01234567;
- return (*((uint8_t*)(&i))) == 0x67;
-}
-EOF
-
-if $cc -o $TMPE $TMPC 2>/dev/null ; then
-$TMPE && bigendian="yes"
-else
-echo big/little test failed
-fi
-
-else
-
-# if cross compiling, cannot launch a program, so make a static guess
-if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
- bigendian="yes"
-fi
-
-fi
-
-# host long bits test
-hostlongbits="32"
-if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" = "alpha"; then
- hostlongbits="64"
-fi
-
-# check gcc options support
-cat > $TMPC <<EOF
-int main(void) {
-}
-EOF
-
-have_gcc3_options="no"
-if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
- have_gcc3_options="yes"
-fi
-
-# Check for gcc4, error if pre-gcc4
-if test "$check_gcc" = "yes" ; then
- cat > $TMPC <<EOF
-#if __GNUC__ < 4
-#error gcc3
-#endif
-int main(){return 0;}
-EOF
- if $cc -o $TMPO $TMPC 2>/dev/null ; then
- echo "ERROR: \"$cc\" looks like gcc 4.x"
- echo "QEMU is known to have problems when compiled with gcc 4.x"
- echo "It is recommended that you use gcc 3.x to build QEMU"
- echo "To use this compiler anyway, configure with --disable-gcc-check"
- exit 1;
- fi
-fi
-
-# use our own static build of libpng + libz, since their respective configure script
-# make it hard to build these libraries statically on Cygwin/MSYS
-#
-png=no
-png_static=yes
-png_static_libs="\$(SRC_PATH)/libpng.a \$(SRC_PATH)/libz.a"
-png_cflags="\$(ZLIB_CFLAGS) \$(LIBPNG_CFLAGS)"
-
-##########################################
-# SDL probe
-
-sdl_too_old=no
-
-if test -z "$sdl" ; then
- if test -z "$sdl_config" ; then
- sdl_config="sdl-config"
- fi
- sdl=no
- sdl_static=no
- if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
- # win32 cross compilation case
- sdl_config="i386-mingw32msvc-sdl-config"
- sdl=yes
- else
- # normal SDL probe
- cat > $TMPC << EOF
-#include <SDL.h>
-#undef main /* We don't want SDL to override our main() */
-int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
-EOF
- sdl_cflags=`$sdl_config --cflags 2> /dev/null`
- sdl_libs=`$sdl_config --libs 2> /dev/null`
-
- if $cc -o $TMPE $sdl_cflags $TMPC $sdl_libs 2> /dev/null ; then
- _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
- if test "$_sdlversion" -lt 121 ; then
- sdl_too_old=yes
- else
- sdl=yes
- fi
- fi # sdl compile and link test
-
- # static link with sdl ? only test if needed
- aa="no"
- if test "$force_static_sdl" = "yes" -o "$sdl" = "no"; then
- sdl_static_libs=`$sdl_config --static-libs`
- if test -n "$sdl_static_libs"; then
- if $cc -o $TMPE $sdl_cflags $TMPC $sdl_static_libs 2> $TMPL; then
- sdl_static=yes
- else
- echo "Warning: static libSDL link doesn't work."
- if [ "x$linux" == "xyes" ]; then
- echo "Are you missing the libaudio-dev and the libxt-dev libraries?"
- fi
- echo "Correct the errors below and try again"
- cat $TMPL
- fi
- fi
- fi
- fi # cross compilation
-fi # -w "$sdl"
-
-if test "$force_static_sdl" = "yes" ; then
- if test "$sdl_static" = "no"; then
- echo "could not find a usable static version of SDL"
- exit 3
- else
- sdl="no"
- fi
-else
- # favor dynamic linking in the normal case
- if test "$sdl" = "yes"; then
- sdl_static="no"
- fi
-fi
-
-########################################################
-# ALSA probe
-#
-if test "$alsa" = "yes"; then
- alsa_cflags=`pkg-config --cflags alsa 2> /dev/null`
- alsa_libs=`pkg-config --libs alsa 2> /dev/null`
-
- cat > $TMPC << EOF
-#include <alsa/asoundlib.h>
-int main( void ) { snd_pcm_t* handle; return snd_pcm_open( &handle,NULL,0,0); }
-EOF
-
- if $cc -o $TMPE $alsa_cflags $TMPC $alsa_libs 2> $TMPL ; then
- echo "ALSA seems to be usable on this system"
- else
- echo "the ALSA development files do not seem to be installed on this system"
- if [ "x$linux" = "xyes" ] ; then
- echo "Are you missing the libasound-dev package ?"
- fi
- echo "Correct the erros below and try again"
- cat $TMPL
- exit 1
- fi
-fi
-
-########################################################
-# ESD probe
-#
-if test "$esd" = "yes"; then
- esd_cflags=`pkg-config --cflags esound 2> /dev/null`
- esd_libs=`pkg-config --libs esound 2> /dev/null`
-
- cat > $TMPC << EOF
-#include <esd.h>
-int main( void ) { return esd_open_sound(0); }
-EOF
-
- if $cc -o $TMPE $esd_cflags $TMPC $esd_libs 2> $TMPL ; then
- echo "ESD seems to be usable on this system"
- else
- echo "the EsounD development files do not seem to be installed on this system"
- if [ "x$linux" = "xyes" ] ; then
- echo "Are you missing the libesd-dev package ?"
- fi
- echo "Correct the errors below and try again:"
- cat $TMPL
- rm -f $TMPC $TMPO $TMPE $TMPL
- exit 1
- fi
-fi
-
-# Check if tools are available to build documentation.
-if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
- build_docs="yes"
-fi
-
-if test "$mingw32" = "yes" ; then
-if test -z "$prefix" ; then
- prefix="/c/Program Files/Qemu"
-fi
-mandir="$prefix"
-datadir="$prefix"
-docdir="$prefix"
-bindir="$prefix"
-else
-if test -z "$prefix" ; then
- prefix="/usr/local"
-fi
-mandir="$prefix/share/man"
-datadir="$prefix/share/qemu"
-docdir="$prefix/share/doc/qemu"
-bindir="$prefix/bin"
-fi
-
-echo "Install prefix $prefix"
-echo "BIOS directory $datadir"
-echo "binary directory $bindir"
-if test "$mingw32" = "no" ; then
-echo "Manual directory $mandir"
-echo "ELF interp prefix $interp_prefix"
-fi
-echo "Source path $source_path"
-echo "C compiler $cc"
-echo "Host C compiler $host_cc"
-echo "make $make"
-echo "install $install"
-echo "host CPU $cpu"
-echo "host big endian $bigendian"
-echo "target list $target_list"
-echo "gprof enabled $gprof"
-echo "gdb stub $gdbstub"
-echo "profiler $profiler"
-echo "debug build $debug"
-echo "static build $static"
-if test "$darwin" = "yes" ; then
- echo "Cocoa support $cocoa"
-fi
-png_support="$png"
-if test "$png" = "no" -a "$png_static" = "yes" ; then
- png_support="static"
-fi
-echo "PNG support $png_support"
-sdl_support="$sdl"
-if test "$sdl" = "no" -a "$sdl_static" = "yes"; then
- sdl_support="static"
-fi
-echo "SDL support $sdl_support"
-echo "mingw32 support $mingw32"
-echo "Adlib support $adlib"
-echo "CoreAudio support $coreaudio"
-echo "WinAudio support $winaudio"
-echo "ALSA support $alsa"
-echo "ESD support $esd"
-echo "OSS support $oss"
-echo "DSound support $dsound"
-if test "$fmod" = "yes"; then
- if test -z $fmod_lib || test -z $fmod_inc; then
- echo
- echo "Error: You must specify path to FMOD library and headers"
- echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
- echo
- exit 1
- fi
- fmod_support=" (lib='$fmod_lib' include='$fmod_inc')"
-else
- fmod_support=""
-fi
-echo "FMOD support $fmod $fmod_support"
-echo "kqemu support $kqemu"
-echo "Documentation $build_docs"
-[ ! -z "$uname_release" ] && \
-echo "uname -r $uname_release"
-
-if test $sdl_too_old = "yes"; then
-echo "-> Your SDL version is too old - please upgrade to have SDL support"
-fi
-#if test "$sdl_static" = "no"; then
-# echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
-#fi
-config_mak="config-host.mak"
-config_h="config-host.h"
-
-#echo "Creating $config_mak and $config_h"
-
-echo "# Automatically generated by configure - do not modify" > $config_mak
-echo "# Configured with: $0 $@" >> $config_mak
-echo "/* Automatically generated by configure - do not modify */" > $config_h
-
-echo "prefix=$prefix" >> $config_mak
-echo "bindir=$bindir" >> $config_mak
-echo "mandir=$mandir" >> $config_mak
-echo "datadir=$datadir" >> $config_mak
-echo "docdir=$docdir" >> $config_mak
-echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
-echo "MAKE=$make" >> $config_mak
-echo "INSTALL=$install" >> $config_mak
-echo "CC=$cc" >> $config_mak
-if test "$have_gcc3_options" = "yes" ; then
- echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
-fi
-echo "HOST_CC=$host_cc" >> $config_mak
-
-if test "$debug" = "yes"; then
- echo "OPTIM=-O0 -g -fno-strict-aliasing" >> $config_mak
-else
- echo "OPTIM=-O2 -fomit-frame-pointer -fno-strict-aliasing" >> $config_mak
-fi
-
-echo "AR=$ar" >> $config_mak
-echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
-echo "CFLAGS=$CFLAGS" >> $config_mak
-echo "LDFLAGS=$LDFLAGS" >> $config_mak
-echo "EXESUF=$EXESUF" >> $config_mak
-if test "$cpu" = "i386" ; then
- echo "ARCH=i386" >> $config_mak
- echo "#define HOST_I386 1" >> $config_h
-elif test "$cpu" = "x86_64" ; then
- echo "ARCH=x86_64" >> $config_mak
- echo "#define HOST_X86_64 1" >> $config_h
-elif test "$cpu" = "armv4b" ; then
- echo "ARCH=arm" >> $config_mak
- echo "#define HOST_ARM 1" >> $config_h
-elif test "$cpu" = "armv4l" ; then
- echo "ARCH=arm" >> $config_mak
- echo "#define HOST_ARM 1" >> $config_h
-elif test "$cpu" = "powerpc" ; then
- echo "ARCH=ppc" >> $config_mak
- echo "#define HOST_PPC 1" >> $config_h
-elif test "$cpu" = "mips" ; then
- echo "ARCH=mips" >> $config_mak
- echo "#define HOST_MIPS 1" >> $config_h
-elif test "$cpu" = "s390" ; then
- echo "ARCH=s390" >> $config_mak
- echo "#define HOST_S390 1" >> $config_h
-elif test "$cpu" = "alpha" ; then
- echo "ARCH=alpha" >> $config_mak
- echo "#define HOST_ALPHA 1" >> $config_h
-elif test "$cpu" = "sparc" ; then
- echo "ARCH=sparc" >> $config_mak
- echo "#define HOST_SPARC 1" >> $config_h
-elif test "$cpu" = "sparc64" ; then
- echo "ARCH=sparc64" >> $config_mak
- echo "#define HOST_SPARC64 1" >> $config_h
-elif test "$cpu" = "ia64" ; then
- echo "ARCH=ia64" >> $config_mak
- echo "#define HOST_IA64 1" >> $config_h
-elif test "$cpu" = "m68k" ; then
- echo "ARCH=m68k" >> $config_mak
- echo "#define HOST_M68K 1" >> $config_h
-else
- echo "Unsupported CPU"
- exit 1
-fi
-if test "$bigendian" = "yes" ; then
- echo "WORDS_BIGENDIAN=yes" >> $config_mak
- echo "#define WORDS_BIGENDIAN 1" >> $config_h
-fi
-echo "#define HOST_LONG_BITS $hostlongbits" >> $config_h
-if test "$mingw32" = "yes" ; then
- echo "CONFIG_WIN32=yes" >> $config_mak
- echo "#define CONFIG_WIN32 1" >> $config_h
-elif test -f "/usr/include/byteswap.h" ; then
- echo "#define HAVE_BYTESWAP_H 1" >> $config_h
-fi
-if test "$darwin" = "yes" ; then
- echo "CONFIG_DARWIN=yes" >> $config_mak
- echo "#define CONFIG_DARWIN 1" >> $config_h
-fi
-if test "$solaris" = "yes" ; then
- echo "CONFIG_SOLARIS=yes" >> $config_mak
- echo "#define HOST_SOLARIS $solarisrev" >> $config_h
-fi
-if test "$gdbstub" = "yes" ; then
- echo "CONFIG_GDBSTUB=yes" >> $config_mak
- echo "#define CONFIG_GDBSTUB 1" >> $config_h
-fi
-if test "$gprof" = "yes" ; then
- echo "TARGET_GPROF=yes" >> $config_mak
- echo "#define HAVE_GPROF 1" >> $config_h
-fi
-if test "$static" = "yes" ; then
- echo "CONFIG_STATIC=yes" >> $config_mak
- echo "#define CONFIG_STATIC 1" >> $config_h
-fi
-if test $profiler = "yes" ; then
- echo "#define CONFIG_PROFILER 1" >> $config_h
-fi
-if test "$slirp" = "yes" ; then
- echo "CONFIG_SLIRP=yes" >> $config_mak
- echo "#define CONFIG_SLIRP 1" >> $config_h
-fi
-if test "$adlib" = "yes" ; then
- echo "CONFIG_ADLIB=yes" >> $config_mak
- echo "#define CONFIG_ADLIB 1" >> $config_h
-fi
-if test "$oss" = "yes" ; then
- echo "CONFIG_OSS=yes" >> $config_mak
- echo "#define CONFIG_OSS 1" >> $config_h
-fi
-if test "$coreaudio" = "yes" ; then
- echo "CONFIG_COREAUDIO=yes" >> $config_mak
- echo "#define CONFIG_COREAUDIO 1" >> $config_h
-fi
-if test "$winaudio" = "yes" ; then
- echo "CONFIG_WINAUDIO=yes" >> $config_mak
- echo "#define CONFIG_WINAUDIO 1" >> $config_h
-fi
-if test "$alsa" = "yes" ; then
- echo "CONFIG_ALSA=yes" >> $config_mak
- echo "CONFIG_ALSA_INC=$alsa_cflags" >> $config_mak
- echo "CONFIG_ALSA_LIB=$alsa_libs" >> $config_mak
- echo "#define CONFIG_ALSA 1" >> $config_h
-fi
-if test "$esd" = "yes" ; then
- echo "CONFIG_ESD=yes" >> $config_mak
- echo "CONFIG_ESD_INC=$esd_cflags" >> $config_mak
- echo "CONFIG_ESD_LIB=$esd_libs" >> $config_mak
- echo "#define CONFIG_ESD 1" >> $config_h
-fi
-if test "$dsound" = "yes" ; then
- echo "CONFIG_DSOUND=yes" >> $config_mak
- echo "#define CONFIG_DSOUND 1" >> $config_h
-fi
-if test "$fmod" = "yes" ; then
- echo "CONFIG_FMOD=yes" >> $config_mak
- echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
- echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
- echo "#define CONFIG_FMOD 1" >> $config_h
-fi
-qemu_version=`head $source_path/VERSION`
-echo "VERSION=$qemu_version" >>$config_mak
-echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
-
-echo "SRC_PATH=$source_path" >> $config_mak
-if [ "$source_path_used" = "yes" ]; then
- echo "VPATH=$source_path" >> $config_mak
-fi
-echo "TARGET_DIRS=$target_list" >> $config_mak
-if [ "$build_docs" = "yes" ] ; then
- echo "BUILD_DOCS=yes" >> $config_mak
-fi
-if [ "$build_acpi_tables" = "yes" ] ; then
- echo "BUILD_ACPI_TABLES=yes" >> $config_mak
-fi
-
-# XXX: suppress that
-if [ "$bsd" = "yes" ] ; then
- echo "#define O_LARGEFILE 0" >> $config_h
- echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
- echo "#define _BSD 1" >> $config_h
-fi
-
-if test "$skins" = "yes" ; then
- echo "CONFIG_SKINS=yes" >> $config_mak
- echo "#define CONFIG_SKINS 1" >> $config_h
-fi
-
-echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
-
-for target in $target_list; do
-target_dir="$target"
-config_mak=$target_dir/config.mak
-config_h=$target_dir/config.h
-target_cpu=`echo $target | cut -d '-' -f 1`
-target_bigendian="no"
-[ "$target_cpu" = "armeb" ] && target_bigendian=yes
-[ "$target_cpu" = "sparc" ] && target_bigendian=yes
-[ "$target_cpu" = "sparc64" ] && target_bigendian=yes
-[ "$target_cpu" = "ppc" ] && target_bigendian=yes
-[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
-[ "$target_cpu" = "mips" ] && target_bigendian=yes
-[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
-target_softmmu="no"
-if expr $target : '.*-softmmu' > /dev/null ; then
- target_softmmu="yes"
-fi
-target_user_only="no"
-if expr $target : '.*-user' > /dev/null ; then
- target_user_only="yes"
-fi
-
-if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
- -a "$sdl" = "no" -a "$sdl_static" = "no" -a "$cocoa" = "no" ; then
- echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
- echo "To build QEMU without graphical output configure with --disable-gfx-check"
- echo "Note that this will disable all output from the virtual graphics card."
- exit 1;
-fi
-
-#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
-
-mkdir -p $target_dir
-mkdir -p $target_dir/fpu
-if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
- mkdir -p $target_dir/nwfpe
-fi
-if test "$target_user_only" = "no" ; then
- mkdir -p $target_dir/slirp
-fi
-
-#
-# don't use ln -sf as not all "ln -sf" over write the file/link
-#
-rm -f $target_dir/Makefile
-ln -s $source_path/Makefile.target $target_dir/Makefile
-
-
-echo "# Automatically generated by configure - do not modify" > $config_mak
-echo "/* Automatically generated by configure - do not modify */" > $config_h
-
-
-echo "include ../config-host.mak" >> $config_mak
-echo "#include \"../config-host.h\"" >> $config_h
-
-bflt="no"
-interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
-echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
-
-if test "$target_cpu" = "i386" ; then
- echo "TARGET_ARCH=i386" >> $config_mak
- echo "#define TARGET_ARCH \"i386\"" >> $config_h
- echo "#define TARGET_I386 1" >> $config_h
- if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "i386" ; then
- echo "#define USE_KQEMU 1" >> $config_h
- fi
-elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
- echo "TARGET_ARCH=arm" >> $config_mak
- echo "#define TARGET_ARCH \"arm\"" >> $config_h
- echo "#define TARGET_ARM 1" >> $config_h
- bflt="yes"
-## Added functions for Android ##
- if test "$qfb" = "yes" ; then
- echo "CONFIG_QFB=yes" >> $config_mak
- echo "#define CONFIG_QFB 1" >> $config_h
- fi
- if test "$trace" = "yes" ; then
- echo "CONFIG_TRACE=yes" >> $config_mak
- echo "#define CONFIG_TRACE 1" >> $config_h
- fi
- if test "$nand" = "yes" ; then
- echo "CONFIG_NAND=yes" >> $config_mak
- echo "#define CONFIG_NAND 1" >> $config_h
- fi
- if test "$shaper" = "yes"; then
- echo "CONFIG_SHAPER=yes" >> $config_mak
- echo "#define CONFIG_SHAPER 1" >> $config_h
- fi
-#################################
-elif test "$target_cpu" = "sparc" ; then
- echo "TARGET_ARCH=sparc" >> $config_mak
- echo "#define TARGET_ARCH \"sparc\"" >> $config_h
- echo "#define TARGET_SPARC 1" >> $config_h
-elif test "$target_cpu" = "sparc64" ; then
- echo "TARGET_ARCH=sparc64" >> $config_mak
- echo "#define TARGET_ARCH \"sparc64\"" >> $config_h
- echo "#define TARGET_SPARC 1" >> $config_h
- echo "#define TARGET_SPARC64 1" >> $config_h
-elif test "$target_cpu" = "ppc" ; then
- echo "TARGET_ARCH=ppc" >> $config_mak
- echo "#define TARGET_ARCH \"ppc\"" >> $config_h
- echo "#define TARGET_PPC 1" >> $config_h
-elif test "$target_cpu" = "ppc64" ; then
- echo "TARGET_ARCH=ppc64" >> $config_mak
- echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
- echo "#define TARGET_PPC 1" >> $config_h
- echo "#define TARGET_PPC64 1" >> $config_h
-elif test "$target_cpu" = "x86_64" ; then
- echo "TARGET_ARCH=x86_64" >> $config_mak
- echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
- echo "#define TARGET_I386 1" >> $config_h
- echo "#define TARGET_X86_64 1" >> $config_h
- if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then
- echo "#define USE_KQEMU 1" >> $config_h
- fi
-elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then
- echo "TARGET_ARCH=mips" >> $config_mak
- echo "#define TARGET_ARCH \"mips\"" >> $config_h
- echo "#define TARGET_MIPS 1" >> $config_h
- echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
- echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
-elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
- echo "TARGET_ARCH=sh4" >> $config_mak
- echo "#define TARGET_ARCH \"sh4\"" >> $config_h
- echo "#define TARGET_SH4 1" >> $config_h
- bflt="yes"
-else
- echo "Unsupported target CPU"
- exit 1
-fi
-if test "$target_bigendian" = "yes" ; then
- echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak
- echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h
-fi
-if test "$target_softmmu" = "yes" ; then
- echo "CONFIG_SOFTMMU=yes" >> $config_mak
- echo "#define CONFIG_SOFTMMU 1" >> $config_h
-fi
-if test "$target_user_only" = "yes" ; then
- echo "CONFIG_USER_ONLY=yes" >> $config_mak
- echo "#define CONFIG_USER_ONLY 1" >> $config_h
-fi
-
-if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then
- echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
- echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
-fi
-if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
- echo "TARGET_HAS_BFLT=yes" >> $config_mak
- echo "#define TARGET_HAS_BFLT 1" >> $config_h
-fi
-# sdl defines
-
-if test "$target_user_only" = "no"; then
- if test "$sdl" = "yes" -o "$sdl_static" = "yes" ; then
- echo "#define CONFIG_SDL 1" >> $config_h
- echo "CONFIG_SDL=yes" >> $config_mak
- if test "$sdl_static" = "yes"; then
- echo "SDL_LIBS=$sdl_static_libs" >> $config_mak
- else
- echo "SDL_LIBS=$sdl_libs" >> $config_mak
- fi
- if [ "${aa}" = "yes" ] ; then
- echo "SDL_CFLAGS=$sdl_cflags `aalib-config --cflags`" >> $config_mak
- else
- echo "SDL_CFLAGS=$sdl_cflags" >> $config_mak
- fi
- fi
-fi
-
-# png defines
-if test "$png" = "yes" -o "$png_static" = "yes" ; then
- if test "$target_softmmu" = "yes" -o "$static" = "yes"; then
- echo "PNG_CFLAGS=$png_cflags" >> $config_mak
- if test "$png_static" = "yes"; then
- echo "PNG_LIBS=$png_static_libs" >> $config_mak
- else
- echo "PNG_LIBS=$png_libs" >> $config_mak
- fi
- fi
-fi
-
-if test "$cocoa" = "yes" ; then
- echo "#define CONFIG_COCOA 1" >> $config_h
- echo "CONFIG_COCOA=yes" >> $config_mak
-fi
-
-done # for target in $targets
-
-# build tree in object directory if source path is different from current one
-if test "$source_path_used" = "yes" ; then
- DIRS="tests"
- FILES="Makefile tests/Makefile"
- for dir in $DIRS ; do
- mkdir -p $dir
- done
- # remove the link and recreate it, as not all "ln -sf" overwrite the link
- for f in $FILES ; do
- rm -f $f
- ln -s $source_path/$f $f
- done
-fi
-
-if test "$android_nand_limits" = "yes"; then
- echo "#define CONFIG_NAND_LIMITS 1" >> $config_h
-fi
-
-rm -f $TMPO $TMPC $TMPE $TMPS
diff --git a/distrib/make-distrib.sh b/distrib/make-distrib.sh
index 537bc2c..f53d766 100755
--- a/distrib/make-distrib.sh
+++ b/distrib/make-distrib.sh
@@ -97,8 +97,6 @@ QEMUDIR=$TMPDIR/qemu
copy_source_files $QEMUDIR $QEMUROOT $QEMUVIEW
echo "copying control scripts"
-cp -f $QEMUDIR/Makefile.qemu $QEMUDIR/Makefile
-rm -f $QEMUDIR/Makefile.android
cp $QEMUDIR/distrib/build-emulator.sh $TMPDIR/build-emulator.sh
cp $QEMUDIR/distrib/README $TMPDIR/README
diff --git a/dynlink.h b/dynlink.h
new file mode 100644
index 0000000..c52dae7
--- /dev/null
+++ b/dynlink.h
@@ -0,0 +1,107 @@
+/* Copyright (c) 2008 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Lazy Dynamic Linking Support
+ *
+ * This header file is meant to be included multiple times.
+ *
+ * It is used to define function pointers to symbols in external
+ * shared objects (Unix dynamic libraries) which will be lazily resolved
+ * at runtime, by calling a specific initialization function.
+ *
+ * You must define, before including this header, a DYNLINK_FUNCTIONS
+ * macro which must contain a sequence of DYNLINK_FUNC(ret,name,sig)
+ * statements.
+ *
+ * In each statement, 'ret' is a function return type, 'name' is
+ * the function's name as provided by the library, and 'sig' is
+ * the function signature, including enclosing parentheses.
+ *
+ * Here's an example:
+ *
+ * #define DYNLINK_FUNCTIONS \
+ * DYNLINK_FUNC(int,open,(const char*, int)) \
+ * DYNLINK_FUNC(int,read,(int,char*,int)) \
+ * DYNLINK_FUNC(int,close,(int)) \
+ *
+ *
+ * You must also define a DYNLINK_FUNCTIONS_INIT macro which contains the
+ * name of a generated function used to initialize the function pointers.
+ * (see below)
+ */
+
+#ifndef DYNLINK_FUNCTIONS
+#error DYNLINK_FUNCTIONS should be defined when including this file
+#endif
+
+#ifndef DYNLINK_FUNCTIONS_INIT
+#error DYNLINK_FUNCTIONS_INIT should be defined when including this file
+#endif
+
+/* just in case */
+#undef DYNLINK_FUNC
+
+/* define pointers to dynamic library functions as static pointers.
+ */
+#define DYNLINK_FUNC(ret,name,sig) \
+ static ret (*_dynlink_##name) sig ;
+
+DYNLINK_FUNCTIONS
+#undef DYNLINK_FUNC
+
+/* now define a function that tries to load all dynlink function
+ * pointers. returns 0 on success, or -1 on error (i.e. if any of
+ * the functions could not be loaded).
+ *
+ * 'library' must be the result of a succesful dlopen() call
+ *
+ * You must define DYNLINK_FUNCTIONS_INIT
+ */
+static int
+DYNLINK_FUNCTIONS_INIT(void* library)
+{
+#define DYNLINK_FUNC(ret,name,sig) \
+ do { \
+ _dynlink_##name = dlsym( library, STRINGIFY(name) ); \
+ if (_dynlink_##name == NULL) goto Fail; \
+ } while (0);
+
+ DYNLINK_FUNCTIONS
+#undef DYNLINK_FUNC
+
+ return 0;
+Fail:
+ return -1;
+}
+
+/* in user code, use FF(function_name) to invoke the
+ * corresponding dynamic function named 'function_name'
+ * after initialization succeeded.
+ */
+#ifndef FF
+#define FF(name) (*_dynlink_##name)
+#endif
+
+/* clear macros */
+#undef DYNLINK_FUNC
+#undef DYNLINK_FUNCTIONS
+#undef DYNLINK_FUNCTIONS_INIT
diff --git a/framebuffer.c b/framebuffer.c
index e7c955f..04177e0 100644
--- a/framebuffer.c
+++ b/framebuffer.c
@@ -133,7 +133,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff,
}
void
-qframebuffer_add_producer( QFrameBuffer* qfbuff,
+qframebuffer_set_producer( QFrameBuffer* qfbuff,
void* opaque,
QFrameBufferCheckUpdateFunc pr_check,
QFrameBufferInvalidateFunc pr_invalidate,
diff --git a/framebuffer.h b/framebuffer.h
index 46f9156..1dce0d9 100644
--- a/framebuffer.h
+++ b/framebuffer.h
@@ -12,18 +12,27 @@
#ifndef _QEMU_FRAMEBUFFER_H_
#define _QEMU_FRAMEBUFFER_H_
-/* a simple interface to a framebuffer display. this is to be used by the hardware framebuffer
- * driver (e.g. hw/goldfish_fb.c) to send VRAM updates to the emulator.
+/* A simple abstract interface to framebuffer displays. this is used to
+ * de-couple hardware emulation from final display.
*
- * note the 'rotation' field: it can take values 0, 1, 2 or 3 and corresponds to a rotation
- * that must be performed to the pixels stored in the framebuffer *before* displaying them
- * a value of 1 corresponds to a rotation of 90 clockwise-degrees, when the framebuffer is
- * rotated 90 or 270 degrees, its width/height are swapped automatically
+ * Each QFrameBuffer object holds a pixel buffer that is shared between
+ * one 'Producer' and one or more 'Clients'
*
- * phys_width_mm and phys_height_mm are physical dimensions expressed in millimeters
+ * The Producer is in charge of updating the pixel buffer from the state
+ * of the emulated VRAM. A Client listens to updates to the pixel buffer,
+ * sent from the producer through qframebuffer_update()/_rotate() and
+ * displays them.
*
- * each QFrameBuffer can have one "client" that reacts to VRAM updates or the framebuffer
- * rotations requested by the system.
+ * note the 'rotation' field: it can take values 0, 1, 2 or 3 and corresponds
+ * to a rotation that must be performed to the pixels stored in the framebuffer
+ * *before* displaying them a value of 1 corresponds to a rotation of
+ * 90 clockwise-degrees, when the framebuffer is rotated 90 or 270 degrees,
+ * its width/height are swapped automatically
+ *
+ * phys_width_mm and phys_height_mm are physical dimensions expressed
+ * in millimeters
+ *
+ * More about the client/producer relationships below.
*/
typedef struct QFrameBuffer QFrameBuffer;
@@ -50,8 +59,9 @@ struct QFrameBuffer {
};
-/* the default dpi resolution of a typical framebuffer. this is an average between
- * various prototypes being used during the development of the Android system...
+/* the default dpi resolution of a typical framebuffer. this is an average
+ * between various prototypes being used during the development of the
+ * Android system...
*/
#define DEFAULT_FRAMEBUFFER_DPI 165
@@ -66,25 +76,46 @@ qframebuffer_init( QFrameBuffer* qfbuff,
int rotation,
QFrameBufferFormat format );
-/* recompute phys_width_mm and phys_height_mm according to the emulated screen DPI settings */
+/* recompute phys_width_mm and phys_height_mm according to the emulated
+ * screen DPI settings */
extern void
qframebuffer_set_dpi( QFrameBuffer* qfbuff,
int x_dpi,
int y_dpi );
-/* alternative to qframebuffer_set_dpi where one can set the physical dimensions directly */
-/* in millimeters. for the record 1 inch = 25.4 mm */
+/* alternative to qframebuffer_set_dpi where one can set the physical
+ * dimensions directly in millimeters. for the record 1 inch = 25.4 mm */
extern void
qframebuffer_set_mm( QFrameBuffer* qfbuff,
int width_mm,
int height_mm );
-/* add one client to a given framebuffer */
-/* client functions */
-typedef void (*QFrameBufferUpdateFunc)( void* opaque, int x, int y, int w, int h );
+/* the Client::Update method is called to instruct a client that a given
+ * rectangle of the framebuffer pixels was updated and needs to be
+ * redrawn.
+ */
+typedef void (*QFrameBufferUpdateFunc)( void* opaque, int x, int y,
+ int w, int h );
+
+/* the Client::Rotate method is called to instruct the client that a
+ * framebuffer's internal rotation has changed. This is the rotation
+ * that must be applied before displaying the pixels.
+ *
+ * Note that it is assumed that all framebuffer pixels have changed too
+ * so the client should call its Update method as well.
+ */
typedef void (*QFrameBufferRotateFunc)( void* opaque, int rotation );
+
+/* the Client::Done func tells a client that a framebuffer object was freed.
+ * no more reference to its pixels should be done.
+ */
typedef void (*QFrameBufferDoneFunc) ( void* opaque );
+/* add one client to a given framebuffer.
+ * the current implementation only allows one client per frame-buffer,
+ * but we could allow more for various reasons (e.g. displaying the
+ * framebuffer + dispatching it through VNC at the same time)
+ */
extern void
qframebuffer_add_client( QFrameBuffer* qfbuff,
void* fb_opaque,
@@ -92,58 +123,83 @@ qframebuffer_add_client( QFrameBuffer* qfbuff,
QFrameBufferRotateFunc fb_rotate,
QFrameBufferDoneFunc fb_done );
-/* add one producer to a given framebuffer */
-/* producer functions */
+/* Producer::CheckUpdate is called to let the producer check the
+ * VRAM state (e.g. VRAM dirty pages) to see if anything changed since the
+ * last call to the method. When true, the method should call either
+ * qframebuffer_update() or qframebuffer_rotate() with the appropriate values.
+ */
typedef void (*QFrameBufferCheckUpdateFunc)( void* opaque );
+
+/* Producer::Invalidate tells the producer that the next call to
+ * CheckUpdate should act as if the whole content of VRAM had changed.
+ * this is normally done to force client initialization/refreshes.
+ */
typedef void (*QFrameBufferInvalidateFunc) ( void* opaque );
+
+/* the Producer::Detach method is used to tell the producer that the
+ * underlying QFrameBuffer object is about to be de-allocated.
+ */
typedef void (*QFrameBufferDetachFunc) ( void* opaque );
+/* set the producer of a given framebuffer */
extern void
-qframebuffer_add_producer( QFrameBuffer* qfbuff,
+qframebuffer_set_producer( QFrameBuffer* qfbuff,
void* opaque,
QFrameBufferCheckUpdateFunc fb_check,
QFrameBufferInvalidateFunc fb_invalidate,
QFrameBufferDetachFunc fb_detach );
-/* tell a client that a rectangle region has been updated in the framebuffer pixel buffer */
+/* tell a client that a rectangle region has been updated in the framebuffer
+ * pixel buffer this is typically called from a Producer::CheckUpdate method
+ */
extern void
qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h );
-/* rotate the framebuffer (may swap width/height), and tell a client that we did */
+/* rotate the framebuffer (may swap width/height), and tell all clients.
+ * Should be called from a Producer::CheckUpdate method
+ */
extern void
qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation );
-/* finalize a framebuffer, release its pixel buffer */
+/* finalize a framebuffer, release its pixel buffer. Should be called
+ * from the framebuffer object's owner
+ */
extern void
qframebuffer_done( QFrameBuffer* qfbuff );
+/* this is called repeatedly by the emulator. for each registered framebuffer,
+ * call its producer's CheckUpdate method, if any.
+ */
+extern void
+qframebuffer_check_updates( void );
+
+/* this is called by the emulator. for each registered framebuffer, call
+ * its producer's Invalidate method, if any
+ */
+extern void
+qframebuffer_invalidate_all( void );
+
/*
- * QFrameBuffer objects are created by the emulated system, its characteristics typically
- * depend on the current device skin being used.
+ * to completely separate the implementation of clients, producers, and skins,
+ * we use a simple global FIFO list of QFrameBuffer objects.
*
- * there are also used by emulated framebuffer devices, who don't know much about all this
+ * qframebuffer_fifo_add() is typically called by the emulator initialization
+ * depending on the emulated device's configuration
*
- * use a simple fifo to bridge these together
+ * qframebuffer_fifo_get() is typically called by a hardware framebuffer
+ * emulation.
*/
/* add a new constructed frame buffer object to our global list */
extern void
qframebuffer_fifo_add( QFrameBuffer* qfbuff );
+/* retrieve a frame buffer object from the global FIFO list */
extern QFrameBuffer*
qframebuffer_fifo_get( void );
-/*
- * check all registered framebuffers for updates. tgus wukk cakk tge ckuebt's update
- * functions in the end...
- */
-
-extern void
-qframebuffer_check_updates( void );
-
-extern void
-qframebuffer_invalidate_all( void );
+/* */
#endif /* _QEMU_FRAMEBUFFER_H_ */
diff --git a/hw/android_arm.c b/hw/android_arm.c
index 7b1d446..3455054 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -12,6 +12,7 @@
#include "vl.h"
#include "arm_pic.h"
#include "goldfish_device.h"
+#include "android/globals.h"
int android_audio_enabled;
char* audio_input_source = NULL;
@@ -112,7 +113,8 @@ static void android_arm_init(int ram_size, int vga_ram_size,
goldfish_memlog_init(0xff006000);
- goldfish_battery_init();
+ if (android_hw->hw_battery)
+ goldfish_battery_init();
goldfish_add_device_no_io(&event0_device);
events_dev_init(event0_device.base, goldfish_pic[event0_device.irq]);
@@ -146,4 +148,5 @@ QEMUMachine android_arm_machine = {
"android_arm",
"ARM Android Emulator",
android_arm_init,
+ NULL
};
diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c
index 69b2ef4..3472d73 100644
--- a/hw/goldfish_audio.c
+++ b/hw/goldfish_audio.c
@@ -13,6 +13,7 @@
#include "goldfish_device.h"
#include "audio/audio.h"
#include "android_debug.h"
+#include "android/globals.h"
#define DEBUG 1
@@ -157,8 +158,11 @@ static int audio_state_load( QEMUFile* f, void* opaque, int version_id )
static void enable_audio(struct goldfish_audio_state *s, int enable)
{
// enable or disable the output voice
- AUD_set_active_out(s->voice, (enable & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)) != 0);
- AUD_set_active_in (s->voicein, (enable & AUDIO_INT_READ_BUFFER_FULL) != 0);
+ if (s->voice != NULL)
+ AUD_set_active_out(s->voice, (enable & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)) != 0);
+
+ if (s->voicein)
+ AUD_set_active_in (s->voicein, (enable & AUDIO_INT_READ_BUFFER_FULL) != 0);
// reset buffer information
s->data_1_length = 0;
s->data_2_length = 0;
@@ -456,6 +460,10 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source)
struct goldfish_audio_state *s;
audsettings_t as;
+ /* nothing to do if no audio input and output */
+ if (!android_hw->hw_audioOutput && !android_hw->hw_audioInput)
+ return;
+
s = (struct goldfish_audio_state *)qemu_mallocz(sizeof(*s));
s->dev.name = "goldfish_audio";
s->dev.id = id;
@@ -481,17 +489,19 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source)
as.fmt = AUD_FMT_S16;
as.endianness = AUDIO_HOST_ENDIANNESS;
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "goldfish_audio",
- s,
- goldfish_audio_callback,
- &as
- );
- if (!s->voice) {
- dprint("warning: opening audio output failed\n");
- return;
+ if (android_hw->hw_audioOutput) {
+ s->voice = AUD_open_out (
+ &s->card,
+ s->voice,
+ "goldfish_audio",
+ s,
+ goldfish_audio_callback,
+ &as
+ );
+ if (!s->voice) {
+ dprint("warning: opening audio output failed\n");
+ return;
+ }
}
#if USE_QEMU_AUDIO_IN
@@ -500,16 +510,18 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source)
as.fmt = AUD_FMT_S16;
as.endianness = AUDIO_HOST_ENDIANNESS;
- s->voicein = AUD_open_in (
- &s->card,
- NULL,
- "goldfish_audio_in",
- s,
- goldfish_audio_in_callback,
- &as
- );
- if (!s->voicein) {
- dprint("warning: opening audio input failed\n");
+ if (android_hw->hw_audioInput) {
+ s->voicein = AUD_open_in (
+ &s->card,
+ NULL,
+ "goldfish_audio_in",
+ s,
+ goldfish_audio_in_callback,
+ &as
+ );
+ if (!s->voicein) {
+ dprint("warning: opening audio input failed\n");
+ }
}
#endif
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
index 0924735..db3e25b 100644
--- a/hw/goldfish_fb.c
+++ b/hw/goldfish_fb.c
@@ -392,7 +392,7 @@ void goldfish_fb_init(DisplayState *ds, int id)
s->dev.irq_count = 1;
s->qfbuff = qframebuffer_fifo_get();
- qframebuffer_add_producer( s->qfbuff, s,
+ qframebuffer_set_producer( s->qfbuff, s,
goldfish_fb_update_display,
goldfish_fb_invalidate_display,
goldfish_fb_detach_display );
diff --git a/osdep.h b/osdep.h
index 68d87bf..195fd1c 100644
--- a/osdep.h
+++ b/osdep.h
@@ -3,6 +3,7 @@
#include <stdarg.h>
#include <setjmp.h>
+#include <stddef.h>
#include "config.h"
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args);
diff --git a/proxy/proxy_common.c b/proxy/proxy_common.c
index c5762dc..0e45481 100644
--- a/proxy/proxy_common.c
+++ b/proxy/proxy_common.c
@@ -26,6 +26,7 @@ proxy_LOG(const char* fmt, ...)
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
+ fprintf(stderr, "\n");
}
void
@@ -39,49 +40,39 @@ proxy_set_verbose(int mode)
static ProxyConnection s_connections[1];
+#define MAX_HEX_DUMP 512
+
static void
hex_dump( void* base, int size, const char* prefix )
{
- uint8_t* p = (uint8_t*)base;
- const int max_count = 16;
-
- while (size > 0) {
- int count = size > max_count ? max_count : size;
- int n;
- const char* space = prefix;
-
- for (n = 0; n < count; n++) {
- proxy_LOG( "%s%02x", space, p[n] );
- space = " ";
- }
-
- proxy_LOG( "%-*s", 4 + 3*(max_count-n), "" );
-
- for (n = 0; n < count; n++) {
- int c = p[n];
-
- if (c < 32 || c > 127)
- c = '.';
- proxy_LOG( "%c", c );
- }
- proxy_LOG( "\n" );
- size -= count;
- p += count;
- }
+ STRALLOC_DEFINE(s);
+ if (size > MAX_HEX_DUMP)
+ size = MAX_HEX_DUMP;
+ stralloc_add_hexdump(s, base, size, prefix);
+ proxy_LOG( "%s", stralloc_cstr(s) );
+ stralloc_reset(s);
}
-
void
-proxy_connection_init( ProxyConnection* conn,
- int socket,
- struct sockaddr_in* address,
- ProxyService* service )
+proxy_connection_init( ProxyConnection* conn,
+ int socket,
+ struct sockaddr_in* address,
+ ProxyService* service,
+ ProxyConnectionFreeFunc conn_free,
+ ProxyConnectionSelectFunc conn_select,
+ ProxyConnectionPollFunc conn_poll )
{
conn->socket = socket;
conn->address = address[0];
conn->service = service;
conn->next = NULL;
+ conn->conn_free = conn_free;
+ conn->conn_select = conn_select;
+ conn->conn_poll = conn_poll;
+
+ socket_set_nonblock(socket);
+
{
uint32_t ip = ntohl(address->sin_addr.s_addr);
uint16_t port = ntohs(address->sin_port);
@@ -98,122 +89,154 @@ proxy_connection_init( ProxyConnection* conn,
conn->name[sizeof(conn->name)-1] = 0;
}
- conn->buffer_pos = 0;
- conn->buffer_len = 0;
- conn->buffer = conn->buffer0;
+ stralloc_reset(conn->str);
+ conn->str_pos = 0;
}
void
proxy_connection_done( ProxyConnection* conn )
{
- if (conn->buffer != conn->buffer0) {
- qemu_free(conn->buffer);
+ stralloc_reset( conn->str );
+ if (conn->socket >= 0) {
+ socket_close(conn->socket);
+ conn->socket = -1;
}
}
-int
-proxy_connection_send( ProxyConnection* conn )
+void
+proxy_connection_rewind( ProxyConnection* conn )
{
- int result = -1;
- int fd = conn->socket;
- int avail = conn->buffer_len - conn->buffer_pos;
+ stralloc_t* str = conn->str;
+
+ /* only keep a small buffer in the heap */
+ conn->str_pos = 0;
+ str->n = 0;
+ if (str->a > 1024)
+ stralloc_reset(str);
+}
+
+DataStatus
+proxy_connection_send( ProxyConnection* conn, int fd )
+{
+ stralloc_t* str = conn->str;
+ int avail = str->n - conn->str_pos;
+
+ conn->str_sent = 0;
+
+ if (avail <= 0)
+ return 1;
if (proxy_log) {
- PROXY_LOG("%s: sending %d bytes:\n", conn->name, avail );
- hex_dump( conn->buffer + conn->buffer_pos, avail, ">> " );
+ PROXY_LOG("%s: sending %d bytes:", conn->name, avail );
+ hex_dump( str->s + conn->str_pos, avail, ">> " );
}
while (avail > 0) {
- int n = send(fd, conn->buffer + conn->buffer_pos, avail, 0);
+ int n = send(fd, str->s + conn->str_pos, avail, 0);
+ if (n == 0) {
+ PROXY_LOG("%s: connection reset by peer (send)",
+ conn->name);
+ return DATA_ERROR;
+ }
if (n < 0) {
- if (errno == EINTR)
+ if (socket_errno == EINTR)
continue;
- if (errno == EWOULDBLOCK || errno == EAGAIN)
- return 0;
- PROXY_LOG("%s: error: %s\n", conn->name, strerror(errno));
- return -1;
+
+ if (socket_errno == EWOULDBLOCK || socket_errno == EAGAIN)
+ return DATA_NEED_MORE;
+
+ PROXY_LOG("%s: error: %s", conn->name, socket_errstr());
+ return DATA_ERROR;
}
- conn->buffer_pos += n;
- avail -= n;
+ conn->str_pos += n;
+ conn->str_sent += n;
+ avail -= n;
}
- return 1;
+
+ proxy_connection_rewind(conn);
+ return DATA_COMPLETED;
}
-int
-proxy_connection_receive( ProxyConnection* conn )
+
+DataStatus
+proxy_connection_receive( ProxyConnection* conn, int fd, int wanted )
{
- int result = -1;
- int fd = conn->socket;
- int avail = conn->buffer_len - conn->buffer_pos;
+ stralloc_t* str = conn->str;
- while (avail > 0) {
- int n = recv(fd, conn->buffer + conn->buffer_pos, avail, 0);
+ conn->str_recv = 0;
+
+ while (wanted > 0) {
+ int n;
+
+ stralloc_readyplus( str, wanted );
+ n = recv(fd, str->s + str->n, wanted, 0);
+ if (n == 0) {
+ PROXY_LOG("%s: connection reset by peer (receive)",
+ conn->name);
+ return DATA_ERROR;
+ }
if (n < 0) {
- if (errno == EINTR)
+ if (socket_errno == EINTR)
continue;
- if (errno == EWOULDBLOCK || errno == EAGAIN)
- return 0;
- PROXY_LOG("%s: error: %s\n", conn->name, strerror(errno));
- return -1;
+
+ if (socket_errno == EWOULDBLOCK || socket_errno == EAGAIN)
+ return DATA_NEED_MORE;
+
+ PROXY_LOG("%s: error: %s", conn->name, socket_errstr());
+ return DATA_ERROR;
}
if (proxy_log) {
- PROXY_LOG("%s: received %d bytes:\n", conn->name, n );
- hex_dump( conn->buffer + conn->buffer_pos, n, ">> " );
+ PROXY_LOG("%s: received %d bytes:", conn->name, n );
+ hex_dump( str->s + str->n, n, "<< " );
}
- conn->buffer_pos += n;
- avail -= n;
+ str->n += n;
+ wanted -= n;
+ conn->str_recv += n;
}
- return 1;
+ return DATA_COMPLETED;
}
-int
-proxy_connection_receive_line( ProxyConnection* conn )
+
+DataStatus
+proxy_connection_receive_line( ProxyConnection* conn, int fd )
{
- int result = -1;
- int fd = conn->socket;
+ stralloc_t* str = conn->str;
for (;;) {
char c;
int n = recv(fd, &c, 1, 0);
if (n == 0) {
- PROXY_LOG("%s: disconnected from server\n", conn->name );
- return -1;
+ PROXY_LOG("%s: disconnected from server", conn->name );
+ return DATA_ERROR;
}
if (n < 0) {
- if (errno == EINTR)
+ if (socket_errno == EINTR)
continue;
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
- PROXY_LOG("%s: blocked\n", conn->name);
- return 0;
+
+ if (socket_errno == EWOULDBLOCK || socket_errno == EAGAIN) {
+ PROXY_LOG("%s: blocked", conn->name);
+ return DATA_NEED_MORE;
}
- PROXY_LOG("%s: error: %s\n", conn->name, strerror(errno));
- return -1;
+ PROXY_LOG("%s: error: %s", conn->name, socket_errstr());
+ return DATA_ERROR;
}
+ stralloc_add_c(str, c);
if (c == '\n') {
- if (conn->buffer_pos > 0 && conn->buffer[conn->buffer_pos-1] == '\r')
- conn->buffer_pos -= 1;
-
- conn->buffer[conn->buffer_pos] = 0;
+ str->s[--str->n] = 0;
+ if (str->n > 0 && str->s[str->n-1] == '\r')
+ str->s[--str->n] = 0;
- PROXY_LOG("%s: received '%.*s'\n", conn->name,
- conn->buffer_pos, conn->buffer);
- return 1;
- }
-
- conn->buffer[ conn->buffer_pos++ ] = c;
- if (conn->buffer_pos == conn->buffer_len) {
- PROXY_LOG("%s: line received from proxy is too long\n", conn->name);
- return -1;
+ PROXY_LOG("%s: received '%s'", conn->name,
+ quote_bytes(str->s, str->n));
+ return DATA_COMPLETED;
}
}
}
-
-
static void
proxy_connection_insert( ProxyConnection* conn, ProxyConnection* after )
{
@@ -276,7 +299,7 @@ proxy_manager_atexit( void )
/* free all proxy connections */
while (conn != s_connections) {
ProxyConnection* next = conn->next;
- conn->service->conn_free( conn );
+ conn->conn_free( conn );
conn = next;
}
conn->next = conn;
@@ -293,6 +316,7 @@ proxy_manager_atexit( void )
void
proxy_connection_free( ProxyConnection* conn,
+ int keep_alive,
ProxyEvent event )
{
if (conn) {
@@ -301,18 +325,21 @@ proxy_connection_free( ProxyConnection* conn,
proxy_connection_remove(conn);
if (event != PROXY_EVENT_NONE)
- conn->ev_func( conn->ev_opaque, event );
+ conn->ev_func( conn->ev_opaque, fd, event );
- conn->service->conn_free(conn);
+ if (keep_alive)
+ conn->socket = -1;
+
+ conn->conn_free(conn);
}
}
int
-proxy_manager_add( int socket,
- struct sockaddr_in* address,
- void* ev_opaque,
- ProxyEventFunc ev_func )
+proxy_manager_add( struct sockaddr_in* address,
+ int sock_type,
+ ProxyEventFunc ev_func,
+ void* ev_opaque )
{
int n;
@@ -320,16 +347,14 @@ proxy_manager_add( int socket,
proxy_manager_init();
}
- socket_set_nonblock(socket);
-
for (n = 0; n < s_num_services; n++) {
ProxyService* service = s_services[n];
ProxyConnection* conn = service->serv_connect( service->opaque,
- socket,
+ sock_type,
address );
if (conn != NULL) {
- conn->ev_opaque = ev_opaque;
conn->ev_func = ev_func;
+ conn->ev_opaque = ev_opaque;
proxy_connection_insert(conn, s_connections->prev);
return 0;
}
@@ -343,50 +368,83 @@ proxy_manager_add( int socket,
* the connection accept/refusal occured
*/
void
-proxy_manager_del( int socket )
+proxy_manager_del( void* ev_opaque )
{
ProxyConnection* conn = s_connections->next;
for ( ; conn != s_connections; conn = conn->next ) {
- if (conn->socket == socket) {
- int fd = conn->socket;
+ if (conn->ev_opaque == ev_opaque) {
proxy_connection_remove(conn);
- conn->service->conn_free(conn);
- socket_close(fd);
+ conn->conn_free(conn);
return;
}
}
}
+void
+proxy_select_set( ProxySelect* sel,
+ int fd,
+ unsigned flags )
+{
+ if (fd < 0 || !flags)
+ return;
+
+ if (*sel->pcount < fd+1)
+ *sel->pcount = fd+1;
+
+ if (flags & PROXY_SELECT_READ) {
+ FD_SET( fd, sel->reads );
+ } else {
+ FD_CLR( fd, sel->reads );
+ }
+ if (flags & PROXY_SELECT_WRITE) {
+ FD_SET( fd, sel->writes );
+ } else {
+ FD_CLR( fd, sel->writes );
+ }
+ if (flags & PROXY_SELECT_ERROR) {
+ FD_SET( fd, sel->errors );
+ } else {
+ FD_CLR( fd, sel->errors );
+ }
+}
+
+unsigned
+proxy_select_poll( ProxySelect* sel, int fd )
+{
+ unsigned flags = 0;
+
+ if (fd >= 0) {
+ if ( FD_ISSET(fd, sel->reads) )
+ flags |= PROXY_SELECT_READ;
+ if ( FD_ISSET(fd, sel->writes) )
+ flags |= PROXY_SELECT_WRITE;
+ if ( FD_ISSET(fd, sel->errors) )
+ flags |= PROXY_SELECT_ERROR;
+ }
+ return flags;
+}
+
/* this function is called to update the select file descriptor sets
* with those of the proxified connection sockets that are currently managed */
void
proxy_manager_select_fill( int *pcount, fd_set* read_fds, fd_set* write_fds, fd_set* err_fds)
{
ProxyConnection* conn;
+ ProxySelect sel[1];
if (!s_init)
proxy_manager_init();
- conn = s_connections->next;
- for ( ; conn != s_connections; conn = conn->next ) {
- unsigned flags = conn->service->conn_select(conn);
- int fd = conn->socket;
-
- if (!flags)
- continue;
+ sel->pcount = pcount;
+ sel->reads = read_fds;
+ sel->writes = write_fds;
+ sel->errors = err_fds;
- if (*pcount < fd+1)
- *pcount = fd+1;
-
- if (flags & PROXY_SELECT_READ) {
- FD_SET( fd, read_fds );
- }
- if (flags & PROXY_SELECT_WRITE) {
- FD_SET( fd, write_fds );
- }
- if (flags & PROXY_SELECT_ERROR) {
- FD_SET( fd, err_fds );
- }
+ conn = s_connections->next;
+ while (conn != s_connections) {
+ ProxyConnection* next = conn->next;
+ conn->conn_select(conn, sel);
+ conn = next;
}
}
@@ -395,21 +453,16 @@ void
proxy_manager_poll( fd_set* read_fds, fd_set* write_fds, fd_set* err_fds )
{
ProxyConnection* conn = s_connections->next;
- while (conn != s_connections) {
- ProxyConnection* next = conn->next;
- int fd = conn->socket;
- unsigned flags = 0;
+ ProxySelect sel[1];
- if ( FD_ISSET(fd, read_fds) )
- flags |= PROXY_SELECT_READ;
- if ( FD_ISSET(fd, write_fds) )
- flags |= PROXY_SELECT_WRITE;
- if ( FD_ISSET(fd, err_fds) )
- flags |= PROXY_SELECT_ERROR;
+ sel->pcount = NULL;
+ sel->reads = read_fds;
+ sel->writes = write_fds;
+ sel->errors = err_fds;
- if (flags != 0) {
- conn->service->conn_poll( conn, flags );
- }
+ while (conn != s_connections) {
+ ProxyConnection* next = conn->next;
+ conn->conn_poll( conn, sel );
conn = next;
}
}
@@ -480,7 +533,7 @@ proxy_resolve_server( struct sockaddr_in* addr,
host = gethostbyname(name);
if (host == NULL) {
- PROXY_LOG("%s: can't resolve proxy server name '%s'\n",
+ PROXY_LOG("%s: can't resolve proxy server name '%s'",
__FUNCTION__, name);
goto Exit;
}
@@ -488,7 +541,7 @@ proxy_resolve_server( struct sockaddr_in* addr,
addr->sin_addr = *(struct in_addr*)host->h_addr;
{
uint32_t a = ntohl(addr->sin_addr.s_addr);
- PROXY_LOG("server name '%s' resolved to %d.%d.%d.%d\n", name, (a>>24)&255, (a>>16)&255,(a>>8)&255,a&255);
+ PROXY_LOG("server name '%s' resolved to %d.%d.%d.%d", name, (a>>24)&255, (a>>16)&255,(a>>8)&255,a&255);
}
result = 0;
diff --git a/proxy/proxy_common.h b/proxy/proxy_common.h
index 54889cf..57f224d 100644
--- a/proxy/proxy_common.h
+++ b/proxy/proxy_common.h
@@ -29,7 +29,7 @@ typedef enum {
} ProxyEvent;
/* event can't be NONE when this callback is called */
-typedef void (*ProxyEventFunc)( void* opaque, ProxyEvent event );
+typedef void (*ProxyEventFunc)( void* opaque, int fd, ProxyEvent event );
extern void proxy_set_verbose(int mode);
@@ -61,19 +61,27 @@ typedef struct {
*
* returns 0 on success, or -1 if there is no proxy service for this type of connection
*/
-extern int proxy_manager_add( int socket, struct sockaddr_in* address, void* ev_opaque, ProxyEventFunc ev_func );
+extern int proxy_manager_add( struct sockaddr_in* address,
+ int sock_type,
+ ProxyEventFunc ev_func,
+ void* ev_opaque );
/* remove an on-going proxified socket connection from the manager's list.
* this is only necessary when the socket connection must be canceled before
* the connection accept/refusal occured
*/
-extern void proxy_manager_del( int socket );
+extern void proxy_manager_del( void* ev_opaque );
/* this function is called to update the select file descriptor sets
* with those of the proxified connection sockets that are currently managed */
-extern void proxy_manager_select_fill( int *pcount, fd_set* read_fds, fd_set* write_fds, fd_set* err_fds);
+extern void proxy_manager_select_fill( int *pcount,
+ fd_set* read_fds,
+ fd_set* write_fds,
+ fd_set* err_fds);
/* this function is called to act on proxified connection sockets when network events arrive */
-extern void proxy_manager_poll( fd_set* read_fds, fd_set* write_fds, fd_set* err_fds );
+extern void proxy_manager_poll( fd_set* read_fds,
+ fd_set* write_fds,
+ fd_set* err_fds );
#endif /* END */
diff --git a/proxy/proxy_http.c b/proxy/proxy_http.c
index 83982a7..c3d663c 100644
--- a/proxy/proxy_http.c
+++ b/proxy/proxy_http.c
@@ -10,200 +10,18 @@
** GNU General Public License for more details.
*/
#include "proxy_int.h"
-#include "proxy_http.h"
+#include "proxy_http_int.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "vl.h"
-typedef enum {
- HTTP_NONE = 0,
- HTTP_CONNECTING, /* connecting to the server */
- HTTP_SEND_HEADER, /* connected, sending header to the server */
- HTTP_RECEIVE_ANSWER_LINE1,
- HTTP_RECEIVE_ANSWER_LINE2 /* connected, reading server's answer */
-} HttpConnectionState;
-
-
-typedef struct {
- ProxyConnection root[1];
- HttpConnectionState state;
-} HttpConnection;
-
-
-typedef struct {
- ProxyService root[1];
- struct sockaddr_in server_addr; /* server address and port */
- char* footer; /* the footer contains the static parts of the */
- int footer_len; /* connection header, we generate it only once */
- char footer0[512];
-} HttpService;
-
-
-static void
-http_connection_free( HttpConnection* conn )
-{
- proxy_connection_done(conn->root);
- qemu_free(conn);
-}
-
-
#define HTTP_VERSION "1.1"
-static int
-http_connection_init( HttpConnection* conn )
-{
- HttpService* service = (HttpService*) conn->root->service;
- ProxyConnection* root = conn->root;
- char* p = root->buffer0;
- char* end = p + sizeof(root->buffer0);
- int wlen, ret;
- uint32_t address = ntohl(conn->root->address.sin_addr.s_addr);
- int port = ntohs(conn->root->address.sin_port);
-
- root->buffer_pos = 0;
- root->buffer = p;
-
- p += snprintf(p, end-p, "CONNECT %d.%d.%d.%d:%d HTTP/" HTTP_VERSION "\r\n",
- (address >> 24) & 0xff, (address >> 16) & 0xff,
- (address >> 8) & 0xff, address & 0xff, port);
- if (p >= end) goto Overflow;
-
- p += snprintf(p, end-p, "%.*s", service->footer_len, service->footer);
-
- if (p >= end) {
- Overflow:
- PROXY_LOG("%s: buffer overflow in proxy connection header\n", root->name);
- return -1;
- }
-
- root->buffer_len = (p - root->buffer);
-
- ret = connect( root->socket,
- (struct sockaddr*) &service->server_addr,
- sizeof(service->server_addr) );
- if (ret == 0) {
- /* immediate connection ?? */
- conn->state = HTTP_SEND_HEADER;
- PROXY_LOG("%s: immediate connection\n", root->name);
- }
- else {
- if (socket_errno == EINPROGRESS || socket_errno == EWOULDBLOCK) {
- conn->state = HTTP_CONNECTING;
- PROXY_LOG("%s: connecting\n", conn->root->name);
- }
- else {
- PROXY_LOG("%s: cannot connect to proxy: %s\n", root->name, strerror(errno));
- return -1;
- }
- }
- return 0;
-}
-
-
-static unsigned
-http_connection_select( HttpConnection* conn )
-{
- unsigned flags;
-
- switch (conn->state) {
- case HTTP_RECEIVE_ANSWER_LINE1:
- case HTTP_RECEIVE_ANSWER_LINE2:
- flags = PROXY_SELECT_READ;
- break;
-
- case HTTP_CONNECTING:
- case HTTP_SEND_HEADER:
- flags = PROXY_SELECT_WRITE;
- break;
-
- default:
- flags = 0;
- };
- return flags;
-}
-
-static void
-http_connection_poll( HttpConnection* conn,
- unsigned flags )
-{
- int ret;
- ProxyConnection* root = conn->root;
-
- switch (conn->state)
- {
- case HTTP_CONNECTING:
- PROXY_LOG("%s: connected to http proxy, sending header\n", root->name);
- conn->state = HTTP_SEND_HEADER;
- break;
-
- case HTTP_SEND_HEADER:
- {
- int ret = proxy_connection_send(root);
-
- if (ret < 0) {
- proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR );
- return;
- }
- if (ret == 0)
- return;
-
- root->buffer_len = sizeof(root->buffer0);
- root->buffer_pos = 0;
- conn->state = HTTP_RECEIVE_ANSWER_LINE1;
- PROXY_LOG("%s: header sent, receiving first answer line\n", root->name);
- }
- break;
-
- case HTTP_RECEIVE_ANSWER_LINE1:
- case HTTP_RECEIVE_ANSWER_LINE2:
- {
- int ret = proxy_connection_receive_line(root);
-
- if (ret < 0) {
- proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR );
- return;
- }
- if (ret == 0)
- return;
-
- if (conn->state == HTTP_RECEIVE_ANSWER_LINE1) {
- int http1, http2, codenum;
-
- if ( sscanf(root->buffer, "HTTP/%d.%d %d", &http1, &http2, &codenum) != 3 ) {
- PROXY_LOG( "%s: invalid answer from proxy: '%s'\n",
- root->name, root->buffer );
- proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR );
- return;
- }
-
- /* success is 2xx */
- if (codenum/2 != 100) {
- PROXY_LOG( "%s: connection refused, error=%d\n",
- root->name, codenum );
- proxy_connection_free( root, PROXY_EVENT_CONNECTION_REFUSED );
- return;
- }
- PROXY_LOG("%s: receiving second answer line\n", root->name);
- conn->state = HTTP_RECEIVE_ANSWER_LINE2;
- root->buffer_pos = 0;
- } else {
- /* ok, we're connected */
- PROXY_LOG("%s: connection succeeded\n", root->name);
- proxy_connection_free( root, PROXY_EVENT_CONNECTED );
- }
- }
- break;
-
- default:
- PROXY_LOG("%s: invalid state for read event: %d\n", root->name, conn->state);
- }
-}
-
static void
http_service_free( HttpService* service )
{
- PROXY_LOG("%s\n", __FUNCTION__);
+ PROXY_LOG("%s", __FUNCTION__);
if (service->footer != service->footer0)
qemu_free(service->footer);
qemu_free(service);
@@ -212,11 +30,11 @@ http_service_free( HttpService* service )
static ProxyConnection*
http_service_connect( HttpService* service,
- int socket,
+ int sock_type,
struct sockaddr_in* address )
{
- HttpConnection* conn = qemu_mallocz(sizeof(*conn));
- int sock_type = socket_get_type(socket);
+ uint32_t addr;
+ int port;
/* the HTTP proxy can only handle TCP connections */
if (sock_type != SOCK_STREAM)
@@ -227,14 +45,25 @@ http_service_connect( HttpService* service,
address->sin_port == service->server_addr.sin_port)
return NULL;
- proxy_connection_init( conn->root, socket, address, service->root );
-
- if ( http_connection_init( conn ) < 0 ) {
- http_connection_free( conn );
- return NULL;
+ addr = ntohl(address->sin_addr.s_addr);
+ port = ntohs(address->sin_port);
+
+ PROXY_LOG("%s: trying to connect to %d.%d.%d.%d on port %d",
+ __FUNCTION__,
+ (addr >> 24) & 255,
+ (addr >> 16) & 255,
+ (addr >> 8) & 255,
+ addr & 255,
+ port );
+
+ if (port == 80) {
+ /* use the rewriter for HTTP */
+ PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__);
+ return http_rewriter_connect(service, address);
+ } else {
+ PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__);
+ return http_connector_connect(service, address);
}
-
- return conn->root;
}
@@ -256,7 +85,7 @@ proxy_http_setup( const char* servername,
if (servernamelen < 0)
servernamelen = strlen(servername);
- PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d\n",
+ PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d",
__FUNCTION__, servernamelen, servername, serverport );
/* resolve server address */
@@ -269,7 +98,7 @@ proxy_http_setup( const char* servername,
/* create service object */
service = qemu_mallocz(sizeof(*service));
if (service == NULL) {
- PROXY_LOG("%s: not enough memory to allocate new proxy service\n", __FUNCTION__);
+ PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__);
return -1;
}
@@ -322,7 +151,7 @@ proxy_http_setup( const char* servername,
wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded));
if (wlen < 0) {
- PROXY_LOG( "could not base64 encode '%.*s'\n", uplen, user_pass);
+ PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass);
goto FooterOverflow;
}
@@ -341,7 +170,7 @@ proxy_http_setup( const char* servername,
if (p >= end) {
FooterOverflow:
- PROXY_LOG( "%s: buffer overflow when creating connection footer\n",
+ PROXY_LOG( "%s: buffer overflow when creating connection footer",
__FUNCTION__);
http_service_free(service);
return -1;
@@ -351,18 +180,16 @@ proxy_http_setup( const char* servername,
service->footer_len = (p - service->footer);
}
- PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'\n",
+ PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'",
__FUNCTION__, service->footer_len,
service->footer_len, service->footer );
service->root->opaque = service;
- service->root->serv_free = (ProxyServiceFreeFunc) http_service_free;
- service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect;
- service->root->conn_free = (ProxyConnectionFreeFunc) http_connection_free;
- service->root->conn_select = (ProxyConnectionSelectFunc) http_connection_select;
- service->root->conn_poll = (ProxyConnectionPollFunc) http_connection_poll;
+ service->root->serv_free = (ProxyServiceFreeFunc) http_service_free;
+ service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect;
if (proxy_manager_add_service( service->root ) < 0) {
+ PROXY_LOG("%s: could not register service ?", __FUNCTION__);
http_service_free(service);
return -1;
}
diff --git a/proxy/proxy_http_connector.c b/proxy/proxy_http_connector.c
new file mode 100644
index 0000000..1b2ba3e
--- /dev/null
+++ b/proxy/proxy_http_connector.c
@@ -0,0 +1,213 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "proxy_http_int.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "vl.h"
+
+/* A HttpConnector implements a non-HTTP proxied connection
+ * through the CONNECT method. Many firewalls are configured
+ * to reject these for port 80, so these connections should
+ * use a HttpRewriter instead.
+ */
+
+typedef enum {
+ STATE_NONE = 0,
+ STATE_CONNECTING, /* connecting to the server */
+ STATE_SEND_HEADER, /* connected, sending header to the server */
+ STATE_RECEIVE_ANSWER_LINE1,
+ STATE_RECEIVE_ANSWER_LINE2 /* connected, reading server's answer */
+} ConnectorState;
+
+typedef struct Connection {
+ ProxyConnection root[1];
+ ConnectorState state;
+} Connection;
+
+
+static void
+connection_free( ProxyConnection* root )
+{
+ proxy_connection_done(root);
+ qemu_free(root);
+}
+
+
+
+#define HTTP_VERSION "1.1"
+
+static int
+connection_init( Connection* conn )
+{
+ HttpService* service = (HttpService*) conn->root->service;
+ ProxyConnection* root = conn->root;
+ stralloc_t* str = root->str;
+ int ret;
+ uint32_t address = ntohl(root->address.sin_addr.s_addr);
+ int port = ntohs(root->address.sin_port);
+
+ proxy_connection_rewind(root);
+ stralloc_add_format(str, "CONNECT %d.%d.%d.%d:%d HTTP/" HTTP_VERSION "\r\n",
+ (address >> 24) & 0xff, (address >> 16) & 0xff,
+ (address >> 8) & 0xff, address & 0xff, port);
+
+ stralloc_add_bytes(str, service->footer, service->footer_len);
+
+ do {
+ ret = connect( root->socket,
+ (struct sockaddr*) &service->server_addr,
+ sizeof(service->server_addr) );
+ } while (ret < 0 && socket_errno == EINTR);
+
+ if (ret == 0) {
+ /* immediate connection ?? */
+ conn->state = STATE_SEND_HEADER;
+ PROXY_LOG("%s: immediate connection", root->name);
+ }
+ else {
+ if (socket_errno == EINPROGRESS || socket_errno == EWOULDBLOCK) {
+ conn->state = STATE_CONNECTING;
+ PROXY_LOG("%s: connecting", root->name);
+ }
+ else {
+ PROXY_LOG("%s: cannot connect to proxy: %s", root->name, socket_errstr());
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+static void
+connection_select( ProxyConnection* root,
+ ProxySelect* sel )
+{
+ unsigned flags;
+ Connection* conn = (Connection*)root;
+
+ switch (conn->state) {
+ case STATE_RECEIVE_ANSWER_LINE1:
+ case STATE_RECEIVE_ANSWER_LINE2:
+ flags = PROXY_SELECT_READ;
+ break;
+
+ case STATE_CONNECTING:
+ case STATE_SEND_HEADER:
+ flags = PROXY_SELECT_WRITE;
+ break;
+
+ default:
+ flags = 0;
+ };
+ proxy_select_set(sel, root->socket, flags);
+}
+
+static void
+connection_poll( ProxyConnection* root,
+ ProxySelect* sel )
+{
+ DataStatus ret = DATA_NEED_MORE;
+ Connection* conn = (Connection*)root;
+ int fd = root->socket;
+
+ if (!proxy_select_poll(sel, fd))
+ return;
+
+ switch (conn->state)
+ {
+ case STATE_CONNECTING:
+ PROXY_LOG("%s: connected to http proxy, sending header", root->name);
+ conn->state = STATE_SEND_HEADER;
+ break;
+
+ case STATE_SEND_HEADER:
+ ret = proxy_connection_send(root, fd);
+ if (ret == DATA_COMPLETED) {
+ conn->state = STATE_RECEIVE_ANSWER_LINE1;
+ PROXY_LOG("%s: header sent, receiving first answer line", root->name);
+ }
+ break;
+
+ case STATE_RECEIVE_ANSWER_LINE1:
+ case STATE_RECEIVE_ANSWER_LINE2:
+ ret = proxy_connection_receive_line(root, root->socket);
+ if (ret == DATA_COMPLETED) {
+ if (conn->state == STATE_RECEIVE_ANSWER_LINE1) {
+ int http1, http2, codenum;
+ const char* line = root->str->s;
+
+ if ( sscanf(line, "HTTP/%d.%d %d", &http1, &http2, &codenum) != 3 ) {
+ PROXY_LOG( "%s: invalid answer from proxy: '%s'",
+ root->name, line );
+ ret = DATA_ERROR;
+ break;
+ }
+
+ /* success is 2xx */
+ if (codenum/2 != 100) {
+ PROXY_LOG( "%s: connection refused, error=%d",
+ root->name, codenum );
+ proxy_connection_free( root, 0, PROXY_EVENT_CONNECTION_REFUSED );
+ return;
+ }
+ PROXY_LOG("%s: receiving second answer line", root->name);
+ conn->state = STATE_RECEIVE_ANSWER_LINE2;
+ proxy_connection_rewind(root);
+ } else {
+ /* ok, we're connected */
+ PROXY_LOG("%s: connection succeeded", root->name);
+ proxy_connection_free( root, 1, PROXY_EVENT_CONNECTED );
+ }
+ }
+ break;
+
+ default:
+ PROXY_LOG("%s: invalid state for read event: %d", root->name, conn->state);
+ }
+
+ if (ret == DATA_ERROR) {
+ proxy_connection_free( root, 0, PROXY_EVENT_SERVER_ERROR );
+ }
+}
+
+
+
+ProxyConnection*
+http_connector_connect( HttpService* service,
+ struct sockaddr_in* address )
+{
+ Connection* conn;
+ int s;
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return NULL;
+
+ conn = qemu_mallocz(sizeof(*conn));
+ if (conn == NULL) {
+ socket_close(s);
+ return NULL;
+ }
+
+ proxy_connection_init( conn->root, s, address, service->root,
+ connection_free,
+ connection_select,
+ connection_poll );
+
+ if ( connection_init( conn ) < 0 ) {
+ connection_free( conn->root );
+ return NULL;
+ }
+
+ return conn->root;
+}
diff --git a/proxy/proxy_http_int.h b/proxy/proxy_http_int.h
new file mode 100644
index 0000000..d0a6bc0
--- /dev/null
+++ b/proxy/proxy_http_int.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#ifndef _PROXY_HTTP_INT_H
+#define _PROXY_HTTP_INT_H
+
+#include "proxy_http.h"
+#include "proxy_int.h"
+
+/* the HttpService object */
+typedef struct HttpService {
+ ProxyService root[1];
+ struct sockaddr_in server_addr; /* server address and port */
+ char* footer; /* the footer contains the static parts of the */
+ int footer_len; /* connection header, we generate it only once */
+ char footer0[512];
+} HttpService;
+
+/* create a CONNECT connection (for port != 80) */
+extern ProxyConnection* http_connector_connect(
+ HttpService* service,
+ struct sockaddr_in* address );
+
+/* create a HTTP rewriting connection (for port == 80) */
+extern ProxyConnection* http_rewriter_connect(
+ HttpService* service,
+ struct sockaddr_in* address );
+
+
+#endif /* _PROXY_HTTP_INT_H */
diff --git a/proxy/proxy_http_rewriter.c b/proxy/proxy_http_rewriter.c
new file mode 100644
index 0000000..3e98557
--- /dev/null
+++ b/proxy/proxy_http_rewriter.c
@@ -0,0 +1,1132 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "proxy_http_int.h"
+#include "android_utils.h"
+#include <stdio.h>
+#include <string.h>
+#include "vl.h"
+
+/* this implements a transparent HTTP rewriting proxy
+ *
+ * this is needed because the HTTP spec mandates that
+ * any query made to a proxy uses an absolute URI as
+ * in:
+ *
+ * GET http://www.example.com/index.html HTTP/1.1
+ *
+ * while the Android browser will think it's talking to
+ * a normal web server and will issue a:
+ *
+ * GET /index.html HTTP/1.1
+ * Host: www.example.com
+ *
+ * what we do here is thus the following:
+ *
+ * - read the request header
+ * - rewrite the request's URI to use absolute URI
+ * - send the rewritten header to the proxy
+ * - then read the rest of the request, and tunnel it to the
+ * proxy as well
+ * - read the answer as-is and send it back to the system
+ *
+ * this sounds all easy, but the rules for computing the
+ * sizes of HTTP Message Bodies makes the implementation
+ * a *bit* funky.
+ */
+
+/* define D_ACTIVE to 1 to dump additionnal debugging
+ * info when -debug-proxy is used. These are only needed
+ * when debugging the proxy code.
+ */
+#define D_ACTIVE 1
+
+#if D_ACTIVE
+# define D(...) PROXY_LOG(__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+
+/** *************************************************************
+ **
+ ** HTTP HEADERS
+ **
+ **/
+
+typedef struct HttpHeader {
+ struct HttpHeader* next;
+ const char* key;
+ const char* value;
+} HttpHeader;
+
+static void
+http_header_free( HttpHeader* h )
+{
+ if (h) {
+ qemu_free((char*)h->value);
+ qemu_free(h);
+ }
+}
+
+static int
+http_header_append( HttpHeader* h, const char* value )
+{
+ int old = strlen(h->value);
+ int new = strlen(value);
+ char* s = realloc((char*)h->value, old+new+1);
+ if (s == NULL)
+ return -1;
+ memcpy(s + old, value, new+1);
+ h->value = (const char*)s;
+ return 0;
+}
+
+static HttpHeader*
+http_header_alloc( const char* key, const char* value )
+{
+ int len = strlen(key)+1;
+ HttpHeader* h = malloc(sizeof(*h) + len+1);
+ if (h) {
+ h->next = NULL;
+ h->key = (const char*)(h+1);
+ memcpy( (char*)h->key, key, len );
+ h->value = qemu_strdup(value);
+ }
+ return h;
+}
+
+typedef struct {
+ HttpHeader* first;
+ HttpHeader* last;
+} HttpHeaderList;
+
+static void
+http_header_list_init( HttpHeaderList* l )
+{
+ l->first = l->last = NULL;
+}
+
+static void
+http_header_list_done( HttpHeaderList* l )
+{
+ while (l->first) {
+ HttpHeader* h = l->first;
+ l->first = h->next;
+ http_header_free(h);
+ }
+ l->last = NULL;
+}
+
+static void
+http_header_list_add( HttpHeaderList* l,
+ HttpHeader* h )
+{
+ if (!l->first) {
+ l->first = h;
+ } else {
+ l->last->next = h;
+ }
+ h->next = NULL;
+ l->last = h;
+}
+
+static const char*
+http_header_list_find( HttpHeaderList* l,
+ const char* key )
+{
+ HttpHeader* h;
+ for (h = l->first; h; h = h->next)
+ if (!strcasecmp(h->key, key))
+ return h->value;
+
+ return NULL;
+}
+
+/** *************************************************************
+ **
+ ** HTTP REQUEST AND REPLY
+ **
+ **/
+
+typedef enum {
+ HTTP_REQUEST_UNSUPPORTED = 0,
+ HTTP_REQUEST_GET,
+ HTTP_REQUEST_HEAD,
+ HTTP_REQUEST_POST,
+ HTTP_REQUEST_PUT,
+ HTTP_REQUEST_DELETE,
+} HttpRequestType;
+
+typedef struct {
+ HttpRequestType req_type;
+ char* req_method;
+ char* req_uri;
+ char* req_version;
+ char* rep_version;
+ int rep_code;
+ char* rep_readable;
+ HttpHeaderList headers[1];
+} HttpRequest;
+
+
+static HttpRequest*
+http_request_alloc( const char* method,
+ const char* uri,
+ const char* version )
+{
+ HttpRequest* r = malloc(sizeof(*r));
+
+ r->req_method = qemu_strdup(method);
+ r->req_uri = qemu_strdup(uri);
+ r->req_version = qemu_strdup(version);
+ r->rep_version = NULL;
+ r->rep_code = -1;
+ r->rep_readable = NULL;
+
+ if (!strcmp(method,"GET")) {
+ r->req_type = HTTP_REQUEST_GET;
+ } else if (!strcmp(method,"POST")) {
+ r->req_type = HTTP_REQUEST_POST;
+ } else if (!strcmp(method,"HEAD")) {
+ r->req_type = HTTP_REQUEST_HEAD;
+ } else if (!strcmp(method,"PUT")) {
+ r->req_type = HTTP_REQUEST_PUT;
+ } else if (!strcmp(method,"DELETE")) {
+ r->req_type = HTTP_REQUEST_DELETE;
+ } else
+ r->req_type = HTTP_REQUEST_UNSUPPORTED;
+
+ http_header_list_init(r->headers);
+ return r;
+}
+
+static void
+http_request_replace_uri( HttpRequest* r,
+ const char* uri )
+{
+ const char* old = r->req_uri;
+ r->req_uri = qemu_strdup(uri);
+ qemu_free((char*)old);
+}
+
+static void
+http_request_free( HttpRequest* r )
+{
+ if (r) {
+ http_header_list_done(r->headers);
+
+ qemu_free(r->req_method);
+ qemu_free(r->req_uri);
+ qemu_free(r->req_version);
+ qemu_free(r->rep_version);
+ qemu_free(r->rep_readable);
+ qemu_free(r);
+ }
+}
+
+static char*
+http_request_find_header( HttpRequest* r,
+ const char* key )
+{
+ return (char*)http_header_list_find(r->headers, key);
+}
+
+
+static int
+http_request_add_header( HttpRequest* r,
+ const char* key,
+ const char* value )
+{
+ HttpHeader* h = http_header_alloc(key,value);
+ if (h) {
+ http_header_list_add(r->headers, h);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+http_request_add_to_last_header( HttpRequest* r,
+ const char* line )
+{
+ if (r->headers->last) {
+ return http_header_append( r->headers->last, line );
+ } else {
+ return -1;
+ }
+}
+
+static int
+http_request_set_reply( HttpRequest* r,
+ const char* version,
+ const char* code,
+ const char* readable )
+{
+ if (strcmp(version,"HTTP/1.0") && strcmp(version,"HTTP/1.1")) {
+ PROXY_LOG("%s: bad reply protocol: %s", __FUNCTION__, version);
+ return -1;
+ }
+ r->rep_code = atoi(code);
+ if (r->rep_code == 0) {
+ PROXY_LOG("%s: bad reply code: %d", __FUNCTION__, code);
+ return -1;
+ }
+
+ r->rep_version = qemu_strdup(version);
+ r->rep_readable = qemu_strdup(readable);
+
+ /* reset the list of headers */
+ http_header_list_done(r->headers);
+ return 0;
+}
+
+/** *************************************************************
+ **
+ ** REWRITER CONNECTION
+ **
+ **/
+
+typedef enum {
+ STATE_CONNECTING = 0,
+ STATE_CREATE_SOCKET_PAIR,
+ STATE_REQUEST_FIRST_LINE,
+ STATE_REQUEST_HEADERS,
+ STATE_REQUEST_SEND,
+ STATE_REQUEST_BODY,
+ STATE_REPLY_FIRST_LINE,
+ STATE_REPLY_HEADERS,
+ STATE_REPLY_SEND,
+ STATE_REPLY_BODY,
+} ConnectionState;
+
+/* root->socket is connected to the proxy server. while
+ * slirp_fd is connected to the slirp code through a
+ * socket_pair() we created for this specific purpose.
+ */
+
+typedef enum {
+ BODY_NONE = 0,
+ BODY_KNOWN_LENGTH,
+ BODY_UNTIL_CLOSE,
+ BODY_CHUNKED,
+ BODY_MODE_MAX
+} BodyMode;
+
+static const char* const body_mode_str[BODY_MODE_MAX] = {
+ "NONE", "KNOWN_LENGTH", "UNTIL_CLOSE", "CHUNKED"
+};
+
+typedef struct {
+ ProxyConnection root[1];
+ int slirp_fd;
+ ConnectionState state;
+ HttpRequest* request;
+ BodyMode body_mode;
+ int64_t body_length;
+ int64_t body_total;
+ int64_t body_sent;
+ int64_t chunk_length;
+ int64_t chunk_total;
+ char body_has_data;
+ char body_is_full;
+ char body_is_closed;
+ char parse_chunk_header;
+ char parse_chunk_trailer;
+} RewriteConnection;
+
+
+static void
+rewrite_connection_free( ProxyConnection* root )
+{
+ RewriteConnection* conn = (RewriteConnection*)root;
+
+ if (conn->slirp_fd >= 0) {
+ socket_close(conn->slirp_fd);
+ conn->slirp_fd = -1;
+ }
+ http_request_free(conn->request);
+ proxy_connection_done(root);
+ qemu_free(conn);
+}
+
+
+static int
+rewrite_connection_init( RewriteConnection* conn )
+{
+ HttpService* service = (HttpService*) conn->root->service;
+ ProxyConnection* root = conn->root;
+ int ret;
+
+ conn->slirp_fd = -1;
+ conn->state = STATE_CONNECTING;
+
+ do {
+ ret = connect( root->socket,
+ (struct sockaddr*) &service->server_addr,
+ sizeof(service->server_addr) );
+ } while (ret < 0 && socket_errno == EINTR);
+
+ if (ret < 0) {
+ if (socket_errno == EINPROGRESS || socket_errno == EWOULDBLOCK) {
+ PROXY_LOG("%s: connecting", conn->root->name);
+ }
+ else {
+ PROXY_LOG("%s: cannot connect to proxy: %s", root->name, socket_errstr());
+ return -1;
+ }
+ }
+ else {
+ PROXY_LOG("%s: immediate connection", root->name);
+ conn->state = STATE_CREATE_SOCKET_PAIR;
+ }
+ return 0;
+}
+
+static int
+rewrite_connection_create_sockets( RewriteConnection* conn )
+{
+ /* immediate connection to the proxy. now create a socket
+ * pair and send a 'success' event to slirp */
+ int slirp_1;
+ ProxyConnection* root = conn->root;
+
+ if (socket_pair( &slirp_1, &conn->slirp_fd ) < 0) {
+ PROXY_LOG("%s: coult not create socket pair: %s",
+ root->name, socket_errstr());
+ return -1;
+ }
+
+ root->ev_func( root->ev_opaque, slirp_1, PROXY_EVENT_CONNECTED );
+ conn->state = STATE_REQUEST_FIRST_LINE;
+ return 0;
+}
+
+
+/* read the first line of a given HTTP request. returns -1/0/+1 */
+static DataStatus
+rewrite_connection_read_request( RewriteConnection* conn )
+{
+ ProxyConnection* root = conn->root;
+ DataStatus ret;
+
+ ret = proxy_connection_receive_line(root, conn->slirp_fd);
+ if (ret == DATA_COMPLETED) {
+ /* now parse the first line to see if we can handle it */
+ char* line = root->str->s;
+ char* method;
+ char* uri;
+ char* version;
+ char* p = line;
+
+ method = strsep(&p, " ");
+ if (p == NULL) {
+ PROXY_LOG("%s: can't parse method in '%'",
+ root->name, line);
+ return DATA_ERROR;
+ }
+ uri = strsep(&p, " ");
+ if (p == NULL) {
+ PROXY_LOG( "%s: can't parse URI in '%s'",
+ root->name, line);
+ return DATA_ERROR;
+ }
+ version = strsep(&p, " ");
+ if (p != NULL) {
+ PROXY_LOG( "%s: extra data after version in '%s'",
+ root->name, line);
+ return DATA_ERROR;
+ }
+ if (conn->request)
+ http_request_free(conn->request);
+
+ conn->request = http_request_alloc( method, uri, version );
+ if (!conn->request)
+ return DATA_ERROR;
+
+ proxy_connection_rewind(root);
+ }
+ return ret;
+}
+
+
+static DataStatus
+rewrite_connection_read_reply( RewriteConnection* conn )
+{
+ ProxyConnection* root = conn->root;
+ DataStatus ret;
+
+ ret = proxy_connection_receive_line( root, root->socket );
+ if (ret == DATA_COMPLETED) {
+ HttpRequest* request = conn->request;
+
+ char* line = stralloc_cstr( root->str );
+ char* p = line;
+ char* protocol;
+ char* number;
+ char* readable;
+
+ protocol = strsep(&p, " ");
+ if (p == NULL) {
+ PROXY_LOG("%s: can't parse response protocol: '%s'",
+ root->name, line);
+ return DATA_ERROR;
+ }
+ number = strsep(&p, " ");
+ if (p == NULL) {
+ PROXY_LOG("%s: can't parse response number: '%s'",
+ root->name, line);
+ return DATA_ERROR;
+ }
+ readable = p;
+
+ if (http_request_set_reply(request, protocol, number, readable) < 0)
+ return DATA_ERROR;
+
+ proxy_connection_rewind(root);
+ }
+ return ret;
+}
+
+
+static DataStatus
+rewrite_connection_read_headers( RewriteConnection* conn,
+ int fd )
+{
+ int ret;
+ ProxyConnection* root = conn->root;
+
+ for (;;) {
+ char* line;
+ stralloc_t* str = root->str;
+
+ ret = proxy_connection_receive_line(root, fd);
+ if (ret != DATA_COMPLETED)
+ break;
+
+ str->n = 0;
+ line = str->s;
+
+ if (line[0] == 0) {
+ /* an empty line means the end of headers */
+ ret = 1;
+ break;
+ }
+
+ /* it this a continuation ? */
+ if (line[0] == ' ' || line[0] == '\t') {
+ ret = http_request_add_to_last_header( conn->request, line );
+ }
+ else {
+ char* key;
+ char* value;
+
+ value = line;
+ key = strsep(&value, ":");
+ if (value == NULL) {
+ PROXY_LOG("%s: can't parse header '%s'", root->name, line);
+ ret = -1;
+ break;
+ }
+ value += strspn(value, " ");
+ if (http_request_add_header(conn->request, key, value) < 0)
+ ret = -1;
+ }
+ if (ret == DATA_ERROR)
+ break;
+ }
+ return ret;
+}
+
+static int
+rewrite_connection_rewrite_request( RewriteConnection* conn )
+{
+ ProxyConnection* root = conn->root;
+ HttpService* service = (HttpService*) root->service;
+ HttpRequest* r = conn->request;
+ stralloc_t* str = root->str;
+ HttpHeader* h;
+
+ proxy_connection_rewind(conn->root);
+
+ /* only rewrite the URI if it is not absolute */
+ if (r->req_uri[0] == '/') {
+ char* host = http_request_find_header(r, "Host");
+ if (host == NULL) {
+ PROXY_LOG("%s: uh oh, not Host: in request ?", root->name);
+ } else {
+ /* now create new URI */
+ stralloc_add_str(str, "http://");
+ stralloc_add_str(str, host);
+ stralloc_add_str(str, r->req_uri);
+ http_request_replace_uri(r, stralloc_cstr(str));
+ proxy_connection_rewind(root);
+ }
+ }
+
+ stralloc_format( str, "%s %s %s\r\n", r->req_method, r->req_uri, r->req_version );
+ for (h = r->headers->first; h; h = h->next) {
+ stralloc_add_format( str, "%s: %s\r\n", h->key, h->value );
+ }
+ /* add the service's footer - includes final \r\n */
+ stralloc_add_bytes( str, service->footer, service->footer_len );
+
+ return 0;
+}
+
+static int
+rewrite_connection_rewrite_reply( RewriteConnection* conn )
+{
+ HttpRequest* r = conn->request;
+ ProxyConnection* root = conn->root;
+ stralloc_t* str = root->str;
+ HttpHeader* h;
+
+ proxy_connection_rewind(root);
+ stralloc_format(str, "%s %d %s\r\n", r->rep_version, r->rep_code, r->rep_readable);
+ for (h = r->headers->first; h; h = h->next) {
+ stralloc_add_format(str, "%s: %s\r\n", h->key, h->value);
+ }
+ stralloc_add_str(str, "\r\n");
+
+ return 0;
+}
+
+
+static int
+rewrite_connection_get_body_length( RewriteConnection* conn,
+ int is_request )
+{
+ HttpRequest* r = conn->request;
+ ProxyConnection* root = conn->root;
+ char* content_length;
+ char* transfer_encoding;
+
+ conn->body_mode = BODY_NONE;
+ conn->body_length = 0;
+ conn->body_total = 0;
+ conn->body_sent = 0;
+ conn->body_is_closed = 0;
+ conn->body_is_full = 0;
+ conn->body_has_data = 0;
+
+ proxy_connection_rewind(root);
+
+ if (is_request) {
+ /* only POST and PUT should have a body */
+ if (r->req_type != HTTP_REQUEST_POST &&
+ r->req_type != HTTP_REQUEST_PUT)
+ {
+ return 0;
+ }
+ } else {
+ /* HTTP 1.1 Section 4.3 Message Body states that HEAD requests must not have
+ * a message body, as well as any 1xx, 204 and 304 replies */
+ if (r->req_type == HTTP_REQUEST_HEAD || r->rep_code/100 == 1 ||
+ r->rep_code == 204 || r->rep_code == 304)
+ return 0;
+ }
+
+ content_length = http_request_find_header(r, "Content-Length");
+ if (content_length != NULL) {
+ char* end;
+ int64_t body_len = strtoll( content_length, &end, 10 );
+ if (*end != '\0' || *content_length == '\0' || body_len < 0) {
+ PROXY_LOG("%s: bad content length: %s", root->name, content_length);
+ return DATA_ERROR;
+ }
+ if (body_len > 0) {
+ conn->body_mode = BODY_KNOWN_LENGTH;
+ conn->body_length = body_len;
+ }
+ } else {
+ char* connection = http_request_find_header(r, "Proxy-Connection");
+
+ if (!connection)
+ connection = http_request_find_header(r, "Connection");
+
+ if (!connection || strcasecmp(connection, "Close")) {
+ /* hum, we can't support this at all */
+ PROXY_LOG("%s: can't determine content length, and client wants"
+ " to keep connection opened",
+ root->name);
+ return -1;
+ }
+ /* a negative value means that the data ends when the client
+ * disconnects the connection.
+ */
+ conn->body_mode = BODY_UNTIL_CLOSE;
+ }
+ transfer_encoding = http_request_find_header(r, "Transfer-Encoding");
+ if (transfer_encoding && !strcasecmp(transfer_encoding, "Chunked")) {
+ conn->body_mode = BODY_CHUNKED;
+ conn->parse_chunk_header = 0;
+ conn->parse_chunk_trailer = 0;
+ conn->chunk_length = -1;
+ conn->chunk_total = 0;
+ }
+ D("%s: body_length=%lld body_mode=%s",
+ root->name, conn->body_length,
+ body_mode_str[conn->body_mode]);
+
+ proxy_connection_rewind(root);
+ return 0;
+}
+
+#define MAX_BODY_BUFFER 65536
+
+static DataStatus
+rewrite_connection_read_body( RewriteConnection* conn, int fd )
+{
+ ProxyConnection* root = conn->root;
+ stralloc_t* str = root->str;
+ int wanted = 0, current, avail;
+ DataStatus ret;
+
+ if (conn->body_is_closed) {
+ return DATA_NEED_MORE;
+ }
+
+ /* first, determine how many bytes we want to read. */
+ switch (conn->body_mode) {
+ case BODY_NONE:
+ D("%s: INTERNAL ERROR: SHOULDN'T BE THERE", root->name);
+ return DATA_COMPLETED;
+
+ case BODY_KNOWN_LENGTH:
+ {
+ if (conn->body_length == 0)
+ return DATA_COMPLETED;
+
+ if (conn->body_length > MAX_BODY_BUFFER)
+ wanted = MAX_BODY_BUFFER;
+ else
+ wanted = (int)conn->body_length;
+ }
+ break;
+
+ case BODY_UNTIL_CLOSE:
+ wanted = MAX_BODY_BUFFER;
+ break;
+
+ case BODY_CHUNKED:
+ if (conn->chunk_length < 0) {
+ /* chunk_length < 0 means we need to read a chunk header */
+ /* ensure that 'str' is flushed before doing this */
+ if (!conn->parse_chunk_header) {
+ if (conn->body_has_data)
+ return DATA_NEED_MORE;
+ D("%s: waiting chunk header", root->name);
+ conn->parse_chunk_header = 1;
+ }
+ ret = proxy_connection_receive_line(root, fd);
+ if (ret == DATA_COMPLETED) {
+ char* line = str->s;
+ char* end;
+ long long length;
+
+ length = strtoll(line, &end, 16);
+ if (line[0] == ' ' || (end[0] != '\0' && end[0] != ';')) {
+ PROXY_LOG("%s: invalid chunk header: %s",
+ root->name, line);
+ return DATA_ERROR;
+ }
+ if (length < 0) {
+ PROXY_LOG("%s: invalid chunk length %lld",
+ root->name, length);
+ return DATA_ERROR;
+ }
+ conn->chunk_length = length;
+ conn->chunk_total = 0;
+ if (length == 0) {
+ /* the last chunk, no we need to add the trailer */
+ conn->parse_chunk_trailer = 0;
+ }
+ conn->parse_chunk_header = 0;
+ }
+ }
+
+ if (conn->chunk_length == 0) {
+ /* chunk_length == 0 means we're reading the chunk trailer */
+ /* ensure that 'str' is flushed before reading the trailer */
+ if (!conn->parse_chunk_trailer) {
+ if (conn->body_has_data)
+ return DATA_NEED_MORE;
+ conn->parse_chunk_trailer = 1;
+ }
+ ret = rewrite_connection_read_headers(conn, fd);
+ if (ret == DATA_COMPLETED) {
+ conn->body_is_closed = 1;
+ }
+ return ret;
+ }
+
+ /* if we get here, body_length > 0 */
+ if (conn->chunk_length > MAX_BODY_BUFFER)
+ wanted = MAX_BODY_BUFFER;
+ else
+ wanted = (int)conn->chunk_length;
+ break;
+
+ default:
+ ;
+ }
+
+ /* we don't want more than MAX_BODY_BUFFER bytes in the
+ * buffer we used to pass the body */
+ current = str->n;
+ avail = MAX_BODY_BUFFER - current;
+ if (avail <= 0) {
+ /* wait for some flush */
+ conn->body_is_full = 1;
+ D("%s: waiting to flush %d bytes",
+ root->name, current);
+ return DATA_NEED_MORE;
+ }
+
+ if (wanted > avail)
+ wanted = avail;
+
+ ret = proxy_connection_receive(root, fd, wanted);
+ conn->body_has_data = (str->n > 0);
+ conn->body_is_full = (str->n == MAX_BODY_BUFFER);
+
+ if (ret == DATA_ERROR) {
+ if (conn->body_mode == BODY_UNTIL_CLOSE) {
+ /* a disconnection here is normal and signals the
+ * end of the body */
+ conn->body_total += root->str_recv;
+ D("%s: body completed by close (%lld bytes)",
+ root->name, conn->body_total);
+ conn->body_is_closed = 1;
+ ret = DATA_COMPLETED;
+ }
+ } else {
+ avail = root->str_recv;
+ ret = DATA_NEED_MORE; /* we're not really done yet */
+
+ switch (conn->body_mode) {
+ case BODY_CHUNKED:
+ conn->chunk_total += avail;
+ conn->chunk_length -= avail;
+
+ if (conn->chunk_length == 0) {
+ D("%s: chunk completed (%lld bytes)",
+ root->name, conn->chunk_length);
+ conn->body_total += conn->chunk_total;
+ conn->chunk_total = 0;
+ conn->chunk_length = -1;
+ }
+ break;
+
+ case BODY_KNOWN_LENGTH:
+ conn->body_length -= avail;
+ conn->body_total += avail;
+
+ if (conn->body_length == 0) {
+ D("%s: body completed (%lld bytes)",
+ root->name, conn->body_total);
+ conn->body_is_closed = 1;
+ ret = DATA_COMPLETED;
+ }
+ break;
+
+ case BODY_UNTIL_CLOSE:
+ conn->body_total += avail;
+ break;
+
+ default:
+ ;
+ }
+ }
+ return ret;
+}
+
+static DataStatus
+rewrite_connection_send_body( RewriteConnection* conn, int fd )
+{
+ ProxyConnection* root = conn->root;
+ stralloc_t* str = root->str;
+ DataStatus ret = DATA_NEED_MORE;
+
+ if (conn->body_has_data) {
+ ret = proxy_connection_send(root, fd);
+ if (ret != DATA_ERROR) {
+ int pos = root->str_pos;
+
+ memmove(str->s, str->s+pos, str->n-pos);
+ str->n -= pos;
+ root->str_pos = 0;
+ conn->body_is_full = (str->n == MAX_BODY_BUFFER);
+ conn->body_has_data = (str->n > 0);
+ conn->body_sent += root->str_sent;
+
+ /* ensure that we return DATA_COMPLETED only when
+ * we have sent everything, and there is no more
+ * body pieces to read */
+ if (ret == DATA_COMPLETED) {
+ if (!conn->body_is_closed || conn->body_has_data)
+ ret = DATA_NEED_MORE;
+ else {
+ D("%s: sent all body (%lld bytes)",
+ root->name, conn->body_sent);
+ }
+ }
+ D("%s: sent closed=%d data=%d n=%d ret=%d",
+ root->name, conn->body_is_closed,
+ conn->body_has_data, str->n,
+ ret);
+ }
+ }
+ return ret;
+}
+
+
+static void
+rewrite_connection_select( ProxyConnection* root,
+ ProxySelect* sel )
+{
+ RewriteConnection* conn = (RewriteConnection*)root;
+ int slirp = conn->slirp_fd;
+ int proxy = root->socket;
+
+ switch (conn->state) {
+ case STATE_CONNECTING:
+ case STATE_CREATE_SOCKET_PAIR:
+ /* try to connect to the proxy server */
+ proxy_select_set( sel, proxy, PROXY_SELECT_WRITE );
+ break;
+
+ case STATE_REQUEST_FIRST_LINE:
+ case STATE_REQUEST_HEADERS:
+ proxy_select_set( sel, slirp, PROXY_SELECT_READ );
+ break;
+
+ case STATE_REQUEST_SEND:
+ proxy_select_set( sel, proxy, PROXY_SELECT_WRITE );
+ break;
+
+ case STATE_REQUEST_BODY:
+ if (!conn->body_is_closed && !conn->body_is_full)
+ proxy_select_set( sel, slirp, PROXY_SELECT_READ );
+
+ if (conn->body_has_data)
+ proxy_select_set( sel, proxy, PROXY_SELECT_WRITE );
+ break;
+
+ case STATE_REPLY_FIRST_LINE:
+ case STATE_REPLY_HEADERS:
+ proxy_select_set( sel, proxy, PROXY_SELECT_READ );
+ break;
+
+ case STATE_REPLY_SEND:
+ proxy_select_set( sel, slirp, PROXY_SELECT_WRITE );
+ break;
+
+ case STATE_REPLY_BODY:
+ if (conn->body_has_data)
+ proxy_select_set( sel, slirp, PROXY_SELECT_WRITE );
+
+ if (!conn->body_is_closed && !conn->body_is_full)
+ proxy_select_set( sel, proxy, PROXY_SELECT_READ );
+ break;
+ default:
+ ;
+ };
+}
+
+static void
+rewrite_connection_poll( ProxyConnection* root,
+ ProxySelect* sel )
+{
+ RewriteConnection* conn = (RewriteConnection*)root;
+
+ int slirp = conn->slirp_fd;
+ int proxy = root->socket;
+ int has_slirp = proxy_select_poll(sel, slirp);
+ int has_proxy = proxy_select_poll(sel, proxy);
+ DataStatus ret = DATA_NEED_MORE;
+
+ switch (conn->state) {
+ case STATE_CONNECTING:
+ if (has_proxy) {
+ PROXY_LOG("%s: connected to proxy", root->name);
+ conn->state = STATE_CREATE_SOCKET_PAIR;
+ }
+ break;
+
+ case STATE_CREATE_SOCKET_PAIR:
+ if (has_proxy) {
+ if (rewrite_connection_create_sockets(conn) < 0) {
+ ret = DATA_ERROR;
+ } else {
+ D("%s: socket pair created", root->name);
+ conn->state = STATE_REQUEST_FIRST_LINE;
+ }
+ }
+ break;
+
+ case STATE_REQUEST_FIRST_LINE:
+ if (has_slirp) {
+ ret = rewrite_connection_read_request(conn);
+ if (ret == DATA_COMPLETED) {
+ PROXY_LOG("%s: request first line ok", root->name);
+ conn->state = STATE_REQUEST_HEADERS;
+ }
+ }
+ break;
+
+ case STATE_REQUEST_HEADERS:
+ if (has_slirp) {
+ ret = rewrite_connection_read_headers(conn, slirp);
+ if (ret == DATA_COMPLETED) {
+ PROXY_LOG("%s: request headers ok", root->name);
+ if (rewrite_connection_rewrite_request(conn) < 0)
+ ret = DATA_ERROR;
+ else
+ conn->state = STATE_REQUEST_SEND;
+ }
+ }
+ break;
+
+ case STATE_REQUEST_SEND:
+ if (has_proxy) {
+ ret = proxy_connection_send(root, proxy);
+ if (ret == DATA_COMPLETED) {
+ if (rewrite_connection_get_body_length(conn, 1) < 0) {
+ ret = DATA_ERROR;
+ } else if (conn->body_mode != BODY_NONE) {
+ PROXY_LOG("%s: request sent, waiting for body",
+ root->name);
+ conn->state = STATE_REQUEST_BODY;
+ } else {
+ PROXY_LOG("%s: request sent, waiting for reply",
+ root->name);
+ conn->state = STATE_REPLY_FIRST_LINE;
+ }
+ }
+ }
+ break;
+
+ case STATE_REQUEST_BODY:
+ if (has_slirp) {
+ ret = rewrite_connection_read_body(conn, slirp);
+ }
+ if (ret != DATA_ERROR && has_proxy) {
+ ret = rewrite_connection_send_body(conn, proxy);
+ if (ret == DATA_COMPLETED) {
+ PROXY_LOG("%s: request body ok, waiting for reply",
+ root->name);
+ conn->state = STATE_REPLY_FIRST_LINE;
+ }
+ }
+ break;
+
+ case STATE_REPLY_FIRST_LINE:
+ if (has_proxy) {
+ ret = rewrite_connection_read_reply(conn);
+ if (ret == DATA_COMPLETED) {
+ PROXY_LOG("%s: reply first line ok", root->name);
+ conn->state = STATE_REPLY_HEADERS;
+ }
+ }
+ break;
+
+ case STATE_REPLY_HEADERS:
+ if (has_proxy) {
+ ret = rewrite_connection_read_headers(conn, proxy);
+ if (ret == DATA_COMPLETED) {
+ PROXY_LOG("%s: reply headers ok", root->name);
+ if (rewrite_connection_rewrite_reply(conn) < 0)
+ ret = DATA_ERROR;
+ else
+ conn->state = STATE_REPLY_SEND;
+ }
+ }
+ break;
+
+ case STATE_REPLY_SEND:
+ if (has_slirp) {
+ ret = proxy_connection_send(conn->root, slirp);
+ if (ret == DATA_COMPLETED) {
+ if (rewrite_connection_get_body_length(conn, 0) < 0) {
+ ret = DATA_ERROR;
+ } else if (conn->body_mode != BODY_NONE) {
+ PROXY_LOG("%s: reply sent, waiting for body",
+ root->name);
+ conn->state = STATE_REPLY_BODY;
+ } else {
+ PROXY_LOG("%s: reply sent, looping to waiting request",
+ root->name);
+ conn->state = STATE_REQUEST_FIRST_LINE;
+ }
+ }
+ }
+ break;
+
+ case STATE_REPLY_BODY:
+ if (has_proxy) {
+ ret = rewrite_connection_read_body(conn, proxy);
+ }
+ if (ret != DATA_ERROR && has_slirp) {
+ ret = rewrite_connection_send_body(conn, slirp);
+ if (ret == DATA_COMPLETED) {
+ if (conn->body_mode == BODY_UNTIL_CLOSE) {
+ PROXY_LOG("%s: closing connection", root->name);
+ ret = DATA_ERROR;
+ } else {
+ PROXY_LOG("%s: reply body ok, looping to waiting request",
+ root->name);
+ conn->state = STATE_REQUEST_FIRST_LINE;
+ }
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+ if (ret == DATA_ERROR)
+ proxy_connection_free(root, 0, PROXY_EVENT_NONE);
+
+ return;
+}
+
+
+ProxyConnection*
+http_rewriter_connect( HttpService* service,
+ struct sockaddr_in* address )
+{
+ RewriteConnection* conn;
+ int s;
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return NULL;
+
+ conn = qemu_mallocz(sizeof(*conn));
+ if (conn == NULL) {
+ socket_close(s);
+ return NULL;
+ }
+
+ proxy_connection_init( conn->root, s, address, service->root,
+ rewrite_connection_free,
+ rewrite_connection_select,
+ rewrite_connection_poll );
+
+ if ( rewrite_connection_init( conn ) < 0 ) {
+ rewrite_connection_free( conn->root );
+ return NULL;
+ }
+
+ return conn->root;
+}
diff --git a/proxy/proxy_int.h b/proxy/proxy_int.h
index 9d91169..e71d9d6 100644
--- a/proxy/proxy_int.h
+++ b/proxy/proxy_int.h
@@ -14,6 +14,7 @@
#include "proxy_common.h"
#include "sockets.h"
+#include "android_utils.h"
extern int proxy_log;
@@ -24,11 +25,44 @@ proxy_LOG(const char* fmt, ...);
do { if (proxy_log) proxy_LOG(__VA_ARGS__); } while (0)
+/* ProxySelect is used to handle events */
+
+enum {
+ PROXY_SELECT_READ = (1 << 0),
+ PROXY_SELECT_WRITE = (1 << 1),
+ PROXY_SELECT_ERROR = (1 << 2)
+};
+
+typedef struct {
+ int* pcount;
+ fd_set* reads;
+ fd_set* writes;
+ fd_set* errors;
+} ProxySelect;
+
+extern void proxy_select_set( ProxySelect* sel,
+ int fd,
+ unsigned flags );
+
+extern unsigned proxy_select_poll( ProxySelect* sel, int fd );
+
+
/* sockets proxy manager internals */
typedef struct ProxyConnection ProxyConnection;
typedef struct ProxyService ProxyService;
+/* free a given proxified connection */
+typedef void (*ProxyConnectionFreeFunc) ( ProxyConnection* conn );
+
+/* modify the ProxySelect to tell which events to listen to */
+typedef void (*ProxyConnectionSelectFunc) ( ProxyConnection* conn,
+ ProxySelect* sel );
+
+/* action a proxy connection when select() returns certain events for its socket */
+typedef void (*ProxyConnectionPollFunc) ( ProxyConnection* conn,
+ ProxySelect* sel );
+
/* root ProxyConnection object */
struct ProxyConnection {
@@ -42,51 +76,93 @@ struct ProxyConnection {
/* the following is useful for all types of services */
char name[64]; /* for debugging purposes */
- int buffer_pos;
- int buffer_len;
- char* buffer;
- char buffer0[ 1024 ];
- /* rest of data depend on ProxyService */
+ stralloc_t str[1]; /* network buffer (dynamic) */
+ int str_pos; /* see proxy_connection_send() */
+ int str_sent; /* see proxy_connection_send() */
+ int str_recv; /* see proxy_connection_receive() */
+
+ /* connection methods */
+ ProxyConnectionFreeFunc conn_free;
+ ProxyConnectionSelectFunc conn_select;
+ ProxyConnectionPollFunc conn_poll;
+
+ /* rest of data depend on exact implementation */
};
extern void
-proxy_connection_init( ProxyConnection* conn,
- int socket,
- struct sockaddr_in* address,
- ProxyService* service );
+proxy_connection_init( ProxyConnection* conn,
+ int socket,
+ struct sockaddr_in* address,
+ ProxyService* service,
+ ProxyConnectionFreeFunc conn_free,
+ ProxyConnectionSelectFunc conn_select,
+ ProxyConnectionPollFunc conn_poll );
extern void
proxy_connection_done( ProxyConnection* conn );
+/* free the proxy connection object. this will also
+ * close the corresponding socket unless the
+ * 'keep_alive' flag is set to TRUE.
+ */
extern void
proxy_connection_free( ProxyConnection* conn,
+ int keep_alive,
ProxyEvent event );
-/* tries to send data from the connection's buffer to the proxy.
- * returns 1 when all data has been sent (i.e. buffer_pos == buffer_len),
- * 0 if there is still some data to send, or -1 in case of error
+/* status of data transfer operations */
+typedef enum {
+ DATA_ERROR = -1,
+ DATA_NEED_MORE = 0,
+ DATA_COMPLETED = 1
+} DataStatus;
+
+/* try to send data from the connection's buffer to a socket.
+ * starting from offset conn->str_pos in the buffer
+ *
+ * returns DATA_COMPLETED if everything could be written
+ * returns DATA_ERROR for a socket disconnection or error
+ * returns DATA_NEED_MORE if all data could not be sent.
+ *
+ * on exit, conn->str_sent contains the number of bytes
+ * that were really sent. conn->str_pos will be incremented
+ * by conn->str_sent as well.
+ *
+ * note that in case of success (DATA_COMPLETED), this also
+ * performs a proxy_connection_rewind which sets conn->str_pos
+ * to 0.
*/
-extern int
-proxy_connection_send( ProxyConnection* conn );
-
-/* tries to receive data from the connection's buffer from the proxy
- * returns 1 when all data has been received (buffer_pos == buffer_len)
- * returns 0 if there is still some data to receive
- * returns -1 in case of error
+extern DataStatus
+proxy_connection_send( ProxyConnection* conn, int fd );
+
+/* try to read 'wanted' bytes into conn->str from a socket
+ *
+ * returns DATA_COMPLETED if all bytes could be read
+ * returns DATA_NEED_MORE if not all bytes could be read
+ * returns DATA_ERROR in case of socket disconnection or error
+ *
+ * on exit, the amount of data received is in conn->str_recv
*/
-extern int
-proxy_connection_receive( ProxyConnection* conn );
+extern DataStatus
+proxy_connection_receive( ProxyConnection* conn, int fd, int wanted );
-/* tries to receive a line of text from the proxy
+/* tries to receive a line of text from the proxy.
+ * when an entire line is read, the trailing \r\n is stripped
+ * and replaced by a terminating zero. str->n will be the
+ * lenght of the line, exclusing the terminating zero.
* returns 1 when a line has been received
* returns 0 if there is still some data to receive
* returns -1 in case of error
*/
-extern int
-proxy_connection_receive_line( ProxyConnection* conn );
+extern DataStatus
+proxy_connection_receive_line( ProxyConnection* conn, int fd );
+
+/* rewind the string buffer for a new operation */
+extern void
+proxy_connection_rewind( ProxyConnection* conn );
/* base64 encode a source string, returns size of encoded result,
* or -1 if there was not enough room in the destination buffer
@@ -103,38 +179,19 @@ proxy_resolve_server( struct sockaddr_in* addr,
/* a ProxyService is really a proxy server and associated options */
-enum {
- PROXY_SELECT_READ = (1 << 0),
- PROXY_SELECT_WRITE = (1 << 1),
- PROXY_SELECT_ERROR = (1 << 2)
-};
-
/* destroy a given proxy service */
typedef void (*ProxyServiceFreeFunc) ( void* opaque );
/* tries to create a new proxified connection, returns NULL if the service can't
* handle this address */
typedef ProxyConnection* (*ProxyServiceConnectFunc)( void* opaque,
- int socket,
+ int socket_type,
struct sockaddr_in* address );
-/* free a given proxified connection */
-typedef void (*ProxyConnectionFreeFunc) ( ProxyConnection* conn );
-
-/* return flags corresponding to the select() events to wait to a proxified connection */
-typedef unsigned (*ProxyConnectionSelectFunc) ( ProxyConnection* conn );
-
-/* action a proxy connection when select() returns certain events for its socket */
-typedef void (*ProxyConnectionPollFunc) ( ProxyConnection* conn,
- unsigned select_flags );
-
struct ProxyService {
void* opaque;
ProxyServiceFreeFunc serv_free;
ProxyServiceConnectFunc serv_connect;
- ProxyConnectionFreeFunc conn_free;
- ProxyConnectionSelectFunc conn_select;
- ProxyConnectionPollFunc conn_poll;
};
extern int
@@ -142,4 +199,3 @@ proxy_manager_add_service( ProxyService* service );
#endif /* _PROXY_INT_H */
-
diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh
deleted file mode 100644
index bd278d9..0000000
--- a/qemu-binfmt-conf.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-# enable automatic i386/ARM/SPARC/PPC program execution by the kernel
-
-# load the binfmt_misc module
-/sbin/modprobe binfmt_misc
-
-# probe cpu type
-cpu=`uname -m`
-case "$cpu" in
- i386|i486|i586|i686|i86pc|BePC)
- cpu="i386"
- ;;
- "Power Macintosh"|ppc|ppc64)
- cpu="ppc"
- ;;
- armv4l)
- cpu="arm"
- ;;
-esac
-
-# register the interpreter for each cpu except for the native one
-if [ $cpu != "i386" ] ; then
- echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
- echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
-fi
-if [ $cpu != "arm" ] ; then
- echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register
- echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register
-fi
-if [ $cpu != "sparc" ] ; then
- echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register
-fi
-if [ $cpu != "ppc" ] ; then
- echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register
-fi
-if [ $cpu != "mips" ] ; then
- echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register
- echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register
-fi
diff --git a/qemu-doc.texi b/qemu-doc.texi
deleted file mode 100644
index ddf0456..0000000
--- a/qemu-doc.texi
+++ /dev/null
@@ -1,1875 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-@c %**start of header
-@setfilename qemu-doc.info
-@settitle QEMU CPU Emulator User Documentation
-@exampleindent 0
-@paragraphindent 0
-@c %**end of header
-
-@iftex
-@titlepage
-@sp 7
-@center @titlefont{QEMU CPU Emulator}
-@sp 1
-@center @titlefont{User Documentation}
-@sp 3
-@end titlepage
-@end iftex
-
-@ifnottex
-@node Top
-@top
-
-@menu
-* Introduction::
-* Installation::
-* QEMU PC System emulator::
-* QEMU System emulator for non PC targets::
-* QEMU Linux User space emulator::
-* compilation:: Compilation from the sources
-* Index::
-@end menu
-@end ifnottex
-
-@contents
-
-@node Introduction
-@chapter Introduction
-
-@menu
-* intro_features:: Features
-@end menu
-
-@node intro_features
-@section Features
-
-QEMU is a FAST! processor emulator using dynamic translation to
-achieve good emulation speed.
-
-QEMU has two operating modes:
-
-@itemize @minus
-
-@item
-Full system emulation. In this mode, QEMU emulates a full system (for
-example a PC), including one or several processors and various
-peripherals. It can be used to launch different Operating Systems
-without rebooting the PC or to debug system code.
-
-@item
-User mode emulation (Linux host only). In this mode, QEMU can launch
-Linux processes compiled for one CPU on another CPU. It can be used to
-launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
-to ease cross-compilation and cross-debugging.
-
-@end itemize
-
-QEMU can run without an host kernel driver and yet gives acceptable
-performance.
-
-For system emulation, the following hardware targets are supported:
-@itemize
-@item PC (x86 or x86_64 processor)
-@item ISA PC (old style PC without PCI bus)
-@item PREP (PowerPC processor)
-@item G3 BW PowerMac (PowerPC processor)
-@item Mac99 PowerMac (PowerPC processor, in progress)
-@item Sun4m (32-bit Sparc processor)
-@item Sun4u (64-bit Sparc processor, in progress)
-@item Malta board (32-bit MIPS processor)
-@item ARM Integrator/CP (ARM926E or 1026E processor)
-@item ARM Versatile baseboard (ARM926E)
-@end itemize
-
-For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported.
-
-@node Installation
-@chapter Installation
-
-If you want to compile QEMU yourself, see @ref{compilation}.
-
-@menu
-* install_linux:: Linux
-* install_windows:: Windows
-* install_mac:: Macintosh
-@end menu
-
-@node install_linux
-@section Linux
-
-If a precompiled package is available for your distribution - you just
-have to install it. Otherwise, see @ref{compilation}.
-
-@node install_windows
-@section Windows
-
-Download the experimental binary installer at
-@url{http://www.free.oszoo.org/@/download.html}.
-
-@node install_mac
-@section Mac OS X
-
-Download the experimental binary installer at
-@url{http://www.free.oszoo.org/@/download.html}.
-
-@node QEMU PC System emulator
-@chapter QEMU PC System emulator
-
-@menu
-* pcsys_introduction:: Introduction
-* pcsys_quickstart:: Quick Start
-* sec_invocation:: Invocation
-* pcsys_keys:: Keys
-* pcsys_monitor:: QEMU Monitor
-* disk_images:: Disk Images
-* pcsys_network:: Network emulation
-* direct_linux_boot:: Direct Linux Boot
-* pcsys_usb:: USB emulation
-* gdb_usage:: GDB usage
-* pcsys_os_specific:: Target OS specific information
-@end menu
-
-@node pcsys_introduction
-@section Introduction
-
-@c man begin DESCRIPTION
-
-The QEMU PC System emulator simulates the
-following peripherals:
-
-@itemize @minus
-@item
-i440FX host PCI bridge and PIIX3 PCI to ISA bridge
-@item
-Cirrus CLGD 5446 PCI VGA card or dummy VGA card with Bochs VESA
-extensions (hardware level, including all non standard modes).
-@item
-PS/2 mouse and keyboard
-@item
-2 PCI IDE interfaces with hard disk and CD-ROM support
-@item
-Floppy disk
-@item
-NE2000 PCI network adapters
-@item
-Serial ports
-@item
-Creative SoundBlaster 16 sound card
-@item
-ENSONIQ AudioPCI ES1370 sound card
-@item
-Adlib(OPL2) - Yamaha YM3812 compatible chip
-@item
-PCI UHCI USB controller and a virtual USB hub.
-@end itemize
-
-SMP is supported with up to 255 CPUs.
-
-Note that adlib is only available when QEMU was configured with
--enable-adlib
-
-QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
-VGA BIOS.
-
-QEMU uses YM3812 emulation by Tatsuyuki Satoh.
-
-@c man end
-
-@node pcsys_quickstart
-@section Quick Start
-
-Download and uncompress the linux image (@file{linux.img}) and type:
-
-@example
-qemu linux.img
-@end example
-
-Linux should boot and give you a prompt.
-
-@node sec_invocation
-@section Invocation
-
-@example
-@c man begin SYNOPSIS
-usage: qemu [options] [disk_image]
-@c man end
-@end example
-
-@c man begin OPTIONS
-@var{disk_image} is a raw hard disk image for IDE hard disk 0.
-
-General options:
-@table @option
-@item -M machine
-Select the emulated machine (@code{-M ?} for list)
-
-@item -fda file
-@item -fdb file
-Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
-use the host floppy by using @file{/dev/fd0} as filename.
-
-@item -hda file
-@item -hdb file
-@item -hdc file
-@item -hdd file
-Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
-
-@item -cdrom file
-Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and
-@option{-cdrom} at the same time). You can use the host CD-ROM by
-using @file{/dev/cdrom} as filename.
-
-@item -boot [a|c|d]
-Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is
-the default.
-
-@item -snapshot
-Write to temporary files instead of disk image files. In this case,
-the raw disk image you use is not written back. You can however force
-the write back by pressing @key{C-a s} (@pxref{disk_images}).
-
-@item -no-fd-bootchk
-Disable boot signature checking for floppy disks in Bochs BIOS. It may
-be needed to boot from old floppy disks.
-
-@item -m megs
-Set virtual RAM size to @var{megs} megabytes. Default is 128 MB.
-
-@item -smp n
-Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255
-CPUs are supported.
-
-@item -nographic
-
-Normally, QEMU uses SDL to display the VGA output. With this option,
-you can totally disable graphical output so that QEMU is a simple
-command line application. The emulated serial port is redirected on
-the console. Therefore, you can still use QEMU to debug a Linux kernel
-with a serial console.
-
-@item -vnc d
-
-Normally, QEMU uses SDL to display the VGA output. With this option,
-you can have QEMU listen on VNC display @var{d} and redirect the VGA
-display over the VNC session. It is very useful to enable the usb
-tablet device when using this option (option @option{-usbdevice
-tablet}). When using the VNC display, you must use the @option{-k}
-option to set the keyboard layout.
-
-@item -k language
-
-Use keyboard layout @var{language} (for example @code{fr} for
-French). This option is only needed where it is not easy to get raw PC
-keycodes (e.g. on Macs, with some X11 servers or with a VNC
-display). You don't normally need to use it on PC/Linux or PC/Windows
-hosts.
-
-The available layouts are:
-@example
-ar de-ch es fo fr-ca hu ja mk no pt-br sv
-da en-gb et fr fr-ch is lt nl pl ru th
-de en-us fi fr-be hr it lv nl-be pt sl tr
-@end example
-
-The default is @code{en-us}.
-
-@item -audio-help
-
-Will show the audio subsystem help: list of drivers, tunable
-parameters.
-
-@item -soundhw card1,card2,... or -soundhw all
-
-Enable audio and selected sound hardware. Use ? to print all
-available sound hardware.
-
-@example
-qemu -soundhw sb16,adlib hda
-qemu -soundhw es1370 hda
-qemu -soundhw all hda
-qemu -soundhw ?
-@end example
-
-@item -localtime
-Set the real time clock to local time (the default is to UTC
-time). This option is needed to have correct date in MS-DOS or
-Windows.
-
-@item -full-screen
-Start in full screen.
-
-@item -pidfile file
-Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
-from a script.
-
-@item -win2k-hack
-Use it when installing Windows 2000 to avoid a disk full bug. After
-Windows 2000 is installed, you no longer need this option (this option
-slows down the IDE transfers).
-
-@end table
-
-USB options:
-@table @option
-
-@item -usb
-Enable the USB driver (will be the default soon)
-
-@item -usbdevice devname
-Add the USB device @var{devname}. @xref{usb_devices}.
-@end table
-
-Network options:
-
-@table @option
-
-@item -net nic[,vlan=n][,macaddr=addr][,model=type]
-Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
-= 0 is the default). The NIC is currently an NE2000 on the PC
-target. Optionally, the MAC address can be changed. If no
-@option{-net} option is specified, a single NIC is created.
-Qemu can emulate several different models of network card. Valid values for
-@var{type} are @code{ne2k_pci}, @code{ne2k_isa}, @code{rtl8139},
-@code{smc91c111} and @code{lance}. Not all devices are supported on all
-targets.
-
-@item -net user[,vlan=n][,hostname=name]
-Use the user mode network stack which requires no administrator
-priviledge to run. @option{hostname=name} can be used to specify the client
-hostname reported by the builtin DHCP server.
-
-@item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file]
-Connect the host TAP network interface @var{name} to VLAN @var{n} and
-use the network script @var{file} to configure it. The default
-network script is @file{/etc/qemu-ifup}. If @var{name} is not
-provided, the OS automatically provides one. @option{fd=h} can be
-used to specify the handle of an already opened host TAP interface. Example:
-
-@example
-qemu linux.img -net nic -net tap
-@end example
-
-More complicated example (two NICs, each one connected to a TAP device)
-@example
-qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
- -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
-@end example
-
-
-@item -net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]
-
-Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
-machine using a TCP socket connection. If @option{listen} is
-specified, QEMU waits for incoming connections on @var{port}
-(@var{host} is optional). @option{connect} is used to connect to
-another QEMU instance using the @option{listen} option. @option{fd=h}
-specifies an already opened TCP socket.
-
-Example:
-@example
-# launch a first QEMU instance
-qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
- -net socket,listen=:1234
-# connect the VLAN 0 of this instance to the VLAN 0
-# of the first instance
-qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
- -net socket,connect=127.0.0.1:1234
-@end example
-
-@item -net socket[,vlan=n][,fd=h][,mcast=maddr:port]
-
-Create a VLAN @var{n} shared with another QEMU virtual
-machines using a UDP multicast socket, effectively making a bus for
-every QEMU with same multicast address @var{maddr} and @var{port}.
-NOTES:
-@enumerate
-@item
-Several QEMU can be running on different hosts and share same bus (assuming
-correct multicast setup for these hosts).
-@item
-mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see
-@url{http://user-mode-linux.sf.net}.
-@item Use @option{fd=h} to specify an already opened UDP multicast socket.
-@end enumerate
-
-Example:
-@example
-# launch one QEMU instance
-qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
- -net socket,mcast=230.0.0.1:1234
-# launch another QEMU instance on same "bus"
-qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
- -net socket,mcast=230.0.0.1:1234
-# launch yet another QEMU instance on same "bus"
-qemu linux.img -net nic,macaddr=52:54:00:12:34:58 \
- -net socket,mcast=230.0.0.1:1234
-@end example
-
-Example (User Mode Linux compat.):
-@example
-# launch QEMU instance (note mcast address selected
-# is UML's default)
-qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
- -net socket,mcast=239.192.168.1:1102
-# launch UML
-/path/to/linux ubd0=/path/to/root_fs eth0=mcast
-@end example
-
-@item -net none
-Indicate that no network devices should be configured. It is used to
-override the default configuration (@option{-net nic -net user}) which
-is activated if no @option{-net} options are provided.
-
-@item -tftp prefix
-When using the user mode network stack, activate a built-in TFTP
-server. All filenames beginning with @var{prefix} can be downloaded
-from the host to the guest using a TFTP client. The TFTP client on the
-guest must be configured in binary mode (use the command @code{bin} of
-the Unix TFTP client). The host IP address on the guest is as usual
-10.0.2.2.
-
-@item -smb dir
-When using the user mode network stack, activate a built-in SMB
-server so that Windows OSes can access to the host files in @file{dir}
-transparently.
-
-In the guest Windows OS, the line:
-@example
-10.0.2.4 smbserver
-@end example
-must be added in the file @file{C:\WINDOWS\LMHOSTS} (for windows 9x/Me)
-or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000).
-
-Then @file{dir} can be accessed in @file{\\smbserver\qemu}.
-
-Note that a SAMBA server must be installed on the host OS in
-@file{/usr/sbin/smbd}. QEMU was tested succesfully with smbd version
-2.2.7a from the Red Hat 9 and version 3.0.10-1.fc3 from Fedora Core 3.
-
-@item -redir [tcp|udp]:host-port:[guest-host]:guest-port
-
-When using the user mode network stack, redirect incoming TCP or UDP
-connections to the host port @var{host-port} to the guest
-@var{guest-host} on guest port @var{guest-port}. If @var{guest-host}
-is not specified, its value is 10.0.2.15 (default address given by the
-built-in DHCP server).
-
-For example, to redirect host X11 connection from screen 1 to guest
-screen 0, use the following:
-
-@example
-# on the host
-qemu -redir tcp:6001::6000 [...]
-# this host xterm should open in the guest X11 server
-xterm -display :1
-@end example
-
-To redirect telnet connections from host port 5555 to telnet port on
-the guest, use the following:
-
-@example
-# on the host
-qemu -redir tcp:5555::23 [...]
-telnet localhost 5555
-@end example
-
-Then when you use on the host @code{telnet localhost 5555}, you
-connect to the guest telnet server.
-
-@end table
-
-Linux boot specific: When using these options, you can use a given
-Linux kernel without installing it in the disk image. It can be useful
-for easier testing of various kernels.
-
-@table @option
-
-@item -kernel bzImage
-Use @var{bzImage} as kernel image.
-
-@item -append cmdline
-Use @var{cmdline} as kernel command line
-
-@item -initrd file
-Use @var{file} as initial ram disk.
-
-@end table
-
-Debug/Expert options:
-@table @option
-
-@item -serial dev
-Redirect the virtual serial port to host character device
-@var{dev}. The default device is @code{vc} in graphical mode and
-@code{stdio} in non graphical mode.
-
-This option can be used several times to simulate up to 4 serials
-ports.
-
-Available character devices are:
-@table @code
-@item vc
-Virtual console
-@item pty
-[Linux only] Pseudo TTY (a new PTY is automatically allocated)
-@item null
-void device
-@item /dev/XXX
-[Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
-parameters are set according to the emulated ones.
-@item /dev/parportN
-[Linux only, parallel port only] Use host parallel port
-@var{N}. Currently only SPP parallel port features can be used.
-@item file:filename
-Write output to filename. No character can be read.
-@item stdio
-[Unix only] standard input/output
-@item pipe:filename
-name pipe @var{filename}
-@item fdpair:fd1:fd2
-[Unix only] Use fd1 as input and fd2 as output (from the point of view of the emulator).
-@item COMn
-[Windows only] Use host serial port @var{n}
-@item udp:[remote_host]:remote_port[@@[src_ip]:src_port]
-This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specifed @var{src_port} a random port is automatically chosen.
-
-If you just want a simple readonly console you can use @code{netcat} or
-@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
-@code{nc -u -l -p 4555}. Any time qemu writes something to that port it
-will appear in the netconsole session.
-
-If you plan to send characters back via netconsole or you want to stop
-and start qemu a lot of times, you should have qemu use the same
-source port each time by using something like @code{-serial
-udp::4555@@:4556} to qemu. Another approach is to use a patched
-version of netcat which can listen to a TCP port and send and receive
-characters via udp. If you have a patched version of netcat which
-activates telnet remote echo and single char transfer, then you can
-use the following options to step up a netcat redirector to allow
-telnet on port 5555 to access the qemu port.
-@table @code
-@item Qemu Options:
--serial udp::4555@@:4556
-@item netcat options:
--u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T
-@item telnet options:
-localhost 5555
-@end table
-
-
-@item tcp:[host]:port[,server][,nowait]
-The TCP Net Console has two modes of operation. It can send the serial
-I/O to a location or wait for a connection from a location. By default
-the TCP Net Console is sent to @var{host} at the @var{port}. If you use
-the @var{,server} option QEMU will wait for a client socket application
-to connect to the port before continuing, unless the @code{,nowait}
-option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only
-one TCP connection at a time is accepted. You can use @code{telnet} to
-connect to the corresponding character device.
-@table @code
-@item Example to send tcp console to 192.168.0.2 port 4444
--serial tcp:192.168.0.2:4444
-@item Example to listen and wait on port 4444 for connection
--serial tcp::4444,server
-@item Example to not wait and listen on ip 192.168.0.100 port 4444
--serial tcp:192.168.0.100:4444,server,nowait
-@end table
-
-@item telnet:host:port[,server][,nowait]
-The telnet protocol is used instead of raw tcp sockets. The options
-work the same as if you had specified @code{-serial tcp}. The
-difference is that the port acts like a telnet server or client using
-telnet option negotiation. This will also allow you to send the
-MAGIC_SYSRQ sequence if you use a telnet that supports sending the break
-sequence. Typically in unix telnet you do it with Control-] and then
-type "send break" followed by pressing the enter key.
-
-@end table
-
-@item -parallel dev
-Redirect the virtual parallel port to host device @var{dev} (same
-devices as the serial port). On Linux hosts, @file{/dev/parportN} can
-be used to use hardware devices connected on the corresponding host
-parallel port.
-
-This option can be used several times to simulate up to 3 parallel
-ports.
-
-@item -monitor dev
-Redirect the monitor to host device @var{dev} (same devices as the
-serial port).
-The default device is @code{vc} in graphical mode and @code{stdio} in
-non graphical mode.
-
-@item -s
-Wait gdb connection to port 1234 (@pxref{gdb_usage}).
-@item -p port
-Change gdb connection port.
-@item -S
-Do not start CPU at startup (you must type 'c' in the monitor).
-@item -d
-Output log in /tmp/qemu.log
-@item -hdachs c,h,s,[,t]
-Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
-@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
-translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
-all thoses parameters. This option is useful for old MS-DOS disk
-images.
-
-@item -std-vga
-Simulate a standard VGA card with Bochs VBE extensions (default is
-Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0
-VBE extensions (e.g. Windows XP) and if you want to use high
-resolution modes (>= 1280x1024x16) then you should use this option.
-
-@item -no-acpi
-Disable ACPI (Advanced Configuration and Power Interface) support. Use
-it if your guest OS complains about ACPI problems (PC target machine
-only).
-
-@item -loadvm file
-Start right away with a saved state (@code{loadvm} in monitor)
-@end table
-
-@c man end
-
-@node pcsys_keys
-@section Keys
-
-@c man begin OPTIONS
-
-During the graphical emulation, you can use the following keys:
-@table @key
-@item Ctrl-Alt-f
-Toggle full screen
-
-@item Ctrl-Alt-n
-Switch to virtual console 'n'. Standard console mappings are:
-@table @emph
-@item 1
-Target system display
-@item 2
-Monitor
-@item 3
-Serial port
-@end table
-
-@item Ctrl-Alt
-Toggle mouse and keyboard grab.
-@end table
-
-In the virtual consoles, you can use @key{Ctrl-Up}, @key{Ctrl-Down},
-@key{Ctrl-PageUp} and @key{Ctrl-PageDown} to move in the back log.
-
-During emulation, if you are using the @option{-nographic} option, use
-@key{Ctrl-a h} to get terminal commands:
-
-@table @key
-@item Ctrl-a h
-Print this help
-@item Ctrl-a x
-Exit emulatior
-@item Ctrl-a s
-Save disk data back to file (if -snapshot)
-@item Ctrl-a b
-Send break (magic sysrq in Linux)
-@item Ctrl-a c
-Switch between console and monitor
-@item Ctrl-a Ctrl-a
-Send Ctrl-a
-@end table
-@c man end
-
-@ignore
-
-@c man begin SEEALSO
-The HTML documentation of QEMU for more precise information and Linux
-user mode emulator invocation.
-@c man end
-
-@c man begin AUTHOR
-Fabrice Bellard
-@c man end
-
-@end ignore
-
-@node pcsys_monitor
-@section QEMU Monitor
-
-The QEMU monitor is used to give complex commands to the QEMU
-emulator. You can use it to:
-
-@itemize @minus
-
-@item
-Remove or insert removable medias images
-(such as CD-ROM or floppies)
-
-@item
-Freeze/unfreeze the Virtual Machine (VM) and save or restore its state
-from a disk file.
-
-@item Inspect the VM state without an external debugger.
-
-@end itemize
-
-@subsection Commands
-
-The following commands are available:
-
-@table @option
-
-@item help or ? [cmd]
-Show the help for all commands or just for command @var{cmd}.
-
-@item commit
-Commit changes to the disk images (if -snapshot is used)
-
-@item info subcommand
-show various information about the system state
-
-@table @option
-@item info network
-show the various VLANs and the associated devices
-@item info block
-show the block devices
-@item info registers
-show the cpu registers
-@item info history
-show the command line history
-@item info pci
-show emulated PCI device
-@item info usb
-show USB devices plugged on the virtual USB hub
-@item info usbhost
-show all USB host devices
-@end table
-
-@item q or quit
-Quit the emulator.
-
-@item eject [-f] device
-Eject a removable media (use -f to force it).
-
-@item change device filename
-Change a removable media.
-
-@item screendump filename
-Save screen into PPM image @var{filename}.
-
-@item log item1[,...]
-Activate logging of the specified items to @file{/tmp/qemu.log}.
-
-@item savevm filename
-Save the whole virtual machine state to @var{filename}.
-
-@item loadvm filename
-Restore the whole virtual machine state from @var{filename}.
-
-@item stop
-Stop emulation.
-
-@item c or cont
-Resume emulation.
-
-@item gdbserver [port]
-Start gdbserver session (default port=1234)
-
-@item x/fmt addr
-Virtual memory dump starting at @var{addr}.
-
-@item xp /fmt addr
-Physical memory dump starting at @var{addr}.
-
-@var{fmt} is a format which tells the command how to format the
-data. Its syntax is: @option{/@{count@}@{format@}@{size@}}
-
-@table @var
-@item count
-is the number of items to be dumped.
-
-@item format
-can be x (hexa), d (signed decimal), u (unsigned decimal), o (octal),
-c (char) or i (asm instruction).
-
-@item size
-can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86,
-@code{h} or @code{w} can be specified with the @code{i} format to
-respectively select 16 or 32 bit code instruction size.
-
-@end table
-
-Examples:
-@itemize
-@item
-Dump 10 instructions at the current instruction pointer:
-@example
-(qemu) x/10i $eip
-0x90107063: ret
-0x90107064: sti
-0x90107065: lea 0x0(%esi,1),%esi
-0x90107069: lea 0x0(%edi,1),%edi
-0x90107070: ret
-0x90107071: jmp 0x90107080
-0x90107073: nop
-0x90107074: nop
-0x90107075: nop
-0x90107076: nop
-@end example
-
-@item
-Dump 80 16 bit values at the start of the video memory.
-@smallexample
-(qemu) xp/80hx 0xb8000
-0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42
-0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41
-0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72
-0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73
-0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20
-0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720
-0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
-0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
-0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
-0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
-@end smallexample
-@end itemize
-
-@item p or print/fmt expr
-
-Print expression value. Only the @var{format} part of @var{fmt} is
-used.
-
-@item sendkey keys
-
-Send @var{keys} to the emulator. Use @code{-} to press several keys
-simultaneously. Example:
-@example
-sendkey ctrl-alt-f1
-@end example
-
-This command is useful to send keys that your graphical user interface
-intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
-
-@item system_reset
-
-Reset the system.
-
-@item usb_add devname
-
-Add the USB device @var{devname}. For details of available devices see
-@ref{usb_devices}
-
-@item usb_del devname
-
-Remove the USB device @var{devname} from the QEMU virtual USB
-hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor
-command @code{info usb} to see the devices you can remove.
-
-@end table
-
-@subsection Integer expressions
-
-The monitor understands integers expressions for every integer
-argument. You can use register names to get the value of specifics
-CPU registers by prefixing them with @emph{$}.
-
-@node disk_images
-@section Disk Images
-
-Since version 0.6.1, QEMU supports many disk image formats, including
-growable disk images (their size increase as non empty sectors are
-written), compressed and encrypted disk images.
-
-@menu
-* disk_images_quickstart:: Quick start for disk image creation
-* disk_images_snapshot_mode:: Snapshot mode
-* qemu_img_invocation:: qemu-img Invocation
-* disk_images_fat_images:: Virtual FAT disk images
-@end menu
-
-@node disk_images_quickstart
-@subsection Quick start for disk image creation
-
-You can create a disk image with the command:
-@example
-qemu-img create myimage.img mysize
-@end example
-where @var{myimage.img} is the disk image filename and @var{mysize} is its
-size in kilobytes. You can add an @code{M} suffix to give the size in
-megabytes and a @code{G} suffix for gigabytes.
-
-See @ref{qemu_img_invocation} for more information.
-
-@node disk_images_snapshot_mode
-@subsection Snapshot mode
-
-If you use the option @option{-snapshot}, all disk images are
-considered as read only. When sectors in written, they are written in
-a temporary file created in @file{/tmp}. You can however force the
-write back to the raw disk images by using the @code{commit} monitor
-command (or @key{C-a s} in the serial console).
-
-@node qemu_img_invocation
-@subsection @code{qemu-img} Invocation
-
-@include qemu-img.texi
-
-@node disk_images_fat_images
-@subsection Virtual FAT disk images
-
-QEMU can automatically create a virtual FAT disk image from a
-directory tree. In order to use it, just type:
-
-@example
-qemu linux.img -hdb fat:/my_directory
-@end example
-
-Then you access access to all the files in the @file{/my_directory}
-directory without having to copy them in a disk image or to export
-them via SAMBA or NFS. The default access is @emph{read-only}.
-
-Floppies can be emulated with the @code{:floppy:} option:
-
-@example
-qemu linux.img -fda fat:floppy:/my_directory
-@end example
-
-A read/write support is available for testing (beta stage) with the
-@code{:rw:} option:
-
-@example
-qemu linux.img -fda fat:floppy:rw:/my_directory
-@end example
-
-What you should @emph{never} do:
-@itemize
-@item use non-ASCII filenames ;
-@item use "-snapshot" together with ":rw:" ;
-@item expect it to work when loadvm'ing ;
-@item write to the FAT directory on the host system while accessing it with the guest system.
-@end itemize
-
-@node pcsys_network
-@section Network emulation
-
-QEMU can simulate several networks cards (NE2000 boards on the PC
-target) and can connect them to an arbitrary number of Virtual Local
-Area Networks (VLANs). Host TAP devices can be connected to any QEMU
-VLAN. VLAN can be connected between separate instances of QEMU to
-simulate large networks. For simpler usage, a non priviledged user mode
-network stack can replace the TAP device to have a basic network
-connection.
-
-@subsection VLANs
-
-QEMU simulates several VLANs. A VLAN can be symbolised as a virtual
-connection between several network devices. These devices can be for
-example QEMU virtual Ethernet cards or virtual Host ethernet devices
-(TAP devices).
-
-@subsection Using TAP network interfaces
-
-This is the standard way to connect QEMU to a real network. QEMU adds
-a virtual network device on your host (called @code{tapN}), and you
-can then configure it as if it was a real ethernet card.
-
-As an example, you can download the @file{linux-test-xxx.tar.gz}
-archive and copy the script @file{qemu-ifup} in @file{/etc} and
-configure properly @code{sudo} so that the command @code{ifconfig}
-contained in @file{qemu-ifup} can be executed as root. You must verify
-that your host kernel supports the TAP network interfaces: the
-device @file{/dev/net/tun} must be present.
-
-See @ref{direct_linux_boot} to have an example of network use with a
-Linux distribution and @ref{sec_invocation} to have examples of
-command lines using the TAP network interfaces.
-
-@subsection Using the user mode network stack
-
-By using the option @option{-net user} (default configuration if no
-@option{-net} option is specified), QEMU uses a completely user mode
-network stack (you don't need root priviledge to use the virtual
-network). The virtual network configuration is the following:
-
-@example
-
- QEMU VLAN <------> Firewall/DHCP server <-----> Internet
- | (10.0.2.2)
- |
- ----> DNS server (10.0.2.3)
- |
- ----> SMB server (10.0.2.4)
-@end example
-
-The QEMU VM behaves as if it was behind a firewall which blocks all
-incoming connections. You can use a DHCP client to automatically
-configure the network in the QEMU VM. The DHCP server assign addresses
-to the hosts starting from 10.0.2.15.
-
-In order to check that the user mode network is working, you can ping
-the address 10.0.2.2 and verify that you got an address in the range
-10.0.2.x from the QEMU virtual DHCP server.
-
-Note that @code{ping} is not supported reliably to the internet as it
-would require root priviledges. It means you can only ping the local
-router (10.0.2.2).
-
-When using the built-in TFTP server, the router is also the TFTP
-server.
-
-When using the @option{-redir} option, TCP or UDP connections can be
-redirected from the host to the guest. It allows for example to
-redirect X11, telnet or SSH connections.
-
-@subsection Connecting VLANs between QEMU instances
-
-Using the @option{-net socket} option, it is possible to make VLANs
-that span several QEMU instances. See @ref{sec_invocation} to have a
-basic example.
-
-@node direct_linux_boot
-@section Direct Linux Boot
-
-This section explains how to launch a Linux kernel inside QEMU without
-having to make a full bootable image. It is very useful for fast Linux
-kernel testing. The QEMU network configuration is also explained.
-
-@enumerate
-@item
-Download the archive @file{linux-test-xxx.tar.gz} containing a Linux
-kernel and a disk image.
-
-@item Optional: If you want network support (for example to launch X11 examples), you
-must copy the script @file{qemu-ifup} in @file{/etc} and configure
-properly @code{sudo} so that the command @code{ifconfig} contained in
-@file{qemu-ifup} can be executed as root. You must verify that your host
-kernel supports the TUN/TAP network interfaces: the device
-@file{/dev/net/tun} must be present.
-
-When network is enabled, there is a virtual network connection between
-the host kernel and the emulated kernel. The emulated kernel is seen
-from the host kernel at IP address 172.20.0.2 and the host kernel is
-seen from the emulated kernel at IP address 172.20.0.1.
-
-@item Launch @code{qemu.sh}. You should have the following output:
-
-@smallexample
-> ./qemu.sh
-Connected to host network interface: tun0
-Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
-BIOS-provided physical RAM map:
- BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
- BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
-32MB LOWMEM available.
-On node 0 totalpages: 8192
-zone(0): 4096 pages.
-zone(1): 4096 pages.
-zone(2): 0 pages.
-Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe @/ide5=noprobe console=ttyS0
-ide_setup: ide2=noprobe
-ide_setup: ide3=noprobe
-ide_setup: ide4=noprobe
-ide_setup: ide5=noprobe
-Initializing CPU#0
-Detected 2399.621 MHz processor.
-Console: colour EGA 80x25
-Calibrating delay loop... 4744.80 BogoMIPS
-Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, @/0k highmem)
-Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
-Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
-Mount cache hash table entries: 512 (order: 0, 4096 bytes)
-Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
-Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
-CPU: Intel Pentium Pro stepping 03
-Checking 'hlt' instruction... OK.
-POSIX conformance testing by UNIFIX
-Linux NET4.0 for Linux 2.4
-Based upon Swansea University Computer Society NET3.039
-Initializing RT netlink socket
-apm: BIOS not found.
-Starting kswapd
-Journalled Block Device driver loaded
-Detected PS/2 Mouse Port.
-pty: 256 Unix98 ptys configured
-Serial driver version 5.05c (2001-07-08) with no serial options enabled
-ttyS00 at 0x03f8 (irq = 4) is a 16450
-ne.c:v1.10 9/23/94 Donald Becker (becker@@scyld.com)
-Last modified Nov 1, 2000 by Paul Gortmaker
-NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
-eth0: NE2000 found at 0x300, using IRQ 9.
-RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
-Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4
-ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
-hda: QEMU HARDDISK, ATA DISK drive
-ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
-hda: attached ide-disk driver.
-hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63
-Partition check:
- hda:
-Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996
-NET4: Linux TCP/IP 1.0 for NET4.0
-IP Protocols: ICMP, UDP, TCP, IGMP
-IP: routing cache hash table of 512 buckets, 4Kbytes
-TCP: Hash tables configured (established 2048 bind 4096)
-NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
-EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
-VFS: Mounted root (ext2 filesystem).
-Freeing unused kernel memory: 64k freed
-
-Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003
-
-QEMU Linux test distribution (based on Redhat 9)
-
-Type 'exit' to halt the system
-
-sh-2.05b#
-@end smallexample
-
-@item
-Then you can play with the kernel inside the virtual serial console. You
-can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
-about the keys you can type inside the virtual serial console. In
-particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
-the Magic SysRq key.
-
-@item
-If the network is enabled, launch the script @file{/etc/linuxrc} in the
-emulator (don't forget the leading dot):
-@example
-. /etc/linuxrc
-@end example
-
-Then enable X11 connections on your PC from the emulated Linux:
-@example
-xhost +172.20.0.2
-@end example
-
-You can now launch @file{xterm} or @file{xlogo} and verify that you have
-a real Virtual Linux system !
-
-@end enumerate
-
-NOTES:
-@enumerate
-@item
-A 2.5.74 kernel is also included in the archive. Just
-replace the bzImage in qemu.sh to try it.
-
-@item
-In order to exit cleanly from qemu, you can do a @emph{shutdown} inside
-qemu. qemu will automatically exit when the Linux shutdown is done.
-
-@item
-You can boot slightly faster by disabling the probe of non present IDE
-interfaces. To do so, add the following options on the kernel command
-line:
-@example
-ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
-@end example
-
-@item
-The example disk image is a modified version of the one made by Kevin
-Lawton for the plex86 Project (@url{www.plex86.org}).
-
-@end enumerate
-
-@node pcsys_usb
-@section USB emulation
-
-QEMU emulates a PCI UHCI USB controller. You can virtually plug
-virtual USB devices or real host USB devices (experimental, works only
-on Linux hosts). Qemu will automatically create and connect virtual USB hubs
-as neccessary to connect multiple USB devices.
-
-@menu
-* usb_devices::
-* host_usb_devices::
-@end menu
-@node usb_devices
-@subsection Connecting USB devices
-
-USB devices can be connected with the @option{-usbdevice} commandline option
-or the @code{usb_add} monitor command. Available devices are:
-
-@table @var
-@item @code{mouse}
-Virtual Mouse. This will override the PS/2 mouse emulation when activated.
-@item @code{tablet}
-Pointer device that uses abolsute coordinates (like a touchscreen).
-This means qemu is able to report the mouse position without having
-to grab the mouse. Also overrides the PS/2 mouse emulation when activated.
-@item @code{disk:file}
-Mass storage device based on @var{file} (@pxref{disk_images})
-@item @code{host:bus.addr}
-Pass through the host device identified by @var{bus.addr}
-(Linux only)
-@item @code{host:vendor_id:product_id}
-Pass through the host device identified by @var{vendor_id:product_id}
-(Linux only)
-@end table
-
-@node host_usb_devices
-@subsection Using host USB devices on a Linux host
-
-WARNING: this is an experimental feature. QEMU will slow down when
-using it. USB devices requiring real time streaming (i.e. USB Video
-Cameras) are not supported yet.
-
-@enumerate
-@item If you use an early Linux 2.4 kernel, verify that no Linux driver
-is actually using the USB device. A simple way to do that is simply to
-disable the corresponding kernel module by renaming it from @file{mydriver.o}
-to @file{mydriver.o.disabled}.
-
-@item Verify that @file{/proc/bus/usb} is working (most Linux distributions should enable it by default). You should see something like that:
-@example
-ls /proc/bus/usb
-001 devices drivers
-@end example
-
-@item Since only root can access to the USB devices directly, you can either launch QEMU as root or change the permissions of the USB devices you want to use. For testing, the following suffices:
-@example
-chown -R myuid /proc/bus/usb
-@end example
-
-@item Launch QEMU and do in the monitor:
-@example
-info usbhost
- Device 1.2, speed 480 Mb/s
- Class 00: USB device 1234:5678, USB DISK
-@end example
-You should see the list of the devices you can use (Never try to use
-hubs, it won't work).
-
-@item Add the device in QEMU by using:
-@example
-usb_add host:1234:5678
-@end example
-
-Normally the guest OS should report that a new USB device is
-plugged. You can use the option @option{-usbdevice} to do the same.
-
-@item Now you can try to use the host USB device in QEMU.
-
-@end enumerate
-
-When relaunching QEMU, you may have to unplug and plug again the USB
-device to make it work again (this is a bug).
-
-@node gdb_usage
-@section GDB usage
-
-QEMU has a primitive support to work with gdb, so that you can do
-'Ctrl-C' while the virtual machine is running and inspect its state.
-
-In order to use gdb, launch qemu with the '-s' option. It will wait for a
-gdb connection:
-@example
-> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
- -append "root=/dev/hda"
-Connected to host network interface: tun0
-Waiting gdb connection on port 1234
-@end example
-
-Then launch gdb on the 'vmlinux' executable:
-@example
-> gdb vmlinux
-@end example
-
-In gdb, connect to QEMU:
-@example
-(gdb) target remote localhost:1234
-@end example
-
-Then you can use gdb normally. For example, type 'c' to launch the kernel:
-@example
-(gdb) c
-@end example
-
-Here are some useful tips in order to use gdb on system code:
-
-@enumerate
-@item
-Use @code{info reg} to display all the CPU registers.
-@item
-Use @code{x/10i $eip} to display the code at the PC position.
-@item
-Use @code{set architecture i8086} to dump 16 bit code. Then use
-@code{x/10i $cs*16+$eip} to dump the code at the PC position.
-@end enumerate
-
-@node pcsys_os_specific
-@section Target OS specific information
-
-@subsection Linux
-
-To have access to SVGA graphic modes under X11, use the @code{vesa} or
-the @code{cirrus} X11 driver. For optimal performances, use 16 bit
-color depth in the guest and the host OS.
-
-When using a 2.6 guest Linux kernel, you should add the option
-@code{clock=pit} on the kernel command line because the 2.6 Linux
-kernels make very strict real time clock checks by default that QEMU
-cannot simulate exactly.
-
-When using a 2.6 guest Linux kernel, verify that the 4G/4G patch is
-not activated because QEMU is slower with this patch. The QEMU
-Accelerator Module is also much slower in this case. Earlier Fedora
-Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporte this
-patch by default. Newer kernels don't have it.
-
-@subsection Windows
-
-If you have a slow host, using Windows 95 is better as it gives the
-best speed. Windows 2000 is also a good choice.
-
-@subsubsection SVGA graphic modes support
-
-QEMU emulates a Cirrus Logic GD5446 Video
-card. All Windows versions starting from Windows 95 should recognize
-and use this graphic card. For optimal performances, use 16 bit color
-depth in the guest and the host OS.
-
-If you are using Windows XP as guest OS and if you want to use high
-resolution modes which the Cirrus Logic BIOS does not support (i.e. >=
-1280x1024x16), then you should use the VESA VBE virtual graphic card
-(option @option{-std-vga}).
-
-@subsubsection CPU usage reduction
-
-Windows 9x does not correctly use the CPU HLT
-instruction. The result is that it takes host CPU cycles even when
-idle. You can install the utility from
-@url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this
-problem. Note that no such tool is needed for NT, 2000 or XP.
-
-@subsubsection Windows 2000 disk full problem
-
-Windows 2000 has a bug which gives a disk full problem during its
-installation. When installing it, use the @option{-win2k-hack} QEMU
-option to enable a specific workaround. After Windows 2000 is
-installed, you no longer need this option (this option slows down the
-IDE transfers).
-
-@subsubsection Windows 2000 shutdown
-
-Windows 2000 cannot automatically shutdown in QEMU although Windows 98
-can. It comes from the fact that Windows 2000 does not automatically
-use the APM driver provided by the BIOS.
-
-In order to correct that, do the following (thanks to Struan
-Bartlett): go to the Control Panel => Add/Remove Hardware & Next =>
-Add/Troubleshoot a device => Add a new device & Next => No, select the
-hardware from a list & Next => NT Apm/Legacy Support & Next => Next
-(again) a few times. Now the driver is installed and Windows 2000 now
-correctly instructs QEMU to shutdown at the appropriate moment.
-
-@subsubsection Share a directory between Unix and Windows
-
-See @ref{sec_invocation} about the help of the option @option{-smb}.
-
-@subsubsection Windows XP security problems
-
-Some releases of Windows XP install correctly but give a security
-error when booting:
-@example
-A problem is preventing Windows from accurately checking the
-license for this computer. Error code: 0x800703e6.
-@end example
-The only known workaround is to boot in Safe mode
-without networking support.
-
-Future QEMU releases are likely to correct this bug.
-
-@subsection MS-DOS and FreeDOS
-
-@subsubsection CPU usage reduction
-
-DOS does not correctly use the CPU HLT instruction. The result is that
-it takes host CPU cycles even when idle. You can install the utility
-from @url{http://www.vmware.com/software/dosidle210.zip} to solve this
-problem.
-
-@node QEMU System emulator for non PC targets
-@chapter QEMU System emulator for non PC targets
-
-QEMU is a generic emulator and it emulates many non PC
-machines. Most of the options are similar to the PC emulator. The
-differences are mentionned in the following sections.
-
-@menu
-* QEMU PowerPC System emulator::
-* Sparc32 System emulator invocation::
-* Sparc64 System emulator invocation::
-* MIPS System emulator invocation::
-* ARM System emulator invocation::
-@end menu
-
-@node QEMU PowerPC System emulator
-@section QEMU PowerPC System emulator
-
-Use the executable @file{qemu-system-ppc} to simulate a complete PREP
-or PowerMac PowerPC system.
-
-QEMU emulates the following PowerMac peripherals:
-
-@itemize @minus
-@item
-UniNorth PCI Bridge
-@item
-PCI VGA compatible card with VESA Bochs Extensions
-@item
-2 PMAC IDE interfaces with hard disk and CD-ROM support
-@item
-NE2000 PCI adapters
-@item
-Non Volatile RAM
-@item
-VIA-CUDA with ADB keyboard and mouse.
-@end itemize
-
-QEMU emulates the following PREP peripherals:
-
-@itemize @minus
-@item
-PCI Bridge
-@item
-PCI VGA compatible card with VESA Bochs Extensions
-@item
-2 IDE interfaces with hard disk and CD-ROM support
-@item
-Floppy disk
-@item
-NE2000 network adapters
-@item
-Serial port
-@item
-PREP Non Volatile RAM
-@item
-PC compatible keyboard and mouse.
-@end itemize
-
-QEMU uses the Open Hack'Ware Open Firmware Compatible BIOS available at
-@url{http://perso.magic.fr/l_indien/OpenHackWare/index.htm}.
-
-@c man begin OPTIONS
-
-The following options are specific to the PowerPC emulation:
-
-@table @option
-
-@item -g WxH[xDEPTH]
-
-Set the initial VGA graphic mode. The default is 800x600x15.
-
-@end table
-
-@c man end
-
-
-More information is available at
-@url{http://perso.magic.fr/l_indien/qemu-ppc/}.
-
-@node Sparc32 System emulator invocation
-@section Sparc32 System emulator invocation
-
-Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5
-(sun4m architecture). The emulation is somewhat complete.
-
-QEMU emulates the following sun4m peripherals:
-
-@itemize @minus
-@item
-IOMMU
-@item
-TCX Frame buffer
-@item
-Lance (Am7990) Ethernet
-@item
-Non Volatile RAM M48T08
-@item
-Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard
-and power/reset logic
-@item
-ESP SCSI controller with hard disk and CD-ROM support
-@item
-Floppy drive
-@end itemize
-
-The number of peripherals is fixed in the architecture.
-
-Since version 0.8.2, QEMU uses OpenBIOS
-@url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable
-firmware implementation. The goal is to implement a 100% IEEE
-1275-1994 (referred to as Open Firmware) compliant firmware.
-
-A sample Linux 2.6 series kernel and ram disk image are available on
-the QEMU web site. Please note that currently NetBSD, OpenBSD or
-Solaris kernels don't work.
-
-@c man begin OPTIONS
-
-The following options are specific to the Sparc emulation:
-
-@table @option
-
-@item -g WxH
-
-Set the initial TCX graphic mode. The default is 1024x768.
-
-@end table
-
-@c man end
-
-@node Sparc64 System emulator invocation
-@section Sparc64 System emulator invocation
-
-Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
-The emulator is not usable for anything yet.
-
-QEMU emulates the following sun4u peripherals:
-
-@itemize @minus
-@item
-UltraSparc IIi APB PCI Bridge
-@item
-PCI VGA compatible card with VESA Bochs Extensions
-@item
-Non Volatile RAM M48T59
-@item
-PC-compatible serial ports
-@end itemize
-
-@node MIPS System emulator invocation
-@section MIPS System emulator invocation
-
-Use the executable @file{qemu-system-mips} to simulate a MIPS machine.
-The emulator is able to boot a Linux kernel and to run a Linux Debian
-installation from NFS. The following devices are emulated:
-
-@itemize @minus
-@item
-MIPS R4K CPU
-@item
-PC style serial port
-@item
-NE2000 network card
-@end itemize
-
-More information is available in the QEMU mailing-list archive.
-
-@node ARM System emulator invocation
-@section ARM System emulator invocation
-
-Use the executable @file{qemu-system-arm} to simulate a ARM
-machine. The ARM Integrator/CP board is emulated with the following
-devices:
-
-@itemize @minus
-@item
-ARM926E or ARM1026E CPU
-@item
-Two PL011 UARTs
-@item
-SMC 91c111 Ethernet adapter
-@item
-PL110 LCD controller
-@item
-PL050 KMI with PS/2 keyboard and mouse.
-@end itemize
-
-The ARM Versatile baseboard is emulated with the following devices:
-
-@itemize @minus
-@item
-ARM926E CPU
-@item
-PL190 Vectored Interrupt Controller
-@item
-Four PL011 UARTs
-@item
-SMC 91c111 Ethernet adapter
-@item
-PL110 LCD controller
-@item
-PL050 KMI with PS/2 keyboard and mouse.
-@item
-PCI host bridge. Note the emulated PCI bridge only provides access to
-PCI memory space. It does not provide access to PCI IO space.
-This means some devices (eg. ne2k_pci NIC) are not useable, and others
-(eg. rtl8139 NIC) are only useable when the guest drivers use the memory
-mapped control registers.
-@item
-PCI OHCI USB controller.
-@item
-LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices.
-@end itemize
-
-A Linux 2.6 test image is available on the QEMU web site. More
-information is available in the QEMU mailing-list archive.
-
-@node QEMU Linux User space emulator
-@chapter QEMU Linux User space emulator
-
-@menu
-* Quick Start::
-* Wine launch::
-* Command line options::
-* Other binaries::
-@end menu
-
-@node Quick Start
-@section Quick Start
-
-In order to launch a Linux process, QEMU needs the process executable
-itself and all the target (x86) dynamic libraries used by it.
-
-@itemize
-
-@item On x86, you can just try to launch any process by using the native
-libraries:
-
-@example
-qemu-i386 -L / /bin/ls
-@end example
-
-@code{-L /} tells that the x86 dynamic linker must be searched with a
-@file{/} prefix.
-
-@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources):
-
-@example
-qemu-i386 -L / qemu-i386 -L / /bin/ls
-@end example
-
-@item On non x86 CPUs, you need first to download at least an x86 glibc
-(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that
-@code{LD_LIBRARY_PATH} is not set:
-
-@example
-unset LD_LIBRARY_PATH
-@end example
-
-Then you can launch the precompiled @file{ls} x86 executable:
-
-@example
-qemu-i386 tests/i386/ls
-@end example
-You can look at @file{qemu-binfmt-conf.sh} so that
-QEMU is automatically launched by the Linux kernel when you try to
-launch x86 executables. It requires the @code{binfmt_misc} module in the
-Linux kernel.
-
-@item The x86 version of QEMU is also included. You can try weird things such as:
-@example
-qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 \
- /usr/local/qemu-i386/bin/ls-i386
-@end example
-
-@end itemize
-
-@node Wine launch
-@section Wine launch
-
-@itemize
-
-@item Ensure that you have a working QEMU with the x86 glibc
-distribution (see previous section). In order to verify it, you must be
-able to do:
-
-@example
-qemu-i386 /usr/local/qemu-i386/bin/ls-i386
-@end example
-
-@item Download the binary x86 Wine install
-(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
-
-@item Configure Wine on your account. Look at the provided script
-@file{/usr/local/qemu-i386/@/bin/wine-conf.sh}. Your previous
-@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
-
-@item Then you can try the example @file{putty.exe}:
-
-@example
-qemu-i386 /usr/local/qemu-i386/wine/bin/wine \
- /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
-@end example
-
-@end itemize
-
-@node Command line options
-@section Command line options
-
-@example
-usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
-@end example
-
-@table @option
-@item -h
-Print the help
-@item -L path
-Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
-@item -s size
-Set the x86 stack size in bytes (default=524288)
-@end table
-
-Debug options:
-
-@table @option
-@item -d
-Activate log (logfile=/tmp/qemu.log)
-@item -p pagesize
-Act as if the host page size was 'pagesize' bytes
-@end table
-
-@node Other binaries
-@section Other binaries
-
-@command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF
-binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB
-configurations), and arm-uclinux bFLT format binaries.
-
-The binary format is detected automatically.
-
-@node compilation
-@chapter Compilation from the sources
-
-@menu
-* Linux/Unix::
-* Windows::
-* Cross compilation for Windows with Linux::
-* Mac OS X::
-@end menu
-
-@node Linux/Unix
-@section Linux/Unix
-
-@subsection Compilation
-
-First you must decompress the sources:
-@example
-cd /tmp
-tar zxvf qemu-x.y.z.tar.gz
-cd qemu-x.y.z
-@end example
-
-Then you configure QEMU and build it (usually no options are needed):
-@example
-./configure
-make
-@end example
-
-Then type as root user:
-@example
-make install
-@end example
-to install QEMU in @file{/usr/local}.
-
-@subsection Tested tool versions
-
-In order to compile QEMU succesfully, it is very important that you
-have the right tools. The most important one is gcc. I cannot guaranty
-that QEMU works if you do not use a tested gcc version. Look at
-'configure' and 'Makefile' if you want to make a different gcc
-version work.
-
-@example
-host gcc binutils glibc linux distribution
-----------------------------------------------------------------------
-x86 3.2 2.13.2 2.1.3 2.4.18
- 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
- 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
-
-PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
- 3.2
-
-Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
-
-Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
-
-ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
-
-[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
- for gcc version >= 3.3.
-[2] Linux >= 2.4.20 is necessary for precise exception support
- (untested).
-[3] 2.4.9-ac10-rmk2-np1-cerf2
-
-[4] gcc 2.95.x generates invalid code when using too many register
-variables. You must use gcc 3.x on PowerPC.
-@end example
-
-@node Windows
-@section Windows
-
-@itemize
-@item Install the current versions of MSYS and MinGW from
-@url{http://www.mingw.org/}. You can find detailed installation
-instructions in the download section and the FAQ.
-
-@item Download
-the MinGW development library of SDL 1.2.x
-(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
-@url{http://www.libsdl.org}. Unpack it in a temporary place, and
-unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool
-directory. Edit the @file{sdl-config} script so that it gives the
-correct SDL directory when invoked.
-
-@item Extract the current version of QEMU.
-
-@item Start the MSYS shell (file @file{msys.bat}).
-
-@item Change to the QEMU directory. Launch @file{./configure} and
-@file{make}. If you have problems using SDL, verify that
-@file{sdl-config} can be launched from the MSYS command line.
-
-@item You can install QEMU in @file{Program Files/Qemu} by typing
-@file{make install}. Don't forget to copy @file{SDL.dll} in
-@file{Program Files/Qemu}.
-
-@end itemize
-
-@node Cross compilation for Windows with Linux
-@section Cross compilation for Windows with Linux
-
-@itemize
-@item
-Install the MinGW cross compilation tools available at
-@url{http://www.mingw.org/}.
-
-@item
-Install the Win32 version of SDL (@url{http://www.libsdl.org}) by
-unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment
-variable so that @file{i386-mingw32msvc-sdl-config} can be launched by
-the QEMU configuration script.
-
-@item
-Configure QEMU for Windows cross compilation:
-@example
-./configure --enable-mingw32
-@end example
-If necessary, you can change the cross-prefix according to the prefix
-choosen for the MinGW tools with --cross-prefix. You can also use
---prefix to set the Win32 install path.
-
-@item You can install QEMU in the installation directory by typing
-@file{make install}. Don't forget to copy @file{SDL.dll} in the
-installation directory.
-
-@end itemize
-
-Note: Currently, Wine does not seem able to launch
-QEMU for Win32.
-
-@node Mac OS X
-@section Mac OS X
-
-The Mac OS X patches are not fully merged in QEMU, so you should look
-at the QEMU mailing list archive to have all the necessary
-information.
-
-@node Index
-@chapter Index
-@printindex cp
-
-@bye
diff --git a/shaper.c b/shaper.c
index 83e5aea..2c5492a 100644
--- a/shaper.c
+++ b/shaper.c
@@ -546,7 +546,7 @@ netdelay_send_aux( NetDelay delay, const void* data, size_t size, void* opaqu
int latency = delay->min_ms;
int range = delay->max_ms - delay->min_ms;
- if (delay > 0)
+ if (range > 0)
latency += rand() % range;
//fprintf(stderr, "NetDelay:RST: delay creation for %s\n", session_to_string(info) );
diff --git a/skins/skin_argb.h b/skins/skin_argb.h
index c39b4ef..b3f0a6d 100644
--- a/skins/skin_argb.h
+++ b/skins/skin_argb.h
@@ -89,7 +89,7 @@ mmx_interp255( mmx_t m1, mmx_t m2, mmx_t zero, int alpha )
#define ARGB_UNPACK(x,v) x = mmx_load8888((v), _zero)
#define ARGB_PACK(x) mmx_save8888(x, _zero)
#define ARGB_COPY(x,y) x = y
-#define ARGB_SUM(x1,x2,x3) x1 = _mm_add_si64(x2, x3)
+#define ARGB_SUM(x1,x2,x3) x1 = _mm_add_pi32(x2, x3)
#define ARGB_REDUCE(x,red) \
({ \
int _red = (red) >> 8; \
diff --git a/skins/skin_keyset.c b/skins/skin_keyset.c
index ffde933..f9e6af7 100644
--- a/skins/skin_keyset.c
+++ b/skins/skin_keyset.c
@@ -530,7 +530,8 @@ skin_keyset_get_default( void )
"BUTTON_DPAD_RIGHT Keypad_6\n"
"BUTTON_DPAD_DOWN Keypad_2\n"
- "TOGGLE_TRACKBALL Ctrl-T\n"
+ "TOGGLE_TRACKBALL F6\n"
+ "SHOW_TRACKBALL Delete\n"
"CHANGE_LAYOUT_PREV Keypad_7, Ctrl-F11\n"
"CHANGE_LAYOUT_NEXT Keypad_9, Ctrl-F12\n"
diff --git a/skins/skin_keyset.h b/skins/skin_keyset.h
index 7b8831f..10b60fa 100644
--- a/skins/skin_keyset.h
+++ b/skins/skin_keyset.h
@@ -39,6 +39,7 @@ typedef struct SkinKeyset SkinKeyset;
_SKIN_KEY_COMMAND(TOGGLE_TRACING,"toggle code profiling") \
_SKIN_KEY_COMMAND(TOGGLE_FULLSCREEN,"toggle fullscreen mode") \
_SKIN_KEY_COMMAND(TOGGLE_TRACKBALL,"toggle trackball mode") \
+ _SKIN_KEY_COMMAND(SHOW_TRACKBALL,"show trackball") \
_SKIN_KEY_COMMAND(BUTTON_DPAD_CENTER,"DPad center") \
_SKIN_KEY_COMMAND(BUTTON_DPAD_LEFT,"DPad left") \
_SKIN_KEY_COMMAND(BUTTON_DPAD_RIGHT,"DPad right") \
diff --git a/skins/skin_trackball.c b/skins/skin_trackball.c
index 4db8c95..ae0cd8e 100644
--- a/skins/skin_trackball.c
+++ b/skins/skin_trackball.c
@@ -187,9 +187,25 @@ typedef struct SkinTrackBall
int acc_threshold;
double acc_scale;
+ /* rotation applied to events send to the system */
+ SkinRotation rotation;
+
} TrackBallRec, *TrackBall;
+/* The following constants are used to better mimic a real trackball.
+ *
+ * ACC_THRESHOLD is used to filter small ball movements out.
+ * If the length of the relative mouse motion is smaller than this
+ * constant, then no corresponding ball event will be sent to the
+ * system.
+ *
+ * ACC_SCALE is used to scale the relative mouse motion vector into
+ * the corresponding ball motion vector.
+ */
+#define ACC_THRESHOLD 20
+#define ACC_SCALE 0.2
+
static void
trackball_init( TrackBall ball, int diameter, int ring,
unsigned ball_color, unsigned dot_color,
@@ -199,9 +215,8 @@ trackball_init( TrackBall ball, int diameter, int ring,
memset( ball, 0, sizeof(*ball) );
- /* XXX: hard-coded constants are evil */
- ball->acc_threshold = 20;
- ball->acc_scale = 0.2;
+ ball->acc_threshold = ACC_THRESHOLD;
+ ball->acc_scale = ACC_SCALE;
/* init SDL surface */
ball->diameter = diameter2;
@@ -209,6 +224,8 @@ trackball_init( TrackBall ball, int diameter, int ring,
ball->dot_color = dot_color;
ball->ring_color = ring_color;
+ ball->rotation = SKIN_ROTATION_0;
+
ball->pixels = (unsigned*)calloc( diameter2*diameter2, sizeof(unsigned) );
ball->surface = sdl_surface_from_argb32( ball->pixels, diameter2, diameter2 );
@@ -405,10 +422,33 @@ trackball_move( TrackBall ball, int dx, int dy )
{
int ddx = ball->acc_x * ball->acc_scale;
int ddy = ball->acc_y * ball->acc_scale;
+ int ddt;
ball->acc_x = 0;
ball->acc_y = 0;
+ switch (ball->rotation) {
+ case SKIN_ROTATION_0:
+ break;
+
+ case SKIN_ROTATION_90:
+ ddt = ddx;
+ ddx = ddy;
+ ddy = -ddt;
+ break;
+
+ case SKIN_ROTATION_180:
+ ddx = -ddx;
+ ddy = -ddy;
+ break;
+
+ case SKIN_ROTATION_270:
+ ddt = ddx;
+ ddx = -ddy;
+ ddy = ddt;
+ break;
+ }
+
kbd_mouse_event(ddx, ddy, 1, 0);
}
@@ -577,3 +617,10 @@ skin_trackball_rect( SkinTrackBall* ball, SDL_Rect* rect )
rect->w = ball->diameter;
rect->h = ball->diameter;
}
+
+
+void
+skin_trackball_set_rotation( SkinTrackBall* ball, SkinRotation rotation )
+{
+ ball->rotation = rotation & 3;
+}
diff --git a/skins/skin_trackball.h b/skins/skin_trackball.h
index 3ea6d2d..b4f1ab3 100644
--- a/skins/skin_trackball.h
+++ b/skins/skin_trackball.h
@@ -13,6 +13,7 @@
#define _ANDROID_SKIN_TRACKBALL_H
#include <SDL.h>
+#include "skin_rect.h"
typedef struct SkinTrackBall SkinTrackBall;
@@ -35,5 +36,8 @@ extern void skin_trackball_refresh ( SkinTrackBall* ball );
extern void skin_trackball_draw ( SkinTrackBall* ball, int x, int y, SDL_Surface* dst );
extern void skin_trackball_destroy ( SkinTrackBall* ball );
+/* this sets the rotation that will be applied to mouse events sent to the system */
+extern void skin_trackball_set_rotation( SkinTrackBall* ball, SkinRotation rotation);
+
#endif /* END */
diff --git a/skins/skin_window.c b/skins/skin_window.c
index f3f5a66..6d2c217 100644
--- a/skins/skin_window.c
+++ b/skins/skin_window.c
@@ -21,6 +21,11 @@
/* when shrinking, we reduce the pixel ratio by this fixed amount */
#define SHRINK_SCALE 0.6
+/* maximum value of LCD brighness */
+#define LCD_BRIGHTNESS_MIN 0
+#define LCD_BRIGHTNESS_DEFAULT 128
+#define LCD_BRIGHTNESS_MAX 255
+
typedef struct Background {
SkinImage* image;
SkinRect rect;
@@ -81,6 +86,7 @@ typedef struct ADisplay {
QFrameBuffer* qfbuff;
SkinImage* onion; /* onion image */
SkinRect onion_rect; /* onion rect, if any */
+ int brightness;
} ADisplay;
static void
@@ -129,7 +135,10 @@ display_init( ADisplay* disp, SkinDisplay* sdisp, SkinLocation* loc, SkinRect
#endif
disp->qfbuff = sdisp->qfbuff;
disp->data = sdisp->qfbuff->pixels;
- disp->onion = NULL;
+ disp->onion = NULL;
+
+ disp->brightness = LCD_BRIGHTNESS_DEFAULT;
+
return (disp->data == NULL) ? -1 : 0;
}
@@ -219,6 +228,141 @@ dotmatrix_dither_argb32( unsigned char* pixels, int x, int y, int w, int h,
#endif /* DOT_MATRIX */
+/* technical note about the lightness emulation
+ *
+ * we try to emulate something that looks like the Dream's
+ * non-linear LCD lightness, without going too dark or bright.
+ *
+ * the default lightness is around 105 (about 40%) and we prefer
+ * to keep full RGB colors at that setting, to not alleviate
+ * developers who will not understand why the emulator's colors
+ * look slightly too dark.
+ *
+ * we also want to implement a 'bright' mode by de-saturating
+ * colors towards bright white.
+ *
+ * All of this leads to the implementation below that looks like
+ * the following:
+ *
+ * if (level == MIN)
+ * screen is off
+ *
+ * if (level > MIN && level < LOW)
+ * interpolate towards black, with
+ * MINALPHA = 0.2
+ * alpha = MINALPHA + (1-MINALPHA)*(level-MIN)/(LOW-MIN)
+ *
+ * if (level >= LOW && level <= HIGH)
+ * keep full RGB colors
+ *
+ * if (level > HIGH)
+ * interpolate towards bright white, with
+ * MAXALPHA = 0.6
+ * alpha = MAXALPHA*(level-HIGH)/(MAX-HIGH)
+ *
+ * we probably want some sort of power law instead of interpolating
+ * linearly, but frankly, this is sufficient for most uses.
+ */
+
+#define LCD_BRIGHTNESS_LOW 80
+#define LCD_BRIGHTNESS_HIGH 180
+
+#define LCD_ALPHA_LOW_MIN 0.2
+#define LCD_ALPHA_HIGH_MAX 0.6
+
+/* treat as special value to turn screen off */
+#define LCD_BRIGHTNESS_OFF LCD_BRIGHTNESS_MIN
+
+static void
+lcd_brightness_argb32( unsigned char* pixels, SkinRect* r, int pitch, int brightness )
+{
+ const unsigned b_min = LCD_BRIGHTNESS_MIN;
+ const unsigned b_max = LCD_BRIGHTNESS_MAX;
+ const unsigned b_low = LCD_BRIGHTNESS_LOW;
+ const unsigned b_high = LCD_BRIGHTNESS_HIGH;
+
+ unsigned alpha = brightness;
+ int w = r->size.w;
+ int h = r->size.h;
+
+ if (alpha < b_min)
+ alpha = b_min;
+ else if (alpha > b_max)
+ alpha = b_max;
+
+ pixels += 4*r->pos.x + r->pos.y*pitch;
+
+ if (alpha < b_low)
+ {
+ const unsigned alpha_min = (255*LCD_ALPHA_LOW_MIN);
+ const unsigned alpha_range = (255 - alpha_min);
+
+ alpha = alpha_min + ((alpha - b_min)*alpha_range) / (b_low - b_min);
+
+ for ( ; h > 0; h-- ) {
+ unsigned* line = (unsigned*) pixels;
+ int nn;
+
+ for (nn = 0; nn < w; nn++) {
+ unsigned c = line[nn];
+ unsigned ag = (c >> 8) & 0x00ff00ff;
+ unsigned rb = (c) & 0x00ff00ff;
+
+ ag = (ag*alpha) & 0xff00ff00;
+ rb = ((rb*alpha) >> 8) & 0x00ff00ff;
+
+ line[nn] = (unsigned)(ag | rb);
+ }
+ pixels += pitch;
+ }
+ }
+ else if (alpha > LCD_BRIGHTNESS_HIGH) /* 'superluminous' mode */
+ {
+ const unsigned alpha_max = (255*LCD_ALPHA_HIGH_MAX);
+ const unsigned alpha_range = (255-alpha_max);
+ unsigned ialpha;
+
+ alpha = ((alpha - b_high)*alpha_range) / (b_max - b_high);
+ ialpha = 255-alpha;
+
+ for ( ; h > 0; h-- ) {
+ unsigned* line = (unsigned*) pixels;
+ int nn;
+
+ for (nn = 0; nn < w; nn++) {
+ unsigned c = line[nn];
+ unsigned ag = (c >> 8) & 0x00ff00ff;
+ unsigned rb = (c) & 0x00ff00ff;
+
+ /* interpolate towards bright white, i.e. 0x00ffffff */
+ ag = ((ag*ialpha + 0x00ff00ff*alpha)) & 0xff00ff00;
+ rb = ((rb*ialpha + 0x00ff00ff*alpha) >> 8) & 0x00ff00ff;
+
+ line[nn] = (unsigned)(ag | rb);
+ }
+ pixels += pitch;
+ }
+ }
+}
+
+
+/* this is called when the LCD framebuffer is off */
+static void
+lcd_off_argb32( unsigned char* pixels, SkinRect* r, int pitch )
+{
+ int x = r->pos.x;
+ int y = r->pos.y;
+ int w = r->size.w;
+ int h = r->size.h;
+
+ pixels += 4*x + y*pitch;
+ for ( ; h > 0; h-- ) {
+ memset( pixels, 0, w*4 );
+ pixels += pitch;
+ }
+}
+
+
static void
display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface )
{
@@ -245,84 +389,95 @@ display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface )
rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
#endif
SDL_LockSurface( surface );
- switch ( disp->rotation & 3 )
- {
- case ANDROID_ROTATION_0:
- src_line += x*2 + y*src_pitch;
- for (yy = h; yy > 0; yy--)
+ if (disp->brightness == LCD_BRIGHTNESS_OFF)
+ {
+ lcd_off_argb32( surface->pixels, &r, dst_pitch );
+ }
+ else
+ {
+ switch ( disp->rotation & 3 )
{
- uint32_t* dst = (uint32_t*)dst_line;
- uint16_t* src = (uint16_t*)src_line;
+ case ANDROID_ROTATION_0:
+ src_line += x*2 + y*src_pitch;
- for (xx = 0; xx < w; xx++) {
- dst[xx] = rgb565_to_argb32(src[xx]);
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint16_t* src = (uint16_t*)src_line;
+
+ for (xx = 0; xx < w; xx++) {
+ dst[xx] = rgb565_to_argb32(src[xx]);
+ }
+ src_line += src_pitch;
+ dst_line += dst_pitch;
}
- src_line += src_pitch;
- dst_line += dst_pitch;
- }
- break;
-
- case ANDROID_ROTATION_90:
- src_line += y*2 + (disp_w - x - 1)*src_pitch;
+ break;
- for (yy = h; yy > 0; yy--)
- {
- uint32_t* dst = (uint32_t*)dst_line;
- uint8_t* src = src_line;
+ case ANDROID_ROTATION_90:
+ src_line += y*2 + (disp_w - x - 1)*src_pitch;
- for (xx = w; xx > 0; xx--)
+ for (yy = h; yy > 0; yy--)
{
- dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
- src -= src_pitch;
- dst += 1;
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint8_t* src = src_line;
+
+ for (xx = w; xx > 0; xx--)
+ {
+ dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+ src -= src_pitch;
+ dst += 1;
+ }
+ src_line += 2;
+ dst_line += dst_pitch;
}
- src_line += 2;
- dst_line += dst_pitch;
- }
- break;
+ break;
- case ANDROID_ROTATION_180:
- src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch;
+ case ANDROID_ROTATION_180:
+ src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch;
- for (yy = h; yy > 0; yy--)
- {
- uint16_t* src = (uint16_t*)src_line;
- uint32_t* dst = (uint32_t*)dst_line;
-
- for (xx = w; xx > 0; xx--) {
- dst[0] = rgb565_to_argb32(src[0]);
- src -= 1;
- dst += 1;
- }
+ for (yy = h; yy > 0; yy--)
+ {
+ uint16_t* src = (uint16_t*)src_line;
+ uint32_t* dst = (uint32_t*)dst_line;
- src_line -= src_pitch;
- dst_line += dst_pitch;
- }
- break;
+ for (xx = w; xx > 0; xx--) {
+ dst[0] = rgb565_to_argb32(src[0]);
+ src -= 1;
+ dst += 1;
+ }
- default: /* ANDROID_ROTATION_270 */
- src_line += (disp_h-1-y)*2 + x*src_pitch;
+ src_line -= src_pitch;
+ dst_line += dst_pitch;
+ }
+ break;
- for (yy = h; yy > 0; yy--)
- {
- uint32_t* dst = (uint32_t*)dst_line;
- uint8_t* src = src_line;
+ default: /* ANDROID_ROTATION_270 */
+ src_line += (disp_h-1-y)*2 + x*src_pitch;
- for (xx = w; xx > 0; xx--) {
- dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
- dst += 1;
- src += src_pitch;
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint8_t* src = src_line;
+
+ for (xx = w; xx > 0; xx--) {
+ dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+ dst += 1;
+ src += src_pitch;
+ }
+ src_line -= 2;
+ dst_line += dst_pitch;
}
- src_line -= 2;
- dst_line += dst_pitch;
}
- }
#if DOT_MATRIX
- dotmatrix_dither_argb32( surface->pixels, r.pos.x, r.pos.y, r.size.w, r.size.h, surface->pitch );
+ dotmatrix_dither_argb32( surface->pixels, r.pos.x, r.pos.y, r.size.w, r.size.h, surface->pitch );
#endif
+ /* apply lightness */
+ lcd_brightness_argb32( surface->pixels, &r, surface->pitch, disp->brightness );
+ }
SDL_UnlockSurface( surface );
+ /* Apply onion skin */
if (disp->onion != NULL) {
SkinRect r2;
@@ -468,34 +623,31 @@ ball_state_redraw( BallState* state, SkinRect* rect, SDL_Surface* surface )
}
static void
-ball_state_show( BallState* state )
+ball_state_show( BallState* state, int enable )
{
- if ( !state->tracking ) {
- state->tracking = 1;
- SDL_ShowCursor(0);
- SDL_WM_GrabInput( SDL_GRAB_ON );
- skin_trackball_refresh( state->ball );
- skin_window_redraw( state->window, &state->rect );
+ if (enable) {
+ if ( !state->tracking ) {
+ state->tracking = 1;
+ SDL_ShowCursor(0);
+ SDL_WM_GrabInput( SDL_GRAB_ON );
+ skin_trackball_refresh( state->ball );
+ skin_window_redraw( state->window, &state->rect );
+ }
+ } else {
+ if ( state->tracking ) {
+ state->tracking = 0;
+ SDL_WM_GrabInput( SDL_GRAB_OFF );
+ SDL_ShowCursor(1);
+ skin_window_redraw( state->window, &state->rect );
+ }
}
}
-static void
-ball_state_hide( BallState* state )
-{
- if ( state->tracking ) {
- state->tracking = 0;
- SDL_WM_GrabInput( SDL_GRAB_OFF );
- SDL_ShowCursor(1);
-
- skin_window_redraw( state->window, &state->rect );
- }
-}
static void
ball_state_set( BallState* state, SkinTrackBall* ball )
{
- if ( state->tracking )
- ball_state_hide( state );
+ ball_state_show( state, 0 );
state->ball = ball;
if (ball != NULL) {
@@ -509,15 +661,6 @@ ball_state_set( BallState* state, SkinTrackBall* ball )
}
}
-static void
-ball_state_toggle( BallState* state )
-{
- if (state->tracking)
- ball_state_hide( state );
- else
- ball_state_show( state );
-}
-
typedef struct Layout {
int num_buttons;
int num_backgrounds;
@@ -669,6 +812,11 @@ struct SkinWindow {
char fullscreen;
char no_display;
+ char enable_touch;
+ char enable_trackball;
+ char enable_dpad;
+ char enable_qwerty;
+
SkinImage* onion;
SkinRotation onion_rotation;
int onion_alpha;
@@ -698,6 +846,9 @@ skin_window_find_finger( SkinWindow* window,
finger->display = NULL;
finger->inside = 0;
+ if (!window->enable_touch)
+ return;
+
LAYOUT_LOOP_DISPLAYS(&window->layout,disp)
if ( skin_rect_contains( &disp->rect, x, y ) ) {
finger->inside = 1;
@@ -767,6 +918,38 @@ skin_window_move_mouse( SkinWindow* window,
}
LAYOUT_LOOP_END_BUTTONS
+ /* filter DPAD and QWERTY buttons right here */
+ if (hover != NULL) {
+ switch (hover->keycode) {
+ /* these correspond to the DPad */
+ case kKeyCodeDpadUp:
+ case kKeyCodeDpadDown:
+ case kKeyCodeDpadLeft:
+ case kKeyCodeDpadRight:
+ case kKeyCodeDpadCenter:
+ if (!window->enable_dpad)
+ hover = NULL;
+ break;
+
+ /* these correspond to non-qwerty buttons */
+ case kKeyCodeSoftLeft:
+ case kKeyCodeSoftRight:
+ case kKeyCodeVolumeUp:
+ case kKeyCodeVolumeDown:
+ case kKeyCodePower:
+ case kKeyCodeHome:
+ case kKeyCodeBack:
+ case kKeyCodeCall:
+ case kKeyCodeEndCall:
+ break;
+
+ /* all the rest is assumed to be qwerty */
+ default:
+ if (!window->enable_qwerty)
+ hover = NULL;
+ }
+ }
+
if (hover != NULL) {
hover->down = 1;
skin_window_redraw( window, &hover->rect );
@@ -801,12 +984,12 @@ skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball )
}
void
-skin_window_toggle_trackball( SkinWindow* window )
+skin_window_show_trackball( SkinWindow* window, int enable )
{
BallState* state = &window->ball;
- if (state->ball != NULL) {
- ball_state_toggle(state);
+ if (state->ball != NULL && window->enable_trackball) {
+ ball_state_show(state, enable);
}
}
@@ -829,6 +1012,12 @@ skin_window_create( SkinLayout* slayout, int x, int y, double scale, int no
window->scaler = skin_scaler_create();
window->no_display = no_display;
+ /* enable everything by default */
+ window->enable_touch = 1;
+ window->enable_trackball = 1;
+ window->enable_dpad = 1;
+ window->enable_qwerty = 1;
+
if (skin_window_reset(window, slayout) < 0) {
skin_window_free( window );
return NULL;
@@ -844,6 +1033,30 @@ skin_window_create( SkinLayout* slayout, int x, int y, double scale, int no
}
void
+skin_window_enable_touch( SkinWindow* window, int enabled )
+{
+ window->enable_touch = !!enabled;
+}
+
+void
+skin_window_enable_trackball( SkinWindow* window, int enabled )
+{
+ window->enable_trackball = !!enabled;
+}
+
+void
+skin_window_enable_dpad( SkinWindow* window, int enabled )
+{
+ window->enable_dpad = !!enabled;
+}
+
+void
+skin_window_enable_qwerty( SkinWindow* window, int enabled )
+{
+ window->enable_qwerty = !!enabled;
+}
+
+void
skin_window_set_title( SkinWindow* window, const char* title )
{
if (window && title)
@@ -945,6 +1158,17 @@ skin_window_reset ( SkinWindow* window, SkinLayout* slayout )
}
void
+skin_window_set_lcd_brightness( SkinWindow* window, int brightness )
+{
+ ADisplay* disp = window->layout.displays;
+
+ if (disp != NULL) {
+ disp->brightness = brightness;
+ skin_window_redraw( window, NULL );
+ }
+}
+
+void
skin_window_free ( SkinWindow* window )
{
if (window) {
diff --git a/skins/skin_window.h b/skins/skin_window.h
index 5ca1568..9f00f3e 100644
--- a/skins/skin_window.h
+++ b/skins/skin_window.h
@@ -27,6 +27,11 @@ extern SkinWindow* skin_window_create( SkinLayout* layout,
double scale,
int no_display );
+extern void skin_window_enable_touch( SkinWindow* window, int enabled );
+extern void skin_window_enable_trackball( SkinWindow* window, int enabled );
+extern void skin_window_enable_dpad( SkinWindow* window, int enabled );
+extern void skin_window_enable_qwerty( SkinWindow* window, int enabled );
+
extern int skin_window_reset ( SkinWindow* window, SkinLayout* layout );
extern void skin_window_free ( SkinWindow* window );
extern void skin_window_redraw( SkinWindow* window, SkinRect* rect );
@@ -44,9 +49,12 @@ extern void skin_window_set_title( SkinWindow* window,
const char* title );
extern void skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball );
-extern void skin_window_toggle_trackball( SkinWindow* window );
+extern void skin_window_show_trackball( SkinWindow* window, int enable );
extern void skin_window_toggle_fullscreen( SkinWindow* window );
+/* change the brightness of the emulator LCD screen. 'brightness' will be clamped to 0..255 */
+extern void skin_window_set_lcd_brightness( SkinWindow* window, int brightness );
+
typedef struct {
int width;
int height;
diff --git a/slirp/if.c b/slirp/if.c
index b589c42..9d814c2 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -266,7 +266,7 @@ diddit:
void
if_start(void)
{
- MBuf ifm, *ifqt;
+ MBuf ifm, ifqt;
DEBUG_CALL("if_start");
diff --git a/slirp/socket.c b/slirp/socket.c
index 8ddc95c..bdae392 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -74,7 +74,7 @@ sofree(so)
struct socket *so;
{
if (so->so_state & SS_PROXIFIED)
- proxy_manager_del(so->s);
+ proxy_manager_del(so);
if (so->extra) {
sofree(so->extra);
@@ -543,7 +543,7 @@ solisten(port, laddr, lport, flags)
{
struct sockaddr_in addr;
struct socket *so;
- int s, addrlen = sizeof(addr), opt = 1;
+ int s, addrlen = sizeof(addr);
DEBUG_CALL("solisten");
DEBUG_ARG("port = %d", port);
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index b42e6ea..59aae0a 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -387,11 +387,13 @@ tcp_sockclosed(tp)
static void
tcp_proxy_event( struct socket* so,
+ int s,
ProxyEvent event )
{
so->so_state &= ~SS_PROXIFIED;
if (event == PROXY_EVENT_CONNECTED) {
+ so->s = s;
so->so_state &= ~(SS_ISFCONNECTING);
}
else {
@@ -415,21 +417,17 @@ tcp_proxy_event( struct socket* so,
int tcp_fconnect(so)
struct socket *so;
{
- int ret=0;
- int try_proxy = 0;
-
- DEBUG_CALL("tcp_fconnect");
- DEBUG_ARG("so = %lx", (long )so);
-
- if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) {
- int s=so->s;
+ int ret=0;
+ int try_proxy = 1;
struct sockaddr_in addr;
- socket_set_nonblock(s);
- socket_set_xreuseaddr(s);
- socket_set_oobinline(s);
+ DEBUG_CALL("tcp_fconnect");
+ DEBUG_ARG("so = %lx", (long )so);
addr.sin_family = AF_INET;
+ addr.sin_addr = so->so_faddr;
+ addr.sin_port = so->so_fport;
+
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
/* It's an alias */
int last_byte = ntohl(so->so_faddr.s_addr) & 0xff;
@@ -438,32 +436,39 @@ int tcp_fconnect(so)
addr.sin_addr = dns_addr[last_byte - CTL_DNS];
else
addr.sin_addr = loopback_addr;
- } else {
- addr.sin_addr = so->so_faddr;
- try_proxy = 1;
+ try_proxy = 0;
}
- addr.sin_port = so->so_fport;
DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
- "addr.sin_addr.s_addr=%.16s\n",
- ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+ "addr.sin_addr.s_addr=%.16s proxy=%d\n",
+ ntohs(addr.sin_port), inet_ntoa(addr.sin_addr),
+ try_proxy));
if (try_proxy) {
- if (!proxy_manager_add(s, &addr, so, (ProxyEventFunc) tcp_proxy_event)) {
+ if (!proxy_manager_add(&addr, SOCK_STREAM, (ProxyEventFunc) tcp_proxy_event, so)) {
soisfconnecting(so);
+ so->s = -1;
so->so_state |= SS_PROXIFIED;
return 0;
}
}
- /* We don't care what port we get */
- ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
+ if ((ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0)
+ {
+ int s = so->s;
+
+ socket_set_nonblock(s);
+ socket_set_xreuseaddr(s);
+ socket_set_oobinline(s);
+
+ /* We don't care what port we get */
+ ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
- /*
- * If it's not in progress, it failed, so we just return 0,
- * without clearing SS_NOFDREF
- */
- soisfconnecting(so);
+ /*
+ * If it's not in progress, it failed, so we just return 0,
+ * without clearing SS_NOFDREF
+ */
+ soisfconnecting(so);
}
return(ret);
@@ -840,7 +845,7 @@ tcp_emu(so, m)
* A typical packet for player version 1.0 (release version):
*
* 0000:50 4E 41 00 05
- * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
+ * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....�..g�l�c..P
* 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
* 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
* 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
@@ -852,8 +857,8 @@ tcp_emu(so, m)
*
* A typical packet for player version 2.0 (beta):
*
- * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
- * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
+ * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........�.
+ * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux�c..Win2.0.0
* 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
* 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
* 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
diff --git a/sockets.c b/sockets.c
index 3a5e96d..1a0d356 100644
--- a/sockets.c
+++ b/sockets.c
@@ -447,3 +447,71 @@ socket_unix_client( const char* name, int type )
}
#endif
+
+
+int
+socket_pair(int *fd1, int *fd2)
+{
+#ifndef _WIN32
+ int fds[2];
+ int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+ if (!ret) {
+ socket_set_nonblock(fds[0]);
+ socket_set_nonblock(fds[1]);
+ *fd1 = fds[0];
+ *fd2 = fds[1];
+ }
+ return ret;
+#else /* _WIN32 */
+ /* on Windows, select() only works with network sockets, which
+ * means we absolutely cannot use Win32 PIPEs to implement
+ * socket pairs with the current event loop implementation.
+ * We're going to do like Cygwin: create a random pair
+ * of localhost TCP sockets and connect them together
+ */
+ int s0, s1, s2, port;
+ struct sockaddr_in sockin;
+ socklen_t len;
+
+ /* first, create the 'server' socket.
+ * a port number of 0 means 'any port between 1024 and 5000.
+ * see Winsock bind() documentation for details */
+ s0 = socket_loopback_server( 0, SOCK_STREAM );
+ if (s0 < 0)
+ return -1;
+
+ /* now connect a client socket to it, we first need to
+ * extract the server socket's port number */
+ len = sizeof sockin;
+ if (getsockname(s0, (struct sockaddr*) &sockin, &len) < 0) {
+ closesocket (s0);
+ return -1;
+ }
+
+ port = ntohs(sockin.sin_port);
+ s2 = socket_loopback_client( port, SOCK_STREAM );
+ if (s2 < 0) {
+ closesocket(s0);
+ return -1;
+ }
+
+ /* we need to accept the connection on the server socket
+ * this will create the second socket for the pair
+ */
+ len = sizeof sockin;
+ s1 = accept(s0, (struct sockaddr*) &sockin, &len);
+ if (s1 == INVALID_SOCKET) {
+ closesocket (s0);
+ closesocket (s2);
+ return -1;
+ }
+ socket_set_nonblock(s1);
+
+ /* close server socket */
+ closesocket(s0);
+ *fd1 = s1;
+ *fd2 = s2;
+ return 0;
+#endif /* _WIN32 */
+}
diff --git a/sockets.h b/sockets.h
index c1f6d80..f336ada 100644
--- a/sockets.h
+++ b/sockets.h
@@ -52,6 +52,15 @@ int socket_init( void );
int socket_get_type(int fd);
+/* this call creates a pair of non-blocking sockets connected
+ * to each other. this is equivalent to calling the Unix function:
+ * socketpair(AF_LOCAL,SOCK_STREAM,0,&fds)
+ *
+ * on Windows, this will use a pair of TCP loopback sockets instead
+ * returns 0 on success, -1 on error.
+ */
+int socket_pair(int *fd1, int *fd2);
+
/* set SO_REUSEADDR on Unix, SO_EXCLUSIVEADDR on Windows */
int socket_set_xreuseaddr(int fd);
int socket_set_nonblock(int fd);
diff --git a/telephony/sysdeps_qemu.c b/telephony/sysdeps_qemu.c
index e1107aa..469e0fe 100644
--- a/telephony/sysdeps_qemu.c
+++ b/telephony/sysdeps_qemu.c
@@ -315,11 +315,11 @@ SysChannel
sys_channel_create_tcp_server( int port )
{
SysChannel channel = sys_channel_alloc();
- const int BACKLOG = 4;
channel->fd = socket_anyaddr_server( port, SOCK_STREAM );
if (channel->fd < 0) {
- D( "%s: failed to created network socket on TCP:%d\n", port );
+ D( "%s: failed to created network socket on TCP:%d\n",
+ __FUNCTION__, port );
sys_channel_free( channel );
return NULL;
}
diff --git a/texi2pod.pl b/texi2pod.pl
deleted file mode 100755
index 176627e..0000000
--- a/texi2pod.pl
+++ /dev/null
@@ -1,428 +0,0 @@
-#! /usr/bin/perl -w
-
-# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
-
-# This file is part of GNU CC.
-
-# GNU CC 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, or (at your option)
-# any later version.
-
-# GNU CC 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 GNU CC; see the file COPYING. If not, write to
-# the Free Software Foundation, 59 Temple Place - Suite 330,
-# Boston MA 02111-1307, USA.
-
-# This does trivial (and I mean _trivial_) conversion of Texinfo
-# markup to Perl POD format. It's intended to be used to extract
-# something suitable for a manpage from a Texinfo document.
-
-$output = 0;
-$skipping = 0;
-%sects = ();
-$section = "";
-@icstack = ();
-@endwstack = ();
-@skstack = ();
-@instack = ();
-$shift = "";
-%defs = ();
-$fnno = 1;
-$inf = "";
-$ibase = "";
-
-while ($_ = shift) {
- if (/^-D(.*)$/) {
- if ($1 ne "") {
- $flag = $1;
- } else {
- $flag = shift;
- }
- $value = "";
- ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
- die "no flag specified for -D\n"
- unless $flag ne "";
- die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
- unless $flag =~ /^[a-zA-Z0-9_-]+$/;
- $defs{$flag} = $value;
- } elsif (/^-/) {
- usage();
- } else {
- $in = $_, next unless defined $in;
- $out = $_, next unless defined $out;
- usage();
- }
-}
-
-if (defined $in) {
- $inf = gensym();
- open($inf, "<$in") or die "opening \"$in\": $!\n";
- $ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
-} else {
- $inf = \*STDIN;
-}
-
-if (defined $out) {
- open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
-}
-
-while(defined $inf) {
-while(<$inf>) {
- # Certain commands are discarded without further processing.
- /^\@(?:
- [a-z]+index # @*index: useful only in complete manual
- |need # @need: useful only in printed manual
- |(?:end\s+)?group # @group .. @end group: ditto
- |page # @page: ditto
- |node # @node: useful only in .info file
- |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents
- )\b/x and next;
-
- chomp;
-
- # Look for filename and title markers.
- /^\@setfilename\s+([^.]+)/ and $fn = $1, next;
- /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
-
- # Identify a man title but keep only the one we are interested in.
- /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
- if (exists $defs{$1}) {
- $fn = $1;
- $tl = postprocess($2);
- }
- next;
- };
-
- # Look for blocks surrounded by @c man begin SECTION ... @c man end.
- # This really oughta be @ifman ... @end ifman and the like, but such
- # would require rev'ing all other Texinfo translators.
- /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
- $output = 1 if exists $defs{$2};
- $sect = $1;
- next;
- };
- /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
- /^\@c\s+man\s+end/ and do {
- $sects{$sect} = "" unless exists $sects{$sect};
- $sects{$sect} .= postprocess($section);
- $section = "";
- $output = 0;
- next;
- };
-
- # handle variables
- /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
- $defs{$1} = $2;
- next;
- };
- /^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
- delete $defs{$1};
- next;
- };
-
- next unless $output;
-
- # Discard comments. (Can't do it above, because then we'd never see
- # @c man lines.)
- /^\@c\b/ and next;
-
- # End-block handler goes up here because it needs to operate even
- # if we are skipping.
- /^\@end\s+([a-z]+)/ and do {
- # Ignore @end foo, where foo is not an operation which may
- # cause us to skip, if we are presently skipping.
- my $ended = $1;
- next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/;
-
- die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
- die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
-
- $endw = pop @endwstack;
-
- if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
- $skipping = pop @skstack;
- next;
- } elsif ($ended =~ /^(?:example|smallexample|display)$/) {
- $shift = "";
- $_ = ""; # need a paragraph break
- } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
- $_ = "\n=back\n";
- $ic = pop @icstack;
- } else {
- die "unknown command \@end $ended at line $.\n";
- }
- };
-
- # We must handle commands which can cause skipping even while we
- # are skipping, otherwise we will not process nested conditionals
- # correctly.
- /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
- push @endwstack, $endw;
- push @skstack, $skipping;
- $endw = "ifset";
- $skipping = 1 unless exists $defs{$1};
- next;
- };
-
- /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
- push @endwstack, $endw;
- push @skstack, $skipping;
- $endw = "ifclear";
- $skipping = 1 if exists $defs{$1};
- next;
- };
-
- /^\@(ignore|menu|iftex)\b/ and do {
- push @endwstack, $endw;
- push @skstack, $skipping;
- $endw = $1;
- $skipping = 1;
- next;
- };
-
- next if $skipping;
-
- # Character entities. First the ones that can be replaced by raw text
- # or discarded outright:
- s/\@copyright\{\}/(c)/g;
- s/\@dots\{\}/.../g;
- s/\@enddots\{\}/..../g;
- s/\@([.!? ])/$1/g;
- s/\@[:-]//g;
- s/\@bullet(?:\{\})?/*/g;
- s/\@TeX\{\}/TeX/g;
- s/\@pounds\{\}/\#/g;
- s/\@minus(?:\{\})?/-/g;
- s/\\,/,/g;
-
- # Now the ones that have to be replaced by special escapes
- # (which will be turned back into text by unmunge())
- s/&/&amp;/g;
- s/\@\{/&lbrace;/g;
- s/\@\}/&rbrace;/g;
- s/\@\@/&at;/g;
-
- # Inside a verbatim block, handle @var specially.
- if ($shift ne "") {
- s/\@var\{([^\}]*)\}/<$1>/g;
- }
-
- # POD doesn't interpret E<> inside a verbatim block.
- if ($shift eq "") {
- s/</&lt;/g;
- s/>/&gt;/g;
- } else {
- s/</&LT;/g;
- s/>/&GT;/g;
- }
-
- # Single line command handlers.
-
- /^\@include\s+(.+)$/ and do {
- push @instack, $inf;
- $inf = gensym();
-
- # Try cwd and $ibase.
- open($inf, "<" . $1)
- or open($inf, "<" . $ibase . "/" . $1)
- or die "cannot open $1 or $ibase/$1: $!\n";
- next;
- };
-
- /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
- and $_ = "\n=head2 $1\n";
- /^\@subsection\s+(.+)$/
- and $_ = "\n=head3 $1\n";
-
- # Block command handlers:
- /^\@itemize\s+(\@[a-z]+|\*|-)/ and do {
- push @endwstack, $endw;
- push @icstack, $ic;
- $ic = $1;
- $_ = "\n=over 4\n";
- $endw = "itemize";
- };
-
- /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
- push @endwstack, $endw;
- push @icstack, $ic;
- if (defined $1) {
- $ic = $1 . ".";
- } else {
- $ic = "1.";
- }
- $_ = "\n=over 4\n";
- $endw = "enumerate";
- };
-
- /^\@([fv]?table)\s+(\@[a-z]+)/ and do {
- push @endwstack, $endw;
- push @icstack, $ic;
- $endw = $1;
- $ic = $2;
- $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
- $ic =~ s/\@(?:code|kbd)/C/;
- $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
- $ic =~ s/\@(?:file)/F/;
- $_ = "\n=over 4\n";
- };
-
- /^\@((?:small)?example|display)/ and do {
- push @endwstack, $endw;
- $endw = $1;
- $shift = "\t";
- $_ = ""; # need a paragraph break
- };
-
- /^\@itemx?\s*(.+)?$/ and do {
- if (defined $1) {
- # Entity escapes prevent munging by the <> processing below.
-# print "$ic\n";
- $_ = "\n=item $ic\&LT;$1\&GT;\n";
- } else {
- $_ = "\n=item $ic\n";
- $ic =~ y/A-Ya-y/B-Zb-z/;
- $ic =~ s/(\d+)/$1 + 1/eg;
- }
- };
-
- $section .= $shift.$_."\n";
-}
-# End of current file.
-close($inf);
-$inf = pop @instack;
-}
-
-die "No filename or title\n" unless defined $fn && defined $tl;
-
-$sects{NAME} = "$fn \- $tl\n";
-$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
-
-for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
- BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
- if(exists $sects{$sect}) {
- $head = $sect;
- $head =~ s/SEEALSO/SEE ALSO/;
- print "=head1 $head\n\n";
- print scalar unmunge ($sects{$sect});
- print "\n";
- }
-}
-
-sub usage
-{
- die "usage: $0 [-D toggle...] [infile [outfile]]\n";
-}
-
-sub postprocess
-{
- local $_ = $_[0];
-
- # @value{foo} is replaced by whatever 'foo' is defined as.
- while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
- if (! exists $defs{$2}) {
- print STDERR "Option $2 not defined\n";
- s/\Q$1\E//;
- } else {
- $value = $defs{$2};
- s/\Q$1\E/$value/;
- }
- }
-
- # Formatting commands.
- # Temporary escape for @r.
- s/\@r\{([^\}]*)\}/R<$1>/g;
- s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
- s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
- s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
- s/\@sc\{([^\}]*)\}/\U$1/g;
- s/\@file\{([^\}]*)\}/F<$1>/g;
- s/\@w\{([^\}]*)\}/S<$1>/g;
- s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
-
- # Cross references are thrown away, as are @noindent and @refill.
- # (@noindent is impossible in .pod, and @refill is unnecessary.)
- # @* is also impossible in .pod; we discard it and any newline that
- # follows it. Similarly, our macro @gol must be discarded.
-
- s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
- s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
- s/;\s+\@pxref\{(?:[^\}]*)\}//g;
- s/\@noindent\s*//g;
- s/\@refill//g;
- s/\@gol//g;
- s/\@\*\s*\n?//g;
-
- # @uref can take one, two, or three arguments, with different
- # semantics each time. @url and @email are just like @uref with
- # one argument, for our purposes.
- s/\@(?:uref|url|email)\{([^\},]*)\}/&lt;B<$1>&gt;/g;
- s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
- s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
-
- # Turn B<blah I<blah> blah> into B<blah> I<blah> B<blah> to
- # match Texinfo semantics of @emph inside @samp. Also handle @r
- # inside bold.
- s/&LT;/</g;
- s/&GT;/>/g;
- 1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B</g;
- 1 while (s/B<([^<>]*)I<([^>]+)>/B<$1>I<$2>B</g);
- 1 while (s/I<([^<>]*)B<([^>]+)>/I<$1>B<$2>I</g);
- s/[BI]<>//g;
- s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
- s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
-
- # Extract footnotes. This has to be done after all other
- # processing because otherwise the regexp will choke on formatting
- # inside @footnote.
- while (/\@footnote/g) {
- s/\@footnote\{([^\}]+)\}/[$fnno]/;
- add_footnote($1, $fnno);
- $fnno++;
- }
-
- return $_;
-}
-
-sub unmunge
-{
- # Replace escaped symbols with their equivalents.
- local $_ = $_[0];
-
- s/&lt;/E<lt>/g;
- s/&gt;/E<gt>/g;
- s/&lbrace;/\{/g;
- s/&rbrace;/\}/g;
- s/&at;/\@/g;
- s/&amp;/&/g;
- return $_;
-}
-
-sub add_footnote
-{
- unless (exists $sects{FOOTNOTES}) {
- $sects{FOOTNOTES} = "\n=over 4\n\n";
- }
-
- $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
- $sects{FOOTNOTES} .= $_[0];
- $sects{FOOTNOTES} .= "\n\n";
-}
-
-# stolen from Symbol.pm
-{
- my $genseq = 0;
- sub gensym
- {
- my $name = "GEN" . $genseq++;
- my $ref = \*{$name};
- delete $::{$name};
- return $ref;
- }
-}
diff --git a/translate.make b/translate.make
index 136d5a5..cba105f 100644
--- a/translate.make
+++ b/translate.make
@@ -7,7 +7,8 @@ EMULATOR_OP_LIBRARIES := $(EMULATOR_OP_LIBRARIES) $(LOCAL_MODULE)
LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
LOCAL_CC := $(MY_CC)
-LOCAL_CFLAGS += $(OP_CFLAGS)
+LOCAL_LDFLAGS += $(my_32bit_ldflags)
+LOCAL_CFLAGS += $(my_32bit_cflags) $(OP_CFLAGS)
INTERMEDIATE := $(call intermediates-dir-for,STATIC_LIBRARIES,$(LOCAL_MODULE),true)
OP_OBJ := $(INTERMEDIATE)/target-arm/op.o
diff --git a/vl.c b/vl.c
index adb708c..98d2fa3 100644
--- a/vl.c
+++ b/vl.c
@@ -116,12 +116,8 @@ extern void android_emulation_teardown( void );
#ifdef TARGET_PPC
#define DEFAULT_RAM_SIZE 144
#else
-#if 1 /* Android */
-#define DEFAULT_RAM_SIZE 96
-#else
#define DEFAULT_RAM_SIZE 128
#endif
-#endif
/* in ms */
#define GUI_REFRESH_INTERVAL (1000/60)