diff options
-rw-r--r-- | android/avd/hardware-properties.ini | 17 | ||||
-rw-r--r-- | android/camera/camera-capture-linux.c | 55 | ||||
-rw-r--r-- | android/camera/camera-capture-mac.c | 4 | ||||
-rwxr-xr-x | android/camera/camera-capture-windows.c | 105 | ||||
-rwxr-xr-x | android/camera/camera-common.h | 26 | ||||
-rwxr-xr-x | android/camera/camera-format-converters.c | 5 | ||||
-rw-r--r-- | android/camera/camera-service.c | 80 | ||||
-rw-r--r-- | android/hw-qemud.c | 30 | ||||
-rw-r--r-- | android/main.c | 11 | ||||
-rw-r--r-- | arch_init.c | 10 | ||||
-rw-r--r-- | hw/android_arm.c | 1 | ||||
-rw-r--r-- | hw/goldfish_audio.c | 2 | ||||
-rw-r--r-- | hw/goldfish_device.c | 13 | ||||
-rw-r--r-- | hw/goldfish_device.h | 14 | ||||
-rw-r--r-- | hw/goldfish_interrupt.c | 2 | ||||
-rw-r--r-- | hw/goldfish_pipe.c | 19 | ||||
-rw-r--r-- | hw/i8259.c | 3 | ||||
-rw-r--r-- | hw/pc.c | 4 | ||||
-rw-r--r-- | savevm.c | 6 | ||||
-rw-r--r-- | vl-android.c | 5 |
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); @@ -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, @@ -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); @@ -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); |