VirtualBox

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

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

Video hw accel: fallback for PBO allocation failure

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