this is the Peter Barrett USBHostShell program, a bit modified for being a bit more talkactive, just to let u know how the USB protocol layer is going on, and all the data trasnfers. Also there is a small implementation of HID descriptors, but not functional... yet :S the aim is to at least implement the gamepad HID, and make an array of function pointer to each HID function

Dependencies:   mbed

Committer:
Sergio
Date:
Mon Sep 13 12:40:05 2010 +0000
Revision:
0:e1e03118b8fe

        

Who changed what in which revision?

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