Adds the input_events region

The purpose of this region is to allow processes to send input events
to the input service (initially, may later be moved to the VSoC
driver) either from the host or the guest.

Test: run locally
Bug: 67895611
Change-Id: Idf1195cac4c76beb690dee7e9541f84fade4c279
Merged-In: Idf1195cac4c76beb690dee7e9541f84fade4c279
(cherry picked from commit 7510c968ec56378300dda76727e36b40b0f5dc63)
diff --git a/Android.bp b/Android.bp
index 348a98b..028d8ce 100644
--- a/Android.bp
+++ b/Android.bp
@@ -92,6 +92,8 @@
         "common/vsoc/lib/fb_bcast_layout.cpp",
         "common/vsoc/lib/fb_bcast_region_view.cpp",
         "common/vsoc/lib/gralloc_layout.cpp",
+        "common/vsoc/lib/input_events_layout.cpp",
+        "common/vsoc/lib/input_events_region_view.cpp",
         "common/vsoc/lib/lock_common.cpp",
         "common/vsoc/lib/region_view.cpp",
         "common/vsoc/lib/wifi_exchange_layout.cpp",
diff --git a/common/vsoc/lib/input_events_layout.cpp b/common/vsoc/lib/input_events_layout.cpp
new file mode 100644
index 0000000..3f1da61
--- /dev/null
+++ b/common/vsoc/lib/input_events_layout.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Define some of the string constants associated with the region layout.
+#include "common/vsoc/shm/input_events_layout.h"
+
+namespace vsoc {
+namespace layout {
+
+namespace input_events {
+
+const char* InputEventsLayout::region_name = "input_events";
+
+}  // namespace input_events
+}  // namespace layout
+}  // namespace vsoc
diff --git a/common/vsoc/lib/input_events_region_view.cpp b/common/vsoc/lib/input_events_region_view.cpp
new file mode 100644
index 0000000..191fe03
--- /dev/null
+++ b/common/vsoc/lib/input_events_region_view.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "common/vsoc/lib/input_events_region_view.h"
+
+#include <linux/input.h>
+#include <linux/uinput.h>
+
+#include "common/vsoc/lib/circqueue_impl.h"
+
+using vsoc::layout::input_events::InputEventsLayout;
+
+namespace vsoc {
+namespace input_events {
+
+namespace {
+void InitInputEvent(InputEvent* evt, uint16_t type, uint16_t code, uint32_t value) {
+  evt->type = type;
+  evt->code = code;
+  evt->value = value;
+}
+}  // namespace
+
+const int InputEventsRegionView::kMaxEventsPerPacket = 4;
+
+bool InputEventsRegionView::HandleSingleTouchEvent(bool down, int x, int y) {
+  // TODO(jemoreira): Use multitouch when available
+  InputEvent events[4];
+  // Make sure to modify kMaxEventPerPacket if more events are sent.
+  InitInputEvent(&events[0], EV_ABS, ABS_X, x);
+  InitInputEvent(&events[1], EV_ABS, ABS_Y, y);
+  InitInputEvent(&events[2], EV_KEY, BTN_TOUCH, down);
+  InitInputEvent(&events[3], EV_SYN, 0, 0);
+  return 0 <
+         data()->touch_screen_queue.Write(
+             this, reinterpret_cast<char*>(&events[0]), sizeof(events), true);
+}
+
+bool InputEventsRegionView::HandlePowerButtonEvent(bool down) {
+  InputEvent events[2];
+  InitInputEvent(&events[0], EV_KEY, KEY_POWER, down);
+  InitInputEvent(&events[1], EV_SYN, 0, 0);
+  return 0 < data()->power_button_queue.Write(
+                 this, reinterpret_cast<char*>(&events[0]),
+                 sizeof(events), true);
+}
+
+bool InputEventsRegionView::HandleKeyboardEvent(bool down, uint16_t key_code) {
+  InputEvent events[2];
+  InitInputEvent(&events[0], EV_KEY, key_code, down);
+  InitInputEvent(&events[1], EV_SYN, 0, 0);
+  return 0 <
+         data()->keyboard_queue.Write(this, reinterpret_cast<char*>(&events[0]),
+                                      sizeof(events), true);
+}
+
+intptr_t InputEventsRegionView::GetScreenEventsOrWait(InputEvent* evt,
+                                                      int max_event_count) {
+  intptr_t ret = this->data()->touch_screen_queue.Read(
+      this, reinterpret_cast<char*>(evt), sizeof(InputEvent) * max_event_count);
+  if (ret < 0) {
+    return ret;
+  }
+  return ret / sizeof(InputEvent);
+}
+
+intptr_t InputEventsRegionView::GetKeyboardEventsOrWait(InputEvent* evt,
+                                                        int max_event_count) {
+  intptr_t ret = this->data()->keyboard_queue.Read(
+      this, reinterpret_cast<char*>(evt), sizeof(InputEvent) * max_event_count);
+  if (ret < 0) {
+    return ret;
+  }
+  return ret / sizeof(InputEvent);
+}
+
+intptr_t InputEventsRegionView::GetPowerButtonEventsOrWait(
+    InputEvent* evt, int max_event_count) {
+  intptr_t ret = this->data()->power_button_queue.Read(
+      this, reinterpret_cast<char*>(evt), sizeof(InputEvent) * max_event_count);
+  if (ret < 0) {
+    return ret;
+  }
+  return ret / sizeof(InputEvent);
+}
+
+}
+}
diff --git a/common/vsoc/lib/input_events_region_view.h b/common/vsoc/lib/input_events_region_view.h
new file mode 100644
index 0000000..87627ed
--- /dev/null
+++ b/common/vsoc/lib/input_events_region_view.h
@@ -0,0 +1,54 @@
+#pragma once
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/vsoc/lib/typed_region_view.h"
+#include "common/vsoc/shm/input_events_layout.h"
+#include "uapi/vsoc_shm.h"
+
+namespace vsoc {
+namespace input_events {
+
+struct InputEvent {
+  uint16_t type;
+  uint16_t code;
+  uint32_t value;
+};
+
+class InputEventsRegionView
+    : public vsoc::TypedRegionView<
+          vsoc::layout::input_events::InputEventsLayout> {
+ public:
+  static const int kMaxEventsPerPacket;
+  // Generates a touch event, may returns true if successful, false if there was
+  // an error, most likely that the queue is full.
+  bool HandleSingleTouchEvent(bool down, int x, int y);
+  bool HandlePowerButtonEvent(bool down);
+  bool HandleKeyboardEvent(bool down, uint16_t key_code);
+
+  // TODO(jemoreira): HandleMultiTouchEvent()...
+
+  // Read input events from the queue, waits if there are none available.
+  // Returns the number of events read or a negative value in case of an error
+  // (most likely the next packet in the queue is larger than the buffer
+  // provided).
+  intptr_t GetScreenEventsOrWait(InputEvent* buffer, int max_event_count);
+  intptr_t GetKeyboardEventsOrWait(InputEvent* buffer, int max_event_count);
+  intptr_t GetPowerButtonEventsOrWait(InputEvent* buffer, int max_event_count);
+};
+
+}  // namespace input_events
+}  // namespace vsoc
diff --git a/common/vsoc/shm/circqueue.h b/common/vsoc/shm/circqueue.h
index 5422b8e..a8daf40 100644
--- a/common/vsoc/shm/circqueue.h
+++ b/common/vsoc/shm/circqueue.h
@@ -149,7 +149,7 @@
    * Writes [buffer_in, buffer_in + bytes) to the queue.
    * If the number of bytes to be written exceeds the size of the queue
    * -ENOSPC will be returned.
-   * If non_blocking is true and there is not enogh free space on the queue to
+   * If non_blocking is true and there is not enough free space on the queue to
    * write all the data -EWOULDBLOCK will be returned.
    */
   intptr_t Write(RegionSignalingInterface* r,
diff --git a/common/vsoc/shm/input_events_layout.h b/common/vsoc/shm/input_events_layout.h
new file mode 100644
index 0000000..83ad70b
--- /dev/null
+++ b/common/vsoc/shm/input_events_layout.h
@@ -0,0 +1,43 @@
+#pragma once
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/vsoc/shm/base.h"
+#include "common/vsoc/shm/circqueue.h"
+#include "common/vsoc/shm/version.h"
+
+// Memory layout for region carrying input events from host to guest
+
+namespace vsoc {
+namespace layout {
+
+namespace input_events {
+
+struct InputEventsLayout : public RegionLayout {
+  static const char* region_name;
+  // Event queues for the different input devices supported. Both the power
+  // button and the keyboard need only generate 2 input events for every
+  // 'hardware' event, so 16 bytes are enough, however when the touchscreen has
+  // multitouch enabled the number of generated events is significantly higher.
+  CircularPacketQueue<10, 256> touch_screen_queue;
+  CircularPacketQueue<10, 16> keyboard_queue;
+  CircularPacketQueue<10, 16> power_button_queue;
+};
+ASSERT_SHM_COMPATIBLE(InputEventsLayout, input_events);
+
+}  // namespace input_events
+}  // namespace layout
+}  // namespace vsoc
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
index 54baf34..2c404d7 100644
--- a/common/vsoc/shm/version.h
+++ b/common/vsoc/shm/version.h
@@ -103,6 +103,17 @@
 static const std::size_t GrallocBufferLayout_size = 1;
 }  // namespace gralloc
 
+// Versioning information for input_events_layout.h
+// Changes to these structures will affect only the input_events region
+namespace input_events {
+namespace {
+const uint32_t version = 0;
+}
+// Three circular queues, each with a 1024 bytes buffer, a 32 bits spinlock and
+// two 32 bits inetgers
+static const std::size_t InputEventsLayout_size = 3 * (1024 + 3 * 4);
+}  // namespace input_events
+
 // Versioning information for fb_bcast_layout.h
 // Changes to these structures will affect only the framebuffer broadcast region
 namespace framebuffer {
diff --git a/host/config/vsoc_mem.json b/host/config/vsoc_mem.json
index 411b3c5..7a46f68 100644
--- a/host/config/vsoc_mem.json
+++ b/host/config/vsoc_mem.json
@@ -35,6 +35,23 @@
    },
 
    {
+     "device_name" : "input_events",
+     "__comment" : "Send input events from host to guest",
+     "current_version" : 0,
+     "min_compatible_version" : 0,
+     "region_size": 4096,
+
+     "guest_to_host_signal_table" : {
+       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
+       "num_nodes_lg2" : 2
+      },
+
+     "host_to_guest_signal_table" : {
+       "num_nodes_lg2" : 2
+      }
+   },
+
+   {
      "device_name" : "fb_broadcast",
      "__comment" : "Broadcasts new frames",
      "current_version" : 0,