VirtualBox

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

Last change on this file since 26000 was 26000, checked in by vboxsync, 15 years ago

wddm: StartDevice impl

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