| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "spi-child.h" |
| |
| #include <ddktl/fidl.h> |
| #include <fbl/vector.h> |
| |
| #include "spi.h" |
| |
| namespace spi { |
| |
| namespace sharedmemory = fuchsia_hardware_sharedmemory; |
| |
| void SpiChild::TransmitVector(::fidl::VectorView<uint8_t> data, |
| TransmitVectorCompleter::Sync& completer) { |
| size_t rx_actual; |
| zx_status_t status = spi_.Exchange(cs_, data.data(), data.count(), nullptr, 0, &rx_actual); |
| if (status == ZX_OK) { |
| completer.Reply(ZX_OK); |
| } else { |
| completer.Reply(status); |
| } |
| } |
| |
| void SpiChild::ReceiveVector(uint32_t size, ReceiveVectorCompleter::Sync& completer) { |
| fbl::Vector<uint8_t> rxdata; |
| rxdata.reserve(size); |
| size_t rx_actual; |
| zx_status_t status = spi_.Exchange(cs_, nullptr, 0, rxdata.begin(), size, &rx_actual); |
| if (status == ZX_OK && rx_actual == size) { |
| auto rx_vector = fidl::VectorView<uint8_t>::FromExternal(rxdata.data(), size); |
| completer.Reply(ZX_OK, std::move(rx_vector)); |
| } else { |
| completer.Reply(status == ZX_OK ? ZX_ERR_INTERNAL : status, fidl::VectorView<uint8_t>()); |
| } |
| } |
| |
| void SpiChild::ExchangeVector(::fidl::VectorView<uint8_t> txdata, |
| ExchangeVectorCompleter::Sync& completer) { |
| fbl::Vector<uint8_t> rxdata; |
| const size_t size = txdata.count(); |
| rxdata.reserve(size); |
| size_t rx_actual; |
| zx_status_t status = spi_.Exchange(cs_, txdata.data(), size, rxdata.begin(), size, &rx_actual); |
| if (status == ZX_OK && rx_actual == size) { |
| auto rx_vector = fidl::VectorView<uint8_t>::FromExternal(rxdata.data(), size); |
| completer.Reply(ZX_OK, std::move(rx_vector)); |
| } else { |
| completer.Reply(status == ZX_OK ? ZX_ERR_INTERNAL : status, fidl::VectorView<uint8_t>()); |
| } |
| } |
| |
| void SpiChild::RegisterVmo(uint32_t vmo_id, fuchsia_mem::wire::Range vmo, |
| sharedmemory::wire::SharedVmoRight rights, |
| RegisterVmoCompleter::Sync& completer) { |
| sharedmemory::wire::SharedVmoRegister_RegisterVmo_Result result; |
| sharedmemory::wire::SharedVmoRegister_RegisterVmo_Response response = {}; |
| zx_status_t status = spi_.RegisterVmo(cs_, vmo_id, std::move(vmo.vmo), vmo.offset, vmo.size, |
| static_cast<uint32_t>(rights)); |
| if (status == ZX_OK) { |
| result.set_response( |
| fidl::ObjectView<sharedmemory::wire::SharedVmoRegister_RegisterVmo_Response>::FromExternal( |
| &response)); |
| } else { |
| result.set_err(fidl::ObjectView<zx_status_t>::FromExternal(&status)); |
| } |
| completer.Reply(std::move(result)); |
| } |
| |
| void SpiChild::UnregisterVmo(uint32_t vmo_id, UnregisterVmoCompleter::Sync& completer) { |
| sharedmemory::wire::SharedVmoRegister_UnregisterVmo_Result result; |
| sharedmemory::wire::SharedVmoRegister_UnregisterVmo_Response response = {}; |
| zx_status_t status = spi_.UnregisterVmo(cs_, vmo_id, &response.vmo); |
| if (status == ZX_OK) { |
| result.set_response( |
| fidl::ObjectView< |
| sharedmemory::wire::SharedVmoRegister_UnregisterVmo_Response>::FromExternal(&response)); |
| } else { |
| result.set_err(fidl::ObjectView<zx_status_t>::FromExternal(&status)); |
| } |
| completer.Reply(std::move(result)); |
| } |
| |
| void SpiChild::Transmit(sharedmemory::wire::SharedVmoBuffer buffer, |
| TransmitCompleter::Sync& completer) { |
| sharedmemory::wire::SharedVmoIo_Transmit_Result result; |
| sharedmemory::wire::SharedVmoIo_Transmit_Response response = {}; |
| zx_status_t status = spi_.TransmitVmo(cs_, buffer.vmo_id, buffer.offset, buffer.size); |
| if (status == ZX_OK) { |
| result.set_response( |
| fidl::ObjectView<sharedmemory::wire::SharedVmoIo_Transmit_Response>::FromExternal( |
| &response)); |
| } else { |
| result.set_err(fidl::ObjectView<zx_status_t>::FromExternal(&status)); |
| } |
| completer.Reply(std::move(result)); |
| } |
| |
| void SpiChild::Receive(sharedmemory::wire::SharedVmoBuffer buffer, |
| ReceiveCompleter::Sync& completer) { |
| sharedmemory::wire::SharedVmoIo_Receive_Result result; |
| sharedmemory::wire::SharedVmoIo_Receive_Response response = {}; |
| zx_status_t status = spi_.ReceiveVmo(cs_, buffer.vmo_id, buffer.offset, buffer.size); |
| if (status == ZX_OK) { |
| result.set_response( |
| fidl::ObjectView<sharedmemory::wire::SharedVmoIo_Receive_Response>::FromExternal( |
| &response)); |
| } else { |
| result.set_err(fidl::ObjectView<zx_status_t>::FromExternal(&status)); |
| } |
| completer.Reply(std::move(result)); |
| } |
| |
| void SpiChild::Exchange(sharedmemory::wire::SharedVmoBuffer tx_buffer, |
| sharedmemory::wire::SharedVmoBuffer rx_buffer, |
| ExchangeCompleter::Sync& completer) { |
| sharedmemory::wire::SharedVmoIo_Exchange_Result result; |
| sharedmemory::wire::SharedVmoIo_Exchange_Response response = {}; |
| |
| zx_status_t status; |
| if (tx_buffer.size != rx_buffer.size) { |
| status = ZX_ERR_INVALID_ARGS; |
| } else { |
| status = spi_.ExchangeVmo(cs_, tx_buffer.vmo_id, tx_buffer.offset, rx_buffer.vmo_id, |
| rx_buffer.offset, tx_buffer.size); |
| } |
| |
| if (status == ZX_OK) { |
| result.set_response( |
| fidl::ObjectView<sharedmemory::wire::SharedVmoIo_Exchange_Response>::FromExternal( |
| &response)); |
| } else { |
| result.set_err(fidl::ObjectView<zx_status_t>::FromExternal(&status)); |
| } |
| completer.Reply(std::move(result)); |
| } |
| |
| zx_status_t SpiChild::DdkMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn) { |
| DdkTransaction transaction(txn); |
| fidl::WireDispatch<fuchsia_hardware_spi::Device>(this, msg, &transaction); |
| return transaction.Status(); |
| } |
| |
| zx_status_t SpiChild::SpiTransmit(const uint8_t* txdata_list, size_t txdata_count) { |
| size_t actual; |
| spi_.Exchange(cs_, txdata_list, txdata_count, nullptr, 0, &actual); |
| return ZX_OK; |
| } |
| zx_status_t SpiChild::SpiReceive(uint32_t size, uint8_t* out_rxdata_list, size_t rxdata_count, |
| size_t* out_rxdata_actual) { |
| spi_.Exchange(cs_, nullptr, 0, out_rxdata_list, rxdata_count, out_rxdata_actual); |
| return ZX_OK; |
| } |
| |
| zx_status_t SpiChild::SpiExchange(const uint8_t* txdata_list, size_t txdata_count, |
| uint8_t* out_rxdata_list, size_t rxdata_count, |
| size_t* out_rxdata_actual) { |
| spi_.Exchange(cs_, txdata_list, txdata_count, out_rxdata_list, rxdata_count, out_rxdata_actual); |
| return ZX_OK; |
| } |
| |
| void SpiChild::SpiConnectServer(zx::channel server) { |
| spi_parent_.ConnectServer(std::move(server), this); |
| } |
| |
| void SpiChild::DdkUnbind(ddk::UnbindTxn txn) { txn.Reply(); } |
| |
| void SpiChild::DdkRelease() { __UNUSED bool dummy = Release(); } |
| |
| } // namespace spi |