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
;
47 uint8_t compatibleId
[8];
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 length
+= sizeof(*func
);
65 hdr
->dwLength
= cpu_to_le32(length
);
66 hdr
->bcdVersion_lo
= 0x00;
67 hdr
->bcdVersion_hi
= 0x01;
68 hdr
->wIndex_lo
= 0x04;
69 hdr
->wIndex_hi
= 0x00;
74 /* ------------------------------------------------------------------ */
76 typedef struct msos_prop_hdr
{
78 uint8_t bcdVersion_lo
;
79 uint8_t bcdVersion_hi
;
84 } QEMU_PACKED msos_prop_hdr
;
86 typedef struct msos_prop
{
88 uint32_t dwPropertyDataType
;
89 uint8_t dwPropertyNameLength_lo
;
90 uint8_t dwPropertyNameLength_hi
;
91 uint8_t bPropertyName
[];
92 } QEMU_PACKED msos_prop
;
94 typedef struct msos_prop_data
{
95 uint32_t dwPropertyDataLength
;
96 uint8_t bPropertyData
[];
97 } QEMU_PACKED msos_prop_data
;
99 typedef enum msos_prop_type
{
101 MSOS_REG_EXPAND_SZ
= 2,
103 MSOS_REG_DWORD_LE
= 4,
104 MSOS_REG_DWORD_BE
= 5,
106 MSOS_REG_MULTI_SZ
= 7,
109 static int usb_desc_msos_prop_name(struct msos_prop
*prop
,
112 int length
= wcslen(name
) + 1;
115 prop
->dwPropertyNameLength_lo
= usb_lo(length
*2);
116 prop
->dwPropertyNameLength_hi
= usb_hi(length
*2);
117 for (i
= 0; i
< length
; i
++) {
118 prop
->bPropertyName
[i
*2] = usb_lo(name
[i
]);
119 prop
->bPropertyName
[i
*2+1] = usb_hi(name
[i
]);
124 static int usb_desc_msos_prop_str(uint8_t *dest
, msos_prop_type type
,
125 const wchar_t *name
, const wchar_t *value
)
127 struct msos_prop
*prop
= (void *)dest
;
128 struct msos_prop_data
*data
;
129 int length
= sizeof(*prop
);
130 int i
, vlen
= wcslen(value
) + 1;
132 prop
->dwPropertyDataType
= cpu_to_le32(type
);
133 length
+= usb_desc_msos_prop_name(prop
, name
);
134 data
= (void *)(dest
+ length
);
136 data
->dwPropertyDataLength
= cpu_to_le32(vlen
*2);
137 length
+= sizeof(*prop
);
139 for (i
= 0; i
< vlen
; i
++) {
140 data
->bPropertyData
[i
*2] = usb_lo(value
[i
]);
141 data
->bPropertyData
[i
*2+1] = usb_hi(value
[i
]);
145 prop
->dwLength
= cpu_to_le32(length
);
149 static int usb_desc_msos_prop_dword(uint8_t *dest
, const wchar_t *name
,
152 struct msos_prop
*prop
= (void *)dest
;
153 struct msos_prop_data
*data
;
154 int length
= sizeof(*prop
);
156 prop
->dwPropertyDataType
= cpu_to_le32(MSOS_REG_DWORD_LE
);
157 length
+= usb_desc_msos_prop_name(prop
, name
);
158 data
= (void *)(dest
+ length
);
160 data
->dwPropertyDataLength
= cpu_to_le32(4);
161 data
->bPropertyData
[0] = (value
) & 0xff;
162 data
->bPropertyData
[1] = (value
>> 8) & 0xff;
163 data
->bPropertyData
[2] = (value
>> 16) & 0xff;
164 data
->bPropertyData
[3] = (value
>> 24) & 0xff;
165 length
+= sizeof(*prop
) + 4;
167 prop
->dwLength
= cpu_to_le32(length
);
171 static int usb_desc_msos_prop(const USBDesc
*desc
, uint8_t *dest
)
173 msos_prop_hdr
*hdr
= (void *)dest
;
174 int length
= sizeof(*hdr
);
177 if (desc
->msos
->Label
) {
179 * Given as example in the specs. Havn't figured yet where
180 * this label shows up in the windows gui.
182 length
+= usb_desc_msos_prop_str(dest
+length
, MSOS_REG_SZ
,
183 L
"Label", desc
->msos
->Label
);
187 if (desc
->msos
->SelectiveSuspendEnabled
) {
189 * Signaling remote wakeup capability in the standard usb
190 * descriptors isn't enouth to make windows actually use it.
191 * This is the "Yes, we really mean it" registy entry to flip
192 * the switch in the windows drivers.
194 length
+= usb_desc_msos_prop_dword(dest
+length
,
195 L
"SelectiveSuspendEnabled", 1);
199 hdr
->dwLength
= cpu_to_le32(length
);
200 hdr
->bcdVersion_lo
= 0x00;
201 hdr
->bcdVersion_hi
= 0x01;
202 hdr
->wIndex_lo
= 0x05;
203 hdr
->wIndex_hi
= 0x00;
204 hdr
->wCount_lo
= usb_lo(count
);
205 hdr
->wCount_hi
= usb_hi(count
);
209 /* ------------------------------------------------------------------ */
211 int usb_desc_msos(const USBDesc
*desc
, USBPacket
*p
,
212 int index
, uint8_t *dest
, size_t len
)
214 void *buf
= g_malloc0(4096);
219 length
= usb_desc_msos_compat(desc
, buf
);
222 length
= usb_desc_msos_prop(desc
, buf
);
229 memcpy(dest
, buf
, length
);
232 p
->actual_length
= length
;