usb_osx.c revision 13081c6915220db03886b177f1a8e0b2c63467c9
1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/* 2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * All rights reserved. 4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * 5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Redistribution and use in source and binary forms, with or without 6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * modification, are permitted provided that the following conditions 7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * are met: 8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * * Redistributions of source code must retain the above copyright 9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * notice, this list of conditions and the following disclaimer. 10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * * Redistributions in binary form must reproduce the above copyright 11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * notice, this list of conditions and the following disclaimer in 12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * the documentation and/or other materials provided with the 13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distribution. 14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * 15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * SUCH DAMAGE. 27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h> 30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <CoreFoundation/CoreFoundation.h> 31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <IOKit/IOKitLib.h> 32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <IOKit/IOCFPlugIn.h> 33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <IOKit/usb/IOUSBLib.h> 34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <IOKit/IOMessage.h> 35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <mach/mach_port.h> 36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "usb.h" 38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/* 41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Internal helper functions and associated definitions. 42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if TRACE_USB 45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define WARN(x...) fprintf(stderr, x) 46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#else 47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define WARN(x...) 48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif 49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define ERR(x...) fprintf(stderr, "ERROR: " x) 51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** An open usb device */ 53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct usb_handle 54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int success; 56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ifc_match_func callback; 57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project usb_ifc_info info; 58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 bulkIn; 60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 bulkOut; 61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOUSBInterfaceInterface190 **interface; 62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project unsigned int zero_mask; 63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}; 64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Try out all the interfaces and see if there's a match. Returns 0 on 66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * success, -1 on failure. */ 67b64063737e93638a09205e9310b58d8ddd7138ecJeff Brownstatic int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) { 68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOReturn kr; 69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOUSBFindInterfaceRequest request; 70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project io_iterator_t iterator; 71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project io_service_t usbInterface; 72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOCFPlugInInterface **plugInInterface; 73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOUSBInterfaceInterface190 **interface = NULL; 74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project HRESULT result; 75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project SInt32 score; 76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 interfaceNumEndpoints; 77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 endpoint; 78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 configuration; 79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Placing the constant KIOUSBFindInterfaceDontCare into the following 81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // fields of the IOUSBFindInterfaceRequest structure will allow us to 82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // find all of the interfaces 83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project request.bInterfaceClass = kIOUSBFindInterfaceDontCare; 84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; 85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; 86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project request.bAlternateSetting = kIOUSBFindInterfaceDontCare; 87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // SetConfiguration will kill an existing UMS connection, so let's 89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // not do this if not necessary. 90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project configuration = 0; 91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*dev)->GetConfiguration(dev, &configuration); 92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (configuration != 1) 93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*dev)->SetConfiguration(dev, 1); 94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Get an iterator for the interfaces on the device 96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator); 97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Couldn't create a device interface iterator: (%08x)\n", kr); 100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project while ((usbInterface = IOIteratorNext(iterator))) { 104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Create an intermediate plugin 105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = IOCreatePlugInInterfaceForService( 106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project usbInterface, 107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kIOUSBInterfaceUserClientTypeID, 108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kIOCFPlugInInterfaceID, 109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project &plugInInterface, 110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project &score); 111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // No longer need the usbInterface object now that we have the plugin 113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (void) IOObjectRelease(usbInterface); 114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if ((kr != 0) || (!plugInInterface)) { 116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project WARN("Unable to create plugin (%08x)\n", kr); 117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Now create the interface interface for the interface 121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result = (*plugInInterface)->QueryInterface( 122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project plugInInterface, 123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), 124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (LPVOID) &interface); 125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // No longer need the intermediate plugin 127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*plugInInterface)->Release(plugInInterface); 128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (result || !interface) { 130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Couldn't create interface interface: (%08x)\n", 131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (unsigned int) result); 132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // continue so we can try the next interface 133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Now open the interface. This will cause the pipes 138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * associated with the endpoints in the interface descriptor 139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * to be instantiated. 140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * TODO: Earlier comments here indicated that it was a bad 144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * idea to just open any interface, because opening "mass 145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * storage endpoints" is bad. However, the only way to find 146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * out if an interface does bulk in or out is to open it, and 147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * the framework in this application wants to be told about 148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * bulk in / out before deciding whether it actually wants to 149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * use the interface. Maybe something needs to be done about 150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * this situation. 151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*interface)->USBInterfaceOpen(interface); 154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project WARN("Could not open interface: (%08x)\n", kr); 157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (void) (*interface)->Release(interface); 158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // continue so we can try the next interface 159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Get the number of endpoints associated with this interface. 163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); 164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Unable to get number of endpoints: (%08x)\n", kr); 167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto next_interface; 168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Get interface class, subclass and protocol 171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 || 172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 || 173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0) 174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project { 175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Unable to get interface class, subclass and protocol\n"); 176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto next_interface; 177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.has_bulk_in = 0; 180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.has_bulk_out = 0; 181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Iterate over the endpoints for this interface and see if there 183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // are any that do bulk in/out. 184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { 185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 transferType; 186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt16 maxPacketSize; 187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 interval; 188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 number; 189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 direction; 190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*interface)->GetPipeProperties(interface, endpoint, 192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project &direction, 193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project &number, &transferType, &maxPacketSize, &interval); 194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr == 0) { 196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (transferType != kUSBBulk) { 197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (direction == kUSBIn) { 201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.has_bulk_in = 1; 202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->bulkIn = endpoint; 203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else if (direction == kUSBOut) { 204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.has_bulk_out = 1; 205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->bulkOut = endpoint; 206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (handle->info.ifc_protocol == 0x01) { 209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->zero_mask = maxPacketSize - 1; 210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("could not get pipe properties\n"); 213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (handle->info.has_bulk_in && handle->info.has_bulk_out) { 216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (handle->callback(&handle->info) == 0) { 221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->interface = interface; 222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->success = 1; 223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Clear both the endpoints, because it has been observed 226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * that the Mac may otherwise (incorrectly) start out with 227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * them in bad state. 228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (handle->info.has_bulk_in) { 231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*interface)->ClearPipeStallBothEnds(interface, 232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->bulkIn); 233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 234286d50fe34edef9b93cde6a3e2d052b2b96d071cNick Pelly ERR("could not clear input pipe; result %x, ignoring...\n", kr); 235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (handle->info.has_bulk_out) { 239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*interface)->ClearPipeStallBothEnds(interface, 240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->bulkOut); 241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 242286d50fe34edef9b93cde6a3e2d052b2b96d071cNick Pelly ERR("could not clear output pipe; result %x, ignoring....\n", kr); 243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectnext_interface: 250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*interface)->USBInterfaceClose(interface); 251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*interface)->Release(interface); 252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Try out the given device and see if there's a match. Returns 0 on 258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * success, -1 on failure. 259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int try_device(io_service_t device, usb_handle *handle) { 261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kern_return_t kr; 262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOCFPlugInInterface **plugin = NULL; 263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOUSBDeviceInterface182 **dev = NULL; 264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project SInt32 score; 265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project HRESULT result; 266dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt8 serialIndex; 26713081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson UInt32 locationId; 268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 269dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Create an intermediate plugin. 270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = IOCreatePlugInInterfaceForService(device, 271dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kIOUSBDeviceUserClientTypeID, 272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kIOCFPlugInInterfaceID, 273dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project &plugin, &score); 274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if ((kr != 0) || (plugin == NULL)) { 276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Unable to create a plug-in (%08x)\n", kr); 277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 278dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Now create the device interface. 281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result = (*plugin)->QueryInterface(plugin, 282dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); 283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if ((result != 0) || (dev == NULL)) { 284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Couldn't create a device interface (%08x)\n", (int) result); 285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * We don't need the intermediate interface after the device interface 290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * is created. 291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IODestroyPlugInInterface(plugin); 293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // So, we have a device, finally. Grab its vitals. 295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor); 297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("GetDeviceVendor"); 299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product); 303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("GetDeviceProduct"); 305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class); 309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("GetDeviceClass"); 311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass); 315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("GetDeviceSubClass"); 317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol); 321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr != 0) { 322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("GetDeviceProtocol"); 323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 32613081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson kr = (*dev)->GetLocationID(dev, &locationId); 32713081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson if (kr != 0) { 32813081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson ERR("GetLocationId"); 32913081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson goto error; 33013081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson } 33113081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson snprintf(handle->info.device_path, sizeof(handle->info.device_path), "usb:%lX", locationId); 33213081c6915220db03886b177f1a8e0b2c63467c9Scott Anderson 333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); 334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (serialIndex > 0) { 336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOUSBDevRequest req; 337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt16 buffer[256]; 338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); 340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project req.bRequest = kUSBRqGetDescriptor; 341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project req.wValue = (kUSBStringDesc << 8) | serialIndex; 342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project req.wIndex = 0; 343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project req.pData = buffer; 344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project req.wLength = sizeof(buffer); 345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kr = (*dev)->DeviceRequest(dev, &req); 346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (kr == kIOReturnSuccess && req.wLenDone > 0) { 348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int i, count; 349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // skip first word, and copy the rest to the serial string, changing shorts to bytes. 351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project count = (req.wLenDone - 1) / 2; 352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (i = 0; i < count; i++) 353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.serial_number[i] = buffer[i + 1]; 354dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.serial_number[i] = 0; 355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // device has no serial number 358dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project handle->info.serial_number[0] = 0; 359dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 360b4add9b74525210478bac702d27fdaf9cf7ab18fElliott Hughes handle->info.writable = 1; 361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 362dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (try_interfaces(dev, handle)) { 363dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project goto error; 364dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 365dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 366dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*dev)->Release(dev); 367dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 368dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 369dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project error: 370dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 371dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (dev != NULL) { 372dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (*dev)->Release(dev); 373dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 375dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 376dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 377dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Initializes the USB system. Returns 0 on success, -1 on error. */ 380dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int init_usb(ifc_match_func callback, usb_handle **handle) { 381dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int ret = -1; 382dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project CFMutableDictionaryRef matchingDict; 383dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kern_return_t result; 384dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project io_iterator_t iterator; 385dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project usb_handle h; 386dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 387dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project h.success = 0; 388dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project h.callback = callback; 389dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 391dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Create our matching dictionary to find appropriate devices. 392dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * IOServiceAddMatchingNotification consumes the reference, so we 393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * do not need to release it. 394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 395dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project matchingDict = IOServiceMatching(kIOUSBDeviceClassName); 396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 397dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (matchingDict == NULL) { 398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Couldn't create USB matching dictionary.\n"); 399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 400dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 401dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 402dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result = IOServiceGetMatchingServices( 403dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project kIOMasterPortDefault, matchingDict, &iterator); 404dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 405dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (result != 0) { 406dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("Could not create iterator."); 407dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 408dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 409dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 410dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (;;) { 411dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (! IOIteratorIsValid(iterator)) { 412dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 413dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Apple documentation advises resetting the iterator if 414dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * it should become invalid during iteration. 415dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 416dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOIteratorReset(iterator); 417dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 418dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 419dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 420dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project io_service_t device = IOIteratorNext(iterator); 421dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 422dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (device == 0) { 423dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 424dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 425dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 426dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (try_device(device, &h) != 0) { 427dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOObjectRelease(device); 428dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ret = -1; 429dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 430dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 431dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 432dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h.success) { 433dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *handle = calloc(1, sizeof(usb_handle)); 434dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project memcpy(*handle, &h, sizeof(usb_handle)); 435dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ret = 0; 436dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 437dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 438dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 439dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOObjectRelease(device); 440dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 441dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 442dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOObjectRelease(iterator); 443dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 444dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return ret; 445dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 446dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 447dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 448dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 449dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/* 450dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Definitions of this file's public functions. 451dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 452dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 453dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectusb_handle *usb_open(ifc_match_func callback) { 454dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project usb_handle *handle = NULL; 455dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (init_usb(callback, &handle) < 0) { 457dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* Something went wrong initializing USB. */ 458dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return NULL; 459dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 460dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 461dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return handle; 462dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 464dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint usb_close(usb_handle *h) { 465dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* TODO: Something better here? */ 466dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 467dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 468dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 469dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint usb_read(usb_handle *h, void *data, int len) { 470dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOReturn result; 471dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project UInt32 numBytes = len; 472dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 473dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (len == 0) { 474dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 475dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 476dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 477dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h == NULL) { 478dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 479dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 480dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h->interface == NULL) { 482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("usb_read interface was null\n"); 483dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 484dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 485dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h->bulkIn == 0) { 487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("bulkIn endpoint not assigned\n"); 488dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 489dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 490dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 491dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result = (*h->interface)->ReadPipe( 492dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project h->interface, h->bulkIn, data, &numBytes); 493dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 494dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (result == 0) { 495dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return (int) numBytes; 496dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 497dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("usb_read failed with status %x\n", result); 498dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 499dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 500dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 501dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 502dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 503dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint usb_write(usb_handle *h, const void *data, int len) { 504dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project IOReturn result; 505dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 506dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (len == 0) { 507dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 508dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 509dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 510dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h == NULL) { 511dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 512dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 513dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 514dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h->interface == NULL) { 515dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("usb_write interface was null\n"); 516dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 517dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 518dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 519dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (h->bulkOut == 0) { 520dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("bulkOut endpoint not assigned\n"); 521dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 522dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 523dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 524b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown#if 0 525dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result = (*h->interface)->WritePipe( 526dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project h->interface, h->bulkOut, (void *)data, len); 527b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown#else 528b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown /* Attempt to work around crashes in the USB driver that may be caused 529b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown * by trying to write too much data at once. The kernel IOCopyMapper 530b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown * panics if a single iovmAlloc needs more than half of its mapper pages. 531b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown */ 532b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown const int maxLenToSend = 1048576; // 1 MiB 533b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown int lenRemaining = len; 534b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown result = 0; 535b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown while (lenRemaining > 0) { 536b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown int lenToSend = lenRemaining > maxLenToSend 537b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown ? maxLenToSend : lenRemaining; 538b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown 539b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown result = (*h->interface)->WritePipe( 540b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown h->interface, h->bulkOut, (void *)data, lenToSend); 541b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown if (result != 0) break; 542b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown 543b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown lenRemaining -= lenToSend; 544b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown data = (const char*)data + lenToSend; 545b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown } 546b64063737e93638a09205e9310b58d8ddd7138ecJeff Brown#endif 547dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 548dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project #if 0 549dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if ((result == 0) && (h->zero_mask)) { 550dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* we need 0-markers and our transfer */ 551dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(!(len & h->zero_mask)) { 552dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result = (*h->interface)->WritePipe( 553dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project h->interface, h->bulkOut, (void *)data, 0); 554dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 555dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 556dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project #endif 557dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 558dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (result != 0) { 559dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ERR("usb_write failed with status %x\n", result); 560dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 561dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 562dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 563dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return len; 564dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 565