VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c@ 58113

Last change on this file since 58113 was 58113, checked in by vboxsync, 9 years ago

VBoxGuest: Vbgd -> VGDrv, cleanups - will probably not build cleanly everywhere. :)

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