/// <summary> /// Gets the configuration descriptor from the specified device. /// </summary> /// <param name="device">The device info of the device to get the descriptor from.</param> /// <returns>True if USB transfer completed successfully. Otherwise, false.</returns> public static unsafe bool GetConfigurationDescriptors(USBDeviceInfo device) { #if USB_TRACE DBGMSG("USB: GET_DESCRIPTOR Config"); #endif //64 byte buffer ushort bufferSize = 64; byte* buffer = (byte*)FOS_System.Heap.AllocZeroed(bufferSize, "USBManager: GetConfigDescriptor"); bool success = false; try { USBTransfer transfer = new USBTransfer(); device.hc.SetupTransfer(device, transfer, USBTransferType.Control, 0, bufferSize); device.hc.SETUPTransaction(transfer, 8, 0x80, 6, 2, 0, 0, bufferSize); device.hc.INTransaction(transfer, false, buffer, 64); device.hc.OUTTransaction(transfer, true, null, 0); device.hc.IssueTransfer(transfer); success = transfer.success; if (transfer.success) { byte currentConfig = GetConfiguration(device); // parse to config (len=9,type=2), interface (len=9,type=4) or endpoint (len=7,type=5) #if USB_TRACE DBGMSG("---------------------------------------------------------------------"); #endif byte* addr = buffer; byte* lastByte = addr + bufferSize; ushort numEndpoints = 1; // First pass. Retrieve usb_interfaceDescriptor which contains the number of endpoints while (addr < lastByte) { byte type = *(addr + 1); byte length = *addr; if (length == 9 && type == 2) { ConfigurationDescriptor* descriptor = (ConfigurationDescriptor*)addr; Configuration config = new Configuration(); config.Attribs = (Configuration.Attributes)descriptor->attributes; config.Selector = descriptor->configurationValue; config.MaxPower = descriptor->maxPower; config.NumInterfaces = descriptor->numInterfaces; if (currentConfig == config.Selector) { config.Description = GetUnicodeStringDescriptor(device, descriptor->configuration); } else { config.Description = new UnicodeString() { StringType = 0, Value = "[Unable to load at this time]" }; } device.Configurations.Add(config); #if USB_TRACE ShowConfiguration(config); #endif } else if (length == 9 && type == 4) { InterfaceDescriptor* descriptor = (InterfaceDescriptor*)addr; Interface interf = new Interface(); interf.InterfaceNumber = descriptor->interfaceNumber; interf.AlternateSetting = descriptor->alternateSetting; interf.Class = descriptor->interfaceClass; interf.Subclass = descriptor->interfaceSubclass; interf.Protocol = descriptor->interfaceProtocol; interf.Description = GetUnicodeStringDescriptor(device, descriptor->StringIndex); interf.NumEndpoints = descriptor->numEndpoints; device.Interfaces.Add(interf); #if USB_TRACE ShowInterface(interf); #endif if (interf.Class == 8) { // store interface number for mass storage transfers device.MSD_InterfaceNum = interf.InterfaceNumber; device.InterfaceClass = interf.Class; device.InterfaceSubclass = interf.Subclass; } numEndpoints += interf.NumEndpoints; } else if (length == 7 && type == 5) { //Skip endpoints in first pass } else { #if USB_TRACE DBGMSG(((FOS_System.String)"Unknown descriptor: Length=") + length + ", Type=" + type); #endif if (length == 0) { break; } } addr += length; } FOS_System.Object endpointZero = device.Endpoints[0]; device.Endpoints.Empty(); device.Endpoints.Add(endpointZero); for (int i = 0; i < numEndpoints - 1; i++) { device.Endpoints.Add(new Endpoint()); } // Second pass. Fill in endpoint information addr = buffer; while (addr < lastByte) { byte type = *(addr + 1); byte length = *addr; if (length == 7 && type == 5) { EndpointDescriptor* descriptor = (EndpointDescriptor*)addr; byte ep_id = (byte)(descriptor->endpointAddress & 0xF); #if USB_TRACE if (ep_id >= numEndpoints) { DBGMSG("ep_id >= numEndpoints!!"); } #endif Endpoint endpoint = (Endpoint)device.Endpoints[ep_id]; endpoint.MPS = descriptor->maxPacketSize; endpoint.Type = Endpoint.Types.BIDIR; // Can be overwritten below endpoint.Address = (byte)(descriptor->endpointAddress & 0xF); endpoint.Attributes = descriptor->attributes; endpoint.Interval = descriptor->interval; // store endpoint numbers for IN/OUT mass storage transfers, attributes must be 0x2, because there are also endpoints with attributes 0x3(interrupt) if ((descriptor->endpointAddress & 0x80) > 0 && descriptor->attributes == 0x2) { if (ep_id < 3) { device.MSD_INEndpointID = ep_id; } endpoint.Type = Endpoint.Types.IN; } if ((descriptor->endpointAddress & 0x80) == 0 && descriptor->attributes == 0x2) { if (ep_id < 3) { device.MSD_OUTEndpointID = ep_id; } endpoint.Type = Endpoint.Types.OUT; } #if USB_TRACE ShowEndpoint(endpoint); #endif } else if (length == 0) { break; } addr += length; } } } finally { FOS_System.Heap.Free(buffer); } return success; }
private static void ShowConfiguration(Configuration d) { DBGMSG(((FOS_System.String)"Number of interfaces: ") + d.NumInterfaces); DBGMSG(((FOS_System.String)"ID of config: ") + d.Selector); if (d.Description != null) { DBGMSG(((FOS_System.String)"Description: ") + d.Description.Value); } else { DBGMSG("Description: [NONE]"); } DBGMSG(((FOS_System.String)"Remote wakeup: ") + (((d.Attribs & Configuration.Attributes.RemoteWakeup) != 0) ? "Yes" : "No")); DBGMSG(((FOS_System.String)"Self-powered: ") + (((d.Attribs & Configuration.Attributes.SelfPowered) != 0) ? "Yes" : "No")); DBGMSG(((FOS_System.String)"Max power (mA): ") + d.MaxPower * 2); // 2 mA steps used BasicConsole.DelayOutput(1); }