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