From b77a57935b392d5b056b83f0e2dd03ab894bc0ce Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 Nov 2011 21:50:22 +0800 Subject: [PATCH] Modules/USB - Coming along, reading descriptors now - Updated WriteUTF8 to accept NULL as a destination --- Kernel/lib.c | 34 +++---- Modules/USB/Core/usb.c | 180 ++++++++++++++++++++++++++++++++--- Modules/USB/Core/usb_proto.h | 70 +++++++++++++- Modules/USB/UHCI/uhci.c | 99 ++++++++++++++++--- Modules/USB/UHCI/uhci.h | 17 +++- 5 files changed, 354 insertions(+), 46 deletions(-) diff --git a/Kernel/lib.c b/Kernel/lib.c index c1e2807e..2b786ece 100644 --- a/Kernel/lib.c +++ b/Kernel/lib.c @@ -720,37 +720,39 @@ int WriteUTF8(Uint8 *str, Uint32 Val) { // ASCII if( Val < 128 ) { - *str = Val; + if( str ) { + *str = Val; + } return 1; } // Two Byte if( Val < 0x8000 ) { - *str = 0xC0 | (Val >> 6); - str ++; - *str = 0x80 | (Val & 0x3F); + if( str ) { + *str++ = 0xC0 | (Val >> 6); + *str++ = 0x80 | (Val & 0x3F); + } return 2; } // Three Byte if( Val < 0x10000 ) { - *str = 0xE0 | (Val >> 12); - str ++; - *str = 0x80 | ((Val >> 6) & 0x3F); - str ++; - *str = 0x80 | (Val & 0x3F); + if( str ) { + *str++ = 0xE0 | (Val >> 12); + *str++ = 0x80 | ((Val >> 6) & 0x3F); + *str++ = 0x80 | (Val & 0x3F); + } return 3; } // Four Byte if( Val < 0x110000 ) { - *str = 0xF0 | (Val >> 18); - str ++; - *str = 0x80 | ((Val >> 12) & 0x3F); - str ++; - *str = 0x80 | ((Val >> 6) & 0x3F); - str ++; - *str = 0x80 | (Val & 0x3F); + if( str ) { + *str++ = 0xF0 | (Val >> 18); + *str++ = 0x80 | ((Val >> 12) & 0x3F); + *str++ = 0x80 | ((Val >> 6) & 0x3F); + *str++ = 0x80 | (Val & 0x3F); + } return 4; } diff --git a/Modules/USB/Core/usb.c b/Modules/USB/Core/usb.c index 272ff6c8..b43aae4d 100644 --- a/Modules/USB/Core/usb.c +++ b/Modules/USB/Core/usb.c @@ -22,6 +22,10 @@ void *USB_GetDeviceDataPtr(tUSBDevice *Dev); void USB_SetDeviceDataPtr(tUSBDevice *Dev, void *Ptr); int USB_int_AllocateAddress(tUSBHost *Host); int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address); + int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest); +char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index); + + int _UTF16to8(Uint16 *Input, int InputLen, char *Dest); // === CODE === tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts) @@ -44,7 +48,7 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts) host->RootHubDev.Driver = NULL; host->RootHubDev.Data = NULL; - host->RootHub.Device = NULL; + host->RootHub.Device = &host->RootHubDev; host->RootHub.CheckPorts = NULL; host->RootHub.nPorts = nPorts; memset(host->RootHub.Devices, 0, sizeof(void*)*nPorts); @@ -53,9 +57,6 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts) host->Next = gUSB_Hosts; gUSB_Hosts = host; - // Initialise? - HostDef->CheckPorts(ControllerPtr); - return &host->RootHub; } @@ -90,6 +91,74 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) LOG("Assigned address %i", dev->Address); // 2. Get device information + { + struct sDescriptor_Device desc; + LOG("Getting device descriptor"); + // Endpoint 0, Desc Type 1, Index 0 + USB_int_ReadDescriptor(dev, 0, 1, 0, sizeof(desc), &desc); + + LOG("Device Descriptor = {"); + LOG(" .Length = %i", desc.Length); + LOG(" .Type = %i", desc.Type); + LOG(" .USBVersion = 0x%04x", desc.USBVersion); + LOG(" .DeviceClass = 0x%02x", desc.DeviceClass); + LOG(" .DeviceSubClass = 0x%02x", desc.DeviceSubClass); + LOG(" .DeviceProtocol = 0x%02x", desc.DeviceProtocol); + LOG(" .MaxPacketSize = 0x%02x", desc.MaxPacketSize); + LOG(" .VendorID = 0x%04x", desc.VendorID); + LOG(" .ProductID = 0x%04x", desc.ProductID); + LOG(" .DeviceID = 0x%04x", desc.DeviceID); + LOG(" .ManufacturerStr = Str %i", desc.ManufacturerStr); + LOG(" .ProductStr = Str %i", desc.ProductStr); + LOG(" .SerialNumberStr = Str %i", desc.SerialNumberStr); + LOG(" .NumConfigurations = %i", desc.SerialNumberStr); + LOG("}"); + + if( desc.ManufacturerStr ) + { + char *tmp = USB_int_GetDeviceString(dev, 0, desc.ManufacturerStr); + LOG("ManufacturerStr = '%s'", tmp); + free(tmp); + } + if( desc.ProductStr ) + { + char *tmp = USB_int_GetDeviceString(dev, 0, desc.ProductStr); + LOG("ProductStr = '%s'", tmp); + free(tmp); + } + if( desc.SerialNumberStr ) + { + char *tmp = USB_int_GetDeviceString(dev, 0, desc.SerialNumberStr); + LOG("SerialNumbertStr = '%s'", tmp); + free(tmp); + } + } + + // 3. Get configurations + for( int i = 0; i < 1; i ++ ) + { + struct sDescriptor_Configuration desc; +// void *full_buf; + + USB_int_ReadDescriptor(dev, 0, 2, 0, sizeof(desc), &desc); + LOG("Configuration Descriptor %i = {", i); + LOG(" .Length = %i", desc.Length); + LOG(" .Type = %i", desc.Type); + LOG(" .TotalLength = 0x%x", LittleEndian16(desc.TotalLength)); + LOG(" .NumInterfaces = %i", desc.NumInterfaces); + LOG(" .ConfigurationValue = %i", desc.ConfigurationValue); + LOG(" .ConfigurationStr = %i", desc.ConfigurationStr); + LOG(" .AttributesBmp = 0b%b", desc.AttributesBmp); + LOG(" .MaxPower = %i (*2mA)", desc.MaxPower); + LOG("}"); + if( desc.ConfigurationStr ) { + char *tmp = USB_int_GetDeviceString(dev, 0, desc.ConfigurationStr); + LOG("ConfigurationStr = '%s'", tmp); + free(tmp); + } + + // TODO: Interfaces + } // Done. LEAVE('-'); @@ -108,24 +177,42 @@ int USB_int_AllocateAddress(tUSBHost *Host) int i; for( i = 1; i < 128; i ++ ) { - if(Host->AddressBitmap[i/8] & (1 << i)) + if(Host->AddressBitmap[i/8] & (1 << (i%8))) continue ; + Host->AddressBitmap[i/8] |= 1 << (i%8); return i; } return 0; } +void USB_int_DeallocateAddress(tUSBHost *Host, int Address) +{ + Host->AddressBitmap[Address/8] &= ~(1 << (Address%8)); +} + int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address) { + void *hdl; 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 + // TODO: Endian + req.Value = LittleEndian16( Address & 0x7F ); // wValue + req.Index = LittleEndian16( 0 ); // wIndex + req.Length = LittleEndian16( 0 ); // wLength // Addr 0:0, Data Toggle = 0, no interrupt - return Host->HostDef->SendSETUP(Host->Ptr, 0, 0, 0, FALSE, &req, sizeof(req)) == NULL; + hdl = Host->HostDef->SendSETUP(Host->Ptr, 0, 0, 0, FALSE, &req, sizeof(req)); + if(!hdl) + return 1; + + // TODO: Data toggle? + hdl = Host->HostDef->SendIN(Host->Ptr, 0, 0, 0, FALSE, NULL, 0); + + while( Host->HostDef->IsOpComplete(Host->Ptr, hdl) == 0 ) + Time_Delay(1); + + return 0; } int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest) @@ -137,9 +224,9 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i req.ReqType = 0x80; req.Request = 6; // GET_DESCRIPTOR - req.Value = ((Type & 0xFF) << 8) | (Index & 0xFF); - req.Index = 0; // TODO: Language ID - req.Length = Length; + req.Value = LittleEndian16( ((Type & 0xFF) << 8) | (Index & 0xFF) ); + req.Index = LittleEndian16( 0 ); // TODO: Language ID + req.Length = LittleEndian16( Length ); Dev->Host->HostDef->SendSETUP( Dev->Host->Ptr, Dev->Address, Endpoint, @@ -170,3 +257,72 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i return 0; } + +char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index) +{ + struct sDescriptor_String str; + int src_len, new_len; + char *ret; + + USB_int_ReadDescriptor(Dev, Endpoint, 3, Index, sizeof(str), &str); + if(str.Length > sizeof(str)) { + Log_Notice("USB", "String is %i bytes, which is over prealloc size (%i)", + str.Length, sizeof(str) + ); + // HACK: + str.Length = sizeof(str); + } + src_len = (str.Length - 2) / sizeof(str.Data[0]); + + new_len = _UTF16to8(str.Data, src_len, NULL); + ret = malloc( new_len + 1 ); + _UTF16to8(str.Data, src_len, ret); + ret[new_len] = 0; + return ret; +} + +int _UTF16to8(Uint16 *Input, int InputLen, char *Dest) +{ + int str_len, cp_len; + Uint32 saved_bits = 0; + str_len = 0; + for( int i = 0; i < InputLen; i ++) + { + Uint32 cp; + Uint16 val = Input[i]; + if( val >= 0xD800 && val <= 0xDBFF ) + { + // Multibyte - Leading + if(i + 1 > InputLen) { + cp = '?'; + } + else { + saved_bits = (val - 0xD800) << 10; + saved_bits += 0x10000; + continue ; + } + } + else if( val >= 0xDC00 && val <= 0xDFFF ) + { + if( !saved_bits ) { + cp = '?'; + } + else { + saved_bits |= (val - 0xDC00); + cp = saved_bits; + } + } + else + cp = val; + + cp_len = WriteUTF8((Uint8*)Dest, cp); + if(Dest) + Dest += cp_len; + str_len += cp_len; + + saved_bits = 0; + } + + return str_len; +} + diff --git a/Modules/USB/Core/usb_proto.h b/Modules/USB/Core/usb_proto.h index 3a98e479..776237da 100644 --- a/Modules/USB/Core/usb_proto.h +++ b/Modules/USB/Core/usb_proto.h @@ -17,7 +17,7 @@ struct sDeviceRequest struct sDescriptor_Device { Uint8 Length; - Uint8 Type; // = + Uint8 Type; // = 1 Uint16 USBVersion; // BCD, 0x210 = 2.10 Uint8 DeviceClass; Uint8 DeviceSubClass; @@ -26,6 +26,7 @@ struct sDescriptor_Device Uint16 VendorID; Uint16 ProductID; + Uint16 DeviceID; // BCD Uint8 ManufacturerStr; Uint8 ProductStr; @@ -34,5 +35,72 @@ struct sDescriptor_Device Uint8 NumConfigurations; }; +struct sDescriptor_Configuration +{ + Uint8 Length; + Uint8 Type; // = 2 + + Uint16 TotalLength; + Uint8 NumInterfaces; + Uint8 ConfigurationValue; + Uint8 ConfigurationStr; + Uint8 AttributesBmp; + Uint8 MaxPower; // in units of 2 mA +}; + +struct sDescriptor_String +{ + Uint8 Length; + Uint8 Type; // = 3 + + Uint16 Data[62]; // 62 is arbitary +}; + +struct sDescriptor_Interface +{ + Uint8 Length; + Uint8 Type; // = 4 + + Uint8 InterfaceNum; + Uint8 AlternateSetting; + Uint8 NumEndpoints; // Excludes endpoint 0 + + Uint8 InterfaceClass; // + Uint8 InterfaceSubClass; + Uint8 InterfaceProtocol; + + Uint8 InterfaceStr; +}; + +struct sDescriptor_Endpoint +{ + Uint8 Length; + Uint8 Type; // = 5 + Uint8 Address; // 3:0 Endpoint Num, 7: Direction (IN/OUT) + /** + * 1:0 - Transfer Type + * - 00 = Control + * - 01 = Isochronous + * - 10 = Bulk + * - 11 = Interrupt + * 3:2 - Synchronisation type (Isonchronous only) + * - 00 = No Synchronisation + * - 01 = Asynchronous + * - 10 = Adaptive + * - 11 = Synchronous + * 5:4 - Usage type (Isonchronous only) + * - 00 = Data endpoint + * - 01 = Feedback endpoint + */ + Uint8 Attributes; + + Uint16 MaxPacketSize; + + /** + * + */ + Uint8 PollingInterval; +}; + #endif diff --git a/Modules/USB/UHCI/uhci.c b/Modules/USB/UHCI/uhci.c index 2018d5fa..9d68ac0d 100644 --- a/Modules/USB/UHCI/uhci.c +++ b/Modules/USB/UHCI/uhci.c @@ -24,6 +24,7 @@ void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int 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); + int UHCI_IsTransferComplete(void *Ptr, void *Handle); void UHCI_Hub_Poll(tUSBHub *Hub, tUSBDevice *Dev); int UHCI_Int_InitHost(tUHCI_Controller *Host); void UHCI_CheckPortUpdate(tUHCI_Controller *Host); @@ -37,7 +38,8 @@ tUSBHostDef gUHCI_HostDef = { .SendIN = UHCI_DataIN, .SendOUT = UHCI_DataOUT, .SendSETUP = UHCI_SendSetup, - .CheckPorts = (void*)UHCI_CheckPortUpdate + .CheckPorts = (void*)UHCI_CheckPortUpdate, + .IsOpComplete = UHCI_IsTransferComplete }; // === CODE === @@ -64,6 +66,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", @@ -82,6 +85,8 @@ 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 == MAX_CONTROLLERS) { @@ -106,15 +111,56 @@ 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; } 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); + tPAddr td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool ); + tUHCI_TD *prev_td; + Uint32 link; + + // TODO: How to handle FRNUM incrementing while we are in this function? + + // 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 { + // TODO: Fix this to work with a non-contiguous pool + prev_td = gaUHCI_TDPool + (link - td_pool_base) / sizeof(gaUHCI_TDPool[0]); + 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); } /** @@ -131,8 +177,15 @@ void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int td = UHCI_int_AllocateTD(Cont); + if( !td ) { + // + 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; @@ -140,8 +193,10 @@ 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 = return NULL; @@ -153,12 +208,14 @@ void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int // 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"); + 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.DestPtr = Data; UHCI_int_AppendTD(Cont, td); @@ -180,6 +237,12 @@ void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, tUSBHostCb Cb, return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, Cb, Data, Length); } +int UHCI_IsTransferComplete(void *Ptr, void *Handle) +{ + tUHCI_TD *td = Handle; + return !(td->Control & (1 << 23)); +} + void UHCI_Hub_Poll(tUSBHub *Hub, tUSBDevice *Dev) { tUHCI_Controller *cont = USB_GetDeviceDataPtr(Dev); @@ -227,6 +290,7 @@ 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); @@ -255,13 +319,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); } @@ -270,5 +334,14 @@ void UHCI_CheckPortUpdate(tUHCI_Controller *Host) void UHCI_InterruptHandler(int IRQ, void *Ptr) { - Log_Debug("UHCI", "UHIC Interrupt"); + tUHCI_Controller *Host = Ptr; + Uint16 status = inw(Host->IOBase + USBSTS); + Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x", status); + + if( status & 1 ) + { + // Interrupt-on-completion + } + + outw(Host->IOBase + USBSTS, status); } diff --git a/Modules/USB/UHCI/uhci.h b/Modules/USB/UHCI/uhci.h index 7d88d354..6056c987 100644 --- a/Modules/USB/UHCI/uhci.h +++ b/Modules/USB/UHCI/uhci.h @@ -104,10 +104,19 @@ struct sUHCI_TD */ Uint32 BufferPointer; - /** - * \brief Avaliable for use by software - */ - Uint32 Avaliable[4]; + union + { + /** + * \brief Avaliable for use by software + */ + Uint32 Avaliable[4]; + + struct + { + void *Callback; + void *DestPtr; + } _info; + }; }; struct sUHCI_QH -- 2.20.1