X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FUSB%2FUHCI%2Fuhci.c;h=3c2abd9e3d80fdfdd5352afe8a1d40928710be56;hb=0e361ff8d9472885f770a370c0d477c229041572;hp=83059ad2c6cc64f0a22342f7455cef8ce5ae04b0;hpb=cbf85c64a5745b1f08f5c0a5ebda5d9a8d726871;p=tpg%2Facess2.git diff --git a/Modules/USB/UHCI/uhci.c b/Modules/USB/UHCI/uhci.c index 83059ad2..3c2abd9e 100644 --- a/Modules/USB/UHCI/uhci.c +++ b/Modules/USB/UHCI/uhci.c @@ -1,5 +1,7 @@ /* * Acess 2 USB Stack + * - By John Hodge (thePowersGang) + * * Universal Host Controller Interface */ #define DEBUG 1 @@ -20,13 +22,13 @@ void UHCI_Cleanup(); tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont); void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD); -void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *Data, size_t Length); -void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *Data, size_t Length); -void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *Data, size_t Length); -void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *Data, size_t Length); -void UHCI_Hub_Poll(tUSBHub *Hub, tUSBDevice *Dev); +void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); +void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); +void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); +void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); + int UHCI_IsTransferComplete(void *Ptr, void *Handle); int UHCI_Int_InitHost(tUHCI_Controller *Host); -void UHCI_CheckPortUpdate(tUHCI_Controller *Host); +void UHCI_CheckPortUpdate(void *Ptr); void UHCI_InterruptHandler(int IRQ, void *Ptr); // === GLOBALS === @@ -37,7 +39,8 @@ tUSBHostDef gUHCI_HostDef = { .SendIN = UHCI_DataIN, .SendOUT = UHCI_DataOUT, .SendSETUP = UHCI_SendSetup, - .CheckPorts = (void*)UHCI_CheckPortUpdate + .CheckPorts = UHCI_CheckPortUpdate, + .IsOpComplete = UHCI_IsTransferComplete }; // === CODE === @@ -64,6 +67,7 @@ int UHCI_Initialise(const char **Arguments) Log_Warning("UHCI", "MMIO is not supported"); continue ; } + cinfo->IOBase &= ~1; cinfo->IRQNum = PCI_GetIRQ(id); Log_Debug("UHCI", "Controller PCI #%i: IO Base = 0x%x, IRQ %i", @@ -80,6 +84,9 @@ int UHCI_Initialise(const char **Arguments) } cinfo->RootHub = USB_RegisterHost(&gUHCI_HostDef, cinfo, 2); + LOG("cinfo->RootHub = %p", cinfo->RootHub); + + UHCI_CheckPortUpdate(cinfo); i ++; } @@ -105,15 +112,64 @@ tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont) { if(gaUHCI_TDPool[i].Link == 0) { gaUHCI_TDPool[i].Link = 1; + gaUHCI_TDPool[i].Control = 1 << 23; return &gaUHCI_TDPool[i]; } + // Still in use? Skip + if( gaUHCI_TDPool[i].Control & (1 << 23) ) + continue ; + // Is there a callback on it? Skip + if( gaUHCI_TDPool[i]._info.Callback ) + continue ; + // TODO: Garbage collect, but that means removing from the list too + #if 0 + // Ok, this is actually unused + gaUHCI_TDPool[i].Link = 1; + gaUHCI_TDPool[i].Control = 1 << 23; + return &gaUHCI_TDPool[i]; + #endif } return NULL; } +tUHCI_TD *UHCI_int_GetTDFromPhys(tPAddr PAddr) +{ + // TODO: Fix this to work with a non-contiguous pool + static tPAddr td_pool_base; + if(!td_pool_base) td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool ); + return gaUHCI_TDPool + (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]); +} + void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD) { - Log_Warning("UHCI", "TODO: Implement AppendTD"); + int next_frame = (inw(Cont->IOBase + FRNUM) + 2) & (1024-1); + tUHCI_TD *prev_td; + Uint32 link; + + // TODO: How to handle FRNUM incrementing while we are in this function? + +// LOG("USBINTR = 0x%x", inw(Cont->IOBase + USBINTR)); + + // Empty list + if( Cont->FrameList[next_frame] & 1 ) + { + // TODO: Ensure 32-bit paddr + Cont->FrameList[next_frame] = MM_GetPhysAddr( (tVAddr)TD ); + LOG("next_frame = %i", next_frame); + return; + } + + // Find the end of the list + link = Cont->FrameList[next_frame]; + do { + prev_td = UHCI_int_GetTDFromPhys(link); + link = prev_td->Link; + } while( !(link & 1) ); + + // Append + prev_td->Link = MM_GetPhysAddr( (tVAddr)TD ); + + LOG("next_frame = %i, prev_td = %p", next_frame, prev_td); } /** @@ -122,7 +178,9 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD) * \param Addr Function Address * 16 + Endpoint * \param bTgl Data toggle value */ -void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *Data, size_t Length) +void *UHCI_int_SendTransaction( + tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, + tUSBHostCb Cb, void *CbData, void *Data, size_t Length) { tUHCI_TD *td; @@ -130,8 +188,15 @@ void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int td = UHCI_int_AllocateTD(Cont); + if( !td ) { + // TODO: Wait for one to free? + Log_Error("UHCI", "No avaliable TDs, transaction dropped"); + return NULL; + } + td->Link = 1; td->Control = (Length - 1) & 0x7FF; + td->Control |= (1 << 23); td->Token = ((Length - 1) & 0x7FF) << 21; td->Token |= (bTgl & 1) << 19; td->Token |= (Addr & 0xF) << 15; @@ -139,51 +204,60 @@ void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int td->Token |= Type; // TODO: Ensure 32-bit paddr - if( ((tVAddr)Data & PAGE_SIZE) + Length > PAGE_SIZE ) { - Log_Warning("UHCI", "TODO: Support non single page transfers"); + if( ((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE ) { + Log_Warning("UHCI", "TODO: Support non single page transfers (%x + %x > %x)", + (tVAddr)Data & (PAGE_SIZE-1), Length, PAGE_SIZE + ); // TODO: Need to enable IOC to copy the data back // td->BufferPointer = + td->_info.bCopyData = 1; return NULL; } else { td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data ); + td->_info.bCopyData = 0; } // Interrupt on completion if( Cb ) { td->Control |= (1 << 24); - td->Avaliable[0] = (tVAddr)Cb; // NOTE: if ERRPTR then the TD is kept allocated until checked - #if BITS > 32 - td->Avaliable[1] = (tVAddr)Cb >> 32; - #endif - Log_Warning("UHCI", "TODO: Support IOC... somehow"); + LOG("IOC Cb=%p CbData=%p", Cb, CbData); + td->_info.Callback = Cb; // NOTE: if ERRPTR then the TD is kept allocated until checked + td->_info.CallbackPtr = CbData; } + + td->_info.DataPtr = Data; UHCI_int_AppendTD(Cont, td); return td; } -void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *Data, size_t Length) +void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) { - return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x69, DataTgl, Cb, Data, Length); + return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x69, DataTgl, Cb, CbData, Buf, Length); } -void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *Data, size_t Length) +void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) { - return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0xE1, DataTgl, Cb, Data, Length); + return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0xE1, DataTgl, Cb, CbData, Buf, Length); } -void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *Data, size_t Length) +void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) { - return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, Cb, Data, Length); + return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, Cb, CbData, Buf, Length); } -void UHCI_Hub_Poll(tUSBHub *Hub, tUSBDevice *Dev) +int UHCI_IsTransferComplete(void *Ptr, void *Handle) { - tUHCI_Controller *cont = USB_GetDeviceDataPtr(Dev); - - UHCI_CheckPortUpdate(cont); + tUHCI_TD *td = Handle; + int ret; + ret = !(td->Control & (1 << 23)); + if(ret) { + td->_info.Callback = NULL; + td->Link = 1; + } + return ret; } // === INTERNAL FUNCTIONS === @@ -226,14 +300,16 @@ int UHCI_Int_InitHost(tUHCI_Controller *Host) outw( Host->IOBase + USBINTR, 0x000F ); PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 ); + // Enable processing outw( Host->IOBase + USBCMD, 0x0001 ); LEAVE('i', 0); return 0; } -void UHCI_CheckPortUpdate(tUHCI_Controller *Host) +void UHCI_CheckPortUpdate(void *Ptr) { + tUHCI_Controller *Host = Ptr; // Enable ports for( int i = 0; i < 2; i ++ ) { @@ -254,13 +330,13 @@ void UHCI_CheckPortUpdate(tUHCI_Controller *Host) LOG("Port %i has something", i); // Reset port (set bit 9) LOG("Reset"); - outw( port, 0x0100 ); + outw( port, 0x0200 ); Time_Delay(50); // 50ms delay - outw( port, inw(port) & ~0x0100 ); + outw( port, inw(port) & ~0x0200 ); // Enable port LOG("Enable"); Time_Delay(50); // 50ms delay - outw( port, inw(port) & 0x0004 ); + outw( port, inw(port) | 0x0004 ); // Tell USB there's a new device USB_DeviceConnected(Host->RootHub, i); } @@ -269,5 +345,47 @@ void UHCI_CheckPortUpdate(tUHCI_Controller *Host) void UHCI_InterruptHandler(int IRQ, void *Ptr) { - Log_Debug("UHCI", "UHIC Interrupt"); + tUHCI_Controller *Host = Ptr; + int frame = ((int)inw(Host->IOBase + FRNUM) & 0x3FF) - 1; + Uint16 status = inw(Host->IOBase + USBSTS); + if(frame < 0) frame += 1024; + Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x, frame = %i", status, frame); + + // Interrupt-on-completion + if( status & 1 ) + { + tPAddr link; + + link = Host->FrameList[frame]; + Host->FrameList[frame] = 1; + while( !(link & 1) ) + { + tUHCI_TD *td = UHCI_int_GetTDFromPhys(link); + int byte_count = (td->Control&0x7FF)+1; + LOG("link = 0x%x, td = %p, byte_count = %i", link, td, byte_count); + // Handle non-page aligned destination + // TODO: This will break if the destination is not in global memory + if(td->_info.bCopyData) + { + void *ptr = (void*)MM_MapTemp(td->BufferPointer); + memcpy(td->_info.DataPtr, ptr, byte_count); + MM_FreeTemp((tVAddr)ptr); + } + // Callback + if(td->_info.Callback && td->_info.Callback != INVLPTR) + { + LOG("Calling cb %p", td->_info.Callback); + td->_info.Callback(td->_info.CallbackPtr, td->_info.DataPtr, byte_count); + td->_info.Callback = NULL; + } + link = td->Link; + if( td->_info.Callback != INVLPTR ) + td->Link = 1; + } + +// Host->LastCleanedFrame = frame; + } + + LOG("status = 0x%02x", status); + outw(Host->IOBase + USBSTS, status); }