1 /* mbed USBHost Library
2 * Copyright (c) 2006-2013 ARM Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "USBHostHub.h"
24 #define GET_STATUS 0x00
25 #define CLEAR_FEATURE 0x01
26 #define GET_STATE 0x02
27 #define SET_FEATURE 0x03
28 #define GET_DESCRIPTOR 0x06
30 #define PORT_CONNECTION_FEATURE (0x00)
31 #define PORT_ENABLE_FEATURE (0x01)
32 #define PORT_RESET_FEATURE (0x04)
33 #define PORT_POWER_FEATURE (0x08)
35 #define C_PORT_CONNECTION_FEATURE (16)
36 #define C_PORT_ENABLE_FEATURE (17)
37 #define C_PORT_RESET_FEATURE (20)
39 #define PORT_CONNECTION (1 << 0)
40 #define PORT_ENABLE (1 << 1)
41 #define PORT_SUSPEND (1 << 2)
42 #define PORT_OVER_CURRENT (1 << 3)
43 #define PORT_RESET (1 << 4)
44 #define PORT_POWER (1 << 8)
45 #define PORT_LOW_SPEED (1 << 9)
47 #define C_PORT_CONNECTION (1 << 16)
48 #define C_PORT_ENABLE (1 << 17)
49 #define C_PORT_SUSPEND (1 << 18)
50 #define C_PORT_OVER_CURRENT (1 << 19)
51 #define C_PORT_RESET (1 << 20)
53 USBHostHub::USBHostHub() {
58 void USBHostHub::init() {
59 dev_connected
= false;
62 dev_connected
= false;
64 hub_device_found
= false;
66 hub_characteristics
= 0;
68 for (int i
= 0; i
< MAX_HUB_PORT
; i
++) {
69 device_children
[i
] = NULL
;
73 void USBHostHub::setHost(USBHost
* host_
) {
77 bool USBHostHub::connected()
82 bool USBHostHub::connect(USBDeviceConnected
* dev
)
88 if(host
->enumerate(dev
, this)) {
93 if (hub_device_found
) {
96 int_in
= dev
->getEndpoint(hub_intf
, INTERRUPT_ENDPOINT
, IN
);
103 USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p - intf: %d]", dev
->getVid(), dev
->getPid(), dev
, hub_intf
);
104 dev
->setName("Hub", hub_intf
);
105 host
->registerDriver(dev
, hub_intf
, this, &USBHostHub::disconnect
);
107 int_in
->attach(this, &USBHostHub::rxHandler
);
109 // get HUB descriptor
110 host
->controlRead( dev
,
111 USB_DEVICE_TO_HOST
| USB_REQUEST_TYPE_CLASS
,
113 0x29 << 8, 0, buf
, sizeof(HubDescriptor
));
115 hub_characteristics
= buf
[3];
117 USB_DBG("Hub has %d port", nb_port
);
119 for (uint8_t j
= 1; j
<= nb_port
; j
++) {
120 setPortFeature(PORT_POWER_FEATURE
, j
);
124 host
->interruptRead(dev
, int_in
, buf
, 1, false);
125 dev_connected
= true;
132 void USBHostHub::disconnect() {
136 /*virtual*/ void USBHostHub::setVidPid(uint16_t vid
, uint16_t pid
)
138 // we don't check VID/PID for MSD driver
141 /*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
143 if ((hub_intf
== -1) &&
144 (intf_class
== HUB_CLASS
) &&
145 (intf_subclass
== 0) &&
146 (intf_protocol
== 0)) {
153 /*virtual*/ bool USBHostHub::useEndpoint(uint8_t intf_nb
, ENDPOINT_TYPE type
, ENDPOINT_DIRECTION dir
) //Must return true if the endpoint will be used
155 if (intf_nb
== hub_intf
) {
156 if ((type
== INTERRUPT_ENDPOINT
) && (dir
== IN
)) {
157 hub_device_found
= true;
164 void USBHostHub::deviceConnected(USBDeviceConnected
* dev
) {
165 device_children
[dev
->getPort() - 1] = dev
;
168 void USBHostHub::deviceDisconnected(USBDeviceConnected
* dev
) {
169 device_children
[dev
->getPort() - 1] = NULL
;
172 void USBHostHub::hubDisconnected() {
173 for (uint8_t i
= 0; i
< MAX_HUB_PORT
; i
++) {
174 if (device_children
[i
] != NULL
) {
175 host
->freeDevice(device_children
[i
]);
180 void USBHostHub::rxHandler() {
183 if (int_in
->getState() == USB_TYPE_IDLE
) {
184 for (int port
= 1; port
<= nb_port
; port
++) {
185 status
= getPortStatus(port
);
186 USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev
->getHub(), port
, dev
, status
);
188 // if connection status has changed
189 if (status
& C_PORT_CONNECTION
) {
190 if (status
& PORT_CONNECTION
) {
191 USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev
->getHub(), port
);
192 host
->deviceConnected(dev
->getHub() + 1, port
, status
& PORT_LOW_SPEED
, this);
194 USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev
->getHub(), port
);
195 host
->deviceDisconnected(dev
->getHub() + 1, port
, this, 0);
198 clearPortFeature(C_PORT_CONNECTION_FEATURE
, port
);
201 if (status
& C_PORT_RESET
) {
202 clearPortFeature(C_PORT_RESET_FEATURE
, port
);
205 if (status
& C_PORT_ENABLE
) {
206 clearPortFeature(C_PORT_ENABLE_FEATURE
, port
);
209 if ((status
& PORT_OVER_CURRENT
)) {
210 USB_ERR("OVER CURRENT DETECTED\r\n");
211 clearPortFeature(PORT_OVER_CURRENT
, port
);
212 host
->deviceDisconnected(dev
->getHub() + 1, port
, this, 0);
216 host
->interruptRead(dev
, int_in
, buf
, 1, false);
220 void USBHostHub::portReset(uint8_t port
) {
223 USB_DBG("reset port %d on hub: %p [this: %p]", port
, dev
, this)
224 setPortFeature(PORT_RESET_FEATURE
, port
);
225 #if defined(TARGET_RZ_A1H)
226 Thread::wait(50); // Reset release waiting for Hi-Speed check.
229 status
= getPortStatus(port
);
230 if (status
& (PORT_ENABLE
| PORT_RESET
))
232 if (status
& PORT_OVER_CURRENT
) {
233 USB_ERR("OVER CURRENT DETECTED\r\n");
234 clearPortFeature(PORT_OVER_CURRENT
, port
);
235 host
->deviceDisconnected(dev
->getHub() + 1, port
, this, 0);
242 void USBHostHub::setPortFeature(uint32_t feature
, uint8_t port
) {
243 host
->controlWrite( dev
,
244 USB_HOST_TO_DEVICE
| USB_REQUEST_TYPE_CLASS
| USB_RECIPIENT_INTERFACE
| USB_RECIPIENT_ENDPOINT
,
252 void USBHostHub::clearPortFeature(uint32_t feature
, uint8_t port
) {
253 host
->controlWrite( dev
,
254 USB_HOST_TO_DEVICE
| USB_REQUEST_TYPE_CLASS
| USB_RECIPIENT_INTERFACE
| USB_RECIPIENT_ENDPOINT
,
262 uint32_t USBHostHub::getPortStatus(uint8_t port
) {
264 host
->controlRead( dev
,
265 USB_DEVICE_TO_HOST
| USB_REQUEST_TYPE_CLASS
| USB_RECIPIENT_INTERFACE
| USB_RECIPIENT_ENDPOINT
,