new rebased wip

Change-Id: I8f9c2faa469614f7a18cc44cef313765edf96a36
diff --git a/zircon/system/dev/audio/usb-audio/usb-midi-sink.cc b/zircon/system/dev/audio/usb-audio/usb-midi-sink.cc
index a36f70f..3f865d7 100644
--- a/zircon/system/dev/audio/usb-audio/usb-midi-sink.cc
+++ b/zircon/system/dev/audio/usb-audio/usb-midi-sink.cc
@@ -150,12 +150,77 @@
   return status;
 }
 
-void UsbMidiSink::GetInfo(GetInfoCompleter::Sync completer) {
-  llcpp::fuchsia::hardware::midi::Info info = {
-      .is_sink = true,
-      .is_source = false,
-  };
-  completer.Reply(info);
+void UsbMidiSink::GetDirection(GetDirectionCompleter::Sync completer) {
+  completer.Reply(llcpp::fuchsia::hardware::midi::Direction::SINK);
+}
+
+void UsbMidiSink::Read(uint64_t count, ReadCompleter::Sync completer) {
+  auto result = llcpp::fuchsia::hardware::midi::Device_Read_Result();
+  result.set_err(ZX_ERR_NOT_SUPPORTED);
+  completer.Reply(std::move(result));
+}
+
+void UsbMidiSink::Write(fidl::VectorView<uint8_t> data, WriteCompleter::Sync completer) {
+  const uint8_t* src = data.data();
+  auto length = data.count();
+  zx_status_t status = ZX_OK;
+
+  fbl::AutoLock al(&mutex_);
+
+  if (dead_) {
+    status = ZX_ERR_IO_NOT_PRESENT;
+    goto error;
+  }
+
+  while (length > 0) {
+    sync_completion_wait(&free_write_completion_, ZX_TIME_INFINITE);
+    if (dead_) {
+      status = ZX_ERR_IO_NOT_PRESENT;
+      goto error;
+    }
+
+    std::optional<UsbRequest> req;
+    req = free_write_reqs_.pop();
+    if (free_write_reqs_.is_empty()) {
+      sync_completion_reset(&free_write_completion_);
+    }
+
+    if (!req) {
+      // shouldn't happen!
+      status = ZX_ERR_INTERNAL;
+      goto error;
+    }
+
+    size_t message_length = get_midi_message_length(*src);
+    if (message_length < 1 || message_length > length) {
+      status = ZX_ERR_INVALID_ARGS;
+      goto error;
+    }
+
+    uint8_t buffer[4];
+    buffer[0] = (src[0] & 0xF0) >> 4;
+    buffer[1] = src[0];
+    buffer[2] = (message_length > 1 ? src[1] : 0);
+    buffer[3] = (message_length > 2 ? src[2] : 0);
+
+    req->CopyTo(buffer, 4, 0);
+    req->request()->header.length = 4;
+    usb_request_complete_t complete = {
+        .callback = [](void* ctx,
+                       usb_request_t* req) { static_cast<UsbMidiSink*>(ctx)->WriteComplete(req); },
+        .ctx = this,
+    };
+    usb_.RequestQueue(req->take(), &complete);
+
+    src += message_length;
+    length -= message_length;
+  }
+
+error:
+  UpdateSignals();
+  auto result = llcpp::fuchsia::hardware::midi::Device_Write_Result();
+  result.set_err(status);
+  completer.Reply(std::move(result));
 }
 
 zx_status_t UsbMidiSink::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
diff --git a/zircon/system/dev/audio/usb-audio/usb-midi-sink.h b/zircon/system/dev/audio/usb-audio/usb-midi-sink.h
index 4f2fc01..ccf1cc36 100644
--- a/zircon/system/dev/audio/usb-audio/usb-midi-sink.h
+++ b/zircon/system/dev/audio/usb-audio/usb-midi-sink.h
@@ -7,11 +7,11 @@
 
 #include <fuchsia/hardware/midi/llcpp/fidl.h>
 #include <lib/sync/completion.h>
+#include <lib/zircon-internal/thread_annotations.h>
 
 #include <ddktl/device.h>
 #include <ddktl/protocol/empty-protocol.h>
 #include <fbl/mutex.h>
-#include <lib/zircon-internal/thread_annotations.h>
 #include <usb/request-cpp.h>
 #include <usb/usb.h>
 
@@ -46,7 +46,9 @@
   zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
 
   // FIDL methods.
-  void GetInfo(GetInfoCompleter::Sync completer) final;
+  void GetDirection(GetDirectionCompleter::Sync completer) final;
+  void Read(uint64_t count, ReadCompleter::Sync completer) final;
+  void Write(::fidl::VectorView<uint8_t> data, WriteCompleter::Sync completer) final;
 
  private:
   zx_status_t Init(int index, const usb_interface_descriptor_t* intf,
diff --git a/zircon/system/dev/audio/usb-audio/usb-midi-source.cc b/zircon/system/dev/audio/usb-audio/usb-midi-source.cc
index 2da4bce..b2859a3 100644
--- a/zircon/system/dev/audio/usb-audio/usb-midi-source.cc
+++ b/zircon/system/dev/audio/usb-audio/usb-midi-source.cc
@@ -142,12 +142,63 @@
   return status;
 }
 
-void UsbMidiSource::GetInfo(GetInfoCompleter::Sync completer) {
-  llcpp::fuchsia::hardware::midi::Info info = {
-      .is_sink = false,
-      .is_source = true,
-  };
-  completer.Reply(info);
+void UsbMidiSource::GetDirection(GetDirectionCompleter::Sync completer) {
+  completer.Reply(llcpp::fuchsia::hardware::midi::Direction::SOURCE);
+}
+
+void UsbMidiSource::Read(uint64_t count, ReadCompleter::Sync completer) {
+  auto result = llcpp::fuchsia::hardware::midi::Device_Read_Result();
+  zx_status_t status = ZX_OK;
+
+  fbl::AutoLock al(&mutex_);
+
+  if (dead_) {
+    status = ZX_ERR_IO_NOT_PRESENT;
+    goto error;
+  }
+
+  if (count < 3) {
+    status = ZX_ERR_BUFFER_TOO_SMALL;
+    goto error;
+  }
+
+  {
+    usb_request_complete_t complete = {
+        .callback = [](void* ctx,
+                       usb_request_t* req) { static_cast<UsbMidiSource*>(ctx)->ReadComplete(req); },
+        .ctx = this,
+    };
+
+    auto req = completed_reads_.pop();
+    if (!req.has_value()) {
+      status = ZX_ERR_SHOULD_WAIT;
+      goto error;
+    }
+
+    // MIDI events are 4 bytes. We can ignore the zeroth byte
+    uint8_t data[3];
+    req->CopyFrom(data, 3, 1);
+
+    auto response = llcpp::fuchsia::hardware::midi::Device_Read_Response();
+    response.data = fidl::VectorView(get_midi_message_length(data[0]), data);
+    result.set_response(std::move(response));
+
+    free_read_reqs_.push(std::move(*req));
+    while ((req = free_read_reqs_.pop()).has_value()) {
+      usb_.RequestQueue(req->take(), &complete);
+    }
+  }
+
+error:
+  UpdateSignals();
+  result.set_err(status);
+  completer.Reply(std::move(result));
+}
+
+void UsbMidiSource::Write(fidl::VectorView<uint8_t> data, WriteCompleter::Sync completer) {
+  auto result = llcpp::fuchsia::hardware::midi::Device_Write_Result();
+  result.set_err(ZX_ERR_NOT_SUPPORTED);
+  completer.Reply(std::move(result));
 }
 
 zx_status_t UsbMidiSource::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
diff --git a/zircon/system/dev/audio/usb-audio/usb-midi-source.h b/zircon/system/dev/audio/usb-audio/usb-midi-source.h
index 0bea48e..1ab93c5 100644
--- a/zircon/system/dev/audio/usb-audio/usb-midi-source.h
+++ b/zircon/system/dev/audio/usb-audio/usb-midi-source.h
@@ -6,11 +6,11 @@
 #define ZIRCON_SYSTEM_DEV_AUDIO_USB_AUDIO_USB_MIDI_SOURCE_H_
 
 #include <fuchsia/hardware/midi/llcpp/fidl.h>
+#include <lib/zircon-internal/thread_annotations.h>
 
 #include <ddktl/device.h>
 #include <ddktl/protocol/empty-protocol.h>
 #include <fbl/mutex.h>
-#include <lib/zircon-internal/thread_annotations.h>
 #include <usb/request-cpp.h>
 #include <usb/usb.h>
 
@@ -45,7 +45,9 @@
   zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
 
   // FIDL methods.
-  void GetInfo(GetInfoCompleter::Sync completer) final;
+  void GetDirection(GetDirectionCompleter::Sync completer) final;
+  void Read(uint64_t count, ReadCompleter::Sync completer) final;
+  void Write(::fidl::VectorView<uint8_t> data, WriteCompleter::Sync completer) final;
 
  private:
   zx_status_t Init(int index, const usb_interface_descriptor_t* intf,
diff --git a/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/fidl.cc b/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/fidl.cc
index 66a2438..c7ab531 100644
--- a/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/fidl.cc
+++ b/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/fidl.cc
@@ -9,72 +9,197 @@
 namespace hardware {
 namespace midi {
 
+::llcpp::fuchsia::hardware::midi::Device_Write_Result::Device_Write_Result() {
+  tag_ = Tag::Invalid;
+}
+
+::llcpp::fuchsia::hardware::midi::Device_Write_Result::~Device_Write_Result() {
+  Destroy();
+}
+
+void ::llcpp::fuchsia::hardware::midi::Device_Write_Result::Destroy() {
+  switch (which()) {
+  case Tag::kResponse:
+    response_.~Device_Write_Response();
+    break;
+  default:
+    break;
+  }
+  tag_ = Tag::Invalid;
+}
+
+void ::llcpp::fuchsia::hardware::midi::Device_Write_Result::MoveImpl_(Device_Write_Result&& other) {
+  switch (other.which()) {
+  case Tag::kResponse:
+    mutable_response() = std::move(other.mutable_response());
+    break;
+  case Tag::kErr:
+    mutable_err() = std::move(other.mutable_err());
+    break;
+  default:
+    break;
+  }
+  other.Destroy();
+}
+
+void ::llcpp::fuchsia::hardware::midi::Device_Write_Result::SizeAndOffsetAssertionHelper() {
+  static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device_Write_Result, response_) == 8);
+  static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device_Write_Result, err_) == 8);
+  static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device_Write_Result) == ::llcpp::fuchsia::hardware::midi::Device_Write_Result::PrimarySize);
+}
+
+
+Device_Write_Response& ::llcpp::fuchsia::hardware::midi::Device_Write_Result::mutable_response() {
+  if (which() != Tag::kResponse) {
+    Destroy();
+    new (&response_) Device_Write_Response;
+  }
+  tag_ = Tag::kResponse;
+  return response_;
+}
+
+int32_t& ::llcpp::fuchsia::hardware::midi::Device_Write_Result::mutable_err() {
+  if (which() != Tag::kErr) {
+    Destroy();
+    new (&err_) int32_t;
+  }
+  tag_ = Tag::kErr;
+  return err_;
+}
+
+
+::llcpp::fuchsia::hardware::midi::Device_Read_Result::Device_Read_Result() {
+  tag_ = Tag::Invalid;
+}
+
+::llcpp::fuchsia::hardware::midi::Device_Read_Result::~Device_Read_Result() {
+  Destroy();
+}
+
+void ::llcpp::fuchsia::hardware::midi::Device_Read_Result::Destroy() {
+  switch (which()) {
+  case Tag::kResponse:
+    response_.~Device_Read_Response();
+    break;
+  default:
+    break;
+  }
+  tag_ = Tag::Invalid;
+}
+
+void ::llcpp::fuchsia::hardware::midi::Device_Read_Result::MoveImpl_(Device_Read_Result&& other) {
+  switch (other.which()) {
+  case Tag::kResponse:
+    mutable_response() = std::move(other.mutable_response());
+    break;
+  case Tag::kErr:
+    mutable_err() = std::move(other.mutable_err());
+    break;
+  default:
+    break;
+  }
+  other.Destroy();
+}
+
+void ::llcpp::fuchsia::hardware::midi::Device_Read_Result::SizeAndOffsetAssertionHelper() {
+  static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device_Read_Result, response_) == 8);
+  static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device_Read_Result, err_) == 8);
+  static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device_Read_Result) == ::llcpp::fuchsia::hardware::midi::Device_Read_Result::PrimarySize);
+}
+
+
+Device_Read_Response& ::llcpp::fuchsia::hardware::midi::Device_Read_Result::mutable_response() {
+  if (which() != Tag::kResponse) {
+    Destroy();
+    new (&response_) Device_Read_Response;
+  }
+  tag_ = Tag::kResponse;
+  return response_;
+}
+
+int32_t& ::llcpp::fuchsia::hardware::midi::Device_Read_Result::mutable_err() {
+  if (which() != Tag::kErr) {
+    Destroy();
+    new (&err_) int32_t;
+  }
+  tag_ = Tag::kErr;
+  return err_;
+}
+
+
 namespace {
 
 [[maybe_unused]]
-constexpr uint64_t kDevice_GetInfo_Ordinal = 0x7eddfe3c00000000lu;
-extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceGetInfoResponseTable;
+constexpr uint64_t kDevice_GetDirection_Ordinal = 0x74864c4300000000lu;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceGetDirectionResponseTable;
+[[maybe_unused]]
+constexpr uint64_t kDevice_Read_Ordinal = 0x3ddea0b700000000lu;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceReadResponseTable;
+[[maybe_unused]]
+constexpr uint64_t kDevice_Write_Ordinal = 0x1d9a6e2700000000lu;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceWriteRequestTable;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceWriteResponseTable;
 
 }  // namespace
 template <>
-Device::ResultOf::GetInfo_Impl<Device::GetInfoResponse>::GetInfo_Impl(zx::unowned_channel _client_end) {
-  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<GetInfoRequest>();
+Device::ResultOf::GetDirection_Impl<Device::GetDirectionResponse>::GetDirection_Impl(zx::unowned_channel _client_end) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<GetDirectionRequest>();
   ::fidl::internal::AlignedBuffer<_kWriteAllocSize> _write_bytes_inlined;
   auto& _write_bytes_array = _write_bytes_inlined;
   uint8_t* _write_bytes = _write_bytes_array.view().data();
-  memset(_write_bytes, 0, GetInfoRequest::PrimarySize);
-  ::fidl::BytePart _request_bytes(_write_bytes, _kWriteAllocSize, sizeof(GetInfoRequest));
-  ::fidl::DecodedMessage<GetInfoRequest> _decoded_request(std::move(_request_bytes));
+  memset(_write_bytes, 0, GetDirectionRequest::PrimarySize);
+  ::fidl::BytePart _request_bytes(_write_bytes, _kWriteAllocSize, sizeof(GetDirectionRequest));
+  ::fidl::DecodedMessage<GetDirectionRequest> _decoded_request(std::move(_request_bytes));
   Super::SetResult(
-      Device::InPlace::GetInfo(std::move(_client_end), Super::response_buffer()));
+      Device::InPlace::GetDirection(std::move(_client_end), Super::response_buffer()));
 }
 
-Device::ResultOf::GetInfo Device::SyncClient::GetInfo() {
-  return ResultOf::GetInfo(zx::unowned_channel(this->channel_));
+Device::ResultOf::GetDirection Device::SyncClient::GetDirection() {
+  return ResultOf::GetDirection(zx::unowned_channel(this->channel_));
 }
 
-Device::ResultOf::GetInfo Device::Call::GetInfo(zx::unowned_channel _client_end) {
-  return ResultOf::GetInfo(std::move(_client_end));
+Device::ResultOf::GetDirection Device::Call::GetDirection(zx::unowned_channel _client_end) {
+  return ResultOf::GetDirection(std::move(_client_end));
 }
 
 template <>
-Device::UnownedResultOf::GetInfo_Impl<Device::GetInfoResponse>::GetInfo_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer) {
-  FIDL_ALIGNDECL uint8_t _write_bytes[sizeof(GetInfoRequest)] = {};
+Device::UnownedResultOf::GetDirection_Impl<Device::GetDirectionResponse>::GetDirection_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer) {
+  FIDL_ALIGNDECL uint8_t _write_bytes[sizeof(GetDirectionRequest)] = {};
   ::fidl::BytePart _request_buffer(_write_bytes, sizeof(_write_bytes));
-  memset(_request_buffer.data(), 0, GetInfoRequest::PrimarySize);
-  _request_buffer.set_actual(sizeof(GetInfoRequest));
-  ::fidl::DecodedMessage<GetInfoRequest> _decoded_request(std::move(_request_buffer));
+  memset(_request_buffer.data(), 0, GetDirectionRequest::PrimarySize);
+  _request_buffer.set_actual(sizeof(GetDirectionRequest));
+  ::fidl::DecodedMessage<GetDirectionRequest> _decoded_request(std::move(_request_buffer));
   Super::SetResult(
-      Device::InPlace::GetInfo(std::move(_client_end), std::move(_response_buffer)));
+      Device::InPlace::GetDirection(std::move(_client_end), std::move(_response_buffer)));
 }
 
-Device::UnownedResultOf::GetInfo Device::SyncClient::GetInfo(::fidl::BytePart _response_buffer) {
-  return UnownedResultOf::GetInfo(zx::unowned_channel(this->channel_), std::move(_response_buffer));
+Device::UnownedResultOf::GetDirection Device::SyncClient::GetDirection(::fidl::BytePart _response_buffer) {
+  return UnownedResultOf::GetDirection(zx::unowned_channel(this->channel_), std::move(_response_buffer));
 }
 
-Device::UnownedResultOf::GetInfo Device::Call::GetInfo(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer) {
-  return UnownedResultOf::GetInfo(std::move(_client_end), std::move(_response_buffer));
+Device::UnownedResultOf::GetDirection Device::Call::GetDirection(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer) {
+  return UnownedResultOf::GetDirection(std::move(_client_end), std::move(_response_buffer));
 }
 
-zx_status_t Device::SyncClient::GetInfo_Deprecated(Info* out_info) {
-  return Device::Call::GetInfo_Deprecated(zx::unowned_channel(this->channel_), out_info);
+zx_status_t Device::SyncClient::GetDirection_Deprecated(Direction* out_direction) {
+  return Device::Call::GetDirection_Deprecated(zx::unowned_channel(this->channel_), out_direction);
 }
 
-zx_status_t Device::Call::GetInfo_Deprecated(zx::unowned_channel _client_end, Info* out_info) {
-  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<GetInfoRequest>();
+zx_status_t Device::Call::GetDirection_Deprecated(zx::unowned_channel _client_end, Direction* out_direction) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<GetDirectionRequest>();
   FIDL_ALIGNDECL uint8_t _write_bytes[_kWriteAllocSize] = {};
-  auto& _request = *reinterpret_cast<GetInfoRequest*>(_write_bytes);
-  _request._hdr.ordinal = kDevice_GetInfo_Ordinal;
-  ::fidl::BytePart _request_bytes(_write_bytes, _kWriteAllocSize, sizeof(GetInfoRequest));
-  ::fidl::DecodedMessage<GetInfoRequest> _decoded_request(std::move(_request_bytes));
+  auto& _request = *reinterpret_cast<GetDirectionRequest*>(_write_bytes);
+  _request._hdr.ordinal = kDevice_GetDirection_Ordinal;
+  ::fidl::BytePart _request_bytes(_write_bytes, _kWriteAllocSize, sizeof(GetDirectionRequest));
+  ::fidl::DecodedMessage<GetDirectionRequest> _decoded_request(std::move(_request_bytes));
   auto _encode_request_result = ::fidl::Encode(std::move(_decoded_request));
   if (_encode_request_result.status != ZX_OK) {
     return _encode_request_result.status;
   }
-  constexpr uint32_t _kReadAllocSize = ::fidl::internal::ClampedMessageSize<GetInfoResponse>();
+  constexpr uint32_t _kReadAllocSize = ::fidl::internal::ClampedMessageSize<GetDirectionResponse>();
   FIDL_ALIGNDECL uint8_t _read_bytes[_kReadAllocSize];
   ::fidl::BytePart _response_bytes(_read_bytes, _kReadAllocSize);
-  auto _call_result = ::fidl::Call<GetInfoRequest, GetInfoResponse>(
+  auto _call_result = ::fidl::Call<GetDirectionRequest, GetDirectionResponse>(
     std::move(_client_end), std::move(_encode_request_result.message), std::move(_response_bytes));
   if (_call_result.status != ZX_OK) {
     return _call_result.status;
@@ -84,56 +209,290 @@
     return _decode_result.status;
   }
   auto& _response = *_decode_result.message.message();
-  *out_info = std::move(_response.info);
+  *out_direction = std::move(_response.direction);
   return ZX_OK;
 }
 
-::fidl::DecodeResult<Device::GetInfoResponse> Device::SyncClient::GetInfo_Deprecated(::fidl::BytePart _response_buffer, Info* out_info) {
-  return Device::Call::GetInfo_Deprecated(zx::unowned_channel(this->channel_), std::move(_response_buffer), out_info);
+::fidl::DecodeResult<Device::GetDirectionResponse> Device::SyncClient::GetDirection_Deprecated(::fidl::BytePart _response_buffer, Direction* out_direction) {
+  return Device::Call::GetDirection_Deprecated(zx::unowned_channel(this->channel_), std::move(_response_buffer), out_direction);
 }
 
-::fidl::DecodeResult<Device::GetInfoResponse> Device::Call::GetInfo_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer, Info* out_info) {
-  FIDL_ALIGNDECL uint8_t _write_bytes[sizeof(GetInfoRequest)] = {};
+::fidl::DecodeResult<Device::GetDirectionResponse> Device::Call::GetDirection_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer, Direction* out_direction) {
+  FIDL_ALIGNDECL uint8_t _write_bytes[sizeof(GetDirectionRequest)] = {};
   ::fidl::BytePart _request_buffer(_write_bytes, sizeof(_write_bytes));
-  auto& _request = *reinterpret_cast<GetInfoRequest*>(_request_buffer.data());
-  _request._hdr.ordinal = kDevice_GetInfo_Ordinal;
-  _request_buffer.set_actual(sizeof(GetInfoRequest));
-  ::fidl::DecodedMessage<GetInfoRequest> _decoded_request(std::move(_request_buffer));
+  auto& _request = *reinterpret_cast<GetDirectionRequest*>(_request_buffer.data());
+  _request._hdr.ordinal = kDevice_GetDirection_Ordinal;
+  _request_buffer.set_actual(sizeof(GetDirectionRequest));
+  ::fidl::DecodedMessage<GetDirectionRequest> _decoded_request(std::move(_request_buffer));
   auto _encode_request_result = ::fidl::Encode(std::move(_decoded_request));
   if (_encode_request_result.status != ZX_OK) {
-    return ::fidl::DecodeResult<GetInfoResponse>(_encode_request_result.status, _encode_request_result.error);
+    return ::fidl::DecodeResult<GetDirectionResponse>(_encode_request_result.status, _encode_request_result.error);
   }
-  auto _call_result = ::fidl::Call<GetInfoRequest, GetInfoResponse>(
+  auto _call_result = ::fidl::Call<GetDirectionRequest, GetDirectionResponse>(
     std::move(_client_end), std::move(_encode_request_result.message), std::move(_response_buffer));
   if (_call_result.status != ZX_OK) {
-    return ::fidl::DecodeResult<GetInfoResponse>(_call_result.status, _call_result.error);
+    return ::fidl::DecodeResult<GetDirectionResponse>(_call_result.status, _call_result.error);
   }
   auto _decode_result = ::fidl::Decode(std::move(_call_result.message));
   if (_decode_result.status != ZX_OK) {
     return _decode_result;
   }
   auto& _response = *_decode_result.message.message();
-  *out_info = std::move(_response.info);
+  *out_direction = std::move(_response.direction);
   return _decode_result;
 }
 
-::fidl::DecodeResult<Device::GetInfoResponse> Device::InPlace::GetInfo(zx::unowned_channel _client_end, ::fidl::BytePart response_buffer) {
-  constexpr uint32_t _write_num_bytes = sizeof(GetInfoRequest);
+::fidl::DecodeResult<Device::GetDirectionResponse> Device::InPlace::GetDirection(zx::unowned_channel _client_end, ::fidl::BytePart response_buffer) {
+  constexpr uint32_t _write_num_bytes = sizeof(GetDirectionRequest);
   ::fidl::internal::AlignedBuffer<_write_num_bytes> _write_bytes;
   ::fidl::BytePart _request_buffer = _write_bytes.view();
   _request_buffer.set_actual(_write_num_bytes);
-  ::fidl::DecodedMessage<GetInfoRequest> params(std::move(_request_buffer));
+  ::fidl::DecodedMessage<GetDirectionRequest> params(std::move(_request_buffer));
   params.message()->_hdr = {};
-  params.message()->_hdr.ordinal = kDevice_GetInfo_Ordinal;
+  params.message()->_hdr.ordinal = kDevice_GetDirection_Ordinal;
   auto _encode_request_result = ::fidl::Encode(std::move(params));
   if (_encode_request_result.status != ZX_OK) {
-    return ::fidl::DecodeResult<Device::GetInfoResponse>::FromFailure(
+    return ::fidl::DecodeResult<Device::GetDirectionResponse>::FromFailure(
         std::move(_encode_request_result));
   }
-  auto _call_result = ::fidl::Call<GetInfoRequest, GetInfoResponse>(
+  auto _call_result = ::fidl::Call<GetDirectionRequest, GetDirectionResponse>(
     std::move(_client_end), std::move(_encode_request_result.message), std::move(response_buffer));
   if (_call_result.status != ZX_OK) {
-    return ::fidl::DecodeResult<Device::GetInfoResponse>::FromFailure(
+    return ::fidl::DecodeResult<Device::GetDirectionResponse>::FromFailure(
+        std::move(_call_result));
+  }
+  return ::fidl::Decode(std::move(_call_result.message));
+}
+
+template <>
+Device::ResultOf::Read_Impl<Device::ReadResponse>::Read_Impl(zx::unowned_channel _client_end, uint64_t count) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<ReadRequest>();
+  ::fidl::internal::AlignedBuffer<_kWriteAllocSize> _write_bytes_inlined;
+  auto& _write_bytes_array = _write_bytes_inlined;
+  uint8_t* _write_bytes = _write_bytes_array.view().data();
+  memset(_write_bytes, 0, ReadRequest::PrimarySize);
+  auto& _request = *reinterpret_cast<ReadRequest*>(_write_bytes);
+  _request.count = std::move(count);
+  ::fidl::BytePart _request_bytes(_write_bytes, _kWriteAllocSize, sizeof(ReadRequest));
+  ::fidl::DecodedMessage<ReadRequest> _decoded_request(std::move(_request_bytes));
+  Super::SetResult(
+      Device::InPlace::Read(std::move(_client_end), std::move(_decoded_request), Super::response_buffer()));
+}
+
+Device::ResultOf::Read Device::SyncClient::Read(uint64_t count) {
+  return ResultOf::Read(zx::unowned_channel(this->channel_), std::move(count));
+}
+
+Device::ResultOf::Read Device::Call::Read(zx::unowned_channel _client_end, uint64_t count) {
+  return ResultOf::Read(std::move(_client_end), std::move(count));
+}
+
+template <>
+Device::UnownedResultOf::Read_Impl<Device::ReadResponse>::Read_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer) {
+  if (_request_buffer.capacity() < ReadRequest::PrimarySize) {
+    Super::SetFailure(::fidl::DecodeResult<ReadResponse>(ZX_ERR_BUFFER_TOO_SMALL, ::fidl::internal::kErrorRequestBufferTooSmall));
+    return;
+  }
+  memset(_request_buffer.data(), 0, ReadRequest::PrimarySize);
+  auto& _request = *reinterpret_cast<ReadRequest*>(_request_buffer.data());
+  _request.count = std::move(count);
+  _request_buffer.set_actual(sizeof(ReadRequest));
+  ::fidl::DecodedMessage<ReadRequest> _decoded_request(std::move(_request_buffer));
+  Super::SetResult(
+      Device::InPlace::Read(std::move(_client_end), std::move(_decoded_request), std::move(_response_buffer)));
+}
+
+Device::UnownedResultOf::Read Device::SyncClient::Read(::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer) {
+  return UnownedResultOf::Read(zx::unowned_channel(this->channel_), std::move(_request_buffer), std::move(count), std::move(_response_buffer));
+}
+
+Device::UnownedResultOf::Read Device::Call::Read(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer) {
+  return UnownedResultOf::Read(std::move(_client_end), std::move(_request_buffer), std::move(count), std::move(_response_buffer));
+}
+
+::fidl::DecodeResult<Device::ReadResponse> Device::SyncClient::Read_Deprecated(::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer, Device_Read_Result* out_result) {
+  return Device::Call::Read_Deprecated(zx::unowned_channel(this->channel_), std::move(_request_buffer), std::move(count), std::move(_response_buffer), out_result);
+}
+
+::fidl::DecodeResult<Device::ReadResponse> Device::Call::Read_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer, Device_Read_Result* out_result) {
+  if (_request_buffer.capacity() < ReadRequest::PrimarySize) {
+    return ::fidl::DecodeResult<ReadResponse>(ZX_ERR_BUFFER_TOO_SMALL, ::fidl::internal::kErrorRequestBufferTooSmall);
+  }
+  auto& _request = *reinterpret_cast<ReadRequest*>(_request_buffer.data());
+  _request._hdr.ordinal = kDevice_Read_Ordinal;
+  _request.count = std::move(count);
+  _request_buffer.set_actual(sizeof(ReadRequest));
+  ::fidl::DecodedMessage<ReadRequest> _decoded_request(std::move(_request_buffer));
+  auto _encode_request_result = ::fidl::Encode(std::move(_decoded_request));
+  if (_encode_request_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<ReadResponse>(_encode_request_result.status, _encode_request_result.error);
+  }
+  auto _call_result = ::fidl::Call<ReadRequest, ReadResponse>(
+    std::move(_client_end), std::move(_encode_request_result.message), std::move(_response_buffer));
+  if (_call_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<ReadResponse>(_call_result.status, _call_result.error);
+  }
+  auto _decode_result = ::fidl::Decode(std::move(_call_result.message));
+  if (_decode_result.status != ZX_OK) {
+    return _decode_result;
+  }
+  auto& _response = *_decode_result.message.message();
+  *out_result = std::move(_response.result);
+  return _decode_result;
+}
+
+::fidl::DecodeResult<Device::ReadResponse> Device::InPlace::Read(zx::unowned_channel _client_end, ::fidl::DecodedMessage<ReadRequest> params, ::fidl::BytePart response_buffer) {
+  params.message()->_hdr = {};
+  params.message()->_hdr.ordinal = kDevice_Read_Ordinal;
+  auto _encode_request_result = ::fidl::Encode(std::move(params));
+  if (_encode_request_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<Device::ReadResponse>::FromFailure(
+        std::move(_encode_request_result));
+  }
+  auto _call_result = ::fidl::Call<ReadRequest, ReadResponse>(
+    std::move(_client_end), std::move(_encode_request_result.message), std::move(response_buffer));
+  if (_call_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<Device::ReadResponse>::FromFailure(
+        std::move(_call_result));
+  }
+  return ::fidl::Decode(std::move(_call_result.message));
+}
+
+template <>
+Device::ResultOf::Write_Impl<Device::WriteResponse>::Write_Impl(zx::unowned_channel _client_end, ::fidl::VectorView<uint8_t> data) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<WriteRequest>();
+  std::unique_ptr _write_bytes_boxed = std::make_unique<::fidl::internal::AlignedBuffer<_kWriteAllocSize>>();
+  auto& _write_bytes_array = *_write_bytes_boxed;
+  WriteRequest _request = {};
+  _request.data = std::move(data);
+  auto _linearize_result = ::fidl::Linearize(&_request, _write_bytes_array.view());
+  if (_linearize_result.status != ZX_OK) {
+    Super::SetFailure(std::move(_linearize_result));
+    return;
+  }
+  ::fidl::DecodedMessage<WriteRequest> _decoded_request = std::move(_linearize_result.message);
+  Super::SetResult(
+      Device::InPlace::Write(std::move(_client_end), std::move(_decoded_request), Super::response_buffer()));
+}
+
+Device::ResultOf::Write Device::SyncClient::Write(::fidl::VectorView<uint8_t> data) {
+  return ResultOf::Write(zx::unowned_channel(this->channel_), std::move(data));
+}
+
+Device::ResultOf::Write Device::Call::Write(zx::unowned_channel _client_end, ::fidl::VectorView<uint8_t> data) {
+  return ResultOf::Write(std::move(_client_end), std::move(data));
+}
+
+template <>
+Device::UnownedResultOf::Write_Impl<Device::WriteResponse>::Write_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer) {
+  if (_request_buffer.capacity() < WriteRequest::PrimarySize) {
+    Super::SetFailure(::fidl::DecodeResult<WriteResponse>(ZX_ERR_BUFFER_TOO_SMALL, ::fidl::internal::kErrorRequestBufferTooSmall));
+    return;
+  }
+  WriteRequest _request = {};
+  _request.data = std::move(data);
+  auto _linearize_result = ::fidl::Linearize(&_request, std::move(_request_buffer));
+  if (_linearize_result.status != ZX_OK) {
+    Super::SetFailure(std::move(_linearize_result));
+    return;
+  }
+  ::fidl::DecodedMessage<WriteRequest> _decoded_request = std::move(_linearize_result.message);
+  Super::SetResult(
+      Device::InPlace::Write(std::move(_client_end), std::move(_decoded_request), std::move(_response_buffer)));
+}
+
+Device::UnownedResultOf::Write Device::SyncClient::Write(::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer) {
+  return UnownedResultOf::Write(zx::unowned_channel(this->channel_), std::move(_request_buffer), std::move(data), std::move(_response_buffer));
+}
+
+Device::UnownedResultOf::Write Device::Call::Write(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer) {
+  return UnownedResultOf::Write(std::move(_client_end), std::move(_request_buffer), std::move(data), std::move(_response_buffer));
+}
+
+zx_status_t Device::SyncClient::Write_Deprecated(::fidl::VectorView<uint8_t> data, Device_Write_Result* out_result) {
+  return Device::Call::Write_Deprecated(zx::unowned_channel(this->channel_), std::move(data), out_result);
+}
+
+zx_status_t Device::Call::Write_Deprecated(zx::unowned_channel _client_end, ::fidl::VectorView<uint8_t> data, Device_Write_Result* out_result) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<WriteRequest>();
+  std::unique_ptr<uint8_t[]> _write_bytes_unique_ptr(new uint8_t[_kWriteAllocSize]);
+  uint8_t* _write_bytes = _write_bytes_unique_ptr.get();
+  WriteRequest _request = {};
+  _request._hdr.ordinal = kDevice_Write_Ordinal;
+  _request.data = std::move(data);
+  auto _linearize_result = ::fidl::Linearize(&_request, ::fidl::BytePart(_write_bytes,
+                                                                         _kWriteAllocSize));
+  if (_linearize_result.status != ZX_OK) {
+    return _linearize_result.status;
+  }
+  ::fidl::DecodedMessage<WriteRequest> _decoded_request = std::move(_linearize_result.message);
+  auto _encode_request_result = ::fidl::Encode(std::move(_decoded_request));
+  if (_encode_request_result.status != ZX_OK) {
+    return _encode_request_result.status;
+  }
+  constexpr uint32_t _kReadAllocSize = ::fidl::internal::ClampedMessageSize<WriteResponse>();
+  FIDL_ALIGNDECL uint8_t _read_bytes[_kReadAllocSize];
+  ::fidl::BytePart _response_bytes(_read_bytes, _kReadAllocSize);
+  auto _call_result = ::fidl::Call<WriteRequest, WriteResponse>(
+    std::move(_client_end), std::move(_encode_request_result.message), std::move(_response_bytes));
+  if (_call_result.status != ZX_OK) {
+    return _call_result.status;
+  }
+  auto _decode_result = ::fidl::Decode(std::move(_call_result.message));
+  if (_decode_result.status != ZX_OK) {
+    return _decode_result.status;
+  }
+  auto& _response = *_decode_result.message.message();
+  *out_result = std::move(_response.result);
+  return ZX_OK;
+}
+
+::fidl::DecodeResult<Device::WriteResponse> Device::SyncClient::Write_Deprecated(::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer, Device_Write_Result* out_result) {
+  return Device::Call::Write_Deprecated(zx::unowned_channel(this->channel_), std::move(_request_buffer), std::move(data), std::move(_response_buffer), out_result);
+}
+
+::fidl::DecodeResult<Device::WriteResponse> Device::Call::Write_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer, Device_Write_Result* out_result) {
+  if (_request_buffer.capacity() < WriteRequest::PrimarySize) {
+    return ::fidl::DecodeResult<WriteResponse>(ZX_ERR_BUFFER_TOO_SMALL, ::fidl::internal::kErrorRequestBufferTooSmall);
+  }
+  WriteRequest _request = {};
+  _request._hdr.ordinal = kDevice_Write_Ordinal;
+  _request.data = std::move(data);
+  auto _linearize_result = ::fidl::Linearize(&_request, std::move(_request_buffer));
+  if (_linearize_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<WriteResponse>(_linearize_result.status, _linearize_result.error);
+  }
+  ::fidl::DecodedMessage<WriteRequest> _decoded_request = std::move(_linearize_result.message);
+  auto _encode_request_result = ::fidl::Encode(std::move(_decoded_request));
+  if (_encode_request_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<WriteResponse>(_encode_request_result.status, _encode_request_result.error);
+  }
+  auto _call_result = ::fidl::Call<WriteRequest, WriteResponse>(
+    std::move(_client_end), std::move(_encode_request_result.message), std::move(_response_buffer));
+  if (_call_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<WriteResponse>(_call_result.status, _call_result.error);
+  }
+  auto _decode_result = ::fidl::Decode(std::move(_call_result.message));
+  if (_decode_result.status != ZX_OK) {
+    return _decode_result;
+  }
+  auto& _response = *_decode_result.message.message();
+  *out_result = std::move(_response.result);
+  return _decode_result;
+}
+
+::fidl::DecodeResult<Device::WriteResponse> Device::InPlace::Write(zx::unowned_channel _client_end, ::fidl::DecodedMessage<WriteRequest> params, ::fidl::BytePart response_buffer) {
+  params.message()->_hdr = {};
+  params.message()->_hdr.ordinal = kDevice_Write_Ordinal;
+  auto _encode_request_result = ::fidl::Encode(std::move(params));
+  if (_encode_request_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<Device::WriteResponse>::FromFailure(
+        std::move(_encode_request_result));
+  }
+  auto _call_result = ::fidl::Call<WriteRequest, WriteResponse>(
+    std::move(_client_end), std::move(_encode_request_result.message), std::move(response_buffer));
+  if (_call_result.status != ZX_OK) {
+    return ::fidl::DecodeResult<Device::WriteResponse>::FromFailure(
         std::move(_call_result));
   }
   return ::fidl::Decode(std::move(_call_result.message));
@@ -148,15 +507,39 @@
   }
   fidl_message_header_t* hdr = reinterpret_cast<fidl_message_header_t*>(msg->bytes);
   switch (hdr->ordinal) {
-    case kDevice_GetInfo_Ordinal:
+    case kDevice_GetDirection_Ordinal:
     {
-      auto result = ::fidl::DecodeAs<GetInfoRequest>(msg);
+      auto result = ::fidl::DecodeAs<GetDirectionRequest>(msg);
       if (result.status != ZX_OK) {
         txn->Close(ZX_ERR_INVALID_ARGS);
         return true;
       }
-      impl->GetInfo(
-        Interface::GetInfoCompleter::Sync(txn));
+      impl->GetDirection(
+        Interface::GetDirectionCompleter::Sync(txn));
+      return true;
+    }
+    case kDevice_Read_Ordinal:
+    {
+      auto result = ::fidl::DecodeAs<ReadRequest>(msg);
+      if (result.status != ZX_OK) {
+        txn->Close(ZX_ERR_INVALID_ARGS);
+        return true;
+      }
+      auto message = result.message.message();
+      impl->Read(std::move(message->count),
+        Interface::ReadCompleter::Sync(txn));
+      return true;
+    }
+    case kDevice_Write_Ordinal:
+    {
+      auto result = ::fidl::DecodeAs<WriteRequest>(msg);
+      if (result.status != ZX_OK) {
+        txn->Close(ZX_ERR_INVALID_ARGS);
+        return true;
+      }
+      auto message = result.message.message();
+      impl->Write(std::move(message->data),
+        Interface::WriteCompleter::Sync(txn));
       return true;
     }
     default: {
@@ -175,31 +558,99 @@
 }
 
 
-void Device::Interface::GetInfoCompleterBase::Reply(Info info) {
-  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<GetInfoResponse>();
+void Device::Interface::GetDirectionCompleterBase::Reply(Direction direction) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<GetDirectionResponse>();
   FIDL_ALIGNDECL uint8_t _write_bytes[_kWriteAllocSize] = {};
-  auto& _response = *reinterpret_cast<GetInfoResponse*>(_write_bytes);
-  _response._hdr.ordinal = kDevice_GetInfo_Ordinal;
-  _response.info = std::move(info);
-  ::fidl::BytePart _response_bytes(_write_bytes, _kWriteAllocSize, sizeof(GetInfoResponse));
-  CompleterBase::SendReply(::fidl::DecodedMessage<GetInfoResponse>(std::move(_response_bytes)));
+  auto& _response = *reinterpret_cast<GetDirectionResponse*>(_write_bytes);
+  _response._hdr.ordinal = kDevice_GetDirection_Ordinal;
+  _response.direction = std::move(direction);
+  ::fidl::BytePart _response_bytes(_write_bytes, _kWriteAllocSize, sizeof(GetDirectionResponse));
+  CompleterBase::SendReply(::fidl::DecodedMessage<GetDirectionResponse>(std::move(_response_bytes)));
 }
 
-void Device::Interface::GetInfoCompleterBase::Reply(::fidl::BytePart _buffer, Info info) {
-  if (_buffer.capacity() < GetInfoResponse::PrimarySize) {
+void Device::Interface::GetDirectionCompleterBase::Reply(::fidl::BytePart _buffer, Direction direction) {
+  if (_buffer.capacity() < GetDirectionResponse::PrimarySize) {
     CompleterBase::Close(ZX_ERR_INTERNAL);
     return;
   }
-  auto& _response = *reinterpret_cast<GetInfoResponse*>(_buffer.data());
-  _response._hdr.ordinal = kDevice_GetInfo_Ordinal;
-  _response.info = std::move(info);
-  _buffer.set_actual(sizeof(GetInfoResponse));
-  CompleterBase::SendReply(::fidl::DecodedMessage<GetInfoResponse>(std::move(_buffer)));
+  auto& _response = *reinterpret_cast<GetDirectionResponse*>(_buffer.data());
+  _response._hdr.ordinal = kDevice_GetDirection_Ordinal;
+  _response.direction = std::move(direction);
+  _buffer.set_actual(sizeof(GetDirectionResponse));
+  CompleterBase::SendReply(::fidl::DecodedMessage<GetDirectionResponse>(std::move(_buffer)));
 }
 
-void Device::Interface::GetInfoCompleterBase::Reply(::fidl::DecodedMessage<GetInfoResponse> params) {
+void Device::Interface::GetDirectionCompleterBase::Reply(::fidl::DecodedMessage<GetDirectionResponse> params) {
   params.message()->_hdr = {};
-  params.message()->_hdr.ordinal = kDevice_GetInfo_Ordinal;
+  params.message()->_hdr.ordinal = kDevice_GetDirection_Ordinal;
+  CompleterBase::SendReply(std::move(params));
+}
+
+
+void Device::Interface::ReadCompleterBase::Reply(Device_Read_Result result) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<ReadResponse>();
+  std::unique_ptr<uint8_t[]> _write_bytes_unique_ptr(new uint8_t[_kWriteAllocSize]);
+  uint8_t* _write_bytes = _write_bytes_unique_ptr.get();
+  ReadResponse _response = {};
+  _response._hdr.ordinal = kDevice_Read_Ordinal;
+  _response.result = std::move(result);
+  auto _linearize_result = ::fidl::Linearize(&_response, ::fidl::BytePart(_write_bytes,
+                                                                          _kWriteAllocSize));
+  if (_linearize_result.status != ZX_OK) {
+    CompleterBase::Close(ZX_ERR_INTERNAL);
+    return;
+  }
+  CompleterBase::SendReply(std::move(_linearize_result.message));
+}
+
+void Device::Interface::ReadCompleterBase::Reply(::fidl::BytePart _buffer, Device_Read_Result result) {
+  if (_buffer.capacity() < ReadResponse::PrimarySize) {
+    CompleterBase::Close(ZX_ERR_INTERNAL);
+    return;
+  }
+  ReadResponse _response = {};
+  _response._hdr.ordinal = kDevice_Read_Ordinal;
+  _response.result = std::move(result);
+  auto _linearize_result = ::fidl::Linearize(&_response, std::move(_buffer));
+  if (_linearize_result.status != ZX_OK) {
+    CompleterBase::Close(ZX_ERR_INTERNAL);
+    return;
+  }
+  CompleterBase::SendReply(std::move(_linearize_result.message));
+}
+
+void Device::Interface::ReadCompleterBase::Reply(::fidl::DecodedMessage<ReadResponse> params) {
+  params.message()->_hdr = {};
+  params.message()->_hdr.ordinal = kDevice_Read_Ordinal;
+  CompleterBase::SendReply(std::move(params));
+}
+
+
+void Device::Interface::WriteCompleterBase::Reply(Device_Write_Result result) {
+  constexpr uint32_t _kWriteAllocSize = ::fidl::internal::ClampedMessageSize<WriteResponse>();
+  FIDL_ALIGNDECL uint8_t _write_bytes[_kWriteAllocSize] = {};
+  auto& _response = *reinterpret_cast<WriteResponse*>(_write_bytes);
+  _response._hdr.ordinal = kDevice_Write_Ordinal;
+  _response.result = std::move(result);
+  ::fidl::BytePart _response_bytes(_write_bytes, _kWriteAllocSize, sizeof(WriteResponse));
+  CompleterBase::SendReply(::fidl::DecodedMessage<WriteResponse>(std::move(_response_bytes)));
+}
+
+void Device::Interface::WriteCompleterBase::Reply(::fidl::BytePart _buffer, Device_Write_Result result) {
+  if (_buffer.capacity() < WriteResponse::PrimarySize) {
+    CompleterBase::Close(ZX_ERR_INTERNAL);
+    return;
+  }
+  auto& _response = *reinterpret_cast<WriteResponse*>(_buffer.data());
+  _response._hdr.ordinal = kDevice_Write_Ordinal;
+  _response.result = std::move(result);
+  _buffer.set_actual(sizeof(WriteResponse));
+  CompleterBase::SendReply(::fidl::DecodedMessage<WriteResponse>(std::move(_buffer)));
+}
+
+void Device::Interface::WriteCompleterBase::Reply(::fidl::DecodedMessage<WriteResponse> params) {
+  params.message()->_hdr = {};
+  params.message()->_hdr.ordinal = kDevice_Write_Ordinal;
   CompleterBase::SendReply(std::move(params));
 }
 
diff --git a/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/include/fuchsia/hardware/midi/llcpp/fidl.h b/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/include/fuchsia/hardware/midi/llcpp/fidl.h
index 8192cc3..648352d 100644
--- a/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/include/fuchsia/hardware/midi/llcpp/fidl.h
+++ b/zircon/system/fidl/fuchsia-hardware-midi/gen/llcpp/include/fuchsia/hardware/midi/llcpp/fidl.h
@@ -20,43 +20,272 @@
 namespace hardware {
 namespace midi {
 
-struct Info;
+enum class Direction : uint8_t {
+  SOURCE = 1u,
+  SINK = 2u,
+};
+
+
+struct Device_Write_Response;
+struct Device_Write_Result;
+struct Device_Read_Response;
+struct Device_Read_Result;
 class Device;
 
 
 
-// Describes what type of MIDI device an implementation of Device represents
-struct Info {
+struct Device_Write_Response {
   static constexpr const fidl_type_t* Type = nullptr;
   static constexpr uint32_t MaxNumHandles = 0;
-  static constexpr uint32_t PrimarySize = 2;
+  static constexpr uint32_t PrimarySize = 8;
   [[maybe_unused]]
   static constexpr uint32_t MaxOutOfLine = 0;
 
-  // Whether or not this device is a MIDI sink
-  bool is_sink = {};
-
-  // Whether or not this device is a MIDI source
-  bool is_source = {};
+  uint64_t actual = {};
 };
 
-extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceGetInfoResponseTable;
+extern "C" const fidl_type_t fuchsia_hardware_midi_Device_Write_ResultTable;
+
+struct Device_Write_Result {
+  enum class Tag : fidl_union_tag_t {
+    kResponse = 0,
+    kErr = 1,
+    Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
+  };
+
+  Device_Write_Result();
+  ~Device_Write_Result();
+
+  Device_Write_Result(Device_Write_Result&& other) {
+    tag_ = Tag::Invalid;
+    if (this != &other) {
+      MoveImpl_(std::move(other));
+    }
+  }
+
+  Device_Write_Result& operator=(Device_Write_Result&& other) {
+    if (this != &other) {
+      MoveImpl_(std::move(other));
+    }
+    return *this;
+  }
+
+  bool has_invalid_tag() const { return tag_ == Tag::Invalid; }
+
+  bool is_response() const { return tag_ == Tag::kResponse; }
+
+  Device_Write_Response& mutable_response();
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, Device_Write_Response>::value && std::is_copy_assignable<T>::value>
+  set_response(const T& v) {
+    mutable_response() = v;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, Device_Write_Response>::value && std::is_move_assignable<T>::value>
+  set_response(T&& v) {
+    mutable_response() = std::move(v);
+  }
+
+  Device_Write_Response const & response() const { return response_; }
+
+  bool is_err() const { return tag_ == Tag::kErr; }
+
+  int32_t& mutable_err();
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, int32_t>::value && std::is_copy_assignable<T>::value>
+  set_err(const T& v) {
+    mutable_err() = v;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, int32_t>::value && std::is_move_assignable<T>::value>
+  set_err(T&& v) {
+    mutable_err() = std::move(v);
+  }
+
+  int32_t const & err() const { return err_; }
+
+  Tag which() const { return tag_; }
+
+  static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_Device_Write_ResultTable;
+  static constexpr uint32_t MaxNumHandles = 0;
+  static constexpr uint32_t PrimarySize = 16;
+  [[maybe_unused]]
+  static constexpr uint32_t MaxOutOfLine = 0;
+
+ private:
+  void Destroy();
+  void MoveImpl_(Device_Write_Result&& other);
+  static void SizeAndOffsetAssertionHelper();
+  Tag tag_;
+  union {
+    Device_Write_Response response_;
+    int32_t err_;
+  };
+};
+
+extern "C" const fidl_type_t fuchsia_hardware_midi_Device_Read_ResponseTable;
+
+struct Device_Read_Response {
+  static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_Device_Read_ResponseTable;
+  static constexpr uint32_t MaxNumHandles = 0;
+  static constexpr uint32_t PrimarySize = 16;
+  [[maybe_unused]]
+  static constexpr uint32_t MaxOutOfLine = 4294967295;
+
+  ::fidl::VectorView<uint8_t> data = {};
+};
+
+extern "C" const fidl_type_t fuchsia_hardware_midi_Device_Read_ResultTable;
+
+struct Device_Read_Result {
+  enum class Tag : fidl_union_tag_t {
+    kResponse = 0,
+    kErr = 1,
+    Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
+  };
+
+  Device_Read_Result();
+  ~Device_Read_Result();
+
+  Device_Read_Result(Device_Read_Result&& other) {
+    tag_ = Tag::Invalid;
+    if (this != &other) {
+      MoveImpl_(std::move(other));
+    }
+  }
+
+  Device_Read_Result& operator=(Device_Read_Result&& other) {
+    if (this != &other) {
+      MoveImpl_(std::move(other));
+    }
+    return *this;
+  }
+
+  bool has_invalid_tag() const { return tag_ == Tag::Invalid; }
+
+  bool is_response() const { return tag_ == Tag::kResponse; }
+
+  Device_Read_Response& mutable_response();
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, Device_Read_Response>::value && std::is_copy_assignable<T>::value>
+  set_response(const T& v) {
+    mutable_response() = v;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, Device_Read_Response>::value && std::is_move_assignable<T>::value>
+  set_response(T&& v) {
+    mutable_response() = std::move(v);
+  }
+
+  Device_Read_Response const & response() const { return response_; }
+
+  bool is_err() const { return tag_ == Tag::kErr; }
+
+  int32_t& mutable_err();
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, int32_t>::value && std::is_copy_assignable<T>::value>
+  set_err(const T& v) {
+    mutable_err() = v;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_convertible<T, int32_t>::value && std::is_move_assignable<T>::value>
+  set_err(T&& v) {
+    mutable_err() = std::move(v);
+  }
+
+  int32_t const & err() const { return err_; }
+
+  Tag which() const { return tag_; }
+
+  static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_Device_Read_ResultTable;
+  static constexpr uint32_t MaxNumHandles = 0;
+  static constexpr uint32_t PrimarySize = 24;
+  [[maybe_unused]]
+  static constexpr uint32_t MaxOutOfLine = 4294967295;
+
+ private:
+  void Destroy();
+  void MoveImpl_(Device_Read_Result&& other);
+  static void SizeAndOffsetAssertionHelper();
+  Tag tag_;
+  union {
+    Device_Read_Response response_;
+    int32_t err_;
+  };
+};
+
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceGetDirectionResponseTable;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceReadResponseTable;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceWriteRequestTable;
+extern "C" const fidl_type_t fuchsia_hardware_midi_DeviceWriteResponseTable;
 
 class Device final {
   Device() = delete;
  public:
 
-  struct GetInfoResponse final {
+  struct GetDirectionResponse final {
     FIDL_ALIGNDECL
     fidl_message_header_t _hdr;
-    Info info;
+    Direction direction;
 
-    static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_DeviceGetInfoResponseTable;
+    static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_DeviceGetDirectionResponseTable;
     static constexpr uint32_t MaxNumHandles = 0;
     static constexpr uint32_t PrimarySize = 24;
     static constexpr uint32_t MaxOutOfLine = 0;
   };
-  using GetInfoRequest = ::fidl::AnyZeroArgMessage;
+  using GetDirectionRequest = ::fidl::AnyZeroArgMessage;
+
+  struct ReadResponse final {
+    FIDL_ALIGNDECL
+    fidl_message_header_t _hdr;
+    Device_Read_Result result;
+
+    static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_DeviceReadResponseTable;
+    static constexpr uint32_t MaxNumHandles = 0;
+    static constexpr uint32_t PrimarySize = 40;
+    static constexpr uint32_t MaxOutOfLine = 4294967295;
+  };
+  struct ReadRequest final {
+    FIDL_ALIGNDECL
+    fidl_message_header_t _hdr;
+    uint64_t count;
+
+    static constexpr const fidl_type_t* Type = nullptr;
+    static constexpr uint32_t MaxNumHandles = 0;
+    static constexpr uint32_t PrimarySize = 24;
+    static constexpr uint32_t MaxOutOfLine = 0;
+    using ResponseType = ReadResponse;
+  };
+
+  struct WriteResponse final {
+    FIDL_ALIGNDECL
+    fidl_message_header_t _hdr;
+    Device_Write_Result result;
+
+    static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_DeviceWriteResponseTable;
+    static constexpr uint32_t MaxNumHandles = 0;
+    static constexpr uint32_t PrimarySize = 32;
+    static constexpr uint32_t MaxOutOfLine = 0;
+  };
+  struct WriteRequest final {
+    FIDL_ALIGNDECL
+    fidl_message_header_t _hdr;
+    ::fidl::VectorView<uint8_t> data;
+
+    static constexpr const fidl_type_t* Type = &fuchsia_hardware_midi_DeviceWriteRequestTable;
+    static constexpr uint32_t MaxNumHandles = 0;
+    static constexpr uint32_t PrimarySize = 32;
+    static constexpr uint32_t MaxOutOfLine = 4294967295;
+    using ResponseType = WriteResponse;
+  };
 
 
   // Collection of return types of FIDL calls in this interface.
@@ -64,13 +293,45 @@
     ResultOf() = delete;
    private:
     template <typename ResponseType>
-    class GetInfo_Impl final : private ::fidl::internal::OwnedSyncCallBase<ResponseType> {
+    class GetDirection_Impl final : private ::fidl::internal::OwnedSyncCallBase<ResponseType> {
       using Super = ::fidl::internal::OwnedSyncCallBase<ResponseType>;
      public:
-      GetInfo_Impl(zx::unowned_channel _client_end);
-      ~GetInfo_Impl() = default;
-      GetInfo_Impl(GetInfo_Impl&& other) = default;
-      GetInfo_Impl& operator=(GetInfo_Impl&& other) = default;
+      GetDirection_Impl(zx::unowned_channel _client_end);
+      ~GetDirection_Impl() = default;
+      GetDirection_Impl(GetDirection_Impl&& other) = default;
+      GetDirection_Impl& operator=(GetDirection_Impl&& other) = default;
+      using Super::status;
+      using Super::error;
+      using Super::ok;
+      using Super::Unwrap;
+      using Super::value;
+      using Super::operator->;
+      using Super::operator*;
+    };
+    template <typename ResponseType>
+    class Read_Impl final : private ::fidl::internal::OwnedSyncCallBase<ResponseType> {
+      using Super = ::fidl::internal::OwnedSyncCallBase<ResponseType>;
+     public:
+      Read_Impl(zx::unowned_channel _client_end, uint64_t count);
+      ~Read_Impl() = default;
+      Read_Impl(Read_Impl&& other) = default;
+      Read_Impl& operator=(Read_Impl&& other) = default;
+      using Super::status;
+      using Super::error;
+      using Super::ok;
+      using Super::Unwrap;
+      using Super::value;
+      using Super::operator->;
+      using Super::operator*;
+    };
+    template <typename ResponseType>
+    class Write_Impl final : private ::fidl::internal::OwnedSyncCallBase<ResponseType> {
+      using Super = ::fidl::internal::OwnedSyncCallBase<ResponseType>;
+     public:
+      Write_Impl(zx::unowned_channel _client_end, ::fidl::VectorView<uint8_t> data);
+      ~Write_Impl() = default;
+      Write_Impl(Write_Impl&& other) = default;
+      Write_Impl& operator=(Write_Impl&& other) = default;
       using Super::status;
       using Super::error;
       using Super::ok;
@@ -81,7 +342,9 @@
     };
 
    public:
-    using GetInfo = GetInfo_Impl<GetInfoResponse>;
+    using GetDirection = GetDirection_Impl<GetDirectionResponse>;
+    using Read = Read_Impl<ReadResponse>;
+    using Write = Write_Impl<WriteResponse>;
   };
 
   // Collection of return types of FIDL calls in this interface,
@@ -90,13 +353,45 @@
     UnownedResultOf() = delete;
    private:
     template <typename ResponseType>
-    class GetInfo_Impl final : private ::fidl::internal::UnownedSyncCallBase<ResponseType> {
+    class GetDirection_Impl final : private ::fidl::internal::UnownedSyncCallBase<ResponseType> {
       using Super = ::fidl::internal::UnownedSyncCallBase<ResponseType>;
      public:
-      GetInfo_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer);
-      ~GetInfo_Impl() = default;
-      GetInfo_Impl(GetInfo_Impl&& other) = default;
-      GetInfo_Impl& operator=(GetInfo_Impl&& other) = default;
+      GetDirection_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer);
+      ~GetDirection_Impl() = default;
+      GetDirection_Impl(GetDirection_Impl&& other) = default;
+      GetDirection_Impl& operator=(GetDirection_Impl&& other) = default;
+      using Super::status;
+      using Super::error;
+      using Super::ok;
+      using Super::Unwrap;
+      using Super::value;
+      using Super::operator->;
+      using Super::operator*;
+    };
+    template <typename ResponseType>
+    class Read_Impl final : private ::fidl::internal::UnownedSyncCallBase<ResponseType> {
+      using Super = ::fidl::internal::UnownedSyncCallBase<ResponseType>;
+     public:
+      Read_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer);
+      ~Read_Impl() = default;
+      Read_Impl(Read_Impl&& other) = default;
+      Read_Impl& operator=(Read_Impl&& other) = default;
+      using Super::status;
+      using Super::error;
+      using Super::ok;
+      using Super::Unwrap;
+      using Super::value;
+      using Super::operator->;
+      using Super::operator*;
+    };
+    template <typename ResponseType>
+    class Write_Impl final : private ::fidl::internal::UnownedSyncCallBase<ResponseType> {
+      using Super = ::fidl::internal::UnownedSyncCallBase<ResponseType>;
+     public:
+      Write_Impl(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer);
+      ~Write_Impl() = default;
+      Write_Impl(Write_Impl&& other) = default;
+      Write_Impl& operator=(Write_Impl&& other) = default;
       using Super::status;
       using Super::error;
       using Super::ok;
@@ -107,7 +402,9 @@
     };
 
    public:
-    using GetInfo = GetInfo_Impl<GetInfoResponse>;
+    using GetDirection = GetDirection_Impl<GetDirectionResponse>;
+    using Read = Read_Impl<ReadResponse>;
+    using Write = Write_Impl<WriteResponse>;
   };
 
   class SyncClient final {
@@ -121,21 +418,51 @@
 
     ::zx::channel* mutable_channel() { return &channel_; }
 
-    // Get information about the type of MIDI device
+    // Get direction of the MIDI device
     // Allocates 40 bytes of message buffer on the stack. No heap allocation necessary.
-    ResultOf::GetInfo GetInfo();
+    ResultOf::GetDirection GetDirection();
 
-    // Get information about the type of MIDI device
+    // Get direction of the MIDI device
     // Caller provides the backing storage for FIDL message via request and response buffers.
-    UnownedResultOf::GetInfo GetInfo(::fidl::BytePart _response_buffer);
+    UnownedResultOf::GetDirection GetDirection(::fidl::BytePart _response_buffer);
 
-    // Get information about the type of MIDI device
-    zx_status_t GetInfo_Deprecated(Info* out_info);
+    // Get direction of the MIDI device
+    zx_status_t GetDirection_Deprecated(Direction* out_direction);
 
-    // Get information about the type of MIDI device
+    // Get direction of the MIDI device
     // Caller provides the backing storage for FIDL message via request and response buffers.
     // The lifetime of handles in the response, unless moved, is tied to the returned RAII object.
-    ::fidl::DecodeResult<GetInfoResponse> GetInfo_Deprecated(::fidl::BytePart _response_buffer, Info* out_info);
+    ::fidl::DecodeResult<GetDirectionResponse> GetDirection_Deprecated(::fidl::BytePart _response_buffer, Direction* out_direction);
+
+    // Reads MIDI data from a MIDI source
+    // Allocates 24 bytes of request buffer on the stack. Response is heap-allocated.
+    ResultOf::Read Read(uint64_t count);
+
+    // Reads MIDI data from a MIDI source
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    UnownedResultOf::Read Read(::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer);
+
+
+    // Reads MIDI data from a MIDI source
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    // The lifetime of handles in the response, unless moved, is tied to the returned RAII object.
+    ::fidl::DecodeResult<ReadResponse> Read_Deprecated(::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer, Device_Read_Result* out_result);
+
+    // Reads MIDI data to a MIDI sink
+    // Allocates 32 bytes of response buffer on the stack. Request is heap-allocated.
+    ResultOf::Write Write(::fidl::VectorView<uint8_t> data);
+
+    // Reads MIDI data to a MIDI sink
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    UnownedResultOf::Write Write(::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer);
+
+    // Reads MIDI data to a MIDI sink
+    zx_status_t Write_Deprecated(::fidl::VectorView<uint8_t> data, Device_Write_Result* out_result);
+
+    // Reads MIDI data to a MIDI sink
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    // The lifetime of handles in the response, unless moved, is tied to the returned RAII object.
+    ::fidl::DecodeResult<WriteResponse> Write_Deprecated(::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer, Device_Write_Result* out_result);
 
    private:
     ::zx::channel channel_;
@@ -146,21 +473,51 @@
     Call() = delete;
    public:
 
-    // Get information about the type of MIDI device
+    // Get direction of the MIDI device
     // Allocates 40 bytes of message buffer on the stack. No heap allocation necessary.
-    static ResultOf::GetInfo GetInfo(zx::unowned_channel _client_end);
+    static ResultOf::GetDirection GetDirection(zx::unowned_channel _client_end);
 
-    // Get information about the type of MIDI device
+    // Get direction of the MIDI device
     // Caller provides the backing storage for FIDL message via request and response buffers.
-    static UnownedResultOf::GetInfo GetInfo(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer);
+    static UnownedResultOf::GetDirection GetDirection(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer);
 
-    // Get information about the type of MIDI device
-    static zx_status_t GetInfo_Deprecated(zx::unowned_channel _client_end, Info* out_info);
+    // Get direction of the MIDI device
+    static zx_status_t GetDirection_Deprecated(zx::unowned_channel _client_end, Direction* out_direction);
 
-    // Get information about the type of MIDI device
+    // Get direction of the MIDI device
     // Caller provides the backing storage for FIDL message via request and response buffers.
     // The lifetime of handles in the response, unless moved, is tied to the returned RAII object.
-    static ::fidl::DecodeResult<GetInfoResponse> GetInfo_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer, Info* out_info);
+    static ::fidl::DecodeResult<GetDirectionResponse> GetDirection_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _response_buffer, Direction* out_direction);
+
+    // Reads MIDI data from a MIDI source
+    // Allocates 24 bytes of request buffer on the stack. Response is heap-allocated.
+    static ResultOf::Read Read(zx::unowned_channel _client_end, uint64_t count);
+
+    // Reads MIDI data from a MIDI source
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    static UnownedResultOf::Read Read(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer);
+
+
+    // Reads MIDI data from a MIDI source
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    // The lifetime of handles in the response, unless moved, is tied to the returned RAII object.
+    static ::fidl::DecodeResult<ReadResponse> Read_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, uint64_t count, ::fidl::BytePart _response_buffer, Device_Read_Result* out_result);
+
+    // Reads MIDI data to a MIDI sink
+    // Allocates 32 bytes of response buffer on the stack. Request is heap-allocated.
+    static ResultOf::Write Write(zx::unowned_channel _client_end, ::fidl::VectorView<uint8_t> data);
+
+    // Reads MIDI data to a MIDI sink
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    static UnownedResultOf::Write Write(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer);
+
+    // Reads MIDI data to a MIDI sink
+    static zx_status_t Write_Deprecated(zx::unowned_channel _client_end, ::fidl::VectorView<uint8_t> data, Device_Write_Result* out_result);
+
+    // Reads MIDI data to a MIDI sink
+    // Caller provides the backing storage for FIDL message via request and response buffers.
+    // The lifetime of handles in the response, unless moved, is tied to the returned RAII object.
+    static ::fidl::DecodeResult<WriteResponse> Write_Deprecated(zx::unowned_channel _client_end, ::fidl::BytePart _request_buffer, ::fidl::VectorView<uint8_t> data, ::fidl::BytePart _response_buffer, Device_Write_Result* out_result);
 
   };
 
@@ -170,8 +527,14 @@
     InPlace() = delete;
    public:
 
-    // Get information about the type of MIDI device
-    static ::fidl::DecodeResult<GetInfoResponse> GetInfo(zx::unowned_channel _client_end, ::fidl::BytePart response_buffer);
+    // Get direction of the MIDI device
+    static ::fidl::DecodeResult<GetDirectionResponse> GetDirection(zx::unowned_channel _client_end, ::fidl::BytePart response_buffer);
+
+    // Reads MIDI data from a MIDI source
+    static ::fidl::DecodeResult<ReadResponse> Read(zx::unowned_channel _client_end, ::fidl::DecodedMessage<ReadRequest> params, ::fidl::BytePart response_buffer);
+
+    // Reads MIDI data to a MIDI sink
+    static ::fidl::DecodeResult<WriteResponse> Write(zx::unowned_channel _client_end, ::fidl::DecodedMessage<WriteRequest> params, ::fidl::BytePart response_buffer);
 
   };
 
@@ -183,19 +546,47 @@
     using _Outer = Device;
     using _Base = ::fidl::CompleterBase;
 
-    class GetInfoCompleterBase : public _Base {
+    class GetDirectionCompleterBase : public _Base {
      public:
-      void Reply(Info info);
-      void Reply(::fidl::BytePart _buffer, Info info);
-      void Reply(::fidl::DecodedMessage<GetInfoResponse> params);
+      void Reply(Direction direction);
+      void Reply(::fidl::BytePart _buffer, Direction direction);
+      void Reply(::fidl::DecodedMessage<GetDirectionResponse> params);
 
      protected:
       using ::fidl::CompleterBase::CompleterBase;
     };
 
-    using GetInfoCompleter = ::fidl::Completer<GetInfoCompleterBase>;
+    using GetDirectionCompleter = ::fidl::Completer<GetDirectionCompleterBase>;
 
-    virtual void GetInfo(GetInfoCompleter::Sync _completer) = 0;
+    virtual void GetDirection(GetDirectionCompleter::Sync _completer) = 0;
+
+    class ReadCompleterBase : public _Base {
+     public:
+      void Reply(Device_Read_Result result);
+      void Reply(::fidl::BytePart _buffer, Device_Read_Result result);
+      void Reply(::fidl::DecodedMessage<ReadResponse> params);
+
+     protected:
+      using ::fidl::CompleterBase::CompleterBase;
+    };
+
+    using ReadCompleter = ::fidl::Completer<ReadCompleterBase>;
+
+    virtual void Read(uint64_t count, ReadCompleter::Sync _completer) = 0;
+
+    class WriteCompleterBase : public _Base {
+     public:
+      void Reply(Device_Write_Result result);
+      void Reply(::fidl::BytePart _buffer, Device_Write_Result result);
+      void Reply(::fidl::DecodedMessage<WriteResponse> params);
+
+     protected:
+      using ::fidl::CompleterBase::CompleterBase;
+    };
+
+    using WriteCompleter = ::fidl::Completer<WriteCompleterBase>;
+
+    virtual void Write(::fidl::VectorView<uint8_t> data, WriteCompleter::Sync _completer) = 0;
 
   };
 
@@ -227,18 +618,63 @@
 namespace fidl {
 
 template <>
-struct IsFidlType<::llcpp::fuchsia::hardware::midi::Info> : public std::true_type {};
-static_assert(std::is_standard_layout_v<::llcpp::fuchsia::hardware::midi::Info>);
-static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Info, is_sink) == 0);
-static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Info, is_source) == 1);
-static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Info) == ::llcpp::fuchsia::hardware::midi::Info::PrimarySize);
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device_Write_Response> : public std::true_type {};
+static_assert(std::is_standard_layout_v<::llcpp::fuchsia::hardware::midi::Device_Write_Response>);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device_Write_Response, actual) == 0);
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device_Write_Response) == ::llcpp::fuchsia::hardware::midi::Device_Write_Response::PrimarySize);
 
 template <>
-struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device::GetInfoResponse> : public std::true_type {};
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device_Write_Result> : public std::true_type {};
+static_assert(std::is_standard_layout_v<::llcpp::fuchsia::hardware::midi::Device_Write_Result>);
+
 template <>
-struct IsFidlMessage<::llcpp::fuchsia::hardware::midi::Device::GetInfoResponse> : public std::true_type {};
-static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device::GetInfoResponse)
-    == ::llcpp::fuchsia::hardware::midi::Device::GetInfoResponse::PrimarySize);
-static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device::GetInfoResponse, info) == 16);
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device_Read_Response> : public std::true_type {};
+static_assert(std::is_standard_layout_v<::llcpp::fuchsia::hardware::midi::Device_Read_Response>);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device_Read_Response, data) == 0);
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device_Read_Response) == ::llcpp::fuchsia::hardware::midi::Device_Read_Response::PrimarySize);
+
+template <>
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device_Read_Result> : public std::true_type {};
+static_assert(std::is_standard_layout_v<::llcpp::fuchsia::hardware::midi::Device_Read_Result>);
+
+template <>
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device::GetDirectionResponse> : public std::true_type {};
+template <>
+struct IsFidlMessage<::llcpp::fuchsia::hardware::midi::Device::GetDirectionResponse> : public std::true_type {};
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device::GetDirectionResponse)
+    == ::llcpp::fuchsia::hardware::midi::Device::GetDirectionResponse::PrimarySize);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device::GetDirectionResponse, direction) == 16);
+
+template <>
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device::ReadRequest> : public std::true_type {};
+template <>
+struct IsFidlMessage<::llcpp::fuchsia::hardware::midi::Device::ReadRequest> : public std::true_type {};
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device::ReadRequest)
+    == ::llcpp::fuchsia::hardware::midi::Device::ReadRequest::PrimarySize);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device::ReadRequest, count) == 16);
+
+template <>
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device::ReadResponse> : public std::true_type {};
+template <>
+struct IsFidlMessage<::llcpp::fuchsia::hardware::midi::Device::ReadResponse> : public std::true_type {};
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device::ReadResponse)
+    == ::llcpp::fuchsia::hardware::midi::Device::ReadResponse::PrimarySize);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device::ReadResponse, result) == 16);
+
+template <>
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device::WriteRequest> : public std::true_type {};
+template <>
+struct IsFidlMessage<::llcpp::fuchsia::hardware::midi::Device::WriteRequest> : public std::true_type {};
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device::WriteRequest)
+    == ::llcpp::fuchsia::hardware::midi::Device::WriteRequest::PrimarySize);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device::WriteRequest, data) == 16);
+
+template <>
+struct IsFidlType<::llcpp::fuchsia::hardware::midi::Device::WriteResponse> : public std::true_type {};
+template <>
+struct IsFidlMessage<::llcpp::fuchsia::hardware::midi::Device::WriteResponse> : public std::true_type {};
+static_assert(sizeof(::llcpp::fuchsia::hardware::midi::Device::WriteResponse)
+    == ::llcpp::fuchsia::hardware::midi::Device::WriteResponse::PrimarySize);
+static_assert(offsetof(::llcpp::fuchsia::hardware::midi::Device::WriteResponse, result) == 16);
 
 }  // namespace fidl
diff --git a/zircon/system/fidl/fuchsia-hardware-midi/midi.fidl b/zircon/system/fidl/fuchsia-hardware-midi/midi.fidl
index 6b1ce1a..66f8437 100644
--- a/zircon/system/fidl/fuchsia-hardware-midi/midi.fidl
+++ b/zircon/system/fidl/fuchsia-hardware-midi/midi.fidl
@@ -4,16 +4,23 @@
 
 library fuchsia.hardware.midi;
 
+using zx;
+
 /// Describes what type of MIDI device an implementation of Device represents
-struct Info {
-    /// Whether or not this device is a MIDI sink
-    bool is_sink;
-    /// Whether or not this device is a MIDI source
-    bool is_source;
+enum Direction : uint8 {
+    /// A MIDI source
+    SOURCE = 1;
+    /// A MIDI sink
+    SINK = 2;
 };
 
-[Layout = "Simple"]
 protocol Device {
-    /// Get information about the type of MIDI device
-    GetInfo() -> (Info info);
+    /// Get direction of the MIDI device
+    GetDirection() -> (Direction direction);
+
+    /// Reads MIDI data from a MIDI source
+    Read(uint64 count) -> (bytes data) error zx.status;
+	
+    /// Reads MIDI data to a MIDI sink
+    Write(bytes data) -> (uint64 actual) error zx.status;
 };
diff --git a/zircon/system/uapp/midiecho/BUILD.gn b/zircon/system/uapp/midiecho/BUILD.gn
index 2895bee..1b4a2be 100644
--- a/zircon/system/uapp/midiecho/BUILD.gn
+++ b/zircon/system/uapp/midiecho/BUILD.gn
@@ -4,10 +4,11 @@
 
 executable("midiecho") {
   sources = [
-    "midiecho.c",
+    "midiecho.cc",
   ]
   deps = [
-    "$zx/system/fidl/fuchsia-hardware-midi:c",
+    "$zx/system/fidl/fuchsia-hardware-midi:llcpp",
+    "$zx/system/ulib/fbl",
     "$zx/system/ulib/fdio",
     "$zx/system/ulib/zircon",
   ]
diff --git a/zircon/system/uapp/midiecho/midiecho.c b/zircon/system/uapp/midiecho/midiecho.c
deleted file mode 100644
index 74e2622..0000000
--- a/zircon/system/uapp/midiecho/midiecho.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2016 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 <dirent.h>
-#include <fcntl.h>
-#include <fuchsia/hardware/midi/c/fidl.h>
-#include <lib/fdio/unsafe.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <zircon/types.h>
-
-#define DEV_MIDI "/dev/class/midi"
-
-static bool open_devices(int* out_src_fd, int* out_dest_fd) {
-  int src_fd = -1;
-  int dest_fd = -1;
-
-  struct dirent* de;
-  DIR* dir = opendir(DEV_MIDI);
-  if (!dir) {
-    printf("Error opening %s\n", DEV_MIDI);
-    return -1;
-  }
-
-  while ((de = readdir(dir)) != NULL && (src_fd == -1 || dest_fd == -1)) {
-    char devname[128];
-
-    snprintf(devname, sizeof(devname), "%s/%s", DEV_MIDI, de->d_name);
-    int fd = open(devname, O_RDWR);
-    if (fd < 0) {
-      printf("Error opening %s\n", devname);
-      continue;
-    }
-
-    fuchsia_hardware_midi_Info device_info;
-    fdio_t* fdio = fdio_unsafe_fd_to_io(fd);
-    zx_status_t status =
-        fuchsia_hardware_midi_DeviceGetInfo(fdio_unsafe_borrow_channel(fdio), &device_info);
-    fdio_unsafe_release(fdio);
-    if (status != ZX_OK) {
-      printf("fuchsia.hardware.midi.Device/GetInfo failed for %s\n", devname);
-      close(fd);
-      continue;
-    }
-    if (device_info.is_source) {
-      if (src_fd == -1) {
-        src_fd = fd;
-      } else {
-        close(fd);
-      }
-    } else if (device_info.is_sink) {
-      if (dest_fd == -1) {
-        dest_fd = fd;
-      } else {
-        close(fd);
-      }
-    } else {
-      close(fd);
-    }
-  }
-
-  closedir(dir);
-  if (src_fd == -1) {
-    close(dest_fd);
-    return false;
-  }
-  if (dest_fd == -1) {
-    close(src_fd);
-    return false;
-  }
-
-  *out_src_fd = src_fd;
-  *out_dest_fd = dest_fd;
-  return true;
-}
-
-int main(int argc, char** argv) {
-  int src_fd = -1, dest_fd = -1;
-  if (!open_devices(&src_fd, &dest_fd)) {
-    printf("couldn't find a usable MIDI source and sink\n");
-    return -1;
-  }
-
-  while (1) {
-    uint8_t buffer[3];
-
-    int length = read(src_fd, buffer, sizeof(buffer));
-    if (length < 0)
-      break;
-    printf("MIDI event:");
-    for (int i = 0; i < length; i++) {
-      printf(" %02X", buffer[i]);
-    }
-    printf("\n");
-    if (write(dest_fd, buffer, length) < 0)
-      break;
-  }
-
-  close(src_fd);
-  close(dest_fd);
-
-  return 0;
-}
diff --git a/zircon/system/uapp/midiecho/midiecho.cc b/zircon/system/uapp/midiecho/midiecho.cc
new file mode 100644
index 0000000..3354f3c
--- /dev/null
+++ b/zircon/system/uapp/midiecho/midiecho.cc
@@ -0,0 +1,124 @@
+// Copyright 2016 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 <dirent.h>
+#include <fcntl.h>
+#include <fuchsia/hardware/midi/llcpp/fidl.h>
+#include <lib/fdio/unsafe.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <zircon/types.h>
+
+#include <fbl/algorithm.h>
+
+#define DEV_MIDI "/dev/class/midi"
+
+namespace midi = llcpp::fuchsia::hardware::midi;
+
+static bool open_devices(int* out_src_fd, int* out_dest_fd) {
+  int src_fd = -1;
+  int dest_fd = -1;
+
+  struct dirent* de;
+  DIR* dir = opendir(DEV_MIDI);
+  if (!dir) {
+    printf("Error opening %s\n", DEV_MIDI);
+    return -1;
+  }
+
+  while ((de = readdir(dir)) != NULL && (src_fd == -1 || dest_fd == -1)) {
+    char devname[128];
+
+    snprintf(devname, sizeof(devname), "%s/%s", DEV_MIDI, de->d_name);
+    int fd = open(devname, O_RDWR);
+    if (fd < 0) {
+      printf("Error opening %s\n", devname);
+      continue;
+    }
+
+    fdio_t* fdio = fdio_unsafe_fd_to_io(fd);
+    midi::Device::SyncClient client(zx::channel(fdio_unsafe_borrow_channel(fdio)));
+
+    auto direction = client.GetDirection();
+    fdio_unsafe_release(fdio);
+    if (direction.status() != ZX_OK) {
+      printf("fuchsia.hardware.midi.Device/GetInfo failed for %s\n", devname);
+      close(fd);
+      continue;
+    }
+    if (direction.value().direction == midi::Direction::SOURCE) {
+      if (src_fd == -1) {
+        src_fd = fd;
+      } else {
+        close(fd);
+      }
+    } else if (direction.value().direction == midi::Direction::SINK) {
+      if (dest_fd == -1) {
+        dest_fd = fd;
+      } else {
+        close(fd);
+      }
+    } else {
+      close(fd);
+    }
+  }
+
+  closedir(dir);
+  if (src_fd == -1) {
+    close(dest_fd);
+    return false;
+  }
+  if (dest_fd == -1) {
+    close(src_fd);
+    return false;
+  }
+
+  *out_src_fd = src_fd;
+  *out_dest_fd = dest_fd;
+  return true;
+}
+
+int main(int argc, char** argv) {
+  int src_fd = -1, dest_fd = -1;
+  if (!open_devices(&src_fd, &dest_fd)) {
+    printf("couldn't find a usable MIDI source and sink\n");
+    return -1;
+  }
+
+  auto* src_fdio = fdio_unsafe_fd_to_io(src_fd);
+  auto* dest_fdio = fdio_unsafe_fd_to_io(dest_fd);
+  /*
+      while (1) {
+          uint8_t request_buffer[fidl::MaxSizeInChannel<midi::Device::ReadRequest>()] = {};
+          uint8_t response_buffer[fidl::MaxSizeInChannel<midi::Device::ReadResponse>()] = {};
+
+          fidl::DecodedMessage<midi::Device::ReadRequest>
+  request(fidl::BytePart::WrapFull(request_buffer)); request.message()->count = 3; auto result =
+  midi::Device::Call::Read(zx::unowned_channel(fdio_unsafe_borrow_channel(src_fdio)),
+  std::move(request), fidl::BytePart::WrapEmpty(response_buffer)); midi::Device::ReadResponse*
+  response = result.Unwrap(); auto read_response = response->result.response();
+
+          auto data = read_response.data.data();
+          auto length = read_response.data.count();
+          if (length < 0) break;
+          printf("MIDI event:");
+          for (size_t i = 0; i < length; i++) {
+              printf(" %02X", data[i]);
+          }
+          printf("\n");
+
+
+  //        if (write(dest_fd, buffer, length) < 0) break;
+      }
+  */
+  fdio_unsafe_release(src_fdio);
+  fdio_unsafe_release(dest_fdio);
+  close(src_fd);
+  close(dest_fd);
+
+  return 0;
+}