qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

desc-msos.c (7038B)


      1 #include "qemu/osdep.h"
      2 #include "hw/usb.h"
      3 #include "desc.h"
      4 
      5 /*
      6  * Microsoft OS Descriptors
      7  *
      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:
     11  *
     12  * compatid descriptor
     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).
     15  *
     16  * properties descriptor
     17  *   Does carry registry entries.  They show up in
     18  *   HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
     19  *
     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".
     28  *
     29  * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
     30  *
     31  */
     32 
     33 /* ------------------------------------------------------------------ */
     34 
     35 typedef struct msos_compat_hdr {
     36     uint32_t dwLength;
     37     uint8_t  bcdVersion_lo;
     38     uint8_t  bcdVersion_hi;
     39     uint8_t  wIndex_lo;
     40     uint8_t  wIndex_hi;
     41     uint8_t  bCount;
     42     uint8_t  reserved[7];
     43 } QEMU_PACKED msos_compat_hdr;
     44 
     45 typedef struct msos_compat_func {
     46     uint8_t  bFirstInterfaceNumber;
     47     uint8_t  reserved_1;
     48     char     compatibleId[8];
     49     uint8_t  subCompatibleId[8];
     50     uint8_t  reserved_2[6];
     51 } QEMU_PACKED msos_compat_func;
     52 
     53 static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
     54 {
     55     msos_compat_hdr *hdr = (void *)dest;
     56     msos_compat_func *func;
     57     int length = sizeof(*hdr);
     58     int count = 0;
     59 
     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);
     66     }
     67     length += sizeof(*func);
     68     count++;
     69 
     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;
     75     hdr->bCount        = count;
     76     return length;
     77 }
     78 
     79 /* ------------------------------------------------------------------ */
     80 
     81 typedef struct msos_prop_hdr {
     82     uint32_t dwLength;
     83     uint8_t  bcdVersion_lo;
     84     uint8_t  bcdVersion_hi;
     85     uint8_t  wIndex_lo;
     86     uint8_t  wIndex_hi;
     87     uint8_t  wCount_lo;
     88     uint8_t  wCount_hi;
     89 } QEMU_PACKED msos_prop_hdr;
     90 
     91 typedef struct msos_prop {
     92     uint32_t dwLength;
     93     uint32_t dwPropertyDataType;
     94     uint8_t  dwPropertyNameLength_lo;
     95     uint8_t  dwPropertyNameLength_hi;
     96     uint8_t  bPropertyName[];
     97 } QEMU_PACKED msos_prop;
     98 
     99 typedef struct msos_prop_data {
    100     uint32_t dwPropertyDataLength;
    101     uint8_t  bPropertyData[];
    102 } QEMU_PACKED msos_prop_data;
    103 
    104 typedef enum msos_prop_type {
    105     MSOS_REG_SZ        = 1,
    106     MSOS_REG_EXPAND_SZ = 2,
    107     MSOS_REG_BINARY    = 3,
    108     MSOS_REG_DWORD_LE  = 4,
    109     MSOS_REG_DWORD_BE  = 5,
    110     MSOS_REG_LINK      = 6,
    111     MSOS_REG_MULTI_SZ  = 7,
    112 } msos_prop_type;
    113 
    114 static int usb_desc_msos_prop_name(struct msos_prop *prop,
    115                                    const wchar_t *name)
    116 {
    117     int length = wcslen(name) + 1;
    118     int i;
    119 
    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]);
    125     }
    126     return length*2;
    127 }
    128 
    129 static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
    130                                   const wchar_t *name, const wchar_t *value)
    131 {
    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;
    136 
    137     prop->dwPropertyDataType = cpu_to_le32(type);
    138     length += usb_desc_msos_prop_name(prop, name);
    139     data = (void *)(dest + length);
    140 
    141     data->dwPropertyDataLength = cpu_to_le32(vlen*2);
    142     length += sizeof(*prop);
    143 
    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]);
    147     }
    148     length += vlen*2;
    149 
    150     prop->dwLength = cpu_to_le32(length);
    151     return length;
    152 }
    153 
    154 static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
    155                                     uint32_t value)
    156 {
    157     struct msos_prop *prop = (void *)dest;
    158     struct msos_prop_data *data;
    159     int length = sizeof(*prop);
    160 
    161     prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
    162     length += usb_desc_msos_prop_name(prop, name);
    163     data = (void *)(dest + length);
    164 
    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;
    171 
    172     prop->dwLength = cpu_to_le32(length);
    173     return length;
    174 }
    175 
    176 static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
    177 {
    178     msos_prop_hdr *hdr = (void *)dest;
    179     int length = sizeof(*hdr);
    180     int count = 0;
    181 
    182     if (desc->msos->Label) {
    183         /*
    184          * Given as example in the specs.  Haven't figured yet where
    185          * this label shows up in the windows gui.
    186          */
    187         length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
    188                                          L"Label", desc->msos->Label);
    189         count++;
    190     }
    191 
    192     if (desc->msos->SelectiveSuspendEnabled) {
    193         /*
    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.
    198          */
    199         length += usb_desc_msos_prop_dword(dest+length,
    200                                            L"SelectiveSuspendEnabled", 1);
    201         count++;
    202     }
    203 
    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);
    211     return length;
    212 }
    213 
    214 /* ------------------------------------------------------------------ */
    215 
    216 int usb_desc_msos(const USBDesc *desc,  USBPacket *p,
    217                   int index, uint8_t *dest, size_t len)
    218 {
    219     void *buf = g_malloc0(4096);
    220     int length = 0;
    221 
    222     switch (index) {
    223     case 0x0004:
    224         length = usb_desc_msos_compat(desc, buf);
    225         break;
    226     case 0x0005:
    227         length = usb_desc_msos_prop(desc, buf);
    228         break;
    229     }
    230 
    231     if (length > len) {
    232         length = len;
    233     }
    234     memcpy(dest, buf, length);
    235     g_free(buf);
    236 
    237     p->actual_length = length;
    238     return 0;
    239 }