VirtualBox

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

Last change on this file was 106281, checked in by vboxsync, 2 months ago

DevOHCI: Quick fix for deadlock when pfnAbortEpByAddr is called. Ran into it while windows 2000 was shutting down (almost finished, screen all blue, but never powering off). There is a question whether we should re-reade the endpoint descriptor after regaining the lock, but the guest is free to change it regardless of whether we're holding the lock or not, so I guess it makes little difference.

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