Modules/USB - Working on driver support, little headache
[tpg/acess2.git] / Modules / USB / Core / usb.c
index 0b4bc63..7713435 100644 (file)
@@ -18,10 +18,14 @@ extern tUSBHost     *gUSB_Hosts;
 tUSBHub        *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
 void   USB_DeviceConnected(tUSBHub *Hub, int Port);
 void   USB_DeviceDisconnected(tUSBHub *Hub, int Port);
-void   *USB_GetDeviceDataPtr(tUSBDevice *Dev);
-void   USB_SetDeviceDataPtr(tUSBDevice *Dev, void *Ptr);
+void   *USB_GetDeviceDataPtr(tUSBInterface *Dev);
+void   USB_SetDeviceDataPtr(tUSBInterface *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)
@@ -37,14 +41,14 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts)
        host->Ptr = ControllerPtr;
        memset(host->AddressBitmap, 0, sizeof(host->AddressBitmap));
 
-       host->RootHubDev.Next = NULL;
+//     host->RootHubDev.Next = NULL;
        host->RootHubDev.ParentHub = NULL;
        host->RootHubDev.Host = host;
        host->RootHubDev.Address = 0;
-       host->RootHubDev.Driver = NULL;
-       host->RootHubDev.Data = NULL;
+//     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;
 }
 
@@ -71,12 +72,12 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
        
        // Create structure
        dev = malloc(sizeof(tUSBDevice));
-       dev->Next = NULL;
+//     dev->Next = NULL;
        dev->ParentHub = Hub;
        dev->Host = Hub->Device->Host;
        dev->Address = 0;
-       dev->Driver = 0;
-       dev->Data = 0;
+//     dev->Driver = 0;
+//     dev->Data = 0;
 
        // 1. Assign an address
        dev->Address = USB_int_AllocateAddress(dev->Host);
@@ -90,6 +91,118 @@ 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;
+               char    *cur_ptr;
+               
+               USB_int_ReadDescriptor(dev, 0, 2, i, 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);
+               }
+
+               cur_ptr = full_buf = malloc( LittleEndian16(desc.TotalLength) );
+               USB_int_ReadDescriptor(dev, 0, 2, i, desc.TotalLength, full_buf);
+
+               cur_ptr += desc.Length;
+
+               // TODO: Interfaces
+               for( int j = 0; j < desc.NumInterfaces; j ++ )
+               {
+                       struct sDescriptor_Interface *iface;
+                       iface = (void*)cur_ptr;
+                       // TODO: Sanity check with remaining space
+                       cur_ptr += sizeof(*iface);
+                       
+                       LOG("Interface %i/%i = {", i, j);
+                       LOG(" .InterfaceNum = %i", iface->InterfaceNum);
+                       LOG(" .NumEndpoints = %i", iface->NumEndpoints);
+                       LOG(" .InterfaceClass = 0x%x", iface->InterfaceClass);
+                       LOG(" .InterfaceSubClass = 0x%x", iface->InterfaceSubClass);
+                       LOG(" .InterfaceProcol = 0x%x", iface->InterfaceProtocol);
+
+                       if( iface->InterfaceStr ) {
+                               char    *tmp = USB_int_GetDeviceString(dev, 0, iface->InterfaceStr);
+                               LOG(" .InterfaceStr = %i '%s'", iface->InterfaceStr, tmp);
+                               free(tmp);
+                       }
+                       LOG("}");
+
+                       for( int k = 0; k < iface->NumEndpoints; k ++ )
+                       {
+                               struct sDescriptor_Endpoint *endpt;
+                               endpt = (void*)cur_ptr;
+                               // TODO: Sanity check with remaining space
+                               cur_ptr += sizeof(*endpt);
+                               
+                               LOG("Endpoint %i/%i/%i = {", i, j, k);
+                               LOG(" .Address = 0x%2x", endpt->Address);
+                               LOG(" .Attributes = 0b%8b", endpt->Attributes);
+                               LOG(" .MaxPacketSize = %i", LittleEndian16(endpt->MaxPacketSize));
+                               LOG(" .PollingInterval = %i", endpt->PollingInterval);
+                               LOG("}");
+                       }
+               }
+               
+               free(full_buf);
+       }
 
        // Done.
        LEAVE('-');
@@ -100,61 +213,186 @@ 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; }
+void *USB_GetDeviceDataPtr(tUSBInterface *Dev) { return Dev->Data; }
+void USB_SetDeviceDataPtr(tUSBInterface *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))
+               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));
+}
+
+void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
+{
+       void    *hdl;
+       // TODO: Sanity check (and check that Type is valid)
+       struct sDeviceRequest   req;
+       req.ReqType = Type;
+       req.Request = Req;
+       req.Value = LittleEndian16( Val );
+       req.Index = LittleEndian16( Indx );
+       req.Length = LittleEndian16( Len );
+       
+       hdl = Host->HostDef->SendSETUP(Host->Ptr, Addr, EndPt, 0, NULL, &req, sizeof(req));
+
+       // TODO: Data toggle?
+       // TODO: Correct sequence? (Some OUT requests need an IN)
+       if( Type & 0x80 )
+       {
+               hdl = Host->HostDef->SendIN(Host->Ptr, Addr, EndPt, 0, NULL, Data, Len);
+               while( Host->HostDef->IsOpComplete(Host->Ptr, hdl) == 0 )
+                       Time_Delay(1);
+       }
+       else
+       {
+               hdl = Host->HostDef->SendOUT(Host->Ptr, Addr, EndPt, 0, NULL, Data, Len);
+       }
+       return hdl;
+}
+
 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, NULL, &req, sizeof(req));
+       if(!hdl)
+               return 1;
+
+       hdl = Host->HostDef->SendIN(Host->Ptr, 0, 0, 0, NULL, 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)
 {
-       struct sDeviceRequest   req;
        const int       ciMaxPacketSize = 0x400;
+       struct sDeviceRequest   req;
+        int    bToggle = 0;
+       void    *final;
+
        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,
-               0, FALSE,
+               0, NULL,
                &req, sizeof(req)
                );
        
+       bToggle = 1;
        while( Length > ciMaxPacketSize )
        {
                Dev->Host->HostDef->SendIN(
                        Dev->Host->Ptr, Dev->Address, Endpoint,
-                       1, FALSE,
+                       bToggle, NULL,
                        Dest, ciMaxPacketSize
                        );
+               bToggle = !bToggle;
                Length -= ciMaxPacketSize;
        }
 
-       // TODO: Complete and get completion    
+       final = Dev->Host->HostDef->SendIN(
+               Dev->Host->Ptr, Dev->Address, Endpoint,
+               bToggle, INVLPTR,
+               Dest, Length
+               );
+
+       while( Dev->Host->HostDef->IsOpComplete(Dev->Host->Ptr, final) == 0 )
+               Time_Delay(1);
 
        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)) {
+//             // IMPOSSIBLE!
+//             Log_Error("USB", "String is %i bytes, which is over prealloc size (%i)",
+//                     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;
+}
+

UCC git Repository :: git.ucc.asn.au