PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
endpoint.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 void addToHcEndpointList(u8 type, UsbdHcED_t *ed)
14{
15 ed->m_next = memPool->m_hcEdBuf[type].m_next;
16 memPool->m_hcEdBuf[type].m_next = ed;
17}
18
19static void removeHcEdFromList(int type, const UsbdHcED_t *hcEd)
20{
21 UsbdHcED_t *prev;
22 UsbdHcED_t *pos;
23
24 prev = &memPool->m_hcEdBuf[type];
25 for ( pos = prev->m_next; pos && pos != hcEd; prev = pos, pos = pos->m_next )
26 {
27 }
28 if ( pos )
29 {
30 prev->m_next = pos->m_next;
31 }
32}
33
34static int
35setupBandwidthInterruptScheduling(UsbdEndpoint_t *ep, const UsbEndpointDescriptor *endpDesc, int isLowSpeedDevice)
36{
37 int maxPacketSize;
38 u32 *interruptBandwidthSchedulingValues;
39 int endpType;
40 int waitHigh;
41 int waitLow;
42 int schedulingIndex;
43 int i;
44 int packetSizeForScheduling;
45 u32 *value_ptr2;
46
47 maxPacketSize = endpDesc->wMaxPacketSizeLB + (endpDesc->wMaxPacketSizeHB << 8);
48 interruptBandwidthSchedulingValues = memPool->m_interruptBandwidthSchedulingValues;
49 if ( endpDesc->bInterval >= 0x20u )
50 {
51 endpType = 31;
52 waitHigh = 1;
53 waitLow = 32;
54 }
55 else if ( endpDesc->bInterval >= 0x10u )
56 {
57 endpType = 15;
58 waitHigh = 2;
59 waitLow = 16;
60 }
61 else if ( endpDesc->bInterval >= 8u )
62 {
63 endpType = 7;
64 waitHigh = 4;
65 waitLow = 8;
66 }
67 else if ( endpDesc->bInterval >= 4u )
68 {
69 endpType = 3;
70 waitHigh = 8;
71 waitLow = 4;
72 }
73 else if ( endpDesc->bInterval >= 2u )
74 {
75 endpType = 1;
76 waitHigh = 16;
77 waitLow = 2;
78 }
79 else
80 {
81 endpType = 0;
82 waitHigh = 32;
83 waitLow = 1;
84 }
85 schedulingIndex = 0;
86 if ( waitLow >= 2 )
87 {
88 int maxValueSum;
89
90 schedulingIndex = -1;
91 maxValueSum = 0;
92 for ( i = 0; i < waitLow; i += 1 )
93 {
94 int valueSum;
95 u32 *value_ptr1;
96 int j;
97
98 valueSum = 0;
99 value_ptr1 = &interruptBandwidthSchedulingValues[i];
100 for ( j = 0; j < waitHigh; j += 1 )
101 {
102 valueSum += *value_ptr1;
103 value_ptr1 += waitLow;
104 }
105 if ( schedulingIndex < 0 || valueSum < maxValueSum )
106 {
107 schedulingIndex = i;
108 maxValueSum = valueSum;
109 }
110 }
111 endpType += schedulingIndex;
112 }
113 packetSizeForScheduling = maxPacketSize + 13;
114 if ( maxPacketSize >= 65 )
115 packetSizeForScheduling = 77;
116 ep->m_schedulingIndex = schedulingIndex;
117 ep->m_waitHigh = waitHigh;
118 ep->m_waitLow = waitLow;
119 ep->m_packetSizeForScheduling = packetSizeForScheduling;
120 if ( isLowSpeedDevice )
121 packetSizeForScheduling *= 8;
122 value_ptr2 = &interruptBandwidthSchedulingValues[schedulingIndex];
123 for ( i = 0; i < waitHigh; i += 1 )
124 {
125 *value_ptr2 += packetSizeForScheduling;
126 value_ptr2 += waitLow;
127 }
128 return endpType;
129}
130
131static void removeEndpointFromQueue(const UsbdEndpoint_t *ep, int isLowSpeedDevice)
132{
133 int i;
134 u32 *value_ptr;
135
136 value_ptr = &memPool->m_interruptBandwidthSchedulingValues[ep->m_schedulingIndex];
137 for ( i = 0; i < ep->m_waitHigh; i += 1 )
138 {
139 *value_ptr -= (ep->m_packetSizeForScheduling * (isLowSpeedDevice ? 8 : 1));
140 if ( (int)*value_ptr < 0 )
141 *value_ptr = 0;
142 value_ptr += ep->m_waitLow;
143 }
144}
145
146UsbdEndpoint_t *openDeviceEndpoint(UsbdDevice_t *dev, const UsbEndpointDescriptor *endpDesc, u32 alignFlag)
147{
148 UsbdHcTD_t *td;
149 int endpType;
150 UsbdEndpoint_t *newEp;
151
152 td = NULL;
153 endpType = 0;
154 newEp = allocEndpointForDevice(dev, alignFlag);
155 if ( !newEp )
156 {
157 dbg_printf("ran out of endpoints\n");
158 return NULL;
159 }
160 if ( endpDesc )
161 {
162 int hcMaxPktSize;
163 int flags;
164
165 hcMaxPktSize = endpDesc->wMaxPacketSizeLB + (endpDesc->wMaxPacketSizeHB << 8);
166 switch ( endpDesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK )
167 {
168 case USB_ENDPOINT_XFER_CONTROL:
169 {
170 endpType = TYPE_CONTROL;
171 break;
172 }
173 case USB_ENDPOINT_XFER_ISOC:
174 {
175 endpType = TYPE_ISOCHRON;
176 td = (UsbdHcTD_t *)allocIsoTd();
177 if ( !td )
178 {
179 cleanUpFunc(dev, newEp);
180 dbg_printf("Open ISOC EP: no TDs left\n");
181 return NULL;
182 }
183 alignFlag = 1;
184 break;
185 }
186 case USB_ENDPOINT_XFER_BULK:
187 {
188 endpType = TYPE_BULK;
189 if ( (endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN )
190 alignFlag = 1;
191 break;
192 }
193 case USB_ENDPOINT_XFER_INT:
194 {
195 endpType = setupBandwidthInterruptScheduling(newEp, endpDesc, dev->m_isLowSpeedDevice);
196 dbg_printf(
197 "opening INT endpoint (%d - %p), interval %d, list %d\n", newEp->m_id, newEp, endpDesc->bInterval, endpType);
198 if ( (endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN )
199 alignFlag = 1;
200 break;
201 }
202 default:
203 break;
204 }
205 if ( !alignFlag && hcMaxPktSize > 62 )
206 {
207 hcMaxPktSize = 62;
208 }
209 flags = (hcMaxPktSize << 16) & 0x7FF0000;
210 if ( endpType == TYPE_ISOCHRON )
211 flags |= HCED_ISOC;
212 if ( dev->m_isLowSpeedDevice )
213 flags |= HCED_SPEED;
214 flags |= ((endpDesc->bEndpointAddress & 0x1F) << 7)
215 | ((endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ? HCED_DIR_IN : HCED_DIR_OUT);
216 newEp->m_hcEd->m_hcArea.asu32 = flags | (dev->m_functionAddress & 0x7F);
217 }
218 else
219 {
220 newEp->m_hcEd->m_hcArea.asu32 = 0x80000;
221 newEp->m_hcEd->m_hcArea.asu32 |= dev->m_isLowSpeedDevice ? HCED_SPEED : 0;
222 endpType = TYPE_CONTROL;
223 }
224 newEp->m_endpointType = endpType;
225 if ( !td )
226 {
227 td = allocTd();
228 }
229 if ( !td )
230 {
231 dbg_printf("Ran out of TDs\n");
232 cleanUpFunc(dev, newEp);
233 return NULL;
234 }
235 newEp->m_hcEd->m_tdHead = td;
236 newEp->m_hcEd->m_tdTail = td;
237 addToHcEndpointList(endpType & 0xFF, newEp->m_hcEd);
238 return newEp;
239}
240
241static void killEndpoint(UsbdEndpoint_t *ep)
242{
243 UsbdHcED_t *hcEd;
244 int i;
245 UsbdIoRequest_t *req;
246
247 hcEd = ep->m_hcEd;
248 if ( ep->m_endpointType == TYPE_ISOCHRON )
249 {
250 for ( i = 0; i < usbConfig.m_maxIsoTransfDesc; i += 1 )
251 {
252 if ( memPool->m_hcIsoTdToIoReqLUT[i] && memPool->m_hcIsoTdToIoReqLUT[i]->m_correspEndpoint == ep )
253 {
254 freeIoRequest(memPool->m_hcIsoTdToIoReqLUT[i]);
255 memPool->m_hcIsoTdToIoReqLUT[i] = NULL;
256 freeIsoTd(&memPool->m_hcIsoTdBuf[i]);
257 }
258 }
259 freeIsoTd((UsbdHcIsoTD_t *)hcEd->m_tdTail);
260 hcEd->m_tdTail = NULL;
261 }
262 else
263 {
264 for ( i = 0; i < usbConfig.m_maxTransfDesc; i += 1 )
265 {
266 if ( memPool->m_hcTdToIoReqLUT[i] && memPool->m_hcTdToIoReqLUT[i]->m_correspEndpoint == ep )
267 {
268 freeIoRequest(memPool->m_hcTdToIoReqLUT[i]);
269 memPool->m_hcTdToIoReqLUT[i] = NULL;
270 freeTd(&memPool->m_hcTdBuf[i]);
271 }
272 }
273 freeTd(hcEd->m_tdTail);
274 hcEd->m_tdTail = NULL;
275 }
276 hcEd->m_tdHead = NULL;
277 for ( req = ep->m_ioReqListStart; req; req = ep->m_ioReqListStart )
278 {
279 if ( req->m_next )
280 req->m_next->m_prev = req->m_prev;
281 else
282 ep->m_ioReqListEnd = req->m_prev;
283 if ( req->m_prev )
284 req->m_prev->m_next = req->m_next;
285 else
286 ep->m_ioReqListStart = req->m_next;
287 freeIoRequest(req);
288 }
289 removeEndpointFromQueue(ep, ep->m_correspDevice->m_isLowSpeedDevice);
290 if ( ep->m_inTdQueue != NOTIN_QUEUE )
291 {
292 if ( ep->m_busyNext )
293 ep->m_busyNext->m_busyPrev = ep->m_busyPrev;
294 else
295 memPool->m_tdQueueEnd = ep->m_busyPrev;
296 if ( ep->m_busyPrev )
297 ep->m_busyPrev->m_busyNext = ep->m_busyNext;
298 else
299 memPool->m_tdQueueStart = ep->m_busyNext;
300 ep->m_inTdQueue = NOTIN_QUEUE;
301 }
302 ep->m_prev = memPool->m_freeEpListEnd;
303 if ( memPool->m_freeEpListEnd )
304 memPool->m_freeEpListEnd->m_next = ep;
305 else
306 memPool->m_freeEpListStart = ep;
307 ep->m_next = NULL;
308 memPool->m_freeEpListEnd = ep;
309}
310
311int removeEndpointFromDevice(UsbdDevice_t *dev, UsbdEndpoint_t *ep)
312{
313 ep->m_hcEd->m_hcArea.stru.m_hcArea |= HCED_SKIP;
314 removeHcEdFromList(ep->m_endpointType, ep->m_hcEd);
315 if ( ep->m_next )
316 ep->m_next->m_prev = ep->m_prev;
317 else
318 dev->m_endpointListEnd = ep->m_prev;
319 if ( ep->m_prev )
320 ep->m_prev->m_next = ep->m_next;
321 else
322 dev->m_endpointListStart = ep->m_next;
323 ep->m_correspDevice = NULL;
324 addTimerCallback(&ep->m_timer, (TimerCallback)killEndpoint, ep, 200);
325 return 0;
326}