descriptor_generator.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. """
  2. * Tiny USB stack - Descriptor table generator
  3. *
  4. * Copyright (C) 2009-2011 Michael Buesch <m@bues.ch>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * version 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. """
  15. import sys
  16. import atexit
  17. # bcdUSB
  18. USB_BCD_10 = 0x0100
  19. USB_BCD_11 = 0x0110
  20. USB_BCD_20 = 0x0200
  21. USB_TYPE_STANDARD = 0x00 << 5
  22. USB_TYPE_CLASS = 0x01 << 5
  23. USB_TYPE_VENDOR = 0x02 << 5
  24. USB_TYPE_RESERVED = 0x03 << 5
  25. # Descriptor types
  26. USB_DT_DEVICE = 0x01
  27. USB_DT_CONFIG = 0x02
  28. USB_DT_STRING = 0x03
  29. USB_DT_INTERFACE = 0x04
  30. USB_DT_ENDPOINT = 0x05
  31. # HID descriptor types
  32. HID_DT_HID = USB_TYPE_CLASS | 0x01
  33. HID_DT_REPORT = USB_TYPE_CLASS | 0x02
  34. HID_DT_PHYSICAL = USB_TYPE_CLASS | 0x03
  35. # Descriptor sizes per descriptor type
  36. USB_DT_DEVICE_SIZE = 18
  37. USB_DT_CONFIG_SIZE = 9
  38. USB_DT_INTERFACE_SIZE = 9
  39. USB_DT_ENDPOINT_SIZE = 7
  40. USB_DT_ENDPOINT_AUDIO_SIZE = 9
  41. USB_DT_HUB_NONVAR_SIZE = 7
  42. # from config descriptor bmAttributes
  43. USB_CONFIG_ATT_ONE = 1 << 7 # must be set
  44. USB_CONFIG_ATT_SELFPOWER = 1 << 6 # self powered
  45. USB_CONFIG_ATT_WAKEUP = 1 << 5 # can wakeup
  46. USB_CONFIG_ATT_BATTERY = 1 << 4 # battery powered
  47. # Device and/or Interface Class codes
  48. USB_CLASS_PER_INTERFACE = 0 # for DeviceClass
  49. USB_CLASS_AUDIO = 1
  50. USB_CLASS_COMM = 2
  51. USB_CLASS_HID = 3
  52. USB_CLASS_PRINTER = 7
  53. USB_CLASS_PTP = 6
  54. USB_CLASS_MASS_STORAGE = 8
  55. USB_CLASS_HUB = 9
  56. USB_CLASS_DATA = 10
  57. USB_CLASS_VENDOR_SPEC = 0xff
  58. # EP directions
  59. USB_ENDPOINT_IN = 0x80
  60. USB_ENDPOINT_OUT = 0x00
  61. # EP bmAttributes
  62. USB_ENDPOINT_XFERTYPE_MASK = 0x03
  63. USB_ENDPOINT_XFER_CONTROL = 0
  64. USB_ENDPOINT_XFER_ISOC = 1
  65. USB_ENDPOINT_XFER_BULK = 2
  66. USB_ENDPOINT_XFER_INT = 3
  67. USB_ENDPOINT_MAX_ADJUSTABLE = 0x80
  68. class Descriptor(object):
  69. STRDESC = 0xFF
  70. def __init__(self, parentDevice=None):
  71. self.parentDevice = parentDevice
  72. self.attributes = {}
  73. self.index = 0
  74. def getParentDevice(self):
  75. if self.parentDevice:
  76. return self.parentDevice
  77. return self
  78. @staticmethod
  79. def name2type(name):
  80. if name.startswith("bcd") or\
  81. name.startswith("id") or\
  82. name.startswith("w"):
  83. return 16
  84. if name.startswith("i"):
  85. return Descriptor.STRDESC
  86. if name.startswith("bm") or\
  87. name.startswith("b"):
  88. return 8
  89. raise Exception("Could not determine type from name '%s'" % name)
  90. def __createValue(self, name, value):
  91. if self.name2type(name) == Descriptor.STRDESC:
  92. sd = StringDescriptor(value)
  93. self.getParentDevice().addStringDescriptor(sd)
  94. return sd
  95. return value
  96. def __destroyValue(self, name, value):
  97. if self.name2type(name) == Descriptor.STRDESC:
  98. self.getParentDevice().removeStringDescriptor(value)
  99. def alloc(self, name, value):
  100. if name in self.attributes:
  101. raise Exception("Attribute " + name + " double allocation")
  102. self.attributes[name] = [self.index, self.__createValue(name, value)]
  103. self.index += 1
  104. def set(self, name, value):
  105. if not name in self.attributes:
  106. raise Exception("Attribute " + name + " not found")
  107. self.__destroyValue(name, self.attributes[name][1])
  108. self.attributes[name][1] = self.__createValue(name, value)
  109. def getValue(self, name):
  110. if not name in self.attributes:
  111. raise Exception("Attribute " + name + " not found")
  112. (index, value) = self.attributes[name]
  113. return value
  114. def getList(self):
  115. # Returns a list of (name, value) tuples.
  116. l = [ None ] * len(self.attributes)
  117. for attrName in self.attributes:
  118. (index, value) = self.attributes[attrName]
  119. l[index] = (attrName, value)
  120. return l
  121. class StringDescriptor(object):
  122. def __init__(self, string=None, ccode=None, strId=None):
  123. if ccode is None:
  124. ccode = []
  125. uni = string.encode("UTF-16-LE")
  126. for i in range(0, len(uni), 2):
  127. pfx = ""
  128. if i != 0 and i % 8 == 0:
  129. pfx = "\n\t"
  130. ccode.append("%s0x%02X, 0x%02X" %\
  131. (pfx, ord(uni[i]), ord(uni[i+1])))
  132. self.ccode = ", ".join(ccode)
  133. self.text = string
  134. else:
  135. self.ccode = ccode
  136. self.text = ccode
  137. self.strId = strId
  138. def getId(self):
  139. return self.strId
  140. def setId(self, strId):
  141. self.strId = strId
  142. def getText(self):
  143. return self.text
  144. def getCCode(self):
  145. return self.ccode
  146. class Device(Descriptor):
  147. def __init__(self):
  148. Descriptor.__init__(self)
  149. self.configs = []
  150. self.stringDescs = []
  151. # Only one language for now
  152. langSd = StringDescriptor(ccode="0x09, 0x04", strId=0) # Language ID (US)
  153. self.addStringDescriptor(langSd)
  154. self.alloc("bLength", USB_DT_DEVICE_SIZE)
  155. self.alloc("bDescriptorType", USB_DT_DEVICE)
  156. self.alloc("bcdUSB", USB_BCD_11)
  157. self.alloc("bDeviceClass", 0)
  158. self.alloc("bDeviceSubClass", 0)
  159. self.alloc("bDeviceProtocol", 0)
  160. self.alloc("bMaxPacketSize0", 0)
  161. self.alloc("idVendor", 0x6666)
  162. self.alloc("idProduct", 0x1337)
  163. self.alloc("bcdDevice", 0)
  164. self.alloc("iManufacturer", "")
  165. self.alloc("iProduct", "")
  166. self.alloc("iSerialNumber", "")
  167. self.alloc("bNumConfigurations", 0)
  168. def addConfiguration(self, configuration):
  169. self.configs.append(configuration)
  170. def addStringDescriptor(self, sd):
  171. self.stringDescs.append(sd)
  172. def removeStringDescriptor(self, sd):
  173. self.stringDescs.remove(sd)
  174. def __setStringDescriptorIds(self):
  175. nextId = 1
  176. for sd in self.stringDescs:
  177. if sd.getId() is not None:
  178. continue
  179. sd.setId(nextId)
  180. nextId += 1
  181. def __autoConfig(self):
  182. self.set("bNumConfigurations", len(self.configs))
  183. configNr = 1
  184. interfNr = 0
  185. for config in self.configs:
  186. totalLength = config.getValue("bLength")
  187. config.set("bConfigurationValue", configNr)
  188. configNr += 1
  189. config.set("bNumInterfaces", len(config.interfaces))
  190. for interface in config.interfaces:
  191. totalLength += interface.getValue("bLength")
  192. interface.set("bInterfaceNumber", interfNr)
  193. interfNr += 1
  194. interface.set("bNumEndpoints", len(interface.endpoints))
  195. for ep in interface.endpoints:
  196. totalLength += ep.getValue("bLength")
  197. if interface.hiddevice:
  198. totalLength += interface.hiddevice.getValue("bLength")
  199. config.set("wTotalLength", totalLength)
  200. def __attrParse(self, attr):
  201. (name, value) = attr
  202. attrType = Descriptor.name2type(name)
  203. if attrType == Descriptor.STRDESC:
  204. sd = value
  205. value = "0x%02X, " % sd.getId()
  206. elif attrType == 8:
  207. value = "0x%02X, " % int(value)
  208. elif attrType == 16:
  209. value = int(value)
  210. value = "0x%02X, 0x%02X, " % (value & 0xFF, (value >> 8) & 0xFF)
  211. else:
  212. raise Exception("Unknown type (%s)" % str(attrType))
  213. return (name, attrType, value)
  214. def __attrDump(self, attrList):
  215. s = []
  216. count = 0
  217. for attr in attrList:
  218. (name, attrType, value) = self.__attrParse(attr)
  219. s.append(value)
  220. if attrType == 16:
  221. count += 2
  222. else:
  223. count += 1
  224. if count % 10 == 0 and count != 0:
  225. s.append("\n\t")
  226. return ("".join(s), count)
  227. def __repr__(self):
  228. self.__setStringDescriptorIds()
  229. self.__autoConfig()
  230. s = [ "/*** THIS FILE IS GENERATED. DO NOT EDIT! ***/\n\n" ]
  231. s.append("struct descriptor_ptr {\n")
  232. s.append("\tconst void * USB_PROGMEM ptr;\n")
  233. s.append("\tuint8_t size;\n")
  234. s.append("};\n\n")
  235. s.append("static const uint8_t USB_PROGMEM device_descriptor[] = {\n\t")
  236. (string, cnt) = self.__attrDump(self.getList())
  237. s.append(string)
  238. s.append("\n};\n\n")
  239. configNr = 0
  240. for config in self.configs:
  241. count = 0
  242. s.append("static const uint8_t USB_PROGMEM config%d_descriptor[] = {\n\t" % configNr)
  243. (string, cnt) = self.__attrDump(config.getList())
  244. s.append(string)
  245. count += cnt
  246. s.append("\n")
  247. for interface in config.interfaces:
  248. s.append("\t/* Interface */\n\t")
  249. (string, cnt) = self.__attrDump(interface.getList())
  250. s.append(string)
  251. count += cnt
  252. s.append("\n")
  253. if interface.hiddevice:
  254. s.append("\t/* HID Device */\n\t")
  255. (string, cnt) = self.__attrDump(interface.hiddevice.getList())
  256. s.append(string)
  257. s.append("\n\t#define HID_DEVICE_DESC_OFFSET\t%d" % count)
  258. count += cnt
  259. s.append("\n")
  260. for ep in interface.endpoints:
  261. s.append("\t/* Endpoint */\n\t")
  262. (string, cnt) = self.__attrDump(ep.getList())
  263. s.append(string)
  264. count += cnt
  265. s.append("\n")
  266. s.append("};\n\n")
  267. configNr += 1
  268. s.append("static const struct descriptor_ptr USB_PROGMEM config_descriptor_ptrs[] = {\n")
  269. for i in range(0, len(self.configs)):
  270. s.append("\t{\n")
  271. s.append("\t\t.ptr\t= config%d_descriptor,\n" % i)
  272. s.append("\t\t.size\t= sizeof(config%d_descriptor),\n" % i)
  273. s.append("\t},\n")
  274. s.append("};\n\n")
  275. for sd in self.stringDescs:
  276. s.append("\n/* %d: " % sd.getId())
  277. s.append(sd.getText())
  278. s.append(" */\n")
  279. s.append("static const char USB_PROGMEM string%d_descriptor[] = {\n" % sd.getId())
  280. s.append("\t%s\n};\n" % sd.getCCode())
  281. s.append("\n")
  282. s.append("static const struct descriptor_ptr USB_PROGMEM string_descriptor_ptrs[] = {\n")
  283. for sd in self.stringDescs:
  284. s.append("\t{\n")
  285. s.append("\t\t.ptr\t= string%d_descriptor,\n" % sd.getId())
  286. s.append("\t\t.size\t= sizeof(string%d_descriptor),\n" % sd.getId())
  287. s.append("\t},\n")
  288. s.append("};\n\n")
  289. return "".join(s)
  290. def dump(self):
  291. print self
  292. class Configuration(Descriptor):
  293. def __init__(self, device):
  294. Descriptor.__init__(self, device)
  295. self.device = device
  296. device.addConfiguration(self)
  297. self.interfaces = []
  298. self.alloc("bLength", USB_DT_CONFIG_SIZE)
  299. self.alloc("bDescriptorType", USB_DT_CONFIG)
  300. self.alloc("wTotalLength", 0)
  301. self.alloc("bNumInterfaces", 0)
  302. self.alloc("bConfigurationValue", 0)
  303. self.alloc("iConfiguration", "")
  304. self.alloc("bmAttributes", 0)
  305. self.alloc("bMaxPower", 500 / 2)
  306. def addInterface(self, interface):
  307. self.interfaces.append(interface)
  308. class Interface(Descriptor):
  309. def __init__(self, configuration):
  310. Descriptor.__init__(self, configuration.getParentDevice())
  311. self.configuration = configuration
  312. configuration.addInterface(self)
  313. self.endpoints = []
  314. self.hiddevice = None
  315. self.alloc("bLength", USB_DT_INTERFACE_SIZE)
  316. self.alloc("bDescriptorType", USB_DT_INTERFACE)
  317. self.alloc("bInterfaceNumber", 0)
  318. self.alloc("bAlternateSetting", 0)
  319. self.alloc("bNumEndpoints", 0)
  320. self.alloc("bInterfaceClass", 0)
  321. self.alloc("bInterfaceSubClass", 0)
  322. self.alloc("bInterfaceProtocol", 0)
  323. self.alloc("iInterface", "")
  324. def addEndpoint(self, endpoint):
  325. self.endpoints.append(endpoint)
  326. def addHIDDevice(self, hidDevice):
  327. if (self.hiddevice):
  328. raise Exception("Only one HID device")
  329. self.hiddevice = hidDevice
  330. class Endpoint(Descriptor):
  331. def __init__(self, interface):
  332. Descriptor.__init__(self, interface.getParentDevice())
  333. self.interface = interface
  334. interface.addEndpoint(self)
  335. self.alloc("bLength", USB_DT_ENDPOINT_SIZE)
  336. self.alloc("bDescriptorType", USB_DT_ENDPOINT)
  337. self.alloc("bEndpointAddress", 0)
  338. self.alloc("bmAttributes", 0)
  339. self.alloc("wMaxPacketSize", 0)
  340. self.alloc("bInterval", 0)
  341. class HIDDevice(Descriptor):
  342. def __init__(self, interface):
  343. Descriptor.__init__(self, interface.getParentDevice())
  344. self.interface = interface
  345. interface.addHIDDevice(self)
  346. self.alloc("bLength", 9)
  347. self.alloc("bDescriptorType", HID_DT_HID)
  348. self.alloc("bcdHID", 0x0111)
  349. self.alloc("bCountryCode", 0)
  350. self.alloc("bNumDescriptors", 0)
  351. self.alloc("bClassDescriptorType", 0)
  352. self.alloc("wClassDescriptorLength", 0)
  353. device = Device()
  354. try:
  355. device.set("idVendor", int(sys.argv[1], 16))
  356. device.set("idProduct", int(sys.argv[2], 16))
  357. except (ValueError, IndexError), e:
  358. pass
  359. atexit.register(device.dump)