PS2SDK
PS2 Homebrew Libraries
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 
13 static 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 
143 static 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 
258 static 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 
345 void 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 }
_hcIsoTd
Definition: usbdpriv.h:144
UsbDeviceRequest
Definition: usbd.h:22
usbdpriv.h
_hcTd
Definition: usbdpriv.h:136
_hcEd
Definition: usbdpriv.h:165
USB_RC_NOTACCESSED
#define USB_RC_NOTACCESSED
Definition: usbd.h:262
_ioRequest
Definition: usbdpriv.h:82
_endpoint
Definition: usbdpriv.h:173