Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.

Dependencies:   mbed

Committer:
AjK
Date:
Mon Oct 11 10:34:55 2010 +0000
Revision:
0:0a841b89d614
Totally Alpha quality as this project isn\t completed. Just publishing it as it answers many questions asked in the forums

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:0a841b89d614 1 /****************************************************************************
AjK 0:0a841b89d614 2 * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd
AjK 0:0a841b89d614 3 *
AjK 0:0a841b89d614 4 * This file is part of the Satellite Observers Workbench (SOWB).
AjK 0:0a841b89d614 5 *
AjK 0:0a841b89d614 6 * SOWB is free software: you can redistribute it and/or modify
AjK 0:0a841b89d614 7 * it under the terms of the GNU General Public License as published by
AjK 0:0a841b89d614 8 * the Free Software Foundation, either version 3 of the License, or
AjK 0:0a841b89d614 9 * (at your option) any later version.
AjK 0:0a841b89d614 10 *
AjK 0:0a841b89d614 11 * SOWB is distributed in the hope that it will be useful,
AjK 0:0a841b89d614 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
AjK 0:0a841b89d614 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
AjK 0:0a841b89d614 14 * GNU General Public License for more details.
AjK 0:0a841b89d614 15 *
AjK 0:0a841b89d614 16 * You should have received a copy of the GNU General Public License
AjK 0:0a841b89d614 17 * along with SOWB. If not, see <http://www.gnu.org/licenses/>.
AjK 0:0a841b89d614 18 *
AjK 0:0a841b89d614 19 * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $
AjK 0:0a841b89d614 20 *
AjK 0:0a841b89d614 21 ***************************************************************************/
AjK 0:0a841b89d614 22
AjK 0:0a841b89d614 23 #include "sowb.h"
AjK 0:0a841b89d614 24 #include "usbeh_endpoint.h"
AjK 0:0a841b89d614 25 #include "usbeh_device.h"
AjK 0:0a841b89d614 26 #include "usbeh_controller.h"
AjK 0:0a841b89d614 27 #include "usbeh_api.h"
AjK 0:0a841b89d614 28
AjK 0:0a841b89d614 29 #include "main.h"
AjK 0:0a841b89d614 30 #include "debug.h"
AjK 0:0a841b89d614 31
AjK 0:0a841b89d614 32 void USBEH_Controller::process(void) {
AjK 0:0a841b89d614 33 USBEH_Endpoint *endpoint;
AjK 0:0a841b89d614 34 USBEH_U16 elapsed = hcca.frameNumber - (USBEH_U16)this->frameNumber;
AjK 0:0a841b89d614 35 this->frameNumber += elapsed;
AjK 0:0a841b89d614 36
AjK 0:0a841b89d614 37 while (this->callbacksPending) {
AjK 0:0a841b89d614 38 for (int i = 0; i < USBEH_MAX_ENDPOINTS_TOTAL; i++) {
AjK 0:0a841b89d614 39 endpoint = this->endpoints + i;
AjK 0:0a841b89d614 40 if (endpoint->currentState == USBEH_Endpoint::callbackPending) {
AjK 0:0a841b89d614 41 this->callbacksPending--;
AjK 0:0a841b89d614 42 endpoint->currentState = USBEH_Endpoint::idle;
AjK 0:0a841b89d614 43 endpoint->callback(
AjK 0:0a841b89d614 44 endpoint->device(),
AjK 0:0a841b89d614 45 endpoint->address(),
AjK 0:0a841b89d614 46 endpoint->status(),
AjK 0:0a841b89d614 47 (USBEH_U08 *)endpoint->userData,
AjK 0:0a841b89d614 48 endpoint->length,
AjK 0:0a841b89d614 49 endpoint->userData);
AjK 0:0a841b89d614 50 }
AjK 0:0a841b89d614 51 }
AjK 0:0a841b89d614 52 }
AjK 0:0a841b89d614 53
AjK 0:0a841b89d614 54 if (this->rootHubStatusChange) {
AjK 0:0a841b89d614 55 USBEH_U32 status = USBEH_HcRhPortStatus1;
AjK 0:0a841b89d614 56 this->rootHubStatusChange = 0;
AjK 0:0a841b89d614 57 if (status >> 16) {
AjK 0:0a841b89d614 58 hubStatusChange(0, 1, status);
AjK 0:0a841b89d614 59 USBEH_HcRhPortStatus1 = status & 0xFFFF0000;
AjK 0:0a841b89d614 60 }
AjK 0:0a841b89d614 61 }
AjK 0:0a841b89d614 62
AjK 0:0a841b89d614 63 if (this->connectCountdown) {
AjK 0:0a841b89d614 64 if (elapsed >= this->connectCountdown) {
AjK 0:0a841b89d614 65 this->connectCountdown = 0;
AjK 0:0a841b89d614 66 connect(this->connectHub, this->connectPort & 0x7F, this->connectPort & 0x80);
AjK 0:0a841b89d614 67 }
AjK 0:0a841b89d614 68 else {
AjK 0:0a841b89d614 69 this->connectCountdown -= elapsed;
AjK 0:0a841b89d614 70 }
AjK 0:0a841b89d614 71 }
AjK 0:0a841b89d614 72 }
AjK 0:0a841b89d614 73
AjK 0:0a841b89d614 74 void USBEH_Controller::init(void) {
AjK 0:0a841b89d614 75 memset(this, 0, sizeof(USBEH_Controller));
AjK 0:0a841b89d614 76 endpointZero.currentState = USBEH_Endpoint::notQueued;
AjK 0:0a841b89d614 77 initHW(&hcca);
AjK 0:0a841b89d614 78 delayMS(10);
AjK 0:0a841b89d614 79 }
AjK 0:0a841b89d614 80
AjK 0:0a841b89d614 81 void USBEH_Controller::hubInterrupt(int device) {
AjK 0:0a841b89d614 82 USBEH_Device *dev = &devices[device - 1];
AjK 0:0a841b89d614 83
AjK 0:0a841b89d614 84 for (int i = 0; i < dev->hubPortCount; i++) {
AjK 0:0a841b89d614 85 int port = i + 1;
AjK 0:0a841b89d614 86 if (dev->hubInterruptData * (1 << port)) {
AjK 0:0a841b89d614 87 USBEH_U32 status = 0;
AjK 0:0a841b89d614 88 usbeh_api_get_port_status(device, port, &status);
AjK 0:0a841b89d614 89 if (status >> 16) {
AjK 0:0a841b89d614 90 if (connectPending && (status & USBEH_CONNECT_STATUS_CHANGE)) {
AjK 0:0a841b89d614 91 hubStatusChange(device, port, status);
AjK 0:0a841b89d614 92 if (status & USBEH_CONNECT_STATUS_CHANGE) {
AjK 0:0a841b89d614 93 usbeh_api_clear_port_feature(device, USBEH_C_PORT_CONNECTION, port);
AjK 0:0a841b89d614 94 }
AjK 0:0a841b89d614 95 if (status & USBEH_PORT_RESET_STATUS_CAHNGE) {
AjK 0:0a841b89d614 96 usbeh_api_clear_port_feature(device, USBEH_C_PORT_RESET, port);
AjK 0:0a841b89d614 97 }
AjK 0:0a841b89d614 98 }
AjK 0:0a841b89d614 99 }
AjK 0:0a841b89d614 100 }
AjK 0:0a841b89d614 101 }
AjK 0:0a841b89d614 102 }
AjK 0:0a841b89d614 103
AjK 0:0a841b89d614 104 void USBEH_Controller::hubInterruptCallback(int device, int endpoint, int status, USBEH_U08 *data, int length, void *userData) {
AjK 0:0a841b89d614 105 USBEH_Controller *controller = (USBEH_Controller *)userData;
AjK 0:0a841b89d614 106 if (status == 0) {
AjK 0:0a841b89d614 107 controller->hubInterrupt(device);
AjK 0:0a841b89d614 108 }
AjK 0:0a841b89d614 109 usbeh_api_interrupt_transfer(device, endpoint, data, 1, hubInterruptCallback, userData);
AjK 0:0a841b89d614 110 }
AjK 0:0a841b89d614 111
AjK 0:0a841b89d614 112 int USBEH_Controller::initHub(int device) {
AjK 0:0a841b89d614 113 USBEH_U08 buffer[16];
AjK 0:0a841b89d614 114 int r = usbeh_api_control_transfer(device, USBEH_DEVICE_TO_HOST | USBEH_REQUEST_TYPE_CLASS | USBEH_RECIPIENT_DEVICE, USBEH_GET_DESCRIPTOR, (USBEH_DESCRIPTOR_TYPE_HUB << 8), 0, buffer, sizeof(buffer), 0, 0);
AjK 0:0a841b89d614 115 if (r < 0) return -1;
AjK 0:0a841b89d614 116
AjK 0:0a841b89d614 117 USBEH_Device *dev = &this->devices[device - 1];
AjK 0:0a841b89d614 118
AjK 0:0a841b89d614 119 int ports = buffer[2];
AjK 0:0a841b89d614 120
AjK 0:0a841b89d614 121 for (int i = 0; i < ports; i++) {
AjK 0:0a841b89d614 122 usbeh_api_set_port_power(device, i + 1);
AjK 0:0a841b89d614 123 }
AjK 0:0a841b89d614 124
AjK 0:0a841b89d614 125 return usbeh_api_interrupt_transfer(device, 0x81, &dev->hubInterruptData,1, hubInterruptCallback, this);
AjK 0:0a841b89d614 126 }
AjK 0:0a841b89d614 127
AjK 0:0a841b89d614 128 int USBEH_Controller::transfer(USBEH_Endpoint *endpoint, int token, USBEH_U08 *data, int len, int state) {
AjK 0:0a841b89d614 129
AjK 0:0a841b89d614 130 int toggle = 0;
AjK 0:0a841b89d614 131
AjK 0:0a841b89d614 132 if (endpoint->address() == 0) {
AjK 0:0a841b89d614 133 toggle = (token == USBEH_TOKEN_SETUP) ? USBEH_TD_TOGGLE_0 : USBEH_TD_TOGGLE_1;
AjK 0:0a841b89d614 134 }
AjK 0:0a841b89d614 135
AjK 0:0a841b89d614 136 if (token != USBEH_TOKEN_SETUP) {
AjK 0:0a841b89d614 137 token = (token == USBEH_TOKEN_IN ? USBEH_TD_IN : USBEH_TD_OUT);
AjK 0:0a841b89d614 138 }
AjK 0:0a841b89d614 139
AjK 0:0a841b89d614 140 USBEH_HCTD *head = &endpoint->tdHead;
AjK 0:0a841b89d614 141 USBEH_HCTD *tail = &this->commonTail;
AjK 0:0a841b89d614 142
AjK 0:0a841b89d614 143 head->control = USBEH_TD_ROUNDING | token | USBEH_TD_DELAY_INT(0) | toggle | USBEH_TD_CC;
AjK 0:0a841b89d614 144 head->currentBufferPointer = (USBEH_U32)data;
AjK 0:0a841b89d614 145 head->bufferEnd = (USBEH_U32)(data + len - 1);
AjK 0:0a841b89d614 146 head->next = (USBEH_U32)tail;
AjK 0:0a841b89d614 147
AjK 0:0a841b89d614 148 USBEH_HCED *ed = &endpoint->endpointDescriptor;
AjK 0:0a841b89d614 149 ed->headTd = (USBEH_U32)head | (ed->headTd & 0x00000002);
AjK 0:0a841b89d614 150 ed->tailTd = (USBEH_U32)tail;
AjK 0:0a841b89d614 151
AjK 0:0a841b89d614 152 switch (endpoint->flags & 3) {
AjK 0:0a841b89d614 153 case USBEH_ENDPOINT_CONTROL:
AjK 0:0a841b89d614 154 USBEH_HcControlHeadED = endpoint->queue(USBEH_HcControlHeadED);
AjK 0:0a841b89d614 155 endpoint->currentState = state;
AjK 0:0a841b89d614 156 USBEH_HcCommandStatus = USBEH_HcCommandStatus | USBEH_CONTROL_LIST_FILLED;
AjK 0:0a841b89d614 157 USBEH_HcControl |= USBEH_CONTROL_LIST_ENABLE;
AjK 0:0a841b89d614 158 break;
AjK 0:0a841b89d614 159 case USBEH_ENDPOINT_BULK:
AjK 0:0a841b89d614 160 USBEH_HcBulkHeadED = endpoint->queue(USBEH_HcBulkHeadED);
AjK 0:0a841b89d614 161 endpoint->currentState = state;
AjK 0:0a841b89d614 162 USBEH_HcCommandStatus = USBEH_HcCommandStatus | USBEH_BULK_LIST_FILLED;
AjK 0:0a841b89d614 163 USBEH_HcControl |= USBEH_BULK_LIST_ENABLE;
AjK 0:0a841b89d614 164 break;
AjK 0:0a841b89d614 165 case USBEH_ENDPOINT_INTERRUPT:
AjK 0:0a841b89d614 166 hcca.interruptTable[0] = endpoint->queue(hcca.interruptTable[0]);
AjK 0:0a841b89d614 167 endpoint->currentState = state;
AjK 0:0a841b89d614 168 USBEH_HcControl |= USBEH_PERIODIC_LIST_ENABLE;
AjK 0:0a841b89d614 169 break;
AjK 0:0a841b89d614 170 }
AjK 0:0a841b89d614 171
AjK 0:0a841b89d614 172 return 0;
AjK 0:0a841b89d614 173 }
AjK 0:0a841b89d614 174
AjK 0:0a841b89d614 175 bool USBEH_Controller::remove(USBEH_HCED *ed, volatile USBEH_HCED **queue) {
AjK 0:0a841b89d614 176 if (*queue == 0) return false;
AjK 0:0a841b89d614 177 if (*queue == (volatile USBEH_HCED *)ed) {
AjK 0:0a841b89d614 178 *queue = (volatile USBEH_HCED *)ed->next;
AjK 0:0a841b89d614 179 return true;
AjK 0:0a841b89d614 180 }
AjK 0:0a841b89d614 181
AjK 0:0a841b89d614 182 volatile USBEH_HCED *head = *queue;
AjK 0:0a841b89d614 183 while (head) {
AjK 0:0a841b89d614 184 if (head->next == (USBEH_U32)ed) {
AjK 0:0a841b89d614 185 head->next = ed->next;
AjK 0:0a841b89d614 186 return true;
AjK 0:0a841b89d614 187 }
AjK 0:0a841b89d614 188 head = (volatile USBEH_HCED *)head->next;
AjK 0:0a841b89d614 189 }
AjK 0:0a841b89d614 190
AjK 0:0a841b89d614 191 return false;
AjK 0:0a841b89d614 192 }
AjK 0:0a841b89d614 193
AjK 0:0a841b89d614 194 void USBEH_Controller::release(USBEH_Endpoint *endpoint) {
AjK 0:0a841b89d614 195 if (endpoint->currentState != USBEH_Endpoint::notQueued) {
AjK 0:0a841b89d614 196 USBEH_HCED *ed = (USBEH_HCED *)endpoint;
AjK 0:0a841b89d614 197 ed->control |= 0x4000;
AjK 0:0a841b89d614 198 switch (endpoint->flags & 0x3) {
AjK 0:0a841b89d614 199 case USBEH_ENDPOINT_CONTROL:
AjK 0:0a841b89d614 200 remove(ed, (volatile USBEH_HCED **)&USBEH_HcControlHeadED);
AjK 0:0a841b89d614 201 break;
AjK 0:0a841b89d614 202 case USBEH_ENDPOINT_BULK:
AjK 0:0a841b89d614 203 remove(ed, (volatile USBEH_HCED **)&USBEH_HcBulkHeadED);
AjK 0:0a841b89d614 204 break;
AjK 0:0a841b89d614 205 case USBEH_ENDPOINT_INTERRUPT:
AjK 0:0a841b89d614 206 for (int i = 0; i < 32; i++) {
AjK 0:0a841b89d614 207 remove(ed, (volatile USBEH_HCED **)&hcca.interruptTable[i]);
AjK 0:0a841b89d614 208 }
AjK 0:0a841b89d614 209 break;
AjK 0:0a841b89d614 210 }
AjK 0:0a841b89d614 211
AjK 0:0a841b89d614 212 USBEH_U16 fn = hcca.frameNumber;
AjK 0:0a841b89d614 213 while (fn == hcca.frameNumber) ;
AjK 0:0a841b89d614 214 }
AjK 0:0a841b89d614 215
AjK 0:0a841b89d614 216 memset(endpoint, 0, sizeof(USBEH_Endpoint));
AjK 0:0a841b89d614 217 }
AjK 0:0a841b89d614 218
AjK 0:0a841b89d614 219 int USBEH_Controller::addEndpoint(int device, USBEH_endpointDescriptor *endpoint) {
AjK 0:0a841b89d614 220 return addEndpoint(device, endpoint->bEndpointAddress, endpoint->bmAttributes, endpoint->wMaxPacketSize, endpoint->bInterval);
AjK 0:0a841b89d614 221 }
AjK 0:0a841b89d614 222
AjK 0:0a841b89d614 223 int USBEH_Controller::addEndpoint(int device, int endpoint, int attributes, int maxPacketSize, int interval) {
AjK 0:0a841b89d614 224 USBEH_Device *dev = &this->devices[device - 1];
AjK 0:0a841b89d614 225 USBEH_Endpoint *ep = allocateEndpoint(device, endpoint, attributes, maxPacketSize);
AjK 0:0a841b89d614 226 if (!ep) {
AjK 0:0a841b89d614 227 return -1;
AjK 0:0a841b89d614 228 }
AjK 0:0a841b89d614 229 dev->setEndpointIndex(endpoint, ep - this->endpoints);
AjK 0:0a841b89d614 230 ep->endpointDescriptor.control |= dev->flags;
AjK 0:0a841b89d614 231 return 0;
AjK 0:0a841b89d614 232
AjK 0:0a841b89d614 233 }
AjK 0:0a841b89d614 234
AjK 0:0a841b89d614 235 USBEH_Endpoint * USBEH_Controller::allocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize) {
AjK 0:0a841b89d614 236 for (int i = 0; i < USBEH_MAX_ENDPOINTS_TOTAL; i++) {
AjK 0:0a841b89d614 237 USBEH_Endpoint *ep = &this->endpoints[i];
AjK 0:0a841b89d614 238 if (ep->currentState == 0) {
AjK 0:0a841b89d614 239 ep->flags = (endpointAddress & 0x80) | (type & 0x3);
AjK 0:0a841b89d614 240 ep->currentState = USBEH_Endpoint::notQueued;
AjK 0:0a841b89d614 241 ep->endpointDescriptor.control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device;
AjK 0:0a841b89d614 242 return ep;
AjK 0:0a841b89d614 243 }
AjK 0:0a841b89d614 244 }
AjK 0:0a841b89d614 245 return 0;
AjK 0:0a841b89d614 246 }
AjK 0:0a841b89d614 247
AjK 0:0a841b89d614 248 int USBEH_Controller::addDevice(int hub, int port, bool isLowSpeed) {
AjK 0:0a841b89d614 249 int device = addDeviceCore(hub, port, isLowSpeed);
AjK 0:0a841b89d614 250 if (device < 0) {
AjK 0:0a841b89d614 251 disconnect(hub, port);
AjK 0:0a841b89d614 252 resetPort(hub, port);
AjK 0:0a841b89d614 253 return -1;
AjK 0:0a841b89d614 254 }
AjK 0:0a841b89d614 255 return device;
AjK 0:0a841b89d614 256 }
AjK 0:0a841b89d614 257
AjK 0:0a841b89d614 258 int USBEH_Controller::addDeviceCore(int hub, int port, bool isLowSpeed) {
AjK 0:0a841b89d614 259
AjK 0:0a841b89d614 260 int lowSpeed = isLowSpeed ? 0x2000 : 0;
AjK 0:0a841b89d614 261
AjK 0:0a841b89d614 262 USBEH_deviceDescriptor desc;
AjK 0:0a841b89d614 263
AjK 0:0a841b89d614 264 endpointZero.endpointDescriptor.control = (8 << 16) | lowSpeed;
AjK 0:0a841b89d614 265
AjK 0:0a841b89d614 266 int result = usbeh_api_get_descriptor(0, USBEH_DESCRIPTOR_TYPE_DEVICE, 0, (USBEH_U08 *)&desc, 8);
AjK 0:0a841b89d614 267
AjK 0:0a841b89d614 268 if (result < 0) {
AjK 0:0a841b89d614 269 #ifdef DEBUG_USB_DRIVER
AjK 0:0a841b89d614 270 debug_printf("usbeh_api_get_descriptor() failed with %d (0x%x) at line %d\r\n", result, result, __LINE__);
AjK 0:0a841b89d614 271 #endif
AjK 0:0a841b89d614 272 return result;
AjK 0:0a841b89d614 273 }
AjK 0:0a841b89d614 274
AjK 0:0a841b89d614 275 endpointZero.endpointDescriptor.control = (desc.bMaxPacketSize << 16) | lowSpeed;
AjK 0:0a841b89d614 276
AjK 0:0a841b89d614 277 result = usbeh_api_get_descriptor(0, USBEH_DESCRIPTOR_TYPE_DEVICE, 0, (USBEH_U08 *)&desc, sizeof(desc));
AjK 0:0a841b89d614 278 if (result < 0) {
AjK 0:0a841b89d614 279 #ifdef DEBUG_USB_DRIVER
AjK 0:0a841b89d614 280 debug_printf("usbeh_api_get_descriptor() failed with %d at line %d\r\n", result, __LINE__);
AjK 0:0a841b89d614 281 #endif
AjK 0:0a841b89d614 282 return result;
AjK 0:0a841b89d614 283 }
AjK 0:0a841b89d614 284
AjK 0:0a841b89d614 285 int device = 0;
AjK 0:0a841b89d614 286 for (int i = 0; i < USBEH_MAX_DEVICES; i++) {
AjK 0:0a841b89d614 287 if (devices[i].port == 0) {
AjK 0:0a841b89d614 288 device = i + 1;
AjK 0:0a841b89d614 289 break;
AjK 0:0a841b89d614 290 }
AjK 0:0a841b89d614 291 }
AjK 0:0a841b89d614 292
AjK 0:0a841b89d614 293 if (!device) {
AjK 0:0a841b89d614 294 return -1;
AjK 0:0a841b89d614 295 }
AjK 0:0a841b89d614 296
AjK 0:0a841b89d614 297 result = usbeh_api_set_address(0, device);
AjK 0:0a841b89d614 298 if (result) {
AjK 0:0a841b89d614 299 return result;
AjK 0:0a841b89d614 300 }
AjK 0:0a841b89d614 301
AjK 0:0a841b89d614 302 delayMS(2);
AjK 0:0a841b89d614 303
AjK 0:0a841b89d614 304 USBEH_Device *dev = &devices[device - 1];
AjK 0:0a841b89d614 305 dev->init(&desc, hub, port, device, lowSpeed);
AjK 0:0a841b89d614 306 addEndpoint(device, 0, USBEH_ENDPOINT_CONTROL, desc.bMaxPacketSize, 0);
AjK 0:0a841b89d614 307 this->connectPending = 0;
AjK 0:0a841b89d614 308
AjK 0:0a841b89d614 309 if ((result = usbeh_api_get_descriptor(device, USBEH_DESCRIPTOR_TYPE_DEVICE, 0, (USBEH_U08 *)&desc, sizeof(desc))) < 0) {
AjK 0:0a841b89d614 310 #ifdef DEBUG_USB_DRIVER
AjK 0:0a841b89d614 311 debug_printf("usbeh_api_get_descriptor() failed with %d at line %d\r\n", result, __LINE__);
AjK 0:0a841b89d614 312 #endif
AjK 0:0a841b89d614 313 return result;
AjK 0:0a841b89d614 314 }
AjK 0:0a841b89d614 315
AjK 0:0a841b89d614 316 result = setConfigurationAndInterface(device, 1, -1, &desc);
AjK 0:0a841b89d614 317
AjK 0:0a841b89d614 318 if (desc.bDeviceClass == CLASS_HUB) {
AjK 0:0a841b89d614 319 initHub(device);
AjK 0:0a841b89d614 320 }
AjK 0:0a841b89d614 321
AjK 0:0a841b89d614 322 return device;
AjK 0:0a841b89d614 323 }
AjK 0:0a841b89d614 324
AjK 0:0a841b89d614 325 int USBEH_Controller::setConfigurationAndInterface(int device, int configuration, int interfaceNumber, USBEH_deviceDescriptor *desc) {
AjK 0:0a841b89d614 326 USBEH_U08 buffer[255];
AjK 0:0a841b89d614 327 USBEH_interfaceDescriptor *found[16];
AjK 0:0a841b89d614 328 USBEH_endpointDescriptor *ed;
AjK 0:0a841b89d614 329
AjK 0:0a841b89d614 330 for (int i = 0; i < 16; i++) {
AjK 0:0a841b89d614 331 found[i] = (USBEH_interfaceDescriptor *)NULL;
AjK 0:0a841b89d614 332 }
AjK 0:0a841b89d614 333
AjK 0:0a841b89d614 334 int err = usbeh_api_get_descriptor(device, USBEH_DESCRIPTOR_TYPE_CONFIGURATION, 0, buffer, sizeof(buffer));
AjK 0:0a841b89d614 335 if (err < 0) {
AjK 0:0a841b89d614 336 #ifdef DEBUG_USB_DRIVER
AjK 0:0a841b89d614 337 debug_printf("GET_DESCRIPTOR failed at line %d\r\n", __LINE__);
AjK 0:0a841b89d614 338 #endif
AjK 0:0a841b89d614 339 return err;
AjK 0:0a841b89d614 340 }
AjK 0:0a841b89d614 341
AjK 0:0a841b89d614 342 err = usbeh_api_set_configuration(device, configuration);
AjK 0:0a841b89d614 343 if (err < 0) {
AjK 0:0a841b89d614 344 return err;
AjK 0:0a841b89d614 345 }
AjK 0:0a841b89d614 346
AjK 0:0a841b89d614 347 int interfaceCounter = 0;
AjK 0:0a841b89d614 348 int len = buffer[2] | (buffer[3] << 8);
AjK 0:0a841b89d614 349 USBEH_U08 *d = buffer;
AjK 0:0a841b89d614 350 USBEH_U08 *end = d + len;
AjK 0:0a841b89d614 351 while (d < end) {
AjK 0:0a841b89d614 352 //printf("Testing descriptor type %02x\n\r", d[1]);
AjK 0:0a841b89d614 353 if (d[1] == USBEH_DESCRIPTOR_TYPE_INTERFACE) {
AjK 0:0a841b89d614 354 //printf(" Found interface descriptor type %02x\n\r", d[1]);
AjK 0:0a841b89d614 355 USBEH_interfaceDescriptor *id = (USBEH_interfaceDescriptor *)d;
AjK 0:0a841b89d614 356 if (interfaceNumber == -1 || id->bInterfaceNumber == interfaceNumber) {
AjK 0:0a841b89d614 357 found[interfaceCounter++] = id;
AjK 0:0a841b89d614 358 d += d[0];
AjK 0:0a841b89d614 359 while (d < end && d[1] != USBEH_DESCRIPTOR_TYPE_INTERFACE) {
AjK 0:0a841b89d614 360 switch (d[1]) {
AjK 0:0a841b89d614 361 case USBEH_DESCRIPTOR_TYPE_ENDPOINT:
AjK 0:0a841b89d614 362 ed = (USBEH_endpointDescriptor *)d;
AjK 0:0a841b89d614 363 //printf(" Adding endpoint 0x%02x for interface %d\r\n", ed->bEndpointAddress, id->bInterfaceNumber);
AjK 0:0a841b89d614 364 addEndpoint(device, ed);
AjK 0:0a841b89d614 365 break;
AjK 0:0a841b89d614 366 default:
AjK 0:0a841b89d614 367 // Skip unknown descriptor.
AjK 0:0a841b89d614 368 //printf(" Unknown descriptor type: %02x\r\n", d[1]);
AjK 0:0a841b89d614 369 break;
AjK 0:0a841b89d614 370 }
AjK 0:0a841b89d614 371 d += d[0];
AjK 0:0a841b89d614 372 }
AjK 0:0a841b89d614 373 }
AjK 0:0a841b89d614 374 }
AjK 0:0a841b89d614 375 else {
AjK 0:0a841b89d614 376 d += d[0];
AjK 0:0a841b89d614 377 }
AjK 0:0a841b89d614 378 }
AjK 0:0a841b89d614 379
AjK 0:0a841b89d614 380 if (interfaceCounter == 0) {
AjK 0:0a841b89d614 381 return USBEH_ERR_INTERFACE_NOT_FOUND;
AjK 0:0a841b89d614 382 }
AjK 0:0a841b89d614 383
AjK 0:0a841b89d614 384 usbeh_api_on_load_device(device, desc, found);
AjK 0:0a841b89d614 385
AjK 0:0a841b89d614 386 return 0;
AjK 0:0a841b89d614 387 }
AjK 0:0a841b89d614 388
AjK 0:0a841b89d614 389 void USBEH_Controller::processDoneQueue(USBEH_U32 tdList) {
AjK 0:0a841b89d614 390 USBEH_Endpoint *endpoint;
AjK 0:0a841b89d614 391 USBEH_HCTD *list = reverse((USBEH_HCTD *)tdList);
AjK 0:0a841b89d614 392 while (list) {
AjK 0:0a841b89d614 393 endpoint = (USBEH_Endpoint *)(list - 1);
AjK 0:0a841b89d614 394 list = (USBEH_HCTD *)list->next;
AjK 0:0a841b89d614 395 int ep = endpoint->address();
AjK 0:0a841b89d614 396 bool in = endpoint->flags & 0x80;
AjK 0:0a841b89d614 397 int status = (endpoint->tdHead.control >> 28) & 0xF;
AjK 0:0a841b89d614 398
AjK 0:0a841b89d614 399 if (status != 0) {
AjK 0:0a841b89d614 400 endpoint->currentState = USBEH_Endpoint::idle;
AjK 0:0a841b89d614 401 }
AjK 0:0a841b89d614 402 else {
AjK 0:0a841b89d614 403 switch (endpoint->currentState) {
AjK 0:0a841b89d614 404 case USBEH_Endpoint::setupQueued:
AjK 0:0a841b89d614 405 if (endpoint->length == 0) {
AjK 0:0a841b89d614 406 transfer(endpoint, in ? USBEH_TOKEN_OUT : USBEH_TOKEN_IN, 0, 0, USBEH_Endpoint::statusQueued);
AjK 0:0a841b89d614 407 }
AjK 0:0a841b89d614 408 else {
AjK 0:0a841b89d614 409 transfer(endpoint, in ? USBEH_TOKEN_IN : USBEH_TOKEN_OUT, (USBEH_U08 *)endpoint->data, endpoint->length, USBEH_Endpoint::dataQueued);
AjK 0:0a841b89d614 410 }
AjK 0:0a841b89d614 411 break;
AjK 0:0a841b89d614 412
AjK 0:0a841b89d614 413 case USBEH_Endpoint::dataQueued:
AjK 0:0a841b89d614 414 if (endpoint->tdHead.currentBufferPointer) {
AjK 0:0a841b89d614 415 endpoint->length = endpoint->tdHead.currentBufferPointer - (USBEH_U32)endpoint->data;
AjK 0:0a841b89d614 416 }
AjK 0:0a841b89d614 417
AjK 0:0a841b89d614 418 if (ep == 0) {
AjK 0:0a841b89d614 419 transfer(endpoint, in ? USBEH_TOKEN_OUT : USBEH_TOKEN_IN, 0, 0, USBEH_Endpoint::statusQueued);
AjK 0:0a841b89d614 420 }
AjK 0:0a841b89d614 421 else {
AjK 0:0a841b89d614 422 endpoint->currentState = USBEH_Endpoint::idle;
AjK 0:0a841b89d614 423 }
AjK 0:0a841b89d614 424 break;
AjK 0:0a841b89d614 425
AjK 0:0a841b89d614 426 case USBEH_Endpoint::statusQueued:
AjK 0:0a841b89d614 427 endpoint->currentState = USBEH_Endpoint::idle;
AjK 0:0a841b89d614 428 break;
AjK 0:0a841b89d614 429 }
AjK 0:0a841b89d614 430 }
AjK 0:0a841b89d614 431
AjK 0:0a841b89d614 432 if (endpoint->callback && endpoint->currentState == USBEH_Endpoint::idle) {
AjK 0:0a841b89d614 433 //if (endpoint->address() != 0x81) printf("\r\nCallback pending for 0x%02X\r\n", endpoint->address());
AjK 0:0a841b89d614 434 endpoint->currentState = USBEH_Endpoint::callbackPending;
AjK 0:0a841b89d614 435 this->callbacksPending++;
AjK 0:0a841b89d614 436 }
AjK 0:0a841b89d614 437 }
AjK 0:0a841b89d614 438 }
AjK 0:0a841b89d614 439
AjK 0:0a841b89d614 440 void USBEH_Controller::resetPort(int hub, int port) {
AjK 0:0a841b89d614 441 this->connectPending++;
AjK 0:0a841b89d614 442 if (hub == 0) {
AjK 0:0a841b89d614 443 USBEH_HcRhPortStatus1 = USBEH_PORT_RESET_STATUS;
AjK 0:0a841b89d614 444 }
AjK 0:0a841b89d614 445 else {
AjK 0:0a841b89d614 446 usbeh_api_set_port_reset(hub, port);
AjK 0:0a841b89d614 447 }
AjK 0:0a841b89d614 448 }
AjK 0:0a841b89d614 449
AjK 0:0a841b89d614 450 void USBEH_Controller::connect(int hub, int port, bool lowSpeed) {
AjK 0:0a841b89d614 451 #ifdef DEBUG_USB_DRIVER
AjK 0:0a841b89d614 452 debug_printf("%s called at line %d\r\n", __FUNCTION__, __LINE__);
AjK 0:0a841b89d614 453 #endif
AjK 0:0a841b89d614 454 addDevice(hub, port, lowSpeed);
AjK 0:0a841b89d614 455 }
AjK 0:0a841b89d614 456
AjK 0:0a841b89d614 457 void USBEH_Controller::disconnect(int hub, int port) {
AjK 0:0a841b89d614 458 for (int i = 0; i < USBEH_MAX_DEVICES; i++) {
AjK 0:0a841b89d614 459 USBEH_Device *dev = this->devices + i;
AjK 0:0a841b89d614 460 if (dev->port == port && dev->hub == hub) {
AjK 0:0a841b89d614 461 for (int p = 0; p < dev->hubPortCount; p++) {
AjK 0:0a841b89d614 462 disconnect(i + 1, p + 1);
AjK 0:0a841b89d614 463 }
AjK 0:0a841b89d614 464 for (int j = 1; j < USBEH_MAX_ENDPOINTS_PER_DEVICE * 2; j += 2) {
AjK 0:0a841b89d614 465 USBEH_U08 endpointIndex = dev->endpoints[j];
AjK 0:0a841b89d614 466 if (endpointIndex != 0xFF) {
AjK 0:0a841b89d614 467 release(this->endpoints + endpointIndex);
AjK 0:0a841b89d614 468 }
AjK 0:0a841b89d614 469 dev->port = 0;
AjK 0:0a841b89d614 470 dev->flags = 0;
AjK 0:0a841b89d614 471 return;
AjK 0:0a841b89d614 472 }
AjK 0:0a841b89d614 473 }
AjK 0:0a841b89d614 474 }
AjK 0:0a841b89d614 475 }
AjK 0:0a841b89d614 476
AjK 0:0a841b89d614 477 void USBEH_Controller::hubStatusChange(int hub, int port, USBEH_U32 status) {
AjK 0:0a841b89d614 478 if (status & USBEH_CONNECT_STATUS_CHANGE) {
AjK 0:0a841b89d614 479 if (status & USBEH_CURRENT_CONNECT_STATUS) {
AjK 0:0a841b89d614 480 resetPort(hub, port);
AjK 0:0a841b89d614 481 }
AjK 0:0a841b89d614 482 else {
AjK 0:0a841b89d614 483 disconnect(hub, port);
AjK 0:0a841b89d614 484 }
AjK 0:0a841b89d614 485 }
AjK 0:0a841b89d614 486
AjK 0:0a841b89d614 487 if (status & USBEH_PORT_RESET_STATUS_CHANGE) {
AjK 0:0a841b89d614 488 if (!(status & USBEH_PORT_RESET_STATUS)) {
AjK 0:0a841b89d614 489 this->connectCountdown = 200;
AjK 0:0a841b89d614 490 if (status & USBEH_LOW_SPEED_DEVICE) {
AjK 0:0a841b89d614 491 port |= 0x80;
AjK 0:0a841b89d614 492 }
AjK 0:0a841b89d614 493 this->connectHub = hub;
AjK 0:0a841b89d614 494 this->connectPort = port;
AjK 0:0a841b89d614 495 }
AjK 0:0a841b89d614 496 }
AjK 0:0a841b89d614 497 }
AjK 0:0a841b89d614 498
AjK 0:0a841b89d614 499 void USBEH_Controller::delayMS(int ms) {
AjK 0:0a841b89d614 500 USBEH_U16 f = ms + hcca.frameNumber;
AjK 0:0a841b89d614 501 while (f != hcca.frameNumber) ;
AjK 0:0a841b89d614 502 }
AjK 0:0a841b89d614 503
AjK 0:0a841b89d614 504 void USBEH_Controller::initHW(USBEH_HCCA *cca) {
AjK 0:0a841b89d614 505 NVIC_DisableIRQ(USB_IRQn);
AjK 0:0a841b89d614 506
AjK 0:0a841b89d614 507 LPC_SC->PCONP |= (1UL << 31);
AjK 0:0a841b89d614 508 LPC_USB->USBClkCtrl |= USBEH_CLOCK_MASK;
AjK 0:0a841b89d614 509 while ((LPC_USB->USBClkSt & USBEH_CLOCK_MASK) != USBEH_CLOCK_MASK);
AjK 0:0a841b89d614 510
AjK 0:0a841b89d614 511 USBEH_OTGStCtrl |= 1;
AjK 0:0a841b89d614 512 USBEH_USBClkCtrl &= ~USBEH_PORTSEL_CLK_EN;
AjK 0:0a841b89d614 513
AjK 0:0a841b89d614 514 LPC_PINCON->PINSEL1 &= ~( (3<<26) | (3<<28) );
AjK 0:0a841b89d614 515 LPC_PINCON->PINSEL1 |= ( (1<<26) | (1<<28));
AjK 0:0a841b89d614 516
AjK 0:0a841b89d614 517 USBEH_HcControl = 0;
AjK 0:0a841b89d614 518 USBEH_HcControlHeadED = 0;
AjK 0:0a841b89d614 519 USBEH_HcBulkHeadED = 0;
AjK 0:0a841b89d614 520 USBEH_HcCommandStatus = USBEH_HOST_CONTROLLER_RESET;
AjK 0:0a841b89d614 521 USBEH_HcFmInterval = USBEH_DEFAULT_FMINTERVAL;
AjK 0:0a841b89d614 522 USBEH_HcPeriodicStart = USBEH_FRAMEINTERVAL * 90 / 100;
AjK 0:0a841b89d614 523
AjK 0:0a841b89d614 524 USBEH_HcControl = (USBEH_HcControl & (~USBEH_HOST_CONTROLLER_FUNCTIONAL_STATE)) | USBEH_OPERATIONAL_MASK;
AjK 0:0a841b89d614 525 USBEH_HcRhStatus = USBEH_SET_GLOBAL_POWER;
AjK 0:0a841b89d614 526
AjK 0:0a841b89d614 527 USBEH_HcHCCA = (USBEH_U32)cca;
AjK 0:0a841b89d614 528 USBEH_HcInterruptStatus |= USBEH_HcInterruptStatus;
AjK 0:0a841b89d614 529 USBEH_HcInterruptEnable |= USBEH_MASTER_IRQ_ENABLE | USBEH_WRITEBACK_DONE_HEAD | USBEH_ROOT_HUB_STATUS_CHANGE | USBEH_FRAME_NUMBER_OVERFLOW | USBEH_START_OF_FRAME;
AjK 0:0a841b89d614 530
AjK 0:0a841b89d614 531 NVIC_EnableIRQ(USB_IRQn);
AjK 0:0a841b89d614 532 while (cca->frameNumber < 10);
AjK 0:0a841b89d614 533 }
AjK 0:0a841b89d614 534
AjK 0:0a841b89d614 535 USBEH_HCTD * USBEH_Controller::reverse(USBEH_HCTD *current) {
AjK 0:0a841b89d614 536 USBEH_HCTD *result = NULL, *temp;
AjK 0:0a841b89d614 537 while (current) {
AjK 0:0a841b89d614 538 temp = (USBEH_HCTD *)current->next;
AjK 0:0a841b89d614 539 current->next = (USBEH_U32)result;
AjK 0:0a841b89d614 540 result = current;
AjK 0:0a841b89d614 541 current = temp;
AjK 0:0a841b89d614 542 }
AjK 0:0a841b89d614 543 return result;
AjK 0:0a841b89d614 544 }
AjK 0:0a841b89d614 545
AjK 0:0a841b89d614 546 USBEH_Endpoint * USBEH_Controller::getEndpoint(int device, int ep) {
AjK 0:0a841b89d614 547 if (device == 0) {
AjK 0:0a841b89d614 548 return &endpointZero;
AjK 0:0a841b89d614 549 }
AjK 0:0a841b89d614 550 if (device > USBEH_MAX_DEVICES) {
AjK 0:0a841b89d614 551 return 0;
AjK 0:0a841b89d614 552 }
AjK 0:0a841b89d614 553 int i = devices[device - 1].getEndpointIndex(ep);
AjK 0:0a841b89d614 554 if (i == -1) {
AjK 0:0a841b89d614 555 return 0;
AjK 0:0a841b89d614 556 }
AjK 0:0a841b89d614 557 return endpoints + i;
AjK 0:0a841b89d614 558 }
AjK 0:0a841b89d614 559
AjK 0:0a841b89d614 560 /* The controller is defined withinn the API section. */
AjK 0:0a841b89d614 561 extern USBEH_Controller sys_usb_controller;
AjK 0:0a841b89d614 562
AjK 0:0a841b89d614 563 USBEH_SOF_COUNTER *sof_counter_head = NULL;
AjK 0:0a841b89d614 564
AjK 0:0a841b89d614 565 /* The USB interrupt handler. */
AjK 0:0a841b89d614 566 extern "C" void USB_IRQHandler (void) __irq {
AjK 0:0a841b89d614 567
AjK 0:0a841b89d614 568 USBEH_U32 int_status = USBEH_HcInterruptStatus;
AjK 0:0a841b89d614 569
AjK 0:0a841b89d614 570 if (int_status & USBEH_ROOT_HUB_STATUS_CHANGE) {
AjK 0:0a841b89d614 571 sys_usb_controller.rootHubStatusChange++;
AjK 0:0a841b89d614 572 }
AjK 0:0a841b89d614 573
AjK 0:0a841b89d614 574 USBEH_U32 head = 0;
AjK 0:0a841b89d614 575
AjK 0:0a841b89d614 576 if (int_status & USBEH_WRITEBACK_DONE_HEAD) {
AjK 0:0a841b89d614 577 head = sys_usb_controller.hcca.doneHead;
AjK 0:0a841b89d614 578 sys_usb_controller.hcca.doneHead = 0;
AjK 0:0a841b89d614 579 }
AjK 0:0a841b89d614 580
AjK 0:0a841b89d614 581 if (int_status & USBEH_START_OF_FRAME) {
AjK 0:0a841b89d614 582 for (USBEH_SOF_COUNTER *list = sof_counter_head; list != NULL; list = list->next) {
AjK 0:0a841b89d614 583 if (list->mode & USBEH_SOF_COUNTER_DEC && list->flag == 0) {
AjK 0:0a841b89d614 584 if (list->counter > 0) list->counter--;
AjK 0:0a841b89d614 585 if (list->counter == 0) {
AjK 0:0a841b89d614 586 list->flag = 1;
AjK 0:0a841b89d614 587 list->counter = list->reload;
AjK 0:0a841b89d614 588 if (list->callback != NULL) {
AjK 0:0a841b89d614 589 (list->callback)((struct _sof_counter *)list);
AjK 0:0a841b89d614 590 }
AjK 0:0a841b89d614 591 }
AjK 0:0a841b89d614 592 }
AjK 0:0a841b89d614 593 }
AjK 0:0a841b89d614 594 }
AjK 0:0a841b89d614 595
AjK 0:0a841b89d614 596 USBEH_HcInterruptStatus = int_status;
AjK 0:0a841b89d614 597
AjK 0:0a841b89d614 598 if (head) {
AjK 0:0a841b89d614 599 sys_usb_controller.processDoneQueue(head);
AjK 0:0a841b89d614 600 }
AjK 0:0a841b89d614 601 }
AjK 0:0a841b89d614 602