| 1748 | | |
|---|
| 1749 | | /** |
|---|
| 1750 | | * Applies all (golbal and VM) filters to the given USB device. The device |
|---|
| 1751 | | * must be either a newly attached device or a device released by a VM. |
|---|
| 1752 | | * |
|---|
| 1753 | | * This method will request the USB proxy service to release the device (give |
|---|
| 1754 | | * it back to the host) if none of the global or VM filters want to capture |
|---|
| 1755 | | * the device. |
|---|
| 1756 | | * |
|---|
| 1757 | | * @param aDevice USB device to apply filters to. |
|---|
| 1758 | | * @param aMachine Machine the device was released by or @c NULL. |
|---|
| 1759 | | * |
|---|
| 1760 | | * @note the method must be called from under this object's write lock and |
|---|
| 1761 | | * from the aDevice's write lock. |
|---|
| 1762 | | */ |
|---|
| 1763 | | HRESULT Host::applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice, |
|---|
| 1764 | | SessionMachine *aMachine /* = NULL */) |
|---|
| 1765 | | { |
|---|
| 1766 | | LogFlowThisFunc(("{%s}\n", aDevice->name().raw())); |
|---|
| 1767 | | |
|---|
| 1768 | | /* |
|---|
| 1769 | | * Verify preconditions. |
|---|
| 1770 | | */ |
|---|
| 1771 | | /// @todo must check for read lock, it's enough here |
|---|
| 1772 | | AssertReturn(isWriteLockOnCurrentThread(), E_FAIL); |
|---|
| 1773 | | AssertReturn(aDevice->isWriteLockOnCurrentThread(), E_FAIL); |
|---|
| 1774 | | /* Quietly ignore unsupported and unavailable device. */ |
|---|
| 1775 | | if ( aDevice->unistate() == kHostUSBDeviceState_UsedByHost |
|---|
| 1776 | | || aDevice->unistate() == kHostUSBDeviceState_Unsupported) /** @todo !aDevice->isCapturable() or something */ |
|---|
| 1777 | | { |
|---|
| 1778 | | LogFlowThisFunc(("{%s} %s - quietly ignored\n", aDevice->name().raw(), aDevice->stateName())); |
|---|
| 1779 | | return S_OK; |
|---|
| 1780 | | } |
|---|
| 1781 | | |
|---|
| 1782 | | VirtualBox::SessionMachineVector machines; |
|---|
| 1783 | | mParent->getOpenedMachines (machines); |
|---|
| 1784 | | |
|---|
| 1785 | | /// @todo it may be better to take a copy of filters to iterate and leave |
|---|
| 1786 | | /// the host lock before calling HostUSBDevice:requestCaptureForVM() (which |
|---|
| 1787 | | /// may call the VM process). |
|---|
| 1788 | | /// Moving this matching into USBProxyService at the same time would be |
|---|
| 1789 | | /// nice too, that'll simplify the locking a bit more. |
|---|
| 1790 | | |
|---|
| 1791 | | /* apply global filters */ |
|---|
| 1792 | | USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin(); |
|---|
| 1793 | | for (; it != mUSBDeviceFilters.end(); ++ it) |
|---|
| 1794 | | { |
|---|
| 1795 | | AutoWriteLock filterLock (*it); |
|---|
| 1796 | | const HostUSBDeviceFilter::Data &data = (*it)->data(); |
|---|
| 1797 | | if (aDevice->isMatch (data)) |
|---|
| 1798 | | { |
|---|
| 1799 | | USBDeviceFilterAction_T action = USBDeviceFilterAction_Null; |
|---|
| 1800 | | (*it)->COMGETTER (Action) (&action); |
|---|
| 1801 | | if (action == USBDeviceFilterAction_Ignore) |
|---|
| 1802 | | { |
|---|
| 1803 | | /* request to give the device back to the host */ |
|---|
| 1804 | | aDevice->requestReleaseToHost(); |
|---|
| 1805 | | /* nothing to do any more */ |
|---|
| 1806 | | return S_OK; |
|---|
| 1807 | | } |
|---|
| 1808 | | if (action == USBDeviceFilterAction_Hold) |
|---|
| 1809 | | break; |
|---|
| 1810 | | } |
|---|
| 1811 | | } |
|---|
| 1812 | | |
|---|
| 1813 | | /* apply machine filters */ |
|---|
| 1814 | | size_t i = 0; |
|---|
| 1815 | | for (; i < machines.size(); ++ i) |
|---|
| 1816 | | { |
|---|
| 1817 | | /* skip the machine the device was just detached from */ |
|---|
| 1818 | | if (aMachine && machines [i] == aMachine) |
|---|
| 1819 | | continue; |
|---|
| 1820 | | |
|---|
| 1821 | | if (applyMachineUSBFilters (machines [i], aDevice)) |
|---|
| 1822 | | break; |
|---|
| 1823 | | } |
|---|
| 1824 | | |
|---|
| 1825 | | if (i == machines.size()) |
|---|
| 1826 | | { |
|---|
| 1827 | | /* no matched machine filters, check what to do */ |
|---|
| 1828 | | if (it == mUSBDeviceFilters.end()) |
|---|
| 1829 | | { |
|---|
| 1830 | | /* no any filter matched at all */ |
|---|
| 1831 | | /* request to give the device back to the host */ |
|---|
| 1832 | | aDevice->requestReleaseToHost(); |
|---|
| 1833 | | } |
|---|
| 1834 | | else |
|---|
| 1835 | | { |
|---|
| 1836 | | /* there was a global Hold filter */ |
|---|
| 1837 | | aDevice->requestHold(); |
|---|
| 1838 | | } |
|---|
| 1839 | | } |
|---|
| 1840 | | |
|---|
| 1841 | | return S_OK; |
|---|
| 1842 | | } |
|---|
| 1843 | | |
|---|
| 1844 | | /** |
|---|
| 1845 | | * Runs through filters of the given machine and asks the USB proxy service |
|---|
| 1846 | | * to capture the given USB device when there is a match. |
|---|
| 1847 | | * |
|---|
| 1848 | | * @param aMachine Machine whose filters are to be run. |
|---|
| 1849 | | * @param aDevice USB device, a candidate for auto-capturing. |
|---|
| 1850 | | * @return @c true if there was a match and @c false otherwise. |
|---|
| 1851 | | * |
|---|
| 1852 | | * @note the method must be called from under this object's write lock and |
|---|
| 1853 | | * from the aDevice's write lock. |
|---|
| 1854 | | * |
|---|
| 1855 | | * @note Locks aMachine for reading. |
|---|
| 1856 | | */ |
|---|
| 1857 | | bool Host::applyMachineUSBFilters (SessionMachine *aMachine, |
|---|
| 1858 | | ComObjPtr <HostUSBDevice> &aDevice) |
|---|
| 1859 | | { |
|---|
| 1860 | | LogFlowThisFunc(("{%s}\n", aDevice->name().raw())); |
|---|
| 1861 | | |
|---|
| 1862 | | /* |
|---|
| 1863 | | * Validate preconditions. |
|---|
| 1864 | | */ |
|---|
| 1865 | | AssertReturn(aMachine, false); |
|---|
| 1866 | | /// @todo must check for read lock, it's enough here |
|---|
| 1867 | | AssertReturn(isWriteLockOnCurrentThread(), false); |
|---|
| 1868 | | AssertReturn(aDevice->isWriteLockOnCurrentThread(), false); |
|---|
| 1869 | | /* Let HostUSBDevice::requestCaptureToVM() validate the state. */ |
|---|
| 1870 | | |
|---|
| 1871 | | ULONG maskedIfs; |
|---|
| 1872 | | bool hasMatch = aMachine->hasMatchingUSBFilter (aDevice, &maskedIfs); |
|---|
| 1873 | | if (hasMatch) |
|---|
| 1874 | | { |
|---|
| 1875 | | /** @todo r=bird: this is wrong as requestAttachToVM may return false for different reasons that we. */ |
|---|
| 1876 | | /* try to capture the device */ |
|---|
| 1877 | | HRESULT hrc = aDevice->requestCaptureForVM (aMachine, false /* aSetError */, maskedIfs); |
|---|
| 1878 | | return SUCCEEDED (hrc); |
|---|
| 1879 | | } |
|---|
| 1880 | | |
|---|
| 1881 | | return hasMatch; |
|---|
| 1882 | | } |
|---|
| 1883 | | |
|---|
| 1884 | | /** |
|---|
| 1885 | | * Called by USB proxy service when a new device is physically attached |
|---|
| 1886 | | * to the host. |
|---|
| 1887 | | * |
|---|
| 1888 | | * @param aDevice Pointer to the device which has been attached. |
|---|
| 1889 | | */ |
|---|
| 1890 | | void Host::onUSBDeviceAttached (HostUSBDevice *aDevice) |
|---|
| 1891 | | { |
|---|
| 1892 | | /* |
|---|
| 1893 | | * Validate precoditions. |
|---|
| 1894 | | */ |
|---|
| 1895 | | AssertReturnVoid(aDevice); |
|---|
| 1896 | | AssertReturnVoid(isWriteLockOnCurrentThread()); |
|---|
| 1897 | | AssertReturnVoid(aDevice->isWriteLockOnCurrentThread()); |
|---|
| 1898 | | LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n", |
|---|
| 1899 | | aDevice, aDevice->name().raw(), aDevice->stateName(), aDevice->id().raw())); |
|---|
| 1900 | | |
|---|
| 1901 | | /* apply all filters */ |
|---|
| 1902 | | ComObjPtr <HostUSBDevice> device (aDevice); |
|---|
| 1903 | | HRESULT rc = applyAllUSBFilters (device); |
|---|
| 1904 | | AssertComRC (rc); |
|---|
| 1905 | | } |
|---|
| 1906 | | |
|---|
| 1907 | | /** |
|---|
| 1908 | | * Called by USB proxy service when the device is physically detached |
|---|
| 1909 | | * from the host. |
|---|
| 1910 | | * |
|---|
| 1911 | | * @param aDevice Pointer to the device which has been detached. |
|---|
| 1912 | | */ |
|---|
| 1913 | | void Host::onUSBDeviceDetached (HostUSBDevice *aDevice) |
|---|
| 1914 | | { |
|---|
| 1915 | | /* |
|---|
| 1916 | | * Validate preconditions. |
|---|
| 1917 | | */ |
|---|
| 1918 | | AssertReturnVoid(aDevice); |
|---|
| 1919 | | AssertReturnVoid(isWriteLockOnCurrentThread()); |
|---|
| 1920 | | AssertReturnVoid(aDevice->isWriteLockOnCurrentThread()); |
|---|
| 1921 | | LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n", |
|---|
| 1922 | | aDevice, aDevice->name().raw(), aDevice->stateName(), aDevice->id().raw())); |
|---|
| 1923 | | |
|---|
| 1924 | | /* |
|---|
| 1925 | | * Detach the device from any machine currently using it, |
|---|
| 1926 | | * reset all data and uninitialize the device object. |
|---|
| 1927 | | */ |
|---|
| 1928 | | aDevice->onPhysicalDetached(); |
|---|
| 1929 | | } |
|---|
| 1930 | | |
|---|
| 1931 | | /** |
|---|
| 1932 | | * Called by USB proxy service when the state of the device has changed |
|---|
| 1933 | | * either because of the state change request or because of some external |
|---|
| 1934 | | * interaction. |
|---|
| 1935 | | * |
|---|
| 1936 | | * @param aDevice The device in question. |
|---|
| 1937 | | * @param aRunFilters Whether to run filters. |
|---|
| 1938 | | * @param aIgnoreMachine The machine to ignore when running filters. |
|---|
| 1939 | | */ |
|---|
| 1940 | | void Host::onUSBDeviceStateChanged (HostUSBDevice *aDevice, bool aRunFilters, SessionMachine *aIgnoreMachine) |
|---|
| 1941 | | { |
|---|
| 1942 | | /* |
|---|
| 1943 | | * Validate preconditions. |
|---|
| 1944 | | */ |
|---|
| 1945 | | LogFlowThisFunc(("aDevice=%p\n", aDevice)); |
|---|
| 1946 | | AssertReturnVoid(aDevice); |
|---|
| 1947 | | AssertReturnVoid(isWriteLockOnCurrentThread()); |
|---|
| 1948 | | AssertReturnVoid(aDevice->isWriteLockOnCurrentThread()); |
|---|
| 1949 | | LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n", |
|---|
| 1950 | | aDevice, aDevice->name().raw(), aDevice->stateName(), aDevice->id().raw())); |
|---|
| 1951 | | |
|---|
| 1952 | | /* |
|---|
| 1953 | | * Run filters if requested to do so. |
|---|
| 1954 | | */ |
|---|
| 1955 | | if (aRunFilters) |
|---|
| 1956 | | { |
|---|
| 1957 | | ComObjPtr<HostUSBDevice> device(aDevice); |
|---|
| 1958 | | HRESULT rc = applyAllUSBFilters(device, aIgnoreMachine); |
|---|
| 1959 | | AssertComRC(rc); |
|---|
| 1960 | | } |
|---|
| 1961 | | } |
|---|
| 1962 | | #endif /* VBOX_WITH_USB */ |
|---|
| 1963 | | |
|---|