| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <ddk/platform-defs.h> |
| #include <fuchsia/camera/common/c/fidl.h> |
| #include <fuchsia/camera/common/llcpp/fidl.h> |
| #include <fuchsia/hardware/camera/c/fidl.h> |
| #include <lib/driver-integration-test/fixture.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/zx/eventpair.h> |
| #include <lib/zx/vmo.h> |
| #include <zxtest/zxtest.h> |
| #include <zircon/syscalls.h> |
| |
| |
| using driver_integration_test::IsolatedDevmgr; |
| |
| namespace { |
| |
| constexpr uint32_t kPageSize = 4096; |
| |
| // TODO(CAM-43): Replace with sysmem version when available? |
| zx_status_t Gralloc(fuchsia_camera_common_VideoFormat format, uint32_t num_buffers, |
| fuchsia_sysmem_BufferCollectionInfo* buffer_collection, |
| zx::vmo vmos[64]) { |
| // In the future, some special alignment might happen here, or special |
| // memory allocated... |
| // Simple GetBufferSize. Only valid for simple formats: |
| size_t buffer_size = fbl::round_up( |
| format.format.height * format.format.planes[0].bytes_per_row, kPageSize); |
| buffer_collection->buffer_count = num_buffers; |
| buffer_collection->vmo_size = buffer_size; |
| buffer_collection->format.image = format.format; |
| zx_status_t status; |
| for (uint32_t i = 0; i < num_buffers; ++i) { |
| status = zx::vmo::create(buffer_size, 0, &vmos[i]); |
| if (status != ZX_OK) { |
| return status; |
| } |
| buffer_collection->vmos[i] = vmos[i].get(); |
| } |
| return ZX_OK; |
| } |
| |
| // Integration test for the driver defined in zircon/system/dev/virtual_camera. |
| // This test code loads the driver into an isolated devmgr and tests behavior. |
| class VirtualCameraTest : public zxtest::Test { |
| void SetUp() override; |
| |
| protected: |
| IsolatedDevmgr devmgr_; |
| fbl::unique_fd fd_; |
| zx_handle_t device_handle_; |
| fuchsia_sysmem_BufferCollectionInfo info_0_; |
| zx::vmo vmos_0_[64]; |
| }; |
| |
| const board_test::DeviceEntry kDeviceEntry = []() { |
| board_test::DeviceEntry entry = {}; |
| entry.vid = PDEV_VID_TEST; |
| entry.pid = PDEV_PID_VCAMERA_TEST; |
| entry.did = PDEV_DID_TEST_VCAMERA; |
| return entry; |
| }(); |
| |
| void VirtualCameraTest::SetUp() { |
| IsolatedDevmgr::Args args; |
| args.driver_search_paths.push_back("/boot/driver"); |
| args.driver_search_paths.push_back("/boot/driver/test"); |
| args.device_list.push_back(kDeviceEntry); |
| zx_status_t status = IsolatedDevmgr::Create(&args, &devmgr_); |
| ASSERT_EQ(status, ZX_OK); |
| |
| status = devmgr_integration_test::RecursiveWaitForFile( |
| devmgr_.devfs_root(), "sys/platform/11:05:b/virtual_camera", |
| zx::time::infinite(), &fd_); |
| ASSERT_EQ(ZX_OK, status); |
| |
| status = fdio_get_service_handle(fd_.get(), &device_handle_); |
| ASSERT_EQ(ZX_OK, status); |
| } |
| |
| TEST_F(VirtualCameraTest, GetDeviceInfoGetFormatsTest) { |
| fuchsia_hardware_camera_DeviceInfo device_info; |
| zx_status_t status = |
| fuchsia_hardware_camera_ControlV2GetDeviceInfo(device_handle_, &device_info); |
| ASSERT_EQ(ZX_OK, status); |
| EXPECT_EQ(1, device_info.max_stream_count); |
| EXPECT_EQ(fuchsia_hardware_camera_CAMERA_OUTPUT_STREAM, |
| device_info.output_capabilities); |
| |
| fuchsia_camera_common_VideoFormat formats[16]; |
| uint32_t total_count; |
| uint32_t actual_count; |
| int32_t out_status; |
| status = fuchsia_hardware_camera_ControlV2GetFormats( |
| device_handle_, 1, formats, &total_count, &actual_count, &out_status); |
| ASSERT_EQ(ZX_OK, status); |
| auto format = formats[0]; |
| EXPECT_EQ(640, format.format.width); |
| EXPECT_EQ(480, format.format.height); |
| EXPECT_EQ(1, format.format.layers); |
| EXPECT_EQ(30, format.rate.frames_per_sec_numerator); |
| EXPECT_EQ(1, format.rate.frames_per_sec_denominator); |
| EXPECT_EQ(1, total_count); |
| EXPECT_EQ(1, actual_count); |
| |
| zx::eventpair driver_token; |
| zx::eventpair stream_token; |
| status = zx::eventpair::create(0, &stream_token, &driver_token); |
| ASSERT_EQ(ZX_OK, status); |
| |
| zx::channel client_request; |
| zx::channel server_request; |
| status = zx::channel::create(0, &client_request, &server_request); |
| ASSERT_EQ(ZX_OK, status); |
| status = Gralloc(format, 2, &info_0_, vmos_0_); |
| ASSERT_EQ(ZX_OK, status); |
| status = fuchsia_hardware_camera_ControlV2CreateStream( |
| device_handle_, &info_0_, &format.rate, server_request.release(), driver_token.release()); |
| ASSERT_EQ(ZX_OK, status); |
| |
| // Not fully implemented yet - this is a sanity check. |
| zx_handle_t stream_handle = client_request.release(); |
| status = fuchsia_camera_common_StreamStart(stream_handle); |
| EXPECT_EQ(ZX_OK, status); |
| |
| stream_token.reset(); |
| zx_signals_t pending; |
| zx::time deadline = zx::deadline_after(zx::sec(5)); |
| zx::channel client = zx::channel(stream_handle); |
| ASSERT_EQ(ZX_OK, client.wait_one(ZX_CHANNEL_PEER_CLOSED, deadline, &pending)); |
| ASSERT_EQ(pending & ZX_CHANNEL_PEER_CLOSED, ZX_CHANNEL_PEER_CLOSED); |
| } |
| |
| } // namespace |