desc-msos.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #include "hw/usb.h"
  2. #include "hw/usb/desc.h"
  3. /*
  4. * Microsoft OS Descriptors
  5. *
  6. * Windows tries to fetch some special descriptors with informations
  7. * specifically for windows. Presence is indicated using a special
  8. * string @ index 0xee. There are two kinds of descriptors:
  9. *
  10. * compatid descriptor
  11. * Used to bind drivers, if usb class isn't specific enougth.
  12. * Used for PTP/MTP for example (both share the same usb class).
  13. *
  14. * properties descriptor
  15. * Does carry registry entries. They show up in
  16. * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
  17. *
  18. * Note that Windows caches the stuff it got in the registry, so when
  19. * playing with this you have to delete registry subtrees to make
  20. * windows query the device again:
  21. * HLM\SYSTEM\CurrentControlSet\Control\usbflags
  22. * HLM\SYSTEM\CurrentControlSet\Enum\USB
  23. * Windows will complain it can't delete entries on the second one.
  24. * It has deleted everything it had permissions too, which is enouth
  25. * as this includes "Device Parameters".
  26. *
  27. * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
  28. *
  29. */
  30. /* ------------------------------------------------------------------ */
  31. typedef struct msos_compat_hdr {
  32. uint32_t dwLength;
  33. uint8_t bcdVersion_lo;
  34. uint8_t bcdVersion_hi;
  35. uint8_t wIndex_lo;
  36. uint8_t wIndex_hi;
  37. uint8_t bCount;
  38. uint8_t reserved[7];
  39. } QEMU_PACKED msos_compat_hdr;
  40. typedef struct msos_compat_func {
  41. uint8_t bFirstInterfaceNumber;
  42. uint8_t reserved_1;
  43. uint8_t compatibleId[8];
  44. uint8_t subCompatibleId[8];
  45. uint8_t reserved_2[6];
  46. } QEMU_PACKED msos_compat_func;
  47. static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
  48. {
  49. msos_compat_hdr *hdr = (void *)dest;
  50. msos_compat_func *func;
  51. int length = sizeof(*hdr);
  52. int count = 0;
  53. func = (void *)(dest + length);
  54. func->bFirstInterfaceNumber = 0;
  55. func->reserved_1 = 0x01;
  56. length += sizeof(*func);
  57. count++;
  58. hdr->dwLength = cpu_to_le32(length);
  59. hdr->bcdVersion_lo = 0x00;
  60. hdr->bcdVersion_hi = 0x01;
  61. hdr->wIndex_lo = 0x04;
  62. hdr->wIndex_hi = 0x00;
  63. hdr->bCount = count;
  64. return length;
  65. }
  66. /* ------------------------------------------------------------------ */
  67. typedef struct msos_prop_hdr {
  68. uint32_t dwLength;
  69. uint8_t bcdVersion_lo;
  70. uint8_t bcdVersion_hi;
  71. uint8_t wIndex_lo;
  72. uint8_t wIndex_hi;
  73. uint8_t wCount_lo;
  74. uint8_t wCount_hi;
  75. } QEMU_PACKED msos_prop_hdr;
  76. typedef struct msos_prop {
  77. uint32_t dwLength;
  78. uint32_t dwPropertyDataType;
  79. uint8_t dwPropertyNameLength_lo;
  80. uint8_t dwPropertyNameLength_hi;
  81. uint8_t bPropertyName[];
  82. } QEMU_PACKED msos_prop;
  83. typedef struct msos_prop_data {
  84. uint32_t dwPropertyDataLength;
  85. uint8_t bPropertyData[];
  86. } QEMU_PACKED msos_prop_data;
  87. typedef enum msos_prop_type {
  88. MSOS_REG_SZ = 1,
  89. MSOS_REG_EXPAND_SZ = 2,
  90. MSOS_REG_BINARY = 3,
  91. MSOS_REG_DWORD_LE = 4,
  92. MSOS_REG_DWORD_BE = 5,
  93. MSOS_REG_LINK = 6,
  94. MSOS_REG_MULTI_SZ = 7,
  95. } msos_prop_type;
  96. static int usb_desc_msos_prop_name(struct msos_prop *prop,
  97. const wchar_t *name)
  98. {
  99. int length = wcslen(name) + 1;
  100. int i;
  101. prop->dwPropertyNameLength_lo = usb_lo(length*2);
  102. prop->dwPropertyNameLength_hi = usb_hi(length*2);
  103. for (i = 0; i < length; i++) {
  104. prop->bPropertyName[i*2] = usb_lo(name[i]);
  105. prop->bPropertyName[i*2+1] = usb_hi(name[i]);
  106. }
  107. return length*2;
  108. }
  109. static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
  110. const wchar_t *name, const wchar_t *value)
  111. {
  112. struct msos_prop *prop = (void *)dest;
  113. struct msos_prop_data *data;
  114. int length = sizeof(*prop);
  115. int i, vlen = wcslen(value) + 1;
  116. prop->dwPropertyDataType = cpu_to_le32(type);
  117. length += usb_desc_msos_prop_name(prop, name);
  118. data = (void *)(dest + length);
  119. data->dwPropertyDataLength = cpu_to_le32(vlen*2);
  120. length += sizeof(*prop);
  121. for (i = 0; i < vlen; i++) {
  122. data->bPropertyData[i*2] = usb_lo(value[i]);
  123. data->bPropertyData[i*2+1] = usb_hi(value[i]);
  124. }
  125. length += vlen*2;
  126. prop->dwLength = cpu_to_le32(length);
  127. return length;
  128. }
  129. static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
  130. uint32_t value)
  131. {
  132. struct msos_prop *prop = (void *)dest;
  133. struct msos_prop_data *data;
  134. int length = sizeof(*prop);
  135. prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
  136. length += usb_desc_msos_prop_name(prop, name);
  137. data = (void *)(dest + length);
  138. data->dwPropertyDataLength = cpu_to_le32(4);
  139. data->bPropertyData[0] = (value) & 0xff;
  140. data->bPropertyData[1] = (value >> 8) & 0xff;
  141. data->bPropertyData[2] = (value >> 16) & 0xff;
  142. data->bPropertyData[3] = (value >> 24) & 0xff;
  143. length += sizeof(*prop) + 4;
  144. prop->dwLength = cpu_to_le32(length);
  145. return length;
  146. }
  147. static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
  148. {
  149. msos_prop_hdr *hdr = (void *)dest;
  150. int length = sizeof(*hdr);
  151. int count = 0;
  152. if (desc->msos->Label) {
  153. /*
  154. * Given as example in the specs. Havn't figured yet where
  155. * this label shows up in the windows gui.
  156. */
  157. length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
  158. L"Label", desc->msos->Label);
  159. count++;
  160. }
  161. if (desc->msos->SelectiveSuspendEnabled) {
  162. /*
  163. * Signaling remote wakeup capability in the standard usb
  164. * descriptors isn't enouth to make windows actually use it.
  165. * This is the "Yes, we really mean it" registy entry to flip
  166. * the switch in the windows drivers.
  167. */
  168. length += usb_desc_msos_prop_dword(dest+length,
  169. L"SelectiveSuspendEnabled", 1);
  170. count++;
  171. }
  172. hdr->dwLength = cpu_to_le32(length);
  173. hdr->bcdVersion_lo = 0x00;
  174. hdr->bcdVersion_hi = 0x01;
  175. hdr->wIndex_lo = 0x05;
  176. hdr->wIndex_hi = 0x00;
  177. hdr->wCount_lo = usb_lo(count);
  178. hdr->wCount_hi = usb_hi(count);
  179. return length;
  180. }
  181. /* ------------------------------------------------------------------ */
  182. int usb_desc_msos(const USBDesc *desc, USBPacket *p,
  183. int index, uint8_t *dest, size_t len)
  184. {
  185. void *buf = g_malloc0(4096);
  186. int length = 0;
  187. switch (index) {
  188. case 0x0004:
  189. length = usb_desc_msos_compat(desc, buf);
  190. break;
  191. case 0x0005:
  192. length = usb_desc_msos_prop(desc, buf);
  193. break;
  194. }
  195. if (length > len) {
  196. length = len;
  197. }
  198. memcpy(dest, buf, length);
  199. free(buf);
  200. p->actual_length = length;
  201. return 0;
  202. }