usb_osx.c revision b4add9b74525210478bac702d27fdaf9cf7ab18f
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. */
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int try_interfaces(IOUSBDeviceInterface **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) {
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    ERR("could not clear input pipe; result %d", kr);
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    return -1;
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (handle->info.has_bulk_out) {
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                kr = (*interface)->ClearPipeStallBothEnds(interface,
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                        handle->bulkOut);
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (kr != 0) {
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    ERR("could not clear output pipe; result %d", kr);
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    return -1;
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return 0;
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectnext_interface:
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        (*interface)->USBInterfaceClose(interface);
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        (*interface)->Release(interface);
254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Try out the given device and see if there's a match. Returns 0 on
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * success, -1 on failure.
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int try_device(io_service_t device, usb_handle *handle) {
263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kern_return_t kr;
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    IOCFPlugInInterface **plugin = NULL;
265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    IOUSBDeviceInterface182 **dev = NULL;
266dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SInt32 score;
267dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    HRESULT result;
268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    UInt8 serialIndex;
269dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create an intermediate plugin.
271dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = IOCreatePlugInInterfaceForService(device,
272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            kIOUSBDeviceUserClientTypeID,
273dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            kIOCFPlugInInterfaceID,
274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            &plugin, &score);
275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if ((kr != 0) || (plugin == NULL)) {
277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("Unable to create a plug-in (%08x)\n", kr);
278dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Now create the device interface.
282dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    result = (*plugin)->QueryInterface(plugin,
283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if ((result != 0) || (dev == NULL)) {
285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("Couldn't create a device interface (%08x)\n", (int) result);
286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /*
290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * We don't need the intermediate interface after the device interface
291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * is created.
292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    IODestroyPlugInInterface(plugin);
294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // So, we have a device, finally. Grab its vitals.
296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (kr != 0) {
299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("GetDeviceVendor");
300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product);
304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (kr != 0) {
305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("GetDeviceProduct");
306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class);
310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (kr != 0) {
311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("GetDeviceClass");
312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass);
316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (kr != 0) {
317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("GetDeviceSubClass");
318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol);
322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (kr != 0) {
323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("GetDeviceProtocol");
324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (serialIndex > 0) {
330dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        IOUSBDevRequest req;
331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        UInt16  buffer[256];
332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        req.bRequest = kUSBRqGetDescriptor;
335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        req.wValue = (kUSBStringDesc << 8) | serialIndex;
336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        req.wIndex = 0;
337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        req.pData = buffer;
338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        req.wLength = sizeof(buffer);
339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        kr = (*dev)->DeviceRequest(dev, &req);
340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (kr == kIOReturnSuccess && req.wLenDone > 0) {
342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            int i, count;
343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // skip first word, and copy the rest to the serial string, changing shorts to bytes.
345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            count = (req.wLenDone - 1) / 2;
346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            for (i = 0; i < count; i++)
347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project              handle->info.serial_number[i] = buffer[i + 1];
348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            handle->info.serial_number[i] = 0;
349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // device has no serial number
352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        handle->info.serial_number[0] = 0;
353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
354b4add9b74525210478bac702d27fdaf9cf7ab18fElliott Hughes    handle->info.writable = 1;
355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (try_interfaces(dev, handle)) {
357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        goto error;
358dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
359dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
360dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    (*dev)->Release(dev);
361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
362dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
363dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    error:
364dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
365dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (dev != NULL) {
366dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        (*dev)->Release(dev);
367dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
368dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
369dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return -1;
370dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
371dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
372dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
373dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Initializes the USB system. Returns 0 on success, -1 on error. */
374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int init_usb(ifc_match_func callback, usb_handle **handle) {
375dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int ret = -1;
376dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    CFMutableDictionaryRef matchingDict;
377dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    kern_return_t result;
378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    io_iterator_t iterator;
379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    usb_handle h;
380dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
381dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    h.success = 0;
382dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    h.callback = callback;
383dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
384dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /*
385dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Create our matching dictionary to find appropriate devices.
386dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * IOServiceAddMatchingNotification consumes the reference, so we
387dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * do not need to release it.
388dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
389dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
391dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (matchingDict == NULL) {
392dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("Couldn't create USB matching dictionary.\n");
393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
395dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    result = IOServiceGetMatchingServices(
397dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            kIOMasterPortDefault, matchingDict, &iterator);
398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result != 0) {
400dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("Could not create iterator.");
401dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
402dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
403dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
404dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (;;) {
405dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (! IOIteratorIsValid(iterator)) {
406dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            /*
407dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project             * Apple documentation advises resetting the iterator if
408dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project             * it should become invalid during iteration.
409dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project             */
410dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            IOIteratorReset(iterator);
411dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
412dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
413dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
414dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        io_service_t device = IOIteratorNext(iterator);
415dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
416dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (device == 0) {
417dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
418dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
419dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
420dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (try_device(device, &h) != 0) {
421dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            IOObjectRelease(device);
422dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            ret = -1;
423dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
424dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
425dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
426dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (h.success) {
427dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            *handle = calloc(1, sizeof(usb_handle));
428dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            memcpy(*handle, &h, sizeof(usb_handle));
429dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            ret = 0;
430dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
431dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
432dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
433dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        IOObjectRelease(device);
434dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
435dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
436dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    IOObjectRelease(iterator);
437dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
438dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return ret;
439dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
440dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
441dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
442dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
443dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
444dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Definitions of this file's public functions.
445dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
446dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
447dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectusb_handle *usb_open(ifc_match_func callback) {
448dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    usb_handle *handle = NULL;
449dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
450dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (init_usb(callback, &handle) < 0) {
451dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        /* Something went wrong initializing USB. */
452dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
453dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
454dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
455dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return handle;
456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
457dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
458dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint usb_close(usb_handle *h) {
459dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* TODO: Something better here? */
460dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
461dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
462dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint usb_read(usb_handle *h, void *data, int len) {
464dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    IOReturn result;
465dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    UInt32 numBytes = len;
466dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
467dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len == 0) {
468dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
469dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
470dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
471dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (h == NULL) {
472dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
473dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
474dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
475dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (h->interface == NULL) {
476dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("usb_read interface was null\n");
477dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
478dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
479dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
480dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (h->bulkIn == 0) {
481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("bulkIn endpoint not assigned\n");
482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
483dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
484dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
485dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    result = (*h->interface)->ReadPipe(
486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            h->interface, h->bulkIn, data, &numBytes);
487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
488dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result == 0) {
489dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return (int) numBytes;
490dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
491dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("usb_read failed with status %x\n", result);
492dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
493dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
494dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return -1;
495dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
496dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
497dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint usb_write(usb_handle *h, const void *data, int len) {
498dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    IOReturn result;
499dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
500dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len == 0) {
501dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
502dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
503dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
504dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (h == NULL) {
505dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
506dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
507dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
508dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (h->interface == NULL) {
509dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("usb_write interface was null\n");
510dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
511dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
512dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
513dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (h->bulkOut == 0) {
514dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("bulkOut endpoint not assigned\n");
515dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
516dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
517dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
518dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    result = (*h->interface)->WritePipe(
519dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            h->interface, h->bulkOut, (void *)data, len);
520dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
521dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    #if 0
522dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if ((result == 0) && (h->zero_mask)) {
523dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        /* we need 0-markers and our transfer */
524dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if(!(len & h->zero_mask)) {
525dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            result = (*h->interface)->WritePipe(
526dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    h->interface, h->bulkOut, (void *)data, 0);
527dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
528dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
529dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    #endif
530dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
531dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result != 0) {
532dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        ERR("usb_write failed with status %x\n", result);
533dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
534dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
535dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
536dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return len;
537dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
538