2
0

desc-msos.c 6.9 KB

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