Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.
usbeh/usbeh_controller.cpp@0:0a841b89d614, 2010-10-11 (annotated)
- 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?
User | Revision | Line number | New 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 |