USBHost library. NOTE: This library is only officially supported on the LPC1768 platform. For more information, please see the handbook page.

Dependencies:   FATFileSystem mbed-rtos

Dependents:   BTstack WallbotWii SD to Flash Data Transfer USBHost-MSD_HelloWorld ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHostHub.cpp Source File

USBHostHub.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 "USBHostHub.h"
00018 
00019 #if MAX_HUB_NB
00020 
00021 #include "USBHost.h"
00022 #include "dbg.h"
00023 
00024 #define GET_STATUS 0x00
00025 #define CLEAR_FEATURE 0x01
00026 #define GET_STATE 0x02
00027 #define SET_FEATURE 0x03
00028 #define GET_DESCRIPTOR 0x06
00029 
00030 #define PORT_CONNECTION_FEATURE     (0x00)
00031 #define PORT_ENABLE_FEATURE         (0x01)
00032 #define PORT_RESET_FEATURE          (0x04)
00033 #define PORT_POWER_FEATURE          (0x08)
00034 
00035 #define C_PORT_CONNECTION_FEATURE     (16)
00036 #define C_PORT_ENABLE_FEATURE         (17)
00037 #define C_PORT_RESET_FEATURE          (20)
00038 
00039 #define PORT_CONNECTION   (1 << 0)
00040 #define PORT_ENABLE       (1 << 1)
00041 #define PORT_SUSPEND      (1 << 2)
00042 #define PORT_OVER_CURRENT (1 << 3)
00043 #define PORT_RESET        (1 << 4)
00044 #define PORT_POWER        (1 << 8)
00045 #define PORT_LOW_SPEED    (1 << 9)
00046 
00047 #define C_PORT_CONNECTION   (1 << 16)
00048 #define C_PORT_ENABLE       (1 << 17)
00049 #define C_PORT_SUSPEND      (1 << 18)
00050 #define C_PORT_OVER_CURRENT (1 << 19)
00051 #define C_PORT_RESET        (1 << 20)
00052 
00053 USBHostHub::USBHostHub()
00054 {
00055     host = NULL;
00056     init();
00057 }
00058 
00059 void USBHostHub::init()
00060 {
00061     dev_connected = false;
00062     dev = NULL;
00063     int_in = NULL;
00064     dev_connected = false;
00065     hub_intf = -1;
00066     hub_device_found = false;
00067     nb_port = 0;
00068     hub_characteristics = 0;
00069 
00070     for (int i = 0; i < MAX_HUB_PORT; i++) {
00071         device_children[i] = NULL;
00072     }
00073 }
00074 
00075 void USBHostHub::setHost(USBHost * host_)
00076 {
00077     host = host_;
00078 }
00079 
00080 bool USBHostHub::connected()
00081 {
00082     return dev_connected;
00083 }
00084 
00085 bool USBHostHub::connect(USBDeviceConnected * dev)
00086 {
00087     if (dev_connected) {
00088         return true;
00089     }
00090 
00091     if(host->enumerate(dev, this)) {
00092         init();
00093         return false;
00094     }
00095 
00096     if (hub_device_found) {
00097         this->dev = dev;
00098 
00099         int_in = dev->getEndpoint(hub_intf, INTERRUPT_ENDPOINT, IN);
00100 
00101         if (!int_in) {
00102             init();
00103             return false;
00104         }
00105 
00106         USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, hub_intf);
00107         dev->setName("Hub", hub_intf);
00108         host->registerDriver(dev, hub_intf, this, &USBHostHub::disconnect);
00109 
00110         int_in->attach(this, &USBHostHub::rxHandler);
00111 
00112         // get HUB descriptor
00113         host->controlRead(  dev,
00114                             USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
00115                             GET_DESCRIPTOR,
00116                             0x29 << 8, 0, buf, sizeof(HubDescriptor));
00117         nb_port = buf[2];
00118         hub_characteristics = buf[3];
00119 
00120         USB_DBG("Hub has %d port", nb_port);
00121 
00122         for (uint8_t j = 1; j <= nb_port; j++) {
00123             setPortFeature(PORT_POWER_FEATURE, j);
00124         }
00125         wait_ms(buf[5]*2);
00126 
00127         host->interruptRead(dev, int_in, buf, 1, false);
00128         dev_connected = true;
00129         return true;
00130     }
00131 
00132     return false;
00133 }
00134 
00135 void USBHostHub::disconnect()
00136 {
00137     init();
00138 }
00139 
00140 /*virtual*/ void USBHostHub::setVidPid(uint16_t vid, uint16_t pid)
00141 {
00142     // we don't check VID/PID for MSD driver
00143 }
00144 
00145 /*virtual*/ bool USBHostHub::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
00146 {
00147     if ((hub_intf == -1) &&
00148             (intf_class == HUB_CLASS) &&
00149             (intf_subclass == 0) &&
00150             (intf_protocol == 0)) {
00151         hub_intf = intf_nb;
00152         return true;
00153     }
00154     return false;
00155 }
00156 
00157 /*virtual*/ bool USBHostHub::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
00158 {
00159     if (intf_nb == hub_intf) {
00160         if ((type == INTERRUPT_ENDPOINT) && (dir == IN)) {
00161             hub_device_found = true;
00162             return true;
00163         }
00164     }
00165     return false;
00166 }
00167 
00168 void USBHostHub::deviceConnected(USBDeviceConnected * dev)
00169 {
00170     device_children[dev->getPort() - 1] = dev;
00171 }
00172 
00173 void USBHostHub::deviceDisconnected(USBDeviceConnected * dev)
00174 {
00175     device_children[dev->getPort() - 1] = NULL;
00176 }
00177 
00178 void USBHostHub::hubDisconnected()
00179 {
00180     for (uint8_t i = 0; i < MAX_HUB_PORT; i++) {
00181         if (device_children[i] != NULL) {
00182             host->freeDevice(device_children[i]);
00183         }
00184     }
00185 }
00186 
00187 void USBHostHub::rxHandler()
00188 {
00189     uint32_t status;
00190     if (int_in) {
00191         if ((int_in->getLengthTransferred())&&(int_in->getState() == USB_TYPE_IDLE)) {
00192             for (int port = 1; port <= nb_port; port++) {
00193                 status = getPortStatus(port);
00194                 USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev->getHub(), port, dev, status);
00195 
00196                 // if connection status has changed
00197                 if (status & C_PORT_CONNECTION) {
00198                     if (status & PORT_CONNECTION) {
00199                         USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev->getHub(), port);
00200                         host->deviceConnected(dev->getHub() + 1, port, status & PORT_LOW_SPEED, this);
00201                     } else {
00202                         USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev->getHub(), port);
00203                         host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
00204                     }
00205 
00206                     clearPortFeature(C_PORT_CONNECTION_FEATURE, port);
00207                 }
00208 
00209                 if (status & C_PORT_RESET) {
00210                     clearPortFeature(C_PORT_RESET_FEATURE, port);
00211                 }
00212 
00213                 if (status & C_PORT_ENABLE) {
00214                     clearPortFeature(C_PORT_ENABLE_FEATURE, port);
00215                 }
00216 
00217                 if ((status & PORT_OVER_CURRENT)) {
00218                     USB_ERR("OVER CURRENT DETECTED\r\n");
00219                     clearPortFeature(PORT_OVER_CURRENT, port);
00220                     host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
00221                 }
00222             }
00223         }
00224         host->interruptRead(dev, int_in, buf, 1, false);
00225     }
00226 }
00227 
00228 void USBHostHub::portReset(uint8_t port)
00229 {
00230     // reset port
00231     uint32_t status;
00232     USB_DBG("reset port %d on hub: %p [this: %p]", port, dev, this)
00233     setPortFeature(PORT_RESET_FEATURE, port);
00234 #if defined(TARGET_RZ_A1H)
00235     Thread::wait(50);   // Reset release waiting for Hi-Speed check.
00236 #endif
00237     while(1) {
00238         status = getPortStatus(port);
00239         /*  disconnection since reset request */
00240         if (!(status & PORT_CONNECTION)) {
00241             break;
00242         }
00243         if (status & (PORT_ENABLE | PORT_RESET)) {
00244             break;
00245         }
00246         if (status & PORT_OVER_CURRENT) {
00247             USB_ERR("OVER CURRENT DETECTED\r\n");
00248             clearPortFeature(PORT_OVER_CURRENT, port);
00249             host->deviceDisconnected(dev->getHub() + 1, port, this, 0);
00250             break;
00251         }
00252         Thread::wait(10);
00253     }
00254 }
00255 
00256 void USBHostHub::setPortFeature(uint32_t feature, uint8_t port)
00257 {
00258     host->controlWrite( dev,
00259                         USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
00260                         SET_FEATURE,
00261                         feature,
00262                         port,
00263                         NULL,
00264                         0);
00265 }
00266 
00267 void USBHostHub::clearPortFeature(uint32_t feature, uint8_t port)
00268 {
00269     host->controlWrite( dev,
00270                         USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
00271                         CLEAR_FEATURE,
00272                         feature,
00273                         port,
00274                         NULL,
00275                         0);
00276 }
00277 
00278 uint32_t USBHostHub::getPortStatus(uint8_t port)
00279 {
00280     uint32_t st;
00281     host->controlRead(  dev,
00282                         USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
00283                         GET_STATUS,
00284                         0,
00285                         port,
00286                         (uint8_t *)&st,
00287                         4);
00288     return st;
00289 }
00290 
00291 #endif