VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxVideo/HGSMIBase.cpp@ 65047

Last change on this file since 65047 was 65047, checked in by vboxsync, 8 years ago

bugref:8282: Additions/linux: submit DRM driver to the Linux kernel: rename VBoxVideoVBE.h to VBoxVideoHW.h in preparation for moving all guest-side parts from VBoxVideo.h to there and leaving only host-side parts in VBoxVideo.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.0 KB
Line 
1/* $Id: HGSMIBase.cpp 65047 2017-01-01 10:53:29Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - HGSMI initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2016 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <VBox/VBoxVideoGuest.h>
20#include <VBox/VBoxVideo.h>
21#include <VBox/Hardware/VBoxVideoHW.h>
22
23#include <iprt/asm.h>
24#include <iprt/string.h>
25
26/** Send completion notification to the host for the command located at offset
27 * @a offt into the host command buffer. */
28static void HGSMINotifyHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, HGSMIOFFSET offt)
29{
30 VBoxVideoCmnPortWriteUlong(pCtx->port, offt);
31}
32
33
34/**
35 * Inform the host that a command has been handled.
36 *
37 * @param pCtx the context containing the heap to be used
38 * @param pvMem pointer into the heap as mapped in @a pCtx to the command to
39 * be completed
40 */
41DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx,
42 void *pvMem)
43{
44 HGSMIBUFFERHEADER *pHdr = HGSMIBufferHeaderFromData(pvMem);
45 HGSMIOFFSET offMem = HGSMIPointerToOffset(&pCtx->areaCtx, pHdr);
46 VBVOAssert(offMem != HGSMIOFFSET_VOID);
47 if(offMem != HGSMIOFFSET_VOID)
48 {
49 HGSMINotifyHostCmdComplete(pCtx, offMem);
50 }
51}
52
53
54/** Submit an incoming host command to the appropriate handler. */
55static void hgsmiHostCmdProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx,
56 HGSMIOFFSET offBuffer)
57{
58 int rc = HGSMIBufferProcess(&pCtx->areaCtx, &pCtx->channels, offBuffer);
59 VBVOAssert(!RT_FAILURE(rc));
60 if(RT_FAILURE(rc))
61 {
62 /* failure means the command was not submitted to the handler for some reason
63 * it's our responsibility to notify its completion in this case */
64 HGSMINotifyHostCmdComplete(pCtx, offBuffer);
65 }
66 /* if the cmd succeeded it's responsibility of the callback to complete it */
67}
68
69/** Get the next command from the host. */
70static HGSMIOFFSET hgsmiGetHostBuffer(PHGSMIHOSTCOMMANDCONTEXT pCtx)
71{
72 return VBoxVideoCmnPortReadUlong(pCtx->port);
73}
74
75
76/** Get and handle the next command from the host. */
77static void hgsmiHostCommandQueryProcess(PHGSMIHOSTCOMMANDCONTEXT pCtx)
78{
79 HGSMIOFFSET offset = hgsmiGetHostBuffer(pCtx);
80 VBVOAssertReturnVoid(offset != HGSMIOFFSET_VOID);
81 hgsmiHostCmdProcess(pCtx, offset);
82}
83
84
85/** Drain the host command queue. */
86DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx)
87{
88 while (pCtx->pfHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
89 {
90 if (!ASMAtomicCmpXchgBool(&pCtx->fHostCmdProcessing, true, false))
91 return;
92 hgsmiHostCommandQueryProcess(pCtx);
93 ASMAtomicWriteBool(&pCtx->fHostCmdProcessing, false);
94 }
95}
96
97
98/** Detect whether HGSMI is supported by the host. */
99DECLHIDDEN(bool) VBoxHGSMIIsSupported(void)
100{
101 uint16_t DispiId;
102
103 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
104 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
105
106 DispiId = VBoxVideoCmnPortReadUshort(VBE_DISPI_IOPORT_DATA);
107
108 return (DispiId == VBE_DISPI_ID_HGSMI);
109}
110
111
112/**
113 * Allocate and initialise a command descriptor in the guest heap for a
114 * guest-to-host command.
115 *
116 * @returns pointer to the descriptor's command data buffer
117 * @param pCtx the context containing the heap to be used
118 * @param cbData the size of the command data to go into the descriptor
119 * @param u8Ch the HGSMI channel to be used, set to the descriptor
120 * @param u16Op the HGSMI command to be sent, set to the descriptor
121 */
122DECLHIDDEN(void *) VBoxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx,
123 HGSMISIZE cbData,
124 uint8_t u8Ch,
125 uint16_t u16Op)
126{
127#ifdef VBOX_WDDM_MINIPORT
128 return VBoxSHGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
129#else
130 return HGSMIHeapAlloc (&pCtx->heapCtx, cbData, u8Ch, u16Op);
131#endif
132}
133
134
135/**
136 * Free a descriptor allocated by @a VBoxHGSMIBufferAlloc.
137 *
138 * @param pCtx the context containing the heap used
139 * @param pvBuffer the pointer returned by @a VBoxHGSMIBufferAlloc
140 */
141DECLHIDDEN(void) VBoxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx,
142 void *pvBuffer)
143{
144#ifdef VBOX_WDDM_MINIPORT
145 VBoxSHGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
146#else
147 HGSMIHeapFree (&pCtx->heapCtx, pvBuffer);
148#endif
149}
150
151
152/**
153 * Submit a command descriptor allocated by @a VBoxHGSMIBufferAlloc.
154 *
155 * @param pCtx the context containing the heap used
156 * @param pvBuffer the pointer returned by @a VBoxHGSMIBufferAlloc
157 */
158DECLHIDDEN(int) VBoxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx,
159 void *pvBuffer)
160{
161 /* Initialize the buffer and get the offset for port IO. */
162 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (HGSMIGUESTCMDHEAP_GET(&pCtx->heapCtx), pvBuffer);
163
164 VBVOAssert(offBuffer != HGSMIOFFSET_VOID);
165 if (offBuffer != HGSMIOFFSET_VOID)
166 {
167 /* Submit the buffer to the host. */
168 VBoxVideoCmnPortWriteUlong(pCtx->port, offBuffer);
169 /* Make the compiler aware that the host has changed memory. */
170 ASMCompilerBarrier();
171 return VINF_SUCCESS;
172 }
173
174 return VERR_INVALID_PARAMETER;
175}
176
177
178/** Inform the host of the location of the host flags in VRAM via an HGSMI
179 * command. */
180static int vboxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
181 HGSMIOFFSET offLocation)
182{
183 HGSMIBUFFERLOCATION *p;
184 int rc = VINF_SUCCESS;
185
186 /* Allocate the IO buffer. */
187 p = (HGSMIBUFFERLOCATION *)VBoxHGSMIBufferAlloc(pCtx,
188 sizeof(HGSMIBUFFERLOCATION),
189 HGSMI_CH_HGSMI,
190 HGSMI_CC_HOST_FLAGS_LOCATION);
191 if (p)
192 {
193 /* Prepare data to be sent to the host. */
194 p->offLocation = offLocation;
195 p->cbLocation = sizeof(HGSMIHOSTFLAGS);
196 rc = VBoxHGSMIBufferSubmit(pCtx, p);
197 /* Free the IO buffer. */
198 VBoxHGSMIBufferFree(pCtx, p);
199 }
200 else
201 rc = VERR_NO_MEMORY;
202 return rc;
203}
204
205
206/**
207 * Inform the host of the location of the host flags in VRAM via an HGSMI
208 * command.
209 * @returns IPRT status value.
210 * @returns VERR_NOT_IMPLEMENTED if the host does not support the command.
211 * @returns VERR_NO_MEMORY if a heap allocation fails.
212 * @param pCtx the context of the guest heap to use.
213 * @param offLocation the offset chosen for the flags withing guest
214 * VRAM.
215 */
216DECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx,
217 HGSMIOFFSET offLocation)
218{
219 return vboxHGSMIReportFlagsLocation(pCtx, offLocation);
220}
221
222
223/** Notify the host of HGSMI-related guest capabilities via an HGSMI command.
224 */
225static int vboxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
226 uint32_t fCaps)
227{
228 VBVACAPS *pCaps;
229 int rc = VINF_SUCCESS;
230
231 /* Allocate the IO buffer. */
232 pCaps = (VBVACAPS *)VBoxHGSMIBufferAlloc(pCtx,
233 sizeof(VBVACAPS), HGSMI_CH_VBVA,
234 VBVA_INFO_CAPS);
235
236 if (pCaps)
237 {
238 /* Prepare data to be sent to the host. */
239 pCaps->rc = VERR_NOT_IMPLEMENTED;
240 pCaps->fCaps = fCaps;
241 rc = VBoxHGSMIBufferSubmit(pCtx, pCaps);
242 if (RT_SUCCESS(rc))
243 {
244 VBVOAssertRC(pCaps->rc);
245 rc = pCaps->rc;
246 }
247 /* Free the IO buffer. */
248 VBoxHGSMIBufferFree(pCtx, pCaps);
249 }
250 else
251 rc = VERR_NO_MEMORY;
252 return rc;
253}
254
255
256/**
257 * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
258 * @returns IPRT status value.
259 * @returns VERR_NOT_IMPLEMENTED if the host does not support the command.
260 * @returns VERR_NO_MEMORY if a heap allocation fails.
261 * @param pCtx the context of the guest heap to use.
262 * @param fCaps the capabilities to report, see VBVACAPS.
263 */
264DECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
265 uint32_t fCaps)
266{
267 return vboxHGSMISendCapsInfo(pCtx, fCaps);
268}
269
270
271/** Tell the host about the location of the area of VRAM set aside for the host
272 * heap. */
273static int vboxHGSMIReportHostArea(PHGSMIGUESTCOMMANDCONTEXT pCtx,
274 uint32_t u32AreaOffset, uint32_t u32AreaSize)
275{
276 VBVAINFOHEAP *p;
277 int rc = VINF_SUCCESS;
278
279 /* Allocate the IO buffer. */
280 p = (VBVAINFOHEAP *)VBoxHGSMIBufferAlloc(pCtx,
281 sizeof (VBVAINFOHEAP), HGSMI_CH_VBVA,
282 VBVA_INFO_HEAP);
283 if (p)
284 {
285 /* Prepare data to be sent to the host. */
286 p->u32HeapOffset = u32AreaOffset;
287 p->u32HeapSize = u32AreaSize;
288 rc = VBoxHGSMIBufferSubmit(pCtx, p);
289 /* Free the IO buffer. */
290 VBoxHGSMIBufferFree(pCtx, p);
291 }
292 else
293 rc = VERR_NO_MEMORY;
294 return rc;
295}
296
297
298/**
299 * Get the information needed to map the basic communication structures in
300 * device memory into our address space. All pointer parameters are optional.
301 *
302 * @param cbVRAM how much video RAM is allocated to the device
303 * @param poffVRAMBaseMapping where to save the offset from the start of the
304 * device VRAM of the whole area to map
305 * @param pcbMapping where to save the mapping size
306 * @param poffGuestHeapMemory where to save the offset into the mapped area
307 * of the guest heap backing memory
308 * @param pcbGuestHeapMemory where to save the size of the guest heap
309 * backing memory
310 * @param poffHostFlags where to save the offset into the mapped area
311 * of the host flags
312 */
313DECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM,
314 uint32_t *poffVRAMBaseMapping,
315 uint32_t *pcbMapping,
316 uint32_t *poffGuestHeapMemory,
317 uint32_t *pcbGuestHeapMemory,
318 uint32_t *poffHostFlags)
319{
320 VBVOAssertPtrNullReturnVoid(poffVRAMBaseMapping);
321 VBVOAssertPtrNullReturnVoid(pcbMapping);
322 VBVOAssertPtrNullReturnVoid(poffGuestHeapMemory);
323 VBVOAssertPtrNullReturnVoid(pcbGuestHeapMemory);
324 VBVOAssertPtrNullReturnVoid(poffHostFlags);
325 if (poffVRAMBaseMapping)
326 *poffVRAMBaseMapping = cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE;
327 if (pcbMapping)
328 *pcbMapping = VBVA_ADAPTER_INFORMATION_SIZE;
329 if (poffGuestHeapMemory)
330 *poffGuestHeapMemory = 0;
331 if (pcbGuestHeapMemory)
332 *pcbGuestHeapMemory = VBVA_ADAPTER_INFORMATION_SIZE
333 - sizeof(HGSMIHOSTFLAGS);
334 if (poffHostFlags)
335 *poffHostFlags = VBVA_ADAPTER_INFORMATION_SIZE
336 - sizeof(HGSMIHOSTFLAGS);
337}
338
339
340/**
341 * Set up the HGSMI guest-to-host command context.
342 * @returns iprt status value
343 * @param pCtx the context to set up
344 * @param pvGuestHeapMemory a pointer to the mapped backing memory for
345 * the guest heap
346 * @param cbGuestHeapMemory the size of the backing memory area
347 * @param offVRAMGuestHeapMemory the offset of the memory pointed to by
348 * @a pvGuestHeapMemory within the video RAM
349 */
350DECLHIDDEN(int) VBoxHGSMISetupGuestContext(PHGSMIGUESTCOMMANDCONTEXT pCtx,
351 void *pvGuestHeapMemory,
352 uint32_t cbGuestHeapMemory,
353 uint32_t offVRAMGuestHeapMemory,
354 const HGSMIENV *pEnv)
355{
356 /** @todo should we be using a fixed ISA port value here? */
357 pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
358#ifdef VBOX_WDDM_MINIPORT
359 return VBoxSHGSMIInit(&pCtx->heapCtx, pvGuestHeapMemory,
360 cbGuestHeapMemory, offVRAMGuestHeapMemory, pEnv);
361#else
362 return HGSMIHeapSetup(&pCtx->heapCtx, pvGuestHeapMemory,
363 cbGuestHeapMemory, offVRAMGuestHeapMemory, pEnv);
364#endif
365}
366
367
368/**
369 * Get the information needed to map the area used by the host to send back
370 * requests.
371 *
372 * @param pCtx the context containing the heap to use
373 * @param cbVRAM how much video RAM is allocated to the device
374 * @param offVRAMBaseMapping the offset of the basic communication structures
375 * into the guest's VRAM
376 * @param poffVRAMHostArea where to store the offset into VRAM of the host
377 * heap area
378 * @param pcbHostArea where to store the size of the host heap area
379 */
380DECLHIDDEN(void) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx,
381 uint32_t cbVRAM,
382 uint32_t offVRAMBaseMapping,
383 uint32_t *poffVRAMHostArea,
384 uint32_t *pcbHostArea)
385{
386 uint32_t offVRAMHostArea = offVRAMBaseMapping, cbHostArea = 0;
387
388 VBVOAssertPtrReturnVoid(poffVRAMHostArea);
389 VBVOAssertPtrReturnVoid(pcbHostArea);
390 VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbHostArea);
391 if (cbHostArea != 0)
392 {
393 uint32_t cbHostAreaMaxSize = cbVRAM / 4;
394 /** @todo what is the idea of this? */
395 if (cbHostAreaMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
396 {
397 cbHostAreaMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
398 }
399 if (cbHostArea > cbHostAreaMaxSize)
400 {
401 cbHostArea = cbHostAreaMaxSize;
402 }
403 /* Round up to 4096 bytes. */
404 cbHostArea = (cbHostArea + 0xFFF) & ~0xFFF;
405 offVRAMHostArea = offVRAMBaseMapping - cbHostArea;
406 }
407
408 *pcbHostArea = cbHostArea;
409 *poffVRAMHostArea = offVRAMHostArea;
410 // LogFunc(("offVRAMHostArea = 0x%08X, cbHostArea = 0x%08X\n",
411 // offVRAMHostArea, cbHostArea));
412}
413
414
415/**
416 * Initialise the host context structure.
417 *
418 * @param pCtx the context structure to initialise
419 * @param pvBaseMapping where the basic HGSMI structures are mapped at
420 * @param offHostFlags the offset of the host flags into the basic HGSMI
421 * structures
422 * @param pvHostAreaMapping where the area for the host heap is mapped at
423 * @param offVRAMHostArea offset of the host heap area into VRAM
424 * @param cbHostArea size in bytes of the host heap area
425 */
426DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx,
427 void *pvBaseMapping,
428 uint32_t offHostFlags,
429 void *pvHostAreaMapping,
430 uint32_t offVRAMHostArea,
431 uint32_t cbHostArea)
432{
433 uint8_t *pu8HostFlags = ((uint8_t *)pvBaseMapping) + offHostFlags;
434 pCtx->pfHostFlags = (HGSMIHOSTFLAGS *)pu8HostFlags;
435 /** @todo should we really be using a fixed ISA port value here? */
436 pCtx->port = (RTIOPORT)VGA_PORT_HGSMI_HOST;
437 HGSMIAreaInitialize(&pCtx->areaCtx, pvHostAreaMapping, cbHostArea,
438 offVRAMHostArea);
439}
440
441
442/**
443 * Tell the host about the ways it can use to communicate back to us via an
444 * HGSMI command
445 *
446 * @returns iprt status value
447 * @param pCtx the context containing the heap to use
448 * @param offVRAMFlagsLocation where we wish the host to place its flags
449 * relative to the start of the VRAM
450 * @param fCaps additions HGSMI capabilities the guest
451 * supports
452 * @param offVRAMHostArea offset into VRAM of the host heap area
453 * @param cbHostArea size in bytes of the host heap area
454 */
455DECLHIDDEN(int) VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
456 HGSMIOFFSET offVRAMFlagsLocation,
457 uint32_t fCaps,
458 uint32_t offVRAMHostArea,
459 uint32_t cbHostArea)
460{
461 // Log(("VBoxVideo::vboxSetupAdapterInfo\n"));
462
463 /* setup the flags first to ensure they are initialized by the time the
464 * host heap is ready */
465 int rc = vboxHGSMIReportFlagsLocation(pCtx, offVRAMFlagsLocation);
466 VBVOAssertRC(rc);
467 if (RT_SUCCESS(rc) && fCaps)
468 {
469 /* Inform about caps */
470 rc = vboxHGSMISendCapsInfo(pCtx, fCaps);
471 VBVOAssertRC(rc);
472 }
473 if (RT_SUCCESS (rc))
474 {
475 /* Report the host heap location. */
476 rc = vboxHGSMIReportHostArea(pCtx, offVRAMHostArea, cbHostArea);
477 VBVOAssertRC(rc);
478 }
479 // Log(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
480 return rc;
481}
482
483
484/** Sanity test on first call. We do not worry about concurrency issues. */
485static int testQueryConf(PHGSMIGUESTCOMMANDCONTEXT pCtx)
486{
487 static bool cOnce = false;
488 uint32_t ulValue = 0;
489 int rc;
490
491 if (cOnce)
492 return VINF_SUCCESS;
493 cOnce = true;
494 rc = VBoxQueryConfHGSMI(pCtx, UINT32_MAX, &ulValue);
495 if (RT_SUCCESS(rc) && ulValue == UINT32_MAX)
496 return VINF_SUCCESS;
497 cOnce = false;
498 if (RT_FAILURE(rc))
499 return rc;
500 return VERR_INTERNAL_ERROR;
501}
502
503
504/**
505 * Query the host for an HGSMI configuration parameter via an HGSMI command.
506 * @returns iprt status value
507 * @param pCtx the context containing the heap used
508 * @param u32Index the index of the parameter to query,
509 * @see VBVACONF32::u32Index
510 * @param u32DefValue defaut value
511 * @param pulValue where to store the value of the parameter on success
512 */
513DECLHIDDEN(int) VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx,
514 uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue)
515{
516 int rc = VINF_SUCCESS;
517 VBVACONF32 *p;
518 // LogFunc(("u32Index = %d\n", u32Index));
519
520 rc = testQueryConf(pCtx);
521 if (RT_FAILURE(rc))
522 return rc;
523 /* Allocate the IO buffer. */
524 p = (VBVACONF32 *)VBoxHGSMIBufferAlloc(pCtx,
525 sizeof(VBVACONF32), HGSMI_CH_VBVA,
526 VBVA_QUERY_CONF32);
527 if (p)
528 {
529 /* Prepare data to be sent to the host. */
530 p->u32Index = u32Index;
531 p->u32Value = u32DefValue;
532 rc = VBoxHGSMIBufferSubmit(pCtx, p);
533 if (RT_SUCCESS(rc))
534 {
535 *pulValue = p->u32Value;
536 // LogFunc(("u32Value = %d\n", p->u32Value));
537 }
538 /* Free the IO buffer. */
539 VBoxHGSMIBufferFree(pCtx, p);
540 }
541 else
542 rc = VERR_NO_MEMORY;
543 // LogFunc(("rc = %d\n", rc));
544 return rc;
545}
546
547DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx,
548 uint32_t u32Index, uint32_t *pulValue)
549{
550 return VBoxQueryConfHGSMIDef(pCtx, u32Index, UINT32_MAX, pulValue);
551}
552
553/**
554 * Pass the host a new mouse pointer shape via an HGSMI command.
555 *
556 * @returns success or failure
557 * @param fFlags cursor flags, @see VMMDevReqMousePointer::fFlags
558 * @param cHotX horizontal position of the hot spot
559 * @param cHotY vertical position of the hot spot
560 * @param cWidth width in pixels of the cursor
561 * @param cHeight height in pixels of the cursor
562 * @param pPixels pixel data, @see VMMDevReqMousePointer for the format
563 * @param cbLength size in bytes of the pixel data
564 */
565DECLHIDDEN(int) VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx,
566 uint32_t fFlags,
567 uint32_t cHotX,
568 uint32_t cHotY,
569 uint32_t cWidth,
570 uint32_t cHeight,
571 uint8_t *pPixels,
572 uint32_t cbLength)
573{
574 VBVAMOUSEPOINTERSHAPE *p;
575 uint32_t cbData = 0;
576 int rc = VINF_SUCCESS;
577
578 if (fFlags & VBOX_MOUSE_POINTER_SHAPE)
579 {
580 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
581 cbData = ((((cWidth + 7) / 8) * cHeight + 3) & ~3)
582 + cWidth * 4 * cHeight;
583 /* If shape is supplied, then always create the pointer visible.
584 * See comments in 'vboxUpdatePointerShape'
585 */
586 fFlags |= VBOX_MOUSE_POINTER_VISIBLE;
587 }
588 // LogFlowFunc(("cbData %d, %dx%d\n", cbData, cWidth, cHeight));
589 if (cbData > cbLength)
590 {
591 // LogFunc(("calculated pointer data size is too big (%d bytes, limit %d)\n",
592 // cbData, cbLength));
593 return VERR_INVALID_PARAMETER;
594 }
595 /* Allocate the IO buffer. */
596 p = (VBVAMOUSEPOINTERSHAPE *)VBoxHGSMIBufferAlloc(pCtx,
597 sizeof(VBVAMOUSEPOINTERSHAPE)
598 + cbData,
599 HGSMI_CH_VBVA,
600 VBVA_MOUSE_POINTER_SHAPE);
601 if (p)
602 {
603 /* Prepare data to be sent to the host. */
604 /* Will be updated by the host. */
605 p->i32Result = VINF_SUCCESS;
606 /* We have our custom flags in the field */
607 p->fu32Flags = fFlags;
608 p->u32HotX = cHotX;
609 p->u32HotY = cHotY;
610 p->u32Width = cWidth;
611 p->u32Height = cHeight;
612 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
613 /* Copy the actual pointer data. */
614 memcpy (p->au8Data, pPixels, cbData);
615 rc = VBoxHGSMIBufferSubmit(pCtx, p);
616 if (RT_SUCCESS(rc))
617 rc = p->i32Result;
618 /* Free the IO buffer. */
619 VBoxHGSMIBufferFree(pCtx, p);
620 }
621 else
622 rc = VERR_NO_MEMORY;
623 // LogFlowFunc(("rc %d\n", rc));
624 return rc;
625}
626
627
628/**
629 * Report the guest cursor position. The host may wish to use this information
630 * to re-position its own cursor (though this is currently unlikely). The
631 * current host cursor position is returned.
632 * @param pCtx The context containing the heap used.
633 * @param fReportPosition Are we reporting a position?
634 * @param x Guest cursor X position.
635 * @param y Guest cursor Y position.
636 * @param pxHost Host cursor X position is stored here. Optional.
637 * @param pyHost Host cursor Y position is stored here. Optional.
638 * @returns iprt status code.
639 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
640 */
641DECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y,
642 uint32_t *pxHost, uint32_t *pyHost)
643{
644 int rc = VINF_SUCCESS;
645 VBVACURSORPOSITION *p;
646 // Log(("%s: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)x, (unsigned)y));
647
648 /* Allocate the IO buffer. */
649 p = (VBVACURSORPOSITION *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVACURSORPOSITION), HGSMI_CH_VBVA, VBVA_CURSOR_POSITION);
650 if (p)
651 {
652 /* Prepare data to be sent to the host. */
653 p->fReportPosition = fReportPosition ? 1 : 0;
654 p->x = x;
655 p->y = y;
656 rc = VBoxHGSMIBufferSubmit(pCtx, p);
657 if (RT_SUCCESS(rc))
658 {
659 if (pxHost)
660 *pxHost = p->x;
661 if (pyHost)
662 *pyHost = p->y;
663 // Log(("%s: return: x=%u, y=%u\n", __PRETTY_FUNCTION__, (unsigned)p->x, (unsigned)p->y));
664 }
665 /* Free the IO buffer. */
666 VBoxHGSMIBufferFree(pCtx, p);
667 }
668 else
669 rc = VERR_NO_MEMORY;
670 // LogFunc(("rc = %d\n", rc));
671 return rc;
672}
673
674
675/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
676 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
677 * host information which is needed by the guest.
678 *
679 * Reading will not cause a switch to the host.
680 *
681 * Have to take into account:
682 * * synchronization: host must write to the memory only from EMT,
683 * large structures must be read under flag, which tells the host
684 * that the guest is currently reading the memory (OWNER flag?).
685 * * guest writes: may be allocate a page for the host info and make
686 * the page readonly for the guest.
687 * * the information should be available only for additions drivers.
688 * * VMMDev additions driver will inform the host which version of the info it expects,
689 * host must support all versions.
690 *
691 */
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