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

Dependencies:   FATFileSystem mbed-rtos

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHost.cpp Source File

USBHost.cpp

00001 /* mbed USBHost Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "USBHost.h"
00018 #define USB_DEBUG
00019 #include "BaseUsbHostDebug.h"
00020 #define TEST
00021 #include "BaseUsbHostTest.h"
00022 
00023 USBHost* USBHost::inst = NULL;
00024 
00025 USBHost* USBHost::getHostInst() {
00026     if (inst == NULL) {
00027         inst = new USBHost();
00028         inst->init();
00029     }
00030     return inst;
00031 }
00032 
00033 void USBHost::poll()
00034 {
00035     if (inst) {
00036         inst->task();
00037     }
00038 }
00039 
00040 USBHost::USBHost() {
00041 }
00042 
00043 /* virtual */ bool USBHost::addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) {
00044     USBDeviceConnected* dev = new USBDeviceConnected;
00045     USBEndpoint* ep = new USBEndpoint(dev);
00046     dev->init(0, port, lowSpeed);
00047     dev->setAddress(0);
00048     dev->setEpCtl(ep);
00049     uint8_t desc[18];
00050     wait_ms(100);
00051 
00052     int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8);
00053     USB_TEST_ASSERT(rc == USB_TYPE_OK);
00054     if (rc != USB_TYPE_OK) {
00055         USB_ERR("ADD DEVICE FAILD");
00056     }
00057     USB_DBG_HEX(desc, 8);
00058     DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
00059     ep->setSize(dev_desc->bMaxPacketSize);
00060 
00061     int new_addr = USBDeviceConnected::getNewAddress();
00062     rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0);
00063     USB_TEST_ASSERT(rc == USB_TYPE_OK);
00064     dev->setAddress(new_addr);
00065     wait_ms(100);
00066 
00067     rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
00068     USB_TEST_ASSERT(rc == USB_TYPE_OK);
00069     USB_DBG_HEX(desc, sizeof(desc));
00070 
00071     dev->setVid(dev_desc->idVendor);
00072     dev->setPid(dev_desc->idProduct);
00073     dev->setClass(dev_desc->bDeviceClass);
00074     USB_INFO("parent:%p port:%d speed:%s VID:%04x PID:%04x class:%02x addr:%d",
00075         parent, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(),
00076         dev->getAddress());
00077 
00078     DeviceLists.push_back(dev);
00079 
00080     if (dev->getClass() == HUB_CLASS) {
00081         const int config = 1;
00082         int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
00083         USB_TEST_ASSERT(rc == USB_TYPE_OK);
00084         wait_ms(100);
00085         Hub(dev);
00086     }
00087     return true;
00088 }
00089 
00090 // enumerate a device with the control USBEndpoint
00091 USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
00092 {
00093     if (dev->getClass() == HUB_CLASS) { // skip hub class
00094         return USB_TYPE_OK;
00095     }
00096     uint8_t desc[18];
00097     USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
00098     USB_TEST_ASSERT(rc == USB_TYPE_OK);
00099     USB_DBG_HEX(desc, sizeof(desc));
00100     if (rc != USB_TYPE_OK) {
00101         return rc;
00102     }
00103     DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
00104     dev->setClass(dev_desc->bDeviceClass);
00105     pEnumerator->setVidPid(dev->getVid(), dev->getPid());
00106 
00107     rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4);
00108     USB_TEST_ASSERT(rc == USB_TYPE_OK);
00109     USB_DBG_HEX(desc, 4);
00110 
00111     int TotalLength = desc[2]|desc[3]<<8;
00112     uint8_t* buf = new uint8_t[TotalLength];
00113     rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength);
00114     USB_TEST_ASSERT(rc == USB_TYPE_OK);
00115     //USB_DBG_HEX(buf, TotalLength);
00116 
00117     // Parse the configuration descriptor
00118     parseConfDescr(dev, buf, TotalLength, pEnumerator);
00119     delete[] buf;
00120     // only set configuration if not enumerated before
00121     if (!dev->isEnumerated()) {
00122         USB_DBG("Set configuration 1 on dev: %p", dev);
00123         // sixth step: set configuration (only 1 supported)
00124         int config = 1;
00125         USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
00126         if (res != USB_TYPE_OK) {
00127             USB_ERR("SET CONF FAILED");
00128             return res;
00129         }
00130         // Some devices may require this delay
00131         wait_ms(100);
00132         dev->setEnumerated();
00133         // Now the device is enumerated!
00134         USB_DBG("dev %p is enumerated", dev);
00135     }
00136     return USB_TYPE_OK;
00137 }
00138 
00139 // this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
00140 void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
00141 {
00142     uint32_t index = 0;
00143     uint32_t len_desc = 0;
00144     uint8_t id = 0;
00145     USBEndpoint * ep = NULL;
00146     uint8_t intf_nb = 0;
00147     bool parsing_intf = false;
00148     uint8_t current_intf = 0;
00149     EndpointDescriptor* ep_desc;
00150 
00151     while (index < len) {
00152         len_desc = conf_descr[index];
00153         id = conf_descr[index+1];
00154         USB_DBG_HEX(conf_descr+index, len_desc);
00155         switch (id) {
00156             case CONFIGURATION_DESCRIPTOR:
00157                 USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
00158                 dev->setNbIntf(conf_descr[4]);
00159                 break;
00160             case INTERFACE_DESCRIPTOR:
00161                 if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
00162                     intf_nb++;
00163                     current_intf = conf_descr[index + 2];
00164                     dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
00165                     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]);
00166                     parsing_intf = true;
00167                 } else {
00168                     parsing_intf = false;
00169                 }
00170                 break;
00171             case ENDPOINT_DESCRIPTOR:
00172                 ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index);
00173                 if (parsing_intf && (intf_nb <= MAX_INTF) ) {
00174                     ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03);
00175                     ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT;
00176                     if(pEnumerator->useEndpoint(current_intf, type, dir)) {
00177                         ep = new USBEndpoint(dev);
00178                         ep->init(type, dir, ep_desc->wMaxPacketSize, ep_desc->bEndpointAddress);
00179                         USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
00180                         dev->addEndpoint(current_intf, ep);
00181                     }
00182                 }
00183                 break;
00184             case HID_DESCRIPTOR:
00185                 //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
00186                 break;
00187             default:
00188                 break;
00189         }
00190         index += len_desc;
00191     }
00192 }
00193 
00194 USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
00195     USBEndpoint* ep = dev->getEpCtl();
00196     return controlRead(ep, requestType, request, value, index, buf, len);
00197 }
00198 
00199 USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
00200     USBEndpoint* ep = dev->getEpCtl();
00201     return controlWrite(ep, requestType, request, value, index, buf, len);
00202 }
00203 
00204 USB_TYPE USBHost::controlRead(USBEndpoint* ep, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t* buf, uint32_t len)
00205 {
00206     SETUP_PACKET setup(requestType, request, value, index, len);
00207     int result = token_setup(ep, &setup, len); // setup stage
00208     if (result < 0) {
00209         return USB_TYPE_ERROR;
00210     }
00211 
00212     result = token_in(ep, buf, len); // data stage
00213     if (result < 0) {
00214         return USB_TYPE_ERROR;
00215     }
00216     int read_len = result;
00217 
00218     ep->m_pED->setToggleDATA1();
00219     result = token_out(ep); // status stage
00220     if (result < 0) {
00221         return USB_TYPE_ERROR;
00222     }
00223     ep->setLengthTransferred(read_len);
00224     return USB_TYPE_OK;
00225 }
00226 
00227 USB_TYPE USBHost::controlWrite(USBEndpoint* ep, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len)
00228 {
00229     SETUP_PACKET setup(requestType, request, value, index, len);
00230     int result = token_setup(ep, &setup, len); // setup stage
00231     if (result < 0) {
00232         return USB_TYPE_ERROR;
00233     }
00234     int write_len = 0;
00235     if (buf != NULL) {
00236         result = token_out(ep, buf, len); // data stage
00237         if (result < 0) {
00238             return USB_TYPE_ERROR;
00239         }
00240         write_len = result;
00241     }
00242     ep->m_pED->setToggleDATA1();
00243     result = token_in(ep); // status stage
00244     if (result < 0) {
00245         return USB_TYPE_ERROR;
00246     }
00247     ep->setLengthTransferred(write_len);
00248     return USB_TYPE_OK;
00249 }
00250 
00251 USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
00252     if (!blocking) {
00253         ep->setBuffer(buf, len);
00254         ep_queue.push(ep);
00255         token_inNB(ep, buf, len);
00256         return USB_TYPE_PROCESSING;
00257     }
00258     int result = token_in(ep, buf, len);
00259     if (result >= 0) {
00260         ep->setLengthTransferred(result);
00261         return USB_TYPE_OK;
00262     }
00263     return USB_TYPE_ERROR;
00264 }
00265 
00266 USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint* ep, uint8_t * buf, uint32_t len, bool blocking)
00267 {
00268     int result = token_out(ep, buf, len);
00269     if (result >= 0) {
00270         ep->setLengthTransferred(result);
00271         return USB_TYPE_OK;
00272     }    
00273     return USB_TYPE_ERROR;
00274 }
00275 
00276 USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
00277     if (!blocking) {
00278         ep->setBuffer(buf, len);
00279         ep_queue.push(ep);
00280         token_inNB(ep, buf, len);
00281         return USB_TYPE_PROCESSING;
00282     }
00283     int result = token_in(ep, buf, len);
00284     if (result >= 0) {
00285         ep->setLengthTransferred(result);
00286         return USB_TYPE_OK;
00287     }
00288     return USB_TYPE_ERROR;
00289 }
00290 
00291 int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size) {
00292     if (ep->getState() != USB_TYPE_PROCESSING) {
00293         ep->setState(USB_TYPE_PROCESSING);
00294         ep->setBuffer(data, size);
00295         token_inNB(ep, data, size);
00296     }
00297     if (token_inNB_result(ep) != USB_TYPE_PROCESSING) {
00298         return ep->getLengthTransferred();
00299     }
00300     return -1;
00301 }
00302 
00303 int USBHost::bulkReadNB(USBEndpoint*ep, uint8_t* data, int size) {
00304     return interruptReadNB(ep, data, size);
00305 }
00306 
00307 void USBHost::task() {
00308     USBEndpoint* ep = ep_queue.pop();
00309     if (ep) {
00310         if (token_inNB_result(ep) == USB_TYPE_OK) {
00311             ep->call();
00312         } else {
00313             ep_queue.push(ep);
00314         }
00315     }
00316 }
00317