A more capable USB Host. The API supports synchronous and Asynchronous control, interrupt and bulk transfers. It has built in support for hubs and hot plugging. It can support any number of devices and endpoints limited only by sram. The test shell supports mouse, keyboard and mass storage/fat.

Dependencies:   mbed

Committer:
peterbarrett1967
Date:
Fri Apr 02 22:28:01 2010 +0000
Revision:
0:5ad808014a49

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
peterbarrett1967 0:5ad808014a49 1
peterbarrett1967 0:5ad808014a49 2 /*
peterbarrett1967 0:5ad808014a49 3 Copyright (c) 2010 Peter Barrett
peterbarrett1967 0:5ad808014a49 4
peterbarrett1967 0:5ad808014a49 5 Permission is hereby granted, free of charge, to any person obtaining a copy
peterbarrett1967 0:5ad808014a49 6 of this software and associated documentation files (the "Software"), to deal
peterbarrett1967 0:5ad808014a49 7 in the Software without restriction, including without limitation the rights
peterbarrett1967 0:5ad808014a49 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
peterbarrett1967 0:5ad808014a49 9 copies of the Software, and to permit persons to whom the Software is
peterbarrett1967 0:5ad808014a49 10 furnished to do so, subject to the following conditions:
peterbarrett1967 0:5ad808014a49 11
peterbarrett1967 0:5ad808014a49 12 The above copyright notice and this permission notice shall be included in
peterbarrett1967 0:5ad808014a49 13 all copies or substantial portions of the Software.
peterbarrett1967 0:5ad808014a49 14
peterbarrett1967 0:5ad808014a49 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
peterbarrett1967 0:5ad808014a49 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
peterbarrett1967 0:5ad808014a49 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
peterbarrett1967 0:5ad808014a49 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
peterbarrett1967 0:5ad808014a49 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
peterbarrett1967 0:5ad808014a49 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
peterbarrett1967 0:5ad808014a49 21 THE SOFTWARE.
peterbarrett1967 0:5ad808014a49 22 */
peterbarrett1967 0:5ad808014a49 23
peterbarrett1967 0:5ad808014a49 24 #include "mbed.h"
peterbarrett1967 0:5ad808014a49 25 #include "USBHost.h"
peterbarrett1967 0:5ad808014a49 26
peterbarrett1967 0:5ad808014a49 27 // Config (default uses x bytes)
peterbarrett1967 0:5ad808014a49 28 #define MAX_DEVICES 8 // Max number of devices
peterbarrett1967 0:5ad808014a49 29 #define MAX_ENDPOINTS_TOTAL 16 // Max number of endpoints total
peterbarrett1967 0:5ad808014a49 30 #define MAX_ENDPOINTS_PER_DEVICE 8 // Max number of endpoints for any one device
peterbarrett1967 0:5ad808014a49 31
peterbarrett1967 0:5ad808014a49 32 #define USBLOG 1
peterbarrett1967 0:5ad808014a49 33 #if USBLOG
peterbarrett1967 0:5ad808014a49 34 #define LOG(...) printf(__VA_ARGS__)
peterbarrett1967 0:5ad808014a49 35 #else
peterbarrett1967 0:5ad808014a49 36 #define LOG(...) do {} while(0)
peterbarrett1967 0:5ad808014a49 37 #endif
peterbarrett1967 0:5ad808014a49 38
peterbarrett1967 0:5ad808014a49 39 // USB host structures
peterbarrett1967 0:5ad808014a49 40
peterbarrett1967 0:5ad808014a49 41 #define USB_RAM_SIZE 16*1024 // AHB SRAM block 1 TODO MACHINE DEPENDENT
peterbarrett1967 0:5ad808014a49 42 #define USB_RAM_BASE 0x2007C000
peterbarrett1967 0:5ad808014a49 43
peterbarrett1967 0:5ad808014a49 44 #define TOKEN_SETUP 0
peterbarrett1967 0:5ad808014a49 45 #define TOKEN_IN 1
peterbarrett1967 0:5ad808014a49 46 #define TOKEN_OUT 2
peterbarrett1967 0:5ad808014a49 47
peterbarrett1967 0:5ad808014a49 48 // Status flags from hub
peterbarrett1967 0:5ad808014a49 49 #define PORT_CONNECTION 0
peterbarrett1967 0:5ad808014a49 50 #define PORT_ENABLE 1
peterbarrett1967 0:5ad808014a49 51 #define PORT_SUSPEND 2
peterbarrett1967 0:5ad808014a49 52 #define PORT_OVER_CURRENT 3
peterbarrett1967 0:5ad808014a49 53 #define PORT_RESET 4
peterbarrett1967 0:5ad808014a49 54 #define PORT_POWER 8
peterbarrett1967 0:5ad808014a49 55 #define PORT_LOW_SPEED 9
peterbarrett1967 0:5ad808014a49 56
peterbarrett1967 0:5ad808014a49 57 #define C_PORT_CONNECTION 16
peterbarrett1967 0:5ad808014a49 58 #define C_PORT_ENABLE 17
peterbarrett1967 0:5ad808014a49 59 #define C_PORT_SUSPEND 18
peterbarrett1967 0:5ad808014a49 60 #define C_PORT_OVER_CURRENT 19
peterbarrett1967 0:5ad808014a49 61 #define C_PORT_RESET 20
peterbarrett1967 0:5ad808014a49 62
peterbarrett1967 0:5ad808014a49 63 typedef struct {
peterbarrett1967 0:5ad808014a49 64 u8 bm_request_type;
peterbarrett1967 0:5ad808014a49 65 u8 b_request;
peterbarrett1967 0:5ad808014a49 66 u16 w_value;
peterbarrett1967 0:5ad808014a49 67 u16 w_index;
peterbarrett1967 0:5ad808014a49 68 u16 w_length;
peterbarrett1967 0:5ad808014a49 69 } Setup;
peterbarrett1967 0:5ad808014a49 70
peterbarrett1967 0:5ad808014a49 71
peterbarrett1967 0:5ad808014a49 72 // Hub stuff is kept private just to keep api simple
peterbarrett1967 0:5ad808014a49 73 int SetPortFeature(int device, int feature, int index);
peterbarrett1967 0:5ad808014a49 74 int ClearPortFeature(int device, int feature, int index);
peterbarrett1967 0:5ad808014a49 75 int SetPortPower(int device, int port);
peterbarrett1967 0:5ad808014a49 76 int SetPortReset(int device, int port);
peterbarrett1967 0:5ad808014a49 77 int GetPortStatus(int device, int port, u32* status);
peterbarrett1967 0:5ad808014a49 78
peterbarrett1967 0:5ad808014a49 79 //===================================================================
peterbarrett1967 0:5ad808014a49 80 //===================================================================
peterbarrett1967 0:5ad808014a49 81 // Hardware defines
peterbarrett1967 0:5ad808014a49 82
peterbarrett1967 0:5ad808014a49 83 // HcControl
peterbarrett1967 0:5ad808014a49 84 #define PeriodicListEnable 0x00000004
peterbarrett1967 0:5ad808014a49 85 #define IsochronousEnable 0x00000008
peterbarrett1967 0:5ad808014a49 86 #define ControlListEnable 0x00000010
peterbarrett1967 0:5ad808014a49 87 #define BulkListEnable 0x00000020
peterbarrett1967 0:5ad808014a49 88 #define OperationalMask 0x00000080
peterbarrett1967 0:5ad808014a49 89 #define HostControllerFunctionalState 0x000000C0
peterbarrett1967 0:5ad808014a49 90
peterbarrett1967 0:5ad808014a49 91 // HcCommandStatus
peterbarrett1967 0:5ad808014a49 92 #define HostControllerReset 0x00000001
peterbarrett1967 0:5ad808014a49 93 #define ControlListFilled 0x00000002
peterbarrett1967 0:5ad808014a49 94 #define BulkListFilled 0x00000004
peterbarrett1967 0:5ad808014a49 95
peterbarrett1967 0:5ad808014a49 96 // HcInterruptStatus Register
peterbarrett1967 0:5ad808014a49 97 #define WritebackDoneHead 0x00000002
peterbarrett1967 0:5ad808014a49 98 #define StartofFrame 0x00000004
peterbarrett1967 0:5ad808014a49 99 #define ResumeDetected 0x00000008
peterbarrett1967 0:5ad808014a49 100 #define UnrecoverableError 0x00000010
peterbarrett1967 0:5ad808014a49 101 #define FrameNumberOverflow 0x00000020
peterbarrett1967 0:5ad808014a49 102 #define RootHubStatusChange 0x00000040
peterbarrett1967 0:5ad808014a49 103 #define OwnershipChange 0x00000080
peterbarrett1967 0:5ad808014a49 104 #define MasterInterruptEnable 0x80000000
peterbarrett1967 0:5ad808014a49 105
peterbarrett1967 0:5ad808014a49 106 // HcRhStatus
peterbarrett1967 0:5ad808014a49 107 #define SetGlobalPower 0x00010000
peterbarrett1967 0:5ad808014a49 108 #define DeviceRemoteWakeupEnable 0x00008000
peterbarrett1967 0:5ad808014a49 109
peterbarrett1967 0:5ad808014a49 110 // HcRhPortStatus (hub 0, port 1)
peterbarrett1967 0:5ad808014a49 111 #define CurrentConnectStatus 0x00000001
peterbarrett1967 0:5ad808014a49 112 #define PortEnableStatus 0x00000002
peterbarrett1967 0:5ad808014a49 113 #define PortSuspendStatus 0x00000004
peterbarrett1967 0:5ad808014a49 114 #define PortOverCurrentIndicator 0x00000008
peterbarrett1967 0:5ad808014a49 115 #define PortResetStatus 0x00000010
peterbarrett1967 0:5ad808014a49 116
peterbarrett1967 0:5ad808014a49 117 #define PortPowerStatus 0x00000100
peterbarrett1967 0:5ad808014a49 118 #define LowspeedDevice 0x00000200
peterbarrett1967 0:5ad808014a49 119 #define HighspeedDevice 0x00000400
peterbarrett1967 0:5ad808014a49 120
peterbarrett1967 0:5ad808014a49 121 #define ConnectStatusChange (CurrentConnectStatus << 16)
peterbarrett1967 0:5ad808014a49 122 #define PortResetStatusChange (PortResetStatus << 16)
peterbarrett1967 0:5ad808014a49 123
peterbarrett1967 0:5ad808014a49 124
peterbarrett1967 0:5ad808014a49 125 #define TD_ROUNDING (u32)0x00040000
peterbarrett1967 0:5ad808014a49 126 #define TD_SETUP (u32)0x00000000
peterbarrett1967 0:5ad808014a49 127 #define TD_IN (u32)0x00100000
peterbarrett1967 0:5ad808014a49 128 #define TD_OUT (u32)0x00080000
peterbarrett1967 0:5ad808014a49 129 #define TD_DELAY_INT(x) (u32)((x) << 21)
peterbarrett1967 0:5ad808014a49 130 #define TD_TOGGLE_0 (u32)0x02000000
peterbarrett1967 0:5ad808014a49 131 #define TD_TOGGLE_1 (u32)0x03000000
peterbarrett1967 0:5ad808014a49 132 #define TD_CC (u32)0xF0000000
peterbarrett1967 0:5ad808014a49 133
peterbarrett1967 0:5ad808014a49 134 // HostController EndPoint Descriptor
peterbarrett1967 0:5ad808014a49 135 typedef struct {
peterbarrett1967 0:5ad808014a49 136 volatile u32 Control;
peterbarrett1967 0:5ad808014a49 137 volatile u32 TailTd;
peterbarrett1967 0:5ad808014a49 138 volatile u32 HeadTd;
peterbarrett1967 0:5ad808014a49 139 volatile u32 Next;
peterbarrett1967 0:5ad808014a49 140 } HCED;
peterbarrett1967 0:5ad808014a49 141
peterbarrett1967 0:5ad808014a49 142 // HostController Transfer Descriptor
peterbarrett1967 0:5ad808014a49 143 typedef struct {
peterbarrett1967 0:5ad808014a49 144 volatile u32 Control;
peterbarrett1967 0:5ad808014a49 145 volatile u32 CurrBufPtr;
peterbarrett1967 0:5ad808014a49 146 volatile u32 Next;
peterbarrett1967 0:5ad808014a49 147 volatile u32 BufEnd;
peterbarrett1967 0:5ad808014a49 148 } HCTD;
peterbarrett1967 0:5ad808014a49 149
peterbarrett1967 0:5ad808014a49 150 // Host Controller Communication Area
peterbarrett1967 0:5ad808014a49 151 typedef struct {
peterbarrett1967 0:5ad808014a49 152 volatile u32 InterruptTable[32];
peterbarrett1967 0:5ad808014a49 153 volatile u16 FrameNumber;
peterbarrett1967 0:5ad808014a49 154 volatile u16 FrameNumberPad;
peterbarrett1967 0:5ad808014a49 155 volatile u32 DoneHead;
peterbarrett1967 0:5ad808014a49 156 volatile u8 Reserved[120];
peterbarrett1967 0:5ad808014a49 157 } HCCA;
peterbarrett1967 0:5ad808014a49 158
peterbarrett1967 0:5ad808014a49 159 //====================================================================================
peterbarrett1967 0:5ad808014a49 160 //====================================================================================
peterbarrett1967 0:5ad808014a49 161
peterbarrett1967 0:5ad808014a49 162 class HostController;
peterbarrett1967 0:5ad808014a49 163 class Endpoint;
peterbarrett1967 0:5ad808014a49 164 class Device;
peterbarrett1967 0:5ad808014a49 165
peterbarrett1967 0:5ad808014a49 166 // must be 3*16 bytes long
peterbarrett1967 0:5ad808014a49 167 class Endpoint
peterbarrett1967 0:5ad808014a49 168 {
peterbarrett1967 0:5ad808014a49 169 public:
peterbarrett1967 0:5ad808014a49 170 HCED EndpointDescriptor; // Pointer to EndpointDescriptor == Pointer to Endpoint
peterbarrett1967 0:5ad808014a49 171 HCTD TDHead;
peterbarrett1967 0:5ad808014a49 172
peterbarrett1967 0:5ad808014a49 173 enum State
peterbarrett1967 0:5ad808014a49 174 {
peterbarrett1967 0:5ad808014a49 175 Free,
peterbarrett1967 0:5ad808014a49 176 NotQueued,
peterbarrett1967 0:5ad808014a49 177 Idle,
peterbarrett1967 0:5ad808014a49 178 SetupQueued,
peterbarrett1967 0:5ad808014a49 179 DataQueued,
peterbarrett1967 0:5ad808014a49 180 StatusQueued,
peterbarrett1967 0:5ad808014a49 181 CallbackPending
peterbarrett1967 0:5ad808014a49 182 };
peterbarrett1967 0:5ad808014a49 183
peterbarrett1967 0:5ad808014a49 184 volatile u8 CurrentState;
peterbarrett1967 0:5ad808014a49 185 u8 Flags; // 0x80 In, 0x03 mask endpoint type
peterbarrett1967 0:5ad808014a49 186
peterbarrett1967 0:5ad808014a49 187 u16 Length;
peterbarrett1967 0:5ad808014a49 188 u8* Data;
peterbarrett1967 0:5ad808014a49 189 USBCallback Callback; // Must be a multiple of 16 bytes long
peterbarrett1967 0:5ad808014a49 190 void* UserData;
peterbarrett1967 0:5ad808014a49 191
peterbarrett1967 0:5ad808014a49 192 int Address()
peterbarrett1967 0:5ad808014a49 193 {
peterbarrett1967 0:5ad808014a49 194 int ep = (EndpointDescriptor.Control >> 7) & 0xF;
peterbarrett1967 0:5ad808014a49 195 if (ep)
peterbarrett1967 0:5ad808014a49 196 ep |= Flags & 0x80;
peterbarrett1967 0:5ad808014a49 197 return ep;
peterbarrett1967 0:5ad808014a49 198 }
peterbarrett1967 0:5ad808014a49 199
peterbarrett1967 0:5ad808014a49 200 int Device()
peterbarrett1967 0:5ad808014a49 201 {
peterbarrett1967 0:5ad808014a49 202 return EndpointDescriptor.Control & 0x7F;
peterbarrett1967 0:5ad808014a49 203 }
peterbarrett1967 0:5ad808014a49 204
peterbarrett1967 0:5ad808014a49 205 int Status()
peterbarrett1967 0:5ad808014a49 206 {
peterbarrett1967 0:5ad808014a49 207 return (TDHead.Control >> 28) & 0xF;
peterbarrett1967 0:5ad808014a49 208 }
peterbarrett1967 0:5ad808014a49 209
peterbarrett1967 0:5ad808014a49 210 u32 Enqueue(u32 head)
peterbarrett1967 0:5ad808014a49 211 {
peterbarrett1967 0:5ad808014a49 212 if (CurrentState == NotQueued)
peterbarrett1967 0:5ad808014a49 213 {
peterbarrett1967 0:5ad808014a49 214 EndpointDescriptor.Next = head;
peterbarrett1967 0:5ad808014a49 215 head = (u32)&EndpointDescriptor;
peterbarrett1967 0:5ad808014a49 216 CurrentState = Idle;
peterbarrett1967 0:5ad808014a49 217 }
peterbarrett1967 0:5ad808014a49 218 return head;
peterbarrett1967 0:5ad808014a49 219 }
peterbarrett1967 0:5ad808014a49 220 };
peterbarrett1967 0:5ad808014a49 221
peterbarrett1967 0:5ad808014a49 222 class Device
peterbarrett1967 0:5ad808014a49 223 {
peterbarrett1967 0:5ad808014a49 224 public:
peterbarrett1967 0:5ad808014a49 225 u8 _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2];
peterbarrett1967 0:5ad808014a49 226 u8 Hub;
peterbarrett1967 0:5ad808014a49 227 u8 Port;
peterbarrett1967 0:5ad808014a49 228 u8 Addr;
peterbarrett1967 0:5ad808014a49 229 u8 Pad;
peterbarrett1967 0:5ad808014a49 230
peterbarrett1967 0:5ad808014a49 231 // Only if this device is a hub
peterbarrett1967 0:5ad808014a49 232 u8 HubPortCount; // nonzero if this is a hub
peterbarrett1967 0:5ad808014a49 233 u8 HubInterruptData;
peterbarrett1967 0:5ad808014a49 234 u8 HubMap;
peterbarrett1967 0:5ad808014a49 235 u8 HubMask;
peterbarrett1967 0:5ad808014a49 236
peterbarrett1967 0:5ad808014a49 237 int Flags; // 1 = Disconnected
peterbarrett1967 0:5ad808014a49 238
peterbarrett1967 0:5ad808014a49 239 Setup SetupBuffer;
peterbarrett1967 0:5ad808014a49 240
peterbarrett1967 0:5ad808014a49 241 // Allocate endpoint zero
peterbarrett1967 0:5ad808014a49 242 int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed)
peterbarrett1967 0:5ad808014a49 243 {
peterbarrett1967 0:5ad808014a49 244 Hub = hub;
peterbarrett1967 0:5ad808014a49 245 Port = port;
peterbarrett1967 0:5ad808014a49 246 Addr = addr;
peterbarrett1967 0:5ad808014a49 247 Flags = lowSpeed;
peterbarrett1967 0:5ad808014a49 248 memset(_endpointMap,0xFF,sizeof(_endpointMap));
peterbarrett1967 0:5ad808014a49 249 return 0;
peterbarrett1967 0:5ad808014a49 250 }
peterbarrett1967 0:5ad808014a49 251
peterbarrett1967 0:5ad808014a49 252 int SetEndpointIndex(int ep, int endpointIndex)
peterbarrett1967 0:5ad808014a49 253 {
peterbarrett1967 0:5ad808014a49 254 for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2)
peterbarrett1967 0:5ad808014a49 255 {
peterbarrett1967 0:5ad808014a49 256 if (_endpointMap[i] == 0xFF) // Add endpoint to map
peterbarrett1967 0:5ad808014a49 257 {
peterbarrett1967 0:5ad808014a49 258 _endpointMap[i] = ep;
peterbarrett1967 0:5ad808014a49 259 _endpointMap[i+1] = endpointIndex;
peterbarrett1967 0:5ad808014a49 260 return 0;
peterbarrett1967 0:5ad808014a49 261 }
peterbarrett1967 0:5ad808014a49 262 }
peterbarrett1967 0:5ad808014a49 263 return ERR_ENDPOINT_NONE_LEFT;
peterbarrett1967 0:5ad808014a49 264 }
peterbarrett1967 0:5ad808014a49 265
peterbarrett1967 0:5ad808014a49 266 int GetEndpointIndex(int ep)
peterbarrett1967 0:5ad808014a49 267 {
peterbarrett1967 0:5ad808014a49 268 for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2)
peterbarrett1967 0:5ad808014a49 269 {
peterbarrett1967 0:5ad808014a49 270 if (_endpointMap[i] == ep)
peterbarrett1967 0:5ad808014a49 271 return _endpointMap[i+1];
peterbarrett1967 0:5ad808014a49 272 if (_endpointMap[i] == 0xFF)
peterbarrett1967 0:5ad808014a49 273 break;
peterbarrett1967 0:5ad808014a49 274 }
peterbarrett1967 0:5ad808014a49 275 return -1;
peterbarrett1967 0:5ad808014a49 276 }
peterbarrett1967 0:5ad808014a49 277 };
peterbarrett1967 0:5ad808014a49 278
peterbarrett1967 0:5ad808014a49 279 class HostController
peterbarrett1967 0:5ad808014a49 280 {
peterbarrett1967 0:5ad808014a49 281 public:
peterbarrett1967 0:5ad808014a49 282 HCCA CommunicationArea;
peterbarrett1967 0:5ad808014a49 283 Endpoint Endpoints[MAX_ENDPOINTS_TOTAL]; // Multiple of 16
peterbarrett1967 0:5ad808014a49 284
peterbarrett1967 0:5ad808014a49 285 Endpoint EndpointZero; // For device enumeration
peterbarrett1967 0:5ad808014a49 286 HCTD _commonTail;
peterbarrett1967 0:5ad808014a49 287 Setup _setupZero;
peterbarrett1967 0:5ad808014a49 288
peterbarrett1967 0:5ad808014a49 289 Device Devices[MAX_DEVICES];
peterbarrett1967 0:5ad808014a49 290 u32 _frameNumber; // 32 bit ms counter
peterbarrett1967 0:5ad808014a49 291
peterbarrett1967 0:5ad808014a49 292 u8 _callbacksPending; // Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue
peterbarrett1967 0:5ad808014a49 293 u8 _rootHubStatusChange; // Root hub status has changed, set from ISR
peterbarrett1967 0:5ad808014a49 294 u8 _unused0;
peterbarrett1967 0:5ad808014a49 295 u8 _unused1;
peterbarrett1967 0:5ad808014a49 296
peterbarrett1967 0:5ad808014a49 297 u8 _connectPending; // Reset has initiated a connect
peterbarrett1967 0:5ad808014a49 298 u8 _connectCountdown; // Number of ms left after reset before we can connect
peterbarrett1967 0:5ad808014a49 299 u8 _connectHub; // Will connect on this hub
peterbarrett1967 0:5ad808014a49 300 u8 _connectPort; // ... and this port
peterbarrett1967 0:5ad808014a49 301
peterbarrett1967 0:5ad808014a49 302 u8 SRAM[0]; // Start of free SRAM
peterbarrett1967 0:5ad808014a49 303
peterbarrett1967 0:5ad808014a49 304 void Loop()
peterbarrett1967 0:5ad808014a49 305 {
peterbarrett1967 0:5ad808014a49 306 u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber; // extend to 32 bits
peterbarrett1967 0:5ad808014a49 307 _frameNumber += elapsed;
peterbarrett1967 0:5ad808014a49 308
peterbarrett1967 0:5ad808014a49 309 // Do callbacks, if any
peterbarrett1967 0:5ad808014a49 310 while (_callbacksPending)
peterbarrett1967 0:5ad808014a49 311 {
peterbarrett1967 0:5ad808014a49 312 for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++)
peterbarrett1967 0:5ad808014a49 313 {
peterbarrett1967 0:5ad808014a49 314 Endpoint* endpoint = Endpoints + i;
peterbarrett1967 0:5ad808014a49 315 if (endpoint->CurrentState == Endpoint::CallbackPending)
peterbarrett1967 0:5ad808014a49 316 {
peterbarrett1967 0:5ad808014a49 317 _callbacksPending--;
peterbarrett1967 0:5ad808014a49 318 endpoint->CurrentState = Endpoint::Idle;
peterbarrett1967 0:5ad808014a49 319 endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData);
peterbarrett1967 0:5ad808014a49 320 }
peterbarrett1967 0:5ad808014a49 321 }
peterbarrett1967 0:5ad808014a49 322 }
peterbarrett1967 0:5ad808014a49 323
peterbarrett1967 0:5ad808014a49 324 // Deal with changes on the root hub
peterbarrett1967 0:5ad808014a49 325 if (_rootHubStatusChange)
peterbarrett1967 0:5ad808014a49 326 {
peterbarrett1967 0:5ad808014a49 327 u32 status = LPC_USB->HcRhPortStatus1;
peterbarrett1967 0:5ad808014a49 328 _rootHubStatusChange = 0;
peterbarrett1967 0:5ad808014a49 329 if (status >> 16)
peterbarrett1967 0:5ad808014a49 330 {
peterbarrett1967 0:5ad808014a49 331 HubStatusChange(0,1,status);
peterbarrett1967 0:5ad808014a49 332 LPC_USB->HcRhPortStatus1 = status & 0xFFFF0000; // clear status changes
peterbarrett1967 0:5ad808014a49 333 }
peterbarrett1967 0:5ad808014a49 334 }
peterbarrett1967 0:5ad808014a49 335
peterbarrett1967 0:5ad808014a49 336 // Connect after reset timeout
peterbarrett1967 0:5ad808014a49 337 if (_connectCountdown)
peterbarrett1967 0:5ad808014a49 338 {
peterbarrett1967 0:5ad808014a49 339 if (elapsed >= _connectCountdown)
peterbarrett1967 0:5ad808014a49 340 {
peterbarrett1967 0:5ad808014a49 341 _connectCountdown = 0;
peterbarrett1967 0:5ad808014a49 342 Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80);
peterbarrett1967 0:5ad808014a49 343 } else
peterbarrett1967 0:5ad808014a49 344 _connectCountdown -= elapsed;
peterbarrett1967 0:5ad808014a49 345 }
peterbarrett1967 0:5ad808014a49 346 }
peterbarrett1967 0:5ad808014a49 347
peterbarrett1967 0:5ad808014a49 348 // HubInterrupt - bitmap in dev->HubInterruptData
peterbarrett1967 0:5ad808014a49 349 void HubInterrupt(int device)
peterbarrett1967 0:5ad808014a49 350 {
peterbarrett1967 0:5ad808014a49 351 Device* dev = &Devices[device-1];
peterbarrett1967 0:5ad808014a49 352 for (int i = 0; i < dev->HubPortCount; i++)
peterbarrett1967 0:5ad808014a49 353 {
peterbarrett1967 0:5ad808014a49 354 int port = i+1;
peterbarrett1967 0:5ad808014a49 355 if (dev->HubInterruptData & (1 << port))
peterbarrett1967 0:5ad808014a49 356 {
peterbarrett1967 0:5ad808014a49 357 u32 status = 0;
peterbarrett1967 0:5ad808014a49 358 GetPortStatus(device,port,&status);
peterbarrett1967 0:5ad808014a49 359 if (status >> 16)
peterbarrett1967 0:5ad808014a49 360 {
peterbarrett1967 0:5ad808014a49 361 if (_connectPending && (status & ConnectStatusChange))
peterbarrett1967 0:5ad808014a49 362 continue; // Don't connect again until previous device has been added and addressed
peterbarrett1967 0:5ad808014a49 363
peterbarrett1967 0:5ad808014a49 364 HubStatusChange(device,port,status);
peterbarrett1967 0:5ad808014a49 365 if (status & ConnectStatusChange)
peterbarrett1967 0:5ad808014a49 366 ClearPortFeature(device,C_PORT_CONNECTION,port);
peterbarrett1967 0:5ad808014a49 367 if (status & PortResetStatusChange)
peterbarrett1967 0:5ad808014a49 368 ClearPortFeature(device,C_PORT_RESET,port);
peterbarrett1967 0:5ad808014a49 369 }
peterbarrett1967 0:5ad808014a49 370 }
peterbarrett1967 0:5ad808014a49 371 }
peterbarrett1967 0:5ad808014a49 372 }
peterbarrett1967 0:5ad808014a49 373
peterbarrett1967 0:5ad808014a49 374 static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
peterbarrett1967 0:5ad808014a49 375 {
peterbarrett1967 0:5ad808014a49 376 HostController* controller = (HostController*)userData;
peterbarrett1967 0:5ad808014a49 377 if (status == 0)
peterbarrett1967 0:5ad808014a49 378 controller->HubInterrupt(device);
peterbarrett1967 0:5ad808014a49 379 USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData);
peterbarrett1967 0:5ad808014a49 380 }
peterbarrett1967 0:5ad808014a49 381
peterbarrett1967 0:5ad808014a49 382 int InitHub(int device)
peterbarrett1967 0:5ad808014a49 383 {
peterbarrett1967 0:5ad808014a49 384 u8 buf[16];
peterbarrett1967 0:5ad808014a49 385 int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf));
peterbarrett1967 0:5ad808014a49 386 if (r < 0)
peterbarrett1967 0:5ad808014a49 387 return ERR_HUB_INIT_FAILED;
peterbarrett1967 0:5ad808014a49 388
peterbarrett1967 0:5ad808014a49 389 // turn on power on the hubs ports
peterbarrett1967 0:5ad808014a49 390 Device* dev = &Devices[device-1];
peterbarrett1967 0:5ad808014a49 391 int ports = buf[2];
peterbarrett1967 0:5ad808014a49 392 dev->HubPortCount = ports;
peterbarrett1967 0:5ad808014a49 393 for (int i = 0; i < ports; i++)
peterbarrett1967 0:5ad808014a49 394 SetPortPower(device,i+1);
peterbarrett1967 0:5ad808014a49 395
peterbarrett1967 0:5ad808014a49 396 // Enable hub change interrupts
peterbarrett1967 0:5ad808014a49 397 return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this);
peterbarrett1967 0:5ad808014a49 398 }
peterbarrett1967 0:5ad808014a49 399
peterbarrett1967 0:5ad808014a49 400 int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval)
peterbarrett1967 0:5ad808014a49 401 {
peterbarrett1967 0:5ad808014a49 402 LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\n",device,ep,attributes,maxPacketSize,interval);
peterbarrett1967 0:5ad808014a49 403 Device* dev = &Devices[device-1];
peterbarrett1967 0:5ad808014a49 404 Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize);
peterbarrett1967 0:5ad808014a49 405 if (!endpoint)
peterbarrett1967 0:5ad808014a49 406 return ERR_ENDPOINT_NONE_LEFT;
peterbarrett1967 0:5ad808014a49 407 dev->SetEndpointIndex(ep,endpoint - Endpoints);
peterbarrett1967 0:5ad808014a49 408 endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed
peterbarrett1967 0:5ad808014a49 409 return 0; // TODO ed->bInterval
peterbarrett1967 0:5ad808014a49 410 }
peterbarrett1967 0:5ad808014a49 411
peterbarrett1967 0:5ad808014a49 412 int AddEndpoint(int device, EndpointDescriptor* ed)
peterbarrett1967 0:5ad808014a49 413 {
peterbarrett1967 0:5ad808014a49 414 return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval);
peterbarrett1967 0:5ad808014a49 415 }
peterbarrett1967 0:5ad808014a49 416
peterbarrett1967 0:5ad808014a49 417 // allocate a endpoint
peterbarrett1967 0:5ad808014a49 418 Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize)
peterbarrett1967 0:5ad808014a49 419 {
peterbarrett1967 0:5ad808014a49 420 for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++)
peterbarrett1967 0:5ad808014a49 421 {
peterbarrett1967 0:5ad808014a49 422 Endpoint* ep = &Endpoints[i];
peterbarrett1967 0:5ad808014a49 423 if (ep->CurrentState == 0)
peterbarrett1967 0:5ad808014a49 424 {
peterbarrett1967 0:5ad808014a49 425 //LOG("Allocated endpoint %d to %02X:%02X\n",i,device,endpointAddress);
peterbarrett1967 0:5ad808014a49 426 ep->Flags = (endpointAddress & 0x80) | (type & 3);
peterbarrett1967 0:5ad808014a49 427 ep->CurrentState = Endpoint::NotQueued;
peterbarrett1967 0:5ad808014a49 428 ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device;
peterbarrett1967 0:5ad808014a49 429 return ep;
peterbarrett1967 0:5ad808014a49 430 }
peterbarrett1967 0:5ad808014a49 431 }
peterbarrett1967 0:5ad808014a49 432 return 0;
peterbarrett1967 0:5ad808014a49 433 }
peterbarrett1967 0:5ad808014a49 434
peterbarrett1967 0:5ad808014a49 435 Endpoint* GetEndpoint(int device, int ep)
peterbarrett1967 0:5ad808014a49 436 {
peterbarrett1967 0:5ad808014a49 437 if (device == 0)
peterbarrett1967 0:5ad808014a49 438 {
peterbarrett1967 0:5ad808014a49 439 //printf("WARNING: USING DEVICE 0\n");
peterbarrett1967 0:5ad808014a49 440 return &EndpointZero;
peterbarrett1967 0:5ad808014a49 441 }
peterbarrett1967 0:5ad808014a49 442 if (device > MAX_DEVICES)
peterbarrett1967 0:5ad808014a49 443 return 0;
peterbarrett1967 0:5ad808014a49 444 int i = Devices[device-1].GetEndpointIndex(ep);
peterbarrett1967 0:5ad808014a49 445 if (i == -1)
peterbarrett1967 0:5ad808014a49 446 return 0;
peterbarrett1967 0:5ad808014a49 447 return Endpoints + i;
peterbarrett1967 0:5ad808014a49 448 }
peterbarrett1967 0:5ad808014a49 449
peterbarrett1967 0:5ad808014a49 450 int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state)
peterbarrett1967 0:5ad808014a49 451 {
peterbarrett1967 0:5ad808014a49 452 //LOG("Transfer %02X T:%d Len:%d S:%d\n",endpoint->Address(),token,len,state);
peterbarrett1967 0:5ad808014a49 453
peterbarrett1967 0:5ad808014a49 454 int toggle = 0;
peterbarrett1967 0:5ad808014a49 455 if (endpoint->Address() == 0)
peterbarrett1967 0:5ad808014a49 456 toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1;
peterbarrett1967 0:5ad808014a49 457
peterbarrett1967 0:5ad808014a49 458 if (token != TOKEN_SETUP)
peterbarrett1967 0:5ad808014a49 459 token = (token == TOKEN_IN ? TD_IN : TD_OUT);
peterbarrett1967 0:5ad808014a49 460
peterbarrett1967 0:5ad808014a49 461 HCTD* head = &endpoint->TDHead;
peterbarrett1967 0:5ad808014a49 462 HCTD* tail = &_commonTail;
peterbarrett1967 0:5ad808014a49 463
peterbarrett1967 0:5ad808014a49 464 head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC;
peterbarrett1967 0:5ad808014a49 465 head->CurrBufPtr = (u32)data;
peterbarrett1967 0:5ad808014a49 466 head->BufEnd = (u32)(data + len - 1);
peterbarrett1967 0:5ad808014a49 467 head->Next = (u32)tail;
peterbarrett1967 0:5ad808014a49 468
peterbarrett1967 0:5ad808014a49 469 HCED* ed = &endpoint->EndpointDescriptor;
peterbarrett1967 0:5ad808014a49 470 ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002); // carry toggle
peterbarrett1967 0:5ad808014a49 471 ed->TailTd = (u32)tail;
peterbarrett1967 0:5ad808014a49 472
peterbarrett1967 0:5ad808014a49 473 //HCTD* td = head;
peterbarrett1967 0:5ad808014a49 474 //LOG("%04X TD %08X %08X %08X Next:%08X\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next);
peterbarrett1967 0:5ad808014a49 475 //LOG("%04X ED %08X %08X %08X\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd);
peterbarrett1967 0:5ad808014a49 476
peterbarrett1967 0:5ad808014a49 477 switch (endpoint->Flags & 3)
peterbarrett1967 0:5ad808014a49 478 {
peterbarrett1967 0:5ad808014a49 479 case ENDPOINT_CONTROL:
peterbarrett1967 0:5ad808014a49 480 LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED); // May change state NotQueued->Idle
peterbarrett1967 0:5ad808014a49 481 endpoint->CurrentState = state; // Get in before an int
peterbarrett1967 0:5ad808014a49 482 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled;
peterbarrett1967 0:5ad808014a49 483 LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable;
peterbarrett1967 0:5ad808014a49 484 break;
peterbarrett1967 0:5ad808014a49 485
peterbarrett1967 0:5ad808014a49 486 case ENDPOINT_BULK:
peterbarrett1967 0:5ad808014a49 487 LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED);
peterbarrett1967 0:5ad808014a49 488 endpoint->CurrentState = state;
peterbarrett1967 0:5ad808014a49 489 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled;
peterbarrett1967 0:5ad808014a49 490 LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable;
peterbarrett1967 0:5ad808014a49 491 break;
peterbarrett1967 0:5ad808014a49 492
peterbarrett1967 0:5ad808014a49 493 case ENDPOINT_INTERRUPT:
peterbarrett1967 0:5ad808014a49 494 CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]);
peterbarrett1967 0:5ad808014a49 495 endpoint->CurrentState = state;
peterbarrett1967 0:5ad808014a49 496 LPC_USB->HcControl |= PeriodicListEnable;
peterbarrett1967 0:5ad808014a49 497 break;
peterbarrett1967 0:5ad808014a49 498 }
peterbarrett1967 0:5ad808014a49 499 return 0;
peterbarrett1967 0:5ad808014a49 500 }
peterbarrett1967 0:5ad808014a49 501
peterbarrett1967 0:5ad808014a49 502 // Remove an endpoint from an active queue
peterbarrett1967 0:5ad808014a49 503 bool Remove(HCED* ed, volatile HCED** queue)
peterbarrett1967 0:5ad808014a49 504 {
peterbarrett1967 0:5ad808014a49 505 if (*queue == 0)
peterbarrett1967 0:5ad808014a49 506 return false;
peterbarrett1967 0:5ad808014a49 507 if (*queue == (volatile HCED*)ed)
peterbarrett1967 0:5ad808014a49 508 {
peterbarrett1967 0:5ad808014a49 509 *queue = (volatile HCED*)ed->Next; // At head of queue
peterbarrett1967 0:5ad808014a49 510 return true;
peterbarrett1967 0:5ad808014a49 511 }
peterbarrett1967 0:5ad808014a49 512
peterbarrett1967 0:5ad808014a49 513 volatile HCED* head = *queue;
peterbarrett1967 0:5ad808014a49 514 while (head)
peterbarrett1967 0:5ad808014a49 515 {
peterbarrett1967 0:5ad808014a49 516 if (head->Next == (u32)ed)
peterbarrett1967 0:5ad808014a49 517 {
peterbarrett1967 0:5ad808014a49 518 head->Next = ed->Next;
peterbarrett1967 0:5ad808014a49 519 return true;
peterbarrett1967 0:5ad808014a49 520 }
peterbarrett1967 0:5ad808014a49 521 head = (volatile HCED*)head->Next;
peterbarrett1967 0:5ad808014a49 522 }
peterbarrett1967 0:5ad808014a49 523 return false;
peterbarrett1967 0:5ad808014a49 524 }
peterbarrett1967 0:5ad808014a49 525
peterbarrett1967 0:5ad808014a49 526 void Release(Endpoint* endpoint)
peterbarrett1967 0:5ad808014a49 527 {
peterbarrett1967 0:5ad808014a49 528 if (endpoint->CurrentState == Endpoint::NotQueued)
peterbarrett1967 0:5ad808014a49 529 {
peterbarrett1967 0:5ad808014a49 530 // Never event used it, nothing to do
peterbarrett1967 0:5ad808014a49 531 }
peterbarrett1967 0:5ad808014a49 532 else
peterbarrett1967 0:5ad808014a49 533 {
peterbarrett1967 0:5ad808014a49 534 HCED* ed = (HCED*)endpoint;
peterbarrett1967 0:5ad808014a49 535 ed->Control |= 0x4000; // SKIP
peterbarrett1967 0:5ad808014a49 536 switch (endpoint->Flags & 0x03)
peterbarrett1967 0:5ad808014a49 537 {
peterbarrett1967 0:5ad808014a49 538 case ENDPOINT_CONTROL:
peterbarrett1967 0:5ad808014a49 539 Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED);
peterbarrett1967 0:5ad808014a49 540 break;
peterbarrett1967 0:5ad808014a49 541 case ENDPOINT_BULK:
peterbarrett1967 0:5ad808014a49 542 Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED);
peterbarrett1967 0:5ad808014a49 543 break;
peterbarrett1967 0:5ad808014a49 544 case ENDPOINT_INTERRUPT:
peterbarrett1967 0:5ad808014a49 545 for (int i = 0; i < 32; i++)
peterbarrett1967 0:5ad808014a49 546 Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]);
peterbarrett1967 0:5ad808014a49 547 break;
peterbarrett1967 0:5ad808014a49 548 }
peterbarrett1967 0:5ad808014a49 549
peterbarrett1967 0:5ad808014a49 550 u16 fn = CommunicationArea.FrameNumber;
peterbarrett1967 0:5ad808014a49 551 while (fn == CommunicationArea.FrameNumber)
peterbarrett1967 0:5ad808014a49 552 ; // Wait for next frame
peterbarrett1967 0:5ad808014a49 553
peterbarrett1967 0:5ad808014a49 554 }
peterbarrett1967 0:5ad808014a49 555
peterbarrett1967 0:5ad808014a49 556 // In theory, the endpoint is now dead.
peterbarrett1967 0:5ad808014a49 557 // TODO: Will Callbacks ever be pending? BUGBUG
peterbarrett1967 0:5ad808014a49 558 memset(endpoint,0,sizeof(Endpoint));
peterbarrett1967 0:5ad808014a49 559 }
peterbarrett1967 0:5ad808014a49 560
peterbarrett1967 0:5ad808014a49 561 // Pop the last TD from the list
peterbarrett1967 0:5ad808014a49 562 HCTD* Reverse(HCTD* current)
peterbarrett1967 0:5ad808014a49 563 {
peterbarrett1967 0:5ad808014a49 564 HCTD *result = NULL,*temp;
peterbarrett1967 0:5ad808014a49 565 while (current)
peterbarrett1967 0:5ad808014a49 566 {
peterbarrett1967 0:5ad808014a49 567 temp = (HCTD*)current->Next;
peterbarrett1967 0:5ad808014a49 568 current->Next = (u32)result;
peterbarrett1967 0:5ad808014a49 569 result = current;
peterbarrett1967 0:5ad808014a49 570 current = temp;
peterbarrett1967 0:5ad808014a49 571 }
peterbarrett1967 0:5ad808014a49 572 return result;
peterbarrett1967 0:5ad808014a49 573 }
peterbarrett1967 0:5ad808014a49 574
peterbarrett1967 0:5ad808014a49 575 // Called from interrupt...
peterbarrett1967 0:5ad808014a49 576 // Control endpoints use a state machine to progress through the transfers
peterbarrett1967 0:5ad808014a49 577 void ProcessDoneQueue(u32 tdList)
peterbarrett1967 0:5ad808014a49 578 {
peterbarrett1967 0:5ad808014a49 579 HCTD* list = Reverse((HCTD*)tdList);
peterbarrett1967 0:5ad808014a49 580 while (list)
peterbarrett1967 0:5ad808014a49 581 {
peterbarrett1967 0:5ad808014a49 582 Endpoint* endpoint = (Endpoint*)(list-1);
peterbarrett1967 0:5ad808014a49 583 list = (HCTD*)list->Next;
peterbarrett1967 0:5ad808014a49 584 int ep = endpoint->Address();
peterbarrett1967 0:5ad808014a49 585 bool in = endpoint->Flags & 0x80;
peterbarrett1967 0:5ad808014a49 586 int status = (endpoint->TDHead.Control >> 28) & 0xF;
peterbarrett1967 0:5ad808014a49 587
peterbarrett1967 0:5ad808014a49 588 //LOG("ProcessDoneQueue %02X %08X\n",ep,endpoint->TDHead.Control);
peterbarrett1967 0:5ad808014a49 589
peterbarrett1967 0:5ad808014a49 590 if (status != 0)
peterbarrett1967 0:5ad808014a49 591 {
peterbarrett1967 0:5ad808014a49 592 LOG("ProcessDoneQueue status %02X %d\n",ep,status);
peterbarrett1967 0:5ad808014a49 593 endpoint->CurrentState = Endpoint::Idle;
peterbarrett1967 0:5ad808014a49 594 } else {
peterbarrett1967 0:5ad808014a49 595 switch (endpoint->CurrentState)
peterbarrett1967 0:5ad808014a49 596 {
peterbarrett1967 0:5ad808014a49 597 case Endpoint::SetupQueued:
peterbarrett1967 0:5ad808014a49 598 if (endpoint->Length == 0)
peterbarrett1967 0:5ad808014a49 599 Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Skip Data Phase
peterbarrett1967 0:5ad808014a49 600 else
peterbarrett1967 0:5ad808014a49 601 Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued); // Setup is done, now Data
peterbarrett1967 0:5ad808014a49 602 break;
peterbarrett1967 0:5ad808014a49 603
peterbarrett1967 0:5ad808014a49 604 case Endpoint::DataQueued:
peterbarrett1967 0:5ad808014a49 605 if (endpoint->TDHead.CurrBufPtr)
peterbarrett1967 0:5ad808014a49 606 endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data;
peterbarrett1967 0:5ad808014a49 607
peterbarrett1967 0:5ad808014a49 608 if (ep == 0)
peterbarrett1967 0:5ad808014a49 609 Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Data is done, now Status, Control only
peterbarrett1967 0:5ad808014a49 610 else
peterbarrett1967 0:5ad808014a49 611 endpoint->CurrentState = Endpoint::Idle;
peterbarrett1967 0:5ad808014a49 612 break;
peterbarrett1967 0:5ad808014a49 613
peterbarrett1967 0:5ad808014a49 614 case Endpoint::StatusQueued: // Transaction is done
peterbarrett1967 0:5ad808014a49 615 endpoint->CurrentState = Endpoint::Idle;
peterbarrett1967 0:5ad808014a49 616 break;
peterbarrett1967 0:5ad808014a49 617 }
peterbarrett1967 0:5ad808014a49 618 }
peterbarrett1967 0:5ad808014a49 619
peterbarrett1967 0:5ad808014a49 620 // Complete, flag if we need a callback
peterbarrett1967 0:5ad808014a49 621 if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle)
peterbarrett1967 0:5ad808014a49 622 {
peterbarrett1967 0:5ad808014a49 623 endpoint->CurrentState = Endpoint::CallbackPending;
peterbarrett1967 0:5ad808014a49 624 _callbacksPending++;
peterbarrett1967 0:5ad808014a49 625 }
peterbarrett1967 0:5ad808014a49 626 }
peterbarrett1967 0:5ad808014a49 627 }
peterbarrett1967 0:5ad808014a49 628
peterbarrett1967 0:5ad808014a49 629 // Hack to reset devices that don't want to connect
peterbarrett1967 0:5ad808014a49 630 int AddDevice(int hub, int port, bool isLowSpeed)
peterbarrett1967 0:5ad808014a49 631 {
peterbarrett1967 0:5ad808014a49 632 int device = AddDeviceCore(hub,port,isLowSpeed);
peterbarrett1967 0:5ad808014a49 633 if (device < 0)
peterbarrett1967 0:5ad808014a49 634 {
peterbarrett1967 0:5ad808014a49 635 LOG("========RETRY ADD DEVICE========\n"); // This will go for ever.. TODO power cycle root?
peterbarrett1967 0:5ad808014a49 636 Disconnect(hub,port); // Could not read descriptor at assigned address, reset this port and try again
peterbarrett1967 0:5ad808014a49 637 ResetPort(hub,port); // Cheap bluetooth dongles often need this on a hotplug
peterbarrett1967 0:5ad808014a49 638 return -1;
peterbarrett1967 0:5ad808014a49 639 }
peterbarrett1967 0:5ad808014a49 640 return device;
peterbarrett1967 0:5ad808014a49 641 }
peterbarrett1967 0:5ad808014a49 642
peterbarrett1967 0:5ad808014a49 643 int AddDeviceCore(int hub, int port, bool isLowSpeed)
peterbarrett1967 0:5ad808014a49 644 {
peterbarrett1967 0:5ad808014a49 645 int lowSpeed = isLowSpeed ? 0x2000 : 0;
peterbarrett1967 0:5ad808014a49 646 DeviceDescriptor desc;
peterbarrett1967 0:5ad808014a49 647 EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed; // MaxPacketSize == 8
peterbarrett1967 0:5ad808014a49 648 int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8);
peterbarrett1967 0:5ad808014a49 649 if (r < 0)
peterbarrett1967 0:5ad808014a49 650 {
peterbarrett1967 0:5ad808014a49 651 LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\n");
peterbarrett1967 0:5ad808014a49 652 return r;
peterbarrett1967 0:5ad808014a49 653 }
peterbarrett1967 0:5ad808014a49 654
peterbarrett1967 0:5ad808014a49 655 EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed; // Actual MaxPacketSize
peterbarrett1967 0:5ad808014a49 656 r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc));
peterbarrett1967 0:5ad808014a49 657 if (r < 0)
peterbarrett1967 0:5ad808014a49 658 return r;
peterbarrett1967 0:5ad808014a49 659
peterbarrett1967 0:5ad808014a49 660 LOG("\nClass %02X found %04X:%04X\n\n",desc.bDeviceClass,desc.idVendor,desc.idProduct);
peterbarrett1967 0:5ad808014a49 661
peterbarrett1967 0:5ad808014a49 662 // Now assign the device an address, move off EndpointZero
peterbarrett1967 0:5ad808014a49 663 int device = 0;
peterbarrett1967 0:5ad808014a49 664 for (int i = 0; i < MAX_DEVICES; i++)
peterbarrett1967 0:5ad808014a49 665 {
peterbarrett1967 0:5ad808014a49 666 if (Devices[i].Port == 0)
peterbarrett1967 0:5ad808014a49 667 {
peterbarrett1967 0:5ad808014a49 668 device = i+1;
peterbarrett1967 0:5ad808014a49 669 break;
peterbarrett1967 0:5ad808014a49 670 }
peterbarrett1967 0:5ad808014a49 671 }
peterbarrett1967 0:5ad808014a49 672 if (!device)
peterbarrett1967 0:5ad808014a49 673 return ERR_DEVICE_NONE_LEFT;
peterbarrett1967 0:5ad808014a49 674
peterbarrett1967 0:5ad808014a49 675 r = SetAddress(0,device);
peterbarrett1967 0:5ad808014a49 676 if (r)
peterbarrett1967 0:5ad808014a49 677 return r;
peterbarrett1967 0:5ad808014a49 678 DelayMS(2);
peterbarrett1967 0:5ad808014a49 679
peterbarrett1967 0:5ad808014a49 680 // Now at a nonzero address, create control endpoint
peterbarrett1967 0:5ad808014a49 681 Device* dev = &Devices[device-1];
peterbarrett1967 0:5ad808014a49 682 dev->Init(&desc,hub,port,device,lowSpeed);
peterbarrett1967 0:5ad808014a49 683 AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0);
peterbarrett1967 0:5ad808014a49 684 _connectPending = 0;
peterbarrett1967 0:5ad808014a49 685
peterbarrett1967 0:5ad808014a49 686 // Verify this all works
peterbarrett1967 0:5ad808014a49 687 r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc));
peterbarrett1967 0:5ad808014a49 688 if (r < 0)
peterbarrett1967 0:5ad808014a49 689 return r;
peterbarrett1967 0:5ad808014a49 690
peterbarrett1967 0:5ad808014a49 691 // Set to interface 0 by default
peterbarrett1967 0:5ad808014a49 692 // Calls LoadDevice if interface is found
peterbarrett1967 0:5ad808014a49 693 r = SetConfigurationAndInterface(device,1,0,&desc);
peterbarrett1967 0:5ad808014a49 694
peterbarrett1967 0:5ad808014a49 695 if (desc.bDeviceClass == CLASS_HUB)
peterbarrett1967 0:5ad808014a49 696 InitHub(device); // Handle hubs in this code
peterbarrett1967 0:5ad808014a49 697
peterbarrett1967 0:5ad808014a49 698 return device;
peterbarrett1967 0:5ad808014a49 699 }
peterbarrett1967 0:5ad808014a49 700
peterbarrett1967 0:5ad808014a49 701 // Walk descriptors and create endpoints for a given device
peterbarrett1967 0:5ad808014a49 702 // TODO configuration !=1, alternate settings etc.
peterbarrett1967 0:5ad808014a49 703 int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc)
peterbarrett1967 0:5ad808014a49 704 {
peterbarrett1967 0:5ad808014a49 705 u8 buffer[255];
peterbarrett1967 0:5ad808014a49 706 int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer));
peterbarrett1967 0:5ad808014a49 707 if (err < 0)
peterbarrett1967 0:5ad808014a49 708 return err;
peterbarrett1967 0:5ad808014a49 709
peterbarrett1967 0:5ad808014a49 710 err = SetConfiguration(device,configuration);
peterbarrett1967 0:5ad808014a49 711 if (err < 0)
peterbarrett1967 0:5ad808014a49 712 return err;
peterbarrett1967 0:5ad808014a49 713
peterbarrett1967 0:5ad808014a49 714 // Add the endpoints for this interface
peterbarrett1967 0:5ad808014a49 715 int len = buffer[2] | (buffer[3] << 8);
peterbarrett1967 0:5ad808014a49 716 u8* d = buffer;
peterbarrett1967 0:5ad808014a49 717 u8* end = d + len;
peterbarrett1967 0:5ad808014a49 718 InterfaceDescriptor* found = 0;
peterbarrett1967 0:5ad808014a49 719 while (d < end)
peterbarrett1967 0:5ad808014a49 720 {
peterbarrett1967 0:5ad808014a49 721 if (d[1] == DESCRIPTOR_TYPE_INTERFACE)
peterbarrett1967 0:5ad808014a49 722 {
peterbarrett1967 0:5ad808014a49 723 InterfaceDescriptor* id = (InterfaceDescriptor*)d;
peterbarrett1967 0:5ad808014a49 724 if (id->bInterfaceNumber == interfaceNumber)
peterbarrett1967 0:5ad808014a49 725 {
peterbarrett1967 0:5ad808014a49 726 found = id;
peterbarrett1967 0:5ad808014a49 727 d += d[0];
peterbarrett1967 0:5ad808014a49 728 while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE)
peterbarrett1967 0:5ad808014a49 729 {
peterbarrett1967 0:5ad808014a49 730 switch (d[1])
peterbarrett1967 0:5ad808014a49 731 {
peterbarrett1967 0:5ad808014a49 732 case DESCRIPTOR_TYPE_ENDPOINT:
peterbarrett1967 0:5ad808014a49 733 AddEndpoint(device,(EndpointDescriptor*)d);
peterbarrett1967 0:5ad808014a49 734 break;
peterbarrett1967 0:5ad808014a49 735 default:
peterbarrett1967 0:5ad808014a49 736 LOG("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]);
peterbarrett1967 0:5ad808014a49 737 }
peterbarrett1967 0:5ad808014a49 738 d += d[0];
peterbarrett1967 0:5ad808014a49 739 }
peterbarrett1967 0:5ad808014a49 740 }
peterbarrett1967 0:5ad808014a49 741 }
peterbarrett1967 0:5ad808014a49 742 d += d[0];
peterbarrett1967 0:5ad808014a49 743 }
peterbarrett1967 0:5ad808014a49 744
peterbarrett1967 0:5ad808014a49 745 if (!found)
peterbarrett1967 0:5ad808014a49 746 return ERR_INTERFACE_NOT_FOUND;
peterbarrett1967 0:5ad808014a49 747 OnLoadDevice(device,desc,found);
peterbarrett1967 0:5ad808014a49 748 return 0;
peterbarrett1967 0:5ad808014a49 749 }
peterbarrett1967 0:5ad808014a49 750
peterbarrett1967 0:5ad808014a49 751 void Init()
peterbarrett1967 0:5ad808014a49 752 {
peterbarrett1967 0:5ad808014a49 753 LOG("USB INIT (Controller is %d bytes)\n",sizeof(*this));
peterbarrett1967 0:5ad808014a49 754 memset(this,0,sizeof(HostController));
peterbarrett1967 0:5ad808014a49 755 EndpointZero.CurrentState = Endpoint::NotQueued;
peterbarrett1967 0:5ad808014a49 756 HWInit(&CommunicationArea);
peterbarrett1967 0:5ad808014a49 757 DelayMS(10);
peterbarrett1967 0:5ad808014a49 758 }
peterbarrett1967 0:5ad808014a49 759
peterbarrett1967 0:5ad808014a49 760 void ResetPort(int hub, int port)
peterbarrett1967 0:5ad808014a49 761 {
peterbarrett1967 0:5ad808014a49 762 LOG("ResetPort Hub:%d Port:%d\n",hub,port);
peterbarrett1967 0:5ad808014a49 763 _connectPending++; // Only reset/add 1 device at a time
peterbarrett1967 0:5ad808014a49 764 if (hub == 0)
peterbarrett1967 0:5ad808014a49 765 LPC_USB->HcRhPortStatus1 = PortResetStatus; // Reset Root Hub, port 1
peterbarrett1967 0:5ad808014a49 766 else
peterbarrett1967 0:5ad808014a49 767 SetPortReset(hub,port); // or reset other hub
peterbarrett1967 0:5ad808014a49 768 }
peterbarrett1967 0:5ad808014a49 769
peterbarrett1967 0:5ad808014a49 770 void Disconnect(int hub, int port)
peterbarrett1967 0:5ad808014a49 771 {
peterbarrett1967 0:5ad808014a49 772 LOG("Disconnect Hub:%d Port:%d\n",hub,port); // Mark a device for destruction
peterbarrett1967 0:5ad808014a49 773 for (int i = 0; i < MAX_DEVICES; i++)
peterbarrett1967 0:5ad808014a49 774 {
peterbarrett1967 0:5ad808014a49 775 Device* dev = Devices + i;
peterbarrett1967 0:5ad808014a49 776 if (dev->Port == port && dev->Hub == hub)
peterbarrett1967 0:5ad808014a49 777 {
peterbarrett1967 0:5ad808014a49 778 // Disconnect everything that is attached to this device if it is a hub
peterbarrett1967 0:5ad808014a49 779 for (int p = 0; p < dev->HubPortCount; p++)
peterbarrett1967 0:5ad808014a49 780 Disconnect(i+1,p+1);
peterbarrett1967 0:5ad808014a49 781
peterbarrett1967 0:5ad808014a49 782 // Now release endpoints
peterbarrett1967 0:5ad808014a49 783 for (int j = 1; j < MAX_ENDPOINTS_PER_DEVICE*2; j += 2)
peterbarrett1967 0:5ad808014a49 784 {
peterbarrett1967 0:5ad808014a49 785 u8 endpointIndex = dev->_endpointMap[j];
peterbarrett1967 0:5ad808014a49 786 if (endpointIndex != 0xFF)
peterbarrett1967 0:5ad808014a49 787 Release(Endpoints + endpointIndex);
peterbarrett1967 0:5ad808014a49 788 }
peterbarrett1967 0:5ad808014a49 789 dev->Port = 0; // Device is now free
peterbarrett1967 0:5ad808014a49 790 dev->Flags = 0;
peterbarrett1967 0:5ad808014a49 791 return;
peterbarrett1967 0:5ad808014a49 792 }
peterbarrett1967 0:5ad808014a49 793 }
peterbarrett1967 0:5ad808014a49 794 }
peterbarrett1967 0:5ad808014a49 795
peterbarrett1967 0:5ad808014a49 796 // called after reset
peterbarrett1967 0:5ad808014a49 797 void Connect(int hub, int port, bool lowspeed)
peterbarrett1967 0:5ad808014a49 798 {
peterbarrett1967 0:5ad808014a49 799 LOG("Connect Hub:%d Port:%d %s\n",hub,port,lowspeed ? "slow" : "full");
peterbarrett1967 0:5ad808014a49 800 AddDevice(hub,port,lowspeed);
peterbarrett1967 0:5ad808014a49 801 }
peterbarrett1967 0:5ad808014a49 802
peterbarrett1967 0:5ad808014a49 803 // Called from interrupt
peterbarrett1967 0:5ad808014a49 804 void HubStatusChange(int hub, int port, u32 status)
peterbarrett1967 0:5ad808014a49 805 {
peterbarrett1967 0:5ad808014a49 806 LOG("HubStatusChange Hub:%d Port:%d %08X\n",hub,port,status);
peterbarrett1967 0:5ad808014a49 807 if (status & ConnectStatusChange)
peterbarrett1967 0:5ad808014a49 808 {
peterbarrett1967 0:5ad808014a49 809 if (status & CurrentConnectStatus) // Connecting
peterbarrett1967 0:5ad808014a49 810 ResetPort(hub,port); // Reset to initiate connect (state machine?)
peterbarrett1967 0:5ad808014a49 811 else
peterbarrett1967 0:5ad808014a49 812 Disconnect(hub,port);
peterbarrett1967 0:5ad808014a49 813 }
peterbarrett1967 0:5ad808014a49 814
peterbarrett1967 0:5ad808014a49 815 if (status & PortResetStatusChange)
peterbarrett1967 0:5ad808014a49 816 {
peterbarrett1967 0:5ad808014a49 817 if (!(status & PortResetStatus))
peterbarrett1967 0:5ad808014a49 818 {
peterbarrett1967 0:5ad808014a49 819 _connectCountdown = 200; // Schedule a connection in 200ms
peterbarrett1967 0:5ad808014a49 820 if (status & LowspeedDevice)
peterbarrett1967 0:5ad808014a49 821 port |= 0x80;
peterbarrett1967 0:5ad808014a49 822 _connectHub = hub;
peterbarrett1967 0:5ad808014a49 823 _connectPort = port;
peterbarrett1967 0:5ad808014a49 824 }
peterbarrett1967 0:5ad808014a49 825 }
peterbarrett1967 0:5ad808014a49 826 }
peterbarrett1967 0:5ad808014a49 827
peterbarrett1967 0:5ad808014a49 828 #define HOST_CLK_EN (1<<0)
peterbarrett1967 0:5ad808014a49 829 #define PORTSEL_CLK_EN (1<<3)
peterbarrett1967 0:5ad808014a49 830 #define AHB_CLK_EN (1<<4)
peterbarrett1967 0:5ad808014a49 831 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
peterbarrett1967 0:5ad808014a49 832
peterbarrett1967 0:5ad808014a49 833 #define FRAMEINTERVAL (12000-1) // 1ms
peterbarrett1967 0:5ad808014a49 834 #define DEFAULT_FMINTERVAL ((((6 * (FRAMEINTERVAL - 210)) / 7) << 16) | FRAMEINTERVAL)
peterbarrett1967 0:5ad808014a49 835
peterbarrett1967 0:5ad808014a49 836 void DelayMS(int ms)
peterbarrett1967 0:5ad808014a49 837 {
peterbarrett1967 0:5ad808014a49 838 u16 f = ms + CommunicationArea.FrameNumber;
peterbarrett1967 0:5ad808014a49 839 while (f != CommunicationArea.FrameNumber)
peterbarrett1967 0:5ad808014a49 840 ;
peterbarrett1967 0:5ad808014a49 841 }
peterbarrett1967 0:5ad808014a49 842
peterbarrett1967 0:5ad808014a49 843 static void HWInit(HCCA* cca)
peterbarrett1967 0:5ad808014a49 844 {
peterbarrett1967 0:5ad808014a49 845 NVIC_DisableIRQ(USB_IRQn);
peterbarrett1967 0:5ad808014a49 846
peterbarrett1967 0:5ad808014a49 847 // turn on power for USB
peterbarrett1967 0:5ad808014a49 848 LPC_SC->PCONP |= (1UL<<31);
peterbarrett1967 0:5ad808014a49 849 // Enable USB host clock, port selection and AHB clock
peterbarrett1967 0:5ad808014a49 850 LPC_USB->USBClkCtrl |= CLOCK_MASK;
peterbarrett1967 0:5ad808014a49 851 // Wait for clocks to become available
peterbarrett1967 0:5ad808014a49 852 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
peterbarrett1967 0:5ad808014a49 853 ;
peterbarrett1967 0:5ad808014a49 854
peterbarrett1967 0:5ad808014a49 855 // We are a Host
peterbarrett1967 0:5ad808014a49 856 LPC_USB->OTGStCtrl |= 1;
peterbarrett1967 0:5ad808014a49 857 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; // we don't need port selection clock until we do OTG
peterbarrett1967 0:5ad808014a49 858
peterbarrett1967 0:5ad808014a49 859 // configure USB pins
peterbarrett1967 0:5ad808014a49 860 LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28));
peterbarrett1967 0:5ad808014a49 861 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // USB D+/D-
peterbarrett1967 0:5ad808014a49 862
peterbarrett1967 0:5ad808014a49 863 LPC_PINCON->PINSEL3 &= ~((3 << 6) | (3 << 22)); // USB_PPWR, USB_OVRCR
peterbarrett1967 0:5ad808014a49 864 LPC_PINCON->PINSEL3 |= ((2 << 6) | (2 << 22));
peterbarrett1967 0:5ad808014a49 865
peterbarrett1967 0:5ad808014a49 866 LPC_PINCON->PINSEL4 &= ~(3 << 18); // USB_CONNECT
peterbarrett1967 0:5ad808014a49 867 LPC_PINCON->PINSEL4 |= (1 << 18);
peterbarrett1967 0:5ad808014a49 868
peterbarrett1967 0:5ad808014a49 869 // Reset OHCI block
peterbarrett1967 0:5ad808014a49 870 LPC_USB->HcControl = 0;
peterbarrett1967 0:5ad808014a49 871 LPC_USB->HcControlHeadED = 0;
peterbarrett1967 0:5ad808014a49 872 LPC_USB->HcBulkHeadED = 0;
peterbarrett1967 0:5ad808014a49 873
peterbarrett1967 0:5ad808014a49 874 LPC_USB->HcCommandStatus = HostControllerReset;
peterbarrett1967 0:5ad808014a49 875 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL;
peterbarrett1967 0:5ad808014a49 876 LPC_USB->HcPeriodicStart = FRAMEINTERVAL*90/100;
peterbarrett1967 0:5ad808014a49 877
peterbarrett1967 0:5ad808014a49 878 LPC_USB->HcControl = (LPC_USB->HcControl & (~HostControllerFunctionalState)) | OperationalMask;
peterbarrett1967 0:5ad808014a49 879 LPC_USB->HcRhStatus = SetGlobalPower;
peterbarrett1967 0:5ad808014a49 880
peterbarrett1967 0:5ad808014a49 881 LPC_USB->HcHCCA = (u32)cca;
peterbarrett1967 0:5ad808014a49 882 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
peterbarrett1967 0:5ad808014a49 883 LPC_USB->HcInterruptEnable = MasterInterruptEnable | WritebackDoneHead | RootHubStatusChange | FrameNumberOverflow;
peterbarrett1967 0:5ad808014a49 884
peterbarrett1967 0:5ad808014a49 885 NVIC_SetPriority(USB_IRQn, 0);
peterbarrett1967 0:5ad808014a49 886 NVIC_EnableIRQ(USB_IRQn);
peterbarrett1967 0:5ad808014a49 887 while (cca->FrameNumber < 10)
peterbarrett1967 0:5ad808014a49 888 ; // 10ms delay before diving in
peterbarrett1967 0:5ad808014a49 889 }
peterbarrett1967 0:5ad808014a49 890 };
peterbarrett1967 0:5ad808014a49 891
peterbarrett1967 0:5ad808014a49 892 //====================================================================================
peterbarrett1967 0:5ad808014a49 893 //====================================================================================
peterbarrett1967 0:5ad808014a49 894 // Host controller instance and Interrupt handler
peterbarrett1967 0:5ad808014a49 895
peterbarrett1967 0:5ad808014a49 896 static HostController _controller __attribute__((at(USB_RAM_BASE)));
peterbarrett1967 0:5ad808014a49 897
peterbarrett1967 0:5ad808014a49 898 extern "C" void USB_IRQHandler(void) __irq;
peterbarrett1967 0:5ad808014a49 899 void USB_IRQHandler (void) __irq
peterbarrett1967 0:5ad808014a49 900 {
peterbarrett1967 0:5ad808014a49 901 u32 int_status = LPC_USB->HcInterruptStatus;
peterbarrett1967 0:5ad808014a49 902
peterbarrett1967 0:5ad808014a49 903 if (int_status & RootHubStatusChange) // Root hub status change
peterbarrett1967 0:5ad808014a49 904 _controller._rootHubStatusChange++; // Just flag the controller, will be processed in USBLoop
peterbarrett1967 0:5ad808014a49 905
peterbarrett1967 0:5ad808014a49 906 u32 head = 0;
peterbarrett1967 0:5ad808014a49 907 if (int_status & WritebackDoneHead)
peterbarrett1967 0:5ad808014a49 908 {
peterbarrett1967 0:5ad808014a49 909 head = _controller.CommunicationArea.DoneHead; // Writeback Done
peterbarrett1967 0:5ad808014a49 910 _controller.CommunicationArea.DoneHead = 0;
peterbarrett1967 0:5ad808014a49 911 }
peterbarrett1967 0:5ad808014a49 912 LPC_USB->HcInterruptStatus = int_status;
peterbarrett1967 0:5ad808014a49 913
peterbarrett1967 0:5ad808014a49 914 if (head)
peterbarrett1967 0:5ad808014a49 915 _controller.ProcessDoneQueue(head); // TODO - low bit can be set BUGBUG
peterbarrett1967 0:5ad808014a49 916 }
peterbarrett1967 0:5ad808014a49 917
peterbarrett1967 0:5ad808014a49 918 //====================================================================================
peterbarrett1967 0:5ad808014a49 919 //====================================================================================
peterbarrett1967 0:5ad808014a49 920 // API Methods
peterbarrett1967 0:5ad808014a49 921
peterbarrett1967 0:5ad808014a49 922 void USBInit()
peterbarrett1967 0:5ad808014a49 923 {
peterbarrett1967 0:5ad808014a49 924 return _controller.Init();
peterbarrett1967 0:5ad808014a49 925 }
peterbarrett1967 0:5ad808014a49 926
peterbarrett1967 0:5ad808014a49 927 void USBLoop()
peterbarrett1967 0:5ad808014a49 928 {
peterbarrett1967 0:5ad808014a49 929 return _controller.Loop();
peterbarrett1967 0:5ad808014a49 930 }
peterbarrett1967 0:5ad808014a49 931
peterbarrett1967 0:5ad808014a49 932 u8* USBGetBuffer(u32* len)
peterbarrett1967 0:5ad808014a49 933 {
peterbarrett1967 0:5ad808014a49 934 *len = USB_RAM_SIZE - sizeof(HostController);
peterbarrett1967 0:5ad808014a49 935 return _controller.SRAM;
peterbarrett1967 0:5ad808014a49 936 }
peterbarrett1967 0:5ad808014a49 937
peterbarrett1967 0:5ad808014a49 938 static Setup* GetSetup(int device)
peterbarrett1967 0:5ad808014a49 939 {
peterbarrett1967 0:5ad808014a49 940 if (device == 0)
peterbarrett1967 0:5ad808014a49 941 return &_controller._setupZero;
peterbarrett1967 0:5ad808014a49 942
peterbarrett1967 0:5ad808014a49 943 if (device < 1 || device > MAX_DEVICES)
peterbarrett1967 0:5ad808014a49 944 return 0;
peterbarrett1967 0:5ad808014a49 945 return &_controller.Devices[device-1].SetupBuffer;
peterbarrett1967 0:5ad808014a49 946 }
peterbarrett1967 0:5ad808014a49 947
peterbarrett1967 0:5ad808014a49 948 // Loop until IO on endpoint is complete
peterbarrett1967 0:5ad808014a49 949 static int WaitIODone(Endpoint* endpoint)
peterbarrett1967 0:5ad808014a49 950 {
peterbarrett1967 0:5ad808014a49 951 if (endpoint->CurrentState == Endpoint::NotQueued)
peterbarrett1967 0:5ad808014a49 952 return 0;
peterbarrett1967 0:5ad808014a49 953 while (endpoint->CurrentState != Endpoint::Idle)
peterbarrett1967 0:5ad808014a49 954 USBLoop(); // May generate callbacks, mount or unmount devices etc
peterbarrett1967 0:5ad808014a49 955 int status = endpoint->Status();
peterbarrett1967 0:5ad808014a49 956 if (status == 0)
peterbarrett1967 0:5ad808014a49 957 return endpoint->Length;
peterbarrett1967 0:5ad808014a49 958 return -status;
peterbarrett1967 0:5ad808014a49 959 }
peterbarrett1967 0:5ad808014a49 960
peterbarrett1967 0:5ad808014a49 961 int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData)
peterbarrett1967 0:5ad808014a49 962 {
peterbarrett1967 0:5ad808014a49 963 Endpoint* endpoint = _controller.GetEndpoint(device,ep);
peterbarrett1967 0:5ad808014a49 964 if (!endpoint)
peterbarrett1967 0:5ad808014a49 965 return ERR_ENDPOINT_NOT_FOUND;
peterbarrett1967 0:5ad808014a49 966
peterbarrett1967 0:5ad808014a49 967 WaitIODone(endpoint);
peterbarrett1967 0:5ad808014a49 968 endpoint->Flags = flags;
peterbarrett1967 0:5ad808014a49 969 endpoint->Data = data;
peterbarrett1967 0:5ad808014a49 970 endpoint->Length = length;
peterbarrett1967 0:5ad808014a49 971 endpoint->Callback = callback;
peterbarrett1967 0:5ad808014a49 972 endpoint->UserData = userData;
peterbarrett1967 0:5ad808014a49 973 if (ep == 0)
peterbarrett1967 0:5ad808014a49 974 _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued);
peterbarrett1967 0:5ad808014a49 975 else
peterbarrett1967 0:5ad808014a49 976 _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued);
peterbarrett1967 0:5ad808014a49 977 if (callback)
peterbarrett1967 0:5ad808014a49 978 return IO_PENDING;
peterbarrett1967 0:5ad808014a49 979 return WaitIODone(endpoint);
peterbarrett1967 0:5ad808014a49 980 }
peterbarrett1967 0:5ad808014a49 981
peterbarrett1967 0:5ad808014a49 982 int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData)
peterbarrett1967 0:5ad808014a49 983 {
peterbarrett1967 0:5ad808014a49 984 Setup* setup = GetSetup(device);
peterbarrett1967 0:5ad808014a49 985 if (!setup)
peterbarrett1967 0:5ad808014a49 986 return ERR_DEVICE_NOT_FOUND;
peterbarrett1967 0:5ad808014a49 987
peterbarrett1967 0:5ad808014a49 988 // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call
peterbarrett1967 0:5ad808014a49 989 WaitIODone(_controller.GetEndpoint(device,0));
peterbarrett1967 0:5ad808014a49 990
peterbarrett1967 0:5ad808014a49 991 setup->bm_request_type = request_type;
peterbarrett1967 0:5ad808014a49 992 setup->b_request = request;
peterbarrett1967 0:5ad808014a49 993 setup->w_value = value;
peterbarrett1967 0:5ad808014a49 994 setup->w_index = index;
peterbarrett1967 0:5ad808014a49 995 setup->w_length = length;
peterbarrett1967 0:5ad808014a49 996 return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData);
peterbarrett1967 0:5ad808014a49 997 }
peterbarrett1967 0:5ad808014a49 998
peterbarrett1967 0:5ad808014a49 999 int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData)
peterbarrett1967 0:5ad808014a49 1000 {
peterbarrett1967 0:5ad808014a49 1001 return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData);
peterbarrett1967 0:5ad808014a49 1002 }
peterbarrett1967 0:5ad808014a49 1003
peterbarrett1967 0:5ad808014a49 1004 int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData)
peterbarrett1967 0:5ad808014a49 1005 {
peterbarrett1967 0:5ad808014a49 1006 return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData);
peterbarrett1967 0:5ad808014a49 1007 }
peterbarrett1967 0:5ad808014a49 1008
peterbarrett1967 0:5ad808014a49 1009 int GetDescriptor(int device, int descType,int descIndex, u8* data, int length)
peterbarrett1967 0:5ad808014a49 1010 {
peterbarrett1967 0:5ad808014a49 1011 return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0);
peterbarrett1967 0:5ad808014a49 1012 }
peterbarrett1967 0:5ad808014a49 1013
peterbarrett1967 0:5ad808014a49 1014 int GetString(int device, int index, char* dst, int length)
peterbarrett1967 0:5ad808014a49 1015 {
peterbarrett1967 0:5ad808014a49 1016 u8 buffer[255];
peterbarrett1967 0:5ad808014a49 1017 int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer));
peterbarrett1967 0:5ad808014a49 1018 if (le < 0)
peterbarrett1967 0:5ad808014a49 1019 return le;
peterbarrett1967 0:5ad808014a49 1020 if (length < 1)
peterbarrett1967 0:5ad808014a49 1021 return -1;
peterbarrett1967 0:5ad808014a49 1022 length <<= 1;
peterbarrett1967 0:5ad808014a49 1023 if (le > length)
peterbarrett1967 0:5ad808014a49 1024 le = length;
peterbarrett1967 0:5ad808014a49 1025 for (int j = 2; j < le; j += 2)
peterbarrett1967 0:5ad808014a49 1026 *dst++ = buffer[j];
peterbarrett1967 0:5ad808014a49 1027 *dst = 0;
peterbarrett1967 0:5ad808014a49 1028 return (le>>1)-1;
peterbarrett1967 0:5ad808014a49 1029 }
peterbarrett1967 0:5ad808014a49 1030
peterbarrett1967 0:5ad808014a49 1031 int SetAddress(int device, int new_addr)
peterbarrett1967 0:5ad808014a49 1032 {
peterbarrett1967 0:5ad808014a49 1033 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0);
peterbarrett1967 0:5ad808014a49 1034 }
peterbarrett1967 0:5ad808014a49 1035
peterbarrett1967 0:5ad808014a49 1036 int SetConfiguration(int device, int configNum)
peterbarrett1967 0:5ad808014a49 1037 {
peterbarrett1967 0:5ad808014a49 1038 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0);
peterbarrett1967 0:5ad808014a49 1039 }
peterbarrett1967 0:5ad808014a49 1040
peterbarrett1967 0:5ad808014a49 1041 int SetInterface(int device, int ifNum, int altNum)
peterbarrett1967 0:5ad808014a49 1042 {
peterbarrett1967 0:5ad808014a49 1043 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0);
peterbarrett1967 0:5ad808014a49 1044 }
peterbarrett1967 0:5ad808014a49 1045
peterbarrett1967 0:5ad808014a49 1046 // HUB stuff
peterbarrett1967 0:5ad808014a49 1047 int SetPortFeature(int device, int feature, int index)
peterbarrett1967 0:5ad808014a49 1048 {
peterbarrett1967 0:5ad808014a49 1049 return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0);
peterbarrett1967 0:5ad808014a49 1050 }
peterbarrett1967 0:5ad808014a49 1051
peterbarrett1967 0:5ad808014a49 1052 int ClearPortFeature(int device, int feature, int index)
peterbarrett1967 0:5ad808014a49 1053 {
peterbarrett1967 0:5ad808014a49 1054 return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0);
peterbarrett1967 0:5ad808014a49 1055 }
peterbarrett1967 0:5ad808014a49 1056
peterbarrett1967 0:5ad808014a49 1057 int SetPortPower(int device, int port)
peterbarrett1967 0:5ad808014a49 1058 {
peterbarrett1967 0:5ad808014a49 1059 int r = SetPortFeature(device,PORT_POWER,port);
peterbarrett1967 0:5ad808014a49 1060 _controller.DelayMS(20); // 80ms to turn on a hubs power... DESCRIPTOR? todo
peterbarrett1967 0:5ad808014a49 1061 return r;
peterbarrett1967 0:5ad808014a49 1062 }
peterbarrett1967 0:5ad808014a49 1063
peterbarrett1967 0:5ad808014a49 1064 int SetPortReset(int device, int port)
peterbarrett1967 0:5ad808014a49 1065 {
peterbarrett1967 0:5ad808014a49 1066 return SetPortFeature(device,PORT_RESET,port);
peterbarrett1967 0:5ad808014a49 1067 }
peterbarrett1967 0:5ad808014a49 1068
peterbarrett1967 0:5ad808014a49 1069 int GetPortStatus(int device, int port, u32* status)
peterbarrett1967 0:5ad808014a49 1070 {
peterbarrett1967 0:5ad808014a49 1071 return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4);
peterbarrett1967 0:5ad808014a49 1072 }