~ruther/stm32h747i-disco-usb-image-viewer

ref: 68abb4c6d986c3d7f3f04aa5c6610190960c1104 stm32h747i-disco-usb-image-viewer/firmware/include/usb.h -rw-r--r-- 17.2 KiB
68abb4c6 — Rutherther chore: tidy up rust code 2 months ago
                                                                                
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
#include <stdint.h>
#include <stm32h747xx.h>
#include "generic.h"
#include <stdbool.h>

#ifndef USB_H
#define USB_H

// NOTE: fields here have to be kept in same order,
// and care must be taken the structs are not padded.
// They are from the usb standard.

#define USB_SUBLANG_ENGLISH_US 0x01
#define USB_LANG_ENGLISH 0x09

#pragma GCC diagnostic error "-Wpadded"

/**
 * @struct usb_device_status_t
 * USB Device status halfword
 */
typedef struct {
  uint8_t self_powered : 1;     /**< Is the device self powered? */
  uint8_t remote_wakeup : 1;    /**< Can the device be remotely waken up by usb? */
  uint16_t reserved_zeros : 14; /**< Should be zeros, reserved. */
} usb_device_status_t;
_Static_assert(sizeof(usb_device_status_t) == 2, "Size check");

/**
 * @struct usb_endpoint_status_t
 * USB endpoint status halfword
 */
typedef struct {
  uint8_t halt : 1;             /**< Is the endpoint halted? */
  uint16_t reserved_zeros : 15; /**< Should be zeros, reserved */
} usb_endpoint_status_t;
_Static_assert(sizeof(usb_endpoint_status_t) == 2, "Size check");

/**
 * @struct usb_interface_status_t
 * USB interface status halfword
 */
typedef struct {
  uint16_t reserved; /**< Should be zeros, reserved. */
} usb_interface_status_t;
_Static_assert(sizeof(usb_interface_status_t) == 2, "Size check");

/**
 * @enum usb_setup_command_direction_t
 * USB setup command request direction
 */
typedef enum {
  USB_SETUP_HOST_TO_DEVICE, /**< The host will send data to device. */
  USB_SETUP_DEVICE_TO_HOST, /**< The device will send dat to host. */
} usb_setup_command_direction_t;

/**
 * @enum usb_setup_command_type_t
 * USB setup command type
 */
typedef enum {
  USB_SETUP_STANDARD, /**< A standard setup command */
  USB_SETUP_CLASS,    /**< A class-specific setup commandj */
  USB_SETUP_VENDOR,   /**< A vendor-specific setup command */
  USB_SETUP_RESERVED, /**< Reserved. */
} usb_setup_command_type_t;

/**
 * @enum usb_setup_command_recipient_t
 * USB setup command recipient
 */
typedef enum {
  USB_SETUP_DEVICE,    /**< The command's recipient is the device */
  USB_SETUP_INTERFACE, /**< The command's recipient is an interface (ie. get descriptor of an interface) */
  USB_SETUP_ENDPOINT,  /**< The command's recipient is an endpoint (ie. get descriptor of an endpoint) */
  USB_SETUP_OTHER,     /**< Other. */
} usb_setup_command_recipient_t;

/**
 * @struct usb_setup_command_request_type_t
 * USB setup command request type
 */
typedef struct __attribute__((packed)) {
  uint8_t recipient : 5;                       /**< The address of the recipient */
  usb_setup_command_type_t type : 2;           /**< The type of the command */
  usb_setup_command_direction_t direction : 1; /**< The direction of the setup command */
} usb_setup_command_request_type_t;

/**
 * @enum usb_setup_request_t
 * Generic setup request commands
 */
typedef enum __attribute__((packed)) {
  USB_SETUP_GET_STATUS = 0,        /**< Get status byte from the device */
  USB_SETUP_CLEAR_FEATURE = 1,     /**< Clear a feature of an interface or an endpoint, like halt */
  RESERVED1 = 2,                   /**< Reserved. */
  USB_SETUP_SET_FEATURE = 3,       /**< Set a feature of an interface or an endpoint, like halt. */
  RESERVED2 = 4,                   /**< Reserved. */
  USB_SETUP_SET_ADDRESS = 5,       /**< Set address of the device to what is in data of the request. */
  USB_SETUP_GET_DESCRIPTOR = 6,    /**< Get a specific descriptor of the device. It should be sent in data stage. */
  USB_SETUP_SET_DESCRIPTOR = 7,    /**< Set an alternate setting for given descriptor. */
  USB_SETUP_GET_CONFIGURATION = 8, /**< Get currently used configuration alternate setting. */
  USB_SETUP_SET_CONFIGURATION = 9, /**< Set alternate configuration. */
  USB_SETUP_GET_INTERFACE = 10,    /**< Get currently used interface alternate setting. */
  USB_SETUP_SET_INTERFACE = 11,    /**< Set alternate interface. */
  USB_SETUP_SYNCH_FRAME = 12,      /**< I don't know. */
} usb_setup_request_t;

/**
 * @enum usb_setup_feature_selector_t
 * USB setup features for SET_FEATURE and CLEAR_FEATURE
 */
typedef enum {
  USB_FEATURE_ENDPOINT_HALT = 0,        /**< Endpoint halt feature */
  USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, /**< Device remote wakeup feature */
  USB_FEATURE_TEST_MODE = 2,            /**< Device test mode */
} usb_setup_feature_selector_t;

typedef enum {
  DESCRIPTOR_DEVICE = 1,
  DESCRIPTOR_CONFIGURATION = 2,
  DESCRIPTOR_STRING = 3,
  DESCRIPTOR_INTERFACE = 4,
  DESCRIPTOR_ENDPOINT = 5,
  DESCRIPTOR_DEVICE_QUALIFIER = 6,
  DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7,
  DESCRIPTOR_INTERFACE_POWER = 8,
} usb_descriptor_type_t;

/**
 * @struct usb_setup_command_t
 * USB setup command structure
 */
typedef struct __attribute__((packed)) {
  usb_setup_command_request_type_t bmRequestType; /**< Type of the request */
  usb_setup_request_t bRequest;                   /**< The request data. */
  uint16_t wValue;                                /**< Value of the request, dependant on the request type. For example device address to set. */
  uint16_t wIndex;                                /**< Index, dependant on the request type. For example interface index. */
  uint16_t wLength;                               /**< For output request, amount of data. For input request, maximum number of bytes to send. */
} usb_setup_command_t;
_Static_assert(sizeof(usb_setup_command_t) == 8, "Size check");

/**
 * @struct usb_descriptor_t
 * Header of every usb descriptor
 */
typedef struct __attribute__((packed)) {
  uint8_t bLength;         /**< Full length of this descriptor. */
  uint8_t bDescriptorType; /**< Type of the descriptor - usb_descriptor_type_t */
} usb_descriptor_t;

typedef struct {
  usb_descriptor_t header;
  uint16_t bcdUSB;
  uint8_t bDeviceClass;
  uint8_t bDeviceSubClass;
  uint8_t bDeviceProtocol;
  uint8_t bMaxPacketSize0;
  uint16_t idVendor;
  uint16_t idProduct;
  uint16_t bcdDevice;
  uint8_t iManufacturer;
  uint8_t iProduct;
  uint8_t iSerialNumber;
  uint8_t bNumConfigurations;
} usb_device_descriptor_t;
_Static_assert(sizeof(usb_device_descriptor_t) == 18, "Size check");

typedef struct {
  usb_descriptor_t header;
  uint16_t bcdUSB;
  uint8_t bDeviceClass;
  uint8_t bDeviceSubClass;
  uint8_t bDeviceProtocol;
  uint8_t bMaxPacketSize0;
  uint8_t bNumConfigurations;
  uint8_t bReserved;
} usb_device_qualifier_t;
_Static_assert(sizeof(usb_device_qualifier_t) == 10, "Size check");

typedef struct {
  uint8_t reserved1 : 1;
  uint8_t self_powered : 1;
  uint8_t remote_wakeup : 1;
  uint8_t reserved_zeros: 5;
} usb_configuration_descriptor_attributes;

typedef struct __attribute__((packed)) {
  usb_descriptor_t header;
  uint16_t wTotalLength;
  uint8_t bNumInterfaces;
  uint8_t bConfigurationValue;
  uint8_t iConfiguration;
  usb_configuration_descriptor_attributes bmAttributes;
  uint8_t bMaxPower;
} usb_configuration_descriptor_t;
_Static_assert(sizeof(usb_configuration_descriptor_t) == 9, "Size check");

typedef usb_configuration_descriptor_t usb_other_speed_configuration_t;

typedef struct __attribute__((packed)) {
  usb_descriptor_t header;
  uint8_t bInterfaceNumber;
  uint8_t bAlternateSetting;
  uint8_t bNumEndpoints;
  uint8_t bInterfaceClass;
  uint8_t bInterfaceSubClass;
  uint8_t bInterfaceProtocol;
  uint8_t iInterface;
} usb_interface_descriptor_t;
_Static_assert(sizeof(usb_interface_descriptor_t) == 9, "Size check");

typedef enum {
  USB_ENDPOINT_OUT = 0,
  USB_ENDPOINT_IN = 1,
} usb_endpoint_direction_t;

typedef struct __attribute__((packed)) {
  uint8_t endpoint_number : 4;
  uint8_t reserved : 3;
  usb_endpoint_direction_t direction : 1;
} usb_endpoint_address_t;

typedef enum {
  USB_ENDPOINT_TYPE_CONTROL = 0,
  USB_ENDPOINT_TYPE_ISOCHRONOUS = 1,
  USB_ENDPOINT_TYPE_BULK = 2,
  USB_ENDPOINT_TYPE_INTERRUPT = 3,
} usb_endpoint_transfer_type_t;

typedef enum {
  USB_ENDPOINT_SYNC_NO_SYNC = 0,
  USB_ENDPOINT_SYNC_ASYNCHRONOUS = 1,
  USB_ENDPOINT_SYNC_ADAPTIVE = 2,
  USB_ENDPOINT_SYNC_SYNCHRONOUS = 3,
} usb_endpoint_synchronization_type_t;

typedef enum {
  USB_ENDPOINT_USAGE_DATA = 0,
  USB_ENDPOINT_USAGE_FEEDBACK = 1,
  USB_ENDPOINT_USAGE_IMPLICIT_FEEDBACK = 2,
  USB_ENDPOINT_USAGE_RESERVED = 3,
} usb_endpoint_usage_type_t;

typedef struct __attribute__((packed)) {
  usb_endpoint_transfer_type_t transfer_type : 2;
  usb_endpoint_synchronization_type_t synchronization_type : 2;
  usb_endpoint_usage_type_t usage_type : 2;
  uint8_t reserved_zeros : 2;
} usb_endpoint_attributes_t;

typedef struct __attribute__((packed)) {
  usb_descriptor_t header;
  usb_endpoint_address_t bEndpointAddress;
  usb_endpoint_attributes_t bmAttributes;
  uint16_t wMaxPacketSize;
  uint8_t bInterval;
} usb_endpoint_descriptor_t;
_Static_assert(sizeof(usb_endpoint_descriptor_t) == 7, "Size check");

#pragma GCC diagnostic ignored "-Wpadded"
typedef struct {
  // uint8_t bLength; // lengto of wLANGID + 2
  usb_descriptor_t header;
  uint16_t *wLANGID; // should have length equal to bLength - 2
} usb_string_descriptor_zero_t;

typedef struct {
  usb_descriptor_t header;
  uint16_t *bString;
} usb_unicode_string_descriptor_t;

// NOTE: End of structs from usb specification here


/**
 * @brief Put data into fifo
 * @details
 * This function will fill fifo of the given endpoint, without configuring the endpoint.
 * The motivation for this function is to be able to pass multiple structures into the fifo.
 * For example if you want to send usb configuration, you first send configuration descriptor,
 * then endpoint descriptor and so on. These structures are not usually aligned to 4 bytes.
 * So we need to always pass in only part of the structure that is divisible by 4 bytes and
 * put the rest to the next one. To do that, we accept pointers to sub word data and bytes.
 * It's expected to first send all structures, and at the end, if the sub_word_bytes is >0,
 * to send one more call with size == 4, and data == sub_word_data.
 * These hold the data that overflow this 4 byte threshold.
 * @param[in,out] endpoint NOT used.
 * @param[out] data The data to send, like a usb descriptor.
 * @param[in] size Size of the data to send.
 * @param[out] fifo_tx_target The fifo to put the data to. It is written to the same address even for multiple words.
 * @param[in, out] sub_word_data Input and output data. For input this means data to prefix the transfer with. For output this means what to prefix next transfer with.
 * @param[in, out] sub_word_bytes Input and output byte count of sub_word_data.
 */
void usb_generic_fill_fifo_words(USB_OTG_INEndpointTypeDef *endpoint,
                      uint8_t *data,
                      uint16_t size,
                      volatile uint32_t *fifo_tx_target,
                      uint32_t *sub_word_data,
                      uint8_t *sub_word_bytes);

void usb_generic_fill_fifo(USB_OTG_INEndpointTypeDef *endpoint,
                      uint8_t *data,
                      uint16_t size,
                      volatile uint32_t *fifo_tx_target);

task_result_t usb_generic_setup_in_endpoint(USB_OTG_INEndpointTypeDef *endpoint,
                                   uint16_t size,
                                   uint16_t max_packet_size);

/**
 * @brief Send data through usb
 * @details Configures the endpoint with given data count, fills fifos with those, and enabled the endpoint.
 * @param[in,out] endpoint The endpoint to send the data with.
 * @param[out] data Description
 * @param[in] size Number of bytes to send.
 * @param[out] fifo_tx_target Address of the fifo. All data is written to this exact address, no offsets are made.
 */
task_result_t usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
                      uint8_t *data,
                      uint16_t size,
                      volatile uint32_t *fifo_tx_target);

bool usb_is_inendpoint_ready(USB_OTG_INEndpointTypeDef *endpoint);
bool usb_check_fifo_space(USB_OTG_INEndpointTypeDef *endpoint, uint16_t size);

/**
 * @brief Read data from the usb fifo.
 * @details The data are read from the fifo pointer, without any offsets, and put into data array
 * @param[in,out] data The array to put data to
 * @param[in] size Number of bytes to store in the array.
 * @param[out] fifo_rx_source Address of the fifo. All data are read from this exact address, no offsets are made.
 */
task_result_t usb_generic_read(uint8_t *data,
                               uint16_t size,
                               volatile uint32_t *fifo_rx_source);

/**
 * @brief Sends descriptor
 * @details Sends data matching the given descriptor. It is expected that the descriptor has length set properly.
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] descriptor The descriptor to send. The wlength has to be set.
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                         usb_descriptor_t *descriptor,
                         uint16_t max_size,
                         volatile uint32_t *fifo_tx_target);

/**
 * @brief Sends device descriptor.
 * @details Sets appropriate length of the descriptor, and then sends it using @see usb_send_descriptor
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                usb_device_descriptor_t *descriptor,
                                uint16_t max_size,
                                volatile uint32_t *fifo_tx_target);

/**
 * @brief Sends device qualifier descriptor.
 * @details Sets appropriate length of the descriptor, and then sends it using @see usb_send_descriptor
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef* endpoint,usb_device_qualifier_t *descriptor,
                                          uint16_t max_size,
                                          volatile uint32_t *fifo_tx_target);

/**
 * @brief Sends interface qualifier descriptor.
 * @details Sets appropriate length of the descriptor, and then sends it using @see usb_send_descriptor
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                   usb_interface_descriptor_t *descriptor,
                                   uint16_t max_size,
                                   volatile uint32_t *fifo_tx_target);

/**
 * @brief Sends endpoint qualifier descriptor.
 * @details Sets appropriate length of the descriptor, and then sends it using @see usb_send_descriptor
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                           usb_endpoint_descriptor_t *descriptor,
                                           uint16_t max_size,
                                           volatile uint32_t *fifo_tx_target);

/**
 * @brief Sends string descriptor zero.
 * @details The length of the array has to be known, it is determined by wLength of the header.
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] string_descriptor The descriptor to send. The wLength NEEDS to be correct!
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_string_descriptor_zero(
    USB_OTG_INEndpointTypeDef *endpoint,
    usb_string_descriptor_zero_t *string_descriptor,
    uint16_t max_size,
    volatile uint32_t *fifo_tx_target);

/**
 * @brief Sends unicode string descriptor.
 * @details The length of the array has to be known, it is determined by wLength of the header.
 * @param[in,out] endpoint The endpoint to send data with.
 * @param[out] string_descriptor The descriptor to send. The wLength NEEDS to be correct!
 * @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
 */
task_result_t usb_send_unicode_string_descriptor(
    USB_OTG_INEndpointTypeDef *endpoint,
    usb_unicode_string_descriptor_t *string_descriptor,
    uint16_t max_size,
    volatile uint32_t *fifo_tx_target);

task_result_t usb_send_unicode_string_descriptor(
    USB_OTG_INEndpointTypeDef *endpoint,
    usb_unicode_string_descriptor_t *string_descriptor,
    uint16_t max_size,
    volatile uint32_t *fifo_tx_target);

void usb_flush_tx_fifo(USB_OTG_GlobalTypeDef* core, uint16_t fifo_num);
void usb_flush_rx_fifo(USB_OTG_GlobalTypeDef* core);

#endif // USB_H
Do not follow this link