282 lines
11 KiB
Python
282 lines
11 KiB
Python
import math
|
|
|
|
import ConfigGenerator
|
|
import StructGenerator
|
|
from enum import Enum
|
|
|
|
|
|
# Descriptor type
|
|
class USB_DescType(Enum):
|
|
UD_Device = 1
|
|
UD_Configuration = 2
|
|
UD_String = 3
|
|
UD_Interface = 4
|
|
UD_Endpoint = 5
|
|
UD_DeviceQualifier = 6
|
|
# NOT FULL!
|
|
|
|
|
|
class USB_DescriptorSize(Enum):
|
|
Header = 2
|
|
Configuration = 9
|
|
Interface = 9
|
|
Endpoint = 7
|
|
Device = 18
|
|
DeviceQualifier = 9
|
|
|
|
|
|
# base class for descriptor generator
|
|
class Descriptor(StructGenerator.StructRecord):
|
|
def __init__(self, name, ctype, content, comment=None):
|
|
super().__init__(name, ctype, content, comment)
|
|
self.qualifiers = "const"
|
|
self.typedef = ctype[8:]
|
|
self.attribute = "packed"
|
|
|
|
# generate content for .c file
|
|
def gen_c(self):
|
|
return "{:s} {:s}".format(self.qualifiers, self.print_assigment())
|
|
|
|
# generate content for .h file
|
|
def gen_h(self, print_typedef=False):
|
|
decl = "extern {:s} {:s}".format(self.qualifiers, self.print_declaration())
|
|
tdef = ""
|
|
if print_typedef:
|
|
tdef = "{:s}\n".format(self.print_typedef())
|
|
return tdef + decl
|
|
|
|
|
|
# -----------------------------
|
|
class DeviceDescriptor(Descriptor):
|
|
def __init__(self, dev, str_mgr: ConfigGenerator.StringManager):
|
|
# add strings to the string manager
|
|
str_mgr.add_string("vendor_string", dev["vendor_string"])
|
|
str_mgr.add_string("product_string", dev["product_string"])
|
|
str_mgr.add_string("serial_number", dev["serial_number"])
|
|
|
|
# generate device descriptor
|
|
numOfConfs = len(dev["configurations"]) # get number of configurations
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.Device.value],
|
|
["bDescriptorType", "u8", "UD_Device", True],
|
|
["bcdUSB", "u16", 0x0200],
|
|
["bDeviceClass", "u8", dev["class"]],
|
|
["bDeviceSubclass", "u8", dev["subclass"]],
|
|
["bDeviceProtocol", "u8", dev["protocol_code"]],
|
|
["bMaxPacketSize0", "u8", dev["max_ep0_packet_size"]],
|
|
["idVendor", "u16", dev["vendor_id"]],
|
|
["idProduct", "u16", dev["product_id"]],
|
|
["bcdDevice", "u16", dev["device_release_bcd"]],
|
|
["iManufacturer", "u8", str_mgr.get_numeric_id("vendor_string")],
|
|
["iProduct", "u8", str_mgr.get_numeric_id("product_string")],
|
|
["iSerialNumber", "u8", str_mgr.get_numeric_id("serial_number")],
|
|
["bNumConfigurations", "u8", numOfConfs]]
|
|
|
|
super().__init__("devDesc", "struct _USB_DeviceDesc", StructGenerator.RecordFactory.createa(records),
|
|
comment="Device Descriptor")
|
|
|
|
|
|
class DeviceQualifierDescriptor(Descriptor):
|
|
def __init__(self, dev):
|
|
# generate device descriptor
|
|
numOfConfs = len(dev["configurations"]) # get number of configurations
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.DeviceQualifier.value],
|
|
["bDescriptorType", "u8", "UD_DeviceQualifier", True],
|
|
["bcdUSB", "u16", 0x0200],
|
|
["bDeviceClass", "u8", dev["class"]],
|
|
["bDeviceSubclass", "u8", dev["subclass"]],
|
|
["bDeviceProtocol", "u8", dev["protocol_code"]],
|
|
["bMaxPacketSize", "u8", dev["max_ep0_packet_size"]],
|
|
["bNumConfigurations", "u8", numOfConfs]]
|
|
|
|
super().__init__("devQualDesc", "struct _USB_DeviceQualifierDesc",
|
|
StructGenerator.RecordFactory.createa(records), comment="Device Qualifier descriptor")
|
|
|
|
|
|
class StringDescriptor(Descriptor):
|
|
def __init__(self, text_langid, name):
|
|
if isinstance(text_langid, str):
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.Header.value + 2 * len(text_langid)],
|
|
["bDescriptorType", "u8", "UD_String", True],
|
|
["bString", "str", text_langid]]
|
|
elif isinstance(text_langid, int):
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.Header.value + 2],
|
|
["bDescriptorType", "u8", "UD_String", True],
|
|
["bString", "u16", text_langid]]
|
|
|
|
super().__init__(name, "struct _USB_StrDesc_{:s}".format(name), StructGenerator.RecordFactory.createa(records),
|
|
comment="String descriptor")
|
|
|
|
|
|
class ConfigurationDescriptor(Descriptor):
|
|
def __init__(self, name, conf, total_length):
|
|
|
|
# fill in attributes
|
|
attributes = "USB_CONFIG_ATTR_USB1_1_FLAG"
|
|
if conf["is_bus_powered"] == False:
|
|
attributes += " | USB_CONFIG_ATTR_SELF_POWERED"
|
|
elif conf["can_wake_up_host"] == True:
|
|
attributes += " | USB_CONFIG_ATTR_REMOTE_WKUP"
|
|
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.Configuration.value],
|
|
["bDescriptorType", "u8", "UD_Configuration", True],
|
|
["wTotalLength", "u16", total_length, True],
|
|
["bNumInterfaces", "u8", len(conf["interfaces"])],
|
|
["bConfigurationValue", "u8", conf["id"]],
|
|
["iConfiguration", "u8", 0],
|
|
["bmAttributes", "u8", attributes, True],
|
|
["bMaxPower", "u8", math.ceil(conf["max_power_mA"] / 2)]]
|
|
|
|
super().__init__(name, "struct _USB_ConfigurationDesc", StructGenerator.RecordFactory.createa(records),
|
|
comment="Configuration descriptor")
|
|
|
|
|
|
class InterfaceDescriptor(Descriptor):
|
|
def __init__(self, name, intf):
|
|
self.ep_count = len(intf["endpoints"])
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.Interface.value],
|
|
["bDescriptorType", "u8", "UD_Interface", True],
|
|
["bInterfaceNumber", "u8", intf["id"]],
|
|
["bAlternateSetting", "u8", 0],
|
|
["bNumEndpoints", "u8", self.ep_count],
|
|
["bInterfaceClass", "u8", intf["class"]],
|
|
["bInterfaceSubclass", "u8", intf["subclass"]],
|
|
["bInterfaceProtocol", "u8", intf["protocol_code"]],
|
|
["iInterface", "u8", 0]]
|
|
|
|
super().__init__(name, "struct _USB_InterfaceDesc", StructGenerator.RecordFactory.createa(records),
|
|
comment="Interface descriptor : {:d}".format(intf["id"]))
|
|
|
|
|
|
class EndpointDescriptor(Descriptor):
|
|
def __init__(self, name, ep):
|
|
# endpoint direction
|
|
endpoint_dir = ""
|
|
conf_ep_dir_lower = ep["direction"].lower()
|
|
if conf_ep_dir_lower == "in":
|
|
endpoint_dir = "USB_IN"
|
|
elif conf_ep_dir_lower == "out":
|
|
endpoint_dir = "USB_OUT"
|
|
|
|
# transfer type
|
|
transfer_type = ""
|
|
conf_ep_transfer_type_lower = ep["transfer_type"].lower()
|
|
if conf_ep_transfer_type_lower == "control":
|
|
transfer_type = "UT_Control"
|
|
elif conf_ep_transfer_type_lower == "interrupt":
|
|
transfer_type = "UT_Interrupt"
|
|
elif conf_ep_transfer_type_lower == "bulk":
|
|
transfer_type = "UT_Bulk"
|
|
elif conf_ep_transfer_type_lower == "isochronous":
|
|
transfer_type = "UT_Isochronous"
|
|
|
|
records = [
|
|
["bLength", "u8", USB_DescriptorSize.Endpoint.value],
|
|
["bDescriptorType", "u8", "UD_Endpoint", True],
|
|
["bEndpointAddress", "u8", "({:s} << 7) | ({:d})".format(endpoint_dir, ep["n"]), True],
|
|
["bmAttributes", "u8", transfer_type, True],
|
|
["wMaxPacketSize", "u16", ep["max_packet_size"]],
|
|
["bInterval", "u8", ep["service_interval"]]
|
|
]
|
|
|
|
super().__init__(name, "struct _USB_EndpointDesc", StructGenerator.RecordFactory.createa(records),
|
|
comment="Endpoint descriptor : {:d} {:s}".format(ep["n"], ep["direction"]))
|
|
|
|
|
|
# --------------------------
|
|
# ------ CDC-related -------
|
|
# --------------------------
|
|
|
|
class HeaderFunctionalDescriptor(Descriptor):
|
|
def __init__(self, name, hfd, str_mgr):
|
|
records = [
|
|
["bLength", "u8", 0x05],
|
|
["bDescriptorType", "u8", 0x24],
|
|
["bDescriptorSubType", "u8", 0x00],
|
|
["bcdCDC", "u16", 0x0110]]
|
|
|
|
super().__init__(name, "struct _USB_HeaderFunctionalDescriptor", StructGenerator.RecordFactory.createa(records),
|
|
comment="Header Functional descriptor")
|
|
|
|
|
|
class AbstractControlManagementFunctionalDescriptor(Descriptor):
|
|
def __init__(self, name, acmfd, str_mgr):
|
|
records = [
|
|
["bLength", "u8", 0x04],
|
|
["bDescriptorType", "u8", 0x24],
|
|
["bDescriptorSubType", "u8", 0x02],
|
|
["bmCapabilities", "u8", 0x02]] # TODO: no capabilities
|
|
|
|
super().__init__(name, "struct _USB_AbstractControlManagementFunctionalDescriptor",
|
|
StructGenerator.RecordFactory.createa(records),
|
|
comment="Abstract Control Management Functional descriptor")
|
|
|
|
|
|
class UnionFunctionalDescriptor(Descriptor):
|
|
def __init__(self, name, ufd, str_mgr):
|
|
records = [
|
|
["bLength", "u8", 0x05],
|
|
["bDescriptorType", "u8", 0x24],
|
|
["bDescriptorSubType", "u8", 0x06],
|
|
["bMasterInterface", "u8", ufd["master_interface"]], # TODO: control interface
|
|
["bSlaveInterface0", "u8", ufd["slave_interface"]]] # TODO: data interface
|
|
|
|
super().__init__(name, "struct _USB_UnionFunctionalDescriptor", StructGenerator.RecordFactory.createa(records),
|
|
comment="Union Functional descriptor")
|
|
|
|
|
|
class CallManagementFunctionalDescriptor(Descriptor):
|
|
def __init__(self, name, cmfd, str_mgr):
|
|
records = [
|
|
["bLength", "u8", 0x05],
|
|
["bDescriptorType", "u8", 0x24],
|
|
["bDescriptorSubType", "u8", 0x01],
|
|
["bmCapabilities", "u8", 0x00],
|
|
["dDataInterface", "u8", cmfd["data_interface"]]]
|
|
|
|
super().__init__(name, "struct _USB_CallManagementFunctionalDescriptor",
|
|
StructGenerator.RecordFactory.createa(records),
|
|
comment="Call Management Functional descriptor")
|
|
|
|
|
|
class EthernetNetworkingFunctionalDescriptor(Descriptor):
|
|
def __init__(self, name, enfd, str_mgr: ConfigGenerator.StringManager):
|
|
|
|
# add MAC address to the string manager
|
|
str_mgr.add_string("mac_address", enfd["mac_address"])
|
|
|
|
# populate fields
|
|
records = [
|
|
["bLength", "u8", 0x0D],
|
|
["bDescriptorType", "u8", 0x24],
|
|
["bDescriptorSubType", "u8", 0x0F],
|
|
["iMACAddress", "u8", str_mgr.get_numeric_id("mac_address")], # MAC address is stored as a string
|
|
["bmEthernetStatistics", "u32", 0x00], # no collection of statistics
|
|
["wMaxSegmentSize", "u16", enfd["max_segment_size"]],
|
|
["wNumberMCFilters", "u16", 0x00], # we don't support multicast filters
|
|
["bNumberPowerFilters", "u8", 0x00], # no pattern for waking up the host
|
|
]
|
|
|
|
super().__init__(name, "struct _USB_EthernetNetworkingFunctionalDescriptor",
|
|
StructGenerator.RecordFactory.createa(records),
|
|
comment="Ethernet Networking Functional descriptor")
|
|
|
|
|
|
class DescriptorFactory:
|
|
REGISTRY = {
|
|
"hfd": HeaderFunctionalDescriptor,
|
|
"acmfd": AbstractControlManagementFunctionalDescriptor,
|
|
"ufd": UnionFunctionalDescriptor,
|
|
"cmfd": CallManagementFunctionalDescriptor,
|
|
"enfd": EthernetNetworkingFunctionalDescriptor
|
|
}
|
|
|
|
@staticmethod
|
|
def generate(name, varname, data, str_mgr):
|
|
return DescriptorFactory.REGISTRY[name](varname, data, str_mgr)
|