PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
iLink_TxRx.c
1/* iLink_TxRx.c
2 * Purpose: Contains the functions that are used to transmit IEEE1394 response and request packets via the UBUF.
3 * Only quadlet reads and writes are supported by functions in this files.
4 *
5 * Last Updated: 2012/02/21
6 * Programmer: SP193
7 */
8
9#include <intrman.h>
10#include <stdio.h>
11#include <sysmem.h>
12#include <thbase.h>
13#include <thevent.h>
14#include <thsemap.h>
15
16#include "iLinkman.h"
17#include "iLink_internal.h"
18
19extern unsigned short int LocalNodeID;
20extern int GenerationNumber;
21extern int IntrEventFlag;
22
23extern struct ILINKMemMap *ILINKRegisterBase;
24extern struct DMAChannelRegBlock *iLinkDMACRegs;
25extern unsigned *TargetBuffer;
26extern unsigned int LocalCachedIntr0Register;
27extern int UBUFTxSema;
28
29static int iLinkSendData(struct TransactionContextData *trContext, unsigned int *header, unsigned int HeaderLength, unsigned int *payload, unsigned int PayloadLength);
30
31static int iLinkSendData(struct TransactionContextData *trContext, unsigned int *header, unsigned int HeaderLength, unsigned int *payload, unsigned int PayloadLength)
32{
33 unsigned int i, *data;
34 u32 FlagBits;
35
36 WaitSema(UBUFTxSema);
37 ClearEventFlag(IntrEventFlag, ~(iLinkEventDataSent | iLinkEventDataReceived | iLinkEventError));
38
39 ILINKRegisterBase->ubufTransmitClear = 0;
40 data = header;
41
42 /* Transmit the header... */
43 for (i = 0; i < HeaderLength; i++) {
44 if ((trContext != NULL) && (trContext->GenerationNumber != GenerationNumber))
45 return (-1021);
46
47 ILINKRegisterBase->ubufTransmitNext = *data;
48 data++;
49 }
50
51 /* Now transmit the payload. */
52 if (PayloadLength > 0) {
53 data = payload;
54 for (i = 0; i < PayloadLength; i++) {
55 if ((trContext != NULL) && (trContext->GenerationNumber != GenerationNumber))
56 return (-1021);
57 ILINKRegisterBase->ubufTransmitNext = *data;
58 data++;
59 }
60 }
61
62 ILINKRegisterBase->ubufTransmitLast = *(data - 1);
63
64 DEBUG_PRINTF("Transmitting payload...\n");
65 WaitEventFlag(IntrEventFlag, iLinkEventDataSent | iLinkEventError, WEF_OR, &FlagBits);
66
67 if (FlagBits & iLinkEventError) {
68 DEBUG_PRINTF("iLinkman: TX Error.\n");
69 }
70
71 SignalSema(UBUFTxSema);
72
73 return ((FlagBits & iLinkEventError) ? (unsigned int)(-1) : PayloadLength);
74}
75
76void SendResponse(unsigned short int NodeID, unsigned short RcvdBusID, unsigned char rCode, unsigned char tLabel, unsigned char tCode, unsigned char speed, unsigned int *buffer, unsigned int nQuads)
77{
78 struct ieee1394_TrResponsePacketHdr ResponseHeader;
79 unsigned int ResponseHeaderLength;
80
81 ResponseHeaderLength = (tCode == IEEE1394_TCODE_READB_RESPONSE) ? 4 : 3;
82
83 DEBUG_PRINTF("Sending response to: 0x%04x, RcvdBusID: 0x%04x, rcode: %d, Header length: %u, speed: 0x%04x. Payload length: 0x%08x.\n", NodeID, RcvdBusID, rCode, ResponseHeaderLength, speed, nQuads);
84 DEBUG_PRINTF("tCode: 0x%02x\n", tCode);
85
86 ResponseHeader.header = (((unsigned int)RcvdBusID) << 22) | (((unsigned int)speed) << 16) | (((unsigned int)tLabel) << 10) | (1 << 8) | (((unsigned int)tCode) << 4);
87 ResponseHeader.header2 = (((unsigned int)NodeID) << 16) | (((unsigned int)rCode) << 12);
88 ResponseHeader.reserved = 0;
89 ResponseHeader.LastField = nQuads << 18;
90
91 iLinkSendData(NULL, (unsigned int *)&ResponseHeader, ResponseHeaderLength, buffer, nQuads);
92}
93
94static iop_sys_clock_t Timeout = {
95 0x8E9400, /* 0x800*125us / (1/36.5MHz) */
96 0};
97
98static unsigned int TimeoutCallbackFunction(void *argv)
99{
100 (void)argv;
101
102 iSetEventFlag(IntrEventFlag, iLinkEventError);
103 return 0;
104}
105
106static int iLinkSync(unsigned int PayloadLength)
107{
108 u32 FlagBits;
109
110 DEBUG_PRINTF("Payload transmitted. Now awaiting response...\n");
111
112 SetAlarm(&Timeout, &TimeoutCallbackFunction, NULL);
113 WaitEventFlag(IntrEventFlag, iLinkEventDataReceived | iLinkEventError, WEF_OR, &FlagBits);
114
115 if (!(FlagBits & iLinkEventError)) {
116 CancelAlarm(&TimeoutCallbackFunction, NULL);
117 } else {
118 DEBUG_PRINTF("iLinkman: Split timeout.\n");
119 LocalCachedIntr0Register |= iLink_INTR0_STO;
120 }
121
122 DEBUG_PRINTF("Processing results...\n");
123
124 if (LocalCachedIntr0Register & iLink_INTR0_InvAck)
125 return (-1023);
126 if (LocalCachedIntr0Register & iLink_INTR0_STO)
127 return (-1024);
128 if (LocalCachedIntr0Register & iLink_INTR0_AckMiss)
129 return (-1025);
130 if (LocalCachedIntr0Register & iLink_INTR0_RetEx)
131 return (-1026);
132 /* if (!(LocalCachedIntr0Register & iLink_INTR0_AckRcvd))
133 return (-1); */ /* Don't test for an acknowledge, as this somehow doesn't work right. :/ */
134
135 return PayloadLength;
136}
137
138int iLinkReadReq(struct TransactionContextData *trContext, unsigned short int offset_high, unsigned int offset_low, void *buffer, unsigned int nBytes)
139{
140 unsigned int nBytesToTransfer;
141 struct ieee1394_TrPacketHdr TxHeader;
142 int result;
143 unsigned char tlabel, tCode;
144
145 DEBUG_PRINTF("iLinkTrRead() 0x%08x %08x; nbytes: 0x%08x. Node: 0x%04x.\n", offset_high, offset_low, nBytes, trContext->NodeID);
146
147 TargetBuffer = buffer;
148
149 tlabel = 1; /* Note: As the tlabel is the same, multiple simultaneous transactions will probably not be possible. */
150 tCode = IEEE1394_TCODE_READQ;
151 TxHeader.header = (((unsigned int)trContext->speed) << 16) | (((unsigned int)tlabel) << 10) | (1 << 8) | (((unsigned int)tCode) << 4);
152 TxHeader.offset_high = (((unsigned int)trContext->NodeID) << 16) | offset_high;
153 TxHeader.offset_low = offset_low;
154 TxHeader.misc = nBytes << 16;
155
156 nBytesToTransfer = sizeof(struct ieee1394_TrPacketHdr) - 4; /* Quadlet reads do not have the data length field. */
157
158 if ((result = iLinkSendData(trContext, (unsigned int *)&TxHeader, nBytesToTransfer >> 2, NULL, 0)) >= 0) {
159 result = iLinkSync(nBytesToTransfer);
160 }
161
162 return result;
163}
164
165int iLinkWriteReq(struct TransactionContextData *trContext, unsigned short int offset_high, unsigned int offset_low, void *buffer, unsigned int nBytes)
166{
167 unsigned int nBytesToTransfer;
168 struct ieee1394_TrPacketHdr TxHeader;
169 int result;
170 unsigned char tlabel, tCode;
171
172 DEBUG_PRINTF("iLinkTrWrite() 0x%08x %08x; nbytes: 0x%08x. Node: 0x%04x.\n", offset_high, offset_low, nBytes, trContext->NodeID);
173
174 tlabel = 1; /* Note: As the tlabel is the same, multiple simultaneous transactions will probably not be possible. */
175 tCode = IEEE1394_TCODE_WRITEQ;
176 TxHeader.header = (((unsigned int)trContext->speed) << 16) | (((unsigned int)tlabel) << 10) | (1 << 8) | (((unsigned int)tCode) << 4);
177 TxHeader.offset_high = (((unsigned int)trContext->NodeID) << 16) | offset_high;
178 TxHeader.offset_low = offset_low;
179 TxHeader.misc = nBytes << 16;
180
181 nBytesToTransfer = sizeof(struct ieee1394_TrPacketHdr) - 4; /* Quadlet writes do not have the data length field. */
182
183 if ((result = iLinkSendData(trContext, (unsigned int *)&TxHeader, nBytesToTransfer >> 2, buffer, nBytes >> 2)) >= 0) {
184 result = iLinkSync(nBytesToTransfer);
185 }
186
187 return result;
188}