1e532b2e0SPeter Maydell #include "qemu/osdep.h" 25319dc7bSGerd Hoffmann #include "hw/usb.h" 3*463581a8SMichael S. Tsirkin #include "desc.h" 45319dc7bSGerd Hoffmann 55319dc7bSGerd Hoffmann /* 65319dc7bSGerd Hoffmann * Microsoft OS Descriptors 75319dc7bSGerd Hoffmann * 85319dc7bSGerd Hoffmann * Windows tries to fetch some special descriptors with informations 95319dc7bSGerd Hoffmann * specifically for windows. Presence is indicated using a special 105319dc7bSGerd Hoffmann * string @ index 0xee. There are two kinds of descriptors: 115319dc7bSGerd Hoffmann * 125319dc7bSGerd Hoffmann * compatid descriptor 135319dc7bSGerd Hoffmann * Used to bind drivers, if usb class isn't specific enougth. 145319dc7bSGerd Hoffmann * Used for PTP/MTP for example (both share the same usb class). 155319dc7bSGerd Hoffmann * 165319dc7bSGerd Hoffmann * properties descriptor 175319dc7bSGerd Hoffmann * Does carry registry entries. They show up in 185319dc7bSGerd Hoffmann * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters 195319dc7bSGerd Hoffmann * 205319dc7bSGerd Hoffmann * Note that Windows caches the stuff it got in the registry, so when 215319dc7bSGerd Hoffmann * playing with this you have to delete registry subtrees to make 225319dc7bSGerd Hoffmann * windows query the device again: 235319dc7bSGerd Hoffmann * HLM\SYSTEM\CurrentControlSet\Control\usbflags 245319dc7bSGerd Hoffmann * HLM\SYSTEM\CurrentControlSet\Enum\USB 255319dc7bSGerd Hoffmann * Windows will complain it can't delete entries on the second one. 265319dc7bSGerd Hoffmann * It has deleted everything it had permissions too, which is enouth 275319dc7bSGerd Hoffmann * as this includes "Device Parameters". 285319dc7bSGerd Hoffmann * 295319dc7bSGerd Hoffmann * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx 305319dc7bSGerd Hoffmann * 315319dc7bSGerd Hoffmann */ 325319dc7bSGerd Hoffmann 335319dc7bSGerd Hoffmann /* ------------------------------------------------------------------ */ 345319dc7bSGerd Hoffmann 355319dc7bSGerd Hoffmann typedef struct msos_compat_hdr { 365319dc7bSGerd Hoffmann uint32_t dwLength; 375319dc7bSGerd Hoffmann uint8_t bcdVersion_lo; 385319dc7bSGerd Hoffmann uint8_t bcdVersion_hi; 395319dc7bSGerd Hoffmann uint8_t wIndex_lo; 405319dc7bSGerd Hoffmann uint8_t wIndex_hi; 415319dc7bSGerd Hoffmann uint8_t bCount; 425319dc7bSGerd Hoffmann uint8_t reserved[7]; 435319dc7bSGerd Hoffmann } QEMU_PACKED msos_compat_hdr; 445319dc7bSGerd Hoffmann 455319dc7bSGerd Hoffmann typedef struct msos_compat_func { 465319dc7bSGerd Hoffmann uint8_t bFirstInterfaceNumber; 475319dc7bSGerd Hoffmann uint8_t reserved_1; 48409951f5SGerd Hoffmann char compatibleId[8]; 495319dc7bSGerd Hoffmann uint8_t subCompatibleId[8]; 505319dc7bSGerd Hoffmann uint8_t reserved_2[6]; 515319dc7bSGerd Hoffmann } QEMU_PACKED msos_compat_func; 525319dc7bSGerd Hoffmann 535319dc7bSGerd Hoffmann static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest) 545319dc7bSGerd Hoffmann { 555319dc7bSGerd Hoffmann msos_compat_hdr *hdr = (void *)dest; 565319dc7bSGerd Hoffmann msos_compat_func *func; 575319dc7bSGerd Hoffmann int length = sizeof(*hdr); 585319dc7bSGerd Hoffmann int count = 0; 595319dc7bSGerd Hoffmann 605319dc7bSGerd Hoffmann func = (void *)(dest + length); 615319dc7bSGerd Hoffmann func->bFirstInterfaceNumber = 0; 625319dc7bSGerd Hoffmann func->reserved_1 = 0x01; 63409951f5SGerd Hoffmann if (desc->msos->CompatibleID) { 64409951f5SGerd Hoffmann snprintf(func->compatibleId, sizeof(func->compatibleId), 65409951f5SGerd Hoffmann "%s", desc->msos->CompatibleID); 66409951f5SGerd Hoffmann } 675319dc7bSGerd Hoffmann length += sizeof(*func); 685319dc7bSGerd Hoffmann count++; 695319dc7bSGerd Hoffmann 705319dc7bSGerd Hoffmann hdr->dwLength = cpu_to_le32(length); 715319dc7bSGerd Hoffmann hdr->bcdVersion_lo = 0x00; 725319dc7bSGerd Hoffmann hdr->bcdVersion_hi = 0x01; 735319dc7bSGerd Hoffmann hdr->wIndex_lo = 0x04; 745319dc7bSGerd Hoffmann hdr->wIndex_hi = 0x00; 755319dc7bSGerd Hoffmann hdr->bCount = count; 765319dc7bSGerd Hoffmann return length; 775319dc7bSGerd Hoffmann } 785319dc7bSGerd Hoffmann 795319dc7bSGerd Hoffmann /* ------------------------------------------------------------------ */ 805319dc7bSGerd Hoffmann 815319dc7bSGerd Hoffmann typedef struct msos_prop_hdr { 825319dc7bSGerd Hoffmann uint32_t dwLength; 835319dc7bSGerd Hoffmann uint8_t bcdVersion_lo; 845319dc7bSGerd Hoffmann uint8_t bcdVersion_hi; 855319dc7bSGerd Hoffmann uint8_t wIndex_lo; 865319dc7bSGerd Hoffmann uint8_t wIndex_hi; 875319dc7bSGerd Hoffmann uint8_t wCount_lo; 885319dc7bSGerd Hoffmann uint8_t wCount_hi; 895319dc7bSGerd Hoffmann } QEMU_PACKED msos_prop_hdr; 905319dc7bSGerd Hoffmann 915319dc7bSGerd Hoffmann typedef struct msos_prop { 925319dc7bSGerd Hoffmann uint32_t dwLength; 935319dc7bSGerd Hoffmann uint32_t dwPropertyDataType; 945319dc7bSGerd Hoffmann uint8_t dwPropertyNameLength_lo; 955319dc7bSGerd Hoffmann uint8_t dwPropertyNameLength_hi; 965319dc7bSGerd Hoffmann uint8_t bPropertyName[]; 975319dc7bSGerd Hoffmann } QEMU_PACKED msos_prop; 985319dc7bSGerd Hoffmann 995319dc7bSGerd Hoffmann typedef struct msos_prop_data { 1005319dc7bSGerd Hoffmann uint32_t dwPropertyDataLength; 1015319dc7bSGerd Hoffmann uint8_t bPropertyData[]; 1025319dc7bSGerd Hoffmann } QEMU_PACKED msos_prop_data; 1035319dc7bSGerd Hoffmann 1045319dc7bSGerd Hoffmann typedef enum msos_prop_type { 1055319dc7bSGerd Hoffmann MSOS_REG_SZ = 1, 1065319dc7bSGerd Hoffmann MSOS_REG_EXPAND_SZ = 2, 1075319dc7bSGerd Hoffmann MSOS_REG_BINARY = 3, 1085319dc7bSGerd Hoffmann MSOS_REG_DWORD_LE = 4, 1095319dc7bSGerd Hoffmann MSOS_REG_DWORD_BE = 5, 1105319dc7bSGerd Hoffmann MSOS_REG_LINK = 6, 1115319dc7bSGerd Hoffmann MSOS_REG_MULTI_SZ = 7, 1125319dc7bSGerd Hoffmann } msos_prop_type; 1135319dc7bSGerd Hoffmann 1145319dc7bSGerd Hoffmann static int usb_desc_msos_prop_name(struct msos_prop *prop, 1155319dc7bSGerd Hoffmann const wchar_t *name) 1165319dc7bSGerd Hoffmann { 1175319dc7bSGerd Hoffmann int length = wcslen(name) + 1; 1185319dc7bSGerd Hoffmann int i; 1195319dc7bSGerd Hoffmann 1205319dc7bSGerd Hoffmann prop->dwPropertyNameLength_lo = usb_lo(length*2); 1215319dc7bSGerd Hoffmann prop->dwPropertyNameLength_hi = usb_hi(length*2); 1225319dc7bSGerd Hoffmann for (i = 0; i < length; i++) { 1235319dc7bSGerd Hoffmann prop->bPropertyName[i*2] = usb_lo(name[i]); 1245319dc7bSGerd Hoffmann prop->bPropertyName[i*2+1] = usb_hi(name[i]); 1255319dc7bSGerd Hoffmann } 1265319dc7bSGerd Hoffmann return length*2; 1275319dc7bSGerd Hoffmann } 1285319dc7bSGerd Hoffmann 1295319dc7bSGerd Hoffmann static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type, 1305319dc7bSGerd Hoffmann const wchar_t *name, const wchar_t *value) 1315319dc7bSGerd Hoffmann { 1325319dc7bSGerd Hoffmann struct msos_prop *prop = (void *)dest; 1335319dc7bSGerd Hoffmann struct msos_prop_data *data; 1345319dc7bSGerd Hoffmann int length = sizeof(*prop); 1355319dc7bSGerd Hoffmann int i, vlen = wcslen(value) + 1; 1365319dc7bSGerd Hoffmann 1375319dc7bSGerd Hoffmann prop->dwPropertyDataType = cpu_to_le32(type); 1385319dc7bSGerd Hoffmann length += usb_desc_msos_prop_name(prop, name); 1395319dc7bSGerd Hoffmann data = (void *)(dest + length); 1405319dc7bSGerd Hoffmann 1415319dc7bSGerd Hoffmann data->dwPropertyDataLength = cpu_to_le32(vlen*2); 1425319dc7bSGerd Hoffmann length += sizeof(*prop); 1435319dc7bSGerd Hoffmann 1445319dc7bSGerd Hoffmann for (i = 0; i < vlen; i++) { 1455319dc7bSGerd Hoffmann data->bPropertyData[i*2] = usb_lo(value[i]); 1465319dc7bSGerd Hoffmann data->bPropertyData[i*2+1] = usb_hi(value[i]); 1475319dc7bSGerd Hoffmann } 1485319dc7bSGerd Hoffmann length += vlen*2; 1495319dc7bSGerd Hoffmann 1505319dc7bSGerd Hoffmann prop->dwLength = cpu_to_le32(length); 1515319dc7bSGerd Hoffmann return length; 1525319dc7bSGerd Hoffmann } 1535319dc7bSGerd Hoffmann 1545319dc7bSGerd Hoffmann static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name, 1555319dc7bSGerd Hoffmann uint32_t value) 1565319dc7bSGerd Hoffmann { 1575319dc7bSGerd Hoffmann struct msos_prop *prop = (void *)dest; 1585319dc7bSGerd Hoffmann struct msos_prop_data *data; 1595319dc7bSGerd Hoffmann int length = sizeof(*prop); 1605319dc7bSGerd Hoffmann 1615319dc7bSGerd Hoffmann prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE); 1625319dc7bSGerd Hoffmann length += usb_desc_msos_prop_name(prop, name); 1635319dc7bSGerd Hoffmann data = (void *)(dest + length); 1645319dc7bSGerd Hoffmann 1655319dc7bSGerd Hoffmann data->dwPropertyDataLength = cpu_to_le32(4); 1665319dc7bSGerd Hoffmann data->bPropertyData[0] = (value) & 0xff; 1675319dc7bSGerd Hoffmann data->bPropertyData[1] = (value >> 8) & 0xff; 1685319dc7bSGerd Hoffmann data->bPropertyData[2] = (value >> 16) & 0xff; 1695319dc7bSGerd Hoffmann data->bPropertyData[3] = (value >> 24) & 0xff; 1705319dc7bSGerd Hoffmann length += sizeof(*prop) + 4; 1715319dc7bSGerd Hoffmann 1725319dc7bSGerd Hoffmann prop->dwLength = cpu_to_le32(length); 1735319dc7bSGerd Hoffmann return length; 1745319dc7bSGerd Hoffmann } 1755319dc7bSGerd Hoffmann 1765319dc7bSGerd Hoffmann static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest) 1775319dc7bSGerd Hoffmann { 1785319dc7bSGerd Hoffmann msos_prop_hdr *hdr = (void *)dest; 1795319dc7bSGerd Hoffmann int length = sizeof(*hdr); 1805319dc7bSGerd Hoffmann int count = 0; 1815319dc7bSGerd Hoffmann 1825319dc7bSGerd Hoffmann if (desc->msos->Label) { 1835319dc7bSGerd Hoffmann /* 1845319dc7bSGerd Hoffmann * Given as example in the specs. Havn't figured yet where 1855319dc7bSGerd Hoffmann * this label shows up in the windows gui. 1865319dc7bSGerd Hoffmann */ 1875319dc7bSGerd Hoffmann length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ, 1885319dc7bSGerd Hoffmann L"Label", desc->msos->Label); 1895319dc7bSGerd Hoffmann count++; 1905319dc7bSGerd Hoffmann } 1915319dc7bSGerd Hoffmann 1925319dc7bSGerd Hoffmann if (desc->msos->SelectiveSuspendEnabled) { 1935319dc7bSGerd Hoffmann /* 1945319dc7bSGerd Hoffmann * Signaling remote wakeup capability in the standard usb 1955319dc7bSGerd Hoffmann * descriptors isn't enouth to make windows actually use it. 1965319dc7bSGerd Hoffmann * This is the "Yes, we really mean it" registy entry to flip 1975319dc7bSGerd Hoffmann * the switch in the windows drivers. 1985319dc7bSGerd Hoffmann */ 1995319dc7bSGerd Hoffmann length += usb_desc_msos_prop_dword(dest+length, 2005319dc7bSGerd Hoffmann L"SelectiveSuspendEnabled", 1); 2015319dc7bSGerd Hoffmann count++; 2025319dc7bSGerd Hoffmann } 2035319dc7bSGerd Hoffmann 2045319dc7bSGerd Hoffmann hdr->dwLength = cpu_to_le32(length); 2055319dc7bSGerd Hoffmann hdr->bcdVersion_lo = 0x00; 2065319dc7bSGerd Hoffmann hdr->bcdVersion_hi = 0x01; 2075319dc7bSGerd Hoffmann hdr->wIndex_lo = 0x05; 2085319dc7bSGerd Hoffmann hdr->wIndex_hi = 0x00; 2095319dc7bSGerd Hoffmann hdr->wCount_lo = usb_lo(count); 2105319dc7bSGerd Hoffmann hdr->wCount_hi = usb_hi(count); 2115319dc7bSGerd Hoffmann return length; 2125319dc7bSGerd Hoffmann } 2135319dc7bSGerd Hoffmann 2145319dc7bSGerd Hoffmann /* ------------------------------------------------------------------ */ 2155319dc7bSGerd Hoffmann 2165319dc7bSGerd Hoffmann int usb_desc_msos(const USBDesc *desc, USBPacket *p, 2175319dc7bSGerd Hoffmann int index, uint8_t *dest, size_t len) 2185319dc7bSGerd Hoffmann { 2195319dc7bSGerd Hoffmann void *buf = g_malloc0(4096); 2205319dc7bSGerd Hoffmann int length = 0; 2215319dc7bSGerd Hoffmann 2225319dc7bSGerd Hoffmann switch (index) { 2235319dc7bSGerd Hoffmann case 0x0004: 2245319dc7bSGerd Hoffmann length = usb_desc_msos_compat(desc, buf); 2255319dc7bSGerd Hoffmann break; 2265319dc7bSGerd Hoffmann case 0x0005: 2275319dc7bSGerd Hoffmann length = usb_desc_msos_prop(desc, buf); 2285319dc7bSGerd Hoffmann break; 2295319dc7bSGerd Hoffmann } 2305319dc7bSGerd Hoffmann 2315319dc7bSGerd Hoffmann if (length > len) { 2325319dc7bSGerd Hoffmann length = len; 2335319dc7bSGerd Hoffmann } 2345319dc7bSGerd Hoffmann memcpy(dest, buf, length); 2350c6f807fSMarkus Armbruster g_free(buf); 2365319dc7bSGerd Hoffmann 2375319dc7bSGerd Hoffmann p->actual_length = length; 2385319dc7bSGerd Hoffmann return 0; 2395319dc7bSGerd Hoffmann } 240