Pulse Oximeter (NONIN) communicates with mbed via Bluetooth dongle and sends Heart Rate and Oxygen Saturation via GPRS module

Dependencies:   C12832 GPS GSM mbed

Fork of myBlueUSB_localfix by Nobuaki Aoki

Committer:
samialshorman
Date:
Tue Apr 14 21:48:07 2015 +0000
Revision:
3:55a622e3dbb5
Parent:
0:003889bc474f
Nonin (Pulse Oximeter) connected to mbed lpc 1768 by Bluetooth dongle and sends SMS including Heart Rate and Oxygen saturation by GPRS module

Who changed what in which revision?

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