Simple USBHost library for LPC4088. Backward compatibility of official-USBHost.

Dependencies:   FATFileSystem mbed-rtos

EA LPC4088 QSB専用の簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。
examples:

Import programLPC4088-USBHostMSD_HelloWorld

Simple USBHost MSD(USB flash drive) for EA LPC4088 QSB test program

Import programLPC4088-BTstack_example

BTstack for EA LPC4088 QSB example program

Import programLPC4088-USBHostC270_example

Simple USBHost WebCam for EA LPC4088 QSB/LPC1768 test program

Committer:
va009039
Date:
Fri Apr 25 05:18:55 2014 +0000
Revision:
0:148fca6fd246
first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
va009039 0:148fca6fd246 1 /* mbed USBHost Library
va009039 0:148fca6fd246 2 * Copyright (c) 2006-2013 ARM Limited
va009039 0:148fca6fd246 3 *
va009039 0:148fca6fd246 4 * Licensed under the Apache License, Version 2.0 (the "License");
va009039 0:148fca6fd246 5 * you may not use this file except in compliance with the License.
va009039 0:148fca6fd246 6 * You may obtain a copy of the License at
va009039 0:148fca6fd246 7 *
va009039 0:148fca6fd246 8 * http://www.apache.org/licenses/LICENSE-2.0
va009039 0:148fca6fd246 9 *
va009039 0:148fca6fd246 10 * Unless required by applicable law or agreed to in writing, software
va009039 0:148fca6fd246 11 * distributed under the License is distributed on an "AS IS" BASIS,
va009039 0:148fca6fd246 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
va009039 0:148fca6fd246 13 * See the License for the specific language governing permissions and
va009039 0:148fca6fd246 14 * limitations under the License.
va009039 0:148fca6fd246 15 */
va009039 0:148fca6fd246 16
va009039 0:148fca6fd246 17 #include "USBHost.h"
va009039 0:148fca6fd246 18 #define USB_DEBUG
va009039 0:148fca6fd246 19 #include "BaseUsbHostDebug.h"
va009039 0:148fca6fd246 20 #define TEST
va009039 0:148fca6fd246 21 #include "BaseUsbHostTest.h"
va009039 0:148fca6fd246 22
va009039 0:148fca6fd246 23 USBHost* USBHost::inst = NULL;
va009039 0:148fca6fd246 24
va009039 0:148fca6fd246 25 USBHost* USBHost::getHostInst() {
va009039 0:148fca6fd246 26 if (inst == NULL) {
va009039 0:148fca6fd246 27 inst = new USBHost();
va009039 0:148fca6fd246 28 inst->init();
va009039 0:148fca6fd246 29 }
va009039 0:148fca6fd246 30 return inst;
va009039 0:148fca6fd246 31 }
va009039 0:148fca6fd246 32
va009039 0:148fca6fd246 33 void USBHost::poll()
va009039 0:148fca6fd246 34 {
va009039 0:148fca6fd246 35 if (inst) {
va009039 0:148fca6fd246 36 inst->task();
va009039 0:148fca6fd246 37 }
va009039 0:148fca6fd246 38 }
va009039 0:148fca6fd246 39
va009039 0:148fca6fd246 40 USBHost::USBHost() {
va009039 0:148fca6fd246 41 }
va009039 0:148fca6fd246 42
va009039 0:148fca6fd246 43 /* virtual */ bool USBHost::addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) {
va009039 0:148fca6fd246 44 USBDeviceConnected* dev = new USBDeviceConnected;
va009039 0:148fca6fd246 45 USBEndpoint* ep = new USBEndpoint(dev);
va009039 0:148fca6fd246 46 dev->init(0, port, lowSpeed);
va009039 0:148fca6fd246 47 dev->setAddress(0);
va009039 0:148fca6fd246 48 dev->setEpCtl(ep);
va009039 0:148fca6fd246 49 uint8_t desc[18];
va009039 0:148fca6fd246 50 wait_ms(100);
va009039 0:148fca6fd246 51
va009039 0:148fca6fd246 52 int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8);
va009039 0:148fca6fd246 53 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 54 if (rc != USB_TYPE_OK) {
va009039 0:148fca6fd246 55 USB_ERR("ADD DEVICE FAILD");
va009039 0:148fca6fd246 56 }
va009039 0:148fca6fd246 57 USB_DBG_HEX(desc, 8);
va009039 0:148fca6fd246 58 DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
va009039 0:148fca6fd246 59 ep->setSize(dev_desc->bMaxPacketSize);
va009039 0:148fca6fd246 60
va009039 0:148fca6fd246 61 int new_addr = USBDeviceConnected::getNewAddress();
va009039 0:148fca6fd246 62 rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0);
va009039 0:148fca6fd246 63 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 64 dev->setAddress(new_addr);
va009039 0:148fca6fd246 65 wait_ms(100);
va009039 0:148fca6fd246 66
va009039 0:148fca6fd246 67 rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
va009039 0:148fca6fd246 68 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 69 USB_DBG_HEX(desc, sizeof(desc));
va009039 0:148fca6fd246 70
va009039 0:148fca6fd246 71 dev->setVid(dev_desc->idVendor);
va009039 0:148fca6fd246 72 dev->setPid(dev_desc->idProduct);
va009039 0:148fca6fd246 73 dev->setClass(dev_desc->bDeviceClass);
va009039 0:148fca6fd246 74 USB_INFO("parent:%p port:%d speed:%s VID:%04x PID:%04x class:%02x addr:%d",
va009039 0:148fca6fd246 75 parent, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(),
va009039 0:148fca6fd246 76 dev->getAddress());
va009039 0:148fca6fd246 77
va009039 0:148fca6fd246 78 DeviceLists.push_back(dev);
va009039 0:148fca6fd246 79
va009039 0:148fca6fd246 80 if (dev->getClass() == HUB_CLASS) {
va009039 0:148fca6fd246 81 const int config = 1;
va009039 0:148fca6fd246 82 int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
va009039 0:148fca6fd246 83 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 84 wait_ms(100);
va009039 0:148fca6fd246 85 Hub(dev);
va009039 0:148fca6fd246 86 }
va009039 0:148fca6fd246 87 return true;
va009039 0:148fca6fd246 88 }
va009039 0:148fca6fd246 89
va009039 0:148fca6fd246 90 // enumerate a device with the control USBEndpoint
va009039 0:148fca6fd246 91 USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
va009039 0:148fca6fd246 92 {
va009039 0:148fca6fd246 93 if (dev->getClass() == HUB_CLASS) { // skip hub class
va009039 0:148fca6fd246 94 return USB_TYPE_OK;
va009039 0:148fca6fd246 95 }
va009039 0:148fca6fd246 96 uint8_t desc[18];
va009039 0:148fca6fd246 97 USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
va009039 0:148fca6fd246 98 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 99 USB_DBG_HEX(desc, sizeof(desc));
va009039 0:148fca6fd246 100 if (rc != USB_TYPE_OK) {
va009039 0:148fca6fd246 101 return rc;
va009039 0:148fca6fd246 102 }
va009039 0:148fca6fd246 103 DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
va009039 0:148fca6fd246 104 dev->setClass(dev_desc->bDeviceClass);
va009039 0:148fca6fd246 105 pEnumerator->setVidPid(dev->getVid(), dev->getPid());
va009039 0:148fca6fd246 106
va009039 0:148fca6fd246 107 rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4);
va009039 0:148fca6fd246 108 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 109 USB_DBG_HEX(desc, 4);
va009039 0:148fca6fd246 110
va009039 0:148fca6fd246 111 int TotalLength = desc[2]|desc[3]<<8;
va009039 0:148fca6fd246 112 uint8_t* buf = new uint8_t[TotalLength];
va009039 0:148fca6fd246 113 rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength);
va009039 0:148fca6fd246 114 USB_TEST_ASSERT(rc == USB_TYPE_OK);
va009039 0:148fca6fd246 115 //USB_DBG_HEX(buf, TotalLength);
va009039 0:148fca6fd246 116
va009039 0:148fca6fd246 117 // Parse the configuration descriptor
va009039 0:148fca6fd246 118 parseConfDescr(dev, buf, TotalLength, pEnumerator);
va009039 0:148fca6fd246 119 delete[] buf;
va009039 0:148fca6fd246 120 // only set configuration if not enumerated before
va009039 0:148fca6fd246 121 if (!dev->isEnumerated()) {
va009039 0:148fca6fd246 122 USB_DBG("Set configuration 1 on dev: %p", dev);
va009039 0:148fca6fd246 123 // sixth step: set configuration (only 1 supported)
va009039 0:148fca6fd246 124 int config = 1;
va009039 0:148fca6fd246 125 USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
va009039 0:148fca6fd246 126 if (res != USB_TYPE_OK) {
va009039 0:148fca6fd246 127 USB_ERR("SET CONF FAILED");
va009039 0:148fca6fd246 128 return res;
va009039 0:148fca6fd246 129 }
va009039 0:148fca6fd246 130 // Some devices may require this delay
va009039 0:148fca6fd246 131 wait_ms(100);
va009039 0:148fca6fd246 132 dev->setEnumerated();
va009039 0:148fca6fd246 133 // Now the device is enumerated!
va009039 0:148fca6fd246 134 USB_DBG("dev %p is enumerated", dev);
va009039 0:148fca6fd246 135 }
va009039 0:148fca6fd246 136 return USB_TYPE_OK;
va009039 0:148fca6fd246 137 }
va009039 0:148fca6fd246 138
va009039 0:148fca6fd246 139 // this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
va009039 0:148fca6fd246 140 void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
va009039 0:148fca6fd246 141 {
va009039 0:148fca6fd246 142 uint32_t index = 0;
va009039 0:148fca6fd246 143 uint32_t len_desc = 0;
va009039 0:148fca6fd246 144 uint8_t id = 0;
va009039 0:148fca6fd246 145 USBEndpoint * ep = NULL;
va009039 0:148fca6fd246 146 uint8_t intf_nb = 0;
va009039 0:148fca6fd246 147 bool parsing_intf = false;
va009039 0:148fca6fd246 148 uint8_t current_intf = 0;
va009039 0:148fca6fd246 149 EndpointDescriptor* ep_desc;
va009039 0:148fca6fd246 150
va009039 0:148fca6fd246 151 while (index < len) {
va009039 0:148fca6fd246 152 len_desc = conf_descr[index];
va009039 0:148fca6fd246 153 id = conf_descr[index+1];
va009039 0:148fca6fd246 154 USB_DBG_HEX(conf_descr+index, len_desc);
va009039 0:148fca6fd246 155 switch (id) {
va009039 0:148fca6fd246 156 case CONFIGURATION_DESCRIPTOR:
va009039 0:148fca6fd246 157 USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
va009039 0:148fca6fd246 158 dev->setNbIntf(conf_descr[4]);
va009039 0:148fca6fd246 159 break;
va009039 0:148fca6fd246 160 case INTERFACE_DESCRIPTOR:
va009039 0:148fca6fd246 161 if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
va009039 0:148fca6fd246 162 intf_nb++;
va009039 0:148fca6fd246 163 current_intf = conf_descr[index + 2];
va009039 0:148fca6fd246 164 dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
va009039 0:148fca6fd246 165 USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
va009039 0:148fca6fd246 166 parsing_intf = true;
va009039 0:148fca6fd246 167 } else {
va009039 0:148fca6fd246 168 parsing_intf = false;
va009039 0:148fca6fd246 169 }
va009039 0:148fca6fd246 170 break;
va009039 0:148fca6fd246 171 case ENDPOINT_DESCRIPTOR:
va009039 0:148fca6fd246 172 ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index);
va009039 0:148fca6fd246 173 if (parsing_intf && (intf_nb <= MAX_INTF) ) {
va009039 0:148fca6fd246 174 ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03);
va009039 0:148fca6fd246 175 ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT;
va009039 0:148fca6fd246 176 if(pEnumerator->useEndpoint(current_intf, type, dir)) {
va009039 0:148fca6fd246 177 ep = new USBEndpoint(dev);
va009039 0:148fca6fd246 178 ep->init(type, dir, ep_desc->wMaxPacketSize, ep_desc->bEndpointAddress);
va009039 0:148fca6fd246 179 USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
va009039 0:148fca6fd246 180 dev->addEndpoint(current_intf, ep);
va009039 0:148fca6fd246 181 }
va009039 0:148fca6fd246 182 }
va009039 0:148fca6fd246 183 break;
va009039 0:148fca6fd246 184 case HID_DESCRIPTOR:
va009039 0:148fca6fd246 185 //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
va009039 0:148fca6fd246 186 break;
va009039 0:148fca6fd246 187 default:
va009039 0:148fca6fd246 188 break;
va009039 0:148fca6fd246 189 }
va009039 0:148fca6fd246 190 index += len_desc;
va009039 0:148fca6fd246 191 }
va009039 0:148fca6fd246 192 }
va009039 0:148fca6fd246 193
va009039 0:148fca6fd246 194 USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
va009039 0:148fca6fd246 195 USBEndpoint* ep = dev->getEpCtl();
va009039 0:148fca6fd246 196 return controlRead(ep, requestType, request, value, index, buf, len);
va009039 0:148fca6fd246 197 }
va009039 0:148fca6fd246 198
va009039 0:148fca6fd246 199 USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
va009039 0:148fca6fd246 200 USBEndpoint* ep = dev->getEpCtl();
va009039 0:148fca6fd246 201 return controlWrite(ep, requestType, request, value, index, buf, len);
va009039 0:148fca6fd246 202 }
va009039 0:148fca6fd246 203
va009039 0:148fca6fd246 204 USB_TYPE USBHost::controlRead(USBEndpoint* ep, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t* buf, uint32_t len)
va009039 0:148fca6fd246 205 {
va009039 0:148fca6fd246 206 SETUP_PACKET setup(requestType, request, value, index, len);
va009039 0:148fca6fd246 207 int result = token_setup(ep, &setup, len); // setup stage
va009039 0:148fca6fd246 208 if (result < 0) {
va009039 0:148fca6fd246 209 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 210 }
va009039 0:148fca6fd246 211
va009039 0:148fca6fd246 212 result = token_in(ep, buf, len); // data stage
va009039 0:148fca6fd246 213 if (result < 0) {
va009039 0:148fca6fd246 214 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 215 }
va009039 0:148fca6fd246 216 int read_len = result;
va009039 0:148fca6fd246 217
va009039 0:148fca6fd246 218 ep->m_pED->setToggleDATA1();
va009039 0:148fca6fd246 219 result = token_out(ep); // status stage
va009039 0:148fca6fd246 220 if (result < 0) {
va009039 0:148fca6fd246 221 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 222 }
va009039 0:148fca6fd246 223 ep->setLengthTransferred(read_len);
va009039 0:148fca6fd246 224 return USB_TYPE_OK;
va009039 0:148fca6fd246 225 }
va009039 0:148fca6fd246 226
va009039 0:148fca6fd246 227 USB_TYPE USBHost::controlWrite(USBEndpoint* ep, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len)
va009039 0:148fca6fd246 228 {
va009039 0:148fca6fd246 229 SETUP_PACKET setup(requestType, request, value, index, len);
va009039 0:148fca6fd246 230 int result = token_setup(ep, &setup, len); // setup stage
va009039 0:148fca6fd246 231 if (result < 0) {
va009039 0:148fca6fd246 232 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 233 }
va009039 0:148fca6fd246 234 int write_len = 0;
va009039 0:148fca6fd246 235 if (buf != NULL) {
va009039 0:148fca6fd246 236 result = token_out(ep, buf, len); // data stage
va009039 0:148fca6fd246 237 if (result < 0) {
va009039 0:148fca6fd246 238 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 239 }
va009039 0:148fca6fd246 240 write_len = result;
va009039 0:148fca6fd246 241 }
va009039 0:148fca6fd246 242 ep->m_pED->setToggleDATA1();
va009039 0:148fca6fd246 243 result = token_in(ep); // status stage
va009039 0:148fca6fd246 244 if (result < 0) {
va009039 0:148fca6fd246 245 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 246 }
va009039 0:148fca6fd246 247 ep->setLengthTransferred(write_len);
va009039 0:148fca6fd246 248 return USB_TYPE_OK;
va009039 0:148fca6fd246 249 }
va009039 0:148fca6fd246 250
va009039 0:148fca6fd246 251 USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
va009039 0:148fca6fd246 252 if (!blocking) {
va009039 0:148fca6fd246 253 ep->setBuffer(buf, len);
va009039 0:148fca6fd246 254 ep_queue.push(ep);
va009039 0:148fca6fd246 255 token_inNB(ep, buf, len);
va009039 0:148fca6fd246 256 return USB_TYPE_PROCESSING;
va009039 0:148fca6fd246 257 }
va009039 0:148fca6fd246 258 int result = token_in(ep, buf, len);
va009039 0:148fca6fd246 259 if (result >= 0) {
va009039 0:148fca6fd246 260 ep->setLengthTransferred(result);
va009039 0:148fca6fd246 261 return USB_TYPE_OK;
va009039 0:148fca6fd246 262 }
va009039 0:148fca6fd246 263 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 264 }
va009039 0:148fca6fd246 265
va009039 0:148fca6fd246 266 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint* ep, uint8_t * buf, uint32_t len, bool blocking)
va009039 0:148fca6fd246 267 {
va009039 0:148fca6fd246 268 int result = token_out(ep, buf, len);
va009039 0:148fca6fd246 269 if (result >= 0) {
va009039 0:148fca6fd246 270 ep->setLengthTransferred(result);
va009039 0:148fca6fd246 271 return USB_TYPE_OK;
va009039 0:148fca6fd246 272 }
va009039 0:148fca6fd246 273 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 274 }
va009039 0:148fca6fd246 275
va009039 0:148fca6fd246 276 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
va009039 0:148fca6fd246 277 if (!blocking) {
va009039 0:148fca6fd246 278 ep->setBuffer(buf, len);
va009039 0:148fca6fd246 279 ep_queue.push(ep);
va009039 0:148fca6fd246 280 token_inNB(ep, buf, len);
va009039 0:148fca6fd246 281 return USB_TYPE_PROCESSING;
va009039 0:148fca6fd246 282 }
va009039 0:148fca6fd246 283 int result = token_in(ep, buf, len);
va009039 0:148fca6fd246 284 if (result >= 0) {
va009039 0:148fca6fd246 285 ep->setLengthTransferred(result);
va009039 0:148fca6fd246 286 return USB_TYPE_OK;
va009039 0:148fca6fd246 287 }
va009039 0:148fca6fd246 288 return USB_TYPE_ERROR;
va009039 0:148fca6fd246 289 }
va009039 0:148fca6fd246 290
va009039 0:148fca6fd246 291 int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size) {
va009039 0:148fca6fd246 292 if (ep->getState() != USB_TYPE_PROCESSING) {
va009039 0:148fca6fd246 293 ep->setState(USB_TYPE_PROCESSING);
va009039 0:148fca6fd246 294 ep->setBuffer(data, size);
va009039 0:148fca6fd246 295 token_inNB(ep, data, size);
va009039 0:148fca6fd246 296 }
va009039 0:148fca6fd246 297 if (token_inNB_result(ep) != USB_TYPE_PROCESSING) {
va009039 0:148fca6fd246 298 return ep->getLengthTransferred();
va009039 0:148fca6fd246 299 }
va009039 0:148fca6fd246 300 return -1;
va009039 0:148fca6fd246 301 }
va009039 0:148fca6fd246 302
va009039 0:148fca6fd246 303 int USBHost::bulkReadNB(USBEndpoint*ep, uint8_t* data, int size) {
va009039 0:148fca6fd246 304 return interruptReadNB(ep, data, size);
va009039 0:148fca6fd246 305 }
va009039 0:148fca6fd246 306
va009039 0:148fca6fd246 307 void USBHost::task() {
va009039 0:148fca6fd246 308 USBEndpoint* ep = ep_queue.pop();
va009039 0:148fca6fd246 309 if (ep) {
va009039 0:148fca6fd246 310 if (token_inNB_result(ep) == USB_TYPE_OK) {
va009039 0:148fca6fd246 311 ep->call();
va009039 0:148fca6fd246 312 } else {
va009039 0:148fca6fd246 313 ep_queue.push(ep);
va009039 0:148fca6fd246 314 }
va009039 0:148fca6fd246 315 }
va009039 0:148fca6fd246 316 }
va009039 0:148fca6fd246 317