PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
io_request.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "usbdpriv.h"
12
13static int setupControlTransfer(UsbdEndpoint_t *ep)
14{
15 UsbdIoRequest_t *curIoReq;
16 UsbdHcTD_t *dataTd;
17 UsbdHcTD_t *tailTd;
18 UsbdHcTD_t *statusTd;
19
20 if ( !ep->m_hcEd->m_tdTail || ED_HALTED(*(ep->m_hcEd)) || ED_SKIPPED(*(ep->m_hcEd)) || !ep->m_ioReqListStart )
21 {
22 // endpoint error
23 if ( ep->m_inTdQueue == NOTIN_QUEUE )
24 return 0;
25 if ( ep->m_busyNext )
26 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
27 else
28 memPool->m_tdQueueEnd = ep->m_busyPrev;
29 if ( ep->m_busyPrev )
30 {
31 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
32 }
33 else
34 {
35 memPool->m_tdQueueStart = ep->m_busyNext;
36 }
37 ep->m_inTdQueue = NOTIN_QUEUE;
38 return 0;
39 }
40 curIoReq = ep->m_ioReqListStart;
41 dataTd = NULL;
42 if ( curIoReq->m_destPtr && (int)curIoReq->m_length > 0 )
43 {
44 dataTd = allocTd();
45 if ( !dataTd )
46 {
47 if ( ep->m_inTdQueue != NOTIN_QUEUE )
48 return 0;
49 ep->m_busyPrev = memPool->m_tdQueueEnd;
50 if ( memPool->m_tdQueueEnd )
51 {
52 memPool->m_tdQueueEnd->m_busyNext = ep;
53 }
54 else
55 {
56 memPool->m_tdQueueStart = ep;
57 }
58 ep->m_busyNext = NULL;
59 memPool->m_tdQueueEnd = ep;
60 ep->m_inTdQueue = GENTD_QUEUE;
61 return 0;
62 }
63 }
64 statusTd = allocTd();
65 tailTd = allocTd();
66 if ( !statusTd || !tailTd )
67 {
68 freeTd(dataTd);
69 freeTd(statusTd);
70 freeTd(tailTd);
71 if ( ep->m_inTdQueue != NOTIN_QUEUE )
72 return 0;
73 ep->m_busyPrev = memPool->m_tdQueueEnd;
74 if ( memPool->m_tdQueueEnd )
75 {
76 memPool->m_tdQueueEnd->m_busyNext = ep;
77 }
78 else
79 {
80 memPool->m_tdQueueStart = ep;
81 }
82 ep->m_busyNext = NULL;
83 memPool->m_tdQueueEnd = ep;
84 ep->m_inTdQueue = GENTD_QUEUE;
85 return 0;
86 }
87 if ( curIoReq->m_next )
88 curIoReq->m_next->m_prev = curIoReq->m_prev;
89 else
90 ep->m_ioReqListEnd = curIoReq->m_prev;
91 if ( curIoReq->m_prev )
92 curIoReq->m_prev->m_next = curIoReq->m_next;
93 else
94 ep->m_ioReqListStart = curIoReq->m_next;
95 // first stage: setup
96 ep->m_hcEd->m_tdTail->m_hcArea = TD_HCAREA(USB_RC_NOTACCESSED, 2, 7, TD_SETUP, 0) << 16;
97 ep->m_hcEd->m_tdTail->m_curBufPtr = &curIoReq->m_devReq;
98 ep->m_hcEd->m_tdTail->m_next = dataTd ? dataTd : statusTd;
99 ep->m_hcEd->m_tdTail->m_bufferEnd = ((u8 *)&curIoReq->m_devReq) + sizeof(UsbDeviceRequest) - 1;
100 memPool->m_hcTdToIoReqLUT[ep->m_hcEd->m_tdTail - memPool->m_hcTdBuf] = curIoReq;
101 // second stage: data
102 if ( dataTd )
103 {
104 dataTd->m_hcArea = (curIoReq->m_devReq.requesttype & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ?
105 (TD_HCAREA(USB_RC_NOTACCESSED, 3, 7, TD_OUT, 1) << 16) :
106 (TD_HCAREA(USB_RC_NOTACCESSED, 3, 7, TD_IN, 1) << 16);
107 dataTd->m_next = statusTd;
108 dataTd->m_curBufPtr = curIoReq->m_destPtr;
109 dataTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + curIoReq->m_length - 1;
110 memPool->m_hcTdToIoReqLUT[dataTd - memPool->m_hcTdBuf] = curIoReq;
111 }
112 // third stage: status
113 statusTd->m_hcArea = (curIoReq->m_devReq.requesttype & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ?
114 (TD_HCAREA(USB_RC_NOTACCESSED, 3, 0, TD_IN, 0) << 16) :
115 (TD_HCAREA(USB_RC_NOTACCESSED, 3, 0, TD_OUT, 0) << 16);
116 statusTd->m_curBufPtr = NULL;
117 statusTd->m_next = tailTd;
118 statusTd->m_bufferEnd = NULL;
119 memPool->m_hcTdToIoReqLUT[statusTd - memPool->m_hcTdBuf] = curIoReq;
120 ep->m_hcEd->m_tdTail = tailTd;
121 memPool->m_ohciRegs->HcCommandStatus |= OHCI_COM_CLF; // control list filled
122 if ( ep->m_ioReqListStart )
123 {
124 return 1;
125 }
126 if ( ep->m_inTdQueue == NOTIN_QUEUE )
127 {
128 return 1;
129 }
130 // remove endpoint from busy list if there are no IoRequests left
131 if ( ep->m_busyNext )
132 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
133 else
134 memPool->m_tdQueueEnd = ep->m_busyPrev;
135 if ( ep->m_busyPrev )
136 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
137 else
138 memPool->m_tdQueueStart = ep->m_busyNext;
139 ep->m_inTdQueue = NOTIN_QUEUE;
140 return 1;
141}
142
143static int setupIsocronTransfer(UsbdEndpoint_t *ep)
144{
145 UsbdHcED_t *ed;
146 UsbdIoRequest_t *curIoReq;
147 UsbdHcIsoTD_t *curTd;
148 UsbdHcIsoTD_t *newTd;
149 u16 frameNo;
150
151 ed = ep->m_hcEd;
152 if ( !ed->m_tdTail || ED_HALTED(*ed) || ED_SKIPPED(*ed) || !ep->m_ioReqListStart )
153 {
154 // endpoint error
155 if ( ep->m_inTdQueue == NOTIN_QUEUE )
156 return 0;
157 if ( ep->m_busyNext )
158 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
159 else
160 memPool->m_tdQueueEnd = ep->m_busyPrev;
161 if ( ep->m_busyPrev )
162 {
163 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
164 }
165 else
166 {
167 memPool->m_tdQueueStart = ep->m_busyNext;
168 }
169 ep->m_inTdQueue = NOTIN_QUEUE;
170 return 0;
171 }
172 curIoReq = ep->m_ioReqListStart;
173 curTd = (UsbdHcIsoTD_t *)ed->m_tdTail;
174 newTd = allocIsoTd();
175 if ( !newTd )
176 {
177 if ( ep->m_inTdQueue != NOTIN_QUEUE )
178 return 0;
179 ep->m_busyPrev = memPool->m_tdQueueEnd;
180 if ( memPool->m_tdQueueEnd )
181 memPool->m_tdQueueEnd->m_busyNext = ep;
182 else
183 memPool->m_tdQueueStart = ep;
184 ep->m_busyNext = NULL;
185 memPool->m_tdQueueEnd = ep;
186 ep->m_inTdQueue = ISOTD_QUEUE;
187 return 0;
188 }
189 if ( curIoReq->m_next )
190 curIoReq->m_next->m_prev = curIoReq->m_prev;
191 else
192 ep->m_ioReqListEnd = curIoReq->m_prev;
193 if ( curIoReq->m_prev )
194 curIoReq->m_prev->m_next = curIoReq->m_next;
195 else
196 ep->m_ioReqListStart = curIoReq->m_next;
197 if ( (UsbdHcTD_t *)((uiptr)ed->m_tdHead & ~0xF) == ed->m_tdTail )
198 frameNo = (memPool->m_hcHCCA->FrameNumber + 2) & 0xFFFF;
199 else
200 frameNo = (ep->m_isochronLastFrameNum) & 0xFFFF;
201 frameNo = (u16)(frameNo + (curIoReq->m_waitFrames & 0xFFFF));
202 ep->m_isochronLastFrameNum = (curIoReq->m_req.bNumPackets ? (curIoReq->m_req.bNumPackets & 0xFFFF) : 1) + frameNo;
203 if ( curIoReq->m_req.bNumPackets )
204 {
205 int psw0_tmp;
206 int i;
207
208 curTd->m_hcArea = ((curIoReq->m_req.bNumPackets - 1) << 24) | frameNo | (USB_RC_NOTACCESSED << 28);
209 curTd->m_next = newTd;
210 curTd->m_bufferPage0 = (void *)((uiptr)curIoReq->m_destPtr & ~0xFFF);
211 curTd->m_bufferEnd = NULL;
212 if ( curIoReq->m_destPtr && (int)(curIoReq->m_length) > 0 )
213 {
214 curTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + ((int)curIoReq->m_length - 1);
215 }
216 psw0_tmp = ((uiptr)curIoReq->m_destPtr & 0xFFF) | (USB_RC_NOTACCESSED << 12);
217 for ( i = 0; i < (int)curIoReq->m_req.bNumPackets; i += 1 )
218 {
219 curTd->m_psw[i] = psw0_tmp;
220 psw0_tmp += curIoReq->m_req.Packets[i].bLength;
221 }
222 }
223 else
224 {
225 curTd->m_hcArea = frameNo | (USB_RC_NOTACCESSED << 28);
226 curTd->m_next = newTd;
227 curTd->m_bufferPage0 = (void *)((uiptr)curIoReq->m_destPtr & ~0xFFF);
228 curTd->m_bufferEnd = NULL;
229 if ( curIoReq->m_destPtr && (int)(curIoReq->m_length) > 0 )
230 {
231 curTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + ((int)curIoReq->m_length - 1);
232 }
233 curTd->m_psw[0] = ((uiptr)curIoReq->m_destPtr & 0xFFF) | (USB_RC_NOTACCESSED << 12);
234 }
235 memPool->m_hcIsoTdToIoReqLUT[curTd - memPool->m_hcIsoTdBuf] = curIoReq;
236 ed->m_tdTail = (UsbdHcTD_t *)newTd;
237 if ( ep->m_ioReqListStart )
238 {
239 return 1;
240 }
241 if ( ep->m_inTdQueue == NOTIN_QUEUE )
242 {
243 return 1;
244 }
245 // remove endpoint from busy list if there are no IoRequests left
246 if ( ep->m_busyNext )
247 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
248 else
249 memPool->m_tdQueueEnd = ep->m_busyPrev;
250 if ( ep->m_busyPrev )
251 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
252 else
253 memPool->m_tdQueueStart = ep->m_busyNext;
254 ep->m_inTdQueue = NOTIN_QUEUE;
255 return 1;
256}
257
258static int setupBulkTransfer(UsbdEndpoint_t *ep)
259{
260 UsbdHcED_t *ed;
261 UsbdIoRequest_t *curIoReq;
262 UsbdHcTD_t *curTd;
263 UsbdHcTD_t *newTd;
264
265 ed = ep->m_hcEd;
266 if ( !ed->m_tdTail || ED_HALTED(*ed) || ED_SKIPPED(*ed) || !ep->m_ioReqListStart )
267 {
268 // endpoint error
269 dbg_printf("ERROR UsbdEndpoint_t error\n");
270 if ( ep->m_inTdQueue == NOTIN_QUEUE )
271 return 0;
272 if ( ep->m_busyNext )
273 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
274 else
275 memPool->m_tdQueueEnd = ep->m_busyPrev;
276 if ( ep->m_busyPrev )
277 {
278 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
279 }
280 else
281 {
282 memPool->m_tdQueueStart = ep->m_busyNext;
283 }
284 ep->m_inTdQueue = NOTIN_QUEUE;
285 return 0;
286 }
287 curIoReq = ep->m_ioReqListStart;
288 curTd = ed->m_tdTail;
289 newTd = allocTd();
290 if ( !newTd )
291 {
292 if ( ep->m_inTdQueue != NOTIN_QUEUE )
293 return 0;
294 ep->m_busyPrev = memPool->m_tdQueueEnd;
295 if ( memPool->m_tdQueueEnd )
296 memPool->m_tdQueueEnd->m_busyNext = ep;
297 else
298 memPool->m_tdQueueStart = ep;
299 ep->m_busyNext = NULL;
300 memPool->m_tdQueueEnd = ep;
301 ep->m_inTdQueue = GENTD_QUEUE;
302 return 0;
303 }
304 if ( curIoReq->m_next )
305 curIoReq->m_next->m_prev = curIoReq->m_prev;
306 else
307 ep->m_ioReqListEnd = curIoReq->m_prev;
308 if ( curIoReq->m_prev )
309 curIoReq->m_prev->m_next = curIoReq->m_next;
310 else
311 ep->m_ioReqListStart = curIoReq->m_next;
312 curTd->m_hcArea = TD_HCAREA(USB_RC_NOTACCESSED, 0, 0, 3, 1) << 16;
313 curTd->m_next = newTd;
314 curTd->m_curBufPtr = curIoReq->m_destPtr;
315 curTd->m_bufferEnd = NULL;
316 if ( curIoReq->m_destPtr && (int)curIoReq->m_length > 0 )
317 {
318 curTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + ((int)curIoReq->m_length - 1);
319 }
320 memPool->m_hcTdToIoReqLUT[curTd - memPool->m_hcTdBuf] = curIoReq;
321 ed->m_tdTail = newTd;
322 if ( ep->m_endpointType == TYPE_BULK )
323 memPool->m_ohciRegs->HcCommandStatus |= OHCI_COM_BLF; // Bulk List Filled
324 if ( ep->m_ioReqListStart )
325 {
326 return 1;
327 }
328 if ( ep->m_inTdQueue == NOTIN_QUEUE )
329 {
330 return 1;
331 }
332 // remove endpoint from busy list if there are no IoRequests left
333 if ( ep->m_busyNext )
334 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
335 else
336 memPool->m_tdQueueEnd = ep->m_busyPrev;
337 if ( ep->m_busyPrev )
338 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
339 else
340 memPool->m_tdQueueStart = ep->m_busyNext;
341 ep->m_inTdQueue = NOTIN_QUEUE;
342 return 1;
343}
344
345void handleIoReqList(UsbdEndpoint_t *ep)
346{
347 switch ( ep->m_endpointType )
348 {
349 case TYPE_CONTROL:
350 {
351 setupControlTransfer(ep);
352 break;
353 }
354 case TYPE_ISOCHRON:
355 {
356 setupIsocronTransfer(ep);
357 break;
358 }
359 case TYPE_BULK:
360 default: // bulk or interrupt
361 {
362 setupBulkTransfer(ep);
363 break;
364 }
365 }
366}
#define USB_RC_NOTACCESSED
Definition usbd.h:262