From: John Hodge Date: Fri, 25 Nov 2011 01:53:00 +0000 (+0800) Subject: Modules/USB - Working on a structure for the USB subsystem X-Git-Tag: rel0.14~72 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=dfe55553735a8cfa2b7207e5096caddded32c992;p=tpg%2Facess2.git Modules/USB - Working on a structure for the USB subsystem --- diff --git a/Makefile.cfg b/Makefile.cfg index 3b1bfd5e..d36dca54 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -54,10 +54,10 @@ MODULES += Storage/FDDv2 MODULES += Network/NE2000 Network/RTL8139 MODULES += Display/VESA MODULES += Display/BochsGA -#MODULES += Interfaces/UDI MODULES += Input/PS2KbMouse MODULES += x86/ISADMA x86/VGAText -MODULES += USB/Core +MODULES += USB/Core USB/UHCI +#MODULES += Interfaces/UDI endif ifeq ($(ARCHDIR),x86_64) @@ -68,7 +68,6 @@ MODULES += Display/BochsGA MODULES += Interfaces/UDI MODULES += Input/PS2KbMouse MODULES += x86/ISADMA x86/VGAText -MODULES += USB/Core endif ifeq ($(ARCHDIR),armv7) diff --git a/Modules/USB/Core/Makefile b/Modules/USB/Core/Makefile index b4cd3237..7e8c30d9 100644 --- a/Modules/USB/Core/Makefile +++ b/Modules/USB/Core/Makefile @@ -1,7 +1,8 @@ # # -OBJ = main.o usb.o uhci.o +OBJ = main.o usb.o +CPPFLAGS = -Iinclude NAME = Core -include ../Makefile.tpl diff --git a/Modules/USB/Core/include/usb_core.h b/Modules/USB/Core/include/usb_core.h new file mode 100644 index 00000000..9169b0fa --- /dev/null +++ b/Modules/USB/Core/include/usb_core.h @@ -0,0 +1,43 @@ +/* + * Acess2 USB Stack + * - By John Hodge (thePowersGang) + * + * usb_core.h + * - Core USB IO Header + */ +#ifndef _USB_CORE_H_ +#define _USB_CORE_H_ + +typedef struct sUSBDevice tUSBDevice; +typedef struct sUSBDriver tUSBDriver; + +/** + */ +struct sUSBDriver +{ + tUSBDriver *Next; + + const char *Name; + + // TODO: Check class codes and provide other identifcation options + Uint32 ClassCode; + + void (*Connected)(tUSBDevice *Dev); + void (*Disconnected)(tUSBDevice *Dev); + + int MaxEndpoints; + struct { + // 0: Bulk, 1: Control, 2: Interrupt + int Type; + // Data availiable Callback + void (*Interrupt)(tUSBDevice *Dev, int Length, void *Data); + } Endpoints[]; +}; + +extern void *USB_GetDeviceDataPtr(tUSBDevice *Dev); +extern void USB_SetDeviceDataPtr(tUSBDevice *Dev, void *Ptr); + +extern void USB_SendData(tUSBDevice *Dev, int Endpoint, int Length, void *Data); + +#endif + diff --git a/Modules/USB/Core/include/usb_host.h b/Modules/USB/Core/include/usb_host.h new file mode 100644 index 00000000..7dc79243 --- /dev/null +++ b/Modules/USB/Core/include/usb_host.h @@ -0,0 +1,31 @@ +/* + * Acess2 USB Stack + * - By John Hodge (thePowersGang) + * + * usb_host.h + * - USB Host Controller Interface + */ +#ifndef _USB_HOST_H_ +#define _USB_HOST_H_ + +#include "usb_core.h" +#include "usb_hub.h" + +typedef struct sUSBHostDef tUSBHostDef; + +/** + * \brief Defines a USB Host Controller type + */ +struct sUSBHostDef +{ + void *(*SendIN)(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); + void *(*SendOUT)(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); + void *(*SendSETUP)(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); + + void (*CheckPorts)(void *Ptr); +}; + +extern tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts); + +#endif + diff --git a/Modules/USB/Core/include/usb_hub.h b/Modules/USB/Core/include/usb_hub.h new file mode 100644 index 00000000..f48936bc --- /dev/null +++ b/Modules/USB/Core/include/usb_hub.h @@ -0,0 +1,28 @@ +/* + * Acess2 USB Stack + * - By John Hodge (thePowersGang) + * + * usb_hub.h + * - Core Hub Definitions + */ +#ifndef _USB_HUB_H_ +#define _USB_HUB_H_ + +#include "usb_core.h" + +typedef struct sUSBHub tUSBHub; + +typedef void (*tUSB_HubPoll)(tUSBHub *Hub, tUSBDevice *HubDev); + +/** + * \brief Register a device as a hub + * + * Used by the hub class initialisation routine. + */ +extern tUSBHub USB_RegisterHub(tUSBDevice *Device, int nPorts, tUSB_HubPoll PollCallback); + +extern void USB_DeviceConnected(tUSBHub *Hub, int Port); +extern void USB_DeviceDisconnected(tUSBHub *Hub, int Port); + +#endif + diff --git a/Modules/USB/Core/main.c b/Modules/USB/Core/main.c index 9a6458ef..baf13320 100644 --- a/Modules/USB/Core/main.c +++ b/Modules/USB/Core/main.c @@ -10,9 +10,6 @@ #include #include "usb.h" -// === IMPORTS === -extern int UHCI_Initialise(void); - // === PROTOTYPES === int USB_Install(char **Arguments); void USB_Cleanup(void); @@ -32,8 +29,9 @@ tDevFS_Driver gUSB_DrvInfo = { .IOCtl = USB_IOCtl } }; -tUSBDevice *gUSB_RootHubs = NULL; tUSBHost *gUSB_Hosts = NULL; +tUSBHub *gUSB_Hubs = NULL; +tUSBHub *gUSB_HubsEnd = NULL; // === CODE === /** @@ -41,7 +39,6 @@ tUSBHost *gUSB_Hosts = NULL; */ int USB_Install(char **Arguments) { - UHCI_Initialise(); Log_Warning("USB", "Not Complete - Devel Only"); return MODULE_ERR_OK; } @@ -53,15 +50,12 @@ int USB_PollThread(void *unused) { for(;;) { - for( tUSBHost *host = gUSB_Hosts; host; host = host->Next ) - { - // host->CheckPorts(host); - } - - for( tUSBDevice *dev = gUSB_RootHubs; dev; dev = dev->Next ) + for( tUSBHub *hub = gUSB_Hubs; hub; hub = hub->Next ) { - + hub->CheckPorts(hub, hub->Device); } + // TODO: Fine tune + Time_Delay(250); } } diff --git a/Modules/USB/Core/uhci.c b/Modules/USB/Core/uhci.c deleted file mode 100644 index f50324fa..00000000 --- a/Modules/USB/Core/uhci.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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 === -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"); -} diff --git a/Modules/USB/Core/uhci.h b/Modules/USB/Core/uhci.h deleted file mode 100644 index 968ce431..00000000 --- a/Modules/USB/Core/uhci.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * AcessOS Version 1 - * USB Stack - * - Universal Host Controller Interface - */ -#ifndef _UHCI_H_ -#define _UHCI_H_ - -// === TYPES === -typedef struct sUHCI_Controller tUHCI_Controller; -typedef struct sUHCI_TD tUHCI_TD; -typedef struct sUHCI_QH tUHCI_QH; - -// === STRUCTURES === -struct sUHCI_Controller -{ - /** - * \brief PCI Device ID - */ - Uint16 PciId; - - /** - * \brief IO Base Address - */ - Uint16 IOBase; - - /** - * \brief IRQ Number assigned to the device - */ - int IRQNum; - - /** - * \brief Frame list - * - * 31:4 - Frame Pointer - * 3:2 - Reserved - * 1 - QH/TD Selector - * 0 - Terminate (Empty Pointer) - */ - Uint32 *FrameList; - - /** - * \brief Physical Address of the Frame List - */ - tPAddr PhysFrameList; -}; - -struct sUHCI_TD -{ - /** - * \brief Next Entry in list - * - * 31:4 - Address - * 3 - Reserved - * 2 - Depth/Breadth Select - * 1 - QH/TD Select - * 0 - Terminate (Last in List) - */ - Uint32 Link; - - /** - * \brief Control and Status Field - * - * 31:30 - Reserved - * 29 - Short Packet Detect (Input Only) - * 28:27 - Number of Errors Allowed - * 26 - Low Speed Device (Communicating with a low speed device) - * 25 - Isynchonious Select - * 24 - Interrupt on Completion (IOC) - * 23:16 - Status - * 23 - Active - * 22 - Stalled - * 21 - Data Buffer Error - * 20 - Babble Detected - * 19 - NAK Detected - * 18 - CRC/Timout Error - * 17 - Bitstuff Error - * 16 - Reserved - * 15:11 - Reserved - * 10:0 - Actual Length (Number of bytes transfered) - */ - Uint32 Control; - - /** - * \brief Packet Header - * - * 31:21 - Maximum Length (0=1, Max 0x4FF, 0x7FF=0) - * 20 - Reserved - * 19 - Data Toggle - * 18:15 - Endpoint - * 14:8 - Device Address - * 7:0 - PID (Packet Identifcation) - Only 96, E1, 2D allowed - * - * 0x96 = Data IN - * 0xE1 = Data Out - * 0x2D = Setup - */ - Uint32 Token; - - /** - * \brief Pointer to the data to send - */ - Uint32 BufferPointer; - - /** - * \brief Avaliable for use by software - */ - Uint32 Avaliable[4]; -}; - -struct sUHCI_QH -{ - /** - * \brief Next Entry in list - * - * 31:4 - Address - * 3:2 - Reserved - * 1 - QH/TD Select - * 0 - Terminate (Last in List) - */ - Uint32 Next; - - - /** - * \brief Next Entry in list - * - * 31:4 - Address - * 3:2 - Reserved - * 1 - QH/TD Select - * 0 - Terminate (Last in List) - */ - Uint32 Child; -}; - -// === ENUMERATIONS === -enum eUHCI_IOPorts { - /** - * \brief USB Command Register - * - * 15:8 - Reserved - * 7 - Maximum Packet Size selector (1: 64 bytes, 0: 32 bytes) - * 6 - Configure Flag (No Hardware Effect) - * 5 - Software Debug (Don't think it will be needed) - * 4 - Force Global Resume - * 3 - Enter Global Suspend Mode - * 2 - Global Reset (Resets all devices on the bus) - * 1 - Host Controller Reset (Reset just the controller) - * 0 - Run/Stop - */ - USBCMD = 0x00, - /** - * \brief USB Status Register - * - * 15:6 - Reserved - * 5 - HC Halted, set to 1 when USBCMD:RS is set to 0 - * 4 - Host Controller Process Error (Errors related to the bus) - * 3 - Host System Error (Errors related to the OS/PCI Bus) - * 2 - Resume Detect (Set if a RESUME command is sent to the Controller) - * 1 - USB Error Interrupt - * 0 - USB Interrupts (Set if a transaction with the IOC bit set is completed) - */ - USBSTS = 0x02, - /** - * \brief USB Interrupt Enable Register - * - * 15:4 - Reserved - * 3 - Short Packet Interrupt Enable - * 2 - Interrupt on Complete (IOC) Enable - * 1 - Resume Interrupt Enable - * 0 - Timout / CRC Error Interrupt Enable - */ - USBINTR = 0x04, - /** - * \brief Frame Number (Index into the Frame List) - * - * 15:11 - Reserved - * 10:0 - Index (Incremented each approx 1ms) - */ - FRNUM = 0x06, - /** - * \brief Frame List Base Address - * - * 31:12 - Pysical Address >> 12 - * 11:0 - Reserved (Set to Zero) - */ - FLBASEADD = 0x08, // 32-bit - /** - * \brief Start-of-frame Modify Register - * \note 8-bits only - * - * Sets the size of a frame - * Frequency = (11936+n)/12000 kHz - * - * 7 - Reserved - * 6:0 - - */ - SOFMOD = 0x0C, // 8bit - /** - * \brief Port Status and Controll Register (Port 1) - * - * 15:13 - Reserved - * 12 - Suspend - * 11:10 - Reserved - * 9 - Port Reset - * 8 - Low Speed Device Attached - * 5:4 - Line Status - * 3 - Port Enable/Disable Change - Used for detecting device removal - * 2 - Port Enable/Disable - * 1 - Connect Status Change - * 0 - Current Connect Status - */ - PORTSC1 = 0x10, - /** - * \brief Port Status and Controll Register (Port 2) - * - * See ::PORTSC1 - */ - PORTSC2 = 0x12 -}; - -#endif diff --git a/Modules/USB/Core/usb.c b/Modules/USB/Core/usb.c index ab9a4894..de884e48 100644 --- a/Modules/USB/Core/usb.c +++ b/Modules/USB/Core/usb.c @@ -7,24 +7,57 @@ #include #include #include "usb.h" +#include "usb_proto.h" +// === STRUCTURES === // === CODE === -void USB_RegisterHost(tUSBHost *HostDef, void *ControllerPtr) +tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts) { // TODO: + return NULL; +} + +void USB_DeviceConnected(tUSBHub *Hub, int Port) +{ + if( Port >= Hub->nPorts ) return ; + if( Hub->Devices[Port] ) return ; + + // 0. Perform port init? (done in hub?) + // 1. Assign an address + + // 2. Get device information +} + +void USB_DeviceDisconnected(tUSBHub *Hub, int Port) +{ + +} + +void *USB_GetDeviceDataPtr(tUSBDevice *Dev) { return Dev->Data; } +void USB_SetDeviceDataPtr(tUSBDevice *Dev, void *Ptr) { Dev->Data = Ptr; } + +int USB_int_AllocateAddress(tUSBHost *Host) +{ + int i; + for( i = 1; i < 128; i ++ ) + { + if(Host->AddressBitmap[i/8] & (1 << i)) + continue ; + return i; + } + return 0; } int USB_int_SendSetupSetAddress(tUSBHost *Host, void *Ptr, int Address) { - Uint8 data[8]; - data[0] = 0; // bmRequestType - data[1] = 5; // SET_ADDRESS - data[2] = Address & 0x7F; // wValue (low) - data[3] = 0; // wValue (high) - data[4] = 0; // wLength - data[6] = 0; // wLength + struct sDeviceRequest req; + req.ReqType = 0; // bmRequestType + req.Request = 5; // SET_ADDRESS + req.Value = Address & 0x7F; // wValue + req.Index = 0; // wIndex + req.Length = 0; // wLength // Addr 0:0, Data Toggle = 0, no interrupt - return Host->SendSETUP(Ptr, 0, 0, 0, FALSE, data, 8) == NULL; + return Host->HostDef->SendSETUP(Ptr, 0, 0, 0, FALSE, &req, sizeof(req)) == NULL; } diff --git a/Modules/USB/Core/usb.h b/Modules/USB/Core/usb.h index 9bc45c8e..65bba9d0 100644 --- a/Modules/USB/Core/usb.h +++ b/Modules/USB/Core/usb.h @@ -5,37 +5,23 @@ #ifndef _USB_H_ #define _USB_H_ -// === TYPES === +#include +#include +#include + typedef struct sUSBHost tUSBHost; -typedef struct sUSBHub tUSBHub; -typedef struct sUSBDevice tUSBDevice; // === STRUCTURES === -/** - * \brief Defines a USB Host Controller type - */ -struct sUSBHost -{ - tUSBHost *Next; - - void (*CheckPorts)(void *Ptr); - - void *(*SendIN)(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); - void *(*SendOUT)(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); - void *(*SendSETUP)(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length); -}; - /** * \brief USB Hub data */ struct sUSBHub { - /** - * \brief Host controller used - */ - tUSBHost *HostDef; - void *Controller; - + tUSBHub *Next; + tUSBDevice *Device; + + tUSB_HubPoll CheckPorts; + int nPorts; tUSBDevice *Devices[]; }; @@ -46,19 +32,28 @@ struct sUSBHub struct sUSBDevice { tUSBDevice *Next; - tUSBDevice *Hub; + tUSBDevice *ParentHub; + /** + * \brief Host controller used + */ + tUSBHost *Host; int Address; - int Type; + tUSBDriver *Driver; + void *Data; +}; + +struct sUSBHost +{ + struct sUSBHost *Next; + + tUSBHostDef *HostDef; + void *Ptr; - union { - tUSBHub Hub; - char Impl[0]; - } Data; + Uint8 AddressBitmap[128/8]; }; -extern void USB_RegisterHost(tUSBHost *HostDef, void *ControllerPtr); extern void USB_NewDevice(tUSBHub *Hub); #endif diff --git a/Modules/USB/Core/usb_proto.h b/Modules/USB/Core/usb_proto.h new file mode 100644 index 00000000..3a98e479 --- /dev/null +++ b/Modules/USB/Core/usb_proto.h @@ -0,0 +1,38 @@ +/** + */ +#ifndef _USB_PROTO_H_ +#define _USB_PROTO_H_ + +struct sDeviceRequest +{ + Uint8 ReqType; + Uint8 Request; + Uint16 Value; + Uint16 Index; + Uint16 Length; +}; + +/* + */ +struct sDescriptor_Device +{ + Uint8 Length; + Uint8 Type; // = + Uint16 USBVersion; // BCD, 0x210 = 2.10 + Uint8 DeviceClass; + Uint8 DeviceSubClass; + Uint8 DeviceProtocol; + Uint8 MaxPacketSize; + + Uint16 VendorID; + Uint16 ProductID; + + Uint8 ManufacturerStr; + Uint8 ProductStr; + Uint8 SerialNumberStr; + + Uint8 NumConfigurations; +}; + +#endif + diff --git a/Modules/USB/HID/hid.h b/Modules/USB/HID/hid.h new file mode 100644 index 00000000..373496e8 --- /dev/null +++ b/Modules/USB/HID/hid.h @@ -0,0 +1,47 @@ +/* + * Acess2 USB Stack HID Driver + * - By John Hodge (thePowersGang) + * + * hid.h + * - Core header + */ +#ifndef _HID_H_ +#define _HID_H_ + +// Report Descriptor Types +// - 0: Main +// > 8: Input - Axis/Button etc +// > 9: Output - LED/Position +// > B: Feature - +// > A: Collection - Group of Input/Output/Feature +// > C: End collection +// - 1: Global (Not restored on main) +// - 2: Local +// > +// - 3: Reserved/Unused + +// I/O/F Data Values +#define HID_IOF_CONSTANT 0x001 //!< Host Read-only +#define HID_IOF_VARIABLE 0x002 //!< + +struct sLongItem +{ + Uint8 Header; // 0xFE (Tag 15, Type 3, Size 2) + Uint8 DataSize; + Uint8 Tag; +}; + +struct sDescriptor_HID +{ + Uint8 Length; + Uint8 Type; // + Uint16 Version; // 0x0111 = 1.11 + Uint8 CountryCode; + Uint8 NumDescriptors; // >= 1 + struct { + Uint8 DescType; + Uint16 DescLen; + } Descriptors[]; +} + +#endif diff --git a/Modules/USB/UHCI/Makefile b/Modules/USB/UHCI/Makefile new file mode 100644 index 00000000..798159af --- /dev/null +++ b/Modules/USB/UHCI/Makefile @@ -0,0 +1,8 @@ +# +# + +OBJ = uhci.o +CPPFLAGS = -I../Core/include +NAME = UHCI + +-include ../Makefile.tpl diff --git a/Modules/USB/UHCI/uhci.c b/Modules/USB/UHCI/uhci.c new file mode 100644 index 00000000..8e41e27a --- /dev/null +++ b/Modules/USB/UHCI/uhci.c @@ -0,0 +1,265 @@ +/* + * Acess 2 USB Stack + * Universal Host Controller Interface + */ +#define DEBUG 1 +#define VERSION VER2(0,5) +#include +#include +#include +#include +#include +#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); +void UHCI_Hub_Poll(tUSBHub *Hub, tUSBDevice *Dev); + int UHCI_Int_InitHost(tUHCI_Controller *Host); +void UHCI_CheckPortUpdate(tUHCI_Controller *Host); +void UHCI_InterruptHandler(int IRQ, void *Ptr); + +// === GLOBALS === +MODULE_DEFINE(0, VERSION, USB_UHCI, UHCI_Initialise, NULL, "USB_Core", NULL); +tUHCI_TD gaUHCI_TDPool[NUM_TDs]; +tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS]; +tUSBHostDef gUHCI_HostDef = { + .SendIN = UHCI_DataIN, + .SendOUT = UHCI_DataOUT, + .SendSETUP = UHCI_SendSetup, + .CheckPorts = (void*)UHCI_CheckPortUpdate + }; + +// === 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; + } + + cinfo->RootHub = USB_RegisterHost(&gUHCI_HostDef, cinfo, 2); + + 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); +} + +void UHCI_Hub_Poll(tUSBHub *Hub, tUSBDevice *Dev) +{ + tUHCI_Controller *cont = USB_GetDeviceDataPtr(Dev); + + UHCI_CheckPortUpdate(cont); +} + +// === 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) ) + { + // Tell the USB code it's gone. + USB_DeviceDisconnected(Host->RootHub, i); + 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 ); + // Tell USB there's a new device + USB_DeviceConnected(Host->RootHub, i); + } + } +} + +void UHCI_InterruptHandler(int IRQ, void *Ptr) +{ + Log_Debug("UHCI", "UHIC Interrupt"); +} diff --git a/Modules/USB/UHCI/uhci.h b/Modules/USB/UHCI/uhci.h new file mode 100644 index 00000000..7d88d354 --- /dev/null +++ b/Modules/USB/UHCI/uhci.h @@ -0,0 +1,223 @@ +/* + * AcessOS Version 1 + * USB Stack + * - Universal Host Controller Interface + */ +#ifndef _UHCI_H_ +#define _UHCI_H_ + +// === TYPES === +typedef struct sUHCI_Controller tUHCI_Controller; +typedef struct sUHCI_TD tUHCI_TD; +typedef struct sUHCI_QH tUHCI_QH; + +// === STRUCTURES === +struct sUHCI_Controller +{ + /** + * \brief PCI Device ID + */ + Uint16 PciId; + + /** + * \brief IO Base Address + */ + Uint16 IOBase; + + /** + * \brief IRQ Number assigned to the device + */ + int IRQNum; + + /** + * \brief Frame list + * + * 31:4 - Frame Pointer + * 3:2 - Reserved + * 1 - QH/TD Selector + * 0 - Terminate (Empty Pointer) + */ + Uint32 *FrameList; + + /** + * \brief Physical Address of the Frame List + */ + tPAddr PhysFrameList; + + tUSBHub *RootHub; +}; + +struct sUHCI_TD +{ + /** + * \brief Next Entry in list + * + * 31:4 - Address + * 3 - Reserved + * 2 - Depth/Breadth Select + * 1 - QH/TD Select + * 0 - Terminate (Last in List) + */ + Uint32 Link; + + /** + * \brief Control and Status Field + * + * 31:30 - Reserved + * 29 - Short Packet Detect (Input Only) + * 28:27 - Number of Errors Allowed + * 26 - Low Speed Device (Communicating with a low speed device) + * 25 - Isynchonious Select + * 24 - Interrupt on Completion (IOC) + * 23:16 - Status + * 23 - Active + * 22 - Stalled + * 21 - Data Buffer Error + * 20 - Babble Detected + * 19 - NAK Detected + * 18 - CRC/Timout Error + * 17 - Bitstuff Error + * 16 - Reserved + * 15:11 - Reserved + * 10:0 - Actual Length (Number of bytes transfered) + */ + Uint32 Control; + + /** + * \brief Packet Header + * + * 31:21 - Maximum Length (0=1, Max 0x4FF, 0x7FF=0) + * 20 - Reserved + * 19 - Data Toggle + * 18:15 - Endpoint + * 14:8 - Device Address + * 7:0 - PID (Packet Identifcation) - Only 96, E1, 2D allowed + * + * 0x96 = Data IN + * 0xE1 = Data Out + * 0x2D = Setup + */ + Uint32 Token; + + /** + * \brief Pointer to the data to send + */ + Uint32 BufferPointer; + + /** + * \brief Avaliable for use by software + */ + Uint32 Avaliable[4]; +}; + +struct sUHCI_QH +{ + /** + * \brief Next Entry in list + * + * 31:4 - Address + * 3:2 - Reserved + * 1 - QH/TD Select + * 0 - Terminate (Last in List) + */ + Uint32 Next; + + + /** + * \brief Next Entry in list + * + * 31:4 - Address + * 3:2 - Reserved + * 1 - QH/TD Select + * 0 - Terminate (Last in List) + */ + Uint32 Child; +}; + +// === ENUMERATIONS === +enum eUHCI_IOPorts { + /** + * \brief USB Command Register + * + * 15:8 - Reserved + * 7 - Maximum Packet Size selector (1: 64 bytes, 0: 32 bytes) + * 6 - Configure Flag (No Hardware Effect) + * 5 - Software Debug (Don't think it will be needed) + * 4 - Force Global Resume + * 3 - Enter Global Suspend Mode + * 2 - Global Reset (Resets all devices on the bus) + * 1 - Host Controller Reset (Reset just the controller) + * 0 - Run/Stop + */ + USBCMD = 0x00, + /** + * \brief USB Status Register + * + * 15:6 - Reserved + * 5 - HC Halted, set to 1 when USBCMD:RS is set to 0 + * 4 - Host Controller Process Error (Errors related to the bus) + * 3 - Host System Error (Errors related to the OS/PCI Bus) + * 2 - Resume Detect (Set if a RESUME command is sent to the Controller) + * 1 - USB Error Interrupt + * 0 - USB Interrupts (Set if a transaction with the IOC bit set is completed) + */ + USBSTS = 0x02, + /** + * \brief USB Interrupt Enable Register + * + * 15:4 - Reserved + * 3 - Short Packet Interrupt Enable + * 2 - Interrupt on Complete (IOC) Enable + * 1 - Resume Interrupt Enable + * 0 - Timout / CRC Error Interrupt Enable + */ + USBINTR = 0x04, + /** + * \brief Frame Number (Index into the Frame List) + * + * 15:11 - Reserved + * 10:0 - Index (Incremented each approx 1ms) + */ + FRNUM = 0x06, + /** + * \brief Frame List Base Address + * + * 31:12 - Pysical Address >> 12 + * 11:0 - Reserved (Set to Zero) + */ + FLBASEADD = 0x08, // 32-bit + /** + * \brief Start-of-frame Modify Register + * \note 8-bits only + * + * Sets the size of a frame + * Frequency = (11936+n)/12000 kHz + * + * 7 - Reserved + * 6:0 - + */ + SOFMOD = 0x0C, // 8bit + /** + * \brief Port Status and Controll Register (Port 1) + * + * 15:13 - Reserved + * 12 - Suspend + * 11:10 - Reserved + * 9 - Port Reset + * 8 - Low Speed Device Attached + * 5:4 - Line Status + * 3 - Port Enable/Disable Change - Used for detecting device removal + * 2 - Port Enable/Disable + * 1 - Connect Status Change + * 0 - Current Connect Status + */ + PORTSC1 = 0x10, + /** + * \brief Port Status and Controll Register (Port 2) + * + * See ::PORTSC1 + */ + PORTSC2 = 0x12 +}; + +#endif