VirtualBox

Ignore:
Timestamp:
May 26, 2011 10:33:21 AM (14 years ago)
Author:
vboxsync
Message:

VBoxMouse,VBoxGuest/win: NEW_PROTOCOL for mouse integration

Location:
trunk/src/VBox/Additions/WINNT/Mouse
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Mouse/NT5/VBoxMF.h

    r37163 r37221  
    5656    VMMDevReqMouseStatus       *pSCReq;              /* Preallocated request to use in pfnServiceCB */
    5757
     58    IO_REMOVE_LOCK RemoveLock;
    5859} VBOXMOUSE_DEVEXT, *PVBOXMOUSE_DEVEXT;
    5960
     
    7677VOID VBoxDeviceRemoved(PVBOXMOUSE_DEVEXT pDevExt);
    7778
     79VOID VBoxDrvNotifyServiceCB(PVBOXMOUSE_DEVEXT pDevExt, PMOUSE_INPUT_DATA InputDataStart, PMOUSE_INPUT_DATA InputDataEnd, PULONG  InputDataConsumed);
     80
    7881#endif /*VBOXMF_H*/
  • trunk/src/VBox/Additions/WINNT/Mouse/NT5/VBoxMFDriver.cpp

    r37163 r37221  
    2020#include <VBox/VBoxGuestLib.h>
    2121#include <iprt/initterm.h>
     22#include <iprt/assert.h>
    2223
    2324#ifdef ALLOC_PRAGMA
     
    6364}
    6465
     66#define VBOXUSB_RLTAG 'LRBV'
     67
    6568NTSTATUS VBoxDrvAddDevice(IN PDRIVER_OBJECT Driver, IN PDEVICE_OBJECT PDO)
    6669{
     
    8285    RtlZeroMemory(pDevExt, sizeof(VBOXMOUSE_DEVEXT));
    8386
     87    IoInitializeRemoveLock(&pDevExt->RemoveLock, VBOXUSB_RLTAG, 1, 100);
     88
     89    rc = IoAcquireRemoveLock(&pDevExt->RemoveLock, pDevExt);
     90    if (!NT_SUCCESS(rc))
     91    {
     92        WARN(("IoAcquireRemoveLock failed with %#x", rc));
     93        IoDeleteDevice(pDO);
     94        return rc;
     95    }
     96
    8497    pDOParent = IoAttachDeviceToDeviceStack(pDO, PDO);
    8598    if (!pDOParent)
    8699    {
     100        IoReleaseRemoveLockAndWait(&pDevExt->RemoveLock, pDevExt);
     101
    87102        WARN(("IoAttachDeviceToDeviceStack failed"));
    88103        IoDeleteDevice(pDO);
     
    105120NTSTATUS VBoxIrpPassthrough(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    106121{
    107     PIO_STACK_LOCATION pStack;
    108     PVBOXMOUSE_DEVEXT pDevExt;
    109     LOGF_ENTER();
    110 
    111     pStack = IoGetCurrentIrpStackLocation(Irp);
     122    PVBOXMOUSE_DEVEXT pDevExt;
     123    LOGF_ENTER();
     124
    112125    pDevExt = (PVBOXMOUSE_DEVEXT) DeviceObject->DeviceExtension;
    113126
     
    127140    pDevExt = (PVBOXMOUSE_DEVEXT) DeviceObject->DeviceExtension;
    128141
    129     if (pDevExt->pSCReq)
    130     {
    131         int rc = VbglGRPerform(&pDevExt->pSCReq->header);
    132 
    133         if (RT_SUCCESS(rc))
    134         {
    135             if (pDevExt->pSCReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
    136             {
    137                 PMOUSE_INPUT_DATA pData = InputDataStart;
    138                 while (pData<InputDataEnd)
    139                 {
    140                     pData->LastX = pDevExt->pSCReq->pointerXPos;
    141                     pData->LastY = pDevExt->pSCReq->pointerYPos;
    142                     pData->Flags = MOUSE_MOVE_ABSOLUTE;
    143                     pData++;
    144                 }
    145             }
    146         }
    147         else
    148         {
    149             WARN(("VbglGRPerform failed with rc=%#x", rc));
    150         }
    151     }
    152 
    153     /* Call original callback */
    154     pDevExt->OriginalConnectData.pfnServiceCB(pDevExt->OriginalConnectData.pDO,
    155                                               InputDataStart, InputDataEnd, InputDataConsumed);
     142    VBoxDrvNotifyServiceCB(pDevExt, InputDataStart, InputDataEnd, InputDataConsumed);
    156143
    157144    LOGF_LEAVE();
     
    219206        {
    220207            LOGF(("IRP_MN_REMOVE_DEVICE"));
     208
     209            IoReleaseRemoveLockAndWait(&pDevExt->RemoveLock, pDevExt);
     210
    221211            VBoxDeviceRemoved(pDevExt);
    222212
  • trunk/src/VBox/Additions/WINNT/Mouse/NT5/VBoxMFInternal.cpp

    r37163 r37221  
    1919#include "VBoxMF.h"
    2020#include <VBox/VBoxGuestLib.h>
     21#include <VBox/VBoxGuest.h>
     22#include <iprt/assert.h>
     23#include <iprt/asm.h>
     24
     25typedef struct VBOXGDC
     26{
     27    PDEVICE_OBJECT pDo;
     28    PFILE_OBJECT pFo;
     29} VBOXGDC, *PVBOXGDC;
    2130
    2231typedef struct _VBoxGlobalContext
     
    2736    volatile LONG fHostInformed;
    2837    volatile LONG fHostMouseFound;
     38    VBOXGDC Gdc;
     39    KSPIN_LOCK SyncLock;
     40    KEVENT TerminateEvent;
     41    KEVENT MouseEvent;
     42    PKTHREAD pThread;
     43    volatile PVBOXMOUSE_DEVEXT pCurrentDevExt;
     44    LIST_ENTRY DevExtList;
     45    MOUSE_INPUT_DATA LastReportedData;
    2946} VBoxGlobalContext;
    3047
    31 static VBoxGlobalContext g_ctx = {0, FALSE, FALSE, FALSE, FALSE};
     48static VBoxGlobalContext g_ctx = {};
     49
     50NTSTATUS VBoxGdcInit()
     51{
     52    UNICODE_STRING UniName;
     53    RtlInitUnicodeString(&UniName, VBOXGUEST_DEVICE_NAME_NT);
     54    NTSTATUS Status = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_ctx.Gdc.pFo, &g_ctx.Gdc.pDo);
     55    if (!NT_SUCCESS(Status))
     56    {
     57        WARN(("IoGetDeviceObjectPointer failed Status(0x%x)", Status));
     58        memset(&g_ctx.Gdc, 0, sizeof (g_ctx.Gdc));
     59    }
     60    return Status;
     61}
     62
     63BOOLEAN VBoxGdcIsInitialized()
     64{
     65    return !!g_ctx.Gdc.pDo;
     66}
     67
     68NTSTATUS VBoxGdcTerm()
     69{
     70    if (!g_ctx.Gdc.pFo)
     71        return STATUS_SUCCESS;
     72    /* this will dereference device object as well */
     73    ObDereferenceObject(g_ctx.Gdc.pFo);
     74    return STATUS_SUCCESS;
     75}
     76
     77static NTSTATUS vboxGdcSubmitAsync(ULONG uCtl, PVOID pvBuffer, SIZE_T cbBuffer, PKEVENT pEvent, PIO_STATUS_BLOCK pIoStatus)
     78{
     79    NTSTATUS Status;
     80    PIRP pIrp;
     81    KIRQL Irql = KeGetCurrentIrql();
     82    Assert(Irql == PASSIVE_LEVEL);
     83
     84    pIrp = IoBuildDeviceIoControlRequest(uCtl, g_ctx.Gdc.pDo, NULL, 0, NULL, 0, TRUE, pEvent, pIoStatus);
     85    if (!pIrp)
     86    {
     87        WARN(("IoBuildDeviceIoControlRequest failed!!\n"));
     88        pIoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
     89        pIoStatus->Information = 0;
     90        return STATUS_INSUFFICIENT_RESOURCES;
     91    }
     92
     93    PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp);
     94    pSl->Parameters.Others.Argument1 = (PVOID)pvBuffer;
     95    pSl->Parameters.Others.Argument2 = (PVOID)cbBuffer;
     96    Status = IoCallDriver(g_ctx.Gdc.pDo, pIrp);
     97
     98    return Status;
     99}
     100
     101static NTSTATUS vboxGdcSubmit(ULONG uCtl, PVOID pvBuffer, SIZE_T cbBuffer)
     102{
     103    IO_STATUS_BLOCK IoStatus = {0};
     104    KEVENT Event;
     105    NTSTATUS Status;
     106
     107    KeInitializeEvent(&Event, NotificationEvent, FALSE);
     108
     109    Status = vboxGdcSubmitAsync(uCtl, pvBuffer, cbBuffer, &Event, &IoStatus);
     110    if (Status == STATUS_PENDING)
     111    {
     112        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
     113        Status = IoStatus.Status;
     114    }
     115
     116    return Status;
     117}
     118
     119/* overwrites the previously set one, can be NULL to clear the event */
     120NTSTATUS VBoxGdcSetMouseNotifyEvent(PKEVENT pEvent)
     121{
     122    if (!VBoxGdcIsInitialized())
     123    {
     124        WARN(("Guest Device Communication not initialized"));
     125        return STATUS_UNSUCCESSFUL;
     126    }
     127
     128    NTSTATUS Status = vboxGdcSubmit(VBOXGUEST_IOCTL_INTERNAL_SET_MOUSE_NOTIFY_EVENT, pEvent, sizeof (pEvent));
     129    if (!NT_SUCCESS(Status))
     130    {
     131        WARN(("vboxGdcSubmit failed Status(0x%x)", Status));
     132    }
     133    return Status;
     134}
     135
     136/**
     137 * helper function used for system thread creation
     138 */
     139static NTSTATUS vboxCreateSystemThread(PKTHREAD *ppThread, PKSTART_ROUTINE pfnStartRoutine, PVOID pvStartContext)
     140{
     141    OBJECT_ATTRIBUTES ObjectAttributes;
     142    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
     143
     144    InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
     145
     146    HANDLE hThread;
     147    NTSTATUS Status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, (PKSTART_ROUTINE)pfnStartRoutine, pvStartContext);
     148    Assert(Status == STATUS_SUCCESS);
     149    if (Status == STATUS_SUCCESS)
     150    {
     151        Status = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)ppThread, NULL);
     152        Assert(Status == STATUS_SUCCESS);
     153        ZwClose(hThread);
     154        if (Status == STATUS_SUCCESS)
     155        {
     156            return STATUS_SUCCESS;
     157        }
     158
     159        /* @todo: how would we fail in this case ?*/
     160    }
     161    return Status;
     162}
     163
     164static VOID vboxMouseEventPollerThread(PVOID pvContext)
     165{
     166    PKEVENT apEvents[] = {&g_ctx.MouseEvent, &g_ctx.TerminateEvent};
     167    NTSTATUS Status;
     168    while (1)
     169    {
     170        Status = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), (PVOID*)apEvents,
     171                WaitAny, Executive, KernelMode, FALSE /* BOOLEAN  Alertable */,
     172                NULL /* PLARGE_INTEGER Timeout */,
     173                NULL /* PKWAIT_BLOCK WaitBlockArray */
     174                );
     175        Assert(NT_SUCCESS(Status));
     176
     177        if (Status != STATUS_WAIT_0)
     178        {
     179            /* terminate event */
     180            Assert(Status == STATUS_WAIT_1);
     181            break;
     182        }
     183
     184        ULONG InputDataConsumed = 0;
     185        PVBOXMOUSE_DEVEXT pDevExt = (PVBOXMOUSE_DEVEXT)ASMAtomicUoReadPtr((void * volatile *)&g_ctx.pCurrentDevExt);
     186        if (pDevExt)
     187        {
     188#define VBOXMOUSE_POLLERTAG 'PMBV'
     189            Status = IoAcquireRemoveLock(&pDevExt->RemoveLock, pDevExt);
     190            if (NT_SUCCESS(Status))
     191            {
     192                VBoxDrvNotifyServiceCB(pDevExt, &g_ctx.LastReportedData, &g_ctx.LastReportedData + 1, &InputDataConsumed);
     193                IoReleaseRemoveLock(&pDevExt->RemoveLock, pDevExt);
     194            }
     195            else
     196            {
     197                WARN(("IoAcquireRemoveLock failed, Status (0x%x)", Status));
     198            }
     199        }
     200        else
     201        {
     202            WARN(("no current pDevExt specified"));
     203        }
     204    }
     205
     206    PsTerminateSystemThread(STATUS_SUCCESS);
     207}
     208
     209static NTSTATUS vboxNewProtInit(PVBOXMOUSE_DEVEXT pCurrentDevExt)
     210{
     211    NTSTATUS Status = VBoxGdcInit();
     212    if (NT_SUCCESS(Status))
     213    {
     214        KeInitializeSpinLock(&g_ctx.SyncLock);
     215        KeInitializeEvent(&g_ctx.TerminateEvent, NotificationEvent, FALSE);
     216        KeInitializeEvent(&g_ctx.MouseEvent, SynchronizationEvent, FALSE);
     217
     218        Status = VBoxGdcSetMouseNotifyEvent(&g_ctx.MouseEvent);
     219        if (NT_SUCCESS(Status))
     220        {
     221            Status = vboxCreateSystemThread(&g_ctx.pThread, vboxMouseEventPollerThread, NULL);
     222            if (NT_SUCCESS(Status))
     223            {
     224                g_ctx.pCurrentDevExt = pCurrentDevExt;
     225                return STATUS_SUCCESS;
     226            }
     227            g_ctx.pThread = NULL;
     228            NTSTATUS tmpStatus = VBoxGdcSetMouseNotifyEvent(NULL);
     229            Assert(NT_SUCCESS(tmpStatus));
     230        }
     231    }
     232
     233    return Status;
     234}
     235
     236static BOOLEAN vboxNewProtIsSupported()
     237{
     238    return !!g_ctx.pThread;
     239}
     240
     241static NTSTATUS vboxNewProtTerm()
     242{
     243    KeSetEvent(&g_ctx.TerminateEvent, 0, FALSE);
     244    NTSTATUS Status = KeWaitForSingleObject(g_ctx.pThread, Executive, KernelMode, FALSE, NULL);
     245    if (!NT_SUCCESS(Status))
     246    {
     247        WARN(("KeWaitForSingleObject failed, Status (0x%x)", Status));
     248        return Status;
     249    }
     250
     251    Status = VBoxGdcSetMouseNotifyEvent(NULL);
     252    if (!NT_SUCCESS(Status))
     253    {
     254        WARN(("VBoxGdcSetMouseNotifyEvent failed, Status (0x%x)", Status));
     255        return Status;
     256    }
     257
     258    ObDereferenceObject(g_ctx.pThread);
     259    g_ctx.pThread = NULL;
     260
     261    return Status;
     262}
     263
     264static NTSTATUS vboxNewProtSetCurrentDevExt(PVBOXMOUSE_DEVEXT pCurrentDevExt)
     265{
     266    ASMAtomicWritePtrVoid((void * volatile *)&g_ctx.pCurrentDevExt, pCurrentDevExt);
     267    return STATUS_SUCCESS;
     268}
     269
     270VOID VBoxDrvNotifyServiceCB(PVBOXMOUSE_DEVEXT pDevExt, PMOUSE_INPUT_DATA InputDataStart, PMOUSE_INPUT_DATA InputDataEnd, PULONG  InputDataConsumed)
     271{
     272    KIRQL Irql;
     273    /* we need to avoid concurrency between the poller thread and our ServiceCB.
     274     * this is perhaps not the best way of doing things, but the most easiest to avoid concurrency
     275     * and to ensure the pfnServiceCB is invoked at DISPATCH_LEVEL */
     276    KeAcquireSpinLock(&g_ctx.SyncLock, &Irql);
     277    if (pDevExt->pSCReq)
     278    {
     279        int rc = VbglGRPerform(&pDevExt->pSCReq->header);
     280
     281        if (RT_SUCCESS(rc))
     282        {
     283            if (pDevExt->pSCReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
     284            {
     285                PMOUSE_INPUT_DATA pData = InputDataStart;
     286                while (pData<InputDataEnd)
     287                {
     288                    pData->LastX = pDevExt->pSCReq->pointerXPos;
     289                    pData->LastY = pDevExt->pSCReq->pointerYPos;
     290                    pData->Flags = MOUSE_MOVE_ABSOLUTE;
     291                    if (vboxNewProtIsSupported())
     292                        pData->Flags |= MOUSE_VIRTUAL_DESKTOP;
     293                    pData++;
     294                }
     295
     296                /* get the last data & cache it */
     297                --pData;
     298                g_ctx.LastReportedData.UnitId = pData->UnitId;
     299            }
     300        }
     301        else
     302        {
     303            WARN(("VbglGRPerform failed with rc=%#x", rc));
     304        }
     305    }
     306
     307    /* Call original callback */
     308    pDevExt->OriginalConnectData.pfnServiceCB(pDevExt->OriginalConnectData.pDO,
     309                                              InputDataStart, InputDataEnd, InputDataConsumed);
     310    KeReleaseSpinLock(&g_ctx.SyncLock, Irql);
     311}
    32312
    33313static BOOLEAN vboxIsVBGLInited(void)
     
    73353                WARN(("VBGL init failed with rc=%#x", rc));
    74354            }
     355
     356            vboxNewProtInit(pDevExt);
    75357        }
    76358    }
     
    172454        {
    173455            req->mouseFeatures = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
     456            if (vboxNewProtIsSupported())
     457                req->mouseFeatures |= VMMDEV_MOUSE_NEW_PROTOCOL;
     458
    174459            req->pointerXPos = 0;
    175460            req->pointerYPos = 0;
     
    260545    if (callCnt == 0)
    261546    {
     547        vboxNewProtTerm();
     548
    262549        if (vboxIsVBGLInited())
    263550        {
  • trunk/src/VBox/Additions/WINNT/Mouse/common/VBoxMouseLog.h

    r37163 r37221  
    1919#ifndef VBOXMOUSELOG_H
    2020#define VBOXMOUSELOG_H
     21
     22#ifdef DEBUG_misha
     23#include <iprt/assert.h>
     24#endif
    2125
    2226#define VBOX_MOUSE_LOG_NAME "VBoxMouse"
     
    4448    } while (0)
    4549
     50#ifdef DEBUG_misha
     51# define BREAK_WARN() AssertFailed()
     52#else
     53# define BREAK_WARN() do {} while(0)
     54#endif
     55
    4656#define WARN(_a)                                                                  \
    4757    do                                                                            \
     
    5060        Log(_a);                                                                  \
    5161        Log((VBOX_MOUSE_LOG_SUFFIX_FMT VBOX_MOUSE_LOG_SUFFIX_PARMS));             \
     62        BREAK_WARN(); \
    5263    } while (0)
    5364
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