]> Git Repo - qemu.git/blob - hw/usb/desc-msos.c
Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-5' into staging
[qemu.git] / hw / usb / desc-msos.c
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
34 typedef 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
44 typedef struct msos_compat_func {
45     uint8_t  bFirstInterfaceNumber;
46     uint8_t  reserved_1;
47     uint8_t  compatibleId[8];
48     uint8_t  subCompatibleId[8];
49     uint8_t  reserved_2[6];
50 } QEMU_PACKED msos_compat_func;
51
52 static 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;
62     length += sizeof(*func);
63     count++;
64
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;
70     hdr->bCount        = count;
71     return length;
72 }
73
74 /* ------------------------------------------------------------------ */
75
76 typedef struct msos_prop_hdr {
77     uint32_t dwLength;
78     uint8_t  bcdVersion_lo;
79     uint8_t  bcdVersion_hi;
80     uint8_t  wIndex_lo;
81     uint8_t  wIndex_hi;
82     uint8_t  wCount_lo;
83     uint8_t  wCount_hi;
84 } QEMU_PACKED msos_prop_hdr;
85
86 typedef struct msos_prop {
87     uint32_t dwLength;
88     uint32_t dwPropertyDataType;
89     uint8_t  dwPropertyNameLength_lo;
90     uint8_t  dwPropertyNameLength_hi;
91     uint8_t  bPropertyName[];
92 } QEMU_PACKED msos_prop;
93
94 typedef struct msos_prop_data {
95     uint32_t dwPropertyDataLength;
96     uint8_t  bPropertyData[];
97 } QEMU_PACKED msos_prop_data;
98
99 typedef enum msos_prop_type {
100     MSOS_REG_SZ        = 1,
101     MSOS_REG_EXPAND_SZ = 2,
102     MSOS_REG_BINARY    = 3,
103     MSOS_REG_DWORD_LE  = 4,
104     MSOS_REG_DWORD_BE  = 5,
105     MSOS_REG_LINK      = 6,
106     MSOS_REG_MULTI_SZ  = 7,
107 } msos_prop_type;
108
109 static int usb_desc_msos_prop_name(struct msos_prop *prop,
110                                    const wchar_t *name)
111 {
112     int length = wcslen(name) + 1;
113     int i;
114
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]);
120     }
121     return length*2;
122 }
123
124 static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
125                                   const wchar_t *name, const wchar_t *value)
126 {
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;
131
132     prop->dwPropertyDataType = cpu_to_le32(type);
133     length += usb_desc_msos_prop_name(prop, name);
134     data = (void *)(dest + length);
135
136     data->dwPropertyDataLength = cpu_to_le32(vlen*2);
137     length += sizeof(*prop);
138
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]);
142     }
143     length += vlen*2;
144
145     prop->dwLength = cpu_to_le32(length);
146     return length;
147 }
148
149 static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
150                                     uint32_t value)
151 {
152     struct msos_prop *prop = (void *)dest;
153     struct msos_prop_data *data;
154     int length = sizeof(*prop);
155
156     prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
157     length += usb_desc_msos_prop_name(prop, name);
158     data = (void *)(dest + length);
159
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;
166
167     prop->dwLength = cpu_to_le32(length);
168     return length;
169 }
170
171 static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
172 {
173     msos_prop_hdr *hdr = (void *)dest;
174     int length = sizeof(*hdr);
175     int count = 0;
176
177     if (desc->msos->Label) {
178         /*
179          * Given as example in the specs.  Havn't figured yet where
180          * this label shows up in the windows gui.
181          */
182         length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
183                                          L"Label", desc->msos->Label);
184         count++;
185     }
186
187     if (desc->msos->SelectiveSuspendEnabled) {
188         /*
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.
193          */
194         length += usb_desc_msos_prop_dword(dest+length,
195                                            L"SelectiveSuspendEnabled", 1);
196         count++;
197     }
198
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);
206     return length;
207 }
208
209 /* ------------------------------------------------------------------ */
210
211 int usb_desc_msos(const USBDesc *desc,  USBPacket *p,
212                   int index, uint8_t *dest, size_t len)
213 {
214     void *buf = g_malloc0(4096);
215     int length = 0;
216
217     switch (index) {
218     case 0x0004:
219         length = usb_desc_msos_compat(desc, buf);
220         break;
221     case 0x0005:
222         length = usb_desc_msos_prop(desc, buf);
223         break;
224     }
225
226     if (length > len) {
227         length = len;
228     }
229     memcpy(dest, buf, length);
230     free(buf);
231
232     p->actual_length = length;
233     return 0;
234 }
This page took 0.0371 seconds and 4 git commands to generate.