VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/DevOHCI.cpp@ 100347

Last change on this file since 100347 was 99739, checked in by vboxsync, 22 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 219.8 KB
Line 
1/* $Id: DevOHCI.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * DevOHCI - Open Host Controller Interface for USB.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_dev_ohci OHCI - Open Host Controller Interface Emulation.
29 *
30 * This component implements an OHCI USB controller. It is split roughly in
31 * to two main parts, the first part implements the register level
32 * specification of USB OHCI and the second part maintains the root hub (which
33 * is an integrated component of the device).
34 *
35 * The OHCI registers are used for the usual stuff like enabling and disabling
36 * interrupts. Since the USB time is divided in to 1ms frames and various
37 * interrupts may need to be triggered at frame boundary time, a timer-based
38 * approach was taken. Whenever the bus is enabled ohci->eof_timer will be set.
39 *
40 * The actual USB transfers are stored in main memory (along with endpoint and
41 * transfer descriptors). The ED's for all the control and bulk endpoints are
42 * found by consulting the HcControlHeadED and HcBulkHeadED registers
43 * respectively. Interrupt ED's are different, they are found by looking
44 * in the HCCA (another communication area in main memory).
45 *
46 * At the start of every frame (in function ohci_sof) we traverse all enabled
47 * ED lists and queue up as many transfers as possible. No attention is paid
48 * to control/bulk service ratios or bandwidth requirements since our USB
49 * could conceivably contain a dozen high speed busses so this would
50 * artificially limit the performance.
51 *
52 * Once we have a transfer ready to go (in function ohciR3ServiceTd) we
53 * allocate an URB on the stack, fill in all the relevant fields and submit
54 * it using the VUSBIRhSubmitUrb function. The roothub device and the virtual
55 * USB core code (vusb.c) coordinates everything else from this point onwards.
56 *
57 * When the URB has been successfully handed to the lower level driver, our
58 * prepare callback gets called and we can remove the TD from the ED transfer
59 * list. This stops us queueing it twice while it completes.
60 * bird: no, we don't remove it because that confuses the guest! (=> crashes)
61 *
62 * Completed URBs are reaped at the end of every frame (in function
63 * ohci_frame_boundary). Our completion routine makes use of the ED and TD
64 * fields in the URB to store the physical addresses of the descriptors so
65 * that they may be modified in the roothub callbacks. Our completion
66 * routine (ohciR3RhXferCompletion) carries out a number of tasks:
67 * -# Retires the TD associated with the transfer, setting the
68 * relevant error code etc.
69 * -# Updates done-queue interrupt timer and potentially causes
70 * a writeback of the done-queue.
71 * -# If the transfer was device-to-host, we copy the data in to
72 * the host memory.
73 *
74 * As for error handling OHCI allows for 3 retries before failing a transfer,
75 * an error count is stored in each transfer descriptor. A halt flag is also
76 * stored in the transfer descriptor. That allows for ED's to be disabled
77 * without stopping the bus and de-queuing them.
78 *
79 * When the bus is started and stopped we call VUSBIDevPowerOn/Off() on our
80 * roothub to indicate it's powering up and powering down. Whenever we power
81 * down, the USB core makes sure to synchronously complete all outstanding
82 * requests so that the OHCI is never seen in an inconsistent state by the
83 * guest OS (Transfers are not meant to be unlinked until they've actually
84 * completed, but we can't do that unless we work synchronously, so we just
85 * have to fake it).
86 * bird: we do work synchronously now, anything causes guest crashes.
87 */
88
89
90/*********************************************************************************************************************************
91* Header Files *
92*********************************************************************************************************************************/
93#define LOG_GROUP LOG_GROUP_DEV_OHCI
94#include <VBox/pci.h>
95#include <VBox/vmm/pdm.h>
96#include <VBox/vmm/mm.h>
97#include <VBox/err.h>
98#include <VBox/log.h>
99#include <VBox/AssertGuest.h>
100#include <iprt/assert.h>
101#include <iprt/string.h>
102#include <iprt/asm.h>
103#include <iprt/asm-math.h>
104#include <iprt/semaphore.h>
105#include <iprt/critsect.h>
106#include <iprt/param.h>
107#ifdef IN_RING3
108# include <iprt/alloca.h>
109# include <iprt/mem.h>
110# include <iprt/thread.h>
111# include <iprt/uuid.h>
112#endif
113#include <VBox/vusb.h>
114#include "VBoxDD.h"
115
116
117#define VBOX_WITH_OHCI_PHYS_READ_CACHE
118//#define VBOX_WITH_OHCI_PHYS_READ_STATS
119
120
121/*********************************************************************************************************************************
122* Structures and Typedefs *
123*********************************************************************************************************************************/
124/** The current saved state version. */
125#define OHCI_SAVED_STATE_VERSION OHCI_SAVED_STATE_VERSION_NO_EOF_TIMER
126/** The current saved state version.
127 * @since 6.1.0beta3/rc1 */
128#define OHCI_SAVED_STATE_VERSION_NO_EOF_TIMER 6
129/** The current saved with the start-of-frame timer.
130 * @since 4.3.x */
131#define OHCI_SAVED_STATE_VERSION_EOF_TIMER 5
132/** The saved state with support of up to 8 ports.
133 * @since 3.1 or so */
134#define OHCI_SAVED_STATE_VERSION_8PORTS 4
135
136
137/** Maximum supported number of Downstream Ports on the root hub. 15 ports
138 * is the maximum defined by the OHCI spec. Must match the number of status
139 * register words to the 'opreg' array.
140 */
141#define OHCI_NDP_MAX 15
142
143/** Default NDP, chosen to be compatible with everything. */
144#define OHCI_NDP_DEFAULT 12
145
146/* Macro to query the number of currently configured ports. */
147#define OHCI_NDP_CFG(pohci) ((pohci)->RootHub.desc_a & OHCI_RHA_NDP)
148/** Macro to convert a EHCI port index (zero based) to a VUSB roothub port ID (one based). */
149#define OHCI_PORT_2_VUSB_PORT(a_uPort) ((a_uPort) + 1)
150
151/** Pointer to OHCI device data. */
152typedef struct OHCI *POHCI;
153/** Read-only pointer to the OHCI device data. */
154typedef struct OHCI const *PCOHCI;
155
156#ifndef VBOX_DEVICE_STRUCT_TESTCASE
157/**
158 * Host controller transfer descriptor data.
159 */
160typedef struct VUSBURBHCITDINT
161{
162 /** Type of TD. */
163 uint32_t TdType;
164 /** The address of the */
165 RTGCPHYS32 TdAddr;
166 /** A copy of the TD. */
167 uint32_t TdCopy[16];
168} VUSBURBHCITDINT;
169
170/**
171 * The host controller data associated with each URB.
172 */
173typedef struct VUSBURBHCIINT
174{
175 /** The endpoint descriptor address. */
176 RTGCPHYS32 EdAddr;
177 /** Number of Tds in the array. */
178 uint32_t cTds;
179 /** When this URB was created.
180 * (Used for isochronous frames and for logging.) */
181 uint32_t u32FrameNo;
182 /** Flag indicating that the TDs have been unlinked. */
183 bool fUnlinked;
184} VUSBURBHCIINT;
185#endif
186
187/**
188 * An OHCI root hub port.
189 */
190typedef struct OHCIHUBPORT
191{
192 /** The port register. */
193 uint32_t fReg;
194 /** Flag whether there is a device attached to the port. */
195 bool fAttached;
196 bool afPadding[3];
197} OHCIHUBPORT;
198/** Pointer to an OHCI hub port. */
199typedef OHCIHUBPORT *POHCIHUBPORT;
200
201/**
202 * The OHCI root hub, shared.
203 */
204typedef struct OHCIROOTHUB
205{
206 uint32_t status;
207 uint32_t desc_a;
208 uint32_t desc_b;
209#if HC_ARCH_BITS == 64
210 uint32_t Alignment0; /**< Align aPorts on a 8 byte boundary. */
211#endif
212 OHCIHUBPORT aPorts[OHCI_NDP_MAX];
213} OHCIROOTHUB;
214/** Pointer to the OHCI root hub. */
215typedef OHCIROOTHUB *POHCIROOTHUB;
216
217
218/**
219 * The OHCI root hub, ring-3 data.
220 *
221 * @implements PDMIBASE
222 * @implements VUSBIROOTHUBPORT
223 * @implements PDMILEDPORTS
224 */
225typedef struct OHCIROOTHUBR3
226{
227 /** Pointer to the base interface of the VUSB RootHub. */
228 R3PTRTYPE(PPDMIBASE) pIBase;
229 /** Pointer to the connector interface of the VUSB RootHub. */
230 R3PTRTYPE(PVUSBIROOTHUBCONNECTOR) pIRhConn;
231 /** The base interface exposed to the roothub driver. */
232 PDMIBASE IBase;
233 /** The roothub port interface exposed to the roothub driver. */
234 VUSBIROOTHUBPORT IRhPort;
235
236 /** The LED. */
237 PDMLED Led;
238 /** The LED ports. */
239 PDMILEDPORTS ILeds;
240 /** Partner of ILeds. */
241 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
242
243 OHCIHUBPORT aPorts[OHCI_NDP_MAX];
244 R3PTRTYPE(POHCI) pOhci;
245} OHCIROOTHUBR3;
246/** Pointer to the OHCI ring-3 root hub data. */
247typedef OHCIROOTHUBR3 *POHCIROOTHUBR3;
248
249#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
250typedef struct OHCIPAGECACHE
251{
252 /** Last read physical page address. */
253 RTGCPHYS GCPhysReadCacheAddr;
254 /** Copy of last read physical page. */
255 uint8_t abPhysReadCache[GUEST_PAGE_SIZE];
256} OHCIPAGECACHE;
257typedef OHCIPAGECACHE *POHCIPAGECACHE;
258#endif
259
260/**
261 * OHCI device data, shared.
262 */
263typedef struct OHCI
264{
265 /** Start of current frame. */
266 uint64_t SofTime;
267 /** done queue interrupt counter */
268 uint32_t dqic : 3;
269 /** frame number overflow. */
270 uint32_t fno : 1;
271
272 /** Align roothub structure on a 8-byte boundary. */
273 uint32_t u32Alignment0;
274 /** Root hub device, shared data. */
275 OHCIROOTHUB RootHub;
276
277 /* OHCI registers */
278
279 /** @name Control partition
280 * @{ */
281 /** HcControl. */
282 uint32_t ctl;
283 /** HcCommandStatus. */
284 uint32_t status;
285 /** HcInterruptStatus. */
286 uint32_t intr_status;
287 /** HcInterruptEnabled. */
288 uint32_t intr;
289 /** @} */
290
291 /** @name Memory pointer partition
292 * @{ */
293 /** HcHCCA. */
294 uint32_t hcca;
295 /** HcPeriodCurrentEd. */
296 uint32_t per_cur;
297 /** HcControlCurrentED. */
298 uint32_t ctrl_cur;
299 /** HcControlHeadED. */
300 uint32_t ctrl_head;
301 /** HcBlockCurrendED. */
302 uint32_t bulk_cur;
303 /** HcBlockHeadED. */
304 uint32_t bulk_head;
305 /** HcDoneHead. */
306 uint32_t done;
307 /** @} */
308
309 /** @name Frame counter partition
310 * @{ */
311 /** HcFmInterval.FSMPS - FSLargestDataPacket */
312 uint32_t fsmps : 15;
313 /** HcFmInterval.FIT - FrameItervalToggle */
314 uint32_t fit : 1;
315 /** HcFmInterval.FI - FrameInterval */
316 uint32_t fi : 14;
317 /** HcFmRemaining.FRT - toggle bit. */
318 uint32_t frt : 1;
319 /** HcFmNumber.
320 * @remark The register size is 16-bit, but for debugging and performance
321 * reasons we maintain a 32-bit counter. */
322 uint32_t HcFmNumber;
323 /** HcPeriodicStart */
324 uint32_t pstart;
325 /** @} */
326
327 /** This member and all the following are not part of saved state. */
328 uint64_t SavedStateEnd;
329
330 /** The number of virtual time ticks per frame. */
331 uint64_t cTicksPerFrame;
332 /** The number of virtual time ticks per USB bus tick. */
333 uint64_t cTicksPerUsbTick;
334
335 /** Detected canceled isochronous URBs. */
336 STAMCOUNTER StatCanceledIsocUrbs;
337 /** Detected canceled general URBs. */
338 STAMCOUNTER StatCanceledGenUrbs;
339 /** Dropped URBs (endpoint halted, or URB canceled). */
340 STAMCOUNTER StatDroppedUrbs;
341
342 /** VM timer frequency used for frame timer calculations. */
343 uint64_t u64TimerHz;
344 /** Idle detection flag; must be cleared at start of frame */
345 bool fIdle;
346 /** A flag indicating that the bulk list may have in-flight URBs. */
347 bool fBulkNeedsCleaning;
348
349 bool afAlignment3[2];
350 uint32_t Alignment4; /**< Align size on a 8 byte boundary. */
351
352 /** Critical section synchronising interrupt handling. */
353 PDMCRITSECT CsIrq;
354
355 /** The MMIO region handle. */
356 IOMMMIOHANDLE hMmio;
357} OHCI;
358
359
360/**
361 * OHCI device data, ring-3.
362 */
363typedef struct OHCIR3
364{
365 /** The root hub, ring-3 portion. */
366 OHCIROOTHUBR3 RootHub;
367 /** Pointer to the device instance - R3 ptr. */
368 PPDMDEVINSR3 pDevInsR3;
369
370 /** Number of in-flight TDs. */
371 unsigned cInFlight;
372 unsigned Alignment0; /**< Align aInFlight on a 8 byte boundary. */
373 /** Array of in-flight TDs. */
374 struct ohci_td_in_flight
375 {
376 /** Address of the transport descriptor. */
377 uint32_t GCPhysTD;
378 /** Flag indicating an inactive (not-linked) URB. */
379 bool fInactive;
380 /** Pointer to the URB. */
381 R3PTRTYPE(PVUSBURB) pUrb;
382 } aInFlight[257];
383
384#if HC_ARCH_BITS == 32
385 uint32_t Alignment1;
386#endif
387
388 /** Number of in-done-queue TDs. */
389 unsigned cInDoneQueue;
390 /** Array of in-done-queue TDs. */
391 struct ohci_td_in_done_queue
392 {
393 /** Address of the transport descriptor. */
394 uint32_t GCPhysTD;
395 } aInDoneQueue[64];
396 /** When the tail of the done queue was added.
397 * Used to calculate the age of the done queue. */
398 uint32_t u32FmDoneQueueTail;
399#if R3_ARCH_BITS == 32
400 /** Align pLoad, the stats and the struct size correctly. */
401 uint32_t Alignment2;
402#endif
403
404#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
405 /** Last read physical page for caching ED reads in the framer thread. */
406 OHCIPAGECACHE CacheED;
407 /** Last read physical page for caching TD reads in the framer thread. */
408 OHCIPAGECACHE CacheTD;
409#endif
410
411 /** Critical section to synchronize the framer and URB completion handler. */
412 RTCRITSECT CritSect;
413
414 /** The restored periodic frame rate. */
415 uint32_t uRestoredPeriodicFrameRate;
416} OHCIR3;
417/** Pointer to ring-3 OHCI state. */
418typedef OHCIR3 *POHCIR3;
419
420/**
421 * OHCI device data, ring-0.
422 */
423typedef struct OHCIR0
424{
425 uint32_t uUnused;
426} OHCIR0;
427/** Pointer to ring-0 OHCI state. */
428typedef OHCIR0 *POHCIR0;
429
430
431/**
432 * OHCI device data, raw-mode.
433 */
434typedef struct OHCIRC
435{
436 uint32_t uUnused;
437} OHCIRC;
438/** Pointer to raw-mode OHCI state. */
439typedef OHCIRC *POHCIRC;
440
441
442/** @typedef OHCICC
443 * The instance data for the current context. */
444typedef CTX_SUFF(OHCI) OHCICC;
445/** @typedef POHCICC
446 * Pointer to the instance data for the current context. */
447typedef CTX_SUFF(POHCI) POHCICC;
448
449
450/** Standard OHCI bus speed */
451#define OHCI_DEFAULT_TIMER_FREQ 1000
452
453/** Host Controller Communications Area
454 * @{ */
455#define OHCI_HCCA_NUM_INTR 32
456#define OHCI_HCCA_OFS (OHCI_HCCA_NUM_INTR * sizeof(uint32_t))
457typedef struct OCHIHCCA
458{
459 uint16_t frame;
460 uint16_t pad;
461 uint32_t done;
462} OCHIHCCA;
463AssertCompileSize(OCHIHCCA, 8);
464/** @} */
465
466/** @name OHCI Endpoint Descriptor
467 * @{ */
468
469#define ED_PTR_MASK (~(uint32_t)0xf)
470#define ED_HWINFO_MPS 0x07ff0000
471#define ED_HWINFO_ISO RT_BIT(15)
472#define ED_HWINFO_SKIP RT_BIT(14)
473#define ED_HWINFO_LOWSPEED RT_BIT(13)
474#define ED_HWINFO_IN RT_BIT(12)
475#define ED_HWINFO_OUT RT_BIT(11)
476#define ED_HWINFO_DIR (RT_BIT(11) | RT_BIT(12))
477#define ED_HWINFO_ENDPOINT 0x780 /* 4 bits */
478#define ED_HWINFO_ENDPOINT_SHIFT 7
479#define ED_HWINFO_FUNCTION 0x7f /* 7 bits */
480#define ED_HEAD_CARRY RT_BIT(1)
481#define ED_HEAD_HALTED RT_BIT(0)
482
483/**
484 * OHCI Endpoint Descriptor.
485 */
486typedef struct OHCIED
487{
488 /** Flags and stuff. */
489 uint32_t hwinfo;
490 /** TailP - TD Queue Tail pointer. Bits 0-3 ignored / preserved. */
491 uint32_t TailP;
492 /** HeadP - TD Queue head pointer. Bit 0 - Halted, Bit 1 - toggleCarry. Bit 2&3 - 0. */
493 uint32_t HeadP;
494 /** NextED - Next Endpoint Descriptor. Bits 0-3 ignored / preserved. */
495 uint32_t NextED;
496} OHCIED, *POHCIED;
497typedef const OHCIED *PCOHCIED;
498/** @} */
499AssertCompileSize(OHCIED, 16);
500
501
502/** @name Completion Codes
503 * @{ */
504#define OHCI_CC_NO_ERROR (UINT32_C(0x00) << 28)
505#define OHCI_CC_CRC (UINT32_C(0x01) << 28)
506#define OHCI_CC_STALL (UINT32_C(0x04) << 28)
507#define OHCI_CC_DEVICE_NOT_RESPONDING (UINT32_C(0x05) << 28)
508#define OHCI_CC_DNR OHCI_CC_DEVICE_NOT_RESPONDING
509#define OHCI_CC_PID_CHECK_FAILURE (UINT32_C(0x06) << 28)
510#define OHCI_CC_UNEXPECTED_PID (UINT32_C(0x07) << 28)
511#define OHCI_CC_DATA_OVERRUN (UINT32_C(0x08) << 28)
512#define OHCI_CC_DATA_UNDERRUN (UINT32_C(0x09) << 28)
513/* 0x0a..0x0b - reserved */
514#define OHCI_CC_BUFFER_OVERRUN (UINT32_C(0x0c) << 28)
515#define OHCI_CC_BUFFER_UNDERRUN (UINT32_C(0x0d) << 28)
516#define OHCI_CC_NOT_ACCESSED_0 (UINT32_C(0x0e) << 28)
517#define OHCI_CC_NOT_ACCESSED_1 (UINT32_C(0x0f) << 28)
518/** @} */
519
520
521/** @name OHCI General transfer descriptor
522 * @{ */
523
524/** Error count (EC) shift. */
525#define TD_ERRORS_SHIFT 26
526/** Error count max. (One greater than what the EC field can hold.) */
527#define TD_ERRORS_MAX 4
528
529/** CC - Condition code mask. */
530#define TD_HWINFO_CC (UINT32_C(0xf0000000))
531#define TD_HWINFO_CC_SHIFT 28
532/** EC - Error count. */
533#define TD_HWINFO_ERRORS (RT_BIT(26) | RT_BIT(27))
534/** T - Data toggle. */
535#define TD_HWINFO_TOGGLE (RT_BIT(24) | RT_BIT(25))
536#define TD_HWINFO_TOGGLE_HI (RT_BIT(25))
537#define TD_HWINFO_TOGGLE_LO (RT_BIT(24))
538/** DI - Delay interrupt. */
539#define TD_HWINFO_DI (RT_BIT(21) | RT_BIT(22) | RT_BIT(23))
540#define TD_HWINFO_IN (RT_BIT(20))
541#define TD_HWINFO_OUT (RT_BIT(19))
542/** DP - Direction / PID. */
543#define TD_HWINFO_DIR (RT_BIT(19) | RT_BIT(20))
544/** R - Buffer rounding. */
545#define TD_HWINFO_ROUNDING (RT_BIT(18))
546/** Bits that are reserved / unknown. */
547#define TD_HWINFO_UNKNOWN_MASK (UINT32_C(0x0003ffff))
548
549/** SETUP - to endpoint. */
550#define OHCI_TD_DIR_SETUP 0x0
551/** OUT - to endpoint. */
552#define OHCI_TD_DIR_OUT 0x1
553/** IN - from endpoint. */
554#define OHCI_TD_DIR_IN 0x2
555/** Reserved. */
556#define OHCI_TD_DIR_RESERVED 0x3
557
558/**
559 * OHCI general transfer descriptor
560 */
561typedef struct OHCITD
562{
563 uint32_t hwinfo;
564 /** CBP - Current Buffer Pointer. (32-bit physical address) */
565 uint32_t cbp;
566 /** NextTD - Link to the next transfer descriptor. (32-bit physical address, dword aligned) */
567 uint32_t NextTD;
568 /** BE - Buffer End (inclusive). (32-bit physical address) */
569 uint32_t be;
570} OHCITD, *POHCITD;
571typedef const OHCITD *PCOHCITD;
572/** @} */
573AssertCompileSize(OHCIED, 16);
574
575
576/** @name OHCI isochronous transfer descriptor.
577 * @{ */
578/** SF - Start frame number. */
579#define ITD_HWINFO_SF 0xffff
580/** DI - Delay interrupt. (TD_HWINFO_DI) */
581#define ITD_HWINFO_DI (RT_BIT(21) | RT_BIT(22) | RT_BIT(23))
582#define ITD_HWINFO_DI_SHIFT 21
583/** FC - Frame count. */
584#define ITD_HWINFO_FC (RT_BIT(24) | RT_BIT(25) | RT_BIT(26))
585#define ITD_HWINFO_FC_SHIFT 24
586/** CC - Condition code mask. (=TD_HWINFO_CC) */
587#define ITD_HWINFO_CC UINT32_C(0xf0000000)
588#define ITD_HWINFO_CC_SHIFT 28
589/** The buffer page 0 mask (lower 12 bits are ignored). */
590#define ITD_BP0_MASK UINT32_C(0xfffff000)
591
592#define ITD_NUM_PSW 8
593/** OFFSET - offset of the package into the buffer page.
594 * (Only valid when CC set to Not Accessed.)
595 *
596 * Note that the top bit of the OFFSET field is overlapping with the
597 * first bit in the CC field. This is ok because both 0xf and 0xe are
598 * defined as "Not Accessed".
599 */
600#define ITD_PSW_OFFSET 0x1fff
601/** SIZE field mask for IN bound transfers.
602 * (Only valid when CC isn't Not Accessed.)*/
603#define ITD_PSW_SIZE 0x07ff
604/** CC field mask.
605 * USed to indicate the format of SIZE (Not Accessed -> OFFSET). */
606#define ITD_PSW_CC 0xf000
607#define ITD_PSW_CC_SHIFT 12
608
609/**
610 * OHCI isochronous transfer descriptor.
611 */
612typedef struct OHCIITD
613{
614 uint32_t HwInfo;
615 /** BP0 - Buffer Page 0. The lower 12 bits are ignored. */
616 uint32_t BP0;
617 /** NextTD - Link to the next transfer descriptor. (32-bit physical address, dword aligned) */
618 uint32_t NextTD;
619 /** BE - Buffer End (inclusive). (32-bit physical address) */
620 uint32_t BE;
621 /** (OffsetN/)PSWN - package status word array (0..7).
622 * The format varies depending on whether the package has been completed or not. */
623 uint16_t aPSW[ITD_NUM_PSW];
624} OHCIITD, *POHCIITD;
625typedef const OHCIITD *PCOHCIITD;
626/** @} */
627AssertCompileSize(OHCIITD, 32);
628
629/**
630 * OHCI register operator.
631 */
632typedef struct OHCIOPREG
633{
634 const char *pszName;
635 VBOXSTRICTRC (*pfnRead )(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value);
636 VBOXSTRICTRC (*pfnWrite)(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t u32Value);
637} OHCIOPREG;
638
639
640/* OHCI Local stuff */
641#define OHCI_CTL_CBSR ((1<<0)|(1<<1)) /* Control/Bulk Service Ratio. */
642#define OHCI_CTL_PLE (1<<2) /* Periodic List Enable. */
643#define OHCI_CTL_IE (1<<3) /* Isochronous Enable. */
644#define OHCI_CTL_CLE (1<<4) /* Control List Enable. */
645#define OHCI_CTL_BLE (1<<5) /* Bulk List Enable. */
646#define OHCI_CTL_HCFS ((1<<6)|(1<<7)) /* Host Controller Functional State. */
647#define OHCI_USB_RESET 0x00
648#define OHCI_USB_RESUME 0x40
649#define OHCI_USB_OPERATIONAL 0x80
650#define OHCI_USB_SUSPEND 0xc0
651#define OHCI_CTL_IR (1<<8) /* Interrupt Routing (host/SMI). */
652#define OHCI_CTL_RWC (1<<9) /* Remote Wakeup Connected. */
653#define OHCI_CTL_RWE (1<<10) /* Remote Wakeup Enabled. */
654
655#define OHCI_STATUS_HCR (1<<0) /* Host Controller Reset. */
656#define OHCI_STATUS_CLF (1<<1) /* Control List Filled. */
657#define OHCI_STATUS_BLF (1<<2) /* Bulk List Filled. */
658#define OHCI_STATUS_OCR (1<<3) /* Ownership Change Request. */
659#define OHCI_STATUS_SOC ((1<<6)|(1<<7)) /* Scheduling Overrun Count. */
660
661/** @name Interrupt Status and Enabled/Disabled Flags
662 * @{ */
663/** SO - Scheduling overrun. */
664#define OHCI_INTR_SCHEDULING_OVERRUN RT_BIT(0)
665/** WDH - HcDoneHead writeback. */
666#define OHCI_INTR_WRITE_DONE_HEAD RT_BIT(1)
667/** SF - Start of frame. */
668#define OHCI_INTR_START_OF_FRAME RT_BIT(2)
669/** RD - Resume detect. */
670#define OHCI_INTR_RESUME_DETECT RT_BIT(3)
671/** UE - Unrecoverable error. */
672#define OHCI_INTR_UNRECOVERABLE_ERROR RT_BIT(4)
673/** FNO - Frame number overflow. */
674#define OHCI_INTR_FRAMENUMBER_OVERFLOW RT_BIT(5)
675/** RHSC- Root hub status change. */
676#define OHCI_INTR_ROOT_HUB_STATUS_CHANGE RT_BIT(6)
677/** OC - Ownership change. */
678#define OHCI_INTR_OWNERSHIP_CHANGE RT_BIT(30)
679/** MIE - Master interrupt enable. */
680#define OHCI_INTR_MASTER_INTERRUPT_ENABLED RT_BIT(31)
681/** @} */
682
683#define OHCI_HCCA_SIZE 0x100
684#define OHCI_HCCA_MASK UINT32_C(0xffffff00)
685
686#define OHCI_FMI_FI UINT32_C(0x00003fff) /* Frame Interval. */
687#define OHCI_FMI_FSMPS UINT32_C(0x7fff0000) /* Full-Speed Max Packet Size. */
688#define OHCI_FMI_FSMPS_SHIFT 16
689#define OHCI_FMI_FIT UINT32_C(0x80000000) /* Frame Interval Toggle. */
690#define OHCI_FMI_FIT_SHIFT 31
691
692#define OHCI_FR_FRT RT_BIT_32(31) /* Frame Remaining Toggle */
693
694#define OHCI_LS_THRESH 0x628 /* Low-Speed Threshold. */
695
696#define OHCI_RHA_NDP (0xff) /* Number of Downstream Ports. */
697#define OHCI_RHA_PSM RT_BIT_32(8) /* Power Switching Mode. */
698#define OHCI_RHA_NPS RT_BIT_32(9) /* No Power Switching. */
699#define OHCI_RHA_DT RT_BIT_32(10) /* Device Type. */
700#define OHCI_RHA_OCPM RT_BIT_32(11) /* Over-Current Protection Mode. */
701#define OHCI_RHA_NOCP RT_BIT_32(12) /* No Over-Current Protection. */
702#define OHCI_RHA_POTPGP UINT32_C(0xff000000) /* Power On To Power Good Time. */
703
704#define OHCI_RHS_LPS RT_BIT_32(0) /* Local Power Status. */
705#define OHCI_RHS_OCI RT_BIT_32(1) /* Over-Current Indicator. */
706#define OHCI_RHS_DRWE RT_BIT_32(15) /* Device Remote Wakeup Enable. */
707#define OHCI_RHS_LPSC RT_BIT_32(16) /* Local Power Status Change. */
708#define OHCI_RHS_OCIC RT_BIT_32(17) /* Over-Current Indicator Change. */
709#define OHCI_RHS_CRWE RT_BIT_32(31) /* Clear Remote Wakeup Enable. */
710
711/** @name HcRhPortStatus[n] - RH Port Status register (read).
712 * @{ */
713/** CCS - CurrentConnectionStatus - 0 = no device, 1 = device. */
714#define OHCI_PORT_CCS RT_BIT(0)
715/** ClearPortEnable (when writing CCS). */
716#define OHCI_PORT_CLRPE OHCI_PORT_CCS
717/** PES - PortEnableStatus. */
718#define OHCI_PORT_PES RT_BIT(1)
719/** PSS - PortSuspendStatus */
720#define OHCI_PORT_PSS RT_BIT(2)
721/** POCI- PortOverCurrentIndicator. */
722#define OHCI_PORT_POCI RT_BIT(3)
723/** ClearSuspendStatus (when writing POCI). */
724#define OHCI_PORT_CLRSS OHCI_PORT_POCI
725/** PRS - PortResetStatus */
726#define OHCI_PORT_PRS RT_BIT(4)
727/** PPS - PortPowerStatus */
728#define OHCI_PORT_PPS RT_BIT(8)
729/** LSDA - LowSpeedDeviceAttached */
730#define OHCI_PORT_LSDA RT_BIT(9)
731/** ClearPortPower (when writing LSDA). */
732#define OHCI_PORT_CLRPP OHCI_PORT_LSDA
733/** CSC - ConnectStatusChange */
734#define OHCI_PORT_CSC RT_BIT(16)
735/** PESC - PortEnableStatusChange */
736#define OHCI_PORT_PESC RT_BIT(17)
737/** PSSC - PortSuspendStatusChange */
738#define OHCI_PORT_PSSC RT_BIT(18)
739/** OCIC - OverCurrentIndicatorChange */
740#define OHCI_PORT_OCIC RT_BIT(19)
741/** PRSC - PortResetStatusChange */
742#define OHCI_PORT_PRSC RT_BIT(20)
743/** The mask of RW1C bits. */
744#define OHCI_PORT_CLEAR_CHANGE_MASK (OHCI_PORT_CSC | OHCI_PORT_PESC | OHCI_PORT_PSSC | OHCI_PORT_OCIC | OHCI_PORT_PRSC)
745/** @} */
746
747
748#ifndef VBOX_DEVICE_STRUCT_TESTCASE
749
750#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
751/*
752 * Explain
753 */
754typedef struct OHCIDESCREADSTATS
755{
756 uint32_t cReads;
757 uint32_t cPageChange;
758 uint32_t cMinReadsPerPage;
759 uint32_t cMaxReadsPerPage;
760
761 uint32_t cReadsLastPage;
762 uint32_t u32LastPageAddr;
763} OHCIDESCREADSTATS;
764typedef OHCIDESCREADSTATS *POHCIDESCREADSTATS;
765
766typedef struct OHCIPHYSREADSTATS
767{
768 OHCIDESCREADSTATS ed;
769 OHCIDESCREADSTATS td;
770 OHCIDESCREADSTATS all;
771
772 uint32_t cCrossReads;
773 uint32_t cCacheReads;
774 uint32_t cPageReads;
775} OHCIPHYSREADSTATS;
776typedef OHCIPHYSREADSTATS *POHCIPHYSREADSTATS;
777typedef OHCIPHYSREADSTATS const *PCOHCIPHYSREADSTATS;
778#endif /* VBOX_WITH_OHCI_PHYS_READ_STATS */
779
780
781/*********************************************************************************************************************************
782* Global Variables *
783*********************************************************************************************************************************/
784#if defined(VBOX_WITH_OHCI_PHYS_READ_STATS) && defined(IN_RING3)
785static OHCIPHYSREADSTATS g_PhysReadState;
786#endif
787
788#if defined(LOG_ENABLED) && defined(IN_RING3)
789static bool g_fLogBulkEPs = false;
790static bool g_fLogControlEPs = false;
791static bool g_fLogInterruptEPs = false;
792#endif
793#ifdef IN_RING3
794/**
795 * SSM descriptor table for the OHCI structure.
796 */
797static SSMFIELD const g_aOhciFields[] =
798{
799 SSMFIELD_ENTRY( OHCI, SofTime),
800 SSMFIELD_ENTRY_CUSTOM( dpic+fno, RT_OFFSETOF(OHCI, SofTime) + RT_SIZEOFMEMB(OHCI, SofTime), 4),
801 SSMFIELD_ENTRY( OHCI, RootHub.status),
802 SSMFIELD_ENTRY( OHCI, RootHub.desc_a),
803 SSMFIELD_ENTRY( OHCI, RootHub.desc_b),
804 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[0].fReg),
805 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[1].fReg),
806 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[2].fReg),
807 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[3].fReg),
808 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[4].fReg),
809 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[5].fReg),
810 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[6].fReg),
811 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[7].fReg),
812 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[8].fReg),
813 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[9].fReg),
814 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[10].fReg),
815 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[11].fReg),
816 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[12].fReg),
817 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[13].fReg),
818 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[14].fReg),
819 SSMFIELD_ENTRY( OHCI, ctl),
820 SSMFIELD_ENTRY( OHCI, status),
821 SSMFIELD_ENTRY( OHCI, intr_status),
822 SSMFIELD_ENTRY( OHCI, intr),
823 SSMFIELD_ENTRY( OHCI, hcca),
824 SSMFIELD_ENTRY( OHCI, per_cur),
825 SSMFIELD_ENTRY( OHCI, ctrl_cur),
826 SSMFIELD_ENTRY( OHCI, ctrl_head),
827 SSMFIELD_ENTRY( OHCI, bulk_cur),
828 SSMFIELD_ENTRY( OHCI, bulk_head),
829 SSMFIELD_ENTRY( OHCI, done),
830 SSMFIELD_ENTRY_CUSTOM( fsmps+fit+fi+frt, RT_OFFSETOF(OHCI, done) + RT_SIZEOFMEMB(OHCI, done), 4),
831 SSMFIELD_ENTRY( OHCI, HcFmNumber),
832 SSMFIELD_ENTRY( OHCI, pstart),
833 SSMFIELD_ENTRY_TERM()
834};
835
836/**
837 * SSM descriptor table for the older 8-port OHCI structure.
838 */
839static SSMFIELD const g_aOhciFields8Ports[] =
840{
841 SSMFIELD_ENTRY( OHCI, SofTime),
842 SSMFIELD_ENTRY_CUSTOM( dpic+fno, RT_OFFSETOF(OHCI, SofTime) + RT_SIZEOFMEMB(OHCI, SofTime), 4),
843 SSMFIELD_ENTRY( OHCI, RootHub.status),
844 SSMFIELD_ENTRY( OHCI, RootHub.desc_a),
845 SSMFIELD_ENTRY( OHCI, RootHub.desc_b),
846 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[0].fReg),
847 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[1].fReg),
848 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[2].fReg),
849 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[3].fReg),
850 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[4].fReg),
851 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[5].fReg),
852 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[6].fReg),
853 SSMFIELD_ENTRY( OHCI, RootHub.aPorts[7].fReg),
854 SSMFIELD_ENTRY( OHCI, ctl),
855 SSMFIELD_ENTRY( OHCI, status),
856 SSMFIELD_ENTRY( OHCI, intr_status),
857 SSMFIELD_ENTRY( OHCI, intr),
858 SSMFIELD_ENTRY( OHCI, hcca),
859 SSMFIELD_ENTRY( OHCI, per_cur),
860 SSMFIELD_ENTRY( OHCI, ctrl_cur),
861 SSMFIELD_ENTRY( OHCI, ctrl_head),
862 SSMFIELD_ENTRY( OHCI, bulk_cur),
863 SSMFIELD_ENTRY( OHCI, bulk_head),
864 SSMFIELD_ENTRY( OHCI, done),
865 SSMFIELD_ENTRY_CUSTOM( fsmps+fit+fi+frt, RT_OFFSETOF(OHCI, done) + RT_SIZEOFMEMB(OHCI, done), 4),
866 SSMFIELD_ENTRY( OHCI, HcFmNumber),
867 SSMFIELD_ENTRY( OHCI, pstart),
868 SSMFIELD_ENTRY_TERM()
869};
870#endif
871
872
873/*********************************************************************************************************************************
874* Internal Functions *
875*********************************************************************************************************************************/
876RT_C_DECLS_BEGIN
877#ifdef IN_RING3
878/* Update host controller state to reflect a device attach */
879static void ohciR3RhPortPower(POHCIROOTHUBR3 pRh, unsigned iPort, bool fPowerUp);
880static void ohciR3BusResume(PPDMDEVINS pDevIns, POHCI pOhci, POHCICC pThisCC, bool fHardware);
881static void ohciR3BusStop(POHCICC pThisCC);
882#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
883static void ohciR3PhysReadCacheInvalidate(POHCIPAGECACHE pPageCache);
884#endif
885
886static DECLCALLBACK(void) ohciR3RhXferCompletion(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
887static DECLCALLBACK(bool) ohciR3RhXferError(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
888
889static int ohciR3InFlightFind(POHCICC pThisCC, uint32_t GCPhysTD);
890# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
891static int ohciR3InDoneQueueFind(POHCICC pThisCC, uint32_t GCPhysTD);
892# endif
893#endif /* IN_RING3 */
894RT_C_DECLS_END
895
896
897/**
898 * Update PCI IRQ levels
899 */
900static void ohciUpdateInterruptLocked(PPDMDEVINS pDevIns, POHCI ohci, const char *msg)
901{
902 int level = 0;
903
904 if ( (ohci->intr & OHCI_INTR_MASTER_INTERRUPT_ENABLED)
905 && (ohci->intr_status & ohci->intr)
906 && !(ohci->ctl & OHCI_CTL_IR))
907 level = 1;
908
909 PDMDevHlpPCISetIrq(pDevIns, 0, level);
910 if (level)
911 {
912 uint32_t val = ohci->intr_status & ohci->intr;
913 Log2(("ohci: Fired off interrupt %#010x - SO=%d WDH=%d SF=%d RD=%d UE=%d FNO=%d RHSC=%d OC=%d - %s\n",
914 val, val & 1, (val >> 1) & 1, (val >> 2) & 1, (val >> 3) & 1, (val >> 4) & 1, (val >> 5) & 1,
915 (val >> 6) & 1, (val >> 30) & 1, msg)); NOREF(val); NOREF(msg);
916 }
917}
918
919#ifdef IN_RING3
920
921/**
922 * Set an interrupt, use the wrapper ohciSetInterrupt.
923 */
924DECLINLINE(int) ohciR3SetInterruptInt(PPDMDEVINS pDevIns, POHCI ohci, int rcBusy, uint32_t intr, const char *msg)
925{
926 int rc = PDMDevHlpCritSectEnter(pDevIns, &ohci->CsIrq, rcBusy);
927 if (rc != VINF_SUCCESS)
928 return rc;
929
930 if ( (ohci->intr_status & intr) != intr )
931 {
932 ohci->intr_status |= intr;
933 ohciUpdateInterruptLocked(pDevIns, ohci, msg);
934 }
935
936 PDMDevHlpCritSectLeave(pDevIns, &ohci->CsIrq);
937 return rc;
938}
939
940/**
941 * Set an interrupt wrapper macro for logging purposes.
942 */
943# define ohciR3SetInterrupt(a_pDevIns, a_pOhci, a_fIntr) \
944 ohciR3SetInterruptInt(a_pDevIns, a_pOhci, VERR_IGNORED, a_fIntr, #a_fIntr)
945
946
947/**
948 * Sets the HC in the unrecoverable error state and raises the appropriate interrupt.
949 *
950 * @param pDevIns The device instance.
951 * @param pThis The OHCI instance.
952 * @param iCode Diagnostic code.
953 */
954DECLINLINE(void) ohciR3RaiseUnrecoverableError(PPDMDEVINS pDevIns, POHCI pThis, int iCode)
955{
956 LogRelMax(10, ("OHCI#%d: Raising unrecoverable error (%d)\n", pDevIns->iInstance, iCode));
957 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_UNRECOVERABLE_ERROR);
958}
959
960
961/* Carry out a hardware remote wakeup */
962static void ohciR3RemoteWakeup(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
963{
964 if ((pThis->ctl & OHCI_CTL_HCFS) != OHCI_USB_SUSPEND)
965 return;
966 if (!(pThis->RootHub.status & OHCI_RHS_DRWE))
967 return;
968 ohciR3BusResume(pDevIns, pThis, pThisCC, true /* hardware */);
969}
970
971
972/**
973 * Query interface method for the roothub LUN.
974 */
975static DECLCALLBACK(void *) ohciR3RhQueryInterface(PPDMIBASE pInterface, const char *pszIID)
976{
977 POHCICC pThisCC = RT_FROM_MEMBER(pInterface, OHCICC, RootHub.IBase);
978 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->RootHub.IBase);
979 PDMIBASE_RETURN_INTERFACE(pszIID, VUSBIROOTHUBPORT, &pThisCC->RootHub.IRhPort);
980 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->RootHub.ILeds);
981 return NULL;
982}
983
984/**
985 * Gets the pointer to the status LED of a unit.
986 *
987 * @returns VBox status code.
988 * @param pInterface Pointer to the interface structure containing the called function pointer.
989 * @param iLUN The unit which status LED we desire.
990 * @param ppLed Where to store the LED pointer.
991 */
992static DECLCALLBACK(int) ohciR3RhQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
993{
994 POHCICC pThisCC = RT_FROM_MEMBER(pInterface, OHCICC, RootHub.ILeds);
995 if (iLUN == 0)
996 {
997 *ppLed = &pThisCC->RootHub.Led;
998 return VINF_SUCCESS;
999 }
1000 return VERR_PDM_LUN_NOT_FOUND;
1001}
1002
1003
1004/** Converts a OHCI.roothub.IRhPort pointer to a OHCICC one. */
1005#define VUSBIROOTHUBPORT_2_OHCI(a_pInterface) RT_FROM_MEMBER(a_pInterface, OHCICC, RootHub.IRhPort)
1006
1007/**
1008 * Get the number of available ports in the hub.
1009 *
1010 * @returns The number of ports available.
1011 * @param pInterface Pointer to this structure.
1012 * @param pAvailable Bitmap indicating the available ports. Set bit == available port.
1013 */
1014static DECLCALLBACK(unsigned) ohciR3RhGetAvailablePorts(PVUSBIROOTHUBPORT pInterface, PVUSBPORTBITMAP pAvailable)
1015{
1016 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
1017 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
1018 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
1019 unsigned cPorts = 0;
1020
1021 memset(pAvailable, 0, sizeof(*pAvailable));
1022
1023 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1024 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1025
1026
1027 for (unsigned iPort = 0; iPort < OHCI_NDP_CFG(pThis); iPort++)
1028 if (!pThis->RootHub.aPorts[iPort].fAttached)
1029 {
1030 cPorts++;
1031 ASMBitSet(pAvailable, iPort + 1);
1032 }
1033
1034 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1035 return cPorts;
1036}
1037
1038
1039/**
1040 * Gets the supported USB versions.
1041 *
1042 * @returns The mask of supported USB versions.
1043 * @param pInterface Pointer to this structure.
1044 */
1045static DECLCALLBACK(uint32_t) ohciR3RhGetUSBVersions(PVUSBIROOTHUBPORT pInterface)
1046{
1047 RT_NOREF(pInterface);
1048 return VUSB_STDVER_11;
1049}
1050
1051
1052/** @interface_method_impl{VUSBIROOTHUBPORT,pfnAttach} */
1053static DECLCALLBACK(int) ohciR3RhAttach(PVUSBIROOTHUBPORT pInterface, uint32_t uPort, VUSBSPEED enmSpeed)
1054{
1055 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
1056 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
1057 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
1058 LogFlow(("ohciR3RhAttach: uPort=%u\n", uPort));
1059 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1060 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1061
1062 /*
1063 * Validate and adjust input.
1064 */
1065 Assert(uPort >= 1 && uPort <= OHCI_NDP_CFG(pThis));
1066 uPort--;
1067 Assert(!pThis->RootHub.aPorts[uPort].fAttached);
1068 /* Only LS/FS devices should end up here. */
1069 Assert(enmSpeed == VUSB_SPEED_LOW || enmSpeed == VUSB_SPEED_FULL);
1070
1071 /*
1072 * Attach it.
1073 */
1074 pThis->RootHub.aPorts[uPort].fReg = OHCI_PORT_CCS | OHCI_PORT_CSC;
1075 if (enmSpeed == VUSB_SPEED_LOW)
1076 pThis->RootHub.aPorts[uPort].fReg |= OHCI_PORT_LSDA;
1077 pThis->RootHub.aPorts[uPort].fAttached = true;
1078 ohciR3RhPortPower(&pThisCC->RootHub, uPort, 1 /* power on */);
1079
1080 ohciR3RemoteWakeup(pDevIns, pThis, pThisCC);
1081 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
1082
1083 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1084 return VINF_SUCCESS;
1085}
1086
1087
1088/**
1089 * A device is being detached from a port in the roothub.
1090 *
1091 * @param pInterface Pointer to this structure.
1092 * @param uPort The port number assigned to the device.
1093 */
1094static DECLCALLBACK(void) ohciR3RhDetach(PVUSBIROOTHUBPORT pInterface, uint32_t uPort)
1095{
1096 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
1097 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
1098 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
1099 LogFlow(("ohciR3RhDetach: uPort=%u\n", uPort));
1100 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1101 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1102
1103 /*
1104 * Validate and adjust input.
1105 */
1106 Assert(uPort >= 1 && uPort <= OHCI_NDP_CFG(pThis));
1107 uPort--;
1108 Assert(pThis->RootHub.aPorts[uPort].fAttached);
1109
1110 /*
1111 * Detach it.
1112 */
1113 pThis->RootHub.aPorts[uPort].fAttached = false;
1114 if (pThis->RootHub.aPorts[uPort].fReg & OHCI_PORT_PES)
1115 pThis->RootHub.aPorts[uPort].fReg = OHCI_PORT_CSC | OHCI_PORT_PESC;
1116 else
1117 pThis->RootHub.aPorts[uPort].fReg = OHCI_PORT_CSC;
1118
1119 ohciR3RemoteWakeup(pDevIns, pThis, pThisCC);
1120 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
1121
1122 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1123}
1124
1125
1126/**
1127 * One of the roothub devices has completed its reset operation.
1128 *
1129 * Currently, we don't think anything is required to be done here
1130 * so it's just a stub for forcing async resetting of the devices
1131 * during a root hub reset.
1132 *
1133 * @param pDev The root hub device.
1134 * @param uPort The port of the device completing the reset.
1135 * @param rc The result of the operation.
1136 * @param pvUser Pointer to the controller.
1137 */
1138static DECLCALLBACK(void) ohciR3RhResetDoneOneDev(PVUSBIDEVICE pDev, uint32_t uPort, int rc, void *pvUser)
1139{
1140 LogRel(("OHCI: root hub reset completed with %Rrc\n", rc));
1141 RT_NOREF(pDev, uPort, rc, pvUser);
1142}
1143
1144
1145/**
1146 * Reset the root hub.
1147 *
1148 * @returns VBox status code.
1149 * @param pInterface Pointer to this structure.
1150 * @param fResetOnLinux This is used to indicate whether we're at VM reset time and
1151 * can do real resets or if we're at any other time where that
1152 * isn't such a good idea.
1153 * @remark Do NOT call VUSBIDevReset on the root hub in an async fashion!
1154 * @thread EMT
1155 */
1156static DECLCALLBACK(int) ohciR3RhReset(PVUSBIROOTHUBPORT pInterface, bool fResetOnLinux)
1157{
1158 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
1159 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
1160 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
1161 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1162 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1163
1164 Log(("ohci: root hub reset%s\n", fResetOnLinux ? " (reset on linux)" : ""));
1165
1166 pThis->RootHub.status = 0;
1167 pThis->RootHub.desc_a = OHCI_RHA_NPS | OHCI_NDP_CFG(pThis); /* Preserve NDP value. */
1168 pThis->RootHub.desc_b = 0x0; /* Impl. specific */
1169
1170 /*
1171 * We're pending to _reattach_ the device without resetting them.
1172 * Except, during VM reset where we use the opportunity to do a proper
1173 * reset before the guest comes along and expect things.
1174 *
1175 * However, it's very very likely that we're not doing the right thing
1176 * here if coming from the guest (USB Reset state). The docs talks about
1177 * root hub resetting, however what exact behaviour in terms of root hub
1178 * status and changed bits, and HC interrupts aren't stated clearly. IF we
1179 * get trouble and see the guest doing "USB Resets" we will have to look
1180 * into this. For the time being we stick with simple.
1181 */
1182 for (unsigned iPort = 0; iPort < OHCI_NDP_CFG(pThis); iPort++)
1183 {
1184 if (pThis->RootHub.aPorts[iPort].fAttached)
1185 {
1186 pThis->RootHub.aPorts[iPort].fReg = OHCI_PORT_CCS | OHCI_PORT_CSC | OHCI_PORT_PPS;
1187 if (fResetOnLinux)
1188 {
1189 PVM pVM = PDMDevHlpGetVM(pDevIns);
1190 VUSBIRhDevReset(pThisCC->RootHub.pIRhConn, OHCI_PORT_2_VUSB_PORT(iPort), fResetOnLinux,
1191 ohciR3RhResetDoneOneDev, pThis, pVM);
1192 }
1193 }
1194 else
1195 pThis->RootHub.aPorts[iPort].fReg = 0;
1196 }
1197 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_ROOT_HUB_STATUS_CHANGE);
1198
1199 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1200 return VINF_SUCCESS;
1201}
1202
1203
1204/**
1205 * Does a software or hardware reset of the controller.
1206 *
1207 * This is called in response to setting HcCommandStatus.HCR, hardware reset,
1208 * and device construction.
1209 *
1210 * @param pDevIns The device instance.
1211 * @param pThis The ohci instance data.
1212 * @param pThisCC The ohci instance data, current context.
1213 * @param fNewMode The new mode of operation. This is UsbSuspend if it's a
1214 * software reset, and UsbReset if it's a hardware reset / cold boot.
1215 * @param fResetOnLinux Set if we can do a real reset of the devices attached to the root hub.
1216 * This is really a just a hack for the non-working linux device reset.
1217 * Linux has this feature called 'logical disconnect' if device reset fails
1218 * which prevents us from doing resets when the guest asks for it - the guest
1219 * will get confused when the device seems to be reconnected everytime it tries
1220 * to reset it. But if we're at hardware reset time, we can allow a device to
1221 * be 'reconnected' without upsetting the guest.
1222 *
1223 * @remark This hasn't got anything to do with software setting the mode to UsbReset.
1224 */
1225static void ohciR3DoReset(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, uint32_t fNewMode, bool fResetOnLinux)
1226{
1227 Log(("ohci: %s reset%s\n", fNewMode == OHCI_USB_RESET ? "hardware" : "software",
1228 fResetOnLinux ? " (reset on linux)" : ""));
1229
1230 /* Clear list enable bits first, so that any processing currently in progress terminates quickly. */
1231 pThis->ctl &= ~(OHCI_CTL_BLE | OHCI_CTL_CLE | OHCI_CTL_PLE);
1232
1233 /* Stop the bus in any case, disabling walking the lists. */
1234 ohciR3BusStop(pThisCC);
1235
1236 /*
1237 * Cancel all outstanding URBs.
1238 *
1239 * We can't, and won't, deal with URBs until we're moved out of the
1240 * suspend/reset state. Also, a real HC isn't going to send anything
1241 * any more when a reset has been signaled.
1242 */
1243 pThisCC->RootHub.pIRhConn->pfnCancelAllUrbs(pThisCC->RootHub.pIRhConn);
1244 Assert(pThisCC->cInFlight == 0);
1245
1246 /*
1247 * Reset the hardware registers.
1248 */
1249 if (fNewMode == OHCI_USB_RESET)
1250 pThis->ctl = OHCI_CTL_RWC; /* We're the firmware, set RemoteWakeupConnected. */
1251 else
1252 pThis->ctl &= OHCI_CTL_IR | OHCI_CTL_RWC; /* IR and RWC are preserved on software reset. */
1253
1254 /* Clear the HCFS bits first to make setting the new state work. */
1255 pThis->ctl &= ~OHCI_CTL_HCFS;
1256 pThis->ctl |= fNewMode;
1257 pThis->status = 0;
1258 pThis->intr_status = 0;
1259 pThis->intr = 0;
1260 PDMDevHlpPCISetIrq(pDevIns, 0, 0);
1261
1262 pThis->hcca = 0;
1263 pThis->per_cur = 0;
1264 pThis->ctrl_head = pThis->ctrl_cur = 0;
1265 pThis->bulk_head = pThis->bulk_cur = 0;
1266 pThis->done = 0;
1267
1268 pThis->fsmps = 0x2778; /* To-Be-Defined, use the value linux sets...*/
1269 pThis->fit = 0;
1270 pThis->fi = 11999; /* (12MHz ticks, one frame is 1ms) */
1271 pThis->frt = 0;
1272 pThis->HcFmNumber = 0;
1273 pThis->pstart = 0;
1274
1275 pThis->dqic = 0x7;
1276 pThis->fno = 0;
1277
1278#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
1279 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheED);
1280 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheTD);
1281#endif
1282
1283 /*
1284 * If this is a hardware reset, we will initialize the root hub too.
1285 * Software resets doesn't do this according to the specs.
1286 * (It's not possible to have device connected at the time of the
1287 * device construction, so nothing to worry about there.)
1288 */
1289 if (fNewMode == OHCI_USB_RESET)
1290 pThisCC->RootHub.pIRhConn->pfnReset(pThisCC->RootHub.pIRhConn, fResetOnLinux);
1291}
1292
1293
1294/**
1295 * Reads physical memory.
1296 */
1297DECLINLINE(void) ohciR3PhysRead(PPDMDEVINS pDevIns, uint32_t Addr, void *pvBuf, size_t cbBuf)
1298{
1299 if (cbBuf)
1300 PDMDevHlpPCIPhysReadUser(pDevIns, Addr, pvBuf, cbBuf);
1301}
1302
1303/**
1304 * Reads physical memory - metadata.
1305 */
1306DECLINLINE(void) ohciR3PhysReadMeta(PPDMDEVINS pDevIns, uint32_t Addr, void *pvBuf, size_t cbBuf)
1307{
1308 if (cbBuf)
1309 PDMDevHlpPCIPhysReadMeta(pDevIns, Addr, pvBuf, cbBuf);
1310}
1311
1312/**
1313 * Writes physical memory.
1314 */
1315DECLINLINE(void) ohciR3PhysWrite(PPDMDEVINS pDevIns, uint32_t Addr, const void *pvBuf, size_t cbBuf)
1316{
1317 if (cbBuf)
1318 PDMDevHlpPCIPhysWriteUser(pDevIns, Addr, pvBuf, cbBuf);
1319}
1320
1321/**
1322 * Writes physical memory - metadata.
1323 */
1324DECLINLINE(void) ohciR3PhysWriteMeta(PPDMDEVINS pDevIns, uint32_t Addr, const void *pvBuf, size_t cbBuf)
1325{
1326 if (cbBuf)
1327 PDMDevHlpPCIPhysWriteMeta(pDevIns, Addr, pvBuf, cbBuf);
1328}
1329
1330/**
1331 * Read an array of dwords from physical memory and correct endianness.
1332 */
1333DECLINLINE(void) ohciR3GetDWords(PPDMDEVINS pDevIns, uint32_t Addr, uint32_t *pau32s, int c32s)
1334{
1335 ohciR3PhysReadMeta(pDevIns, Addr, pau32s, c32s * sizeof(uint32_t));
1336# ifndef RT_LITTLE_ENDIAN
1337 for(int i = 0; i < c32s; i++)
1338 pau32s[i] = RT_H2LE_U32(pau32s[i]);
1339# endif
1340}
1341
1342/**
1343 * Write an array of dwords from physical memory and correct endianness.
1344 */
1345DECLINLINE(void) ohciR3PutDWords(PPDMDEVINS pDevIns, uint32_t Addr, const uint32_t *pau32s, int cu32s)
1346{
1347# ifdef RT_LITTLE_ENDIAN
1348 ohciR3PhysWriteMeta(pDevIns, Addr, pau32s, cu32s << 2);
1349# else
1350 for (int i = 0; i < c32s; i++, pau32s++, Addr += sizeof(*pau32s))
1351 {
1352 uint32_t u32Tmp = RT_H2LE_U32(*pau32s);
1353 ohciR3PhysWriteMeta(pDevIns, Addr, (uint8_t *)&u32Tmp, sizeof(u32Tmp));
1354 }
1355# endif
1356}
1357
1358
1359
1360# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
1361
1362static void descReadStatsReset(POHCIDESCREADSTATS p)
1363{
1364 p->cReads = 0;
1365 p->cPageChange = 0;
1366 p->cMinReadsPerPage = UINT32_MAX;
1367 p->cMaxReadsPerPage = 0;
1368
1369 p->cReadsLastPage = 0;
1370 p->u32LastPageAddr = 0;
1371}
1372
1373static void physReadStatsReset(POHCIPHYSREADSTATS p)
1374{
1375 descReadStatsReset(&p->ed);
1376 descReadStatsReset(&p->td);
1377 descReadStatsReset(&p->all);
1378
1379 p->cCrossReads = 0;
1380 p->cCacheReads = 0;
1381 p->cPageReads = 0;
1382}
1383
1384static void physReadStatsUpdateDesc(POHCIDESCREADSTATS p, uint32_t u32Addr)
1385{
1386 const uint32_t u32PageAddr = u32Addr & ~UINT32_C(0xFFF);
1387
1388 ++p->cReads;
1389
1390 if (p->u32LastPageAddr == 0)
1391 {
1392 /* First call. */
1393 ++p->cReadsLastPage;
1394 p->u32LastPageAddr = u32PageAddr;
1395 }
1396 else if (u32PageAddr != p->u32LastPageAddr)
1397 {
1398 /* New page. */
1399 ++p->cPageChange;
1400
1401 p->cMinReadsPerPage = RT_MIN(p->cMinReadsPerPage, p->cReadsLastPage);
1402 p->cMaxReadsPerPage = RT_MAX(p->cMaxReadsPerPage, p->cReadsLastPage);;
1403
1404 p->cReadsLastPage = 1;
1405 p->u32LastPageAddr = u32PageAddr;
1406 }
1407 else
1408 {
1409 /* Read on the same page. */
1410 ++p->cReadsLastPage;
1411 }
1412}
1413
1414static void physReadStatsPrint(POHCIPHYSREADSTATS p)
1415{
1416 p->ed.cMinReadsPerPage = RT_MIN(p->ed.cMinReadsPerPage, p->ed.cReadsLastPage);
1417 p->ed.cMaxReadsPerPage = RT_MAX(p->ed.cMaxReadsPerPage, p->ed.cReadsLastPage);;
1418
1419 p->td.cMinReadsPerPage = RT_MIN(p->td.cMinReadsPerPage, p->td.cReadsLastPage);
1420 p->td.cMaxReadsPerPage = RT_MAX(p->td.cMaxReadsPerPage, p->td.cReadsLastPage);;
1421
1422 p->all.cMinReadsPerPage = RT_MIN(p->all.cMinReadsPerPage, p->all.cReadsLastPage);
1423 p->all.cMaxReadsPerPage = RT_MAX(p->all.cMaxReadsPerPage, p->all.cReadsLastPage);;
1424
1425 LogRel(("PHYSREAD:\n"
1426 " ED: %d, %d, %d/%d\n"
1427 " TD: %d, %d, %d/%d\n"
1428 " ALL: %d, %d, %d/%d\n"
1429 " C: %d, %d, %d\n"
1430 "",
1431 p->ed.cReads, p->ed.cPageChange, p->ed.cMinReadsPerPage, p->ed.cMaxReadsPerPage,
1432 p->td.cReads, p->td.cPageChange, p->td.cMinReadsPerPage, p->td.cMaxReadsPerPage,
1433 p->all.cReads, p->all.cPageChange, p->all.cMinReadsPerPage, p->all.cMaxReadsPerPage,
1434 p->cCrossReads, p->cCacheReads, p->cPageReads
1435 ));
1436
1437 physReadStatsReset(p);
1438}
1439
1440# endif /* VBOX_WITH_OHCI_PHYS_READ_STATS */
1441# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
1442
1443static void ohciR3PhysReadCacheInvalidate(POHCIPAGECACHE pPageCache)
1444{
1445 pPageCache->GCPhysReadCacheAddr = NIL_RTGCPHYS;
1446}
1447
1448static void ohciR3PhysReadCacheRead(PPDMDEVINS pDevIns, POHCIPAGECACHE pPageCache, RTGCPHYS GCPhys, void *pvBuf, size_t cbBuf)
1449{
1450 const RTGCPHYS PageAddr = GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
1451
1452 if (PageAddr == ((GCPhys + cbBuf) & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK))
1453 {
1454 if (PageAddr != pPageCache->GCPhysReadCacheAddr)
1455 {
1456 PDMDevHlpPCIPhysRead(pDevIns, PageAddr, pPageCache->abPhysReadCache, sizeof(pPageCache->abPhysReadCache));
1457 pPageCache->GCPhysReadCacheAddr = PageAddr;
1458# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
1459 ++g_PhysReadState.cPageReads;
1460# endif
1461 }
1462
1463 memcpy(pvBuf, &pPageCache->abPhysReadCache[GCPhys & GUEST_PAGE_OFFSET_MASK], cbBuf);
1464# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
1465 ++g_PhysReadState.cCacheReads;
1466# endif
1467 }
1468 else
1469 {
1470 PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbBuf);
1471# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
1472 ++g_PhysReadState.cCrossReads;
1473# endif
1474 }
1475}
1476
1477
1478/**
1479 * Updates the data in the given page cache if the given guest physical address is currently contained
1480 * in the cache.
1481 *
1482 * @param pPageCache The page cache to update.
1483 * @param GCPhys The guest physical address needing the update.
1484 * @param pvBuf Pointer to the buffer to update the page cache with.
1485 * @param cbBuf Number of bytes to update.
1486 */
1487static void ohciR3PhysCacheUpdate(POHCIPAGECACHE pPageCache, RTGCPHYS GCPhys, const void *pvBuf, size_t cbBuf)
1488{
1489 const RTGCPHYS GCPhysPage = GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
1490
1491 if (GCPhysPage == pPageCache->GCPhysReadCacheAddr)
1492 {
1493 uint32_t offPage = GCPhys & GUEST_PAGE_OFFSET_MASK;
1494 memcpy(&pPageCache->abPhysReadCache[offPage], pvBuf, RT_MIN(GUEST_PAGE_SIZE - offPage, cbBuf));
1495 }
1496}
1497
1498/**
1499 * Update any cached ED data with the given endpoint descriptor at the given address.
1500 *
1501 * @param pThisCC The OHCI instance data for the current context.
1502 * @param EdAddr Endpoint descriptor address.
1503 * @param pEd The endpoint descriptor which got updated.
1504 */
1505DECLINLINE(void) ohciR3CacheEdUpdate(POHCICC pThisCC, RTGCPHYS32 EdAddr, PCOHCIED pEd)
1506{
1507 ohciR3PhysCacheUpdate(&pThisCC->CacheED, EdAddr + RT_OFFSETOF(OHCIED, HeadP), &pEd->HeadP, sizeof(uint32_t));
1508}
1509
1510
1511/**
1512 * Update any cached TD data with the given transfer descriptor at the given address.
1513 *
1514 * @param pThisCC The OHCI instance data, current context.
1515 * @param TdAddr Transfer descriptor address.
1516 * @param pTd The transfer descriptor which got updated.
1517 */
1518DECLINLINE(void) ohciR3CacheTdUpdate(POHCICC pThisCC, RTGCPHYS32 TdAddr, PCOHCITD pTd)
1519{
1520 ohciR3PhysCacheUpdate(&pThisCC->CacheTD, TdAddr, pTd, sizeof(*pTd));
1521}
1522
1523# endif /* VBOX_WITH_OHCI_PHYS_READ_CACHE */
1524
1525/**
1526 * Reads an OHCIED.
1527 */
1528DECLINLINE(void) ohciR3ReadEd(PPDMDEVINS pDevIns, uint32_t EdAddr, POHCIED pEd)
1529{
1530# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
1531 physReadStatsUpdateDesc(&g_PhysReadState.ed, EdAddr);
1532 physReadStatsUpdateDesc(&g_PhysReadState.all, EdAddr);
1533# endif
1534#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
1535 POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
1536 ohciR3PhysReadCacheRead(pDevIns, &pThisCC->CacheED, EdAddr, pEd, sizeof(*pEd));
1537#else
1538 ohciR3GetDWords(pDevIns, EdAddr, (uint32_t *)pEd, sizeof(*pEd) >> 2);
1539#endif
1540}
1541
1542/**
1543 * Reads an OHCITD.
1544 */
1545DECLINLINE(void) ohciR3ReadTd(PPDMDEVINS pDevIns, uint32_t TdAddr, POHCITD pTd)
1546{
1547# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
1548 physReadStatsUpdateDesc(&g_PhysReadState.td, TdAddr);
1549 physReadStatsUpdateDesc(&g_PhysReadState.all, TdAddr);
1550# endif
1551#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
1552 POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
1553 ohciR3PhysReadCacheRead(pDevIns, &pThisCC->CacheTD, TdAddr, pTd, sizeof(*pTd));
1554#else
1555 ohciR3GetDWords(pDevIns, TdAddr, (uint32_t *)pTd, sizeof(*pTd) >> 2);
1556#endif
1557# ifdef LOG_ENABLED
1558 if (LogIs3Enabled())
1559 {
1560 uint32_t hichg;
1561 hichg = pTd->hwinfo;
1562 Log3(("ohciR3ReadTd(,%#010x,): R=%d DP=%d DI=%d T=%d EC=%d CC=%#x CBP=%#010x NextTD=%#010x BE=%#010x UNK=%#x\n",
1563 TdAddr,
1564 (pTd->hwinfo >> 18) & 1,
1565 (pTd->hwinfo >> 19) & 3,
1566 (pTd->hwinfo >> 21) & 7,
1567 (pTd->hwinfo >> 24) & 3,
1568 (pTd->hwinfo >> 26) & 3,
1569 (pTd->hwinfo >> 28) &15,
1570 pTd->cbp,
1571 pTd->NextTD,
1572 pTd->be,
1573 pTd->hwinfo & TD_HWINFO_UNKNOWN_MASK));
1574# if 0
1575 if (LogIs3Enabled())
1576 {
1577 /*
1578 * usbohci.sys (32-bit XP) allocates 0x80 bytes per TD:
1579 * 0x00-0x0f is the OHCI TD.
1580 * 0x10-0x1f for isochronous TDs
1581 * 0x20 is the physical address of this TD.
1582 * 0x24 is initialized with 0x64745948, probably a magic.
1583 * 0x28 is some kind of flags. the first bit begin the allocated / not allocated indicator.
1584 * 0x30 is a pointer to something. endpoint? interface? device?
1585 * 0x38 is initialized to 0xdeadface. but is changed into a pointer or something.
1586 * 0x40 looks like a pointer.
1587 * The rest is unknown and initialized with zeros.
1588 */
1589 uint8_t abXpTd[0x80];
1590 ohciR3PhysRead(pDevIns, TdAddr, abXpTd, sizeof(abXpTd));
1591 Log3(("WinXpTd: alloc=%d PhysSelf=%RX32 s2=%RX32 magic=%RX32 s4=%RX32 s5=%RX32\n"
1592 "%.*Rhxd\n",
1593 abXpTd[28] & RT_BIT(0),
1594 *((uint32_t *)&abXpTd[0x20]), *((uint32_t *)&abXpTd[0x30]),
1595 *((uint32_t *)&abXpTd[0x24]), *((uint32_t *)&abXpTd[0x38]),
1596 *((uint32_t *)&abXpTd[0x40]),
1597 sizeof(abXpTd), &abXpTd[0]));
1598 }
1599# endif
1600 }
1601# endif
1602}
1603
1604/**
1605 * Reads an OHCIITD.
1606 */
1607DECLINLINE(void) ohciR3ReadITd(PPDMDEVINS pDevIns, POHCI pThis, uint32_t ITdAddr, POHCIITD pITd)
1608{
1609 ohciR3GetDWords(pDevIns, ITdAddr, (uint32_t *)pITd, sizeof(*pITd) / sizeof(uint32_t));
1610# ifdef LOG_ENABLED
1611 if (LogIs3Enabled())
1612 {
1613 Log3(("ohciR3ReadITd(,%#010x,): SF=%#06x (%#RX32) DI=%#x FC=%d CC=%#x BP0=%#010x NextTD=%#010x BE=%#010x\n",
1614 ITdAddr,
1615 pITd->HwInfo & 0xffff, pThis->HcFmNumber,
1616 (pITd->HwInfo >> 21) & 7,
1617 (pITd->HwInfo >> 24) & 7,
1618 (pITd->HwInfo >> 28) &15,
1619 pITd->BP0,
1620 pITd->NextTD,
1621 pITd->BE));
1622 Log3(("psw0=%x:%03x psw1=%x:%03x psw2=%x:%03x psw3=%x:%03x psw4=%x:%03x psw5=%x:%03x psw6=%x:%03x psw7=%x:%03x\n",
1623 pITd->aPSW[0] >> 12, pITd->aPSW[0] & 0xfff,
1624 pITd->aPSW[1] >> 12, pITd->aPSW[1] & 0xfff,
1625 pITd->aPSW[2] >> 12, pITd->aPSW[2] & 0xfff,
1626 pITd->aPSW[3] >> 12, pITd->aPSW[3] & 0xfff,
1627 pITd->aPSW[4] >> 12, pITd->aPSW[4] & 0xfff,
1628 pITd->aPSW[5] >> 12, pITd->aPSW[5] & 0xfff,
1629 pITd->aPSW[6] >> 12, pITd->aPSW[6] & 0xfff,
1630 pITd->aPSW[7] >> 12, pITd->aPSW[7] & 0xfff));
1631 }
1632# else
1633 RT_NOREF(pThis);
1634# endif
1635}
1636
1637
1638/**
1639 * Writes an OHCIED.
1640 */
1641DECLINLINE(void) ohciR3WriteEd(PPDMDEVINS pDevIns, uint32_t EdAddr, PCOHCIED pEd)
1642{
1643# ifdef LOG_ENABLED
1644 if (LogIs3Enabled())
1645 {
1646 OHCIED EdOld;
1647 uint32_t hichg;
1648
1649 ohciR3GetDWords(pDevIns, EdAddr, (uint32_t *)&EdOld, sizeof(EdOld) >> 2);
1650 hichg = EdOld.hwinfo ^ pEd->hwinfo;
1651 Log3(("ohciR3WriteEd(,%#010x,): %sFA=%#x %sEN=%#x %sD=%#x %sS=%d %sK=%d %sF=%d %sMPS=%#x %sTailP=%#010x %sHeadP=%#010x %sH=%d %sC=%d %sNextED=%#010x\n",
1652 EdAddr,
1653 (hichg >> 0) & 0x7f ? "*" : "", (pEd->hwinfo >> 0) & 0x7f,
1654 (hichg >> 7) & 0xf ? "*" : "", (pEd->hwinfo >> 7) & 0xf,
1655 (hichg >> 11) & 3 ? "*" : "", (pEd->hwinfo >> 11) & 3,
1656 (hichg >> 13) & 1 ? "*" : "", (pEd->hwinfo >> 13) & 1,
1657 (hichg >> 14) & 1 ? "*" : "", (pEd->hwinfo >> 14) & 1,
1658 (hichg >> 15) & 1 ? "*" : "", (pEd->hwinfo >> 15) & 1,
1659 (hichg >> 24) &0x3ff ? "*" : "", (pEd->hwinfo >> 16) &0x3ff,
1660 EdOld.TailP != pEd->TailP ? "*" : "", pEd->TailP,
1661 (EdOld.HeadP & ~3) != (pEd->HeadP & ~3) ? "*" : "", pEd->HeadP & ~3,
1662 (EdOld.HeadP ^ pEd->HeadP) & 1 ? "*" : "", pEd->HeadP & 1,
1663 (EdOld.HeadP ^ pEd->HeadP) & 2 ? "*" : "", (pEd->HeadP >> 1) & 1,
1664 EdOld.NextED != pEd->NextED ? "*" : "", pEd->NextED));
1665 }
1666# endif
1667
1668 ohciR3PutDWords(pDevIns, EdAddr + RT_OFFSETOF(OHCIED, HeadP), &pEd->HeadP, 1);
1669#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
1670 POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
1671 ohciR3CacheEdUpdate(pThisCC, EdAddr, pEd);
1672#endif
1673}
1674
1675
1676/**
1677 * Writes an OHCITD.
1678 */
1679DECLINLINE(void) ohciR3WriteTd(PPDMDEVINS pDevIns, uint32_t TdAddr, PCOHCITD pTd, const char *pszLogMsg)
1680{
1681# ifdef LOG_ENABLED
1682 if (LogIs3Enabled())
1683 {
1684 OHCITD TdOld;
1685 ohciR3GetDWords(pDevIns, TdAddr, (uint32_t *)&TdOld, sizeof(TdOld) >> 2);
1686 uint32_t hichg = TdOld.hwinfo ^ pTd->hwinfo;
1687 Log3(("ohciR3WriteTd(,%#010x,): %sR=%d %sDP=%d %sDI=%#x %sT=%d %sEC=%d %sCC=%#x %sCBP=%#010x %sNextTD=%#010x %sBE=%#010x (%s)\n",
1688 TdAddr,
1689 (hichg >> 18) & 1 ? "*" : "", (pTd->hwinfo >> 18) & 1,
1690 (hichg >> 19) & 3 ? "*" : "", (pTd->hwinfo >> 19) & 3,
1691 (hichg >> 21) & 7 ? "*" : "", (pTd->hwinfo >> 21) & 7,
1692 (hichg >> 24) & 3 ? "*" : "", (pTd->hwinfo >> 24) & 3,
1693 (hichg >> 26) & 3 ? "*" : "", (pTd->hwinfo >> 26) & 3,
1694 (hichg >> 28) &15 ? "*" : "", (pTd->hwinfo >> 28) &15,
1695 TdOld.cbp != pTd->cbp ? "*" : "", pTd->cbp,
1696 TdOld.NextTD != pTd->NextTD ? "*" : "", pTd->NextTD,
1697 TdOld.be != pTd->be ? "*" : "", pTd->be,
1698 pszLogMsg));
1699 }
1700# else
1701 RT_NOREF(pszLogMsg);
1702# endif
1703 ohciR3PutDWords(pDevIns, TdAddr, (uint32_t *)pTd, sizeof(*pTd) >> 2);
1704#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
1705 POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
1706 ohciR3CacheTdUpdate(pThisCC, TdAddr, pTd);
1707#endif
1708}
1709
1710/**
1711 * Writes an OHCIITD.
1712 */
1713DECLINLINE(void) ohciR3WriteITd(PPDMDEVINS pDevIns, POHCI pThis, uint32_t ITdAddr, PCOHCIITD pITd, const char *pszLogMsg)
1714{
1715# ifdef LOG_ENABLED
1716 if (LogIs3Enabled())
1717 {
1718 OHCIITD ITdOld;
1719 ohciR3GetDWords(pDevIns, ITdAddr, (uint32_t *)&ITdOld, sizeof(ITdOld) / sizeof(uint32_t));
1720 uint32_t HIChg = ITdOld.HwInfo ^ pITd->HwInfo;
1721 Log3(("ohciR3WriteITd(,%#010x,): %sSF=%#x (now=%#RX32) %sDI=%#x %sFC=%d %sCC=%#x %sBP0=%#010x %sNextTD=%#010x %sBE=%#010x (%s)\n",
1722 ITdAddr,
1723 (HIChg & 0xffff) & 1 ? "*" : "", pITd->HwInfo & 0xffff, pThis->HcFmNumber,
1724 (HIChg >> 21) & 7 ? "*" : "", (pITd->HwInfo >> 21) & 7,
1725 (HIChg >> 24) & 7 ? "*" : "", (pITd->HwInfo >> 24) & 7,
1726 (HIChg >> 28) &15 ? "*" : "", (pITd->HwInfo >> 28) &15,
1727 ITdOld.BP0 != pITd->BP0 ? "*" : "", pITd->BP0,
1728 ITdOld.NextTD != pITd->NextTD ? "*" : "", pITd->NextTD,
1729 ITdOld.BE != pITd->BE ? "*" : "", pITd->BE,
1730 pszLogMsg));
1731 Log3(("psw0=%s%x:%s%03x psw1=%s%x:%s%03x psw2=%s%x:%s%03x psw3=%s%x:%s%03x psw4=%s%x:%s%03x psw5=%s%x:%s%03x psw6=%s%x:%s%03x psw7=%s%x:%s%03x\n",
1732 (ITdOld.aPSW[0] >> 12) != (pITd->aPSW[0] >> 12) ? "*" : "", pITd->aPSW[0] >> 12, (ITdOld.aPSW[0] & 0xfff) != (pITd->aPSW[0] & 0xfff) ? "*" : "", pITd->aPSW[0] & 0xfff,
1733 (ITdOld.aPSW[1] >> 12) != (pITd->aPSW[1] >> 12) ? "*" : "", pITd->aPSW[1] >> 12, (ITdOld.aPSW[1] & 0xfff) != (pITd->aPSW[1] & 0xfff) ? "*" : "", pITd->aPSW[1] & 0xfff,
1734 (ITdOld.aPSW[2] >> 12) != (pITd->aPSW[2] >> 12) ? "*" : "", pITd->aPSW[2] >> 12, (ITdOld.aPSW[2] & 0xfff) != (pITd->aPSW[2] & 0xfff) ? "*" : "", pITd->aPSW[2] & 0xfff,
1735 (ITdOld.aPSW[3] >> 12) != (pITd->aPSW[3] >> 12) ? "*" : "", pITd->aPSW[3] >> 12, (ITdOld.aPSW[3] & 0xfff) != (pITd->aPSW[3] & 0xfff) ? "*" : "", pITd->aPSW[3] & 0xfff,
1736 (ITdOld.aPSW[4] >> 12) != (pITd->aPSW[4] >> 12) ? "*" : "", pITd->aPSW[4] >> 12, (ITdOld.aPSW[4] & 0xfff) != (pITd->aPSW[4] & 0xfff) ? "*" : "", pITd->aPSW[4] & 0xfff,
1737 (ITdOld.aPSW[5] >> 12) != (pITd->aPSW[5] >> 12) ? "*" : "", pITd->aPSW[5] >> 12, (ITdOld.aPSW[5] & 0xfff) != (pITd->aPSW[5] & 0xfff) ? "*" : "", pITd->aPSW[5] & 0xfff,
1738 (ITdOld.aPSW[6] >> 12) != (pITd->aPSW[6] >> 12) ? "*" : "", pITd->aPSW[6] >> 12, (ITdOld.aPSW[6] & 0xfff) != (pITd->aPSW[6] & 0xfff) ? "*" : "", pITd->aPSW[6] & 0xfff,
1739 (ITdOld.aPSW[7] >> 12) != (pITd->aPSW[7] >> 12) ? "*" : "", pITd->aPSW[7] >> 12, (ITdOld.aPSW[7] & 0xfff) != (pITd->aPSW[7] & 0xfff) ? "*" : "", pITd->aPSW[7] & 0xfff));
1740 }
1741# else
1742 RT_NOREF(pThis, pszLogMsg);
1743# endif
1744 ohciR3PutDWords(pDevIns, ITdAddr, (uint32_t *)pITd, sizeof(*pITd) / sizeof(uint32_t));
1745}
1746
1747
1748# ifdef LOG_ENABLED
1749
1750/**
1751 * Core TD queue dumper. LOG_ENABLED builds only.
1752 */
1753DECLINLINE(void) ohciR3DumpTdQueueCore(PPDMDEVINS pDevIns, POHCICC pThisCC, uint32_t GCPhysHead, uint32_t GCPhysTail, bool fFull)
1754{
1755 uint32_t GCPhys = GCPhysHead;
1756 int cIterations = 128;
1757 for (;;)
1758 {
1759 OHCITD Td;
1760 Log4(("%#010x%s%s", GCPhys,
1761 GCPhys && ohciR3InFlightFind(pThisCC, GCPhys) >= 0 ? "~" : "",
1762 GCPhys && ohciR3InDoneQueueFind(pThisCC, GCPhys) >= 0 ? "^" : ""));
1763 if (GCPhys == 0 || GCPhys == GCPhysTail)
1764 break;
1765
1766 /* can't use ohciR3ReadTd() because of Log4. */
1767 ohciR3GetDWords(pDevIns, GCPhys, (uint32_t *)&Td, sizeof(Td) >> 2);
1768 if (fFull)
1769 Log4((" [R=%d DP=%d DI=%d T=%d EC=%d CC=%#x CBP=%#010x NextTD=%#010x BE=%#010x] -> ",
1770 (Td.hwinfo >> 18) & 1,
1771 (Td.hwinfo >> 19) & 3,
1772 (Td.hwinfo >> 21) & 7,
1773 (Td.hwinfo >> 24) & 3,
1774 (Td.hwinfo >> 26) & 3,
1775 (Td.hwinfo >> 28) &15,
1776 Td.cbp,
1777 Td.NextTD,
1778 Td.be));
1779 else
1780 Log4((" -> "));
1781 GCPhys = Td.NextTD & ED_PTR_MASK;
1782 Assert(GCPhys != GCPhysHead);
1783 if (!--cIterations)
1784 break;
1785 }
1786}
1787
1788/**
1789 * Dumps a TD queue. LOG_ENABLED builds only.
1790 */
1791DECLINLINE(void) ohciR3DumpTdQueue(PPDMDEVINS pDevIns, POHCICC pThisCC, uint32_t GCPhysHead, const char *pszMsg)
1792{
1793 if (pszMsg)
1794 Log4(("%s: ", pszMsg));
1795 ohciR3DumpTdQueueCore(pDevIns, pThisCC, GCPhysHead, 0, true);
1796 Log4(("\n"));
1797}
1798
1799/**
1800 * Core ITD queue dumper. LOG_ENABLED builds only.
1801 */
1802DECLINLINE(void) ohciR3DumpITdQueueCore(PPDMDEVINS pDevIns, POHCICC pThisCC, uint32_t GCPhysHead, uint32_t GCPhysTail, bool fFull)
1803{
1804 RT_NOREF(fFull);
1805 uint32_t GCPhys = GCPhysHead;
1806 int cIterations = 100;
1807 for (;;)
1808 {
1809 OHCIITD ITd;
1810 Log4(("%#010x%s%s", GCPhys,
1811 GCPhys && ohciR3InFlightFind(pThisCC, GCPhys) >= 0 ? "~" : "",
1812 GCPhys && ohciR3InDoneQueueFind(pThisCC, GCPhys) >= 0 ? "^" : ""));
1813 if (GCPhys == 0 || GCPhys == GCPhysTail)
1814 break;
1815
1816 /* can't use ohciR3ReadTd() because of Log4. */
1817 ohciR3GetDWords(pDevIns, GCPhys, (uint32_t *)&ITd, sizeof(ITd) / sizeof(uint32_t));
1818 /*if (fFull)
1819 Log4((" [R=%d DP=%d DI=%d T=%d EC=%d CC=%#x CBP=%#010x NextTD=%#010x BE=%#010x] -> ",
1820 (Td.hwinfo >> 18) & 1,
1821 (Td.hwinfo >> 19) & 3,
1822 (Td.hwinfo >> 21) & 7,
1823 (Td.hwinfo >> 24) & 3,
1824 (Td.hwinfo >> 26) & 3,
1825 (Td.hwinfo >> 28) &15,
1826 Td.cbp,
1827 Td.NextTD,
1828 Td.be));
1829 else*/
1830 Log4((" -> "));
1831 GCPhys = ITd.NextTD & ED_PTR_MASK;
1832 Assert(GCPhys != GCPhysHead);
1833 if (!--cIterations)
1834 break;
1835 }
1836}
1837
1838/**
1839 * Dumps a ED list. LOG_ENABLED builds only.
1840 */
1841DECLINLINE(void) ohciR3DumpEdList(PPDMDEVINS pDevIns, POHCICC pThisCC, uint32_t GCPhysHead, const char *pszMsg, bool fTDs)
1842{
1843 RT_NOREF(fTDs);
1844 uint32_t GCPhys = GCPhysHead;
1845 if (pszMsg)
1846 Log4(("%s:", pszMsg));
1847 for (;;)
1848 {
1849 OHCIED Ed;
1850
1851 /* ED */
1852 Log4((" %#010x={", GCPhys));
1853 if (!GCPhys)
1854 {
1855 Log4(("END}\n"));
1856 return;
1857 }
1858
1859 /* TDs */
1860 ohciR3ReadEd(pDevIns, GCPhys, &Ed);
1861 if (Ed.hwinfo & ED_HWINFO_ISO)
1862 Log4(("[I]"));
1863 if ((Ed.HeadP & ED_HEAD_HALTED) || (Ed.hwinfo & ED_HWINFO_SKIP))
1864 {
1865 if ((Ed.HeadP & ED_HEAD_HALTED) && (Ed.hwinfo & ED_HWINFO_SKIP))
1866 Log4(("SH}"));
1867 else if (Ed.hwinfo & ED_HWINFO_SKIP)
1868 Log4(("S-}"));
1869 else
1870 Log4(("-H}"));
1871 }
1872 else
1873 {
1874 if (Ed.hwinfo & ED_HWINFO_ISO)
1875 ohciR3DumpITdQueueCore(pDevIns, pThisCC, Ed.HeadP & ED_PTR_MASK, Ed.TailP & ED_PTR_MASK, false);
1876 else
1877 ohciR3DumpTdQueueCore(pDevIns, pThisCC, Ed.HeadP & ED_PTR_MASK, Ed.TailP & ED_PTR_MASK, false);
1878 Log4(("}"));
1879 }
1880
1881 /* next */
1882 GCPhys = Ed.NextED & ED_PTR_MASK;
1883 Assert(GCPhys != GCPhysHead);
1884 }
1885 /* not reached */
1886}
1887
1888# endif /* LOG_ENABLED */
1889
1890
1891DECLINLINE(int) ohciR3InFlightFindFree(POHCICC pThisCC, const int iStart)
1892{
1893 unsigned i = iStart;
1894 while (i < RT_ELEMENTS(pThisCC->aInFlight))
1895 {
1896 if (pThisCC->aInFlight[i].pUrb == NULL)
1897 return i;
1898 i++;
1899 }
1900 i = iStart;
1901 while (i-- > 0)
1902 {
1903 if (pThisCC->aInFlight[i].pUrb == NULL)
1904 return i;
1905 }
1906 return -1;
1907}
1908
1909
1910/**
1911 * Record an in-flight TD.
1912 *
1913 * @param pThis OHCI instance data, shared edition.
1914 * @param pThisCC OHCI instance data, ring-3 edition.
1915 * @param GCPhysTD Physical address of the TD.
1916 * @param pUrb The URB.
1917 */
1918static void ohciR3InFlightAdd(POHCI pThis, POHCICC pThisCC, uint32_t GCPhysTD, PVUSBURB pUrb)
1919{
1920 int i = ohciR3InFlightFindFree(pThisCC, (GCPhysTD >> 4) % RT_ELEMENTS(pThisCC->aInFlight));
1921 if (i >= 0)
1922 {
1923# ifdef LOG_ENABLED
1924 pUrb->pHci->u32FrameNo = pThis->HcFmNumber;
1925# endif
1926 pThisCC->aInFlight[i].GCPhysTD = GCPhysTD;
1927 pThisCC->aInFlight[i].pUrb = pUrb;
1928 pThisCC->cInFlight++;
1929 return;
1930 }
1931 AssertMsgFailed(("Out of space cInFlight=%d!\n", pThisCC->cInFlight));
1932 RT_NOREF(pThis);
1933}
1934
1935
1936/**
1937 * Record in-flight TDs for an URB.
1938 *
1939 * @param pThis OHCI instance data, shared edition.
1940 * @param pThisCC OHCI instance data, ring-3 edition.
1941 * @param pUrb The URB.
1942 */
1943static void ohciR3InFlightAddUrb(POHCI pThis, POHCICC pThisCC, PVUSBURB pUrb)
1944{
1945 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
1946 ohciR3InFlightAdd(pThis, pThisCC, pUrb->paTds[iTd].TdAddr, pUrb);
1947}
1948
1949
1950/**
1951 * Finds a in-flight TD.
1952 *
1953 * @returns Index of the record.
1954 * @returns -1 if not found.
1955 * @param pThisCC OHCI instance data, ring-3 edition.
1956 * @param GCPhysTD Physical address of the TD.
1957 * @remark This has to be fast.
1958 */
1959static int ohciR3InFlightFind(POHCICC pThisCC, uint32_t GCPhysTD)
1960{
1961 unsigned cLeft = pThisCC->cInFlight;
1962 unsigned i = (GCPhysTD >> 4) % RT_ELEMENTS(pThisCC->aInFlight);
1963 const int iLast = i;
1964 while (i < RT_ELEMENTS(pThisCC->aInFlight))
1965 {
1966 if (pThisCC->aInFlight[i].GCPhysTD == GCPhysTD && pThisCC->aInFlight[i].pUrb)
1967 return i;
1968 if (pThisCC->aInFlight[i].pUrb)
1969 if (cLeft-- <= 1)
1970 return -1;
1971 i++;
1972 }
1973 i = iLast;
1974 while (i-- > 0)
1975 {
1976 if (pThisCC->aInFlight[i].GCPhysTD == GCPhysTD && pThisCC->aInFlight[i].pUrb)
1977 return i;
1978 if (pThisCC->aInFlight[i].pUrb)
1979 if (cLeft-- <= 1)
1980 return -1;
1981 }
1982 return -1;
1983}
1984
1985
1986/**
1987 * Checks if a TD is in-flight.
1988 *
1989 * @returns true if in flight, false if not.
1990 * @param pThisCC OHCI instance data, ring-3 edition.
1991 * @param GCPhysTD Physical address of the TD.
1992 */
1993static bool ohciR3IsTdInFlight(POHCICC pThisCC, uint32_t GCPhysTD)
1994{
1995 return ohciR3InFlightFind(pThisCC, GCPhysTD) >= 0;
1996}
1997
1998/**
1999 * Returns a URB associated with an in-flight TD, if any.
2000 *
2001 * @returns pointer to URB if TD is in flight.
2002 * @returns NULL if not in flight.
2003 * @param pThisCC OHCI instance data, ring-3 edition.
2004 * @param GCPhysTD Physical address of the TD.
2005 */
2006static PVUSBURB ohciR3TdInFlightUrb(POHCICC pThisCC, uint32_t GCPhysTD)
2007{
2008 int i;
2009
2010 i = ohciR3InFlightFind(pThisCC, GCPhysTD);
2011 if ( i >= 0 )
2012 return pThisCC->aInFlight[i].pUrb;
2013 return NULL;
2014}
2015
2016/**
2017 * Removes a in-flight TD.
2018 *
2019 * @returns 0 if found. For logged builds this is the number of frames the TD has been in-flight.
2020 * @returns -1 if not found.
2021 * @param pThis OHCI instance data, shared edition (for logging).
2022 * @param pThisCC OHCI instance data, ring-3 edition.
2023 * @param GCPhysTD Physical address of the TD.
2024 */
2025static int ohciR3InFlightRemove(POHCI pThis, POHCICC pThisCC, uint32_t GCPhysTD)
2026{
2027 int i = ohciR3InFlightFind(pThisCC, GCPhysTD);
2028 if (i >= 0)
2029 {
2030# ifdef LOG_ENABLED
2031 const int cFramesInFlight = pThis->HcFmNumber - pThisCC->aInFlight[i].pUrb->pHci->u32FrameNo;
2032# else
2033 const int cFramesInFlight = 0; RT_NOREF(pThis);
2034# endif
2035 Log2(("ohciR3InFlightRemove: reaping TD=%#010x %d frames (%#010x-%#010x)\n",
2036 GCPhysTD, cFramesInFlight, pThisCC->aInFlight[i].pUrb->pHci->u32FrameNo, pThis->HcFmNumber));
2037 pThisCC->aInFlight[i].GCPhysTD = 0;
2038 pThisCC->aInFlight[i].pUrb = NULL;
2039 pThisCC->cInFlight--;
2040 return cFramesInFlight;
2041 }
2042 AssertMsgFailed(("TD %#010x is not in flight\n", GCPhysTD));
2043 return -1;
2044}
2045
2046
2047/**
2048 * Clear any possible leftover traces of a URB from the in-flight tracking.
2049 * Useful if broken guests confuse the tracking logic by using the same TD
2050 * for multiple URBs. See @bugref{10410}.
2051 *
2052 * @param pThisCC OHCI instance data, ring-3 edition.
2053 * @param pUrb The URB.
2054 */
2055static void ohciR3InFlightClearUrb(POHCICC pThisCC, PVUSBURB pUrb)
2056{
2057 unsigned i = 0;
2058 while (i < RT_ELEMENTS(pThisCC->aInFlight))
2059 {
2060 if (pThisCC->aInFlight[i].pUrb == pUrb)
2061 {
2062 Log2(("ohciR3InFlightClearUrb: clearing leftover URB!!\n"));
2063 pThisCC->aInFlight[i].GCPhysTD = 0;
2064 pThisCC->aInFlight[i].pUrb = NULL;
2065 pThisCC->cInFlight--;
2066 }
2067 i++;
2068 }
2069}
2070
2071
2072/**
2073 * Removes all TDs associated with a URB from the in-flight tracking.
2074 *
2075 * @returns 0 if found. For logged builds this is the number of frames the TD has been in-flight.
2076 * @returns -1 if not found.
2077 * @param pThis OHCI instance data, shared edition (for logging).
2078 * @param pThisCC OHCI instance data, ring-3 edition.
2079 * @param pUrb The URB.
2080 */
2081static int ohciR3InFlightRemoveUrb(POHCI pThis, POHCICC pThisCC, PVUSBURB pUrb)
2082{
2083 int cFramesInFlight = ohciR3InFlightRemove(pThis, pThisCC, pUrb->paTds[0].TdAddr);
2084 if (pUrb->pHci->cTds > 1)
2085 {
2086 for (unsigned iTd = 1; iTd < pUrb->pHci->cTds; iTd++)
2087 if (ohciR3InFlightRemove(pThis, pThisCC, pUrb->paTds[iTd].TdAddr) < 0)
2088 cFramesInFlight = -1;
2089 }
2090 ohciR3InFlightClearUrb(pThisCC, pUrb);
2091 return cFramesInFlight;
2092}
2093
2094
2095# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
2096
2097/**
2098 * Empties the in-done-queue.
2099 * @param pThisCC OHCI instance data, ring-3 edition.
2100 */
2101static void ohciR3InDoneQueueZap(POHCICC pThisCC)
2102{
2103 pThisCC->cInDoneQueue = 0;
2104}
2105
2106/**
2107 * Finds a TD in the in-done-queue.
2108 * @returns >= 0 on success.
2109 * @returns -1 if not found.
2110 * @param pThisCC OHCI instance data, ring-3 edition.
2111 * @param GCPhysTD Physical address of the TD.
2112 */
2113static int ohciR3InDoneQueueFind(POHCICC pThisCC, uint32_t GCPhysTD)
2114{
2115 unsigned i = pThisCC->cInDoneQueue;
2116 while (i-- > 0)
2117 if (pThisCC->aInDoneQueue[i].GCPhysTD == GCPhysTD)
2118 return i;
2119 return -1;
2120}
2121
2122/**
2123 * Checks that the specified TD is not in the done queue.
2124 * @param pThisCC OHCI instance data, ring-3 edition.
2125 * @param GCPhysTD Physical address of the TD.
2126 */
2127static bool ohciR3InDoneQueueCheck(POHCICC pThisCC, uint32_t GCPhysTD)
2128{
2129 int i = ohciR3InDoneQueueFind(pThisCC, GCPhysTD);
2130# if 0
2131 /* This condition has been observed with the USB tablet emulation or with
2132 * a real USB mouse and an SMP XP guest. I am also not sure if this is
2133 * really a problem for us. The assertion checks that the guest doesn't
2134 * re-submit a TD which is still in the done queue. It seems to me that
2135 * this should only be a problem if we either keep track of TDs in the done
2136 * queue somewhere else as well (in which case we should also free those
2137 * references in time, and I can't see any code doing that) or if we
2138 * manipulate TDs in the done queue in some way that might fail if they are
2139 * re-submitted (can't see anything like that either).
2140 */
2141 AssertMsg(i < 0, ("TD %#010x (i=%d)\n", GCPhysTD, i));
2142# endif
2143 return i < 0;
2144}
2145
2146
2147# if defined(VBOX_STRICT) && defined(LOG_ENABLED)
2148/**
2149 * Adds a TD to the in-done-queue tracking, checking that it's not there already.
2150 * @param pThisCC OHCI instance data, ring-3 edition.
2151 * @param GCPhysTD Physical address of the TD.
2152 */
2153static void ohciR3InDoneQueueAdd(POHCICC pThisCC, uint32_t GCPhysTD)
2154{
2155 Assert(pThisCC->cInDoneQueue + 1 <= RT_ELEMENTS(pThisCC->aInDoneQueue));
2156 if (ohciR3InDoneQueueCheck(pThisCC, GCPhysTD))
2157 pThisCC->aInDoneQueue[pThisCC->cInDoneQueue++].GCPhysTD = GCPhysTD;
2158}
2159# endif /* VBOX_STRICT */
2160# endif /* defined(VBOX_STRICT) || defined(LOG_ENABLED) */
2161
2162
2163/**
2164 * OHCI Transport Buffer - represents a OHCI Transport Descriptor (TD).
2165 * A TD may be split over max 2 pages.
2166 */
2167typedef struct OHCIBUF
2168{
2169 /** Pages involved. */
2170 struct OHCIBUFVEC
2171 {
2172 /** The 32-bit physical address of this part. */
2173 uint32_t Addr;
2174 /** The length. */
2175 uint32_t cb;
2176 } aVecs[2];
2177 /** Number of valid entries in aVecs. */
2178 uint32_t cVecs;
2179 /** The total length. */
2180 uint32_t cbTotal;
2181} OHCIBUF, *POHCIBUF;
2182
2183
2184/**
2185 * Sets up a OHCI transport buffer.
2186 *
2187 * @param pBuf OHCI buffer.
2188 * @param cbp Current buffer pointer. 32-bit physical address.
2189 * @param be Last byte in buffer (BufferEnd). 32-bit physical address.
2190 */
2191static void ohciR3BufInit(POHCIBUF pBuf, uint32_t cbp, uint32_t be)
2192{
2193 if (!cbp || !be)
2194 {
2195 pBuf->cVecs = 0;
2196 pBuf->cbTotal = 0;
2197 Log2(("ohci: cbp=%#010x be=%#010x cbTotal=0 EMPTY\n", cbp, be));
2198 }
2199 else if ((cbp & ~0xfff) == (be & ~0xfff) && (cbp <= be))
2200 {
2201 pBuf->aVecs[0].Addr = cbp;
2202 pBuf->aVecs[0].cb = (be - cbp) + 1;
2203 pBuf->cVecs = 1;
2204 pBuf->cbTotal = pBuf->aVecs[0].cb;
2205 Log2(("ohci: cbp=%#010x be=%#010x cbTotal=%u\n", cbp, be, pBuf->cbTotal));
2206 }
2207 else
2208 {
2209 pBuf->aVecs[0].Addr = cbp;
2210 pBuf->aVecs[0].cb = 0x1000 - (cbp & 0xfff);
2211 pBuf->aVecs[1].Addr = be & ~0xfff;
2212 pBuf->aVecs[1].cb = (be & 0xfff) + 1;
2213 pBuf->cVecs = 2;
2214 pBuf->cbTotal = pBuf->aVecs[0].cb + pBuf->aVecs[1].cb;
2215 Log2(("ohci: cbp=%#010x be=%#010x cbTotal=%u PAGE FLIP\n", cbp, be, pBuf->cbTotal));
2216 }
2217}
2218
2219/**
2220 * Updates a OHCI transport buffer.
2221 *
2222 * This is called upon completion to adjust the sector lengths if
2223 * the total length has changed. (received less then we had space for
2224 * or a partial transfer.)
2225 *
2226 * @param pBuf The buffer to update. cbTotal contains the new total on input.
2227 * While the aVecs[*].cb members is updated upon return.
2228 */
2229static void ohciR3BufUpdate(POHCIBUF pBuf)
2230{
2231 for (uint32_t i = 0, cbCur = 0; i < pBuf->cVecs; i++)
2232 {
2233 if (cbCur + pBuf->aVecs[i].cb > pBuf->cbTotal)
2234 {
2235 pBuf->aVecs[i].cb = pBuf->cbTotal - cbCur;
2236 pBuf->cVecs = i + 1;
2237 return;
2238 }
2239 cbCur += pBuf->aVecs[i].cb;
2240 }
2241}
2242
2243
2244/** A worker for ohciR3UnlinkTds(). */
2245static bool ohciR3UnlinkIsochronousTdInList(PPDMDEVINS pDevIns, POHCI pThis, uint32_t TdAddr, POHCIITD pITd, POHCIED pEd)
2246{
2247 const uint32_t LastTdAddr = pEd->TailP & ED_PTR_MASK;
2248 Log(("ohciUnlinkIsocTdInList: Unlinking non-head ITD! TdAddr=%#010RX32 HeadTdAddr=%#010RX32 LastEdAddr=%#010RX32\n",
2249 TdAddr, pEd->HeadP & ED_PTR_MASK, LastTdAddr));
2250 AssertMsgReturn(LastTdAddr != TdAddr, ("TdAddr=%#010RX32\n", TdAddr), false);
2251
2252 uint32_t cIterations = 256;
2253 uint32_t CurTdAddr = pEd->HeadP & ED_PTR_MASK;
2254 while ( CurTdAddr != LastTdAddr
2255 && cIterations-- > 0)
2256 {
2257 OHCIITD ITd;
2258 ohciR3ReadITd(pDevIns, pThis, CurTdAddr, &ITd);
2259 if ((ITd.NextTD & ED_PTR_MASK) == TdAddr)
2260 {
2261 ITd.NextTD = (pITd->NextTD & ED_PTR_MASK) | (ITd.NextTD & ~ED_PTR_MASK);
2262 ohciR3WriteITd(pDevIns, pThis, CurTdAddr, &ITd, "ohciUnlinkIsocTdInList");
2263 pITd->NextTD &= ~ED_PTR_MASK;
2264 return true;
2265 }
2266
2267 /* next */
2268 CurTdAddr = ITd.NextTD & ED_PTR_MASK;
2269 }
2270
2271 Log(("ohciUnlinkIsocTdInList: TdAddr=%#010RX32 wasn't found in the list!!! (cIterations=%d)\n", TdAddr, cIterations));
2272 return false;
2273}
2274
2275
2276/** A worker for ohciR3UnlinkTds(). */
2277static bool ohciR3UnlinkGeneralTdInList(PPDMDEVINS pDevIns, uint32_t TdAddr, POHCITD pTd, POHCIED pEd)
2278{
2279 const uint32_t LastTdAddr = pEd->TailP & ED_PTR_MASK;
2280 Log(("ohciR3UnlinkGeneralTdInList: Unlinking non-head TD! TdAddr=%#010RX32 HeadTdAddr=%#010RX32 LastEdAddr=%#010RX32\n",
2281 TdAddr, pEd->HeadP & ED_PTR_MASK, LastTdAddr));
2282 AssertMsgReturn(LastTdAddr != TdAddr, ("TdAddr=%#010RX32\n", TdAddr), false);
2283
2284 uint32_t cIterations = 256;
2285 uint32_t CurTdAddr = pEd->HeadP & ED_PTR_MASK;
2286 while ( CurTdAddr != LastTdAddr
2287 && cIterations-- > 0)
2288 {
2289 OHCITD Td;
2290 ohciR3ReadTd(pDevIns, CurTdAddr, &Td);
2291 if ((Td.NextTD & ED_PTR_MASK) == TdAddr)
2292 {
2293 Td.NextTD = (pTd->NextTD & ED_PTR_MASK) | (Td.NextTD & ~ED_PTR_MASK);
2294 ohciR3WriteTd(pDevIns, CurTdAddr, &Td, "ohciR3UnlinkGeneralTdInList");
2295 pTd->NextTD &= ~ED_PTR_MASK;
2296 return true;
2297 }
2298
2299 /* next */
2300 CurTdAddr = Td.NextTD & ED_PTR_MASK;
2301 }
2302
2303 Log(("ohciR3UnlinkGeneralTdInList: TdAddr=%#010RX32 wasn't found in the list!!! (cIterations=%d)\n", TdAddr, cIterations));
2304 return false;
2305}
2306
2307
2308/**
2309 * Unlinks the TDs that makes up the URB from the ED.
2310 *
2311 * @returns success indicator. true if successfully unlinked.
2312 * @returns false if the TD was not found in the list.
2313 */
2314static bool ohciR3UnlinkTds(PPDMDEVINS pDevIns, POHCI pThis, PVUSBURB pUrb, POHCIED pEd)
2315{
2316 /*
2317 * Don't unlink more than once.
2318 */
2319 if (pUrb->pHci->fUnlinked)
2320 return true;
2321 pUrb->pHci->fUnlinked = true;
2322
2323 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
2324 {
2325 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
2326 {
2327 POHCIITD pITd = (POHCIITD)&pUrb->paTds[iTd].TdCopy[0];
2328 const uint32_t ITdAddr = pUrb->paTds[iTd].TdAddr;
2329
2330 /*
2331 * Unlink the TD from the ED list.
2332 * The normal case is that it's at the head of the list.
2333 */
2334 Assert((ITdAddr & ED_PTR_MASK) == ITdAddr);
2335 if ((pEd->HeadP & ED_PTR_MASK) == ITdAddr)
2336 {
2337 pEd->HeadP = (pITd->NextTD & ED_PTR_MASK) | (pEd->HeadP & ~ED_PTR_MASK);
2338 pITd->NextTD &= ~ED_PTR_MASK;
2339 }
2340 else
2341 {
2342 /*
2343 * It's probably somewhere in the list, not a unlikely situation with
2344 * the current isochronous code.
2345 */
2346 if (!ohciR3UnlinkIsochronousTdInList(pDevIns, pThis, ITdAddr, pITd, pEd))
2347 return false;
2348 }
2349 }
2350 }
2351 else
2352 {
2353 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
2354 {
2355 POHCITD pTd = (POHCITD)&pUrb->paTds[iTd].TdCopy[0];
2356 const uint32_t TdAddr = pUrb->paTds[iTd].TdAddr;
2357
2358 /** @todo r=bird: Messing with the toggle flag in prepare is probably not correct
2359 * when we encounter a STALL error, 4.3.1.3.7.2: ''If an endpoint returns a STALL
2360 * PID, the Host Controller retires the General TD with the ConditionCode set
2361 * to STALL and halts the endpoint. The CurrentBufferPointer, ErrorCount, and
2362 * dataToggle fields retain the values that they had at the start of the
2363 * transaction.'' */
2364
2365 /* update toggle and set data toggle carry */
2366 pTd->hwinfo &= ~TD_HWINFO_TOGGLE;
2367 if ( pTd->hwinfo & TD_HWINFO_TOGGLE_HI )
2368 {
2369 if ( !!(pTd->hwinfo & TD_HWINFO_TOGGLE_LO) ) /** @todo r=bird: is it just me or doesn't this make sense at all? */
2370 pTd->hwinfo |= TD_HWINFO_TOGGLE_LO;
2371 else
2372 pTd->hwinfo &= ~TD_HWINFO_TOGGLE_LO;
2373 }
2374 else
2375 {
2376 if ( !!(pEd->HeadP & ED_HEAD_CARRY) ) /** @todo r=bird: is it just me or doesn't this make sense at all? */
2377 pEd->HeadP |= ED_HEAD_CARRY;
2378 else
2379 pEd->HeadP &= ~ED_HEAD_CARRY;
2380 }
2381
2382 /*
2383 * Unlink the TD from the ED list.
2384 * The normal case is that it's at the head of the list.
2385 */
2386 Assert((TdAddr & ED_PTR_MASK) == TdAddr);
2387 if ((pEd->HeadP & ED_PTR_MASK) == TdAddr)
2388 {
2389 pEd->HeadP = (pTd->NextTD & ED_PTR_MASK) | (pEd->HeadP & ~ED_PTR_MASK);
2390 pTd->NextTD &= ~ED_PTR_MASK;
2391 }
2392 else
2393 {
2394 /*
2395 * The TD is probably somewhere in the list.
2396 *
2397 * This shouldn't ever happen unless there was a failure! Even on failure,
2398 * we can screw up the HCD state by picking out a TD from within the list
2399 * like this! If this turns out to be a problem, we have to find a better
2400 * solution. For now we'll hope the HCD handles it...
2401 */
2402 if (!ohciR3UnlinkGeneralTdInList(pDevIns, TdAddr, pTd, pEd))
2403 return false;
2404 }
2405
2406 /*
2407 * Only unlink the first TD on error.
2408 * See comment in ohciR3RhXferCompleteGeneralURB().
2409 */
2410 if (pUrb->enmStatus != VUSBSTATUS_OK)
2411 break;
2412 }
2413 }
2414
2415 return true;
2416}
2417
2418
2419/**
2420 * Checks that the transport descriptors associated with the URB
2421 * hasn't been changed in any way indicating that they may have been canceled.
2422 *
2423 * This rountine also updates the TD copies contained within the URB.
2424 *
2425 * @returns true if the URB has been canceled, otherwise false.
2426 * @param pDevIns The device instance.
2427 * @param pThis The OHCI instance.
2428 * @param pUrb The URB in question.
2429 * @param pEd The ED pointer (optional).
2430 */
2431static bool ohciR3HasUrbBeenCanceled(PPDMDEVINS pDevIns, POHCI pThis, PVUSBURB pUrb, PCOHCIED pEd)
2432{
2433 if (!pUrb)
2434 return true;
2435
2436 /*
2437 * Make sure we've got an endpoint descriptor so we can
2438 * check for tail TDs.
2439 */
2440 OHCIED Ed;
2441 if (!pEd)
2442 {
2443 ohciR3ReadEd(pDevIns, pUrb->pHci->EdAddr, &Ed);
2444 pEd = &Ed;
2445 }
2446
2447 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
2448 {
2449 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
2450 {
2451 union
2452 {
2453 OHCIITD ITd;
2454 uint32_t au32[8];
2455 } u;
2456 if ( (pUrb->paTds[iTd].TdAddr & ED_PTR_MASK)
2457 == (pEd->TailP & ED_PTR_MASK))
2458 {
2459 Log(("%s: ohciR3HasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled (tail)! [iso]\n",
2460 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr));
2461 STAM_COUNTER_INC(&pThis->StatCanceledIsocUrbs);
2462 return true;
2463 }
2464 ohciR3ReadITd(pDevIns, pThis, pUrb->paTds[iTd].TdAddr, &u.ITd);
2465 if ( u.au32[0] != pUrb->paTds[iTd].TdCopy[0] /* hwinfo */
2466 || u.au32[1] != pUrb->paTds[iTd].TdCopy[1] /* bp0 */
2467 || u.au32[3] != pUrb->paTds[iTd].TdCopy[3] /* be */
2468 || ( u.au32[2] != pUrb->paTds[iTd].TdCopy[2] /* NextTD */
2469 && iTd + 1 < pUrb->pHci->cTds /* ignore the last one */)
2470 || u.au32[4] != pUrb->paTds[iTd].TdCopy[4] /* psw0&1 */
2471 || u.au32[5] != pUrb->paTds[iTd].TdCopy[5] /* psw2&3 */
2472 || u.au32[6] != pUrb->paTds[iTd].TdCopy[6] /* psw4&5 */
2473 || u.au32[7] != pUrb->paTds[iTd].TdCopy[7] /* psw6&7 */
2474 )
2475 {
2476 Log(("%s: ohciR3HasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled! [iso]\n",
2477 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr));
2478 Log2((" %.*Rhxs (cur)\n"
2479 "!= %.*Rhxs (copy)\n",
2480 sizeof(u.ITd), &u.ITd, sizeof(u.ITd), &pUrb->paTds[iTd].TdCopy[0]));
2481 STAM_COUNTER_INC(&pThis->StatCanceledIsocUrbs);
2482 return true;
2483 }
2484 pUrb->paTds[iTd].TdCopy[2] = u.au32[2];
2485 }
2486 }
2487 else
2488 {
2489 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
2490 {
2491 union
2492 {
2493 OHCITD Td;
2494 uint32_t au32[4];
2495 } u;
2496 if ( (pUrb->paTds[iTd].TdAddr & ED_PTR_MASK)
2497 == (pEd->TailP & ED_PTR_MASK))
2498 {
2499 Log(("%s: ohciR3HasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled (tail)!\n",
2500 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr));
2501 STAM_COUNTER_INC(&pThis->StatCanceledGenUrbs);
2502 return true;
2503 }
2504 ohciR3ReadTd(pDevIns, pUrb->paTds[iTd].TdAddr, &u.Td);
2505 if ( u.au32[0] != pUrb->paTds[iTd].TdCopy[0] /* hwinfo */
2506 || u.au32[1] != pUrb->paTds[iTd].TdCopy[1] /* cbp */
2507 || u.au32[3] != pUrb->paTds[iTd].TdCopy[3] /* be */
2508 || ( u.au32[2] != pUrb->paTds[iTd].TdCopy[2] /* NextTD */
2509 && iTd + 1 < pUrb->pHci->cTds /* ignore the last one */)
2510 )
2511 {
2512 Log(("%s: ohciR3HasUrbBeenCanceled: iTd=%d cTds=%d TdAddr=%#010RX32 canceled!\n",
2513 pUrb->pszDesc, iTd, pUrb->pHci->cTds, pUrb->paTds[iTd].TdAddr));
2514 Log2((" %.*Rhxs (cur)\n"
2515 "!= %.*Rhxs (copy)\n",
2516 sizeof(u.Td), &u.Td, sizeof(u.Td), &pUrb->paTds[iTd].TdCopy[0]));
2517 STAM_COUNTER_INC(&pThis->StatCanceledGenUrbs);
2518 return true;
2519 }
2520 pUrb->paTds[iTd].TdCopy[2] = u.au32[2];
2521 }
2522 }
2523 return false;
2524}
2525
2526
2527/**
2528 * Returns the OHCI_CC_* corresponding to the VUSB status code.
2529 *
2530 * @returns OHCI_CC_* value.
2531 * @param enmStatus The VUSB status code.
2532 */
2533static uint32_t ohciR3VUsbStatus2OhciStatus(VUSBSTATUS enmStatus)
2534{
2535 switch (enmStatus)
2536 {
2537 case VUSBSTATUS_OK: return OHCI_CC_NO_ERROR;
2538 case VUSBSTATUS_STALL: return OHCI_CC_STALL;
2539 case VUSBSTATUS_CRC: return OHCI_CC_CRC;
2540 case VUSBSTATUS_DATA_UNDERRUN: return OHCI_CC_DATA_UNDERRUN;
2541 case VUSBSTATUS_DATA_OVERRUN: return OHCI_CC_DATA_OVERRUN;
2542 case VUSBSTATUS_DNR: return OHCI_CC_DNR;
2543 case VUSBSTATUS_NOT_ACCESSED: return OHCI_CC_NOT_ACCESSED_1;
2544 default:
2545 Log(("pUrb->enmStatus=%#x!!!\n", enmStatus));
2546 return OHCI_CC_DNR;
2547 }
2548}
2549
2550
2551/**
2552 * Lock the given OHCI controller instance.
2553 *
2554 * @param pThisCC The OHCI controller instance to lock, ring-3 edition.
2555 */
2556DECLINLINE(void) ohciR3Lock(POHCICC pThisCC)
2557{
2558 RTCritSectEnter(&pThisCC->CritSect);
2559
2560# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
2561 /* Clear all caches here to avoid reading stale data from previous lock holders. */
2562 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheED);
2563 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheTD);
2564# endif
2565}
2566
2567
2568/**
2569 * Unlocks the given OHCI controller instance.
2570 *
2571 * @param pThisCC The OHCI controller instance to unlock, ring-3 edition.
2572 */
2573DECLINLINE(void) ohciR3Unlock(POHCICC pThisCC)
2574{
2575# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
2576 /*
2577 * Clear all caches here to avoid leaving stale data behind (paranoia^2,
2578 * already done in ohciR3Lock).
2579 */
2580 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheED);
2581 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheTD);
2582# endif
2583
2584 RTCritSectLeave(&pThisCC->CritSect);
2585}
2586
2587
2588/**
2589 * Worker for ohciR3RhXferCompletion that handles the completion of
2590 * a URB made up of isochronous TDs.
2591 *
2592 * In general, all URBs should have status OK.
2593 */
2594static void ohciR3RhXferCompleteIsochronousURB(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, PVUSBURB pUrb
2595 /*, POHCIED pEd , int cFmAge*/)
2596{
2597 /*
2598 * Copy the data back (if IN operation) and update the TDs.
2599 */
2600 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
2601 {
2602 POHCIITD pITd = (POHCIITD)&pUrb->paTds[iTd].TdCopy[0];
2603 const uint32_t ITdAddr = pUrb->paTds[iTd].TdAddr;
2604 const unsigned cFrames = ((pITd->HwInfo & ITD_HWINFO_FC) >> ITD_HWINFO_FC_SHIFT) + 1;
2605 unsigned R = (pUrb->pHci->u32FrameNo & ITD_HWINFO_SF) - (pITd->HwInfo & ITD_HWINFO_SF);
2606 if (R >= 8)
2607 R = 0; /* submitted ahead of time. */
2608
2609 /*
2610 * Only one case of TD level condition code is document, so
2611 * just set NO_ERROR here to reduce number duplicate code.
2612 */
2613 pITd->HwInfo &= ~TD_HWINFO_CC;
2614 AssertCompile(OHCI_CC_NO_ERROR == 0);
2615
2616 if (pUrb->enmStatus == VUSBSTATUS_OK)
2617 {
2618 /*
2619 * Update the frames and copy back the data.
2620 * We assume that we don't get incorrect lengths here.
2621 */
2622 for (unsigned i = 0; i < cFrames; i++)
2623 {
2624 if ( i < R
2625 || pUrb->aIsocPkts[i - R].enmStatus == VUSBSTATUS_NOT_ACCESSED)
2626 {
2627 /* It should already be NotAccessed. */
2628 pITd->aPSW[i] |= 0xe000; /* (Don't touch the 12th bit.) */
2629 continue;
2630 }
2631
2632 /* Update the PSW (save the offset first in case of a IN). */
2633 uint32_t off = pITd->aPSW[i] & ITD_PSW_OFFSET;
2634 pITd->aPSW[i] = ohciR3VUsbStatus2OhciStatus(pUrb->aIsocPkts[i - R].enmStatus)
2635 >> (TD_HWINFO_CC_SHIFT - ITD_PSW_CC_SHIFT);
2636
2637 if ( pUrb->enmDir == VUSBDIRECTION_IN
2638 && ( pUrb->aIsocPkts[i - R].enmStatus == VUSBSTATUS_OK
2639 || pUrb->aIsocPkts[i - R].enmStatus == VUSBSTATUS_DATA_UNDERRUN
2640 || pUrb->aIsocPkts[i - R].enmStatus == VUSBSTATUS_DATA_OVERRUN))
2641 {
2642 /* Set the size. */
2643 const unsigned cb = pUrb->aIsocPkts[i - R].cb;
2644 pITd->aPSW[i] |= cb & ITD_PSW_SIZE;
2645 /* Copy data. */
2646 if (cb)
2647 {
2648 uint8_t *pb = &pUrb->abData[pUrb->aIsocPkts[i - R].off];
2649 if (off + cb > 0x1000)
2650 {
2651 if (off < 0x1000)
2652 {
2653 /* both */
2654 const unsigned cb0 = 0x1000 - off;
2655 ohciR3PhysWrite(pDevIns, (pITd->BP0 & ITD_BP0_MASK) + off, pb, cb0);
2656 ohciR3PhysWrite(pDevIns, pITd->BE & ITD_BP0_MASK, pb + cb0, cb - cb0);
2657 }
2658 else /* only in the 2nd page */
2659 ohciR3PhysWrite(pDevIns, (pITd->BE & ITD_BP0_MASK) + (off & ITD_BP0_MASK), pb, cb);
2660 }
2661 else /* only in the 1st page */
2662 ohciR3PhysWrite(pDevIns, (pITd->BP0 & ITD_BP0_MASK) + off, pb, cb);
2663 Log5(("packet %d: off=%#x cb=%#x pb=%p (%#x)\n"
2664 "%.*Rhxd\n",
2665 i + R, off, cb, pb, pb - &pUrb->abData[0], cb, pb));
2666 //off += cb;
2667 }
2668 }
2669 }
2670
2671 /*
2672 * If the last package ended with a NotAccessed status, set ITD CC
2673 * to DataOverrun to indicate scheduling overrun.
2674 */
2675 if (pUrb->aIsocPkts[pUrb->cIsocPkts - 1].enmStatus == VUSBSTATUS_NOT_ACCESSED)
2676 pITd->HwInfo |= OHCI_CC_DATA_OVERRUN;
2677 }
2678 else
2679 {
2680 Log(("DevOHCI: Taking untested code path at line %d...\n", __LINE__));
2681 /*
2682 * Most status codes only applies to the individual packets.
2683 *
2684 * If we get a URB level error code of this kind, we'll distribute
2685 * it to all the packages unless some other status is available for
2686 * a package. This is a bit fuzzy, and we will get rid of this code
2687 * before long!
2688 */
2689 //if (pUrb->enmStatus != VUSBSTATUS_DATA_OVERRUN)
2690 {
2691 const unsigned uCC = ohciR3VUsbStatus2OhciStatus(pUrb->enmStatus)
2692 >> (TD_HWINFO_CC_SHIFT - ITD_PSW_CC_SHIFT);
2693 for (unsigned i = 0; i < cFrames; i++)
2694 pITd->aPSW[i] = uCC;
2695 }
2696 //else
2697 // pITd->HwInfo |= ohciR3VUsbStatus2OhciStatus(pUrb->enmStatus);
2698 }
2699
2700 /*
2701 * Update the done queue interrupt timer.
2702 */
2703 uint32_t DoneInt = (pITd->HwInfo & ITD_HWINFO_DI) >> ITD_HWINFO_DI_SHIFT;
2704 if ((pITd->HwInfo & TD_HWINFO_CC) != OHCI_CC_NO_ERROR)
2705 DoneInt = 0; /* It's cleared on error. */
2706 if ( DoneInt != 0x7
2707 && DoneInt < pThis->dqic)
2708 pThis->dqic = DoneInt;
2709
2710 /*
2711 * Move on to the done list and write back the modified TD.
2712 */
2713# ifdef LOG_ENABLED
2714 if (!pThis->done)
2715 pThisCC->u32FmDoneQueueTail = pThis->HcFmNumber;
2716# ifdef VBOX_STRICT
2717 ohciR3InDoneQueueAdd(pThisCC, ITdAddr);
2718# endif
2719# endif
2720 pITd->NextTD = pThis->done;
2721 pThis->done = ITdAddr;
2722
2723 Log(("%s: ohciR3RhXferCompleteIsochronousURB: ITdAddr=%#010x EdAddr=%#010x SF=%#x (%#x) CC=%#x FC=%d "
2724 "psw0=%x:%x psw1=%x:%x psw2=%x:%x psw3=%x:%x psw4=%x:%x psw5=%x:%x psw6=%x:%x psw7=%x:%x R=%d\n",
2725 pUrb->pszDesc, ITdAddr,
2726 pUrb->pHci->EdAddr,
2727 pITd->HwInfo & ITD_HWINFO_SF, pThis->HcFmNumber,
2728 (pITd->HwInfo & ITD_HWINFO_CC) >> ITD_HWINFO_CC_SHIFT,
2729 (pITd->HwInfo & ITD_HWINFO_FC) >> ITD_HWINFO_FC_SHIFT,
2730 pITd->aPSW[0] >> ITD_PSW_CC_SHIFT, pITd->aPSW[0] & ITD_PSW_SIZE,
2731 pITd->aPSW[1] >> ITD_PSW_CC_SHIFT, pITd->aPSW[1] & ITD_PSW_SIZE,
2732 pITd->aPSW[2] >> ITD_PSW_CC_SHIFT, pITd->aPSW[2] & ITD_PSW_SIZE,
2733 pITd->aPSW[3] >> ITD_PSW_CC_SHIFT, pITd->aPSW[3] & ITD_PSW_SIZE,
2734 pITd->aPSW[4] >> ITD_PSW_CC_SHIFT, pITd->aPSW[4] & ITD_PSW_SIZE,
2735 pITd->aPSW[5] >> ITD_PSW_CC_SHIFT, pITd->aPSW[5] & ITD_PSW_SIZE,
2736 pITd->aPSW[6] >> ITD_PSW_CC_SHIFT, pITd->aPSW[6] & ITD_PSW_SIZE,
2737 pITd->aPSW[7] >> ITD_PSW_CC_SHIFT, pITd->aPSW[7] & ITD_PSW_SIZE,
2738 R));
2739 ohciR3WriteITd(pDevIns, pThis, ITdAddr, pITd, "retired");
2740 }
2741 RT_NOREF(pThisCC);
2742}
2743
2744
2745/**
2746 * Worker for ohciR3RhXferCompletion that handles the completion of
2747 * a URB made up of general TDs.
2748 */
2749static void ohciR3RhXferCompleteGeneralURB(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, PVUSBURB pUrb,
2750 POHCIED pEd, int cFmAge)
2751{
2752 RT_NOREF(cFmAge);
2753
2754 /*
2755 * Copy the data back (if IN operation) and update the TDs.
2756 */
2757 unsigned cbLeft = pUrb->cbData;
2758 uint8_t *pb = &pUrb->abData[0];
2759 for (unsigned iTd = 0; iTd < pUrb->pHci->cTds; iTd++)
2760 {
2761 POHCITD pTd = (POHCITD)&pUrb->paTds[iTd].TdCopy[0];
2762 const uint32_t TdAddr = pUrb->paTds[iTd].TdAddr;
2763
2764 /*
2765 * Setup a ohci transfer buffer and calc the new cbp value.
2766 */
2767 OHCIBUF Buf;
2768 ohciR3BufInit(&Buf, pTd->cbp, pTd->be);
2769 uint32_t NewCbp;
2770 if (cbLeft >= Buf.cbTotal)
2771 NewCbp = 0;
2772 else
2773 {
2774 /* (len may have changed for short transfers) */
2775 Buf.cbTotal = cbLeft;
2776 ohciR3BufUpdate(&Buf);
2777 Assert(Buf.cVecs >= 1);
2778 NewCbp = Buf.aVecs[Buf.cVecs-1].Addr + Buf.aVecs[Buf.cVecs-1].cb;
2779 }
2780
2781 /*
2782 * Write back IN buffers.
2783 */
2784 if ( pUrb->enmDir == VUSBDIRECTION_IN
2785 && ( pUrb->enmStatus == VUSBSTATUS_OK
2786 || pUrb->enmStatus == VUSBSTATUS_DATA_OVERRUN
2787 || pUrb->enmStatus == VUSBSTATUS_DATA_UNDERRUN)
2788 && Buf.cbTotal > 0)
2789 {
2790 Assert(Buf.cVecs > 0);
2791
2792 /* Be paranoid */
2793 if ( Buf.aVecs[0].cb > cbLeft
2794 || ( Buf.cVecs > 1
2795 && Buf.aVecs[1].cb > (cbLeft - Buf.aVecs[0].cb)))
2796 {
2797 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 1);
2798 return;
2799 }
2800
2801 ohciR3PhysWrite(pDevIns, Buf.aVecs[0].Addr, pb, Buf.aVecs[0].cb);
2802 if (Buf.cVecs > 1)
2803 ohciR3PhysWrite(pDevIns, Buf.aVecs[1].Addr, pb + Buf.aVecs[0].cb, Buf.aVecs[1].cb);
2804 }
2805
2806 /* advance the data buffer. */
2807 cbLeft -= Buf.cbTotal;
2808 pb += Buf.cbTotal;
2809
2810 /*
2811 * Set writeback field.
2812 */
2813 /* zero out writeback fields for retirement */
2814 pTd->hwinfo &= ~TD_HWINFO_CC;
2815 /* always update the CurrentBufferPointer; essential for underrun/overrun errors */
2816 pTd->cbp = NewCbp;
2817
2818 if (pUrb->enmStatus == VUSBSTATUS_OK)
2819 {
2820 pTd->hwinfo &= ~TD_HWINFO_ERRORS;
2821
2822 /* update done queue interrupt timer */
2823 uint32_t DoneInt = (pTd->hwinfo & TD_HWINFO_DI) >> 21;
2824 if ( DoneInt != 0x7
2825 && DoneInt < pThis->dqic)
2826 pThis->dqic = DoneInt;
2827 Log(("%s: ohciR3RhXferCompleteGeneralURB: ED=%#010x TD=%#010x Age=%d enmStatus=%d cbTotal=%#x NewCbp=%#010RX32 dqic=%d\n",
2828 pUrb->pszDesc, pUrb->pHci->EdAddr, TdAddr, cFmAge, pUrb->enmStatus, Buf.cbTotal, NewCbp, pThis->dqic));
2829 }
2830 else
2831 {
2832 Log(("%s: ohciR3RhXferCompleteGeneralURB: HALTED ED=%#010x TD=%#010x (age %d) pUrb->enmStatus=%d\n",
2833 pUrb->pszDesc, pUrb->pHci->EdAddr, TdAddr, cFmAge, pUrb->enmStatus));
2834 pEd->HeadP |= ED_HEAD_HALTED;
2835 pThis->dqic = 0; /* "If the Transfer Descriptor is being retired with an error,
2836 * then the Done Queue Interrupt Counter is cleared as if the
2837 * InterruptDelay field were zero."
2838 */
2839 switch (pUrb->enmStatus)
2840 {
2841 case VUSBSTATUS_STALL:
2842 pTd->hwinfo |= OHCI_CC_STALL;
2843 break;
2844 case VUSBSTATUS_CRC:
2845 pTd->hwinfo |= OHCI_CC_CRC;
2846 break;
2847 case VUSBSTATUS_DATA_UNDERRUN:
2848 pTd->hwinfo |= OHCI_CC_DATA_UNDERRUN;
2849 break;
2850 case VUSBSTATUS_DATA_OVERRUN:
2851 pTd->hwinfo |= OHCI_CC_DATA_OVERRUN;
2852 break;
2853 default: /* what the hell */
2854 Log(("pUrb->enmStatus=%#x!!!\n", pUrb->enmStatus));
2855 RT_FALL_THRU();
2856 case VUSBSTATUS_DNR:
2857 pTd->hwinfo |= OHCI_CC_DNR;
2858 break;
2859 }
2860 }
2861
2862 /*
2863 * Move on to the done list and write back the modified TD.
2864 */
2865# ifdef LOG_ENABLED
2866 if (!pThis->done)
2867 pThisCC->u32FmDoneQueueTail = pThis->HcFmNumber;
2868# ifdef VBOX_STRICT
2869 ohciR3InDoneQueueAdd(pThisCC, TdAddr);
2870# endif
2871# endif
2872 pTd->NextTD = pThis->done;
2873 pThis->done = TdAddr;
2874
2875 ohciR3WriteTd(pDevIns, TdAddr, pTd, "retired");
2876
2877 /*
2878 * If we've halted the endpoint, we stop here.
2879 * ohciR3UnlinkTds() will make sure we've only unliked the first TD.
2880 *
2881 * The reason for this is that while we can have more than one TD in a URB, real
2882 * OHCI hardware will only deal with one TD at the time and it's therefore incorrect
2883 * to retire TDs after the endpoint has been halted. Win2k will crash or enter infinite
2884 * kernel loop if we don't behave correctly. (See @bugref{1646}.)
2885 */
2886 if (pEd->HeadP & ED_HEAD_HALTED)
2887 break;
2888 }
2889 RT_NOREF(pThisCC);
2890}
2891
2892
2893/**
2894 * Transfer completion callback routine.
2895 *
2896 * VUSB will call this when a transfer have been completed
2897 * in a one or another way.
2898 *
2899 * @param pInterface Pointer to OHCI::ROOTHUB::IRhPort.
2900 * @param pUrb Pointer to the URB in question.
2901 */
2902static DECLCALLBACK(void) ohciR3RhXferCompletion(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)
2903{
2904 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
2905 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
2906 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
2907 LogFlow(("%s: ohciR3RhXferCompletion: EdAddr=%#010RX32 cTds=%d TdAddr0=%#010RX32\n",
2908 pUrb->pszDesc, pUrb->pHci->EdAddr, pUrb->pHci->cTds, pUrb->paTds[0].TdAddr));
2909
2910 ohciR3Lock(pThisCC);
2911
2912 int cFmAge = ohciR3InFlightRemoveUrb(pThis, pThisCC, pUrb);
2913
2914 /* Do nothing requiring memory access if the HC encountered an unrecoverable error. */
2915 if (!(pThis->intr_status & OHCI_INTR_UNRECOVERABLE_ERROR))
2916 {
2917 pThis->fIdle = false; /* Mark as active */
2918
2919 /* get the current end point descriptor. */
2920 OHCIED Ed;
2921 ohciR3ReadEd(pDevIns, pUrb->pHci->EdAddr, &Ed);
2922
2923 /*
2924 * Check that the URB hasn't been canceled and then try unlink the TDs.
2925 *
2926 * We drop the URB if the ED is marked halted/skip ASSUMING that this
2927 * means the HCD has canceled the URB.
2928 *
2929 * If we succeed here (i.e. not dropping the URB), the TdCopy members will
2930 * be updated but not yet written. We will delay the writing till we're done
2931 * with the data copying, buffer pointer advancing and error handling.
2932 */
2933 if (pUrb->enmStatus == VUSBSTATUS_UNDO)
2934 {
2935 /* Leave the TD alone - the HCD doesn't want us talking to the device. */
2936 Log(("%s: ohciR3RhXferCompletion: CANCELED {ED=%#010x cTds=%d TD0=%#010x age %d}\n",
2937 pUrb->pszDesc, pUrb->pHci->EdAddr, pUrb->pHci->cTds, pUrb->paTds[0].TdAddr, cFmAge));
2938 STAM_COUNTER_INC(&pThis->StatDroppedUrbs);
2939 ohciR3Unlock(pThisCC);
2940 return;
2941 }
2942 bool fHasBeenCanceled = false;
2943 if ( (Ed.HeadP & ED_HEAD_HALTED)
2944 || (Ed.hwinfo & ED_HWINFO_SKIP)
2945 || cFmAge < 0
2946 || (fHasBeenCanceled = ohciR3HasUrbBeenCanceled(pDevIns, pThis, pUrb, &Ed))
2947 || !ohciR3UnlinkTds(pDevIns, pThis, pUrb, &Ed)
2948 )
2949 {
2950 Log(("%s: ohciR3RhXferCompletion: DROPPED {ED=%#010x cTds=%d TD0=%#010x age %d} because:%s%s%s%s%s!!!\n",
2951 pUrb->pszDesc, pUrb->pHci->EdAddr, pUrb->pHci->cTds, pUrb->paTds[0].TdAddr, cFmAge,
2952 (Ed.HeadP & ED_HEAD_HALTED) ? " ep halted" : "",
2953 (Ed.hwinfo & ED_HWINFO_SKIP) ? " ep skip" : "",
2954 (Ed.HeadP & ED_PTR_MASK) != pUrb->paTds[0].TdAddr ? " ep head-changed" : "",
2955 cFmAge < 0 ? " td not-in-flight" : "",
2956 fHasBeenCanceled ? " td canceled" : ""));
2957 NOREF(fHasBeenCanceled);
2958 STAM_COUNTER_INC(&pThis->StatDroppedUrbs);
2959 ohciR3Unlock(pThisCC);
2960 return;
2961 }
2962
2963 /*
2964 * Complete the TD updating and write the back.
2965 * When appropriate also copy data back to the guest memory.
2966 */
2967 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
2968 ohciR3RhXferCompleteIsochronousURB(pDevIns, pThis, pThisCC, pUrb /*, &Ed , cFmAge*/);
2969 else
2970 ohciR3RhXferCompleteGeneralURB(pDevIns, pThis, pThisCC, pUrb, &Ed, cFmAge);
2971
2972 /* finally write back the endpoint descriptor. */
2973 ohciR3WriteEd(pDevIns, pUrb->pHci->EdAddr, &Ed);
2974 }
2975
2976 ohciR3Unlock(pThisCC);
2977}
2978
2979
2980/**
2981 * Handle transfer errors.
2982 *
2983 * VUSB calls this when a transfer attempt failed. This function will respond
2984 * indicating whether to retry or complete the URB with failure.
2985 *
2986 * @returns true if the URB should be retired.
2987 * @returns false if the URB should be retried.
2988 * @param pInterface Pointer to OHCI::ROOTHUB::IRhPort.
2989 * @param pUrb Pointer to the URB in question.
2990 */
2991static DECLCALLBACK(bool) ohciR3RhXferError(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)
2992{
2993 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
2994 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
2995 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
2996
2997 /*
2998 * Isochronous URBs can't be retried.
2999 */
3000 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
3001 return true;
3002
3003 /*
3004 * Don't retry on stall.
3005 */
3006 if (pUrb->enmStatus == VUSBSTATUS_STALL)
3007 {
3008 Log2(("%s: ohciR3RhXferError: STALL, giving up.\n", pUrb->pszDesc));
3009 return true;
3010 }
3011
3012 ohciR3Lock(pThisCC);
3013 bool fRetire = false;
3014 /*
3015 * Check if the TDs still are valid.
3016 * This will make sure the TdCopy is up to date.
3017 */
3018 const uint32_t TdAddr = pUrb->paTds[0].TdAddr;
3019/** @todo IMPORTANT! we must check if the ED is still valid at this point!!! */
3020 if (ohciR3HasUrbBeenCanceled(pDevIns, pThis, pUrb, NULL))
3021 {
3022 Log(("%s: ohciR3RhXferError: TdAddr0=%#x canceled!\n", pUrb->pszDesc, TdAddr));
3023 fRetire = true;
3024 }
3025 else
3026 {
3027 /*
3028 * Get and update the error counter.
3029 */
3030 POHCITD pTd = (POHCITD)&pUrb->paTds[0].TdCopy[0];
3031 unsigned cErrs = (pTd->hwinfo & TD_HWINFO_ERRORS) >> TD_ERRORS_SHIFT;
3032 pTd->hwinfo &= ~TD_HWINFO_ERRORS;
3033 cErrs++;
3034 pTd->hwinfo |= (cErrs % TD_ERRORS_MAX) << TD_ERRORS_SHIFT;
3035 ohciR3WriteTd(pDevIns, TdAddr, pTd, "ohciR3RhXferError");
3036
3037 if (cErrs >= TD_ERRORS_MAX - 1)
3038 {
3039 Log2(("%s: ohciR3RhXferError: too many errors, giving up!\n", pUrb->pszDesc));
3040 fRetire = true;
3041 }
3042 else
3043 Log2(("%s: ohciR3RhXferError: cErrs=%d: retrying...\n", pUrb->pszDesc, cErrs));
3044 }
3045
3046 ohciR3Unlock(pThisCC);
3047 return fRetire;
3048}
3049
3050
3051/**
3052 * Service a general transport descriptor.
3053 */
3054static bool ohciR3ServiceTd(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, VUSBXFERTYPE enmType,
3055 PCOHCIED pEd, uint32_t EdAddr, uint32_t TdAddr, uint32_t *pNextTdAddr, const char *pszListName)
3056{
3057 RT_NOREF(pszListName);
3058
3059 /*
3060 * Read the TD and setup the buffer data.
3061 */
3062 OHCITD Td;
3063 ohciR3ReadTd(pDevIns, TdAddr, &Td);
3064 OHCIBUF Buf;
3065 ohciR3BufInit(&Buf, Td.cbp, Td.be);
3066
3067 *pNextTdAddr = Td.NextTD & ED_PTR_MASK;
3068
3069 /*
3070 * Determine the direction.
3071 */
3072 VUSBDIRECTION enmDir;
3073 switch (pEd->hwinfo & ED_HWINFO_DIR)
3074 {
3075 case ED_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break;
3076 case ED_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break;
3077 default:
3078 switch (Td.hwinfo & TD_HWINFO_DIR)
3079 {
3080 case TD_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break;
3081 case TD_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break;
3082 case 0: enmDir = VUSBDIRECTION_SETUP; break;
3083 default:
3084 Log(("ohciR3ServiceTd: Invalid direction!!!! Td.hwinfo=%#x Ed.hwdinfo=%#x\n", Td.hwinfo, pEd->hwinfo));
3085 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 2);
3086 return false;
3087 }
3088 break;
3089 }
3090
3091 pThis->fIdle = false; /* Mark as active */
3092
3093 /*
3094 * Allocate and initialize a new URB.
3095 */
3096 PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, VUSB_DEVICE_PORT_INVALID,
3097 enmType, enmDir, Buf.cbTotal, 1, NULL);
3098 if (!pUrb)
3099 return false; /* retry later... */
3100
3101 pUrb->EndPt = (pEd->hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT;
3102 pUrb->fShortNotOk = !(Td.hwinfo & TD_HWINFO_ROUNDING);
3103 pUrb->enmStatus = VUSBSTATUS_OK;
3104 pUrb->pHci->EdAddr = EdAddr;
3105 pUrb->pHci->fUnlinked = false;
3106 pUrb->pHci->cTds = 1;
3107 pUrb->paTds[0].TdAddr = TdAddr;
3108 pUrb->pHci->u32FrameNo = pThis->HcFmNumber;
3109 AssertCompile(sizeof(pUrb->paTds[0].TdCopy) >= sizeof(Td));
3110 memcpy(pUrb->paTds[0].TdCopy, &Td, sizeof(Td));
3111
3112 /* copy data if out bound transfer. */
3113 pUrb->cbData = Buf.cbTotal;
3114 if ( Buf.cbTotal
3115 && Buf.cVecs > 0
3116 && enmDir != VUSBDIRECTION_IN)
3117 {
3118 /* Be paranoid. */
3119 if ( Buf.aVecs[0].cb > pUrb->cbData
3120 || ( Buf.cVecs > 1
3121 && Buf.aVecs[1].cb > (pUrb->cbData - Buf.aVecs[0].cb)))
3122 {
3123 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 3);
3124 VUSBIRhFreeUrb(pThisCC->RootHub.pIRhConn, pUrb);
3125 return false;
3126 }
3127
3128 ohciR3PhysRead(pDevIns, Buf.aVecs[0].Addr, pUrb->abData, Buf.aVecs[0].cb);
3129 if (Buf.cVecs > 1)
3130 ohciR3PhysRead(pDevIns, Buf.aVecs[1].Addr, &pUrb->abData[Buf.aVecs[0].cb], Buf.aVecs[1].cb);
3131 }
3132
3133 /*
3134 * Submit the URB.
3135 */
3136 ohciR3InFlightAdd(pThis, pThisCC, TdAddr, pUrb);
3137 Log(("%s: ohciR3ServiceTd: submitting TdAddr=%#010x EdAddr=%#010x cbData=%#x\n",
3138 pUrb->pszDesc, TdAddr, EdAddr, pUrb->cbData));
3139
3140 ohciR3Unlock(pThisCC);
3141 int rc = VUSBIRhSubmitUrb(pThisCC->RootHub.pIRhConn, pUrb, &pThisCC->RootHub.Led);
3142 ohciR3Lock(pThisCC);
3143 if (RT_SUCCESS(rc))
3144 return true;
3145
3146 /* Failure cleanup. Can happen if we're still resetting the device or out of resources. */
3147 Log(("ohciR3ServiceTd: failed submitting TdAddr=%#010x EdAddr=%#010x pUrb=%p!!\n",
3148 TdAddr, EdAddr, pUrb));
3149 ohciR3InFlightRemove(pThis, pThisCC, TdAddr);
3150 return false;
3151}
3152
3153
3154/**
3155 * Service a the head TD of an endpoint.
3156 */
3157static bool ohciR3ServiceHeadTd(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, VUSBXFERTYPE enmType,
3158 PCOHCIED pEd, uint32_t EdAddr, const char *pszListName)
3159{
3160 /*
3161 * Read the TD, after first checking if it's already in-flight.
3162 */
3163 uint32_t TdAddr = pEd->HeadP & ED_PTR_MASK;
3164 if (ohciR3IsTdInFlight(pThisCC, TdAddr))
3165 return false;
3166# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
3167 ohciR3InDoneQueueCheck(pThisCC, TdAddr);
3168# endif
3169 return ohciR3ServiceTd(pDevIns, pThis, pThisCC, enmType, pEd, EdAddr, TdAddr, &TdAddr, pszListName);
3170}
3171
3172
3173/**
3174 * Service one or more general transport descriptors (bulk or interrupt).
3175 */
3176static bool ohciR3ServiceTdMultiple(PPDMDEVINS pDevIns, POHCI pThis, VUSBXFERTYPE enmType, PCOHCIED pEd, uint32_t EdAddr,
3177 uint32_t TdAddr, uint32_t *pNextTdAddr, const char *pszListName)
3178{
3179 RT_NOREF(pszListName);
3180
3181 /*
3182 * Read the TDs involved in this URB.
3183 */
3184 struct OHCITDENTRY
3185 {
3186 /** The TD. */
3187 OHCITD Td;
3188 /** The associated OHCI buffer tracker. */
3189 OHCIBUF Buf;
3190 /** The TD address. */
3191 uint32_t TdAddr;
3192 /** Pointer to the next element in the chain (stack). */
3193 struct OHCITDENTRY *pNext;
3194 } Head;
3195
3196 POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
3197# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
3198 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheTD);
3199# endif
3200
3201 /* read the head */
3202 ohciR3ReadTd(pDevIns, TdAddr, &Head.Td);
3203 ohciR3BufInit(&Head.Buf, Head.Td.cbp, Head.Td.be);
3204 Head.TdAddr = TdAddr;
3205 Head.pNext = NULL;
3206
3207 /* combine with more TDs. */
3208 struct OHCITDENTRY *pTail = &Head;
3209 unsigned cbTotal = pTail->Buf.cbTotal;
3210 unsigned cTds = 1;
3211 while ( (pTail->Buf.cbTotal == 0x1000 || pTail->Buf.cbTotal == 0x2000)
3212 && !(pTail->Td.hwinfo & TD_HWINFO_ROUNDING) /* This isn't right for *BSD, but let's not . */
3213 && (pTail->Td.NextTD & ED_PTR_MASK) != (pEd->TailP & ED_PTR_MASK)
3214 && cTds < 128)
3215 {
3216 struct OHCITDENTRY *pCur = (struct OHCITDENTRY *)alloca(sizeof(*pCur));
3217
3218 pCur->pNext = NULL;
3219 pCur->TdAddr = pTail->Td.NextTD & ED_PTR_MASK;
3220 ohciR3ReadTd(pDevIns, pCur->TdAddr, &pCur->Td);
3221 ohciR3BufInit(&pCur->Buf, pCur->Td.cbp, pCur->Td.be);
3222
3223 /* Don't combine if the direction doesn't match up. There can't actually be
3224 * a mismatch for bulk/interrupt EPs unless the guest is buggy.
3225 */
3226 if ( (pCur->Td.hwinfo & (TD_HWINFO_DIR))
3227 != (Head.Td.hwinfo & (TD_HWINFO_DIR)))
3228 break;
3229
3230 pTail->pNext = pCur;
3231 pTail = pCur;
3232 cbTotal += pCur->Buf.cbTotal;
3233 cTds++;
3234 }
3235
3236 /* calc next TD address */
3237 *pNextTdAddr = pTail->Td.NextTD & ED_PTR_MASK;
3238
3239 /*
3240 * Determine the direction.
3241 */
3242 VUSBDIRECTION enmDir;
3243 switch (pEd->hwinfo & ED_HWINFO_DIR)
3244 {
3245 case ED_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break;
3246 case ED_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break;
3247 default:
3248 Log(("ohciR3ServiceTdMultiple: WARNING! Ed.hwdinfo=%#x bulk or interrupt EP shouldn't rely on the TD for direction...\n", pEd->hwinfo));
3249 switch (Head.Td.hwinfo & TD_HWINFO_DIR)
3250 {
3251 case TD_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break;
3252 case TD_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break;
3253 default:
3254 Log(("ohciR3ServiceTdMultiple: Invalid direction!!!! Head.Td.hwinfo=%#x Ed.hwdinfo=%#x\n", Head.Td.hwinfo, pEd->hwinfo));
3255 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 4);
3256 return false;
3257 }
3258 break;
3259 }
3260
3261 pThis->fIdle = false; /* Mark as active */
3262
3263 /*
3264 * Allocate and initialize a new URB.
3265 */
3266 PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, VUSB_DEVICE_PORT_INVALID,
3267 enmType, enmDir, cbTotal, cTds, "ohciR3ServiceTdMultiple");
3268 if (!pUrb)
3269 /* retry later... */
3270 return false;
3271 Assert(pUrb->cbData == cbTotal);
3272
3273 pUrb->enmType = enmType;
3274 pUrb->EndPt = (pEd->hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT;
3275 pUrb->enmDir = enmDir;
3276 pUrb->fShortNotOk = !(pTail->Td.hwinfo & TD_HWINFO_ROUNDING);
3277 pUrb->enmStatus = VUSBSTATUS_OK;
3278 pUrb->pHci->cTds = cTds;
3279 pUrb->pHci->EdAddr = EdAddr;
3280 pUrb->pHci->fUnlinked = false;
3281 pUrb->pHci->u32FrameNo = pThis->HcFmNumber;
3282
3283 /* Copy data and TD information. */
3284 unsigned iTd = 0;
3285 uint8_t *pb = &pUrb->abData[0];
3286 for (struct OHCITDENTRY *pCur = &Head; pCur; pCur = pCur->pNext, iTd++)
3287 {
3288 /* data */
3289 if ( cbTotal
3290 && enmDir != VUSBDIRECTION_IN
3291 && pCur->Buf.cVecs > 0)
3292 {
3293 ohciR3PhysRead(pDevIns, pCur->Buf.aVecs[0].Addr, pb, pCur->Buf.aVecs[0].cb);
3294 if (pCur->Buf.cVecs > 1)
3295 ohciR3PhysRead(pDevIns, pCur->Buf.aVecs[1].Addr, pb + pCur->Buf.aVecs[0].cb, pCur->Buf.aVecs[1].cb);
3296 }
3297 pb += pCur->Buf.cbTotal;
3298
3299 /* TD info */
3300 pUrb->paTds[iTd].TdAddr = pCur->TdAddr;
3301 AssertCompile(sizeof(pUrb->paTds[iTd].TdCopy) >= sizeof(pCur->Td));
3302 memcpy(pUrb->paTds[iTd].TdCopy, &pCur->Td, sizeof(pCur->Td));
3303 }
3304
3305 /*
3306 * Submit the URB.
3307 */
3308 ohciR3InFlightAddUrb(pThis, pThisCC, pUrb);
3309 Log(("%s: ohciR3ServiceTdMultiple: submitting cbData=%#x EdAddr=%#010x cTds=%d TdAddr0=%#010x\n",
3310 pUrb->pszDesc, pUrb->cbData, EdAddr, cTds, TdAddr));
3311 ohciR3Unlock(pThisCC);
3312 int rc = VUSBIRhSubmitUrb(pThisCC->RootHub.pIRhConn, pUrb, &pThisCC->RootHub.Led);
3313 ohciR3Lock(pThisCC);
3314 if (RT_SUCCESS(rc))
3315 return true;
3316
3317 /* Failure cleanup. Can happen if we're still resetting the device or out of resources. */
3318 Log(("ohciR3ServiceTdMultiple: failed submitting pUrb=%p cbData=%#x EdAddr=%#010x cTds=%d TdAddr0=%#010x - rc=%Rrc\n",
3319 pUrb, cbTotal, EdAddr, cTds, TdAddr, rc));
3320 /* NB: We cannot call ohciR3InFlightRemoveUrb() because the URB is already gone! */
3321 for (struct OHCITDENTRY *pCur = &Head; pCur; pCur = pCur->pNext, iTd++)
3322 ohciR3InFlightRemove(pThis, pThisCC, pCur->TdAddr);
3323 return false;
3324}
3325
3326
3327/**
3328 * Service the head TD of an endpoint.
3329 */
3330static bool ohciR3ServiceHeadTdMultiple(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, VUSBXFERTYPE enmType,
3331 PCOHCIED pEd, uint32_t EdAddr, const char *pszListName)
3332{
3333 /*
3334 * First, check that it's not already in-flight.
3335 */
3336 uint32_t TdAddr = pEd->HeadP & ED_PTR_MASK;
3337 if (ohciR3IsTdInFlight(pThisCC, TdAddr))
3338 return false;
3339# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
3340 ohciR3InDoneQueueCheck(pThisCC, TdAddr);
3341# endif
3342 return ohciR3ServiceTdMultiple(pDevIns, pThis, enmType, pEd, EdAddr, TdAddr, &TdAddr, pszListName);
3343}
3344
3345
3346/**
3347 * A worker for ohciR3ServiceIsochronousEndpoint which unlinks a ITD
3348 * that belongs to the past.
3349 */
3350static bool ohciR3ServiceIsochronousTdUnlink(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, POHCIITD pITd, uint32_t ITdAddr,
3351 uint32_t ITdAddrPrev, PVUSBURB pUrb, POHCIED pEd, uint32_t EdAddr)
3352{
3353 LogFlow(("%s%sohciR3ServiceIsochronousTdUnlink: Unlinking ITD: ITdAddr=%#010x EdAddr=%#010x ITdAddrPrev=%#010x\n",
3354 pUrb ? pUrb->pszDesc : "", pUrb ? ": " : "", ITdAddr, EdAddr, ITdAddrPrev));
3355
3356 /*
3357 * Do the unlinking.
3358 */
3359 const uint32_t ITdAddrNext = pITd->NextTD & ED_PTR_MASK;
3360 if (ITdAddrPrev)
3361 {
3362 /* Get validate the previous TD */
3363 int iInFlightPrev = ohciR3InFlightFind(pThisCC, ITdAddrPrev);
3364 AssertMsgReturn(iInFlightPrev >= 0, ("ITdAddr=%#RX32\n", ITdAddrPrev), false);
3365 PVUSBURB pUrbPrev = pThisCC->aInFlight[iInFlightPrev].pUrb;
3366 if (ohciR3HasUrbBeenCanceled(pDevIns, pThis, pUrbPrev, pEd)) /* ensures the copy is correct. */
3367 return false;
3368
3369 /* Update the copy and write it back. */
3370 POHCIITD pITdPrev = ((POHCIITD)pUrbPrev->paTds[0].TdCopy);
3371 pITdPrev->NextTD = (pITdPrev->NextTD & ~ED_PTR_MASK) | ITdAddrNext;
3372 ohciR3WriteITd(pDevIns, pThis, ITdAddrPrev, pITdPrev, "ohciR3ServiceIsochronousEndpoint");
3373 }
3374 else
3375 {
3376 /* It's the head node. update the copy from the caller and write it back. */
3377 pEd->HeadP = (pEd->HeadP & ~ED_PTR_MASK) | ITdAddrNext;
3378 ohciR3WriteEd(pDevIns, EdAddr, pEd);
3379 }
3380
3381 /*
3382 * If it's in flight, just mark the URB as unlinked (there is only one ITD per URB atm).
3383 * Otherwise, retire it to the done queue with an error and cause a done line interrupt (?).
3384 */
3385 if (pUrb)
3386 {
3387 pUrb->pHci->fUnlinked = true;
3388 if (ohciR3HasUrbBeenCanceled(pDevIns, pThis, pUrb, pEd)) /* ensures the copy is correct (paranoia). */
3389 return false;
3390
3391 POHCIITD pITdCopy = ((POHCIITD)pUrb->paTds[0].TdCopy);
3392 pITd->NextTD = pITdCopy->NextTD &= ~ED_PTR_MASK;
3393 }
3394 else
3395 {
3396 pITd->HwInfo &= ~ITD_HWINFO_CC;
3397 pITd->HwInfo |= OHCI_CC_DATA_OVERRUN;
3398
3399 pITd->NextTD = pThis->done;
3400 pThis->done = ITdAddr;
3401
3402 pThis->dqic = 0;
3403 }
3404
3405 ohciR3WriteITd(pDevIns, pThis, ITdAddr, pITd, "ohciR3ServiceIsochronousTdUnlink");
3406 return true;
3407}
3408
3409
3410/**
3411 * A worker for ohciR3ServiceIsochronousEndpoint which submits the specified TD.
3412 *
3413 * @returns true on success.
3414 * @returns false on failure to submit.
3415 * @param pDevIns The device instance.
3416 * @param pThis The OHCI controller instance data, shared edition.
3417 * @param pThisCC The OHCI controller instance data, ring-3 edition.
3418 * @param pITd The transfer descriptor to service.
3419 * @param ITdAddr The address of the transfer descriptor in gues memory.
3420 * @param R The start packet (frame) relative to the start of frame in HwInfo.
3421 * @param pEd The OHCI endpoint descriptor.
3422 * @param EdAddr The endpoint descriptor address in guest memory.
3423 */
3424static bool ohciR3ServiceIsochronousTd(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC,
3425 POHCIITD pITd, uint32_t ITdAddr, const unsigned R, PCOHCIED pEd, uint32_t EdAddr)
3426{
3427 /*
3428 * Determine the endpoint direction.
3429 */
3430 VUSBDIRECTION enmDir;
3431 switch (pEd->hwinfo & ED_HWINFO_DIR)
3432 {
3433 case ED_HWINFO_OUT: enmDir = VUSBDIRECTION_OUT; break;
3434 case ED_HWINFO_IN: enmDir = VUSBDIRECTION_IN; break;
3435 default:
3436 Log(("ohciR3ServiceIsochronousTd: Invalid direction!!!! Ed.hwdinfo=%#x\n", pEd->hwinfo));
3437 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 5);
3438 return false;
3439 }
3440
3441 /*
3442 * Extract the packet sizes and calc the total URB size.
3443 */
3444 struct
3445 {
3446 uint16_t cb;
3447 uint16_t off;
3448 } aPkts[ITD_NUM_PSW];
3449
3450 /* first entry (R) */
3451 uint32_t cbTotal = 0;
3452 if (((uint32_t)pITd->aPSW[R] >> ITD_PSW_CC_SHIFT) < (OHCI_CC_NOT_ACCESSED_0 >> TD_HWINFO_CC_SHIFT))
3453 {
3454 Log(("ITdAddr=%RX32 PSW%d.CC=%#x < 'Not Accessed'!\n", ITdAddr, R, pITd->aPSW[R] >> ITD_PSW_CC_SHIFT)); /* => Unrecoverable Error*/
3455 pThis->intr_status |= OHCI_INTR_UNRECOVERABLE_ERROR;
3456 return false;
3457 }
3458 uint16_t offPrev = aPkts[0].off = (pITd->aPSW[R] & ITD_PSW_OFFSET);
3459
3460 /* R+1..cFrames */
3461 const unsigned cFrames = ((pITd->HwInfo & ITD_HWINFO_FC) >> ITD_HWINFO_FC_SHIFT) + 1;
3462 for (unsigned iR = R + 1; iR < cFrames; iR++)
3463 {
3464 const uint16_t PSW = pITd->aPSW[iR];
3465 const uint16_t off = aPkts[iR - R].off = (PSW & ITD_PSW_OFFSET);
3466 cbTotal += aPkts[iR - R - 1].cb = off - offPrev;
3467 if (off < offPrev)
3468 {
3469 Log(("ITdAddr=%RX32 PSW%d.offset=%#x < offPrev=%#x!\n", ITdAddr, iR, off, offPrev)); /* => Unrecoverable Error*/
3470 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 6);
3471 return false;
3472 }
3473 if (((uint32_t)PSW >> ITD_PSW_CC_SHIFT) < (OHCI_CC_NOT_ACCESSED_0 >> TD_HWINFO_CC_SHIFT))
3474 {
3475 Log(("ITdAddr=%RX32 PSW%d.CC=%#x < 'Not Accessed'!\n", ITdAddr, iR, PSW >> ITD_PSW_CC_SHIFT)); /* => Unrecoverable Error*/
3476 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 7);
3477 return false;
3478 }
3479 offPrev = off;
3480 }
3481
3482 /* calc offEnd and figure out the size of the last packet. */
3483 const uint32_t offEnd = (pITd->BE & 0xfff)
3484 + (((pITd->BE & ITD_BP0_MASK) != (pITd->BP0 & ITD_BP0_MASK)) << 12)
3485 + 1 /* BE is inclusive */;
3486 if (offEnd < offPrev)
3487 {
3488 Log(("ITdAddr=%RX32 offEnd=%#x < offPrev=%#x!\n", ITdAddr, offEnd, offPrev)); /* => Unrecoverable Error*/
3489 ohciR3RaiseUnrecoverableError(pDevIns, pThis, 8);
3490 return false;
3491 }
3492 cbTotal += aPkts[cFrames - 1 - R].cb = offEnd - offPrev;
3493 Assert(cbTotal <= 0x2000);
3494
3495 pThis->fIdle = false; /* Mark as active */
3496
3497 /*
3498 * Allocate and initialize a new URB.
3499 */
3500 PVUSBURB pUrb = VUSBIRhNewUrb(pThisCC->RootHub.pIRhConn, pEd->hwinfo & ED_HWINFO_FUNCTION, VUSB_DEVICE_PORT_INVALID,
3501 VUSBXFERTYPE_ISOC, enmDir, cbTotal, 1, NULL);
3502 if (!pUrb)
3503 /* retry later... */
3504 return false;
3505
3506 pUrb->EndPt = (pEd->hwinfo & ED_HWINFO_ENDPOINT) >> ED_HWINFO_ENDPOINT_SHIFT;
3507 pUrb->fShortNotOk = false;
3508 pUrb->enmStatus = VUSBSTATUS_OK;
3509 pUrb->pHci->EdAddr = EdAddr;
3510 pUrb->pHci->cTds = 1;
3511 pUrb->pHci->fUnlinked = false;
3512 pUrb->pHci->u32FrameNo = pThis->HcFmNumber;
3513 pUrb->paTds[0].TdAddr = ITdAddr;
3514 AssertCompile(sizeof(pUrb->paTds[0].TdCopy) >= sizeof(*pITd));
3515 memcpy(pUrb->paTds[0].TdCopy, pITd, sizeof(*pITd));
3516# if 0 /* color the data */
3517 memset(pUrb->abData, 0xfe, cbTotal);
3518# endif
3519
3520 /* copy the data */
3521 if ( cbTotal
3522 && enmDir != VUSBDIRECTION_IN)
3523 {
3524 const uint32_t off0 = pITd->aPSW[R] & ITD_PSW_OFFSET;
3525 if (off0 < 0x1000)
3526 {
3527 if (offEnd > 0x1000)
3528 {
3529 /* both pages. */
3530 const unsigned cb0 = 0x1000 - off0;
3531 ohciR3PhysRead(pDevIns, (pITd->BP0 & ITD_BP0_MASK) + off0, &pUrb->abData[0], cb0);
3532 ohciR3PhysRead(pDevIns, pITd->BE & ITD_BP0_MASK, &pUrb->abData[cb0], offEnd & 0xfff);
3533 }
3534 else /* a portion of the 1st page. */
3535 ohciR3PhysRead(pDevIns, (pITd->BP0 & ITD_BP0_MASK) + off0, pUrb->abData, offEnd - off0);
3536 }
3537 else /* a portion of the 2nd page. */
3538 ohciR3PhysRead(pDevIns, (pITd->BE & UINT32_C(0xfffff000)) + (off0 & 0xfff), pUrb->abData, cbTotal);
3539 }
3540
3541 /* setup the packets */
3542 pUrb->cIsocPkts = cFrames - R;
3543 unsigned off = 0;
3544 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
3545 {
3546 pUrb->aIsocPkts[i].enmStatus = VUSBSTATUS_NOT_ACCESSED;
3547 pUrb->aIsocPkts[i].off = off;
3548 off += pUrb->aIsocPkts[i].cb = aPkts[i].cb;
3549 }
3550 Assert(off == cbTotal);
3551
3552 /*
3553 * Submit the URB.
3554 */
3555 ohciR3InFlightAdd(pThis, pThisCC, ITdAddr, pUrb);
3556 Log(("%s: ohciR3ServiceIsochronousTd: submitting cbData=%#x cIsocPkts=%d EdAddr=%#010x TdAddr=%#010x SF=%#x (%#x)\n",
3557 pUrb->pszDesc, pUrb->cbData, pUrb->cIsocPkts, EdAddr, ITdAddr, pITd->HwInfo & ITD_HWINFO_SF, pThis->HcFmNumber));
3558 ohciR3Unlock(pThisCC);
3559 int rc = VUSBIRhSubmitUrb(pThisCC->RootHub.pIRhConn, pUrb, &pThisCC->RootHub.Led);
3560 ohciR3Lock(pThisCC);
3561 if (RT_SUCCESS(rc))
3562 return true;
3563
3564 /* Failure cleanup. Can happen if we're still resetting the device or out of resources. */
3565 Log(("ohciR3ServiceIsochronousTd: failed submitting pUrb=%p cbData=%#x EdAddr=%#010x cTds=%d ITdAddr0=%#010x - rc=%Rrc\n",
3566 pUrb, cbTotal, EdAddr, 1, ITdAddr, rc));
3567 ohciR3InFlightRemove(pThis, pThisCC, ITdAddr);
3568 return false;
3569}
3570
3571
3572/**
3573 * Service an isochronous endpoint.
3574 */
3575static void ohciR3ServiceIsochronousEndpoint(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, POHCIED pEd, uint32_t EdAddr)
3576{
3577 /*
3578 * We currently process this as if the guest follows the interrupt end point chaining
3579 * hierarchy described in the documenation. This means that for an isochronous endpoint
3580 * with a 1 ms interval we expect to find in-flight TDs at the head of the list. We will
3581 * skip over all in-flight TDs which timeframe has been exceed. Those which aren't in
3582 * flight but which are too late will be retired (possibly out of order, but, we don't
3583 * care right now).
3584 *
3585 * When we reach a TD which still has a buffer which is due for take off, we will
3586 * stop iterating TDs. If it's in-flight, there isn't anything to be done. Otherwise
3587 * we will push it onto the runway for immediate take off. In this process we
3588 * might have to complete buffers which didn't make it on time, something which
3589 * complicates the kind of status info we need to keep around for the TD.
3590 *
3591 * Note: We're currently not making any attempt at reassembling ITDs into URBs.
3592 * However, this will become necessary because of EMT scheduling and guest
3593 * like linux using one TD for each frame (simple but inefficient for us).
3594 */
3595 OHCIITD ITd;
3596 uint32_t ITdAddr = pEd->HeadP & ED_PTR_MASK;
3597 uint32_t ITdAddrPrev = 0;
3598 uint32_t u32NextFrame = UINT32_MAX;
3599 const uint16_t u16CurFrame = pThis->HcFmNumber;
3600 for (;;)
3601 {
3602 /* check for end-of-chain. */
3603 if ( ITdAddr == (pEd->TailP & ED_PTR_MASK)
3604 || !ITdAddr)
3605 break;
3606
3607 /*
3608 * If isochronous endpoints are around, don't slow down the timer. Getting the timing right
3609 * is difficult enough as it is.
3610 */
3611 pThis->fIdle = false;
3612
3613 /*
3614 * Read the current ITD and check what we're supposed to do about it.
3615 */
3616 ohciR3ReadITd(pDevIns, pThis, ITdAddr, &ITd);
3617 const uint32_t ITdAddrNext = ITd.NextTD & ED_PTR_MASK;
3618 const int16_t R = u16CurFrame - (uint16_t)(ITd.HwInfo & ITD_HWINFO_SF); /* 4.3.2.3 */
3619 const int16_t cFrames = ((ITd.HwInfo & ITD_HWINFO_FC) >> ITD_HWINFO_FC_SHIFT) + 1;
3620
3621 if (R < cFrames)
3622 {
3623 /*
3624 * It's inside the current or a future launch window.
3625 *
3626 * We will try maximize the TD in flight here to deal with EMT scheduling
3627 * issues and similar stuff which will screw up the time. So, we will only
3628 * stop submitting TD when we reach a gap (in time) or end of the list.
3629 */
3630 if ( R < 0 /* (a future frame) */
3631 && (uint16_t)u32NextFrame != (uint16_t)(ITd.HwInfo & ITD_HWINFO_SF))
3632 break;
3633 if (ohciR3InFlightFind(pThisCC, ITdAddr) < 0)
3634 if (!ohciR3ServiceIsochronousTd(pDevIns, pThis, pThisCC, &ITd, ITdAddr, R < 0 ? 0 : R, pEd, EdAddr))
3635 break;
3636
3637 ITdAddrPrev = ITdAddr;
3638 }
3639 else
3640 {
3641# if 1
3642 /*
3643 * Ok, the launch window for this TD has passed.
3644 * If it's not in flight it should be retired with a DataOverrun status (TD).
3645 *
3646 * Don't remove in-flight TDs before they complete.
3647 * Windows will, upon the completion of another ITD it seems, check for if
3648 * any other TDs has been unlinked. If we unlink them before they really
3649 * complete all the packet status codes will be NotAccessed and Windows
3650 * will fail the URB with status USBD_STATUS_ISOCH_REQUEST_FAILED.
3651 *
3652 * I don't know if unlinking TDs out of order could cause similar problems,
3653 * time will show.
3654 */
3655 int iInFlight = ohciR3InFlightFind(pThisCC, ITdAddr);
3656 if (iInFlight >= 0)
3657 ITdAddrPrev = ITdAddr;
3658 else if (!ohciR3ServiceIsochronousTdUnlink(pDevIns, pThis, pThisCC, &ITd, ITdAddr, ITdAddrPrev, NULL, pEd, EdAddr))
3659 {
3660 Log(("ohciR3ServiceIsochronousEndpoint: Failed unlinking old ITD.\n"));
3661 break;
3662 }
3663# else /* BAD IDEA: */
3664 /*
3665 * Ok, the launch window for this TD has passed.
3666 * If it's not in flight it should be retired with a DataOverrun status (TD).
3667 *
3668 * If it's in flight we will try unlink it from the list prematurely to
3669 * help the guest to move on and shorten the list we have to walk. We currently
3670 * are successful with the first URB but then it goes too slowly...
3671 */
3672 int iInFlight = ohciR3InFlightFind(pThis, ITdAddr);
3673 if (!ohciR3ServiceIsochronousTdUnlink(pThis, &ITd, ITdAddr, ITdAddrPrev,
3674 iInFlight < 0 ? NULL : pThis->aInFlight[iInFlight].pUrb,
3675 pEd, EdAddr))
3676 {
3677 Log(("ohciR3ServiceIsochronousEndpoint: Failed unlinking old ITD.\n"));
3678 break;
3679 }
3680# endif
3681 }
3682
3683 /* advance to the next ITD */
3684 ITdAddr = ITdAddrNext;
3685 u32NextFrame = (ITd.HwInfo & ITD_HWINFO_SF) + cFrames;
3686 }
3687}
3688
3689
3690/**
3691 * Checks if a endpoints has TDs queued and is ready to have them processed.
3692 *
3693 * @returns true if it's ok to process TDs.
3694 * @param pEd The endpoint data.
3695 */
3696DECLINLINE(bool) ohciR3IsEdReady(PCOHCIED pEd)
3697{
3698 return (pEd->HeadP & ED_PTR_MASK) != (pEd->TailP & ED_PTR_MASK)
3699 && !(pEd->HeadP & ED_HEAD_HALTED)
3700 && !(pEd->hwinfo & ED_HWINFO_SKIP);
3701}
3702
3703
3704/**
3705 * Checks if an endpoint has TDs queued (not necessarily ready to have them processed).
3706 *
3707 * @returns true if endpoint may have TDs queued.
3708 * @param pEd The endpoint data.
3709 */
3710DECLINLINE(bool) ohciR3IsEdPresent(PCOHCIED pEd)
3711{
3712 return (pEd->HeadP & ED_PTR_MASK) != (pEd->TailP & ED_PTR_MASK)
3713 && !(pEd->HeadP & ED_HEAD_HALTED);
3714}
3715
3716
3717/**
3718 * Services the bulk list.
3719 *
3720 * On the bulk list we must reassemble URBs from multiple TDs using heuristics
3721 * derived from USB tracing done in the guests and guest source code (when available).
3722 */
3723static void ohciR3ServiceBulkList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
3724{
3725# ifdef LOG_ENABLED
3726 if (g_fLogBulkEPs)
3727 ohciR3DumpEdList(pDevIns, pThisCC, pThis->bulk_head, "Bulk before", true);
3728 if (pThis->bulk_cur)
3729 Log(("ohciR3ServiceBulkList: bulk_cur=%#010x before listprocessing!!! HCD have positioned us!!!\n", pThis->bulk_cur));
3730# endif
3731
3732 /*
3733 * ", HC will start processing the Bulk list and will set BF [BulkListFilled] to 0"
3734 * - We've simplified and are always starting at the head of the list and working
3735 * our way thru to the end each time.
3736 */
3737 pThis->status &= ~OHCI_STATUS_BLF;
3738 pThis->fBulkNeedsCleaning = false;
3739 pThis->bulk_cur = 0;
3740
3741 uint32_t EdAddr = pThis->bulk_head;
3742 uint32_t cIterations = 256;
3743 while (EdAddr
3744 && (pThis->ctl & OHCI_CTL_BLE)
3745 && (cIterations-- > 0))
3746 {
3747 OHCIED Ed;
3748
3749 /* Bail if previous processing ended up in the unrecoverable error state. */
3750 if (pThis->intr_status & OHCI_INTR_UNRECOVERABLE_ERROR)
3751 break;
3752
3753 ohciR3ReadEd(pDevIns, EdAddr, &Ed);
3754 Assert(!(Ed.hwinfo & ED_HWINFO_ISO)); /* the guest is screwing us */
3755 if (ohciR3IsEdReady(&Ed))
3756 {
3757 pThis->status |= OHCI_STATUS_BLF;
3758 pThis->fBulkNeedsCleaning = true;
3759
3760# if 1
3761 /*
3762
3763 * After we figured out that all the TDs submitted for dealing with MSD
3764 * read/write data really makes up on single URB, and that we must
3765 * reassemble these TDs into an URB before submitting it, there is no
3766 * longer any need for servicing anything other than the head *URB*
3767 * on a bulk endpoint.
3768 */
3769 ohciR3ServiceHeadTdMultiple(pDevIns, pThis, pThisCC, VUSBXFERTYPE_BULK, &Ed, EdAddr, "Bulk");
3770# else
3771 /*
3772 * This alternative code was used before we started reassembling URBs from
3773 * multiple TDs. We keep it handy for debugging.
3774 */
3775 uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK;
3776 if (!ohciR3IsTdInFlight(pThis, TdAddr))
3777 {
3778 do
3779 {
3780 if (!ohciR3ServiceTdMultiple(pThis, VUSBXFERTYPE_BULK, &Ed, EdAddr, TdAddr, &TdAddr, "Bulk"))
3781 {
3782 LogFlow(("ohciR3ServiceBulkList: ohciR3ServiceTdMultiple -> false\n"));
3783 break;
3784 }
3785 if ( (TdAddr & ED_PTR_MASK) == (Ed.TailP & ED_PTR_MASK)
3786 || !TdAddr /* paranoia */)
3787 {
3788 LogFlow(("ohciR3ServiceBulkList: TdAddr=%#010RX32 Ed.TailP=%#010RX32\n", TdAddr, Ed.TailP));
3789 break;
3790 }
3791
3792 ohciR3ReadEd(pDevIns, EdAddr, &Ed); /* It might have been updated on URB completion. */
3793 } while (ohciR3IsEdReady(&Ed));
3794 }
3795# endif
3796 }
3797 else
3798 {
3799 if (Ed.hwinfo & ED_HWINFO_SKIP)
3800 {
3801 LogFlow(("ohciR3ServiceBulkList: Ed=%#010RX32 Ed.TailP=%#010RX32 SKIP\n", EdAddr, Ed.TailP));
3802 /* If the ED is in 'skip' state, no transactions on it are allowed and we must
3803 * cancel outstanding URBs, if any.
3804 */
3805 uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK;
3806 PVUSBURB pUrb = ohciR3TdInFlightUrb(pThisCC, TdAddr);
3807 if (pUrb)
3808 pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb);
3809 }
3810 }
3811
3812 /* Trivial loop detection. */
3813 if (EdAddr == (Ed.NextED & ED_PTR_MASK))
3814 break;
3815 /* Proceed to the next endpoint. */
3816 EdAddr = Ed.NextED & ED_PTR_MASK;
3817 }
3818
3819# ifdef LOG_ENABLED
3820 if (g_fLogBulkEPs)
3821 ohciR3DumpEdList(pDevIns, pThisCC, pThis->bulk_head, "Bulk after ", true);
3822# endif
3823}
3824
3825
3826/**
3827 * Abort outstanding transfers on the bulk list.
3828 *
3829 * If the guest disabled bulk list processing, we must abort any outstanding transfers
3830 * (that is, cancel in-flight URBs associated with the list). This is required because
3831 * there may be outstanding read URBs that will never get a response from the device
3832 * and would block further communication.
3833 */
3834static void ohciR3UndoBulkList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
3835{
3836# ifdef LOG_ENABLED
3837 if (g_fLogBulkEPs)
3838 ohciR3DumpEdList(pDevIns, pThisCC, pThis->bulk_head, "Bulk before", true);
3839 if (pThis->bulk_cur)
3840 Log(("ohciR3UndoBulkList: bulk_cur=%#010x before list processing!!! HCD has positioned us!!!\n", pThis->bulk_cur));
3841# endif
3842
3843 /* This flag follows OHCI_STATUS_BLF, but BLF doesn't change when list processing is disabled. */
3844 pThis->fBulkNeedsCleaning = false;
3845
3846 uint32_t EdAddr = pThis->bulk_head;
3847 uint32_t cIterations = 256;
3848 while (EdAddr
3849 && (cIterations-- > 0))
3850 {
3851 OHCIED Ed;
3852
3853 ohciR3ReadEd(pDevIns, EdAddr, &Ed);
3854 Assert(!(Ed.hwinfo & ED_HWINFO_ISO)); /* the guest is screwing us */
3855 if (ohciR3IsEdPresent(&Ed))
3856 {
3857 uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK;
3858 if (ohciR3IsTdInFlight(pThisCC, TdAddr))
3859 {
3860 LogFlow(("ohciR3UndoBulkList: Ed=%#010RX32 Ed.TailP=%#010RX32 UNDO\n", EdAddr, Ed.TailP));
3861 PVUSBURB pUrb = ohciR3TdInFlightUrb(pThisCC, TdAddr);
3862 if (pUrb)
3863 pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb);
3864 }
3865 }
3866
3867 /* Trivial loop detection. */
3868 if (EdAddr == (Ed.NextED & ED_PTR_MASK))
3869 break;
3870 /* Proceed to the next endpoint. */
3871 EdAddr = Ed.NextED & ED_PTR_MASK;
3872 }
3873}
3874
3875
3876/**
3877 * Services the control list.
3878 *
3879 * The control list has complex URB assembling, but that's taken
3880 * care of at VUSB level (unlike the other transfer types).
3881 */
3882static void ohciR3ServiceCtrlList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
3883{
3884# ifdef LOG_ENABLED
3885 if (g_fLogControlEPs)
3886 ohciR3DumpEdList(pDevIns, pThisCC, pThis->ctrl_head, "Ctrl before", true);
3887 if (pThis->ctrl_cur)
3888 Log(("ohciR3ServiceCtrlList: ctrl_cur=%010x before list processing!!! HCD have positioned us!!!\n", pThis->ctrl_cur));
3889# endif
3890
3891 /*
3892 * ", HC will start processing the list and will set ControlListFilled to 0"
3893 * - We've simplified and are always starting at the head of the list and working
3894 * our way thru to the end each time.
3895 */
3896 pThis->status &= ~OHCI_STATUS_CLF;
3897 pThis->ctrl_cur = 0;
3898
3899 uint32_t EdAddr = pThis->ctrl_head;
3900 uint32_t cIterations = 256;
3901 while ( EdAddr
3902 && (pThis->ctl & OHCI_CTL_CLE)
3903 && (cIterations-- > 0))
3904 {
3905 OHCIED Ed;
3906
3907 /* Bail if previous processing ended up in the unrecoverable error state. */
3908 if (pThis->intr_status & OHCI_INTR_UNRECOVERABLE_ERROR)
3909 break;
3910
3911 ohciR3ReadEd(pDevIns, EdAddr, &Ed);
3912 Assert(!(Ed.hwinfo & ED_HWINFO_ISO)); /* the guest is screwing us */
3913 if (ohciR3IsEdReady(&Ed))
3914 {
3915# if 1
3916 /*
3917 * Control TDs depends on order and stage. Only one can be in-flight
3918 * at any given time. OTOH, some stages are completed immediately,
3919 * so we process the list until we've got a head which is in-flight
3920 * or reach the end of the list.
3921 */
3922 do
3923 {
3924 if ( !ohciR3ServiceHeadTd(pDevIns, pThis, pThisCC, VUSBXFERTYPE_CTRL, &Ed, EdAddr, "Control")
3925 || ohciR3IsTdInFlight(pThisCC, Ed.HeadP & ED_PTR_MASK))
3926 {
3927 pThis->status |= OHCI_STATUS_CLF;
3928 break;
3929 }
3930 ohciR3ReadEd(pDevIns, EdAddr, &Ed); /* It might have been updated on URB completion. */
3931 } while (ohciR3IsEdReady(&Ed));
3932# else
3933 /* Simplistic, for debugging. */
3934 ohciR3ServiceHeadTd(pThis, VUSBXFERTYPE_CTRL, &Ed, EdAddr, "Control");
3935 pThis->status |= OHCI_STATUS_CLF;
3936# endif
3937 }
3938
3939 /* Trivial loop detection. */
3940 if (EdAddr == (Ed.NextED & ED_PTR_MASK))
3941 break;
3942 /* Proceed to the next endpoint. */
3943 EdAddr = Ed.NextED & ED_PTR_MASK;
3944 }
3945
3946# ifdef LOG_ENABLED
3947 if (g_fLogControlEPs)
3948 ohciR3DumpEdList(pDevIns, pThisCC, pThis->ctrl_head, "Ctrl after ", true);
3949# endif
3950}
3951
3952
3953/**
3954 * Services the periodic list.
3955 *
3956 * On the interrupt portion of the periodic list we must reassemble URBs from multiple
3957 * TDs using heuristics derived from USB tracing done in the guests and guest source
3958 * code (when available).
3959 */
3960static void ohciR3ServicePeriodicList(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
3961{
3962 /*
3963 * Read the list head from the HCCA.
3964 */
3965 const unsigned iList = pThis->HcFmNumber % OHCI_HCCA_NUM_INTR;
3966 uint32_t EdAddr;
3967 ohciR3GetDWords(pDevIns, pThis->hcca + iList * sizeof(EdAddr), &EdAddr, 1);
3968
3969# ifdef LOG_ENABLED
3970 const uint32_t EdAddrHead = EdAddr;
3971 if (g_fLogInterruptEPs)
3972 {
3973 char sz[48];
3974 RTStrPrintf(sz, sizeof(sz), "Int%02x before", iList);
3975 ohciR3DumpEdList(pDevIns, pThisCC, EdAddrHead, sz, true);
3976 }
3977# endif
3978
3979 /*
3980 * Iterate the endpoint list.
3981 */
3982 unsigned cIterations = 128;
3983 while (EdAddr
3984 && (pThis->ctl & OHCI_CTL_PLE)
3985 && (cIterations-- > 0))
3986 {
3987 OHCIED Ed;
3988
3989 /* Bail if previous processing ended up in the unrecoverable error state. */
3990 if (pThis->intr_status & OHCI_INTR_UNRECOVERABLE_ERROR)
3991 break;
3992
3993 ohciR3ReadEd(pDevIns, EdAddr, &Ed);
3994 if (ohciR3IsEdReady(&Ed))
3995 {
3996 /*
3997 * "There is no separate head pointer of isochronous transfers. The first
3998 * isochronous Endpoint Descriptor simply links to the last interrupt
3999 * Endpoint Descriptor."
4000 */
4001 if (!(Ed.hwinfo & ED_HWINFO_ISO))
4002 {
4003 /*
4004 * Presently we will only process the head URB on an interrupt endpoint.
4005 */
4006 ohciR3ServiceHeadTdMultiple(pDevIns, pThis, pThisCC, VUSBXFERTYPE_INTR, &Ed, EdAddr, "Periodic");
4007 }
4008 else if (pThis->ctl & OHCI_CTL_IE)
4009 {
4010 /*
4011 * Presently only the head ITD.
4012 */
4013 ohciR3ServiceIsochronousEndpoint(pDevIns, pThis, pThisCC, &Ed, EdAddr);
4014 }
4015 else
4016 break;
4017 }
4018 else
4019 {
4020 if (Ed.hwinfo & ED_HWINFO_SKIP)
4021 {
4022 Log3(("ohciR3ServicePeriodicList: Ed=%#010RX32 Ed.TailP=%#010RX32 SKIP\n", EdAddr, Ed.TailP));
4023 /* If the ED is in 'skip' state, no transactions on it are allowed and we must
4024 * cancel outstanding URBs, if any.
4025 */
4026 uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK;
4027 PVUSBURB pUrb = ohciR3TdInFlightUrb(pThisCC, TdAddr);
4028 if (pUrb)
4029 pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb);
4030 }
4031 }
4032 /* Trivial loop detection. */
4033 if (EdAddr == (Ed.NextED & ED_PTR_MASK))
4034 break;
4035 /* Proceed to the next endpoint. */
4036 EdAddr = Ed.NextED & ED_PTR_MASK;
4037 }
4038
4039# ifdef LOG_ENABLED
4040 if (g_fLogInterruptEPs)
4041 {
4042 char sz[48];
4043 RTStrPrintf(sz, sizeof(sz), "Int%02x after ", iList);
4044 ohciR3DumpEdList(pDevIns, pThisCC, EdAddrHead, sz, true);
4045 }
4046# endif
4047}
4048
4049
4050/**
4051 * Update the HCCA.
4052 *
4053 * @param pDevIns The device instance.
4054 * @param pThis The OHCI controller instance data, shared edition.
4055 * @param pThisCC The OHCI controller instance data, ring-3 edition.
4056 */
4057static void ohciR3UpdateHCCA(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
4058{
4059 OCHIHCCA hcca;
4060 ohciR3PhysRead(pDevIns, pThis->hcca + OHCI_HCCA_OFS, &hcca, sizeof(hcca));
4061
4062 hcca.frame = RT_H2LE_U16((uint16_t)pThis->HcFmNumber);
4063 hcca.pad = 0;
4064
4065 bool fWriteDoneHeadInterrupt = false;
4066 if ( pThis->dqic == 0
4067 && (pThis->intr_status & OHCI_INTR_WRITE_DONE_HEAD) == 0)
4068 {
4069 uint32_t done = pThis->done;
4070
4071 if (pThis->intr_status & ~( OHCI_INTR_MASTER_INTERRUPT_ENABLED | OHCI_INTR_OWNERSHIP_CHANGE
4072 | OHCI_INTR_WRITE_DONE_HEAD) )
4073 done |= 0x1;
4074
4075 hcca.done = RT_H2LE_U32(done);
4076 pThis->done = 0;
4077 pThis->dqic = 0x7;
4078
4079 Log(("ohci: Writeback Done (%#010x) on frame %#x (age %#x)\n", hcca.done,
4080 pThis->HcFmNumber, pThis->HcFmNumber - pThisCC->u32FmDoneQueueTail));
4081# ifdef LOG_ENABLED
4082 ohciR3DumpTdQueue(pDevIns, pThisCC, hcca.done & ED_PTR_MASK, "DoneQueue");
4083# endif
4084 Assert(RT_OFFSETOF(OCHIHCCA, done) == 4);
4085# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
4086 ohciR3InDoneQueueZap(pThisCC);
4087# endif
4088 fWriteDoneHeadInterrupt = true;
4089 }
4090
4091 Log3(("ohci: Updating HCCA on frame %#x\n", pThis->HcFmNumber));
4092 ohciR3PhysWriteMeta(pDevIns, pThis->hcca + OHCI_HCCA_OFS, (uint8_t *)&hcca, sizeof(hcca));
4093 if (fWriteDoneHeadInterrupt)
4094 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_WRITE_DONE_HEAD);
4095 RT_NOREF(pThisCC);
4096}
4097
4098
4099/**
4100 * Go over the in-flight URB list and cancel any URBs that are no longer in use.
4101 * This occurs when the host removes EDs or TDs from the lists and we don't notice
4102 * the sKip bit. Such URBs must be promptly canceled, otherwise there is a risk
4103 * they might "steal" data destined for another URB.
4104 */
4105static void ohciR3CancelOrphanedURBs(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
4106{
4107 bool fValidHCCA = !( pThis->hcca >= OHCI_HCCA_MASK
4108 || pThis->hcca < ~OHCI_HCCA_MASK);
4109 unsigned i, cLeft;
4110 int j;
4111 uint32_t EdAddr;
4112 PVUSBURB pUrb;
4113
4114 /* If the HCCA is not currently valid, or there are no in-flight URBs,
4115 * there's nothing to do.
4116 */
4117 if (!fValidHCCA || !pThisCC->cInFlight)
4118 return;
4119
4120 /* Initially mark all in-flight URBs as inactive. */
4121 for (i = 0, cLeft = pThisCC->cInFlight; cLeft && i < RT_ELEMENTS(pThisCC->aInFlight); i++)
4122 {
4123 if (pThisCC->aInFlight[i].pUrb)
4124 {
4125 pThisCC->aInFlight[i].fInactive = true;
4126 cLeft--;
4127 }
4128 }
4129 Assert(cLeft == 0);
4130
4131# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
4132 /* Get hcca data to minimize calls to ohciR3GetDWords/PDMDevHlpPCIPhysRead. */
4133 uint32_t au32HCCA[OHCI_HCCA_NUM_INTR];
4134 ohciR3GetDWords(pDevIns, pThis->hcca, au32HCCA, OHCI_HCCA_NUM_INTR);
4135# endif
4136
4137 /* Go over all bulk/control/interrupt endpoint lists; any URB found in these lists
4138 * is marked as active again.
4139 */
4140 for (i = 0; i < OHCI_HCCA_NUM_INTR + 2; i++)
4141 {
4142 switch (i)
4143 {
4144 case OHCI_HCCA_NUM_INTR:
4145 EdAddr = pThis->bulk_head;
4146 break;
4147 case OHCI_HCCA_NUM_INTR + 1:
4148 EdAddr = pThis->ctrl_head;
4149 break;
4150 default:
4151# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
4152 EdAddr = au32HCCA[i];
4153# else
4154 ohciR3GetDWords(pDevIns, pThis->hcca + i * sizeof(EdAddr), &EdAddr, 1);
4155# endif
4156 break;
4157 }
4158
4159 unsigned cIterED = 128;
4160 while ( EdAddr
4161 && (cIterED-- > 0))
4162 {
4163 OHCIED Ed;
4164 OHCITD Td;
4165
4166 ohciR3ReadEd(pDevIns, EdAddr, &Ed);
4167 uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK;
4168 uint32_t TailP = Ed.TailP & ED_PTR_MASK;
4169 unsigned cIterTD = 0;
4170 if ( !(Ed.hwinfo & ED_HWINFO_SKIP)
4171 && (TdAddr != TailP))
4172 {
4173# ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
4174 ohciR3PhysReadCacheInvalidate(&pThisCC->CacheTD);
4175# endif
4176 do
4177 {
4178 ohciR3ReadTd(pDevIns, TdAddr, &Td);
4179 j = ohciR3InFlightFind(pThisCC, TdAddr);
4180 if (j > -1)
4181 pThisCC->aInFlight[j].fInactive = false;
4182 TdAddr = Td.NextTD & ED_PTR_MASK;
4183 /* See #8125.
4184 * Sometimes the ED is changed by the guest between ohciR3ReadEd above and here.
4185 * Then the code reads TD pointed by the new TailP, which is not allowed.
4186 * Luckily Windows guests have Td.NextTD = 0 in the tail TD.
4187 * Also having a real TD at 0 is very unlikely.
4188 * So do not continue.
4189 */
4190 if (TdAddr == 0)
4191 break;
4192 /* Failsafe for temporarily looped lists. */
4193 if (++cIterTD == 128)
4194 break;
4195 } while (TdAddr != (Ed.TailP & ED_PTR_MASK));
4196 }
4197 /* Trivial loop detection. */
4198 if (EdAddr == (Ed.NextED & ED_PTR_MASK))
4199 break;
4200 /* Proceed to the next endpoint. */
4201 EdAddr = Ed.NextED & ED_PTR_MASK;
4202 }
4203 }
4204
4205 /* In-flight URBs still marked as inactive are not used anymore and need
4206 * to be canceled.
4207 */
4208 for (i = 0, cLeft = pThisCC->cInFlight; cLeft && i < RT_ELEMENTS(pThisCC->aInFlight); i++)
4209 {
4210 if (pThisCC->aInFlight[i].pUrb)
4211 {
4212 cLeft--;
4213 pUrb = pThisCC->aInFlight[i].pUrb;
4214 if ( pThisCC->aInFlight[i].fInactive
4215 && pUrb->enmState == VUSBURBSTATE_IN_FLIGHT
4216 && pUrb->enmType != VUSBXFERTYPE_CTRL)
4217 pThisCC->RootHub.pIRhConn->pfnCancelUrbsEp(pThisCC->RootHub.pIRhConn, pUrb);
4218 }
4219 }
4220 Assert(cLeft == 0);
4221}
4222
4223
4224/**
4225 * Generate a Start-Of-Frame event, and set a timer for End-Of-Frame.
4226 */
4227static void ohciR3StartOfFrame(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
4228{
4229# ifdef LOG_ENABLED
4230 const uint32_t status_old = pThis->status;
4231# endif
4232
4233 /*
4234 * Update HcFmRemaining.FRT and update start of frame time.
4235 */
4236 pThis->frt = pThis->fit;
4237 pThis->SofTime += pThis->cTicksPerFrame;
4238
4239 /*
4240 * Check that the HCCA address isn't bogus. Linux 2.4.x is known to start
4241 * the bus with a hcca of 0 to work around problem with a specific controller.
4242 */
4243 bool fValidHCCA = !( pThis->hcca >= OHCI_HCCA_MASK
4244 || pThis->hcca < ~OHCI_HCCA_MASK);
4245
4246# if 1
4247 /*
4248 * Update the HCCA.
4249 * Should be done after SOF but before HC read first ED in this frame.
4250 */
4251 if (fValidHCCA)
4252 ohciR3UpdateHCCA(pDevIns, pThis, pThisCC);
4253# endif
4254
4255 /* "After writing to HCCA, HC will set SF in HcInterruptStatus" - guest isn't executing, so ignore the order! */
4256 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_START_OF_FRAME);
4257
4258 if (pThis->fno)
4259 {
4260 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_FRAMENUMBER_OVERFLOW);
4261 pThis->fno = 0;
4262 }
4263
4264 /* If the HCCA address is invalid, we're quitting here to avoid doing something which cannot be reported to the HCD. */
4265 if (!fValidHCCA)
4266 {
4267 Log(("ohciR3StartOfFrame: skipping hcca part because hcca=%RX32 (our 'valid' range: %RX32-%RX32)\n",
4268 pThis->hcca, ~OHCI_HCCA_MASK, OHCI_HCCA_MASK));
4269 return;
4270 }
4271
4272 /*
4273 * Periodic EPs.
4274 */
4275 if (pThis->ctl & OHCI_CTL_PLE)
4276 ohciR3ServicePeriodicList(pDevIns, pThis, pThisCC);
4277
4278 /*
4279 * Control EPs.
4280 */
4281 if ( (pThis->ctl & OHCI_CTL_CLE)
4282 && (pThis->status & OHCI_STATUS_CLF) )
4283 ohciR3ServiceCtrlList(pDevIns, pThis, pThisCC);
4284
4285 /*
4286 * Bulk EPs.
4287 */
4288 if ( (pThis->ctl & OHCI_CTL_BLE)
4289 && (pThis->status & OHCI_STATUS_BLF))
4290 ohciR3ServiceBulkList(pDevIns, pThis, pThisCC);
4291 else if ((pThis->status & OHCI_STATUS_BLF)
4292 && pThis->fBulkNeedsCleaning)
4293 ohciR3UndoBulkList(pDevIns, pThis, pThisCC); /* If list disabled but not empty, abort endpoints. */
4294
4295# if 0
4296 /*
4297 * Update the HCCA after processing the lists and everything. A bit experimental.
4298 *
4299 * ASSUME the guest won't be very upset if a TD is completed, retired and handed
4300 * back immediately. The idea is to be able to retire the data and/or status stages
4301 * of a control transfer together with the setup stage, thus saving a frame. This
4302 * behaviour is should be perfectly ok, since the setup (and maybe data) stages
4303 * have already taken at least one frame to complete.
4304 *
4305 * But, when implementing the first synchronous virtual USB devices, we'll have to
4306 * verify that the guest doesn't choke when having a TD returned in the same frame
4307 * as it was submitted.
4308 */
4309 ohciR3UpdateHCCA(pThis);
4310# endif
4311
4312# ifdef LOG_ENABLED
4313 if (pThis->status ^ status_old)
4314 {
4315 uint32_t val = pThis->status;
4316 uint32_t chg = val ^ status_old; NOREF(chg);
4317 Log2(("ohciR3StartOfFrame: HcCommandStatus=%#010x: %sHCR=%d %sCLF=%d %sBLF=%d %sOCR=%d %sSOC=%d\n",
4318 val,
4319 chg & RT_BIT(0) ? "*" : "", val & 1,
4320 chg & RT_BIT(1) ? "*" : "", (val >> 1) & 1,
4321 chg & RT_BIT(2) ? "*" : "", (val >> 2) & 1,
4322 chg & RT_BIT(3) ? "*" : "", (val >> 3) & 1,
4323 chg & (3<<16)? "*" : "", (val >> 16) & 3));
4324 }
4325# endif
4326}
4327
4328
4329/**
4330 * Updates the HcFmNumber and FNO registers.
4331 */
4332static void ohciR3BumpFrameNumber(POHCI pThis)
4333{
4334 const uint16_t u16OldFmNumber = pThis->HcFmNumber++;
4335 if ((u16OldFmNumber ^ pThis->HcFmNumber) & RT_BIT(15))
4336 pThis->fno = 1;
4337}
4338
4339
4340/**
4341 * Callback for periodic frame processing.
4342 */
4343static DECLCALLBACK(bool) ohciR3StartFrame(PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo)
4344{
4345 RT_NOREF(u32FrameNo);
4346 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
4347 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
4348 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
4349
4350 ohciR3Lock(pThisCC);
4351
4352 /* Reset idle detection flag */
4353 pThis->fIdle = true;
4354
4355# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
4356 physReadStatsReset(&g_PhysReadState);
4357# endif
4358
4359 if (!(pThis->intr_status & OHCI_INTR_UNRECOVERABLE_ERROR))
4360 {
4361 /* Frame boundary, so do EOF stuff here. */
4362 ohciR3BumpFrameNumber(pThis);
4363 if ( (pThis->dqic != 0x7) && (pThis->dqic != 0))
4364 pThis->dqic--;
4365
4366 /* Clean up any URBs that have been removed. */
4367 ohciR3CancelOrphanedURBs(pDevIns, pThis, pThisCC);
4368
4369 /* Start the next frame. */
4370 ohciR3StartOfFrame(pDevIns, pThis, pThisCC);
4371 }
4372
4373# ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
4374 physReadStatsPrint(&g_PhysReadState);
4375# endif
4376
4377 ohciR3Unlock(pThisCC);
4378 return pThis->fIdle;
4379}
4380
4381
4382/**
4383 * @interface_method_impl{VUSBIROOTHUBPORT,pfnFrameRateChanged}
4384 */
4385static DECLCALLBACK(void) ohciR3FrameRateChanged(PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate)
4386{
4387 POHCICC pThisCC = VUSBIROOTHUBPORT_2_OHCI(pInterface);
4388 PPDMDEVINS pDevIns = pThisCC->pDevInsR3;
4389 POHCI pThis = PDMDEVINS_2_DATA(pDevIns, POHCI);
4390
4391 Assert(u32FrameRate <= OHCI_DEFAULT_TIMER_FREQ);
4392
4393 pThis->cTicksPerFrame = pThis->u64TimerHz / u32FrameRate;
4394 if (!pThis->cTicksPerFrame)
4395 pThis->cTicksPerFrame = 1;
4396 pThis->cTicksPerUsbTick = pThis->u64TimerHz >= VUSB_BUS_HZ ? pThis->u64TimerHz / VUSB_BUS_HZ : 1;
4397}
4398
4399
4400/**
4401 * Start sending SOF tokens across the USB bus, lists are processed in
4402 * next frame
4403 */
4404static void ohciR3BusStart(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC)
4405{
4406 pThisCC->RootHub.pIRhConn->pfnPowerOn(pThisCC->RootHub.pIRhConn);
4407 pThis->dqic = 0x7;
4408
4409 Log(("ohci: Bus started\n"));
4410
4411 pThis->SofTime = PDMDevHlpTMTimeVirtGet(pDevIns);
4412 int rc = pThisCC->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThisCC->RootHub.pIRhConn, OHCI_DEFAULT_TIMER_FREQ);
4413 AssertRC(rc);
4414}
4415
4416
4417/**
4418 * Stop sending SOF tokens on the bus
4419 */
4420static void ohciR3BusStop(POHCICC pThisCC)
4421{
4422 int rc = pThisCC->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThisCC->RootHub.pIRhConn, 0);
4423 AssertRC(rc);
4424 pThisCC->RootHub.pIRhConn->pfnPowerOff(pThisCC->RootHub.pIRhConn);
4425}
4426
4427
4428/**
4429 * Move in to resume state
4430 */
4431static void ohciR3BusResume(PPDMDEVINS pDevIns, POHCI pThis, POHCICC pThisCC, bool fHardware)
4432{
4433 pThis->ctl &= ~OHCI_CTL_HCFS;
4434 pThis->ctl |= OHCI_USB_RESUME;
4435
4436 LogFunc(("fHardware=%RTbool RWE=%s\n",
4437 fHardware, (pThis->ctl & OHCI_CTL_RWE) ? "on" : "off"));
4438
4439 if (fHardware && (pThis->ctl & OHCI_CTL_RWE))
4440 ohciR3SetInterrupt(pDevIns, pThis, OHCI_INTR_RESUME_DETECT);
4441
4442 ohciR3BusStart(pDevIns, pThis, pThisCC);
4443}
4444
4445
4446/* Power a port up or down */
4447static void ohciR3RhPortPower(POHCIROOTHUBR3 pRh, unsigned iPort, bool fPowerUp)
4448{
4449 POHCIHUBPORT pPort = &pRh->aPorts[iPort];
4450 bool fOldPPS = !!(pPort->fReg & OHCI_PORT_PPS);
4451
4452 LogFlowFunc(("iPort=%u fPowerUp=%RTbool\n", iPort, fPowerUp));
4453
4454 if (fPowerUp)
4455 {
4456 /* power up */
4457 if (pPort->fAttached)
4458 pPort->fReg |= OHCI_PORT_CCS;
4459 if (pPort->fReg & OHCI_PORT_CCS)
4460 pPort->fReg |= OHCI_PORT_PPS;
4461 if (pPort->fAttached && !fOldPPS)
4462 VUSBIRhDevPowerOn(pRh->pIRhConn, OHCI_PORT_2_VUSB_PORT(iPort));
4463 }
4464 else
4465 {
4466 /* power down */
4467 pPort->fReg &= ~(OHCI_PORT_PPS | OHCI_PORT_CCS | OHCI_PORT_PSS | OHCI_PORT_PRS);
4468 if (pPort->fAttached && fOldPPS)
4469 VUSBIRhDevPowerOff(pRh->pIRhConn, OHCI_PORT_2_VUSB_PORT(iPort));
4470 }
4471}
4472
4473#endif /* IN_RING3 */
4474
4475/**
4476 * Read the HcRevision register.
4477 */
4478static VBOXSTRICTRC HcRevision_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4479{
4480 RT_NOREF(pDevIns, pThis, iReg);
4481 Log2(("HcRevision_r() -> 0x10\n"));
4482 *pu32Value = 0x10; /* OHCI revision 1.0, no emulation. */
4483 return VINF_SUCCESS;
4484}
4485
4486/**
4487 * Write to the HcRevision register.
4488 */
4489static VBOXSTRICTRC HcRevision_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t u32Value)
4490{
4491 RT_NOREF(pDevIns, pThis, iReg, u32Value);
4492 Log2(("HcRevision_w(%#010x) - denied\n", u32Value));
4493 ASSERT_GUEST_MSG_FAILED(("Invalid operation!!! u32Value=%#010x\n", u32Value));
4494 return VINF_SUCCESS;
4495}
4496
4497/**
4498 * Read the HcControl register.
4499 */
4500static VBOXSTRICTRC HcControl_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4501{
4502 RT_NOREF(pDevIns, iReg);
4503 uint32_t ctl = pThis->ctl;
4504 Log2(("HcControl_r -> %#010x - CBSR=%d PLE=%d IE=%d CLE=%d BLE=%d HCFS=%#x IR=%d RWC=%d RWE=%d\n",
4505 ctl, ctl & 3, (ctl >> 2) & 1, (ctl >> 3) & 1, (ctl >> 4) & 1, (ctl >> 5) & 1, (ctl >> 6) & 3, (ctl >> 8) & 1,
4506 (ctl >> 9) & 1, (ctl >> 10) & 1));
4507 *pu32Value = ctl;
4508 return VINF_SUCCESS;
4509}
4510
4511/**
4512 * Write the HcControl register.
4513 */
4514static VBOXSTRICTRC HcControl_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4515{
4516 RT_NOREF(iReg);
4517
4518 /* log it. */
4519 uint32_t chg = pThis->ctl ^ val; NOREF(chg);
4520 Log2(("HcControl_w(%#010x) => %sCBSR=%d %sPLE=%d %sIE=%d %sCLE=%d %sBLE=%d %sHCFS=%#x %sIR=%d %sRWC=%d %sRWE=%d\n",
4521 val,
4522 chg & 3 ? "*" : "", val & 3,
4523 chg & RT_BIT(2) ? "*" : "", (val >> 2) & 1,
4524 chg & RT_BIT(3) ? "*" : "", (val >> 3) & 1,
4525 chg & RT_BIT(4) ? "*" : "", (val >> 4) & 1,
4526 chg & RT_BIT(5) ? "*" : "", (val >> 5) & 1,
4527 chg & (3 << 6)? "*" : "", (val >> 6) & 3,
4528 chg & RT_BIT(8) ? "*" : "", (val >> 8) & 1,
4529 chg & RT_BIT(9) ? "*" : "", (val >> 9) & 1,
4530 chg & RT_BIT(10) ? "*" : "", (val >> 10) & 1));
4531 if (val & ~0x07ff)
4532 Log2(("Unknown bits %#x are set!!!\n", val & ~0x07ff));
4533
4534 /* see what changed and take action on that. */
4535 uint32_t old_state = pThis->ctl & OHCI_CTL_HCFS;
4536 uint32_t new_state = val & OHCI_CTL_HCFS;
4537
4538#ifdef IN_RING3
4539 pThis->ctl = val;
4540 if (new_state != old_state)
4541 {
4542 POHCICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, POHCICC);
4543 switch (new_state)
4544 {
4545 case OHCI_USB_OPERATIONAL:
4546 LogRel(("OHCI: USB Operational\n"));
4547 ohciR3BusStart(pDevIns, pThis, pThisCC);
4548 break;
4549 case OHCI_USB_SUSPEND:
4550 ohciR3BusStop(pThisCC);
4551 LogRel(("OHCI: USB Suspended\n"));
4552 break;
4553 case OHCI_USB_RESUME:
4554 LogRel(("OHCI: USB Resume\n"));
4555 ohciR3BusResume(pDevIns, pThis, pThisCC, false /* not hardware */);
4556 break;
4557 case OHCI_USB_RESET:
4558 {
4559 LogRel(("OHCI: USB Reset\n"));
4560 ohciR3BusStop(pThisCC);
4561 /** @todo This should probably do a real reset, but we don't implement
4562 * that correctly in the roothub reset callback yet. check it's
4563 * comments and argument for more details. */
4564 pThisCC->RootHub.pIRhConn->pfnReset(pThisCC->RootHub.pIRhConn, false /* don't do a real reset */);
4565 break;
4566 }
4567 }
4568 }
4569#else /* !IN_RING3 */
4570 RT_NOREF(pDevIns);
4571 if ( new_state != old_state )
4572 {
4573 Log2(("HcControl_w: state changed -> VINF_IOM_R3_MMIO_WRITE\n"));
4574 return VINF_IOM_R3_MMIO_WRITE;
4575 }
4576 pThis->ctl = val;
4577#endif /* !IN_RING3 */
4578
4579 return VINF_SUCCESS;
4580}
4581
4582/**
4583 * Read the HcCommandStatus register.
4584 */
4585static VBOXSTRICTRC HcCommandStatus_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4586{
4587 uint32_t status = pThis->status;
4588 Log2(("HcCommandStatus_r() -> %#010x - HCR=%d CLF=%d BLF=%d OCR=%d SOC=%d\n",
4589 status, status & 1, (status >> 1) & 1, (status >> 2) & 1, (status >> 3) & 1, (status >> 16) & 3));
4590 *pu32Value = status;
4591 RT_NOREF(pDevIns, iReg);
4592 return VINF_SUCCESS;
4593}
4594
4595/**
4596 * Write to the HcCommandStatus register.
4597 */
4598static VBOXSTRICTRC HcCommandStatus_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4599{
4600 RT_NOREF(pDevIns, iReg);
4601
4602 /* log */
4603 uint32_t chg = pThis->status ^ val; NOREF(chg);
4604 Log2(("HcCommandStatus_w(%#010x) => %sHCR=%d %sCLF=%d %sBLF=%d %sOCR=%d %sSOC=%d\n",
4605 val,
4606 chg & RT_BIT(0) ? "*" : "", val & 1,
4607 chg & RT_BIT(1) ? "*" : "", (val >> 1) & 1,
4608 chg & RT_BIT(2) ? "*" : "", (val >> 2) & 1,
4609 chg & RT_BIT(3) ? "*" : "", (val >> 3) & 1,
4610 chg & (3<<16)? "!!!":"", (pThis->status >> 16) & 3));
4611 if (val & ~0x0003000f)
4612 Log2(("Unknown bits %#x are set!!!\n", val & ~0x0003000f));
4613
4614 /* SOC is read-only */
4615 val = (val & ~OHCI_STATUS_SOC);
4616
4617#ifdef IN_RING3
4618 /* "bits written as '0' remain unchanged in the register" */
4619 pThis->status |= val;
4620 if (pThis->status & OHCI_STATUS_HCR)
4621 {
4622 LogRel(("OHCI: Software reset\n"));
4623 ohciR3DoReset(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, POHCICC), OHCI_USB_SUSPEND, false /* N/A */);
4624 }
4625#else
4626 if ((pThis->status | val) & OHCI_STATUS_HCR)
4627 {
4628 LogFlow(("HcCommandStatus_w: reset -> VINF_IOM_R3_MMIO_WRITE\n"));
4629 return VINF_IOM_R3_MMIO_WRITE;
4630 }
4631 pThis->status |= val;
4632#endif
4633 return VINF_SUCCESS;
4634}
4635
4636/**
4637 * Read the HcInterruptStatus register.
4638 */
4639static VBOXSTRICTRC HcInterruptStatus_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4640{
4641 uint32_t val = pThis->intr_status;
4642 Log2(("HcInterruptStatus_r() -> %#010x - SO=%d WDH=%d SF=%d RD=%d UE=%d FNO=%d RHSC=%d OC=%d\n",
4643 val, val & 1, (val >> 1) & 1, (val >> 2) & 1, (val >> 3) & 1, (val >> 4) & 1, (val >> 5) & 1,
4644 (val >> 6) & 1, (val >> 30) & 1));
4645 *pu32Value = val;
4646 RT_NOREF(pDevIns, iReg);
4647 return VINF_SUCCESS;
4648}
4649
4650/**
4651 * Write to the HcInterruptStatus register.
4652 */
4653static VBOXSTRICTRC HcInterruptStatus_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4654{
4655 RT_NOREF(iReg);
4656
4657 uint32_t res = pThis->intr_status & ~val;
4658 uint32_t chg = pThis->intr_status ^ res; NOREF(chg);
4659
4660 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CsIrq, VINF_IOM_R3_MMIO_WRITE);
4661 if (rc != VINF_SUCCESS)
4662 return rc;
4663
4664 Log2(("HcInterruptStatus_w(%#010x) => %sSO=%d %sWDH=%d %sSF=%d %sRD=%d %sUE=%d %sFNO=%d %sRHSC=%d %sOC=%d\n",
4665 val,
4666 chg & RT_BIT(0) ? "*" : "", res & 1,
4667 chg & RT_BIT(1) ? "*" : "", (res >> 1) & 1,
4668 chg & RT_BIT(2) ? "*" : "", (res >> 2) & 1,
4669 chg & RT_BIT(3) ? "*" : "", (res >> 3) & 1,
4670 chg & RT_BIT(4) ? "*" : "", (res >> 4) & 1,
4671 chg & RT_BIT(5) ? "*" : "", (res >> 5) & 1,
4672 chg & RT_BIT(6) ? "*" : "", (res >> 6) & 1,
4673 chg & RT_BIT(30)? "*" : "", (res >> 30) & 1));
4674 if ( (val & ~0xc000007f)
4675 && val != 0xffffffff /* ignore clear-all-like requests from xp. */)
4676 Log2(("Unknown bits %#x are set!!!\n", val & ~0xc000007f));
4677
4678 /* "The Host Controller Driver may clear specific bits in this
4679 * register by writing '1' to bit positions to be cleared"
4680 */
4681 pThis->intr_status &= ~val;
4682 ohciUpdateInterruptLocked(pDevIns, pThis, "HcInterruptStatus_w");
4683 PDMDevHlpCritSectLeave(pDevIns, &pThis->CsIrq);
4684 return VINF_SUCCESS;
4685}
4686
4687/**
4688 * Read the HcInterruptEnable register
4689 */
4690static VBOXSTRICTRC HcInterruptEnable_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4691{
4692 uint32_t val = pThis->intr;
4693 Log2(("HcInterruptEnable_r() -> %#010x - SO=%d WDH=%d SF=%d RD=%d UE=%d FNO=%d RHSC=%d OC=%d MIE=%d\n",
4694 val, val & 1, (val >> 1) & 1, (val >> 2) & 1, (val >> 3) & 1, (val >> 4) & 1, (val >> 5) & 1,
4695 (val >> 6) & 1, (val >> 30) & 1, (val >> 31) & 1));
4696 *pu32Value = val;
4697 RT_NOREF(pDevIns, iReg);
4698 return VINF_SUCCESS;
4699}
4700
4701/**
4702 * Writes to the HcInterruptEnable register.
4703 */
4704static VBOXSTRICTRC HcInterruptEnable_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4705{
4706 RT_NOREF(iReg);
4707 uint32_t res = pThis->intr | val;
4708 uint32_t chg = pThis->intr ^ res; NOREF(chg);
4709
4710 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CsIrq, VINF_IOM_R3_MMIO_WRITE);
4711 if (rc != VINF_SUCCESS)
4712 return rc;
4713
4714 Log2(("HcInterruptEnable_w(%#010x) => %sSO=%d %sWDH=%d %sSF=%d %sRD=%d %sUE=%d %sFNO=%d %sRHSC=%d %sOC=%d %sMIE=%d\n",
4715 val,
4716 chg & RT_BIT(0) ? "*" : "", res & 1,
4717 chg & RT_BIT(1) ? "*" : "", (res >> 1) & 1,
4718 chg & RT_BIT(2) ? "*" : "", (res >> 2) & 1,
4719 chg & RT_BIT(3) ? "*" : "", (res >> 3) & 1,
4720 chg & RT_BIT(4) ? "*" : "", (res >> 4) & 1,
4721 chg & RT_BIT(5) ? "*" : "", (res >> 5) & 1,
4722 chg & RT_BIT(6) ? "*" : "", (res >> 6) & 1,
4723 chg & RT_BIT(30) ? "*" : "", (res >> 30) & 1,
4724 chg & RT_BIT(31) ? "*" : "", (res >> 31) & 1));
4725 if (val & ~0xc000007f)
4726 Log2(("Uknown bits %#x are set!!!\n", val & ~0xc000007f));
4727
4728 pThis->intr |= val;
4729 ohciUpdateInterruptLocked(pDevIns, pThis, "HcInterruptEnable_w");
4730 PDMDevHlpCritSectLeave(pDevIns, &pThis->CsIrq);
4731 return VINF_SUCCESS;
4732}
4733
4734/**
4735 * Reads the HcInterruptDisable register.
4736 */
4737static VBOXSTRICTRC HcInterruptDisable_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4738{
4739#if 1 /** @todo r=bird: "On read, the current value of the HcInterruptEnable register is returned." */
4740 uint32_t val = pThis->intr;
4741#else /* old code. */
4742 uint32_t val = ~pThis->intr;
4743#endif
4744 Log2(("HcInterruptDisable_r() -> %#010x - SO=%d WDH=%d SF=%d RD=%d UE=%d FNO=%d RHSC=%d OC=%d MIE=%d\n",
4745 val, val & 1, (val >> 1) & 1, (val >> 2) & 1, (val >> 3) & 1, (val >> 4) & 1, (val >> 5) & 1,
4746 (val >> 6) & 1, (val >> 30) & 1, (val >> 31) & 1));
4747
4748 *pu32Value = val;
4749 RT_NOREF(pDevIns, iReg);
4750 return VINF_SUCCESS;
4751}
4752
4753/**
4754 * Writes to the HcInterruptDisable register.
4755 */
4756static VBOXSTRICTRC HcInterruptDisable_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4757{
4758 RT_NOREF(iReg);
4759 uint32_t res = pThis->intr & ~val;
4760 uint32_t chg = pThis->intr ^ res; NOREF(chg);
4761
4762 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CsIrq, VINF_IOM_R3_MMIO_WRITE);
4763 if (rc != VINF_SUCCESS)
4764 return rc;
4765
4766 Log2(("HcInterruptDisable_w(%#010x) => %sSO=%d %sWDH=%d %sSF=%d %sRD=%d %sUE=%d %sFNO=%d %sRHSC=%d %sOC=%d %sMIE=%d\n",
4767 val,
4768 chg & RT_BIT(0) ? "*" : "", res & 1,
4769 chg & RT_BIT(1) ? "*" : "", (res >> 1) & 1,
4770 chg & RT_BIT(2) ? "*" : "", (res >> 2) & 1,
4771 chg & RT_BIT(3) ? "*" : "", (res >> 3) & 1,
4772 chg & RT_BIT(4) ? "*" : "", (res >> 4) & 1,
4773 chg & RT_BIT(5) ? "*" : "", (res >> 5) & 1,
4774 chg & RT_BIT(6) ? "*" : "", (res >> 6) & 1,
4775 chg & RT_BIT(30) ? "*" : "", (res >> 30) & 1,
4776 chg & RT_BIT(31) ? "*" : "", (res >> 31) & 1));
4777 /* Don't bitch about invalid bits here since it makes sense to disable
4778 * interrupts you don't know about. */
4779
4780 pThis->intr &= ~val;
4781 ohciUpdateInterruptLocked(pDevIns, pThis, "HcInterruptDisable_w");
4782 PDMDevHlpCritSectLeave(pDevIns, &pThis->CsIrq);
4783 return VINF_SUCCESS;
4784}
4785
4786/**
4787 * Read the HcHCCA register (Host Controller Communications Area physical address).
4788 */
4789static VBOXSTRICTRC HcHCCA_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4790{
4791 Log2(("HcHCCA_r() -> %#010x\n", pThis->hcca));
4792 *pu32Value = pThis->hcca;
4793 RT_NOREF(pDevIns, iReg);
4794 return VINF_SUCCESS;
4795}
4796
4797/**
4798 * Write to the HcHCCA register (Host Controller Communications Area physical address).
4799 */
4800static VBOXSTRICTRC HcHCCA_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t Value)
4801{
4802 Log2(("HcHCCA_w(%#010x) - old=%#010x new=%#010x\n", Value, pThis->hcca, Value & OHCI_HCCA_MASK));
4803 pThis->hcca = Value & OHCI_HCCA_MASK;
4804 RT_NOREF(pDevIns, iReg);
4805 return VINF_SUCCESS;
4806}
4807
4808/**
4809 * Read the HcPeriodCurrentED register.
4810 */
4811static VBOXSTRICTRC HcPeriodCurrentED_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4812{
4813 Log2(("HcPeriodCurrentED_r() -> %#010x\n", pThis->per_cur));
4814 *pu32Value = pThis->per_cur;
4815 RT_NOREF(pDevIns, iReg);
4816 return VINF_SUCCESS;
4817}
4818
4819/**
4820 * Write to the HcPeriodCurrentED register.
4821 */
4822static VBOXSTRICTRC HcPeriodCurrentED_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4823{
4824 Log(("HcPeriodCurrentED_w(%#010x) - old=%#010x new=%#010x (This is a read only register, only the linux guys don't respect that!)\n",
4825 val, pThis->per_cur, val & ~7));
4826 //AssertMsgFailed(("HCD (Host Controller Driver) should not write to HcPeriodCurrentED! val=%#010x (old=%#010x)\n", val, pThis->per_cur));
4827 AssertMsg(!(val & 7), ("Invalid alignment, val=%#010x\n", val));
4828 pThis->per_cur = val & ~7;
4829 RT_NOREF(pDevIns, iReg);
4830 return VINF_SUCCESS;
4831}
4832
4833/**
4834 * Read the HcControlHeadED register.
4835 */
4836static VBOXSTRICTRC HcControlHeadED_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4837{
4838 Log2(("HcControlHeadED_r() -> %#010x\n", pThis->ctrl_head));
4839 *pu32Value = pThis->ctrl_head;
4840 RT_NOREF(pDevIns, iReg);
4841 return VINF_SUCCESS;
4842}
4843
4844/**
4845 * Write to the HcControlHeadED register.
4846 */
4847static VBOXSTRICTRC HcControlHeadED_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4848{
4849 Log2(("HcControlHeadED_w(%#010x) - old=%#010x new=%#010x\n", val, pThis->ctrl_head, val & ~7));
4850 AssertMsg(!(val & 7), ("Invalid alignment, val=%#010x\n", val));
4851 pThis->ctrl_head = val & ~7;
4852 RT_NOREF(pDevIns, iReg);
4853 return VINF_SUCCESS;
4854}
4855
4856/**
4857 * Read the HcControlCurrentED register.
4858 */
4859static VBOXSTRICTRC HcControlCurrentED_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4860{
4861 Log2(("HcControlCurrentED_r() -> %#010x\n", pThis->ctrl_cur));
4862 *pu32Value = pThis->ctrl_cur;
4863 RT_NOREF(pDevIns, iReg);
4864 return VINF_SUCCESS;
4865}
4866
4867/**
4868 * Write to the HcControlCurrentED register.
4869 */
4870static VBOXSTRICTRC HcControlCurrentED_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4871{
4872 Log2(("HcControlCurrentED_w(%#010x) - old=%#010x new=%#010x\n", val, pThis->ctrl_cur, val & ~7));
4873 AssertMsg(!(pThis->ctl & OHCI_CTL_CLE), ("Illegal write! HcControl.ControlListEnabled is set! val=%#010x\n", val));
4874 AssertMsg(!(val & 7), ("Invalid alignment, val=%#010x\n", val));
4875 pThis->ctrl_cur = val & ~7;
4876 RT_NOREF(pDevIns, iReg);
4877 return VINF_SUCCESS;
4878}
4879
4880/**
4881 * Read the HcBulkHeadED register.
4882 */
4883static VBOXSTRICTRC HcBulkHeadED_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4884{
4885 Log2(("HcBulkHeadED_r() -> %#010x\n", pThis->bulk_head));
4886 *pu32Value = pThis->bulk_head;
4887 RT_NOREF(pDevIns, iReg);
4888 return VINF_SUCCESS;
4889}
4890
4891/**
4892 * Write to the HcBulkHeadED register.
4893 */
4894static VBOXSTRICTRC HcBulkHeadED_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4895{
4896 Log2(("HcBulkHeadED_w(%#010x) - old=%#010x new=%#010x\n", val, pThis->bulk_head, val & ~7));
4897 AssertMsg(!(val & 7), ("Invalid alignment, val=%#010x\n", val));
4898 pThis->bulk_head = val & ~7; /** @todo The ATI OHCI controller on my machine enforces 16-byte address alignment. */
4899 RT_NOREF(pDevIns, iReg);
4900 return VINF_SUCCESS;
4901}
4902
4903/**
4904 * Read the HcBulkCurrentED register.
4905 */
4906static VBOXSTRICTRC HcBulkCurrentED_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4907{
4908 Log2(("HcBulkCurrentED_r() -> %#010x\n", pThis->bulk_cur));
4909 *pu32Value = pThis->bulk_cur;
4910 RT_NOREF(pDevIns, iReg);
4911 return VINF_SUCCESS;
4912}
4913
4914/**
4915 * Write to the HcBulkCurrentED register.
4916 */
4917static VBOXSTRICTRC HcBulkCurrentED_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4918{
4919 Log2(("HcBulkCurrentED_w(%#010x) - old=%#010x new=%#010x\n", val, pThis->bulk_cur, val & ~7));
4920 AssertMsg(!(pThis->ctl & OHCI_CTL_BLE), ("Illegal write! HcControl.BulkListEnabled is set! val=%#010x\n", val));
4921 AssertMsg(!(val & 7), ("Invalid alignment, val=%#010x\n", val));
4922 pThis->bulk_cur = val & ~7;
4923 RT_NOREF(pDevIns, iReg);
4924 return VINF_SUCCESS;
4925}
4926
4927
4928/**
4929 * Read the HcDoneHead register.
4930 */
4931static VBOXSTRICTRC HcDoneHead_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4932{
4933 Log2(("HcDoneHead_r() -> 0x%#08x\n", pThis->done));
4934 *pu32Value = pThis->done;
4935 RT_NOREF(pDevIns, iReg);
4936 return VINF_SUCCESS;
4937}
4938
4939/**
4940 * Write to the HcDoneHead register.
4941 */
4942static VBOXSTRICTRC HcDoneHead_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4943{
4944 RT_NOREF(pDevIns, pThis, iReg, val);
4945 Log2(("HcDoneHead_w(0x%#08x) - denied!!!\n", val));
4946 /*AssertMsgFailed(("Illegal operation!!! val=%#010x\n", val)); - OS/2 does this */
4947 return VINF_SUCCESS;
4948}
4949
4950
4951/**
4952 * Read the HcFmInterval (Fm=Frame) register.
4953 */
4954static VBOXSTRICTRC HcFmInterval_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4955{
4956 uint32_t val = (pThis->fit << 31) | (pThis->fsmps << 16) | (pThis->fi);
4957 Log2(("HcFmInterval_r() -> 0x%#08x - FI=%d FSMPS=%d FIT=%d\n",
4958 val, val & 0x3fff, (val >> 16) & 0x7fff, val >> 31));
4959 *pu32Value = val;
4960 RT_NOREF(pDevIns, iReg);
4961 return VINF_SUCCESS;
4962}
4963
4964/**
4965 * Write to the HcFmInterval (Fm = Frame) register.
4966 */
4967static VBOXSTRICTRC HcFmInterval_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
4968{
4969 RT_NOREF(pDevIns, iReg);
4970
4971 /* log */
4972 uint32_t chg = val ^ ((pThis->fit << 31) | (pThis->fsmps << 16) | pThis->fi); NOREF(chg);
4973 Log2(("HcFmInterval_w(%#010x) => %sFI=%d %sFSMPS=%d %sFIT=%d\n",
4974 val,
4975 chg & 0x00003fff ? "*" : "", val & 0x3fff,
4976 chg & 0x7fff0000 ? "*" : "", (val >> 16) & 0x7fff,
4977 chg >> 31 ? "*" : "", (val >> 31) & 1));
4978 if (pThis->fi != (val & OHCI_FMI_FI))
4979 {
4980 Log(("ohci: FrameInterval: %#010x -> %#010x\n", pThis->fi, val & OHCI_FMI_FI));
4981 AssertMsg(pThis->fit != ((val >> OHCI_FMI_FIT_SHIFT) & 1), ("HCD didn't toggle the FIT bit!!!\n"));
4982 }
4983
4984 /* update */
4985 pThis->fi = val & OHCI_FMI_FI;
4986 pThis->fit = (val & OHCI_FMI_FIT) >> OHCI_FMI_FIT_SHIFT;
4987 pThis->fsmps = (val & OHCI_FMI_FSMPS) >> OHCI_FMI_FSMPS_SHIFT;
4988 return VINF_SUCCESS;
4989}
4990
4991/**
4992 * Read the HcFmRemaining (Fm = Frame) register.
4993 */
4994static VBOXSTRICTRC HcFmRemaining_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
4995{
4996 RT_NOREF(iReg);
4997 uint32_t Value = pThis->frt << 31;
4998 if ((pThis->ctl & OHCI_CTL_HCFS) == OHCI_USB_OPERATIONAL)
4999 {
5000 /*
5001 * Being in USB operational state guarantees SofTime was set already.
5002 */
5003 uint64_t tks = PDMDevHlpTMTimeVirtGet(pDevIns) - pThis->SofTime;
5004 if (tks < pThis->cTicksPerFrame) /* avoid muldiv if possible */
5005 {
5006 uint16_t fr;
5007 tks = ASMMultU64ByU32DivByU32(1, tks, pThis->cTicksPerUsbTick);
5008 fr = (uint16_t)(pThis->fi - tks);
5009 Value |= fr;
5010 }
5011 }
5012
5013 Log2(("HcFmRemaining_r() -> %#010x - FR=%d FRT=%d\n", Value, Value & 0x3fff, Value >> 31));
5014 *pu32Value = Value;
5015 return VINF_SUCCESS;
5016}
5017
5018/**
5019 * Write to the HcFmRemaining (Fm = Frame) register.
5020 */
5021static VBOXSTRICTRC HcFmRemaining_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
5022{
5023 RT_NOREF(pDevIns, pThis, iReg, val);
5024 Log2(("HcFmRemaining_w(%#010x) - denied\n", val));
5025 AssertMsgFailed(("Invalid operation!!! val=%#010x\n", val));
5026 return VINF_SUCCESS;
5027}
5028
5029/**
5030 * Read the HcFmNumber (Fm = Frame) register.
5031 */
5032static VBOXSTRICTRC HcFmNumber_r(PPDMDEVINS pDevIns, PCOHCI pThis, uint32_t iReg, uint32_t *pu32Value)
5033{
5034 RT_NOREF(pDevIns, iReg);
5035 uint32_t val = (uint16_t)pThis->HcFmNumber;
5036 Log2(("HcFmNumber_r() -> %#010x - FN=%#x(%d) (32-bit=%#x(%d))\n", val, val, val, pThis->HcFmNumber, pThis->HcFmNumber));
5037 *pu32Value = val;
5038 return VINF_SUCCESS;
5039}
5040
5041/**
5042 * Write to the HcFmNumber (Fm = Frame) register.
5043 */
5044static VBOXSTRICTRC HcFmNumber_w(PPDMDEVINS pDevIns, POHCI pThis, uint32_t iReg, uint32_t val)
5045{
5046 RT_NOREF(pDevIns, pThis, iReg, val);
5047 Log2(("HcFmNumber_w(%#010x) - denied\n", val));
5048 AssertMsgFailed(("Invalid operation!!! val=%#010x\n", val));
5049 return VINF_SUCCESS;
5050}
5051
5052/**
5053 * Read the HcPeriodicStart register.
5054