5319dc7b42
This patch adds support for special usb descriptors used by microsoft windows. They allow more fine-grained control over driver binding and adding entries to the registry for configuration. As this is a guest-visible change the "msos-desc" compat property has been added to turn this off for 1.7 + older Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
245 lines
8.4 KiB
C
245 lines
8.4 KiB
C
#ifndef QEMU_HW_USB_DESC_H
|
|
#define QEMU_HW_USB_DESC_H
|
|
|
|
#include <inttypes.h>
|
|
#include <wchar.h>
|
|
|
|
/* binary representation */
|
|
typedef struct USBDescriptor {
|
|
uint8_t bLength;
|
|
uint8_t bDescriptorType;
|
|
union {
|
|
struct {
|
|
uint8_t bcdUSB_lo;
|
|
uint8_t bcdUSB_hi;
|
|
uint8_t bDeviceClass;
|
|
uint8_t bDeviceSubClass;
|
|
uint8_t bDeviceProtocol;
|
|
uint8_t bMaxPacketSize0;
|
|
uint8_t idVendor_lo;
|
|
uint8_t idVendor_hi;
|
|
uint8_t idProduct_lo;
|
|
uint8_t idProduct_hi;
|
|
uint8_t bcdDevice_lo;
|
|
uint8_t bcdDevice_hi;
|
|
uint8_t iManufacturer;
|
|
uint8_t iProduct;
|
|
uint8_t iSerialNumber;
|
|
uint8_t bNumConfigurations;
|
|
} device;
|
|
struct {
|
|
uint8_t bcdUSB_lo;
|
|
uint8_t bcdUSB_hi;
|
|
uint8_t bDeviceClass;
|
|
uint8_t bDeviceSubClass;
|
|
uint8_t bDeviceProtocol;
|
|
uint8_t bMaxPacketSize0;
|
|
uint8_t bNumConfigurations;
|
|
uint8_t bReserved;
|
|
} device_qualifier;
|
|
struct {
|
|
uint8_t wTotalLength_lo;
|
|
uint8_t wTotalLength_hi;
|
|
uint8_t bNumInterfaces;
|
|
uint8_t bConfigurationValue;
|
|
uint8_t iConfiguration;
|
|
uint8_t bmAttributes;
|
|
uint8_t bMaxPower;
|
|
} config;
|
|
struct {
|
|
uint8_t bInterfaceNumber;
|
|
uint8_t bAlternateSetting;
|
|
uint8_t bNumEndpoints;
|
|
uint8_t bInterfaceClass;
|
|
uint8_t bInterfaceSubClass;
|
|
uint8_t bInterfaceProtocol;
|
|
uint8_t iInterface;
|
|
} interface;
|
|
struct {
|
|
uint8_t bEndpointAddress;
|
|
uint8_t bmAttributes;
|
|
uint8_t wMaxPacketSize_lo;
|
|
uint8_t wMaxPacketSize_hi;
|
|
uint8_t bInterval;
|
|
uint8_t bRefresh; /* only audio ep */
|
|
uint8_t bSynchAddress; /* only audio ep */
|
|
} endpoint;
|
|
struct {
|
|
uint8_t bMaxBurst;
|
|
uint8_t bmAttributes;
|
|
uint8_t wBytesPerInterval_lo;
|
|
uint8_t wBytesPerInterval_hi;
|
|
} super_endpoint;
|
|
struct {
|
|
uint8_t wTotalLength_lo;
|
|
uint8_t wTotalLength_hi;
|
|
uint8_t bNumDeviceCaps;
|
|
} bos;
|
|
struct {
|
|
uint8_t bDevCapabilityType;
|
|
union {
|
|
struct {
|
|
uint8_t bmAttributes_1;
|
|
uint8_t bmAttributes_2;
|
|
uint8_t bmAttributes_3;
|
|
uint8_t bmAttributes_4;
|
|
} usb2_ext;
|
|
struct {
|
|
uint8_t bmAttributes;
|
|
uint8_t wSpeedsSupported_lo;
|
|
uint8_t wSpeedsSupported_hi;
|
|
uint8_t bFunctionalitySupport;
|
|
uint8_t bU1DevExitLat;
|
|
uint8_t wU2DevExitLat_lo;
|
|
uint8_t wU2DevExitLat_hi;
|
|
} super;
|
|
} u;
|
|
} cap;
|
|
} u;
|
|
} QEMU_PACKED USBDescriptor;
|
|
|
|
struct USBDescID {
|
|
uint16_t idVendor;
|
|
uint16_t idProduct;
|
|
uint16_t bcdDevice;
|
|
uint8_t iManufacturer;
|
|
uint8_t iProduct;
|
|
uint8_t iSerialNumber;
|
|
};
|
|
|
|
struct USBDescDevice {
|
|
uint16_t bcdUSB;
|
|
uint8_t bDeviceClass;
|
|
uint8_t bDeviceSubClass;
|
|
uint8_t bDeviceProtocol;
|
|
uint8_t bMaxPacketSize0;
|
|
uint8_t bNumConfigurations;
|
|
|
|
const USBDescConfig *confs;
|
|
};
|
|
|
|
struct USBDescConfig {
|
|
uint8_t bNumInterfaces;
|
|
uint8_t bConfigurationValue;
|
|
uint8_t iConfiguration;
|
|
uint8_t bmAttributes;
|
|
uint8_t bMaxPower;
|
|
|
|
/* grouped interfaces */
|
|
uint8_t nif_groups;
|
|
const USBDescIfaceAssoc *if_groups;
|
|
|
|
/* "normal" interfaces */
|
|
uint8_t nif;
|
|
const USBDescIface *ifs;
|
|
};
|
|
|
|
/* conceptually an Interface Association Descriptor, and releated interfaces */
|
|
struct USBDescIfaceAssoc {
|
|
uint8_t bFirstInterface;
|
|
uint8_t bInterfaceCount;
|
|
uint8_t bFunctionClass;
|
|
uint8_t bFunctionSubClass;
|
|
uint8_t bFunctionProtocol;
|
|
uint8_t iFunction;
|
|
|
|
uint8_t nif;
|
|
const USBDescIface *ifs;
|
|
};
|
|
|
|
struct USBDescIface {
|
|
uint8_t bInterfaceNumber;
|
|
uint8_t bAlternateSetting;
|
|
uint8_t bNumEndpoints;
|
|
uint8_t bInterfaceClass;
|
|
uint8_t bInterfaceSubClass;
|
|
uint8_t bInterfaceProtocol;
|
|
uint8_t iInterface;
|
|
|
|
uint8_t ndesc;
|
|
USBDescOther *descs;
|
|
USBDescEndpoint *eps;
|
|
};
|
|
|
|
struct USBDescEndpoint {
|
|
uint8_t bEndpointAddress;
|
|
uint8_t bmAttributes;
|
|
uint16_t wMaxPacketSize;
|
|
uint8_t bInterval;
|
|
uint8_t bRefresh;
|
|
uint8_t bSynchAddress;
|
|
|
|
uint8_t is_audio; /* has bRefresh + bSynchAddress */
|
|
uint8_t *extra;
|
|
|
|
/* superspeed endpoint companion */
|
|
uint8_t bMaxBurst;
|
|
uint8_t bmAttributes_super;
|
|
uint16_t wBytesPerInterval;
|
|
};
|
|
|
|
struct USBDescOther {
|
|
uint8_t length;
|
|
const uint8_t *data;
|
|
};
|
|
|
|
struct USBDescMSOS {
|
|
const wchar_t *Label;
|
|
bool SelectiveSuspendEnabled;
|
|
};
|
|
|
|
typedef const char *USBDescStrings[256];
|
|
|
|
struct USBDesc {
|
|
USBDescID id;
|
|
const USBDescDevice *full;
|
|
const USBDescDevice *high;
|
|
const USBDescDevice *super;
|
|
const char* const *str;
|
|
const USBDescMSOS *msos;
|
|
};
|
|
|
|
#define USB_DESC_FLAG_SUPER (1 << 1)
|
|
|
|
/* little helpers */
|
|
static inline uint8_t usb_lo(uint16_t val)
|
|
{
|
|
return val & 0xff;
|
|
}
|
|
|
|
static inline uint8_t usb_hi(uint16_t val)
|
|
{
|
|
return (val >> 8) & 0xff;
|
|
}
|
|
|
|
/* generate usb packages from structs */
|
|
int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
|
bool msos, uint8_t *dest, size_t len);
|
|
int usb_desc_device_qualifier(const USBDescDevice *dev,
|
|
uint8_t *dest, size_t len);
|
|
int usb_desc_config(const USBDescConfig *conf, int flags,
|
|
uint8_t *dest, size_t len);
|
|
int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
|
|
uint8_t *dest, size_t len);
|
|
int usb_desc_iface(const USBDescIface *iface, int flags,
|
|
uint8_t *dest, size_t len);
|
|
int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
|
|
uint8_t *dest, size_t len);
|
|
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
|
|
int usb_desc_msos(const USBDesc *desc, USBPacket *p,
|
|
int index, uint8_t *dest, size_t len);
|
|
|
|
/* control message emulation helpers */
|
|
void usb_desc_init(USBDevice *dev);
|
|
void usb_desc_attach(USBDevice *dev);
|
|
void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
|
|
void usb_desc_create_serial(USBDevice *dev);
|
|
const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
|
|
int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
|
|
int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
|
|
int value, uint8_t *dest, size_t len);
|
|
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
|
int request, int value, int index, int length, uint8_t *data);
|
|
|
|
#endif /* QEMU_HW_USB_DESC_H */
|