The Pedigree Project 0.1
UsbHub.h
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#ifndef USBHUB_H
21#define USBHUB_H
22#include "pedigree/kernel/Atomic.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/machine/Device.h"
25#include "pedigree/kernel/process/Mutex.h"
26#include "pedigree/kernel/process/Semaphore.h"
27#include "pedigree/kernel/processor/types.h"
28#include "pedigree/kernel/utilities/ExtensibleBitmap.h"
29#include "pedigree/kernel/utilities/List.h"
30
31#include <config.h>
32
33#include "modules/system/usb/Usb.h"
34#include "modules/system/usb/UsbStartup.h"
35
36class UsbHub;
38
41 uintptr_t transaction;
42 size_t generation;
43};
44
51class EXPORTED_PUBLIC UsbInterruptInHandle {
52 public:
56
58
60 MUST_USE_RESULT bool reset();
61
62 explicit operator bool() const {
63 return static_cast<UsbHub*>(m_Owner) != nullptr;
64 }
65
66 private:
67 friend class UsbHub;
68
69 void adopt(UsbHub* owner, const UsbInterruptInToken& token, void (*callback)(uintptr_t, ssize_t),
70 uintptr_t parameter);
71
73 UsbInterruptInHandle& operator=(const UsbInterruptInHandle&) = delete;
74
75 Atomic<UsbHub*> m_Owner;
76 Atomic<bool> m_Resetting;
77 UsbInterruptInToken m_Token;
78 void (*m_Callback)(uintptr_t, ssize_t);
79 uintptr_t m_Parameter;
80 bool m_CancellationStarted;
81};
82
83class EXPORTED_PUBLIC UsbHub : public Device {
84 public:
86 class EXPORTED_PUBLIC StartupActivity {
87 public:
88 explicit StartupActivity(UsbHub* hub);
90 explicit operator bool() const {
91 return m_Admitted;
92 }
93 void failed() {
94 m_Outcome = UsbStartup::Outcome::Failed;
95 }
96 void deviceReady() {
97 m_Outcome = UsbStartup::Outcome::DeviceReady;
98 }
99
100 private:
101 StartupActivity(const StartupActivity&) = delete;
102 StartupActivity& operator=(const StartupActivity&) = delete;
103 UsbHub* m_Root;
104 bool m_Admitted;
105 UsbStartup::Outcome m_Outcome = UsbStartup::Outcome::Neutral;
106 };
107
115 class EXPORTED_PUBLIC ConnectionChangeSuppression {
116 public:
120
122
123 explicit operator bool() const {
124 return m_Hub != nullptr;
125 }
126
127 void reset();
128
129 private:
130 friend class UsbHub;
131
132 ConnectionChangeSuppression(UsbHub* hub, size_t port);
133
136
137 UsbHub* m_Hub;
138 size_t m_Port;
139 };
140
141 UsbHub();
142 UsbHub(Device* p);
143
144 virtual ~UsbHub();
145
147 uint8_t port;
148 size_t generation;
149 };
150
152 RootConnection rootConnectionForChild(uint8_t childPort) const;
153 virtual bool controllerAssignsAddresses() const {
154 return false;
155 }
156 virtual bool supportsHubDevices() const {
157 return true;
158 }
159 virtual bool prepareDevice(uint8_t, const UsbEndpoint&) {
160 return true;
161 }
162 virtual bool addressDevice(uint8_t, const UsbEndpoint&) {
163 return false;
164 }
165 virtual bool resetEndpoint(const UsbEndpoint&) {
166 return true;
167 }
168
169 virtual Type getType();
170
172 virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid,
173 uintptr_t pBuffer, size_t nBytes) = 0;
174
176 virtual uintptr_t createTransaction(UsbEndpoint endpointInfo) = 0;
177
187 MUST_USE_RESULT virtual bool doAsync(uintptr_t pTransaction,
188 void (*pCallback)(uintptr_t, ssize_t) = 0,
189 uintptr_t pParam = 0) = 0;
190
200 virtual void cancelAsyncAndDrain(uintptr_t pTransaction, void (*pCallback)(uintptr_t, ssize_t),
201 uintptr_t pParam) = 0;
202
204 MUST_USE_RESULT virtual bool addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer,
205 uint16_t nBytes,
206 void (*pCallback)(uintptr_t, ssize_t),
207 UsbInterruptInHandle& handle,
208 uintptr_t pParam = 0) = 0;
209
211 bool deviceConnected(uint8_t nPort, UsbSpeed speed);
212
214 void deviceDisconnected(uint8_t nPort);
215
218 ssize_t doSync(uintptr_t nTransaction, uint32_t timeout = 5000);
219
220#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
222 static bool runHostedSyncOwnershipRegression();
223
225 static bool runHostedInterruptOwnershipRegression();
226
227 using ConnectionChangePendingHook = void (*)(UsbHub* hub, size_t port, size_t observedState);
228 using ConnectionChangeReplayWaitHook = void (*)(UsbHub* hub, size_t port);
229 static void setConnectionChangePendingHookForTest(ConnectionChangePendingHook hook);
230 static void setConnectionChangeReplayWaitHookForTest(ConnectionChangeReplayWaitHook hook);
231#endif
232
233#if PEDIGREE_CONCURRENCY_SMOKE_TESTS
235 static bool runQemuInterruptOwnershipRegression();
236#endif
237
239 // void getDeviceByIds(size_t vendor, size_t product, void
240 // (*pCallback)(class UsbDevice *));
241
249 virtual bool portReset(uint8_t nPort, bool bErrorResponse = false) = 0;
250
251 private:
252 bool deviceConnectedAdmitted(uint8_t nPort, UsbSpeed speed);
253#if (HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS) || PEDIGREE_CONCURRENCY_SMOKE_TESTS
254 static bool runInterruptOwnershipRegression();
255 static int retireProbeSubtreeForTest(void* parameter);
256#endif
257
259 struct SyncParam {
260 inline SyncParam() : semaphore(0), nResult(-1), owners(2) {}
261
262 ~SyncParam();
263 void releaseOwner();
264
265 Semaphore semaphore;
266 ssize_t nResult;
267 Atomic<size_t> owners;
268 };
269
271 static void syncCallback(uintptr_t pParam, ssize_t ret);
272
273 void deviceDisconnectedLocked(uint8_t nPort);
274 void retirePortContainersLocked(uint8_t nPort, bool* retiredAddresses,
275 bool* pinnedSubtreeAddresses = nullptr);
276 void releaseRetiredAddressesLocked(uint8_t nPort, const bool* retiredAddresses);
277 void retainAddressLocked(size_t address);
278 void releaseAddressLocked(size_t address);
279 void retainAddressesLocked(const bool* addresses);
280 void releaseAddressesLocked(const bool* addresses);
281 static void collectUsbAddresses(Device* device, bool* addresses);
282 static void collectImmediateUsbContainers(Device* device, List<UsbDeviceContainer*>& containers);
283 static void drainSubtreeProbeAdmissions(UsbDeviceContainer* container);
284 static void prepareSubtreeForDisconnection(UsbDeviceContainer* container);
285 void releaseConnectionChangeSuppression(size_t port);
286
290
292 size_t m_AddressReferences[128] = {};
293
296
299
300 static constexpr size_t ConnectionChangePortCount = 32;
301 static constexpr size_t ConnectionChangePending =
302 static_cast<size_t>(1) << ((sizeof(size_t) * 8) - static_cast<size_t>(1));
303 static constexpr size_t ConnectionChangeCountMask = ~ConnectionChangePending;
304
306 Atomic<size_t> m_ConnectionChangeStates[ConnectionChangePortCount];
307
310
313
315 uint8_t m_RootPort;
316
319
321 bool m_RetainDisconnectedAddresses = false;
322
323 protected:
325 virtual bool portSpeed(uint8_t, UsbSpeed&) {
326 return true;
327 }
328
329 virtual bool beginStartupActivity() {
330 return true;
331 }
332 virtual void endStartupActivity(UsbStartup::Outcome) {}
333
334 friend class UsbInterruptInHandle;
336 virtual void releaseDeviceAddress(uint8_t) {}
337
339 MUST_USE_RESULT bool publishInterruptInHandle(UsbInterruptInHandle& handle,
340 const UsbInterruptInToken& token,
341 void (*callback)(uintptr_t, ssize_t),
342 uintptr_t parameter);
343
346 void (*callback)(uintptr_t, ssize_t),
347 uintptr_t parameter,
348 bool producerAlreadyStopped) = 0;
349
351 virtual bool inInterruptCallbackContext() const {
352 return false;
353 }
354
356 void disconnectAllDevices();
357
359 void retainDisconnectedAddressesUntilControllerTeardown();
360
362 void attachToUpstreamHub(UsbHub* upstream, const RootConnection& connection);
363
365 UsbHub* rootHub() const {
366 return m_RootHub;
367 }
368
370 MUST_USE_RESULT bool suppressConnectionChanges(size_t port,
371 ConnectionChangeSuppression& suppression);
372
377 MUST_USE_RESULT bool deferConnectionChangeIfSuppressed(size_t port);
378
380 virtual void replaySuppressedConnectionChange(size_t port);
381
383 virtual size_t currentRootPortGeneration(size_t port) const {
384 (void)port;
385 return 0;
386 }
387};
388
389#endif
Definition List.h:61
Definition Mutex.h:56
Mutex m_TopologyLock
Definition UsbHub.h:298
virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer, size_t nBytes)=0
Adds a new transfer to an existent transaction.
UsbHub * m_RootHub
Definition UsbHub.h:309
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)=0
Creates a new transaction with the given endpoint data.
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)=0
Gets a UsbDevice from a given vendor:product pair.
size_t m_RootPortGeneration
Definition UsbHub.h:318
virtual void cancelAsyncAndDrain(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t), uintptr_t pParam)=0
virtual bool portSpeed(uint8_t, UsbSpeed &)
Definition UsbHub.h:325
virtual void releaseDeviceAddress(uint8_t)
Definition UsbHub.h:336
virtual size_t currentRootPortGeneration(size_t port) const
Definition UsbHub.h:383
virtual MUST_USE_RESULT bool addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes, void(*pCallback)(uintptr_t, ssize_t), UsbInterruptInHandle &handle, uintptr_t pParam=0)=0
Adds an owned recurring interrupt-IN transaction.
UsbHub * rootHub() const
Definition UsbHub.h:365
Mutex m_EnumerationLock
Definition UsbHub.h:295
bool m_IsRootHub
Definition UsbHub.h:312
virtual bool inInterruptCallbackContext() const
Definition UsbHub.h:351
virtual MUST_USE_RESULT bool doAsync(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t)=0, uintptr_t pParam=0)=0
virtual MUST_USE_RESULT bool cancelInterruptInAndDrain(const UsbInterruptInToken &token, void(*callback)(uintptr_t, ssize_t), uintptr_t parameter, bool producerAlreadyStopped)=0
uint8_t m_RootPort
Definition UsbHub.h:315
ExtensibleBitmap m_UsedAddresses
Definition UsbHub.h:289
Structure used synchronous transactions.
Definition UsbHub.h:259