vboxmod.c revision b357df727b216b85d4517efecf466a7b14c2e80c
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/** @file
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * vboxadd -- VirtualBox Guest Additions for Linux
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/*
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Copyright (C) 2006-2007 Sun Microsystems, Inc.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * This file is part of VirtualBox Open Source Edition (OSE), as
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * available from http://www.virtualbox.org. This file is free software;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * you can redistribute it and/or modify it under the terms of the GNU
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * General Public License (GPL) as published by the Free Software
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Foundation, in version 2 as it comes in the "COPYING" file of the
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * Clara, CA 95054 USA or visit http://www.sun.com if you need
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * additional information or have any questions.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering */
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "the-linux-kernel.h"
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#include "version-generated.h"
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/* #define IRQ_DEBUG */
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering/* #define IOCTL_DEBUG */
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#ifdef IOCTL_DEBUG
0d39fa9c69b97a2ceb156053deef69c0866c2b97Lennart Poettering# define IOCTL_ENTRY(name, arg) \
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmekdo { \
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Log(("IOCTL_ENTRY: %s, 0x%x\n", (name), (arg))); \
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering} while(0)
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering# define IOCTL_EXIT(name, arg) \
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poetteringdo { \
4349cd7c1d153c4ffa23cf1cff1644e0afa9bcf0Lennart Poettering Log(("IOCTL_EXIT: %s, 0x%x\n", (name), (arg))); \
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering} while(0)
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#else
4e731273edfe852a3eee2949cd20f49fd5b4f6d7Lennart Poettering# define IOCTL_ENTRY(name, arg) do { } while(0)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering# define IOCTL_EXIT(name, arg) do { } while(0)
8fcde01280adcbd07e8205b91ac52b06305b6208Lennart Poettering#endif
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#ifdef IOCTL_LOG_DEBUG
059cb3858acd038ff2cef10a3a99119bf71a8fc6Lennart Poettering# define IOCTL_LOG_ENTRY(arg) \
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringdo { \
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Log(("IOCTL_ENTRY: Log, 0x%x\n", (arg))); \
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering} while(0)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering# define IOCTL_LOG_EXIT(arg) \
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poetteringdo { \
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering Log(("IOCTL_EXIT: Log, 0x%x\n", (arg))); \
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering} while(0)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering#else
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering# define IOCTL_LOG_ENTRY(arg) do { } while(0)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering# define IOCTL_LOG_EXIT(arg) do { } while(0)
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger#endif
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger#ifdef IOCTL_VMM_DEBUG
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger# define IOCTL_VMM_ENTRY(arg) \
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poetteringdo { \
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek Log(("IOCTL_ENTRY: VMMDevReq, 0x%x\n", (arg))); \
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek} while(0)
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek# define IOCTL_VMM_EXIT(arg) \
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmekdo { \
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek Log(("IOCTL_EXIT: VMMDevReq, 0x%x\n", (arg))); \
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek} while(0)
bf1d7ba70aceddb5dae0cd2e370b8afaf0c81b05Karel Zak#else
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer# define IOCTL_VMM_ENTRY(arg) do { } while(0)
bf1d7ba70aceddb5dae0cd2e370b8afaf0c81b05Karel Zak# define IOCTL_VMM_EXIT(arg) do { } while(0)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#endif
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#include "vboxmod.h"
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#include "waitcompat.h"
00b4ffdecbb39d849af65c0ab741be482325a4a9Lennart Poettering
00b4ffdecbb39d849af65c0ab741be482325a4a9Lennart Poettering#include <VBox/log.h>
00b4ffdecbb39d849af65c0ab741be482325a4a9Lennart Poettering#include <VBox/VBoxDev.h>
00b4ffdecbb39d849af65c0ab741be482325a4a9Lennart Poettering#include <iprt/asm.h>
00b4ffdecbb39d849af65c0ab741be482325a4a9Lennart Poettering#include <iprt/assert.h>
75f86906c52735c98dc0aa7e24b773edb42ee814Lennart Poettering#include <linux/miscdevice.h>
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering#define xstr(s) str(s)
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering#define str(s) #s
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart PoetteringMODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart PoetteringMODULE_AUTHOR("Sun Microsystems, Inc.");
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart PoetteringMODULE_LICENSE("GPL");
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#ifdef MODULE_VERSION
b7def684941808600c344f0be7a2b9fcdda97e0fLennart PoetteringMODULE_VERSION(VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")");
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek#endif
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/* This is called by our assert macros to find out whether we want
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering to insert a breakpoint after the assertion. In kernel modules we
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering do not of course. */
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom GundersenRTDECL(bool) RTAssertDoBreakpoint(void)
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen{
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen return false;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt}
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-SzmekEXPORT_SYMBOL(RTAssertDoBreakpoint);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/** device extension structure (we only support one device instance) */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poetteringstatic VBoxDevice *vboxDev = NULL;
64347fc2b983f33e7efb0fd2bb44e133fb9f30f4Tom Gundersen/** our file node major id (set dynamically) */
64347fc2b983f33e7efb0fd2bb44e133fb9f30f4Tom Gundersen#ifdef CONFIG_VBOXADD_MAJOR
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poetteringstatic unsigned int vbox_major = CONFIG_VBOXADD_MAJOR;
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering#else
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poetteringstatic unsigned int vbox_major = 0;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#endif
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart PoetteringDECLVBGL (void *) vboxadd_cmc_open (void)
bf1d7ba70aceddb5dae0cd2e370b8afaf0c81b05Karel Zak{
bf1d7ba70aceddb5dae0cd2e370b8afaf0c81b05Karel Zak return vboxDev;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering}
47cb901e38cd7092576fc8e76cc4a14f39bf719dLennart Poettering
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal SchmidtDECLVBGL (void) vboxadd_cmc_close (void *opaque)
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt{
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering (void) opaque;
b3208b662948b51ff34e7b7752e28ec7a48708aeZbigniew Jędrzejewski-Szmek}
bf1d7ba70aceddb5dae0cd2e370b8afaf0c81b05Karel Zak
b3208b662948b51ff34e7b7752e28ec7a48708aeZbigniew Jędrzejewski-SzmekEXPORT_SYMBOL (vboxadd_cmc_open);
b3208b662948b51ff34e7b7752e28ec7a48708aeZbigniew Jędrzejewski-SzmekEXPORT_SYMBOL (vboxadd_cmc_close);
b3208b662948b51ff34e7b7752e28ec7a48708aeZbigniew Jędrzejewski-Szmek
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen#define MAX_HGCM_CONNECTIONS 1024
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek/**
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen * Structure for keeping track of HGCM connections owned by user space processes, so that
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen * we can close the connection if a process does not clean up properly (for example if it
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen * was terminated too abruptly).
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen */
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt/* We just define a fixed number of these so far. This can be changed if it ever becomes
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt a problem. */
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersenstatic struct {
4e82fe5213bedcb70e25c0270e516d5f2706d8c8Tom Gundersen /** Open file structure that this connection handle is associated with */
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek struct file *filp;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /** HGCM connection ID */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering uint32_t client_id;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering} hgcm_connections[MAX_HGCM_CONNECTIONS] = { { 0 } };
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/**
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek * Register an HGCM connection as being connected with a given file descriptor, so that it
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek * will be closed automatically when that file descriptor is.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * @returns 0 on success or Linux kernel error number
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen * @param clientID the client ID of the HGCM connection
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen * @param filep the file structure that the connection is to be associated with
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen */
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmekstatic int vboxadd_register_hgcm_connection(uint32_t client_id, struct file *filp)
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek{
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen int i;
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen bool found = false;
336b5c615e9c101476784b32df1b86aaeac96431Zbigniew Jędrzejewski-Szmek
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich Assert(hgcm_connections[i].client_id != client_id);
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich }
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich if (ASMAtomicCmpXchgU32(&hgcm_connections[i].client_id, client_id, 0)) {
336b5c615e9c101476784b32df1b86aaeac96431Zbigniew Jędrzejewski-Szmek hgcm_connections[i].filp = filp;
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich found = true;
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich }
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich }
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich return found ? 0 : -ENFILE; /* Any ideas for a better error code? */
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich}
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich/**
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * Unregister an HGCM connection associated with a given file descriptor without closing
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * the connection.
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich *
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * @returns 0 on success or Linux kernel error number
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich * @param clientID the client ID of the HGCM connection
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich */
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrichstatic int vboxadd_unregister_hgcm_connection_no_close(uint32_t client_id)
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich{
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek int i;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak bool found = false;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak if (hgcm_connections[i].client_id == client_id) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak hgcm_connections[i].filp = NULL;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak hgcm_connections[i].client_id = 0;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak found = true;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak }
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak }
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak Assert(hgcm_connections[i].client_id != client_id);
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak }
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak return found ? 0 : -ENOENT;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak}
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak/**
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * Unregister all HGCM connections associated with a given file descriptor, closing
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * the connections in the process. This should be called when a file descriptor is
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * closed.
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak *
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @returns 0 on success or Linux kernel error number
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @param clientID the client ID of the HGCM connection
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_unregister_all_hgcm_connections(struct file *filp)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak{
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak int i;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak if (hgcm_connections[i].filp == filp) {
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak VBoxGuestHGCMDisconnectInfo infoDisconnect;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak infoDisconnect.u32ClientID = hgcm_connections[i].client_id;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak &infoDisconnect);
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak hgcm_connections[i].filp = NULL;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak hgcm_connections[i].client_id = 0;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak }
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak }
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak return 0;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak}
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak/**
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * File open handler
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak *
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_open(struct inode *inode, struct file *filp)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak{
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak /* no checks required */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak return 0;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak}
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak/**
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * File close handler. Clean up any HGCM connections associated with the open file
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * which might still be open.
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_release(struct inode *inode, struct file * filp)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak{
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak vboxadd_unregister_all_hgcm_connections(filp);
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak return 0;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering}
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poetteringstatic void
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poetteringvboxadd_wait_for_event (VBoxGuestWaitEventInfo *info)
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering{
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering long timeleft;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering uint32_t cInterruptions = vboxDev->u32GuestInterruptions;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering uint32_t in_mask = info->u32EventMaskIn;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_OK;
e8d2f6cde0af86eece9118718ad0a8a19e1cffecLennart Poettering if (RT_INDEFINITE_WAIT != info->u32TimeoutIn) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering timeleft = wait_event_interruptible_timeout
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer (vboxDev->eventq,
1dc2ced4646a78b3dee9e3ea44130f938d6425bcZbigniew Jędrzejewski-Szmek (vboxDev->u32Events & in_mask)
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek || (vboxDev->u32GuestInterruptions != cInterruptions),
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek msecs_to_jiffies (info->u32TimeoutIn)
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer );
94192cdaf652c9717f15274504ed315126c07a93Zbigniew Jędrzejewski-Szmek if (vboxDev->u32GuestInterruptions != cInterruptions) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (timeleft < 0) {
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
0d3d3be1e225d51ebf46fb40a89419eb6a7d334eFranck Bui }
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen if (timeleft == 0) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering else {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (wait_event_interruptible(vboxDev->eventq,
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering (vboxDev->u32Events & in_mask)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering || (vboxDev->u32GuestInterruptions != cInterruptions)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering )
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering ) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering info->u32EventFlagsOut = vboxDev->u32Events & in_mask;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering vboxDev->u32Events &= ~in_mask;
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek}
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek/**
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek * IOCtl handler - wait for an event from the host.
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek *
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek * @returns Linux kernel return code
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek * @param ptr User space pointer to a structure describing the event
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poetteringstatic int vboxadd_wait_event(void *ptr)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering{
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering int rc = 0;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering VBoxGuestWaitEventInfo info;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_from_user (&info, ptr, sizeof (info))) {
b7def684941808600c344f0be7a2b9fcdda97e0fLennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not get event info\n"));
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek rc = -EFAULT;
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (0 == rc) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering vboxadd_wait_for_event (&info);
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen if (copy_to_user (ptr, &info, sizeof (info))) {
67ab5f761f9b854d8ce85f9ee47b298e497f8bd9Tom Gundersen LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not put out_mask\n"));
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt rc = -EFAULT;
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering return 0;
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen}
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering/**
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * succeeds, it will be associated with the file structure used to open it, so that it will be
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * automatically shut down again if the file descriptor is closed.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
0d3d3be1e225d51ebf46fb40a89419eb6a7d334eFranck Bui * @returns 0 on success, or a Linux kernel errno value
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering * @param filp the file structure with which the application opened the driver
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * @param userspace_info userspace pointer to the hgcm connection information
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * (VBoxGuestHGCMConnectInfo structure)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @retval userspace_info userspace pointer to the hgcm connection information
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_hgcm_connect(struct file *filp, unsigned long userspace_info)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak{
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak VBoxGuestHGCMConnectInfo info;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak VBoxGuestHGCMDisconnectInfo infoDisconnect;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak int rc = 0, rcVBox;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (0 != copy_from_user ((void *)&info, (void *)userspace_info, sizeof (info))) {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: can not get connection info\n"));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering return -EFAULT;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering }
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering rcVBox = vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_CONNECT, &info);
64e70e4b86d3f732d3513189312f6220d1d5cfbcThomas Bächler if (RT_FAILURE(rcVBox) || (RT_FAILURE(info.result))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_HGCM_CONNECT: hgcm connection failed. internal ioctl result %Vrc, hgcm result %Vrc\n", rcVBox, info.result));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering rc = RT_FAILURE(rcVBox) ? -RTErrConvertToErrno(rcVBox)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering : -RTErrConvertToErrno(info.result);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering } else {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering /* Register that the connection is associated with this file pointer. */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("Connected, client ID %u\n", info.u32ClientID));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = vboxadd_register_hgcm_connection(info.u32ClientID, filp);
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering if (0 != rc) {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_HGCM_CONNECT: failed to register the HGCM connection\n"));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering } else {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_to_user ((void *)userspace_info, (void *)&info,
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek sizeof(info))) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek LogRelFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: failed to return the connection structure\n"));
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek rc = -EFAULT;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek } else {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek return 0;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek }
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen /* Unregister again, as we didn't get as far as informing userspace. */
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek vboxadd_unregister_hgcm_connection_no_close(info.u32ClientID);
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek }
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek /* And disconnect the hgcm connection again, as we told userspace it failed. */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering infoDisconnect.u32ClientID = info.u32ClientID;
0d3d3be1e225d51ebf46fb40a89419eb6a7d334eFranck Bui vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering &infoDisconnect);
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering }
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering return rc;
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering}
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt/**
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * IOCTL handler. Disconnect a specific HGCM connection.
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering * @returns 0 on success, or a Linux kernel errno value
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering * @param filp the file structure with which the application opened the driver
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * @param userspace_info userspace pointer to the hgcm connection information
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * (VBoxGuestHGCMConnectInfo structure)
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering * @retval userspace_info userspace pointer to the hgcm connection information
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering */
b7def684941808600c344f0be7a2b9fcdda97e0fLennart Poetteringstatic int vboxadd_hgcm_disconnect(struct file *filp, unsigned long userspace_info)
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek{
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek VBoxGuestHGCMDisconnectInfo info;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (0 != copy_from_user ((void *)&info, (void *)userspace_info, sizeof (info))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: can not get info\n"));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering return -EFAULT;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt LogRelFunc(("client ID %u\n", info.u32ClientID));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_to_user ((void *)userspace_info, (void *)&info, sizeof(info))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: failed to return the connection structure\n"));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering return -EFAULT;
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering }
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering return 0;
700e07ffd53083114e91bb4ba646ed26d0463f67Harald Hoyer}
700e07ffd53083114e91bb4ba646ed26d0463f67Harald Hoyer
0d3d3be1e225d51ebf46fb40a89419eb6a7d334eFranck Bui/**
700e07ffd53083114e91bb4ba646ed26d0463f67Harald Hoyer * IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * we know how to handle.
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak *
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @returns iprt status code
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak * @param pInfo kernel space pointer to the filter mask change info
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak */
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zakstatic int vboxadd_control_filter_mask(VBoxGuestFilterMaskInfo *pInfo)
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak{
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak VMMDevCtlGuestFilterMask *pReq = NULL;
3519d230c8bafe834b2dac26ace49fcfba139823Karel Zak int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
700e07ffd53083114e91bb4ba646ed26d0463f67Harald Hoyer
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (RT_FAILURE(rc))
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering else
336b5c615e9c101476784b32df1b86aaeac96431Zbigniew Jędrzejewski-Szmek {
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich pReq->u32OrMask = pInfo->u32OrMask;
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich pReq->u32NotMask = pInfo->u32NotMask;
deb0a77cf0b409141c4b116ae30becb3d878e1adMichael Olbrich rc = VbglGRPerform(&pReq->header);
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek }
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek if (RT_FAILURE(rc))
4652c56c59682f153c34d30b410534e4f0c6fd6aZbigniew Jędrzejewski-Szmek Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: VbglGRPerform failed, rc=%Rrc!\n", rc));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering else if (RT_FAILURE(pReq->header.rc))
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering {
b7def684941808600c344f0be7a2b9fcdda97e0fLennart Poettering Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek rc = pReq->header.rc;
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (pReq)
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers VbglGRFree(&pReq->header);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return rc;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt}
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering/**
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmek * IOCTL handler
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering *
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poetteringstatic int vboxadd_ioctl(struct inode *inode, struct file *filp,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering unsigned int cmd, unsigned long arg)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering{
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering int rc = 0;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* Deal with variable size ioctls first. */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0))
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering char *pszMessage;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering IOCTL_LOG_ENTRY(arg);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering pszMessage = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt if (NULL == pszMessage) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering _IOC_SIZE(cmd)));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering rc = -ENOMEM;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if ( (0 == rc)
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek && copy_from_user(pszMessage, (void*)arg, _IOC_SIZE(cmd))) {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering rc = -EFAULT;
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen }
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen if (0 == rc) {
3d22d1ab57bf44c92e4d9ca95d9728105dd3fb0dTom Gundersen Log(("%.*s", _IOC_SIZE(cmd), pszMessage));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (NULL != pszMessage) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering kfree(pszMessage);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering }
00b4ffdecbb39d849af65c0ab741be482325a4a9Lennart Poettering IOCTL_LOG_EXIT(arg);
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering }
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
689aede8c622ba68d9060e4edee27364445b2007Lennart Poettering VMMDevRequestHeader reqHeader;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering VMMDevRequestHeader *reqFull = NULL;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering size_t cbRequestSize;
5862d652ba14178cff46b8a8fc6c6d8392bf32b1Zbigniew Jędrzejewski-Szmek size_t cbVanillaRequestSize;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
ec6ceb18663940efb1963704923430be0e83f1f7Kay Sievers IOCTL_VMM_ENTRY(arg);
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_from_user(&reqHeader, (void*)arg, sizeof(reqHeader)))
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering {
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek rc = -EFAULT;
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek }
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek if (0 == rc)
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* get the request size */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek if (!cbVanillaRequestSize)
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen {
5607d856b8606ba75446a07ab5e9048753e1d7a6Zbigniew Jędrzejewski-Szmek LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
80c3b720bf3abbcc9427507d540e286c4ceb3e94Tom Gundersen reqHeader.requestType));
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen rc = -EINVAL;
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek }
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek }
b9f111b93f9f442f00266f338b14f25ca8685352Zbigniew Jędrzejewski-Szmek if (0 == rc)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering {
700e07ffd53083114e91bb4ba646ed26d0463f67Harald Hoyer cbRequestSize = reqHeader.size;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (cbRequestSize < cbVanillaRequestSize)
0c17fbce55a9a2ca48318a918adce4c58ae79d98Lennart Poettering {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
0c17fbce55a9a2ca48318a918adce4c58ae79d98Lennart Poettering cbRequestSize,
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen cbVanillaRequestSize,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering reqHeader.requestType));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = -EINVAL;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering }
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering }
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering if (0 == rc)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering /* request storage for the full request */
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering if (VBOX_FAILURE(rc))
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering {
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering rc = -EFAULT;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering }
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (0 == rc)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering {
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* now get the full request */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering {
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek rc = -EFAULT;
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek }
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen }
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger /* now issue the request */
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger if (0 == rc)
135b5212d4234f5b75c9b86c9f924047c8d07589Harald Hoyer {
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen int rrc = VbglGRPerform(reqFull);
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger /* asynchronous processing? */
171181bcd64d5a128f6678107d18ffa1c9388b94Lennart Poettering if (rrc == VINF_HGCM_ASYNC_EXECUTE)
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek wait_event_interruptible (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek rrc = reqFull->rc;
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek }
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek /* failed? */
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek if (VBOX_FAILURE(rrc) || VBOX_FAILURE(reqFull->rc))
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = VBOX_FAILURE(rrc) ? -RTErrConvertToErrno(rrc)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering : -RTErrConvertToErrno(reqFull->rc);
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering }
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek else
093c2cfe3b1ae6081f12927ae7906d90d6623534Tobias Hunger {
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering /* success, copy the result data to user space */
5ecdcf41cbce38c44b399993cb1c356280e0bafdLennart Poettering if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering rc = -EFAULT;
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen }
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen }
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek }
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger if (NULL != reqFull)
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger VbglGRFree(reqFull);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_VMM_EXIT(arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger else if ( ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger || (cmd == VBOXGUEST_IOCTL_HGCM_CALL))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger {
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger /* This IOCTL allows the guest to make an HGCM call from user space. The
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger OS-independant part of the Guest Additions already contain code for making an
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger HGCM call from the guest, but this code assumes that the call is made from the
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger kernel's address space. So before calling it, we have to copy all parameters
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger to the HGCM call from user space to kernel space and reconstruct the structures
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger passed to the call (which include pointers to other memory) inside the kernel's
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger address space. */
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger rc = vbox_ioctl_hgcm_call(arg, vboxDev);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger else
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger {
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger switch (cmd) {
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger case VBOXGUEST_IOCTL_WAITEVENT:
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_WAITEVENT", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger rc = vboxadd_wait_event((void *) arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_WAITEVENT", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger break;
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger ++vboxDev->u32GuestInterruptions;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger break;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger case VBOXGUEST_IOCTL_HGCM_CONNECT:
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger rc = vboxadd_hgcm_connect(filp, arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau break;
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
d15d0333be6a1ca7fdd99a1881d967b6be8f387aZbigniew Jędrzejewski-Szmek IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering vboxadd_hgcm_disconnect(filp, arg);
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
eb5800026d5a6754514fb8f8a8561b49974fc879Michael Marineau break;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger {
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger VBoxGuestFilterMaskInfo info;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_ENTRY("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger if (copy_from_user((void*)&info, (void*)arg, sizeof(info)))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger {
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger rc = -EFAULT;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger break;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
104bc12fbc23c3ca852d9d389805c615cd590d01nmartensen rc = -RTErrConvertToErrno(vboxadd_control_filter_mask(&info));
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger IOCTL_EXIT("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger break;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
059cb3858acd038ff2cef10a3a99119bf71a8fc6Lennart Poettering default:
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering LogRelFunc(("unknown command: %x\n", cmd));
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering rc = -EINVAL;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger break;
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering return rc;
059cb3858acd038ff2cef10a3a99119bf71a8fc6Lennart Poettering}
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering
059cb3858acd038ff2cef10a3a99119bf71a8fc6Lennart Poettering#ifdef DEBUG
141a79f491fd4bf5ea0d66039065c9f9649bfc0eZbigniew Jędrzejewski-Szmekstatic ssize_t
059cb3858acd038ff2cef10a3a99119bf71a8fc6Lennart Poetteringvboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
141a79f491fd4bf5ea0d66039065c9f9649bfc0eZbigniew Jędrzejewski-Szmek{
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering if (count != 8 || *loff != 0)
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering {
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering return -EINVAL;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering }
f88dc3edeb9c49622fcc773cb6153238fe9efbe2Tobias Hunger *(uint32_t *) buf = vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering *(uint32_t *) (buf + 4) = vboxDev->u32Events;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering *loff += 8;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering return 8;
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering}
f88dc3edeb9c49622fcc773cb6153238fe9efbe2Tobias Hunger#endif
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering/** strategy handlers (file operations) */
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poetteringstatic struct file_operations vbox_fops =
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering{
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering .owner = THIS_MODULE,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering .open = vboxadd_open,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering .release = vboxadd_release,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering .ioctl = vboxadd_ioctl,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering#ifdef DEBUG
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering .read = vboxadd_read,
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering#endif
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering .llseek = no_llseek
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering};
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering
9f103625b145a397e67c3714766775b615c8b587Tobias Hungerstatic struct miscdevice gMiscDevice =
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger{
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger minor: MISC_DYNAMIC_MINOR,
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger name: "vboxadd",
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger fops: &vbox_fops
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger};
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger#ifndef IRQ_RETVAL
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger/* interrupt handlers in 2.4 kernels don't return anything */
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger# define irqreturn_t void
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger# define IRQ_RETVAL(n)
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger#endif
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger/**
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * vboxadd_irq_handler
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger *
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * Interrupt handler
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger *
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @returns scsi error code
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @param irq Irq number
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @param dev_id Irq handler parameter
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger * @param regs Regs
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering *
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering */
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poettering#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
6db615c17ee7a434f9e0c40d67a1f833d8f3cc9dLennart Poetteringstatic irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering#else
d0aa9ce51915f6f7448adfeb4be0f46cc1356124Zbigniew Jędrzejewski-Szmekstatic irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering#endif
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering{
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering int fIRQTaken = 0;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering int rcVBox;
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
07719a21b6425d378b36bb8d7f47ad5ec5296d28Lennart Poettering#ifdef IRQ_DEBUG
07719a21b6425d378b36bb8d7f47ad5ec5296d28Lennart Poettering Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#endif
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* check if IRQ was asserted by VBox */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering {
a6903061530cac5fbaa99a080a93221c02c349f9Lennart Poettering#ifdef IRQ_DEBUG
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering vboxDev->irqAckRequest->events));
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering#endif
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering /* make a copy of the event mask */
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
b5884878a2874447b2a9f07f324a7cd909d96d48Lennart Poettering if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(vboxDev->irqAckRequest->header.rc))
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt {
9473414219330b9febc1d0712bbf49ad74cf962fLennart Poettering if (RT_LIKELY (vboxDev->irqAckRequest->events))
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger {
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger vboxDev->u32Events |= vboxDev->irqAckRequest->events;
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek wake_up (&vboxDev->eventq);
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger }
2e8522767e27d5686206794c69e0aa95da6e798bZbigniew Jędrzejewski-Szmek }
9f103625b145a397e67c3714766775b615c8b587Tobias Hunger else
5e398e546ea65751e6a774daf828fe06f74434a2Tom Gundersen {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* impossible... */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering LogRelFunc(("IRQ was not acknowledged! rc = %Vrc, header.rc = %Vrc\n",
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering rcVBox, vboxDev->irqAckRequest->header.rc));
ac4785b031451030aeb5cd46e94c7e8f43796decHarald Hoyer BUG ();
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek }
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* it was ours! */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering fIRQTaken = 1;
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering }
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering#ifdef IRQ_DEBUG
ac4785b031451030aeb5cd46e94c7e8f43796decHarald Hoyer else
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* we might be attached to a shared interrupt together with another device. */
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
75a59316ea0d4bb9d04cce138817d9fa8a75479fZbigniew Jędrzejewski-Szmek vboxDev->pVMMDevMemory,
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering vboxDev->u32Events));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering }
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering#endif
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* it was ours */
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering return IRQ_RETVAL(fIRQTaken);
126cc76074b763c7de9edec848fb86b22e8a78efZbigniew Jędrzejewski-Szmek}
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering/**
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering * Helper function to reserve a fixed kernel address space window
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering * and tell the VMM that it can safely put its hypervisor there.
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering * This function might fail which is not a critical error.
59cfa62f20f566b2c0279405b302e890812b3334Lennart Poettering */
126cc76074b763c7de9edec848fb86b22e8a78efZbigniew Jędrzejewski-Szmekstatic int vboxadd_reserve_hypervisor(void)
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering{
6b1dc2bd3cdb3bd932b0692be636ddd2879edb92Lennart Poettering VMMDevReqHypervisorInfo *req = NULL;
int rcVBox;
/* allocate request structure */
rcVBox = VbglGRAlloc(
(VMMDevRequestHeader**)&req,
sizeof(VMMDevReqHypervisorInfo),
VMMDevReq_GetHypervisorInfo
);
if (VBOX_FAILURE(rcVBox))
{
LogRelFunc(("failed to allocate hypervisor info structure! rc = %Vrc\n", rcVBox));
goto bail_out;
}
/* query the hypervisor information */
rcVBox = VbglGRPerform(&req->header);
if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
{
/* are we supposed to make a reservation? */
if (req->hypervisorSize)
{
/** @todo repeat this several times until we get an address the host likes */
void *hypervisorArea;
/* reserve another 4MB because the start needs to be 4MB aligned */
uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
/* perform a fictive IO space mapping */
hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
if (hypervisorArea)
{
/* communicate result to VMM, align at 4MB */
req->hypervisorStart = (vmmDevHypPtr)RT_ALIGN_P(hypervisorArea, 0x400000);
req->header.requestType = VMMDevReq_SetHypervisorInfo;
req->header.rc = VERR_GENERAL_FAILURE;
rcVBox = VbglGRPerform(&req->header);
if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
{
/* store mapping for future unmapping */
vboxDev->hypervisorStart = hypervisorArea;
vboxDev->hypervisorSize = hypervisorSize;
}
else
{
LogRelFunc(("failed to set hypervisor region! rc = %Vrc, header.rc = %Vrc\n",
rcVBox, req->header.rc));
goto bail_out;
}
}
else
{
LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
goto bail_out;
}
}
}
else
{
LogRelFunc(("failed to query hypervisor info! rc = %Vrc, header.rc = %Vrc\n",
rcVBox, req->header.rc));
goto bail_out;
}
/* successful return */
VbglGRFree(&req->header);
return 0;
bail_out:
/* error return */
if (req)
VbglGRFree(&req->header);
return 1;
}
/**
* Helper function to free the hypervisor address window
*
*/
static int vboxadd_free_hypervisor(void)
{
VMMDevReqHypervisorInfo *req = NULL;
int rcVBox;
/* allocate request structure */
rcVBox = VbglGRAlloc(
(VMMDevRequestHeader**)&req,
sizeof(VMMDevReqHypervisorInfo),
VMMDevReq_SetHypervisorInfo
);
if (VBOX_FAILURE(rcVBox))
{
LogRelFunc(("failed to allocate hypervisor info structure! rc = %Vrc\n", rcVBox));
goto bail_out;
}
/* reset the hypervisor information */
req->hypervisorStart = 0;
req->hypervisorSize = 0;
rcVBox = VbglGRPerform(&req->header);
if (VBOX_SUCCESS(rcVBox) && VBOX_SUCCESS(req->header.rc))
{
/* now we can free the associated IO space mapping */
iounmap(vboxDev->hypervisorStart);
vboxDev->hypervisorStart = 0;
}
else
{
LogRelFunc(("failed to reset hypervisor info! rc = %Vrc, header.rc = %Vrc\n",
rcVBox, req->header.rc));
goto bail_out;
}
return 0;
bail_out:
if (req)
VbglGRFree(&req->header);
return 1;
}
/**
* Helper to free resources
*
*/
static void free_resources(void)
{
if (vboxDev)
{
/* at first detach from IRQ! */
if (vboxDev->irq)
free_irq(vboxDev->irq, vboxDev);
if (vboxDev->hypervisorStart)
vboxadd_free_hypervisor();
if (vboxDev->irqAckRequest)
{
VbglGRFree(&vboxDev->irqAckRequest->header);
VbglTerminate();
}
if (vboxDev->pVMMDevMemory)
iounmap(vboxDev->pVMMDevMemory);
if (vboxDev->vmmdevmem)
release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
kfree(vboxDev);
vboxDev = NULL;
}
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
#define PCI_DEV_PUT(x) pci_dev_put(x)
#else
#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
#define PCI_DEV_PUT(x)
#endif
/**
* Module initialization
*
*/
static __init int init(void)
{
int err;
int rcVBox;
struct pci_dev *pcidev = NULL;
VMMDevReportGuestInfo *infoReq = NULL;
if (vboxadd_cmc_init ())
{
printk (KERN_ERR "vboxadd: could not init cmc.\n");
return -ENODEV;
}
/*
* Detect PCI device
*/
pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
if (!pcidev)
{
printk(KERN_ERR "vboxadd: VirtualBox PCI device not found.\n");
return -ENODEV;
}
err = pci_enable_device (pcidev);
if (err)
{
Log(("vboxadd: could not enable device: %d\n", err));
PCI_DEV_PUT(pcidev);
return -ENODEV;
}
LogRel(("Starting VirtualBox version %s Guest Additions\n",
VBOX_VERSION_STRING));
/* register a character device */
if (vbox_major > 0)
{
err = register_chrdev(vbox_major, "vboxadd", &vbox_fops);
if (err < 0 || (vbox_major & err) || (!vbox_major && !err))
{
LogRelFunc(("register_chrdev failed: vbox_major: %d, err = %d\n",
vbox_major, err));
PCI_DEV_PUT(pcidev);
return -ENODEV;
}
/* if no major code was set, take the return value */
if (!vbox_major)
vbox_major = err;
}
else
{
err = misc_register(&gMiscDevice);
if (err)
{
LogRelFunc(("misc_register failed (rc=%d)\n", err));
return -ENODEV;
}
}
/* allocate and initialize device extension */
vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
if (!vboxDev)
{
LogRelFunc(("cannot allocate device!\n"));
err = -ENOMEM;
goto fail;
}
memset(vboxDev, 0, sizeof(*vboxDev));
snprintf(vboxDev->name, sizeof(vboxDev->name), "vboxadd");
/* get the IO port region */
vboxDev->io_port = pci_resource_start(pcidev, 0);
/* get the memory region */
vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
/* all resources found? */
if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
{
LogRelFunc(("did not find expected hardware resources!\n"));
err = -ENXIO;
goto fail;
}
/* request ownership of adapter memory */
if (request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size, "vboxadd") == 0)
{
LogRelFunc(("failed to request adapter memory!\n"));
err = -ENXIO;
goto fail;
}
/* map adapter memory into kernel address space and check version */
vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
vboxDev->vmmdevmem_size);
if (!vboxDev->pVMMDevMemory)
{
LogRelFunc(("ioremap failed\n"));
err = -ENOMEM;
goto fail;
}
if (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
{
LogRelFunc(("invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
err = -ENXIO;
goto fail;
}
/* initialize VBGL subsystem */
rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
if (VBOX_FAILURE(rcVBox))
{
LogRelFunc(("could not initialize VBGL subsystem! rc = %Vrc\n", rcVBox));
err = -ENXIO;
goto fail;
}
/* report guest information to host, this must be done as the very first request */
rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
if (VBOX_FAILURE(rcVBox))
{
LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
err = -ENOMEM;
goto fail;
}
/* report guest version to host, the VMMDev requires that to be done first */
infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
infoReq->guestInfo.osType = VBOXOSTYPE_Linux26;
#else
infoReq->guestInfo.osType = VBOXOSTYPE_Linux24;
#endif
rcVBox = VbglGRPerform(&infoReq->header);
if (VBOX_FAILURE(rcVBox) || VBOX_FAILURE(infoReq->header.rc))
{
LogRelFunc(("error reporting guest info to host! rc = %Vrc, header.rc = %Vrc\n",
rcVBox, infoReq->header.rc));
VbglGRFree(&infoReq->header);
err = -ENXIO;
goto fail;
}
VbglGRFree(&infoReq->header);
/* Unset the graphics capability until/unless X is loaded. */
/** @todo check the error code once we bump the additions version.
For now we ignore it for compatibility with older hosts. */
{
VMMDevReqGuestCapabilities2 *vmmreqGuestCaps;
rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vmmreqGuestCaps,
sizeof(VMMDevReqGuestCapabilities2),
VMMDevReq_SetGuestCapabilities);
if (VBOX_FAILURE(rcVBox))
{
LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
err = -ENOMEM;
goto fail;
}
vmmreqGuestCaps->u32OrMask = 0;
vmmreqGuestCaps->u32NotMask = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
rcVBox = VbglGRPerform(&vmmreqGuestCaps->header);
VbglGRFree(&vmmreqGuestCaps->header);
if (RT_FAILURE(rcVBox))
{
err = -ENXIO;
goto fail;
}
}
/* perform hypervisor address space reservation */
if (vboxadd_reserve_hypervisor())
{
/* we just ignore the error, no address window reservation, non fatal */
}
/* allocate a VMM request structure for use in the ISR */
rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
if (VBOX_FAILURE(rcVBox))
{
LogRelFunc(("could not allocate request structure! rc = %Vrc\n", rcVBox));
err = -ENOMEM;
goto fail;
}
/* get ISR */
err = request_irq(pcidev->irq, vboxadd_irq_handler,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
IRQF_SHARED,
#else
SA_SHIRQ,
#endif
"vboxadd", vboxDev);
if (err)
{
LogRelFunc(("could not request IRQ %d, err: %d\n", pcidev->irq, err));
goto fail;
}
vboxDev->irq = pcidev->irq;
init_waitqueue_head (&vboxDev->eventq);
/* some useful information for the user but don't show this on the console */
LogRel(("VirtualBox device settings: major %d, IRQ %d, "
"I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
"hypervisor window at 0x%p (size 0x%x)\n",
vbox_major, vboxDev->irq, vboxDev->io_port,
vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
vboxDev->hypervisorStart, vboxDev->hypervisorSize));
Log(("Successfully loaded VirtualBox device version "
VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")\n"));
/* successful return */
PCI_DEV_PUT(pcidev);
return 0;
fail:
PCI_DEV_PUT(pcidev);
free_resources();
unregister_chrdev(vbox_major, "vboxadd");
return err;
}
/**
* Module termination
*
*/
static __exit void fini(void)
{
unregister_chrdev(vbox_major, "vboxadd");
free_resources();
vboxadd_cmc_fini ();
}
module_init(init);
module_exit(fini);
/* PCI hotplug structure */
static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
{
{
.vendor = VMMDEV_VENDORID,
.device = VMMDEV_DEVICEID
},
{
/* empty entry */
}
};
MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
int __gxx_personality_v0 = 0xdeadbeef;
/*
* Local Variables:
* c-mode: bsd
* indent-tabs-mode: nil
* c-plusplus: evil
* End:
*/