haze: add GetObjectPropsSupported, GetObjectPropDesc, GetObjectPropValue

This commit is contained in:
Liam 2023-04-16 11:17:32 -04:00
parent 0ba4cc2004
commit 409399d690
7 changed files with 444 additions and 58 deletions

View file

@ -28,3 +28,5 @@
const auto _tmp_r_abort_rc = (res_expr); \
HAZE_ASSERT(R_SUCCEEDED(_tmp_r_abort_rc)); \
}
#define HAZE_UNREACHABLE_DEFAULT_CASE() default: HAZE_ASSERT(false)

View file

@ -123,15 +123,15 @@ namespace haze {
PtpResponseCode_NoStreamEnabled = 0x2022,
PtpResponseCode_InvalidDataSet = 0x2023,
PtpResponseCode_MtpUndefined = 0xa800,
PtpResponseCode_MtpInvalid_ObjectPropCode = 0xa801,
PtpResponseCode_MtpInvalid_ObjectProp_Format = 0xa802,
PtpResponseCode_MtpInvalid_ObjectProp_Value = 0xa803,
PtpResponseCode_MtpInvalid_ObjectReference = 0xa804,
PtpResponseCode_MtpInvalid_Dataset = 0xa806,
PtpResponseCode_MtpSpecification_By_Group_Unsupported = 0xa807,
PtpResponseCode_MtpSpecification_By_Depth_Unsupported = 0xa808,
PtpResponseCode_MtpObject_Too_Large = 0xa809,
PtpResponseCode_MtpObjectProp_Not_Supported = 0xa80a,
PtpResponseCode_MtpInvalidObjectPropCode = 0xa801,
PtpResponseCode_MtpInvalidObjectPropFormat = 0xa802,
PtpResponseCode_MtpInvalidObjectPropValue = 0xa803,
PtpResponseCode_MtpInvalidObjectReference = 0xa804,
PtpResponseCode_MtpInvalidDataset = 0xa806,
PtpResponseCode_MtpSpecificationByGroupUnsupported = 0xa807,
PtpResponseCode_MtpSpecificationByDepthUnsupported = 0xa808,
PtpResponseCode_MtpObjectTooLarge = 0xa809,
PtpResponseCode_MtpObjectPropNotSupported = 0xa80a,
};
enum PtpEventCode : u16 {
@ -152,6 +152,225 @@ namespace haze {
PtpEventCode_UnreportedStatus = 0x400e,
};
enum PtpDataTypeCode : u16 {
PtpDataTypeCode_Undefined = 0x0000,
PtpDataTypeCode_S8 = 0x0001,
PtpDataTypeCode_U8 = 0x0002,
PtpDataTypeCode_S16 = 0x0003,
PtpDataTypeCode_U16 = 0x0004,
PtpDataTypeCode_S32 = 0x0005,
PtpDataTypeCode_U32 = 0x0006,
PtpDataTypeCode_S64 = 0x0007,
PtpDataTypeCode_U64 = 0x0008,
PtpDataTypeCode_S128 = 0x0009,
PtpDataTypeCode_U128 = 0x000a,
PtpDataTypeCode_ArrayMask = (1u << 14),
PtpDataTypeCode_S8Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_S8,
PtpDataTypeCode_U8Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_U8,
PtpDataTypeCode_S16Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_S16,
PtpDataTypeCode_U16Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_U16,
PtpDataTypeCode_S32Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_S32,
PtpDataTypeCode_U32Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_U32,
PtpDataTypeCode_S64Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_S64,
PtpDataTypeCode_U64Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_U64,
PtpDataTypeCode_S128Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_S128,
PtpDataTypeCode_U128Array = PtpDataTypeCode_ArrayMask | PtpDataTypeCode_U128,
PtpDataTypeCode_String = 0xffff,
};
enum PtpPropertyGetSetFlag : u8 {
PtpPropertyGetSetFlag_Get = 0x00,
PtpPropertyGetSetFlag_GetSet = 0x01,
};
enum PtpPropertyGroupCode : u32 {
PtpPropertyGroupCode_Default = 0x00000000,
};
enum PtpPropertyFormFlag : u8 {
PtpPropertyFormFlag_None = 0x00,
PtpPropertyFormFlag_Range = 0x01,
PtpPropertyFormFlag_Enumeration = 0x02,
PtpPropertyFormFlag_DateTime = 0x03,
PtpPropertyFormFlag_FixedLengthArray = 0x04,
PtpPropertyFormFlag_RegularExpression = 0x05,
PtpPropertyFormFlag_ByteArray = 0x06,
PtpPropertyFormFlag_LongString = 0xff,
};
enum PtpObjectPropertyCode : u16 {
PtpObjectPropertyCode_StorageId = 0xdc01,
PtpObjectPropertyCode_ObjectFormat = 0xdc02,
PtpObjectPropertyCode_ProtectionStatus = 0xdc03,
PtpObjectPropertyCode_ObjectSize = 0xdc04,
PtpObjectPropertyCode_AssociationType = 0xdc05,
PtpObjectPropertyCode_AssociationDesc = 0xdc06,
PtpObjectPropertyCode_ObjectFileName = 0xdc07,
PtpObjectPropertyCode_DateCreated = 0xdc08,
PtpObjectPropertyCode_DateModified = 0xdc09,
PtpObjectPropertyCode_Keywords = 0xdc0a,
PtpObjectPropertyCode_ParentObject = 0xdc0b,
PtpObjectPropertyCode_AllowedFolderContents = 0xdc0c,
PtpObjectPropertyCode_Hidden = 0xdc0d,
PtpObjectPropertyCode_SystemObject = 0xdc0e,
PtpObjectPropertyCode_PersistantUniqueObjectIdentifier = 0xdc41,
PtpObjectPropertyCode_SyncId = 0xdc42,
PtpObjectPropertyCode_PropertyBag = 0xdc43,
PtpObjectPropertyCode_Name = 0xdc44,
PtpObjectPropertyCode_CreatedBy = 0xdc45,
PtpObjectPropertyCode_Artist = 0xdc46,
PtpObjectPropertyCode_DateAuthored = 0xdc47,
PtpObjectPropertyCode_Description = 0xdc48,
PtpObjectPropertyCode_UrlReference = 0xdc49,
PtpObjectPropertyCode_LanguageLocale = 0xdc4a,
PtpObjectPropertyCode_CopyrightInformation = 0xdc4b,
PtpObjectPropertyCode_Source = 0xdc4c,
PtpObjectPropertyCode_OriginLocation = 0xdc4d,
PtpObjectPropertyCode_DateAdded = 0xdc4e,
PtpObjectPropertyCode_NonConsumable = 0xdc4f,
PtpObjectPropertyCode_CorruptOrUnplayable = 0xdc50,
PtpObjectPropertyCode_ProducerSerialNumber = 0xdc51,
PtpObjectPropertyCode_RepresentativeSampleFormat = 0xdc81,
PtpObjectPropertyCode_RepresentativeSampleSize = 0xdc82,
PtpObjectPropertyCode_RepresentativeSampleHeight = 0xdc83,
PtpObjectPropertyCode_RepresentativeSampleWidth = 0xdc84,
PtpObjectPropertyCode_RepresentativeSampleDuration = 0xdc85,
PtpObjectPropertyCode_RepresentativeSampleData = 0xdc86,
PtpObjectPropertyCode_Width = 0xdc87,
PtpObjectPropertyCode_Height = 0xdc88,
PtpObjectPropertyCode_Duration = 0xdc89,
PtpObjectPropertyCode_Rating = 0xdc8a,
PtpObjectPropertyCode_Track = 0xdc8b,
PtpObjectPropertyCode_Genre = 0xdc8c,
PtpObjectPropertyCode_Credits = 0xdc8d,
PtpObjectPropertyCode_Lyrics = 0xdc8e,
PtpObjectPropertyCode_SubscriptionContentId = 0xdc8f,
PtpObjectPropertyCode_ProducedBy = 0xdc90,
PtpObjectPropertyCode_UseCount = 0xdc91,
PtpObjectPropertyCode_SkipCount = 0xdc92,
PtpObjectPropertyCode_LastAccessed = 0xdc93,
PtpObjectPropertyCode_ParentalRating = 0xdc94,
PtpObjectPropertyCode_MetaGenre = 0xdc95,
PtpObjectPropertyCode_Composer = 0xdc96,
PtpObjectPropertyCode_EffectiveRating = 0xdc97,
PtpObjectPropertyCode_Subtitle = 0xdc98,
PtpObjectPropertyCode_OriginalReleaseDate = 0xdc99,
PtpObjectPropertyCode_AlbumName = 0xdc9a,
PtpObjectPropertyCode_AlbumArtist = 0xdc9b,
PtpObjectPropertyCode_Mood = 0xdc9c,
PtpObjectPropertyCode_DrmStatus = 0xdc9d,
PtpObjectPropertyCode_SubDescription = 0xdc9e,
PtpObjectPropertyCode_IsCropped = 0xdcd1,
PtpObjectPropertyCode_IsColorCorrected = 0xdcd2,
PtpObjectPropertyCode_ImageBitDepth = 0xdcd3,
PtpObjectPropertyCode_Fnumber = 0xdcd4,
PtpObjectPropertyCode_ExposureTime = 0xdcd5,
PtpObjectPropertyCode_ExposureIndex = 0xdcd6,
PtpObjectPropertyCode_DisplayName = 0xdce0,
PtpObjectPropertyCode_BodyText = 0xdce1,
PtpObjectPropertyCode_Subject = 0xdce2,
PtpObjectPropertyCode_Priority = 0xdce3,
PtpObjectPropertyCode_GivenName = 0xdd00,
PtpObjectPropertyCode_MiddleNames = 0xdd01,
PtpObjectPropertyCode_FamilyName = 0xdd02,
PtpObjectPropertyCode_Prefix = 0xdd03,
PtpObjectPropertyCode_Suffix = 0xdd04,
PtpObjectPropertyCode_PhoneticGivenName = 0xdd05,
PtpObjectPropertyCode_PhoneticFamilyName = 0xdd06,
PtpObjectPropertyCode_EmailPrimary = 0xdd07,
PtpObjectPropertyCode_EmailPersonal1 = 0xdd08,
PtpObjectPropertyCode_EmailPersonal2 = 0xdd09,
PtpObjectPropertyCode_EmailBusiness1 = 0xdd0a,
PtpObjectPropertyCode_EmailBusiness2 = 0xdd0b,
PtpObjectPropertyCode_EmailOthers = 0xdd0c,
PtpObjectPropertyCode_PhoneNumberPrimary = 0xdd0d,
PtpObjectPropertyCode_PhoneNumberPersonal = 0xdd0e,
PtpObjectPropertyCode_PhoneNumberPersonal2 = 0xdd0f,
PtpObjectPropertyCode_PhoneNumberBusiness = 0xdd10,
PtpObjectPropertyCode_PhoneNumberBusiness2 = 0xdd11,
PtpObjectPropertyCode_PhoneNumberMobile = 0xdd12,
PtpObjectPropertyCode_PhoneNumberMobile2 = 0xdd13,
PtpObjectPropertyCode_FaxNumberPrimary = 0xdd14,
PtpObjectPropertyCode_FaxNumberPersonal = 0xdd15,
PtpObjectPropertyCode_FaxNumberBusiness = 0xdd16,
PtpObjectPropertyCode_PagerNumber = 0xdd17,
PtpObjectPropertyCode_PhoneNumberOthers = 0xdd18,
PtpObjectPropertyCode_PrimaryWebAddress = 0xdd19,
PtpObjectPropertyCode_PersonalWebAddress = 0xdd1a,
PtpObjectPropertyCode_BusinessWebAddress = 0xdd1b,
PtpObjectPropertyCode_InstantMessengerAddress = 0xdd1c,
PtpObjectPropertyCode_InstantMessengerAddress2 = 0xdd1d,
PtpObjectPropertyCode_InstantMessengerAddress3 = 0xdd1e,
PtpObjectPropertyCode_PostalAddressPersonalFull = 0xdd1f,
PtpObjectPropertyCode_PostalAddressPersonalFullLine1 = 0xdd20,
PtpObjectPropertyCode_PostalAddressPersonalFullLine2 = 0xdd21,
PtpObjectPropertyCode_PostalAddressPersonalFullCity = 0xdd22,
PtpObjectPropertyCode_PostalAddressPersonalFullRegion = 0xdd23,
PtpObjectPropertyCode_PostalAddressPersonalFullPostalCode = 0xdd24,
PtpObjectPropertyCode_PostalAddressPersonalFullCountry = 0xdd25,
PtpObjectPropertyCode_PostalAddressBusinessFull = 0xdd26,
PtpObjectPropertyCode_PostalAddressBusinessLine1 = 0xdd27,
PtpObjectPropertyCode_PostalAddressBusinessLine2 = 0xdd28,
PtpObjectPropertyCode_PostalAddressBusinessCity = 0xdd29,
PtpObjectPropertyCode_PostalAddressBusinessRegion = 0xdd2a,
PtpObjectPropertyCode_PostalAddressBusinessPostalCode = 0xdd2b,
PtpObjectPropertyCode_PostalAddressBusinessCountry = 0xdd2c,
PtpObjectPropertyCode_PostalAddressOtherFull = 0xdd2d,
PtpObjectPropertyCode_PostalAddressOtherLine1 = 0xdd2e,
PtpObjectPropertyCode_PostalAddressOtherLine2 = 0xdd2f,
PtpObjectPropertyCode_PostalAddressOtherCity = 0xdd30,
PtpObjectPropertyCode_PostalAddressOtherRegion = 0xdd31,
PtpObjectPropertyCode_PostalAddressOtherPostalCode = 0xdd32,
PtpObjectPropertyCode_PostalAddressOtherCountry = 0xdd33,
PtpObjectPropertyCode_OrganizationName = 0xdd34,
PtpObjectPropertyCode_PhoneticOrganizationName = 0xdd35,
PtpObjectPropertyCode_Role = 0xdd36,
PtpObjectPropertyCode_Birthdate = 0xdd37,
PtpObjectPropertyCode_MessageTo = 0xdd40,
PtpObjectPropertyCode_MessageCC = 0xdd41,
PtpObjectPropertyCode_MessageBCC = 0xdd42,
PtpObjectPropertyCode_MessageRead = 0xdd43,
PtpObjectPropertyCode_MessageReceivedTime = 0xdd44,
PtpObjectPropertyCode_MessageSender = 0xdd45,
PtpObjectPropertyCode_ActivityBeginTime = 0xdd50,
PtpObjectPropertyCode_ActivityEndTime = 0xdd51,
PtpObjectPropertyCode_ActivityLocation = 0xdd52,
PtpObjectPropertyCode_ActivityRequiredAttendees = 0xdd54,
PtpObjectPropertyCode_ActivityOptionalAttendees = 0xdd55,
PtpObjectPropertyCode_ActivityResources = 0xdd56,
PtpObjectPropertyCode_ActivityAccepted = 0xdd57,
PtpObjectPropertyCode_Owner = 0xdd5d,
PtpObjectPropertyCode_Editor = 0xdd5e,
PtpObjectPropertyCode_Webmaster = 0xdd5f,
PtpObjectPropertyCode_UrlSource = 0xdd60,
PtpObjectPropertyCode_UrlDestination = 0xdd61,
PtpObjectPropertyCode_TimeBookmark = 0xdd62,
PtpObjectPropertyCode_ObjectBookmark = 0xdd63,
PtpObjectPropertyCode_ByteBookmark = 0xdd64,
PtpObjectPropertyCode_LastBuildDate = 0xdd70,
PtpObjectPropertyCode_TimetoLive = 0xdd71,
PtpObjectPropertyCode_MediaGuid = 0xdd72,
PtpObjectPropertyCode_TotalBitRate = 0xde91,
PtpObjectPropertyCode_BitRateType = 0xde92,
PtpObjectPropertyCode_SampleRate = 0xde93,
PtpObjectPropertyCode_NumberOfChannels = 0xde94,
PtpObjectPropertyCode_AudioBitDepth = 0xde95,
PtpObjectPropertyCode_ScanDepth = 0xde97,
PtpObjectPropertyCode_AudioWaveCodec = 0xde99,
PtpObjectPropertyCode_AudioBitRate = 0xde9a,
PtpObjectPropertyCode_VideoFourCcCodec = 0xde9b,
PtpObjectPropertyCode_VideoBitRate = 0xde9c,
PtpObjectPropertyCode_FramesPerThousandSeconds = 0xde9d,
PtpObjectPropertyCode_KeyFrameDistance = 0xde9e,
PtpObjectPropertyCode_BufferSize = 0xde9f,
PtpObjectPropertyCode_EncodingQuality = 0xdea0,
PtpObjectPropertyCode_EncodingProfile = 0xdea1,
PtpObjectPropertyCode_BuyFlag = 0xd901,
};
enum PtpDevicePropertyCode : u16 {
PtpDevicePropertyCode_Undefined = 0x5000,
PtpDevicePropertyCode_BatteryLevel = 0x5001,
@ -264,4 +483,5 @@ namespace haze {
u32 parent_object_id;
u32 object_id;
};
}

View file

@ -119,19 +119,6 @@ namespace haze {
/* Otherwise, do nothing. */
/* ... */
}
template <typename T, typename... Args>
constexpr T *New(Args&&... args) {
T *t = static_cast<T *>(this->Allocate(sizeof(T)));
std::construct_at(t, std::forward<Args>(args)...);
return t;
}
template <typename T>
constexpr void Delete(T *t) {
std::destroy_at(t);
this->Deallocate(t, sizeof(T));
}
};
}

View file

@ -51,7 +51,7 @@ namespace haze {
Result WriteResponse(PtpResponseCode code, Data &&data);
Result WriteResponse(PtpResponseCode code);
/* Operations. */
/* PTP operations. */
Result GetDeviceInfo(PtpDataParser &dp);
Result OpenSession(PtpDataParser &dp);
Result CloseSession(PtpDataParser &dp);
@ -63,6 +63,12 @@ namespace haze {
Result SendObjectInfo(PtpDataParser &dp);
Result SendObject(PtpDataParser &dp);
Result DeleteObject(PtpDataParser &dp);
/* MTP operations. */
Result GetObjectPropsSupported(PtpDataParser &dp);
Result GetObjectPropDesc(PtpDataParser &dp);
Result GetObjectPropValue(PtpDataParser &dp);
Result SetObjectPropValue(PtpDataParser &dp);
};
}

View file

@ -34,6 +34,7 @@ namespace haze {
R_DEFINE_ERROR_RESULT(StorageNotFound, 10);
R_DEFINE_ERROR_RESULT(OperationNotSupported, 11);
R_DEFINE_ERROR_RESULT(UnknownRequestType, 12);
R_DEFINE_ERROR_RESULT(GeneralFailure, 13);
R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 13);
R_DEFINE_ERROR_RESULT(GeneralFailure, 14);
}

View file

@ -49,6 +49,7 @@ namespace haze {
}
Result EventReactor::WaitForImpl(s32 *out_arg_waiter, const Waiter *arg_waiters, s32 num_arg_waiters) {
HAZE_ASSERT(0 <= num_arg_waiters && num_arg_waiters <= svc::ArgumentHandleCountMax);
HAZE_ASSERT(m_num_wait_objects + num_arg_waiters <= svc::ArgumentHandleCountMax);
while (true) {

View file

@ -22,24 +22,24 @@ namespace haze {
namespace {
constexpr UsbCommsInterfaceInfo MtpInterfaceInfo = {
.bInterfaceClass = 0x06,
.bInterfaceClass = 0x06,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01,
};
/* This is a VID:PID recognized by libmtp. */
constexpr u16 SwitchMtpIdVendor = 0x057e;
constexpr u16 SwitchMtpIdVendor = 0x057e;
constexpr u16 SwitchMtpIdProduct = 0x201d;
/* Constants used for MTP GetDeviceInfo response. */
constexpr u16 MtpStandardVersion = 100;
constexpr u32 MtpVendorExtensionId = 6;
constexpr auto MtpVendorExtensionDesc = "microsoft.com: 1.0;";
constexpr u16 MtpStandardVersion = 100;
constexpr u32 MtpVendorExtensionId = 6;
constexpr auto MtpVendorExtensionDesc = "microsoft.com: 1.0;";
constexpr u16 MtpFunctionalModeDefault = 0;
constexpr auto MtpDeviceManufacturer = "Nintendo";
constexpr auto MtpDeviceModel = "Switch";
constexpr auto MtpDeviceVersion = "1.0.0";
constexpr auto MtpDeviceSerialNumber = "SerialNumber";
constexpr auto MtpDeviceManufacturer = "Nintendo";
constexpr auto MtpDeviceModel = "Switch";
constexpr auto MtpDeviceVersion = "1.0.0";
constexpr auto MtpDeviceSerialNumber = "SerialNumber";
enum StorageId : u32 {
StorageId_SdmcFs = 0xffffffffu - 1,
@ -57,17 +57,38 @@ namespace haze {
PtpOperationCode_SendObjectInfo,
PtpOperationCode_SendObject,
PtpOperationCode_DeleteObject,
PtpOperationCode_MtpGetObjectPropsSupported,
PtpOperationCode_MtpGetObjectPropDesc,
PtpOperationCode_MtpGetObjectPropValue,
PtpOperationCode_MtpSetObjectPropValue,
};
constexpr const PtpEventCode SupportedEventCodes[] = { /* ... */};
constexpr const PtpDevicePropertyCode SupportedPropertyCodes[] = { /* ...*/ };
constexpr const PtpObjectFormatCode SupportedCaptureFormats[] = { /* ...*/ };
constexpr const PtpEventCode SupportedEventCodes[] = { /* ... */ };
constexpr const PtpDevicePropertyCode SupportedDeviceProperties[] = { /* ... */ };
constexpr const PtpObjectFormatCode SupportedCaptureFormats[] = { /* ... */ };
constexpr const PtpObjectFormatCode SupportedPlaybackFormats[] = {
PtpObjectFormatCode_Undefined,
PtpObjectFormatCode_Association,
};
constexpr const PtpObjectPropertyCode SupportedObjectProperties[] = {
PtpObjectPropertyCode_StorageId,
PtpObjectPropertyCode_ObjectFormat,
PtpObjectPropertyCode_ObjectSize,
PtpObjectPropertyCode_ObjectFileName,
};
constexpr bool IsSupportedObjectPropertyCode(PtpObjectPropertyCode c) {
for (size_t i = 0; i < util::size(SupportedObjectProperties); i++) {
if (SupportedObjectProperties[i] == c) {
return true;
}
}
return false;
}
constexpr const StorageId SupportedStorageIds[] = {
StorageId_SdmcFs,
};
@ -141,16 +162,16 @@ namespace haze {
constexpr s64 DirectoryReadSize = 32;
constexpr u64 FsBufferSize = haze::UsbBulkPacketBufferSize;
constinit char g_filename_str[PtpStringMaxLength + 1];
constinit char g_capture_date_str[PtpStringMaxLength + 1];
constinit char g_modification_date_str[PtpStringMaxLength + 1];
constinit char g_keywords_str[PtpStringMaxLength + 1];
constinit char g_filename_str[PtpStringMaxLength + 1] = {};
constinit char g_capture_date_str[PtpStringMaxLength + 1] = {};
constinit char g_modification_date_str[PtpStringMaxLength + 1] = {};
constinit char g_keywords_str[PtpStringMaxLength + 1] = {};
constinit FsDirectoryEntry g_dir_entries[DirectoryReadSize] = {};
constinit u8 g_fs_buffer[FsBufferSize] = {};
alignas(4_KB) constinit u8 g_bulk_write_buffer[haze::UsbBulkPacketBufferSize] = {};
alignas(4_KB) constinit u8 g_bulk_read_buffer[haze::UsbBulkPacketBufferSize] = {};
alignas(4_KB) constinit u8 g_bulk_read_buffer[haze::UsbBulkPacketBufferSize] = {};
}
@ -190,7 +211,11 @@ namespace haze {
R_CATCH(haze::ResultObjectNotFound) {
R_TRY(this->WriteResponse(PtpResponseCode_InvalidObjectHandle));
}
R_CATCH(fs::ResultPathNotFound, fs::ResultPathAlreadyExists, fs::ResultTargetLocked, fs::ResultDirectoryNotEmpty, fs::ResultNotEnoughFreeSpaceSdCard) {
R_CATCH(haze::ResultUnknownPropertyCode) {
R_TRY(this->WriteResponse(PtpResponseCode_MtpObjectPropNotSupported));
}
R_CATCH_MODULE(fs) {
/* Errors from fs are typically recoverable. */
R_TRY(this->WriteResponse(PtpResponseCode_GeneralError));
}
R_CATCH_ALL() {
@ -217,18 +242,22 @@ namespace haze {
}
switch (m_request_header.code) {
case PtpOperationCode_GetDeviceInfo: R_RETURN(this->GetDeviceInfo(dp)); break;
case PtpOperationCode_OpenSession: R_RETURN(this->OpenSession(dp)); break;
case PtpOperationCode_CloseSession: R_RETURN(this->CloseSession(dp)); break;
case PtpOperationCode_GetStorageIds: R_RETURN(this->GetStorageIds(dp)); break;
case PtpOperationCode_GetStorageInfo: R_RETURN(this->GetStorageInfo(dp)); break;
case PtpOperationCode_GetObjectHandles: R_RETURN(this->GetObjectHandles(dp)); break;
case PtpOperationCode_GetObjectInfo: R_RETURN(this->GetObjectInfo(dp)); break;
case PtpOperationCode_GetObject: R_RETURN(this->GetObject(dp)); break;
case PtpOperationCode_SendObjectInfo: R_RETURN(this->SendObjectInfo(dp)); break;
case PtpOperationCode_SendObject: R_RETURN(this->SendObject(dp)); break;
case PtpOperationCode_DeleteObject: R_RETURN(this->DeleteObject(dp)); break;
default: R_THROW(haze::ResultOperationNotSupported());
case PtpOperationCode_GetDeviceInfo: R_RETURN(this->GetDeviceInfo(dp)); break;
case PtpOperationCode_OpenSession: R_RETURN(this->OpenSession(dp)); break;
case PtpOperationCode_CloseSession: R_RETURN(this->CloseSession(dp)); break;
case PtpOperationCode_GetStorageIds: R_RETURN(this->GetStorageIds(dp)); break;
case PtpOperationCode_GetStorageInfo: R_RETURN(this->GetStorageInfo(dp)); break;
case PtpOperationCode_GetObjectHandles: R_RETURN(this->GetObjectHandles(dp)); break;
case PtpOperationCode_GetObjectInfo: R_RETURN(this->GetObjectInfo(dp)); break;
case PtpOperationCode_GetObject: R_RETURN(this->GetObject(dp)); break;
case PtpOperationCode_SendObjectInfo: R_RETURN(this->SendObjectInfo(dp)); break;
case PtpOperationCode_SendObject: R_RETURN(this->SendObject(dp)); break;
case PtpOperationCode_DeleteObject: R_RETURN(this->DeleteObject(dp)); break;
case PtpOperationCode_MtpGetObjectPropsSupported: R_RETURN(this->GetObjectPropsSupported(dp)); break;
case PtpOperationCode_MtpGetObjectPropDesc: R_RETURN(this->GetObjectPropDesc(dp)); break;
case PtpOperationCode_MtpGetObjectPropValue: R_RETURN(this->GetObjectPropValue(dp)); break;
case PtpOperationCode_MtpSetObjectPropValue: R_RETURN(this->SetObjectPropValue(dp)); break;
default: R_THROW(haze::ResultOperationNotSupported());
}
}
@ -264,7 +293,7 @@ namespace haze {
R_TRY(db.Add(MtpFunctionalModeDefault));
R_TRY(db.AddArray(SupportedOperationCodes, util::size(SupportedOperationCodes)));
R_TRY(db.AddArray(SupportedEventCodes, util::size(SupportedEventCodes)));
R_TRY(db.AddArray(SupportedPropertyCodes, util::size(SupportedPropertyCodes)));
R_TRY(db.AddArray(SupportedDeviceProperties, util::size(SupportedDeviceProperties)));
R_TRY(db.AddArray(SupportedCaptureFormats, util::size(SupportedCaptureFormats)));
R_TRY(db.AddArray(SupportedPlaybackFormats, util::size(SupportedPlaybackFormats)));
R_TRY(db.AddString(MtpDeviceManufacturer));
@ -329,10 +358,10 @@ namespace haze {
R_TRY(m_fs.GetTotalSpace("/", std::addressof(total_space)));
R_TRY(m_fs.GetFreeSpace("/", std::addressof(free_space)));
storage_info.max_capacity = total_space;
storage_info.free_space_in_bytes = free_space;
storage_info.max_capacity = total_space;
storage_info.free_space_in_bytes = free_space;
storage_info.free_space_in_images = 0;
storage_info.storage_description = "SD Card";
storage_info.storage_description = "SD Card";
}
break;
default:
@ -700,4 +729,144 @@ namespace haze {
/* We succeeded. */
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
}
Result PtpResponder::GetObjectPropsSupported(PtpDataParser &dp) {
R_TRY(dp.Finalize());
PtpDataBuilder db(g_bulk_write_buffer, std::addressof(m_usb_server));
/* Write information about all object properties we can support. */
R_TRY(db.WriteVariableLengthData(m_request_header, [&] {
R_RETURN(db.AddArray(SupportedObjectProperties, util::size(SupportedObjectProperties)));
}));
/* We succeeded. */
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
}
Result PtpResponder::GetObjectPropDesc(PtpDataParser &dp) {
PtpObjectPropertyCode property_code;
u16 object_format;
R_TRY(dp.Read(std::addressof(property_code)));
R_TRY(dp.Read(std::addressof(object_format)));
R_TRY(dp.Finalize());
/* Ensure we have a valid property code before continuing. */
R_UNLESS(IsSupportedObjectPropertyCode(property_code), haze::ResultUnknownPropertyCode());
/* Begin writing information about the property code. */
PtpDataBuilder db(g_bulk_write_buffer, std::addressof(m_usb_server));
R_TRY(db.WriteVariableLengthData(m_request_header, [&] {
R_TRY(db.Add(property_code));
/* Each property code corresponds to a different pattern, which contains the data type, */
/* whether the property can be set for an object, and the default value of the property. */
switch (property_code) {
case PtpObjectPropertyCode_ObjectSize:
{
R_TRY(db.Add(PtpDataTypeCode_U64));
R_TRY(db.Add(PtpPropertyGetSetFlag_Get));
R_TRY(db.Add<u64>(0));
}
break;
case PtpObjectPropertyCode_StorageId:
{
R_TRY(db.Add(PtpDataTypeCode_U32));
R_TRY(db.Add(PtpPropertyGetSetFlag_Get));
R_TRY(db.Add(StorageId_SdmcFs));
}
break;
case PtpObjectPropertyCode_ObjectFormat:
{
R_TRY(db.Add(PtpDataTypeCode_U32));
R_TRY(db.Add(PtpPropertyGetSetFlag_Get));
R_TRY(db.Add(PtpObjectFormatCode_Undefined));
}
break;
case PtpObjectPropertyCode_ObjectFileName:
{
R_TRY(db.Add(PtpDataTypeCode_String));
R_TRY(db.Add(PtpPropertyGetSetFlag_GetSet));
R_TRY(db.AddString(""));
}
break;
HAZE_UNREACHABLE_DEFAULT_CASE();
}
/* Group code is a required part of the response, but doesn't seem to be used for anything. */
R_TRY(db.Add(PtpPropertyGroupCode_Default));
/* We don't use the form flag. */
R_TRY(db.Add(PtpPropertyFormFlag_None));
R_SUCCEED();
}));
/* We succeeded. */
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
}
Result PtpResponder::GetObjectPropValue(PtpDataParser &dp) {
u32 object_id;
PtpObjectPropertyCode property_code;
R_TRY(dp.Read(std::addressof(object_id)));
R_TRY(dp.Read(std::addressof(property_code)));
R_TRY(dp.Finalize());
/* Ensure we have a valid property code before continuing. */
R_UNLESS(IsSupportedObjectPropertyCode(property_code), haze::ResultUnknownPropertyCode());
/* Check if we know about the object. If we don't, it's an error. */
auto * const fileobj = m_object_database.GetObject(object_id);
R_UNLESS(fileobj != nullptr, haze::ResultObjectNotFound());
/* Get the object type. */
FsDirEntryType entry_type;
R_TRY(m_fs.GetEntryType(fileobj->GetName(), std::addressof(entry_type)));
/* Get the object size. */
s64 size = 0;
if (entry_type == FsDirEntryType_File) {
FsFile file;
R_TRY(m_fs.OpenFile(fileobj->GetName(), FsOpenMode_Read, std::addressof(file)));
/* Ensure we maintain a clean state on exit. */
ON_SCOPE_EXIT { m_fs.CloseFile(std::addressof(file)); };
R_TRY(m_fs.GetFileSize(std::addressof(file), std::addressof(size)));
}
/* Begin writing the requested object property. */
PtpDataBuilder db(g_bulk_write_buffer, std::addressof(m_usb_server));
R_TRY(db.WriteVariableLengthData(m_request_header, [&] {
switch (property_code) {
case PtpObjectPropertyCode_ObjectSize:
R_TRY(db.Add<u64>(size));
break;
case PtpObjectPropertyCode_StorageId:
R_TRY(db.Add(StorageId_SdmcFs));
break;
case PtpObjectPropertyCode_ObjectFormat:
R_TRY(db.Add(entry_type == FsDirEntryType_File ? PtpObjectFormatCode_Undefined : PtpObjectFormatCode_Association));
break;
case PtpObjectPropertyCode_ObjectFileName:
R_TRY(db.AddString(std::strrchr(fileobj->GetName(), '/') + 1));
break;
HAZE_UNREACHABLE_DEFAULT_CASE();
}
R_SUCCEED();
}));
/* We succeeded. */
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
}
Result PtpResponder::SetObjectPropValue(PtpDataParser &dp) {
R_THROW(haze::ResultOperationNotSupported());
}
}