aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android/avd/hardware-properties.ini17
-rw-r--r--android/camera/camera-capture-linux.c55
-rw-r--r--android/camera/camera-capture-mac.c4
-rwxr-xr-xandroid/camera/camera-capture-windows.c105
-rwxr-xr-xandroid/camera/camera-common.h26
-rwxr-xr-xandroid/camera/camera-format-converters.c5
-rw-r--r--android/camera/camera-service.c80
-rw-r--r--android/hw-qemud.c30
-rw-r--r--android/main.c11
-rw-r--r--arch_init.c10
-rw-r--r--hw/android_arm.c1
-rw-r--r--hw/goldfish_audio.c2
-rw-r--r--hw/goldfish_device.c13
-rw-r--r--hw/goldfish_device.h14
-rw-r--r--hw/goldfish_interrupt.c2
-rw-r--r--hw/goldfish_pipe.c19
-rw-r--r--hw/i8259.c3
-rw-r--r--hw/pc.c4
-rw-r--r--savevm.c6
-rw-r--r--vl-android.c5
20 files changed, 317 insertions, 95 deletions
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index fb53536..a2b05df 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -14,10 +14,8 @@
# - once to implement the hardware configuration loader
# (see android/avd/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)
-#
+# It is also packaged by the SDK and parsed by tools to let the developers
+# create AVDs.
#
# NOTE: if you remove items from this file, be sure that you do not break
# the emulator build.
@@ -55,6 +53,13 @@ default = yes
abstract = Touch-screen support
description = Whether there is a touch screen or not on the device.
+# Hardware main keys (back/home)
+name = hw.mainKeys
+type = boolean
+default = yes
+abstract = Hardware Back/Home keys
+description = Whether there are hardware back/home keys on the device.
+
# Trackball support
name = hw.trackBall
type = boolean
@@ -305,10 +310,12 @@ abstract = 1-st emulated web camera direction
description = Direction of the 1-st emulated web camera
# Defines direction of the emulated webcam with index 1
+# Note that first two cameras must face in opposite directions in order to enable
+# camera switch in the camera application.
#
name = hw.webcam.1.direction
type = string
-default = front
+default = back
abstract = 2-nd emulated web camera direction
description = Direction of the 2-nd emulated web camera
diff --git a/android/camera/camera-capture-linux.c b/android/camera/camera-capture-linux.c
index 895690d..8a96c0c 100644
--- a/android/camera/camera-capture-linux.c
+++ b/android/camera/camera-capture-linux.c
@@ -26,9 +26,9 @@
#include "android/camera/camera-capture.h"
#include "android/camera/camera-format-converters.h"
+#define E(...) derror(__VA_ARGS__)
+#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__)
#define D_ACTIVE VERBOSE_CHECK(camera)
/* the T(...) macro is used to dump traffic */
@@ -282,6 +282,38 @@ _camera_device_free(LinuxCameraDevice* lcd)
}
}
+/* Resets camera device after capturing.
+ * Since new capture request may require different frame dimensions we must
+ * reset camera device by reopening its handle. Otherwise attempts to set up new
+ * frame properties (different from the previous one) may fail. */
+static void
+_camera_device_reset(LinuxCameraDevice* cd)
+{
+ struct v4l2_cropcap cropcap;
+ struct v4l2_crop crop;
+
+ /* Free capturing framebuffers first. */
+ if (cd->framebuffers != NULL) {
+ _free_framebuffers(cd->framebuffers, cd->framebuffer_num, cd->io_type);
+ free(cd->framebuffers);
+ cd->framebuffers = NULL;
+ cd->framebuffer_num = 0;
+ }
+
+ /* Reset device handle. */
+ close(cd->handle);
+ cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0);
+
+ if (cd->handle >= 0) {
+ /* Select video input, video standard and tune here. */
+ cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap);
+ crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ crop.c = cropcap.defrect; /* reset to default */
+ _xioctl (cd->handle, VIDIOC_S_CROP, &crop);
+ }
+}
+
/* Memory maps buffers and shares mapped memory with the device.
* Return:
* 0 Framebuffers have been mapped.
@@ -466,8 +498,6 @@ _camera_device_open(LinuxCameraDevice* cd)
struct stat st;
if (stat(cd->device_name, &st)) {
- E("%s: Cannot identify camera device '%s': %s",
- __FUNCTION__, cd->device_name, strerror(errno));
return -1;
}
@@ -825,6 +855,7 @@ camera_device_start_capturing(CameraDevice* ccd,
fmt_str[4] = '\0';
E("%s: Camera '%s' does not support pixel format '%s' with dimensions %dx%d",
__FUNCTION__, cd->device_name, fmt_str, frame_width, frame_height);
+ _camera_device_reset(cd);
return -1;
}
/* VIDIOC_S_FMT may has changed some properties of the structure. Make sure
@@ -834,6 +865,7 @@ camera_device_start_capturing(CameraDevice* ccd,
fmt_str[4] = '\0';
E("%s: Dimensions %dx%d are wrong for pixel format '%s'",
__FUNCTION__, frame_width, frame_height, fmt_str);
+ _camera_device_reset(cd);
return -1;
}
memcpy(&cd->actual_pixel_format, &fmt.fmt.pix, sizeof(struct v4l2_pix_format));
@@ -847,6 +879,7 @@ camera_device_start_capturing(CameraDevice* ccd,
r = _camera_device_mmap_framebuffer(cd);
if (r < 0) {
/* Some critical error has ocurred. Bail out. */
+ _camera_device_reset(cd);
return -1;
} else if (r > 0) {
/* Device doesn't support memory mapping. Retrieve to the next performant
@@ -854,17 +887,20 @@ camera_device_start_capturing(CameraDevice* ccd,
r = _camera_device_user_framebuffer(cd);
if (r < 0) {
/* Some critical error has ocurred. Bail out. */
+ _camera_device_reset(cd);
return -1;
} else if (r > 0) {
/* The only thing left for us is direct reading from the device. */
if (!(cd->caps.capabilities & V4L2_CAP_READWRITE)) {
E("%s: Don't know how to access frames on device '%s'",
__FUNCTION__, cd->device_name);
+ _camera_device_reset(cd);
return -1;
}
r = _camera_device_direct_framebuffer(cd);
if (r != 0) {
/* Any error at this point is a critical one. */
+ _camera_device_reset(cd);
return -1;
}
}
@@ -877,6 +913,7 @@ camera_device_start_capturing(CameraDevice* ccd,
if (_xioctl (cd->handle, VIDIOC_STREAMON, &type) < 0) {
E("%s: VIDIOC_STREAMON on camera '%s' has failed: %s",
__FUNCTION__, cd->device_name, strerror(errno));
+ _camera_device_reset(cd);
return -1;
}
}
@@ -919,18 +956,10 @@ camera_device_stop_capturing(CameraDevice* ccd)
return -1;
}
- if (cd->framebuffers != NULL) {
- _free_framebuffers(cd->framebuffers, cd->framebuffer_num, cd->io_type);
- free(cd->framebuffers);
- cd->framebuffers = NULL;
- cd->framebuffer_num = 0;
- }
-
/* Reopen the device to reset its internal state. It seems that if we don't
* do that, an attempt to reinit the device with different frame dimensions
* would fail. */
- close(cd->handle);
- cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0);
+ _camera_device_reset(cd);
return 0;
}
diff --git a/android/camera/camera-capture-mac.c b/android/camera/camera-capture-mac.c
index 8a793c1..764a055 100644
--- a/android/camera/camera-capture-mac.c
+++ b/android/camera/camera-capture-mac.c
@@ -21,9 +21,9 @@
#include "android/camera/camera-capture.h"
+#define E(...) derror(__VA_ARGS__)
+#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__)
#define D_ACTIVE VERBOSE_CHECK(camera)
/* the T(...) macro is used to dump traffic */
diff --git a/android/camera/camera-capture-windows.c b/android/camera/camera-capture-windows.c
index 0fb172e..28820a8 100755
--- a/android/camera/camera-capture-windows.c
+++ b/android/camera/camera-capture-windows.c
@@ -23,9 +23,9 @@
#include "android/camera/camera-capture.h"
#include "android/camera/camera-format-converters.h"
+#define E(...) derror(__VA_ARGS__)
+#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__)
#define D_ACTIVE VERBOSE_CHECK(camera)
/* the T(...) macro is used to dump traffic */
@@ -145,6 +145,46 @@ _camera_device_free(WndCameraDevice* cd)
}
}
+/* Resets camera device after capturing.
+ * Since new capture request may require different frame dimensions we must
+ * reset frame info cached in the capture window. The only way to do that would
+ * be closing, and reopening it again. */
+static void
+_camera_device_reset(WndCameraDevice* cd)
+{
+ if (cd != NULL && cd->cap_window != NULL) {
+ capDriverDisconnect(cd->cap_window);
+ if (cd->dc != NULL) {
+ ReleaseDC(cd->cap_window, cd->dc);
+ cd->dc = NULL;
+ }
+ if (cd->gdi_bitmap != NULL) {
+ free(cd->gdi_bitmap);
+ cd->gdi_bitmap = NULL;
+ }
+ if (cd->frame_bitmap != NULL) {
+ free(cd->frame_bitmap);
+ cd->frame_bitmap = NULL;
+ }
+ if (cd->framebuffer != NULL) {
+ free(cd->framebuffer);
+ cd->framebuffer = NULL;
+ }
+
+ /* Recreate the capturing window. */
+ DestroyWindow(cd->cap_window);
+ cd->cap_window = capCreateCaptureWindow(cd->window_name, WS_CHILD, 0, 0,
+ 0, 0, HWND_MESSAGE, 1);
+ }
+}
+
+/* Gets an absolute value out of a signed integer. */
+static __inline__ int
+_abs(int val)
+{
+ return (val < 0) ? -val : val;
+}
+
/*******************************************************************************
* CameraDevice API
******************************************************************************/
@@ -212,29 +252,54 @@ camera_device_start_capturing(CameraDevice* cd,
/* Connect capture window to the video capture driver. */
if (!capDriverConnect(wcd->cap_window, wcd->input_channel)) {
- E("%s: Unable to connect to the video capturing driver #%d: %d",
- __FUNCTION__, wcd->input_channel, GetLastError());
return -1;
}
- /* Get frame information from the driver. */
+ /* Get current frame information from the driver. */
format_info_size = capGetVideoFormatSize(wcd->cap_window);
if (format_info_size == 0) {
E("%s: Unable to get video format size: %d",
__FUNCTION__, GetLastError());
+ _camera_device_reset(wcd);
return -1;
}
wcd->frame_bitmap = (BITMAPINFO*)malloc(format_info_size);
if (wcd->frame_bitmap == NULL) {
E("%s: Unable to allocate frame bitmap info buffer", __FUNCTION__);
+ _camera_device_reset(wcd);
return -1;
}
if (!capGetVideoFormat(wcd->cap_window, wcd->frame_bitmap,
format_info_size)) {
E("%s: Unable to obtain video format: %d", __FUNCTION__, GetLastError());
+ _camera_device_reset(wcd);
return -1;
}
+ /* Lets see if we need to set different frame dimensions */
+ if (wcd->frame_bitmap->bmiHeader.biWidth != frame_width ||
+ abs(wcd->frame_bitmap->bmiHeader.biHeight) != frame_height) {
+ /* Dimensions don't match. Set new frame info. */
+ wcd->frame_bitmap->bmiHeader.biWidth = frame_width;
+ wcd->frame_bitmap->bmiHeader.biHeight = frame_height;
+ /* We need to recalculate image size, since the capture window / driver
+ * will use image size provided by us. */
+ if (wcd->frame_bitmap->bmiHeader.biBitCount == 24) {
+ /* Special case that may require WORD boundary alignment. */
+ uint32_t bpl = (frame_width * 3 + 1) & ~1;
+ wcd->frame_bitmap->bmiHeader.biSizeImage = bpl * frame_height;
+ } else {
+ wcd->frame_bitmap->bmiHeader.biSizeImage =
+ (frame_width * frame_height * wcd->frame_bitmap->bmiHeader.biBitCount) / 8;
+ }
+ if (!capSetVideoFormat(wcd->cap_window, wcd->frame_bitmap,
+ format_info_size)) {
+ E("%s: Unable to set video format: %d", __FUNCTION__, GetLastError());
+ _camera_device_reset(wcd);
+ return -1;
+ }
+ }
+
if (wcd->frame_bitmap->bmiHeader.biCompression > BI_PNG) {
D("%s: Video capturing driver has reported pixel format %.4s",
__FUNCTION__, (const char*)&wcd->frame_bitmap->bmiHeader.biCompression);
@@ -253,22 +318,13 @@ camera_device_start_capturing(CameraDevice* cd,
wcd->is_top_down = 0;
}
- /* Make sure that frame dimensions match. */
- if (frame_width != wcd->frame_bitmap->bmiHeader.biWidth ||
- frame_height != wcd->frame_bitmap->bmiHeader.biHeight) {
- E("%s: Requested dimensions %dx%d do not match the actual %dx%d",
- __FUNCTION__, frame_width, frame_height,
- wcd->frame_bitmap->bmiHeader.biWidth,
- wcd->frame_bitmap->bmiHeader.biHeight);
- return -1;
- }
-
/* Get DC for the capturing window that will be used when we deal with
* bitmaps obtained from the camera device during frame capturing. */
wcd->dc = GetDC(wcd->cap_window);
if (wcd->dc == NULL) {
E("%s: Unable to obtain DC for %s: %d",
__FUNCTION__, wcd->window_name, GetLastError());
+ _camera_device_reset(wcd);
return -1;
}
@@ -286,6 +342,7 @@ camera_device_start_capturing(CameraDevice* cd,
!OpenClipboard(wcd->cap_window)) {
E("%s: Device '%s' is unable to save frame to the clipboard: %d",
__FUNCTION__, wcd->window_name, GetLastError());
+ _camera_device_reset(wcd);
return -1;
}
@@ -296,6 +353,7 @@ camera_device_start_capturing(CameraDevice* cd,
E("%s: Device '%s' is unable to obtain frame from the clipboard: %d",
__FUNCTION__, wcd->window_name, GetLastError());
CloseClipboard();
+ _camera_device_reset(wcd);
return -1;
}
@@ -304,6 +362,7 @@ camera_device_start_capturing(CameraDevice* cd,
E("%s: Device '%s' is unable to obtain frame's bitmap: %d",
__FUNCTION__, wcd->window_name, GetLastError());
CloseClipboard();
+ _camera_device_reset(wcd);
return -1;
}
@@ -317,6 +376,7 @@ camera_device_start_capturing(CameraDevice* cd,
__FUNCTION__, frame_width, frame_height,
wcd->frame_bitmap->bmiHeader.biWidth,
wcd->frame_bitmap->bmiHeader.biHeight);
+ _camera_device_reset(wcd);
return -1;
}
@@ -324,6 +384,7 @@ camera_device_start_capturing(CameraDevice* cd,
wcd->gdi_bitmap = (BITMAPINFO*)malloc(wcd->frame_bitmap->bmiHeader.biSize);
if (wcd->gdi_bitmap == NULL) {
E("%s: Unable to allocate gdi bitmap info", __FUNCTION__);
+ _camera_device_reset(wcd);
return -1;
}
memcpy(wcd->gdi_bitmap, wcd->frame_bitmap,
@@ -350,6 +411,7 @@ camera_device_start_capturing(CameraDevice* cd,
if (wcd->framebuffer == NULL) {
E("%s: Unable to allocate %d bytes for framebuffer",
__FUNCTION__, wcd->gdi_bitmap->bmiHeader.biSizeImage);
+ _camera_device_reset(wcd);
return -1;
}
@@ -357,16 +419,17 @@ camera_device_start_capturing(CameraDevice* cd,
if (wcd->gdi_bitmap->bmiHeader.biBitCount == 16) {
wcd->pixel_format = V4L2_PIX_FMT_RGB565;
} else if (wcd->gdi_bitmap->bmiHeader.biBitCount == 24) {
- wcd->pixel_format = V4L2_PIX_FMT_RGB24;
+ wcd->pixel_format = V4L2_PIX_FMT_BGR24;
} else if (wcd->gdi_bitmap->bmiHeader.biBitCount == 32) {
- wcd->pixel_format = V4L2_PIX_FMT_RGB32;
+ wcd->pixel_format = V4L2_PIX_FMT_BGR32;
} else {
E("%s: Unsupported number of bits per pixel %d",
__FUNCTION__, wcd->gdi_bitmap->bmiHeader.biBitCount);
+ _camera_device_reset(wcd);
return -1;
}
- D("%s: Capturing device '%s': %d bytes in %.4s [%dx%d] frame",
+ D("%s: Capturing device '%s': %d bits per pixel in %.4s [%dx%d] frame",
__FUNCTION__, wcd->window_name, wcd->gdi_bitmap->bmiHeader.biBitCount,
(const char*)&wcd->pixel_format, wcd->frame_bitmap->bmiHeader.biWidth,
wcd->frame_bitmap->bmiHeader.biHeight);
@@ -393,8 +456,8 @@ camera_device_stop_capturing(CameraDevice* cd)
ReleaseDC(wcd->cap_window, wcd->dc);
wcd->dc = NULL;
- /* Disconnect from the driver. */
- capDriverDisconnect(wcd->cap_window);
+ /* Reset the device in preparation for the next capture. */
+ _camera_device_reset(wcd);
return 0;
}
@@ -499,7 +562,6 @@ enumerate_camera_devices(CameraInfo* cis, int max)
* the course of the routine. Also note that on Windows all frames will be
* 640x480. */
if (!camera_device_start_capturing(cd, V4L2_PIX_FMT_RGB32, 640, 480)) {
- camera_device_stop_capturing(cd);
/* capXxx API supports only single frame size (always observed 640x480,
* but the actual numbers may vary). */
cis[found].frame_sizes = (CameraFrameDim*)malloc(sizeof(CameraFrameDim));
@@ -519,6 +581,7 @@ enumerate_camera_devices(CameraInfo* cis, int max)
} else {
E("%s: Unable to allocate dimensions", __FUNCTION__);
}
+ camera_device_stop_capturing(cd);
} else {
/* No more cameras. */
camera_device_close(cd);
diff --git a/android/camera/camera-common.h b/android/camera/camera-common.h
index 126b3ed..de09045 100755
--- a/android/camera/camera-common.h
+++ b/android/camera/camera-common.h
@@ -176,5 +176,31 @@ typedef struct CameraDevice {
/* Opaque pointer used by the camera capturing API. */
void* opaque;
} CameraDevice;
+
+/* Returns current time in microseconds. */
+static __inline__ uint64_t
+_get_timestamp(void)
+{
+ struct timeval t;
+ t.tv_sec = t.tv_usec = 0;
+ gettimeofday(&t, NULL);
+ return (uint64_t)t.tv_sec * 1000000LL + t.tv_usec;
+}
+
+/* Sleeps for the given amount of milliseconds */
+static __inline__ void
+_camera_sleep(int millisec)
+{
+ struct timeval t;
+ const uint64_t wake_at = _get_timestamp() + (uint64_t)millisec * 1000;
+ do {
+ const uint64_t stamp = _get_timestamp();
+ if ((stamp / 1000) >= (wake_at / 1000)) {
+ break;
+ }
+ t.tv_sec = (wake_at - stamp) / 1000000;
+ t.tv_usec = (wake_at - stamp) - (uint64_t)t.tv_sec * 1000000;
+ } while (select(0, NULL, NULL, NULL, &t) < 0 && errno == EINTR);
+}
#endif /* ANDROID_CAMERA_CAMERA_COMMON_H_ */
diff --git a/android/camera/camera-format-converters.c b/android/camera/camera-format-converters.c
index c675f15..3366a44 100755
--- a/android/camera/camera-format-converters.c
+++ b/android/camera/camera-format-converters.c
@@ -24,9 +24,10 @@
#endif
#include "android/camera/camera-format-converters.h"
+#define E(...) derror(__VA_ARGS__)
+#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__)
+#define D_ACTIVE VERBOSE_CHECK(camera)
/*
* NOTE: RGB and big/little endian considerations. Wherewer in this code RGB
diff --git a/android/camera/camera-service.c b/android/camera/camera-service.c
index 282acb4..ee3ea6e 100644
--- a/android/camera/camera-service.c
+++ b/android/camera/camera-service.c
@@ -28,9 +28,9 @@
#include "android/camera/camera-format-converters.h"
#include "android/camera/camera-service.h"
+#define E(...) derror(__VA_ARGS__)
+#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__)
-#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__)
#define D_ACTIVE VERBOSE_CHECK(camera)
/* the T(...) macro is used to dump traffic */
@@ -445,8 +445,11 @@ _camera_service_init(CameraServiceDesc* csd)
}
/* For each webcam declared in hw.ini find an actual camera information
- * descriptor, and save it into the service descriptor for the emulation. */
- for (i = 0; i < android_hw->hw_webcam_count; i++) {
+ * descriptor, and save it into the service descriptor for the emulation.
+ * Stop the loop when all the connected cameras have been added to the
+ * service. */
+ for (i = 0; i < android_hw->hw_webcam_count &&
+ csd->camera_count < connected_cnt; i++) {
const char* disp_name;
const char* dir;
CameraInfo* found;
@@ -497,9 +500,32 @@ _camera_service_init(CameraServiceDesc* csd)
csd->camera_count++;
memset(found, 0, sizeof(CameraInfo));
} else {
- dwarning("Camera name '%s' is not found in the list of connected cameras.\n"
- "Use -webcam-list emulator option to obtain the list of connected camera names\n\n",
- disp_name);
+ W("Camera name '%s' is not found in the list of connected cameras.\n"
+ "Use '-webcam list' emulator option to obtain the list of connected camera names.\n",
+ disp_name);
+ }
+ }
+
+ /* Make sure that camera 0 and camera 1 are facing in opposite directions.
+ * If they don't the camera application will crash on an attempt to switch
+ * cameras. */
+ if (csd->camera_count > 0) {
+ const char* cam2_dir = NULL;
+ const char* cam2_name = NULL;
+ if (csd->camera_count >= 2) {
+ cam2_dir = csd->camera_info[1].direction;
+ cam2_name = csd->camera_info[1].display_name;
+ } else if (strcmp(android_hw->hw_fakeCamera, "off")) {
+ cam2_dir = android_hw->hw_fakeCamera;
+ cam2_name = "fake camera";
+ }
+ if (cam2_dir != NULL && !strcmp(csd->camera_info[0].direction, cam2_dir)) {
+ W("Cameras '%s' and '%s' are both facing %s.\n"
+ "It is required by the camera application that first two emulated cameras\n"
+ "are facing in opposite directions. If they both are facing in the same direction,\n"
+ "the camera application will crash on an attempt to switch the camera.\n",
+ csd->camera_info[0].display_name, cam2_name, cam2_dir);
+
}
}
}
@@ -752,10 +778,6 @@ struct CameraClient
* Note that memory allocated for this buffer
* also contains preview framebuffer. */
uint8_t* video_frame;
- /* Point to Cb pane inside the video frame buffer. */
- uint8_t* video_frame_Cb;
- /* Point to Cr pane inside the video frame buffer. */
- uint8_t* video_frame_Cr;
/* Preview frame buffer.
* This address points inside the 'video_frame' buffer. */
uint16_t* preview_frame;
@@ -1090,11 +1112,6 @@ _camera_client_query_start(CameraClient* cc, QemudClient* qc, const char* param)
/* Set framebuffer pointers. */
cc->preview_frame = (uint16_t*)(cc->video_frame + cc->video_frame_size);
- /* TODO: Get rid if this! It assumes that client's framebuffer is YV12. Let
- * the camera do the conversion. All we need is to ensure that framebuffers
- * allocated here are large enough! */
- cc->video_frame_Cb = cc->video_frame + cc->pixel_num;
- cc->video_frame_Cr = cc->video_frame_Cb + cc->pixel_num / 4;
/* Start the camera. */
if (camera_device_start_capturing(cc->camera, cc->camera_info->pixel_format,
@@ -1164,6 +1181,7 @@ _camera_client_query_frame(CameraClient* cc, QemudClient* qc, const char* param)
ClientFrameBuffer fbs[2];
int fbs_num = 0;
size_t payload_size;
+ uint64_t tick;
/* Sanity check. */
if (cc->video_frame == NULL) {
@@ -1212,25 +1230,41 @@ _camera_client_query_frame(CameraClient* cc, QemudClient* qc, const char* param)
}
/* Capture new frame. */
+ tick = _get_timestamp();
repeat = camera_device_read_frame(cc->camera, fbs, fbs_num);
/* Note that there is no (known) way how to wait on next frame being
- * available, so we dequeue frame buffer from the device only when we know
- * it's available. Instead we're shooting in the dark, and quite often
+ * available, so we could dequeue frame buffer from the device only when we
+ * know it's available. Instead we're shooting in the dark, and quite often
* device will response with EAGAIN, indicating that it doesn't have frame
* ready. In turn, it means that the last frame we have obtained from the
* device is still good, and we can reply with the cached frames. The only
* case when we need to keep trying to obtain a new frame is when frame cache
- * is empty. */
- while (repeat == 1 && !cc->frames_cached) {
+ * is empty. To prevent ourselves from an indefinite loop in case device got
+ * stuck on something (observed with some Microsoft devices) we will limit
+ * the loop by 2 second time period (which is more than enough to obtain
+ * something from the device) */
+ while (repeat == 1 && !cc->frames_cached &&
+ (_get_timestamp() - tick) < 2000000LL) {
+ /* Sleep for 10 millisec before repeating the attempt. */
+ _camera_sleep(10);
repeat = camera_device_read_frame(cc->camera, fbs, fbs_num);
}
- if (repeat < 0) {
- E("%s: Unable to obtain video frame from the camera '%s': %s",
- __FUNCTION__, cc->device_name, strerror(errno));
+ if (repeat == 1 && !cc->frames_cached) {
+ /* Waited too long for the first frame. */
+ E("%s: Unable to obtain first video frame from the camera '%s' in %d milliseconds: %s.",
+ __FUNCTION__, cc->device_name,
+ (uint32_t)(_get_timestamp() - tick) / 1000, strerror(errno));
_qemu_client_reply_ko(qc, "Unable to obtain video frame from the camera");
return;
+ } else if (repeat < 0) {
+ /* An I/O error. */
+ E("%s: Unable to obtain video frame from the camera '%s': %s.",
+ __FUNCTION__, cc->device_name, strerror(errno));
+ _qemu_client_reply_ko(qc, strerror(errno));
+ return;
}
+
/* We have cached something... */
cc->frames_cached = 1;
diff --git a/android/hw-qemud.c b/android/hw-qemud.c
index b8d912c..0820e4c 100644
--- a/android/hw-qemud.c
+++ b/android/hw-qemud.c
@@ -45,7 +45,7 @@
/* Version number of snapshots code. Increment whenever the data saved
* or the layout in which it is saved is changed.
*/
-#define QEMUD_SAVE_VERSION 1
+#define QEMUD_SAVE_VERSION 2
#define min(a, b) (((a) < (b)) ? (a) : (b))
@@ -934,7 +934,7 @@ qemud_client_save(QEMUFile* f, QemudClient* c)
/* save generic information */
qemud_service_save_name(f, c->service);
qemu_put_be32(f, c->protocol);
- if (_is_pipe_client(c)) {
+ if (!_is_pipe_client(c)) {
qemu_put_be32(f, c->ProtocolSelector.Serial.channel);
}
@@ -959,7 +959,7 @@ qemud_client_save(QEMUFile* f, QemudClient* c)
* corresponding service.
*/
static int
-qemud_client_load(QEMUFile* f, QemudService* current_services )
+qemud_client_load(QEMUFile* f, QemudService* current_services, int version )
{
char *service_name = qemud_service_load_name(f);
if (service_name == NULL)
@@ -973,13 +973,19 @@ qemud_client_load(QEMUFile* f, QemudService* current_services )
return -EIO;
}
- /* get protocol. */
- QemudProtocol protocol = qemu_get_be32(f);
- /* get channel id */
int channel = -1;
- if (protocol == QEMUD_PROTOCOL_SERIAL) {
- qemu_get_be32(f);
+
+ if (version >= 2) {
+ /* get protocol. */
+ QemudProtocol protocol = qemu_get_be32(f);
+ /* get channel id */
+ if (protocol == QEMUD_PROTOCOL_SERIAL) {
+ channel = qemu_get_be32(f);
+ }
+ } else {
+ channel = qemu_get_be32(f);
}
+
if (channel == 0) {
D("%s: illegal snapshot: client for control channel must no be saved\n",
__FUNCTION__);
@@ -1791,7 +1797,7 @@ qemud_load_services( QEMUFile* f, QemudService* current_services )
* changes, there is no communication with the guest.
*/
static int
-qemud_load_clients(QEMUFile* f, QemudMultiplexer* m )
+qemud_load_clients(QEMUFile* f, QemudMultiplexer* m, int version )
{
/* Remove all clients, except on the control channel.*/
qemud_multiplexer_disconnect_noncontrol(m);
@@ -1800,7 +1806,7 @@ qemud_load_clients(QEMUFile* f, QemudMultiplexer* m )
int client_count = qemu_get_be32(f);
int i, ret;
for (i = 0; i < client_count; i++) {
- if ((ret = qemud_client_load(f, m->services))) {
+ if ((ret = qemud_client_load(f, m->services, version))) {
return ret;
}
}
@@ -1816,14 +1822,12 @@ qemud_load(QEMUFile *f, void* opaque, int version)
QemudMultiplexer *m = opaque;
int ret;
- if (version != QEMUD_SAVE_VERSION)
- return -1;
if ((ret = qemud_serial_load(f, m->serial)))
return ret;
if ((ret = qemud_load_services(f, m->services)))
return ret;
- if ((ret = qemud_load_clients(f, m)))
+ if ((ret = qemud_load_clients(f, m, version)))
return ret;
return 0;
diff --git a/android/main.c b/android/main.c
index c2f8663..56ae698 100644
--- a/android/main.c
+++ b/android/main.c
@@ -455,6 +455,17 @@ int main(int argc, char **argv)
opts->trace = tracePath;
}
+ /* Update CPU architecture for HW configs created from build dir. */
+ if (inAndroidBuild) {
+#if defined(TARGET_ARM)
+ free(android_hw->hw_cpu_arch);
+ android_hw->hw_cpu_arch = ASTRDUP("arm");
+#elif defined(TARGET_I386)
+ free(android_hw->hw_cpu_arch);
+ android_hw->hw_cpu_arch = ASTRDUP("x86");
+#endif
+ }
+
n = 1;
/* generate arguments for the underlying qemu main() */
{
diff --git a/arch_init.c b/arch_init.c
index b966d8a..7285d27 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -382,7 +382,7 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
addr &= TARGET_PAGE_MASK;
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
- if (version_id == 3) {
+ if (version_id != 3) {
if (addr != ram_bytes_total()) {
return -EINVAL;
}
@@ -418,13 +418,11 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
total_ram_bytes -= length;
}
}
- }
-
- if (flags & RAM_SAVE_FLAG_COMPRESS) {
+ } else if (flags & RAM_SAVE_FLAG_COMPRESS) {
void *host;
uint8_t ch;
- if (version_id == 3)
+ if (version_id != 3)
host = qemu_get_ram_ptr(addr);
else
host = host_from_stream_offset(f, addr, flags);
@@ -443,7 +441,7 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
} else if (flags & RAM_SAVE_FLAG_PAGE) {
void *host;
- if (version_id == 3)
+ if (version_id != 3)
host = qemu_get_ram_ptr(addr);
else
host = host_from_stream_offset(f, addr, flags);
diff --git a/hw/android_arm.c b/hw/android_arm.c
index 188051b..c93a4db 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -77,7 +77,6 @@ static void android_arm_init_(ram_addr_t ram_size,
cpu_model = "arm926";
env = cpu_init(cpu_model);
- register_savevm( "cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, env );
ram_offset = qemu_ram_alloc(NULL,"android_arm",ram_size);
cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c
index 434522c..60e652c 100644
--- a/hw/goldfish_audio.c
+++ b/hw/goldfish_audio.c
@@ -263,7 +263,7 @@ static int audio_state_load( QEMUFile* f, void* opaque, int version_id )
goldfish_audio_buff_get( s->out_buff2, f );
goldfish_audio_buff_get (s->in_buff, f);
}
- return -1;
+ return ret;
}
static void enable_audio(struct goldfish_audio_state *s, int enable)
diff --git a/hw/goldfish_device.c b/hw/goldfish_device.c
index e98161a..e3dbfcb 100644
--- a/hw/goldfish_device.c
+++ b/hw/goldfish_device.c
@@ -12,6 +12,7 @@
#include "qemu_file.h"
#include "arm_pic.h"
#include "goldfish_device.h"
+#include "android/utils/debug.h"
#ifdef TARGET_I386
#include "kvm.h"
#endif
@@ -59,6 +60,18 @@ int goldfish_add_device_no_io(struct goldfish_device *dev)
if(dev->irq == 0 && dev->irq_count > 0) {
dev->irq = goldfish_free_irq;
goldfish_free_irq += dev->irq_count;
+#ifdef TARGET_I386
+ /* Make sure that we pass by the reserved IRQs. */
+ while (goldfish_free_irq == GFD_KBD_IRQ ||
+ goldfish_free_irq == GFD_MOUSE_IRQ ||
+ goldfish_free_irq == GFD_ERR_IRQ) {
+ goldfish_free_irq++;
+ }
+#endif
+ if (goldfish_free_irq >= GFD_MAX_IRQ) {
+ derror("Goldfish device has exceeded available IRQ number.");
+ exit(1);
+ }
}
//printf("goldfish_add_device: %s, base %x %x, irq %d %d\n",
// dev->name, dev->base, dev->size, dev->irq, dev->irq_count);
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
index 19f4b32..a9e3f83 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -55,4 +55,18 @@ void trace_dev_init();
void events_dev_init(uint32_t base, qemu_irq irq);
void nand_dev_init(uint32_t base);
+#ifdef TARGET_I386
+/* Maximum IRQ number available for a device on x86. */
+#define GFD_MAX_IRQ 16
+/* IRQ reserved for keyboard. */
+#define GFD_KBD_IRQ 1
+/* IRQ reserved for mouse. */
+#define GFD_MOUSE_IRQ 12
+/* IRQ reserved for error (raising an exception in TB code). */
+#define GFD_ERR_IRQ 13
+#else
+/* Maximum IRQ number available for a device on ARM. */
+#define GFD_MAX_IRQ 32
#endif
+
+#endif /* GOLDFISH_DEVICE_H */
diff --git a/hw/goldfish_interrupt.c b/hw/goldfish_interrupt.c
index c620664..f4c5a89 100644
--- a/hw/goldfish_interrupt.c
+++ b/hw/goldfish_interrupt.c
@@ -166,7 +166,7 @@ qemu_irq* goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq
qemu_irq* qi;
s = qemu_mallocz(sizeof(*s));
- qi = qemu_allocate_irqs(goldfish_int_set_irq, s, 32);
+ qi = qemu_allocate_irqs(goldfish_int_set_irq, s, GFD_MAX_IRQ);
s->dev.name = "goldfish_interrupt_controller";
s->dev.id = -1;
s->dev.base = base;
diff --git a/hw/goldfish_pipe.c b/hw/goldfish_pipe.c
index 2227093..b3c6975 100644
--- a/hw/goldfish_pipe.c
+++ b/hw/goldfish_pipe.c
@@ -14,6 +14,9 @@
#include "hw/goldfish_pipe.h"
#include "hw/goldfish_device.h"
#include "qemu-timer.h"
+#ifdef CONFIG_KVM
+#include "kvm.h"
+#endif
#define DEBUG 0
@@ -875,7 +878,13 @@ pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
GoldfishPipeBuffer buffer;
uint32_t address = dev->address;
uint32_t page = address & TARGET_PAGE_MASK;
- target_phys_addr_t phys = cpu_get_phys_page_debug(env, page);
+ target_phys_addr_t phys;
+#ifdef CONFIG_KVM
+ if(kvm_enabled()) {
+ cpu_synchronize_state(env, 0);
+ }
+#endif
+ phys = cpu_get_phys_page_debug(env, page);
buffer.data = qemu_get_ram_ptr(phys) + (address - page);
buffer.size = dev->size;
dev->status = pipe->funcs->recvBuffers(pipe->opaque, &buffer, 1);
@@ -889,7 +898,13 @@ pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
GoldfishPipeBuffer buffer;
uint32_t address = dev->address;
uint32_t page = address & TARGET_PAGE_MASK;
- target_phys_addr_t phys = cpu_get_phys_page_debug(env, page);
+ target_phys_addr_t phys;
+#ifdef CONFIG_KVM
+ if(kvm_enabled()) {
+ cpu_synchronize_state(env, 0);
+ }
+#endif
+ phys = cpu_get_phys_page_debug(env, page);
buffer.data = qemu_get_ram_ptr(phys) + (address - page);
buffer.size = dev->size;
dev->status = pipe->funcs->sendBuffers(pipe->opaque, &buffer, 1);
diff --git a/hw/i8259.c b/hw/i8259.c
index 091ba7a..0049e73 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -25,6 +25,7 @@
#include "pc.h"
#include "isa.h"
#include "monitor.h"
+#include "goldfish_device.h"
/* debug PIC */
//#define DEBUG_PIC
@@ -559,7 +560,7 @@ qemu_irq *i8259_init(qemu_irq parent_irq)
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
isa_pic = s;
- return qemu_allocate_irqs(i8259_set_irq, s, 16);
+ return qemu_allocate_irqs(i8259_set_irq, s, GFD_MAX_IRQ);
}
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
diff --git a/hw/pc.c b/hw/pc.c
index 7a83b4c..f44c44e 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1033,7 +1033,7 @@ static void pc_init1(ram_addr_t ram_size,
cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
i8259 = i8259_init(cpu_irq[0]);
- ferr_irq = i8259[13];
+ ferr_irq = i8259[GFD_ERR_IRQ];
#define IRQ_PDEV_BUS 4
goldfish_device_init(i8259, 0xff010000, 0x7f0000, 5, 5);
@@ -1177,7 +1177,7 @@ static void pc_init1(ram_addr_t ram_size,
}
#endif
- i8042_init(i8259[1], i8259[12], 0x60);
+ i8042_init(i8259[GFD_KBD_IRQ], i8259[GFD_MOUSE_IRQ], 0x60);
DMA_init(0);
goldfish_fb_init(0);
diff --git a/savevm.c b/savevm.c
index 5da7a8c..c08e8fa 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1121,7 +1121,11 @@ int qemu_loadvm_state(QEMUFile *f)
le->next = first_le;
first_le = le;
- le->se->load_state(f, le->se->opaque, le->version_id);
+ if (le->se->load_state(f, le->se->opaque, le->version_id)) {
+ fprintf(stderr, "savevm: unable to load section %s\n", idstr);
+ ret = -EINVAL;
+ goto out;
+ }
break;
case QEMU_VM_SECTION_PART:
case QEMU_VM_SECTION_END:
diff --git a/vl-android.c b/vl-android.c
index f0b2ae8..322ddca 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -3689,6 +3689,9 @@ int main(int argc, char **argv, char **envp)
hwLcd_setBootProperty(density);
}
+ /* Initialize presence of hardware nav button */
+ boot_property_add("qemu.hw.mainkeys", android_hw->hw_mainKeys ? "1" : "0");
+
/* Initialize TCP dump */
if (android_op_tcpdump) {
if (qemu_tcpdump_start(android_op_tcpdump) < 0) {
@@ -4169,7 +4172,7 @@ int main(int argc, char **argv, char **envp)
android_hw->hw_cpu_arch);
exit(1);
}
-#elif defined(TARGET_X86)
+#elif defined(TARGET_I386)
if (strcmp(android_hw->hw_cpu_arch,"x86") != 0) {
fprintf(stderr, "-- Invalid CPU architecture: %s, expected 'x86'\n",
android_hw->hw_cpu_arch);