VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring and some cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.5 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 33997 2010-11-11 14:45:10Z 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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 Log(("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 /** The generic command handler builds up a list of commands - in reverse
662 * order! - here */
663 VBVAHOSTCMD *pCmd;
664 bool bValid;
665}VBVADISP_CHANNELCONTEXT;
666
667typedef struct _VBVA_CHANNELCONTEXTS
668{
669 PVBOXVIDEO_COMMON pCommon;
670 uint32_t cUsed;
671 uint32_t cContexts;
672 VBVAMINIPORT_CHANNELCONTEXT mpContext;
673 VBVADISP_CHANNELCONTEXT aContexts[1];
674}VBVA_CHANNELCONTEXTS;
675
676static int vboxVBVADeleteChannelContexts(PVBOXVIDEO_COMMON pCommon,
677 VBVA_CHANNELCONTEXTS * pContext)
678{
679 VBoxVideoCmnMemFreeDriver(pCommon, pContext);
680 return VINF_SUCCESS;
681}
682
683static int vboxVBVACreateChannelContexts(PVBOXVIDEO_COMMON pCommon, VBVA_CHANNELCONTEXTS ** ppContext)
684{
685 uint32_t cDisplays = (uint32_t)pCommon->cDisplays;
686 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
687 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocDriver(pCommon, size);
688 if(pContext)
689 {
690 memset(pContext, 0, size);
691 pContext->cContexts = cDisplays;
692 pContext->pCommon = pCommon;
693 *ppContext = pContext;
694 return VINF_SUCCESS;
695 }
696 return VERR_GENERAL_FAILURE;
697}
698
699static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
700{
701 if(iId < 0)
702 {
703 return NULL;
704 }
705 else if(pCallbacks->cContexts > (uint32_t)iId)
706 {
707 return &pCallbacks->aContexts[iId];
708 }
709 return NULL;
710}
711
712DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
713{
714 PVBOXVIDEO_COMMON pCommon = (PVBOXVIDEO_COMMON)hHGSMI;
715 HGSMIHostCmdComplete (pCommon, pCmd);
716}
717
718/** Reverses a NULL-terminated linked list of VBVAHOSTCMD structures. */
719static VBVAHOSTCMD *vboxVBVAReverseList(VBVAHOSTCMD *pList)
720{
721 VBVAHOSTCMD *pFirst = NULL;
722 while (pList)
723 {
724 VBVAHOSTCMD *pNext = pList;
725 pList = pList->u.pNext;
726 pNext->u.pNext = pFirst;
727 pFirst = pNext;
728 }
729 return pFirst;
730}
731
732DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, uint32_t iDevice, struct _VBVAHOSTCMD ** ppCmd)
733{
734// if(display < 0)
735// return VERR_INVALID_PARAMETER;
736 if(!ppCmd)
737 return VERR_INVALID_PARAMETER;
738
739 PVBOXVIDEO_COMMON pCommon = (PVBOXVIDEO_COMMON)hHGSMI;
740
741 /* pick up the host commands */
742 hgsmiProcessHostCommandQueue(pCommon);
743
744 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&pCommon->channels, u8Channel);
745 if(pChannel)
746 {
747 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
748 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDevice);
749 Assert(pDispContext);
750 if(pDispContext)
751 {
752 VBVAHOSTCMD *pCmd;
753 do
754 pCmd = pDispContext->pCmd;
755 while (!ASMAtomicCmpXchgPtr(&pDispContext->pCmd, NULL, pCmd));
756 *ppCmd = vboxVBVAReverseList(pCmd);
757
758 return VINF_SUCCESS;
759 }
760 }
761
762 return VERR_INVALID_PARAMETER;
763}
764
765
766static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
767{
768 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
769// Assert(0);
770 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
771 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
772 {
773 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
774 Assert(pHdr->iDstID >= 0);
775 if(pHdr->iDstID >= 0)
776 {
777 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
778 Assert(pHandler && pHandler->bValid);
779 if(pHandler && pHandler->bValid)
780 {
781 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
782 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
783 {
784 Assert(!pCur->u.Data);
785 Assert(!pFirst);
786 Assert(!pLast);
787
788 switch(u16ChannelInfo)
789 {
790 case VBVAHG_DISPLAY_CUSTOM:
791 {
792#if 0 /* Never taken */
793 if(pLast)
794 {
795 pLast->u.pNext = pCur;
796 pLast = pCur;
797 }
798 else
799#endif
800 {
801 pFirst = pCur;
802 pLast = pCur;
803 }
804 Assert(!pCur->u.Data);
805#if 0 /* Who is supposed to set pNext? */
806 //TODO: use offset here
807 pCur = pCur->u.pNext;
808 Assert(!pCur);
809#else
810 Assert(!pCur->u.pNext);
811 pCur = NULL;
812#endif
813 Assert(pFirst);
814 Assert(pFirst == pLast);
815 break;
816 }
817 case VBVAHG_EVENT:
818 {
819 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
820 VBoxVideoCmnSignalEvent(pCallbacks->pCommon, pEventCmd->pEvent);
821 }
822 default:
823 {
824 Assert(u16ChannelInfo==VBVAHG_EVENT);
825 Assert(!pCur->u.Data);
826#if 0 /* pLast has been asserted to be NULL, and who should set pNext? */
827 //TODO: use offset here
828 if(pLast)
829 pLast->u.pNext = pCur->u.pNext;
830 VBVAHOSTCMD * pNext = pCur->u.pNext;
831 pCur->u.pNext = NULL;
832#else
833 Assert(!pCur->u.pNext);
834#endif
835 HGSMIHostCmdComplete(pCallbacks->pCommon, pCur);
836#if 0 /* pNext is NULL, and the other things have already been asserted */
837 pCur = pNext;
838 Assert(!pCur);
839 Assert(!pFirst);
840 Assert(pFirst == pLast);
841#else
842 pCur = NULL;
843#endif
844 break;
845 }
846 }
847 }
848
849 /* we do not support lists currently */
850 Assert(pFirst == pLast);
851 if(pLast)
852 {
853 Assert(pLast->u.pNext == NULL);
854 }
855
856 if(pFirst)
857 {
858 Assert(pLast);
859 VBVAHOSTCMD *pCmd;
860 do
861 {
862 pCmd = pHandler->pCmd;
863 pFirst->u.pNext = pCmd;
864 }
865 while (!ASMAtomicCmpXchgPtr(&pHandler->pCmd, pFirst, pCmd));
866 }
867 else
868 {
869 Assert(!pLast);
870 }
871 return VINF_SUCCESS;
872 }
873 }
874 else
875 {
876 //TODO: impl
877// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
878// if(pHandler && pHandler->pfnChannelHandler)
879// {
880// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
881//
882// return VINF_SUCCESS;
883// }
884 }
885 }
886 /* no handlers were found, need to complete the command here */
887 HGSMIHostCmdComplete(pCallbacks->pCommon, pvBuffer);
888 return VINF_SUCCESS;
889}
890
891static HGSMICHANNELHANDLER g_OldHandler;
892
893int vboxVBVAChannelDisplayEnable(PVBOXVIDEO_COMMON pCommon,
894 int iDisplay, /* negative would mean this is a miniport handler */
895 uint8_t u8Channel)
896{
897 VBVA_CHANNELCONTEXTS * pContexts;
898 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&pCommon->channels, u8Channel);
899 if(!pChannel)
900 {
901 int rc = vboxVBVACreateChannelContexts(pCommon, &pContexts);
902 if(RT_FAILURE(rc))
903 {
904 return rc;
905 }
906 }
907 else
908 {
909 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
910 }
911
912 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
913 Assert(pDispContext);
914 if(pDispContext)
915 {
916#ifdef DEBUGVHWASTRICT
917 Assert(!pDispContext->bValid);
918#endif
919 Assert(!pDispContext->pCmd);
920 if(!pDispContext->bValid)
921 {
922 pDispContext->bValid = true;
923 pDispContext->pCmd = NULL;
924
925 int rc = VINF_SUCCESS;
926 if(!pChannel)
927 {
928 rc = HGSMIChannelRegister (&pCommon->channels,
929 u8Channel,
930 "VGA Miniport HGSMI channel",
931 vboxVBVAChannelGenericHandler,
932 pContexts,
933 &g_OldHandler);
934 }
935
936 if(RT_SUCCESS(rc))
937 {
938 pContexts->cUsed++;
939 return VINF_SUCCESS;
940 }
941 }
942 }
943
944 if(!pChannel)
945 {
946 vboxVBVADeleteChannelContexts(pCommon, pContexts);
947 }
948
949 return VERR_GENERAL_FAILURE;
950}
951#endif /* !VBOX_WITH_WDDM */
952
953/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
954 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
955 * host information which is needed by the guest.
956 *
957 * Reading will not cause a switch to the host.
958 *
959 * Have to take into account:
960 * * synchronization: host must write to the memory only from EMT,
961 * large structures must be read under flag, which tells the host
962 * that the guest is currently reading the memory (OWNER flag?).
963 * * guest writes: may be allocate a page for the host info and make
964 * the page readonly for the guest.
965 * * the information should be available only for additions drivers.
966 * * VMMDev additions driver will inform the host which version of the info it expects,
967 * host must support all versions.
968 *
969 */
970
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