VirtualBox

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

Last change on this file since 33876 was 33876, 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: 33.2 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 33876 2010-11-08 21:32:28Z 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
19#include "VBoxVideo.h"
20#include "Helper.h"
21
22#include <iprt/asm.h>
23#include <iprt/log.h>
24#include <iprt/thread.h>
25#include <VBox/VMMDev.h>
26#include <VBox/VBoxGuest.h>
27#include <VBox/VBoxVideo.h>
28
29#include <VBoxDisplay.h>
30
31#include "vboxioctl.h"
32
33void HGSMINotifyHostCmdComplete (PVBOXVIDEO_COMMON pCommon, HGSMIOFFSET offt)
34{
35 VBoxHGSMIHostWrite(pCommon, offt);
36}
37
38void HGSMIClearIrq (PVBOXVIDEO_COMMON pCommon)
39{
40 VBoxHGSMIHostWrite(pCommon, HGSMIOFFSET_VOID);
41}
42
43static void HGSMIHostCmdComplete (PVBOXVIDEO_COMMON pCommon, void * pvMem)
44{
45 HGSMIOFFSET offMem = HGSMIPointerToOffset (&pCommon->areaHostHeap, HGSMIBufferHeaderFromData (pvMem));
46 Assert(offMem != HGSMIOFFSET_VOID);
47 if(offMem != HGSMIOFFSET_VOID)
48 {
49 HGSMINotifyHostCmdComplete (pCommon, offMem);
50 }
51}
52
53static void hgsmiHostCmdProcess(PVBOXVIDEO_COMMON pCommon, HGSMIOFFSET offBuffer)
54{
55 int rc = HGSMIBufferProcess (&pCommon->areaHostHeap,
56 &pCommon->channels,
57 offBuffer);
58 Assert(!RT_FAILURE(rc));
59 if(RT_FAILURE(rc))
60 {
61 /* failure means the command was not submitted to the handler for some reason
62 * it's our responsibility to notify its completion in this case */
63 HGSMINotifyHostCmdComplete(pCommon, offBuffer);
64 }
65 /* if the cmd succeeded it's responsibility of the callback to complete it */
66}
67
68static HGSMIOFFSET hgsmiGetHostBuffer (PVBOXVIDEO_COMMON pCommon)
69{
70 return VBoxHGSMIHostRead(pCommon);
71}
72
73static void hgsmiHostCommandQueryProcess (PVBOXVIDEO_COMMON pCommon)
74{
75 HGSMIOFFSET offset = hgsmiGetHostBuffer (pCommon);
76 Assert(offset != HGSMIOFFSET_VOID);
77 if(offset != HGSMIOFFSET_VOID)
78 {
79 hgsmiHostCmdProcess(pCommon, offset);
80 }
81}
82
83void hgsmiProcessHostCommandQueue(PVBOXVIDEO_COMMON pCommon)
84{
85 while (pCommon->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
86 {
87 if (!ASMAtomicCmpXchgBool(&pCommon->bHostCmdProcessing, true, false))
88 return;
89 hgsmiHostCommandQueryProcess(pCommon);
90 ASMAtomicWriteBool(&pCommon->bHostCmdProcessing, false);
91 }
92}
93
94/* Detect whether HGSMI is supported by the host. */
95BOOLEAN VBoxHGSMIIsSupported (void)
96{
97 USHORT DispiId;
98
99 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
100 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
101
102 DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
103
104 return (DispiId == VBE_DISPI_ID_HGSMI);
105}
106
107typedef int FNHGSMICALLINIT (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData);
108typedef FNHGSMICALLINIT *PFNHGSMICALLINIT;
109
110typedef int FNHGSMICALLFINALIZE (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData);
111typedef FNHGSMICALLFINALIZE *PFNHGSMICALLFINALIZE;
112
113void* vboxHGSMIBufferAlloc(PVBOXVIDEO_COMMON pCommon,
114 HGSMISIZE cbData,
115 uint8_t u8Ch,
116 uint16_t u16Op)
117{
118#ifdef VBOX_WITH_WDDM
119 /* @todo: add synchronization */
120#endif
121 return HGSMIHeapAlloc (&pCommon->hgsmiAdapterHeap, cbData, u8Ch, u16Op);
122}
123
124void vboxHGSMIBufferFree (PVBOXVIDEO_COMMON pCommon, void *pvBuffer)
125{
126#ifdef VBOX_WITH_WDDM
127 /* @todo: add synchronization */
128#endif
129 HGSMIHeapFree (&pCommon->hgsmiAdapterHeap, pvBuffer);
130}
131
132int vboxHGSMIBufferSubmit (PVBOXVIDEO_COMMON pCommon, void *pvBuffer)
133{
134 /* Initialize the buffer and get the offset for port IO. */
135 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCommon->hgsmiAdapterHeap, pvBuffer);
136
137 Assert(offBuffer != HGSMIOFFSET_VOID);
138 if (offBuffer != HGSMIOFFSET_VOID)
139 {
140 /* Submit the buffer to the host. */
141 VBoxHGSMIGuestWrite(pCommon, offBuffer);
142 return VINF_SUCCESS;
143 }
144
145 return VERR_INVALID_PARAMETER;
146}
147
148static int vboxCallChannel (PVBOXVIDEO_COMMON pCommon,
149 uint8_t u8Ch,
150 uint16_t u16Op,
151 HGSMISIZE cbData,
152 PFNHGSMICALLINIT pfnInit,
153 PFNHGSMICALLFINALIZE pfnFinalize,
154 void *pvContext)
155{
156 int rc = VINF_SUCCESS;
157
158 /* Allocate the IO buffer. */
159 void *p = HGSMIHeapAlloc (&pCommon->hgsmiAdapterHeap, cbData, u8Ch, u16Op);
160
161 if (!p)
162 {
163 rc = VERR_NO_MEMORY;
164 }
165 else
166 {
167 /* Prepare data to be sent to the host. */
168 if (pfnInit)
169 {
170 rc = pfnInit (pCommon, pvContext, p);
171 }
172
173 if (RT_SUCCESS (rc))
174 {
175 /* Initialize the buffer and get the offset for port IO. */
176 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCommon->hgsmiAdapterHeap,
177 p);
178
179 /* Submit the buffer to the host. */
180 VBoxHGSMIGuestWrite(pCommon, offBuffer);
181
182 if (pfnFinalize)
183 {
184 rc = pfnFinalize (pCommon, pvContext, p);
185 }
186 }
187 else
188 {
189 AssertFailed ();
190 rc = VERR_INTERNAL_ERROR;
191 }
192
193 /* Free the IO buffer. */
194 HGSMIHeapFree (&pCommon->hgsmiAdapterHeap, p);
195 }
196
197 return rc;
198}
199
200static int vboxCallVBVA (PVBOXVIDEO_COMMON pCommon,
201 uint16_t u16Op,
202 HGSMISIZE cbData,
203 PFNHGSMICALLINIT pfnInit,
204 PFNHGSMICALLFINALIZE pfnFinalize,
205 void *pvContext)
206{
207 return vboxCallChannel (pCommon,
208 HGSMI_CH_VBVA,
209 u16Op,
210 cbData,
211 pfnInit,
212 pfnFinalize,
213 pvContext);
214}
215
216typedef struct _QUERYCONFCTX
217{
218 uint32_t u32Index;
219 ULONG *pulValue;
220} QUERYCONFCTX;
221
222static int vbvaInitQueryConf (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
223{
224 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
225 VBVACONF32 *p = (VBVACONF32 *)pvData;
226
227 p->u32Index = pCtx->u32Index;
228 p->u32Value = 0;
229
230 return VINF_SUCCESS;
231}
232
233static int vbvaFinalizeQueryConf (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
234{
235 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
236 VBVACONF32 *p = (VBVACONF32 *)pvData;
237
238 if (pCtx->pulValue)
239 {
240 *pCtx->pulValue = p->u32Value;
241 }
242
243 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->u32Value));
244 return VINF_SUCCESS;
245}
246
247static int vboxQueryConfHGSMI (PVBOXVIDEO_COMMON pCommon, uint32_t u32Index, ULONG *pulValue)
248{
249 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
250
251 QUERYCONFCTX context;
252
253 context.u32Index = u32Index;
254 context.pulValue = pulValue;
255
256 int rc = vboxCallVBVA (pCommon,
257 VBVA_QUERY_CONF32,
258 sizeof (VBVACONF32),
259 vbvaInitQueryConf,
260 vbvaFinalizeQueryConf,
261 &context);
262
263 dprintf(("VBoxVideo::vboxQueryConf: rc = %d\n", rc));
264
265 return rc;
266}
267
268int VBoxHGSMISendViewInfo(PVBOXVIDEO_COMMON pCommon, uint32_t u32Count, PFNHGSMIFILLVIEWINFO pfnFill, void *pvData)
269{
270 int rc;
271 /* Issue the screen info command. */
272 void *p = vboxHGSMIBufferAlloc (pCommon, sizeof(VBVAINFOVIEW) * u32Count,
273 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
274 Assert(p);
275 if (p)
276 {
277 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
278 rc = pfnFill(pvData, pInfo);
279 if (RT_SUCCESS(rc))
280 vboxHGSMIBufferSubmit (pCommon, p);
281 vboxHGSMIBufferFree (pCommon, p);
282 }
283 else
284 rc = VERR_NO_MEMORY;
285 return rc;
286}
287
288
289int vbvaInitInfoCaps (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
290{
291 VBVACAPS *pCaps = (VBVACAPS*)pvData;
292 pCaps->rc = VERR_NOT_IMPLEMENTED;
293 pCaps->fCaps = pCommon->fCaps;
294 return VINF_SUCCESS;
295}
296
297
298int vbvaFinalizeInfoCaps (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
299{
300 VBVACAPS *pCaps = (VBVACAPS*)pvData;
301 AssertRC(pCaps->rc);
302 return pCaps->rc;
303}
304
305static int vbvaInitInfoHeap (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
306{
307 NOREF (pvContext);
308 VBVAINFOHEAP *p = (VBVAINFOHEAP *)pvData;
309
310 p->u32HeapOffset = pCommon->cbVRAM
311 - pCommon->cbMiniportHeap
312 - VBVA_ADAPTER_INFORMATION_SIZE;
313 p->u32HeapSize = pCommon->cbMiniportHeap;
314
315 return VINF_SUCCESS;
316}
317
318static int hgsmiInitFlagsLocation (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
319{
320 NOREF (pvContext);
321 HGSMIBUFFERLOCATION *p = (HGSMIBUFFERLOCATION *)pvData;
322
323 p->offLocation = pCommon->cbVRAM - sizeof (HGSMIHOSTFLAGS);
324 p->cbLocation = sizeof (HGSMIHOSTFLAGS);
325
326 return VINF_SUCCESS;
327}
328
329
330static int vboxSetupAdapterInfoHGSMI (PVBOXVIDEO_COMMON pCommon)
331{
332 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
333
334 /* setup the flags first to ensure they are initialized by the time the host heap is ready */
335 int rc = vboxCallChannel(pCommon,
336 HGSMI_CH_HGSMI,
337 HGSMI_CC_HOST_FLAGS_LOCATION,
338 sizeof (HGSMIBUFFERLOCATION),
339 hgsmiInitFlagsLocation,
340 NULL,
341 NULL);
342 AssertRC(rc);
343 if (RT_SUCCESS(rc) && pCommon->fCaps)
344 {
345 /* Inform about caps */
346 rc = vboxCallVBVA (pCommon,
347 VBVA_INFO_CAPS,
348 sizeof (VBVACAPS),
349 vbvaInitInfoCaps,
350 vbvaFinalizeInfoCaps,
351 NULL);
352 AssertRC(rc);
353 }
354 if (RT_SUCCESS (rc))
355 {
356 /* Report the host heap location. */
357 rc = vboxCallVBVA (pCommon,
358 VBVA_INFO_HEAP,
359 sizeof (VBVAINFOHEAP),
360 vbvaInitInfoHeap,
361 NULL,
362 NULL);
363 AssertRC(rc);
364 }
365
366
367 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
368
369 return rc;
370}
371
372
373/**
374 * Helper function to register secondary displays (DualView). Note that this will not
375 * be available on pre-XP versions, and some editions on XP will fail because they are
376 * intentionally crippled.
377 *
378 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
379 * to talk to the host.
380 */
381VOID VBoxSetupDisplaysHGSMI(PVBOXVIDEO_COMMON pCommon,
382 ULONG AdapterMemorySize, uint32_t fCaps)
383{
384 VP_STATUS rc = NO_ERROR;
385
386 dprintf(("VBoxVideo::VBoxSetupDisplays: pCommon = %p\n", pCommon));
387
388 memset(pCommon, 0, sizeof(*pCommon));
389 pCommon->cbVRAM = AdapterMemorySize;
390 pCommon->fCaps = fCaps;
391 pCommon->cDisplays = 1;
392 pCommon->bHGSMI = VBoxHGSMIIsSupported ();
393 /* Why does this use VBoxVideoCmnMemZero? The MSDN docs say that it should
394 * only be used on mapped display adapter memory. Done with memset above. */
395 // VBoxVideoCmnMemZero(&pCommon->areaHostHeap, sizeof(HGSMIAREA));
396 if (pCommon->bHGSMI)
397 {
398 /** @note (michael) moved this here as it is done unconditionally in both
399 * driver branches. Feel free to fix if that is ever changed. */
400 pCommon->IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
401 pCommon->IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
402
403 /* Map the adapter information. It will be needed for HGSMI IO. */
404 rc = VBoxMapAdapterMemory (pCommon, &pCommon->pvAdapterInformation,
405 AdapterMemorySize - VBVA_ADAPTER_INFORMATION_SIZE,
406 VBVA_ADAPTER_INFORMATION_SIZE
407 );
408 if (rc != NO_ERROR)
409 {
410 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
411 rc));
412
413 pCommon->bHGSMI = FALSE;
414 }
415 else
416 {
417 /* Setup a HGSMI heap within the adapter information area. */
418 rc = HGSMIHeapSetup (&pCommon->hgsmiAdapterHeap,
419 pCommon->pvAdapterInformation,
420 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
421 pCommon->cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
422 false /*fOffsetBased*/);
423
424 if (RT_FAILURE (rc))
425 {
426 dprintf(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
427 rc));
428
429 pCommon->bHGSMI = FALSE;
430 }
431 else
432 {
433 pCommon->pHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)pCommon->pvAdapterInformation)
434 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
435 }
436 }
437 }
438
439 /* Setup the host heap and the adapter memory. */
440 if (pCommon->bHGSMI)
441 {
442 /* The miniport heap is used for the host buffers. */
443 ULONG cbMiniportHeap = 0;
444 vboxQueryConfHGSMI (pCommon, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbMiniportHeap);
445
446 if (cbMiniportHeap != 0)
447 {
448 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
449 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 4;
450
451 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
452 {
453 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
454 }
455
456 if (cbMiniportHeap > cbMiniportHeapMaxSize)
457 {
458 cbMiniportHeap = cbMiniportHeapMaxSize;
459 }
460
461 /* Round up to 4096 bytes. */
462 pCommon->cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
463
464 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, pCommon->cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
465 cbMiniportHeap, pCommon->cbMiniportHeap, cbMiniportHeapMaxSize));
466
467 /* Map the heap region.
468 *
469 * Note: the heap will be used for the host buffers submitted to the guest.
470 * The miniport driver is responsible for reading FIFO and notifying
471 * display drivers.
472 */
473 rc = VBoxMapAdapterMemory (pCommon, &pCommon->pvMiniportHeap,
474 pCommon->cbVRAM
475 - VBVA_ADAPTER_INFORMATION_SIZE
476 - pCommon->cbMiniportHeap,
477 pCommon->cbMiniportHeap
478 );
479 if (rc != NO_ERROR)
480 {
481 pCommon->pvMiniportHeap = NULL;
482 pCommon->cbMiniportHeap = 0;
483 pCommon->bHGSMI = FALSE;
484 }
485 else
486 {
487 HGSMIOFFSET offBase = pCommon->cbVRAM
488 - VBVA_ADAPTER_INFORMATION_SIZE
489 - pCommon->cbMiniportHeap;
490
491 /* Init the host hap area. Buffers from the host will be placed there. */
492 HGSMIAreaInitialize (&pCommon->areaHostHeap,
493 pCommon->pvMiniportHeap,
494 pCommon->cbMiniportHeap,
495 offBase);
496 }
497 }
498 else
499 {
500 /* Host has not requested a heap. */
501 pCommon->pvMiniportHeap = NULL;
502 pCommon->cbMiniportHeap = 0;
503 }
504 }
505
506 /* Check whether the guest supports multimonitors. */
507 if (pCommon->bHGSMI)
508 {
509 /* Query the configured number of displays. */
510 ULONG cDisplays = 0;
511 vboxQueryConfHGSMI (pCommon, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
512
513 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
514 cDisplays));
515
516 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
517 {
518 /* Host reported some bad value. Continue in the 1 screen mode. */
519 cDisplays = 1;
520 }
521 pCommon->cDisplays = cDisplays;
522 }
523
524 if (pCommon->bHGSMI)
525 {
526 /* Setup the information for the host. */
527 rc = vboxSetupAdapterInfoHGSMI (pCommon);
528
529 if (RT_FAILURE (rc))
530 {
531 pCommon->bHGSMI = FALSE;
532 }
533 }
534
535 if (!pCommon->bHGSMI)
536 VBoxFreeDisplaysHGSMI(pCommon);
537
538 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
539}
540
541static bool VBoxUnmapAdpInfoCallback(PVOID pvCommon)
542{
543 PVBOXVIDEO_COMMON pCommon = (PVBOXVIDEO_COMMON)pvCommon;
544
545 pCommon->pHostFlags = NULL;
546 return TRUE;
547}
548
549void VBoxFreeDisplaysHGSMI(PVBOXVIDEO_COMMON pCommon)
550{
551 VBoxUnmapAdapterMemory(pCommon, &pCommon->pvMiniportHeap);
552 HGSMIHeapDestroy(&pCommon->hgsmiAdapterHeap);
553
554 /* Unmap the adapter information needed for HGSMI IO. */
555 VBoxSyncToVideoIRQ(pCommon, VBoxUnmapAdpInfoCallback, pCommon);
556 VBoxUnmapAdapterMemory(pCommon, &pCommon->pvAdapterInformation);
557}
558
559/*
560 * Send the pointer shape to the host.
561 */
562typedef struct _MOUSEPOINTERSHAPECTX
563{
564 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
565 uint32_t cbData;
566 int32_t i32Result;
567} MOUSEPOINTERSHAPECTX;
568
569static int vbvaInitMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
570{
571 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
572 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
573
574 /* Will be updated by the host. */
575 p->i32Result = VINF_SUCCESS;
576
577 /* We have our custom flags in the field */
578 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
579
580 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
581 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
582 p->u32Width = pCtx->pPointerAttr->Width;
583 p->u32Height = pCtx->pPointerAttr->Height;
584
585 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
586 {
587 /* If shape is supplied, then always create the pointer visible.
588 * See comments in 'vboxUpdatePointerShape'
589 */
590 p->fu32Flags |= VBOX_MOUSE_POINTER_VISIBLE;
591
592 /* Copy the actual pointer data. */
593 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
594 }
595
596 return VINF_SUCCESS;
597}
598
599static int vbvaFinalizeMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
600{
601 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
602 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
603
604 pCtx->i32Result = p->i32Result;
605
606 return VINF_SUCCESS;
607}
608
609BOOLEAN vboxUpdatePointerShape (PVBOXVIDEO_COMMON pCommon,
610 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
611 uint32_t cbLength)
612{
613 uint32_t cbData = 0;
614
615 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
616 {
617 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
618 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
619 + pointerAttr->Width * 4 * pointerAttr->Height;
620 }
621
622#ifndef DEBUG_misha
623 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
624 cbData, pointerAttr->Width, pointerAttr->Height));
625#endif
626
627 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
628 {
629 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
630 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
631 return FALSE;
632 }
633
634 MOUSEPOINTERSHAPECTX ctx;
635
636 ctx.pPointerAttr = pointerAttr;
637 ctx.cbData = cbData;
638 ctx.i32Result = VERR_NOT_SUPPORTED;
639
640 int rc = vboxCallVBVA (pCommon, VBVA_MOUSE_POINTER_SHAPE,
641 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
642 vbvaInitMousePointerShape,
643 vbvaFinalizeMousePointerShape,
644 &ctx);
645#ifndef DEBUG_misha
646 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
647#endif
648
649 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
650}
651
652#ifndef VBOX_WITH_WDDM
653typedef struct _VBVAMINIPORT_CHANNELCONTEXT
654{
655 PFNHGSMICHANNELHANDLER pfnChannelHandler;
656 void *pvChannelHandler;
657}VBVAMINIPORT_CHANNELCONTEXT;
658
659typedef struct _VBVADISP_CHANNELCONTEXT
660{
661 struct _VBVAHOSTCMD * pFirstCmd;
662 struct _VBVAHOSTCMD * pLastCmd;
663 VBOXVCMNSPIN_LOCK pSynchLock;
664#ifdef DEBUG
665 int cCmds;
666#endif
667 bool bValid;
668}VBVADISP_CHANNELCONTEXT;
669
670#ifdef DEBUG
671void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
672{
673 int counter = 0;
674 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
675 {
676 Assert(pCur != pCmd);
677 if(pCur == pList->pLastCmd)
678 {
679 Assert(pCur->u.pNext == NULL);
680 }
681 if(pCur->u.pNext == NULL)
682 {
683 Assert(pCur == pList->pLastCmd);
684 }
685 counter++;
686 }
687
688 Assert(counter == pList->cCmds);
689}
690
691void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
692{
693 VBOXVCMNIRQL oldIrql;
694 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pList->pSynchLock, &oldIrql);
695
696 dbgCheckListLocked(pList, pCmd);
697
698 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pList->pSynchLock, oldIrql);
699}
700
701#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
702#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
703
704#else
705#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
706#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
707#endif
708
709
710typedef struct _VBVA_CHANNELCONTEXTS
711{
712 PDEVICE_EXTENSION PrimaryExtension;
713 uint32_t cUsed;
714 uint32_t cContexts;
715 VBVAMINIPORT_CHANNELCONTEXT mpContext;
716 VBVADISP_CHANNELCONTEXT aContexts[1];
717}VBVA_CHANNELCONTEXTS;
718
719static int vboxVBVADeleteChannelContexts(PVBOXVIDEO_COMMON pCommon,
720 VBVA_CHANNELCONTEXTS * pContext)
721{
722 VBoxVideoCmnMemFreeDriver(pCommon, pContext);
723 return VINF_SUCCESS;
724}
725
726static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
727{
728 uint32_t cDisplays = (uint32_t)commonFromDeviceExt(PrimaryExtension)->cDisplays;
729 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
730 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocDriver(commonFromDeviceExt(PrimaryExtension), size);
731 if(pContext)
732 {
733 memset(pContext, 0, size);
734 pContext->cContexts = cDisplays;
735 pContext->PrimaryExtension = PrimaryExtension;
736 *ppContext = pContext;
737 return VINF_SUCCESS;
738 }
739 return VERR_GENERAL_FAILURE;
740}
741
742static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
743{
744 if(iId < 0)
745 {
746 return NULL;
747 }
748 else if(pCallbacks->cContexts > (uint32_t)iId)
749 {
750 return &pCallbacks->aContexts[iId];
751 }
752 return NULL;
753}
754
755DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
756{
757 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
758 HGSMIHostCmdComplete (commonFromDeviceExt(PrimaryExtension), pCmd);
759}
760
761DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
762{
763// if(display < 0)
764// return VERR_INVALID_PARAMETER;
765 if(!ppCmd)
766 return VERR_INVALID_PARAMETER;
767
768 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
769 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
770
771 /* pick up the host commands */
772 hgsmiProcessHostCommandQueue(commonFromDeviceExt(PrimaryExtension));
773
774 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
775 if(pChannel)
776 {
777 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
778 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
779 Assert(pDispContext);
780 if(pDispContext)
781 {
782 UCHAR oldIrql;
783 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pDispContext->pSynchLock, &oldIrql);
784
785 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
786
787 *ppCmd = pDispContext->pFirstCmd;
788 pDispContext->pFirstCmd = NULL;
789 pDispContext->pLastCmd = NULL;
790#ifdef DEBUG
791 pDispContext->cCmds = 0;
792#endif
793 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pDispContext->pSynchLock, oldIrql);
794
795 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
796
797 return VINF_SUCCESS;
798 }
799 }
800
801 return VERR_INVALID_PARAMETER;
802}
803
804
805static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
806{
807 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
808// Assert(0);
809 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
810 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
811 {
812 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
813 Assert(pHdr->iDstID >= 0);
814 if(pHdr->iDstID >= 0)
815 {
816 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
817 Assert(pHandler && pHandler->bValid);
818 if(pHandler && pHandler->bValid)
819 {
820 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
821 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
822 {
823 Assert(!pCur->u.Data);
824 Assert(!pFirst);
825 Assert(!pLast);
826
827 switch(u16ChannelInfo)
828 {
829 case VBVAHG_DISPLAY_CUSTOM:
830 {
831#if 0 /* Never taken */
832 if(pLast)
833 {
834 pLast->u.pNext = pCur;
835 pLast = pCur;
836 }
837 else
838#endif
839 {
840 pFirst = pCur;
841 pLast = pCur;
842 }
843 Assert(!pCur->u.Data);
844#if 0 /* Who is supposed to set pNext? */
845 //TODO: use offset here
846 pCur = pCur->u.pNext;
847 Assert(!pCur);
848#else
849 Assert(!pCur->u.pNext);
850 pCur = NULL;
851#endif
852 Assert(pFirst);
853 Assert(pFirst == pLast);
854 break;
855 }
856 case VBVAHG_EVENT:
857 {
858 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
859 VBoxVideoCmnSignalEvent(commonFromDeviceExt(pCallbacks->PrimaryExtension), pEventCmd->pEvent);
860 }
861 default:
862 {
863 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
864 Assert(u16ChannelInfo==VBVAHG_EVENT);
865 Assert(!pCur->u.Data);
866#if 0 /* pLast has been asserted to be NULL, and who should set pNext? */
867 //TODO: use offset here
868 if(pLast)
869 pLast->u.pNext = pCur->u.pNext;
870 VBVAHOSTCMD * pNext = pCur->u.pNext;
871 pCur->u.pNext = NULL;
872#else
873 Assert(!pCur->u.pNext);
874#endif
875 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pCur);
876#if 0 /* pNext is NULL, and the other things have already been asserted */
877 pCur = pNext;
878 Assert(!pCur);
879 Assert(!pFirst);
880 Assert(pFirst == pLast);
881#else
882 pCur = NULL;
883#endif
884 break;
885 }
886 }
887 }
888
889 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
890
891 /* we do not support lists currently */
892 Assert(pFirst == pLast);
893 if(pLast)
894 {
895 Assert(pLast->u.pNext == NULL);
896 }
897
898 if(pFirst)
899 {
900 Assert(pLast);
901 UCHAR oldIrql;
902 VBoxVideoCmnSpinLockAcquire(pCallbacks->PrimaryExtension,
903 &pHandler->pSynchLock,
904 &oldIrql);
905
906 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
907
908 if(pHandler->pLastCmd)
909 {
910 pHandler->pLastCmd->u.pNext = pFirst;
911 Assert(pHandler->pFirstCmd);
912 }
913 else
914 {
915 Assert(!pHandler->pFirstCmd);
916 pHandler->pFirstCmd = pFirst;
917 }
918 pHandler->pLastCmd = pLast;
919#ifdef DEBUG
920 pHandler->cCmds++;
921#endif
922 DBG_CHECKLIST_LOCKED(pHandler, NULL);
923
924 VBoxVideoCmnSpinLockRelease(pCallbacks->PrimaryExtension,
925 &pHandler->pSynchLock,
926 oldIrql);
927 }
928 else
929 {
930 Assert(!pLast);
931 }
932 return VINF_SUCCESS;
933 }
934 }
935 else
936 {
937 //TODO: impl
938// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
939// if(pHandler && pHandler->pfnChannelHandler)
940// {
941// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
942//
943// return VINF_SUCCESS;
944// }
945 }
946 }
947 /* no handlers were found, need to complete the command here */
948 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pvBuffer);
949 return VINF_SUCCESS;
950}
951
952static HGSMICHANNELHANDLER g_OldHandler;
953
954int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
955 int iDisplay, /* negative would mean this is a miniport handler */
956 uint8_t u8Channel)
957{
958 VBVA_CHANNELCONTEXTS * pContexts;
959 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
960 if(!pChannel)
961 {
962 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
963 if(RT_FAILURE(rc))
964 {
965 return rc;
966 }
967 }
968 else
969 {
970 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
971 }
972
973 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
974 Assert(pDispContext);
975 if(pDispContext)
976 {
977#ifdef DEBUGVHWASTRICT
978 Assert(!pDispContext->bValid);
979#endif
980 Assert(!pDispContext->pFirstCmd);
981 Assert(!pDispContext->pLastCmd);
982 if(!pDispContext->bValid)
983 {
984 pDispContext->bValid = true;
985 pDispContext->pFirstCmd = NULL;
986 pDispContext->pLastCmd= NULL;
987#ifdef DEBUG
988 pDispContext->cCmds = 0;
989#endif
990
991 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &pDispContext->pSynchLock);
992
993 int rc = VINF_SUCCESS;
994 if(!pChannel)
995 {
996 rc = HGSMIChannelRegister (&commonFromDeviceExt(PrimaryExtension)->channels,
997 u8Channel,
998 "VGA Miniport HGSMI channel",
999 vboxVBVAChannelGenericHandler,
1000 pContexts,
1001 &g_OldHandler);
1002 }
1003
1004 if(RT_SUCCESS(rc))
1005 {
1006 pContexts->cUsed++;
1007 return VINF_SUCCESS;
1008 }
1009 }
1010 }
1011
1012 if(!pChannel)
1013 {
1014 vboxVBVADeleteChannelContexts(commonFromDeviceExt(PrimaryExtension), pContexts);
1015 }
1016
1017 return VERR_GENERAL_FAILURE;
1018}
1019#endif /* !VBOX_WITH_WDDM */
1020
1021/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1022 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1023 * host information which is needed by the guest.
1024 *
1025 * Reading will not cause a switch to the host.
1026 *
1027 * Have to take into account:
1028 * * synchronization: host must write to the memory only from EMT,
1029 * large structures must be read under flag, which tells the host
1030 * that the guest is currently reading the memory (OWNER flag?).
1031 * * guest writes: may be allocate a page for the host info and make
1032 * the page readonly for the guest.
1033 * * the information should be available only for additions drivers.
1034 * * VMMDev additions driver will inform the host which version of the info it expects,
1035 * host must support all versions.
1036 *
1037 */
1038
Note: See TracBrowser for help on using the repository browser.

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