The Pedigree Project  0.1
UsbHubDevice.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "UsbHubDevice.h"
21 #include "modules/system/usb/UsbDevice.h"
22 #include "modules/system/usb/UsbHub.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/time/Time.h"
25 #include "pedigree/kernel/utilities/PointerGuard.h"
26 #include "pedigree/kernel/utilities/new"
27 
28 UsbHubDevice::UsbHubDevice(UsbDevice *dev) : UsbDevice(dev), UsbHub()
29 {
30 }
31 
32 UsbHubDevice::~UsbHubDevice()
33 {
34 }
35 
37 {
38  uint8_t len = getDescriptorLength(0, 0, UsbRequestType::Class);
39  void *pDesc = 0;
40  if (len)
41  {
42  pDesc = getDescriptor(0, 0, len, UsbRequestType::Class);
43  if (!pDesc)
44  return;
45  }
46  else
47  return;
48 
49  HubDescriptor pDescriptor(pDesc);
50  DEBUG_LOG(
51  "USB: HUB: Found a hub with " << Dec << pDescriptor.nPorts << Hex
52  << " ports and hubCharacteristics = "
53  << pDescriptor.hubCharacteristics);
54  m_nPorts = pDescriptor.nPorts;
55  for (size_t i = 0; i < m_nPorts; i++)
56  {
57  // Grab this port's status
58  uint32_t portStatus = getPortStatus(i);
59 
60  // Is power on?
61  if (!(portStatus & (1 << 8)))
62  {
63  DEBUG_LOG(
64  "USB: HUB: Powering up port "
65  << Dec << i << Hex << " [status = " << portStatus << "]...");
66 
67  // Power it on
68  setPortFeature(i, PortPower);
69 
70  // Delay while the power goes on
71  Time::delay(50 * Time::Multiplier::Millisecond);
72 
73  // Done.
74  portStatus = getPortStatus(i);
75 
76  // If port power never went on, skip this port
77  if (!(portStatus & (1 << 8)))
78  {
79  DEBUG_LOG(
80  "USB: HUB: Port " << Dec << i << Hex
81  << " couldn't be powered up.");
82  continue;
83  }
84 
85  DEBUG_LOG(
86  "USB: HUB: Powered up port "
87  << Dec << i << Hex << " [status = " << portStatus << "]...");
88  }
89 
90  if (portReset(i))
91  {
92  // Got a device - what type?
93  portStatus = getPortStatus(i);
94  if (portStatus & (1 << 10))
95  {
96  // High-speed
97  DEBUG_LOG(
98  "USB: HUB: Hub port "
99  << Dec << i << Hex
100  << " has a high-speed device attached to it.");
101  deviceConnected(i, HighSpeed);
102  }
103  else if (portStatus & (1 << 9))
104  {
105  // Low-speed
106  DEBUG_LOG(
107  "USB: HUB: Hub port "
108  << Dec << i << Hex
109  << " has a low-speed device attached to it.");
110  deviceConnected(i, LowSpeed);
111  }
112  else
113  {
114  // Full-speed
115  DEBUG_LOG(
116  "USB: HUB: Hub port "
117  << Dec << i << Hex
118  << " has a full-speed device attached to it.");
119  deviceConnected(i, FullSpeed);
120  }
121  }
122  }
123 
124  m_UsbState = HasDriver;
125 }
126 
127 bool UsbHubDevice::portReset(uint8_t nPort, bool bErrorResponse)
128 {
129  // Reset the port
130  setPortFeature(nPort, PortReset);
131 
132  // Delay while the reset completes
133  Time::delay(50 * Time::Multiplier::Millisecond);
134 
135  // Done with reset
136  clearPortFeature(nPort, PortReset);
137 
138  // Wait for completion
139  while ((getPortStatus(nPort) & (1 << 4)))
140  ;
141 
142  // Port has been powered on and now reset, check to see if it's enabled and
143  // a device is connected
144  uint32_t portStatus = getPortStatus(nPort);
145  return ((portStatus & 0x3) == 0x3);
146 }
147 
148 bool UsbHubDevice::setPortFeature(size_t port, PortFeatureSelectors feature)
149 {
150  return controlRequest(
151  HubPortRequest, UsbRequest::SetFeature, feature, (port + 1) & 0xFF, 0,
152  0);
153 }
154 
155 bool UsbHubDevice::clearPortFeature(size_t port, PortFeatureSelectors feature)
156 {
157  return controlRequest(
158  HubPortRequest, UsbRequest::ClearFeature, feature, (port + 1) & 0xFF, 0,
159  0);
160 }
161 
162 uint32_t UsbHubDevice::getPortStatus(size_t port)
163 {
164  uint32_t *portStatus = new uint32_t(0);
165  PointerGuard<uint32_t> guard(portStatus);
166  controlRequest(
167  UsbRequestDirection::In | HubPortRequest, UsbRequest::GetStatus, 0,
168  (port + 1) & 0xFF, 4, reinterpret_cast<uintptr_t>(portStatus));
169 
170  return *portStatus;
171 }
172 
174  uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer,
175  size_t nBytes)
176 {
177  m_pHub->addTransferToTransaction(
178  pTransaction, bToggle, pid, pBuffer, nBytes);
179 }
180 
182 {
183  if ((m_Speed == HighSpeed) && (endpointInfo.speed != HighSpeed) &&
184  !endpointInfo.nHubAddress)
185  endpointInfo.nHubAddress = m_nAddress;
186  return m_pHub->createTransaction(endpointInfo);
187 }
188 
190  uintptr_t pTransaction, void (*pCallback)(uintptr_t, ssize_t),
191  uintptr_t pParam)
192 {
193  m_pHub->doAsync(pTransaction, pCallback, pParam);
194 }
195 
197  UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes,
198  void (*pCallback)(uintptr_t, ssize_t), uintptr_t pParam)
199 {
200  if ((m_Speed == HighSpeed) && (endpointInfo.speed != HighSpeed) &&
201  (!endpointInfo.nHubAddress))
202  endpointInfo.nHubAddress = m_nAddress;
203  m_pHub->addInterruptInHandler(
204  endpointInfo, pBuffer, nBytes, pCallback, pParam);
205 }
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)=0
Gets a UsbDevice from a given vendor:product pair.
virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer, size_t nBytes)
Adds a new transfer to an existent transaction.
virtual void initialiseDriver()
Implemented by the driver class, initialises driver-specific stuff.
Definition: UsbHubDevice.cc:36
uint32_t getPortStatus(size_t port)
Top 32 bits hold change status.
virtual void addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes, void(*pCallback)(uintptr_t, ssize_t), uintptr_t pParam=0)
Adds a new handler for an interrupt IN transaction.
Definition: Log.h:136
Definition: UsbHub.h:30
bool deviceConnected(uint8_t nPort, UsbSpeed speed)
Called when a device is connected to a port on the hub.
Definition: UsbHub.cc:47
virtual void doAsync(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t)=0, uintptr_t pParam=0)
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)
Gets a UsbDevice from a given vendor:product pair.
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)
Creates a new transaction with the given endpoint data.
Definition: Log.h:138
#define DEBUG_LOG(text)
Definition: Log.h:69