Usermode/libaxwin4 - Handle demarshal failure
[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   1
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 #include <timers.h>
15
16 // === CONSTANTS ===
17 #define MAX_CONTROLLERS 4
18 #define MAX_TD_PAGES    2
19 #define MAX_ENDPT_PAGES 2
20 #define MAX_PACKET_SIZE 0x400   // TODO: Check what should be used
21
22 // === PROTOTYPES ===
23  int    OHCI_Initialise(char **Arguments);
24 void    OHCI_Cleanup(void);
25
26 void    OHCI_InitialiseController(tOHCI_Controller *Controller);
27
28 void    *OHCI_int_AddTD(tOHCI_Controller *Controller, int Dest, int DataTgl, int Type, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
29 void    *OHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
30 void    *OHCI_DataOUT(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
31 void    *OHCI_SendSETUP(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
32  int    OHCI_IsTransferComplete(void *Ptr, void *Handle);
33
34 void    *OHCI_StartPoll(void *Ptr, int Dest, int MaxPeriod, tUSBHostCb Cb, void *CbData, void *DataBuf, size_t Length);
35 void    OHCI_StopPoll(void *Ptr, void *Hdl);
36 void    OHCI_CheckPortUpdate(void *Ptr);
37 void    OHCI_InterruptHandler(int IRQ, void *Ptr);
38
39 tOHCI_Endpoint  *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller, int Dest);
40 tOHCI_Endpoint  *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr);
41 tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller);
42 tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr);
43
44 // === GLOBALS ===
45 MODULE_DEFINE(0, VERSION, USB_OHCI, OHCI_Initialise, OHCI_Cleanup, "USB_Core", NULL);
46 tUSBHostDef     gOHCI_HostDef = {
47         .InterruptIN = OHCI_StartPoll,
48         .StopInterrupt = OHCI_StopPoll,
49
50         .SendIN = OHCI_DataIN,
51         .SendOUT = OHCI_DataOUT,
52         .SendSETUP = OHCI_SendSETUP,
53         .IsOpComplete = OHCI_IsTransferComplete,
54
55
56         .CheckPorts = OHCI_CheckPortUpdate
57         };
58 tOHCI_Controller        gOHCI_Controllers[MAX_CONTROLLERS];
59 tOHCI_GeneralTD *gapOHCI_TDPool[MAX_TD_PAGES];  //!< Virtual pointers to TDs, each has an index in avail bits
60 const int       ciTDs_per_page = PAGE_SIZE/sizeof(tOHCI_GeneralTD);
61 tOHCI_Endpoint  *gapOHCI_EndpointPool[MAX_ENDPT_PAGES];
62 const int       ciEndpoints_per_page = PAGE_SIZE/sizeof(tOHCI_Endpoint);
63
64 // === CODE ===
65 int OHCI_Initialise(char **Arguments)
66 {
67          int    id = -1;
68          int    card_num = 0;
69         
70         while( (id = PCI_GetDeviceByClass(0x0C0310, 0xFFFFFF, id)) != -1 && card_num < MAX_CONTROLLERS )
71         {
72                 tOHCI_Controller        *ctrlr = &gOHCI_Controllers[card_num];
73
74                 ctrlr->ID = card_num;   
75                 ctrlr->PciId = id;      
76                 ctrlr->IRQNum = PCI_GetIRQ(id);
77                 ctrlr->ControlSpacePhys = PCI_GetBAR(id, 0);    // Offset 0x10
78                 PCI_ConfigWrite( id, 4, 2, 0x0006 );    // Enable memory and bus master
79
80                 if( ctrlr->ControlSpacePhys == 0 || ctrlr->ControlSpacePhys & 1 ) {
81                         ctrlr->ControlSpacePhys = 0;
82                         continue ;
83                 }
84
85                 OHCI_InitialiseController( ctrlr );
86         
87                 card_num ++;
88         }
89
90         if( id != -1 ) {
91                 Log_Warning("OHCI", "Too many controllers (> %i) were detected, ignoring the rest",
92                         MAX_CONTROLLERS);
93         }
94         
95         return 0;
96 }
97
98 void OHCI_Cleanup(void)
99 {
100          int    i;
101         // TODO: Cleanup for unload
102         
103         for( i = 0; i < MAX_CONTROLLERS && gOHCI_Controllers[i].ControlSpacePhys; i ++ )
104         {
105                 // TODO: Clean up resources used
106         }
107 }
108
109 void OHCI_InitialiseController(tOHCI_Controller *Controller)
110 {
111         tOHCI_Controller        *cnt = Controller;
112         volatile struct sRegisters      *iospace;
113         
114         Log_Debug("OHCI", "Card #%i at 0x%X, IRQ %i",
115                 cnt->ID, cnt->ControlSpacePhys, cnt->IRQNum);
116         
117         // - Prepare mappings
118         cnt->ControlSpace = (void*)MM_MapHWPages(cnt->ControlSpacePhys, 1);
119         IRQ_AddHandler( cnt->IRQNum, OHCI_InterruptHandler, cnt);
120         iospace = cnt->ControlSpace;
121         
122         Log_Debug("OHCI", "Card #%i version is 0x%x", cnt->ID, iospace->HcRevision);
123
124         // Check who had control
125         if( iospace->HcControl & (1 << 8) )     // InterruptRouting
126         {
127                 LOG("USB was in the hands of SMM, asking for it back");
128                 // SMM has control, ask for it back
129                 // - Write '1' to OwnershipChangeRequest
130                 // - Wait for InterruptRouting to clear
131                 // TODO: Timeout
132                 while( iospace->HcControl & (1 << 8) ) ;
133                 LOG("Obtained USB");
134         }
135         else if( (iospace->HcControl & 0xC0) != 0x00 )  // UsbReset
136         {
137                 LOG("USB was in the hands of the BIOS");
138                 // BIOS had control, check for Operational
139                 if( (iospace->HcControl & 0xC0) != 0x80 )       // UsbOperational
140                 {
141                         // - If not, set to resume
142                         iospace->HcControl &= ~0xC0;    // UsbResume
143                         iospace->HcControl |= 0x40;     // UsbResume
144                         // TODO: Wait
145                 }
146         }
147         else
148         {       
149                 // Cold boot, wait a bit
150                 // TODO: Wait for reset time
151         }
152
153         // Allocate HCCA area   
154         cnt->HCCA = (void*)MM_AllocDMA(1, 32, &cnt->HCCAPhys);
155         if( !cnt->HCCA ) {
156                 Log_Error("OHCI", "Unable to allocate HCCA (1 page, 32-bit)");
157                 return ;
158         }
159         // TODO: Check return value
160         // - HCCA is 256 bytes in length, but I like alignment
161         cnt->IntLists = (void*)( (tVAddr)cnt->HCCA + 512 );
162         LOG("HCCAPhys = %P, HCCA = %p", cnt->HCCAPhys, cnt->HCCA);
163         
164         // --- Restart the controller ---
165         Uint32  fm_interval = iospace->HcFmInterval;
166         iospace->HcCommandStatus |= (1 << 0);
167         // - Wait 10 micro-seconds
168         // TODO: 
169         iospace->HcFmInterval = fm_interval;
170         // (Now in UsbSuspend state)
171         // - Wait 2ms
172         // TODO:
173         // - Check that things are good?
174
175         // --- Initialise Virtual Queues ---
176         memset(cnt->IntLists, 0, sizeof(*cnt->IntLists));
177         // Set next pointers into a binary tree
178         {
179                 tPAddr  next_lvl = cnt->HCCAPhys + 512;
180                 next_lvl += 16 * sizeof(tOHCI_Endpoint);
181                 for( int i = 0; i < 16; i ++ )
182                         cnt->IntLists->Period16[i].NextED = next_lvl + i/2 * sizeof(tOHCI_Endpoint);
183                 next_lvl += 8 * sizeof(tOHCI_Endpoint);
184                 for( int i = 0; i < 8; i ++ )
185                         cnt->IntLists->Period8[i].NextED = next_lvl + i/2 * sizeof(tOHCI_Endpoint);
186                 next_lvl += 4 * sizeof(tOHCI_Endpoint);
187                 for( int i = 0; i < 4; i ++ )
188                         cnt->IntLists->Period4[i].NextED = next_lvl + i/2 * sizeof(tOHCI_Endpoint);
189                 next_lvl += 2 * sizeof(tOHCI_Endpoint);
190                 for( int i = 0; i < 2; i ++ )
191                         cnt->IntLists->Period2[i].NextED = next_lvl + sizeof(tOHCI_Endpoint);
192                 next_lvl += 1 * sizeof(tOHCI_Endpoint);
193                 cnt->IntLists->Period1[0].NextED = next_lvl;
194         }
195         // Set all endpoints to be skipped
196         for( int i = 0; i < 32; i ++ )
197         {
198                 tOHCI_Endpoint  *ep = &cnt->IntLists->Period16[i];
199                 ep->Flags |= (1 << 14); // Skip
200         }
201
202         // --- Initialise HCCA ---
203         // - Interrupt table is set up to point to each 
204         for( int i = 0; i < 32; i ++ )
205         {
206                 static const int _balance[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
207                 cnt->HCCA->HccaInterruptTable[i] = cnt->HCCAPhys + 512 + _balance[i&15] * sizeof(tOHCI_Endpoint);
208         }
209         cnt->HCCA->HccaFrameNumber = 0;
210         cnt->HCCA->HccaDoneHead = 0;
211
212         // --- Initialise Registers
213         iospace->HcControlHeadED = MM_GetPhysAddr( (tVAddr)&cnt->IntLists->StopED );
214         iospace->HcBulkHeadED = MM_GetPhysAddr( (tVAddr)&cnt->IntLists->StopED );
215         iospace->HcHCCA = cnt->HCCAPhys;
216         iospace->HcInterruptEnable = 0x7B;      // 0111 1011 (RHSC, FNO, UE, RD, WDH, SO)
217         iospace->HcInterruptDisable = 0x4;      // Disable SOF interrupts
218         iospace->HcControl = 0x3C;      // All queues on
219         iospace->HcPeriodicStart = fm_interval / 10 * 9;        // 90% of fm_interval
220         
221         // --- Start
222         iospace->HcControl |= (2 << 6); // UsbOperational
223
224         LOG("HcRhDescriptorA = 0x%x", iospace->HcRhDescriptorA);
225         LOG("HcRhDescriptorB = 0x%x", iospace->HcRhDescriptorB);
226         
227         // --- Tell USB core that this controller is avaliable
228         cnt->nPorts = iospace->HcRhDescriptorA & 0x7F;
229         if( cnt->nPorts > 15 ) {
230                 // Oops?
231                 Log_Warning("OHCI", "Controller reports %i ports, but spec only allows 15, capping", cnt->nPorts);
232                 cnt->nPorts = 15;
233         }
234         cnt->RootHub = USB_RegisterHost(&gOHCI_HostDef, cnt, cnt->nPorts);
235 }
236
237 // --- USB IO Functions ---
238 void *OHCI_int_DoTD(
239         tOHCI_Controller *Controller, int Dest,
240         int DataTgl, int Type,
241         tUSBHostCb Cb, void *CbData,
242         void *Buf, size_t Length
243         )
244 {
245         tOHCI_GeneralTD *td;
246         tPAddr  td_phys;
247         tOHCI_Endpoint  *ep;
248
249         // --- Sanity check
250         if( Length > MAX_PACKET_SIZE )
251                 return NULL;
252         
253         ENTER("pController xDest iDataTgl iType pCb pCbData pBuf iLength",
254                 Controller, Dest, DataTgl, Type, Cb, CbData, Buf, Length);
255
256         // ---- Check that the packet resides within memory the controller can access
257         if( MM_GetPhysAddr((tVAddr)Buf) >= (1ULL << 32) || MM_GetPhysAddr((tVAddr)Buf + Length -1) >= (1ULL << 32) )
258         {
259                 // TODO: Handle destination outside of 32-bit address range
260                 Log_Warning("OHCI", "_int_DoTD - Buffer outside of 32-bit range, TODO: Handle this");
261                 LEAVE('n');
262                 return NULL;
263         }
264
265         // --- Find/Allocate Endpoint descriptor
266         ep = OHCI_int_AllocateEndpt(Controller, Dest);
267         if( !ep ) {
268                 Log_Warning("OHCI", "_int_DoTD - Unable to find/allocate Endpoint 0x%x... oops", Dest);
269                 LEAVE('n');
270                 return NULL;
271         }
272         
273         // --- Allocate a TD
274         td = OHCI_int_AllocateGTD(Controller);
275         if( !td ) {
276                 Log_Warning("OHCI", "_int_DoTD - Unable to allocate TD... oops");
277                 LEAVE('n');
278                 return NULL;
279         }
280         td_phys = MM_GetPhysAddr( (tVAddr)td );
281         
282         // --- Fill the TD
283         td->Flags |= (1 << 18); // Buffer rounding
284         td->Flags |= (Type & 3) << 19;  // Type/Direction
285         td->Flags |= (2 | DataTgl) << 24;       // Data Toggle
286         td->CBP = MM_GetPhysAddr( (tVAddr) Buf );
287         td->BE = MM_GetPhysAddr( (tVAddr)Buf + Length - 1 );
288         // - Save callback etc
289         td->CbPointer = (tVAddr)Cb;
290         td->CbArg = (tVAddr)CbData;
291
292         // --- Add to the end of the Endpoint's list
293         if( ep->TailP )
294                 OHCI_int_GetGTDFromPhys( ep->TailP )->NextTD = td_phys;
295         else
296                 ep->HeadP = td_phys;
297         ep->TailP = td_phys;
298
299         LEAVE('p', td);
300         return td;
301 }
302 void *OHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
303 {
304         return OHCI_int_DoTD(Ptr, Dest, DataTgl, 2, Cb, CbData, Buf, Length);
305 }
306 void *OHCI_DataOUT(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
307 {
308         return OHCI_int_DoTD(Ptr, Dest, DataTgl, 1, Cb, CbData, Buf, Length);
309 }
310 void *OHCI_SendSETUP(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
311 {
312         return OHCI_int_DoTD(Ptr, Dest, DataTgl, 0, Cb, CbData, Buf, Length);
313 }
314 int OHCI_IsTransferComplete(void *Ptr, void *Handle)
315 {
316         tOHCI_GeneralTD *td = Handle;
317         
318         ENTER("pPtr pHandle", Ptr, Handle);
319
320         if( td->CBP != 0 )
321         {
322                 LEAVE('i', 0);
323                 return 0;
324         }
325         else
326         {
327                 Log_Warning("OHCI", "TODO: Implement cleanup in OHCI_IsTransferComplete");
328                 LEAVE('i', 1);
329                 return 1;
330         }
331 }
332
333 // --- Interrupt polling ---
334 void *OHCI_StartPoll(void *Ptr, int Dest, int MaxPeriod, tUSBHostCb Cb, void *CbData, void *DataBuf, size_t Length)
335 {
336          int    slot;
337
338         if( MaxPeriod <= 0 )    return NULL;
339
340         // Allocate? (or obtain) an ED
341         
342         // Get update rate
343         for( slot = 32; slot > MaxPeriod && slot; slot >>= 1 );
344
345         // Allocate a TD
346         
347         // Place onto list
348         switch( slot )
349         {
350         case 1:
351                 // Add to period 1 list
352                 break;
353         case 2:
354                 // Determine best list by current load
355                 break;
356         case 4:
357                 break;
358         case 8:
359                 break;
360         case 16:
361                 break;
362         case 32:
363                 break;
364         default:
365                 Log_Error("OHCI", "OHCI_StartPoll - `slot` is invalid (%i)", slot);
366                 break;
367         }
368
369         Log_Warning("OHCI", "TODO: Implement OHCI_StartPoll");
370         return NULL;
371 }
372
373 void OHCI_StopPoll(void *Ptr, void *Hdl)
374 {
375         // Remove from list
376 }
377
378 // --- Root hub ---
379 void OHCI_CheckPortUpdate(void *Ptr)
380 {
381         tOHCI_Controller        *cnt = Ptr;
382         for( int i = 0; i < cnt->nPorts; i ++ )
383         {
384                 volatile Uint32 *status_ptr = &cnt->ControlSpace->HcRhPortStatus[i];
385                 Uint32  status = *status_ptr;
386                 // Connect change?
387                 if( status & (1 << 16) )
388                 {
389                         LOG("Connect status change port %i, *status = 0x%x", i, status);
390                         // Connect or disconnect?
391                         if( status & (1 << 0) )
392                         {
393                                 // Connect, set things up :)
394                         
395                                 // - TODO: Power on?            
396         
397                                 // - Reset port
398                                 *status_ptr = 1 << 4;   // PRS
399                                 Time_Delay(50);
400                                 // - Enable port
401                                 *status_ptr = 1 << 1;   // SetPortEnable
402                                 LOG("Device connected on port %i", i);  
403
404                                 // - Tell stack
405                                 USB_DeviceConnected(cnt->RootHub, i);
406                         }
407                         else
408                         {
409                                 // Disconnect
410                                 USB_DeviceDisconnected(cnt->RootHub, i);
411                         }
412                 }
413                 
414                 // TODO: Handle other bits?
415         }
416 }
417
418 // --- Interrupt handler
419 void OHCI_InterruptHandler(int IRQ, void *Ptr)
420 {
421         tOHCI_Controller        *cnt = Ptr;
422         // TODO: Interrupt handler
423         LOG("Interrupt on controller %i - Status = 0x%x",
424                 cnt->ID, cnt->ControlSpace->HcInterruptStatus);
425         
426         cnt->ControlSpace->HcInterruptStatus = cnt->ControlSpace->HcInterruptStatus;
427 }
428
429 // --- Internal Functions ---
430 tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller, int Dest)
431 {
432         tOHCI_Endpoint  *first_free_ep = NULL;
433         tOHCI_Endpoint  *first_freeable_ep = NULL;
434          int    pg, i;
435          int    _dest;
436         
437         // Convert 8.4 dev:endpt destination into 4.7 endpt:dev
438         _dest = (Dest >> 4) | ((Dest & 0xF) << 7);
439         
440         // TODO: Locking
441         for( pg = 0; pg < MAX_ENDPT_PAGES; pg ++ )
442         {
443                 if( !gapOHCI_EndpointPool[pg] ) {
444                         tPAddr  paddr;  // Not used
445                         gapOHCI_EndpointPool[pg] = (void*)MM_AllocDMA(1, 32, &paddr);
446                         memset(gapOHCI_EndpointPool[pg], 0, PAGE_SIZE);
447                 }
448                 
449                 for( i = 0; i < ciEndpoints_per_page; i ++ )
450                 {
451                         tOHCI_Endpoint  *ep = &gapOHCI_EndpointPool[pg][i];
452                         
453                         // Check if it's allocated
454                         if( ep->Flags & (1 << 31) )
455                         {
456                                 if( ep->HeadP == 0 )
457                                         first_freeable_ep = ep;
458                                 
459                                 if( ((ep->Flags >> 27) & 0xF) != Controller->ID )
460                                         continue ;
461                                 if( (ep->Flags & 0x7FF) != _dest )
462                                         continue ;
463                                 return ep;
464                         }
465                         else
466                         {
467                                 if( !first_free_ep )
468                                         first_free_ep = ep;
469                         }
470                 }
471         }
472         
473         if( first_free_ep ) {
474                 first_free_ep->Flags = (1 << 31);
475                 
476                 // Set controller ID
477                 first_free_ep->Flags |= Controller->ID << 27;
478                 first_free_ep->Flags |= _dest;
479                 first_free_ep->Flags |= 1023 << 16;     // Max Packet Size
480                 
481                 return first_free_ep;
482         }
483
484         if( first_freeable_ep ) {
485                 #if 0
486                 first_free_ep->Flags = (1 << 31);
487                 
488                 // Set controller ID
489                 first_free_ep->Flags |= Controller->ID << 27;
490                 first_free_ep->Flags |= _dest;
491                 
492                 return first_free_ep;
493                 #endif
494                 Log_Warning("OHCI", "TODO: Implement freeing EPs when no avalable slots");
495         }
496         
497         return NULL;
498 }
499
500 tOHCI_Endpoint *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr)
501 {
502          int    i;
503         for( i = 0; i < MAX_ENDPT_PAGES; i ++ )
504         {
505                 tPAddr  addr;
506                 addr = MM_GetPhysAddr( (tVAddr)gapOHCI_EndpointPool[i] );
507                 if( PhysAddr >= addr && PhysAddr < addr + 0x1000 )
508                 {
509                         return gapOHCI_EndpointPool[i] + (PhysAddr - addr) / sizeof(tOHCI_Endpoint);
510                 }
511         }
512         return NULL;
513 }
514
515 tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller)
516 {
517          int    pg, i;
518         // TODO: Locking
519         for( pg = 0; pg < MAX_TD_PAGES; pg ++ )
520         {
521                 if( !gapOHCI_TDPool[pg] ) {
522                         tPAddr  paddr;  // Not used
523                         gapOHCI_TDPool[pg] = (void*)MM_AllocDMA(1, 32, &paddr);
524                         memset(gapOHCI_TDPool[pg], 0, PAGE_SIZE);
525                 }
526                 
527                 for( i = 0; i < ciTDs_per_page; i ++ )
528                 {
529                         // Check if allocated, and if not take it
530                         if( gapOHCI_TDPool[pg][i].Flags & (1 << 31) )
531                                 continue ;
532                         gapOHCI_TDPool[pg][i].Flags = (1 << 31);
533                         
534                         // Set controller ID
535                         gapOHCI_TDPool[pg][i].Flags |= Controller->ID << 27;
536                         
537                         return &gapOHCI_TDPool[pg][i];
538                 }
539         }
540         return NULL;
541 }
542
543 tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr)
544 {
545          int    i;
546         for( i = 0; i < MAX_TD_PAGES; i ++ )
547         {
548                 tPAddr  addr;
549                 addr = MM_GetPhysAddr( (tVAddr)gapOHCI_TDPool[i] );
550                 if( PhysAddr >= addr && PhysAddr < addr + 0x1000 )
551                 {
552                         return gapOHCI_TDPool[i] + (PhysAddr - addr) / sizeof(tOHCI_GeneralTD);
553                 }
554         }
555         return NULL;
556 }
557

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