VirtualBox

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

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

Windows guest video driver: NT fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.2 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 23255 2009-09-23 12:38:37Z 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
472BOOLEAN vboxQueueDpcVoid(IN PVOID HwDeviceExtension, IN PMINIPORT_DPC_ROUTINE CallbackRoutine, IN PVOID Context)
473{
474 return FALSE;
475}
476
477void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
478{
479 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
480
481 if (vboxQueryWinVersion() <= WINNT4)
482 {
483 /* VideoPortGetProcAddress is available for >= win2k */
484 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
485 pCallbacks->pfnSetEvent = vboxSetEventVoid;
486 pCallbacks->pfnClearEvent = vboxClearEventVoid;
487 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
488 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
489 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
490 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
491 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
492 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
493 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
494 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
495 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
496 pCallbacks->pfnFreePool = vboxFreePoolVoid;
497 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
498 return;
499 }
500
501 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
502 (PrimaryExtension,
503 (PUCHAR)"VideoPortWaitForSingleObject");
504 Assert(pCallbacks->pfnWaitForSingleObject);
505
506 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
507 (PrimaryExtension,
508 (PUCHAR)"VideoPortSetEvent");
509 Assert(pCallbacks->pfnSetEvent);
510
511 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
512 (PrimaryExtension,
513 (PUCHAR)"VideoPortClearEvent");
514 Assert(pCallbacks->pfnClearEvent);
515
516 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
517 (PrimaryExtension,
518 (PUCHAR)"VideoPortCreateEvent");
519 Assert(pCallbacks->pfnCreateEvent);
520
521 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
522 (PrimaryExtension,
523 (PUCHAR)"VideoPortDeleteEvent");
524 Assert(pCallbacks->pfnDeleteEvent);
525
526 if(pCallbacks->pfnWaitForSingleObject
527 && pCallbacks->pfnSetEvent
528 && pCallbacks->pfnClearEvent
529 && pCallbacks->pfnCreateEvent
530 && pCallbacks->pfnDeleteEvent)
531 {
532 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
533 }
534 else
535 {
536 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
537 pCallbacks->pfnSetEvent = vboxSetEventVoid;
538 pCallbacks->pfnClearEvent = vboxClearEventVoid;
539 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
540 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
541 }
542
543 pCallbacks->pfnCreateSpinLock = (PFNCREATESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
544 (PrimaryExtension,
545 (PUCHAR)"VideoPortCreateSpinLock");
546 Assert(pCallbacks->pfnCreateSpinLock);
547
548 pCallbacks->pfnDeleteSpinLock = (PFNDELETESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
549 (PrimaryExtension,
550 (PUCHAR)"VideoPortDeleteSpinLock");
551 Assert(pCallbacks->pfnDeleteSpinLock);
552
553 pCallbacks->pfnAcquireSpinLock = (PFNACQUIRESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
554 (PrimaryExtension,
555 (PUCHAR)"VideoPortAcquireSpinLock");
556 Assert(pCallbacks->pfnAcquireSpinLock);
557
558 pCallbacks->pfnReleaseSpinLock = (PFNRELEASESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
559 (PrimaryExtension,
560 (PUCHAR)"VideoPortReleaseSpinLock");
561 Assert(pCallbacks->pfnReleaseSpinLock);
562
563 pCallbacks->pfnAcquireSpinLockAtDpcLevel = (PFNACQUIRESPINLOCKATDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
564 (PrimaryExtension,
565 (PUCHAR)"VideoPortAcquireSpinLockAtDpcLevel");
566 Assert(pCallbacks->pfnAcquireSpinLockAtDpcLevel);
567
568 pCallbacks->pfnReleaseSpinLockFromDpcLevel = (PFNRELEASESPINLOCKFROMDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
569 (PrimaryExtension,
570 (PUCHAR)"VideoPortReleaseSpinLockFromDpcLevel");
571 Assert(pCallbacks->pfnReleaseSpinLockFromDpcLevel);
572
573 if(pCallbacks->pfnCreateSpinLock
574 && pCallbacks->pfnDeleteSpinLock
575 && pCallbacks->pfnAcquireSpinLock
576 && pCallbacks->pfnReleaseSpinLock
577 && pCallbacks->pfnAcquireSpinLockAtDpcLevel
578 && pCallbacks->pfnReleaseSpinLockFromDpcLevel)
579 {
580 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_SPINLOCK;
581 }
582 else
583 {
584 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
585 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
586 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
587 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
588 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
589 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
590 }
591
592 pCallbacks->pfnAllocatePool = (PFNALLOCATEPOOL)(pConfigInfo->VideoPortGetProcAddress)
593 (PrimaryExtension,
594 (PUCHAR)"VideoPortAllocatePool");
595 Assert(pCallbacks->pfnAllocatePool);
596
597 pCallbacks->pfnFreePool = (PFNFREEPOOL)(pConfigInfo->VideoPortGetProcAddress)
598 (PrimaryExtension,
599 (PUCHAR)"VideoPortFreePool");
600 Assert(pCallbacks->pfnFreePool);
601
602 if(pCallbacks->pfnAllocatePool
603 && pCallbacks->pfnFreePool)
604 {
605 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
606 }
607 else
608 {
609 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
610 pCallbacks->pfnFreePool = vboxFreePoolVoid;
611 }
612
613 pCallbacks->pfnQueueDpc = (PFNQUEUEDPC)(pConfigInfo->VideoPortGetProcAddress)
614 (PrimaryExtension,
615 (PUCHAR)"VideoPortQueueDpc");
616 Assert(pCallbacks->pfnQueueDpc);
617
618 if(pCallbacks->pfnQueueDpc)
619 {
620 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
621 }
622 else
623 {
624 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
625 }
626
627#ifdef DEBUG_misha
628 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
629 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_SPINLOCK);
630#endif
631}
632
633/**
634 * Helper function to register secondary displays (DualView). Note that this will not
635 * be available on pre-XP versions, and some editions on XP will fail because they are
636 * intentionally crippled.
637 *
638 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
639 * to talk to the host.
640 */
641VOID VBoxSetupDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
642{
643 VP_STATUS rc = NO_ERROR;
644
645 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
646 PrimaryExtension));
647
648 /* Preinitialize the primary extension.
649 * Note: bVBoxVideoSupported is set to FALSE, because HGSMI is active instead.
650 */
651 PrimaryExtension->pNext = NULL;
652 PrimaryExtension->pPrimary = PrimaryExtension;
653 PrimaryExtension->iDevice = 0;
654 PrimaryExtension->ulFrameBufferOffset = 0;
655 PrimaryExtension->ulFrameBufferSize = 0;
656 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
657 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
658 PrimaryExtension->u.primary.cDisplays = 1;
659 PrimaryExtension->u.primary.cbVRAM = AdapterMemorySize;
660 PrimaryExtension->u.primary.cbMiniportHeap = 0;
661 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
662 PrimaryExtension->u.primary.pvAdapterInformation = NULL;
663 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
664 PrimaryExtension->u.primary.bHGSMI = VBoxHGSMIIsSupported (PrimaryExtension);
665 VideoPortZeroMemory(&PrimaryExtension->u.primary.areaHostHeap, sizeof(HGSMIAREA));
666 VideoPortZeroMemory(&PrimaryExtension->areaDisplay, sizeof(HGSMIAREA));
667
668 if (PrimaryExtension->u.primary.IOPortGuest == 0)
669 {
670 PrimaryExtension->u.primary.bHGSMI = false;
671 }
672
673 if (PrimaryExtension->u.primary.bHGSMI)
674 {
675 /* Map the adapter information. It will be needed for HGSMI IO. */
676 rc = VBoxMapAdapterMemory (PrimaryExtension,
677 &PrimaryExtension->u.primary.pvAdapterInformation,
678 PrimaryExtension->u.primary.cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
679 VBVA_ADAPTER_INFORMATION_SIZE
680 );
681 if (rc != NO_ERROR)
682 {
683 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
684 rc));
685
686 PrimaryExtension->u.primary.bHGSMI = FALSE;
687 }
688 else
689 {
690 /* Setup a HGSMI heap within the adapter information area. */
691 rc = HGSMIHeapSetup (&PrimaryExtension->u.primary.hgsmiAdapterHeap,
692 PrimaryExtension->u.primary.pvAdapterInformation,
693 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
694 PrimaryExtension->u.primary.cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE);
695
696 if (RT_FAILURE (rc))
697 {
698 dprintf(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
699 rc));
700
701 PrimaryExtension->u.primary.bHGSMI = FALSE;
702 }
703 else
704 {
705 PrimaryExtension->u.primary.pHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)PrimaryExtension->u.primary.pvAdapterInformation)
706 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
707 }
708 }
709 }
710
711 /* Setup the host heap and the adapter memory. */
712 if (PrimaryExtension->u.primary.bHGSMI)
713 {
714 /* The miniport heap is used for the host buffers. */
715 ULONG cbMiniportHeap = 0;
716 vboxQueryConfHGSMI (PrimaryExtension, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbMiniportHeap);
717
718 if (cbMiniportHeap != 0)
719 {
720 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
721 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 4;
722
723 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
724 {
725 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
726 }
727
728 if (cbMiniportHeap > cbMiniportHeapMaxSize)
729 {
730 cbMiniportHeap = cbMiniportHeapMaxSize;
731 }
732
733 /* Round up to 4096 bytes. */
734 PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
735
736 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
737 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
738
739 /* Map the heap region.
740 *
741 * Note: the heap will be used for the host buffers submitted to the guest.
742 * The miniport driver is responsible for reading FIFO and notifying
743 * display drivers.
744 */
745 rc = VBoxMapAdapterMemory (PrimaryExtension,
746 &PrimaryExtension->u.primary.pvMiniportHeap,
747 PrimaryExtension->u.primary.cbVRAM
748 - VBVA_ADAPTER_INFORMATION_SIZE
749 - PrimaryExtension->u.primary.cbMiniportHeap,
750 PrimaryExtension->u.primary.cbMiniportHeap
751 );
752 if (rc != NO_ERROR)
753 {
754 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
755 PrimaryExtension->u.primary.cbMiniportHeap = 0;
756 PrimaryExtension->u.primary.bHGSMI = FALSE;
757 }
758 else
759 {
760 HGSMIOFFSET offBase = PrimaryExtension->u.primary.cbVRAM
761 - VBVA_ADAPTER_INFORMATION_SIZE
762 - PrimaryExtension->u.primary.cbMiniportHeap;
763
764 /* Init the host hap area. Buffers from the host will be placed there. */
765 HGSMIAreaInitialize (&PrimaryExtension->u.primary.areaHostHeap,
766 PrimaryExtension->u.primary.pvMiniportHeap,
767 PrimaryExtension->u.primary.cbMiniportHeap,
768 offBase);
769 }
770 }
771 else
772 {
773 /* Host has not requested a heap. */
774 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
775 PrimaryExtension->u.primary.cbMiniportHeap = 0;
776 }
777 }
778
779 /* Check whether the guest supports multimonitors. */
780 if (PrimaryExtension->u.primary.bHGSMI)
781 {
782 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
783 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
784
785 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
786 if (vboxQueryWinVersion() > WINNT4)
787 {
788 /* This bluescreens on NT4, hence the above version check */
789 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
790 (PrimaryExtension,
791 (PUCHAR)"VideoPortCreateSecondaryDisplay");
792 }
793
794 if (pfnCreateSecondaryDisplay != NULL)
795 {
796 /* Query the configured number of displays. */
797 ULONG cDisplays = 0;
798 vboxQueryConfHGSMI (PrimaryExtension, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
799
800 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
801 cDisplays));
802
803 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
804 {
805 /* Host reported some bad value. Continue in the 1 screen mode. */
806 cDisplays = 1;
807 }
808
809 PDEVICE_EXTENSION pPrev = PrimaryExtension;
810
811 ULONG iDisplay;
812 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
813 {
814 PDEVICE_EXTENSION SecondaryExtension = NULL;
815 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
816
817 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
818 rc, SecondaryExtension));
819
820 if (rc != NO_ERROR)
821 {
822 break;
823 }
824
825 SecondaryExtension->pNext = NULL;
826 SecondaryExtension->pPrimary = PrimaryExtension;
827 SecondaryExtension->iDevice = iDisplay;
828 SecondaryExtension->ulFrameBufferOffset = 0;
829 SecondaryExtension->ulFrameBufferSize = 0;
830 SecondaryExtension->u.secondary.bEnabled = FALSE;
831
832 /* Update the list pointers. */
833 pPrev->pNext = SecondaryExtension;
834 pPrev = SecondaryExtension;
835
836 /* Take the successfully created display into account. */
837 PrimaryExtension->u.primary.cDisplays++;
838 }
839 }
840
841 /* Failure to create secondary displays is not fatal */
842 rc = NO_ERROR;
843 }
844
845 /* Now when the number of monitors is known and extensions are created,
846 * calculate the layout of framebuffers.
847 */
848 VBoxComputeFrameBufferSizes (PrimaryExtension);
849
850 if (PrimaryExtension->u.primary.bHGSMI)
851 {
852 /* Setup the information for the host. */
853 rc = vboxSetupAdapterInfoHGSMI (PrimaryExtension);
854
855 if (RT_FAILURE (rc))
856 {
857 PrimaryExtension->u.primary.bHGSMI = FALSE;
858 }
859 }
860
861 if (!PrimaryExtension->u.primary.bHGSMI)
862 {
863 /* Unmap the memory if VBoxVideo is not supported. */
864 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap);
865 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation);
866
867 HGSMIHeapDestroy (&PrimaryExtension->u.primary.hgsmiAdapterHeap);
868 }
869
870 if (PrimaryExtension->u.primary.bHGSMI)
871 {
872 PrimaryExtension->u.primary.VideoPortProcs.pfnCreateSpinLock(PrimaryExtension, &PrimaryExtension->u.primary.pSynchLock);
873 }
874
875 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
876}
877
878
879/*
880 * Send the pointer shape to the host.
881 */
882typedef struct _MOUSEPOINTERSHAPECTX
883{
884 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
885 uint32_t cbData;
886 int32_t i32Result;
887} MOUSEPOINTERSHAPECTX;
888
889static int vbvaInitMousePointerShape (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
890{
891 NOREF (PrimaryExtension);
892
893 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
894 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
895
896 /* Will be updated by the host. */
897 p->i32Result = VINF_SUCCESS;
898
899 /* We have our custom flags in the field */
900 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
901
902 /* Even if pointer is invisible, we have to pass following data,
903 * so host could create the pointer with initial status - invisible
904 */
905 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
906 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
907 p->u32Width = pCtx->pPointerAttr->Width;
908 p->u32Height = pCtx->pPointerAttr->Height;
909
910 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
911 {
912 /* Copy the actual pointer data. */
913 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
914 }
915
916 return VINF_SUCCESS;
917}
918
919static int vbvaFinalizeMousePointerShape (PDEVICE_EXTENSION PrimaryExtension, void *pvContext, void *pvData)
920{
921 NOREF (PrimaryExtension);
922
923 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
924 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
925
926 pCtx->i32Result = p->i32Result;
927
928 return VINF_SUCCESS;
929}
930
931BOOLEAN vboxUpdatePointerShape (PDEVICE_EXTENSION PrimaryExtension,
932 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
933 uint32_t cbLength)
934{
935 uint32_t cbData = 0;
936
937 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
938 {
939 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
940 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
941 + pointerAttr->Width * 4 * pointerAttr->Height;
942 }
943
944 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
945 cbData, pointerAttr->Width, pointerAttr->Height));
946
947 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
948 {
949 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
950 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
951 return FALSE;
952 }
953
954 MOUSEPOINTERSHAPECTX ctx;
955
956 ctx.pPointerAttr = pointerAttr;
957 ctx.cbData = cbData;
958 ctx.i32Result = VERR_NOT_SUPPORTED;
959
960 int rc = vboxCallVBVA (PrimaryExtension,
961 VBVA_MOUSE_POINTER_SHAPE,
962 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
963 vbvaInitMousePointerShape,
964 vbvaFinalizeMousePointerShape,
965 &ctx);
966
967 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
968
969 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
970}
971
972typedef struct _VBVAMINIPORT_CHANNELCONTEXT
973{
974 PFNHGSMICHANNELHANDLER pfnChannelHandler;
975 void *pvChannelHandler;
976}VBVAMINIPORT_CHANNELCONTEXT;
977
978typedef struct _VBVADISP_CHANNELCONTEXT
979{
980 struct _VBVAHOSTCMD * pFirstCmd;
981 struct _VBVAHOSTCMD * pLastCmd;
982 PSPIN_LOCK pSynchLock;
983#ifdef DEBUG
984 int cCmds;
985#endif
986 bool bValid;
987}VBVADISP_CHANNELCONTEXT;
988
989#ifdef DEBUG
990void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
991{
992 int counter = 0;
993 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
994 {
995 Assert(pCur != pCmd);
996 if(pCur == pList->pLastCmd)
997 {
998 Assert(pCur->u.pNext == NULL);
999 }
1000 if(pCur->u.pNext == NULL)
1001 {
1002 Assert(pCur == pList->pLastCmd);
1003 }
1004 counter++;
1005 }
1006
1007 Assert(counter == pList->cCmds);
1008}
1009
1010void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1011{
1012 UCHAR oldIrql;
1013 PrimaryExtension->u.primary.VideoPortProcs.pfnAcquireSpinLock(PrimaryExtension,
1014 pList->pSynchLock,
1015 &oldIrql);
1016
1017 dbgCheckListLocked(pList, pCmd);
1018
1019 PrimaryExtension->u.primary.VideoPortProcs.pfnReleaseSpinLock(PrimaryExtension,
1020 pList->pSynchLock,
1021 oldIrql);
1022}
1023
1024#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
1025#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
1026
1027#else
1028#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
1029#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
1030#endif
1031
1032
1033typedef struct _VBVA_CHANNELCONTEXTS
1034{
1035 PDEVICE_EXTENSION PrimaryExtension;
1036 uint32_t cUsed;
1037 uint32_t cContexts;
1038 VBVAMINIPORT_CHANNELCONTEXT mpContext;
1039 VBVADISP_CHANNELCONTEXT aContexts[1];
1040}VBVA_CHANNELCONTEXTS;
1041
1042static int vboxVBVADeleteChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS * pContext)
1043{
1044 PrimaryExtension->u.primary.VideoPortProcs.pfnFreePool(PrimaryExtension,pContext);
1045 return VINF_SUCCESS;
1046}
1047
1048static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
1049{
1050 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
1051 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
1052 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)PrimaryExtension->u.primary.VideoPortProcs.pfnAllocatePool(PrimaryExtension,
1053 VBoxVpNonPagedPool,
1054 size,
1055 MEM_TAG);
1056 if(pContext)
1057 {
1058 memset(pContext, 0, size);
1059 pContext->cContexts = cDisplays;
1060 pContext->PrimaryExtension = PrimaryExtension;
1061 *ppContext = pContext;
1062 return VINF_SUCCESS;
1063 }
1064 return VERR_GENERAL_FAILURE;
1065}
1066
1067static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
1068{
1069 if(iId < 0)
1070 {
1071 return NULL;
1072 }
1073 else if(pCallbacks->cContexts > (uint32_t)iId)
1074 {
1075 return &pCallbacks->aContexts[iId];
1076 }
1077 return NULL;
1078}
1079
1080DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
1081{
1082 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
1083 HGSMIHostCmdComplete (PrimaryExtension, pCmd);
1084}
1085
1086DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
1087{
1088// if(display < 0)
1089// return VERR_INVALID_PARAMETER;
1090 if(!ppCmd)
1091 return VERR_INVALID_PARAMETER;
1092
1093 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
1094 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
1095
1096 /* pick up the host commands */
1097 VBoxVideoHGSMIDpc(PrimaryExtension, NULL);
1098
1099 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&PrimaryExtension->u.primary.channels, u8Channel);
1100 if(pChannel)
1101 {
1102 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1103 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
1104 Assert(pDispContext);
1105 if(pDispContext)
1106 {
1107 UCHAR oldIrql;
1108 PrimaryExtension->u.primary.VideoPortProcs.pfnAcquireSpinLock(PrimaryExtension,
1109 pDispContext->pSynchLock,
1110 &oldIrql);
1111
1112 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
1113
1114 *ppCmd = pDispContext->pFirstCmd;
1115 pDispContext->pFirstCmd = NULL;
1116 pDispContext->pLastCmd = NULL;
1117#ifdef DEBUG
1118 pDispContext->cCmds = 0;
1119#endif
1120 PrimaryExtension->u.primary.VideoPortProcs.pfnReleaseSpinLock(PrimaryExtension,
1121 pDispContext->pSynchLock,
1122 oldIrql);
1123
1124 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
1125
1126 return VINF_SUCCESS;
1127 }
1128 }
1129
1130 return VERR_INVALID_PARAMETER;
1131}
1132
1133static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1134{
1135 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
1136// Assert(0);
1137 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
1138 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
1139 {
1140 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
1141 Assert(pHdr->iDstID >= 0);
1142 if(pHdr->iDstID >= 0)
1143 {
1144 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
1145 Assert(pHandler && pHandler->bValid);
1146 if(pHandler && pHandler->bValid)
1147 {
1148 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
1149 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
1150 {
1151 Assert(!pCur->u.Data);
1152 Assert(!pFirst);
1153 Assert(!pLast);
1154
1155 switch(u16ChannelInfo)
1156 {
1157 case VBVAHG_DISPLAY_CUSTOM:
1158 {
1159 if(pLast)
1160 {
1161 pLast->u.pNext = pCur;
1162 pLast = pCur;
1163 }
1164 else
1165 {
1166 pFirst = pCur;
1167 pLast = pCur;
1168 }
1169 Assert(!pCur->u.Data);
1170 //TODO: use offset here
1171 pCur = pCur->u.pNext;
1172 Assert(!pCur);
1173 Assert(pFirst);
1174 Assert(pFirst == pLast);
1175 break;
1176 }
1177 case VBVAHG_EVENT:
1178 {
1179 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
1180 PEVENT pEvent = (PEVENT)pEventCmd->pEvent;
1181 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(
1182 pCallbacks->PrimaryExtension,
1183 pEvent);
1184 }
1185 default:
1186 {
1187 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
1188 Assert(u16ChannelInfo==VBVAHG_EVENT);
1189 Assert(!pCur->u.Data);
1190 //TODO: use offset here
1191 if(pLast)
1192 pLast->u.pNext = pCur->u.pNext;
1193 VBVAHOSTCMD * pNext = pCur->u.pNext;
1194 pCur->u.pNext = NULL;
1195 HGSMIHostCmdComplete(pCallbacks->PrimaryExtension, pCur);
1196 pCur = pNext;
1197 Assert(!pCur);
1198 Assert(!pFirst);
1199 Assert(pFirst == pLast);
1200 break;
1201 }
1202 }
1203 }
1204
1205 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
1206
1207 /* we do not support lists currently */
1208 Assert(pFirst == pLast);
1209 if(pLast)
1210 {
1211 Assert(pLast->u.pNext == NULL);
1212 }
1213
1214 if(pFirst)
1215 {
1216 Assert(pLast);
1217 UCHAR oldIrql;
1218 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnAcquireSpinLock(pCallbacks->PrimaryExtension,
1219 pHandler->pSynchLock,
1220 &oldIrql);
1221
1222 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
1223
1224 if(pHandler->pLastCmd)
1225 {
1226 pHandler->pLastCmd->u.pNext = pFirst;
1227 Assert(pHandler->pFirstCmd);
1228 }
1229 else
1230 {
1231 Assert(!pHandler->pFirstCmd);
1232 pHandler->pFirstCmd = pFirst;
1233 }
1234 pHandler->pLastCmd = pLast;
1235#ifdef DEBUG
1236 pHandler->cCmds++;
1237#endif
1238 DBG_CHECKLIST_LOCKED(pHandler, NULL);
1239
1240 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnReleaseSpinLock(pCallbacks->PrimaryExtension,
1241 pHandler->pSynchLock,
1242 oldIrql);
1243 }
1244 else
1245 {
1246 Assert(!pLast);
1247 }
1248 return VINF_SUCCESS;
1249 }
1250 }
1251 else
1252 {
1253 //TODO: impl
1254// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
1255// if(pHandler && pHandler->pfnChannelHandler)
1256// {
1257// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
1258//
1259// return VINF_SUCCESS;
1260// }
1261 }
1262 }
1263 /* no handlers were found, need to complete the command here */
1264 HGSMIHostCmdComplete(pCallbacks->PrimaryExtension, pvBuffer);
1265 return VINF_SUCCESS;
1266}
1267
1268static HGSMICHANNELHANDLER g_OldHandler;
1269
1270int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
1271 int iDisplay, /* negative would mean this is a miniport handler */
1272 uint8_t u8Channel)
1273{
1274 VBVA_CHANNELCONTEXTS * pContexts;
1275 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&PrimaryExtension->u.primary.channels, u8Channel);
1276 if(!pChannel)
1277 {
1278 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
1279 if(RT_FAILURE(rc))
1280 {
1281 return rc;
1282 }
1283 }
1284 else
1285 {
1286 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1287 }
1288
1289 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
1290 Assert(pDispContext);
1291 if(pDispContext)
1292 {
1293#ifdef DEBUGVHWASTRICT
1294 Assert(!pDispContext->bValid);
1295#endif
1296 Assert(!pDispContext->pFirstCmd);
1297 Assert(!pDispContext->pLastCmd);
1298 if(!pDispContext->bValid)
1299 {
1300 pDispContext->bValid = true;
1301 pDispContext->pFirstCmd = NULL;
1302 pDispContext->pLastCmd= NULL;
1303#ifdef DEBUG
1304 pDispContext->cCmds = 0;
1305#endif
1306
1307 PrimaryExtension->u.primary.VideoPortProcs.pfnCreateSpinLock(PrimaryExtension, &pDispContext->pSynchLock);
1308
1309 int rc = VINF_SUCCESS;
1310 if(!pChannel)
1311 {
1312 rc = HGSMIChannelRegister (&PrimaryExtension->u.primary.channels,
1313 u8Channel,
1314 "VGA Miniport HGSMI channel",
1315 vboxVBVAChannelGenericHandler,
1316 pContexts,
1317 &g_OldHandler);
1318 }
1319
1320 if(RT_SUCCESS(rc))
1321 {
1322 pContexts->cUsed++;
1323 return VINF_SUCCESS;
1324 }
1325 }
1326 }
1327
1328 if(!pChannel)
1329 {
1330 vboxVBVADeleteChannelContexts(PrimaryExtension, pContexts);
1331 }
1332
1333 return VERR_GENERAL_FAILURE;
1334}
1335
1336/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1337 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1338 * host information which is needed by the guest.
1339 *
1340 * Reading will not cause a switch to the host.
1341 *
1342 * Have to take into account:
1343 * * synchronization: host must write to the memory only from EMT,
1344 * large structures must be read under flag, which tells the host
1345 * that the guest is currently reading the memory (OWNER flag?).
1346 * * guest writes: may be allocate a page for the host info and make
1347 * the page readonly for the guest.
1348 * * the information should be available only for additions drivers.
1349 * * VMMDev additions driver will inform the host which version of the info it expects,
1350 * host must support all versions.
1351 *
1352 */
1353
1354
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