140 lines
3.4 KiB
C
140 lines
3.4 KiB
C
|
/*
|
||
|
PXI.c:
|
||
|
PXI I/O functions.
|
||
|
|
||
|
(c) TuxSH, 2016-2017
|
||
|
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||
|
*/
|
||
|
|
||
|
#include "PXI.h"
|
||
|
|
||
|
void PXIReset(void)
|
||
|
{
|
||
|
REG_PXI_SYNC = 0;
|
||
|
REG_PXI_CNT = CNT_CLEAR_SEND_FIFO;
|
||
|
|
||
|
for(u32 i = 0; i < 16; i += 2)
|
||
|
{
|
||
|
REG_PXI_RECV;
|
||
|
REG_PXI_RECV;
|
||
|
}
|
||
|
|
||
|
REG_PXI_CNT = 0;
|
||
|
REG_PXI_CNT = CNT_ENABLE_FIFOs | CNT_ACKNOWLEDGE_FIFO_ERROR | CNT_CLEAR_SEND_FIFO;
|
||
|
}
|
||
|
|
||
|
void PXITriggerSync9IRQ(void)
|
||
|
{
|
||
|
REG_PXI_INTERRUPT_CNT |= SYNC_TRIGGER_SYNC9_IRQ;
|
||
|
}
|
||
|
|
||
|
bool PXIIsSendFIFOFull(void)
|
||
|
{
|
||
|
return (REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS) != 0;
|
||
|
}
|
||
|
|
||
|
void PXISendByte(u8 byte)
|
||
|
{
|
||
|
REG_PXI_BYTE_SENT_TO_REMOTE = byte;
|
||
|
}
|
||
|
|
||
|
void PXISendWord(u32 word)
|
||
|
{
|
||
|
while(REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS);
|
||
|
REG_PXI_SEND = word;
|
||
|
}
|
||
|
|
||
|
void PXISendBuffer(const u32 *buffer, u32 nbWords)
|
||
|
{
|
||
|
for(; nbWords > 0; nbWords--)
|
||
|
{
|
||
|
while(REG_PXI_CNT & CNT_SEND_FIFO_FULL_STATUS);
|
||
|
REG_PXI_SEND = *buffer++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool PXIIsReceiveFIFOEmpty(void)
|
||
|
{
|
||
|
return (REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS) != 0;
|
||
|
}
|
||
|
|
||
|
u8 PXIReceiveByte(void)
|
||
|
{
|
||
|
return REG_PXI_BYTE_RECEIVED_FROM_REMOTE;
|
||
|
}
|
||
|
|
||
|
u32 PXIReceiveWord(void)
|
||
|
{
|
||
|
while(REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS);
|
||
|
return REG_PXI_RECV;
|
||
|
}
|
||
|
|
||
|
void PXIReceiveBuffer(u32 *buffer, u32 nbWords)
|
||
|
{
|
||
|
for(; nbWords > 0; nbWords--)
|
||
|
{
|
||
|
while(REG_PXI_CNT & CNT_RECEIVE_FIFO_EMPTY_STATUS);
|
||
|
*buffer++ = REG_PXI_RECV;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Result bindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt)
|
||
|
{
|
||
|
Result res = 0;
|
||
|
u32 mask = CNT_ENABLE_FIFOs | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
|
||
|
if(receiveFIFONotEmptyInterrupt != NULL)
|
||
|
{
|
||
|
res = svcBindInterrupt(0x53, *receiveFIFONotEmptyInterrupt, 0, false);
|
||
|
if(R_FAILED(res))
|
||
|
{
|
||
|
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
|
||
|
return res;
|
||
|
}
|
||
|
REG_PXI_CNT = (REG_PXI_CNT & mask) | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ;
|
||
|
}
|
||
|
|
||
|
if(sendFIFOEmptyInterrupt != NULL)
|
||
|
{
|
||
|
res = svcBindInterrupt(0x52, *sendFIFOEmptyInterrupt, 0, false);
|
||
|
if(R_FAILED(res))
|
||
|
{
|
||
|
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
|
||
|
return res;
|
||
|
}
|
||
|
REG_PXI_CNT = (REG_PXI_CNT & mask) | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
|
||
|
}
|
||
|
|
||
|
if(syncInterrupt != NULL)
|
||
|
{
|
||
|
res = svcBindInterrupt(0x50, *syncInterrupt, 0, false);
|
||
|
if(R_FAILED(res))
|
||
|
{
|
||
|
unbindPXIInterrupts(syncInterrupt, receiveFIFONotEmptyInterrupt, sendFIFOEmptyInterrupt);
|
||
|
return res;
|
||
|
}
|
||
|
REG_PXI_INTERRUPT_CNT |= SYNC_ENABLE_SYNC11_IRQ;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
void unbindPXIInterrupts(Handle *syncInterrupt, Handle *receiveFIFONotEmptyInterrupt, Handle *sendFIFOEmptyInterrupt)
|
||
|
{
|
||
|
if(receiveFIFONotEmptyInterrupt != NULL)
|
||
|
{
|
||
|
REG_PXI_CNT &= CNT_ENABLE_FIFOs | CNT_ENABLE_SEND_FIFO_EMPTY_IRQ;
|
||
|
svcUnbindInterrupt(0x53, *receiveFIFONotEmptyInterrupt);
|
||
|
}
|
||
|
|
||
|
if(sendFIFOEmptyInterrupt != NULL)
|
||
|
{
|
||
|
REG_PXI_CNT &= CNT_ENABLE_FIFOs | CNT_ENABLE_RECEIVE_FIFO_NOT_EMPTY_IRQ;
|
||
|
svcUnbindInterrupt(0x52, *sendFIFOEmptyInterrupt);
|
||
|
}
|
||
|
if(syncInterrupt != NULL)
|
||
|
{
|
||
|
REG_PXI_INTERRUPT_CNT &= ~SYNC_ENABLE_SYNC11_IRQ;
|
||
|
svcUnbindInterrupt(0x50, *syncInterrupt);
|
||
|
}
|
||
|
}
|