1 #include "qemu/osdep.h"
6 * Microsoft OS Descriptors
8 * Windows tries to fetch some special descriptors with information
9 * specifically for windows. Presence is indicated using a special
10 * string @ index 0xee. There are two kinds of descriptors:
13 * Used to bind drivers, if usb class isn't specific enough.
14 * Used for PTP/MTP for example (both share the same usb class).
16 * properties descriptor
17 * Does carry registry entries. They show up in
18 * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
20 * Note that Windows caches the stuff it got in the registry, so when
21 * playing with this you have to delete registry subtrees to make
22 * windows query the device again:
23 * HLM\SYSTEM\CurrentControlSet\Control\usbflags
24 * HLM\SYSTEM\CurrentControlSet\Enum\USB
25 * Windows will complain it can't delete entries on the second one.
26 * It has deleted everything it had permissions too, which is enough
27 * as this includes "Device Parameters".
29 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
33 /* ------------------------------------------------------------------ */
35 typedef struct msos_compat_hdr
{
37 uint8_t bcdVersion_lo
;
38 uint8_t bcdVersion_hi
;
43 } QEMU_PACKED msos_compat_hdr
;
45 typedef struct msos_compat_func
{
46 uint8_t bFirstInterfaceNumber
;
49 uint8_t subCompatibleId
[8];
50 uint8_t reserved_2
[6];
51 } QEMU_PACKED msos_compat_func
;
53 static int usb_desc_msos_compat(const USBDesc
*desc
, uint8_t *dest
)
55 msos_compat_hdr
*hdr
= (void *)dest
;
56 msos_compat_func
*func
;
57 int length
= sizeof(*hdr
);
60 func
= (void *)(dest
+ length
);
61 func
->bFirstInterfaceNumber
= 0;
62 func
->reserved_1
= 0x01;
63 if (desc
->msos
->CompatibleID
) {
64 snprintf(func
->compatibleId
, sizeof(func
->compatibleId
),
65 "%s", desc
->msos
->CompatibleID
);
67 length
+= sizeof(*func
);
70 hdr
->dwLength
= cpu_to_le32(length
);
71 hdr
->bcdVersion_lo
= 0x00;
72 hdr
->bcdVersion_hi
= 0x01;
73 hdr
->wIndex_lo
= 0x04;
74 hdr
->wIndex_hi
= 0x00;
79 /* ------------------------------------------------------------------ */
81 typedef struct msos_prop_hdr
{
83 uint8_t bcdVersion_lo
;
84 uint8_t bcdVersion_hi
;
89 } QEMU_PACKED msos_prop_hdr
;
91 typedef struct msos_prop
{
93 uint32_t dwPropertyDataType
;
94 uint8_t dwPropertyNameLength_lo
;
95 uint8_t dwPropertyNameLength_hi
;
96 uint8_t bPropertyName
[];
97 } QEMU_PACKED msos_prop
;
99 typedef struct msos_prop_data
{
100 uint32_t dwPropertyDataLength
;
101 uint8_t bPropertyData
[];
102 } QEMU_PACKED msos_prop_data
;
104 typedef enum msos_prop_type
{
106 MSOS_REG_EXPAND_SZ
= 2,
108 MSOS_REG_DWORD_LE
= 4,
109 MSOS_REG_DWORD_BE
= 5,
111 MSOS_REG_MULTI_SZ
= 7,
114 static int usb_desc_msos_prop_name(struct msos_prop
*prop
,
117 int length
= wcslen(name
) + 1;
120 prop
->dwPropertyNameLength_lo
= usb_lo(length
*2);
121 prop
->dwPropertyNameLength_hi
= usb_hi(length
*2);
122 for (i
= 0; i
< length
; i
++) {
123 prop
->bPropertyName
[i
*2] = usb_lo(name
[i
]);
124 prop
->bPropertyName
[i
*2+1] = usb_hi(name
[i
]);
129 static int usb_desc_msos_prop_str(uint8_t *dest
, msos_prop_type type
,
130 const wchar_t *name
, const wchar_t *value
)
132 struct msos_prop
*prop
= (void *)dest
;
133 struct msos_prop_data
*data
;
134 int length
= sizeof(*prop
);
135 int i
, vlen
= wcslen(value
) + 1;
137 prop
->dwPropertyDataType
= cpu_to_le32(type
);
138 length
+= usb_desc_msos_prop_name(prop
, name
);
139 data
= (void *)(dest
+ length
);
141 data
->dwPropertyDataLength
= cpu_to_le32(vlen
*2);
142 length
+= sizeof(*prop
);
144 for (i
= 0; i
< vlen
; i
++) {
145 data
->bPropertyData
[i
*2] = usb_lo(value
[i
]);
146 data
->bPropertyData
[i
*2+1] = usb_hi(value
[i
]);
150 prop
->dwLength
= cpu_to_le32(length
);
154 static int usb_desc_msos_prop_dword(uint8_t *dest
, const wchar_t *name
,
157 struct msos_prop
*prop
= (void *)dest
;
158 struct msos_prop_data
*data
;
159 int length
= sizeof(*prop
);
161 prop
->dwPropertyDataType
= cpu_to_le32(MSOS_REG_DWORD_LE
);
162 length
+= usb_desc_msos_prop_name(prop
, name
);
163 data
= (void *)(dest
+ length
);
165 data
->dwPropertyDataLength
= cpu_to_le32(4);
166 data
->bPropertyData
[0] = (value
) & 0xff;
167 data
->bPropertyData
[1] = (value
>> 8) & 0xff;
168 data
->bPropertyData
[2] = (value
>> 16) & 0xff;
169 data
->bPropertyData
[3] = (value
>> 24) & 0xff;
170 length
+= sizeof(*prop
) + 4;
172 prop
->dwLength
= cpu_to_le32(length
);
176 static int usb_desc_msos_prop(const USBDesc
*desc
, uint8_t *dest
)
178 msos_prop_hdr
*hdr
= (void *)dest
;
179 int length
= sizeof(*hdr
);
182 if (desc
->msos
->Label
) {
184 * Given as example in the specs. Haven't figured yet where
185 * this label shows up in the windows gui.
187 length
+= usb_desc_msos_prop_str(dest
+length
, MSOS_REG_SZ
,
188 L
"Label", desc
->msos
->Label
);
192 if (desc
->msos
->SelectiveSuspendEnabled
) {
194 * Signaling remote wakeup capability in the standard usb
195 * descriptors isn't enough to make windows actually use it.
196 * This is the "Yes, we really mean it" registry entry to flip
197 * the switch in the windows drivers.
199 length
+= usb_desc_msos_prop_dword(dest
+length
,
200 L
"SelectiveSuspendEnabled", 1);
204 hdr
->dwLength
= cpu_to_le32(length
);
205 hdr
->bcdVersion_lo
= 0x00;
206 hdr
->bcdVersion_hi
= 0x01;
207 hdr
->wIndex_lo
= 0x05;
208 hdr
->wIndex_hi
= 0x00;
209 hdr
->wCount_lo
= usb_lo(count
);
210 hdr
->wCount_hi
= usb_hi(count
);
214 /* ------------------------------------------------------------------ */
216 int usb_desc_msos(const USBDesc
*desc
, USBPacket
*p
,
217 int index
, uint8_t *dest
, size_t len
)
219 void *buf
= g_malloc0(4096);
224 length
= usb_desc_msos_compat(desc
, buf
);
227 length
= usb_desc_msos_prop(desc
, buf
);
234 memcpy(dest
, buf
, length
);
237 p
->actual_length
= length
;