VirtualBox

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

Last change on this file since 22645 was 22645, checked in by vboxsync, 16 years ago

video hw accel: missing additions files to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.2 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 22645 2009-09-01 10:42:04Z vboxsync $ */
2/** @file
3 * VirtualBox Video miniport driver for NT/2k/XP - HGSMI related functions.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
8 *
9 * Sun Microsystems, Inc. confidential
10 * All rights reserved
11 */
12
13
14#include "VBoxVideo.h"
15#include "Helper.h"
16
17#include <iprt/asm.h>
18#include <iprt/log.h>
19#include <iprt/thread.h>
20#include <VBox/VMMDev.h>
21#include <VBox/VBoxGuest.h>
22#include <VBox/VBoxVideo.h>
23
24#include <VBoxDisplay.h>
25
26#include "vboxioctl.h"
27
28#define MEM_TAG 'HVBV'
29
30void HGSMINotifyHostCmdComplete (PDEVICE_EXTENSION PrimaryExtension, HGSMIOFFSET offt)
31{
32 VBoxHGSMIHostWrite(PrimaryExtension, offt);
33}
34
35void HGSMIClearIrq (PDEVICE_EXTENSION PrimaryExtension)
36{
37 VBoxHGSMIHostWrite(PrimaryExtension, HGSMIOFFSET_VOID);
38}
39
40static void HGSMIHostCmdComplete (PDEVICE_EXTENSION PrimaryExtension, void * pvMem)
41{
42 HGSMIOFFSET offMem = HGSMIPointerToOffset (&PrimaryExtension->u.primary.areaHostHeap, HGSMIBufferHeaderFromData (pvMem));
43 Assert(offMem != HGSMIOFFSET_VOID);
44 if(offMem != HGSMIOFFSET_VOID)
45 {
46 HGSMINotifyHostCmdComplete (PrimaryExtension, offMem);
47 }
48}
49
50static void hgsmiHostCmdProcess(PDEVICE_EXTENSION PrimaryExtension, HGSMIOFFSET offBuffer)
51{
52 int rc = HGSMIBufferProcess (&PrimaryExtension->u.primary.areaHostHeap,
53 &PrimaryExtension->u.primary.channels,
54 offBuffer);
55 Assert(!RT_FAILURE(rc));
56 if(RT_FAILURE(rc))
57 {
58 /* failure means the command was not submitted to the handler for some reason
59 * it's our responsibility to notify its completion in this case */
60 HGSMINotifyHostCmdComplete(PrimaryExtension, offBuffer);
61 }
62 /* if the cmd succeeded it's responsibility of the callback to complete it */
63}
64
65static HGSMIOFFSET hgsmiGetHostBuffer (PDEVICE_EXTENSION PrimaryExtension)
66{
67 return VBoxHGSMIHostRead(PrimaryExtension);
68}
69
70static void hgsmiHostCommandQueryProcess (PDEVICE_EXTENSION PrimaryExtension)
71{
72 HGSMIOFFSET offset = hgsmiGetHostBuffer (PrimaryExtension);
73 Assert(offset != HGSMIOFFSET_VOID);
74 if(offset != HGSMIOFFSET_VOID)
75 {
76 hgsmiHostCmdProcess(PrimaryExtension, offset);
77 }
78}
79
80#define VBOX_HGSMI_LOCK(_pe, _plock, _dpc, _pold) \
81 do { \
82 if(_dpc) { \
83 (_pe)->u.primary.VideoPortProcs.pfnAcquireSpinLockAtDpcLevel(_pe, _plock); \
84 } \
85 else {\
86 (_pe)->u.primary.VideoPortProcs.pfnAcquireSpinLock(_pe, _plock, _pold); \
87 }\
88 } while(0)
89
90#define VBOX_HGSMI_UNLOCK(_pe, _plock, _dpc, _pold) \
91 do { \
92 if(_dpc) { \
93 (_pe)->u.primary.VideoPortProcs.pfnReleaseSpinLockFromDpcLevel(_pe, _plock); \
94 } \
95 else {\
96 (_pe)->u.primary.VideoPortProcs.pfnReleaseSpinLock(_pe, _plock, _pold); \
97 }\
98 } while(0)
99
100VOID VBoxVideoHGSMIDpc(
101 IN PVOID HwDeviceExtension,
102 IN PVOID Context
103 )
104{
105 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
106 uint32_t flags = (uint32_t)Context;
107 bool bProcessing = false;
108 UCHAR OldIrql;
109 /* we check if another thread is processing the queue and exit if so */
110 do
111 {
112 bool bLock = false;
113 if(!(PrimaryExtension->u.primary.pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING))
114 {
115 if(!bProcessing)
116 {
117 break;
118 }
119 VBOX_HGSMI_LOCK(PrimaryExtension, PrimaryExtension->u.primary.pSynchLock, flags, &OldIrql);
120 if(!(PrimaryExtension->u.primary.pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING))
121 {
122 Assert(PrimaryExtension->u.primary.bHostCmdProcessing);
123 PrimaryExtension->u.primary.bHostCmdProcessing = false;
124 VBOX_HGSMI_UNLOCK(PrimaryExtension, PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
125 break;
126 }
127 VBOX_HGSMI_UNLOCK(PrimaryExtension, PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
128 }
129 else
130 {
131 if(!bProcessing)
132 {
133 VBOX_HGSMI_LOCK(PrimaryExtension, PrimaryExtension->u.primary.pSynchLock, flags, &OldIrql);
134 if(!(PrimaryExtension->u.primary.pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
135 || PrimaryExtension->u.primary.bHostCmdProcessing)
136 {
137 VBOX_HGSMI_UNLOCK(PrimaryExtension, PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
138 break;
139 }
140 Assert(!PrimaryExtension->u.primary.bHostCmdProcessing);
141 PrimaryExtension->u.primary.bHostCmdProcessing = true;
142 VBOX_HGSMI_UNLOCK(PrimaryExtension, PrimaryExtension->u.primary.pSynchLock, flags, OldIrql);
143 bProcessing = true;
144 }
145 }
146
147 Assert(bProcessing);
148 Assert(PrimaryExtension->u.primary.bHostCmdProcessing);
149 Assert((PrimaryExtension->u.primary.pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0);
150 bProcessing = true;
151
152 hgsmiHostCommandQueryProcess (PrimaryExtension);
153 } while(true/*!PrimaryExtension->u.primary.bPollingStop*/);
154}
155
156/* Detect whether HGSMI is supported by the host. */
157BOOLEAN VBoxHGSMIIsSupported (PDEVICE_EXTENSION PrimaryExtension)
158{
159 USHORT DispiId;
160
161 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
162 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
163
164 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
165
166 return (DispiId == VBE_DISPI_ID_HGSMI);
167}
168
169typedef int FNHGSMICALLINIT (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData);
170typedef FNHGSMICALLINIT *PFNHGSMICALLINIT;
171
172typedef int FNHGSMICALLFINALIZE (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData);
173typedef FNHGSMICALLFINALIZE *PFNHGSMICALLFINALIZE;
174
175static int vboxCallChannel (PDEVICE_EXTENSION PrimaryExtension,
176 uint8_t u8Ch,
177 uint16_t u16Op,
178 HGSMISIZE cbData,
179 PFNHGSMICALLINIT pfnInit,
180 PFNHGSMICALLFINALIZE pfnFinalize,
181 void *pvContext)
182{
183 int rc = VINF_SUCCESS;
184
185 /* Allocate the IO buffer. */
186 if (PrimaryExtension->pPrimary != PrimaryExtension)
187 {
188 dprintf(("VBoxVideo::vboxCallChannel: not primary extension %p!!!\n", PrimaryExtension));
189 return VERR_INVALID_PARAMETER;
190 }
191
192 void *p = HGSMIHeapAlloc (&PrimaryExtension->u.primary.hgsmiAdapterHeap, cbData, u8Ch, u16Op);
193
194 if (!p)
195 {
196 rc = VERR_NO_MEMORY;
197 }
198 else
199 {
200 /* Prepare data to be sent to the host. */
201 if (pfnInit)
202 {
203 rc = pfnInit (PrimaryExtension, pvContext, p);
204 }
205
206 if (RT_SUCCESS (rc))
207 {
208 /* Initialize the buffer and get the offset for port IO. */
209 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&PrimaryExtension->u.primary.hgsmiAdapterHeap,
210 p);
211
212 /* Submit the buffer to the host. */
213 VBoxHGSMIGuestWrite(PrimaryExtension, offBuffer);
214
215 if (pfnFinalize)
216 {
217 rc = pfnFinalize (PrimaryExtension, pvContext, p);
218 }
219 }
220 else
221 {
222 AssertFailed ();
223 rc = VERR_INTERNAL_ERROR;
224 }
225
226 /* Free the IO buffer. */
227 HGSMIHeapFree (&PrimaryExtension->u.primary.hgsmiAdapterHeap, p);
228 }
229
230 return rc;
231}
232
233static int vboxCallVBVA (PDEVICE_EXTENSION PrimaryExtension,
234 uint16_t u16Op,
235 HGSMISIZE cbData,
236 PFNHGSMICALLINIT pfnInit,
237 PFNHGSMICALLFINALIZE pfnFinalize,
238 void *pvContext)
239{
240 return vboxCallChannel (PrimaryExtension,
241 HGSMI_CH_VBVA,
242 u16Op,
243 cbData,
244 pfnInit,
245 pfnFinalize,
246 pvContext);
247}
248
249typedef struct _QUERYCONFCTX
250{
251 uint32_t u32Index;
252 ULONG *pulValue;
253} QUERYCONFCTX;
254
255static int vbvaInitQueryConf (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
256{
257 NOREF (PrimaryExtension);
258
259 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
260 VBVACONF32 *p = (VBVACONF32 *)pvData;
261
262 p->u32Index = pCtx->u32Index;
263 p->u32Value = 0;
264
265 return VINF_SUCCESS;
266}
267
268static int vbvaFinalizeQueryConf (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
269{
270 NOREF (PrimaryExtension);
271
272 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
273 VBVACONF32 *p = (VBVACONF32 *)pvData;
274
275 if (pCtx->pulValue)
276 {
277 *pCtx->pulValue = p->u32Value;
278 }
279
280 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->u32Value));
281 return VINF_SUCCESS;
282}
283
284static int vboxQueryConfHGSMI (PDEVICE_EXTENSION PrimaryExtension, uint32_t u32Index, ULONG *pulValue)
285{
286 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
287
288 QUERYCONFCTX context;
289
290 context.u32Index = u32Index;
291 context.pulValue = pulValue;
292
293 int rc = vboxCallVBVA (PrimaryExtension,
294 VBVA_QUERY_CONF32,
295 sizeof (VBVACONF32),
296 vbvaInitQueryConf,
297 vbvaFinalizeQueryConf,
298 &context);
299
300 dprintf(("VBoxVideo::vboxQueryConf: rc = %d\n", rc));
301
302 return rc;
303}
304
305static int vbvaInitInfoDisplay (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
306{
307 NOREF (pvContext);
308 VBVAINFOVIEW *p = (VBVAINFOVIEW *)pvData;
309
310 int i;
311 PDEVICE_EXTENSION Extension;
312
313 for (i = 0, Extension = PrimaryExtension;
314 i < PrimaryExtension->u.primary.cDisplays && Extension;
315 i++, Extension = Extension->pNext)
316 {
317 p[i].u32ViewIndex = Extension->iDevice;
318 p[i].u32ViewOffset = Extension->ulFrameBufferOffset;
319 p[i].u32ViewSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
320
321 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
322 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
323
324 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
325 p[i].u32ViewSize - cbReservedVRAM:
326 0;
327 }
328
329 if (i == PrimaryExtension->u.primary.cDisplays && Extension == NULL)
330 {
331 return VINF_SUCCESS;
332 }
333
334 AssertFailed ();
335 return VERR_INTERNAL_ERROR;
336}
337
338static int vbvaInitInfoHeap (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
339{
340 NOREF (pvContext);
341 VBVAINFOHEAP *p = (VBVAINFOHEAP *)pvData;
342
343 p->u32HeapOffset = PrimaryExtension->u.primary.cbVRAM
344 - PrimaryExtension->u.primary.cbMiniportHeap
345 - VBVA_ADAPTER_INFORMATION_SIZE;
346 p->u32HeapSize = PrimaryExtension->u.primary.cbMiniportHeap;
347
348 return VINF_SUCCESS;
349}
350
351static int hgsmiInitFlagsLocation (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
352{
353 NOREF (pvContext);
354 HGSMIBUFFERLOCATION *p = (HGSMIBUFFERLOCATION *)pvData;
355
356 p->offLocation = PrimaryExtension->u.primary.cbVRAM - sizeof (HGSMIHOSTFLAGS);
357 p->cbLocation = sizeof (HGSMIHOSTFLAGS);
358
359 return VINF_SUCCESS;
360}
361
362
363static int vboxSetupAdapterInfoHGSMI (PDEVICE_EXTENSION PrimaryExtension)
364{
365 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
366
367 /* setup the flags first to ensure they are initialized by the time the host heap is ready */
368 int rc = vboxCallChannel(PrimaryExtension,
369 HGSMI_CH_HGSMI,
370 HGSMI_CC_HOST_FLAGS_LOCATION,
371 sizeof (HGSMIBUFFERLOCATION),
372 hgsmiInitFlagsLocation,
373 NULL,
374 NULL);
375 AssertRC(rc);
376 if(RT_SUCCESS (rc))
377 {
378 rc = vboxCallVBVA (PrimaryExtension,
379 VBVA_INFO_VIEW,
380 sizeof (VBVAINFOVIEW) * PrimaryExtension->u.primary.cDisplays,
381 vbvaInitInfoDisplay,
382 NULL,
383 NULL);
384 AssertRC(rc);
385 if (RT_SUCCESS (rc))
386 {
387 /* Report the host heap location. */
388 rc = vboxCallVBVA (PrimaryExtension,
389 VBVA_INFO_HEAP,
390 sizeof (VBVAINFOHEAP),
391 vbvaInitInfoHeap,
392 NULL,
393 NULL);
394 AssertRC(rc);
395 }
396 }
397
398
399 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
400
401 return rc;
402}
403
404VP_STATUS vboxWaitForSingleObjectVoid(IN PVOID HwDeviceExtension, IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
405{
406 return ERROR_INVALID_FUNCTION;
407}
408
409LONG vboxSetEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
410{
411 return 0;
412}
413
414VOID vboxClearEventVoid (IN PVOID HwDeviceExtension, IN PEVENT pEvent)
415{
416}
417
418VP_STATUS vboxCreateEventVoid(IN PVOID HwDeviceExtension, IN ULONG EventFlag, IN PVOID Unused, OUT PEVENT *ppEvent)
419{
420 return ERROR_INVALID_FUNCTION;
421}
422
423VP_STATUS vboxDeleteEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
424{
425 return ERROR_INVALID_FUNCTION;
426}
427
428VP_STATUS vboxCreateSpinLockVoid (IN PVOID HwDeviceExtension, OUT PSPIN_LOCK *SpinLock)
429{
430 return ERROR_INVALID_FUNCTION;
431}
432
433VP_STATUS vboxDeleteSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
434{
435 return ERROR_INVALID_FUNCTION;
436}
437
438VOID vboxAcquireSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, OUT PUCHAR OldIrql)
439{
440}
441
442VOID vboxReleaseSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, IN UCHAR NewIrql)
443{
444}
445
446VOID vboxAcquireSpinLockAtDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
447{
448}
449
450VOID vboxReleaseSpinLockFromDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
451{
452}
453
454void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
455{
456 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
457
458 if (vboxQueryWinVersion() <= WINNT4)
459 {
460 /* VideoPortGetProcAddress is available for >= win2k */
461 return;
462 }
463
464 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
465 (PrimaryExtension,
466 (PUCHAR)"VideoPortWaitForSingleObject");
467 Assert(pCallbacks->pfnWaitForSingleObject);
468
469 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
470 (PrimaryExtension,
471 (PUCHAR)"VideoPortSetEvent");
472 Assert(pCallbacks->pfnSetEvent);
473
474 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
475 (PrimaryExtension,
476 (PUCHAR)"VideoPortClearEvent");
477 Assert(pCallbacks->pfnClearEvent);
478
479 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
480 (PrimaryExtension,
481 (PUCHAR)"VideoPortCreateEvent");
482 Assert(pCallbacks->pfnCreateEvent);
483
484 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
485 (PrimaryExtension,
486 (PUCHAR)"VideoPortDeleteEvent");
487 Assert(pCallbacks->pfnDeleteEvent);
488
489 if(pCallbacks->pfnWaitForSingleObject
490 && pCallbacks->pfnSetEvent
491 && pCallbacks->pfnClearEvent
492 && pCallbacks->pfnCreateEvent
493 && pCallbacks->pfnDeleteEvent)
494 {
495 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
496 }
497 else
498 {
499 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
500 pCallbacks->pfnSetEvent = vboxSetEventVoid;
501 pCallbacks->pfnClearEvent = vboxClearEventVoid;
502 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
503 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
504 }
505
506 pCallbacks->pfnCreateSpinLock = (PFNCREATESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
507 (PrimaryExtension,
508 (PUCHAR)"VideoPortCreateSpinLock");
509 Assert(pCallbacks->pfnCreateSpinLock);
510
511 pCallbacks->pfnDeleteSpinLock = (PFNDELETESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
512 (PrimaryExtension,
513 (PUCHAR)"VideoPortDeleteSpinLock");
514 Assert(pCallbacks->pfnDeleteSpinLock);
515
516 pCallbacks->pfnAcquireSpinLock = (PFNACQUIRESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
517 (PrimaryExtension,
518 (PUCHAR)"VideoPortAcquireSpinLock");
519 Assert(pCallbacks->pfnAcquireSpinLock);
520
521 pCallbacks->pfnReleaseSpinLock = (PFNRELEASESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
522 (PrimaryExtension,
523 (PUCHAR)"VideoPortReleaseSpinLock");
524 Assert(pCallbacks->pfnReleaseSpinLock);
525
526 pCallbacks->pfnAcquireSpinLockAtDpcLevel = (PFNACQUIRESPINLOCKATDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
527 (PrimaryExtension,
528 (PUCHAR)"VideoPortAcquireSpinLockAtDpcLevel");
529 Assert(pCallbacks->pfnAcquireSpinLockAtDpcLevel);
530
531 pCallbacks->pfnReleaseSpinLockFromDpcLevel = (PFNRELEASESPINLOCKFROMDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
532 (PrimaryExtension,
533 (PUCHAR)"VideoPortReleaseSpinLockFromDpcLevel");
534 Assert(pCallbacks->pfnReleaseSpinLockFromDpcLevel);
535
536 if(pCallbacks->pfnCreateSpinLock
537 && pCallbacks->pfnDeleteSpinLock
538 && pCallbacks->pfnAcquireSpinLock
539 && pCallbacks->pfnReleaseSpinLock
540 && pCallbacks->pfnAcquireSpinLockAtDpcLevel
541 && pCallbacks->pfnReleaseSpinLockFromDpcLevel)
542 {
543 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_SPINLOCK;
544 }
545 else
546 {
547 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
548 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
549 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
550 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
551 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
552 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
553 }
554
555 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
556 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_SPINLOCK);
557}
558
559/**
560 * Helper function to register secondary displays (DualView). Note that this will not
561 * be available on pre-XP versions, and some editions on XP will fail because they are
562 * intentionally crippled.
563 *
564 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
565 * to talk to the host.
566 */
567VOID VBoxSetupDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
568{
569 VP_STATUS rc = NO_ERROR;
570
571 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
572 PrimaryExtension));
573
574 /* Preinitialize the primary extension.
575 * Note: bVBoxVideoSupported is set to FALSE, because HGSMI is active instead.
576 */
577 PrimaryExtension->pNext = NULL;
578 PrimaryExtension->pPrimary = PrimaryExtension;
579 PrimaryExtension->iDevice = 0;
580 PrimaryExtension->ulFrameBufferOffset = 0;
581 PrimaryExtension->ulFrameBufferSize = 0;
582 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
583 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
584 PrimaryExtension->u.primary.cDisplays = 1;
585 PrimaryExtension->u.primary.cbVRAM = AdapterMemorySize;
586 PrimaryExtension->u.primary.cbMiniportHeap = 0;
587 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
588 PrimaryExtension->u.primary.pvAdapterInformation = NULL;
589 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
590 PrimaryExtension->u.primary.bHGSMI = VBoxHGSMIIsSupported (PrimaryExtension);
591 VideoPortZeroMemory(&PrimaryExtension->u.primary.areaHostHeap, sizeof(HGSMIAREA));
592 VideoPortZeroMemory(&PrimaryExtension->areaDisplay, sizeof(HGSMIAREA));
593
594 if (PrimaryExtension->u.primary.IOPortGuest == 0)
595 {
596 PrimaryExtension->u.primary.bHGSMI = false;
597 }
598
599 if (PrimaryExtension->u.primary.bHGSMI)
600 {
601 /* Map the adapter information. It will be needed for HGSMI IO. */
602 rc = VBoxMapAdapterMemory (PrimaryExtension,
603 &PrimaryExtension->u.primary.pvAdapterInformation,
604 PrimaryExtension->u.primary.cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
605 VBVA_ADAPTER_INFORMATION_SIZE
606 );
607 if (rc != NO_ERROR)
608 {
609 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
610 rc));
611
612 PrimaryExtension->u.primary.bHGSMI = FALSE;
613 }
614 else
615 {
616 /* Setup a HGSMI heap within the adapter information area. */
617 rc = HGSMIHeapSetup (&PrimaryExtension->u.primary.hgsmiAdapterHeap,
618 PrimaryExtension->u.primary.pvAdapterInformation,
619 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
620 PrimaryExtension->u.primary.cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE);
621
622 if (RT_FAILURE (rc))
623 {
624 dprintf(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
625 rc));
626
627 PrimaryExtension->u.primary.bHGSMI = FALSE;
628 }
629 else
630 {
631 PrimaryExtension->u.primary.pHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)PrimaryExtension->u.primary.pvAdapterInformation)
632 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
633 }
634 }
635 }
636
637 /* Setup the host heap and the adapter memory. */
638 if (PrimaryExtension->u.primary.bHGSMI)
639 {
640 /* The miniport heap is used for the host buffers. */
641 ULONG cbMiniportHeap = 0;
642 vboxQueryConfHGSMI (PrimaryExtension, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbMiniportHeap);
643
644 if (cbMiniportHeap != 0)
645 {
646 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
647 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 4;
648
649 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
650 {
651 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
652 }
653
654 if (cbMiniportHeap > cbMiniportHeapMaxSize)
655 {
656 cbMiniportHeap = cbMiniportHeapMaxSize;
657 }
658
659 /* Round up to 4096 bytes. */
660 PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
661
662 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
663 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
664
665 /* Map the heap region.
666 *
667 * Note: the heap will be used for the host buffers submitted to the guest.
668 * The miniport driver is responsible for reading FIFO and notifying
669 * display drivers.
670 */
671 rc = VBoxMapAdapterMemory (PrimaryExtension,
672 &PrimaryExtension->u.primary.pvMiniportHeap,
673 PrimaryExtension->u.primary.cbVRAM
674 - VBVA_ADAPTER_INFORMATION_SIZE
675 - PrimaryExtension->u.primary.cbMiniportHeap,
676 PrimaryExtension->u.primary.cbMiniportHeap
677 );
678 if (rc != NO_ERROR)
679 {
680 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
681 PrimaryExtension->u.primary.cbMiniportHeap = 0;
682 PrimaryExtension->u.primary.bHGSMI = FALSE;
683 }
684 else
685 {
686 HGSMIOFFSET offBase = PrimaryExtension->u.primary.cbVRAM
687 - VBVA_ADAPTER_INFORMATION_SIZE
688 - PrimaryExtension->u.primary.cbMiniportHeap;
689
690 /* Init the host hap area. Buffers from the host will be placed there. */
691 HGSMIAreaInitialize (&PrimaryExtension->u.primary.areaHostHeap,
692 PrimaryExtension->u.primary.pvMiniportHeap,
693 PrimaryExtension->u.primary.cbMiniportHeap,
694 offBase);
695 }
696 }
697 else
698 {
699 /* Host has not requested a heap. */
700 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
701 PrimaryExtension->u.primary.cbMiniportHeap = 0;
702 }
703 }
704
705 /* Check whether the guest supports multimonitors. */
706 if (PrimaryExtension->u.primary.bHGSMI)
707 {
708 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
709 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
710
711 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
712 if (vboxQueryWinVersion() > WINNT4)
713 {
714 /* This bluescreens on NT4, hence the above version check */
715 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
716 (PrimaryExtension,
717 (PUCHAR)"VideoPortCreateSecondaryDisplay");
718 }
719
720 if (pfnCreateSecondaryDisplay != NULL)
721 {
722 /* Query the configured number of displays. */
723 ULONG cDisplays = 0;
724 vboxQueryConfHGSMI (PrimaryExtension, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
725
726 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
727 cDisplays));
728
729 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
730 {
731 /* Host reported some bad value. Continue in the 1 screen mode. */
732 cDisplays = 1;
733 }
734
735 PDEVICE_EXTENSION pPrev = PrimaryExtension;
736
737 ULONG iDisplay;
738 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
739 {
740 PDEVICE_EXTENSION SecondaryExtension = NULL;
741 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
742
743 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
744 rc, SecondaryExtension));
745
746 if (rc != NO_ERROR)
747 {
748 break;
749 }
750
751 SecondaryExtension->pNext = NULL;
752 SecondaryExtension->pPrimary = PrimaryExtension;
753 SecondaryExtension->iDevice = iDisplay;
754 SecondaryExtension->ulFrameBufferOffset = 0;
755 SecondaryExtension->ulFrameBufferSize = 0;
756 SecondaryExtension->u.secondary.bEnabled = FALSE;
757
758 /* Update the list pointers. */
759 pPrev->pNext = SecondaryExtension;
760 pPrev = SecondaryExtension;
761
762 /* Take the successfully created display into account. */
763 PrimaryExtension->u.primary.cDisplays++;
764 }
765 }
766
767 /* Failure to create secondary displays is not fatal */
768 rc = NO_ERROR;
769 }
770
771 /* Now when the number of monitors is known and extensions are created,
772 * calculate the layout of framebuffers.
773 */
774 VBoxComputeFrameBufferSizes (PrimaryExtension);
775
776 if (PrimaryExtension->u.primary.bHGSMI)
777 {
778 /* Setup the information for the host. */
779 rc = vboxSetupAdapterInfoHGSMI (PrimaryExtension);
780
781 if (RT_FAILURE (rc))
782 {
783 PrimaryExtension->u.primary.bHGSMI = FALSE;
784 }
785 }
786
787 if (!PrimaryExtension->u.primary.bHGSMI)
788 {
789 /* Unmap the memory if VBoxVideo is not supported. */
790 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap);
791 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation);
792
793 HGSMIHeapDestroy (&PrimaryExtension->u.primary.hgsmiAdapterHeap);
794 }
795
796 if (PrimaryExtension->u.primary.bHGSMI)
797 {
798 PrimaryExtension->u.primary.VideoPortProcs.pfnCreateSpinLock(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock);
799 }
800
801 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
802}
803
804
805/*
806 * Send the pointer shape to the host.
807 */
808typedef struct _MOUSEPOINTERSHAPECTX
809{
810 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
811 uint32_t cbData;
812 int32_t i32Result;
813} MOUSEPOINTERSHAPECTX;
814
815static int vbvaInitMousePointerShape (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
816{
817 NOREF (PrimaryExtension);
818
819 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
820 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
821
822 /* Will be updated by the host. */
823 p->i32Result = VINF_SUCCESS;
824
825 /* We have our custom flags in the field */
826 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
827
828 /* Even if pointer is invisible, we have to pass following data,
829 * so host could create the pointer with initial status - invisible
830 */
831 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
832 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
833 p->u32Width = pCtx->pPointerAttr->Width;
834 p->u32Height = pCtx->pPointerAttr->Height;
835
836 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
837 {
838 /* Copy the actual pointer data. */
839 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
840 }
841
842 return VINF_SUCCESS;
843}
844
845static int vbvaFinalizeMousePointerShape (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
846{
847 NOREF (PrimaryExtension);
848
849 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
850 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
851
852 pCtx->i32Result = p->i32Result;
853
854 return VINF_SUCCESS;
855}
856
857BOOLEAN vboxUpdatePointerShape (PDEVICE_EXTENSION PrimaryExtension,
858 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
859 uint32_t cbLength)
860{
861 uint32_t cbData = 0;
862
863 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
864 {
865 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
866 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
867 + pointerAttr->Width * 4 * pointerAttr->Height;
868 }
869
870 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
871 cbData, pointerAttr->Width, pointerAttr->Height));
872
873 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
874 {
875 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
876 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
877 return FALSE;
878 }
879
880 MOUSEPOINTERSHAPECTX ctx;
881
882 ctx.pPointerAttr = pointerAttr;
883 ctx.cbData = cbData;
884 ctx.i32Result = VERR_NOT_SUPPORTED;
885
886 int rc = vboxCallVBVA (PrimaryExtension,
887 VBVA_MOUSE_POINTER_SHAPE,
888 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
889 vbvaInitMousePointerShape,
890 vbvaFinalizeMousePointerShape,
891 &ctx);
892
893 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
894
895 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
896}
897
898typedef struct _VBVAMINIPORT_CHANNELCONTEXT
899{
900 PFNHGSMICHANNELHANDLER pfnChannelHandler;
901 void *pvChannelHandler;
902}VBVAMINIPORT_CHANNELCONTEXT;
903
904typedef struct _VBVADISP_CHANNELCONTEXT
905{
906 struct _VBVAHOSTCMD * pFirstCmd;
907 struct _VBVAHOSTCMD * pLastCmd;
908 PSPIN_LOCK pSynchLock;
909#ifdef DEBUG
910 int cCmds;
911#endif
912 bool bValid;
913}VBVADISP_CHANNELCONTEXT;
914
915#ifdef DEBUG
916void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
917{
918 int counter = 0;
919 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
920 {
921 Assert(pCur != pCmd);
922 if(pCur == pList->pLastCmd)
923 {
924 Assert(pCur->u.pNext == NULL);
925 }
926 if(pCur->u.pNext == NULL)
927 {
928 Assert(pCur == pList->pLastCmd);
929 }
930 counter++;
931 }
932
933 Assert(counter == pList->cCmds);
934}
935
936void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
937{
938 UCHAR oldIrql;
939 PrimaryExtension->u.primary.VideoPortProcs.pfnAcquireSpinLock(PrimaryExtension,
940 pList->pSynchLock,
941 &oldIrql);
942
943 dbgCheckListLocked(pList, pCmd);
944
945 PrimaryExtension->u.primary.VideoPortProcs.pfnReleaseSpinLock(PrimaryExtension,
946 pList->pSynchLock,
947 oldIrql);
948}
949
950#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
951#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
952
953#else
954#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
955#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
956#endif
957
958
959typedef struct _VBVA_CHANNELCONTEXTS
960{
961 PDEVICE_EXTENSION PrimaryExtension;
962 uint32_t cUsed;
963 uint32_t cContexts;
964 VBVAMINIPORT_CHANNELCONTEXT mpContext;
965 VBVADISP_CHANNELCONTEXT aContexts[1];
966}VBVA_CHANNELCONTEXTS;
967
968static int vboxVBVADeleteChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS * pContext)
969{
970 VideoPortFreePool(PrimaryExtension,pContext);
971 return VINF_SUCCESS;
972}
973
974static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
975{
976 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
977 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
978 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VideoPortAllocatePool(PrimaryExtension,
979 VpNonPagedPool,
980 size,
981 MEM_TAG);
982 if(pContext)
983 {
984 memset(pContext, 0, size);
985 pContext->cContexts = cDisplays;
986 pContext->PrimaryExtension = PrimaryExtension;
987 *ppContext = pContext;
988 return VINF_SUCCESS;
989 }
990 return VERR_GENERAL_FAILURE;
991}
992
993static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
994{
995 if(iId < 0)
996 {
997 return NULL;
998 }
999 else if(pCallbacks->cContexts > (uint32_t)iId)
1000 {
1001 return &pCallbacks->aContexts[iId];
1002 }
1003 return NULL;
1004}
1005
1006DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
1007{
1008 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
1009 HGSMIHostCmdComplete (PrimaryExtension, pCmd);
1010}
1011
1012DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
1013{
1014// if(display < 0)
1015// return VERR_INVALID_PARAMETER;
1016 if(!ppCmd)
1017 return VERR_INVALID_PARAMETER;
1018
1019 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
1020 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
1021
1022 /* pick up the host commands */
1023 VBoxVideoHGSMIDpc(PrimaryExtension, NULL);
1024
1025 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&PrimaryExtension->u.primary.channels, u8Channel);
1026 if(pChannel)
1027 {
1028 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1029 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
1030 Assert(pDispContext);
1031 if(pDispContext)
1032 {
1033 UCHAR oldIrql;
1034 PrimaryExtension->u.primary.VideoPortProcs.pfnAcquireSpinLock(PrimaryExtension,
1035 pDispContext->pSynchLock,
1036 &oldIrql);
1037
1038 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
1039
1040 *ppCmd = pDispContext->pFirstCmd;
1041 pDispContext->pFirstCmd = NULL;
1042 pDispContext->pLastCmd = NULL;
1043#ifdef DEBUG
1044 pDispContext->cCmds = 0;
1045#endif
1046 PrimaryExtension->u.primary.VideoPortProcs.pfnReleaseSpinLock(PrimaryExtension,
1047 pDispContext->pSynchLock,
1048 oldIrql);
1049
1050 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
1051
1052 return VINF_SUCCESS;
1053 }
1054 }
1055
1056 return VERR_INVALID_PARAMETER;
1057}
1058
1059static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1060{
1061 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
1062// Assert(0);
1063 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
1064 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
1065 {
1066 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
1067 Assert(pHdr->iDstID >= 0);
1068 if(pHdr->iDstID >= 0)
1069 {
1070 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
1071 Assert(pHandler && pHandler->bValid);
1072 if(pHandler && pHandler->bValid)
1073 {
1074 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
1075 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
1076 {
1077 Assert(!pCur->u.Data);
1078 Assert(!pFirst);
1079 Assert(!pLast);
1080
1081 switch(u16ChannelInfo)
1082 {
1083 case VBVAHG_DISPLAY_CUSTOM:
1084 {
1085 if(pLast)
1086 {
1087 pLast->u.pNext = pCur;
1088 pLast = pCur;
1089 }
1090 else
1091 {
1092 pFirst = pCur;
1093 pLast = pCur;
1094 }
1095 Assert(!pCur->u.Data);
1096 //TODO: use offset here
1097 pCur = pCur->u.pNext;
1098 Assert(!pCur);
1099 Assert(pFirst);
1100 Assert(pFirst == pLast);
1101 break;
1102 }
1103 case VBVAHG_EVENT:
1104 {
1105 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
1106 PEVENT pEvent = (PEVENT)pEventCmd->pEvent;
1107 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(
1108 pCallbacks->PrimaryExtension,
1109 pEvent);
1110 }
1111 default:
1112 {
1113 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
1114 Assert(u16ChannelInfo==VBVAHG_EVENT);
1115 Assert(!pCur->u.Data);
1116 //TODO: use offset here
1117 if(pLast)
1118 pLast->u.pNext = pCur->u.pNext;
1119 VBVAHOSTCMD * pNext = pCur->u.pNext;
1120 pCur->u.pNext = NULL;
1121 HGSMIHostCmdComplete(pCallbacks->PrimaryExtension, pCur);
1122 pCur = pNext;
1123 Assert(!pCur);
1124 Assert(!pFirst);
1125 Assert(pFirst == pLast);
1126 break;
1127 }
1128 }
1129 }
1130
1131 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
1132
1133 /* we do not support lists currently */
1134 Assert(pFirst == pLast);
1135 if(pLast)
1136 {
1137 Assert(pLast->u.pNext == NULL);
1138 }
1139
1140 if(pFirst)
1141 {
1142 Assert(pLast);
1143 UCHAR oldIrql;
1144 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnAcquireSpinLock(pCallbacks->PrimaryExtension,
1145 pHandler->pSynchLock,
1146 &oldIrql);
1147
1148 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
1149
1150 if(pHandler->pLastCmd)
1151 {
1152 pHandler->pLastCmd->u.pNext = pFirst;
1153 Assert(pHandler->pFirstCmd);
1154 }
1155 else
1156 {
1157 Assert(!pHandler->pFirstCmd);
1158 pHandler->pFirstCmd = pFirst;
1159 }
1160 pHandler->pLastCmd = pLast;
1161#ifdef DEBUG
1162 pHandler->cCmds++;
1163#endif
1164 DBG_CHECKLIST_LOCKED(pHandler, NULL);
1165
1166 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnReleaseSpinLock(pCallbacks->PrimaryExtension,
1167 pHandler->pSynchLock,
1168 oldIrql);
1169 }
1170 else
1171 {
1172 Assert(!pLast);
1173 }
1174 return VINF_SUCCESS;
1175 }
1176 }
1177 else
1178 {
1179 //TODO: impl
1180// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
1181// if(pHandler && pHandler->pfnChannelHandler)
1182// {
1183// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
1184//
1185// return VINF_SUCCESS;
1186// }
1187 }
1188 }
1189 /* no handlers were found, need to complete the command here */
1190 HGSMIHostCmdComplete(pCallbacks->PrimaryExtension, pvBuffer);
1191 return VINF_SUCCESS;
1192}
1193
1194static HGSMICHANNELHANDLER g_OldHandler;
1195
1196int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
1197 int iDisplay, /* negative would mean this is a miniport handler */
1198 uint8_t u8Channel)
1199{
1200 VBVA_CHANNELCONTEXTS * pContexts;
1201 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&PrimaryExtension->u.primary.channels, u8Channel);
1202 if(!pChannel)
1203 {
1204 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
1205 if(RT_FAILURE(rc))
1206 {
1207 return rc;
1208 }
1209 }
1210 else
1211 {
1212 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1213 }
1214
1215 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
1216 Assert(pDispContext);
1217 if(pDispContext)
1218 {
1219 Assert(!pDispContext->bValid);
1220 Assert(!pDispContext->pFirstCmd);
1221 Assert(!pDispContext->pLastCmd);
1222 if(!pDispContext->bValid)
1223 {
1224 pDispContext->bValid = true;
1225 pDispContext->pFirstCmd = NULL;
1226 pDispContext->pLastCmd= NULL;
1227#ifdef DEBUG
1228 pDispContext->cCmds = 0;
1229#endif
1230
1231 PrimaryExtension->u.primary.VideoPortProcs.pfnCreateSpinLock(PrimaryExtension, &pDispContext->pSynchLock);
1232
1233 int rc = VINF_SUCCESS;
1234 if(!pChannel)
1235 {
1236 rc = HGSMIChannelRegister (&PrimaryExtension->u.primary.channels,
1237 u8Channel,
1238 "VGA Miniport HGSMI channel",
1239 vboxVBVAChannelGenericHandler,
1240 pContexts,
1241 &g_OldHandler);
1242 }
1243
1244 if(RT_SUCCESS(rc))
1245 {
1246 pContexts->cUsed++;
1247 return VINF_SUCCESS;
1248 }
1249 }
1250 }
1251
1252 if(!pChannel)
1253 {
1254 vboxVBVADeleteChannelContexts(PrimaryExtension, pContexts);
1255 }
1256
1257 return VERR_GENERAL_FAILURE;
1258}
1259
1260/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1261 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1262 * host information which is needed by the guest.
1263 *
1264 * Reading will not cause a switch to the host.
1265 *
1266 * Have to take into account:
1267 * * synchronization: host must write to the memory only from EMT,
1268 * large structures must be read under flag, which tells the host
1269 * that the guest is currently reading the memory (OWNER flag?).
1270 * * guest writes: may be allocate a page for the host info and make
1271 * the page readonly for the guest.
1272 * * the information should be available only for additions drivers.
1273 * * VMMDev additions driver will inform the host which version of the info it expects,
1274 * host must support all versions.
1275 *
1276 */
1277
1278
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