/* $Id: USBProxyServiceOs2.cpp 41528 2012-05-31 16:48:33Z vboxsync $ */ /** @file * VirtualBox USB Proxy Service, OS/2 Specialization. */ /* * Copyright (C) 2005-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) 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 * *******************************************************************************/ #define INCL_BASE #define INCL_ERRORS #include "USBProxyService.h" #include "Logging.h" #include #include #include #include #include #include #include /** * Initialize data members. */ USBProxyServiceOs2::USBProxyServiceOs2(Host *aHost) : USBProxyService(aHost), mhev(NULLHANDLE), mhmod(NULLHANDLE), mpfnUsbRegisterChangeNotification(NULL), mpfnUsbDeregisterNotification(NULL), mpfnUsbQueryNumberDevices(NULL), mpfnUsbQueryDeviceReport(NULL) { LogFlowThisFunc(("aHost=%p\n", aHost)); /* * Try initialize the usbcalls stuff. */ int rc = DosCreateEventSem(NULL, &mhev, 0, FALSE); rc = RTErrConvertFromOS2(rc); if (RT_SUCCESS(rc)) { rc = DosLoadModule(NULL, 0, (PCSZ)"usbcalls", &mhmod); rc = RTErrConvertFromOS2(rc); if (RT_SUCCESS(rc)) { if ( (rc = DosQueryProcAddr(mhmod, 0, (PCSZ)"UsbQueryNumberDevices", (PPFN)&mpfnUsbQueryNumberDevices)) == NO_ERROR && (rc = DosQueryProcAddr(mhmod, 0, (PCSZ)"UsbQueryDeviceReport", (PPFN)&mpfnUsbQueryDeviceReport)) == NO_ERROR && (rc = DosQueryProcAddr(mhmod, 0, (PCSZ)"UsbRegisterChangeNotification", (PPFN)&mpfnUsbRegisterChangeNotification)) == NO_ERROR && (rc = DosQueryProcAddr(mhmod, 0, (PCSZ)"UsbDeregisterNotification", (PPFN)&mpfnUsbDeregisterNotification)) == NO_ERROR ) { rc = mpfnUsbRegisterChangeNotification(&mNotifyId, mhev, mhev); if (!rc) { /* * Start the poller thread. */ rc = start(); if (RT_SUCCESS(rc)) { LogFlowThisFunc(("returns successfully - mNotifyId=%d\n", mNotifyId)); mLastError = VINF_SUCCESS; return; } } LogRel(("USBProxyServiceOs2: failed to register change notification, rc=%d\n", rc)); } else LogRel(("USBProxyServiceOs2: failed to load usbcalls\n")); DosFreeModule(mhmod); } else LogRel(("USBProxyServiceOs2: failed to load usbcalls, rc=%d\n", rc)); mhmod = NULLHANDLE; } else mhev = NULLHANDLE; mLastError = rc; LogFlowThisFunc(("returns failure!!! (rc=%Rrc)\n", rc)); } /** * Stop all service threads and free the device chain. */ USBProxyServiceOs2::~USBProxyServiceOs2() { LogFlowThisFunc(("\n")); /* * Stop the service. */ if (isActive()) stop(); /* * Free resources. */ if (mhmod) { if (mpfnUsbDeregisterNotification) mpfnUsbDeregisterNotification(mNotifyId); mpfnUsbRegisterChangeNotification = NULL; mpfnUsbDeregisterNotification = NULL; mpfnUsbQueryNumberDevices = NULL; mpfnUsbQueryDeviceReport = NULL; DosFreeModule(mhmod); mhmod = NULLHANDLE; } } int USBProxyServiceOs2::captureDevice(HostUSBDevice *aDevice) { AssertReturn(aDevice, VERR_GENERAL_FAILURE); AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str())); /* * Don't think we need to do anything when the device is held... fake it. */ Assert(aDevice->isStatePending()); devLock.release(); interruptWait(); return VINF_SUCCESS; } int USBProxyServiceOs2::releaseDevice(HostUSBDevice *aDevice) { AssertReturn(aDevice, VERR_GENERAL_FAILURE); AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str())); /* * We're not really holding it atm., just fake it. */ Assert(aDevice->isStatePending()); devLock.release(); interruptWait(); return VINF_SUCCESS; } bool USBProxyServiceOs2::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine) { AssertReturn(aDevice, false); AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false); return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine); } int USBProxyServiceOs2::wait(RTMSINTERVAL aMillies) { int rc = DosWaitEventSem(mhev, aMillies); return RTErrConvertFromOS2(rc); } int USBProxyServiceOs2::interruptWait(void) { int rc = DosPostEventSem(mhev); return rc == NO_ERROR || rc == ERROR_ALREADY_POSTED ? VINF_SUCCESS : RTErrConvertFromOS2(rc); } #include PUSBDEVICE USBProxyServiceOs2::getDevices(void) { /* * Count the devices. */ ULONG cDevices = 0; int rc = mpfnUsbQueryNumberDevices((PULONG)&cDevices); /* Thanks to com/xpcom, PULONG and ULONG * aren't the same. */ if (rc) return NULL; /* * Retrieve information about each device. */ PUSBDEVICE pFirst = NULL; PUSBDEVICE *ppNext = &pFirst; for (ULONG i = 0; i < cDevices; i++) { /* * Query the device and config descriptors. */ uint8_t abBuf[1024]; ULONG cb = sizeof(abBuf); rc = mpfnUsbQueryDeviceReport(i + 1, (PULONG)&cb, &abBuf[0]); /* see above (PULONG) */ if (rc) continue; PUSBDEVICEDESC pDevDesc = (PUSBDEVICEDESC)&abBuf[0]; if ( cb < sizeof(*pDevDesc) || pDevDesc->bDescriptorType != USB_DT_DEVICE || pDevDesc->bLength < sizeof(*pDevDesc) || pDevDesc->bLength > sizeof(*pDevDesc) * 2) continue; PUSBCONFIGDESC pCfgDesc = (PUSBCONFIGDESC)&abBuf[pDevDesc->bLength]; if ( pCfgDesc->bDescriptorType != USB_DT_CONFIG || pCfgDesc->bLength >= sizeof(*pCfgDesc)) pCfgDesc = NULL; /* * Skip it if it's some kind of hub. */ if (pDevDesc->bDeviceClass == USB_HUB_CLASSCODE) continue; /* * Allocate a new device node and initialize it with the basic stuff. */ PUSBDEVICE pCur = (PUSBDEVICE)RTMemAlloc(sizeof(*pCur)); pCur->bcdUSB = pDevDesc->bcdUSB; pCur->bDeviceClass = pDevDesc->bDeviceClass; pCur->bDeviceSubClass = pDevDesc->bDeviceSubClass; pCur->bDeviceProtocol = pDevDesc->bDeviceProtocol; pCur->idVendor = pDevDesc->idVendor; pCur->idProduct = pDevDesc->idProduct; pCur->bcdDevice = pDevDesc->bcdDevice; pCur->pszManufacturer = RTStrDup(""); pCur->pszProduct = RTStrDup(""); pCur->pszSerialNumber = NULL; pCur->u64SerialHash = 0; //pCur->bNumConfigurations = pDevDesc->bNumConfigurations; pCur->bNumConfigurations = 0; pCur->paConfigurations = NULL; pCur->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE; pCur->enmSpeed = USBDEVICESPEED_UNKNOWN; pCur->pszAddress = NULL; RTStrAPrintf((char **)&pCur->pszAddress, "p=0x%04RX16;v=0x%04RX16;r=0x%04RX16;e=0x%08RX32", pDevDesc->idProduct, pDevDesc->idVendor, pDevDesc->bcdDevice, i); pCur->bBus = 0; pCur->bLevel = 0; pCur->bDevNum = 0; pCur->bDevNumParent = 0; pCur->bPort = 0; pCur->bNumDevices = 0; pCur->bMaxChildren = 0; /* link it */ pCur->pNext = NULL; pCur->pPrev = *ppNext; *ppNext = pCur; ppNext = &pCur->pNext; } return pFirst; }