X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FUSB%2FCore%2Fuhci.c;h=f50324fa8a0ac0958b3d7d93cf394f8b348820da;hb=e41e7f0029020a6ab27cfea37e10b5096ca10a3b;hp=fb92d545e49c928ca8097ed25812d82b0f721e6f;hpb=3764c294f21229bdf700f436fa4884f5e76e0d3a;p=tpg%2Facess2.git diff --git a/Modules/USB/Core/uhci.c b/Modules/USB/Core/uhci.c index fb92d545..f50324fa 100644 --- a/Modules/USB/Core/uhci.c +++ b/Modules/USB/Core/uhci.c @@ -1,127 +1,250 @@ -/* - * Acess 2 USB Stack - * Universal Host Controller Interface - */ -#define DEBUG 1 -#include -#include -#include -#include "usb.h" -#include "uhci.h" - -// === CONSTANTS === -#define MAX_CONTROLLERS 4 -#define NUM_TDs 1024 - -// === PROTOTYPES === - int UHCI_Initialise(); -void UHCI_Cleanup(); - int UHCI_IOCtl(tVFS_Node *node, int id, void *data); - int UHCI_Int_InitHost(tUHCI_Controller *Host); - +/* + * Acess 2 USB Stack + * Universal Host Controller Interface + */ +#define DEBUG 1 +#include +#include +#include +#include +#include "usb.h" +#include "uhci.h" + +// === CONSTANTS === +#define MAX_CONTROLLERS 4 +#define NUM_TDs 1024 + +// === PROTOTYPES === + int UHCI_Initialise(); +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, int bIOC, void *Data, size_t Length); +void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); +void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); +void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); + int UHCI_Int_InitHost(tUHCI_Controller *Host); +void UHCI_InterruptHandler(int IRQ, void *Ptr); + // === GLOBALS === -//Uint gaFrameList[1024]; -tUHCI_TD gaUHCI_TDPool[NUM_TDs]; -tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS]; - -// === CODE === -/** - * \fn int UHCI_Initialise() - * \brief Called to initialise the UHCI Driver - */ -int UHCI_Initialise() -{ - int i=0, id=-1; - int ret; - - ENTER(""); - - // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices - while( (id = PCI_GetDeviceByClass(0x0C03, 0xFFFF, id)) >= 0 && i < MAX_CONTROLLERS ) - { - // NOTE: Check "protocol" from PCI? - - gUHCI_Controllers[i].PciId = id; - // Assign a port range (BAR4, Reserve 32 ports) - //base = PCI_AssignPort( id, 4, 0x20 ); - gUHCI_Controllers[i].IOBase = PCI_GetBAR4(id); - gUHCI_Controllers[i].IRQNum = PCI_GetIRQ(id); - - Log("[USB ] Controller PCI #%i: IO Base = 0x%x, IRQ %i", - id, gUHCI_Controllers[i].IOBase, gUHCI_Controllers[i].IRQNum); - - // Initialise Host - ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]); - // Detect an error - if(ret != 0) { - LEAVE('i', ret); - return ret; - } - - i ++; - } - if(i == MAX_CONTROLLERS) { - Warning("[UHCI ] Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest"); - } - LEAVE('i', i); - return i; -} - -/** - * \fn void UHCI_Cleanup() - * \brief Called just before module is unloaded - */ -void UHCI_Cleanup() -{ +tUHCI_TD gaUHCI_TDPool[NUM_TDs]; +tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS]; +tUSBHost gUHCI_HostDef = { + .SendIN = UHCI_DataIN, + .SendOUT = UHCI_DataOUT, + .SendSETUP = UHCI_SendSetup, + }; + +// === CODE === +/** + * \fn int UHCI_Initialise() + * \brief Called to initialise the UHCI Driver + */ +int UHCI_Initialise(const char **Arguments) +{ + int i=0, id=-1; + int ret; + + ENTER(""); + + // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices + while( (id = PCI_GetDeviceByClass(0x0C03, 0xFFFF, id)) >= 0 && i < MAX_CONTROLLERS ) + { + tUHCI_Controller *cinfo = &gUHCI_Controllers[i]; + // NOTE: Check "protocol" from PCI? + + cinfo->PciId = id; + // Assign a port range (BAR4, Reserve 32 ports) + cinfo->IOBase = PCI_GetBAR(id, 4); + if( !(cinfo->IOBase & 1) ) { + Log_Warning("UHCI", "MMIO is not supported"); + continue ; + } + cinfo->IRQNum = PCI_GetIRQ(id); + + Log_Debug("UHCI", "Controller PCI #%i: IO Base = 0x%x, IRQ %i", + id, cinfo->IOBase, cinfo->IRQNum); + + IRQ_AddHandler(cinfo->IRQNum, UHCI_InterruptHandler, cinfo); + + // Initialise Host + ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]); + // Detect an error + if(ret != 0) { + LEAVE('i', ret); + return ret; + } + + USB_RegisterHost(&gUHCI_HostDef, cinfo); + + i ++; + } + if(i == MAX_CONTROLLERS) { + Log_Warning("UHCI", "Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest"); + } + LEAVE('i', MODULE_ERR_OK); + return MODULE_ERR_OK; +} + +/** + * \fn void UHCI_Cleanup() + * \brief Called just before module is unloaded + */ +void UHCI_Cleanup() +{ +} + +tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont) +{ + int i; + for(i = 0; i < NUM_TDs; i ++) + { + if(gaUHCI_TDPool[i].Link == 0) { + gaUHCI_TDPool[i].Link = 1; + return &gaUHCI_TDPool[i]; + } + } + return NULL; +} + +void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD) +{ + Log_Warning("UHCI", "TODO: Implement AppendTD"); +} + +/** + * \brief Send a transaction to the USB bus + * \param Cont Controller pointer + * \param Addr Function Address * 16 + Endpoint + * \param bTgl Data toggle value + */ +void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, int bIOC, void *Data, size_t Length) +{ + tUHCI_TD *td; + + if( Length > 0x400 ) return NULL; // Controller allows up to 0x500, but USB doesn't + + td = UHCI_int_AllocateTD(Cont); + + td->Link = 1; + td->Control = (Length - 1) & 0x7FF; + td->Token = ((Length - 1) & 0x7FF) << 21; + td->Token |= (bTgl & 1) << 19; + td->Token |= (Addr & 0xF) << 15; + td->Token |= ((Addr/16) & 0xFF) << 8; + 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"); +// td->BufferPointer = + return NULL; + } + else { + td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data ); + } + + if( bIOC ) { +// td->Control + } + + UHCI_int_AppendTD(Cont, td); + + return td; +} + +void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length) +{ + return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x69, DataTgl, bIOC, Data, Length); +} + +void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length) +{ + return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0xE1, DataTgl, bIOC, Data, Length); +} + +void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length) +{ + return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, bIOC, Data, Length); +} + +// === INTERNAL FUNCTIONS === +/** + * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host) + * \brief Initialises a UHCI host controller + * \param Host Pointer - Host to initialise + */ +int UHCI_Int_InitHost(tUHCI_Controller *Host) +{ + ENTER("pHost", Host); + + outw( Host->IOBase + USBCMD, 4 ); // GRESET + Time_Delay(10); + // TODO: Wait for at least 10ms + outw( Host->IOBase + USBCMD, 0 ); // GRESET + + // Allocate Frame List + // - 1 Page, 32-bit address + // - 1 page = 1024 4 byte entries + Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList); + if( !Host->FrameList ) { + Log_Warning("UHCI", "Unable to allocate frame list, aborting"); + LEAVE('i', -1); + return -1; + } + LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList); + memsetd( Host->FrameList, 1, 1024 ); // Clear List (Disabling all entries) + + //! \todo Properly fill frame list + + // Set frame length to 1 ms + outb( Host->IOBase + SOFMOD, 64 ); + + // Set Frame List + outd( Host->IOBase + FLBASEADD, Host->PhysFrameList ); + outw( Host->IOBase + FRNUM, 0 ); + + // Enable Interrupts + outw( Host->IOBase + USBINTR, 0x000F ); + PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 ); + + outw( Host->IOBase + USBCMD, 0x0001 ); + + LEAVE('i', 0); + return 0; +} + +void UHCI_CheckPortUpdate(tUHCI_Controller *Host) +{ + // Enable ports + for( int i = 0; i < 2; i ++ ) + { + int port = Host->IOBase + PORTSC1 + i*2; + // Check for port change + if( !(inw(port) & 0x0002) ) continue; + outw(port, 0x0002); + + // Check if the port is connected + if( !(inw(port) & 1) ) + { + // TODO: Tell the USB code it's gone? + continue; + } + else + { + LOG("Port %i has something", i); + // Reset port (set bit 9) + outw( port, 0x0100 ); + Time_Delay(50); // 50ms delay + outw( port, inw(port) & ~0x0100 ); + // Enable port + Time_Delay(50); // 50ms delay + outw( port, inw(port) & 0x0004 ); + } + } +} + +void UHCI_InterruptHandler(int IRQ, void *Ptr) +{ + Log_Debug("UHCI", "UHIC Interrupt"); } - -/** - * \brief Sends a packet to a device endpoint - */ -int UHCI_SendPacket(int ControllerId, int Length) -{ - //tUHCI_TD *td = UHCI_AllocateTD(); - return 0; -} - -// === INTERNAL FUNCTIONS === -/** - * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host) - * \brief Initialises a UHCI host controller - * \param Host Pointer - Host to initialise - */ -int UHCI_Int_InitHost(tUHCI_Controller *Host) -{ - ENTER("pHost", Host); - - outw( Host->IOBase + USBCMD, 4 ); // GRESET - // TODO: Wait for at least 10ms - outw( Host->IOBase + USBCMD, 0 ); // GRESET - - // Allocate Frame List - Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList); // 1 Page, 32-bit - if( !Host->FrameList ) { - Log_Warning("UHCI", "Unable to allocate frame list, aborting"); - LEAVE('i', -1); - return -1; - } - LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList); - memsetd( Host->FrameList, 1, 1024 ); // Clear List (Disabling all entries) - - //! \todo Properly fill frame list - - // Set frame length to 1 ms - outb( Host->IOBase + SOFMOD, 64 ); - - // Set Frame List Address - outd( Host->IOBase + FLBASEADD, Host->PhysFrameList ); - - // Set Frame Number - outw( Host->IOBase + FRNUM, 0 ); - - // Enable Interrupts - //PCI_WriteWord( Host->PciId, 0xC0, 0x2000 ); - - LEAVE('i', 0); - return 0; -}