X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FUSB%2FUHCI%2Fuhci.c;h=7b40b143dfbe984faa7b2783037a92a3de3b2572;hb=a2495c6ea4f4cab16b5d339ae511428e92e89e73;hp=9fd82303588e2afcabde6dc29968465db25822ab;hpb=3ab2857efdcb81ce34dabf4d07b39ad6f5ab0b4a;p=tpg%2Facess2.git diff --git a/Modules/USB/UHCI/uhci.c b/Modules/USB/UHCI/uhci.c index 9fd82303..7b40b143 100644 --- a/Modules/USB/UHCI/uhci.c +++ b/Modules/USB/UHCI/uhci.c @@ -18,18 +18,23 @@ #define NUM_TDs 1024 // === PROTOTYPES === - int UHCI_Initialise(); + int UHCI_Initialise(char **Arguments); 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_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); +// +static void _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value); +static void _OutWord(tUHCI_Controller *Host, int Reg, Uint16 Value); +static void _OutDWord(tUHCI_Controller *Host, int Reg, Uint32 Value); +static Uint16 _InWord(tUHCI_Controller *Host, int Reg); // === GLOBALS === MODULE_DEFINE(0, VERSION, USB_UHCI, UHCI_Initialise, NULL, "USB_Core", NULL); @@ -39,7 +44,7 @@ tUSBHostDef gUHCI_HostDef = { .SendIN = UHCI_DataIN, .SendOUT = UHCI_DataOUT, .SendSETUP = UHCI_SendSetup, - .CheckPorts = (void*)UHCI_CheckPortUpdate, + .CheckPorts = UHCI_CheckPortUpdate, .IsOpComplete = UHCI_IsTransferComplete }; @@ -48,7 +53,7 @@ tUSBHostDef gUHCI_HostDef = { * \fn int UHCI_Initialise() * \brief Called to initialise the UHCI Driver */ -int UHCI_Initialise(const char **Arguments) +int UHCI_Initialise(char **Arguments) { int i=0, id=-1; int ret; @@ -56,22 +61,28 @@ int UHCI_Initialise(const char **Arguments) ENTER(""); // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices - while( (id = PCI_GetDeviceByClass(0x0C03, 0xFFFF, id)) >= 0 && i < MAX_CONTROLLERS ) + while( (id = PCI_GetDeviceByClass(0x0C0300, 0xFFFFFF, id)) >= 0 && i < MAX_CONTROLLERS ) { tUHCI_Controller *cinfo = &gUHCI_Controllers[i]; + Uint32 base_addr; // NOTE: Check "protocol" from PCI? cinfo->PciId = id; - cinfo->IOBase = PCI_GetBAR(id, 4); - if( !(cinfo->IOBase & 1) ) { - Log_Warning("UHCI", "MMIO is not supported"); - continue ; + base_addr = PCI_GetBAR(id, 4); + + if( base_addr & 1 ) + { + cinfo->IOBase = base_addr & ~1; + cinfo->MemIOMap = NULL; + } + else + { + cinfo->MemIOMap = (void*)MM_MapHWPages(base_addr, 1); } - cinfo->IOBase &= ~1; cinfo->IRQNum = PCI_GetIRQ(id); Log_Debug("UHCI", "Controller PCI #%i: IO Base = 0x%x, IRQ %i", - id, cinfo->IOBase, cinfo->IRQNum); + id, base_addr, cinfo->IRQNum); IRQ_AddHandler(cinfo->IRQNum, UHCI_InterruptHandler, cinfo); @@ -86,10 +97,14 @@ int UHCI_Initialise(const char **Arguments) cinfo->RootHub = USB_RegisterHost(&gUHCI_HostDef, cinfo, 2); LOG("cinfo->RootHub = %p", cinfo->RootHub); - UHCI_CheckPortUpdate(cinfo); - i ++; } + + if(i == 0) { + LEAVE('i', MODULE_ERR_NOTNEEDED); + return MODULE_ERR_NOTNEEDED; + } + if(i == MAX_CONTROLLERS) { Log_Warning("UHCI", "Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest"); } @@ -132,10 +147,25 @@ tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont) return NULL; } +tUHCI_TD *UHCI_int_GetTDFromPhys(tPAddr PAddr) +{ + // TODO: Fix this to work with a non-contiguous pool + static tPAddr td_pool_base; + const int pool_size = NUM_TDs; + int offset; + if(!td_pool_base) td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool ); + offset = (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]); + if( offset < 0 || offset >= pool_size ) + { + Log_Error("UHCI", "TD PAddr %P not from pool", PAddr); + return NULL; + } + return gaUHCI_TDPool + offset; +} + void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD) { - int next_frame = (inw(Cont->IOBase + FRNUM) + 2) & (1024-1); - tPAddr td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool ); + int next_frame = (_InWord(Cont, FRNUM) + 2) & (1024-1); tUHCI_TD *prev_td; Uint32 link; @@ -146,6 +176,7 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD) { // TODO: Ensure 32-bit paddr Cont->FrameList[next_frame] = MM_GetPhysAddr( (tVAddr)TD ); + TD->Control |= (1 << 24); // Ensure that there is an interrupt for each used frame LOG("next_frame = %i", next_frame); return; } @@ -153,8 +184,7 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD) // Find the end of the list link = Cont->FrameList[next_frame]; do { - // TODO: Fix this to work with a non-contiguous pool - prev_td = gaUHCI_TDPool + (link - td_pool_base) / sizeof(gaUHCI_TDPool[0]); + prev_td = UHCI_int_GetTDFromPhys(link); link = prev_td->Link; } while( !(link & 1) ); @@ -170,7 +200,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; @@ -179,7 +211,7 @@ 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; } @@ -200,48 +232,54 @@ void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int ); // 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); + LOG("IOC Cb=%p CbData=%p", Cb, CbData); td->_info.Callback = Cb; // NOTE: if ERRPTR then the TD is kept allocated until checked - if( Cb != INVLPTR ) - { - Log_Warning("UHCI", "TODO: Support IOC... somehow"); - } + td->_info.CallbackPtr = CbData; } - td->_info.DestPtr = Data; + 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); } int UHCI_IsTransferComplete(void *Ptr, void *Handle) { tUHCI_TD *td = Handle; - return !(td->Control & (1 << 23)); + int ret; + ret = !(td->Control & (1 << 23)); + if(ret) { + td->_info.Callback = NULL; + td->Link = 0; + } + return ret; } // === INTERNAL FUNCTIONS === @@ -254,10 +292,9 @@ int UHCI_Int_InitHost(tUHCI_Controller *Host) { ENTER("pHost", Host); - outw( Host->IOBase + USBCMD, 4 ); // GRESET - Time_Delay(10); + _OutWord( Host, USBCMD, 4 ); // GRESET // TODO: Wait for at least 10ms - outw( Host->IOBase + USBCMD, 0 ); // GRESET + _OutWord( Host, USBCMD, 0 ); // GRESET // Allocate Frame List // - 1 Page, 32-bit address @@ -274,35 +311,39 @@ int UHCI_Int_InitHost(tUHCI_Controller *Host) //! \todo Properly fill frame list // Set frame length to 1 ms - outb( Host->IOBase + SOFMOD, 64 ); + _OutByte( Host, SOFMOD, 64 ); // Set Frame List - outd( Host->IOBase + FLBASEADD, Host->PhysFrameList ); - outw( Host->IOBase + FRNUM, 0 ); + _OutDWord( Host, FLBASEADD, Host->PhysFrameList ); + _OutWord( Host, FRNUM, 0 ); // Enable Interrupts - outw( Host->IOBase + USBINTR, 0x000F ); + _OutWord( Host, USBINTR, 0x000F ); PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 ); // Enable processing - outw( Host->IOBase + USBCMD, 0x0001 ); + _OutWord( Host, 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 ++ ) { - int port = Host->IOBase + PORTSC1 + i*2; + int port = PORTSC1 + i*2; + Uint16 status; + + status = _InWord(Host, port); // Check for port change - if( !(inw(port) & 0x0002) ) continue; - outw(port, 0x0002); + if( !(status & 0x0002) ) continue; + _OutWord(Host, port, 0x0002); // Check if the port is connected - if( !(inw(port) & 1) ) + if( !(status & 1) ) { // Tell the USB code it's gone. USB_DeviceDisconnected(Host->RootHub, i); @@ -313,13 +354,13 @@ void UHCI_CheckPortUpdate(tUHCI_Controller *Host) LOG("Port %i has something", i); // Reset port (set bit 9) LOG("Reset"); - outw( port, 0x0200 ); + _OutWord(Host, port, 0x0200); Time_Delay(50); // 50ms delay - outw( port, inw(port) & ~0x0200 ); + _OutWord(Host, port, _InWord(Host, port) & ~0x0200); // Enable port LOG("Enable"); Time_Delay(50); // 50ms delay - outw( port, inw(port) | 0x0004 ); + _OutWord(Host, port, _InWord(Host, port) | 0x0004); // Tell USB there's a new device USB_DeviceConnected(Host->RootHub, i); } @@ -329,13 +370,87 @@ void UHCI_CheckPortUpdate(tUHCI_Controller *Host) void UHCI_InterruptHandler(int IRQ, void *Ptr) { tUHCI_Controller *Host = Ptr; - Uint16 status = inw(Host->IOBase + USBSTS); - Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x", status); + int frame = (_InWord(Host, FRNUM) - 1) & 0x3FF; + Uint16 status = _InWord(Host, USBSTS); +// Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x, frame = %i", status, frame); + // Interrupt-on-completion if( status & 1 ) { - // Interrupt-on-completion + tPAddr link; + + for( int i = 0; i < 10; i ++ ) + { + link = Host->FrameList[frame]; + Host->FrameList[frame] = 1; + while( link && !(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); + Log_Debug("UHCI", "td->_info.DataPtr = %p", td->_info.DataPtr); + 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 = 0; + } + + if(frame == 0) + frame = 0x3ff; + else + frame --; + } + +// Host->LastCleanedFrame = frame; } - outw(Host->IOBase + USBSTS, status); + LOG("status = 0x%02x", status); + _OutWord(Host, USBSTS, status); } + +void _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value) +{ + if( Host->MemIOMap ) + ((Uint8*)Host->MemIOMap)[Reg] = Value; + else + outb(Host->IOBase + Reg, Value); +} + +void _OutWord(tUHCI_Controller *Host, int Reg, Uint16 Value) +{ + if( Host->MemIOMap ) + Host->MemIOMap[Reg/2] = Value; + else + outw(Host->IOBase + Reg, Value); +} + +void _OutDWord(tUHCI_Controller *Host, int Reg, Uint32 Value) +{ + if( Host->MemIOMap ) + ((Uint32*)Host->MemIOMap)[Reg/4] = Value; + else + outd(Host->IOBase + Reg, Value); +} + +Uint16 _InWord(tUHCI_Controller *Host, int Reg) +{ + if( Host->MemIOMap ) + return Host->MemIOMap[Reg/2]; + else + return inw(Host->IOBase + Reg); +} +