XOOMの動作状況を聞き処理を変えてみました。 USBケーブルを抜いた際に処理を終了するようにしました。

Dependencies:   mbed

Committer:
abe00makoto
Date:
Fri May 27 18:51:15 2011 +0000
Revision:
3:432e5675d240
Parent:
0:9fb6c423e32c
nexus one support
maybe support add XOOM ,nexus S

Who changed what in which revision?

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