/// <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 ShowInterface(Interface d) { DBGMSG("---------------------------------------------------------------------"); switch (d.NumEndpoints) { case 0: DBGMSG(((FOS_System.String)"Interface ") + d.InterfaceNumber + " has no endpoint and belongs to class:"); break; case 1: DBGMSG(((FOS_System.String)"Interface ") + d.InterfaceNumber + " has only one endpoint and belongs to class:"); break; default: DBGMSG(((FOS_System.String)"Interface ") + d.InterfaceNumber + " has " + d.NumEndpoints + " endpoints and belongs to class:"); break; } switch (d.Class) { case 0x01: DBGMSG("Audio"); break; case 0x02: DBGMSG("Communications and CDC Control"); break; case 0x03: DBGMSG("HID (Human Interface Device)"); break; case 0x05: DBGMSG("Physical"); break; case 0x06: DBGMSG("Image"); break; case 0x07: DBGMSG("Printer"); break; case 0x08: DBGMSG("Mass Storage, "); switch (d.Subclass) { case 0x01: DBGMSG("Reduced Block Commands, "); break; case 0x02: DBGMSG("SFF-8020i or MMC-2(ATAPI), "); break; case 0x03: DBGMSG("QIC-157 (tape device), "); break; case 0x04: DBGMSG("UFI (e.g. Floppy Disk), "); break; case 0x05: DBGMSG("SFF-8070i (e.g. Floppy Disk), "); break; case 0x06: DBGMSG("SCSI transparent command set, "); break; } switch (d.Protocol) { case 0x00: DBGMSG("CBI protocol with command completion interrupt."); break; case 0x01: DBGMSG("CBI protocol without command completion interrupt."); break; case 0x50: DBGMSG("Bulk-Only Transport protocol."); break; } break; case 0x0A: DBGMSG("CDC-Data"); break; case 0x0B: DBGMSG("Smart Card"); break; case 0x0D: DBGMSG("Content Security"); break; case 0x0E: DBGMSG("Video"); break; case 0x0F: DBGMSG("Personal Healthcare"); break; case 0xDC: DBGMSG("Diagnostic Device"); break; case 0xE0: DBGMSG(((FOS_System.String)"Wireless Controller, subclass: ") + d.Subclass + " protocol: " + d.Protocol + "."); break; case 0xEF: DBGMSG("Miscellaneous"); break; case 0xFE: DBGMSG("Application Specific"); break; case 0xFF: DBGMSG("Vendor Specific"); break; } DBGMSG(((FOS_System.String)"Alternate Setting: ") + d.AlternateSetting); DBGMSG(((FOS_System.String)"Class: ") + d.Class); DBGMSG(((FOS_System.String)"Subclass: ") + d.Subclass); DBGMSG(((FOS_System.String)"Protocol: ") + d.Protocol); if (d.Description != null) { DBGMSG(((FOS_System.String)"Description: ") + d.Description.Value); } else { DBGMSG("Description: [NONE]"); } BasicConsole.DelayOutput(1); }