VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c@ 15539

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

crOpenGL: export to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 27.6 KB
Line 
1/* $Id: vboxhgcm.c 15532 2008-12-15 18:53:11Z vboxsync $ */
2
3/** @file
4 * VBox HGCM connection
5 */
6
7/*
8 * Copyright (C) 2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#ifdef RT_OS_WINDOWS
24 #include <windows.h>
25 #include <ddraw.h>
26#else
27 #include <sys/ioctl.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <unistd.h>
32#endif
33
34#include "cr_error.h"
35#include "cr_net.h"
36#include "cr_bufpool.h"
37#include "cr_mem.h"
38#include "cr_string.h"
39#include "cr_endian.h"
40#include "cr_threads.h"
41#include "net_internals.h"
42
43#include <VBox/VBoxGuest.h>
44#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
45
46typedef struct {
47 int initialized;
48 int num_conns;
49 CRConnection **conns;
50 CRBufferPool *bufpool;
51#ifdef CHROMIUM_THREADSAFE
52 CRmutex mutex;
53 CRmutex recvmutex;
54#endif
55 CRNetReceiveFuncList *recv_list;
56 CRNetCloseFuncList *close_list;
57#ifdef RT_OS_WINDOWS
58 HANDLE hGuestDrv;
59 LPDIRECTDRAW pDirectDraw;
60#else
61 int iGuestDrv;
62#endif
63} CRVBOXHGCMDATA;
64
65static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
66
67typedef enum {
68 CR_VBOXHGCM_USERALLOCATED,
69 CR_VBOXHGCM_MEMORY,
70 CR_VBOXHGCM_MEMORY_BIG
71#ifdef RT_OS_WINDOWS
72 ,CR_VBOXHGCM_DDRAW_SURFACE
73#endif
74} CRVBOXHGCMBUFFERKIND;
75
76#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
77
78typedef struct CRVBOXHGCMBUFFER {
79 uint32_t magic;
80 CRVBOXHGCMBUFFERKIND kind;
81 uint32_t len;
82 uint32_t allocated;
83#ifdef RT_OS_WINDOWS
84 LPDIRECTDRAWSURFACE pDDS;
85#endif
86} CRVBOXHGCMBUFFER;
87
88#ifndef RT_OS_WINDOWS
89 #define TRUE true
90 #define FALSE false
91 #define INVALID_HANDLE_VALUE (-1)
92#endif
93
94/* Some forward declarations */
95static void crVBoxHGCMReceiveMessage(CRConnection *conn);
96
97static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
98{
99 CRASSERT(conn && buf);
100
101 if (!conn->pBuffer || (conn->cbBuffer<len))
102 return FALSE;
103
104 crMemcpy(buf, conn->pBuffer, len);
105
106 conn->cbBuffer -= len;
107 conn->pBuffer = conn->cbBuffer>0 ? (uint8_t*)conn->pBuffer+len : NULL;
108
109 return TRUE;
110}
111
112/*@todo get rid of it*/
113static bool _crVBoxHGCMWriteBytes(CRConnection *conn, const void *buf, uint32_t len)
114{
115 CRASSERT(conn && buf);
116
117 /* make sure there's host buffer and it's clear */
118 CRASSERT(conn->pHostBuffer && !conn->cbHostBuffer);
119 CRASSERT(conn->cbHostBufferAllocated >= len);
120
121 crMemcpy(conn->pHostBuffer, buf, len);
122 conn->cbHostBuffer = len;
123
124 return TRUE;
125}
126
127/**
128 * Send an HGCM request
129 *
130 * @return VBox status code
131 * @param pvData Data pointer
132 * @param cbData Data size
133 */
134/*@todo use vbglR3DoIOCtl here instead */
135static int crVBoxHGCMCall(void *pvData, unsigned cbData)
136{
137#ifdef IN_GUEST
138
139#ifdef RT_OS_WINDOWS
140 DWORD cbReturned;
141
142 if (DeviceIoControl (g_crvboxhgcm.hGuestDrv,
143 VBOXGUEST_IOCTL_HGCM_CALL(cbData),
144 pvData, cbData,
145 pvData, cbData,
146 &cbReturned,
147 NULL))
148 {
149 return VINF_SUCCESS;
150 }
151 crDebug("vboxCall failed with %x\n", GetLastError());
152 return VERR_NOT_SUPPORTED;
153#else
154 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData) >= 0)
155 {
156 return VINF_SUCCESS;
157 }
158 crDebug("vboxCall failed with %x\n", errno);
159 return VERR_NOT_SUPPORTED;
160#endif /*#ifdef RT_OS_WINDOWS*/
161
162#else /*#ifdef IN_GUEST*/
163 crError("crVBoxHGCMCall called on host side!");
164 CRASSERT(FALSE);
165 return VERR_NOT_SUPPORTED;
166#endif
167}
168
169static void *crVBoxHGCMAlloc(CRConnection *conn)
170{
171 CRVBOXHGCMBUFFER *buf;
172
173#ifdef CHROMIUM_THREADSAFE
174 crLockMutex(&g_crvboxhgcm.mutex);
175#endif
176
177 buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
178
179 if (!buf)
180 {
181 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
182 (void *) g_crvboxhgcm.bufpool,
183 (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
184
185#if defined(IN_GUEST) && defined(RT_OS_WINDOWS)
186 /* Try to start DDRAW on guest side */
187 if (!g_crvboxhgcm.pDirectDraw && 0)
188 {
189 HRESULT hr;
190
191 hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL);
192 if (hr != DD_OK)
193 {
194 crWarning("Failed to create DirectDraw interface (%x)\n", hr);
195 g_crvboxhgcm.pDirectDraw = NULL;
196 }
197 else
198 {
199 hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL);
200 if (hr != DD_OK)
201 {
202 crWarning("Failed to SetCooperativeLevel (%x)\n", hr);
203 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
204 g_crvboxhgcm.pDirectDraw = NULL;
205 }
206 crDebug("Created DirectDraw and set CooperativeLevel successfully\n");
207 }
208 }
209
210 /* Try to allocate buffer via DDRAW */
211 if (g_crvboxhgcm.pDirectDraw)
212 {
213 DDSURFACEDESC ddsd;
214 HRESULT hr;
215 LPDIRECTDRAWSURFACE lpDDS;
216
217 memset(&ddsd, 0, sizeof(ddsd));
218 ddsd.dwSize = sizeof(ddsd);
219
220 /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason
221 * also, it would be better to request dwLinearSize but it fails too
222 * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size;
223 */
224
225 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
226 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
227 /* use 1 byte per pixel format */
228 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
229 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
230 ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
231 ddsd.ddpfPixelFormat.dwRBitMask = 0xFF;
232 ddsd.ddpfPixelFormat.dwGBitMask = 0;
233 ddsd.ddpfPixelFormat.dwBBitMask = 0;
234 /* request given buffer size, rounded to 1k */
235 ddsd.dwWidth = 1024;
236 ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth;
237
238 hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL);
239 if (hr != DD_OK)
240 {
241 crWarning("Failed to create DirectDraw surface (%x)\n", hr);
242 }
243 else
244 {
245 crDebug("Created DirectDraw surface (%x)\n", lpDDS);
246
247 hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL);
248 if (hr != DD_OK)
249 {
250 crWarning("Failed to lock DirectDraw surface (%x)\n", hr);
251 IDirectDrawSurface_Release(lpDDS);
252 }
253 else
254 {
255 uint32_t cbLocked;
256 cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight;
257
258 crDebug("Locked %d bytes DirectDraw surface\n", cbLocked);
259
260 buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface;
261 CRASSERT(buf);
262 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
263 buf->kind = CR_VBOXHGCM_DDRAW_SURFACE;
264 buf->allocated = cbLocked;
265 buf->pDDS = lpDDS;
266 }
267 }
268 }
269#endif
270
271 /* We're either on host side, or we failed to allocate DDRAW buffer */
272 if (!buf)
273 {
274 crDebug("Using system malloc\n");
275 buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
276 CRASSERT(buf);
277 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
278 buf->kind = CR_VBOXHGCM_MEMORY;
279 buf->allocated = conn->buffer_size;
280#ifdef RT_OS_WINDOWS
281 buf->pDDS = NULL;
282#endif
283 }
284 }
285
286#ifdef CHROMIUM_THREADSAFE
287 crUnlockMutex(&g_crvboxhgcm.mutex);
288#endif
289
290 return (void *)( buf + 1 );
291
292}
293
294static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
295{
296 CRVBOXHGCMWRITE parms;
297 int rc;
298
299 parms.hdr.result = VINF_SUCCESS;
300 parms.hdr.u32ClientID = conn->u32ClientID;
301 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
302 parms.hdr.cParms = SHCRGL_CPARMS_WRITE;
303
304 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
305 parms.pBuffer.u.Pointer.size = len;
306 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) buf;
307
308 rc = crVBoxHGCMCall(&parms, sizeof(parms));
309
310 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
311 {
312 crDebug("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, parms.hdr.result);
313 }
314}
315
316/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
317 * This halves the number of HGCM calls we do,
318 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
319 */
320static void
321crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
322{
323 CRVBOXHGCMWRITEREAD parms;
324 int rc;
325
326 parms.hdr.result = VINF_SUCCESS;
327 parms.hdr.u32ClientID = conn->u32ClientID;
328 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
329 parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ;
330
331 //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE)
332 {
333 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
334 parms.pBuffer.u.Pointer.size = len;
335 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) buf;
336 }
337 /*else //@todo it fails badly, have to check why
338 {
339 parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr;
340 parms.pBuffer.u.Pointer.size = len;
341 parms.pBuffer.u.Pointer.u.physAddr = (VMMDEVHYPPHYS32) buf;
342 }*/
343
344 CRASSERT(!conn->pBuffer); //make sure there's no data to process
345 parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
346 parms.pWriteback.u.Pointer.size = conn->cbHostBufferAllocated;
347 parms.pWriteback.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) conn->pHostBuffer;
348
349 parms.cbWriteback.type = VMMDevHGCMParmType_32bit;
350 parms.cbWriteback.u.value32 = 0;
351
352 rc = crVBoxHGCMCall(&parms, sizeof(parms));
353
354 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
355 {
356 crDebug("SHCRGL_GUEST_FN_WRITE_READ failed with %x %x\n", rc, parms.hdr.result);
357 return;
358 }
359
360 if (parms.cbWriteback.u.value32)
361 {
362 conn->pBuffer = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;
363 conn->cbBuffer = parms.cbWriteback.u.value32;
364 }
365
366 if (conn->cbBuffer)
367 crVBoxHGCMReceiveMessage(conn);
368}
369
370static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
371 const void *start, unsigned int len)
372{
373 CRVBOXHGCMBUFFER *hgcm_buffer;
374
375 if (!bufp) /* We're sending a user-allocated buffer. */
376 {
377#ifndef IN_GUEST
378 //@todo remove temp buffer allocation in unpacker
379 /* we're at the host side, so just store data until guest polls us */
380 _crVBoxHGCMWriteBytes(conn, start, len);
381#else
382 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
383 crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
384#endif
385 return;
386 }
387
388 /* The region [start .. start + len + 1] lies within a buffer that
389 * was allocated with crVBoxHGCMAlloc() and can be put into the free
390 * buffer pool when we're done sending it.
391 */
392
393 hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
394 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
395
396 /* Length would be passed as part of HGCM pointer description
397 * No need to prepend it to the buffer
398 */
399 crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
400
401 /* Reclaim this pointer for reuse */
402#ifdef CHROMIUM_THREADSAFE
403 crLockMutex(&g_crvboxhgcm.mutex);
404#endif
405 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
406#ifdef CHROMIUM_THREADSAFE
407 crUnlockMutex(&g_crvboxhgcm.mutex);
408#endif
409
410 /* Since the buffer's now in the 'free' buffer pool, the caller can't
411 * use it any more. Setting bufp to NULL will make sure the caller
412 * doesn't try to re-use the buffer.
413 */
414 *bufp = NULL;
415}
416
417static void crVBoxHGCMReadExact( CRConnection *conn, void *buf, unsigned int len )
418{
419 CRASSERT(FALSE);
420}
421
422static void crVBoxHGCMPollHost(CRConnection *conn)
423{
424 CRVBOXHGCMREAD parms;
425 int rc;
426
427 CRASSERT(!conn->pBuffer);
428
429 parms.hdr.result = VINF_SUCCESS;
430 parms.hdr.u32ClientID = conn->u32ClientID;
431 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
432 parms.hdr.cParms = SHCRGL_CPARMS_READ;
433
434 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
435 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
436 parms.pBuffer.u.Pointer.u.linearAddr = (VMMDEVHYPPTR) conn->pHostBuffer;
437
438 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
439 parms.cbBuffer.u.value32 = 0;
440
441 rc = crVBoxHGCMCall(&parms, sizeof(parms));
442
443 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
444 {
445 crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
446 return;
447 }
448
449 if (parms.cbBuffer.u.value32)
450 {
451 conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
452 conn->cbBuffer = parms.cbBuffer.u.value32;
453 }
454}
455
456static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
457{
458 crVBoxHGCMReadExact(conn, buf, len);
459}
460
461static void crVBoxHGCMFree(CRConnection *conn, void *buf)
462{
463 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
464
465 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
466
467 /*@todo wrong len for redir buffers*/
468 conn->recv_credits += hgcm_buffer->len;
469
470 switch (hgcm_buffer->kind)
471 {
472 case CR_VBOXHGCM_MEMORY:
473#ifdef RT_OS_WINDOWS
474 case CR_VBOXHGCM_DDRAW_SURFACE:
475#endif
476#ifdef CHROMIUM_THREADSAFE
477 crLockMutex(&g_crvboxhgcm.mutex);
478#endif
479 if (g_crvboxhgcm.bufpool) {
480 //@todo o'rly?
481 /* pool may have been deallocated just a bit earlier in response
482 * to a SIGPIPE (Broken Pipe) signal.
483 */
484 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
485 }
486#ifdef CHROMIUM_THREADSAFE
487 crUnlockMutex(&g_crvboxhgcm.mutex);
488#endif
489 break;
490
491 case CR_VBOXHGCM_MEMORY_BIG:
492 crFree( hgcm_buffer );
493 break;
494
495 default:
496 crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
497 }
498}
499
500static void crVBoxHGCMReceiveMessage(CRConnection *conn)
501{
502 uint32_t len;
503 CRVBOXHGCMBUFFER *hgcm_buffer;
504 CRMessage *msg;
505 CRMessageType cached_type;
506
507 len = conn->cbBuffer;
508 CRASSERT(len > 0);
509 CRASSERT(conn->pBuffer);
510
511#ifndef IN_GUEST
512 if (conn->allow_redir_ptr)
513 {
514#endif //IN_GUEST
515 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
516
517 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
518 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
519
520 msg = (CRMessage *) (hgcm_buffer + 1);
521
522 msg->header.type = CR_MESSAGE_REDIR_PTR;
523 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
524 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
525
526 cached_type = msg->redirptr.pMessage->type;
527
528 conn->cbBuffer = 0;
529 conn->pBuffer = NULL;
530#ifndef IN_GUEST
531 }
532 else
533 {
534 if ( len <= conn->buffer_size )
535 {
536 /* put in pre-allocated buffer */
537 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
538 }
539 else
540 {
541 /* allocate new buffer,
542 * not using pool here as it's most likely one time transfer of huge texture
543 */
544 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
545 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
546 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
547 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
548#ifdef RT_OS_WINDOWS
549 hgcm_buffer->pDDS = NULL;
550#endif
551 }
552
553 hgcm_buffer->len = len;
554
555 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
556
557 msg = (CRMessage *) (hgcm_buffer + 1);
558 cached_type = msg->header.type;
559 }
560#endif //IN_GUEST
561
562 conn->recv_credits -= len;
563 conn->total_bytes_recv += len;
564
565 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
566
567 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
568 * OOB messages are the programmer's problem. -- Humper 12/17/01
569 */
570 if (cached_type != CR_MESSAGE_OPCODES
571 && cached_type != CR_MESSAGE_OOB
572 && cached_type != CR_MESSAGE_GATHER)
573 {
574 crVBoxHGCMFree(conn, msg);
575 }
576}
577
578/*
579 * Called on host side only, to "accept" client connection
580 */
581static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
582{
583 CRASSERT(conn && conn->pHostBuffer);
584#ifdef IN_GUEST
585 CRASSERT(FALSE);
586#endif
587}
588
589/**
590 * The function that actually connects. This should only be called by clients,
591 * guests in vbox case.
592 * Servers go through crVBoxHGCMAccept;
593 */
594/*@todo use vbglR3Something here */
595static int crVBoxHGCMDoConnect( CRConnection *conn )
596{
597#ifdef IN_GUEST
598 VBoxGuestHGCMConnectInfo info;
599
600#ifdef RT_OS_WINDOWS
601 DWORD cbReturned;
602
603 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
604 {
605 /* open VBox guest driver */
606 g_crvboxhgcm.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
607 GENERIC_READ | GENERIC_WRITE,
608 FILE_SHARE_READ | FILE_SHARE_WRITE,
609 NULL,
610 OPEN_EXISTING,
611 FILE_ATTRIBUTE_NORMAL,
612 NULL);
613
614 /* @todo check if we could rollback to softwareopengl */
615 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
616 {
617 crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
618 return FALSE;
619 }
620 }
621#else
622 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
623 {
624 g_crvboxhgcm.iGuestDrv = open(VBOXGUEST_DEVICE_NAME, O_RDWR, 0);
625 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
626 {
627 crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
628 return FALSE;
629 }
630 }
631#endif
632
633 memset (&info, 0, sizeof (info));
634 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
635 strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
636
637#ifdef RT_OS_WINDOWS
638 if (DeviceIoControl(g_crvboxhgcm.hGuestDrv,
639 VBOXGUEST_IOCTL_HGCM_CONNECT,
640 &info, sizeof (info),
641 &info, sizeof (info),
642 &cbReturned,
643 NULL))
644#else
645 /*@todo it'd fail */
646 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
647#endif
648 {
649 if (info.result == VINF_SUCCESS)
650 {
651 conn->u32ClientID = info.u32ClientID;
652 crDebug("HGCM connect was successful: client id =%x\n", conn->u32ClientID);
653 }
654 else
655 {
656 crDebug("HGCM connect failed with rc=%x\n", info.result);
657 return FALSE;
658 }
659 }
660 else
661 {
662#ifdef RT_OS_WINDOWS
663 crDebug("HGCM connect failed with rc=%x\n", GetLastError());
664#else
665 crDebug("HGCM connect failed with rc=%x\n", errno);
666#endif
667 return FALSE;
668 }
669
670 return TRUE;
671
672#else /*#ifdef IN_GUEST*/
673 crError("crVBoxHGCMDoConnect called on host side!");
674 CRASSERT(FALSE);
675 return FALSE;
676#endif
677}
678
679/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
680static void crVBoxHGCMDoDisconnect( CRConnection *conn )
681{
682 VBoxGuestHGCMDisconnectInfo info;
683#ifdef RT_OS_WINDOWS
684 DWORD cbReturned;
685#endif
686 int i;
687
688 if (conn->pHostBuffer)
689 {
690 crFree(conn->pHostBuffer);
691 conn->pHostBuffer = NULL;
692 conn->cbHostBuffer = 0;
693 conn->cbHostBufferAllocated = 0;
694 }
695
696 conn->pBuffer = NULL;
697 conn->cbBuffer = 0;
698
699 //@todo hold lock here?
700 if (conn->type == CR_VBOXHGCM)
701 {
702 --g_crvboxhgcm.num_conns;
703
704 if (conn->index < g_crvboxhgcm.num_conns)
705 {
706 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
707 g_crvboxhgcm.conns[conn->index]->index = conn->index;
708 }
709 else g_crvboxhgcm.conns[conn->index] = NULL;
710
711 conn->type = CR_NO_CONNECTION;
712 }
713
714#ifndef IN_GUEST
715#else
716 if (conn->u32ClientID)
717 {
718 memset (&info, 0, sizeof (info));
719 info.u32ClientID = conn->u32ClientID;
720
721#ifdef RT_OS_WINDOWS
722 if ( !DeviceIoControl(g_crvboxhgcm.hGuestDrv,
723 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
724 &info, sizeof (info),
725 &info, sizeof (info),
726 &cbReturned,
727 NULL) )
728 {
729 crDebug("Disconnect failed with %x\n", GetLastError());
730 }
731#else
732 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
733 {
734 crDebug("Disconnect failed with %x\n", errno);
735 }
736#endif
737
738 conn->u32ClientID = 0;
739 }
740
741 /* see if any connections remain */
742 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
743 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
744 break;
745
746 /* close guest additions driver*/
747 if (i>=g_crvboxhgcm.num_conns)
748 {
749#ifdef RT_OS_WINDOWS
750 CloseHandle(g_crvboxhgcm.hGuestDrv);
751 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
752#else
753 close(g_crvboxhgcm.iGuestDrv);
754 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
755#endif
756 }
757#endif
758}
759
760static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
761{
762 crVBoxHGCMFree(conn, mess);
763 CRASSERT(FALSE);
764}
765
766static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
767{
768 CRASSERT(FALSE);
769}
770
771void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
772{
773 (void) mtu;
774
775 g_crvboxhgcm.recv_list = rfl;
776 g_crvboxhgcm.close_list = cfl;
777 if (g_crvboxhgcm.initialized)
778 {
779 return;
780 }
781
782 g_crvboxhgcm.initialized = 1;
783
784 g_crvboxhgcm.num_conns = 0;
785 g_crvboxhgcm.conns = NULL;
786
787 /* Can't open VBox guest driver here, because it gets called for host side as well */
788 /*@todo as we have 2 dll versions, can do it now.*/
789
790#ifdef RT_OS_WINDOWS
791 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
792 g_crvboxhgcm.pDirectDraw = NULL;
793#else
794 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
795#endif
796
797#ifdef CHROMIUM_THREADSAFE
798 crInitMutex(&g_crvboxhgcm.mutex);
799 crInitMutex(&g_crvboxhgcm.recvmutex);
800#endif
801 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
802}
803
804/* Callback function used to free buffer pool entries */
805void crVBoxHGCMBufferFree(void *data)
806{
807#ifdef RT_OS_WINDOWS
808 LPDIRECTDRAWSURFACE lpDDS;
809#endif
810 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
811
812 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
813
814 switch (hgcm_buffer->kind)
815 {
816 case CR_VBOXHGCM_MEMORY:
817 crFree( hgcm_buffer );
818 break;
819#ifdef RT_OS_WINDOWS
820 case CR_VBOXHGCM_DDRAW_SURFACE:
821 lpDDS = hgcm_buffer->pDDS;
822 CRASSERT(lpDDS);
823 IDirectDrawSurface_Unlock(lpDDS, NULL);
824 IDirectDrawSurface_Release(lpDDS);
825 crDebug("DDraw surface freed (%x)\n", lpDDS);
826 break;
827#endif
828 case CR_VBOXHGCM_MEMORY_BIG:
829 crFree( hgcm_buffer );
830 break;
831
832 default:
833 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
834 }
835}
836
837void crVBoxHGCMTearDown(void)
838{
839 int32_t i;
840
841 if (!g_crvboxhgcm.initialized) return;
842
843 for (i=0; i<g_crvboxhgcm.num_conns; i++)
844 {
845 crNetDisconnect(g_crvboxhgcm.conns[i]);
846 }
847
848#ifdef CHROMIUM_THREADSAFE
849 crFreeMutex(&g_crvboxhgcm.mutex);
850 crFreeMutex(&g_crvboxhgcm.recvmutex);
851#endif
852
853 if (g_crvboxhgcm.bufpool)
854 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
855 g_crvboxhgcm.bufpool = NULL;
856
857 g_crvboxhgcm.initialized = 0;
858
859 crFree(g_crvboxhgcm.conns);
860 g_crvboxhgcm.conns = NULL;
861
862#ifdef RT_OS_WINDOWS
863 if (g_crvboxhgcm.pDirectDraw)
864 {
865 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
866 g_crvboxhgcm.pDirectDraw = NULL;
867 crDebug("DirectDraw released\n");
868 }
869#endif
870}
871
872void crVBoxHGCMConnection(CRConnection *conn)
873{
874 int i, found = 0;
875 int n_bytes;
876
877 CRASSERT(g_crvboxhgcm.initialized);
878
879 conn->type = CR_VBOXHGCM;
880 conn->Alloc = crVBoxHGCMAlloc;
881 conn->Send = crVBoxHGCMSend;
882 conn->SendExact = crVBoxHGCMWriteExact;
883 conn->Recv = crVBoxHGCMSingleRecv;
884 conn->RecvMsg = crVBoxHGCMReceiveMessage;
885 conn->Free = crVBoxHGCMFree;
886 conn->Accept = crVBoxHGCMAccept;
887 conn->Connect = crVBoxHGCMDoConnect;
888 conn->Disconnect = crVBoxHGCMDoDisconnect;
889 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
890 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
891 conn->index = g_crvboxhgcm.num_conns;
892 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
893 conn->actual_network = 1;
894
895 conn->krecv_buf_size = 0;
896
897 conn->pBuffer = NULL;
898 conn->cbBuffer = 0;
899 conn->allow_redir_ptr = 1;
900
901 //@todo remove this crap at all later
902 conn->cbHostBufferAllocated = 100*1024;
903 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
904 CRASSERT(conn->pHostBuffer);
905 conn->cbHostBuffer = 0;
906
907 /* Find a free slot */
908 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
909 if (g_crvboxhgcm.conns[i] == NULL) {
910 conn->index = i;
911 g_crvboxhgcm.conns[i] = conn;
912 found = 1;
913 break;
914 }
915 }
916
917 /* Realloc connection stack if we couldn't find a free slot */
918 if (found == 0) {
919 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
920 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
921 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
922 }
923}
924
925int crVBoxHGCMRecv(void)
926{
927 int32_t i;
928
929#ifdef IN_GUEST
930 /* we're on guest side, poll host if it got something for us */
931 for (i=0; i<g_crvboxhgcm.num_conns; i++)
932 {
933 CRConnection *conn = g_crvboxhgcm.conns[i];
934
935 if ( !conn || conn->type == CR_NO_CONNECTION )
936 continue;
937
938 if (!conn->pBuffer)
939 {
940 crVBoxHGCMPollHost(conn);
941 }
942 }
943#endif
944
945 for (i=0; i<g_crvboxhgcm.num_conns; i++)
946 {
947 CRConnection *conn = g_crvboxhgcm.conns[i];
948
949 if ( !conn || conn->type == CR_NO_CONNECTION )
950 continue;
951
952 if (conn->cbBuffer>0)
953 {
954 crVBoxHGCMReceiveMessage(conn);
955 }
956 }
957
958 return 0;
959}
960
961CRConnection** crVBoxHGCMDump( int *num )
962{
963 *num = g_crvboxhgcm.num_conns;
964
965 return g_crvboxhgcm.conns;
966}
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