Changeset 49904 in vbox
- Timestamp:
- Dec 14, 2013 6:36:13 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/DarwinKeyboard.cpp
r49850 r49904 41 41 # include <VBox/sup.h> 42 42 # include <IOKit/IOMessage.h> 43 # include <IOKit/usb/IOUSBLib.h> 44 # include <IOKit/IOMessage.h> 43 45 #endif 44 46 … … 46 48 # include <mach/mach.h> 47 49 # include <mach/mach_error.h> 48 # include <IOKit/IOKitLib.h>49 # include <IOKit/IOCFPlugIn.h>50 50 # include <IOKit/hid/IOHIDUsageTables.h> 51 51 # include <CoreFoundation/CoreFoundation.h> 52 52 #endif 53 # include <IOKit/usb/USB.h> 53 54 #include <IOKit/IOKitLib.h> 55 #include <IOKit/IOCFPlugIn.h> 56 #include <IOKit/usb/USB.h> 54 57 #include <IOKit/hid/IOHIDLib.h> 55 58 #include <ApplicationServices/ApplicationServices.h> … … 316 319 CFIndex idxPosition; /** Position in global storage (used to simplify CFArray navigation when removing detached device) */ 317 320 uint64_t cCapsLockTimeout; /** KBD CAPS LOCK key hold timeout (some Apple keyboards only) */ 318 319 io_object_t notification; /** General interest notification stuff: notification reference */ 320 IONotificationPortRef notificationPortRef; /** General interest notification stuff: notification port reference */ 321 321 uint32_t idLocation; /** HID Location ID: unique for an USB device registered in the system */ 322 322 } VBoxKbdState_t; 323 323 … … 337 337 CFMutableArrayRef pFifoEventQueue; /** This queue will be appended in IOKit input callback. Carbon input callback will extract data from it */ 338 338 RTSEMMUTEX fifoEventQueueLock; /** Lock for pFifoEventQueue */ 339 340 io_iterator_t pUsbHidDeviceMatchNotify; /** IOService notification reference: USB HID device matching */ 341 io_iterator_t pUsbHidGeneralInterestNotify; /** IOService notification reference: USB HID general interest 342 notifications (IOService messages) */ 343 IONotificationPortRef pNotificationPrortRef; /** IOService notification port reference: used for both notification 344 types - device match and device general interest message */ 339 345 340 346 /* Carbon events data */ … … 1453 1459 } 1454 1460 1461 /** Get HID Location ID */ 1462 static uint32_t darwinHidLocationId(IOHIDDeviceRef pHidDeviceRef) 1463 { 1464 return darwinQueryIntProperty(pHidDeviceRef, CFSTR(kIOHIDLocationIDKey)); 1465 } 1466 1455 1467 /** Some keyboard devices might freeze after LEDs manipulation. We filter out such devices here. 1456 1468 * In the list below, devices that known to have such issues. If you want to add new device, … … 1467 1479 { 1468 1480 if (productId == 0x8001) /* GK-04008/C keyboard */ 1481 fSupported = false; 1482 } 1483 if (vendorId == 0xE6A) /* Megawin Technology */ 1484 { 1485 if (productId == 0x6001) /* Japanese flexible keyboard */ 1469 1486 fSupported = false; 1470 1487 } … … 1723 1740 } 1724 1741 1725 /** IOHID Device general interest notification callback. We are interested in kIOMessageDeviceHasPoweredOn message. 1726 * When we receive it, we do silently resync kbd which was just resumed. The rest of messages are for debugging 1727 * purpose. */ 1728 static void darwinHidNotificationCb(void *pData, io_service_t unused1, natural_t msg, void *unused2) 1742 /** Helper function to obtain interface for IOUSBInterface IOService. */ 1743 static IOUSBDeviceInterface ** darwinQueryUsbHidInterfaceInterface(io_service_t service) 1744 { 1745 kern_return_t rc; 1746 IOCFPlugInInterface **ppPluginInterface = NULL; 1747 int32_t iScore; 1748 1749 rc = IOCreatePlugInInterfaceForService(service, kIOUSBInterfaceUserClientTypeID, 1750 kIOCFPlugInInterfaceID, &ppPluginInterface, &iScore); 1751 1752 if (rc == kIOReturnSuccess && ppPluginInterface != NULL) 1753 { 1754 IOUSBDeviceInterface **ppUsbDeviceInterface = NULL; 1755 1756 rc = (*ppPluginInterface)->QueryInterface(ppPluginInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), 1757 (LPVOID *)&ppUsbDeviceInterface); 1758 IODestroyPlugInInterface(ppPluginInterface); 1759 1760 if (rc == kIOReturnSuccess && ppUsbDeviceInterface != NULL) 1761 return ppUsbDeviceInterface; 1762 else 1763 LogRel2(("Failed to query plugin interface for USB device\n")); 1764 1765 } 1766 else 1767 LogRel2(("Failed to create plugin interface for USB device\n")); 1768 1769 return NULL; 1770 } 1771 1772 /** Helper function for IOUSBInterface IOService general interest notification callback: resync LEDs. */ 1773 static void darwinUsbHidResyncLeds(VBoxKbdState_t *pKbd) 1774 { 1775 AssertReturnVoid(pKbd); 1776 1777 VBoxHidsState_t *pHidState = (VBoxHidsState_t *)pKbd->pParentContainer; 1778 CFDictionaryRef elementMatchingDict = darwinQueryLedElementMatchingDictionary(); 1779 if (elementMatchingDict) 1780 { 1781 LogRel2(("Do HID device resync at location 0x%X \n", pKbd->idLocation)); 1782 (void)darwinSetDeviceLedsState(pKbd->pDevice, elementMatchingDict, 1783 pHidState->guestState.fNumLockOn, pHidState->guestState.fCapsLockOn, pHidState->guestState.fScrollLockOn); 1784 CFRelease(elementMatchingDict); 1785 } 1786 } 1787 1788 /** IOUSBInterface IOService general interest notification callback. When we receive it, we do 1789 * silently resync kbd which has just changed its state. */ 1790 static void darwinUsbHidGeneralInterestCb(void *pData, io_service_t unused1, natural_t msg, void *unused2) 1729 1791 { 1730 1792 NOREF(unused1); … … 1736 1798 switch (msg) 1737 1799 { 1738 case kIOMessageDeviceHasPoweredOn: 1739 { 1740 LogRel2(("HID general interest notification kIOMessageDeviceHasPoweredOn for KBD %d\n", (int)(pKbd->idxPosition))); 1741 1742 VBoxHidsState_t *pHidState = (VBoxHidsState_t *)pKbd->pParentContainer; 1743 CFDictionaryRef elementMatchingDict = darwinQueryLedElementMatchingDictionary(); 1744 if (elementMatchingDict) 1745 { 1746 (void)darwinSetDeviceLedsState(pKbd->pDevice, elementMatchingDict, 1747 pHidState->guestState.fNumLockOn, pHidState->guestState.fCapsLockOn, pHidState->guestState.fScrollLockOn); 1748 CFRelease(elementMatchingDict); 1749 } 1800 case kIOUSBMessagePortHasBeenSuspended: 1801 { 1802 LogRel2(("IOUSBInterface IOService general interest notification kIOUSBMessagePortHasBeenSuspended for KBD %d (Location ID: 0x%X)\n", 1803 (int)(pKbd->idxPosition), pKbd->idLocation)); 1750 1804 break; 1751 1805 } 1752 1806 1753 case kIOMessageDeviceWillPowerOff: 1754 { 1755 LogRel2(("HID general interest notification kIOMessageDeviceWillPowerOff for KBD %d\n", (int)(pKbd->idxPosition))); 1807 case kIOUSBMessagePortHasBeenResumed: 1808 { 1809 LogRel2(("IOUSBInterface IOService general interest notification kIOUSBMessagePortHasBeenResumed for KBD %d (Location ID: 0x%X)\n", 1810 (int)(pKbd->idxPosition), pKbd->idLocation)); 1811 darwinUsbHidResyncLeds(pKbd); 1756 1812 break; 1757 1813 } 1758 1814 1759 case kIOMessageCanDevicePowerOff: 1760 { 1761 LogRel2(("HID general interest notification kIOMessageCanDevicePowerOff for KBD %d\n", (int)(pKbd->idxPosition))); 1815 case kIOUSBMessagePortHasBeenReset: 1816 { 1817 LogRel2(("IOUSBInterface IOService general interest notification kIOUSBMessagePortHasBeenReset for KBD %d (Location ID: 0x%X)\n", 1818 (int)(pKbd->idxPosition), pKbd->idLocation)); 1819 darwinUsbHidResyncLeds(pKbd); 1762 1820 break; 1763 1821 } 1764 1822 1823 case kIOUSBMessageCompositeDriverReconfigured: 1824 { 1825 LogRel2(("IOUSBInterface IOService general interest notification kIOUSBMessageCompositeDriverReconfigured for KBD %d (Location ID: 0x%X)\n", 1826 (int)(pKbd->idxPosition), pKbd->idLocation)); 1827 darwinUsbHidResyncLeds(pKbd); 1828 break; 1829 } 1830 1831 case kIOMessageServiceWasClosed: 1832 { 1833 LogRel2(("IOUSBInterface IOService general interest notification kIOMessageServiceWasClosed for KBD %d (Location ID: 0x%X)\n", 1834 (int)(pKbd->idxPosition), pKbd->idLocation)); 1835 break; 1836 } 1837 1765 1838 default: 1766 LogRel2(("HID general interest notification 0x%X for KBD %d\n", (int)msg, (int)(pKbd->idxPosition))); 1767 } 1768 } 1769 1770 /** Battle against automatic power management for KBD devices. Register general interest notification 1771 * callback in order to recync KBD device when its driver report that it has been resumed from auto-sleep. */ 1772 static int darwinHidSubscribeInterestNotification(VBoxKbdState_t *pKbd) 1773 { 1774 AssertReturn(pKbd, kIOReturnError); 1775 AssertReturn(pKbd->pDevice, kIOReturnError); 1776 1777 io_service_t service; 1778 kern_return_t rc = kIOReturnError; 1779 1780 service = IOHIDDeviceGetService(pKbd->pDevice); 1781 if (service) 1782 { 1783 pKbd->notificationPortRef = IONotificationPortCreate(kIOMasterPortDefault); 1784 if (pKbd->notificationPortRef) 1785 { 1786 rc = IOServiceAddInterestNotification(pKbd->notificationPortRef, service, kIOGeneralInterest, darwinHidNotificationCb, pKbd, &(pKbd->notification)); 1787 if (rc == kIOReturnSuccess) 1788 { 1789 LogRel2(("Interest notification has been registeted for KBD %d\n", (int)(pKbd->idxPosition))); 1790 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(pKbd->notificationPortRef), kCFRunLoopDefaultMode); 1791 return 0; 1839 LogRel2(("IOUSBInterface IOService general interest notification 0x%X for KBD %d (Location ID: 0x%X)\n", 1840 msg, (int)(pKbd->idxPosition), pKbd->idLocation)); 1841 } 1842 } 1843 1844 /** Get pre-cached KBD device by its Location ID. */ 1845 static VBoxKbdState_t * darwinUsbHidQueryKbdByLocationId(uint32_t idLocation, VBoxHidsState_t *pHidState) 1846 { 1847 AssertReturn(pHidState, NULL); 1848 1849 for (CFIndex i = 0; i < CFArrayGetCount(pHidState->pDeviceCollection); i++) 1850 { 1851 VBoxKbdState_t *pKbd = (VBoxKbdState_t *)CFArrayGetValueAtIndex(pHidState->pDeviceCollection, i); 1852 if (pKbd && pKbd->idLocation == idLocation) 1853 return pKbd; 1854 } 1855 1856 return NULL; 1857 } 1858 1859 /** IOUSBInterface IOService match notification callback: issued when IOService instantinates. 1860 * We subscribe to general interest notifications for available IOServices here. */ 1861 static void darwinUsbHidDeviceMatchCb(void *pData, io_iterator_t iter) 1862 { 1863 AssertReturnVoid(pData); 1864 1865 io_service_t service; 1866 VBoxHidsState_t *pHidState = (VBoxHidsState_t *)pData; 1867 1868 while ((service = IOIteratorNext(iter))) 1869 { 1870 kern_return_t rc; 1871 1872 IOUSBDeviceInterface **ppUsbDeviceInterface = darwinQueryUsbHidInterfaceInterface(service); 1873 1874 if (ppUsbDeviceInterface) 1875 { 1876 uint8_t idDeviceClass, idDeviceSubClass; 1877 uint32_t idLocation; 1878 1879 rc = (*ppUsbDeviceInterface)->GetLocationID (ppUsbDeviceInterface, &idLocation); AssertMsg(rc == 0, ("Failed to get Location ID")); 1880 rc = (*ppUsbDeviceInterface)->GetDeviceClass (ppUsbDeviceInterface, &idDeviceClass); AssertMsg(rc == 0, ("Failed to get Device Class")); 1881 rc = (*ppUsbDeviceInterface)->GetDeviceSubClass(ppUsbDeviceInterface, &idDeviceSubClass); AssertMsg(rc == 0, ("Failed to get Device Subclass")); 1882 1883 if (idDeviceClass == kUSBHIDInterfaceClass && idDeviceSubClass == kUSBHIDBootInterfaceSubClass) 1884 { 1885 VBoxKbdState_t *pKbd = darwinUsbHidQueryKbdByLocationId(idLocation, pHidState); 1886 1887 rc = IOServiceAddInterestNotification(pHidState->pNotificationPrortRef, service, kIOGeneralInterest, 1888 darwinUsbHidGeneralInterestCb, pKbd, &pHidState->pUsbHidGeneralInterestNotify); 1889 1890 AssertMsg(rc == 0, ("Failed to add general interest notification")); 1891 1892 LogRel2(("Found HID device at location 0x%X: class 0x%X, subclass 0x%X\n", idLocation, idDeviceClass, idDeviceSubClass)); 1792 1893 } 1793 } 1794 } 1894 1895 rc = (*ppUsbDeviceInterface)->Release(ppUsbDeviceInterface); AssertMsg(rc == 0, ("Failed to release USB device interface")); 1896 } 1897 1898 IOObjectRelease(service); 1899 } 1900 } 1901 1902 /** Register IOUSBInterface IOService match notification callback in order to recync KBD 1903 * device when it reports state change. */ 1904 static int darwinUsbHidSubscribeInterestNotifications(VBoxHidsState_t *pHidState) 1905 { 1906 AssertReturn(pHidState, kIOReturnBadArgument); 1907 1908 int rc = kIOReturnNoMemory; 1909 CFDictionaryRef pDictionary = IOServiceMatching(kIOUSBInterfaceClassName); 1910 1911 if (pDictionary) 1912 { 1913 pHidState->pNotificationPrortRef = IONotificationPortCreate(kIOMasterPortDefault); 1914 if (pHidState->pNotificationPrortRef) 1915 { 1916 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(pHidState->pNotificationPrortRef), kCFRunLoopDefaultMode); 1917 1918 rc = IOServiceAddMatchingNotification(pHidState->pNotificationPrortRef, kIOMatchedNotification, 1919 pDictionary, darwinUsbHidDeviceMatchCb, pHidState, &pHidState->pUsbHidDeviceMatchNotify); 1920 1921 if (rc == kIOReturnSuccess && &pHidState->pUsbHidDeviceMatchNotify != NULL) 1922 { 1923 darwinUsbHidDeviceMatchCb(pHidState, pHidState->pUsbHidDeviceMatchNotify); 1924 LogRel2(("Successfully subscribed to IOUSBInterface IOService match notifications\n")); 1925 } 1926 else 1927 LogRel2(("Failed to subscribe to IOUSBInterface IOService match notifications: subscription error 0x%X\n", rc)); 1928 } 1929 else 1930 LogRel2(("Failed to subscribe to IOUSBInterface IOService match notifications: unable to create notification port\n")); 1931 } 1932 else 1933 LogRel2(("Failed to subscribe to IOUSBInterface IOService match notifications: no memory\n")); 1795 1934 1796 1935 return rc; 1797 1936 } 1798 1937 1799 /** Remove general interest notification subscription. */ 1800 static void darwinHidUnsubscribeInterestNotification(VBoxKbdState_t *pKbd) 1801 { 1802 AssertReturnVoid(pKbd); 1803 AssertReturnVoid(pKbd->notificationPortRef); 1804 1805 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(pKbd->notificationPortRef), kCFRunLoopDefaultMode); 1806 IONotificationPortDestroy(pKbd->notificationPortRef); 1807 pKbd->notificationPortRef = 0; 1808 1809 LogRel2(("Interest notification has been removed for KBD %d\n", (int)(pKbd->idxPosition))); 1938 /** Remove IOUSBInterface IOService match notification subscription. */ 1939 static void darwinUsbHidUnsubscribeInterestNotifications(VBoxHidsState_t *pHidState) 1940 { 1941 AssertReturnVoid(pHidState); 1942 1943 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(pHidState->pNotificationPrortRef), kCFRunLoopDefaultMode); 1944 IONotificationPortDestroy(pHidState->pNotificationPrortRef); 1945 pHidState->pNotificationPrortRef = NULL; 1946 1947 LogRel2(("Successfully un-subscribed from IOUSBInterface IOService match notifications\n")); 1810 1948 } 1811 1949 … … 1825 1963 //if (RT_FAILURE(RTSemMutexRequest(pHidState->fifoEventQueueLock, RT_INDEFINITE_WAIT))) 1826 1964 // return ; 1827 1828 darwinHidUnsubscribeInterestNotification(pKbd);1829 1965 1830 1966 CFArrayRemoveValueAtIndex(pHidState->pDeviceCollection, pKbd->idxPosition); … … 1866 2002 pKbd->pParentContainer = (void *)pHidState; 1867 2003 pKbd->idxPosition = CFArrayGetCount(pHidState->pDeviceCollection); 2004 pKbd->idLocation = darwinHidLocationId(pDevice); 1868 2005 1869 2006 /* Some Apple keyboards have CAPS LOCK key timeout. According to corresponding … … 1891 2028 } 1892 2029 1893 rc = darwinHidSubscribeInterestNotification(pKbd); 1894 if (rc == 0) 2030 /* Register per-device removal callback */ 2031 IOHIDDeviceRegisterRemovalCallback(pKbd->pDevice, darwinHidRemovalCallback, (void *)pKbd); 2032 2033 /* Register per-device input callback */ 2034 IOHIDDeviceRegisterInputValueCallback(pKbd->pDevice, darwinHidInputCallback, (void *)pKbd); 2035 IOHIDDeviceScheduleWithRunLoop(pKbd->pDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 2036 2037 CFArrayAppendValue(pHidState->pDeviceCollection, (void *)pKbd); 2038 2039 LogRel2(("Saved LEDs for KBD %d (%p): fNumLockOn=%s, fCapsLockOn=%s, fScrollLockOn=%s\n", 2040 (int)pKbd->idxPosition, pKbd, VBOX_BOOL_TO_STR_STATE(pKbd->LED.fNumLockOn), VBOX_BOOL_TO_STR_STATE(pKbd->LED.fCapsLockOn), 2041 VBOX_BOOL_TO_STR_STATE(pKbd->LED.fScrollLockOn))); 2042 2043 if (fApplyLedState) 1895 2044 { 1896 /* Register per-device removal callback */ 1897 IOHIDDeviceRegisterRemovalCallback(pKbd->pDevice, darwinHidRemovalCallback, (void *)pKbd); 1898 1899 /* Register per-device input callback */ 1900 IOHIDDeviceRegisterInputValueCallback(pKbd->pDevice, darwinHidInputCallback, (void *)pKbd); 1901 IOHIDDeviceScheduleWithRunLoop(pKbd->pDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 1902 1903 CFArrayAppendValue(pHidState->pDeviceCollection, (void *)pKbd); 1904 1905 LogRel2(("Saved LEDs for KBD %d (%p): fNumLockOn=%s, fCapsLockOn=%s, fScrollLockOn=%s\n", 1906 (int)pKbd->idxPosition, pKbd, VBOX_BOOL_TO_STR_STATE(pKbd->LED.fNumLockOn), VBOX_BOOL_TO_STR_STATE(pKbd->LED.fCapsLockOn), 1907 VBOX_BOOL_TO_STR_STATE(pKbd->LED.fScrollLockOn))); 1908 1909 if (fApplyLedState) 1910 { 1911 rc = darwinSetDeviceLedsState(pKbd->pDevice, elementMatchingDict, pHidState->guestState.fNumLockOn, 1912 pHidState->guestState.fCapsLockOn, pHidState->guestState.fScrollLockOn); 1913 if (rc != 0) 1914 LogRel2(("Unable to apply guest state to newly attached device\n")); 1915 } 1916 1917 CFRelease(elementMatchingDict); 1918 return; 2045 rc = darwinSetDeviceLedsState(pKbd->pDevice, elementMatchingDict, pHidState->guestState.fNumLockOn, 2046 pHidState->guestState.fCapsLockOn, pHidState->guestState.fScrollLockOn); 2047 if (rc != 0) 2048 LogRel2(("Unable to apply guest state to newly attached device\n")); 1919 2049 } 1920 else 1921 LogRel2(("Unable to subscribe to IOService interest notification for KBD %d. Disable sync for this keyboard.\n", (int)(pKbd->idxPosition))); 2050 2051 CFRelease(elementMatchingDict); 2052 return; 1922 2053 } 1923 2054 … … 2067 2198 pHidState->guestState.fScrollLockOn = false; 2068 2199 2069 return pHidState; 2200 /* Finally, subscribe to USB HID notifications in order to prevent LED artifacts on 2201 automatic power management */ 2202 if (darwinUsbHidSubscribeInterestNotifications(pHidState) == 0) 2203 return pHidState; 2070 2204 } 2071 2205 } … … 2104 2238 2105 2239 AssertReturn(pHidState, kIOReturnError); 2240 2241 darwinUsbHidUnsubscribeInterestNotifications(pHidState); 2106 2242 2107 2243 /* Need to unregister Carbon stuff first */ … … 2136 2272 (int)i, pKbd, VBOX_BOOL_TO_STR_STATE(pKbd->LED.fNumLockOn), VBOX_BOOL_TO_STR_STATE(pKbd->LED.fCapsLockOn), 2137 2273 VBOX_BOOL_TO_STR_STATE(pKbd->LED.fScrollLockOn))); 2138 2139 darwinHidUnsubscribeInterestNotification(pKbd);2140 2274 2141 2275 free(pKbd);
Note:
See TracChangeset
for help on using the changeset viewer.