2 #include "hw/usb/desc.h"
5 * Microsoft OS Descriptors
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:
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).
15 * properties descriptor
16 * Does carry registry entries. They show up in
17 * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
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".
28 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
32 /* ------------------------------------------------------------------ */
34 typedef struct msos_compat_hdr
{
36 uint8_t bcdVersion_lo
;
37 uint8_t bcdVersion_hi
;
42 } QEMU_PACKED msos_compat_hdr
;
44 typedef struct msos_compat_func
{
45 uint8_t bFirstInterfaceNumber
;
48 uint8_t subCompatibleId
[8];
49 uint8_t reserved_2
[6];
50 } QEMU_PACKED msos_compat_func
;
52 static int usb_desc_msos_compat(const USBDesc
*desc
, uint8_t *dest
)
54 msos_compat_hdr
*hdr
= (void *)dest
;
55 msos_compat_func
*func
;
56 int length
= sizeof(*hdr
);
59 func
= (void *)(dest
+ length
);
60 func
->bFirstInterfaceNumber
= 0;
61 func
->reserved_1
= 0x01;
62 if (desc
->msos
->CompatibleID
) {
63 snprintf(func
->compatibleId
, sizeof(func
->compatibleId
),
64 "%s", desc
->msos
->CompatibleID
);
66 length
+= sizeof(*func
);
69 hdr
->dwLength
= cpu_to_le32(length
);
70 hdr
->bcdVersion_lo
= 0x00;
71 hdr
->bcdVersion_hi
= 0x01;
72 hdr
->wIndex_lo
= 0x04;
73 hdr
->wIndex_hi
= 0x00;
78 /* ------------------------------------------------------------------ */
80 typedef struct msos_prop_hdr
{
82 uint8_t bcdVersion_lo
;
83 uint8_t bcdVersion_hi
;
88 } QEMU_PACKED msos_prop_hdr
;
90 typedef struct msos_prop
{
92 uint32_t dwPropertyDataType
;
93 uint8_t dwPropertyNameLength_lo
;
94 uint8_t dwPropertyNameLength_hi
;
95 uint8_t bPropertyName
[];
96 } QEMU_PACKED msos_prop
;
98 typedef struct msos_prop_data
{
99 uint32_t dwPropertyDataLength
;
100 uint8_t bPropertyData
[];
101 } QEMU_PACKED msos_prop_data
;
103 typedef enum msos_prop_type
{
105 MSOS_REG_EXPAND_SZ
= 2,
107 MSOS_REG_DWORD_LE
= 4,
108 MSOS_REG_DWORD_BE
= 5,
110 MSOS_REG_MULTI_SZ
= 7,
113 static int usb_desc_msos_prop_name(struct msos_prop
*prop
,
116 int length
= wcslen(name
) + 1;
119 prop
->dwPropertyNameLength_lo
= usb_lo(length
*2);
120 prop
->dwPropertyNameLength_hi
= usb_hi(length
*2);
121 for (i
= 0; i
< length
; i
++) {
122 prop
->bPropertyName
[i
*2] = usb_lo(name
[i
]);
123 prop
->bPropertyName
[i
*2+1] = usb_hi(name
[i
]);
128 static int usb_desc_msos_prop_str(uint8_t *dest
, msos_prop_type type
,
129 const wchar_t *name
, const wchar_t *value
)
131 struct msos_prop
*prop
= (void *)dest
;
132 struct msos_prop_data
*data
;
133 int length
= sizeof(*prop
);
134 int i
, vlen
= wcslen(value
) + 1;
136 prop
->dwPropertyDataType
= cpu_to_le32(type
);
137 length
+= usb_desc_msos_prop_name(prop
, name
);
138 data
= (void *)(dest
+ length
);
140 data
->dwPropertyDataLength
= cpu_to_le32(vlen
*2);
141 length
+= sizeof(*prop
);
143 for (i
= 0; i
< vlen
; i
++) {
144 data
->bPropertyData
[i
*2] = usb_lo(value
[i
]);
145 data
->bPropertyData
[i
*2+1] = usb_hi(value
[i
]);
149 prop
->dwLength
= cpu_to_le32(length
);
153 static int usb_desc_msos_prop_dword(uint8_t *dest
, const wchar_t *name
,
156 struct msos_prop
*prop
= (void *)dest
;
157 struct msos_prop_data
*data
;
158 int length
= sizeof(*prop
);
160 prop
->dwPropertyDataType
= cpu_to_le32(MSOS_REG_DWORD_LE
);
161 length
+= usb_desc_msos_prop_name(prop
, name
);
162 data
= (void *)(dest
+ length
);
164 data
->dwPropertyDataLength
= cpu_to_le32(4);
165 data
->bPropertyData
[0] = (value
) & 0xff;
166 data
->bPropertyData
[1] = (value
>> 8) & 0xff;
167 data
->bPropertyData
[2] = (value
>> 16) & 0xff;
168 data
->bPropertyData
[3] = (value
>> 24) & 0xff;
169 length
+= sizeof(*prop
) + 4;
171 prop
->dwLength
= cpu_to_le32(length
);
175 static int usb_desc_msos_prop(const USBDesc
*desc
, uint8_t *dest
)
177 msos_prop_hdr
*hdr
= (void *)dest
;
178 int length
= sizeof(*hdr
);
181 if (desc
->msos
->Label
) {
183 * Given as example in the specs. Havn't figured yet where
184 * this label shows up in the windows gui.
186 length
+= usb_desc_msos_prop_str(dest
+length
, MSOS_REG_SZ
,
187 L
"Label", desc
->msos
->Label
);
191 if (desc
->msos
->SelectiveSuspendEnabled
) {
193 * Signaling remote wakeup capability in the standard usb
194 * descriptors isn't enouth to make windows actually use it.
195 * This is the "Yes, we really mean it" registy entry to flip
196 * the switch in the windows drivers.
198 length
+= usb_desc_msos_prop_dword(dest
+length
,
199 L
"SelectiveSuspendEnabled", 1);
203 hdr
->dwLength
= cpu_to_le32(length
);
204 hdr
->bcdVersion_lo
= 0x00;
205 hdr
->bcdVersion_hi
= 0x01;
206 hdr
->wIndex_lo
= 0x05;
207 hdr
->wIndex_hi
= 0x00;
208 hdr
->wCount_lo
= usb_lo(count
);
209 hdr
->wCount_hi
= usb_hi(count
);
213 /* ------------------------------------------------------------------ */
215 int usb_desc_msos(const USBDesc
*desc
, USBPacket
*p
,
216 int index
, uint8_t *dest
, size_t len
)
218 void *buf
= g_malloc0(4096);
223 length
= usb_desc_msos_compat(desc
, buf
);
226 length
= usb_desc_msos_prop(desc
, buf
);
233 memcpy(dest
, buf
, length
);
236 p
->actual_length
= length
;