i2c: command list format, get boot down to linker errors

This commit is contained in:
Michael Scire 2020-10-31 22:52:43 -07:00
parent 134d7f2d9f
commit 3d423c4e0e
5 changed files with 201 additions and 1 deletions

View File

@ -17,6 +17,7 @@
#pragma once
#include <stratosphere/i2c/i2c_types.hpp>
#include <stratosphere/i2c/i2c_select_device_name.hpp>
#include <stratosphere/i2c/i2c_command_list_formatter.hpp>
#include <stratosphere/i2c/sf/i2c_sf_i_session.hpp>
#include <stratosphere/i2c/sf/i2c_sf_i_manager.hpp>
#include <stratosphere/i2c/server/i2c_server_api.hpp>

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/i2c/i2c_types.hpp>
namespace ams::i2c {
constexpr inline size_t CommandListLengthMax = 0x100;
constexpr inline size_t CommandListReceiveCommandSize = 2;
constexpr inline size_t CommandListSendCommandSize = 2;
constexpr inline size_t CommandListSleepCommandSize = 2;
class CommandListFormatter {
NON_COPYABLE(CommandListFormatter);
NON_MOVEABLE(CommandListFormatter);
private:
size_t current_index;
size_t command_list_length;
void *command_list;
private:
Result IsEnqueueAble(size_t sz) const;
public:
CommandListFormatter(void *p, size_t sz) : current_index(0), command_list_length(sz), command_list(p) {
AMS_ABORT_UNLESS(this->command_list_length <= CommandListLengthMax);
}
~CommandListFormatter() { this->command_list = nullptr; }
size_t GetCurrentLength() const { return this->current_index; }
const void *GetListHead() const { return this->command_list; }
Result EnqueueReceiveCommand(i2c::TransactionOption option, size_t size);
Result EnqueueSendCommand(i2c::TransactionOption option, const void *src, size_t size);
Result EnqueueSleepCommand(int us);
};
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "impl/i2c_command_list_format.hpp"
namespace ams::i2c {
Result CommandListFormatter::IsEnqueueAble(size_t sz) const {
R_UNLESS(this->command_list_length - this->current_index >= sz, ResultCommandListFull());
return ResultSuccess();
}
Result CommandListFormatter::EnqueueReceiveCommand(i2c::TransactionOption option, size_t size) {
/* Check that we can enqueue the command. */
constexpr size_t CommandLength = 2;
R_TRY(this->IsEnqueueAble(CommandLength));
/* Get the command list. */
util::BitPack8 *cmd_list = static_cast<util::BitPack8 *>(this->command_list);
/* Get references to the header. */
auto &header0 = cmd_list[this->current_index++];
auto &header1 = cmd_list[this->current_index++];
/* Set the header. */
header0.Set<impl::CommonCommandFormat::CommandId>(impl::CommandId_Receive);
header0.Set<impl::ReceiveCommandFormat::StopCondition>((option & TransactionOption_StopCondition) != 0);
header0.Set<impl::ReceiveCommandFormat::StartCondition>((option & TransactionOption_StartCondition) != 0);
header1.Set<impl::ReceiveCommandFormat::Size>(size);
return ResultSuccess();
}
Result CommandListFormatter::EnqueueSendCommand(i2c::TransactionOption option, const void *src, size_t size) {
/* Check that we can enqueue the command. */
constexpr size_t CommandLength = 2;
R_TRY(this->IsEnqueueAble(CommandLength + size));
/* Get the command list. */
util::BitPack8 *cmd_list = static_cast<util::BitPack8 *>(this->command_list);
/* Get references to the header. */
auto &header0 = cmd_list[this->current_index++];
auto &header1 = cmd_list[this->current_index++];
/* Set the header. */
header0.Set<impl::CommonCommandFormat::CommandId>(impl::CommandId_Send);
header0.Set<impl::SendCommandFormat::StopCondition>((option & TransactionOption_StopCondition) != 0);
header0.Set<impl::SendCommandFormat::StartCondition>((option & TransactionOption_StartCondition) != 0);
header1.Set<impl::SendCommandFormat::Size>(size);
/* Copy the data we're sending. */
std::memcpy(cmd_list + this->current_index, src, size);
this->current_index += size;
return ResultSuccess();
}
Result CommandListFormatter::EnqueueSleepCommand(int us) {
/* Check that we can enqueue the command. */
constexpr size_t CommandLength = 2;
R_TRY(this->IsEnqueueAble(CommandLength));
/* Get the command list. */
util::BitPack8 *cmd_list = static_cast<util::BitPack8 *>(this->command_list);
/* Get references to the header. */
auto &header0 = cmd_list[this->current_index++];
auto &header1 = cmd_list[this->current_index++];
/* Set the header. */
header0.Set<impl::CommonCommandFormat::CommandId>(impl::CommandId_Extension);
header0.Set<impl::CommonCommandFormat::SubCommandId>(impl::SubCommandId_Sleep);
header1.Set<impl::SleepCommandFormat::MicroSeconds>(us);
return ResultSuccess();
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2020 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::i2c::impl {
enum CommandId {
CommandId_Send = 0,
CommandId_Receive = 1,
CommandId_Extension = 2,
CommandId_Count = 3,
};
enum SubCommandId {
SubCommandId_Sleep = 0,
};
struct CommonCommandFormat {
using CommandId = util::BitPack8::Field<0, 2>;
using SubCommandId = util::BitPack8::Field<2, 6>;
};
struct ReceiveCommandFormat {
using StartCondition = util::BitPack8::Field<6, 1, bool>;
using StopCondition = util::BitPack8::Field<7, 1, bool>;
using Size = util::BitPack8::Field<0, 8>;
};
struct SendCommandFormat {
using StartCondition = util::BitPack8::Field<6, 1, bool>;
using StopCondition = util::BitPack8::Field<7, 1, bool>;
using Size = util::BitPack8::Field<0, 8>;
};
struct SleepCommandFormat {
using MicroSeconds = util::BitPack8::Field<0, 8>;
};
}

View File

@ -23,7 +23,7 @@ namespace ams::i2c {
R_DEFINE_ERROR_RESULT(NoAck, 1);
R_DEFINE_ERROR_RESULT(BusBusy, 2);
R_DEFINE_ERROR_RESULT(FullCommandList, 3);
R_DEFINE_ERROR_RESULT(CommandListFull, 3);
R_DEFINE_ERROR_RESULT(UnknownDevice, 5);