[gdc][sherlock] Implement GdcProcessFrame() - partial implementation
- Posts a task in a deque which is drained by a separate thread.
- When the task is run, the necessary callback is called.
TODO: This is just adding hooks to call the necessary callback function
CAM-33 #comment - in progress
Test: Added tests. Run using src/camera/TESTING.md
Change-Id: Iadc05e23b16ba80671a4182c75f8b515794153d8
diff --git a/src/camera/drivers/hw_accel/gdc/BUILD.gn b/src/camera/drivers/hw_accel/gdc/BUILD.gn
index 64ce315..ef1b453 100644
--- a/src/camera/drivers/hw_accel/gdc/BUILD.gn
+++ b/src/camera/drivers/hw_accel/gdc/BUILD.gn
@@ -20,6 +20,8 @@
"//zircon/public/banjo/ddk.protocol.platform.device",
"//zircon/public/banjo/ddk.protocol.sysmem",
"//zircon/public/fidl/fuchsia-sysmem:fuchsia-sysmem_c",
+ "//zircon/public/lib/async-cpp",
+ "//zircon/public/lib/async-loop-cpp",
"//zircon/public/lib/ddk",
"//zircon/public/lib/ddktl",
"//zircon/public/lib/device-protocol-pdev",
@@ -39,6 +41,7 @@
configs -= [ "//build/config/fuchsia:no_cpp_standard_library" ]
configs += [ "//build/config/fuchsia:static_cpp_standard_library" ]
+ configs += [ "//build/config/fuchsia:enable_zircon_asserts" ]
}
package("gdc") {
@@ -63,6 +66,7 @@
deps = [
"//zircon/public/banjo/ddk.protocol.gdc",
"//zircon/public/fidl/fuchsia-sysmem:fuchsia-sysmem_c",
+ "//zircon/public/lib/async-cpp",
"//zircon/public/lib/ddk",
"//zircon/public/lib/ddktl",
"//zircon/public/lib/fzl",
diff --git a/src/camera/drivers/hw_accel/gdc/gdc.cc b/src/camera/drivers/hw_accel/gdc/gdc.cc
index 3f6e28f..503e7f4 100644
--- a/src/camera/drivers/hw_accel/gdc/gdc.cc
+++ b/src/camera/drivers/hw_accel/gdc/gdc.cc
@@ -8,12 +8,11 @@
#include <ddk/debug.h>
#include <ddk/driver.h>
#include <fbl/alloc_checker.h>
-#include <fbl/auto_call.h>
#include <fbl/auto_lock.h>
#include <fbl/unique_ptr.h>
#include <hw/reg.h>
#include <stdint.h>
-#include <threads.h>
+#include <zircon/threads.h>
#include <zircon/types.h>
#include <memory>
@@ -82,10 +81,102 @@
return ZX_OK;
}
+void GdcDevice::ProcessTask(TaskInfo& info) {
+ auto task = info.task;
+ auto input_buffer_index = info.input_buffer_index;
+
+ // TODO(CAM-33): Add Processing of the frame implementation here.
+
+ zx_port_packet_t packet;
+ ZX_ASSERT(ZX_OK == WaitForInterrupt(&packet));
+ gdc_irq_.ack();
+
+ // Currently there is only type of event coming in at this port.
+ // We could possibly add more, like one to terminate the process.
+ if (packet.key == kPortKeyIrqMsg) {
+ // Invoke the callback function and tell about the output buffer index
+ // which is ready to be used.
+ // TODO(CAM-33): pass actual output buffer index instead of
+ // input_buffer_index.
+ task->callback()->frame_ready(task->callback()->ctx, input_buffer_index);
+ }
+}
+
+int GdcDevice::FrameProcessingThread() {
+ FX_LOGF(INFO, "", "%s: start \n", __func__);
+
+ while (running_.load()) {
+ // Waiting for the event when a task is queued.
+ sync_completion_wait(&frame_processing_signal_, ZX_TIME_INFINITE);
+ bool pending_task = false;
+ // Dequeing the entire deque till it drains.
+ do {
+ TaskInfo info;
+ {
+ fbl::AutoLock lock(&deque_lock_);
+ if (!processing_queue_.empty()) {
+ info = processing_queue_.back();
+ processing_queue_.pop_back();
+ pending_task = true;
+ } else {
+ pending_task = false;
+ }
+ }
+ if (pending_task) {
+ ProcessTask(info);
+ }
+ } while (pending_task);
+ // Now that the deque is drained we reset the signal.
+ sync_completion_reset(&frame_processing_signal_);
+ }
+ return 0;
+}
+
zx_status_t GdcDevice::GdcProcessFrame(uint32_t task_index,
uint32_t input_buffer_index) {
- // TODO(braval): Implement this.
- return ZX_ERR_NOT_SUPPORTED;
+ // Find the entry in hashmap.
+ auto task_entry = task_map_.find(task_index);
+ if (task_entry == task_map_.end()) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+ // Validate |input_buffer_index|.
+ if (!task_entry->second->IsInputBufferIndexValid(input_buffer_index)) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+
+ TaskInfo info;
+ info.task = task_entry->second.get();
+ info.input_buffer_index = input_buffer_index;
+
+ // Put the task on queue.
+ fbl::AutoLock lock(&deque_lock_);
+ processing_queue_.push_front(std::move(info));
+ sync_completion_signal(&frame_processing_signal_);
+ return ZX_OK;
+}
+
+zx_status_t GdcDevice::StartThread() {
+ running_.store(true);
+ return thrd_status_to_zx_status(thrd_create_with_name(
+ &processing_thread_,
+ [](void* arg) -> int {
+ return reinterpret_cast<GdcDevice*>(arg)->FrameProcessingThread();
+ },
+ this, "gdc-processing-thread"));
+}
+
+zx_status_t GdcDevice::StopThread() {
+ running_.store(false);
+ // Signal the thread waiting on this signal
+ sync_completion_signal(&frame_processing_signal_);
+ gdc_irq_.destroy();
+ JoinThread();
+ return ZX_OK;
+}
+
+zx_status_t GdcDevice::WaitForInterrupt(zx_port_packet_t* packet) {
+ return port_.wait(zx::time::infinite(), packet);
}
void GdcDevice::GdcRemoveTask(uint32_t task_index) {
@@ -98,7 +189,7 @@
}
void GdcDevice::GdcReleaseFrame(uint32_t task_index, uint32_t buffer_index) {
- // TODO(braval): Implement this.
+ // TODO(CAM-33): Implement this.
}
// static
@@ -131,6 +222,19 @@
return status;
}
+ zx::port port;
+ status = zx::port::create(ZX_PORT_BIND_TO_INTERRUPT, &port);
+ if (status != ZX_OK) {
+ FX_LOGF(ERROR, "%s: port create failed %d\n", __func__, status);
+ return status;
+ }
+
+ status = gdc_irq.bind(port, kPortKeyIrqMsg, 0 /*options*/);
+ if (status != ZX_OK) {
+ FX_LOGF(ERROR, "%s: interrupt bind failed %d\n", __func__, status);
+ return status;
+ }
+
zx::bti bti;
status = pdev.GetBti(0, &bti);
if (status != ZX_OK) {
@@ -141,13 +245,14 @@
fbl::AllocChecker ac;
auto gdc_device = std::unique_ptr<GdcDevice>(
new (&ac) GdcDevice(parent, std::move(*clk_mmio), std::move(*gdc_mmio),
- std::move(gdc_irq), std::move(bti)));
+ std::move(gdc_irq), std::move(bti), std::move(port)));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
gdc_device->InitClocks();
+ status = gdc_device->StartThread();
*out = std::move(gdc_device);
return status;
}
@@ -157,7 +262,10 @@
DdkRemove();
}
-void GdcDevice::DdkRelease() { delete this; }
+void GdcDevice::DdkRelease() {
+ StopThread();
+ delete this;
+}
void GdcDevice::ShutDown() {}
diff --git a/src/camera/drivers/hw_accel/gdc/gdc.h b/src/camera/drivers/hw_accel/gdc/gdc.h
index c855ca1..c492242 100644
--- a/src/camera/drivers/hw_accel/gdc/gdc.h
+++ b/src/camera/drivers/hw_accel/gdc/gdc.h
@@ -2,31 +2,44 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef SRC_CAMERA_DRIVERS_HW_ACCEL_GDC_GDC_H_
+#define SRC_CAMERA_DRIVERS_HW_ACCEL_GDC_GDC_H_
+
#include <ddk/platform-defs.h>
+#ifndef _ALL_SOURCE
+#define _ALL_SOURCE // Enables thrd_create_with_name in <threads.h>.
+#include <threads.h>
+#endif
#include <ddk/protocol/platform/bus.h>
#include <ddk/protocol/platform/device.h>
#include <ddktl/device.h>
#include <ddktl/protocol/gdc.h>
+#include <fbl/auto_lock.h>
+#include <fbl/mutex.h>
#include <fbl/unique_ptr.h>
#include <hw/reg.h>
#include <lib/device-protocol/pdev.h>
#include <lib/device-protocol/platform-device.h>
#include <lib/fidl-utils/bind.h>
#include <lib/mmio/mmio.h>
+#include <lib/sync/completion.h>
+#include <lib/zx/event.h>
#include <lib/zx/interrupt.h>
-#include <threads.h>
#include <zircon/fidl.h>
+#include <atomic>
#include <deque>
-#include <list>
#include <unordered_map>
-#include <vector>
#include "task.h"
namespace gdc {
-
// |GdcDevice| is spawned by the driver in |gdc.cc|
+namespace {
+
+constexpr uint64_t kPortKeyIrqMsg = 0x00;
+
+} // namespace
// This provides ZX_PROTOCOL_GDC.
class GdcDevice;
using GdcDeviceType = ddk::Device<GdcDevice, ddk::Unbindable>;
@@ -35,11 +48,11 @@
public ddk::GdcProtocol<GdcDevice, ddk::base_protocol> {
public:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(GdcDevice);
-
explicit GdcDevice(zx_device_t* parent, ddk ::MmioBuffer clk_mmio,
ddk ::MmioBuffer gdc_mmio, zx::interrupt gdc_irq,
- zx::bti bti)
+ zx::bti bti, zx::port port)
: GdcDeviceType(parent),
+ port_(std::move(port)),
clock_mmio_(std::move(clk_mmio)),
gdc_mmio_(std::move(gdc_mmio)),
gdc_irq_(std::move(gdc_irq)),
@@ -68,6 +81,16 @@
// Used for unit tests.
const ddk::MmioBuffer* gdc_mmio() const { return &gdc_mmio_; }
+ zx_status_t StartThread();
+ zx_status_t StopThread();
+
+ protected:
+ struct TaskInfo {
+ Task* task;
+ uint32_t input_buffer_index;
+ };
+
+ zx::port port_;
private:
friend class GdcDeviceTester;
@@ -75,6 +98,14 @@
// All necessary clean up is done here in ShutDown().
void ShutDown();
void InitClocks();
+ int FrameProcessingThread();
+ int JoinThread() { return thrd_join(processing_thread_, nullptr); }
+
+ void ProcessTask(TaskInfo& info);
+ zx_status_t WaitForInterrupt(zx_port_packet_t* packet);
+
+ // Used to access the processing queue.
+ fbl::Mutex deque_lock_;
// HHI register block has the clock registers
ddk::MmioBuffer clock_mmio_;
@@ -83,6 +114,12 @@
zx::bti bti_;
uint32_t next_task_index_ = 0;
std::unordered_map<uint32_t, std::unique_ptr<Task>> task_map_;
+ std::deque<TaskInfo> processing_queue_ __TA_GUARDED(deque_lock_);
+ thrd_t processing_thread_;
+ sync_completion_t frame_processing_signal_;
+ std::atomic<bool> running_;
};
} // namespace gdc
+
+#endif // SRC_CAMERA_DRIVERS_HW_ACCEL_GDC_GDC_H_
diff --git a/src/camera/drivers/hw_accel/gdc/task.cc b/src/camera/drivers/hw_accel/gdc/task.cc
index 2bda3c7..85eb3d6 100644
--- a/src/camera/drivers/hw_accel/gdc/task.cc
+++ b/src/camera/drivers/hw_accel/gdc/task.cc
@@ -8,7 +8,6 @@
#include <fbl/alloc_checker.h>
#include <lib/syslog/global.h>
#include <stdint.h>
-#include <threads.h>
#include <zircon/types.h>
#include <memory>
@@ -138,6 +137,8 @@
FX_LOG(ERROR, "%s: InitBuffers Failed\n", __func__);
}
+ task->callback_ = callback;
+
*out = std::move(task);
return status;
}
diff --git a/src/camera/drivers/hw_accel/gdc/task.h b/src/camera/drivers/hw_accel/gdc/task.h
index 6b43fae..b58abb1 100644
--- a/src/camera/drivers/hw_accel/gdc/task.h
+++ b/src/camera/drivers/hw_accel/gdc/task.h
@@ -34,14 +34,21 @@
zx_status_t GetInputBufferPhysAddr(uint32_t input_buffer_index,
zx_paddr_t* out) const;
+ // Validates input buffer index.
+ bool IsInputBufferIndexValid(uint32_t input_buffer_index) const {
+ return input_buffer_index < input_buffers_.size();
+ }
+
// Returns a |Buffer| object which is free for use as output buffer.
std::optional<fzl::VmoPool::Buffer> GetOutputBuffer() {
return output_buffers_.LockBufferForWrite();
}
+ const gdc_callback_t* callback() { return callback_; }
+
// Static function to create a task object.
// |input_buffer_collection| : Input buffer collection.
- // |output_buffer_collection| : Onput buffer collection.
+ // |output_buffer_collection| : Output buffer collection.
// |config_vmo| : Configuration is stored in this
// VMO. |callback| : Callback function to call for
// this task. |out| : Pointer to a task
@@ -66,6 +73,7 @@
fzl::PinnedVmo config_vmo_pinned_;
fzl::VmoPool output_buffers_;
fbl::Array<fzl::PinnedVmo> input_buffers_;
+ const gdc_callback_t* callback_;
};
} // namespace gdc
diff --git a/src/camera/drivers/hw_accel/gdc/test/BUILD.gn b/src/camera/drivers/hw_accel/gdc/test/BUILD.gn
index 3eff58d..fc1a325 100644
--- a/src/camera/drivers/hw_accel/gdc/test/BUILD.gn
+++ b/src/camera/drivers/hw_accel/gdc/test/BUILD.gn
@@ -19,9 +19,11 @@
"//zircon/public/banjo/ddk.protocol.platform.device",
"//zircon/public/banjo/ddk.protocol.sysmem",
"//zircon/public/fidl/fuchsia-sysmem:fuchsia-sysmem_c",
+ "//zircon/public/lib/async-loop-cpp",
"//zircon/public/lib/ddk",
"//zircon/public/lib/ddktl",
"//zircon/public/lib/device-protocol-pdev",
+ "//zircon/public/lib/device-protocol-pdev",
"//zircon/public/lib/device-protocol-platform-device",
"//zircon/public/lib/driver",
"//zircon/public/lib/fake-bti",
diff --git a/src/camera/drivers/hw_accel/gdc/test/task-test.cc b/src/camera/drivers/hw_accel/gdc/test/task-test.cc
index 6c89426..9e7df4a 100644
--- a/src/camera/drivers/hw_accel/gdc/test/task-test.cc
+++ b/src/camera/drivers/hw_accel/gdc/test/task-test.cc
@@ -33,6 +33,11 @@
// Integration test for the driver defined in zircon/system/dev/camera/arm-isp.
class TaskTest : public zxtest::Test {
+ public:
+ void ProcessFrameCallback(uint32_t output_buffer_id) {
+ callback_check_.push_back(output_buffer_id);
+ }
+
protected:
void SetUpBufferCollections(uint32_t buffer_collection_count) {
ASSERT_OK(fake_bti_create(bti_handle_.reset_and_get_address()));
@@ -52,12 +57,46 @@
ASSERT_OK(status);
}
+ void SetupForFrameProcessing() {
+ SetUpBufferCollections(kNumberOfBuffers);
+ ddk_mock::MockMmioReg fake_reg_array[kNumberOfBuffers];
+ ddk_mock::MockMmioRegRegion fake_regs(fake_reg_array, sizeof(uint32_t),
+ kNumberOfBuffers);
+ zx::port port;
+ ASSERT_OK(zx::port::create(ZX_PORT_BIND_TO_INTERRUPT, &port));
+ callback_.frame_ready = [](void* ctx, uint32_t idx) {
+ return static_cast<TaskTest*>(ctx)->ProcessFrameCallback(idx);
+ };
+ callback_.ctx = this;
+
+ ASSERT_OK(
+ zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq_));
+ ASSERT_OK(port.duplicate(ZX_RIGHT_SAME_RIGHTS, &port_));
+
+ gdc_device_ = std::make_unique<GdcDevice>(
+ nullptr, ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
+ ddk::MmioBuffer(fake_regs.GetMmioBuffer()), std::move(irq_),
+ std::move(bti_handle_), std::move(port));
+
+ // Start the thread.
+ EXPECT_OK(gdc_device_->StartThread());
+ }
+
+ void TearDown() override {
+ if (bti_handle_ != ZX_HANDLE_INVALID) {
+ fake_bti_destroy(bti_handle_.get());
+ }
+ }
+
zx::vmo config_vmo_;
zx::bti bti_handle_;
+ zx::port port_;
+ zx::interrupt irq_;
gdc_callback_t callback_;
buffer_collection_info_t input_buffer_collection_;
buffer_collection_info_t output_buffer_collection_;
std::unique_ptr<GdcDevice> gdc_device_;
+ std::vector<uint32_t> callback_check_;
};
TEST_F(TaskTest, BasicCreationTest) {
@@ -113,6 +152,168 @@
EXPECT_EQ(ZX_ERR_INVALID_ARGS, status);
}
+TEST_F(TaskTest, InitTaskTest) {
+ SetUpBufferCollections(kNumberOfBuffers);
+ ddk_mock::MockMmioReg fake_reg_array[kNumberOfMmios];
+ ddk_mock::MockMmioRegRegion fake_regs(fake_reg_array, sizeof(uint32_t),
+ kNumberOfMmios);
+ ASSERT_OK(zx::port::create(ZX_PORT_BIND_TO_INTERRUPT, &port_));
+
+ GdcDevice gdc_device(nullptr, ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
+ ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
+ zx::interrupt(), std::move(bti_handle_),
+ std::move(port_));
+
+ std::vector<uint32_t> received_ids;
+ for (uint32_t i = 0; i < kMaxTasks; i++) {
+ zx::vmo config_vmo;
+ ASSERT_OK(config_vmo_.duplicate(ZX_RIGHT_SAME_RIGHTS, &config_vmo));
+
+ uint32_t task_id;
+ zx_status_t status = gdc_device.GdcInitTask(
+ &input_buffer_collection_, &output_buffer_collection_,
+ std::move(config_vmo), &callback_, &task_id);
+ EXPECT_OK(status);
+ // Checking to see if we are getting unique task ids.
+ auto entry = find(received_ids.begin(), received_ids.end(), task_id);
+ EXPECT_EQ(received_ids.end(), entry);
+ received_ids.push_back(task_id);
+ }
+}
+
+TEST_F(TaskTest, RemoveTaskTest) {
+ SetUpBufferCollections(kNumberOfBuffers);
+ ddk_mock::MockMmioReg fake_reg_array[kNumberOfMmios];
+ ddk_mock::MockMmioRegRegion fake_regs(fake_reg_array, sizeof(uint32_t),
+ kNumberOfMmios);
+
+ ASSERT_OK(zx::port::create(ZX_PORT_BIND_TO_INTERRUPT, &port_));
+
+ gdc_device_ = std::make_unique<GdcDevice>(
+ nullptr, ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
+ ddk::MmioBuffer(fake_regs.GetMmioBuffer()), zx::interrupt(),
+ std::move(bti_handle_), std::move(port_));
+
+ uint32_t task_id;
+ zx_status_t status = gdc_device_->GdcInitTask(
+ &input_buffer_collection_, &output_buffer_collection_,
+ std::move(config_vmo_), &callback_, &task_id);
+ EXPECT_OK(status);
+
+ // Valid id.
+ ASSERT_NO_DEATH(([this, task_id]() { gdc_device_->GdcRemoveTask(task_id); }));
+
+ // Invalid id.
+ ASSERT_DEATH(
+ ([this, task_id]() { gdc_device_->GdcRemoveTask(task_id + 1); }));
+}
+
+TEST_F(TaskTest, ProcessInvalidFrameTest) {
+ SetupForFrameProcessing();
+
+ // Invalid task id.
+ zx_status_t status = gdc_device_->GdcProcessFrame(0xFF, 0);
+ EXPECT_EQ(ZX_ERR_INVALID_ARGS, status);
+
+ ASSERT_OK(gdc_device_->StopThread());
+}
+
+TEST_F(TaskTest, InvalidBufferProcessFrameTest) {
+ SetupForFrameProcessing();
+
+ uint32_t task_id;
+ zx_status_t status = gdc_device_->GdcInitTask(
+ &input_buffer_collection_, &output_buffer_collection_,
+ std::move(config_vmo_), &callback_, &task_id);
+ EXPECT_OK(status);
+
+ // Invalid buffer id.
+ status = gdc_device_->GdcProcessFrame(task_id, kNumberOfBuffers);
+ EXPECT_EQ(ZX_ERR_INVALID_ARGS, status);
+
+ ASSERT_OK(gdc_device_->StopThread());
+}
+
+TEST_F(TaskTest, ProcessFrameTest) {
+ SetupForFrameProcessing();
+
+ uint32_t task_id;
+ zx_status_t status = gdc_device_->GdcInitTask(
+ &input_buffer_collection_, &output_buffer_collection_,
+ std::move(config_vmo_), &callback_, &task_id);
+ EXPECT_OK(status);
+
+ // Valid buffer & task id.
+ status = gdc_device_->GdcProcessFrame(task_id, kNumberOfBuffers - 1);
+ EXPECT_OK(status);
+
+ // Trigger the interrupt manually.
+ zx_port_packet packet = {kPortKeyIrqMsg, ZX_PKT_TYPE_USER, ZX_OK, {}};
+ EXPECT_OK(port_.queue(&packet));
+
+ // Check if the callback was called.
+ zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
+ EXPECT_EQ(1, callback_check_.size());
+
+ ASSERT_OK(gdc_device_->StopThread());
+}
+
+TEST_F(TaskTest, MultipleProcessFrameTest) {
+ SetupForFrameProcessing();
+
+ uint32_t task_id;
+ zx_status_t status = gdc_device_->GdcInitTask(
+ &input_buffer_collection_, &output_buffer_collection_,
+ std::move(config_vmo_), &callback_, &task_id);
+
+ // Process few frames, putting them in a queue
+ status = gdc_device_->GdcProcessFrame(task_id, kNumberOfBuffers - 1);
+ EXPECT_OK(status);
+ status = gdc_device_->GdcProcessFrame(task_id, kNumberOfBuffers - 2);
+ EXPECT_OK(status);
+ status = gdc_device_->GdcProcessFrame(task_id, kNumberOfBuffers - 3);
+ EXPECT_OK(status);
+
+ // Trigger the interrupt manually.
+ zx_port_packet packet = {kPortKeyIrqMsg, ZX_PKT_TYPE_USER, ZX_OK, {}};
+ EXPECT_OK(port_.queue(&packet));
+
+ // Check if the callback was called once.
+ zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
+ EXPECT_EQ(1, callback_check_.size());
+
+ // Trigger the interrupt manually.
+ packet = {kPortKeyIrqMsg, ZX_PKT_TYPE_USER, ZX_OK, {}};
+ EXPECT_OK(port_.queue(&packet));
+
+ // Check if the callback was called one more time.
+ zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
+ EXPECT_EQ(2, callback_check_.size());
+
+ // This time adding another frame to process while its
+ // waiting for an interrupt.
+ status = gdc_device_->GdcProcessFrame(task_id, kNumberOfBuffers - 3);
+ EXPECT_OK(status);
+
+ // Trigger the interrupt manually.
+ packet = {kPortKeyIrqMsg, ZX_PKT_TYPE_USER, ZX_OK, {}};
+ EXPECT_OK(port_.queue(&packet));
+
+ // Check if the callback was called one more time.
+ zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
+ EXPECT_EQ(3, callback_check_.size());
+
+ // Trigger the interrupt manually.
+ packet = {kPortKeyIrqMsg, ZX_PKT_TYPE_USER, ZX_OK, {}};
+ EXPECT_OK(port_.queue(&packet));
+
+ // Check if the callback was called one more time.
+ zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
+ EXPECT_EQ(4, callback_check_.size());
+
+ ASSERT_OK(gdc_device_->StopThread());
+}
+
TEST(TaskTest, NonContigVmoTest) {
zx_handle_t bti_handle = ZX_HANDLE_INVALID;
gdc_callback_t callback;
@@ -157,56 +358,5 @@
EXPECT_NE(ZX_OK, status);
}
-TEST_F(TaskTest, InitTaskTest) {
- SetUpBufferCollections(kNumberOfBuffers);
- ddk_mock::MockMmioReg fake_reg_array[kNumberOfMmios];
- ddk_mock::MockMmioRegRegion fake_regs(fake_reg_array, sizeof(uint32_t),
- kNumberOfMmios);
- GdcDevice gdc_device(nullptr, ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
- ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
- zx::interrupt(), std::move(bti_handle_));
-
- std::vector<uint32_t> received_ids;
- for (uint32_t i = 0; i < kMaxTasks; i++) {
- zx::vmo config_vmo;
- ASSERT_OK(config_vmo_.duplicate(ZX_RIGHT_SAME_RIGHTS, &config_vmo));
-
- uint32_t task_id;
- zx_status_t status = gdc_device.GdcInitTask(
- &input_buffer_collection_, &output_buffer_collection_,
- std::move(config_vmo), &callback_, &task_id);
- EXPECT_OK(status);
- // Checking to see if we are getting unique task ids.
- auto entry = find(received_ids.begin(), received_ids.end(), task_id);
- EXPECT_EQ(received_ids.end(), entry);
- received_ids.push_back(task_id);
- }
-}
-
-TEST_F(TaskTest, RemoveTaskTest) {
- SetUpBufferCollections(kNumberOfBuffers);
- ddk_mock::MockMmioReg fake_reg_array[kNumberOfMmios];
- ddk_mock::MockMmioRegRegion fake_regs(fake_reg_array, sizeof(uint32_t),
- kNumberOfMmios);
-
- fbl::AllocChecker ac;
- gdc_device_ = std::make_unique<GdcDevice>(
- nullptr, ddk::MmioBuffer(fake_regs.GetMmioBuffer()),
- ddk::MmioBuffer(fake_regs.GetMmioBuffer()), zx::interrupt(),
- std::move(bti_handle_));
-
- uint32_t task_id;
- zx_status_t status = gdc_device_->GdcInitTask(
- &input_buffer_collection_, &output_buffer_collection_,
- std::move(config_vmo_), &callback_, &task_id);
- EXPECT_OK(status);
-
- // Valid id.
- ASSERT_NO_DEATH(([this, task_id]() { gdc_device_->GdcRemoveTask(task_id); }));
-
- // Invalid id.
- ASSERT_DEATH(
- ([this, task_id]() { gdc_device_->GdcRemoveTask(task_id + 1); }));
-}
} // namespace
} // namespace gdc