The Pedigree Project 0.1
Ohci.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 OHCI_H
21#define OHCI_H
22#include "pedigree/kernel/Atomic.h"
23#include "pedigree/kernel/Spinlock.h"
24#include "pedigree/kernel/compiler.h"
25#include "pedigree/kernel/machine/IrqHandler.h"
26#include "pedigree/kernel/machine/types.h"
27#include "pedigree/kernel/process/Mutex.h"
28#include "pedigree/kernel/process/OperationBarrier.h"
29#include "pedigree/kernel/process/Semaphore.h"
30#include "pedigree/kernel/processor/MemoryRegion.h"
31#include "pedigree/kernel/processor/types.h"
32#include "pedigree/kernel/utilities/ExtensibleBitmap.h"
33#include "pedigree/kernel/utilities/List.h"
34#include "pedigree/kernel/utilities/RequestQueue.h"
35#include "pedigree/kernel/utilities/String.h"
36#include "pedigree/kernel/utilities/new"
37
38#include <config.h>
39
40#include "CallbackDelivery.h"
41#include "PortChangeRequest.h"
42#include "TransferCompletion.h"
43#include "modules/system/usb/Usb.h"
44#include "modules/system/usb/UsbHub.h"
45
46class Device;
47class IoBase;
48
50class Ohci : public UsbHub,
51#if X86_COMMON
52 public IrqHandler,
53#endif
54 public RequestQueue {
55 private:
56 static constexpr size_t EdRegionBytes = 4096;
57 static constexpr size_t EdRegionOffsetMask = EdRegionBytes - 1;
58
59#if THREADS
60 using ControllerLock = Mutex;
61#else
62 // Non-threaded kernels still need IRQ-safe exclusion, but Mutex has no
63 // implementation in that configuration.
65#endif
66
67#if X86_COMMON
69#else
71#endif
72
74 enum Lists { PeriodicList = 0x4, IsochronousList = 0x8, ControlList = 0x10, BulkList = 0x20 };
75
76 public:
77 Ohci(Device* pDev);
78 virtual ~Ohci();
79
80 bool initialised() const {
81 return m_Initialised;
82 }
83
84 struct TD {
85 uint32_t res0 : 18;
86 uint32_t bBuffRounding : 1;
87 uint32_t nPid : 2;
88 uint32_t nIntDelay : 3;
89 uint32_t bDataToggleSrc : 1;
90 uint32_t bDataToggle : 1;
91 uint32_t nErrorCount : 2;
92 uint32_t nStatus : 4;
93 uint32_t pBufferStart;
94 uint32_t res1 : 4;
95 uint32_t pNext : 28;
96 uint32_t pBufferEnd;
97
98 // Custom TD fields
99 uint16_t nBufferSize;
100 uint16_t nNextTDIndex;
101 bool bLast;
102
103 size_t id;
104
105 // Possible values for status
106 enum StatusCodes { CrcError = 1, Stall = 4 };
107
108 UsbError getError() {
109 switch (nStatus) {
110 case CrcError:
111 return ::CrcError;
112 case Stall:
113 return ::Stall;
114 default:
115 return TransactionError;
116 }
117 }
118
119 } PACKED ALIGN(16);
120
121 struct ED {
122 uint32_t nAddress : 7;
123 uint32_t nEndpoint : 4;
124 uint32_t bOut : 1;
125 uint32_t bIn : 1;
126 uint32_t bLoSpeed : 1;
127 uint32_t bSkip : 1;
128 uint32_t bIso : 1;
129 uint32_t nMaxPacketSize : 11;
130 uint32_t res0 : 9;
131 uint32_t pTailTD : 28;
132 uint32_t bHalted : 1;
133 uint32_t bToggleCarry : 1;
134 uint32_t res1 : 2;
135 uint32_t pHeadTD : 28;
136 uint32_t res2 : 4;
137 uint32_t pNext : 28;
138
139 struct MetaData {
141 void (*pCallback)(uintptr_t, ssize_t);
142 uintptr_t pParam;
143
144 UsbEndpoint endpointInfo;
145
146 bool bPeriodic;
147 bool bBuildFailed;
148 TD* pFirstTD;
149 TD* pLastTD;
150 size_t nTotalBytes;
151
152 ED* pPrev;
153 ED* pNext;
154
155 List<TD*> tdList;
156 List<TD*> completedTdList;
157
158 bool bIgnore;
159
160 bool bLinked;
161
162 Lists edType;
164 bool acceptedOperation;
165
166 size_t id;
167 }* pMetaData;
168 } PACKED ALIGN(16);
169
170 struct Hcca {
171 uint32_t pInterruptEDList[32];
172 uint16_t nFrameNumber;
173 uint16_t res0;
174 volatile uint32_t pDoneHead;
175 } PACKED;
176
177 virtual void getName(String& str) {
178 str.assign("OHCI", 5);
179 }
180
181 virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid,
182 uintptr_t pBuffer, size_t nBytes);
183 virtual uintptr_t createTransaction(UsbEndpoint endpointInfo);
184
185 MUST_USE_RESULT virtual bool doAsync(uintptr_t pTransaction,
186 void (*pCallback)(uintptr_t, ssize_t) = 0,
187 uintptr_t pParam = 0);
188 MUST_USE_RESULT virtual bool addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer,
189 uint16_t nBytes,
190 void (*pCallback)(uintptr_t, ssize_t),
191 UsbInterruptInHandle& handle,
192 uintptr_t pParam = 0);
193
195#if X86_COMMON
196 IrqDisposition irq(irq_id_t number) override;
197#endif
198
199 virtual bool portReset(uint8_t nPort, bool bErrorResponse = false);
200
201 protected:
202 virtual void cancelAsyncAndDrain(uintptr_t pTransaction, void (*pCallback)(uintptr_t, ssize_t),
203 uintptr_t pParam);
205 void (*callback)(uintptr_t, ssize_t),
206 uintptr_t parameter,
207 bool producerAlreadyStopped) override;
211 void replaySuppressedConnectionChange(size_t port) override;
212
213 virtual uint64_t executeRequest(uint64_t p1 = 0, uint64_t p2 = 0, uint64_t p3 = 0,
214 uint64_t p4 = 0, uint64_t p5 = 0, uint64_t p6 = 0,
215 uint64_t p7 = 0, uint64_t p8 = 0);
216 void cancelRequest(const Request& request) override;
217
218 private:
220 void stop(Lists list);
221
223 void start(Lists list);
224
231 void setRootHubStatusChangeSource(bool enabled);
232
234 void transitionControllerState(uint32_t control, const char* timeoutMessage);
235
237 void removeED(ED* pED);
238
240 void detachED(ED* pED);
241
243 void removeFromFullSchedule(ED* pED);
244
246 void removeFromDequeueList(ED* pED);
247
249 void reclaimTransferDescriptors(ED* pED);
250
252 void retireEDStorage(ED* pED);
253
256 ED* pED, const UsbHcd::TransferCompletion::Claim& claim);
257
260
261 static void finishDeferredCompletion(void* context);
262
264 inline physical_uintptr_t vtp_ed(ED* pED) {
265 if (!pED || !pED->pMetaData)
266 return 0;
267
268 size_t id = pED->pMetaData->id & EdRegionOffsetMask;
269 Lists type = pED->pMetaData->edType;
270 switch (type) {
271 case ControlList:
272 return m_pControlEDListPhys + (id * sizeof(ED));
273 case BulkList:
274 return m_pBulkEDListPhys + (id * sizeof(ED));
275 default:
276 return 0;
277 }
278 }
279
281 inline ED* ptv_ed(physical_uintptr_t phys) {
282 if (!phys)
283 return 0;
284
285 // Figure out which list the ED was in.
288 if ((m_pControlEDListPhys <= phys) && (phys < (m_pControlEDListPhys + EdRegionBytes))) {
289 return &m_pControlEDList[(phys - m_pControlEDListPhys) / sizeof(ED)];
290 } else if ((m_pBulkEDListPhys <= phys) && (phys < (m_pBulkEDListPhys + EdRegionBytes))) {
291 return &m_pBulkEDList[(phys - m_pBulkEDListPhys) / sizeof(ED)];
292 } else
293 return 0;
294 }
295
296 enum OhciConstants {
297 OhciVersion = 0x00,
298 OhciControl = 0x04, // HcControl register
299 OhciCommandStatus = 0x08, // HcCommandStatus register
300 OhciInterruptStatus = 0x0c, // HcInterruptStatus register
301 OhciInterruptEnable = 0x10, // HcIntrerruptEnable register
302 OhciInterruptDisable = 0x14, // HcIntrerruptDisable register
303 OhciHcca = 0x18, // HcHCCA register
304 OhciControlHeadED = 0x20, // HcControlHeadED register
305 OhciControlCurrentED = 0x24, // HcControlCurrentED register
306 OhciBulkHeadED = 0x28, // HcBulkHeadED register
307 OhciBulkCurrentED = 0x2c, // HcBulkCurrentED register
308 OhciFmInterval = 0x34,
309 OhciRhDescriptorA = 0x48, // HcRhDescriptorA register
310 OhciRhStatus = 0x50,
311 OhciRhPortStatus = 0x54, // HcRhPortStatus registers
312
313 OhciControlStateFunctionalMask = 0xC0,
314
315 OhciControlInterruptRoute = 0x100,
316 OhciControlStateRunning = 0x80, // HostControllerFunctionalState bits for USBOPERATIONAL
317 OhciControlStateSuspended = 0xC0, // HostControllerFunctionalState bits for USBSUSPEND
318 OhciControlListsEnable = 0x30, // 0x34 // PeriodicListEnable,
319 // ControlListEnable and BulkListEnable
320 // bits
321
322 OhciCommandRequestOwnership = 0x08, // Requests ownership change
323 OhciCommandBulkListFilled = 0x04, // BulkListFilled bit
324 OhciCommandControlListFilled = 0x02, // ControlListFilled bit
325 OhciCommandHcReset = 0x01, // HostControllerReset bit
326
327 OhciInterruptMIE = 0x80000000, // MasterInterruptEnable bit
328 OhciInterruptOwnershipChange = 0x40000000,
329 OhciInterruptRhStsChange = 0x40, // RootHubStatusChange bit
330 OhciInterruptFrameNumberOverflow = 0x20,
331 OhciInterruptUnrecoverableError = 0x10,
332 OhciInterruptResumeDetected = 0x08,
333 OhciInterruptWbDoneHead = 0x02, // WritebackDoneHead bit
334 OhciInterruptSchedulingOverrun = 0x01,
335 OhciInterruptStartOfFrame = 0x04, // StartOfFrame interrupt
336 OhciInterruptAll = OhciInterruptMIE | OhciInterruptOwnershipChange | 0x7F,
337 OhciInterruptOperational = OhciInterruptMIE | OhciInterruptFrameNumberOverflow |
338 OhciInterruptUnrecoverableError | OhciInterruptWbDoneHead |
339 OhciInterruptSchedulingOverrun,
340
341 // This bit reads as LPSC but writes as SetGlobalPower. It must never
342 // be echoed as a generic change acknowledgement.
343 OhciRhHubStsSetGlobalPower = 0x10000,
344 OhciRhHubStsOverCurrentCh = 0x20000,
345
346 OhciRhPortStsResCh = 0x100000, // PortResetStatusChange bit
347 OhciRhPortStsOverCurrentCh = 0x80000,
348 OhciRhPortStsSuspendCh = 0x40000,
349 OhciRhPortStsEnableCh = 0x20000,
350 OhciRhPortStsConnStsCh = 0x10000, // ConnectStatusChange bit
351 OhciRhPortStsChangeMask = OhciRhPortStsResCh | OhciRhPortStsOverCurrentCh |
352 OhciRhPortStsSuspendCh | OhciRhPortStsEnableCh |
353 OhciRhPortStsConnStsCh,
354 OhciRhPortStsLoSpeed = 0x200, // LowSpeedDeviceAttached bit
355 OhciRhPortStsPower = 0x100, // PortPowerStatus / SetPortPower bit
356 OhciRhPortStsReset = 0x10, // SetPortReset bit
357 OhciRhPortStsEnable = 0x02, // SetPortEnable bit
358 OhciRhPortStsConnected = 0x01, // CurrentConnectStatus bit
359 };
360
361 IoBase* m_pBase;
362
363 uint8_t m_nPorts;
364 bool m_Initialised;
365 UsbHcd::PortChangeRequest m_PortChanges[UsbHcd::OhciRootPortCount];
366 UsbHcd::DeferredPortChanges m_DeferredPortChanges;
367
370
374
375 Hcca* m_pHcca;
376 uintptr_t m_pHccaPhys;
377
380
383
386 bool m_RootHubStatusChangeDesired;
387 bool m_PortResetActive;
388 Atomic<size_t> m_TeardownPhase;
389
390 Spinlock m_ScheduleChangeLock;
391
394
397
400
401 ED* m_pPeriodicEDList;
402 uintptr_t m_pPeriodicEDListPhys;
403 ExtensibleBitmap m_PeriodicEDBitmap;
404
405 ED* m_pControlEDList;
406 uintptr_t m_pControlEDListPhys;
407 ExtensibleBitmap m_ControlEDBitmap;
408
409 ED* m_pBulkEDList;
410 uintptr_t m_pBulkEDListPhys;
411 ExtensibleBitmap m_BulkEDBitmap;
412
413 TD* m_pTDList;
414 uintptr_t m_pTDListPhys;
415 ExtensibleBitmap m_TDBitmap;
416
417 // Pointers to the current bulk and control queue heads (can be null)
418 ED* m_pBulkQueueHead;
419 ED* m_pControlQueueHead;
420
421 // Pointers to the current bulk and control queue tails
422 ED* m_pBulkQueueTail;
423 ED* m_pControlQueueTail;
424
425 // Pointer to the current periodic queue tail
426 ED* m_pPeriodicQueueTail;
427
430
434
437
440
441 MemoryRegion m_OhciMR;
442
445
448
451
454 irq_id_t m_IrqId;
455
456 Ohci(const Ohci&);
457 void operator=(const Ohci&);
458};
459
460#endif
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
Definition Ohci.h:54
void cancelRequest(const Request &request) override
Definition Ohci.cc:1792
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 Ohci.cc:1182
IrqDisposition irq(irq_id_t number) override
IRQ handler.
Definition Ohci.cc:817
ED * ptv_ed(physical_uintptr_t phys)
Converts a physical address to an ED pointer. Maybe.
Definition Ohci.h:281
virtual MUST_USE_RESULT bool doAsync(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t)=0, uintptr_t pParam=0)
Definition Ohci.cc:1383
void terminalizeEDForTeardown(ED *pED, List< UsbHcd::CallbackDeliveryQueue::Record * > &completions)
Definition Ohci.cc:796
MUST_USE_RESULT bool cancelInterruptInAndDrain(const UsbInterruptInToken &token, void(*callback)(uintptr_t, ssize_t), uintptr_t parameter, bool producerAlreadyStopped) override
Definition Ohci.cc:1632
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)
Creates a new transaction with the given endpoint data.
Definition Ohci.cc:1322
OperationBarrier m_CancellationOperations
Definition Ohci.h:450
bool inInterruptCallbackContext() const override
Definition Ohci.h:208
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 Ohci.cc:1762
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)
Gets a UsbDevice from a given vendor:product pair.
Definition Ohci.cc:1690
void transitionControllerState(uint32_t control, const char *timeoutMessage)
Definition Ohci.cc:603
Spinlock m_ControlListChangeLock
Lock for changing the control list.
Definition Ohci.h:396
void detachED(ED *pED)
Definition Ohci.cc:645
void removeFromFullSchedule(ED *pED)
Definition Ohci.cc:713
void reclaimTransferDescriptors(ED *pED)
Definition Ohci.cc:735
Spinlock m_PeriodicListChangeLock
Lock for changing the periodic list.
Definition Ohci.h:393
Spinlock m_BulkListChangeLock
Lock for changing the bulk list.
Definition Ohci.h:399
IrqProcessingLock m_IrqProcessingLock
Lock for modifying the schedule list itself (m_FullSchedule)
Definition Ohci.h:379
Lists
Enumeration of lists that can be stopped or started.
Definition Ohci.h:74
void stop(Lists list)
Stops the controller from processing the given list.
Definition Ohci.cc:1798
OperationBarrier m_AcceptedOperations
Definition Ohci.h:453
UsbHcd::CallbackDeliveryQueue::Record * prepareCompletion(ED *pED, const UsbHcd::TransferCompletion::Claim &claim)
Definition Ohci.cc:781
void setRootHubStatusChangeSource(bool enabled)
Definition Ohci.cc:598
List< ED * > m_FullSchedule
Definition Ohci.h:433
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 Ohci.cc:1643
Semaphore m_DequeueCount
Semaphore for the dequeue list.
Definition Ohci.h:439
void removeED(ED *pED)
Detaches an ED and queues it for reclamation at the next frame.
Definition Ohci.cc:618
UsbHcd::CallbackDeliveryQueue m_CompletionDeliveries
Definition Ohci.h:382
OperationBarrier m_CallbackOperations
Definition Ohci.h:444
Spinlock m_RootHubLock
Serializes root-hub register access between reset and IRQ paths.
Definition Ohci.h:385
virtual void getName(String &str)
Definition Ohci.h:177
Spinlock m_DequeueListLock
Dequeue list lock.
Definition Ohci.h:429
OperationBarrier m_SubmissionOperations
Definition Ohci.h:447
void retireEDStorage(ED *pED)
Definition Ohci.cc:758
void replaySuppressedConnectionChange(size_t port) override
Definition Ohci.cc:1658
void removeFromDequeueList(ED *pED)
Definition Ohci.cc:724
List< ED * > m_DequeueList
List of EDs ready for dequeue (reclaiming)
Definition Ohci.h:436
ControllerLock m_PortResetMutex
Definition Ohci.h:373
virtual void cancelAsyncAndDrain(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t), uintptr_t pParam)
Definition Ohci.cc:1541
ControllerLock m_Mutex
Global lock.
Definition Ohci.h:369
physical_uintptr_t vtp_ed(ED *pED)
Converts a software ED pointer to a physical address.
Definition Ohci.h:264
IrqDisposition
Definition IrqHandler.h:31
void(* pCallback)(uintptr_t, ssize_t)
Definition Ohci.h:141