2 * Acess2 USB Stack - OHCI Driver
3 * - By John Hodge (thePowersGang)
6 * - Open Host Controller Interface driver
9 #define VERSION VER2(0,1)
16 #define MAX_CONTROLLERS 4
17 #define MAX_TD_PAGES 2
18 #define MAX_ENDPT_PAGES 2
19 #define MAX_PACKET_SIZE 0x1000 // TODO: Check what should be used
22 int OHCI_Initialise(char **Arguments);
23 void OHCI_Cleanup(void);
25 void OHCI_InitialiseController(tOHCI_Controller *Controller);
27 void *OHCI_int_AddTD(tOHCI_Controller *Controller, int Dest, int DataTgl, int Type, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
28 void *OHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
29 void *OHCI_DataOUT(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
30 void *OHCI_SendSETUP(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
31 int OHCI_IsTransferComplete(void *Ptr, void *Handle);
33 void *OHCI_StartPoll(void *Ptr, int Dest, int MaxPeriod, tUSBHostCb Cb, void *CbData, void *DataBuf, size_t Length);
34 void OHCI_StopPoll(void *Ptr, void *Hdl);
35 void OHCI_CheckPortUpdate(void *Ptr);
36 void OHCI_InterruptHandler(int IRQ, void *Ptr);
38 tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller);
39 tOHCI_Endpoint *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr);
40 tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller);
41 tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr);
44 MODULE_DEFINE(0, VERSION, USB_OHCI, OHCI_Initialise, OHCI_Cleanup, "USB_Core", NULL);
45 tUSBHostDef gOHCI_HostDef = {
46 .SendIN = OHCI_DataIN,
47 .SendOUT = OHCI_DataOUT,
48 .SendSETUP = OHCI_SendSETUP,
49 .IsOpComplete = OHCI_IsTransferComplete,
51 // .StartPolling = OHCI_StartPoll,
52 // .StopPolling = OHCI_StopPoll,
54 .CheckPorts = OHCI_CheckPortUpdate
56 tOHCI_Controller gOHCI_Controllers[MAX_CONTROLLERS];
57 tOHCI_GeneralTD *gapOHCI_TDPool[MAX_TD_PAGES]; //!< Virtual pointers to TDs, each has an index in avail bits
58 const int ciTDs_per_page = PAGE_SIZE/sizeof(tOHCI_GeneralTD);
59 tOHCI_Endpoint *gapOHCI_EndpointPool[MAX_ENDPT_PAGES];
60 const int ciEndpoints_per_page = PAGE_SIZE/sizeof(tOHCI_Endpoint);
63 int OHCI_Initialise(char **Arguments)
68 while( (id = PCI_GetDeviceByClass(0x0C0310, 0xFFFFFF, id)) != -1 && card_num < MAX_CONTROLLERS )
70 tOHCI_Controller *ctrlr = &gOHCI_Controllers[card_num];
74 ctrlr->IRQNum = PCI_GetIRQ(id);
75 ctrlr->ControlSpacePhys = PCI_GetBAR(id, 0); // Offset 0x10
77 if( ctrlr->ControlSpacePhys == 0 || ctrlr->ControlSpacePhys & 1 ) {
78 ctrlr->ControlSpacePhys = 0;
82 OHCI_InitialiseController( ctrlr );
88 Log_Warning("OHCI", "Too many controllers (> %i) were detected, ignoring the rest",
95 void OHCI_Cleanup(void)
98 // TODO: Cleanup for unload
100 for( i = 0; i < MAX_CONTROLLERS && gOHCI_Controllers[i].ControlSpacePhys; i ++ )
102 // TODO: Clean up resources used
106 void OHCI_InitialiseController(tOHCI_Controller *Controller)
108 tOHCI_Controller *cnt = Controller;
109 struct sRegisters *iospace;
111 Log_Debug("OHCI", "Card #%i at 0x%X, IRQ %i",
112 cnt->ID, cnt->ControlSpacePhys, cnt->IRQNum);
114 // - Prepare mappings
115 cnt->ControlSpace = (void*)MM_MapHWPages(cnt->ControlSpacePhys, 1);
116 IRQ_AddHandler( cnt->IRQNum, OHCI_InterruptHandler, cnt);
118 // Allocate HCCA area
119 cnt->HCCA = (void*)MM_AllocDMA(1, 32, &cnt->HCCAPhys);
121 Log_Error("OHCI", "Unable to allocate HCCA (1 page, 32-bit)");
124 // TODO: Check return value
125 // - HCCA is 256 bytes in length, but I like alignment
126 cnt->IntLists = (void*)( (tVAddr)cnt->HCCA + 512 );
127 LOG("HCCAPhys = %P, HCCA = %p", cnt->HCCAPhys, cnt->HCCA);
129 iospace = cnt->ControlSpace;
131 // --- Restart the controller ---
132 Uint32 fm_interval = iospace->HcFmInterval;
133 iospace->HcCommandStatus |= (1 << 0);
134 // - Wait 10 micro-seconds
135 iospace->HcFmInterval = fm_interval;
136 // (Now in UsbSuspend state)
139 // --- Initialise Virtual Queues ---
140 memset(cnt->IntLists, 0, sizeof(*cnt->IntLists));
141 // Set next pointers into a binary tree
143 tPAddr next_lvl = cnt->HCCAPhys + 512;
144 next_lvl += 16 * sizeof(tOHCI_Endpoint);
145 for( int i = 0; i < 16; i ++ )
146 cnt->IntLists->Period16[i].NextED = next_lvl + i/2 * sizeof(tOHCI_Endpoint);
147 next_lvl += 8 * sizeof(tOHCI_Endpoint);
148 for( int i = 0; i < 8; i ++ )
149 cnt->IntLists->Period8[i].NextED = next_lvl + i/2 * sizeof(tOHCI_Endpoint);
150 next_lvl += 4 * sizeof(tOHCI_Endpoint);
151 for( int i = 0; i < 4; i ++ )
152 cnt->IntLists->Period4[i].NextED = next_lvl + i/2 * sizeof(tOHCI_Endpoint);
153 next_lvl += 2 * sizeof(tOHCI_Endpoint);
154 for( int i = 0; i < 2; i ++ )
155 cnt->IntLists->Period2[i].NextED = next_lvl + sizeof(tOHCI_Endpoint);
156 next_lvl += 1 * sizeof(tOHCI_Endpoint);
157 cnt->IntLists->Period1[0].NextED = next_lvl;
159 // Set all endpoints to be skipped
160 for( int i = 0; i < 32; i ++ )
162 tOHCI_Endpoint *ep = &cnt->IntLists->Period16[i];
163 ep->Flags |= (1 << 14); // Skip
166 // --- Initialise HCCA ---
167 // - Interrupt table is set up to point to each
168 for( int i = 0; i < 32; i ++ )
170 static const int _balance[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
171 cnt->HCCA->HccaInterruptTable[i] = cnt->HCCAPhys + 512 + _balance[i&15] * sizeof(tOHCI_Endpoint);
173 cnt->HCCA->HccaFrameNumber = 0;
174 cnt->HCCA->HccaDoneHead = 0;
176 // --- Initialise Registers
177 iospace->HcControlHeadED = MM_GetPhysAddr( (tVAddr)&cnt->IntLists->StopED );
178 iospace->HcBulkHeadED = MM_GetPhysAddr( (tVAddr)&cnt->IntLists->StopED );
179 iospace->HcHCCA = cnt->HCCAPhys;
180 iospace->HcInterruptEnable = 0xFFFFFFFF; // TODO: Without SOF detect
181 iospace->HcControl = 0x3C; // All queues on
182 iospace->HcPeriodicStart = fm_interval / 10 * 9; // 90% of fm_interval
185 iospace->HcControl |= (2 << 6); // UsbOperational
188 // --- USB IO Functions ---
190 tOHCI_Controller *Controller, int Dest,
191 int DataTgl, int Type,
192 tUSBHostCb Cb, void *CbData,
193 void *Buf, size_t Length
201 if( Length > MAX_PACKET_SIZE )
204 // Check that the packet resides within memory the controller can access
205 if( MM_GetPhysAddr((tVAddr)Buf) >= (1ULL << 32) || MM_GetPhysAddr((tVAddr)Buf + Length -1) >= (1ULL << 32) )
207 // TODO: Handle destination outside of 32-bit address range
208 Log_Warning("OHCI", "_int_DoTD - Buffer outside of 32-bit range, TODO: Handle this");
212 // Find Endpoint descriptor
214 // - Allocate one if needed
218 td = OHCI_int_AllocateGTD(Controller);
220 Log_Warning("OHCI", "_int_DoTD - Unable to allocate TD... oops");
223 td_phys = MM_GetPhysAddr( (tVAddr)td );
225 td->Flags |= (1 << 18); // Buffer rounding
226 td->Flags |= (Type & 3) << 19; // Type/Direction
227 td->Flags |= (2 | DataTgl) << 24; // Data Toggle
228 td->CBP = MM_GetPhysAddr( (tVAddr) Buf );
229 td->BE = MM_GetPhysAddr( (tVAddr)Buf + Length - 1 );
230 // - Save callback etc
231 td->CbPointer = (tVAddr)Cb;
232 td->CbArg = (tVAddr)CbData;
234 // Add to the end of the Endpoint's list
236 OHCI_int_GetGTDFromPhys( ep->TailP )->NextTD = td_phys;
243 void *OHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
245 return OHCI_int_DoTD(Ptr, Dest, DataTgl, 2, Cb, CbData, Buf, Length);
247 void *OHCI_DataOUT(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
249 return OHCI_int_DoTD(Ptr, Dest, DataTgl, 1, Cb, CbData, Buf, Length);
251 void *OHCI_SendSETUP(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
253 return OHCI_int_DoTD(Ptr, Dest, DataTgl, 0, Cb, CbData, Buf, Length);
255 int OHCI_IsTransferComplete(void *Ptr, void *Handle)
260 // --- Interrupt polling ---
261 void *OHCI_StartPoll(void *Ptr, int Dest, int MaxPeriod, tUSBHostCb Cb, void *CbData, void *DataBuf, size_t Length)
265 if( MaxPeriod <= 0 ) return NULL;
267 // Allocate? (or obtain) an ED
270 for( slot = 32; slot > MaxPeriod && slot; slot >>= 1 );
281 // Add to every second list
284 // Add to every fourth list
287 // Add to every eighth list
296 Log_Error("OHCI", "OHCI_StartPoll - `slot` is invalid (%i)", slot);
303 void OHCI_StopPoll(void *Ptr, void *Hdl)
309 void OHCI_CheckPortUpdate(void *Ptr)
314 // --- Interrupt handler
315 void OHCI_InterruptHandler(int IRQ, void *Ptr)
317 tOHCI_Controller *cnt = Ptr;
318 // TODO: Interrupt handler
319 Log_Debug("OHIC", "Interrupt handler on controller %i", cnt->ID);
322 // --- Internal Functions ---
323 tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller)
327 for( pg = 0; pg < MAX_ENDPT_PAGES; pg ++ )
329 if( !gapOHCI_EndpointPool[pg] ) {
330 gapOHCI_EndpointPool[pg] = (void*)MM_AllocDMA(1, 32, NULL);
331 memset(gapOHCI_EndpointPool, 0, PAGE_SIZE);
334 for( i = 0; i < ciEndpoints_per_page; i ++ )
336 // Check if allocated, and if not take it
337 if( gapOHCI_EndpointPool[pg][i].Flags & (1 << 31) )
339 gapOHCI_EndpointPool[pg][i].Flags = (1 << 31);
342 gapOHCI_EndpointPool[pg][i].Flags |= Controller->ID << 27;
344 return &gapOHCI_EndpointPool[pg][i];
350 tOHCI_Endpoint *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr)
353 for( i = 0; i < MAX_ENDPT_PAGES; i ++ )
356 addr = MM_GetPhysAddr( (tVAddr)gapOHCI_EndpointPool[i] );
357 if( PhysAddr >= addr && PhysAddr < addr + 0x1000 )
359 return gapOHCI_EndpointPool[i] + (PhysAddr - addr) / sizeof(tOHCI_Endpoint);
365 tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller)
371 tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr)
374 for( i = 0; i < MAX_TD_PAGES; i ++ )
377 addr = MM_GetPhysAddr( (tVAddr)gapOHCI_TDPool[i] );
378 if( PhysAddr >= addr && PhysAddr < addr + 0x1000 )
380 return gapOHCI_TDPool[i] + (PhysAddr - addr) / sizeof(tOHCI_GeneralTD);