summaryrefslogtreecommitdiff
path: root/src/host/hub.h
blob: 595b8b64537b81d98a2bc9d9d667c8456832e700 (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
/*
 * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org)
 * SPDX-License-Identifier: MIT
 *
 * This file is part of the TinyUSB stack.
 */

#ifndef TUSB_HUB_H_
#define TUSB_HUB_H_

#include "common/tusb_common.h"

#ifdef __cplusplus
 extern "C" {
#endif

//--------------------------------------------------------------------+
// Configuration
//--------------------------------------------------------------------+

#ifndef CFG_TUH_HUB_BUFSIZE
  #define CFG_TUH_HUB_BUFSIZE 12
#endif

//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
enum {
  HUB_REQUEST_GET_STATUS      = 0  ,
  HUB_REQUEST_CLEAR_FEATURE   = 1  ,
  // 2 is reserved
  HUB_REQUEST_SET_FEATURE     = 3  ,
  // 4-5 are reserved
  HUB_REQUEST_GET_DESCRIPTOR  = 6  ,
  HUB_REQUEST_SET_DESCRIPTOR  = 7  ,
  HUB_REQUEST_CLEAR_TT_BUFFER = 8  ,
  HUB_REQUEST_RESET_TT        = 9  ,
  HUB_REQUEST_GET_TT_STATE    = 10 ,
  HUB_REQUEST_STOP_TT         = 11
};

enum {
  HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0,
  HUB_FEATURE_HUB_OVER_CURRENT_CHANGE
};

enum{
  HUB_FEATURE_PORT_CONNECTION          = 0,
  HUB_FEATURE_PORT_ENABLE              = 1,
  HUB_FEATURE_PORT_SUSPEND             = 2,
  HUB_FEATURE_PORT_OVER_CURRENT        = 3,
  HUB_FEATURE_PORT_RESET               = 4,
  // 5-7 are reserved
  HUB_FEATURE_PORT_POWER               = 8,
  HUB_FEATURE_PORT_LOW_SPEED           = 9,
  // 10-15 are reserved
  HUB_FEATURE_PORT_CONNECTION_CHANGE   = 16,
  HUB_FEATURE_PORT_ENABLE_CHANGE       = 17,
  HUB_FEATURE_PORT_SUSPEND_CHANGE      = 18,
  HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19,
  HUB_FEATURE_PORT_RESET_CHANGE        = 20,
  HUB_FEATURE_PORT_TEST                = 21,
  HUB_FEATURE_PORT_INDICATOR           = 22
};

enum {
  HUB_CHARS_POWER_GANGED_SWITCHING = 0,
  HUB_CHARS_POWER_INDIVIDUAL_SWITCHING = 1,
};

enum {
  HUB_CHARS_OVER_CURRENT_GLOBAL = 0,
  HUB_CHARS_OVER_CURRENT_INDIVIDUAL = 1,
};

// Hub Interface Protocol (USB 2.0 spec Table 11-16)
typedef enum {
  HUB_PROTOCOL_FULL_SPEED     = 0, // Full speed hub
  HUB_PROTOCOL_HIGH_SPEED_STT = 1, // Hi-speed hub with single TT
  HUB_PROTOCOL_HIGH_SPEED_MTT = 2, // Hi-speed hub with multiple TTs
} hub_protocol_t;

typedef struct TU_ATTR_PACKED{
  uint8_t  bLength           ; ///< Size of descriptor
  uint8_t  bDescriptorType   ; ///< Other_speed_Configuration Type
  uint8_t  bNbrPorts;
  uint16_t wHubCharacteristics;
  uint8_t  bPwrOn2PwrGood;
  uint8_t  bHubContrCurrent;
  uint8_t  DeviceRemovable; // bitmap each bit for a port (from bit1)
  uint8_t  PortPwrCtrlMask; // just for compatibility, should be 0xff
} hub_desc_cs_t;
TU_VERIFY_STATIC(sizeof(hub_desc_cs_t) == 9, "size is not correct");
TU_VERIFY_STATIC(CFG_TUH_HUB_BUFSIZE >= sizeof(hub_desc_cs_t), "buffer is not big enough");

typedef struct TU_ATTR_PACKED {
  struct TU_ATTR_PACKED {
    uint8_t logical_power_switching_mode : 2; // [0..1] gannged or individual power switching
    uint8_t compound_device              : 1; // [2] hub is part of compound device
    uint8_t over_current_protect_mode    : 2; // [3..4] global or individual port over-current protection
    uint8_t tt_think_time                : 2; // [5..6] TT think time
    uint8_t port_indicator_supported     : 1; // [7] port indicator supported
  };
  uint8_t rsv1;
} hub_characteristics_t;
TU_VERIFY_STATIC(sizeof(hub_characteristics_t) == 2, "size is not correct");

// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
typedef struct {
  union{
    struct TU_ATTR_PACKED {
      uint16_t local_power_source : 1;
      uint16_t over_current       : 1;
      uint16_t : 14;
    };

    uint16_t value;
  } status, change;
} hub_status_response_t;
TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct");

// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
typedef struct {
  union TU_ATTR_PACKED {
    struct TU_ATTR_PACKED {
      // Bit 0-4 are for change & status
      uint16_t connection             : 1; // [0] 0 = no device, 1 = device connected
      uint16_t port_enable            : 1; // [1] port is enabled
      uint16_t suspend                : 1; // [2]
      uint16_t over_current           : 1; // [3] over-current exists
      uint16_t reset                  : 1; // [4] 0 = no reset, 1 = resetting

      // From Bit 5 are for status only
      uint16_t rsv5_7                 : 3; // [5..7] reserved
      uint16_t port_power             : 1; // [8] 0 = port is off, 1 = port is on
      uint16_t low_speed              : 1; // [9] low speed device attached
      uint16_t high_speed             : 1; // [10] high speed device attached
      uint16_t port_test_mode         : 1; // [11] port in test mode
      uint16_t port_indicator_control : 1; // [12] 0: default color, 1: indicator is software controlled
      uint16_t TU_RESERVED            : 3; // [13..15] reserved
    };

    uint16_t value;
  } status, change;
} hub_port_status_response_t;
TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");

//--------------------------------------------------------------------+
// HUB API
//--------------------------------------------------------------------+

// Clear port feature
bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
                            tuh_xfer_cb_t complete_cb, uintptr_t user_data);

// Set port feature
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
                          tuh_xfer_cb_t complete_cb, uintptr_t user_data);

// Get port status
// If hub_port != 0, resp is ignored. hub_port_get_status_local() can be used to retrieve the status
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void *resp,
                         tuh_xfer_cb_t complete_cb, uintptr_t user_data);

// Get port status from local cache. This does not send a request to the device
bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp);

// Get status from Interrupt endpoint
bool hub_edpt_status_xfer(uint8_t daddr);

// Reset a port
TU_ATTR_ALWAYS_INLINE static inline
bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
  return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_data);
}

// Clear Port Reset Change
TU_ATTR_ALWAYS_INLINE static inline
bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
  return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
}

// Get Hub status (port = 0)
TU_ATTR_ALWAYS_INLINE static inline
bool hub_get_status(uint8_t hub_addr, void* resp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
  return hub_port_get_status(hub_addr, 0, resp, complete_cb, user_data);
}

// Clear Hub feature
TU_ATTR_ALWAYS_INLINE static inline
bool hub_clear_feature(uint8_t hub_addr, uint8_t feature, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
  return hub_port_clear_feature(hub_addr, 0, feature, complete_cb, user_data);
}
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
bool     hub_init(void);
bool     hub_deinit(void);
uint16_t hub_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
bool     hub_set_config(uint8_t daddr, uint8_t itf_num);
bool     hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void     hub_close(uint8_t dev_addr);

#ifdef __cplusplus
 }
#endif

#endif