The Pedigree Project 0.1
Ehci.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 EHCI_H
21#define EHCI_H
22#include "pedigree/kernel/Spinlock.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/machine/IrqHandler.h"
25#include "pedigree/kernel/machine/types.h"
26#include "pedigree/kernel/process/Mutex.h"
27#include "pedigree/kernel/process/OperationBarrier.h"
28#include "pedigree/kernel/process/OwnedThread.h"
29#include "pedigree/kernel/process/Semaphore.h"
30#include "pedigree/kernel/processor/InterruptHandler.h"
31#include "pedigree/kernel/processor/MemoryRegion.h"
32#include "pedigree/kernel/processor/state_forward.h"
33#include "pedigree/kernel/processor/types.h"
34#include "pedigree/kernel/utilities/ExtensibleBitmap.h"
35#include "pedigree/kernel/utilities/RequestQueue.h"
36#include "pedigree/kernel/utilities/String.h"
37
38#include <config.h>
39
40#include "CallbackDelivery.h"
41#include "EhciHandoff.h"
42#include "PortChangeRequest.h"
43#include "TransferCompletion.h"
44#include "modules/system/usb/Usb.h"
45#include "modules/system/usb/UsbHub.h"
46
47class Device;
48class IoBase;
49
51class Ehci : public UsbHub,
52#if X86_COMMON
53 public IrqHandler,
54#else
55 public InterruptHandler,
56#endif
57 public RequestQueue {
58 private:
59#if X86_COMMON
61#else
63#endif
64
65 public:
66 Ehci(Device* pDev);
67 virtual ~Ehci();
68
69 bool initialiseController();
70 void startFirmwareRecovery();
71
72 struct qTD {
73 uint32_t bNextInvalid : 1;
74 uint32_t res0 : 4;
75 uint32_t pNext : 27;
76 uint32_t bAltNextInvalid : 1;
77 uint32_t res1 : 4;
78 uint32_t pAltNext : 27;
79 uint32_t nStatus : 8;
80 uint32_t nPid : 2;
81 uint32_t nErr : 2;
82 uint32_t nPage : 3;
83 uint32_t bIoc : 1;
84 uint32_t nBytes : 15;
85 uint32_t bDataToggle : 1;
86 uint32_t nOffset : 12;
87 uint32_t pPage0 : 20;
88 uint32_t res2 : 12;
89 uint32_t pPage1 : 20;
90 uint32_t res3 : 12;
91 uint32_t pPage2 : 20;
92 uint32_t res4 : 12;
93 uint32_t pPage3 : 20;
94 uint32_t res5 : 12;
95 uint32_t pPage4 : 20;
96
97 // 64-bit qTD fields
98 uint32_t extend0;
99 uint32_t extend1;
100 uint32_t extend2;
101 uint32_t extend3;
102 uint32_t extend4;
103
104 // Custom qTD fields
105 uint16_t nBufferSize;
106 bool processed;
107 // Host-only pointer to an optional below-4 GiB bounce transfer.
108 uint64_t pDma;
109 // Arena entries need a 32-byte stride, while QH overlays start at byte 16.
110 uint8_t padding[1];
111
112 // Possible values for status
113 enum StatusCodes {
114 Halted = 0x40,
115 };
116
117 UsbError getError() {
118 if (nStatus & Halted)
119 return Stall;
120 return TransactionError;
121 }
122 } PACKED ALIGN(4);
123
124 static_assert(sizeof(qTD) == 64);
125 static_assert(alignof(qTD) == 4);
126
127 struct QH {
128 uint32_t bNextInvalid : 1;
129 uint32_t nNextType : 2;
130 uint32_t res0 : 2;
131 uint32_t pNext : 27;
132 uint32_t nAddress : 7;
133 uint32_t bInactiveNext : 1;
134 uint32_t nEndpoint : 4;
135 uint32_t nSpeed : 2;
136 uint32_t bDataToggleSrc : 1;
137 uint32_t hrcl : 1;
138 uint32_t nMaxPacketSize : 11;
139 uint32_t bControlEndpoint : 1;
140 uint32_t nNakReload : 4;
141 uint32_t ism : 8;
142 uint32_t scm : 8;
143 uint32_t nHubAddress : 7;
144 uint32_t nHubPort : 7;
145 uint32_t mult : 2;
146 uint32_t res1 : 5;
147 uint32_t pQTD : 27;
148
149 qTD overlay;
150
151 struct MetaData {
152 MetaData()
153 : pCallback(nullptr),
154 pParam(0),
155 periodicGeneration(0),
156 periodicFrameIndex(static_cast<size_t>(-1)),
157 periodicInterval(0),
158 periodicPending(false),
159 periodicTemplate{},
160 bPeriodic(false),
161 bBuildFailed(false),
162 pFirstQTD(nullptr),
163 pLastQTD(nullptr),
164 nTotalBytes(0),
165 pPrev(nullptr),
166 pNext(nullptr),
167 bIgnore(false),
168 completion() {}
169
172 void (*pCallback)(uintptr_t, ssize_t);
173 uintptr_t pParam;
174 size_t periodicGeneration;
175 size_t periodicFrameIndex;
176 size_t periodicInterval;
177 bool periodicPending;
178 qTD periodicTemplate;
179
180 bool bPeriodic;
181 bool bBuildFailed;
182 qTD* pFirstQTD;
183 qTD* pLastQTD;
184 size_t nTotalBytes;
185
186 QH* pPrev;
187 QH* pNext;
188
189 bool bIgnore;
192 }* pMetaData;
193 } PACKED ALIGN(32);
194
195 static_assert(__builtin_offsetof(QH, overlay) == 0x10);
196 virtual void getName(String& str) {
197 str.assign("EHCI", 5);
198 }
199
200 virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid,
201 uintptr_t pBuffer, size_t nBytes);
202 virtual uintptr_t createTransaction(UsbEndpoint endpointInfo);
203
204 MUST_USE_RESULT virtual bool doAsync(uintptr_t pTransaction,
205 void (*pCallback)(uintptr_t, ssize_t) = 0,
206 uintptr_t pParam = 0);
207 MUST_USE_RESULT virtual bool addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer,
208 uint16_t nBytes,
209 void (*pCallback)(uintptr_t, ssize_t),
210 UsbInterruptInHandle& handle,
211 uintptr_t pParam = 0);
212
214#if X86_COMMON
215 IrqDisposition irq(irq_id_t number) override;
216#else
217 virtual void interrupt(size_t number, InterruptState& state);
218#endif
219
220 void doDequeue();
221
222 virtual bool portReset(uint8_t nPort, bool bErrorResponse = false);
223
224 protected:
225 virtual void cancelAsyncAndDrain(uintptr_t pTransaction, void (*pCallback)(uintptr_t, ssize_t),
226 uintptr_t pParam);
228 void (*callback)(uintptr_t, ssize_t),
229 uintptr_t parameter,
230 bool producerAlreadyStopped) override;
234 void replaySuppressedConnectionChange(size_t port) override;
235
236 virtual uint64_t executeRequest(uint64_t p1 = 0, uint64_t p2 = 0, uint64_t p3 = 0,
237 uint64_t p4 = 0, uint64_t p5 = 0, uint64_t p6 = 0,
238 uint64_t p7 = 0, uint64_t p8 = 0);
239 void cancelRequest(const Request& request) override;
240
241 private:
242 enum EhciConstants {
243 EHCI_CAPLENGTH = 0x00, // Capability Registers Length
244 EHCI_HCIVERSION = 0x02, // Host Controller Interface Version
245 EHCI_HCSPARAMS = 0x04, // Host Controller Structural Parameters
246 EHCI_HCCPARAMS = 0x08, // Host Controller Structural Parameters
247
248 EHCI_CMD = 0x00, // Command register
249 EHCI_STS = 0x04, // Status register
250 EHCI_INTR = 0x08, // Intrerrupt Enable register
251 EHCI_CTRLDSEG = 0x10, // Control Data Structure Segment Register
252 EHCI_FRINDEX = 0x0c, // Periodic Frame Index register
253 EHCI_PERIODICLP = 0x14, // Periodic List Pointer register
254 EHCI_ASYNCLP = 0x18, // Async List Pointer register
255 EHCI_CFGFLAG = 0x40, // Config Flag register
256 EHCI_PORTSC = 0x44, // Port Status/Control registers
257
258 EHCI_CMD_ASYNCLE = 0x20, // Async List Enable bit
259 EHCI_CMD_PERIODICLE = 0x10, // Periodic List Enable bit
260 EHCI_CMD_HCRES = 0x02, // Host Controller Reset bit
261 EHCI_CMD_RUN = 0x01, // Run bit
262
263 EHCI_STS_HALTED = 0x1000, // Host Controller Halted bit
264 EHCI_STS_SYSERR = 0x10, // Host System Error
265 EHCI_STS_ASYNCADVANCE = 0x20, // Async Advance
266 EHCI_STS_PORTCH = 0x4, // Port Change Detect bit
267 EHCI_STS_ERR = 0x2, // Error bit
268 EHCI_STS_INT = 0x1, // On Completition Interrupt bit
269
270 EHCI_PORTSC_PPOW = 0x1000, // Port Power bit
271 EHCI_PORTSC_PRES = 0x100, // Port Reset bit
272 EHCI_PORTSC_OCCH = 0x20, // Over-current Change bit
273 EHCI_PORTSC_ENCH = 0x8, // Port Enable/Disable Change bit
274 EHCI_PORTSC_EN = 0x4, // Port Enabled bit
275 EHCI_PORTSC_CSCH = 0x2, // Port Connect Status Change bit
276 EHCI_PORTSC_CONN = 0x1, // Port Connected bit
277 };
278
280 static uint32_t portControlValue(uint32_t value) {
281 return value & ~(EHCI_PORTSC_OCCH | EHCI_PORTSC_ENCH | EHCI_PORTSC_CSCH);
282 }
283
284 void modifyPortControl(size_t portRegister, uint32_t clearMask, uint32_t setMask);
285
286 uintptr_t createTransactionAdmitted(UsbEndpoint endpointInfo);
287 void addTransferToTransactionAdmitted(uintptr_t pTransaction, bool bToggle, UsbPid pid,
288 uintptr_t pBuffer, size_t nBytes);
289 void releaseQtdChainLocked(QH* qh);
290 void reclaimQhLocked(size_t transaction);
291 void captureCompletionLocked(size_t transaction, QH* qh,
294
295 static void finishDeferredCompletion(void* context);
296 static void rearmPeriodicCompletion(void* context);
297 static void destroyPeriodicCompletion(void* context);
298 void rebuildPeriodicScheduleLocked();
299
300 bool beginStartupActivity() override;
301 void endStartupActivity(UsbStartup::Outcome outcome) override;
302 void completeInitialPort(size_t port);
303 void shutdownController();
304 bool acquireFirmware(uint16_t capability);
305 void returnToFirmware();
306 static int recoverFirmware(void* parameter);
307
308 EhciHandoff::State m_Handoff;
309 uint16_t m_FirmwarePciCommand = 0;
310 bool m_ControllerStopped = false;
311 bool m_HardwareTouched = false;
312 Spinlock m_StartupLock;
313 UsbStartup::State m_Startup;
314 uint16_t m_InitialPortMask = 0;
315 Semaphore m_RecoveryWake{0};
316 Atomic<bool> m_RecoveryStopping{false};
317 OwnedThread m_RecoveryThread;
318
319 IoBase* m_pBase;
320 bool m_HardwareOwned = false;
321
322 uint8_t m_nOpRegsOffset;
323 uint8_t m_nPorts;
324 UsbHcd::PortChangeRequest m_PortChanges[UsbHcd::EhciRootPortCount];
325 UsbHcd::DeferredPortChanges m_DeferredPortChanges;
326
327 Mutex m_Mutex;
328
333 Spinlock m_QueueListChangeLock;
334
335 QH* m_pQHList;
336 uintptr_t m_pQHListPhys;
337 ExtensibleBitmap m_QHBitmap;
338
339 uint32_t* m_pFrameList;
340 uintptr_t m_pFrameListPhys;
341 ExtensibleBitmap m_FrameBitmap;
342
343 qTD* m_pqTDList;
344 uintptr_t m_pqTDListPhys;
345 ExtensibleBitmap m_qTDBitmap;
346
347 // Pointer to the current queue tail, which allows insertion of new queue
348 // heads to the asynchronous schedule.
349 QH* m_pCurrentQueueTail;
350
351 // Pointer to the current queue head. Used to fill pNext automatically
352 // for new queue heads inserted to the asynchronous schedule.
353 QH* m_pCurrentQueueHead;
354
355 MemoryRegion m_EhciMR;
356
359 Atomic<bool> m_DequeueStopping;
360 OwnedThread m_DequeueThread;
361
368 irq_id_t m_IrqId;
369 bool m_InterruptHandlerRegistered;
372
373 Ehci(const Ehci&);
374 void operator=(const Ehci&);
375};
376
377#endif
Definition Ehci.h:57
UsbHcd::CallbackDeliveryQueue m_CompletionDeliveries
Definition Ehci.h:332
MUST_USE_RESULT bool cancelInterruptInAndDrain(const UsbInterruptInToken &token, void(*callback)(uintptr_t, ssize_t), uintptr_t parameter, bool producerAlreadyStopped) override
Definition Ehci.cc:1761
virtual void getName(String &str)
Definition Ehci.h:196
void replaySuppressedConnectionChange(size_t port) override
Definition Ehci.cc:1966
IrqDisposition irq(irq_id_t number) override
IRQ handler.
Definition Ehci.cc:1012
static uint32_t portControlValue(uint32_t value)
Definition Ehci.h:280
Semaphore m_DequeueCount
Definition Ehci.h:358
virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer, size_t nBytes)
Adds a new transfer to an existent transaction.
Definition Ehci.cc:1313
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)
Gets a UsbDevice from a given vendor:product pair.
Definition Ehci.cc:2005
virtual MUST_USE_RESULT bool doAsync(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t)=0, uintptr_t pParam=0)
Definition Ehci.cc:1587
IrqProcessingLock m_IrqProcessingLock
Definition Ehci.h:330
Atomic< size_t > m_InterruptClosure
Definition Ehci.h:371
OperationBarrier m_SubmissionOperations
Definition Ehci.h:363
virtual void cancelAsyncAndDrain(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t), uintptr_t pParam)
Definition Ehci.cc:1661
virtual uint64_t executeRequest(uint64_t p1=0, uint64_t p2=0, uint64_t p3=0, uint64_t p4=0, uint64_t p5=0, uint64_t p6=0, uint64_t p7=0, uint64_t p8=0)
Definition Ehci.cc:2062
OperationBarrier m_CallbackOperations
Definition Ehci.h:367
OperationBarrier m_CancelOperations
Definition Ehci.h:365
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)
Adds an owned recurring interrupt-IN transaction.
Definition Ehci.cc:1839
void cancelRequest(const Request &request) override
Definition Ehci.cc:2105
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)
Creates a new transaction with the given endpoint data.
Definition Ehci.cc:1533
bool inInterruptCallbackContext() const override
Definition Ehci.h:231
Abstract base class for interrupt-handlers.
Abstrace base class for hardware I/O capabilities.
Definition IoBase.h:32
Definition List.h:61
Special memory entity in the kernel's virtual address space.
Definition Mutex.h:56
IrqDisposition
Definition IrqHandler.h:31
void(* pCallback)(uintptr_t, ssize_t)
Definition Ehci.h:172
UsbHcd::TransferCompletion completion
Definition Ehci.h:191