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