📄 usb_osx.c
字号:
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <CoreFoundation/CoreFoundation.h>#include <IOKit/IOKitLib.h>#include <IOKit/IOCFPlugIn.h>#include <IOKit/usb/IOUSBLib.h>#include <IOKit/IOMessage.h>#include <mach/mach_port.h>#include "sysdeps.h"#include <stdio.h>#define TRACE_TAG TRACE_USB#include "adb.h"#define DBG Dtypedef struct { int vid; int pid;} VendorProduct;#define kSupportedDeviceCount 4VendorProduct kSupportedDevices[kSupportedDeviceCount] = { { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER }, { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER_COMP }, { VENDOR_ID_HTC, PRODUCT_ID_DREAM }, { VENDOR_ID_HTC, PRODUCT_ID_DREAM_COMP },};static IONotificationPortRef notificationPort = 0;static io_iterator_t notificationIterators[kSupportedDeviceCount];struct usb_handle{ UInt8 bulkIn; UInt8 bulkOut; IOUSBInterfaceInterface **interface; io_object_t usbNotification; unsigned int zero_mask;};static CFRunLoopRef currentRunLoop = 0;static pthread_mutex_t start_lock;static pthread_cond_t start_cond;static void AndroidDeviceAdded(void *refCon, io_iterator_t iterator);static void AndroidDeviceNotify(void *refCon, io_iterator_t iterator, natural_t messageType, void *messageArgument);static usb_handle* FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product);static intInitUSB(){ CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; SInt32 vendor, product; int i; //* To set up asynchronous notifications, create a notification port and //* add its run loop event source to the program's run loop notificationPort = IONotificationPortCreate(kIOMasterPortDefault); runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); memset(notificationIterators, 0, sizeof(notificationIterators)); //* loop through all supported vendor/product pairs for (i = 0; i < kSupportedDeviceCount; i++) { //* Create our matching dictionary to find the Android device //* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this matchingDict = IOServiceMatching(kIOUSBDeviceClassName); if (!matchingDict) { DBG("ERR: Couldn't create USB matching dictionary.\n"); return -1; } //* Set up two matching dictionaries, one for each product ID we support. //* This will cause the kernel to notify us only if the vendor and product IDs match. vendor = kSupportedDevices[i].vid; product = kSupportedDevices[i].pid; CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor)); CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product)); //* Now set up two notifications: one to be called when a raw device //* is first matched by the I/O Kit and another to be called when the //* device is terminated. //* we need to do this with each matching dictionary. IOServiceAddMatchingNotification( notificationPort, kIOFirstMatchNotification, matchingDict, AndroidDeviceAdded, NULL, ¬ificationIterators[i]); //* Iterate over set of matching devices to access already-present devices //* and to arm the notification AndroidDeviceAdded(NULL, notificationIterators[i]); } return 0;}static voidAndroidDeviceAdded(void *refCon, io_iterator_t iterator){ kern_return_t kr; io_service_t usbDevice; IOCFPlugInInterface **plugInInterface = NULL; IOUSBDeviceInterface182 **dev = NULL; HRESULT result; SInt32 score; UInt16 vendor; UInt16 product; UInt8 serialIndex; char serial[256]; while ((usbDevice = IOIteratorNext(iterator))) { //* Create an intermediate plugin kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); if ((kIOReturnSuccess != kr) || (!plugInInterface)) { DBG("ERR: Unable to create a plug-in (%08x)\n", kr); goto continue1; } //* Now create the device interface result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); if (result || !dev) { DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result); goto continue2; } //* Check the device to see if it's ours kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); if (serialIndex > 0) { IOUSBDevRequest req; UInt16 buffer[256]; req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); req.bRequest = kUSBRqGetDescriptor; req.wValue = (kUSBStringDesc << 8) | serialIndex; req.wIndex = 0; req.pData = buffer; req.wLength = sizeof(buffer); kr = (*dev)->DeviceRequest(dev, &req); if (kr == kIOReturnSuccess && req.wLenDone > 0) { int i, count; // skip first word, and copy the rest to the serial string, changing shorts to bytes. count = (req.wLenDone - 1) / 2; for (i = 0; i < count; i++) serial[i] = buffer[i + 1]; serial[i] = 0; } } usb_handle* handle = NULL; //* Open the device kr = (*dev)->USBDeviceOpen(dev); if (kr != kIOReturnSuccess) { DBG("ERR: Could not open device: %08x\n", kr); goto continue3; } else { //* Find an interface for the device handle = FindDeviceInterface((IOUSBDeviceInterface**)dev, vendor, product); } if (handle == NULL) { DBG("ERR: Could not find device interface: %08x\n", kr); (*dev)->USBDeviceClose(dev); goto continue3; } DBG("AndroidDeviceAdded calling register_usb_transport\n"); register_usb_transport(handle, (serial[0] ? serial : NULL)); // Register for an interest notification of this device being removed. Pass the reference to our // private data as the refCon for the notification. kr = IOServiceAddInterestNotification(notificationPort, usbDevice, kIOGeneralInterest, AndroidDeviceNotify, handle, &handle->usbNotification); if (kIOReturnSuccess != kr) { DBG("ERR: Unable to create interest notification (%08x)\n", kr); }continue3: (void)(*dev)->Release(dev);continue2: IODestroyPlugInInterface(plugInInterface);continue1: IOObjectRelease(usbDevice); }}static voidAndroidDeviceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument){ usb_handle *handle = (usb_handle *)refCon; if (messageType == kIOMessageServiceIsTerminated) { DBG("AndroidDeviceNotify\n"); IOObjectRelease(handle->usbNotification); usb_kick(handle); }}static usb_handle*FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product){ usb_handle* handle = NULL; IOReturn kr; IOUSBFindInterfaceRequest request; io_iterator_t iterator; io_service_t usbInterface; IOCFPlugInInterface **plugInInterface; IOUSBInterfaceInterface **interface = NULL; HRESULT result; SInt32 score; UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol; UInt8 endpoint, configuration; //* Placing the constant KIOUSBFindInterfaceDontCare into the following //* fields of the IOUSBFindInterfaceRequest structure will allow us to //* find all of the interfaces request.bInterfaceClass = kIOUSBFindInterfaceDontCare; request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; request.bAlternateSetting = kIOUSBFindInterfaceDontCare; //* SetConfiguration will kill an existing UMS connection, so let's not do this if not necessary. configuration = 0; (*dev)->GetConfiguration(dev, &configuration); if (configuration != 1) (*dev)->SetConfiguration(dev, 1); //* Get an iterator for the interfaces on the device
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -