mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-23 13:04:50 +00:00
haze: add GetObjectPropsSupported, GetObjectPropDesc, GetObjectPropValue
This commit is contained in:
parent
0ba4cc2004
commit
409399d690
7 changed files with 444 additions and 58 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue