The Pedigree Project  0.1
Ohci.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 "Ohci.h"
21 #include "modules/system/usb/Usb.h"
22 #include "modules/system/usb/UsbHub.h"
23 #include "pedigree/kernel/LockGuard.h"
24 #include "pedigree/kernel/Log.h"
25 #include "pedigree/kernel/Spinlock.h"
26 #include "pedigree/kernel/machine/Device.h"
27 #include "pedigree/kernel/machine/IrqManager.h"
28 #include "pedigree/kernel/machine/Machine.h"
29 #include "pedigree/kernel/machine/Pci.h"
30 #include "pedigree/kernel/machine/types.h"
31 #include "pedigree/kernel/process/Mutex.h"
32 #include "pedigree/kernel/processor/IoBase.h"
33 #include "pedigree/kernel/processor/MemoryRegion.h"
34 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
35 #include "pedigree/kernel/processor/Processor.h"
36 #include "pedigree/kernel/processor/ProcessorInformation.h"
37 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
38 #include "pedigree/kernel/processor/state_forward.h"
39 #include "pedigree/kernel/processor/types.h"
40 #include "pedigree/kernel/time/Time.h"
41 #include "pedigree/kernel/utilities/ExtensibleBitmap.h"
42 #include "pedigree/kernel/utilities/Iterator.h"
43 #include "pedigree/kernel/utilities/List.h"
44 #include "pedigree/kernel/utilities/RequestQueue.h"
45 #include "pedigree/kernel/utilities/String.h"
46 #include "pedigree/kernel/utilities/Vector.h"
47 #include "pedigree/kernel/utilities/utility.h"
48 
49 #define INDEX_FROM_TD(ptr) \
50  (((reinterpret_cast<uintptr_t>((ptr)) & 0xFFF) / sizeof(TD)))
51 #define PHYS_TD(idx) (m_pTDListPhys + ((idx) * sizeof(TD)))
52 
53 Ohci::Ohci(Device *pDev)
54  : UsbHub(pDev), RequestQueue("OHCI"), m_Mutex(false),
55  m_ScheduleChangeLock(), m_PeriodicListChangeLock(),
56  m_ControlListChangeLock(), m_BulkListChangeLock(), m_PeriodicEDBitmap(),
57  m_ControlEDBitmap(), m_BulkEDBitmap(), m_pBulkQueueHead(0),
58  m_pControlQueueHead(0), m_pBulkQueueTail(0), m_pControlQueueTail(0),
59  m_pPeriodicQueueTail(0), m_DequeueListLock(), m_DequeueList(),
60  m_DequeueCount(0), m_OhciMR("Ohci-MR")
61 {
62  setSpecificType(String("OHCI"));
63 
64  // Allocate the memory region
65  if (!PhysicalMemoryManager::instance().allocateRegion(
68  {
69  ERROR("USB: OHCI: Couldn't allocate memory region!");
70  return;
71  }
72 
73  uintptr_t virtualBase =
74  reinterpret_cast<uintptr_t>(m_OhciMR.virtualAddress());
75  uintptr_t physicalBase = m_OhciMR.physicalAddress();
76 
77  m_pHcca = reinterpret_cast<Hcca *>(virtualBase);
78  m_pBulkEDList = reinterpret_cast<ED *>(virtualBase + 0x1000);
79  m_pControlEDList = reinterpret_cast<ED *>(virtualBase + 0x2000);
80  m_pPeriodicEDList = reinterpret_cast<ED *>(virtualBase + 0x3000);
81  m_pTDList = reinterpret_cast<TD *>(virtualBase + 0x4000);
82 
83  m_pHccaPhys = physicalBase;
84  m_pBulkEDListPhys = physicalBase + 0x1000;
85  m_pControlEDListPhys = physicalBase + 0x2000;
86  m_pPeriodicEDListPhys = physicalBase + 0x3000;
87  m_pTDListPhys = physicalBase + 0x4000;
88 
89  // Clear out the HCCA block.
90  ByteSet(m_pHcca, 0, 0x800);
91 
92  // Get an ED for the periodic list
93  m_PeriodicEDBitmap.set(0);
94  ED *pPeriodicED = m_pPeriodicEDList;
95  ByteSet(pPeriodicED, 0, sizeof(ED));
96  pPeriodicED->bSkip = true;
97  pPeriodicED->pMetaData = new ED::MetaData;
98  pPeriodicED->pMetaData->id = 0x2000;
99  pPeriodicED->pMetaData->pPrev = pPeriodicED->pMetaData->pNext = pPeriodicED;
100 
101  // Set all HCCA interrupt ED entries to our periodic ED
102  DoubleWordSet(m_pHcca->pInterruptEDList, m_pPeriodicEDListPhys, 3);
103 
104  // Every periodic ED will be added after this one
105  m_pPeriodicQueueTail = pPeriodicED;
106 
107  m_pBulkQueueTail = m_pBulkQueueHead = 0;
108  m_pControlQueueTail = m_pControlQueueHead = 0;
109 
110 #ifdef X86_COMMON
111  // Make sure bus mastering and MMIO are enabled.
112  uint32_t nPciCmdSts = PciBus::instance().readConfigSpace(this, 1);
113  PciBus::instance().writeConfigSpace(this, 1, nPciCmdSts | 0x6);
114 #endif
115 
116  // Grab the ports
117  m_pBase = m_Addresses[0]->m_Io;
118  m_Addresses[0]->map();
119 
120  // Dump the version of the controller and a nice little banner.
121  uint8_t version = m_pBase->read32(OhciVersion) & 0xFF;
122  DEBUG_LOG(
123  "USB: OHCI: starting up - controller is version "
124  << Dec << ((version & 0xF0) >> 4) << "." << (version & 0xF) << Hex
125  << ".");
126 
127  // Determine first of all if the HC is controlled by the BIOS.
128  uint32_t control = m_pBase->read32(OhciControl);
129  if (control & OhciControlInterruptRoute)
130  {
131  // SMM.
132  DEBUG_LOG("USB: OHCI: currently in SMM!");
133  uint32_t status = m_pBase->read32(OhciCommandStatus);
134  m_pBase->write32(
135  status | OhciCommandRequestOwnership, OhciCommandStatus);
136  while ((control = m_pBase->read32(OhciControl)) &
137  OhciControlInterruptRoute)
138  Time::delay(1 * Time::Multiplier::Millisecond);
139  }
140  else
141  {
142  // Chances are good that the BIOS has the thing running.
143  if (control & OhciControlStateFunctionalMask)
144  DEBUG_LOG("USB: OHCI: BIOS is currently in charge.");
145  else
146  DEBUG_LOG("USB: OHCI: not yet operational.");
147 
148  // Throw the controller into operational mode if it isn't.
149  if (!(control & OhciControlStateRunning))
150  m_pBase->write32(OhciControlStateRunning, OhciControl);
151  }
152 
153  // Perform a reset via the UHCI Control register.
154  m_pBase->write32(control & ~OhciControlStateFunctionalMask, OhciControl);
155  Time::delay(200 * Time::Multiplier::Millisecond);
156 
157  // Grab the FM Interval register (5.1.1.4, OHCI spec).
158  uint32_t interval = m_pBase->read32(OhciFmInterval);
159 
160  // Perform a full hardware reset.
161  m_pBase->write32(OhciCommandHcReset, OhciCommandStatus);
162  while (m_pBase->read32(OhciCommandStatus) & OhciCommandHcReset)
163  Time::delay(5 * Time::Multiplier::Millisecond);
164 
165  // We now have 2 ms to complete all operations before we start the
166  // controller. 5.1.1.4, OHCI spec.
167 
168  // Set up the HCCA block.
169  m_pBase->write32(m_pHccaPhys, OhciHcca);
170 
171  // Set up the operational registers.
172  m_pBase->write32(m_pControlEDListPhys, OhciControlHeadED);
173  m_pBase->write32(m_pBulkEDListPhys, OhciBulkHeadED);
174 
175  // Disable and then enable the interrupts we want.
176  m_pBase->write32(0x4000007F, OhciInterruptDisable);
177  m_pBase->write32(
178  OhciInterruptMIE | OhciInterruptWbDoneHead | 0x1 | 0x10 | 0x20,
179  OhciInterruptEnable);
180 
181  // Prepare the control register
182  control = m_pBase->read32(OhciControl);
183  control &=
184  ~(0x3 | 0x3C | OhciControlStateFunctionalMask |
185  OhciControlInterruptRoute); // Control bulk service, List enable, etc
186  control |= OhciControlListsEnable | OhciControlStateRunning |
187  0x3; // 4:1 control/bulk ED ratio
188  m_pBase->write32(control, OhciControl);
189 
190  // Controller is now running. Yay!
191 
192  // Restore the Frame Interval register (reset by a HC reset)
193  m_pBase->write32(interval | (1U << 31U), OhciFmInterval);
194 
195  DEBUG_LOG(
196  "USB: OHCI: maximum packet size is " << ((interval >> 16) & 0xEFFF));
197 
198  // Turn on all ports on the root hub.
199  m_pBase->write32(0x10000, OhciRhStatus);
200 
201  // Set up the RequestQueue
202  initialise();
203 
204 // Dequeue main thread
205 // new Thread(Processor::information().getCurrentThread()->getParent(),
206 // threadStub, reinterpret_cast<void*>(this));
207 
208 // Install the IRQ handler
209 #ifdef X86_COMMON
210  Machine::instance().getIrqManager()->registerPciIrqHandler(this, this);
211  Machine::instance().getIrqManager()->control(
212  getInterruptNumber(), IrqManager::MitigationThreshold,
213  (1500000 / 64)); // 12KB/ms (12Mbps) in bytes, divided by 64 bytes
214  // maximum per transfer/IRQ-#else
215 #else
217  pDev->getInterruptNumber(), this);
218 #endif
219 
220  // Get the number of ports and delay for power-up for this root hub.
221  uint32_t rhDescA = m_pBase->read32(OhciRhDescriptorA);
222  uint8_t powerWait = ((rhDescA >> 24) & 0xFF) * 2;
223  m_nPorts = rhDescA & 0xFF;
224 
225  DEBUG_LOG(
226  "USB: OHCI: Reset complete, " << Dec << m_nPorts << Hex
227  << " ports available");
228 
229  for (size_t i = 0; i < m_nPorts; i++)
230  {
231  if (!(m_pBase->read32(OhciRhPortStatus + (i * 4)) & OhciRhPortStsPower))
232  {
233  DEBUG_LOG("USB: OHCI: applying power to port " << i);
234 
235  // Needs port power, do so
236  m_pBase->write32(OhciRhPortStsPower, OhciRhPortStatus + (i * 4));
237 
238  // Wait as long as it needs
239  Time::delay(powerWait * Time::Multiplier::Millisecond);
240  }
241 
242  DEBUG_LOG("OHCI: Determining if there's a device on this port");
243 
244  // Check for a connected device
245  if (m_pBase->read32(OhciRhPortStatus + (i * 4)) &
246  OhciRhPortStsConnected)
247  executeRequest(i);
248  }
249 
250  // Enable RootHubStatusChange interrupt now that it's safe to
251  m_pBase->write32(OhciInterruptRhStsChange, OhciInterruptStatus);
252  m_pBase->write32(
253  OhciInterruptMIE | OhciInterruptRhStsChange | OhciInterruptWbDoneHead,
254  OhciInterruptEnable);
255 }
256 
257 Ohci::~Ohci()
258 {
259 }
260 
261 void Ohci::removeED(ED *pED)
262 {
264 
265  if (!pED || !pED->pMetaData)
266  return;
267 
268 #ifdef USB_VERBOSE_DEBUG
269  DEBUG_LOG(
270  "OHCI: removing ED #"
271  << pED->pMetaData->id
272  << " from the schedule to prepare for reclamation");
273 #endif
274 
275  // Make sure the ED is skipped by the host controller until it is properly
276  // dequeued.
277  pED->bSkip = true;
278 
279  ED *pPrev = pED->pMetaData->pPrev;
280  ED *pNext = pED->pMetaData->pNext;
281 
282  ED **pQueueHead = 0;
283  ED **pQueueTail = 0;
284 
285  if (pED->pMetaData->edType == ControlList)
286  {
287  pQueueHead = &m_pControlQueueHead;
288  pQueueTail = &m_pControlQueueTail;
289  }
290  else if (pED->pMetaData->edType == BulkList)
291  {
292  pQueueHead = &m_pBulkQueueHead;
293  pQueueTail = &m_pBulkQueueTail;
294  }
295  else
296  {
297  ERROR("OHCI: ED #" << pED->pMetaData->id << " has an invalid type!");
298  return;
299  }
300 
301  bool bControl = pED->pMetaData->edType == ControlList;
302 
303  // Unlink from the hardware linked list.
304  if (pED == *pQueueHead)
305  {
306 #ifdef USB_VERBOSE_DEBUG
307  DEBUG_LOG("OHCI: ED was a queue head, adjusting controller state "
308  "accordingly");
309 #endif
310 
311  *pQueueHead = pNext;
312 
313  if (bControl)
314  m_pBase->write32(vtp_ed(pNext), OhciControlHeadED);
315  else
316  m_pBase->write32(vtp_ed(pNext), OhciBulkHeadED);
317  }
318  else if (pPrev)
319  {
320  pPrev->pNext = pED->pNext;
321  }
322 
323  // Simply for tracking purposes, make sure the tail is valid.
324  if (pED == *pQueueTail)
325  {
326  *pQueueTail = pPrev;
327  }
328 
329  // Unlink from the software linked list.
330  if (pPrev)
331  pPrev->pMetaData->pNext = pNext;
332  if (pNext)
333  pNext->pMetaData->pPrev = pPrev;
334 
335  // Clear all TDs related to the ED.
336  if (pED->pMetaData->completedTdList.count())
337  {
338  for (List<TD *>::Iterator it = pED->pMetaData->completedTdList.begin();
339  it != pED->pMetaData->completedTdList.end(); it++)
340  {
341  size_t idx = (*it)->id;
342  ByteSet((*it), 0, sizeof(TD));
343  m_TDBitmap.clear(idx);
344  }
345  }
346 
347  // We might still have TDs that haven't been completed, if an earlier
348  // transaction fails somewhere.
349  if (pED->pMetaData->tdList.count())
350  {
351  for (List<TD *>::Iterator it = pED->pMetaData->completedTdList.begin();
352  it != pED->pMetaData->completedTdList.end(); it++)
353  {
354  size_t idx = (*it)->id;
355  ByteSet((*it), 0, sizeof(TD));
356  m_TDBitmap.clear(idx);
357  }
358  }
359 
360  // Disable list processing for this ED
361  stop(pED->pMetaData->edType);
362 
363  // Prepare the ED for reclamation in the next USB frame.
364  {
365  LockGuard<Spinlock> guard(m_DequeueListLock);
366  m_DequeueList.pushBack(pED);
367  }
368 
369  // Clear any pending SOF interrupt and then enable the SOF IRQ.
370  // The IRQ handler will pick up a SOF status and clean up the ED.
371  m_pBase->write32(OhciInterruptStartOfFrame, OhciInterruptStatus);
372  m_pBase->write32(OhciInterruptStartOfFrame, OhciInterruptEnable);
373 }
374 
375 #ifdef X86_COMMON
376 bool Ohci::irq(irq_id_t number, InterruptState &state)
377 #else
378 void Ohci::interrupt(size_t number, InterruptState &state)
379 #endif
380 {
381  if (!m_pHcca)
382  {
383  // Assume not for us - no HCCA yet!
384  return
385 #ifdef X86_COMMON
386  false
387 #endif
388  ;
389  }
390 
391  uint32_t nStatus = 0;
392 
393  // Find out if this came from either a done ED or a useful status.
394  if (m_pHcca->pDoneHead)
395  {
396  // We must process this interrupt.
397  nStatus = OhciInterruptWbDoneHead;
398  if (m_pHcca->pDoneHead & 0x1) // ... ???
399  nStatus |= m_pBase->read32(OhciInterruptStatus) &
400  m_pBase->read32(OhciInterruptEnable);
401  }
402  else
403  {
404  nStatus = m_pBase->read32(OhciInterruptStatus) &
405  m_pBase->read32(OhciInterruptEnable);
406  }
407 
408  // Not for us?
409  if (!nStatus)
410  {
411  DEBUG_LOG("USB: OHCI: irq is not for us");
412  return
413 #ifdef X86_COMMON
414  false
415 #endif
416  ;
417  }
418 
419  // However, make sure we do not get interrupted during handling.
420  m_pBase->write32(OhciInterruptMIE, OhciInterruptDisable);
421 
422  // Clear the MIE bit from the interrupt status. We don't care for it.
423  nStatus &= ~OhciInterruptMIE;
424 
425 #ifdef USB_VERBOSE_DEBUG
426  DEBUG_LOG("OHCI: IRQ " << nStatus);
427 #endif
428 
429  if (nStatus & OhciInterruptUnrecoverableError)
430  {
432 
433  // Don't enable interrupts again, controller is not in a safe state.
434  ERROR("OHCI: controller is hung!");
435  return
436 #ifdef X86_COMMON
437  true
438 #endif
439  ;
440  }
441 
442  if (nStatus & OhciInterruptStartOfFrame)
443  {
444  LockGuard<Spinlock> guard(m_DequeueListLock);
445 
446 #ifdef USB_VERBOSE_DEBUG
447  DEBUG_LOG("OHCI: SOF, preparing to reclaim EDs...");
448 #endif
449 
450  // Firstly disable the SOF interrupt now that we've gotten it.
451  m_pBase->write32(OhciInterruptStartOfFrame, OhciInterruptDisable);
452 
453  // Process the reclaim list.
454  ED *pED = 0;
455  while (1)
456  {
457  if (!m_DequeueList.count())
458  break;
459 
460  pED = m_DequeueList.popFront();
461  if (pED)
462  {
463  size_t id = pED->pMetaData->id & 0xFFF;
464  Lists type = pED->pMetaData->edType;
465 
466 #ifdef USB_VERBOSE_DEBUG
467  DEBUG_LOG("OHCI: freeing ED #" << pED->pMetaData->id << ".");
468 #endif
469 
470  // Destroy the ED and free it's memory space.
471  delete pED->pMetaData;
472  ByteSet(pED, 0, sizeof(ED));
473 
474  switch (type)
475  {
476  case ControlList:
477  m_ControlEDBitmap.clear(id);
478  break;
479  case BulkList:
480  m_BulkEDBitmap.clear(id);
481  break;
482  case PeriodicList:
483  WARNING("periodic: not actually clearing bit");
484  // m_PeriodicEDBitmap.clear(edId);
485  break;
486  case IsochronousList:
487  DEBUG_LOG("USB: OHCI: dequeue on an isochronous ED, "
488  "but we don't support them yet.");
489  break;
490  }
491 
492  // Safe to restore this list to the running state.
494  start(type);
495  }
496  }
497  }
498 
499  // Check for newly connected / disconnected devices
500  if (nStatus & OhciInterruptRhStsChange)
501  for (size_t i = 0; i < m_nPorts; i++)
502  if (m_pBase->read32(OhciRhPortStatus + (i * 4)) &
503  OhciRhPortStsConnStsCh)
504  addAsyncRequest(0, i);
505 
506  // A list of EDs that persist in the schedule. Used to repopulate the
507  // schedule list.
508  List<ED *> persistList;
509 
510  if (nStatus & OhciInterruptWbDoneHead)
511  {
512  ED *pED = 0;
513  do
514  {
515  {
516  LockGuard<Spinlock> guard(m_ScheduleChangeLock);
517  if (m_FullSchedule.count())
518  pED = m_FullSchedule.popFront();
519  else
520  break;
521  }
522 
523  // Assume not yet linked properly
524  if (pED->pMetaData->bIgnore)
525  {
526  persistList.pushBack(pED);
527  continue;
528  }
529 
530  bool bPeriodic = pED->pMetaData->bPeriodic;
531 
532  // Iterate the TD list
533  TD *pTD = 0;
534  while (pED->pMetaData->tdList.count())
535  {
536  pTD = pED->pMetaData->tdList.popFront();
537 
538  // TD not yet handled - return to the list and go to the next
539  // ED.
540  if (pTD->nStatus == 0xF)
541  {
542  pED->pMetaData->tdList.pushFront(pTD);
543  break;
544  }
545 
546  ssize_t nResult;
547  if (pTD->nStatus)
548  {
549 #ifdef USB_VERBOSE_DEBUG
550  if (!bPeriodic)
551  ERROR_NOLOCK("TD Error " << Dec << pTD->nStatus << Hex);
552 #endif
553  nResult = -pTD->getError();
554  }
555  else
556  {
557  if (pTD->pBufferStart)
558  {
559  // Only a part of the buffer has been transfered
560  size_t nBytesLeft =
561  pTD->pBufferEnd - pTD->pBufferStart + 1;
562  nResult = pTD->nBufferSize - nBytesLeft;
563  }
564  else
565  nResult = pTD->nBufferSize;
566  pED->pMetaData->nTotalBytes += nResult;
567  }
568 #ifdef USB_VERBOSE_DEBUG
569  DEBUG_LOG_NOLOCK(
570  "TD #" << Dec << pTD->id << Hex << " [from ED #" << Dec
571  << pED->pMetaData->id << Hex << "] DONE: " << Dec
572  << pED->nAddress << ":" << pED->nEndpoint << " "
573  << (pTD->nPid == 1 ?
574  "OUT" :
575  (pTD->nPid == 2 ?
576  "IN" :
577  (pTD->nPid == 0 ? "SETUP" : "")))
578  << " " << nResult << Hex);
579 #endif
580 
582  bool bEndOfTransfer =
583  (!bPeriodic &&
584  ((nResult < 0) || (pTD == pED->pMetaData->pLastTD))) ||
585  (bPeriodic && (nResult >= 0));
586 
587  if (!bPeriodic)
588  pED->pMetaData->completedTdList.pushBack(pTD);
589 
590  // Last TD or error condition, if async, otherwise only when it
591  // gives no error
592  if (bEndOfTransfer)
593  {
594  // Valid callback?
595  if (pED->pMetaData->pCallback)
596  {
597  pED->pMetaData->pCallback(
598  pED->pMetaData->pParam,
599  nResult < 0 ? nResult :
600  pED->pMetaData->nTotalBytes);
601  }
602 
603  if (!bPeriodic)
604  {
605  removeED(pED);
606  continue;
607  }
608  else
609  {
610  // Invert data toggle
611  pTD->bDataToggle = !pTD->bDataToggle;
612 
613  // Clear the total bytes field so it won't grow with
614  // each completed transfer
615  pED->pMetaData->nTotalBytes = 0;
616  }
617  }
618 
619  // Interrupt TDs need to be always active
620  if (bPeriodic)
621  {
622  pTD->nStatus = 0xf;
623  pTD->pBufferStart = pTD->pBufferEnd - pTD->nBufferSize + 1;
624  pED->pHeadTD = PHYS_TD(pTD->id) >> 4;
625 
626  pED->pMetaData->tdList.pushBack(pTD);
627  break; // Only one TD in a periodic transfer.
628  }
629  }
630 
631  // If this ED is not queued for deletion, make sure we can use it
632  // in the next IRQ.
633  if (!pED->pMetaData->bIgnore)
634  persistList.pushBack(pED);
635  } while (pED);
636  }
637 
638  // Restore EDs into the schedule if they were removed and need to persist.
639  if (persistList.count())
640  {
641  LockGuard<Spinlock> guard(m_ScheduleChangeLock);
642  for (List<ED *>::Iterator it = persistList.begin();
643  it != persistList.end();)
644  {
645  m_FullSchedule.pushBack(*it);
646  it = persistList.erase(it);
647  }
648  }
649 
650  // Clear the interrupt status now.
651  m_pBase->write32(nStatus, OhciInterruptStatus);
652 
653  // Re-enable all interrupts.
654  m_pBase->write32(OhciInterruptMIE, OhciInterruptEnable);
655 
656 #ifdef X86_COMMON
657  return true;
658 #endif
659 }
660 
662  uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer,
663  size_t nBytes)
664 {
665  // Atomic operation: find clear bit, set it
666  size_t nIndex = 0;
667  {
668  LockGuard<Mutex> guard(m_Mutex);
669  nIndex = m_TDBitmap.getFirstClear();
670  if (nIndex >= (0x1000 / sizeof(TD)))
671  {
672  ERROR("USB: OHCI: TD space full");
673  return;
674  }
675  m_TDBitmap.set(nIndex);
676  }
677 
678  // Grab the TD pointer we're going to set up now
679  TD *pTD = &m_pTDList[nIndex];
680  ByteSet(pTD, 0, sizeof(TD));
681  pTD->id = nIndex;
682 
683  // Buffer rounding - allow packets smaller than the buffer we specify
684  pTD->bBuffRounding = 1;
685 
686  // PID for the transfer
687  switch (pid)
688  {
689  case UsbPidSetup:
690  pTD->nPid = 0;
691  break;
692  case UsbPidOut:
693  pTD->nPid = 1;
694  break;
695  case UsbPidIn:
696  pTD->nPid = 2;
697  break;
698  default:
699  pTD->nPid = 3;
700  };
701 
702  // Active
703  pTD->nStatus = 0xf;
704 
705  // Buffer for transfer
706  if (nBytes)
707  {
708  VirtualAddressSpace &va =
709  Processor::information().getVirtualAddressSpace();
710  if (va.isMapped(reinterpret_cast<void *>(pBuffer)))
711  {
712  physical_uintptr_t phys = 0;
713  size_t flags = 0;
714  va.getMapping(reinterpret_cast<void *>(pBuffer), phys, flags);
715  pTD->pBufferStart = phys + (pBuffer & 0xFFF);
716  pTD->pBufferEnd = pTD->pBufferStart + nBytes - 1;
717  }
718  else
719  {
720  ERROR(
721  "OHCI: addTransferToTransaction: Buffer (page "
722  << Dec << pBuffer << Hex << ") isn't mapped!");
723  m_TDBitmap.clear(nIndex);
724  return;
725  }
726 
727  pTD->nBufferSize = nBytes;
728  }
729 
730  // This is the last TD so far
731  pTD->bLast = true;
732 
733  // pTransaction will be 0x0xxx for CONTROL, 0x1xxx for BULK, 0x2xxx for
734  // PERIODIC.
735  size_t transactionType = (pTransaction & 0x3000) >> 12;
736  uintptr_t edOffset = pTransaction & 0xFFF;
737 
738  ED *pED = 0;
739  switch (transactionType)
740  {
741  case 0:
742  pED = &m_pControlEDList[edOffset];
743  break;
744  case 1:
745  pED = &m_pBulkEDList[edOffset];
746  break;
747  case 2:
748  pED = &m_pPeriodicEDList[edOffset];
749  break;
750  default:
751  break;
752  }
753 
754  if (!pED)
755  {
757  ERROR("USB: OHCI: transaction " << pTransaction << " is invalid.");
758  return;
759  }
760 
761  // Add our TD to the ED's queue.
762  if (pED->pMetaData->pLastTD)
763  {
764  pED->pMetaData->pLastTD->pNext = PHYS_TD(nIndex) >> 4;
765  pED->pMetaData->pLastTD->nNextTDIndex = nIndex;
766  pED->pMetaData->pLastTD->bLast = false;
767  }
768  else
769  {
770  pED->pMetaData->pFirstTD = pTD;
771  pED->pHeadTD = PHYS_TD(nIndex) >> 4;
772  }
773  pED->pMetaData->pLastTD = pTD;
774 
775  pED->pMetaData->tdList.pushBack(pTD);
776 }
777 
778 uintptr_t Ohci::createTransaction(UsbEndpoint endpointInfo)
779 {
780  // Determine what kind of transaction this is.
781  bool bIsBulk = endpointInfo.nEndpoint > 0;
782 
783  // Atomic operation: find clear bit, set it
784  ED *pED = 0;
785  size_t nIndex = 0;
786  {
787  LockGuard<Mutex> guard(m_Mutex);
788 
789  if (bIsBulk)
790  nIndex = m_BulkEDBitmap.getFirstClear();
791  else
792  nIndex = m_ControlEDBitmap.getFirstClear();
793 
794  if (nIndex >= (0x1000 / sizeof(ED)))
795  {
796  ERROR("USB: OHCI: ED space full");
797  return static_cast<uintptr_t>(-1);
798  }
799 
800  if (bIsBulk)
801  {
802  m_BulkEDBitmap.set(nIndex);
803  pED = &m_pBulkEDList[nIndex];
804  nIndex += 0x1000;
805  }
806  else
807  {
808  m_ControlEDBitmap.set(nIndex);
809  pED = &m_pControlEDList[nIndex];
810  }
811  }
812 
813  ByteSet(pED, 0, sizeof(ED));
814 
815  // Device address, endpoint and speed
816  pED->nAddress = endpointInfo.nAddress;
817  pED->nEndpoint = endpointInfo.nEndpoint;
818  pED->bLoSpeed = endpointInfo.speed == LowSpeed;
819 
820  // Maximum packet size
821  pED->nMaxPacketSize = endpointInfo.nMaxPacketSize;
822 
823  // Make sure this ED is ignored until it's properly queued.
824  pED->bSkip = true;
825 
826  // Setup the metadata
827  pED->pMetaData = new ED::MetaData;
828  pED->pMetaData->endpointInfo = endpointInfo;
829  pED->pMetaData->id = nIndex;
830  pED->pMetaData->bIgnore = true; // Don't handle this ED until we're ready.
831  pED->pMetaData->edType = bIsBulk ? BulkList : ControlList;
832  pED->pMetaData->bPeriodic = false;
833  pED->pMetaData->pFirstTD = pED->pMetaData->pLastTD = 0;
834  pED->pMetaData->nTotalBytes = 0;
835  pED->pMetaData->pPrev = pED->pMetaData->pNext = 0;
836  pED->pMetaData->bLinked = false;
837 
838  // Complete
839  return nIndex;
840 }
841 
843  uintptr_t pTransaction, void (*pCallback)(uintptr_t, ssize_t),
844  uintptr_t pParam)
845 {
846  // pTransaction will be 0x0xxx for CONTROL, 0x1xxx for BULK, 0x2xxx for
847  // PERIODIC.
848  size_t transactionType = (pTransaction & 0x3000) >> 12;
849  uintptr_t edOffset = pTransaction & 0xFFF;
850 
851  Spinlock *pLock = 0;
852 
853  ED *pED = 0;
854  {
855  LockGuard<Mutex> guard(m_Mutex);
856 
857  bool bValid = false;
858  if (transactionType == 0)
859  bValid = m_ControlEDBitmap.test(edOffset);
860  else if (transactionType == 1)
861  bValid = m_BulkEDBitmap.test(edOffset);
862 
863  if ((pTransaction == static_cast<uintptr_t>(-1)) || !bValid)
864  {
865  ERROR(
866  "OHCI: doAsync: didn't get a valid transaction id ["
867  << pTransaction << ", " << edOffset << "].");
868  return;
869  }
870 
871  if (transactionType == 0)
872  {
873  pED = &m_pControlEDList[edOffset];
874  pLock = &m_ControlListChangeLock;
875  }
876  else if (transactionType == 1)
877  {
878  pED = &m_pBulkEDList[edOffset];
879  pLock = &m_BulkListChangeLock;
880  }
881  else
882  {
883  ERROR(
884  "OHCI: doAsync: only control and bulk transactions supported");
885  return;
886  }
887  }
888 
889  // Set up all the metadata we can at the moment.
890  pED->pMetaData->pCallback = pCallback;
891  pED->pMetaData->pParam = pParam;
892 
893  bool bControl = !pED->pMetaData->endpointInfo.nEndpoint;
894 
895  // Stop the controller as we are modifying the queue.
896  // stop(pED->pMetaData->edType);
897 
898  // Lock while we modify the linked lists.
899  pLock->acquire();
900 
901  // Always at the end of the ED queue. Zero means "no next ED" to OHCI.
902  pED->pNext = 0;
903 
904  // Handle the case where there is not yet a queue head.
905  if (bControl)
906  {
907  if (!m_pControlQueueHead)
908  {
909 #ifdef USB_VERBOSE_DEBUG
910  DEBUG_LOG("OHCI: ED is now the control queue head.");
911 #endif
912  m_pControlQueueHead = pED;
913  }
914  }
915  else
916  {
917  if (!m_pBulkQueueHead)
918  {
919 #ifdef USB_VERBOSE_DEBUG
920  DEBUG_LOG("OHCI: ED is now the control queue head.");
921 #endif
922  m_pBulkQueueHead = pED;
923  }
924  }
925 
926  // Grab the queue head.
927  ED *pQueueHead = 0;
928  physical_uintptr_t queueHeadPhys = 0;
929  if (bControl)
930  {
931  pQueueHead = m_pControlQueueHead;
932  queueHeadPhys = vtp_ed(pQueueHead);
933  }
934  else
935  {
936  pQueueHead = m_pBulkQueueHead;
937  queueHeadPhys = vtp_ed(pQueueHead);
938  }
939 
940  // Update the head of the relevant list.
941  if (queueHeadPhys == vtp_ed(pED))
942  {
943  if (bControl)
944  {
945 #ifdef USB_VERBOSE_DEBUG
946  DEBUG_LOG(
947  "OHCI: new control queue head is "
948  << queueHeadPhys << " compared to "
949  << m_pBase->read32(OhciControlHeadED));
950  DEBUG_LOG(
951  "OHCI: current control queue ED is "
952  << m_pBase->read32(OhciControlCurrentED));
953 #endif
954  m_pBase->write32(queueHeadPhys, OhciControlHeadED);
955  }
956  else
957  {
958 #ifdef USB_VERBOSE_DEBUG
959  DEBUG_LOG("OHCI: new bulk queue head is " << queueHeadPhys);
960 #endif
961  m_pBase->write32(queueHeadPhys, OhciBulkHeadED);
962  }
963  }
964 
965  // Grab the current tail of the list and update it to point to us.
966  ED *pTail = 0;
967  if (bControl)
968  {
969  pTail = m_pControlQueueTail;
970  m_pControlQueueTail = pED;
971  }
972  else
973  {
974  pTail = m_pBulkQueueTail;
975  m_pBulkQueueTail = pED;
976  }
977 
978  // Point the old tail to this ED.
979  if (pTail)
980  {
981  pTail->pNext = vtp_ed(pED) >> 4;
982  pTail->pMetaData->pNext = pED;
983  }
984 
985  // Fix up the software linked list.
986  pED->pMetaData->pNext = 0;
987  pED->pMetaData->pPrev = pTail;
988  pQueueHead->pMetaData->pPrev = 0;
989 
990  // Enable handling of this ED now.
991  pED->bSkip = pED->pMetaData->bIgnore = false;
992  pED->pMetaData->bLinked = true;
993 
994  // Can now unlock.
995  pLock->release();
996 
997  // Add to the housekeeping schedule before we link in proper.
998  m_ScheduleChangeLock.acquire();
999  m_FullSchedule.pushBack(pED);
1000  m_ScheduleChangeLock.release();
1001 
1002  // Restart the controller if it was stopped for some reason.
1003  start(pED->pMetaData->edType);
1004 
1005  // Tell the controller that the list has valid TD in it now.
1006  // The OHCI will automatically stop processing the ED list if it determines
1007  // no more transfers are pending.
1008  uint32_t status = m_pBase->read32(OhciCommandStatus);
1009  status |=
1010  bControl ? OhciCommandControlListFilled : OhciCommandBulkListFilled;
1011  m_pBase->write32(status, OhciCommandStatus);
1012 }
1013 
1015  UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes,
1016  void (*pCallback)(uintptr_t, ssize_t), uintptr_t pParam)
1017 {
1018  // Atomic operation: find clear bit, set it
1019  ED *pED = 0;
1020  size_t nIndex = 0;
1021  {
1022  LockGuard<Mutex> guard(m_Mutex);
1023 
1024  nIndex = m_PeriodicEDBitmap.getFirstClear();
1025  if (nIndex >= (0x1000 / sizeof(ED)))
1026  {
1027  ERROR("USB: OHCI: ED space full");
1028  return;
1029  }
1030 
1031  m_PeriodicEDBitmap.set(nIndex);
1032  pED = &m_pPeriodicEDList[nIndex];
1033 
1034  // Periodic identifier
1035  nIndex += 0x2000;
1036  }
1037 
1038  ByteSet(pED, 0, sizeof(ED));
1039 
1040  // Device address, endpoint and speed
1041  pED->nAddress = endpointInfo.nAddress;
1042  pED->nEndpoint = endpointInfo.nEndpoint;
1043  pED->bLoSpeed = endpointInfo.speed == LowSpeed;
1044 
1045  // Maximum packet size
1046  pED->nMaxPacketSize = endpointInfo.nMaxPacketSize;
1047 
1048  // Make sure this ED is ignored until it's properly queued.
1049  pED->bSkip = true;
1050 
1051  // Setup the metadata
1052  pED->pMetaData = new ED::MetaData;
1053  pED->pMetaData->endpointInfo = endpointInfo;
1054  pED->pMetaData->id = nIndex;
1055  pED->pMetaData->bIgnore = true; // Don't handle this ED until we're ready.
1056  pED->pMetaData->edType = PeriodicList;
1057  pED->pMetaData->pFirstTD = pED->pMetaData->pLastTD = 0;
1058  pED->pMetaData->nTotalBytes = 0;
1059  pED->pMetaData->pPrev = pED->pMetaData->pNext = 0;
1060  pED->pMetaData->bLinked = false;
1061 
1062  pED->pMetaData->bPeriodic = true;
1063 
1064  // Set up the callback and pointer.
1065  pED->pMetaData->pCallback = pCallback;
1066  pED->pMetaData->pParam = pParam;
1067 
1068  // Add to the housekeeping schedule before we link in proper.
1069  m_ScheduleChangeLock.acquire();
1070  m_FullSchedule.pushBack(pED);
1071  m_ScheduleChangeLock.release();
1072 
1073  // Lock before linking.
1074  LockGuard<Spinlock> guard(m_PeriodicListChangeLock);
1075 
1076  pED->pMetaData->pPrev = m_pPeriodicQueueTail;
1077 
1078  m_pPeriodicQueueTail->pNext = vtp_ed(pED) >> 4;
1079  m_pPeriodicQueueTail = pED;
1080 
1081  // All linked in and ready to go!
1082  pED->bSkip = pED->pMetaData->bIgnore = false;
1083  pED->pMetaData->bLinked = true;
1084 
1085  // Start processing of the list if it isn't already active.
1086  start(pED->pMetaData->edType);
1087 }
1088 
1089 bool Ohci::portReset(uint8_t nPort, bool bErrorResponse)
1090 {
1092 
1093  // Perform a reset of the port
1094  m_pBase->write32(
1095  OhciRhPortStsReset | OhciRhPortStsConnStsCh,
1096  OhciRhPortStatus + (nPort * 4));
1097  while (
1098  !(m_pBase->read32(OhciRhPortStatus + (nPort * 4)) & OhciRhPortStsResCh))
1099  Time::delay(5 * Time::Multiplier::Millisecond);
1100  m_pBase->write32(OhciRhPortStsResCh, OhciRhPortStatus + (nPort * 4));
1101 
1102  // Enable the port if not already enabled
1103  if (!(m_pBase->read32(OhciRhPortStatus + (nPort * 4)) &
1104  OhciRhPortStsEnable))
1105  m_pBase->write32(OhciRhPortStsEnable, OhciRhPortStatus + (nPort * 4));
1106 
1107  return true;
1108 }
1109 
1111  uint64_t p1, uint64_t p2, uint64_t p3, uint64_t p4, uint64_t p5,
1112  uint64_t p6, uint64_t p7, uint64_t p8)
1113 {
1114  // Check for a connected device
1115  if (m_pBase->read32(OhciRhPortStatus + (p1 * 4)) & OhciRhPortStsConnected)
1116  {
1117  if (!portReset(p1))
1118  return 0;
1119 
1120  // Determine the speed of the attached device
1121  if (m_pBase->read32(OhciRhPortStatus + (p1 * 4)) & OhciRhPortStsLoSpeed)
1122  {
1123  DEBUG_LOG(
1124  "USB: OHCI: Port "
1125  << Dec << p1 << Hex
1126  << " has a low-speed device connected to it");
1127  deviceConnected(p1, LowSpeed);
1128  }
1129  else
1130  {
1131  DEBUG_LOG(
1132  "USB: OHCI: Port "
1133  << Dec << p1 << Hex
1134  << " has a full-speed device connected to it");
1135  deviceConnected(p1, FullSpeed);
1136  }
1137  }
1138  else
1139  deviceDisconnected(p1);
1140  return 0;
1141 }
1142 
1143 void Ohci::stop(Lists list)
1144 {
1145  if (!m_pHcca)
1146  return;
1147 
1148  uint32_t control = m_pBase->read32(OhciControl);
1149  control &= ~static_cast<int>(list);
1150  m_pBase->write32(control, OhciControl);
1151 }
1152 
1153 void Ohci::start(Lists list)
1154 {
1155  if (!m_pHcca)
1156  return;
1157 
1158  uint32_t control = m_pBase->read32(OhciControl);
1159  control |= static_cast<int>(list);
1160  m_pBase->write32(control, OhciControl);
1161 }
Definition: Ohci.h:66
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
void release()
Definition: Spinlock.cc:273
void pushBack(const T &value)
Definition: List.h:232
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)
Gets a UsbDevice from a given vendor:product pair.
Definition: Ohci.cc:1089
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:661
static PhysicalMemoryManager & instance()
void stop(Lists list)
Stops the controller from processing the given list.
Definition: Ohci.cc:1143
Iterator erase(Iterator &Iter)
Definition: List.h:343
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual void doAsync(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t)=0, uintptr_t pParam=0)
Definition: Ohci.cc:842
void pushFront(const T &value)
Definition: List.h:287
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: Ohci.cc:1014
virtual bool isMapped(void *virtualAddress)=0
T popFront()
Definition: List.h:319
bool acquire(bool recurse=false, bool safe=true)
Definition: Spinlock.cc:43
Definition: String.h:49
static ProcessorInformation & information()
Definition: Processor.cc:45
virtual uintptr_t getInterruptNumber()
Definition: Device.h:262
Definition: Device.h:43
#define WARNING(text)
Definition: Log.h:78
Definition: List.h:64
Definition: Ohci.h:110
uint32_t readConfigSpace(Device *pDev, uint8_t offset)
Definition: Pci.cc:75
Definition: Log.h:136
::Iterator< T, node_t > Iterator
Definition: List.h:71
Iterator begin()
Definition: List.h:123
Definition: UsbHub.h:30
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:1110
virtual irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *pDevice)=0
void removeED(ED *pED)
Prepares an ED to be reclaimed.
Definition: Ohci.cc:261
#define ERROR(text)
Definition: Log.h:82
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)
Creates a new transaction with the given endpoint data.
Definition: Ohci.cc:778
Definition: Log.h:138
void start(Lists list)
Starts processing of the given list.
Definition: Ohci.cc:1153
virtual bool control(uint8_t irq, ControlCode code, size_t argument)
Definition: IrqManager.cc:29
virtual bool irq(irq_id_t number, InterruptState &state)
IRQ handler.
Definition: Ohci.cc:376
#define DEBUG_LOG(text)
Definition: Log.h:69
static InterruptManager & instance()
Iterator end()
Definition: List.h:135
Lists
Enumeration of lists that can be stopped or started.
Definition: Ohci.h:54
void writeConfigSpace(Device *pDev, uint8_t offset, uint32_t data)
Definition: Pci.cc:104
size_t count() const
Definition: List.h:227