IMG_VOID SYSDEVU_GetMemoryInfo(
	IMG_UINT32			ui32DeviceId,
	IMG_VOID **			ppvKmMemory,
	IMG_PHYSADDR *			ppaPhysMemory,
	IMG_UINT64 *		pui64MemSize,
	IMG_UINT64 *		pui64DevMemoryBase
) {

#ifndef __FAKE_HW__
	SYSDEVU_sInfo *dev = findDeviceById(ui32DeviceId);
	if(!gSysDevInitialised || !dev)
	{
		IMG_ASSERT(gSysDevInitialised);
		IMG_ASSERT(dev);
		return;
	}

	if(ppvKmMemory)
		*ppvKmMemory = dev->pui32KmMemBase;

	if(ppaPhysMemory)
		*ppaPhysMemory = dev->paPhysMemBase;

	if(pui64MemSize)
		*pui64MemSize = dev->ui32MemSize;

	if(pui64DevMemoryBase)
		*pui64DevMemoryBase = (IMG_UINT64)dev->pui64DevMemoryBase;
#endif
}
/*!
******************************************************************************

 @Function				SYSDEVU_InvokeDevKmLisr

******************************************************************************/
IMG_RESULT SYSDEVU_InvokeDevKmLisr(
	IMG_UINT32					ui32DeviceId
)
{
    IMG_UINT32  ui32Result;
	SYSDEVU_sInfo *dev = findDeviceById(ui32DeviceId);
	if(!gSysDevInitialised || !dev)
	{
		IMG_ASSERT(gSysDevInitialised);
		IMG_ASSERT(dev);

		ui32Result = IMG_ERROR_INVALID_PARAMETERS;
        return ui32Result;
	}

	IMG_ASSERT(dev->pfnDevKmLisr != IMG_NULL);
    if(dev->pfnDevKmLisr == IMG_NULL)
	{
		ui32Result = IMG_ERROR_INVALID_PARAMETERS;
        return ui32Result;
	}

	dev->pfnDevKmLisr(dev->pvParam);

    return IMG_SUCCESS;
}
int freespace_private_send(FreespaceDeviceId id,
                           const uint8_t* message,
                           int length) {
    int rc;
    int count;
    struct FreespaceDevice* device;
    device = findDeviceById(id);

    if (device == NULL || device->state_ != FREESPACE_OPENED) {
        return FREESPACE_ERROR_NOT_FOUND;
    }

    if (length > device->maxWriteSize_) {
        // Can't write more than the max allowed size, so fail rather than send a partial packet.
        return FREESPACE_ERROR_SEND_TOO_LARGE;
    }

    rc = libusb_interrupt_transfer(device->handle_, device->writeEndpointAddress_, (unsigned char*) message, length, &count, 0);
    if (rc != LIBUSB_SUCCESS) {
        return libusb_to_freespace_error(rc);
    }
    if (length != count) {
        // libusb should never fragment the message.
        return FREESPACE_ERROR_UNEXPECTED;
    }

    return FREESPACE_SUCCESS;
}
/*!
******************************************************************************

 @Function				SYSDEVU_RegisterDevKmLisr

******************************************************************************/
IMG_VOID SYSDEVU_RegisterDevKmLisr(
	IMG_UINT32					ui32DeviceId,
	SYSDEVKM_pfnDevKmLisr		pfnDevKmLisr,
    IMG_VOID *                  pvParam
)
{
	SYSDEVU_sInfo *dev = findDeviceById(ui32DeviceId);
	if(!gSysDevInitialised || !dev)
	{
		IMG_ASSERT(gSysDevInitialised);
		IMG_ASSERT(dev);
		return;
	}

	if (
			(pfnDevKmLisr != IMG_NULL) &&
			(dev->pfnDevKmLisr != IMG_NULL)
		)
	{
		IMG_ASSERT(dev->pfnDevKmLisr == pfnDevKmLisr);
		IMG_ASSERT(dev->pvParam == pvParam);
	}
	else
	{
		dev->pfnDevKmLisr = pfnDevKmLisr;
		dev->pvParam = pvParam;
	}
}
void freespace_closeDevice(FreespaceDeviceId id) {
    struct FreespaceDevice* device;
    device = findDeviceById(id);
    if (device != NULL && device->handle_ != NULL) {
        // Stop receives.
        freespace_terminateReceiveTransfers(device);

        // Should we wait until everything terminates cleanly?

        // Release our lock on the interface.
        libusb_release_interface(device->handle_, device->api_->controlInterfaceNumber_);

        // Re-attach the kernel driver if we detached it before.
        if (device->kernelDriverDetached_) {
            // This currently fails, and there doesn't seem to be anything that we
            // can do.
            libusb_attach_kernel_driver(device->handle_, device->api_->controlInterfaceNumber_);
        }
        libusb_close(device->handle_);
        device->handle_ = NULL;

        if (device->state_ == FREESPACE_DISCONNECTED) {
            removeFreespaceDevice(device);
        } else {
            device->state_ = FREESPACE_CONNECTED;
        }
    }
}
int freespace_getDeviceInfo(FreespaceDeviceId id,
                            struct FreespaceDeviceInfo* info) {
    struct FreespaceDevice* device = findDeviceById(id);

    if (device != NULL) {
        info->vendor = device->idVendor_;
        info->product = device->idProduct_;
        info->name = device->api_->name_;
        info->hVer = device->api_->hVer_;
        return FREESPACE_SUCCESS;
    } else {
        return FREESPACE_ERROR_NOT_FOUND;
    }
}
int freespace_setReceiveMessageCallback(FreespaceDeviceId id,
                                        freespace_receiveMessageCallback callback,
                                        void* cookie) {
    struct FreespaceDevice* device = findDeviceById(id);
    int wereInSyncMode;
    int rc;

    if (device == NULL) {
        return FREESPACE_ERROR_NOT_FOUND;
    }

    wereInSyncMode = (device->receiveMessageCallback_ == NULL && device->receiveCallback_ == NULL);
    device->receiveMessageCallback_ = callback;
    device->receiveMessageCookie_ = cookie;

    if (callback != NULL && wereInSyncMode && device->state_ == FREESPACE_OPENED) {
        struct freespace_message m;
        
        // Transition from sync mode to async mode.

        // Need to run the callback on all received messages.
        struct FreespaceReceiveTransfer* rt;
        rt = &device->receiveQueue_[device->receiveQueueHead_];
        while (rt->submitted_ == 0) {
            rc = freespace_decode_message((const uint8_t*) rt->buffer_, rt->transfer_->actual_length, &m, device->api_->hVer_);
            if (rc == FREESPACE_SUCCESS) {
                callback(device->id_,
                         &m,
                         cookie,
                         libusb_transfer_status_to_freespace_error(rt->transfer_->status));
            } else {
                callback(device->id_,
                         NULL,
                         cookie,
                         rc);
            }

            rt->submitted_ = 1;
            libusb_submit_transfer(rt->transfer_);
            device->receiveQueueHead_++;
            if (device->receiveQueueHead_ >= FREESPACE_RECEIVE_QUEUE_SIZE) {
                device->receiveQueueHead_ = 0;
            }

            rt = &device->receiveQueue_[device->receiveQueueHead_];
        }
    }
    return FREESPACE_SUCCESS;
}
IMG_VOID SYSDEVU_FreeDevice(
	IMG_UINT32					ui32DeviceId
)
{
	SYSDEVU_sInfo *dev = findDeviceById(ui32DeviceId);
	if(!gSysDevInitialised || !dev)
	{
		IMG_ASSERT(gSysDevInitialised);
		IMG_ASSERT(dev);
		return;
	}

	if (dev->ops->free_device)
		dev->ops->free_device(dev);
}
IMG_VOID SYSDEVU_HandleResume(
	IMG_UINT32					ui32DeviceId,
	IMG_BOOL					forAPM
) {
	SYSDEVU_sInfo *dev = findDeviceById(ui32DeviceId);
	if(!gSysDevInitialised || !dev)
	{
		IMG_ASSERT(gSysDevInitialised);
		IMG_ASSERT(dev);
		return;
	}

	if(dev->ops->resume_device)
		dev->ops->resume_device(dev, forAPM);
}
Exemple #10
0
/**
 * Request capture of a specific device.
 *
 * This is in an interface for SessionMachine::CaptureUSBDevice(), which is
 * an internal worker used by Console::AttachUSBDevice() from the VM process.
 *
 * When the request is completed, SessionMachine::onUSBDeviceAttach() will
 * be called for the given machine object.
 *
 *
 * @param   aMachine        The machine to attach the device to.
 * @param   aId             The UUID of the USB device to capture and attach.
 *
 * @returns COM status code and error info.
 *
 * @remarks This method may operate synchronously as well as asynchronously. In the
 *          former case it will temporarily abandon locks because of IPC.
 */
HRESULT USBProxyService::captureDeviceForVM(SessionMachine *aMachine, IN_GUID aId)
{
    ComAssertRet(aMachine, E_INVALIDARG);
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    /*
     * Translate the device id into a device object.
     */
    ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
    if (pHostDevice.isNull())
        return setError(E_INVALIDARG,
                        tr("The USB device with UUID {%RTuuid} is not currently attached to the host"), Guid(aId).raw());

    /*
     * Try to capture the device
     */
    alock.release();
    return pHostDevice->requestCaptureForVM(aMachine, true /* aSetError */);
}
Exemple #11
0
/**
 * Notification from VM process about USB device detaching progress.
 *
 * This is in an interface for SessionMachine::DetachUSBDevice(), which is
 * an internal worker used by Console::DetachUSBDevice() from the VM process.
 *
 * @param   aMachine        The machine which is sending the notification.
 * @param   aId             The UUID of the USB device is concerns.
 * @param   aDone           \a false for the pre-action notification (necessary
 *                          for advancing the device state to avoid confusing
 *                          the guest).
 *                          \a true for the post-action notification. The device
 *                          will be subjected to all filters except those of
 *                          of \a Machine.
 *
 * @returns COM status code.
 *
 * @remarks When \a aDone is \a true this method may end up doing IPC to other
 *          VMs when running filters. In these cases it will temporarily
 *          abandon its locks.
 */
HRESULT USBProxyService::detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone)
{
    LogFlowThisFunc(("aMachine=%p{%s} aId={%RTuuid} aDone=%RTbool\n",
                     aMachine,
                     aMachine->getName().c_str(),
                     Guid(aId).raw(),
                     aDone));

    // get a list of all running machines while we're outside the lock
    // (getOpenedMachines requests locks which are incompatible with the lock of the machines list)
    SessionMachinesList llOpenedMachines;
    mHost->parent()->getOpenedMachines(llOpenedMachines);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
    ComAssertRet(!pHostDevice.isNull(), E_FAIL);
    AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);

    /*
     * Work the state machine.
     */
    LogFlowThisFunc(("id={%RTuuid} state=%s aDone=%RTbool name={%s}\n",
                     pHostDevice->getId().raw(), pHostDevice->getStateName(), aDone, pHostDevice->getName().c_str()));
    bool fRunFilters = false;
    HRESULT hrc = pHostDevice->onDetachFromVM(aMachine, aDone, &fRunFilters);

    /*
     * Run filters if necessary.
     */
    if (    SUCCEEDED(hrc)
        &&  fRunFilters)
    {
        Assert(aDone && pHostDevice->getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->getMachine().isNull());
        devLock.release();
        alock.release();
        HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
        ComAssertComRC(hrc2);
    }
    return hrc;
}
Exemple #12
0
int freespace_flush(FreespaceDeviceId id) {
    struct FreespaceDevice* device = findDeviceById(id);
    struct FreespaceReceiveTransfer* rt;
    struct timeval tv;
    int repeat;
    int maxRepeats = FREESPACE_RECEIVE_QUEUE_SIZE * 2;

    if (device == NULL || device->state_ != FREESPACE_OPENED) {
        return FREESPACE_ERROR_NOT_FOUND;
    }


    // As long as there's work, try again.
    do {
        // Poll libusb to give it a chance to unload as many
        // events as possible.
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        libusb_handle_events_timeout(freespace_libusb_context, &tv);

        repeat = 0;

        // Clear out our queue.
        rt = &device->receiveQueue_[device->receiveQueueHead_];
        while (rt->submitted_ == 0) {
            rt->submitted_ = 1;
            libusb_submit_transfer(rt->transfer_);
            device->receiveQueueHead_++;
            if (device->receiveQueueHead_ >= FREESPACE_RECEIVE_QUEUE_SIZE) {
                device->receiveQueueHead_ = 0;
            }

            rt = &device->receiveQueue_[device->receiveQueueHead_];
            repeat = 1;
        }

        maxRepeats--;
    } while (repeat > 0 && maxRepeats > 0);

    return FREESPACE_SUCCESS;
}
/*!
******************************************************************************

 @Function				SYSDEVU_GetCpuAddrs

******************************************************************************/
IMG_UINT32 SYSDEVU_GetCpuAddrs(
	IMG_UINT32				ui32DeviceId,
	SYSDEVKM_eRegionId		eRegionId,
	IMG_VOID **             ppvCpuKmAddr,
	IMG_PHYSADDR *          ppaCpuPhysAddr,
	IMG_UINT32 *            pui32Size
)
{
	SYSDEVU_sInfo *dev = findDeviceById(ui32DeviceId);
    if(!gSysDevInitialised || !dev)
    {
        IMG_ASSERT(gSysDevInitialised);
        return IMG_ERROR_DEVICE_NOT_FOUND;
    }

#ifdef __FAKE_HW__
    /* provide fake kernel mode addresses for fake hardware */
    gpsInfo[ui32DeviceId]->pui32KmRegBase = (void*)0x1000;
    gpsInfo[ui32DeviceId]->ui32RegSize = 0x1000;
#endif
	switch (eRegionId)
	{
	case SYSDEVKM_REGID_REGISTERS:
	  if(ppvCpuKmAddr)
			*ppvCpuKmAddr = dev->pui32KmRegBase;
	  if(ppaCpuPhysAddr)
			*ppaCpuPhysAddr = dev->paPhysRegBase;
	  if(pui32Size)
			*pui32Size = dev->ui32RegSize;
	  return IMG_SUCCESS;
	  break;
	  
	case SYSDEVKM_REGID_SLAVE_PORT:
	default:
		IMG_ASSERT(IMG_FALSE);
		break;
	}
    
	return IMG_ERROR_GENERIC_FAILURE;
}
SYSDEVU_sInfo *SYSDEVU_GetDeviceById(
	IMG_UINT32 ui32DeviceId
)
{
	return findDeviceById(ui32DeviceId);
}
Exemple #15
0
int freespace_private_sendAsync(FreespaceDeviceId id,
                                const uint8_t* message,
                                int length,
                                unsigned int timeoutMs,
                                freespace_sendCallback callback,
                                void* cookie) {
#ifdef __APPLE__
    // @TODO: Figure out why libusb on darwin doesn't seem to work with asynchronous messages
    int rc;

    rc = freespace_private_send(id, message, length);
    if (callback != NULL) {
        callback(id, cookie, rc);
    }

    return libusb_to_freespace_error(rc);
#else
    struct FreespaceDevice* device;
    device = findDeviceById(id);
    struct libusb_transfer* transfer;
    int rc;

    if (device == NULL || device->state_ != FREESPACE_OPENED) {
        return FREESPACE_ERROR_NOT_FOUND;
    }

    if (length > device->maxWriteSize_) {
        return FREESPACE_ERROR_SEND_TOO_LARGE;
    }

    transfer = libusb_alloc_transfer(0);
    if (transfer == NULL) {
        return FREESPACE_ERROR_OUT_OF_MEMORY;
    }

    transfer->dev_handle = device->handle_;
    transfer->endpoint = device->writeEndpointAddress_;
    transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
    transfer->timeout = timeoutMs;
    transfer->buffer = (unsigned char*) message;
    transfer->length = length;
    transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER;

    if (callback != NULL) {
        struct SendTransferInfo* info = (struct SendTransferInfo*) malloc(sizeof(struct SendTransferInfo));
    	if (info == NULL) {
    	    libusb_free_transfer(transfer);
            return FREESPACE_ERROR_OUT_OF_MEMORY;
    	}
    	info->id = id;
        info->callback = callback;
        info->cookie = cookie;
    	transfer->callback = sendCallback;
    	transfer->user_data = info;
    } else {
    	transfer->callback = NULL;
    	transfer->user_data = NULL;
    }

    rc = libusb_submit_transfer(transfer);

    return libusb_to_freespace_error(rc);
#endif
}
Exemple #16
0
int freespace_private_read(FreespaceDeviceId id,
                           uint8_t* message,
                           int maxLength,
                           unsigned int timeoutMs,
                           int* actualLength) {
    struct FreespaceDevice* device = findDeviceById(id);
    struct FreespaceReceiveTransfer* rt;
    int rc;

    if (device == NULL || device->state_ != FREESPACE_OPENED) {
        return FREESPACE_ERROR_NOT_FOUND;
    }

    if (maxLength < device->maxReadSize_) {
        // Don't risk causing an overflow due to too small
        // a receive buffer.
        return FREESPACE_ERROR_RECEIVE_BUFFER_TOO_SMALL;
    }

    rt = &device->receiveQueue_[device->receiveQueueHead_];

    // Check if we need to wait.
    if (rt->submitted_ != 0) {
        struct timeval tv;

        tv.tv_sec = timeoutMs / 1000;
        tv.tv_usec = (timeoutMs % 1000) * 1000;

        // Wait.
        do {
            rc = libusb_handle_events_timeout(freespace_libusb_context, &tv);
            if (rc != LIBUSB_SUCCESS) {
                return libusb_to_freespace_error(rc);
            }

            // Keep trying until something has been received.
            // Note that libusb_handle_events_timeout could return
            // without a receive if it ends up doing some other
            // processing such as an async send completion or
            // something on another device.

            // TODO: update tv with time left.
            timeoutMs = 0;
        } while (rt->submitted_ != 0 && timeoutMs > 0);

        if (rt->submitted_ != 0) {
            return LIBUSB_ERROR_TIMEOUT;
        }
    }

    // Copy the message out.
    *actualLength = rt->transfer_->actual_length;
    memcpy(message, rt->buffer_, *actualLength);
    rc = libusb_transfer_status_to_freespace_error(rt->transfer_->status);

    // Resubmit the transfer
    rt->submitted_ = 1;
    libusb_submit_transfer(rt->transfer_);
    device->receiveQueueHead_++;
    if (device->receiveQueueHead_ >= FREESPACE_RECEIVE_QUEUE_SIZE) {
        device->receiveQueueHead_ = 0;
    }

    return rc;
}
Exemple #17
0
static int scanDevices() {
    struct libusb_device** devs;
    ssize_t count;
    ssize_t i;
    int rc;
    int needToRescan;

    // Check if the devices need to be rescanned.
    rc = freespace_hotplug_perform(&needToRescan);
    if (rc != FREESPACE_SUCCESS || !needToRescan) {
        return rc;
    }

    count = libusb_get_device_list(freespace_libusb_context, &devs);
    if (count < 0) {
        return libusb_to_freespace_error(count);
    }

    ts++;
    for (i = 0; i < count; i++) {
        struct libusb_device_descriptor desc;
        struct libusb_device* dev = devs[i];
        struct FreespaceDeviceAPI const * api;

        rc = libusb_get_device_descriptor(dev, &desc);
        if (rc < 0) {
            // Can't get the device descriptor, so try the next one.
            continue;
        }

        // Find if this device is in the known list.
        api = lookupDevice(&desc);
        if (api != NULL) {
            uint8_t deviceAddress = libusb_get_device_address(dev);
            struct FreespaceDevice* device;
            device = findDeviceById(deviceAddress);
            if (device == NULL) {
                device = (struct FreespaceDevice*) malloc(sizeof(struct FreespaceDevice));
                if (device == NULL) {
                    // Out of memory.
                    libusb_free_device_list(devs, 1);
                    return FREESPACE_ERROR_OUT_OF_MEMORY;
                }
                memset(device, 0, sizeof(struct FreespaceDevice));

                libusb_ref_device(dev);
                device->dev_ = dev;
                device->idProduct_ = desc.idProduct;
                device->idVendor_ = desc.idVendor;
                device->api_ = api;
                device->id_ = libusb_get_device_address(dev);
                device->state_ = FREESPACE_CONNECTED;
                device->ts_ = ts;
                addFreespaceDevice(device);
                if (hotplugCallback) {
                    hotplugCallback(FREESPACE_HOTPLUG_INSERTION, device->id_, hotplugCookie);
                }
            }
            device->ts_ = ts;
        }
    }

    for (i = 0; i < FREESPACE_MAXIMUM_DEVICE_COUNT; i++) {
        struct FreespaceDevice* d = devices[i];
        if (d != NULL && d->ts_ != ts) {
            if (hotplugCallback) {
                hotplugCallback(FREESPACE_HOTPLUG_REMOVAL, d->id_, hotplugCookie);
            }
            if (d->state_ == FREESPACE_OPENED) {
                d->state_ = FREESPACE_DISCONNECTED;
            } else {
                removeFreespaceDevice(d);
            }
        }
    }

    libusb_free_device_list(devs, 1);
    return FREESPACE_SUCCESS;
}
Exemple #18
0
int freespace_openDevice(FreespaceDeviceId id) {
    struct FreespaceDevice* device = findDeviceById(id);
    struct libusb_config_descriptor *config;
    const struct libusb_interface_descriptor* intd;
    int controlInterfaceNumber;
    int i;
    int rc;

    if (device == NULL) {
        return FREESPACE_ERROR_NOT_FOUND;
    }

    rc = libusb_open(device->dev_, &device->handle_);
    if (rc != LIBUSB_SUCCESS) {
        return libusb_to_freespace_error(rc);
    }

    controlInterfaceNumber = device->api_->controlInterfaceNumber_;
    rc = libusb_kernel_driver_active(device->handle_, controlInterfaceNumber);
    if (rc == 1) {
    	// Kernel driver attached.  Disconnect it.
    	rc = libusb_detach_kernel_driver(device->handle_, controlInterfaceNumber);
    	if (rc == LIBUSB_SUCCESS) {
            device->kernelDriverDetached_ = 1;
    	}
    }

    rc = libusb_claim_interface(device->handle_, controlInterfaceNumber);
    if (rc != LIBUSB_SUCCESS) {
        return libusb_to_freespace_error(rc);
    }

    rc = libusb_get_active_config_descriptor(device->dev_, &config);
    if (rc != LIBUSB_SUCCESS) {
        return libusb_to_freespace_error(rc);
    }

    intd = config->interface[controlInterfaceNumber].altsetting;

    for (i = 0; i < intd[0].bNumEndpoints; ++i) {
        const struct libusb_endpoint_descriptor* endpoint = &intd[0].endpoint[i];

        if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
            device->readEndpointAddress_ = endpoint->bEndpointAddress;
            device->maxReadSize_ = endpoint->wMaxPacketSize;
        } else {
            device->writeEndpointAddress_ = endpoint->bEndpointAddress;
            device->maxWriteSize_ = endpoint->wMaxPacketSize;
        }
    }
    if (device->maxReadSize_ == 0 || device->maxWriteSize_ == 0) {
        // Weird.  The device didn't have a read and write endpoint.
        return FREESPACE_ERROR_UNEXPECTED;
    }

    device->state_ = FREESPACE_OPENED;

    // Start the receive queue working.
    rc = freespace_initiateReceiveTransfers(device);
    return rc;
}