mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
tma: First pass at tio file read/write
This commit is contained in:
parent
efcce68a56
commit
600ad660a6
16 changed files with 600 additions and 15 deletions
|
@ -84,8 +84,8 @@ class DebugMonitorService final : public IServiceObject {
|
|||
|
||||
Result TargetIO_FileOpen(OutBuffer<u64> out_hnd, InBuffer<char> path, int open_mode, u32 create_mode);
|
||||
Result TargetIO_FileClose(InBuffer<u64> hnd);
|
||||
Result TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8> out_data, Out<u32> out_read, u64 offset);
|
||||
Result TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8> data, Out<u32> out_written, u64 offset);
|
||||
Result TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8, BufferType_Type1> out_data, Out<u32> out_read, u64 offset);
|
||||
Result TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8, BufferType_Type1> data, Out<u32> out_written, u64 offset);
|
||||
Result TargetIO_FileSetAttributes(InBuffer<char> path, InBuffer<u8> attributes);
|
||||
Result TargetIO_FileGetInformation(InBuffer<char> path, OutBuffer<u64> out_info, Out<int> is_directory);
|
||||
Result TargetIO_FileSetTime(InBuffer<char> path, u64 create, u64 access, u64 modify);
|
||||
|
|
|
@ -157,7 +157,7 @@ Result DebugMonitorService::TargetIO_FileClose(InBuffer<u64> hnd) {
|
|||
return CloseFileByHandle(hnd[0]);
|
||||
}
|
||||
|
||||
Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8> out_data, Out<u32> out_read, u64 offset) {
|
||||
Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8, BufferType_Type1> out_data, Out<u32> out_read, u64 offset) {
|
||||
if (hnd.num_elements != 1) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ Result DebugMonitorService::TargetIO_FileRead(InBuffer<u64> hnd, OutBuffer<u8> o
|
|||
return rc;
|
||||
}
|
||||
|
||||
Result DebugMonitorService::TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8> data, Out<u32> out_written, u64 offset) {
|
||||
Result DebugMonitorService::TargetIO_FileWrite(InBuffer<u64> hnd, InBuffer<u8, BufferType_Type1> data, Out<u32> out_written, u64 offset) {
|
||||
if (hnd.num_elements != 1) {
|
||||
return 0xF601;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source source/test source/settings
|
||||
SOURCES := source source/test source/settings source/target_io
|
||||
DATA := data
|
||||
INCLUDES := include ../../common/include
|
||||
EXEFS_SRC := exefs_src
|
||||
|
|
|
@ -20,16 +20,15 @@ def main(argc, argv):
|
|||
print 'Waiting for connection...'
|
||||
c.wait_connected()
|
||||
print 'Connected!'
|
||||
c.intf.send_packet(Packet().set_service(ServiceId.SETTINGS_SERVICE).set_task(0x01000000).set_cmd(0).write_str('platformconfig').write_str('platformtype'))
|
||||
print 'Reading atmosphere/BCT.ini...'
|
||||
c.intf.send_packet(Packet().set_service(ServiceId.TARGETIO_SERVICE).set_task(0x01000000).set_cmd(2).write_str('atmosphere/BCT.ini').write_u64(0x109).write_u64(0))
|
||||
resp = c.intf.read_packet()
|
||||
success = resp.read_u8() != 0
|
||||
print 'Succeeded: %s' % str(success)
|
||||
if success:
|
||||
size = resp.read_u32()
|
||||
value = resp.body[resp.offset:resp.offset+size]
|
||||
print 'Value Size: 0x%x' % size
|
||||
print 'Value: %s' % repr(value)
|
||||
|
||||
res_packet = c.intf.read_packet()
|
||||
read_res, size_read = resp.read_u32(), resp.read_u32()
|
||||
print 'Final Result: 0x%x' % res_packet.read_u32()
|
||||
print 'Size Read: 0x%x' % size_read
|
||||
print 'Data:\n%s' % resp.body[resp.offset:]
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -25,5 +25,6 @@ USB_CONNECT = hash("USBConnect")
|
|||
USB_DISCONNECT = hash("USBDisconnect")
|
||||
|
||||
ATMOSPHERE_TEST_SERVICE = hash("AtmosphereTestService")
|
||||
SETTINGS_SERVICE = hash ("SettingsService")
|
||||
SETTINGS_SERVICE = hash("SettingsService")
|
||||
TARGETIO_SERVICE = hash("TIOService")
|
||||
|
188
stratosphere/tma/source/dmnt.c
Normal file
188
stratosphere/tma/source/dmnt.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <switch.h>
|
||||
#include "dmnt.h"
|
||||
|
||||
static Service g_dmntSrv;
|
||||
static u64 g_refCnt;
|
||||
|
||||
Result dmntInitialize(void) {
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_dmntSrv))
|
||||
return 0;
|
||||
|
||||
return smGetService(&g_dmntSrv, "dmnt:-");
|
||||
}
|
||||
|
||||
void dmntExit(void) {
|
||||
if (atomicDecrement64(&g_refCnt) == 0)
|
||||
serviceClose(&g_dmntSrv);
|
||||
}
|
||||
|
||||
Result dmntTargetIOFileOpen(DmntFile *out, const char *path, int flags, DmntTIOCreateOption create_option) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, path, FS_MAX_PATH, BufferType_Normal);
|
||||
ipcAddRecvBuffer(&c, out, sizeof(*out), BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
int flags;
|
||||
u32 create_option;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 29;
|
||||
raw->flags = flags;
|
||||
raw->create_option = create_option;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntTargetIOFileClose(DmntFile *f) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, f, sizeof(*f), BufferType_Normal);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 30;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntTargetIOFileRead(DmntFile *f, u64 off, void* buf, size_t len, size_t *out_read) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, f, sizeof(*f), BufferType_Normal);
|
||||
ipcAddRecvBuffer(&c, buf, len, BufferType_Type1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 offset;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 31;
|
||||
raw->offset = off;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out_read;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_read) {
|
||||
*out_read = resp->out_read;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result dmntTargetIOFileWrite(DmntFile *f, u64 off, const void* buf, size_t len, size_t *out_written) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddSendBuffer(&c, f, sizeof(*f), BufferType_Normal);
|
||||
ipcAddSendBuffer(&c, buf, len, BufferType_Type1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 offset;
|
||||
} *raw;
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 32;
|
||||
raw->offset = off;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_dmntSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out_written;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_written) {
|
||||
*out_written = resp->out_written;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
46
stratosphere/tma/source/dmnt.h
Normal file
46
stratosphere/tma/source/dmnt.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <switch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
u64 handle;
|
||||
} DmntFile;
|
||||
|
||||
typedef enum {
|
||||
DmntTIOCreateOption_CreateNew = 1,
|
||||
DmntTIOCreateOption_CreateAlways = 2,
|
||||
DmntTIOCreateOption_OpenExisting = 3,
|
||||
DmntTIOCreateOption_OpenAlways = 4,
|
||||
DmntTIOCreateOption_ResetSize = 5,
|
||||
} DmntTIOCreateOption;
|
||||
|
||||
Result dmntInitialize(void);
|
||||
void dmntExit(void);
|
||||
|
||||
Result dmntTargetIOFileOpen(DmntFile *out, const char *path, int flags, DmntTIOCreateOption create_option);
|
||||
Result dmntTargetIOFileClose(DmntFile *f);
|
||||
Result dmntTargetIOFileRead(DmntFile *f, u64 off, void* buf, size_t len, size_t* out_read);
|
||||
Result dmntTargetIOFileWrite(DmntFile *f, u64 off, const void* buf, size_t len, size_t* out_written);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
47
stratosphere/tma/source/target_io/tio_service.cpp
Normal file
47
stratosphere/tma/source/target_io/tio_service.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "tio_service.hpp"
|
||||
#include "tio_task.hpp"
|
||||
|
||||
TmaTask *TIOService::NewTask(TmaPacket *packet) {
|
||||
TmaTask *new_task = nullptr;
|
||||
switch (packet->GetCommand()) {
|
||||
case TIOServiceCmd_FileRead:
|
||||
{
|
||||
new_task = new TIOFileReadTask(this->manager);
|
||||
}
|
||||
break;
|
||||
case TIOServiceCmd_FileWrite:
|
||||
{
|
||||
new_task = new TIOFileWriteTask(this->manager);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
new_task = nullptr;
|
||||
break;
|
||||
}
|
||||
if (new_task != nullptr) {
|
||||
new_task->SetServiceId(this->GetServiceId());
|
||||
new_task->SetTaskId(packet->GetTaskId());
|
||||
new_task->OnStart(packet);
|
||||
}
|
||||
|
||||
return new_task;
|
||||
}
|
35
stratosphere/tma/source/target_io/tio_service.hpp
Normal file
35
stratosphere/tma/source/target_io/tio_service.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "../tma_conn_service_ids.hpp"
|
||||
#include "../tma_service.hpp"
|
||||
|
||||
enum TIOServiceCmd : u32 {
|
||||
TIOServiceCmd_FileRead = 2,
|
||||
TIOServiceCmd_FileWrite = 3,
|
||||
};
|
||||
|
||||
class TIOService : public TmaService {
|
||||
public:
|
||||
TIOService(TmaServiceManager *m) : TmaService(m, "TIOService") { }
|
||||
virtual ~TIOService() { }
|
||||
|
||||
virtual TmaTask *NewTask(TmaPacket *packet) override;
|
||||
};
|
152
stratosphere/tma/source/target_io/tio_task.cpp
Normal file
152
stratosphere/tma/source/target_io/tio_task.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "tio_task.hpp"
|
||||
|
||||
|
||||
void TIOFileReadTask::OnStart(TmaPacket *packet) {
|
||||
char path[FS_MAX_PATH];
|
||||
|
||||
packet->ReadString(path, sizeof(path), nullptr);
|
||||
packet->Read<u64>(this->size_remaining);
|
||||
packet->Read<u64>(this->cur_offset);
|
||||
|
||||
if (strlen(path) == 0) {
|
||||
this->SendResult(0x202);
|
||||
return;
|
||||
}
|
||||
|
||||
Result rc = dmntTargetIOFileOpen(&this->handle, path, FS_OPEN_READ, DmntTIOCreateOption_OpenExisting);
|
||||
if (R_FAILED(rc)) {
|
||||
this->SendResult(rc);
|
||||
return;
|
||||
} else {
|
||||
auto packet = this->AllocateSendPacket();
|
||||
rc = this->ProcessPacket(packet);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
this->manager->SendPacket(packet);
|
||||
if (this->size_remaining) {
|
||||
this->SetNeedsPackets(true);
|
||||
} else {
|
||||
this->SendResult(rc);
|
||||
}
|
||||
} else {
|
||||
this->manager->FreePacket(packet);
|
||||
this->SendResult(rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TIOFileReadTask::OnSendPacket(TmaPacket *packet) {
|
||||
Result rc = this->ProcessPacket(packet);
|
||||
|
||||
if (this->size_remaining == 0 || R_FAILED(rc)) {
|
||||
this->SendResult(rc);
|
||||
}
|
||||
}
|
||||
|
||||
void TIOFileReadTask::SendResult(Result rc) {
|
||||
dmntTargetIOFileClose(&this->handle);
|
||||
this->SetNeedsPackets(false);
|
||||
|
||||
auto packet = this->AllocateSendPacket();
|
||||
packet->Write<Result>(rc);
|
||||
this->manager->SendPacket(packet);
|
||||
Complete();
|
||||
}
|
||||
|
||||
Result TIOFileReadTask::ProcessPacket(TmaPacket *packet) {
|
||||
Result rc = 0x196002;
|
||||
|
||||
size_t cur_read = static_cast<u32>((this->size_remaining > MaxDataSize) ? MaxDataSize : this->size_remaining);
|
||||
|
||||
u8 *buf = new u8[cur_read];
|
||||
if (buf != nullptr) {
|
||||
size_t actual_read = 0;
|
||||
rc = dmntTargetIOFileRead(&this->handle, this->cur_offset, buf, cur_read, &actual_read);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
packet->Write<Result>(rc);
|
||||
packet->Write<u32>(actual_read);
|
||||
packet->Write(buf, actual_read);
|
||||
this->cur_offset += actual_read;
|
||||
this->size_remaining -= actual_read;
|
||||
}
|
||||
|
||||
delete buf;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void TIOFileWriteTask::OnStart(TmaPacket *packet) {
|
||||
char path[FS_MAX_PATH];
|
||||
|
||||
packet->ReadString(path, sizeof(path), nullptr);
|
||||
packet->Read<u64>(this->size_remaining);
|
||||
packet->Read<u64>(this->cur_offset);
|
||||
|
||||
if (strlen(path) == 0) {
|
||||
this->SendResult(0x202);
|
||||
return;
|
||||
}
|
||||
|
||||
Result rc = dmntTargetIOFileOpen(&this->handle, path, FS_OPEN_READ, DmntTIOCreateOption_OpenExisting);
|
||||
if (R_FAILED(rc)) {
|
||||
this->SendResult(rc);
|
||||
}
|
||||
}
|
||||
|
||||
void TIOFileWriteTask::OnReceivePacket(TmaPacket *packet) {
|
||||
Result rc = this->ProcessPacket(packet);
|
||||
|
||||
if (this->size_remaining == 0 || R_FAILED(rc)) {
|
||||
this->SendResult(rc);
|
||||
}
|
||||
}
|
||||
|
||||
void TIOFileWriteTask::SendResult(Result rc) {
|
||||
dmntTargetIOFileClose(&this->handle);
|
||||
|
||||
auto packet = this->AllocateSendPacket();
|
||||
packet->Write<Result>(rc);
|
||||
this->manager->SendPacket(packet);
|
||||
Complete();
|
||||
}
|
||||
|
||||
Result TIOFileWriteTask::ProcessPacket(TmaPacket *packet) {
|
||||
Result rc = 0x196002;
|
||||
|
||||
/* Note: N does not bounds check this. We do. */
|
||||
u32 cur_write = 0;
|
||||
packet->Read<u32>(cur_write);
|
||||
|
||||
size_t actual_written = 0;
|
||||
if (cur_write < MaxDataSize) {
|
||||
if (cur_write > this->size_remaining) {
|
||||
cur_write = this->size_remaining;
|
||||
}
|
||||
rc = dmntTargetIOFileWrite(&this->handle, this->cur_offset, packet->GetCurrentBodyPtr(), cur_write, &actual_written);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
this->size_remaining -= actual_written;
|
||||
this->cur_offset += actual_written;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
85
stratosphere/tma/source/target_io/tio_task.hpp
Normal file
85
stratosphere/tma/source/target_io/tio_task.hpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "../tma_task.hpp"
|
||||
#include "../tma_service_manager.hpp"
|
||||
#include "../dmnt.h"
|
||||
|
||||
class TIOTask : public TmaTask {
|
||||
public:
|
||||
TIOTask(TmaServiceManager *m) : TmaTask(m) { }
|
||||
virtual ~TIOTask() { }
|
||||
|
||||
virtual void SendResult(Result rc) {
|
||||
TmaPacket *packet = this->AllocateSendPacket();
|
||||
packet->Write<Result>(rc);
|
||||
this->manager->SendPacket(packet);
|
||||
this->Complete();
|
||||
}
|
||||
|
||||
virtual void OnStart(TmaPacket *packet) = 0;
|
||||
|
||||
virtual void OnReceivePacket(TmaPacket *packet) override {
|
||||
this->Complete();
|
||||
}
|
||||
|
||||
virtual void OnSendPacket(TmaPacket *packet) override {
|
||||
this->Complete();
|
||||
}
|
||||
};
|
||||
|
||||
class TIOFileReadTask : public TIOTask {
|
||||
private:
|
||||
static constexpr size_t HeaderSize = sizeof(Result) + sizeof(u32);
|
||||
static constexpr size_t MaxDataSize = TmaPacket::MaxBodySize - HeaderSize;
|
||||
private:
|
||||
DmntFile handle = {0};
|
||||
u64 size_remaining = 0;
|
||||
u64 cur_offset = 0;
|
||||
public:
|
||||
TIOFileReadTask(TmaServiceManager *m) : TIOTask(m) { }
|
||||
virtual ~TIOFileReadTask() { }
|
||||
|
||||
virtual void OnStart(TmaPacket *packet) override;
|
||||
virtual void OnSendPacket(TmaPacket *packet) override;
|
||||
virtual void SendResult(Result rc) override;
|
||||
|
||||
Result ProcessPacket(TmaPacket *packet);
|
||||
};
|
||||
|
||||
class TIOFileWriteTask : public TIOTask {
|
||||
private:
|
||||
static constexpr size_t HeaderSize = sizeof(u32);
|
||||
static constexpr size_t MaxDataSize = TmaPacket::MaxBodySize - HeaderSize;
|
||||
private:
|
||||
DmntFile handle = {0};
|
||||
u64 size_remaining = 0;
|
||||
u64 cur_offset = 0;
|
||||
public:
|
||||
TIOFileWriteTask(TmaServiceManager *m) : TIOTask(m) { }
|
||||
virtual ~TIOFileWriteTask() { }
|
||||
|
||||
virtual void OnStart(TmaPacket *packet) override;
|
||||
virtual void OnReceivePacket(TmaPacket *packet) override;
|
||||
virtual void SendResult(Result rc) override;
|
||||
|
||||
Result ProcessPacket(TmaPacket *packet);
|
||||
};
|
||||
|
|
@ -166,6 +166,10 @@ class TmaPacket {
|
|||
return GetHeader()->version;
|
||||
}
|
||||
|
||||
u8 *GetCurrentBodyPtr() {
|
||||
return GetBody(this->offset);
|
||||
}
|
||||
|
||||
void ClearOffset() {
|
||||
this->offset = 0;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "tma_target.hpp"
|
||||
|
||||
#include "dmnt.h"
|
||||
|
||||
extern "C" {
|
||||
extern u32 __start__;
|
||||
|
||||
|
@ -70,11 +72,17 @@ void __appInit(void) {
|
|||
fatalSimple(rc);
|
||||
}
|
||||
|
||||
rc = dmntInitialize();
|
||||
if (R_FAILED(rc)) {
|
||||
fatalSimple(rc);
|
||||
}
|
||||
|
||||
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
||||
}
|
||||
|
||||
void __appExit(void) {
|
||||
/* Cleanup services. */
|
||||
dmntExit();
|
||||
setsysExit();
|
||||
pscExit();
|
||||
smExit();
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "test/atmosphere_test_service.hpp"
|
||||
#include "settings/settings_service.hpp"
|
||||
#include "target_io/tio_service.hpp"
|
||||
|
||||
struct TmaTargetConfig {
|
||||
char configuration_id1[0x80];
|
||||
|
@ -210,6 +211,7 @@ void TmaTarget::Initialize() {
|
|||
/* TODO: Make this better. */
|
||||
g_service_manager->AddService(new AtmosphereTestService(g_service_manager));
|
||||
g_service_manager->AddService(new SettingsService(g_service_manager));
|
||||
g_service_manager->AddService(new TIOService(g_service_manager));
|
||||
|
||||
RefreshTargetConfig();
|
||||
|
||||
|
|
|
@ -24,6 +24,21 @@ void TmaTask::SetNeedsPackets(bool n) {
|
|||
this->manager->Tick();
|
||||
}
|
||||
|
||||
TmaPacket *TmaTask::AllocateSendPacket(bool continuation) {
|
||||
auto packet = this->manager->AllocateSendPacket();
|
||||
packet->SetServiceId(this->service_id);
|
||||
packet->SetTaskId(this->task_id);
|
||||
packet->SetCommand(this->command);
|
||||
packet->SetContinuation(continuation);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
void TmaTask::FreePacket(TmaPacket *packet) {
|
||||
this->manager->FreePacket(packet);
|
||||
}
|
||||
|
||||
void TmaTask::Complete() {
|
||||
SetNeedsPackets(false);
|
||||
this->state = TmaTaskState::Complete;
|
||||
|
|
|
@ -68,6 +68,9 @@ class TmaTask {
|
|||
void Signal() { this->signal.Signal(); }
|
||||
void ResetSignal() { this->signal.Reset(); }
|
||||
|
||||
TmaPacket *AllocateSendPacket(bool continuation = true);
|
||||
void FreePacket(TmaPacket *packet);
|
||||
|
||||
void Complete();
|
||||
void Cancel();
|
||||
|
||||
|
|
Loading…
Reference in a new issue