-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'kraxel/tags/pull-usb-2' into staging
usb core+hid: add support for microsoft os descriptors # gpg: Signature made Tue 21 Jan 2014 02:21:29 AM PST using RSA key ID D3E87138 # gpg: Can't check signature: public key not found * kraxel/tags/pull-usb-2: usb-hid: add microsoft os descriptor support usb: add support for microsoft os descriptors Message-id: 1390299772-5368-1-git-send-email-kraxel@redhat.com Signed-off-by: Anthony Liguori <aliguori@amazon.com>
- Loading branch information
Showing
10 changed files
with
305 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#include "hw/usb.h" | ||
#include "hw/usb/desc.h" | ||
|
||
/* | ||
* Microsoft OS Descriptors | ||
* | ||
* Windows tries to fetch some special descriptors with informations | ||
* specifically for windows. Presence is indicated using a special | ||
* string @ index 0xee. There are two kinds of descriptors: | ||
* | ||
* compatid descriptor | ||
* Used to bind drivers, if usb class isn't specific enougth. | ||
* Used for PTP/MTP for example (both share the same usb class). | ||
* | ||
* properties descriptor | ||
* Does carry registry entries. They show up in | ||
* HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters | ||
* | ||
* Note that Windows caches the stuff it got in the registry, so when | ||
* playing with this you have to delete registry subtrees to make | ||
* windows query the device again: | ||
* HLM\SYSTEM\CurrentControlSet\Control\usbflags | ||
* HLM\SYSTEM\CurrentControlSet\Enum\USB | ||
* Windows will complain it can't delete entries on the second one. | ||
* It has deleted everything it had permissions too, which is enouth | ||
* as this includes "Device Parameters". | ||
* | ||
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx | ||
* | ||
*/ | ||
|
||
/* ------------------------------------------------------------------ */ | ||
|
||
typedef struct msos_compat_hdr { | ||
uint32_t dwLength; | ||
uint8_t bcdVersion_lo; | ||
uint8_t bcdVersion_hi; | ||
uint8_t wIndex_lo; | ||
uint8_t wIndex_hi; | ||
uint8_t bCount; | ||
uint8_t reserved[7]; | ||
} QEMU_PACKED msos_compat_hdr; | ||
|
||
typedef struct msos_compat_func { | ||
uint8_t bFirstInterfaceNumber; | ||
uint8_t reserved_1; | ||
uint8_t compatibleId[8]; | ||
uint8_t subCompatibleId[8]; | ||
uint8_t reserved_2[6]; | ||
} QEMU_PACKED msos_compat_func; | ||
|
||
static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest) | ||
{ | ||
msos_compat_hdr *hdr = (void *)dest; | ||
msos_compat_func *func; | ||
int length = sizeof(*hdr); | ||
int count = 0; | ||
|
||
func = (void *)(dest + length); | ||
func->bFirstInterfaceNumber = 0; | ||
func->reserved_1 = 0x01; | ||
length += sizeof(*func); | ||
count++; | ||
|
||
hdr->dwLength = cpu_to_le32(length); | ||
hdr->bcdVersion_lo = 0x00; | ||
hdr->bcdVersion_hi = 0x01; | ||
hdr->wIndex_lo = 0x04; | ||
hdr->wIndex_hi = 0x00; | ||
hdr->bCount = count; | ||
return length; | ||
} | ||
|
||
/* ------------------------------------------------------------------ */ | ||
|
||
typedef struct msos_prop_hdr { | ||
uint32_t dwLength; | ||
uint8_t bcdVersion_lo; | ||
uint8_t bcdVersion_hi; | ||
uint8_t wIndex_lo; | ||
uint8_t wIndex_hi; | ||
uint8_t wCount_lo; | ||
uint8_t wCount_hi; | ||
} QEMU_PACKED msos_prop_hdr; | ||
|
||
typedef struct msos_prop { | ||
uint32_t dwLength; | ||
uint32_t dwPropertyDataType; | ||
uint8_t dwPropertyNameLength_lo; | ||
uint8_t dwPropertyNameLength_hi; | ||
uint8_t bPropertyName[]; | ||
} QEMU_PACKED msos_prop; | ||
|
||
typedef struct msos_prop_data { | ||
uint32_t dwPropertyDataLength; | ||
uint8_t bPropertyData[]; | ||
} QEMU_PACKED msos_prop_data; | ||
|
||
typedef enum msos_prop_type { | ||
MSOS_REG_SZ = 1, | ||
MSOS_REG_EXPAND_SZ = 2, | ||
MSOS_REG_BINARY = 3, | ||
MSOS_REG_DWORD_LE = 4, | ||
MSOS_REG_DWORD_BE = 5, | ||
MSOS_REG_LINK = 6, | ||
MSOS_REG_MULTI_SZ = 7, | ||
} msos_prop_type; | ||
|
||
static int usb_desc_msos_prop_name(struct msos_prop *prop, | ||
const wchar_t *name) | ||
{ | ||
int length = wcslen(name) + 1; | ||
int i; | ||
|
||
prop->dwPropertyNameLength_lo = usb_lo(length*2); | ||
prop->dwPropertyNameLength_hi = usb_hi(length*2); | ||
for (i = 0; i < length; i++) { | ||
prop->bPropertyName[i*2] = usb_lo(name[i]); | ||
prop->bPropertyName[i*2+1] = usb_hi(name[i]); | ||
} | ||
return length*2; | ||
} | ||
|
||
static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type, | ||
const wchar_t *name, const wchar_t *value) | ||
{ | ||
struct msos_prop *prop = (void *)dest; | ||
struct msos_prop_data *data; | ||
int length = sizeof(*prop); | ||
int i, vlen = wcslen(value) + 1; | ||
|
||
prop->dwPropertyDataType = cpu_to_le32(type); | ||
length += usb_desc_msos_prop_name(prop, name); | ||
data = (void *)(dest + length); | ||
|
||
data->dwPropertyDataLength = cpu_to_le32(vlen*2); | ||
length += sizeof(*prop); | ||
|
||
for (i = 0; i < vlen; i++) { | ||
data->bPropertyData[i*2] = usb_lo(value[i]); | ||
data->bPropertyData[i*2+1] = usb_hi(value[i]); | ||
} | ||
length += vlen*2; | ||
|
||
prop->dwLength = cpu_to_le32(length); | ||
return length; | ||
} | ||
|
||
static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name, | ||
uint32_t value) | ||
{ | ||
struct msos_prop *prop = (void *)dest; | ||
struct msos_prop_data *data; | ||
int length = sizeof(*prop); | ||
|
||
prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE); | ||
length += usb_desc_msos_prop_name(prop, name); | ||
data = (void *)(dest + length); | ||
|
||
data->dwPropertyDataLength = cpu_to_le32(4); | ||
data->bPropertyData[0] = (value) & 0xff; | ||
data->bPropertyData[1] = (value >> 8) & 0xff; | ||
data->bPropertyData[2] = (value >> 16) & 0xff; | ||
data->bPropertyData[3] = (value >> 24) & 0xff; | ||
length += sizeof(*prop) + 4; | ||
|
||
prop->dwLength = cpu_to_le32(length); | ||
return length; | ||
} | ||
|
||
static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest) | ||
{ | ||
msos_prop_hdr *hdr = (void *)dest; | ||
int length = sizeof(*hdr); | ||
int count = 0; | ||
|
||
if (desc->msos->Label) { | ||
/* | ||
* Given as example in the specs. Havn't figured yet where | ||
* this label shows up in the windows gui. | ||
*/ | ||
length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ, | ||
L"Label", desc->msos->Label); | ||
count++; | ||
} | ||
|
||
if (desc->msos->SelectiveSuspendEnabled) { | ||
/* | ||
* Signaling remote wakeup capability in the standard usb | ||
* descriptors isn't enouth to make windows actually use it. | ||
* This is the "Yes, we really mean it" registy entry to flip | ||
* the switch in the windows drivers. | ||
*/ | ||
length += usb_desc_msos_prop_dword(dest+length, | ||
L"SelectiveSuspendEnabled", 1); | ||
count++; | ||
} | ||
|
||
hdr->dwLength = cpu_to_le32(length); | ||
hdr->bcdVersion_lo = 0x00; | ||
hdr->bcdVersion_hi = 0x01; | ||
hdr->wIndex_lo = 0x05; | ||
hdr->wIndex_hi = 0x00; | ||
hdr->wCount_lo = usb_lo(count); | ||
hdr->wCount_hi = usb_hi(count); | ||
return length; | ||
} | ||
|
||
/* ------------------------------------------------------------------ */ | ||
|
||
int usb_desc_msos(const USBDesc *desc, USBPacket *p, | ||
int index, uint8_t *dest, size_t len) | ||
{ | ||
void *buf = g_malloc0(4096); | ||
int length = 0; | ||
|
||
switch (index) { | ||
case 0x0004: | ||
length = usb_desc_msos_compat(desc, buf); | ||
break; | ||
case 0x0005: | ||
length = usb_desc_msos_prop(desc, buf); | ||
break; | ||
} | ||
|
||
if (length > len) { | ||
length = len; | ||
} | ||
memcpy(dest, buf, length); | ||
free(buf); | ||
|
||
p->actual_length = length; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.