]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - ubuntu/vbox/vboxguest/VBoxGuest-linux.c
UBUNTU: ubuntu: vbox -- update to 5.2.8-dfsg-2
[mirror_ubuntu-bionic-kernel.git] / ubuntu / vbox / vboxguest / VBoxGuest-linux.c
CommitLineData
ac320018 1/* $Rev: 120349 $ */
056a1eb7
SF
2/** @file
3 * VBoxGuest - Linux specifics.
4 *
5 * Note. Unfortunately, the difference between this and SUPDrv-linux.c is
6 * a little bit too big to be helpful.
7 */
8
9/*
26894aac 10 * Copyright (C) 2006-2017 Oracle Corporation
056a1eb7
SF
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
26894aac
SF
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 */
056a1eb7
SF
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35
36#include "the-linux-kernel.h"
37
38#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
39# define VBOXGUEST_WITH_INPUT_DRIVER
40#endif
41
ac320018
SF
42#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
43# define CONST_4_15 const
44#else
45# define CONST_4_15
46#endif
47
056a1eb7
SF
48#include "VBoxGuestInternal.h"
49#ifdef VBOXGUEST_WITH_INPUT_DRIVER
50# include <linux/input.h>
51#endif
52#include <linux/miscdevice.h>
53#include <linux/poll.h>
54#include <VBox/version.h>
55#include "revision-generated.h"
56
57#include <iprt/assert.h>
58#include <iprt/asm.h>
59#include <iprt/err.h>
60#include <iprt/initterm.h>
61#include <iprt/mem.h>
62#include <iprt/mp.h>
63#include <iprt/process.h>
64#include <iprt/spinlock.h>
65#include <iprt/semaphore.h>
6d209b23 66#include <iprt/string.h>
056a1eb7
SF
67#include <VBox/log.h>
68
69
70/*********************************************************************************************************************************
71* Defined Constants And Macros *
72*********************************************************************************************************************************/
73/** The device name. */
74#define DEVICE_NAME "vboxguest"
75/** The device name for the device node open to everyone. */
76#define DEVICE_NAME_USER "vboxuser"
77/** The name of the PCI driver */
78#define DRIVER_NAME DEVICE_NAME
79
80
81/* 2.4.x compatibility macros that may or may not be defined. */
82#ifndef IRQ_RETVAL
83# define irqreturn_t void
84# define IRQ_RETVAL(n)
85#endif
86
87
88/*********************************************************************************************************************************
89* Internal Functions *
90*********************************************************************************************************************************/
91static void vgdrvLinuxTermPci(struct pci_dev *pPciDev);
92static int vgdrvLinuxProbePci(struct pci_dev *pPciDev, const struct pci_device_id *id);
93static int vgdrvLinuxModInit(void);
94static void vgdrvLinuxModExit(void);
95static int vgdrvLinuxOpen(struct inode *pInode, struct file *pFilp);
96static int vgdrvLinuxRelease(struct inode *pInode, struct file *pFilp);
97#ifdef HAVE_UNLOCKED_IOCTL
98static long vgdrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
99#else
100static int vgdrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
101#endif
6d209b23 102static int vgdrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PVBOXGUESTSESSION pSession);
056a1eb7
SF
103static int vgdrvLinuxFAsync(int fd, struct file *pFile, int fOn);
104static unsigned int vgdrvLinuxPoll(struct file *pFile, poll_table *pPt);
105static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff);
106
107
108/*********************************************************************************************************************************
109* Global Variables *
110*********************************************************************************************************************************/
111/**
112 * Device extention & session data association structure.
113 */
114static VBOXGUESTDEVEXT g_DevExt;
115/** The PCI device. */
116static struct pci_dev *g_pPciDev = NULL;
117/** The base of the I/O port range. */
118static RTIOPORT g_IOPortBase;
119/** The base of the MMIO range. */
120static RTHCPHYS g_MMIOPhysAddr = NIL_RTHCPHYS;
121/** The size of the MMIO range as seen by PCI. */
122static uint32_t g_cbMMIO;
123/** The pointer to the mapping of the MMIO range. */
124static void *g_pvMMIOBase;
125/** Wait queue used by polling. */
126static wait_queue_head_t g_PollEventQueue;
127/** Asynchronous notification stuff. */
128static struct fasync_struct *g_pFAsyncQueue;
129#ifdef VBOXGUEST_WITH_INPUT_DRIVER
130/** Pre-allocated mouse status VMMDev request for use in the IRQ
131 * handler. */
132static VMMDevReqMouseStatus *g_pMouseStatusReq;
133#endif
134#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
135/** Whether we've create the logger or not. */
136static volatile bool g_fLoggerCreated;
137/** Release logger group settings. */
138static char g_szLogGrp[128];
139/** Release logger flags settings. */
140static char g_szLogFlags[128];
141/** Release logger destination settings. */
142static char g_szLogDst[128];
143# if 0
144/** Debug logger group settings. */
145static char g_szDbgLogGrp[128];
146/** Debug logger flags settings. */
147static char g_szDbgLogFlags[128];
148/** Debug logger destination settings. */
149static char g_szDbgLogDst[128];
150# endif
151#endif
152
153/** The input device handle */
154#ifdef VBOXGUEST_WITH_INPUT_DRIVER
155static struct input_dev *g_pInputDevice = NULL;
156#endif
157
158/** The file_operations structure. */
159static struct file_operations g_FileOps =
160{
161 owner: THIS_MODULE,
162 open: vgdrvLinuxOpen,
163 release: vgdrvLinuxRelease,
164#ifdef HAVE_UNLOCKED_IOCTL
165 unlocked_ioctl: vgdrvLinuxIOCtl,
166#else
167 ioctl: vgdrvLinuxIOCtl,
168#endif
169 fasync: vgdrvLinuxFAsync,
170 read: vgdrvLinuxRead,
171 poll: vgdrvLinuxPoll,
172 llseek: no_llseek,
173};
174
175/** The miscdevice structure. */
176static struct miscdevice g_MiscDevice =
177{
178 minor: MISC_DYNAMIC_MINOR,
179 name: DEVICE_NAME,
180 fops: &g_FileOps,
181};
182
183/** The file_operations structure for the user device.
184 * @remarks For the time being we'll be using the same implementation as
185 * /dev/vboxguest here. */
186static struct file_operations g_FileOpsUser =
187{
188 owner: THIS_MODULE,
189 open: vgdrvLinuxOpen,
190 release: vgdrvLinuxRelease,
191#ifdef HAVE_UNLOCKED_IOCTL
192 unlocked_ioctl: vgdrvLinuxIOCtl,
193#else
194 ioctl: vgdrvLinuxIOCtl,
195#endif
196};
197
198/** The miscdevice structure for the user device. */
199static struct miscdevice g_MiscDeviceUser =
200{
201 minor: MISC_DYNAMIC_MINOR,
202 name: DEVICE_NAME_USER,
203 fops: &g_FileOpsUser,
204};
205
206
207/** PCI hotplug structure. */
208static const struct pci_device_id
209#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
210__devinitdata
211#endif
212g_VBoxGuestPciId[] =
213{
214 {
215 vendor: VMMDEV_VENDORID,
216 device: VMMDEV_DEVICEID
217 },
218 {
219 /* empty entry */
220 }
221};
222
223MODULE_DEVICE_TABLE(pci, g_VBoxGuestPciId);
224
225/** Structure for registering the PCI driver. */
226static struct pci_driver g_PciDriver =
227{
228 name: DRIVER_NAME,
229 id_table: g_VBoxGuestPciId,
230 probe: vgdrvLinuxProbePci,
231 remove: vgdrvLinuxTermPci
232};
233
234static PVBOXGUESTSESSION g_pKernelSession = NULL;
235
236
237
238/**
239 * Converts a VBox status code to a linux error code.
240 *
241 * @returns corresponding negative linux error code.
242 * @param rc supdrv error code (SUPDRV_ERR_* defines).
243 */
244static int vgdrvLinuxConvertToNegErrno(int rc)
245{
246 if ( rc > -1000
247 && rc < 1000)
248 return -RTErrConvertToErrno(rc);
249 switch (rc)
250 {
251 case VERR_HGCM_SERVICE_NOT_FOUND: return -ESRCH;
252 case VINF_HGCM_CLIENT_REJECTED: return 0;
253 case VERR_HGCM_INVALID_CMD_ADDRESS: return -EFAULT;
254 case VINF_HGCM_ASYNC_EXECUTE: return 0;
255 case VERR_HGCM_INTERNAL: return -EPROTO;
256 case VERR_HGCM_INVALID_CLIENT_ID: return -EINVAL;
257 case VINF_HGCM_SAVE_STATE: return 0;
258 /* No reason to return this to a guest */
259 // case VERR_HGCM_SERVICE_EXISTS: return -EEXIST;
260 default:
261 AssertMsgFailed(("Unhandled error code %Rrc\n", rc));
262 return -EPROTO;
263 }
264}
265
266
267/**
268 * Does the PCI detection and init of the device.
269 *
270 * @returns 0 on success, negated errno on failure.
271 */
272static int vgdrvLinuxProbePci(struct pci_dev *pPciDev, const struct pci_device_id *id)
273{
274 int rc;
275
276 NOREF(id);
277 AssertReturn(!g_pPciDev, -EINVAL);
278 rc = pci_enable_device(pPciDev);
279 if (rc >= 0)
280 {
281 /* I/O Ports are mandatory, the MMIO bit is not. */
282 g_IOPortBase = pci_resource_start(pPciDev, 0);
283 if (g_IOPortBase != 0)
284 {
285 /*
286 * Map the register address space.
287 */
288 g_MMIOPhysAddr = pci_resource_start(pPciDev, 1);
289 g_cbMMIO = pci_resource_len(pPciDev, 1);
290 if (request_mem_region(g_MMIOPhysAddr, g_cbMMIO, DEVICE_NAME) != NULL)
291 {
292 g_pvMMIOBase = ioremap(g_MMIOPhysAddr, g_cbMMIO);
293 if (g_pvMMIOBase)
294 {
295 /** @todo why aren't we requesting ownership of the I/O ports as well? */
296 g_pPciDev = pPciDev;
297 return 0;
298 }
299
300 /* failure cleanup path */
301 LogRel((DEVICE_NAME ": ioremap failed; MMIO Addr=%RHp cb=%#x\n", g_MMIOPhysAddr, g_cbMMIO));
302 rc = -ENOMEM;
303 release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
304 }
305 else
306 {
307 LogRel((DEVICE_NAME ": failed to obtain adapter memory\n"));
308 rc = -EBUSY;
309 }
310 g_MMIOPhysAddr = NIL_RTHCPHYS;
311 g_cbMMIO = 0;
312 g_IOPortBase = 0;
313 }
314 else
315 {
316 LogRel((DEVICE_NAME ": did not find expected hardware resources\n"));
317 rc = -ENXIO;
318 }
319 pci_disable_device(pPciDev);
320 }
321 else
322 LogRel((DEVICE_NAME ": could not enable device: %d\n", rc));
323 return rc;
324}
325
326
327/**
328 * Clean up the usage of the PCI device.
329 */
330static void vgdrvLinuxTermPci(struct pci_dev *pPciDev)
331{
332 g_pPciDev = NULL;
333 if (pPciDev)
334 {
335 iounmap(g_pvMMIOBase);
336 g_pvMMIOBase = NULL;
337
338 release_mem_region(g_MMIOPhysAddr, g_cbMMIO);
339 g_MMIOPhysAddr = NIL_RTHCPHYS;
340 g_cbMMIO = 0;
341
342 pci_disable_device(pPciDev);
343 }
344}
345
346
347/**
348 * Interrupt service routine.
349 *
350 * @returns In 2.4 it returns void.
351 * In 2.6 we indicate whether we've handled the IRQ or not.
352 *
353 * @param iIrq The IRQ number.
354 * @param pvDevId The device ID, a pointer to g_DevExt.
355 * @param pRegs Register set. Removed in 2.6.19.
356 */
357#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && !defined(DOXYGEN_RUNNING)
358static irqreturn_t vgdrvLinuxISR(int iIrq, void *pvDevId)
359#else
360static irqreturn_t vgdrvLinuxISR(int iIrq, void *pvDevId, struct pt_regs *pRegs)
361#endif
362{
363 bool fTaken = VGDrvCommonISR(&g_DevExt);
364 return IRQ_RETVAL(fTaken);
365}
366
367
368/**
369 * Registers the ISR and initializes the poll wait queue.
370 */
371static int __init vgdrvLinuxInitISR(void)
372{
373 int rc;
374
375 init_waitqueue_head(&g_PollEventQueue);
376 rc = request_irq(g_pPciDev->irq,
377 vgdrvLinuxISR,
378#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
379 IRQF_SHARED,
380#else
381 SA_SHIRQ,
382#endif
383 DEVICE_NAME,
384 &g_DevExt);
385 if (rc)
386 {
387 LogRel((DEVICE_NAME ": could not request IRQ %d: err=%d\n", g_pPciDev->irq, rc));
388 return rc;
389 }
390 return 0;
391}
392
393
394/**
395 * Deregisters the ISR.
396 */
397static void vgdrvLinuxTermISR(void)
398{
399 free_irq(g_pPciDev->irq, &g_DevExt);
400}
401
402
403#ifdef VBOXGUEST_WITH_INPUT_DRIVER
404
405/**
406 * Reports the mouse integration status to the host.
407 *
408 * Calls the kernel IOCtl to report mouse status to the host on behalf of
409 * our kernel session.
410 *
411 * @param fStatus The mouse status to report.
412 */
413static int vgdrvLinuxSetMouseStatus(uint32_t fStatus)
414{
6d209b23
SF
415 int rc;
416 VBGLIOCSETMOUSESTATUS Req;
417 VBGLREQHDR_INIT(&Req.Hdr, SET_MOUSE_STATUS);
418 Req.u.In.fStatus = fStatus;
419 rc = VGDrvCommonIoCtl(VBGL_IOCTL_SET_MOUSE_STATUS, &g_DevExt, g_pKernelSession, &Req.Hdr, sizeof(Req));
420 if (RT_SUCCESS(rc))
421 rc = Req.Hdr.rc;
422 return rc;
056a1eb7
SF
423}
424
425
426/**
427 * Called when the input device is first opened.
428 *
429 * Sets up absolute mouse reporting.
430 */
431static int vboxguestOpenInputDevice(struct input_dev *pDev)
432{
433 int rc = vgdrvLinuxSetMouseStatus(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL);
434 if (RT_FAILURE(rc))
435 return ENODEV;
436 NOREF(pDev);
437 return 0;
438}
439
440
441/**
442 * Called if all open handles to the input device are closed.
443 *
444 * Disables absolute reporting.
445 */
446static void vboxguestCloseInputDevice(struct input_dev *pDev)
447{
448 NOREF(pDev);
449 vgdrvLinuxSetMouseStatus(0);
450}
451
452
453/**
454 * Creates the kernel input device.
455 */
456static int __init vgdrvLinuxCreateInputDevice(void)
457{
6d209b23 458 int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&g_pMouseStatusReq, sizeof(*g_pMouseStatusReq), VMMDevReq_GetMouseStatus);
056a1eb7
SF
459 if (RT_SUCCESS(rc))
460 {
461 g_pInputDevice = input_allocate_device();
462 if (g_pInputDevice)
463 {
464 g_pInputDevice->id.bustype = BUS_PCI;
465 g_pInputDevice->id.vendor = VMMDEV_VENDORID;
466 g_pInputDevice->id.product = VMMDEV_DEVICEID;
467 g_pInputDevice->id.version = VBOX_SHORT_VERSION;
468 g_pInputDevice->open = vboxguestOpenInputDevice;
469 g_pInputDevice->close = vboxguestCloseInputDevice;
470# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
471 g_pInputDevice->cdev.dev = &g_pPciDev->dev;
472# else
473 g_pInputDevice->dev.parent = &g_pPciDev->dev;
474# endif
475 rc = input_register_device(g_pInputDevice);
476 if (rc == 0)
477 {
478 /* Do what one of our competitors apparently does as that works. */
479 ASMBitSet(g_pInputDevice->evbit, EV_ABS);
480 ASMBitSet(g_pInputDevice->evbit, EV_KEY);
481# ifdef EV_SYN
482 ASMBitSet(g_pInputDevice->evbit, EV_SYN);
483# endif
484 input_set_abs_params(g_pInputDevice, ABS_X, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
485 input_set_abs_params(g_pInputDevice, ABS_Y, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
486 ASMBitSet(g_pInputDevice->keybit, BTN_MOUSE);
487 /** @todo this string should be in a header file somewhere. */
488 g_pInputDevice->name = "VirtualBox mouse integration";
489 return 0;
490 }
491
492 input_free_device(g_pInputDevice);
493 }
494 else
495 rc = -ENOMEM;
6d209b23 496 VbglR0GRFree(&g_pMouseStatusReq->header);
056a1eb7
SF
497 g_pMouseStatusReq = NULL;
498 }
499 else
500 rc = -ENOMEM;
501 return rc;
502}
503
504
505/**
506 * Terminates the kernel input device.
507 */
508static void vgdrvLinuxTermInputDevice(void)
509{
6d209b23 510 VbglR0GRFree(&g_pMouseStatusReq->header);
056a1eb7
SF
511 g_pMouseStatusReq = NULL;
512
513 /* See documentation of input_register_device(): input_free_device()
514 * should not be called after a device has been registered. */
515 input_unregister_device(g_pInputDevice);
516}
517
518#endif /* VBOXGUEST_WITH_INPUT_DRIVER */
519
520
521/**
522 * Creates the device nodes.
523 *
524 * @returns 0 on success, negated errno on failure.
525 */
526static int __init vgdrvLinuxInitDeviceNodes(void)
527{
528 /*
529 * The full feature device node.
530 */
531 int rc = misc_register(&g_MiscDevice);
532 if (!rc)
533 {
534 /*
535 * The device node intended to be accessible by all users.
536 */
537 rc = misc_register(&g_MiscDeviceUser);
538 if (!rc)
539 return 0;
540 LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME_USER, rc));
541 misc_deregister(&g_MiscDevice);
542 }
543 else
544 LogRel((DEVICE_NAME ": misc_register failed for %s (rc=%d)\n", DEVICE_NAME, rc));
545 return rc;
546}
547
548
549/**
550 * Deregisters the device nodes.
551 */
552static void vgdrvLinuxTermDeviceNodes(void)
553{
554 misc_deregister(&g_MiscDevice);
555 misc_deregister(&g_MiscDeviceUser);
556}
557
558
559/**
560 * Initialize module.
561 *
562 * @returns appropriate status code.
563 */
564static int __init vgdrvLinuxModInit(void)
565{
566 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
567 PRTLOGGER pRelLogger;
568 int rc;
569
570 /*
571 * Initialize IPRT first.
572 */
573 rc = RTR0Init(0);
574 if (RT_FAILURE(rc))
575 {
576 printk(KERN_ERR DEVICE_NAME ": RTR0Init failed, rc=%d.\n", rc);
577 return -EINVAL;
578 }
579
580 /*
581 * Create the release log.
582 * (We do that here instead of common code because we want to log
583 * early failures using the LogRel macro.)
584 */
585 rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
586 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
587 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER | RTLOGDEST_USER, NULL);
588 if (RT_SUCCESS(rc))
589 {
590#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
591 RTLogGroupSettings(pRelLogger, g_szLogGrp);
592 RTLogFlags(pRelLogger, g_szLogFlags);
593 RTLogDestinations(pRelLogger, g_szLogDst);
594#endif
595 RTLogRelSetDefaultInstance(pRelLogger);
596 }
597#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
598 g_fLoggerCreated = true;
599#endif
600
601 /*
602 * Locate and initialize the PCI device.
603 */
604 rc = pci_register_driver(&g_PciDriver);
605 if (rc >= 0 && g_pPciDev)
606 {
607 /*
608 * Register the interrupt service routine for it.
609 */
610 rc = vgdrvLinuxInitISR();
611 if (rc >= 0)
612 {
613 /*
614 * Call the common device extension initializer.
615 */
616#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_X86)
617 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26;
618#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && defined(RT_ARCH_AMD64)
619 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux26_x64;
620#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_X86)
621 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24;
622#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(RT_ARCH_AMD64)
623 VBOXOSTYPE enmOSType = VBOXOSTYPE_Linux24_x64;
624#else
625# warning "huh? which arch + version is this?"
626 VBOXOSTYPE enmOsType = VBOXOSTYPE_Linux;
627#endif
628 rc = VGDrvCommonInitDevExt(&g_DevExt,
629 g_IOPortBase,
630 g_pvMMIOBase,
631 g_cbMMIO,
632 enmOSType,
633 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
634 if (RT_SUCCESS(rc))
635 {
636 /*
637 * Create the kernel session for this driver.
638 */
639 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &g_pKernelSession);
640 if (RT_SUCCESS(rc))
641 {
642 /*
643 * Create the kernel input device.
644 */
645#ifdef VBOXGUEST_WITH_INPUT_DRIVER
646 rc = vgdrvLinuxCreateInputDevice();
647 if (rc >= 0)
648 {
649#endif
650 /*
651 * Finally, create the device nodes.
652 */
653 rc = vgdrvLinuxInitDeviceNodes();
654 if (rc >= 0)
655 {
656 /* some useful information for the user but don't show this on the console */
657 LogRel((DEVICE_NAME ": misc device minor %d, IRQ %d, I/O port %RTiop, MMIO at %RHp (size 0x%x)\n",
658 g_MiscDevice.minor, g_pPciDev->irq, g_IOPortBase, g_MMIOPhysAddr, g_cbMMIO));
659 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
660 VBOX_VERSION_STRING " (interface " RT_XSTR(VMMDEV_VERSION) ")\n");
661 return rc;
662 }
663
664 /* bail out */
665#ifdef VBOXGUEST_WITH_INPUT_DRIVER
666 vgdrvLinuxTermInputDevice();
667 }
668 else
669 {
670 LogRel((DEVICE_NAME ": vboxguestCreateInputDevice failed with rc=%Rrc\n", rc));
671 rc = RTErrConvertFromErrno(rc);
672 }
673#endif
674 VGDrvCommonCloseSession(&g_DevExt, g_pKernelSession);
675 }
676 VGDrvCommonDeleteDevExt(&g_DevExt);
677 }
678 else
679 {
680 LogRel((DEVICE_NAME ": VGDrvCommonInitDevExt failed with rc=%Rrc\n", rc));
681 rc = RTErrConvertFromErrno(rc);
682 }
683 vgdrvLinuxTermISR();
684 }
685 }
686 else
687 {
688 LogRel((DEVICE_NAME ": PCI device not found, probably running on physical hardware.\n"));
689 rc = -ENODEV;
690 }
691 pci_unregister_driver(&g_PciDriver);
692 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
693 RTLogDestroy(RTLogSetDefaultInstance(NULL));
694 RTR0Term();
695 return rc;
696}
697
698
699/**
700 * Unload the module.
701 */
702static void __exit vgdrvLinuxModExit(void)
703{
704 /*
705 * Inverse order of init.
706 */
707 vgdrvLinuxTermDeviceNodes();
708#ifdef VBOXGUEST_WITH_INPUT_DRIVER
709 vgdrvLinuxTermInputDevice();
710#endif
711 VGDrvCommonCloseSession(&g_DevExt, g_pKernelSession);
712 VGDrvCommonDeleteDevExt(&g_DevExt);
713 vgdrvLinuxTermISR();
714 pci_unregister_driver(&g_PciDriver);
715 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
716 RTLogDestroy(RTLogSetDefaultInstance(NULL));
717 RTR0Term();
718}
719
720
721/**
722 * Device open. Called on open /dev/vboxdrv
723 *
724 * @param pInode Pointer to inode info structure.
725 * @param pFilp Associated file pointer.
726 */
727static int vgdrvLinuxOpen(struct inode *pInode, struct file *pFilp)
728{
729 int rc;
730 PVBOXGUESTSESSION pSession;
731 Log((DEVICE_NAME ": pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
732
733 /*
734 * Call common code to create the user session. Associate it with
735 * the file so we can access it in the other methods.
736 */
737 rc = VGDrvCommonCreateUserSession(&g_DevExt, &pSession);
738 if (RT_SUCCESS(rc))
739 {
740 pFilp->private_data = pSession;
741 if (MINOR(pInode->i_rdev) == g_MiscDeviceUser.minor)
742 pSession->fUserSession = true;
743 }
744
745 Log(("vgdrvLinuxOpen: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
746 &g_DevExt, pSession, rc, vgdrvLinuxConvertToNegErrno(rc), RTProcSelf(), current->pid, current->comm));
747 return vgdrvLinuxConvertToNegErrno(rc);
748}
749
750
751/**
752 * Close device.
753 *
754 * @param pInode Pointer to inode info structure.
755 * @param pFilp Associated file pointer.
756 */
757static int vgdrvLinuxRelease(struct inode *pInode, struct file *pFilp)
758{
759 Log(("vgdrvLinuxRelease: pFilp=%p pSession=%p pid=%d/%d %s\n",
760 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
761
762#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
763 /* This housekeeping was needed in older kernel versions to ensure that
764 * the file pointer didn't get left on the polling queue. */
765 vgdrvLinuxFAsync(-1, pFilp, 0);
766#endif
767 VGDrvCommonCloseSession(&g_DevExt, (PVBOXGUESTSESSION)pFilp->private_data);
768 pFilp->private_data = NULL;
769 return 0;
770}
771
772
773/**
774 * Device I/O Control entry point.
775 *
056a1eb7
SF
776 * @param pFilp Associated file pointer.
777 * @param uCmd The function specified to ioctl().
778 * @param ulArg The argument specified to ioctl().
779 */
6d209b23 780#if defined(HAVE_UNLOCKED_IOCTL) || defined(DOXYGEN_RUNNING)
056a1eb7
SF
781static long vgdrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
782#else
783static int vgdrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
784#endif
785{
6d209b23
SF
786 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFilp->private_data;
787 int rc;
788#ifndef HAVE_UNLOCKED_IOCTL
789 unlock_kernel();
790#endif
791
792#if 0 /* no fast I/O controls defined atm. */
793 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
794 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
795 || uCmd == SUP_IOCTL_FAST_DO_NOP)
796 && pSession->fUnrestricted == true))
797 rc = VGDrvCommonIoCtlFast(uCmd, ulArg, &g_DevExt, pSession);
798 else
799#endif
800 rc = vgdrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
801
802#ifndef HAVE_UNLOCKED_IOCTL
803 lock_kernel();
804#endif
805 return rc;
806}
807
808
809/**
810 * Device I/O Control entry point, slow variant.
811 *
812 * @param pFilp Associated file pointer.
813 * @param uCmd The function specified to ioctl().
814 * @param ulArg The argument specified to ioctl().
815 * @param pSession The session instance.
816 */
817static int vgdrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PVBOXGUESTSESSION pSession)
818{
056a1eb7 819 int rc;
6d209b23
SF
820 VBGLREQHDR Hdr;
821 PVBGLREQHDR pHdr;
822 uint32_t cbBuf;
823
824 Log6(("vgdrvLinuxIOCtlSlow: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
056a1eb7 825
6d209b23
SF
826 /*
827 * Read the header.
828 */
829 if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
830 {
831 Log(("vgdrvLinuxIOCtlSlow: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
832 return -EFAULT;
833 }
834 if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
835 {
836 Log(("vgdrvLinuxIOCtlSlow: bad header version %#x; uCmd=%#x\n", Hdr.uVersion, uCmd));
837 return -EINVAL;
838 }
056a1eb7
SF
839
840 /*
841 * Buffer the request.
6d209b23 842 * Note! The header is revalidated by the common code.
056a1eb7 843 */
6d209b23
SF
844 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
845 if (RT_UNLIKELY(cbBuf > _1M*16))
056a1eb7 846 {
6d209b23
SF
847 Log(("vgdrvLinuxIOCtlSlow: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
848 return -E2BIG;
056a1eb7 849 }
6d209b23
SF
850 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
851 || (cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd) != 0)))
852 {
853 Log(("vgdrvLinuxIOCtlSlow: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
854 return -EINVAL;
855 }
856 pHdr = RTMemAlloc(cbBuf);
857 if (RT_UNLIKELY(!pHdr))
858 {
859 LogRel(("vgdrvLinuxIOCtlSlow: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
860 return -ENOMEM;
861 }
862 if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
863 {
864 Log(("vgdrvLinuxIOCtlSlow: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
865 RTMemFree(pHdr);
866 return -EFAULT;
867 }
868 if (Hdr.cbIn < cbBuf)
869 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
870
871 /*
872 * Process the IOCtl.
873 */
874 rc = VGDrvCommonIoCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
875
876 /*
877 * Copy ioctl data and output buffer back to user space.
878 */
879 if (RT_SUCCESS(rc))
056a1eb7 880 {
6d209b23
SF
881 uint32_t cbOut = pHdr->cbOut;
882 if (RT_UNLIKELY(cbOut > cbBuf))
883 {
884 LogRel(("vgdrvLinuxIOCtlSlow: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
885 cbOut = cbBuf;
886 }
887 if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
056a1eb7 888 {
6d209b23
SF
889 /* this is really bad! */
890 LogRel(("vgdrvLinuxIOCtlSlow: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
891 rc = -EFAULT;
056a1eb7
SF
892 }
893 }
6d209b23 894 else
056a1eb7 895 {
6d209b23
SF
896 Log(("vgdrvLinuxIOCtlSlow: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
897 rc = -EINVAL;
898 }
899 RTMemFree(pHdr);
900
901 Log6(("vgdrvLinuxIOCtlSlow: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
902 return rc;
903}
056a1eb7 904
6d209b23
SF
905
906/**
907 * @note This code is duplicated on other platforms with variations, so please
908 * keep them all up to date when making changes!
909 */
910int VBOXCALL VBoxGuestIDC(void *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq)
911{
912 /*
913 * Simple request validation (common code does the rest).
914 */
915 int rc;
916 if ( RT_VALID_PTR(pReqHdr)
917 && cbReq >= sizeof(*pReqHdr))
918 {
056a1eb7 919 /*
6d209b23 920 * All requests except the connect one requires a valid session.
056a1eb7 921 */
6d209b23
SF
922 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
923 if (pSession)
924 {
925 if ( RT_VALID_PTR(pSession)
926 && pSession->pDevExt == &g_DevExt)
927 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
928 else
929 rc = VERR_INVALID_HANDLE;
930 }
931 else if (uReq == VBGL_IOCTL_IDC_CONNECT)
056a1eb7 932 {
6d209b23
SF
933 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
934 if (RT_SUCCESS(rc))
056a1eb7 935 {
6d209b23
SF
936 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
937 if (RT_FAILURE(rc))
938 VGDrvCommonCloseSession(&g_DevExt, pSession);
056a1eb7
SF
939 }
940 }
941 else
6d209b23 942 rc = VERR_INVALID_HANDLE;
056a1eb7
SF
943 }
944 else
6d209b23 945 rc = VERR_INVALID_POINTER;
056a1eb7
SF
946 return rc;
947}
6d209b23 948EXPORT_SYMBOL(VBoxGuestIDC);
056a1eb7
SF
949
950
951/**
952 * Asynchronous notification activation method.
953 *
954 * @returns 0 on success, negative errno on failure.
955 *
956 * @param fd The file descriptor.
957 * @param pFile The file structure.
958 * @param fOn On/off indicator.
959 */
960static int vgdrvLinuxFAsync(int fd, struct file *pFile, int fOn)
961{
962 return fasync_helper(fd, pFile, fOn, &g_pFAsyncQueue);
963}
964
965
966/**
967 * Poll function.
968 *
969 * This returns ready to read if the mouse pointer mode or the pointer position
970 * has changed since last call to read.
971 *
972 * @returns 0 if no changes, POLLIN | POLLRDNORM if there are unseen changes.
973 *
974 * @param pFile The file structure.
975 * @param pPt The poll table.
976 *
977 * @remarks This is probably not really used, X11 is said to use the fasync
978 * interface instead.
979 */
980static unsigned int vgdrvLinuxPoll(struct file *pFile, poll_table *pPt)
981{
982 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
983 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
984 unsigned int fMask = pSession->u32MousePosChangedSeq != u32CurSeq
985 ? POLLIN | POLLRDNORM
986 : 0;
987 poll_wait(pFile, &g_PollEventQueue, pPt);
988 return fMask;
989}
990
991
992/**
993 * Read to go with our poll/fasync response.
994 *
995 * @returns 1 or -EINVAL.
996 *
997 * @param pFile The file structure.
998 * @param pbBuf The buffer to read into.
999 * @param cbRead The max number of bytes to read.
1000 * @param poff The current file position.
1001 *
1002 * @remarks This is probably not really used as X11 lets the driver do its own
1003 * event reading. The poll condition is therefore also cleared when we
1004 * see VMMDevReq_GetMouseStatus in vgdrvIoCtl_VMMRequest.
1005 */
1006static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff)
1007{
1008 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pFile->private_data;
1009 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
1010
1011 if (*poff != 0)
1012 return -EINVAL;
1013
1014 /*
1015 * Fake a single byte read if we're not up to date with the current mouse position.
1016 */
1017 if ( pSession->u32MousePosChangedSeq != u32CurSeq
1018 && cbRead > 0)
1019 {
1020 pSession->u32MousePosChangedSeq = u32CurSeq;
1021 pbBuf[0] = 0;
1022 return 1;
1023 }
1024 return 0;
1025}
1026
1027
1028void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
1029{
1030#ifdef VBOXGUEST_WITH_INPUT_DRIVER
1031 int rc;
1032#endif
1033 NOREF(pDevExt);
1034
1035 /*
1036 * Wake up everyone that's in a poll() and post anyone that has
1037 * subscribed to async notifications.
1038 */
1039 Log3(("VGDrvNativeISRMousePollEvent: wake_up_all\n"));
1040 wake_up_all(&g_PollEventQueue);
1041 Log3(("VGDrvNativeISRMousePollEvent: kill_fasync\n"));
1042 kill_fasync(&g_pFAsyncQueue, SIGIO, POLL_IN);
1043#ifdef VBOXGUEST_WITH_INPUT_DRIVER
1044 /* Report events to the kernel input device */
1045 g_pMouseStatusReq->mouseFeatures = 0;
1046 g_pMouseStatusReq->pointerXPos = 0;
1047 g_pMouseStatusReq->pointerYPos = 0;
6d209b23 1048 rc = VbglR0GRPerform(&g_pMouseStatusReq->header);
056a1eb7
SF
1049 if (RT_SUCCESS(rc))
1050 {
1051 input_report_abs(g_pInputDevice, ABS_X,
1052 g_pMouseStatusReq->pointerXPos);
1053 input_report_abs(g_pInputDevice, ABS_Y,
1054 g_pMouseStatusReq->pointerYPos);
1055# ifdef EV_SYN
1056 input_sync(g_pInputDevice);
1057# endif
1058 }
1059#endif
1060 Log3(("VGDrvNativeISRMousePollEvent: done\n"));
1061}
1062
1063
056a1eb7
SF
1064#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1065
1066/** log and dbg_log parameter setter. */
ac320018 1067static int vgdrvLinuxParamLogGrpSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1068{
1069 if (g_fLoggerCreated)
1070 {
1071 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1072 if (pLogger)
1073 RTLogGroupSettings(pLogger, pszValue);
1074 }
1075 else if (pParam->name[0] != 'd')
1076 strlcpy(&g_szLogGrp[0], pszValue, sizeof(g_szLogGrp));
1077
1078 return 0;
1079}
1080
1081/** log and dbg_log parameter getter. */
ac320018 1082static int vgdrvLinuxParamLogGrpGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1083{
1084 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1085 *pszBuf = '\0';
1086 if (pLogger)
1087 RTLogGetGroupSettings(pLogger, pszBuf, _4K);
1088 return strlen(pszBuf);
1089}
1090
1091
1092/** log and dbg_log_flags parameter setter. */
ac320018 1093static int vgdrvLinuxParamLogFlagsSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1094{
1095 if (g_fLoggerCreated)
1096 {
1097 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1098 if (pLogger)
1099 RTLogFlags(pLogger, pszValue);
1100 }
1101 else if (pParam->name[0] != 'd')
1102 strlcpy(&g_szLogFlags[0], pszValue, sizeof(g_szLogFlags));
1103 return 0;
1104}
1105
1106/** log and dbg_log_flags parameter getter. */
ac320018 1107static int vgdrvLinuxParamLogFlagsGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1108{
1109 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1110 *pszBuf = '\0';
1111 if (pLogger)
1112 RTLogGetFlags(pLogger, pszBuf, _4K);
1113 return strlen(pszBuf);
1114}
1115
1116
1117/** log and dbg_log_dest parameter setter. */
ac320018 1118static int vgdrvLinuxParamLogDstSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1119{
1120 if (g_fLoggerCreated)
1121 {
1122 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1123 if (pLogger)
1124 RTLogDestinations(pLogger, pszValue);
1125 }
1126 else if (pParam->name[0] != 'd')
1127 strlcpy(&g_szLogDst[0], pszValue, sizeof(g_szLogDst));
1128 return 0;
1129}
1130
1131/** log and dbg_log_dest parameter getter. */
ac320018 1132static int vgdrvLinuxParamLogDstGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1133{
1134 PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
1135 *pszBuf = '\0';
1136 if (pLogger)
1137 RTLogGetDestinations(pLogger, pszBuf, _4K);
1138 return strlen(pszBuf);
1139}
1140
1141
1142/** r3_log_to_host parameter setter. */
ac320018 1143static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1144{
1145 if ( pszValue == NULL
1146 || *pszValue == '\0'
1147 || *pszValue == 'n'
1148 || *pszValue == 'N'
1149 || *pszValue == 'd'
1150 || *pszValue == 'D'
1151 || ( (*pszValue == 'o' || *pszValue == 'O')
1152 && (*pszValue == 'f' || *pszValue == 'F') )
1153 )
1154 g_DevExt.fLoggingEnabled = false;
1155 else
1156 g_DevExt.fLoggingEnabled = true;
1157 return 0;
1158}
1159
1160/** r3_log_to_host parameter getter. */
ac320018 1161static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
056a1eb7
SF
1162{
1163 strcpy(pszBuf, g_DevExt.fLoggingEnabled ? "enabled" : "disabled");
1164 return strlen(pszBuf);
1165}
1166
1167
1168/*
1169 * Define module parameters.
1170 */
1171module_param_call(log, vgdrvLinuxParamLogGrpSet, vgdrvLinuxParamLogGrpGet, NULL, 0664);
1172module_param_call(log_flags, vgdrvLinuxParamLogFlagsSet, vgdrvLinuxParamLogFlagsGet, NULL, 0664);
1173module_param_call(log_dest, vgdrvLinuxParamLogDstSet, vgdrvLinuxParamLogDstGet, NULL, 0664);
1174# ifdef LOG_ENABLED
1175module_param_call(dbg_log, vgdrvLinuxParamLogGrpSet, vgdrvLinuxParamLogGrpGet, NULL, 0664);
1176module_param_call(dbg_log_flags, vgdrvLinuxParamLogFlagsSet, vgdrvLinuxParamLogFlagsGet, NULL, 0664);
1177module_param_call(dbg_log_dest, vgdrvLinuxParamLogDstSet, vgdrvLinuxParamLogDstGet, NULL, 0664);
1178# endif
1179module_param_call(r3_log_to_host, vgdrvLinuxParamR3LogToHostSet, vgdrvLinuxParamR3LogToHostGet, NULL, 0664);
1180
1181#endif /* 2.6.0 and later */
1182
1183
1184module_init(vgdrvLinuxModInit);
1185module_exit(vgdrvLinuxModExit);
1186
1187MODULE_AUTHOR(VBOX_VENDOR);
1188MODULE_DESCRIPTION(VBOX_PRODUCT " Guest Additions for Linux Module");
1189MODULE_LICENSE("GPL");
1190#ifdef MODULE_VERSION
1191MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
1192#endif
1193