X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FUSB%2FOHCI%2Fohci.c;h=3f5060e5871fd403eee8d8ed82460781494b11ab;hb=8dcc3e209d0d728565a18c8dca2b0ba220b74a6f;hp=766ba6d849da1d3674a39f3b506f8138164c84e5;hpb=dbf2fba5c46254f141a52f93fa4d9e626fe72498;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/USB/OHCI/ohci.c b/KernelLand/Modules/USB/OHCI/ohci.c index 766ba6d8..3f5060e5 100644 --- a/KernelLand/Modules/USB/OHCI/ohci.c +++ b/KernelLand/Modules/USB/OHCI/ohci.c @@ -5,18 +5,19 @@ * ohci.c * - Open Host Controller Interface driver */ -#define DEBUG 0 +#define DEBUG 1 #define VERSION VER2(0,1) #include #include "ohci.h" #include #include +#include // === CONSTANTS === #define MAX_CONTROLLERS 4 #define MAX_TD_PAGES 2 #define MAX_ENDPT_PAGES 2 -#define MAX_PACKET_SIZE 0x1000 // TODO: Check what should be used +#define MAX_PACKET_SIZE 0x400 // TODO: Check what should be used // === PROTOTYPES === int OHCI_Initialise(char **Arguments); @@ -35,7 +36,7 @@ void OHCI_StopPoll(void *Ptr, void *Hdl); void OHCI_CheckPortUpdate(void *Ptr); void OHCI_InterruptHandler(int IRQ, void *Ptr); -tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller); +tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller, int Dest); tOHCI_Endpoint *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr); tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller); tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr); @@ -43,13 +44,14 @@ tOHCI_GeneralTD *OHCI_int_GetGTDFromPhys(tPAddr PhysAddr); // === GLOBALS === MODULE_DEFINE(0, VERSION, USB_OHCI, OHCI_Initialise, OHCI_Cleanup, "USB_Core", NULL); tUSBHostDef gOHCI_HostDef = { + .InterruptIN = OHCI_StartPoll, + .StopInterrupt = OHCI_StopPoll, + .SendIN = OHCI_DataIN, .SendOUT = OHCI_DataOUT, .SendSETUP = OHCI_SendSETUP, .IsOpComplete = OHCI_IsTransferComplete, -// .StartPolling = OHCI_StartPoll, -// .StopPolling = OHCI_StopPoll, .CheckPorts = OHCI_CheckPortUpdate }; @@ -73,6 +75,7 @@ int OHCI_Initialise(char **Arguments) ctrlr->PciId = id; ctrlr->IRQNum = PCI_GetIRQ(id); ctrlr->ControlSpacePhys = PCI_GetBAR(id, 0); // Offset 0x10 + PCI_ConfigWrite( id, 4, 2, 0x0006 ); // Enable memory and bus master if( ctrlr->ControlSpacePhys == 0 || ctrlr->ControlSpacePhys & 1 ) { ctrlr->ControlSpacePhys = 0; @@ -106,7 +109,7 @@ void OHCI_Cleanup(void) void OHCI_InitialiseController(tOHCI_Controller *Controller) { tOHCI_Controller *cnt = Controller; - struct sRegisters *iospace; + volatile struct sRegisters *iospace; Log_Debug("OHCI", "Card #%i at 0x%X, IRQ %i", cnt->ID, cnt->ControlSpacePhys, cnt->IRQNum); @@ -114,6 +117,38 @@ void OHCI_InitialiseController(tOHCI_Controller *Controller) // - Prepare mappings cnt->ControlSpace = (void*)MM_MapHWPages(cnt->ControlSpacePhys, 1); IRQ_AddHandler( cnt->IRQNum, OHCI_InterruptHandler, cnt); + iospace = cnt->ControlSpace; + + Log_Debug("OHCI", "Card #%i version is 0x%x", cnt->ID, iospace->HcRevision); + + // Check who had control + if( iospace->HcControl & (1 << 8) ) // InterruptRouting + { + LOG("USB was in the hands of SMM, asking for it back"); + // SMM has control, ask for it back + // - Write '1' to OwnershipChangeRequest + // - Wait for InterruptRouting to clear + // TODO: Timeout + while( iospace->HcControl & (1 << 8) ) ; + LOG("Obtained USB"); + } + else if( (iospace->HcControl & 0xC0) != 0x00 ) // UsbReset + { + LOG("USB was in the hands of the BIOS"); + // BIOS had control, check for Operational + if( (iospace->HcControl & 0xC0) != 0x80 ) // UsbOperational + { + // - If not, set to resume + iospace->HcControl &= ~0xC0; // UsbResume + iospace->HcControl |= 0x40; // UsbResume + // TODO: Wait + } + } + else + { + // Cold boot, wait a bit + // TODO: Wait for reset time + } // Allocate HCCA area cnt->HCCA = (void*)MM_AllocDMA(1, 32, &cnt->HCCAPhys); @@ -126,15 +161,16 @@ void OHCI_InitialiseController(tOHCI_Controller *Controller) cnt->IntLists = (void*)( (tVAddr)cnt->HCCA + 512 ); LOG("HCCAPhys = %P, HCCA = %p", cnt->HCCAPhys, cnt->HCCA); - iospace = cnt->ControlSpace; - // --- Restart the controller --- Uint32 fm_interval = iospace->HcFmInterval; iospace->HcCommandStatus |= (1 << 0); // - Wait 10 micro-seconds + // TODO: iospace->HcFmInterval = fm_interval; // (Now in UsbSuspend state) // - Wait 2ms + // TODO: + // - Check that things are good? // --- Initialise Virtual Queues --- memset(cnt->IntLists, 0, sizeof(*cnt->IntLists)); @@ -177,12 +213,25 @@ void OHCI_InitialiseController(tOHCI_Controller *Controller) iospace->HcControlHeadED = MM_GetPhysAddr( (tVAddr)&cnt->IntLists->StopED ); iospace->HcBulkHeadED = MM_GetPhysAddr( (tVAddr)&cnt->IntLists->StopED ); iospace->HcHCCA = cnt->HCCAPhys; - iospace->HcInterruptEnable = 0xFFFFFFFF; // TODO: Without SOF detect + iospace->HcInterruptEnable = 0x7B; // 0111 1011 (RHSC, FNO, UE, RD, WDH, SO) + iospace->HcInterruptDisable = 0x4; // Disable SOF interrupts iospace->HcControl = 0x3C; // All queues on iospace->HcPeriodicStart = fm_interval / 10 * 9; // 90% of fm_interval // --- Start iospace->HcControl |= (2 << 6); // UsbOperational + + LOG("HcRhDescriptorA = 0x%x", iospace->HcRhDescriptorA); + LOG("HcRhDescriptorB = 0x%x", iospace->HcRhDescriptorB); + + // --- Tell USB core that this controller is avaliable + cnt->nPorts = iospace->HcRhDescriptorA & 0x7F; + if( cnt->nPorts > 15 ) { + // Oops? + Log_Warning("OHCI", "Controller reports %i ports, but spec only allows 15, capping", cnt->nPorts); + cnt->nPorts = 15; + } + cnt->RootHub = USB_RegisterHost(&gOHCI_HostDef, cnt, cnt->nPorts); } // --- USB IO Functions --- @@ -197,31 +246,40 @@ void *OHCI_int_DoTD( tPAddr td_phys; tOHCI_Endpoint *ep; - // Sanity check + // --- Sanity check if( Length > MAX_PACKET_SIZE ) return NULL; - // Check that the packet resides within memory the controller can access + ENTER("pController xDest iDataTgl iType pCb pCbData pBuf iLength", + Controller, Dest, DataTgl, Type, Cb, CbData, Buf, Length); + + // ---- Check that the packet resides within memory the controller can access if( MM_GetPhysAddr((tVAddr)Buf) >= (1ULL << 32) || MM_GetPhysAddr((tVAddr)Buf + Length -1) >= (1ULL << 32) ) { // TODO: Handle destination outside of 32-bit address range Log_Warning("OHCI", "_int_DoTD - Buffer outside of 32-bit range, TODO: Handle this"); + LEAVE('n'); return NULL; } - // Find Endpoint descriptor - // TODO: - // - Allocate one if needed - // TODO: + // --- Find/Allocate Endpoint descriptor + ep = OHCI_int_AllocateEndpt(Controller, Dest); + if( !ep ) { + Log_Warning("OHCI", "_int_DoTD - Unable to find/allocate Endpoint 0x%x... oops", Dest); + LEAVE('n'); + return NULL; + } - // Allocate a TD + // --- Allocate a TD td = OHCI_int_AllocateGTD(Controller); if( !td ) { Log_Warning("OHCI", "_int_DoTD - Unable to allocate TD... oops"); + LEAVE('n'); return NULL; } td_phys = MM_GetPhysAddr( (tVAddr)td ); - // Fill the TD + + // --- Fill the TD td->Flags |= (1 << 18); // Buffer rounding td->Flags |= (Type & 3) << 19; // Type/Direction td->Flags |= (2 | DataTgl) << 24; // Data Toggle @@ -231,13 +289,14 @@ void *OHCI_int_DoTD( td->CbPointer = (tVAddr)Cb; td->CbArg = (tVAddr)CbData; - // Add to the end of the Endpoint's list + // --- Add to the end of the Endpoint's list if( ep->TailP ) OHCI_int_GetGTDFromPhys( ep->TailP )->NextTD = td_phys; else ep->HeadP = td_phys; ep->TailP = td_phys; + LEAVE('p', td); return td; } void *OHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) @@ -254,7 +313,21 @@ void *OHCI_SendSETUP(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbDa } int OHCI_IsTransferComplete(void *Ptr, void *Handle) { - return 0; + tOHCI_GeneralTD *td = Handle; + + ENTER("pPtr pHandle", Ptr, Handle); + + if( td->CBP != 0 ) + { + LEAVE('i', 0); + return 0; + } + else + { + Log_Warning("OHCI", "TODO: Implement cleanup in OHCI_IsTransferComplete"); + LEAVE('i', 1); + return 1; + } } // --- Interrupt polling --- @@ -275,28 +348,25 @@ void *OHCI_StartPoll(void *Ptr, int Dest, int MaxPeriod, tUSBHostCb Cb, void *Cb switch( slot ) { case 1: - // Add to all lists + // Add to period 1 list break; case 2: - // Add to every second list + // Determine best list by current load break; case 4: - // Add to every fourth list break; case 8: - // Add to every eighth list break; case 16: - // Add to first list break; case 32: - // Add to first list break; default: Log_Error("OHCI", "OHCI_StartPoll - `slot` is invalid (%i)", slot); break; } + Log_Warning("OHCI", "TODO: Implement OHCI_StartPoll"); return NULL; } @@ -308,7 +378,41 @@ void OHCI_StopPoll(void *Ptr, void *Hdl) // --- Root hub --- void OHCI_CheckPortUpdate(void *Ptr) { + tOHCI_Controller *cnt = Ptr; + for( int i = 0; i < cnt->nPorts; i ++ ) + { + volatile Uint32 *status_ptr = &cnt->ControlSpace->HcRhPortStatus[i]; + Uint32 status = *status_ptr; + // Connect change? + if( status & (1 << 16) ) + { + LOG("Connect status change port %i, *status = 0x%x", i, status); + // Connect or disconnect? + if( status & (1 << 0) ) + { + // Connect, set things up :) + + // - TODO: Power on? + // - Reset port + *status_ptr = 1 << 4; // PRS + Time_Delay(50); + // - Enable port + *status_ptr = 1 << 1; // SetPortEnable + LOG("Device connected on port %i", i); + + // - Tell stack + USB_DeviceConnected(cnt->RootHub, i); + } + else + { + // Disconnect + USB_DeviceDisconnected(cnt->RootHub, i); + } + } + + // TODO: Handle other bits? + } } // --- Interrupt handler @@ -316,34 +420,80 @@ void OHCI_InterruptHandler(int IRQ, void *Ptr) { tOHCI_Controller *cnt = Ptr; // TODO: Interrupt handler - Log_Debug("OHIC", "Interrupt handler on controller %i", cnt->ID); + LOG("Interrupt on controller %i - Status = 0x%x", + cnt->ID, cnt->ControlSpace->HcInterruptStatus); + + cnt->ControlSpace->HcInterruptStatus = cnt->ControlSpace->HcInterruptStatus; } // --- Internal Functions --- -tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller) +tOHCI_Endpoint *OHCI_int_AllocateEndpt(tOHCI_Controller *Controller, int Dest) { + tOHCI_Endpoint *first_free_ep = NULL; + tOHCI_Endpoint *first_freeable_ep = NULL; int pg, i; + int _dest; + + // Convert 8.4 dev:endpt destination into 4.7 endpt:dev + _dest = (Dest >> 4) | ((Dest & 0xF) << 7); + // TODO: Locking for( pg = 0; pg < MAX_ENDPT_PAGES; pg ++ ) { if( !gapOHCI_EndpointPool[pg] ) { - gapOHCI_EndpointPool[pg] = (void*)MM_AllocDMA(1, 32, NULL); - memset(gapOHCI_EndpointPool, 0, PAGE_SIZE); + tPAddr paddr; // Not used + gapOHCI_EndpointPool[pg] = (void*)MM_AllocDMA(1, 32, &paddr); + memset(gapOHCI_EndpointPool[pg], 0, PAGE_SIZE); } for( i = 0; i < ciEndpoints_per_page; i ++ ) { - // Check if allocated, and if not take it - if( gapOHCI_EndpointPool[pg][i].Flags & (1 << 31) ) - continue ; - gapOHCI_EndpointPool[pg][i].Flags = (1 << 31); - - // Set controller ID - gapOHCI_EndpointPool[pg][i].Flags |= Controller->ID << 27; + tOHCI_Endpoint *ep = &gapOHCI_EndpointPool[pg][i]; - return &gapOHCI_EndpointPool[pg][i]; + // Check if it's allocated + if( ep->Flags & (1 << 31) ) + { + if( ep->HeadP == 0 ) + first_freeable_ep = ep; + + if( ((ep->Flags >> 27) & 0xF) != Controller->ID ) + continue ; + if( (ep->Flags & 0x7FF) != _dest ) + continue ; + return ep; + } + else + { + if( !first_free_ep ) + first_free_ep = ep; + } } } + + if( first_free_ep ) { + first_free_ep->Flags = (1 << 31); + + // Set controller ID + first_free_ep->Flags |= Controller->ID << 27; + first_free_ep->Flags |= _dest; + first_free_ep->Flags |= 1023 << 16; // Max Packet Size + + return first_free_ep; + } + + if( first_freeable_ep ) { + #if 0 + first_free_ep->Flags = (1 << 31); + + // Set controller ID + first_free_ep->Flags |= Controller->ID << 27; + first_free_ep->Flags |= _dest; + + return first_free_ep; + #endif + Log_Warning("OHCI", "TODO: Implement freeing EPs when no avalable slots"); + } + return NULL; } @@ -364,7 +514,29 @@ tOHCI_Endpoint *OHCI_int_GetEndptFromPhys(tPAddr PhysAddr) tOHCI_GeneralTD *OHCI_int_AllocateGTD(tOHCI_Controller *Controller) { + int pg, i; // TODO: Locking + for( pg = 0; pg < MAX_TD_PAGES; pg ++ ) + { + if( !gapOHCI_TDPool[pg] ) { + tPAddr paddr; // Not used + gapOHCI_TDPool[pg] = (void*)MM_AllocDMA(1, 32, &paddr); + memset(gapOHCI_TDPool[pg], 0, PAGE_SIZE); + } + + for( i = 0; i < ciTDs_per_page; i ++ ) + { + // Check if allocated, and if not take it + if( gapOHCI_TDPool[pg][i].Flags & (1 << 31) ) + continue ; + gapOHCI_TDPool[pg][i].Flags = (1 << 31); + + // Set controller ID + gapOHCI_TDPool[pg][i].Flags |= Controller->ID << 27; + + return &gapOHCI_TDPool[pg][i]; + } + } return NULL; }