Welcome to mirror list, hosted at ThFree Co, Russian Federation.

usbd_core.h « inc - github.com/flipperdevices/libusb_stm32.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 587509f7de4057bd28d6519ab91863335d837285 (plain)
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
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
/* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers
 *
 * Copyright ©2016 Dmitry Filimonchuk <dmitrystu[at]gmail[dot]com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *   http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
.*/

#ifndef _USBD_CORE_H_
#define _USBD_CORE_H_
#if defined(__cplusplus)
    extern "C" {
#endif

/**\addtogroup USBD_HW_CORE USB Device HW driver and core API
 * @{ */
#if defined(__DOXYGEN__)
/**\name Compile-time control macros
 * @{ */
#define USBD_PINS_REMAP     /**<\brief Remap USB pins for uC with low pin count packages.*/
#define USBD_SOF_DISABLED   /**<\brief Disables SOF handling.*/
#define USBD_VBUS_DETECT    /**<\brief Enables Vbus detection for L4/F4 driver.*/
#define USBD_DP_PORT        /**<\brief DP pullup port for F103/F303 driver.*/
#define USBD_DP_PIN         /**<\brief DP pullup pin for F103/F303 driver.*/
#define USBD_SOF_OUT        /**<\brief Enables SOF output pin for F4 OTGFS. */
#define USBD_PRIMARY_OTGHS  /**<\brief Sets OTGHS as primary interface for F4*/
#define USBD_USE_EXT_ULPI   /**<\brief Enables external ULPI interface for OTGHS */
#define USB_PMA_SIZE        /**<\brief PMA memoty size in bytes. Adjust this for
                              * the devices that shares PMA memory with CAN in case
                              * of both USB and CAN in use to avoid data corruption. */
/** @} */
#endif

/**\addtogroup USBD_HW USB hardware driver
 * @{ */

/**\anchor USB_EVENTS
 * \name USB device events
 * @{ */
#define usbd_evt_reset      0   /**<\brief Reset.*/
#define usbd_evt_sof        1   /**<\brief Start of frame.*/
#define usbd_evt_susp       2   /**<\brief Suspend.*/
#define usbd_evt_wkup       3   /**<\brief Wakeup.*/
#define usbd_evt_eptx       4   /**<\brief Data packet transmitted*/
#define usbd_evt_eprx       5   /**<\brief Data packet received.*/
#define usbd_evt_epsetup    6   /**<\brief Setup packet received.*/
#define usbd_evt_error      7   /**<\brief Data error.*/
#define usbd_evt_count      8
/** @}*/

/**\anchor USB_LANES_STATUS
 * \name USB lanes connection states
 * @{ */
#define usbd_lane_unk       0   /**<\brief Unknown or proprietary charger.*/
#define usbd_lane_dsc       1   /**<\brief Lanes disconnected.*/
#define usbd_lane_sdp       2   /**<\brief Lanes connected to standard downstream port.*/
#define usbd_lane_cdp       3   /**<\brief Lanes connected to charging downstream port.*/
#define usbd_lane_dcp       4   /**<\brief Lanes connected to dedicated charging port.*/
/** @} */

/**\anchor USBD_HW_CAPS
 * \name USB HW capabilities and status
 * @{ */
#define USBD_HW_ADDRFST     (1 << 0)    /**<\brief Set address before STATUS_OUT.*/
#define USBD_HW_BC          (1 << 1)    /**<\brief Battery charging detection supported.*/
#define USND_HW_HS          (1 << 2)    /**<\brief High speed supported.*/
#define USBD_HW_ENABLED     (1 << 3)    /**<\brief USB device enabled. */
#define USBD_HW_ENUMSPEED   (3 << 4)    /**<\brief USB device enumeration speed mask.*/
#define USBD_HW_SPEED_NC    (0 << 4)    /**<\brief Not connected */
#define USBD_HW_SPEED_LS    (1 << 4)    /**<\brief Low speed */
#define USBD_HW_SPEED_FS    (2 << 4)    /**<\brief Full speed */
#define USBD_HW_SPEED_HS    (3 << 4)    /**<\brief High speed */

/** @} */
/** @} */

/**\addtogroup USBD_CORE USB device core
 * \brief Contains core API
 * @{ */
#define USB_EPTYPE_DBLBUF   0x04    /**<\brief Doublebuffered endpoint (bulk endpoint only).*/

/**\name bmRequestType bitmapped field
 * @{ */
#define USB_REQ_DIRECTION   (1 << 7)    /**<\brief Request direction mask.*/
#define USB_REQ_HOSTTODEV   (0 << 7)    /**<\brief Request direction is HOST to DEVICE.*/
#define USB_REQ_DEVTOHOST   (1 << 7)    /**<\brief Request direction is DEVICE to HOST.*/
#define USB_REQ_TYPE        (3 << 5)    /**<\brief Request type mask.*/
#define USB_REQ_STANDARD    (0 << 5)    /**<\brief Standard request.*/
#define USB_REQ_CLASS       (1 << 5)    /**<\brief Class specified request.*/
#define USB_REQ_VENDOR      (2 << 5)    /**<\brief Vendor specified request.*/
#define USB_REQ_RECIPIENT   (3 << 0)    /**<\brief Request recipient mask.*/
#define USB_REQ_DEVICE      (0 << 0)    /**<\brief Request to device.*/
#define USB_REQ_INTERFACE   (1 << 0)    /**<\brief Request to interface.*/
#define USB_REQ_ENDPOINT    (2 << 0)    /**<\brief Request to endpoint.*/
#define USB_REQ_OTHER       (3 << 0)    /**<\brief Other request.*/
/** @} */


#if !defined(__ASSEMBLER__)
#include <stdbool.h>
#include <stddef.h>
/** @brief USB device machine states
 */
enum usbd_machine_state {
    usbd_state_disabled,
    usbd_state_disconnected,
    usbd_state_default,         /**< Default.*/
    usbd_state_addressed,       /**< Addressed.*/
    usbd_state_configured,      /**< Configured.*/
};

/**\brief USB device control endpoint machine state.*/
enum usbd_ctl_state {
    usbd_ctl_idle,              /**<\brief Idle stage. Awaiting for SETUP packet.*/
    usbd_ctl_rxdata,            /**<\brief RX stage. Receiving DATA-OUT payload.*/
    usbd_ctl_txdata,            /**<\brief TX stage. Transmitting DATA-IN payload.*/
    usbd_ctl_ztxdata,           /**<\brief TX stage. Transmitting DATA-IN payload. Zero length
                                 * packet maybe required..*/
    usbd_ctl_lastdata,          /**<\brief TX stage. Last DATA-IN packed passed to buffer. Awaiting
                                 * for the TX completion.*/
    usbd_ctl_statusin,          /**<\brief STATUS-IN stage.*/
    usbd_ctl_statusout,         /**<\brief STATUS-OUT stage.*/
};

/**\brief Reporting status results.*/
typedef enum _usbd_respond {
    usbd_fail,                  /**<\brief Function has an error, STALLPID will be issued.*/
    usbd_ack,                   /**<\brief Function completes request accepted ZLP or data will be send.*/
    usbd_nak,                   /**<\brief Function is busy. NAK handshake.*/
} usbd_respond;

typedef struct _usbd_device usbd_device;

/**\brief Represents generic USB control request.*/
typedef struct {
    uint8_t     bmRequestType;  /**<\brief This bitmapped field identifies the characteristics of
                                 * the specific request.*/
    uint8_t     bRequest;       /**<\brief This field specifies the particular request.*/
    uint16_t    wValue;         /**<\brief It is used to pass a parameter to the device, specific to
                                 * the request.*/
    uint16_t    wIndex;         /**<\brief It is used to pass a parameter to the device, specific to
                                 * the request.*/
    uint16_t    wLength;        /**<\brief This field specifies the length of the data transferred
                                 * during the second phase of the control transfer.*/
    uint8_t     data[];         /**<\brief Data payload.*/
} usbd_ctlreq;

/** USB device status data.*/
typedef struct {
             void        *data_buf;      /**<\brief Pointer to data buffer used for control requests.*/
             void        *data_ptr;      /**<\brief Pointer to current data for control request.*/
             uint16_t    data_count;     /**<\brief Count remained data for control request.*/
             uint16_t    data_maxsize;   /**<\brief Size of the data buffer for control requests.*/
             uint8_t     ep0size;        /**<\brief Size of the control endpoint.*/
             uint8_t     device_cfg;     /**<\brief Current device configuration number.*/
    volatile uint8_t     device_state;   /**<\brief Current \ref usbd_machine_state.*/
             uint8_t     control_state;  /**<\brief Current \ref usbd_ctl_state.*/
} usbd_status;

/**\brief Generic USB device event callback for events and endpoints processing
  * \param[in] dev pointer to USB device
  * \param event \ref USB_EVENTS "USB event"
  * \param ep active endpoint number
  * \note endpoints with same indexes i.e. 0x01 and 0x81 shares same callback.
  */
typedef void (*usbd_evt_callback)(usbd_device *dev, uint8_t event, uint8_t ep);

/**\brief USB control transfer completed callback function.
 * \param[in] dev pointer to USB device
 * \param[in] req pointer to usb request structure
 * \note usbd_device->complete_callback will be set to NULL after this callback completion.
 */
typedef void (*usbd_rqc_callback)(usbd_device *dev, usbd_ctlreq *req);

/**\brief USB control callback function.
 * \details Uses for the control request processing.
 *          Some requests will be handled by core if callback don't process it (returns FALSE).
 *            If request was not processed STALL PID will be issued.
 *          - GET_CONFIGURATION
 *          - SET_CONFIGURATION (passes to \ref usbd_cfg_callback)
 *          - GET_DESCRIPTOR (passes to \ref usbd_dsc_callback)
 *          - GET_STATUS
 *          - SET_FEATURE, CLEAR_FEATURE (endpoints only)
 *          - SET_ADDRESS
 * \param[in] dev points to USB device
 * \param[in] req points to usb control request
 * \param[out] *callback USB control transfer completion callback, default is NULL (no callback)
 * \return usbd_respond status.
 */
typedef usbd_respond (*usbd_ctl_callback)(usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback);

/**\brief USB get descriptor callback function
 * \details Called when GET_DESCRIPTOR request issued
 * \param[in] req pointer to usb control request structure
 * \param[in,out] address pointer to the descriptor in memory. Points to req->data by default. You
 * can use this buffer.
 * \param[in,out] dsize descriptor size. maximum buffer size by default.
 * \return usbd_ack if you passed the correct descriptor, usbd_fail otherwise.
 */
typedef usbd_respond (*usbd_dsc_callback)(usbd_ctlreq *req, void **address, uint16_t *dsize);

/**\brief USB set configuration callback function
 * \details called when SET_CONFIGURATION request issued
 * \param[in] dev pointer to USB device
 * \param[in] cfg configuration number.
 * \note if config is 0 device endpoints should be de-configured
 * \return TRUE if success
 */
typedef usbd_respond (*usbd_cfg_callback)(usbd_device *dev, uint8_t cfg);

/** @} */

/**\addtogroup USBD_HW
 * @{ */
/**\brief Get USB device status and capabilities.
 * \return Hardware status and capabilities \ref USBD_HW_CAPS */

typedef uint32_t (*usbd_hw_getinfo)(void);

/**\brief Enables or disables USB hardware
 * \param enable Enables USB when TRUE disables otherwise.
 */
typedef void (*usbd_hw_enable)(bool enable);

/** Connects or disconnects USB hardware to/from usb host
 * \param connect Connects USB to host if TRUE, disconnects otherwise
 * \return lanes connection status.
 */
typedef uint8_t (*usbd_hw_connect)(bool connect);

/**\brief Sets USB hardware address
 * \param address USB address
 */
typedef void (*usbd_hw_setaddr)(uint8_t address);

/**\brief Configures endpoint
 * \param ep endpoint address. Use USB_EPDIR_ macros to set endpoint direction
 * \param eptype endpoint type. Use USB_EPTYPE_* macros.
 * \param epsize endpoint size in bytes
 * \return TRUE if success
 */
typedef bool (*usbd_hw_ep_config)(uint8_t ep, uint8_t eptype, uint16_t epsize);

/**\brief De-configures, cleans and disables endpoint
 * \param ep endpoint index
 * \note if you have two one-direction single-buffered endpoints with same index (i.e. 0x02 and 0x82)
 * both will be deconfigured.
 */
typedef void (*usbd_hw_ep_deconfig)(uint8_t ep);

/**\brief Reads data from OUT or control endpoint
 * \param ep endpoint index, should belong to OUT or CONTROL endpoint.
 * \param buf pointer to read buffer
 * \param blen size of the read buffer in bytes
 * \return size of the actually received data, -1 on error.
 * \note if data does not fit buffer it will be truncated
 */
typedef int32_t (*usbd_hw_ep_read)(uint8_t ep, void *buf, uint16_t blen);

/**\brief Writes data to IN or control endpoint
 * \param ep endpoint index, hould belong to IN or CONTROL endpoint
 * \param buf pointer to data buffer
 * \param blen size of data will be written
 * \return number of written bytes
 */
typedef int32_t (*usbd_hw_ep_write)(uint8_t ep, const void *buf, uint16_t blen);

/** Stalls and unstalls endpoint
 * \param ep endpoint address
 * \param stall endpoint will be stalled if TRUE and unstalled otherwise.
 * \note Has no effect on inactive endpoints.
 */
typedef void (*usbd_hw_ep_setstall)(uint8_t ep, bool stall);

/**\brief Checks endpoint for stalled state
 * \param ep endpoint address
 * \return TRUE if endpoint is stalled
 */
typedef bool (*usbd_hw_ep_isstalled)(uint8_t ep);

/**\brief Polls USB hardware for the events
 * \param[in] dev pointer to usb device structure
 * \param callback callback to event processing subroutine
 */
typedef void (*usbd_hw_poll)(usbd_device *dev, usbd_evt_callback callback);

/**\brief Gets frame number from usb hardware.*/
typedef uint16_t (*usbd_hw_get_frameno)(void);


/**\brief Makes a string descriptor contains unique serial number from hardware ID's
 * \param[in] buffer pointer to buffer for the descriptor
 * \return of the descriptor in bytes
 */
typedef uint16_t (*usbd_hw_get_serialno)(void *buffer);

/**\brief Represents a hardware USB driver call table.*/
struct usbd_driver {
    usbd_hw_getinfo         getinfo;            /**<\copybrief usbd_hw_getinfo */
    usbd_hw_enable          enable;             /**<\copybrief usbd_hw_enable */
    usbd_hw_connect         connect;            /**<\copybrief usbd_hw_connect */
    usbd_hw_setaddr         setaddr;            /**<\copybrief usbd_hw_setaddr */
    usbd_hw_ep_config       ep_config;          /**<\copybrief usbd_hw_ep_config */
    usbd_hw_ep_deconfig     ep_deconfig;        /**<\copybrief usbd_hw_ep_deconfig */
    usbd_hw_ep_read         ep_read;            /**<\copybrief usbd_hw_ep_read */
    usbd_hw_ep_write        ep_write;           /**<\copybrief usbd_hw_ep_write */
    usbd_hw_ep_setstall     ep_setstall;        /**<\copybrief usbd_hw_ep_setstall */
    usbd_hw_ep_isstalled    ep_isstalled;       /**<\copybrief usbd_hw_ep_isstalled */
    usbd_hw_poll            poll;               /**<\copybrief usbd_hw_poll */
    usbd_hw_get_frameno     frame_no;           /**<\copybrief usbd_hw_get_frameno */
    usbd_hw_get_serialno    get_serialno_desc;  /**<\copybrief usbd_hw_get_serialno */
};

/** @} */

/**\addtogroup USBD_CORE
 * @{ */

/**\brief Represents a USB device data.*/
struct _usbd_device {
    const struct usbd_driver    *driver;                /**<\copybrief usbd_driver */
    usbd_ctl_callback           control_callback;       /**<\copybrief usbd_ctl_callback */
    usbd_rqc_callback           complete_callback;      /**<\copybrief usbd_rqc_callback */
    usbd_cfg_callback           config_callback;        /**<\copybrief usbd_cfg_callback */
    usbd_dsc_callback           descriptor_callback;    /**<\copybrief usbd_dsc_callback */
    usbd_evt_callback           events[usbd_evt_count]; /**<\brief array of the event callbacks.*/
    usbd_evt_callback           endpoint[8];            /**<\brief array of the endpoint callbacks.*/
    usbd_status                 status;                 /**<\copybrief usbd_status */
};

/**\brief Initializes device structure
 * \param dev USB device that will be initialized
 * \param drv Pointer to hardware driver
 * \param ep0size Control endpoint 0 size
 * \param buffer Pointer to control request data buffer (32-bit aligned)
 * \param bsize Size of the data buffer
 */
inline static void usbd_init(usbd_device *dev, const struct usbd_driver *drv,
                             const uint8_t ep0size, uint32_t *buffer, const uint16_t bsize) {
    dev->driver = drv;
    dev->status.ep0size = ep0size;
    dev->status.data_ptr = buffer;
    dev->status.data_buf = buffer;
    dev->status.data_maxsize = bsize - offsetof(usbd_ctlreq, data);
}

/**\brief Polls USB for events
 * \param dev Pointer to device structure
 * \note can be called as from main routine as from USB interrupt
 */
void usbd_poll(usbd_device *dev);

/**\brief Register callback for all control requests
 * \param dev usb device \ref _usbd_device
 * \param callback user control callback \ref usbd_ctl_callback
 */
inline static void usbd_reg_control(usbd_device *dev, usbd_ctl_callback callback) {
    dev->control_callback = callback;
}

/**\brief Register callback for SET_CONFIG control request
 * \param dev dev usb device \ref _usbd_device
 * \param callback pointer to user \ref usbd_cfg_callback
 */
inline static void usbd_reg_config(usbd_device *dev, usbd_cfg_callback callback) {
    dev->config_callback = callback;
}

/**\brief Register callback for GET_DESCRIPTOR control request
 * \param dev dev usb device \ref _usbd_device
 * \param callback pointer to user \ref usbd_ctl_callback
 */
inline static void usbd_reg_descr(usbd_device *dev, usbd_dsc_callback callback) {
    dev->descriptor_callback = callback;
}

/**\brief Configure endpoint
 * \param dev dev usb device \ref _usbd_device
 * \copydetails usbd_hw_ep_config
 */
inline static bool usbd_ep_config(usbd_device *dev, uint8_t ep, uint8_t eptype, uint16_t epsize) {
    return dev->driver->ep_config(ep, eptype, epsize);
}

/**\brief Deconfigure endpoint
 * \param dev dev usb device \ref _usbd_device
 * \copydetails usbd_hw_ep_deconfig
 */
inline static void usbd_ep_deconfig(usbd_device *dev, uint8_t ep) {
    dev->driver->ep_deconfig(ep);
}

/**\brief Register endpoint callback
 * \param dev dev usb device \ref _usbd_device
 * \param ep endpoint index
 * \param callback pointer to user \ref usbd_evt_callback callback for endpoint events
 */
inline static void usbd_reg_endpoint(usbd_device *dev, uint8_t ep, usbd_evt_callback callback) {
    dev->endpoint[ep & 0x07] = callback;
}

/**\brief Registers event callback
 * \param dev dev usb device \ref _usbd_device
 * \param evt device \ref USB_EVENTS "event" wants to be registered
 * \param callback pointer to user \ref usbd_evt_callback for this event
 */
inline static void usbd_reg_event(usbd_device *dev, uint8_t evt, usbd_evt_callback callback) {
    dev->events[evt] = callback;
}

/**\brief Write data to endpoint
 * \param dev dev usb device \ref _usbd_device
 * \copydetails usbd_hw_ep_write
 */
inline static int32_t usbd_ep_write(usbd_device *dev, uint8_t ep, const void *buf, uint16_t blen) {
    return dev->driver->ep_write(ep, buf, blen);
}

/**\brief Read data from endpoint
 * \param dev dev usb device \ref _usbd_device
 * \copydetails usbd_hw_ep_read
 */
inline static int32_t usbd_ep_read(usbd_device *dev, uint8_t ep, void *buf, uint16_t blen) {
    return dev->driver->ep_read(ep, buf, blen);
}

/**\brief Stall endpoint
 * \param dev dev usb device \ref _usbd_device
 * \param ep endpoint address
 */
inline static void usbd_ep_stall(usbd_device *dev, uint8_t ep) {
    dev->driver->ep_setstall(ep, 1);
}

/**\brief Unstall endpoint
 * \param dev dev usb device \ref _usbd_device
 * \param ep endpoint address
 */
inline static void usbd_ep_unstall(usbd_device *dev, uint8_t ep) {
    dev->driver->ep_setstall(ep, 0);
}

/**\brief Enables or disables USB hardware
 * \param dev dev usb device \ref _usbd_device
 * \param enable Enables USB when TRUE disables otherwise
 */
inline static void usbd_enable(usbd_device *dev, bool enable) {
    dev->driver->enable(enable);
}

/**\brief Connects or disconnects USB hardware to/from usb host
 * \param dev dev usb device \ref _usbd_device
 * \param connect Connects USB to host if TRUE, disconnects otherwise
 * \return lanes connection status. \ref USB_LANES_STATUS
 */
inline static uint8_t usbd_connect(usbd_device *dev, bool connect) {
    return dev->driver->connect(connect);
}

/**\brief Retrieves status and capabilities.
 * \return current HW status, enumeration speed and capabilities \ref USBD_HW_CAPS */
inline static uint32_t usbd_getinfo(usbd_device *dev) {
    return dev->driver->getinfo();
}

#endif //(__ASSEMBLER__)
/** @} */
/** @} */

#if defined(__cplusplus)
    }
#endif
#endif //_USBD_STD_H_