]> Git Repo - qemu.git/blame - hw/usb/desc-msos.c
Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-9' into staging
[qemu.git] / hw / usb / desc-msos.c
CommitLineData
5319dc7b
GH
1#include "hw/usb.h"
2#include "hw/usb/desc.h"
3
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/* ------------------------------------------------------------------ */
33
34typedef struct msos_compat_hdr {
35 uint32_t dwLength;
36 uint8_t bcdVersion_lo;
37 uint8_t bcdVersion_hi;
38 uint8_t wIndex_lo;
39 uint8_t wIndex_hi;
40 uint8_t bCount;
41 uint8_t reserved[7];
42} QEMU_PACKED msos_compat_hdr;
43
44typedef struct msos_compat_func {
45 uint8_t bFirstInterfaceNumber;
46 uint8_t reserved_1;
409951f5 47 char compatibleId[8];
5319dc7b
GH
48 uint8_t subCompatibleId[8];
49 uint8_t reserved_2[6];
50} QEMU_PACKED msos_compat_func;
51
52static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
53{
54 msos_compat_hdr *hdr = (void *)dest;
55 msos_compat_func *func;
56 int length = sizeof(*hdr);
57 int count = 0;
58
59 func = (void *)(dest + length);
60 func->bFirstInterfaceNumber = 0;
61 func->reserved_1 = 0x01;
409951f5
GH
62 if (desc->msos->CompatibleID) {
63 snprintf(func->compatibleId, sizeof(func->compatibleId),
64 "%s", desc->msos->CompatibleID);
65 }
5319dc7b
GH
66 length += sizeof(*func);
67 count++;
68
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;
74 hdr->bCount = count;
75 return length;
76}
77
78/* ------------------------------------------------------------------ */
79
80typedef struct msos_prop_hdr {
81 uint32_t dwLength;
82 uint8_t bcdVersion_lo;
83 uint8_t bcdVersion_hi;
84 uint8_t wIndex_lo;
85 uint8_t wIndex_hi;
86 uint8_t wCount_lo;
87 uint8_t wCount_hi;
88} QEMU_PACKED msos_prop_hdr;
89
90typedef struct msos_prop {
91 uint32_t dwLength;
92 uint32_t dwPropertyDataType;
93 uint8_t dwPropertyNameLength_lo;
94 uint8_t dwPropertyNameLength_hi;
95 uint8_t bPropertyName[];
96} QEMU_PACKED msos_prop;
97
98typedef struct msos_prop_data {
99 uint32_t dwPropertyDataLength;
100 uint8_t bPropertyData[];
101} QEMU_PACKED msos_prop_data;
102
103typedef enum msos_prop_type {
104 MSOS_REG_SZ = 1,
105 MSOS_REG_EXPAND_SZ = 2,
106 MSOS_REG_BINARY = 3,
107 MSOS_REG_DWORD_LE = 4,
108 MSOS_REG_DWORD_BE = 5,
109 MSOS_REG_LINK = 6,
110 MSOS_REG_MULTI_SZ = 7,
111} msos_prop_type;
112
113static int usb_desc_msos_prop_name(struct msos_prop *prop,
114 const wchar_t *name)
115{
116 int length = wcslen(name) + 1;
117 int i;
118
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]);
124 }
125 return length*2;
126}
127
128static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
129 const wchar_t *name, const wchar_t *value)
130{
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;
135
136 prop->dwPropertyDataType = cpu_to_le32(type);
137 length += usb_desc_msos_prop_name(prop, name);
138 data = (void *)(dest + length);
139
140 data->dwPropertyDataLength = cpu_to_le32(vlen*2);
141 length += sizeof(*prop);
142
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]);
146 }
147 length += vlen*2;
148
149 prop->dwLength = cpu_to_le32(length);
150 return length;
151}
152
153static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
154 uint32_t value)
155{
156 struct msos_prop *prop = (void *)dest;
157 struct msos_prop_data *data;
158 int length = sizeof(*prop);
159
160 prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
161 length += usb_desc_msos_prop_name(prop, name);
162 data = (void *)(dest + length);
163
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;
170
171 prop->dwLength = cpu_to_le32(length);
172 return length;
173}
174
175static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
176{
177 msos_prop_hdr *hdr = (void *)dest;
178 int length = sizeof(*hdr);
179 int count = 0;
180
181 if (desc->msos->Label) {
182 /*
183 * Given as example in the specs. Havn't figured yet where
184 * this label shows up in the windows gui.
185 */
186 length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
187 L"Label", desc->msos->Label);
188 count++;
189 }
190
191 if (desc->msos->SelectiveSuspendEnabled) {
192 /*
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.
197 */
198 length += usb_desc_msos_prop_dword(dest+length,
199 L"SelectiveSuspendEnabled", 1);
200 count++;
201 }
202
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);
210 return length;
211}
212
213/* ------------------------------------------------------------------ */
214
215int usb_desc_msos(const USBDesc *desc, USBPacket *p,
216 int index, uint8_t *dest, size_t len)
217{
218 void *buf = g_malloc0(4096);
219 int length = 0;
220
221 switch (index) {
222 case 0x0004:
223 length = usb_desc_msos_compat(desc, buf);
224 break;
225 case 0x0005:
226 length = usb_desc_msos_prop(desc, buf);
227 break;
228 }
229
230 if (length > len) {
231 length = len;
232 }
233 memcpy(dest, buf, length);
234 free(buf);
235
236 p->actual_length = length;
237 return 0;
238}
This page took 0.060741 seconds and 4 git commands to generate.