VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideoHGSMI.cpp@ 34349

Last change on this file since 34349 was 34349, checked in by vboxsync, 14 years ago

Additions/WINNT/Graphics: more refactoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.5 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 34349 2010-11-25 01:53:58Z vboxsync $ */
2/** @file
3 * VirtualBox Video miniport driver for NT/2k/XP - HGSMI related functions.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <string.h>
19
20#include "VBoxVideo.h"
21#include "Helper.h"
22
23#include <iprt/asm.h>
24#include <iprt/log.h>
25#include <iprt/thread.h>
26#include <VBox/VMMDev.h>
27#include <VBox/VBoxGuest.h>
28#include <VBox/VBoxVideo.h>
29
30// #include <VBoxDisplay.h>
31
32// #include "vboxioctl.h"
33
34/** Send completion notification to the host for the command located at offset
35 * @a offt into the host command buffer. */
36void HGSMINotifyHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, HGSMIOFFSET offt)
37{
38 VBoxVideoCmnPortWriteUlong(pCtx->port, offt);
39}
40
41/** Acknowlege an IRQ. */
42void HGSMIClearIrq(PHGSMIHOSTCOMMANDCONTEXT pCtx)
43{
44 VBoxVideoCmnPortWriteUlong(pCtx->port, HGSMIOFFSET_VOID);
45}
46
47/** Inform the host that a command has been handled. */
48static void HGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, void * pvMem)
49{
50 HGSMIBUFFERHEADER *pHdr = HGSMIBufferHeaderFromData(pvMem);
51 HGSMIOFFSET offMem = HGSMIPointerToOffset(&pCtx->areaCtx, pHdr);
52 Assert(offMem != HGSMIOFFSET_VOID);
53 if(offMem != HGSMIOFFSET_VOID)
54 {
55 HGSMINotifyHostCmdComplete(pCtx, offMem);
56 }
57}
58
59/** Submit an incoming host command to the appropriate handler. */
60static void hgsmiHostCmdProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx,
61 HGSMIOFFSET offBuffer)
62{
63 int rc = HGSMIBufferProcess(&pCtx->areaCtx, &pCtx->channels, offBuffer);
64 Assert(!RT_FAILURE(rc));
65 if(RT_FAILURE(rc))
66 {
67 /* failure means the command was not submitted to the handler for some reason
68 * it's our responsibility to notify its completion in this case */
69 HGSMINotifyHostCmdComplete(pCtx, offBuffer);
70 }
71 /* if the cmd succeeded it's responsibility of the callback to complete it */
72}
73
74/** Get the next command from the host. */
75static HGSMIOFFSET hgsmiGetHostBuffer(PHGSMIHOSTCOMMANDCONTEXT pCtx)
76{
77 return VBoxVideoCmnPortReadUlong(pCtx->port);
78}
79
80/** Get and handle the next command from the host. */
81static void hgsmiHostCommandQueryProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx)
82{
83 HGSMIOFFSET offset = hgsmiGetHostBuffer(pCtx);
84 AssertReturnVoid(offset != HGSMIOFFSET_VOID);
85 hgsmiHostCmdProcess(pCtx, offset);
86}
87
88/** Drain the host command queue. */
89void hgsmiProcessHostCommandQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx)
90{
91 while (pCtx->pfHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
92 {
93 if (!ASMAtomicCmpXchgBool(&pCtx->fHostCmdProcessing, true, false))
94 return;
95 hgsmiHostCommandQueryProcess(pCtx);
96 ASMAtomicWriteBool(&pCtx->fHostCmdProcessing, false);
97 }
98}
99
100/** Detect whether HGSMI is supported by the host. */
101bool VBoxHGSMIIsSupported (void)
102{
103 uint16_t DispiId;
104
105 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
106 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
107
108 DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
109
110 return (DispiId == VBE_DISPI_ID_HGSMI);
111}
112
113
114void* vboxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx,
115 HGSMISIZE cbData,
116 uint8_t u8Ch,
117 uint16_t u16Op)
118{
119#ifdef VBOX_WITH_WDDM
120 /* @todo: add synchronization */
121#endif
122 return HGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
123}
124
125void vboxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx, void *pvBuffer)
126{
127#ifdef VBOX_WITH_WDDM
128 /* @todo: add synchronization */
129#endif
130 HGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
131}
132
133int vboxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx, void *pvBuffer)
134{
135 /* Initialize the buffer and get the offset for port IO. */
136 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCtx->heapCtx, pvBuffer);
137
138 Assert(offBuffer != HGSMIOFFSET_VOID);
139 if (offBuffer != HGSMIOFFSET_VOID)
140 {
141 /* Submit the buffer to the host. */
142 VBoxVideoCmnPortWriteUlong(pCtx->port, offBuffer);
143 return VINF_SUCCESS;
144 }
145
146 return VERR_INVALID_PARAMETER;
147}
148
149
150static int vboxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32Index,
151 uint32_t *pulValue)
152{
153 int rc = VINF_SUCCESS;
154 VBVACONF32 *p;
155 LogFunc(("u32Index = %d\n", u32Index));
156
157 /* Allocate the IO buffer. */
158 p = (VBVACONF32 *)HGSMIHeapAlloc(&pCtx->heapCtx,
159 sizeof(VBVACONF32), HGSMI_CH_VBVA,
160 VBVA_QUERY_CONF32);
161 if (p)
162 {
163 /* Prepare data to be sent to the host. */
164 p->u32Index = u32Index;
165 p->u32Value = 0;
166 rc = vboxHGSMIBufferSubmit(pCtx, p);
167 if (RT_SUCCESS(rc))
168 {
169 *pulValue = p->u32Value;
170 LogFunc(("u32Value = %d\n", p->u32Value));
171 }
172 /* Free the IO buffer. */
173 HGSMIHeapFree(&pCtx->heapCtx, p);
174 }
175 else
176 rc = VERR_NO_MEMORY;
177 LogFunc(("rc = %d\n", rc));
178 return rc;
179}
180
181
182static int vboxHGSMIBufferLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
183 HGSMIOFFSET offLocation)
184{
185 HGSMIBUFFERLOCATION *p;
186 int rc = VINF_SUCCESS;
187
188 /* Allocate the IO buffer. */
189 p = (HGSMIBUFFERLOCATION *)HGSMIHeapAlloc(&pCtx->heapCtx,
190 sizeof(HGSMIBUFFERLOCATION),
191 HGSMI_CH_HGSMI,
192 HGSMI_CC_HOST_FLAGS_LOCATION);
193 if (p)
194 {
195 /* Prepare data to be sent to the host. */
196 p->offLocation = offLocation;
197 p->cbLocation = sizeof(HGSMIHOSTFLAGS);
198 rc = vboxHGSMIBufferSubmit(pCtx, p);
199 /* Free the IO buffer. */
200 HGSMIHeapFree (&pCtx->heapCtx, p);
201 }
202 else
203 rc = VERR_NO_MEMORY;
204 return rc;
205}
206
207
208static int vboxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
209 uint32_t fCaps)
210{
211 VBVACAPS *pCaps;
212 int rc = VINF_SUCCESS;
213
214 /* Allocate the IO buffer. */
215 pCaps = (VBVACAPS *)HGSMIHeapAlloc(&pCtx->heapCtx,
216 sizeof(VBVACAPS), HGSMI_CH_VBVA,
217 VBVA_INFO_CAPS);
218
219 if (pCaps)
220 {
221 /* Prepare data to be sent to the host. */
222 pCaps->rc = VERR_NOT_IMPLEMENTED;
223 pCaps->fCaps = fCaps;
224 rc = vboxHGSMIBufferSubmit(pCtx, pCaps);
225 if (RT_SUCCESS(rc))
226 {
227 AssertRC(pCaps->rc);
228 rc = pCaps->rc;
229 }
230 /* Free the IO buffer. */
231 HGSMIHeapFree(&pCtx->heapCtx, pCaps);
232 }
233 else
234 rc = VERR_NO_MEMORY;
235 return rc;
236}
237
238
239static int vboxVBVAInitInfoHeap(PHGSMIGUESTCOMMANDCONTEXT pCtx,
240 uint32_t u32HeapOffset, uint32_t u32HeapSize)
241{
242 VBVAINFOHEAP *p;
243 int rc = VINF_SUCCESS;
244
245 /* Allocate the IO buffer. */
246 p = (VBVAINFOHEAP *)HGSMIHeapAlloc(&pCtx->heapCtx,
247 sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA,
248 VBVA_INFO_HEAP);
249 if (p)
250 {
251 /* Prepare data to be sent to the host. */
252 p->u32HeapOffset = u32HeapOffset;
253 p->u32HeapSize = u32HeapSize;
254 rc = vboxHGSMIBufferSubmit(pCtx, p);
255 /* Free the IO buffer. */
256 HGSMIHeapFree(&pCtx->heapCtx, p);
257 }
258 else
259 rc = VERR_NO_MEMORY;
260 return rc;
261}
262
263
264int VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, uint32_t u32Count,
265 PFNHGSMIFILLVIEWINFO pfnFill, void *pvData)
266{
267 int rc;
268 /* Issue the screen info command. */
269 void *p = vboxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
270 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
271 if (p)
272 {
273 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
274 rc = pfnFill(pvData, pInfo);
275 if (RT_SUCCESS(rc))
276 vboxHGSMIBufferSubmit (pCtx, p);
277 vboxHGSMIBufferFree(pCtx, p);
278 }
279 else
280 rc = VERR_NO_MEMORY;
281 return rc;
282}
283
284
285static int vboxSetupAdapterInfoHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
286 HGSMIOFFSET offBufferLocation,
287 uint32_t fCaps, uint32_t u32HeapOffset,
288 uint32_t u32HeapSize)
289{
290 Log(("VBoxVideo::vboxSetupAdapterInfo\n"));
291
292 /* setup the flags first to ensure they are initialized by the time the host heap is ready */
293 int rc = vboxHGSMIBufferLocation(pCtx, offBufferLocation);
294 AssertRC(rc);
295 if (RT_SUCCESS(rc) && fCaps)
296 {
297 /* Inform about caps */
298 rc = vboxHGSMISendCapsInfo(pCtx, fCaps);
299 AssertRC(rc);
300 }
301 if (RT_SUCCESS (rc))
302 {
303 /* Report the host heap location. */
304 rc = vboxVBVAInitInfoHeap(pCtx, u32HeapOffset, u32HeapSize);
305 AssertRC(rc);
306 }
307 Log(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
308 return rc;
309}
310
311
312/**
313 * Helper function to register secondary displays (DualView). Note that this will not
314 * be available on pre-XP versions, and some editions on XP will fail because they are
315 * intentionally crippled.
316 *
317 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
318 * to talk to the host.
319 */
320void VBoxSetupDisplaysHGSMI(PVBOXVIDEO_COMMON pCommon,
321 uint32_t AdapterMemorySize, uint32_t fCaps)
322{
323 /** @todo I simply converted this from Windows error codes. That is wrong,
324 * but we currently freely mix and match those (failure == rc > 0) and iprt
325 * ones (failure == rc < 0) anyway. This needs to be fully reviewed and
326 * fixed. */
327 int rc = VINF_SUCCESS;
328
329 Log(("VBoxVideo::VBoxSetupDisplays: pCommon = %p\n", pCommon));
330
331 memset(pCommon, 0, sizeof(*pCommon));
332 pCommon->cbVRAM = AdapterMemorySize;
333 pCommon->cDisplays = 1;
334 pCommon->bHGSMI = VBoxHGSMIIsSupported ();
335 /* Why does this use VBoxVideoCmnMemZero? The MSDN docs say that it should
336 * only be used on mapped display adapter memory. Done with memset above. */
337 // VBoxVideoCmnMemZero(&pCommon->areaHostHeap, sizeof(HGSMIAREA));
338 if (pCommon->bHGSMI)
339 {
340 /** @note (michael) moved this here as it is done unconditionally in both
341 * driver branches. Feel free to fix if that is ever changed. */
342 pCommon->hostCtx.port = (RTIOPORT)VGA_PORT_HGSMI_HOST;
343 pCommon->guestCtx.port = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
344
345 /* Map the adapter information. It will be needed for HGSMI IO. */
346 /** @todo all callers of VBoxMapAdapterMemory expect it to use iprt
347 * error codes, but it doesn't. */
348 rc = VBoxMapAdapterMemory (pCommon, &pCommon->pvAdapterInformation,
349 AdapterMemorySize - VBVA_ADAPTER_INFORMATION_SIZE,
350 VBVA_ADAPTER_INFORMATION_SIZE
351 );
352 if (RT_FAILURE(rc))
353 {
354 Log(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
355 rc));
356
357 pCommon->bHGSMI = false;
358 }
359 else
360 {
361 /* Setup a HGSMI heap within the adapter information area. */
362 rc = HGSMIHeapSetup (&pCommon->guestCtx.heapCtx,
363 pCommon->pvAdapterInformation,
364 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
365 pCommon->cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
366 false /*fOffsetBased*/);
367
368 if (RT_FAILURE(rc))
369 {
370 Log(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
371 rc));
372
373 pCommon->bHGSMI = false;
374 }
375 else
376 {
377 pCommon->hostCtx.pfHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)pCommon->pvAdapterInformation)
378 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
379 }
380 }
381 }
382
383 /* Setup the host heap and the adapter memory. */
384 if (pCommon->bHGSMI)
385 {
386 /* The miniport heap is used for the host buffers. */
387 uint32_t cbMiniportHeap = 0;
388 vboxQueryConfHGSMI(&pCommon->guestCtx, VBOX_VBVA_CONF32_HOST_HEAP_SIZE,
389 &cbMiniportHeap);
390
391 if (cbMiniportHeap != 0)
392 {
393 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
394 uint32_t cbMiniportHeapMaxSize = AdapterMemorySize / 4;
395
396 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
397 {
398 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
399 }
400
401 if (cbMiniportHeap > cbMiniportHeapMaxSize)
402 {
403 cbMiniportHeap = cbMiniportHeapMaxSize;
404 }
405
406 /* Round up to 4096 bytes. */
407 pCommon->cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
408
409 Log(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, pCommon->cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
410 cbMiniportHeap, pCommon->cbMiniportHeap, cbMiniportHeapMaxSize));
411
412 /* Map the heap region.
413 *
414 * Note: the heap will be used for the host buffers submitted to the guest.
415 * The miniport driver is responsible for reading FIFO and notifying
416 * display drivers.
417 */
418 rc = VBoxMapAdapterMemory (pCommon, &pCommon->pvMiniportHeap,
419 pCommon->cbVRAM
420 - VBVA_ADAPTER_INFORMATION_SIZE
421 - pCommon->cbMiniportHeap,
422 pCommon->cbMiniportHeap
423 );
424 if (RT_FAILURE(rc))
425 {
426 pCommon->pvMiniportHeap = NULL;
427 pCommon->cbMiniportHeap = 0;
428 pCommon->bHGSMI = false;
429 }
430 else
431 {
432 HGSMIOFFSET offBase = pCommon->cbVRAM
433 - VBVA_ADAPTER_INFORMATION_SIZE
434 - pCommon->cbMiniportHeap;
435
436 /* Init the host hap area. Buffers from the host will be placed there. */
437 HGSMIAreaInitialize (&pCommon->hostCtx.areaCtx,
438 pCommon->pvMiniportHeap,
439 pCommon->cbMiniportHeap,
440 offBase);
441 }
442 }
443 else
444 {
445 /* Host has not requested a heap. */
446 pCommon->pvMiniportHeap = NULL;
447 pCommon->cbMiniportHeap = 0;
448 }
449 }
450
451 /* Check whether the guest supports multimonitors. */
452 if (pCommon->bHGSMI)
453 {
454 /* Query the configured number of displays. */
455 uint32_t cDisplays = 0;
456 vboxQueryConfHGSMI(&pCommon->guestCtx, VBOX_VBVA_CONF32_MONITOR_COUNT,
457 &cDisplays);
458
459 Log(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
460 cDisplays));
461
462 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
463 {
464 /* Host reported some bad value. Continue in the 1 screen mode. */
465 cDisplays = 1;
466 }
467 pCommon->cDisplays = cDisplays;
468 }
469
470 if (pCommon->bHGSMI)
471 {
472 /* Setup the information for the host. */
473 rc = vboxSetupAdapterInfoHGSMI(&pCommon->guestCtx,
474 pCommon->cbVRAM - sizeof(HGSMIHOSTFLAGS),
475 fCaps,
476 pCommon->cbVRAM
477 - pCommon->cbMiniportHeap
478 - VBVA_ADAPTER_INFORMATION_SIZE,
479 pCommon->cbMiniportHeap);
480
481 if (RT_FAILURE(rc))
482 {
483 pCommon->bHGSMI = false;
484 }
485 }
486
487 if (!pCommon->bHGSMI)
488 VBoxFreeDisplaysHGSMI(pCommon);
489
490 Log(("VBoxVideo::VBoxSetupDisplays: finished\n"));
491}
492
493static bool VBoxUnmapAdpInfoCallback(void *pvCommon)
494{
495 PVBOXVIDEO_COMMON pCommon = (PVBOXVIDEO_COMMON)pvCommon;
496
497 pCommon->hostCtx.pfHostFlags = NULL;
498 return true;
499}
500
501void VBoxFreeDisplaysHGSMI(PVBOXVIDEO_COMMON pCommon)
502{
503 VBoxUnmapAdapterMemory(pCommon, &pCommon->pvMiniportHeap);
504 HGSMIHeapDestroy(&pCommon->guestCtx.heapCtx);
505
506 /* Unmap the adapter information needed for HGSMI IO. */
507 VBoxSyncToVideoIRQ(pCommon, VBoxUnmapAdpInfoCallback, pCommon);
508 VBoxUnmapAdapterMemory(pCommon, &pCommon->pvAdapterInformation);
509}
510
511
512bool vboxUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx,
513 uint32_t fFlags,
514 uint32_t cHotX,
515 uint32_t cHotY,
516 uint32_t cWidth,
517 uint32_t cHeight,
518 uint8_t *pPixels,
519 uint32_t cbLength)
520{
521 VBVAMOUSEPOINTERSHAPE *p;
522 uint32_t cbData = 0;
523 int rc = VINF_SUCCESS;
524
525 if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
526 {
527 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
528 cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
529 + cWidth * 4 * cHeight;
530 /* If shape is supplied, then always create the pointer visible.
531 * See comments in 'vboxUpdatePointerShape'
532 */
533 fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
534 }
535#ifndef DEBUG_misha
536 LogFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight));
537#endif
538 if (cbData > cbLength)
539 {
540 LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n",
541 cbData, cbLength));
542 return false;
543 }
544 /* Allocate the IO buffer. */
545 p = (VBVAMOUSEPOINTERSHAPE *)HGSMIHeapAlloc(&pCtx->heapCtx,
546 sizeof(VBVAMOUSEPOINTERSHAPE)
547 + cbData,
548 HGSMI_CH_VBVA,
549 VBVA_MOUSE_POINTER_SHAPE);
550 if (p)
551 {
552 /* Prepare data to be sent to the host. */
553 /* Will be updated by the host. */
554 p->i32Result = VINF_SUCCESS;
555 /* We have our custom flags in the field */
556 p->fu32Flags = fFlags;
557 p->u32HotX = cHotX;
558 p->u32HotY = cHotY;
559 p->u32Width = cWidth;
560 p->u32Height = cHeight;
561 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
562 /* Copy the actual pointer data. */
563 memcpy (p->au8Data, pPixels, cbData);
564 rc = vboxHGSMIBufferSubmit(pCtx, p);
565 if (RT_SUCCESS(rc))
566 rc = p->i32Result;
567 /* Free the IO buffer. */
568 HGSMIHeapFree(&pCtx->heapCtx, p);
569 }
570 else
571 rc = VERR_NO_MEMORY;
572#ifndef DEBUG_misha
573 LogFunc(("rc %d\n", rc));
574#endif
575 return RT_SUCCESS(rc);
576}
577
578#ifndef VBOX_WITH_WDDM
579typedef struct _VBVAMINIPORT_CHANNELCONTEXT
580{
581 PFNHGSMICHANNELHANDLER pfnChannelHandler;
582 void *pvChannelHandler;
583}VBVAMINIPORT_CHANNELCONTEXT;
584
585typedef struct _VBVADISP_CHANNELCONTEXT
586{
587 /** The generic command handler builds up a list of commands - in reverse
588 * order! - here */
589 VBVAHOSTCMD *pCmd;
590 bool bValid;
591}VBVADISP_CHANNELCONTEXT;
592
593typedef struct _VBVA_CHANNELCONTEXTS
594{
595 PVBOXVIDEO_COMMON pCommon;
596 uint32_t cUsed;
597 uint32_t cContexts;
598 VBVAMINIPORT_CHANNELCONTEXT mpContext;
599 VBVADISP_CHANNELCONTEXT aContexts[1];
600}VBVA_CHANNELCONTEXTS;
601
602static int vboxVBVADeleteChannelContexts(PVBOXVIDEO_COMMON pCommon,
603 VBVA_CHANNELCONTEXTS * pContext)
604{
605 VBoxVideoCmnMemFreeDriver(pCommon, pContext);
606 return VINF_SUCCESS;
607}
608
609static int vboxVBVACreateChannelContexts(PVBOXVIDEO_COMMON pCommon, VBVA_CHANNELCONTEXTS ** ppContext)
610{
611 uint32_t cDisplays = (uint32_t)pCommon->cDisplays;
612 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
613 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocDriver(pCommon, size);
614 if(pContext)
615 {
616 memset(pContext, 0, size);
617 pContext->cContexts = cDisplays;
618 pContext->pCommon = pCommon;
619 *ppContext = pContext;
620 return VINF_SUCCESS;
621 }
622 return VERR_GENERAL_FAILURE;
623}
624
625static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
626{
627 if(iId < 0)
628 {
629 return NULL;
630 }
631 else if(pCallbacks->cContexts > (uint32_t)iId)
632 {
633 return &pCallbacks->aContexts[iId];
634 }
635 return NULL;
636}
637
638DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
639{
640 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXVIDEO_COMMON)hHGSMI)->hostCtx;
641 HGSMIHostCmdComplete(pCtx, pCmd);
642}
643
644/** Reverses a NULL-terminated linked list of VBVAHOSTCMD structures. */
645static VBVAHOSTCMD *vboxVBVAReverseList(VBVAHOSTCMD *pList)
646{
647 VBVAHOSTCMD *pFirst = NULL;
648 while (pList)
649 {
650 VBVAHOSTCMD *pNext = pList;
651 pList = pList->u.pNext;
652 pNext->u.pNext = pFirst;
653 pFirst = pNext;
654 }
655 return pFirst;
656}
657
658DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, uint32_t iDevice, struct _VBVAHOSTCMD ** ppCmd)
659{
660// if(display < 0)
661// return VERR_INVALID_PARAMETER;
662 if(!ppCmd)
663 return VERR_INVALID_PARAMETER;
664
665 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXVIDEO_COMMON)hHGSMI)->hostCtx;
666
667 /* pick up the host commands */
668 hgsmiProcessHostCommandQueue(pCtx);
669
670 HGSMICHANNEL *pChannel = HGSMIChannelFindById (&pCtx->channels, u8Channel);
671 if(pChannel)
672 {
673 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
674 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDevice);
675 Assert(pDispContext);
676 if(pDispContext)
677 {
678 VBVAHOSTCMD *pCmd;
679 do
680 pCmd = ASMAtomicReadPtrT(&pDispContext->pCmd, VBVAHOSTCMD *);
681 while (!ASMAtomicCmpXchgPtr(&pDispContext->pCmd, NULL, pCmd));
682 *ppCmd = vboxVBVAReverseList(pCmd);
683
684 return VINF_SUCCESS;
685 }
686 }
687
688 return VERR_INVALID_PARAMETER;
689}
690
691
692static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
693{
694 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
695// Assert(0);
696 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
697 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
698 {
699 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
700 Assert(pHdr->iDstID >= 0);
701 if(pHdr->iDstID >= 0)
702 {
703 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
704 Assert(pHandler && pHandler->bValid);
705 if(pHandler && pHandler->bValid)
706 {
707 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
708 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
709 {
710 Assert(!pCur->u.Data);
711 Assert(!pFirst);
712 Assert(!pLast);
713
714 switch(u16ChannelInfo)
715 {
716 case VBVAHG_DISPLAY_CUSTOM:
717 {
718#if 0 /* Never taken */
719 if(pLast)
720 {
721 pLast->u.pNext = pCur;
722 pLast = pCur;
723 }
724 else
725#endif
726 {
727 pFirst = pCur;
728 pLast = pCur;
729 }
730 Assert(!pCur->u.Data);
731#if 0 /* Who is supposed to set pNext? */
732 //TODO: use offset here
733 pCur = pCur->u.pNext;
734 Assert(!pCur);
735#else
736 Assert(!pCur->u.pNext);
737 pCur = NULL;
738#endif
739 Assert(pFirst);
740 Assert(pFirst == pLast);
741 break;
742 }
743 case VBVAHG_EVENT:
744 {
745 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
746 VBoxVideoCmnSignalEvent(pCallbacks->pCommon, pEventCmd->pEvent);
747 }
748 default:
749 {
750 Assert(u16ChannelInfo==VBVAHG_EVENT);
751 Assert(!pCur->u.Data);
752#if 0 /* pLast has been asserted to be NULL, and who should set pNext? */
753 //TODO: use offset here
754 if(pLast)
755 pLast->u.pNext = pCur->u.pNext;
756 VBVAHOSTCMD * pNext = pCur->u.pNext;
757 pCur->u.pNext = NULL;
758#else
759 Assert(!pCur->u.pNext);
760#endif
761 HGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pCur);
762#if 0 /* pNext is NULL, and the other things have already been asserted */
763 pCur = pNext;
764 Assert(!pCur);
765 Assert(!pFirst);
766 Assert(pFirst == pLast);
767#else
768 pCur = NULL;
769#endif
770 break;
771 }
772 }
773 }
774
775 /* we do not support lists currently */
776 Assert(pFirst == pLast);
777 if(pLast)
778 {
779 Assert(pLast->u.pNext == NULL);
780 }
781
782 if(pFirst)
783 {
784 Assert(pLast);
785 VBVAHOSTCMD *pCmd;
786 do
787 {
788 pCmd = ASMAtomicReadPtrT(&pHandler->pCmd, VBVAHOSTCMD *);
789 pFirst->u.pNext = pCmd;
790 }
791 while (!ASMAtomicCmpXchgPtr(&pHandler->pCmd, pFirst, pCmd));
792 }
793 else
794 {
795 Assert(!pLast);
796 }
797 return VINF_SUCCESS;
798 }
799 }
800 else
801 {
802 //TODO: impl
803// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
804// if(pHandler && pHandler->pfnChannelHandler)
805// {
806// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
807//
808// return VINF_SUCCESS;
809// }
810 }
811 }
812 /* no handlers were found, need to complete the command here */
813 HGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pvBuffer);
814 return VINF_SUCCESS;
815}
816
817static HGSMICHANNELHANDLER g_OldHandler;
818
819int vboxVBVAChannelDisplayEnable(PVBOXVIDEO_COMMON pCommon,
820 int iDisplay, /* negative would mean this is a miniport handler */
821 uint8_t u8Channel)
822{
823 VBVA_CHANNELCONTEXTS * pContexts;
824 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&pCommon->hostCtx.channels, u8Channel);
825 if(!pChannel)
826 {
827 int rc = vboxVBVACreateChannelContexts(pCommon, &pContexts);
828 if(RT_FAILURE(rc))
829 {
830 return rc;
831 }
832 }
833 else
834 {
835 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
836 }
837
838 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
839 Assert(pDispContext);
840 if(pDispContext)
841 {
842#ifdef DEBUGVHWASTRICT
843 Assert(!pDispContext->bValid);
844#endif
845 Assert(!pDispContext->pCmd);
846 if(!pDispContext->bValid)
847 {
848 pDispContext->bValid = true;
849 pDispContext->pCmd = NULL;
850
851 int rc = VINF_SUCCESS;
852 if(!pChannel)
853 {
854 rc = HGSMIChannelRegister (&pCommon->hostCtx.channels,
855 u8Channel,
856 "VGA Miniport HGSMI channel",
857 vboxVBVAChannelGenericHandler,
858 pContexts,
859 &g_OldHandler);
860 }
861
862 if(RT_SUCCESS(rc))
863 {
864 pContexts->cUsed++;
865 return VINF_SUCCESS;
866 }
867 }
868 }
869
870 if(!pChannel)
871 {
872 vboxVBVADeleteChannelContexts(pCommon, pContexts);
873 }
874
875 return VERR_GENERAL_FAILURE;
876}
877#endif /* !VBOX_WITH_WDDM */
878
879/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
880 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
881 * host information which is needed by the guest.
882 *
883 * Reading will not cause a switch to the host.
884 *
885 * Have to take into account:
886 * * synchronization: host must write to the memory only from EMT,
887 * large structures must be read under flag, which tells the host
888 * that the guest is currently reading the memory (OWNER flag?).
889 * * guest writes: may be allocate a page for the host info and make
890 * the page readonly for the guest.
891 * * the information should be available only for additions drivers.
892 * * VMMDev additions driver will inform the host which version of the info it expects,
893 * host must support all versions.
894 *
895 */
896
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