Modules/OHCI - Implementation work, not usable yet, but getting there
[tpg/acess2.git] / KernelLand / Modules / USB / OHCI / ohci.c
1 /*
2  * Acess2 USB Stack - OHCI Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * ohci.c
6  * - Open Host Controller Interface driver
7  */
8 #define DEBUG   0
9 #define VERSION VER2(0,1)
10 #include <usb_host.h>
11 #include "ohci.h"
12 #include <modules.h>
13 #include <drv_pci.h>
14
15 // === CONSTANTS ===
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
20
21 // === PROTOTYPES ===
22  int    OHCI_Initialise(char **Arguments);
23 void    OHCI_Cleanup(void);
24
25 void    OHCI_InitialiseController(tOHCI_Controller *Controller);
26
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);
32
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);
37
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);
42
43 // === GLOBALS ===
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,
50
51 //      .StartPolling = OHCI_StartPoll,
52 //      .StopPolling = OHCI_StopPoll,
53
54         .CheckPorts = OHCI_CheckPortUpdate
55         };
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);
61
62 // === CODE ===
63 int OHCI_Initialise(char **Arguments)
64 {
65          int    id = -1;
66          int    card_num = 0;
67         
68         while( (id = PCI_GetDeviceByClass(0x0C0310, 0xFFFFFF, id)) != -1 && card_num < MAX_CONTROLLERS )
69         {
70                 tOHCI_Controller        *ctrlr = &gOHCI_Controllers[card_num];
71
72                 ctrlr->ID = card_num;   
73                 ctrlr->PciId = id;      
74                 ctrlr->IRQNum = PCI_GetIRQ(id);
75                 ctrlr->ControlSpacePhys = PCI_GetBAR(id, 0);    // Offset 0x10
76
77                 if( ctrlr->ControlSpacePhys == 0 || ctrlr->ControlSpacePhys & 1 ) {
78                         ctrlr->ControlSpacePhys = 0;
79                         continue ;
80                 }
81
82                 OHCI_InitialiseController( ctrlr );
83         
84                 card_num ++;
85         }
86
87         if( id != -1 ) {
88                 Log_Warning("OHCI", "Too many controllers (> %i) were detected, ignoring the rest",
89                         MAX_CONTROLLERS);
90         }
91         
92         return 0;
93 }
94
95 void OHCI_Cleanup(void)
96 {
97          int    i;
98         // TODO: Cleanup for unload
99         
100         for( i = 0; i < MAX_CONTROLLERS && gOHCI_Controllers[i].ControlSpacePhys; i ++ )
101         {
102                 // TODO: Clean up resources used
103         }
104 }
105
106 void OHCI_InitialiseController(tOHCI_Controller *Controller)
107 {
108         tOHCI_Controller        *cnt = Controller;
109         struct sRegisters       *iospace;
110         
111         Log_Debug("OHCI", "Card #%i at 0x%X, IRQ %i",
112                 cnt->ID, cnt->ControlSpacePhys, cnt->IRQNum);
113         
114         // - Prepare mappings
115         cnt->ControlSpace = (void*)MM_MapHWPages(cnt->ControlSpacePhys, 1);
116         IRQ_AddHandler( cnt->IRQNum, OHCI_InterruptHandler, cnt);
117
118         // Allocate HCCA area   
119         cnt->HCCA = (void*)MM_AllocDMA(1, 32, &cnt->HCCAPhys);
120         if( !cnt->HCCA ) {
121                 Log_Error("OHCI", "Unable to allocate HCCA (1 page, 32-bit)");
122                 return ;
123         }
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);
128         
129         iospace = cnt->ControlSpace;
130         
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)
137         // - Wait 2ms
138
139         // --- Initialise Virtual Queues ---
140         memset(cnt->IntLists, 0, sizeof(*cnt->IntLists));
141         // Set next pointers into a binary tree
142         {
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;
158         }
159         // Set all endpoints to be skipped
160         for( int i = 0; i < 32; i ++ )
161         {
162                 tOHCI_Endpoint  *ep = &cnt->IntLists->Period16[i];
163                 ep->Flags |= (1 << 14); // Skip
164         }
165
166         // --- Initialise HCCA ---
167         // - Interrupt table is set up to point to each 
168         for( int i = 0; i < 32; i ++ )
169         {
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);
172         }
173         cnt->HCCA->HccaFrameNumber = 0;
174         cnt->HCCA->HccaDoneHead = 0;
175
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
183         
184         // --- Start
185         iospace->HcControl |= (2 << 6); // UsbOperational
186 }
187
188 // --- USB IO Functions ---
189 void *OHCI_int_DoTD(
190         tOHCI_Controller *Controller, int Dest,
191         int DataTgl, int Type,
192         tUSBHostCb Cb, void *CbData,
193         void *Buf, size_t Length
194         )
195 {
196         tOHCI_GeneralTD *td;
197         tPAddr  td_phys;
198         tOHCI_Endpoint  *ep;
199
200         // Sanity check
201         if( Length > MAX_PACKET_SIZE )
202                 return NULL;
203         
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) )
206         {
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");
209                 return NULL;
210         }
211
212         // Find Endpoint descriptor
213         // TODO:
214         // - Allocate one if needed
215         // TODO:
216         
217         // Allocate a TD
218         td = OHCI_int_AllocateGTD(Controller);
219         if( !td ) {
220                 Log_Warning("OHCI", "_int_DoTD - Unable to allocate TD... oops");
221                 return NULL;
222         }
223         td_phys = MM_GetPhysAddr( (tVAddr)td );
224         // Fill the 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;
233
234         // Add to the end of the Endpoint's list
235         if( ep->TailP )
236                 OHCI_int_GetGTDFromPhys( ep->TailP )->NextTD = td_phys;
237         else
238                 ep->HeadP = td_phys;
239         ep->TailP = td_phys;
240
241         return td;
242 }
243 void *OHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
244 {
245         return OHCI_int_DoTD(Ptr, Dest, DataTgl, 2, Cb, CbData, Buf, Length);
246 }
247 void *OHCI_DataOUT(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
248 {
249         return OHCI_int_DoTD(Ptr, Dest, DataTgl, 1, Cb, CbData, Buf, Length);
250 }
251 void *OHCI_SendSETUP(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
252 {
253         return OHCI_int_DoTD(Ptr, Dest, DataTgl, 0, Cb, CbData, Buf, Length);
254 }
255 int OHCI_IsTransferComplete(void *Ptr, void *Handle)
256 {
257         return 0;
258 }
259
260 // --- Interrupt polling ---
261 void *OHCI_StartPoll(void *Ptr, int Dest, int MaxPeriod, tUSBHostCb Cb, void *CbData, void *DataBuf, size_t Length)
262 {
263          int    slot;
264
265         if( MaxPeriod <= 0 )    return NULL;
266
267         // Allocate? (or obtain) an ED
268         
269         // Get update rate
270         for( slot = 32; slot > MaxPeriod && slot; slot >>= 1 );
271
272         // Allocate a TD
273         
274         // Place onto list
275         switch( slot )
276         {
277         case 1:
278                 // Add to all lists
279                 break;
280         case 2:
281                 // Add to every second list
282                 break;
283         case 4:
284                 // Add to every fourth list
285                 break;
286         case 8:
287                 // Add to every eighth list
288                 break;
289         case 16:
290                 // Add to first list
291                 break;
292         case 32:
293                 // Add to first list
294                 break;
295         default:
296                 Log_Error("OHCI", "OHCI_StartPoll - `slot` is invalid (%i)", slot);
297                 break;
298         }
299
300         return NULL;
301 }
302
303 void OHCI_StopPoll(void *Ptr, void *Hdl)
304 {
305         // Remove from list
306 }
307
308 // --- Root hub ---
309 void OHCI_CheckPortUpdate(void *Ptr)
310 {
311         
312 }
313
314 // --- Interrupt handler
315 void OHCI_InterruptHandler(int IRQ, void *Ptr)
316 {
317         tOHCI_Controller        *cnt = Ptr;
318         // TODO: Interrupt handler
319         Log_Debug("OHIC", "Interrupt handler on controller %i", cnt->ID);
320 }
321
322 // --- Internal Functions ---
323 tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller)
324 {
325          int    pg, i;
326         // TODO: Locking
327         for( pg = 0; pg < MAX_ENDPT_PAGES; pg ++ )
328         {
329                 if( !gapOHCI_EndpointPool[pg] ) {
330                         gapOHCI_EndpointPool[pg] = (void*)MM_AllocDMA(1, 32, NULL);
331                         memset(gapOHCI_EndpointPool, 0, PAGE_SIZE);
332                 }
333                 
334                 for( i = 0; i < ciEndpoints_per_page; i ++ )
335                 {
336                         // Check if allocated, and if not take it
337                         if( gapOHCI_EndpointPool[pg][i].Flags & (1 << 31) )
338                                 continue ;
339                         gapOHCI_EndpointPool[pg][i].Flags = (1 << 31);
340                         
341                         // Set controller ID
342                         gapOHCI_EndpointPool[pg][i].Flags |= Controller->ID << 27;
343                         
344                         return &gapOHCI_EndpointPool[pg][i];
345                 }
346         }
347         return NULL;
348 }
349
350 tOHCI_Endpoint *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr)
351 {
352          int    i;
353         for( i = 0; i < MAX_ENDPT_PAGES; i ++ )
354         {
355                 tPAddr  addr;
356                 addr = MM_GetPhysAddr( (tVAddr)gapOHCI_EndpointPool[i] );
357                 if( PhysAddr >= addr && PhysAddr < addr + 0x1000 )
358                 {
359                         return gapOHCI_EndpointPool[i] + (PhysAddr - addr) / sizeof(tOHCI_Endpoint);
360                 }
361         }
362         return NULL;
363 }
364
365 tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller)
366 {
367         // TODO: Locking
368         return NULL;
369 }
370
371 tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr)
372 {
373          int    i;
374         for( i = 0; i < MAX_TD_PAGES; i ++ )
375         {
376                 tPAddr  addr;
377                 addr = MM_GetPhysAddr( (tVAddr)gapOHCI_TDPool[i] );
378                 if( PhysAddr >= addr && PhysAddr < addr + 0x1000 )
379                 {
380                         return gapOHCI_TDPool[i] + (PhysAddr - addr) / sizeof(tOHCI_GeneralTD);
381                 }
382         }
383         return NULL;
384 }
385

UCC git Repository :: git.ucc.asn.au