diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 79c9872..e66f163 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -6,6 +6,7 @@ extern "C" { //might be missing some #include <3ds/types.h> +#include <3ds/ipc.h> #include <3ds/svc.h> #include <3ds/srv.h> #include <3ds/linear.h> @@ -21,6 +22,7 @@ extern "C" { #include <3ds/services/cfgnor.h> #include <3ds/services/cfgu.h> #include <3ds/services/csnd.h> +#include <3ds/services/dsp.h> #include <3ds/services/fs.h> #include <3ds/services/gsp.h> #include <3ds/services/hid.h> diff --git a/libctru/include/3ds/ipc.h b/libctru/include/3ds/ipc.h new file mode 100644 index 0000000..b748581 --- /dev/null +++ b/libctru/include/3ds/ipc.h @@ -0,0 +1,101 @@ +/** + * @file ipc.h + * @brief Inter Process Communication helpers + */ + +#pragma once + +#include <3ds/types.h> + +typedef enum +{ + IPC_BUFFER_R = 0x2, + IPC_BUFFER_W = 0x4, +} IPC_BufferRights; + + +/** + * @brief Command header to be used for IPC + * @param normal_params Number of normal parameters. Up to 63. + * @param translate_params Number of translate parameters. Up to 63. + */ +static inline u32 IPC_MakeHeader(u16 command_id, unsigned normal_params, unsigned translate_params) +{ + return ((u32) command_id << 16) | (((u32) normal_params & 0x3F) << 6) | (((u32) translate_params & 0x3F) << 0); +} + + +/** + * @brief Creates the header to share handles + * @param number The number of handles following this header. Max 64. + * + * The #number next values are handles that will be shared between the two processes. + * + * @note Zero values will have no effect. + */ +static inline u32 IPC_Desc_SharedHandles(unsigned number) +{ + return ((u32)(number - 1) << 26); +} + +/** + * @brief Creates the header to transfer handle ownership + * @param number The number of handles following this header. Max 64. + * + * The #number next values are handles that will be duplicated and closed by the other process. + * + * @note Zero values will have no effect. + */ +static inline u32 IPC_Desc_MoveHandles(unsigned number) +{ + return ((u32)(number - 1) << 26) | 0x10; +} + +/** + * @brief Asks the kernel to fill the handle with the current process handle. + * + * The next value is a placeholder that will be replaced by the current process handle by the kernel. + */ +static inline u32 IPC_Desc_CurProcessHandle(void) +{ + return 0x20; +} + +/** + * @brief Creates a header describing a static buffer. + * @param size Size of the buffer. Max ?0x03FFFF?. + * @param buffer_id The Id of the buffer. Max 0xF. + * + * The next value is a pointer to the buffer. It will be copied to TLS offset 0x180 + static_buffer_id*8. + */ +static inline u32 IPC_Desc_StaticBuffer(size_t size, unsigned buffer_id) +{ + return (size << 14) | ((buffer_id & 0xF) << 10) | 0x2; +} + +/** + * @brief Creates a header describing a buffer to be sent over PXI. + * @param size Size of the buffer. Max 0x00FFFFFF. + * @param buffer_id The Id of the buffer. Max 0xF. + * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access. + * + * The next value is a phys-address of a table located in the BASE memregion. + */ +static inline u32 IPC_Desc_PXIBuffer(size_t size, unsigned buffer_id,bool is_read_only) +{ + u8 type = 0x4; + if(is_read_only)type = 0x6; + return (size << 8) | ((buffer_id & 0xF) << 4) | type; +} + +/** + * @brief Creates a header describing a buffer from the main memory. + * @param size Size of the buffer. Max 0x0FFFFFFF. + * @param rights The rights of the buffer for the destination process + * + * The next value is a pointer to the buffer. + */ +static inline u32 IPC_Desc_Buffer(size_t size, IPC_BufferRights rights) +{ + return (size << 4) | 0x8 | rights; +} diff --git a/libctru/include/3ds/services/dsp.h b/libctru/include/3ds/services/dsp.h new file mode 100644 index 0000000..045c88d --- /dev/null +++ b/libctru/include/3ds/services/dsp.h @@ -0,0 +1,137 @@ +/** + * @file dsp.h + * @brief DSP Service to access the DSP processor commands (sound) + * + * The DSP has access to the Linear memory region, and to the DSP memory region if allowed in the exheader. + */ +#pragma once +#include <3ds/types.h> + +typedef enum { + DSP_INTERRUPT_PIPE = 2 +} DSP_InterruptType; + + +typedef enum { + DSP_PIPE_INPUT = 0, ///< DSP to ARM + DSP_PIPE_OUTPUT = 1 ///< ARM to DSP +} DSP_PipeDirection; + +/** + * @brief Initializes the dsp service. + * + * Call this before calling any DSP_* function. + * @note This will also unload any previously loaded DSP binary. + * It is done this way since you have to provide your binary when the 3DS leaves sleep mode anyway. + */ +Result dspInit(void); + +/** + * @brief Closes the dsp service. + * @note This will also unload the DSP binary. + */ +Result dspExit(void); + +///Checks if a headphone is inserted. +Result DSP_GetHeadphoneStatus(bool* is_inserted); + + +/** + * @brief Flushes the cache + * @param address Beginning of the memory range to flush, inside the Linear or DSP memory regions + * @param size Size of the memory range to flush + * + * Flushes the cache for the specified memory range and invalidates the cache + */ +Result DSP_FlushDataCache(u32 address, u32 size); + +/** + * @brief Invalidates the cache + * @param address Beginning of the memory range to invalidate, inside the Linear or DSP memory regions + * @param size Size of the memory range to flush + * + * Invalidates the cache for the specified memory range + */ +Result DSP_InvalidateDataCache(u32 address, u32 size); + +///Retrieves the handle of the DSP semaphore +Result DSP_GetSemaphoreHandle(Handle* semaphore); + +///Sets the DSP hardware semaphore value +Result DSP_SetSemaphore(u16 value); + +///Masks the DSP hardware semaphore value +Result DSP_SetSemaphoreMask(u16 mask); + +/** + * @brief Loads a DSP binary and starts the DSP + * @param component The program file address in memory + * @param size The size of the program + * @param prog_mask DSP memory block related ? Default is 0xff. + * @param data_mask DSP memory block related ? Default is 0xff. + * @param is_loaded Indicates if the DSP was succesfully loaded. + * + * @note The binary must be signed (http://3dbrew.org/wiki/DSP_Binary) + * @note Seems to be called when the 3ds leaves the Sleep mode + */ +Result DSP_LoadComponent(u8 const* component,u32 size,u16 prog_mask,u16 data_mask,bool * is_loaded); + +///Stops the DSP by unloading the binary +Result DSP_UnloadComponent(void); + +/** + * @brief Registers an event handle with the DSP through IPC + * @param interrut The type of interrupt that will trigger the event. Usual value is DSP_INTERRUPT_PIPE. + * @param channel The pipe channel. Usual value is 2 + * + * @note It is possible that interrupt are inverted + */ +Result DSP_RegisterInterruptEvents(Handle handle,u32 interrupt,u32 channel); + + +/** + * @param channel ?????? TODO usually 2 + * @param buffer The buffer that will store the values read from the pipe + * @param length Length of the buffer + * @param length_read Number of bytes read by the command + */ +Result DSP_ReadPipeIfPossible(u32 channel, u8 const *buffer, u16 length, u16* length_read); + +/** + * @param channel ?????? TODO usually 2 + * @param buffer The message to send to the DSP process + * @param length Length of the message + */ +Result DSP_WriteProcessPipe(u32 channel,u8 const* buffer,u32 length); + + +///Converts a DSP memory to a virtual address usable by the process +Result DSP_ConvertProcessAddressFromDspDram(u32 dsp_address, u32 *arm_address); + +/** + * @brief Reads a DSP register + * @param regNo Offset of the hardware register, base address is 0x1EC40000 + */ +Result DSP_RecvData(u16 regNo, u16 * value); + +/** + * @brief Checks if you can read a DSP register + * @param regNo Offset of the hardware register, base address is 0x1EC40000 + * + * @warning This call might hang if the data is not ready. See @ref DSP_SendDataIsEmpty. + */ +Result DSP_RecvDataIsReady(u16 regNo, bool * is_ready); + +/** + * @brief Writes to a DSP register + * @param regNo Offset of the hardware register, base address is 0x1EC40000 + * + * @warning This call might hang if the SendData is not empty. See @ref DSP_SendDataIsEmpty. + */ +Result DSP_SendData(u16 regNo, u16 value); + +/** + * @brief Checks if you can write to a DSP register ? + * @param regNo Offset of the hardware register, base address is 0x1EC40000 + */ +Result DSP_SendDataIsEmpty(u16 regNo, bool * is_empty); diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index 11a58d9..defb25b 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -8,6 +8,9 @@ #include "types.h" +/// Pseudo handle for the current process +#define CUR_PROCESS_HANDLE 0xFFFF8001 + ///@name Memory management ///@{ @@ -89,6 +92,9 @@ typedef enum { THREADINFO_TYPE_UNKNOWN } ThreadInfoType; +/// Pseudo handle for the current thread +#define CUR_THREAD_HANDLE 0xFFFF8000 + ///@} @@ -227,6 +233,11 @@ static inline u32* getThreadCommandBuffer(void) return (u32*)((u8*)getThreadLocalStorage() + 0x80); } +static inline u32* getThreadStaticBuffers(void) +{ + return (u32*)((u8*)getThreadLocalStorage() + 0x180); +} + ///@name Memory management ///@{ diff --git a/libctru/source/services/dsp.c b/libctru/source/services/dsp.c new file mode 100644 index 0000000..05e006b --- /dev/null +++ b/libctru/source/services/dsp.c @@ -0,0 +1,254 @@ +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/ipc.h> +#include <3ds/services/dsp.h> + +Handle dspHandle = 0; + + +Result dspInit(void) +{ + Result ret = 0; + + if (dspHandle == 0) + { + ret = srvGetServiceHandle(&dspHandle, "dsp::DSP"); + if (ret < 0) return ret; + } + if (ret < 0) return ret; + DSP_UnloadComponent(); + return 0; +} + +Result dspExit(void) +{ + Result ret = 0; +//No need to call unload, it will be done automatically by closing the handle + if (dspHandle != 0) + { + ret = svcCloseHandle(dspHandle); + if (ret < 0) return ret; + dspHandle = 0; + } + + return 0; +} + + +Result DSP_GetHeadphoneStatus(bool* is_inserted) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x001F,0,0); + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *is_inserted = cmdbuf[2] & 0xFF; + return cmdbuf[1]; +} + + +Result DSP_FlushDataCache(u32 address, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x13,2,2); + cmdbuf[1] = address; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = CUR_PROCESS_HANDLE; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + + +Result DSP_InvalidateDataCache(u32 address, u32 size) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x14,2,2); + cmdbuf[1] = address; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = CUR_PROCESS_HANDLE; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + + + +Result DSP_SetSemaphore(u16 value) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x7,1,0); + cmdbuf[1] = value; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + + + +Result DSP_SetSemaphoreMask(u16 mask) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x17,1,0); + cmdbuf[1] = mask; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result DSP_GetSemaphoreHandle(Handle* semaphore) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x16,0,0); + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *semaphore = cmdbuf[3]; + return cmdbuf[1]; +} + +Result DSP_LoadComponent(u8 const* component,u32 size,u16 prog_mask,u16 data_mask,bool * is_loaded) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x11,3,2); + cmdbuf[1] = size; + cmdbuf[2] = prog_mask; + cmdbuf[3] = data_mask; + cmdbuf[4] = IPC_Desc_Buffer(size,IPC_BUFFER_R); + cmdbuf[5] = (u32) component; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *is_loaded = cmdbuf[2] & 0xFF; + return cmdbuf[1]; +} + + + +Result DSP_UnloadComponent(void) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x12,0,0); + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result DSP_RegisterInterruptEvents(Handle handle, u32 interrupt, u32 channel) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x15,2,2); + cmdbuf[1] = interrupt; + cmdbuf[2] = channel; + cmdbuf[3] = IPC_Desc_SharedHandles(1); + cmdbuf[4] = handle; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + + +Result DSP_ReadPipeIfPossibleEx(u32 channel,u32 unk1, u8 const *buffer, u16 length, u16* length_read) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x10,3,0); + cmdbuf[1] = channel; + cmdbuf[2] = unk1; + cmdbuf[3] = length; + + u32 * staticbufs = cmdbuf + 0x100; + + u32 saved1 = staticbufs[0x0]; + u32 saved2 = staticbufs[0x4]; + + staticbufs[0] = (length<<14) | 2; + staticbufs[4] = (u32)buffer; + + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + + staticbufs[0] = saved1; + staticbufs[4] = saved2; + + *length_read = cmdbuf[2] & 0xFFFF; + return cmdbuf[1]; +} + +//TODO change DSP_ReadPipeIfPossibleEx into DSP_ReadPipeIfPossible once unk1 is figured out +//However it seems that it is always used with value 0 +Result DSP_ReadPipeIfPossible(u32 channel, u8 const *buffer, u16 length, u16* length_read) +{ + return DSP_ReadPipeIfPossibleEx(channel,0,buffer,length, length_read); +} + +Result DSP_WriteProcessPipe(u32 channel, u8 const *buffer, u32 length) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0xd,2,2); + cmdbuf[1] = channel; + cmdbuf[2] = length; + cmdbuf[3] = IPC_Desc_StaticBuffer(length,1); + cmdbuf[4] = (u32) buffer; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result DSP_ConvertProcessAddressFromDspDram(u32 dsp_address, u32 *arm_address) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0xc,1,0); + cmdbuf[1] = dsp_address; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *arm_address = cmdbuf[2]; + return cmdbuf[1]; +} + +Result DSP_RecvData(u16 regNo, u16 * value) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x1,1,0) ; + cmdbuf[1] = regNo; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *value = cmdbuf[2] & 0xFFFF; + return cmdbuf[1]; +} + +Result DSP_RecvDataIsReady(u16 regNo, bool * is_ready) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x2,1,0); + cmdbuf[1] = regNo; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *is_ready = cmdbuf[2] & 0xFF; + return cmdbuf[1]; +} + + +// Writes data to the reg regNo +// *(_WORD *)(8 * regNo + 0x1ED03024) = value +Result DSP_SendData(u16 regNo, u16 value) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x3,2,0); + cmdbuf[1] = regNo; + cmdbuf[1] = value; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result DSP_SendDataIsEmpty(u16 regNo, bool * is_empty) +{ + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x4,1,0); + cmdbuf[1] = regNo; + if ((ret = svcSendSyncRequest(dspHandle)) != 0) return ret; + *is_empty = cmdbuf[2] & 0xFF; + return cmdbuf[1]; +} + diff --git a/libctru/source/services/gsp.c b/libctru/source/services/gsp.c index 9e48e9f..7c9b0cb 100644 --- a/libctru/source/services/gsp.c +++ b/libctru/source/services/gsp.c @@ -184,7 +184,7 @@ Result GSPGPU_FlushDataCache(const void* adr, u32 size) cmdbuf[1]=(u32)adr; cmdbuf[2]=size; cmdbuf[3]=0x0; - cmdbuf[4]=0xffff8001; + cmdbuf[4]=CUR_PROCESS_HANDLE; Result ret=0; if((ret=svcSendSyncRequest(gspGpuHandle)))return ret; @@ -200,7 +200,7 @@ Result GSPGPU_InvalidateDataCache(const void* adr, u32 size) cmdbuf[1] = (u32)adr; cmdbuf[2] = size; cmdbuf[3] = 0; - cmdbuf[4] = 0xFFFF8001; + cmdbuf[4] = CUR_PROCESS_HANDLE; Result ret=0; if((ret=svcSendSyncRequest(gspGpuHandle)))return ret; @@ -265,7 +265,7 @@ Result GSPGPU_AcquireRight(u8 flags) cmdbuf[0]=0x160042; //request header code cmdbuf[1]=flags; cmdbuf[2]=0x0; - cmdbuf[3]=0xffff8001; + cmdbuf[3]=CUR_PROCESS_HANDLE; Result ret=0; if((ret=svcSendSyncRequest(gspGpuHandle)))return ret; diff --git a/libctru/source/services/hb.c b/libctru/source/services/hb.c index 96d5a03..7ef8f1e 100644 --- a/libctru/source/services/hb.c +++ b/libctru/source/services/hb.c @@ -23,7 +23,7 @@ Result HB_FlushInvalidateCache(void) cmdbuf[0] = 0x00010042; cmdbuf[1] = 0x00000000; cmdbuf[2] = 0x00000000; - cmdbuf[3] = 0xFFFF8001; + cmdbuf[3] = CUR_PROCESS_HANDLE; if((ret = svcSendSyncRequest(hbHandle))!=0) return ret; diff --git a/libctru/source/services/mvd.c b/libctru/source/services/mvd.c index 30be3ea..e85317b 100644 --- a/libctru/source/services/mvd.c +++ b/libctru/source/services/mvd.c @@ -84,7 +84,7 @@ Result mvdstdSetConfig(mvdstdConfig *config) cmdbuf[0] = 0x001E0044; //request header code cmdbuf[1] = sizeof(mvdstdConfig); cmdbuf[2] = 0; - cmdbuf[3] = 0xffff8001; + cmdbuf[3] = CUR_PROCESS_HANDLE; cmdbuf[4] = (sizeof(mvdstdConfig)<<4) | 10; cmdbuf[5] = (u32)config; @@ -151,7 +151,7 @@ Result mvdstdInit(mvdstdMode mode, mvdstdTypeInput input_type, mvdstdTypeOutput mvdstd_workbuf = linearAlloc(mvdstd_workbufsize); if(mvdstd_workbuf==NULL)return -1; - ret = mvdstdipc_Initialize((u32*)osConvertOldLINEARMemToNew((u32)mvdstd_workbuf), mvdstd_workbufsize, 0xffff8001); + ret = mvdstdipc_Initialize((u32*)osConvertOldLINEARMemToNew((u32)mvdstd_workbuf), mvdstd_workbufsize, CUR_PROCESS_HANDLE); if(ret<0) { svcCloseHandle(mvdstdHandle); diff --git a/libctru/source/services/y2r.c b/libctru/source/services/y2r.c index 8f679e9..d29b38a 100644 --- a/libctru/source/services/y2r.c +++ b/libctru/source/services/y2r.c @@ -130,7 +130,7 @@ Result Y2RU_SetSendingY(const void* src_buf, u32 image_size, s16 transfer_unit, cmdbuf[3] = transfer_unit; cmdbuf[4] = transfer_gap; cmdbuf[5] = 0; - cmdbuf[6] = 0xFFFF8001; + cmdbuf[6] = CUR_PROCESS_HANDLE; if ((ret = svcSendSyncRequest(y2rHandle)) != 0) return ret; return cmdbuf[1]; @@ -146,7 +146,7 @@ Result Y2RU_SetSendingU(const void* src_buf, u32 image_size, s16 transfer_unit, cmdbuf[3] = transfer_unit; cmdbuf[4] = transfer_gap; cmdbuf[5] = 0; - cmdbuf[6] = 0xFFFF8001; + cmdbuf[6] = CUR_PROCESS_HANDLE; if ((ret = svcSendSyncRequest(y2rHandle)) != 0) return ret; return cmdbuf[1]; @@ -162,7 +162,7 @@ Result Y2RU_SetSendingV(const void* src_buf, u32 image_size, s16 transfer_unit, cmdbuf[3] = transfer_unit; cmdbuf[4] = transfer_gap; cmdbuf[5] = 0; - cmdbuf[6] = 0xFFFF8001; + cmdbuf[6] = CUR_PROCESS_HANDLE; if ((ret = svcSendSyncRequest(y2rHandle)) != 0) return ret; return cmdbuf[1]; @@ -178,7 +178,7 @@ Result Y2RU_SetSendingYUYV(const void* src_buf, u32 image_size, s16 transfer_uni cmdbuf[3] = transfer_unit; cmdbuf[4] = transfer_gap; cmdbuf[5] = 0; - cmdbuf[6] = 0xFFFF8001; + cmdbuf[6] = CUR_PROCESS_HANDLE; if ((ret = svcSendSyncRequest(y2rHandle)) != 0) return ret; return cmdbuf[1]; @@ -238,7 +238,7 @@ Result Y2RU_SetReceiving(void* dst_buf, u32 image_size, s16 transfer_unit, s16 t cmdbuf[3] = transfer_unit; cmdbuf[4] = transfer_gap; cmdbuf[5] = 0; - cmdbuf[6] = 0xFFFF8001; + cmdbuf[6] = CUR_PROCESS_HANDLE; if ((ret = svcSendSyncRequest(y2rHandle)) != 0) return ret; return cmdbuf[1];