VirtualBox

Changeset 40311 in vbox


Ignore:
Timestamp:
Mar 1, 2012 12:09:56 PM (13 years ago)
Author:
vboxsync
Message:

Additions/VBoxGuest: first drop of streams-based Solaris version, not yet tested or even compiled under Solaris.

Location:
trunk/src/VBox/Additions/common/VBoxGuest
Files:
3 added
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuest/Makefile.kmk

    r39358 r40311  
    208208endif
    209209
     210if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK)
     211 PROGRAMS += tstVBoxGuest-solaris
     212 tstVBoxGuest-solaris_TEMPLATE = VBOXR3TSTEXE
     213 tstVBoxGuest-solaris_SOURCES  = \
     214        VBoxGuest-solaris-streams.c \
     215        testcase/tstVBoxGuest-solaris.cpp
     216 tstVBoxGuest-solaris_DEFS     = TESTCASE
     217 tstVBoxGuest-solaris_LIBS     = $(LIB_RUNTIME)
     218endif
     219
    210220include $(KBUILD_PATH)/subfooter.kmk
    211221
  • trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris-streams.c

    r39755 r40311  
    55
    66/*
    7  * Copyright (C) 2007 Oracle Corporation
     7 * Copyright (C) 2012 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1717
    1818
    19 /*******************************************************************************
    20 *   Header Files                                                               *
    21 *******************************************************************************/
    22 #include <sys/conf.h>
    23 #include <sys/modctl.h>
    24 #include <sys/mutex.h>
    25 #include <sys/pci.h>
    26 #include <sys/stat.h>
    27 #include <sys/ddi.h>
    28 #include <sys/ddi_intr.h>
    29 #include <sys/sunddi.h>
    30 #include <sys/open.h>
    31 #include <sys/sunldi.h>
    32 #include <sys/file.h>
     19/******************************************************************************
     20*   Header Files                                                              *
     21******************************************************************************/
     22
     23#ifndef TESTCASE
     24# include <sys/conf.h>
     25# include <sys/modctl.h>
     26# include <sys/mutex.h>
     27# include <sys/pci.h>
     28# include <sys/stat.h>
     29# include <sys/ddi.h>
     30# include <sys/ddi_intr.h>
     31# include <sys/sunddi.h>
     32# include <sys/open.h>
     33# include <sys/sunldi.h>
     34# include <sys/file.h>
    3335#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
     36#else  /* TESTCASE */
     37# undef IN_RING3
     38# define IN_RING0
     39#endif  /* TESTCASE */
    3440
    3541#include "VBoxGuestInternal.h"
     
    4349#include <iprt/asm.h>
    4450
    45 
    46 /*******************************************************************************
    47 *   Defined Constants And Macros                                               *
    48 *******************************************************************************/
     51#ifdef TESTCASE  /* Include this last as we . */
     52# include "testcase/solaris.h"
     53# include <iprt/test.h>
     54#endif  /* TESTCASE */
     55
     56
     57/******************************************************************************
     58*   Defined Constants And Macros                                              *
     59******************************************************************************/
     60
    4961/** The module name. */
    5062#define DEVICE_NAME              "vboxguest"
     
    5365
    5466
    55 /*******************************************************************************
    56 *   Internal Functions                                                         *
    57 *******************************************************************************/
    58 static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
    59 static int VBoxGuestSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
    60 static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
    61 static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
    62 static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal);
    63 static int VBoxGuestSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead);
    64 
    65 static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
    66 static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
    67 static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
    68 
    69 static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip);
    70 static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip);
    71 static uint_t VBoxGuestSolarisISR(caddr_t Arg);
    72 
    73 
    74 /*******************************************************************************
    75 *   Structures and Typedefs                                                    *
    76 *******************************************************************************/
    77 /**
    78  * cb_ops: for drivers that support char/block entry points
     67/******************************************************************************
     68*   Internal functions used in global structures                              *
     69******************************************************************************/
     70
     71static int vboxGuestSolarisOpen(queue_t *pReadQueue, dev_t *pDev, int fFlag,
     72                                int fMode, cred_t *pCred);
     73static int vboxGuestSolarisClose(queue_t *pReadQueue, int fFlag, cred_t *pCred);
     74static int vboxGuestSolarisWPut(queue_t *pWriteQueue, mblk_t *pMBlk);
     75
     76static int vboxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
     77static int vboxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
     78static int vboxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
     79
     80
     81/******************************************************************************
     82*   Driver global structures                                                  *
     83******************************************************************************/
     84
     85#ifndef TESTCASE  /* I see no value in including these. */
     86
     87/*
     88 * mod_info: STREAMS module information.
     89 */
     90static struct module_info g_VBoxGuestSolarisModInfo =
     91{
     92    0x0ffff,                /* module id number */
     93    "vboxguest",
     94    0,                      /* minimum packet size */
     95    INFPSZ,                 /* maximum packet size accepted */
     96    512,                    /* high water mark for data flow control */
     97    128                     /* low water mark */
     98};
     99
     100/*
     101 * rinit: read queue structure for handling messages coming from below.  In
     102 * our case this means the host and the virtual hardware, so we do not need
     103 * the put and service procedures.
     104 */
     105static struct qinit g_VBoxGuestSolarisRInit =
     106{
     107    NULL,                /* put */
     108    NULL,                /* service thread procedure */
     109    vboxGuestSolarisOpen,
     110    vboxGuestSolarisClose,
     111    NULL,                /* reserved */
     112    &g_VBoxGuestSolarisModInfo,
     113    NULL                 /* module statistics structure */
     114};
     115
     116/*
     117 * winit: write queue structure for handling messages coming from above.  Above
     118 * means user space applications: either Guest Additions user space tools or
     119 * applications reading pointer input.  Messages from the last most likely pass
     120 * through at least the "consms" console mouse streams module which multiplexes
     121 * hardware pointer drivers to a single virtual pointer.
     122 */
     123static struct qinit g_VBoxGuestSolarisWInit =
     124{
     125    vboxGuestSolarisWPut,
     126    NULL,                   /* service thread procedure */
     127    NULL,                   /* open */
     128    NULL,                   /* close */
     129    NULL,                   /* reserved */
     130    &g_VBoxGuestSolarisModInfo,
     131    NULL                    /* module statistics structure */
     132};
     133
     134/**
     135 * streamtab: for drivers that support char/block entry points.
     136 */
     137static struct streamtab g_VBoxGuestSolarisStreamTab =
     138{
     139    &g_VBoxGuestSolarisRInit,
     140    &g_VBoxGuestSolarisWInit,
     141    NULL,                   /* MUX rinit */
     142    NULL                    /* MUX winit */
     143};
     144
     145/**
     146 * cb_ops: for drivers that support char/block entry points.
    79147 */
    80148static struct cb_ops g_VBoxGuestSolarisCbOps =
    81149{
    82     VBoxGuestSolarisOpen,
    83     VBoxGuestSolarisClose,
    84     nodev,                  /* b strategy */
    85     nodev,                  /* b dump */
    86     nodev,                  /* b print */
    87     VBoxGuestSolarisRead,
    88     VBoxGuestSolarisWrite,
    89     VBoxGuestSolarisIOCtl,
    90     nodev,                  /* c devmap */
    91     nodev,                  /* c mmap */
    92     nodev,                  /* c segmap */
    93     VBoxGuestSolarisPoll,
     150    nulldev,                /* open */
     151    nulldev,                /* close */
     152    nulldev,                /* b strategy */
     153    nulldev,                /* b dump */
     154    nulldev,                /* b print */
     155    nulldev,                /* c read */
     156    nulldev,                /* c write */
     157    nulldev,                /* c ioctl */
     158    nulldev,                /* c devmap */
     159    nulldev,                /* c mmap */
     160    nulldev,                /* c segmap */
     161    nochpoll,               /* c poll */
    94162    ddi_prop_op,            /* property ops */
    95     NULL,                   /* streamtab  */
     163    g_VBoxGuestSolarisStreamTab,
    96164    D_NEW | D_MP,           /* compat. flag */
    97     CB_REV                  /* revision */
    98165};
    99166
    100167/**
    101  * dev_ops: for driver device operations
     168 * dev_ops: for driver device operations.
    102169 */
    103170static struct dev_ops g_VBoxGuestSolarisDevOps =
     
    105172    DEVO_REV,               /* driver build revision */
    106173    0,                      /* ref count */
    107     VBoxGuestSolarisGetInfo,
     174    vboxGuestSolarisGetInfo,
    108175    nulldev,                /* identify */
    109176    nulldev,                /* probe */
    110     VBoxGuestSolarisAttach,
    111     VBoxGuestSolarisDetach,
     177    vboxGuestSolarisAttach,
     178    vboxGuestSolarisDetach,
    112179    nodev,                  /* reset */
    113180    &g_VBoxGuestSolarisCbOps,
     
    117184
    118185/**
    119  * modldrv: export driver specifics to the kernel
     186 * modldrv: export driver specifics to the kernel.
    120187 */
    121188static struct modldrv g_VBoxGuestSolarisModule =
     
    127194
    128195/**
    129  * modlinkage: export install/remove/info to the kernel
     196 * modlinkage: export install/remove/info to the kernel.
    130197 */
    131198static struct modlinkage g_VBoxGuestSolarisModLinkage =
     
    136203};
    137204
     205#else  /* TESTCASE */
     206static void *g_VBoxGuestSolarisModLinkage;
     207#endif  /* TESTCASE */
     208
    138209/**
    139210 * State info for each open file handle.
     
    142213{
    143214    /** Pointer to the session handle. */
    144     PVBOXGUESTSESSION       pSession;
    145     /** The process reference for posting signals */
    146     void                   *pvProcRef;
     215    PVBOXGUESTSESSION  pSession;
     216    /** The STREAMS write queue which we need for sending messages up to
     217     * user-space. */
     218    queue_t           *pWriteQueue;
     219    /** Our minor number. */
     220    unsigned           cMinor;
     221    /* The current greatest horizontal pixel offset on the screen, used for
     222     * absolute mouse position reporting.
     223     */
     224    unsigned           cMaxScreenX;
     225    /* The current greatest vertical pixel offset on the screen, used for
     226     * absolute mouse position reporting.
     227     */
     228    unsigned           cMaxScreenY;
    147229} vboxguest_state_t;
    148230
    149231
    150 /*******************************************************************************
    151 *   Global Variables                                                           *
    152 *******************************************************************************/
     232/******************************************************************************
     233*   Global Variables                                                          *
     234******************************************************************************/
     235
    153236/** Device handle (we support only one instance). */
    154237static dev_info_t          *g_pDip = NULL;
     
    164247static uint16_t             g_uIOPortBase;
    165248/** Address of the MMIO region.*/
    166 static caddr_t              g_pMMIOBase;
     249static char                *g_pMMIOBase;  /* Actually caddr_t. */
    167250/** Size of the MMIO region. */
    168251static off_t                g_cbMMIO;
     
    171254/** Number of actually allocated interrupt handles */
    172255static size_t               g_cIntrAllocated;
    173 /** The pollhead structure */
    174 static pollhead_t           g_PollHead;
    175256/** The IRQ Mutex */
    176257static kmutex_t             g_IrqMtx;
    177 /** Layered device handle for kernel keep-attached opens */
    178 static ldi_handle_t         g_LdiHandle = NULL;
    179 /** Ref counting for IDCOpen calls */
    180 static uint64_t             g_cLdiOpens = 0;
    181 /** The Mutex protecting the LDI handle in IDC opens */
    182 static kmutex_t             g_LdiMtx;
    183 
    184 /**
    185  * Kernel entry points
    186  */
     258/** Our global state.
     259 * @todo Make this into an opaque pointer in the device extension structure.
     260 * @todo Can't we make do without all these globals anyway?
     261 */
     262static vboxguest_state_t   *g_pState;
     263
     264
     265/******************************************************************************
     266*   Kernel entry points                                                       *
     267******************************************************************************/
     268
     269/** Driver initialisation. */
    187270int _init(void)
    188271{
     
    195278        PRTLOGGER pRelLogger;
    196279        static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
     280        modctl_t *pModCtl;
     281
    197282        rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
    198283                         "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
     
    203288            cmn_err(CE_NOTE, "failed to initialize driver logging rc=%d!\n", rc);
    204289
    205         mutex_init(&g_LdiMtx, NULL, MUTEX_DRIVER, NULL);
    206 
    207290        /*
    208291         * Prevent module autounloading.
    209292         */
    210         modctl_t *pModCtl = mod_getctl(&g_VBoxGuestSolarisModLinkage);
     293        pModCtl = mod_getctl(&g_VBoxGuestSolarisModLinkage);
    211294        if (pModCtl)
    212295            pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
     
    232315
    233316
     317#ifdef TESTCASE
     318/* Nothing in these three really worth testing, plus we would have to stub
     319 * around the IPRT log functions. */
     320#endif
     321
     322
     323/** Driver cleanup. */
    234324int _fini(void)
    235325{
     326    int rc;
     327
    236328    LogFlow((DEVICE_NAME ":_fini\n"));
    237     int rc = mod_remove(&g_VBoxGuestSolarisModLinkage);
     329    rc = mod_remove(&g_VBoxGuestSolarisModLinkage);
    238330    if (!rc)
    239331        ddi_soft_state_fini(&g_pVBoxGuestSolarisState);
     
    242334    RTLogDestroy(RTLogSetDefaultInstance(NULL));
    243335
    244     mutex_destroy(&g_LdiMtx);
    245 
    246336    RTR0Term();
    247337    return rc;
     
    249339
    250340
     341/** Driver identification. */
    251342int _info(struct modinfo *pModInfo)
    252343{
     
    255346}
    256347
     348
     349/******************************************************************************
     350*   Main code                                                                 *
     351******************************************************************************/
     352
     353/**
     354 * Open callback for the read queue, which we use as a generic device open
     355 * handler.
     356 */
     357int vboxGuestSolarisOpen(queue_t *pReadQueue, dev_t *pDev, int fFlag, int fMode,
     358                         cred_t *pCred)
     359{
     360    int                 rc;
     361    PVBOXGUESTSESSION   pSession = NULL;
     362    vboxguest_state_t *pState = NULL;
     363    unsigned cInstance;
     364
     365    NOREF(fFlag);
     366    NOREF(pCred);
     367    LogFlow((DEVICE_NAME "::Open\n"));
     368
     369    /*
     370     * Sanity check on the mode parameter.
     371     */
     372    if (fMode)
     373        return EINVAL;
     374
     375    for (cInstance = 0; cInstance < 4096; cInstance++)
     376    {
     377        if (    !ddi_get_soft_state(g_pVBoxGuestSolarisState, cInstance) /* faster */
     378            &&  ddi_soft_state_zalloc(g_pVBoxGuestSolarisState, cInstance) == DDI_SUCCESS)
     379        {
     380            pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, cInstance);
     381            break;
     382        }
     383    }
     384    if (!pState)
     385    {
     386        Log((DEVICE_NAME "::Open: too many open instances."));
     387        return ENXIO;
     388    }
     389
     390    /*
     391     * Create a new session.
     392     */
     393    rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
     394    if (RT_SUCCESS(rc))
     395    {
     396        pState->pSession = pSession;
     397        *pDev = makedevice(getmajor(*pDev), cInstance);
     398        /* Initialise user data for the queues to our state and vice-versa. */
     399        WR(pReadQueue)->q_ptr = (char *)pState;
     400        pReadQueue->q_ptr = (char *)pState;
     401        pState->pWriteQueue = WR(pReadQueue);
     402        pState->cMinor = cInstance;
     403        g_pState = pState;
     404        qprocson(pState->pWriteQueue);
     405        Log((DEVICE_NAME "::Open: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf()));
     406        return 0;
     407    }
     408
     409    /* Failed, clean up. */
     410    ddi_soft_state_free(g_pVBoxGuestSolarisState, cInstance);
     411
     412    LogRel((DEVICE_NAME "::Open: VBoxGuestCreateUserSession failed. rc=%d\n", rc));
     413    return EFAULT;
     414}
     415
     416
     417/**
     418 * Close callback for the read queue, which we use as a generic device close
     419 * handler.
     420 */
     421int vboxGuestSolarisClose(queue_t *pReadQueue, int fFlag, cred_t *pCred)
     422{
     423    PVBOXGUESTSESSION pSession = NULL;
     424    vboxguest_state_t *pState = (vboxguest_state_t *)pReadQueue->q_ptr;
     425
     426    LogFlow((DEVICE_NAME "::Close pid=%d\n", (int)RTProcSelf()));
     427    NOREF(fFlag);
     428    NOREF(pCred);
     429
     430    if (!pState)
     431    {
     432        Log((DEVICE_NAME "::Close: failed to get pState.\n"));
     433        return EFAULT;
     434    }
     435    qprocsoff(pState->pWriteQueue);
     436    pState->pWriteQueue = NULL;
     437    g_pState = NULL;
     438    pReadQueue->q_ptr = NULL;
     439
     440    pSession = pState->pSession;
     441    pState->pSession = NULL;
     442    Log((DEVICE_NAME "::Close: pSession=%p pState=%p\n", pSession, pState));
     443    ddi_soft_state_free(g_pVBoxGuestSolarisState, pState->cMinor);
     444    if (!pSession)
     445    {
     446        Log((DEVICE_NAME "::Close: failed to get pSession.\n"));
     447        return EFAULT;
     448    }
     449
     450    /*
     451     * Close the session.
     452     */
     453    VBoxGuestCloseSession(&g_DevExt, pSession);
     454    return 0;
     455}
     456
     457
     458/* Helper for vboxGuestSolarisWPut. */
     459static int vboxGuestSolarisDispatchIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk);
     460
     461/**
     462 * Handler for messages sent from above (user-space and upper modules) which
     463 * land in our write queue.
     464 */
     465int vboxGuestSolarisWPut(queue_t *pWriteQueue, mblk_t *pMBlk)
     466{
     467    vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr;
     468   
     469    LogFlowFunc(("\n"));
     470    switch (pMBlk->b_datap->db_type)
     471    {
     472        case M_FLUSH:
     473            /* Flush the write queue if so requested. */
     474            if (*pMBlk->b_rptr & FLUSHW)
     475                flushq(pWriteQueue, FLUSHDATA);
     476
     477            /* Flush the read queue if so requested. */
     478            if (*pMBlk->b_rptr & FLUSHR)
     479                flushq(RD(pWriteQueue), FLUSHDATA);
     480
     481            /* We have no one below us to pass the message on to. */
     482            return 0;
     483        /* M_IOCDATA is additional data attached to (at least) transparent
     484         * IOCtls.  We handle the two together here and separate them further
     485         * down. */
     486        case M_IOCTL:
     487        case M_IOCDATA:
     488        {
     489            int err = vboxGuestSolarisDispatchIOCtl(pWriteQueue, pMBlk);
     490            if (!err)
     491                qreply(pWriteQueue, pMBlk);
     492            else
     493                miocnak(pWriteQueue, pMBlk, 0, err);
     494            break;
     495        }
     496    }
     497    return 0;
     498}
     499
     500
     501/** Data transfer direction of an IOCtl.  This is used for describing
     502 * transparent IOCtls, and @a UNSPECIFIED is not a valid value for them. */
     503enum IOCTLDIRECTION
     504{
     505    /** This IOCtl transfers no data. */
     506    NONE,
     507    /** This IOCtl only transfers data from user to kernel. */
     508    IN,
     509    /** This IOCtl only transfers data from kernel to user. */
     510    OUT,
     511    /** This IOCtl transfers data from user to kernel and back. */
     512    BOTH,
     513    /** We aren't saying anything about how the IOCtl transfers data. */
     514    UNSPECIFIED
     515};
     516
     517/**
     518 * IOCtl handler function.
     519 * @returns 0 on success, error code on failure.
     520 * @param cCmd      The IOCtl command number.
     521 * @param pvData    Buffer for the user data.
     522 * @param cbBuffer  Size of the buffer in @a pvData or zero.
     523 * @param pcbData   Where to set the size of the data returned.  Required for
     524 *                  handlers which return data.
     525 * @param prc       Where to store the return code.  Default is zero.  Only
     526 *                  used for IOCtls without data for convenience of
     527 *                  implemention.
     528 */
     529typedef int FNVBOXGUESTSOLARISIOCTL(vboxguest_state_t *pState, int cCmd,
     530                                    void *pvData, size_t cbBuffer,
     531                                    size_t *pcbData, int *prc);
     532typedef FNVBOXGUESTSOLARISIOCTL *PFNVBOXGUESTSOLARISIOCTL;
     533
     534/* Helpers for vboxGuestSolarisDispatchIOCtl. */
     535static int vboxGuestSolarisHandleIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk,
     536                                       PFNVBOXGUESTSOLARISIOCTL pfnHandler,
     537                                       int cCmd, size_t cbTransparent,
     538                                       enum IOCTLDIRECTION enmDirection);
     539static int vboxGuestSolarisVUIDIOCtl(vboxguest_state_t *pState, int cCmd,
     540                                     void *pvData, size_t cbBuffer,
     541                                     size_t *pcbData, int *prc);
     542static int vboxGuestSolarisGuestIOCtl(vboxguest_state_t *pState, int cCmd,
     543                                      void *pvData, size_t cbBuffer,
     544                                      size_t *pcbData, int *prc);
     545
     546/** Table of supported VUID IOCtls. */
     547struct
     548{
     549    /** The IOCtl number. */
     550    int cCmd;
     551    /** The size of the buffer which needs to be copied between user and kernel
     552     * space, or zero if unknown (must be known for tranparent IOCtls). */
     553    size_t cbBuffer;
     554    /** The direction the buffer data needs to be copied.  This must be
     555     * specified for transparent IOCtls. */
     556    enum IOCTLDIRECTION enmDirection;
     557} s_aVUIDIOCtlDescriptions[] =
     558{
     559   { VUIDGFORMAT,     sizeof(int),                  OUT         },
     560   { VUIDSFORMAT,     0,                            NONE        },
     561   { VUIDGADDR,       0,                            UNSPECIFIED },
     562   { MSIOGETPARMS,    sizeof(Ms_parms),             OUT         },
     563   { MSIOSETPARMS,    0,                            NONE        },
     564   { MSIOSRESOLUTION, sizeof(Ms_screen_resolution), IN          },
     565   { MSIOBUTTONS,     sizeof(int),                  OUT         },
     566   { VUIDGWHEELCOUNT, sizeof(int),                  OUT         },
     567   { VUIDGWHEELINFO,  0,                            UNSPECIFIED },
     568   { VUIDGWHEELSTATE, 0,                            UNSPECIFIED },
     569   { VUIDSWHEELSTATE, 0,                            UNSPECIFIED }
     570};
     571
     572/**
     573 * Handle a STREAMS IOCtl message for our driver on the write stream.  This
     574 * function takes care of the IOCtl logic only and does not call qreply() or
     575 * miocnak() at all - the caller must call these on success or failure
     576 * respectively.
     577 * @returns  0 on success or the IOCtl error code on failure.
     578 * @param  pWriteQueue  pointer to the STREAMS write queue structure.
     579 * @param  pMBlk        pointer to the STREAMS message block structure.
     580 */
     581static int vboxGuestSolarisDispatchIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk)
     582{
     583    struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr;
     584    int cCmd = pIOCBlk->ioc_cmd, cCmdType = (cCmd >> 8) & ~0xff;
     585    size_t cbBuffer;
     586    enum IOCTLDIRECTION enmDirection;
     587
     588    LogFlowFunc(("cCmdType=%c, cCmd=%d\n", cCmdType, cCmd));
     589    switch (cCmdType)
     590    {
     591        case MSIOC:
     592        case VUIOC:
     593        {
     594            unsigned i;
     595           
     596            for (i = 0; i < RT_ELEMENTS(s_aVUIDIOCtlDescriptions); ++i)
     597                if (s_aVUIDIOCtlDescriptions[i].cCmd == cCmd)
     598                {
     599                    cbBuffer     = s_aVUIDIOCtlDescriptions[i].cbBuffer;
     600                    enmDirection = s_aVUIDIOCtlDescriptions[i].enmDirection;
     601                    return vboxGuestSolarisHandleIOCtl(pWriteQueue, pMBlk,
     602                                                     vboxGuestSolarisVUIDIOCtl,
     603                                                       cCmd, cbBuffer,
     604                                                       enmDirection);
     605                }
     606            return EINVAL;
     607        }
     608        case 'V':
     609            return vboxGuestSolarisHandleIOCtl(pWriteQueue, pMBlk,
     610                                               vboxGuestSolarisGuestIOCtl,
     611                                               cCmd, 0, UNSPECIFIED);
     612        default:
     613            return ENOTTY;
     614    }
     615}
     616
     617
     618/* Helpers for vboxGuestSolarisHandleIOCtl. */
     619static int vboxGuestSolarisHandleIOCtlData
     620               (queue_t *pWriteQueue, mblk_t *pMBlk,
     621                PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd,
     622                size_t cbTransparent, enum IOCTLDIRECTION enmDirection);
     623
     624static int vboxGuestSolarisHandleTransparentIOCtl
     625                (queue_t *pWriteQueue, mblk_t *pMBlk,
     626                 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd,
     627                size_t cbTransparent, enum IOCTLDIRECTION enmDirection);
     628
     629static int vboxGuestSolarisHandleIStrIOCtl
     630                (queue_t *pWriteQueue, mblk_t *pMBlk,
     631                 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd);
     632
     633/**
     634 * Generic code for handling STREAMS-specific IOCtl logic and boilerplate.  It
     635 * calls the IOCtl handler passed to it without the handler having to be aware
     636 * of STREAMS structures, or whether this is a transparent (traditional) or an
     637 * I_STR (using a STREAMS structure to describe the data) IOCtl.  With the
     638 * caveat that we only support transparent IOCtls which pass all data in a
     639 * single buffer of a fixed size (I_STR IOCtls are restricted to a single
     640 * buffer anyway, but the caller can choose the buffer size).
     641 * @returns  0 on success or the IOCtl error code on failure.
     642 * @param  pWriteQueue    pointer to the STREAMS write queue structure.
     643 * @param  pMBlk          pointer to the STREAMS message block structure.
     644 * @param  pfnHandler     pointer to the right IOCtl handler function for this
     645 *                        IOCtl number.
     646 * @param  cCmd           IOCtl command number.
     647 * @param  cbTransparent  size of the user space buffer for this IOCtl number,
     648 *                        used for processing transparent IOCtls.  Pass zero
     649 *                        for IOCtls with no maximum buffer size (which will
     650 *                        not be able to be handled as transparent) or with
     651 *                        no argument.
     652 * @param  enmDirection   data transfer direction of the IOCtl.
     653 */
     654static int vboxGuestSolarisHandleIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk,
     655                                       PFNVBOXGUESTSOLARISIOCTL pfnHandler,
     656                                       int cCmd, size_t cbTransparent,
     657                                       enum IOCTLDIRECTION enmDirection)
     658{
     659    struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr;
     660    vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr;
     661
     662    if (pMBlk->b_datap->db_type == M_IOCDATA)
     663        return vboxGuestSolarisHandleIOCtlData(pWriteQueue, pMBlk, pfnHandler,
     664                                               cCmd, cbTransparent,
     665                                               enmDirection);
     666    else if (pIOCBlk->ioc_count == TRANSPARENT)
     667        return vboxGuestSolarisHandleTransparentIOCtl(pWriteQueue, pMBlk,
     668                                                      pfnHandler, cCmd,
     669                                                      cbTransparent,
     670                                                      enmDirection);
     671    else
     672        return vboxGuestSolarisHandleIStrIOCtl(pWriteQueue, pMBlk, pfnHandler,
     673                                               cCmd);
     674}
     675
     676
     677/**
     678 * Helper for vboxGuestSolarisHandleIOCtl.  This rather complicated-looking
     679 * code is basically the standard boilerplate for handling any streams IOCtl
     680 * additional data, which we currently only use for transparent IOCtls.
     681 * @copydoc vboxGuestSolarisHandleIOCtl
     682 */
     683static int vboxGuestSolarisHandleIOCtlData(queue_t *pWriteQueue, mblk_t *pMBlk,
     684                                           PFNVBOXGUESTSOLARISIOCTL pfnHandler,
     685                                           int cCmd, size_t cbTransparent,
     686                                           enum IOCTLDIRECTION enmDirection)
     687{
     688    struct copyresp *pCopyResp = (struct copyresp *)pMBlk->b_rptr;
     689    struct iocblk   *pIOCBlk   = (struct iocblk *)pMBlk->b_rptr;
     690    vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr;
     691
     692    if (pCopyResp->cp_rval)
     693    {
     694        freemsg(pMBlk);
     695        return EAGAIN;  /* cp_rval is a pointer but should be the error. */
     696    }
     697    if ((pCopyResp->cp_private && enmDirection == BOTH) || enmDirection == IN)
     698    {
     699        size_t cbBuffer = pIOCBlk->ioc_count, cbData = 0;
     700        void *pvData = NULL;
     701        int err;
     702
     703        if (cbData < cbTransparent)
     704            return EINVAL;
     705        if (!pMBlk->b_cont)
     706            return EINVAL;
     707        if (enmDirection == BOTH && !pCopyResp->cp_private)
     708            return EINVAL;
     709        pvData = pMBlk->b_cont->b_rptr;
     710        err = pfnHandler(pState, cCmd, pvData, cbBuffer, &cbData, NULL);
     711        if (!err && enmDirection == BOTH)
     712            mcopyout(pMBlk, NULL, cbData, pCopyResp->cp_private, NULL);
     713        else if (!err && enmDirection == IN)
     714            miocack(pWriteQueue, pMBlk, 0, 0);
     715        return err;
     716    }
     717    else
     718    {
     719        AssertReturn(enmDirection == OUT || enmDirection == BOTH, EINVAL);
     720        miocack(pWriteQueue, pMBlk, 0, 0);
     721        return 0;
     722    }
     723}
     724
     725/**
     726 * Helper for vboxGuestSolarisHandleIOCtl.  This rather complicated-looking
     727 * code is basically the standard boilerplate for handling transparent IOCtls,
     728 * that is, IOCtls which are not re-packed inside STREAMS IOCtls.
     729 * @copydoc vboxGuestSolarisHandleIOCtl
     730 */
     731int vboxGuestSolarisHandleTransparentIOCtl
     732                (queue_t *pWriteQueue, mblk_t *pMBlk,
     733                 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd,
     734                 size_t cbTransparent, enum IOCTLDIRECTION enmDirection)
     735{
     736    int err = 0, rc = 0;
     737    size_t cbData = 0;
     738    vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr;
     739
     740    if (   (enmDirection != NONE && !pMBlk->b_cont)
     741        || enmDirection == UNSPECIFIED)
     742        return EINVAL;
     743    if (enmDirection == IN || enmDirection == BOTH)
     744    {
     745        void *pUserAddr = NULL;
     746        /* We only need state data if there is something to copy back. */
     747        if (enmDirection == BOTH)
     748            pUserAddr = *(void **)pMBlk->b_cont->b_rptr;
     749            mcopyin(pMBlk, pUserAddr /* state data */, cbTransparent, NULL);
     750        }
     751        else if (enmDirection == OUT)
     752    {
     753        mblk_t *pMBlkOut = allocb(cbOut, BPRI_MED);
     754        void *pvData;
     755
     756        if (!pMBlkOut)
     757            return EAGAIN;
     758        pvData = pMBlkOut->b_rptr;
     759        err = pfnHandler(pState, cCmd, pvData, cbTransparent, &cbData, NULL);
     760        if (!err)
     761            mcopyout(pMBlk, NULL, cbData, NULL, pMBlkOut);
     762        else
     763            freemsg(pMBlkOut);
     764    }
     765    else
     766    {
     767        AssertReturn(enmDirection == NONE, EINVAL);
     768        err = pfnHandler(pState, cCmd, NULL, 0, NULL, &rc);
     769        if (!err)
     770            miocack(pWriteQueue, pMBlk, 0, rc);
     771    }
     772    return err;
     773}
     774                 
     775/**
     776 * Helper for vboxGuestSolarisHandleIOCtl.  This rather complicated-looking
     777 * code is basically the standard boilerplate for handling any streams IOCtl.
     778 * @copydoc vboxGuestSolarisHandleIOCtl
     779 */
     780static int vboxGuestSolarisHandleIStrIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk,
     781                                           PFNVBOXGUESTSOLARISIOCTL pfnHandler,
     782                                           int cCmd)
     783{
     784    struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr;
     785    vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr;
     786    uint_t cbBuffer = pIOCBlk->ioc_count;
     787    void *pvData = NULL;
     788    int err, rc = 0;
     789    size_t cbData = 0;
     790   
     791    if (cbBuffer && !pMBlk->b_cont)
     792        return EINVAL;
     793    /* Repack the whole buffer into a single message block if needed. */
     794    if (cbBuffer)
     795    {
     796        err = miocpullup(pMBlk, cbBuffer);
     797        if (err)
     798            return err;
     799        pvData = pMBlk->b_cont->b_rptr;
     800    }
     801    err = pfnHandler(pState, cCmd, pvData, cbBuffer, &cbData, &rc);
     802    if (!err)
     803        miocack(pWriteQueue, pMBlk, cbData, rc);
     804    return err;
     805}
     806
     807
     808/**
     809 * Handle a VUID input device IOCtl.
     810 * @copydoc FNVBOXGUESTSOLARISIOCTL
     811 */
     812static int vboxGuestSolarisVUIDIOCtl(vboxguest_state_t *pState, int cCmd,
     813                                     void *pvData, size_t cbBuffer,
     814                                     size_t *pcbData, int *prc)
     815{
     816    LogFlowFunc((": " /* no '\n' */));
     817    switch (cCmd)
     818    {
     819        case VUIDGFORMAT:
     820        {
     821            LogFlowFunc(("VUIDGFORMAT\n"));
     822            AssertReturn(cbBuffer >= sizeof(int), EINVAL);
     823            *(int *)pvData = VUID_FIRM_EVENT;
     824            *pcbData = sizeof(int);
     825            return 0;
     826        }
     827        case VUIDSFORMAT:
     828            LogFlowFunc(("VUIDSFORMAT\n"));
     829            /* We define our native format to be VUID_FIRM_EVENT, so there
     830             * is nothing more to do and we exit here on success or on
     831             * failure. */
     832            return 0;
     833        case VUIDGADDR:
     834        case VUIDSADDR:
     835            LogFlowFunc(("VUIDGADDR/VUIDSADDR\n"));
     836            return ENOTTY;
     837        case MSIOGETPARMS:
     838        {
     839            Ms_parms parms = { 0 };
     840
     841            LogFlowFunc(("MSIOGETPARMS\n"));
     842            AssertReturn(cbBuffer >= sizeof(Ms_parms), EINVAL);
     843            *(Ms_parms *)pvData = parms;
     844            *pcbData = sizeof(Ms_parms);
     845            return 0;
     846        }
     847        case MSIOSETPARMS:
     848            LogFlowFunc(("MSIOSETPARMS\n"));
     849            return 0;
     850        case MSIOSRESOLUTION:
     851        {
     852            Ms_screen_resolution *pResolution = (Ms_screen_resolution *)pvData;
     853            LogFlowFunc(("MSIOSRESOLUTION\n"));
     854            AssertReturn(cbBuffer >= sizeof(Ms_screen_resolution), EINVAL);
     855            pState->cMaxScreenX = pResolution->width  - 1;
     856            pState->cMaxScreenY = pResolution->height - 1;
     857            return 0;
     858        }
     859        case MSIOBUTTONS:
     860        {
     861            LogFlowFunc(("MSIOBUTTONS\n"));
     862            AssertReturn(cbBuffer >= sizeof(int), EINVAL);
     863            *(int *)pvData = 0;
     864            *pcbData = sizeof(int);
     865            return 0;
     866        }
     867        case VUIDGWHEELCOUNT:
     868        {
     869            LogFlowFunc(("VUIDGWHEELCOUNT\n"));
     870            AssertReturn(cbBuffer >= sizeof(int), EINVAL);
     871            *(int *)pvData = 0;
     872            *pcbData = sizeof(int);
     873            return 0;
     874        }
     875        case VUIDGWHEELINFO:
     876        case VUIDGWHEELSTATE:
     877        case VUIDSWHEELSTATE:
     878            LogFlowFunc(("VUIDGWHEELINFO/VUIDGWHEELSTATE/VUIDSWHEELSTATE\n"));
     879            return EINVAL;
     880        default:
     881            LogFlowFunc(("Invalid IOCtl command %x\n", cCmd));
     882            return EINVAL;
     883    }
     884}
     885
     886
     887/**
     888 * Handle a VBoxGuest IOCtl.
     889 * @copydoc FNVBOXGUESTSOLARISIOCTL
     890 */
     891static int vboxGuestSolarisGuestIOCtl(vboxguest_state_t *pState, int cCmd,
     892                                      void *pvData, size_t cbBuffer,
     893                                      size_t *pcbData, int *prc)
     894{
     895    int rc = VBoxGuestCommonIOCtl(cCmd, &g_DevExt, pState->pSession, pvData, cbBuffer, pcbData);
     896    if (RT_SUCCESS(rc))
     897    {
     898        *prc = rc;
     899        return 0;
     900    }
     901    else
     902    {
     903        /*
     904         * We Log() instead of LogRel() here because VBOXGUEST_IOCTL_WAITEVENT can return VERR_TIMEOUT,
     905         * VBOXGUEST_IOCTL_CANCEL_ALL_EVENTS can return VERR_INTERRUPTED and possibly more in the future;
     906         * which are not really failures that require logging.
     907         */
     908        Log((DEVICE_NAME "::IOCtl: VBoxGuestCommonIOCtl failed. Cmd=%#x rc=%d\n", cCmd, rc));
     909        rc = RTErrConvertToErrno(rc);
     910        return rc;
     911    }
     912}
     913
     914
     915/**
     916 * Info entry point, called by solaris kernel for obtaining driver info.
     917 *
     918 * @param   pDip            The module structure instance (do not use).
     919 * @param   enmCmd          Information request type.
     920 * @param   pvArg           Type specific argument.
     921 * @param   ppvResult       Where to store the requested info.
     922 *
     923 * @return  corresponding solaris error code.
     924 */
     925int vboxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd,
     926                            void *pvArg, void **ppvResult)
     927{
     928    int rc = DDI_SUCCESS;
     929
     930    LogFlow((DEVICE_NAME "::GetInfo\n"));
     931    switch (enmCmd)
     932    {
     933        case DDI_INFO_DEVT2DEVINFO:
     934            *ppvResult = (void *)g_pDip;
     935            break;
     936
     937        case DDI_INFO_DEVT2INSTANCE:
     938            *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
     939            break;
     940
     941        default:
     942            rc = DDI_FAILURE;
     943            break;
     944    }
     945
     946    NOREF(pvArg);
     947    return rc;
     948}
     949
     950
     951/* Helpers for vboxGuestSolarisAttach and vboxGuestSolarisDetach. */
     952static int vboxGuestSolarisAddIRQ(dev_info_t *pDip);
     953static void vboxGuestSolarisRemoveIRQ(dev_info_t *pDip);
    257954
    258955/**
     
    264961 * @return  corresponding solaris error code.
    265962 */
    266 static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
     963int vboxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
    267964{
    268965    LogFlow((DEVICE_NAME "::Attach\n"));
     
    271968        case DDI_ATTACH:
    272969        {
     970            int instance, rc;
     971            ddi_acc_handle_t PciHandle;
     972
    273973            if (g_pDip)
    274974            {
     
    276976                return DDI_FAILURE;
    277977            }
    278 
    279             int instance = ddi_get_instance(pDip);
     978            instance = ddi_get_instance(pDip);
    280979
    281980            /*
    282981             * Enable resources for PCI access.
    283982             */
    284             ddi_acc_handle_t PciHandle;
    285             int rc = pci_config_setup(pDip, &PciHandle);
     983            rc = pci_config_setup(pDip, &PciHandle);
    286984            if (rc == DDI_SUCCESS)
    287985            {
     
    289987                 * Map the register address space.
    290988                 */
    291                 caddr_t baseAddr;
     989                char *baseAddr;  /* Actually caddr_t. */
    292990                ddi_device_acc_attr_t deviceAttr;
    293991                deviceAttr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
     
    3121010                             * Add IRQ of VMMDev.
    3131011                             */
    314                             rc = VBoxGuestSolarisAddIRQ(pDip);
     1012                            rc = vboxGuestSolarisAddIRQ(pDip);
    3151013                            if (rc == DDI_SUCCESS)
    3161014                            {
     
    3181016                                 * Call the common device extension initializer.
    3191017                                 */
    320                                 rc = VBoxGuestInitDevExt(&g_DevExt, g_uIOPortBase, g_pMMIOBase, g_cbMMIO,
    3211018#if ARCH_BITS == 64
    322                                                          VBOXOSTYPE_Solaris_x64,
     1019# define VBOXGUEST_OS_TYPE VBOXOSTYPE_Solaris_x64
    3231020#else
    324                                                          VBOXOSTYPE_Solaris,
     1021# define VBOXGUEST_OS_TYPE VBOXOSTYPE_Solaris
    3251022#endif
    326                                                          VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
     1023                                rc = VBoxGuestInitDevExt(&g_DevExt,
     1024                                                         g_uIOPortBase,
     1025                                                         g_pMMIOBase, g_cbMMIO,
     1026                                                         VBOXGUEST_OS_TYPE,
     1027                                          VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
     1028#undef VBOXGUEST_OS_TYPE
    3271029                                if (RT_SUCCESS(rc))
    3281030                                {
     
    3401042                                else
    3411043                                    LogRel((DEVICE_NAME "::Attach: VBoxGuestInitDevExt failed.\n"));
    342                                 VBoxGuestSolarisRemoveIRQ(pDip);
     1044                                vboxGuestSolarisRemoveIRQ(pDip);
    3431045                            }
    3441046                            else
    345                                 LogRel((DEVICE_NAME "::Attach: VBoxGuestSolarisAddIRQ failed.\n"));
     1047                                LogRel((DEVICE_NAME "::Attach: vboxGuestSolarisAddIRQ failed.\n"));
    3461048                            ddi_regs_map_free(&g_PciMMIOHandle);
    3471049                        }
     
    3821084 * @return  corresponding solaris error code.
    3831085 */
    384 static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
     1086int vboxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
    3851087{
    3861088    LogFlow((DEVICE_NAME "::Detach\n"));
     
    3891091        case DDI_DETACH:
    3901092        {
    391             VBoxGuestSolarisRemoveIRQ(pDip);
     1093            vboxGuestSolarisRemoveIRQ(pDip);
    3921094            ddi_regs_map_free(&g_PciIOHandle);
    3931095            ddi_regs_map_free(&g_PciMMIOHandle);
     
    4101112
    4111113
    412 /**
    413  * Info entry point, called by solaris kernel for obtaining driver info.
    414  *
    415  * @param   pDip            The module structure instance (do not use).
    416  * @param   enmCmd          Information request type.
    417  * @param   pvArg           Type specific argument.
    418  * @param   ppvResult       Where to store the requested info.
    419  *
    420  * @return  corresponding solaris error code.
    421  */
    422 static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
    423 {
    424     LogFlow((DEVICE_NAME "::GetInfo\n"));
    425 
    426     int rc = DDI_SUCCESS;
    427     switch (enmCmd)
    428     {
    429         case DDI_INFO_DEVT2DEVINFO:
    430             *ppvResult = (void *)g_pDip;
    431             break;
    432 
    433         case DDI_INFO_DEVT2INSTANCE:
    434             *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
    435             break;
    436 
    437         default:
    438             rc = DDI_FAILURE;
    439             break;
    440     }
    441 
    442     NOREF(pvArg);
    443     return rc;
    444 }
    445 
    446 
    447 /**
    448  * User context entry points
    449  */
    450 static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
    451 {
    452     int                 rc;
    453     PVBOXGUESTSESSION   pSession = NULL;
    454 
    455     LogFlow((DEVICE_NAME "::Open\n"));
    456 
    457     /*
    458      * Verify we are being opened as a character device.
    459      */
    460     if (fType != OTYP_CHR)
    461         return EINVAL;
    462 
    463     vboxguest_state_t *pState = NULL;
    464     unsigned iOpenInstance;
    465     for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
    466     {
    467         if (    !ddi_get_soft_state(g_pVBoxGuestSolarisState, iOpenInstance) /* faster */
    468             &&  ddi_soft_state_zalloc(g_pVBoxGuestSolarisState, iOpenInstance) == DDI_SUCCESS)
    469         {
    470             pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, iOpenInstance);
    471             break;
    472         }
    473     }
    474     if (!pState)
    475     {
    476         Log((DEVICE_NAME "::Open: too many open instances."));
    477         return ENXIO;
    478     }
    479 
    480     /*
    481      * Create a new session.
    482      */
    483     rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
    484     if (RT_SUCCESS(rc))
    485     {
    486         pState->pvProcRef = proc_ref();
    487         pState->pSession = pSession;
    488         *pDev = makedevice(getmajor(*pDev), iOpenInstance);
    489         Log((DEVICE_NAME "::Open: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf()));
    490         return 0;
    491     }
    492 
    493     /* Failed, clean up. */
    494     ddi_soft_state_free(g_pVBoxGuestSolarisState, iOpenInstance);
    495 
    496     LogRel((DEVICE_NAME "::Open: VBoxGuestCreateUserSession failed. rc=%d\n", rc));
    497     return EFAULT;
    498 }
    499 
    500 
    501 static int VBoxGuestSolarisClose(dev_t Dev, int flag, int fType, cred_t *pCred)
    502 {
    503     LogFlow((DEVICE_NAME "::Close pid=%d\n", (int)RTProcSelf()));
    504 
    505     PVBOXGUESTSESSION pSession = NULL;
    506     vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
    507     if (!pState)
    508     {
    509         Log((DEVICE_NAME "::Close: failed to get pState.\n"));
    510         return EFAULT;
    511     }
    512 
    513     proc_unref(pState->pvProcRef);
    514     pSession = pState->pSession;
    515     pState->pSession = NULL;
    516     Log((DEVICE_NAME "::Close: pSession=%p pState=%p\n", pSession, pState));
    517     ddi_soft_state_free(g_pVBoxGuestSolarisState, getminor(Dev));
    518     if (!pSession)
    519     {
    520         Log((DEVICE_NAME "::Close: failed to get pSession.\n"));
    521         return EFAULT;
    522     }
    523 
    524     /*
    525      * Close the session.
    526      */
    527     VBoxGuestCloseSession(&g_DevExt, pSession);
    528     return 0;
    529 }
    530 
    531 
    532 static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
    533 {
    534     LogFlow((DEVICE_NAME "::Read\n"));
    535 
    536     vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
    537     if (!pState)
    538     {
    539         Log((DEVICE_NAME "::Close: failed to get pState.\n"));
    540         return EFAULT;
    541     }
    542 
    543     PVBOXGUESTSESSION pSession = pState->pSession;
    544     uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
    545     if (pSession->u32MousePosChangedSeq != u32CurSeq)
    546         pSession->u32MousePosChangedSeq = u32CurSeq;
    547 
    548     return 0;
    549 }
    550 
    551 
    552 static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
    553 {
    554     LogFlow((DEVICE_NAME "::Write\n"));
    555     return 0;
    556 }
    557 
    558 
    559 /** @def IOCPARM_LEN
    560  * Gets the length from the ioctl number.
    561  * This is normally defined by sys/ioccom.h on BSD systems...
    562  */
    563 #ifndef IOCPARM_LEN
    564 # define IOCPARM_LEN(Code)                      (((Code) >> 16) & IOCPARM_MASK)
    565 #endif
    566 
    567 
    568 /**
    569  * Driver ioctl, an alternate entry point for this character driver.
    570  *
    571  * @param   Dev             Device number
    572  * @param   Cmd             Operation identifier
    573  * @param   pArg            Arguments from user to driver
    574  * @param   Mode            Information bitfield (read/write, address space etc.)
    575  * @param   pCred           User credentials
    576  * @param   pVal            Return value for calling process.
    577  *
    578  * @return  corresponding solaris error code.
    579  */
    580 static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
    581 {
    582     LogFlow((DEVICE_NAME ":VBoxGuestSolarisIOCtl\n"));
    583 
    584     /*
    585      * Get the session from the soft state item.
    586      */
    587     vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
    588     if (!pState)
    589     {
    590         LogRel((DEVICE_NAME "::IOCtl: no state data for %d\n", getminor(Dev)));
    591         return EINVAL;
    592     }
    593 
    594     PVBOXGUESTSESSION pSession = pState->pSession;
    595     if (!pSession)
    596     {
    597         LogRel((DEVICE_NAME "::IOCtl: no session data for %d\n", getminor(Dev)));
    598         return EINVAL;
    599     }
    600 
    601     /*
    602      * Read and validate the request wrapper.
    603      */
    604     VBGLBIGREQ ReqWrap;
    605     if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
    606     {
    607         LogRel((DEVICE_NAME "::IOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
    608         return ENOTTY;
    609     }
    610 
    611     int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
    612     if (RT_UNLIKELY(rc))
    613     {
    614         LogRel((DEVICE_NAME "::IOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%#x.\n", pArg, Cmd, rc));
    615         return EINVAL;
    616     }
    617 
    618     if (ReqWrap.u32Magic != VBGLBIGREQ_MAGIC)
    619     {
    620         LogRel((DEVICE_NAME "::IOCtl: bad magic %#x; pArg=%p Cmd=%#x.\n", ReqWrap.u32Magic, pArg, Cmd));
    621         return EINVAL;
    622     }
    623     if (RT_UNLIKELY(ReqWrap.cbData > _1M*16))
    624     {
    625         LogRel((DEVICE_NAME "::IOCtl: bad size %#x; pArg=%p Cmd=%#x.\n", ReqWrap.cbData, pArg, Cmd));
    626         return EINVAL;
    627     }
    628 
    629     /*
    630      * Read the request payload if any; requests like VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS have no data payload.
    631      */
    632     void *pvBuf = NULL;
    633     if (RT_LIKELY(ReqWrap.cbData > 0))
    634     {
    635         pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
    636         if (RT_UNLIKELY(!pvBuf))
    637         {
    638             LogRel((DEVICE_NAME "::IOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
    639             return ENOMEM;
    640         }
    641 
    642         rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
    643         if (RT_UNLIKELY(rc))
    644         {
    645             RTMemTmpFree(pvBuf);
    646             LogRel((DEVICE_NAME "::IOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
    647             return EFAULT;
    648         }
    649         if (RT_UNLIKELY(!VALID_PTR(pvBuf)))
    650         {
    651             RTMemTmpFree(pvBuf);
    652             LogRel((DEVICE_NAME "::IOCtl: pvBuf invalid pointer %p\n", pvBuf));
    653             return EINVAL;
    654         }
    655     }
    656     Log((DEVICE_NAME "::IOCtl: pSession=%p pid=%d.\n", pSession, (int)RTProcSelf()));
    657 
    658     /*
    659      * Process the IOCtl.
    660      */
    661     size_t cbDataReturned = 0;
    662     rc = VBoxGuestCommonIOCtl(Cmd, &g_DevExt, pSession, pvBuf, ReqWrap.cbData, &cbDataReturned);
    663     if (RT_SUCCESS(rc))
    664     {
    665         rc = 0;
    666         if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
    667         {
    668             LogRel((DEVICE_NAME "::IOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
    669             cbDataReturned = ReqWrap.cbData;
    670         }
    671         if (cbDataReturned > 0)
    672         {
    673             rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
    674             if (RT_UNLIKELY(rc))
    675             {
    676                 LogRel((DEVICE_NAME "::IOCtl: ddi_copyout failed; pvBuf=%p pArg=%p cbDataReturned=%u Cmd=%d. rc=%d\n",
    677                         pvBuf, pArg, cbDataReturned, Cmd, rc));
    678                 rc = EFAULT;
    679             }
    680         }
    681     }
    682     else
    683     {
    684         /*
    685          * We Log() instead of LogRel() here because VBOXGUEST_IOCTL_WAITEVENT can return VERR_TIMEOUT,
    686          * VBOXGUEST_IOCTL_CANCEL_ALL_EVENTS can return VERR_INTERRUPTED and possibly more in the future;
    687          * which are not really failures that require logging.
    688          */
    689         Log((DEVICE_NAME "::IOCtl: VBoxGuestCommonIOCtl failed. Cmd=%#x rc=%d\n", Cmd, rc));
    690         rc = RTErrConvertToErrno(rc);
    691     }
    692     *pVal = rc;
    693     if (pvBuf)
    694         RTMemTmpFree(pvBuf);
    695     return rc;
    696 }
    697 
    698 
    699 static int VBoxGuestSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead)
    700 {
    701     LogFlow((DEVICE_NAME "::Poll: fEvents=%d fAnyYet=%d\n", fEvents, fAnyYet));
    702 
    703     vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
    704     if (RT_LIKELY(pState))
    705     {
    706         PVBOXGUESTSESSION pSession  = (PVBOXGUESTSESSION)pState->pSession;
    707         uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
    708         if (pSession->u32MousePosChangedSeq != u32CurSeq)
    709         {
    710             *pReqEvents |= (POLLIN | POLLRDNORM);
    711             pSession->u32MousePosChangedSeq = u32CurSeq;
    712         }
    713         else
    714         {
    715             *pReqEvents = 0;
    716             if (!fAnyYet)
    717                 *ppPollHead = &g_PollHead;
    718         }
    719 
    720         return 0;
    721     }
    722     else
    723     {
    724         Log((DEVICE_NAME "::Poll: no state data for %d\n", getminor(Dev)));
    725         return EINVAL;
    726     }
    727 }
    728 
     1114/* Interrupt service routine installed by vboxGuestSolarisAddIRQ. */
     1115static uint_t vboxGuestSolarisISR(char *Arg /* Actually caddr_t. */);
    7291116
    7301117/**
     
    7341121 * @param   pDip     Pointer to the device info structure.
    7351122 */
    736 static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip)
    737 {
     1123static int vboxGuestSolarisAddIRQ(dev_info_t *pDip)
     1124{
     1125    int IntrType = 0, rc;
     1126
    7381127    LogFlow((DEVICE_NAME "::AddIRQ: pDip=%p\n", pDip));
    739 
    740     int IntrType = 0;
    741     int rc = ddi_intr_get_supported_types(pDip, &IntrType);
     1128    rc = ddi_intr_get_supported_types(pDip, &IntrType);
    7421129    if (rc == DDI_SUCCESS)
    7431130    {
     
    7591146                    if (g_pIntr)
    7601147                    {
    761                         int IntrAllocated;
     1148                        size_t IntrAllocated;
     1149                        unsigned i;
    7621150                        rc = ddi_intr_alloc(pDip, g_pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL);
    7631151                        if (   rc == DDI_SUCCESS
    7641152                            && IntrAllocated > 0)
    7651153                        {
     1154                            uint_t uIntrPriority;
    7661155                            g_cIntrAllocated = IntrAllocated;
    767                             uint_t uIntrPriority;
    7681156                            rc = ddi_intr_get_pri(g_pIntr[0], &uIntrPriority);
    7691157                            if (rc == DDI_SUCCESS)
     
    7731161
    7741162                                /* Assign interrupt handler functions and enable interrupts. */
    775                                 for (int i = 0; i < IntrAllocated; i++)
     1163                                for (i = 0; i < IntrAllocated; i++)
    7761164                                {
    777                                     rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)VBoxGuestSolarisISR,
     1165                                    rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)vboxGuestSolarisISR,
    7781166                                                            NULL /* No Private Data */, NULL);
    7791167                                    if (rc == DDI_SUCCESS)
     
    7911179                                /* Remove any assigned handlers */
    7921180                                LogRel((DEVICE_NAME ":failed to assign IRQs allocated=%d\n", IntrAllocated));
    793                                 for (int x = 0; x < IntrAllocated; x++)
    794                                     ddi_intr_remove_handler(g_pIntr[x]);
     1181                                for (i = 0; i < IntrAllocated; i++)
     1182                                    ddi_intr_remove_handler(g_pIntr[i]);
    7951183                            }
    7961184                            else
     
    7981186
    7991187                            /* Remove allocated IRQs, too bad we can free only one handle at a time. */
    800                             for (int k = 0; k < g_cIntrAllocated; k++)
    801                                 ddi_intr_free(g_pIntr[k]);
     1188                            for (i = 0; i < g_cIntrAllocated; i++)
     1189                                ddi_intr_free(g_pIntr[i]);
    8021190                        }
    8031191                        else
     
    8281216 * @param   pDip     Pointer to the device info structure.
    8291217 */
    830 static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip)
    831 {
     1218static void vboxGuestSolarisRemoveIRQ(dev_info_t *pDip)
     1219{
     1220    unsigned i;
     1221
    8321222    LogFlow((DEVICE_NAME "::RemoveIRQ:\n"));
    833 
    834     for (int i = 0; i < g_cIntrAllocated; i++)
     1223    for (i = 0; i < g_cIntrAllocated; i++)
    8351224    {
    8361225        int rc = ddi_intr_disable(g_pIntr[i]);
     
    8531242 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
    8541243 */
    855 static uint_t VBoxGuestSolarisISR(caddr_t Arg)
    856 {
     1244static uint_t vboxGuestSolarisISR(char *Arg /* Actually caddr_t. */)
     1245{
     1246    bool fOurIRQ;
     1247
    8571248    LogFlow((DEVICE_NAME "::ISR:\n"));
    858 
    8591249    mutex_enter(&g_IrqMtx);
    860     bool fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
     1250    fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
    8611251    mutex_exit(&g_IrqMtx);
    862 
    8631252    return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED;
    8641253}
    8651254
    8661255
     1256/* Helper for VBoxGuestNativeISRMousePollEvent. */
     1257static void VBoxGuestVUIDPutAbsEvent(ushort_t cEvent, int cValue);
     1258
     1259/**
     1260 * Native part of the IRQ service routine, called when the VBoxGuest mouse
     1261 * pointer is moved.  We send a VUID event up to user space.
     1262 */
    8671263void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
    8681264{
     1265    VMMDevReqMouseStatus *pReq;
     1266    int rc;
    8691267    LogFlow((DEVICE_NAME "::NativeISRMousePollEvent:\n"));
    8701268
    871     /*
    872      * Wake up poll waiters.
    873      */
    874     pollwakeup(&g_PollHead, POLLIN | POLLRDNORM);
    875 }
    876 
    877 
    878 /* Common code that depend on g_DevExt. */
     1269    rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq),
     1270                     VMMDevReq_GetMouseStatus);
     1271    if (RT_FAILURE(rc))
     1272        return;  /* If kernel memory is short a missed event is acceptable! */
     1273    pReq->mouseFeatures = 0;
     1274    pReq->pointerXPos = 0;
     1275    pReq->pointerYPos = 0;
     1276    rc = VbglGRPerform(&pReq->header);
     1277    if (RT_SUCCESS(rc))
     1278    {
     1279        int cMaxScreenX  = g_pState->cMaxScreenX;
     1280        int cMaxScreenY  = g_pState->cMaxScreenY;
     1281
     1282        VBoxGuestVUIDPutAbsEvent(LOC_X_ABSOLUTE,
     1283                                   pReq->pointerXPos * cMaxScreenX
     1284                                 / VMMDEV_MOUSE_RANGE_MAX);
     1285        VBoxGuestVUIDPutAbsEvent(LOC_Y_ABSOLUTE,
     1286                                   pReq->pointerYPos * cMaxScreenY
     1287                                 / VMMDEV_MOUSE_RANGE_MAX);
     1288    }
     1289    VbglGRFree(&pReq->header);
     1290}
     1291
     1292
     1293void VBoxGuestVUIDPutAbsEvent(ushort_t cEvent, int cValue)
     1294{
     1295    queue_t *pReadQueue = RD(g_pState->pWriteQueue);
     1296    mblk_t *pMBlk = allocb(sizeof(Firm_event, BPRI_HI));
     1297    Firm_event *pEvent;
     1298    AssertReturnVoid(cEvent == LOC_X_ABSOLUTE || cEvent == LOC_Y_ABSOLUTE);
     1299    if (!pMBlk)
     1300        return;  /* If kernel memory is short a missed event is acceptable! */
     1301    pEvent = (Firm_event *)pMBlk->b_wptr;
     1302    pEvent->id        = cEvent;
     1303    pEvent->pair_type = FE_PAIR_DELTA;
     1304    pEvent->pair      = cEvent == LOC_X_ABSOLUTE ? LOC_X_DELTA : LOC_Y_DELTA;
     1305    pEvent->value     = cValue;
     1306    uniqtime32(&pEvent->time);
     1307    pMBlk->b_wptr += sizeof(Firm_event);
     1308    /* Put the message on the queue immediately if it is not blocked. */
     1309    if (canput(pReadQueue->q_next))
     1310        putnext(pReadQueue, pMBlk);
     1311    else
     1312        putbq(pReadQueue, pMBlk);
     1313}
     1314
     1315
     1316/* Common code that depends on g_DevExt. */
    8791317#include "VBoxGuestIDC-unix.c.h"
    8801318
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette