From 453c05cf7c75c30f8db9e9bdcef3270a66debc5e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 2 May 2019 06:36:31 -0700 Subject: [PATCH] boot: implement I2cDriverSession --- .../source/i2c_driver/i2c_bus_accessor.cpp | 13 +++ .../source/i2c_driver/i2c_bus_accessor.hpp | 3 + .../source/i2c_driver/i2c_driver_session.cpp | 108 ++++++++++++++++++ .../source/i2c_driver/i2c_driver_session.hpp | 47 ++++++++ .../boot/source/i2c_driver/i2c_types.hpp | 5 + 5 files changed, 176 insertions(+) create mode 100644 stratosphere/boot/source/i2c_driver/i2c_driver_session.cpp create mode 100644 stratosphere/boot/source/i2c_driver/i2c_driver_session.hpp diff --git a/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.cpp b/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.cpp index d7f32fcab..7c2c9f149 100644 --- a/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.cpp +++ b/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.cpp @@ -129,6 +129,19 @@ bool I2cBusAccessor::GetBusy() const { return false; } +void I2cBusAccessor::OnStartTransaction() const { + /* Nothing actually happens here. */ +} + +void I2cBusAccessor::OnStopTransaction() const { + /* Nothing actually happens here. */ +} + +Result I2cBusAccessor::StartTransaction(DriverCommand command, AddressingMode addressing_mode, u32 slave_address) { + /* Nothing actually happens here... */ + return ResultSuccess; +} + Result I2cBusAccessor::Send(const u8 *data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address) { std::scoped_lock lk(this->register_mutex); const u8 *cur_src = data; diff --git a/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.hpp b/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.hpp index e08f1586c..322c0a457 100644 --- a/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.hpp +++ b/stratosphere/boot/source/i2c_driver/i2c_bus_accessor.hpp @@ -74,6 +74,9 @@ class I2cBusAccessor { size_t GetOpenSessions() const; bool GetBusy() const; + void OnStartTransaction() const; + Result StartTransaction(DriverCommand command, AddressingMode addressing_mode, u32 slave_address); Result Send(const u8 *data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address); Result Receive(u8 *out_data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address); + void OnStopTransaction() const; }; diff --git a/stratosphere/boot/source/i2c_driver/i2c_driver_session.cpp b/stratosphere/boot/source/i2c_driver/i2c_driver_session.cpp new file mode 100644 index 000000000..399f24edc --- /dev/null +++ b/stratosphere/boot/source/i2c_driver/i2c_driver_session.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software{ + +} you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY{ + +} without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "i2c_driver_session.hpp" + +void I2cDriverSession::Open(I2cBus bus, u32 slave_address, AddressingMode addr_mode, SpeedMode speed_mode, I2cBusAccessor *bus_accessor, u32 max_retries, u64 retry_wait_time){ + std::scoped_lock lk(this->bus_accessor_mutex); + if (!this->open) { + this->bus_accessor = bus_accessor; + this->bus = bus; + this->slave_address = slave_address; + this->addressing_mode = addr_mode; + this->max_retries = max_retries; + this->retry_wait_time = retry_wait_time; + this->bus_accessor->Open(this->bus, speed_mode); + this->open = true; + } +} + +void I2cDriverSession::Start(){ + std::scoped_lock lk(this->bus_accessor_mutex); + if (this->open) { + if (this->bus_accessor->GetOpenSessions() == 1) { + this->bus_accessor->DoInitialConfig(); + } + } +} + +void I2cDriverSession::Close(){ + std::scoped_lock lk(this->bus_accessor_mutex); + if (this->open) { + this->bus_accessor->Close(); + this->bus_accessor = nullptr; + } +} + +bool I2cDriverSession::IsOpen() const{ + return this->open; +} + +Result I2cDriverSession::DoTransaction(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, DriverCommand command){ + std::scoped_lock lk(this->bus_accessor_mutex); + Result rc; + + if (this->bus_accessor->GetBusy()) { + return ResultI2cBusBusy; + } + + this->bus_accessor->OnStartTransaction(); + + if (R_SUCCEEDED((rc = this->bus_accessor->StartTransaction(command, this->addressing_mode, this->slave_address)))) { + switch (command) { + case DriverCommand_Send: + rc = this->bus_accessor->Send(reinterpret_cast(src), num_bytes, option, this->addressing_mode, this->slave_address); + break; + case DriverCommand_Receive: + rc = this->bus_accessor->Receive(reinterpret_cast(dst), num_bytes, option, this->addressing_mode, this->slave_address); + break; + default: + std::abort(); + } + } + + this->bus_accessor->OnStopTransaction(); + + return rc; +} + +Result I2cDriverSession::DoTransactionWithRetry(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, DriverCommand command){ + Result rc; + + size_t i = 0; + while (true) { + rc = this->DoTransaction(dst, src, num_bytes, option, command); + if (rc == ResultI2cTimedOut) { + i++; + if (i <= this->max_retries) { + svcSleepThread(this->retry_wait_time); + continue; + } + return ResultI2cBusBusy; + } else if (R_FAILED(rc)) { + return rc; + } + return ResultSuccess; + } + return rc; +} diff --git a/stratosphere/boot/source/i2c_driver/i2c_driver_session.hpp b/stratosphere/boot/source/i2c_driver/i2c_driver_session.hpp new file mode 100644 index 000000000..51ddd9e29 --- /dev/null +++ b/stratosphere/boot/source/i2c_driver/i2c_driver_session.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "i2c_types.hpp" +#include "i2c_bus_accessor.hpp" + +class I2cDriverSession { + private: + HosMutex bus_accessor_mutex; + I2cBusAccessor *bus_accessor = nullptr; + I2cBus bus = I2cBus_I2c1; + u32 slave_address = 0; + AddressingMode addressing_mode = AddressingMode_7Bit; + u32 max_retries = 0; + u64 retry_wait_time = 0; + bool open = false; + public: + I2cDriverSession() { + /* ... */ + } + public: + void Open(I2cBus bus, u32 slave_address, AddressingMode addr_mode, SpeedMode speed_mode, I2cBusAccessor *bus_accessor, u32 max_retries, u64 retry_wait_time); + void Start(); + void Close(); + + bool IsOpen() const; + + Result DoTransaction(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, DriverCommand command); + Result DoTransactionWithRetry(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, DriverCommand command); +}; diff --git a/stratosphere/boot/source/i2c_driver/i2c_types.hpp b/stratosphere/boot/source/i2c_driver/i2c_types.hpp index a162e3404..7401baa57 100644 --- a/stratosphere/boot/source/i2c_driver/i2c_types.hpp +++ b/stratosphere/boot/source/i2c_driver/i2c_types.hpp @@ -38,6 +38,11 @@ enum I2cBus { I2cBus_I2c6 = 5, }; +enum DriverCommand { + DriverCommand_Send = 0, + DriverCommand_Receive = 1, +}; + bool IsI2cDeviceSupported(I2cDevice dev); I2cBus GetI2cDeviceBus(I2cDevice dev); u32 GetI2cDeviceSlaveAddress(I2cDevice dev);