PS2SDK
PS2 Homebrew Libraries
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 
13 static 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 
19 static 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 
34 static int
35 setupBandwidthInterruptScheduling(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 
131 static 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 
146 UsbdEndpoint_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 
241 static 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 
311 int 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 }
UsbEndpointDescriptor
Definition: usbd.h:108
_hcIsoTd
Definition: usbdpriv.h:144
usbdpriv.h
_hcTd
Definition: usbdpriv.h:136
_hcEd
Definition: usbdpriv.h:165
_device
Definition: usbdpriv.h:107
_ioRequest
Definition: usbdpriv.h:82
_endpoint
Definition: usbdpriv.h:173