VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevSerial.cpp@ 87766

Last change on this file since 87766 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.5 KB
Line 
1/* $Id: DevSerial.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * DevSerial - 16550A UART emulation.
4 *
5 * The documentation for this device was taken from the PC16550D spec from TI.
6 */
7
8/*
9 * Copyright (C) 2018-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_SERIAL
25#include <VBox/vmm/pdmdev.h>
26#include <VBox/vmm/pdmserialifs.h>
27#include <iprt/assert.h>
28#include <iprt/uuid.h>
29#include <iprt/string.h>
30#include <iprt/semaphore.h>
31#include <iprt/critsect.h>
32
33#include "VBoxDD.h"
34#include "UartCore.h"
35
36
37/*********************************************************************************************************************************
38* Structures and Typedefs *
39*********************************************************************************************************************************/
40
41/**
42 * Shared serial device state.
43 */
44typedef struct DEVSERIAL
45{
46 /** The IRQ value. */
47 uint8_t uIrq;
48 uint8_t bAlignment;
49 /** The base I/O port the device is registered at. */
50 RTIOPORT PortBase;
51 /** The I/O ports registration. */
52 IOMIOPORTHANDLE hIoPorts;
53
54 /** The UART core. */
55 UARTCORE UartCore;
56} DEVSERIAL;
57/** Pointer to the shared serial device state. */
58typedef DEVSERIAL *PDEVSERIAL;
59
60
61/**
62 * Serial device state for ring-3.
63 */
64typedef struct DEVSERIALR3
65{
66 /** The UART core. */
67 UARTCORER3 UartCore;
68} DEVSERIALR3;
69/** Pointer to the serial device state for ring-3. */
70typedef DEVSERIALR3 *PDEVSERIALR3;
71
72
73/**
74 * Serial device state for ring-0.
75 */
76typedef struct DEVSERIALR0
77{
78 /** The UART core. */
79 UARTCORER0 UartCore;
80} DEVSERIALR0;
81/** Pointer to the serial device state for ring-0. */
82typedef DEVSERIALR0 *PDEVSERIALR0;
83
84
85/**
86 * Serial device state for raw-mode.
87 */
88typedef struct DEVSERIALRC
89{
90 /** The UART core. */
91 UARTCORERC UartCore;
92} DEVSERIALRC;
93/** Pointer to the serial device state for raw-mode. */
94typedef DEVSERIALRC *PDEVSERIALRC;
95
96/** The serial device state for the current context. */
97typedef CTX_SUFF(DEVSERIAL) DEVSERIALCC;
98/** Pointer to the serial device state for the current context. */
99typedef CTX_SUFF(PDEVSERIAL) PDEVSERIALCC;
100
101
102#ifndef VBOX_DEVICE_STRUCT_TESTCASE
103
104
105
106PDMBOTHCBDECL(void) serialIrqReq(PPDMDEVINS pDevIns, PUARTCORE pUart, unsigned iLUN, int iLvl)
107{
108 RT_NOREF(pUart, iLUN);
109 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
110 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->uIrq, iLvl);
111}
112
113
114/* -=-=-=-=-=-=-=-=- I/O Port Access Handlers -=-=-=-=-=-=-=-=- */
115
116/**
117 * @callback_method_impl{FNIOMIOPORTNEWOUT}
118 */
119static DECLCALLBACK(VBOXSTRICTRC)
120serialIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
121{
122 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
123 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
124 RT_NOREF_PV(pvUser);
125
126 return uartRegWrite(pDevIns, &pThis->UartCore, &pThisCC->UartCore, offPort, u32, cb);
127}
128
129
130/**
131 * @callback_method_impl{FNIOMIOPORTNEWIN}
132 */
133static DECLCALLBACK(VBOXSTRICTRC)
134serialIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
135{
136 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
137 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
138 RT_NOREF_PV(pvUser);
139
140 return uartRegRead(pDevIns, &pThis->UartCore, &pThisCC->UartCore, offPort, pu32, cb);
141}
142
143
144#ifdef IN_RING3
145
146
147/**
148 * Returns the matching UART type from the given string.
149 *
150 * @returns UART type based on the given string or UARTTYPE_INVALID if an invalid type was passed.
151 * @param pszUartType The UART type.
152 */
153static UARTTYPE serialR3GetUartTypeFromString(const char *pszUartType)
154{
155 if (!RTStrCmp(pszUartType, "16450"))
156 return UARTTYPE_16450;
157 else if (!RTStrCmp(pszUartType, "16550A"))
158 return UARTTYPE_16550A;
159 else if (!RTStrCmp(pszUartType, "16750"))
160 return UARTTYPE_16750;
161
162 AssertLogRelMsgFailedReturn(("Unknown UART type \"%s\" specified", pszUartType), UARTTYPE_INVALID);
163}
164
165
166/* -=-=-=-=-=-=-=-=- Saved State -=-=-=-=-=-=-=-=- */
167
168/**
169 * @callback_method_impl{FNSSMDEVLIVEEXEC}
170 */
171static DECLCALLBACK(int) serialR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
172{
173 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
174 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
175 RT_NOREF(uPass);
176
177 pHlp->pfnSSMPutU8(pSSM, pThis->uIrq);
178 pHlp->pfnSSMPutIOPort(pSSM, pThis->PortBase);
179 pHlp->pfnSSMPutU32(pSSM, pThis->UartCore.enmType);
180
181 return VINF_SSM_DONT_CALL_AGAIN;
182}
183
184
185/**
186 * @callback_method_impl{FNSSMDEVSAVEEXEC}
187 */
188static DECLCALLBACK(int) serialR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
189{
190 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
191 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
192
193 pHlp->pfnSSMPutU8( pSSM, pThis->uIrq);
194 pHlp->pfnSSMPutIOPort(pSSM, pThis->PortBase);
195 pHlp->pfnSSMPutU32( pSSM, pThis->UartCore.enmType);
196
197 uartR3SaveExec(pDevIns, &pThis->UartCore, pSSM);
198 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
199}
200
201
202/**
203 * @callback_method_impl{FNSSMDEVLOADEXEC}
204 */
205static DECLCALLBACK(int) serialR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
206{
207 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
208 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
209 uint8_t bIrq;
210 RTIOPORT PortBase;
211 UARTTYPE enmType;
212 int rc;
213
214 AssertMsgReturn(uVersion >= UART_SAVED_STATE_VERSION_16450, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
215 if (uVersion > UART_SAVED_STATE_VERSION_LEGACY_CODE)
216 {
217 pHlp->pfnSSMGetU8( pSSM, &bIrq);
218 pHlp->pfnSSMGetIOPort(pSSM, &PortBase);
219 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, enmType, UARTTYPE);
220 if (uPass == SSM_PASS_FINAL)
221 {
222 rc = uartR3LoadExec(pDevIns, &pThis->UartCore, pSSM, uVersion, uPass, NULL, NULL);
223 AssertRCReturn(rc, rc);
224 }
225 }
226 else
227 {
228 enmType = uVersion > UART_SAVED_STATE_VERSION_16450 ? UARTTYPE_16550A : UARTTYPE_16450;
229 if (uPass != SSM_PASS_FINAL)
230 {
231 int32_t iIrqTmp;
232 pHlp->pfnSSMGetS32(pSSM, &iIrqTmp);
233 uint32_t uPortBaseTmp;
234 rc = pHlp->pfnSSMGetU32(pSSM, &uPortBaseTmp);
235 AssertRCReturn(rc, rc);
236
237 bIrq = (uint8_t)iIrqTmp;
238 PortBase = (uint32_t)uPortBaseTmp;
239 }
240 else
241 {
242 rc = uartR3LoadExec(pDevIns, &pThis->UartCore, pSSM, uVersion, uPass, &bIrq, &PortBase);
243 AssertRCReturn(rc, rc);
244 }
245 }
246
247 if (uPass == SSM_PASS_FINAL)
248 {
249 /* The marker. */
250 uint32_t u32;
251 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
252 AssertRCReturn(rc, rc);
253 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
254 }
255
256 /*
257 * Check the config.
258 */
259 if ( pThis->uIrq != bIrq
260 || pThis->PortBase != PortBase
261 || pThis->UartCore.enmType != enmType)
262 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
263 N_("Config mismatch - saved IRQ=%#x PortBase=%#x Type=%d; configured IRQ=%#x PortBase=%#x Type=%d"),
264 bIrq, PortBase, enmType, pThis->uIrq, pThis->PortBase, pThis->UartCore.enmType);
265
266 return VINF_SUCCESS;
267}
268
269
270/**
271 * @callback_method_impl{FNSSMDEVLOADDONE}
272 */
273static DECLCALLBACK(int) serialR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
274{
275 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
276 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
277 return uartR3LoadDone(pDevIns, &pThis->UartCore, &pThisCC->UartCore, pSSM);
278}
279
280
281/* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
282
283/**
284 * @interface_method_impl{PDMDEVREG,pfnReset}
285 */
286static DECLCALLBACK(void) serialR3Reset(PPDMDEVINS pDevIns)
287{
288 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
289 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
290 uartR3Reset(pDevIns, &pThis->UartCore, &pThisCC->UartCore);
291}
292
293
294/**
295 * @interface_method_impl{PDMDEVREG,pfnAttach}
296 */
297static DECLCALLBACK(int) serialR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
298{
299 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
300 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
301 RT_NOREF(fFlags);
302 AssertReturn(iLUN == 0, VERR_PDM_LUN_NOT_FOUND);
303
304 return uartR3Attach(pDevIns, &pThis->UartCore, &pThisCC->UartCore, iLUN);
305}
306
307
308/**
309 * @interface_method_impl{PDMDEVREG,pfnDetach}
310 */
311static DECLCALLBACK(void) serialR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
312{
313 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
314 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
315 RT_NOREF(fFlags);
316 AssertReturnVoid(iLUN == 0);
317
318 uartR3Detach(pDevIns, &pThis->UartCore, &pThisCC->UartCore);
319}
320
321
322/**
323 * @interface_method_impl{PDMDEVREG,pfnDestruct}
324 */
325static DECLCALLBACK(int) serialR3Destruct(PPDMDEVINS pDevIns)
326{
327 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
328 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
329
330 uartR3Destruct(pDevIns, &pThis->UartCore);
331 return VINF_SUCCESS;
332}
333
334
335/**
336 * @interface_method_impl{PDMDEVREG,pfnConstruct}
337 */
338static DECLCALLBACK(int) serialR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
339{
340 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
341 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
342 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
343 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
344 int rc;
345
346 Assert(iInstance < 4);
347
348 /*
349 * Validate and read the configuration.
350 */
351 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ|IOBase|YieldOnLSRRead|UartType", "");
352
353 bool fYieldOnLSRRead = false;
354 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "YieldOnLSRRead", &fYieldOnLSRRead, false);
355 if (RT_FAILURE(rc))
356 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
357
358 uint8_t uIrq = 0;
359 rc = pHlp->pfnCFGMQueryU8(pCfg, "IRQ", &uIrq);
360 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
361 {
362 /* Provide sensible defaults. */
363 if (iInstance == 0)
364 uIrq = 4;
365 else if (iInstance == 1)
366 uIrq = 3;
367 else
368 AssertReleaseFailed(); /* irq_lvl is undefined. */
369 }
370 else if (RT_FAILURE(rc))
371 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"IRQ\" value"));
372
373 uint16_t uIoBase = 0;
374 rc = pHlp->pfnCFGMQueryU16(pCfg, "IOBase", &uIoBase);
375 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
376 {
377 if (iInstance == 0)
378 uIoBase = 0x3f8;
379 else if (iInstance == 1)
380 uIoBase = 0x2f8;
381 else
382 AssertReleaseFailed(); /* uIoBase is undefined */
383 }
384 else if (RT_FAILURE(rc))
385 return PDMDEV_SET_ERROR(pDevIns, rc,
386 N_("Configuration error: Failed to get the \"IOBase\" value"));
387
388 char szUartType[32];
389 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "UartType", szUartType, sizeof(szUartType), "16550A");
390 if (RT_FAILURE(rc))
391 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: failed to read \"UartType\" as string"));
392
393 UARTTYPE enmUartType = serialR3GetUartTypeFromString(szUartType);
394 if (enmUartType != UARTTYPE_INVALID)
395 LogRel(("Serial#%d: emulating %s (IOBase: %04x IRQ: %u)\n", pDevIns->iInstance, szUartType, uIoBase, uIrq));
396 else
397 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
398 N_("Configuration error: Invalid \"UartType\" type value: %s"), szUartType);
399
400 pThis->uIrq = uIrq;
401 pThis->PortBase = uIoBase;
402
403 /*
404 * Init locks, using explicit locking where necessary.
405 */
406 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
407 AssertRCReturn(rc, rc);
408
409 /*
410 * Register the I/O ports.
411 */
412 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, uIoBase, 8 /*cPorts*/, serialIoPortWrite, serialIoPortRead,
413 "SERIAL", NULL /*paExtDescs*/, &pThis->hIoPorts);
414 AssertRCReturn(rc, rc);
415
416 /*
417 * Saved state.
418 */
419 rc = PDMDevHlpSSMRegisterEx(pDevIns, UART_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
420 NULL, serialR3LiveExec, NULL,
421 NULL, serialR3SaveExec, NULL,
422 NULL, serialR3LoadExec, serialR3LoadDone);
423 AssertRCReturn(rc, rc);
424
425 /*
426 * Init the UART core structure.
427 */
428 rc = uartR3Init(pDevIns, &pThis->UartCore, &pThisCC->UartCore, enmUartType, 0,
429 fYieldOnLSRRead ? UART_CORE_YIELD_ON_LSR_READ : 0, serialIrqReq);
430 AssertRCReturn(rc, rc);
431
432 serialR3Reset(pDevIns);
433 return VINF_SUCCESS;
434}
435
436#else /* !IN_RING3 */
437
438/**
439 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
440 */
441static DECLCALLBACK(int) serialRZConstruct(PPDMDEVINS pDevIns)
442{
443 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
444 PDEVSERIAL pThis = PDMDEVINS_2_DATA(pDevIns, PDEVSERIAL);
445 PDEVSERIALCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVSERIALCC);
446
447 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
448 AssertRCReturn(rc, rc);
449
450 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPorts, serialIoPortWrite, serialIoPortRead, NULL /*pvUser*/);
451 AssertRCReturn(rc, rc);
452
453 rc = uartRZInit(&pThisCC->UartCore, serialIrqReq);
454 AssertRCReturn(rc, rc);
455
456 return VINF_SUCCESS;
457}
458
459#endif /* !IN_RING3 */
460
461/**
462 * The device registration structure.
463 */
464const PDMDEVREG g_DeviceSerialPort =
465{
466 /* .u32Version = */ PDM_DEVREG_VERSION,
467 /* .uReserved0 = */ 0,
468 /* .szName = */ "serial",
469 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
470 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
471 /* .cMaxInstances = */ UINT32_MAX,
472 /* .uSharedVersion = */ 42,
473 /* .cbInstanceShared = */ sizeof(DEVSERIAL),
474 /* .cbInstanceCC = */ sizeof(DEVSERIALCC),
475 /* .cbInstanceRC = */ sizeof(DEVSERIALRC),
476 /* .cMaxPciDevices = */ 0,
477 /* .cMaxMsixVectors = */ 0,
478 /* .pszDescription = */ "Serial Communication Port",
479#if defined(IN_RING3)
480 /* .pszRCMod = */ "VBoxDDRC.rc",
481 /* .pszR0Mod = */ "VBoxDDR0.r0",
482 /* .pfnConstruct = */ serialR3Construct,
483 /* .pfnDestruct = */ serialR3Destruct,
484 /* .pfnRelocate = */ NULL,
485 /* .pfnMemSetup = */ NULL,
486 /* .pfnPowerOn = */ NULL,
487 /* .pfnReset = */ serialR3Reset,
488 /* .pfnSuspend = */ NULL,
489 /* .pfnResume = */ NULL,
490 /* .pfnAttach = */ serialR3Attach,
491 /* .pfnDetach = */ serialR3Detach,
492 /* .pfnQueryInterface = */ NULL,
493 /* .pfnInitComplete = */ NULL,
494 /* .pfnPowerOff = */ NULL,
495 /* .pfnSoftReset = */ NULL,
496 /* .pfnReserved0 = */ NULL,
497 /* .pfnReserved1 = */ NULL,
498 /* .pfnReserved2 = */ NULL,
499 /* .pfnReserved3 = */ NULL,
500 /* .pfnReserved4 = */ NULL,
501 /* .pfnReserved5 = */ NULL,
502 /* .pfnReserved6 = */ NULL,
503 /* .pfnReserved7 = */ NULL,
504#elif defined(IN_RING0)
505 /* .pfnEarlyConstruct = */ NULL,
506 /* .pfnConstruct = */ serialRZConstruct,
507 /* .pfnDestruct = */ NULL,
508 /* .pfnFinalDestruct = */ NULL,
509 /* .pfnRequest = */ NULL,
510 /* .pfnReserved0 = */ NULL,
511 /* .pfnReserved1 = */ NULL,
512 /* .pfnReserved2 = */ NULL,
513 /* .pfnReserved3 = */ NULL,
514 /* .pfnReserved4 = */ NULL,
515 /* .pfnReserved5 = */ NULL,
516 /* .pfnReserved6 = */ NULL,
517 /* .pfnReserved7 = */ NULL,
518#elif defined(IN_RC)
519 /* .pfnConstruct = */ serialRZConstruct,
520 /* .pfnReserved0 = */ NULL,
521 /* .pfnReserved1 = */ NULL,
522 /* .pfnReserved2 = */ NULL,
523 /* .pfnReserved3 = */ NULL,
524 /* .pfnReserved4 = */ NULL,
525 /* .pfnReserved5 = */ NULL,
526 /* .pfnReserved6 = */ NULL,
527 /* .pfnReserved7 = */ NULL,
528#else
529# error "Not in IN_RING3, IN_RING0 or IN_RC!"
530#endif
531 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
532};
533
534#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
535
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette