summaryrefslogtreecommitdiffstats
path: root/hw/usb/desc.h
blob: 35babdeff624b8dcb419b8b477cff9daf4022ac4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#ifndef QEMU_HW_USB_DESC_H
#define QEMU_HW_USB_DESC_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 related 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 char                *CompatibleID;
    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_MAX_LEN    8192
#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 */