Dependencies:   mbed

Committer:
emh203
Date:
Thu Feb 16 00:41:26 2012 +0000
Revision:
0:76427232f435

        

Who changed what in which revision?

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