VBoxGuest-solaris.c revision 45436b9d55f04ad7c7a9647a3cd35553f0208d9b
/* $Id$ */
/** @file
* VirtualBox Guest Additions Driver for Solaris.
*/
/*
* Copyright (C) 2007 innotek GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
#include "VBoxGuestInternal.h"
#include <VBox/VBoxGuest.h>
#include <iprt/initterm.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The module name. */
#define DEVICE_NAME "vboxadd"
/** The module description as seen in 'modinfo'. */
#define DEVICE_DESC "VirtualBox Guest Additions Driver"
/** @name R0 Log helpers.
* @{ */
/** @} */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int VBoxAddSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int mode, cred_t *pCred, int *pVal);
DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/**
*/
static struct cb_ops g_VBoxAddSolarisCbOps =
{
nodev, /* b strategy */
nodev, /* b dump */
nodev, /* b print */
nodev, /* c devmap */
nodev, /* c mmap */
nodev, /* c segmap */
nochpoll, /* c poll */
ddi_prop_op, /* property ops */
NULL, /* streamtab */
CB_REV /* revision */
};
/**
* dev_ops: for driver device operations
*/
static struct dev_ops g_VBoxAddSolarisDevOps =
{
DEVO_REV, /* driver build revision */
0, /* ref count */
nulldev, /* get info */
nulldev, /* identify */
nulldev, /* probe */
nodev, /* reset */
(struct bus_ops *)0,
nodev /* power */
};
/**
* modldrv: export driver specifics to the kernel
*/
static struct modldrv g_VBoxAddSolarisModule =
{
&mod_driverops, /* extern from kernel */
};
/**
*/
static struct modlinkage g_VBoxAddSolarisModLinkage =
{
MODREV_1, /* loadable module system revision */
NULL /* terminate array of linkage structures */
};
/**
* State info for each open file handle.
*/
typedef struct
{
/** PCI handle of VMMDev. */
/** Interrupt block cookie. */
/** Driver Mutex. */
/** IO Port. */
/** Physical address of the MMIO region.*/
/** Size of the MMIO region. */
/** Kernel session. */
/** VMMDev Version. */
/** Device handle (we support only one instance). */
static dev_info_t *g_pDip;
/** Opaque pointer to state */
static void *g_pVBoxAddSolarisState;
/** Device extention & session data association structure. */
static VBOXGUESTDEVEXT g_DevExt;
/** Spinlock protecting g_apSessionHashTab. */
/** Hash table */
/** Calculates the index into g_apSessionHashTab.*/
/** GCC C++ hack. */
unsigned __gxx_personality_v0 = 0xdecea5ed;
/**
* Kernel entry points
*/
int _init(void)
{
VBA_LOGCONT("_init\n");
if (!rc)
{
if (rc)
}
return rc;
}
int _fini(void)
{
VBA_LOGCONT("_fini\n");
if (!rc)
return rc;
}
{
VBA_LOGCONT("_info\n");
}
/**
* Attach entry point, to attach a device to the system or resume it.
*
* @param pDip The module structure instance.
* @param enmCmd Attach type (ddi_attach_cmd_t)
*
* @return corresponding solaris error code.
*/
{
VBA_LOGCONT("VBoxAddSolarisAttach\n");
switch (enmCmd)
{
case DDI_ATTACH:
{
int rc;
int instance;
if (rc != DDI_SUCCESS)
{
VBA_LOGNOTE("ddi_soft_state_zalloc failed.\n");
return DDI_FAILURE;
}
if (!pState)
{
return DDI_FAILURE;
}
/*
* Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
*/
if (RT_FAILURE(rc))
{
VBA_LOGNOTE("RTR0Init failed.\n");
return DDI_FAILURE;
}
/*
* Initialize the session hash table.
*/
if (RT_SUCCESS(rc))
{
/*
* Enable resources for PCI access.
*/
if (rc == DDI_SUCCESS)
{
/*
* Check vendor and device ID.
*/
if ( uVendorID == VMMDEV_VENDORID
&& uDeviceID == VMMDEV_DEVICEID)
{
/*
* Verify PCI class of the device (a bit paranoid).
*/
if ( uClass == PCI_CLASS_PERIPH
&& uSubClass == PCI_PERIPH_OTHER)
{
/*
* Get register sizes 0 (IO Port) and 1 (MMIO).
*/
{
/*
* Map the register address space.
*/
if (rc == DDI_SUCCESS)
{
if (rc == DDI_SUCCESS)
{
/*
* Add IRQ of VMMDev.
*/
if (rc == DDI_SUCCESS)
{
/*
* Call the common device extension initializer.
*/
if (RT_SUCCESS(rc))
{
if (rc == DDI_SUCCESS)
{
return DDI_SUCCESS;
}
VBA_LOGNOTE("ddi_create_minor_node failed.\n");
}
else
VBA_LOGNOTE("VBoxGuestInitDevExt failed.\n");
}
else
VBA_LOGNOTE("VBoxGuestSolarisAddIRQ failed.\n");
}
else
VBA_LOGNOTE("ddi_regs_map_setup for MMIO region failed.\n");
}
else
VBA_LOGNOTE("ddi_regs_map_setup for IOport failed.\n");
}
else
VBA_LOGNOTE("ddi_dev_regsize failed.\n");
}
else
VBA_LOGNOTE("PCI class/sub-class does not match.\n");
}
else
VBA_LOGNOTE("PCI vendorID, deviceID does not match.\n");
}
else
VBA_LOGNOTE("pci_config_setup failed.\n");
}
else
VBA_LOGNOTE("RTSpinlockCreate failed.\n");
RTR0Term();
return DDI_FAILURE;
}
case DDI_RESUME:
{
/** @todo implement resume for guest driver. */
return DDI_SUCCESS;
}
default:
return DDI_FAILURE;
}
}
/**
* Detach entry point, to detach a device to the system or suspend it.
*
* @param pDip The module structure instance.
* @param enmCmd Attach type (ddi_attach_cmd_t)
*
* @return corresponding solaris error code.
*/
{
VBA_LOGCONT("VBoxAddSolarisDetach\n");
switch (enmCmd)
{
case DDI_DETACH:
{
int rc;
RTR0Term();
return DDI_SUCCESS;
}
case DDI_SUSPEND:
{
/** @todo implement suspend for guest driver. */
return DDI_SUCCESS;
}
default:
return DDI_FAILURE;
}
}
/**
* User context entry points
*/
{
int rc;
VBA_LOGCONT("VBoxAddSolarisOpen\n");
/*
* Create a new session.
*/
if (RT_SUCCESS(rc))
{
/*
* Insert it into the hash table.
*/
Log(("VBoxAddSolarisOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
return 0;
}
return rc;
}
{
/*
* Remove from the hash table.
*/
if (pSession)
{
{
}
else
{
while (pSession)
{
{
break;
}
/* next */
}
}
}
if (!pSession)
{
return VERR_INVALID_PARAMETER;
}
/*
* Close the session.
*/
return 0;
}
{
VBA_LOGCONT("VBoxAddSolarisRead\n");
return DDI_SUCCESS;
}
{
VBA_LOGCONT("VBoxAddSolarisWrite\n");
return DDI_SUCCESS;
}
/**
* Driver ioctl, an alternate entry point for this character driver.
*
* @param Dev Device number
* @param Cmd Operation identifier
* @param pArg Arguments from user to driver
* @param pCred User credentials
* @param pVal Return value for calling process.
*
* @return corresponding solaris error code.
*/
static int VBoxAddSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
{
VBA_LOGCONT("VBoxAddSolarisIOCtl\n");
return DDI_SUCCESS;
}
/**
* Sets IRQ for VMMDev.
*
* @returns Solaris error code.
* @param pDip Pointer to the device info structure.
* @param pvState Pointer to the state info structure.
*/
{
int rc;
VBA_LOGCONT("VBoxGuestSolarisAddIRQ\n");
/*
* These calls are supposedly deprecated. But Sun seems to use them all over
* the place. Anyway, once this works we will switch to the highly elaborate
* and non-obsolete way of setting up IRQs.
*/
if (rc == DDI_SUCCESS)
{
if (rc != DDI_SUCCESS)
VBA_LOGNOTE("ddi_add_intr failed. Cannot set IRQ for VMMDev.\n");
}
else
VBA_LOGNOTE("ddi_get_iblock_cookie failed. Cannot set IRQ for VMMDev.\n");
return rc;
}
/**
* Removes IRQ for VMMDev.
*
* @param pDip Pointer to the device info structure.
* @param pvState Opaque pointer to the state info structure.
*/
{
VBA_LOGCONT("VBoxGuestSolarisRemoveIRQ\n");
}
/**
* Interrupt Service Routine for VMMDev.
*
* @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
*/
{
VBA_LOGCONT("VBoxGuestSolarisISR\n");
}
/**
* VBoxGuest Common ioctl wrapper from VBoxGuestLib.
*
* @returns VBox error code.
* @param pvSession Opaque pointer to the session.
* @param iCmd Requested function.
* @param pvData IO data buffer.
* @param cbData Size of the data buffer.
* @param pcbDataReturned Where to store the amount of returned data.
*/
DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
{
VBA_LOGCONT("VBoxGuestSolarisServiceCall\n");
return VBoxGuestCommonIOCtl(iCmd, &g_DevExt, pState->pKernelSession, pvData, cbData, pcbDataReturned);
}
/**
* Solaris Guest service open.
*
* @returns Opaque pointer to session object.
* @param pu32Version Where to store VMMDev version.
*/
{
VBA_LOGCONT("VBoxGuestSolarisServiceOpen\n");
if (RT_SUCCESS(rc))
{
return pSession;
}
return NULL;
}
/**
* Solaris Guest service close.
*
* @returns VBox error code.
* @param pvState Opaque pointer to the session object.
*/
{
VBA_LOGCONT("VBoxGuestSolarisServiceClose\n");
if (pSession)
{
return VINF_SUCCESS;
}
VBA_LOGNOTE("Invalid pSession.\n");
return VERR_INVALID_HANDLE;
}