📄 usb_osx.c
字号:
/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include <stdio.h>#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 "usb.h"/* * Internal helper functions and associated definitions. */#if TRACE_USB#define WARN(x...) fprintf(stderr, x)#else#define WARN(x...)#endif#define ERR(x...) fprintf(stderr, "ERROR: " x)/** An open usb device */struct usb_handle{ int success; ifc_match_func callback; usb_ifc_info info; UInt8 bulkIn; UInt8 bulkOut; IOUSBInterfaceInterface190 **interface; unsigned int zero_mask;};/** Try out all the interfaces and see if there's a match. Returns 0 on * success, -1 on failure. */static int try_interfaces(IOUSBDeviceInterface **dev, usb_handle *handle) { IOReturn kr; IOUSBFindInterfaceRequest request; io_iterator_t iterator; io_service_t usbInterface; IOCFPlugInInterface **plugInInterface; IOUSBInterfaceInterface190 **interface = NULL; HRESULT result; SInt32 score; UInt8 interfaceNumEndpoints; UInt8 endpoint; UInt8 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 kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator); if (kr != 0) { ERR("Couldn't create a device interface iterator: (%08x)\n", kr); return -1; } while ((usbInterface = IOIteratorNext(iterator))) { // Create an intermediate plugin kr = IOCreatePlugInInterfaceForService( usbInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); // No longer need the usbInterface object now that we have the plugin (void) IOObjectRelease(usbInterface); if ((kr != 0) || (!plugInInterface)) { WARN("Unable to create plugin (%08x)\n", kr); continue; } // Now create the interface interface for the interface result = (*plugInInterface)->QueryInterface( plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) &interface); // No longer need the intermediate plugin (*plugInInterface)->Release(plugInInterface); if (result || !interface) { ERR("Couldn't create interface interface: (%08x)\n", (unsigned int) result); // continue so we can try the next interface continue; } /* * Now open the interface. This will cause the pipes * associated with the endpoints in the interface descriptor * to be instantiated. */ /* * TODO: Earlier comments here indicated that it was a bad * idea to just open any interface, because opening "mass * storage endpoints" is bad. However, the only way to find * out if an interface does bulk in or out is to open it, and * the framework in this application wants to be told about * bulk in / out before deciding whether it actually wants to * use the interface. Maybe something needs to be done about * this situation. */ kr = (*interface)->USBInterfaceOpen(interface); if (kr != 0) { WARN("Could not open interface: (%08x)\n", kr); (void) (*interface)->Release(interface); // continue so we can try the next interface continue; } // Get the number of endpoints associated with this interface. kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); if (kr != 0) { ERR("Unable to get number of endpoints: (%08x)\n", kr); goto next_interface; } // Get interface class, subclass and protocol if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 || (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 || (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0) { ERR("Unable to get interface class, subclass and protocol\n"); goto next_interface; } handle->info.has_bulk_in = 0; handle->info.has_bulk_out = 0; // Iterate over the endpoints for this interface and see if there // are any that do bulk in/out. for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { UInt8 transferType; UInt16 maxPacketSize; UInt8 interval; UInt8 number; UInt8 direction; kr = (*interface)->GetPipeProperties(interface, endpoint, &direction, &number, &transferType, &maxPacketSize, &interval); if (kr == 0) { if (transferType != kUSBBulk) { continue; } if (direction == kUSBIn) { handle->info.has_bulk_in = 1; handle->bulkIn = endpoint; } else if (direction == kUSBOut) { handle->info.has_bulk_out = 1; handle->bulkOut = endpoint; } if (handle->info.ifc_protocol == 0x01) { handle->zero_mask = maxPacketSize - 1; } } else { ERR("could not get pipe properties\n"); } if (handle->info.has_bulk_in && handle->info.has_bulk_out) { break; } } if (handle->callback(&handle->info) == 0) { handle->interface = interface; handle->success = 1; /* * Clear both the endpoints, because it has been observed * that the Mac may otherwise (incorrectly) start out with * them in bad state. */ if (handle->info.has_bulk_in) { kr = (*interface)->ClearPipeStallBothEnds(interface, handle->bulkIn); if (kr != 0) { ERR("could not clear input pipe; result %d", kr); return -1; } } if (handle->info.has_bulk_out) { kr = (*interface)->ClearPipeStallBothEnds(interface, handle->bulkOut); if (kr != 0) { ERR("could not clear output pipe; result %d", kr); return -1; } } return 0; } next_interface: (*interface)->USBInterfaceClose(interface); (*interface)->Release(interface); } return 0;}/** Try out the given device and see if there's a match. Returns 0 on * success, -1 on failure. */static int try_device(io_service_t device, usb_handle *handle) { kern_return_t kr; IOCFPlugInInterface **plugin = NULL; IOUSBDeviceInterface182 **dev = NULL; SInt32 score; HRESULT result; UInt8 serialIndex; // Create an intermediate plugin.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -