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     UInt8 configuration;
     96 
     97     // Placing the constant KIOUSBFindInterfaceDontCare into the following
     98     // fields of the IOUSBFindInterfaceRequest structure will allow us to
     99     // find all of the interfaces
    100     request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
    101     request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
    102     request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
    103     request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
    104 
    105     // SetConfiguration will kill an existing UMS connection, so let's
    106     // not do this if not necessary.
    107     configuration = 0;
    108     (*dev)->GetConfiguration(dev, &configuration);
    109     if (configuration != 1)
    110         (*dev)->SetConfiguration(dev, 1);
    111 
    112     // Get an iterator for the interfaces on the device
    113     kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
    114 
    115     if (kr != 0) {
    116         ERR("Couldn't create a device interface iterator: (%08x)\n", kr);
    117         return -1;
    118     }
    119 
    120     while ((usbInterface = IOIteratorNext(iterator))) {
    121         // Create an intermediate plugin
    122         kr = IOCreatePlugInInterfaceForService(
    123                 usbInterface,
    124                 kIOUSBInterfaceUserClientTypeID,
    125                 kIOCFPlugInInterfaceID,
    126                 &plugInInterface,
    127                 &score);
    128 
    129         // No longer need the usbInterface object now that we have the plugin
    130         (void) IOObjectRelease(usbInterface);
    131 
    132         if ((kr != 0) || (!plugInInterface)) {
    133             WARN("Unable to create plugin (%08x)\n", kr);
    134             continue;
    135         }
    136 
    137         // Now create the interface interface for the interface
    138         result = (*plugInInterface)->QueryInterface(
    139                 plugInInterface,
    140                 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
    141                 (LPVOID*) &interface);
    142 
    143         // No longer need the intermediate plugin
    144         (*plugInInterface)->Release(plugInInterface);
    145 
    146         if (result || !interface) {
    147             ERR("Couldn't create interface interface: (%08x)\n",
    148                (unsigned int) result);
    149             // continue so we can try the next interface
    150             continue;
    151         }
    152 
    153         /*
    154          * Now open the interface. This will cause the pipes
    155          * associated with the endpoints in the interface descriptor
    156          * to be instantiated.
    157          */
    158 
    159         /*
    160          * TODO: Earlier comments here indicated that it was a bad
    161          * idea to just open any interface, because opening "mass
    162          * storage endpoints" is bad. However, the only way to find
    163          * out if an interface does bulk in or out is to open it, and
    164          * the framework in this application wants to be told about
    165          * bulk in / out before deciding whether it actually wants to
    166          * use the interface. Maybe something needs to be done about
    167          * this situation.
    168          */
    169 
    170         kr = (*interface)->USBInterfaceOpen(interface);
    171 
    172         if (kr != 0) {
    173             WARN("Could not open interface: (%08x)\n", kr);
    174             (void) (*interface)->Release(interface);
    175             // continue so we can try the next interface
    176             continue;
    177         }
    178 
    179         // Get the number of endpoints associated with this interface.
    180         kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
    181 
    182         if (kr != 0) {
    183             ERR("Unable to get number of endpoints: (%08x)\n", kr);
    184             goto next_interface;
    185         }
    186 
    187         // Get interface class, subclass and protocol
    188         if ((*interface)->GetInterfaceClass(interface, &handle->info.ifc_class) != 0 ||
    189             (*interface)->GetInterfaceSubClass(interface, &handle->info.ifc_subclass) != 0 ||
    190             (*interface)->GetInterfaceProtocol(interface, &handle->info.ifc_protocol) != 0)
    191         {
    192             ERR("Unable to get interface class, subclass and protocol\n");
    193             goto next_interface;
    194         }
    195 
    196         handle->info.has_bulk_in = 0;
    197         handle->info.has_bulk_out = 0;
    198 
    199         // Iterate over the endpoints for this interface and see if there
    200         // are any that do bulk in/out.
    201         for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
    202             UInt8   transferType;
    203             UInt16  maxPacketSize;
    204             UInt8   interval;
    205             UInt8   number;
    206             UInt8   direction;
    207 
    208             kr = (*interface)->GetPipeProperties(interface, endpoint,
    209                     &direction,
    210                     &number, &transferType, &maxPacketSize, &interval);
    211 
    212             if (kr == 0) {
    213                 if (transferType != kUSBBulk) {
    214                     continue;
    215                 }
    216 
    217                 if (direction == kUSBIn) {
    218                     handle->info.has_bulk_in = 1;
    219                     handle->bulkIn = endpoint;
    220                 } else if (direction == kUSBOut) {
    221                     handle->info.has_bulk_out = 1;
    222                     handle->bulkOut = endpoint;
    223                 }
    224 
    225                 if (handle->info.ifc_protocol == 0x01) {
    226                     handle->zero_mask = maxPacketSize - 1;
    227                 }
    228             } else {
    229                 ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
    230             }
    231 
    232             if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
    233                 break;
    234             }
    235         }
    236 
    237         if (handle->callback(&handle->info) == 0) {
    238             handle->interface = interface;
    239             handle->success = 1;
    240 
    241             /*
    242              * Clear both the endpoints, because it has been observed
    243              * that the Mac may otherwise (incorrectly) start out with
    244              * them in bad state.
    245              */
    246 
    247             if (handle->info.has_bulk_in) {
    248                 kr = (*interface)->ClearPipeStallBothEnds(interface,
    249                         handle->bulkIn);
    250                 if (kr != 0) {
    251                     ERR("could not clear input pipe; result %x, ignoring...\n", kr);
    252                 }
    253             }
    254 
    255             if (handle->info.has_bulk_out) {
    256                 kr = (*interface)->ClearPipeStallBothEnds(interface,
    257                         handle->bulkOut);
    258                 if (kr != 0) {
    259                     ERR("could not clear output pipe; result %x, ignoring....\n", kr);
    260                 }
    261             }
    262 
    263             return 0;
    264         }
    265 
    266 next_interface:
    267         (*interface)->USBInterfaceClose(interface);
    268         (*interface)->Release(interface);
    269     }
    270 
    271     return 0;
    272 }
    273 
    274 /** Try out the given device and see if there's a match. Returns 0 on
    275  * success, -1 on failure.
    276  */
    277 static int try_device(io_service_t device, usb_handle *handle) {
    278     kern_return_t kr;
    279     IOCFPlugInInterface **plugin = NULL;
    280     IOUSBDeviceInterface182 **dev = NULL;
    281     SInt32 score;
    282     HRESULT result;
    283     UInt8 serialIndex;
    284     UInt32 locationId;
    285 
    286     // Create an intermediate plugin.
    287     kr = IOCreatePlugInInterfaceForService(device,
    288             kIOUSBDeviceUserClientTypeID,
    289             kIOCFPlugInInterfaceID,
    290             &plugin, &score);
    291 
    292     if ((kr != 0) || (plugin == NULL)) {
    293         ERR("Unable to create a plug-in (%08x)\n", kr);
    294         goto error;
    295     }
    296 
    297     // Now create the device interface.
    298     result = (*plugin)->QueryInterface(plugin,
    299             CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
    300     if ((result != 0) || (dev == NULL)) {
    301         ERR("Couldn't create a device interface (%08x)\n", (int) result);
    302         goto error;
    303     }
    304 
    305     /*
    306      * We don't need the intermediate interface after the device interface
    307      * is created.
    308      */
    309     IODestroyPlugInInterface(plugin);
    310 
    311     // So, we have a device, finally. Grab its vitals.
    312 
    313 
    314     kr = (*dev)->USBDeviceOpen(dev);
    315     if (kr != 0) {
    316         WARN("USBDeviceOpen");
    317         goto out;
    318     }
    319 
    320     kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
    321     if (kr != 0) {
    322         ERR("GetDeviceVendor");
    323         goto error;
    324     }
    325 
    326     kr = (*dev)->GetDeviceProduct(dev, &handle->info.dev_product);
    327     if (kr != 0) {
    328         ERR("GetDeviceProduct");
    329         goto error;
    330     }
    331 
    332     kr = (*dev)->GetDeviceClass(dev, &handle->info.dev_class);
    333     if (kr != 0) {
    334         ERR("GetDeviceClass");
    335         goto error;
    336     }
    337 
    338     kr = (*dev)->GetDeviceSubClass(dev, &handle->info.dev_subclass);
    339     if (kr != 0) {
    340         ERR("GetDeviceSubClass");
    341         goto error;
    342     }
    343 
    344     kr = (*dev)->GetDeviceProtocol(dev, &handle->info.dev_protocol);
    345     if (kr != 0) {
    346         ERR("GetDeviceProtocol");
    347         goto error;
    348     }
    349 
    350     kr = (*dev)->GetLocationID(dev, &locationId);
    351     if (kr != 0) {
    352         ERR("GetLocationId");
    353         goto error;
    354     }
    355     snprintf(handle->info.device_path, sizeof(handle->info.device_path),
    356              "usb:%" PRIu32 "X", (unsigned int)locationId);
    357 
    358     kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
    359 
    360     if (serialIndex > 0) {
    361         IOUSBDevRequest req;
    362         UInt16  buffer[256];
    363 
    364         req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
    365         req.bRequest = kUSBRqGetDescriptor;
    366         req.wValue = (kUSBStringDesc << 8) | serialIndex;
    367         //language ID (en-us) for serial number string
    368         req.wIndex = 0x0409;
    369         req.pData = buffer;
    370         req.wLength = sizeof(buffer);
    371         kr = (*dev)->DeviceRequest(dev, &req);
    372 
    373         if (kr == kIOReturnSuccess && req.wLenDone > 0) {
    374             int i, count;
    375 
    376             // skip first word, and copy the rest to the serial string, changing shorts to bytes.
    377             count = (req.wLenDone - 1) / 2;
    378             for (i = 0; i < count; i++)
    379               handle->info.serial_number[i] = buffer[i + 1];
    380             handle->info.serial_number[i] = 0;
    381         }
    382     } else {
    383         // device has no serial number
    384         handle->info.serial_number[0] = 0;
    385     }
    386     handle->info.writable = 1;
    387 
    388     if (try_interfaces(dev, handle)) {
    389         goto error;
    390     }
    391 
    392     out:
    393 
    394     (*dev)->USBDeviceClose(dev);
    395     (*dev)->Release(dev);
    396     return 0;
    397 
    398     error:
    399 
    400     if (dev != NULL) {
    401         (*dev)->USBDeviceClose(dev);
    402         (*dev)->Release(dev);
    403     }
    404 
    405     return -1;
    406 }
    407 
    408 
    409 /** Initializes the USB system. Returns 0 on success, -1 on error. */
    410 static int init_usb(ifc_match_func callback, std::unique_ptr<usb_handle>* handle) {
    411     int ret = -1;
    412     CFMutableDictionaryRef matchingDict;
    413     kern_return_t result;
    414     io_iterator_t iterator;
    415     usb_handle h;
    416 
    417     h.success = 0;
    418     h.callback = callback;
    419 
    420     /*
    421      * Create our matching dictionary to find appropriate devices.
    422      * IOServiceAddMatchingNotification consumes the reference, so we
    423      * do not need to release it.
    424      */
    425     matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
    426 
    427     if (matchingDict == NULL) {
    428         ERR("Couldn't create USB matching dictionary.\n");
    429         return -1;
    430     }
    431 
    432     result = IOServiceGetMatchingServices(
    433             kIOMasterPortDefault, matchingDict, &iterator);
    434 
    435     if (result != 0) {
    436         ERR("Could not create iterator.");
    437         return -1;
    438     }
    439 
    440     for (;;) {
    441         if (! IOIteratorIsValid(iterator)) {
    442             /*
    443              * Apple documentation advises resetting the iterator if
    444              * it should become invalid during iteration.
    445              */
    446             IOIteratorReset(iterator);
    447             continue;
    448         }
    449 
    450         io_service_t device = IOIteratorNext(iterator);
    451 
    452         if (device == 0) {
    453             break;
    454         }
    455 
    456         if (try_device(device, &h) != 0) {
    457             IOObjectRelease(device);
    458             ret = -1;
    459             break;
    460         }
    461 
    462         if (h.success) {
    463             handle->reset(new usb_handle);
    464             memcpy(handle->get(), &h, sizeof(usb_handle));
    465             ret = 0;
    466             break;
    467         }
    468 
    469         IOObjectRelease(device);
    470     }
    471 
    472     IOObjectRelease(iterator);
    473 
    474     return ret;
    475 }
    476 
    477 
    478 
    479 /*
    480  * Definitions of this file's public functions.
    481  */
    482 
    483 Transport* usb_open(ifc_match_func callback) {
    484     std::unique_ptr<usb_handle> handle;
    485 
    486     if (init_usb(callback, &handle) < 0) {
    487         /* Something went wrong initializing USB. */
    488         return nullptr;
    489     }
    490 
    491     return new OsxUsbTransport(std::move(handle));
    492 }
    493 
    494 int OsxUsbTransport::Close() {
    495     /* TODO: Something better here? */
    496     return 0;
    497 }
    498 
    499 ssize_t OsxUsbTransport::Read(void* data, size_t len) {
    500     IOReturn result;
    501     UInt32 numBytes = len;
    502 
    503     if (len == 0) {
    504         return 0;
    505     }
    506 
    507     if (handle_ == nullptr) {
    508         return -1;
    509     }
    510 
    511     if (handle_->interface == nullptr) {
    512         ERR("usb_read interface was null\n");
    513         return -1;
    514     }
    515 
    516     if (handle_->bulkIn == 0) {
    517         ERR("bulkIn endpoint not assigned\n");
    518         return -1;
    519     }
    520 
    521     result = (*handle_->interface)->ReadPipe(handle_->interface, handle_->bulkIn, data, &numBytes);
    522 
    523     if (result == 0) {
    524         return (int) numBytes;
    525     } else {
    526         ERR("usb_read failed with status %x\n", result);
    527     }
    528 
    529     return -1;
    530 }
    531 
    532 ssize_t OsxUsbTransport::Write(const void* data, size_t len) {
    533     IOReturn result;
    534 
    535     if (len == 0) {
    536         return 0;
    537     }
    538 
    539     if (handle_ == NULL) {
    540         return -1;
    541     }
    542 
    543     if (handle_->interface == NULL) {
    544         ERR("usb_write interface was null\n");
    545         return -1;
    546     }
    547 
    548     if (handle_->bulkOut == 0) {
    549         ERR("bulkOut endpoint not assigned\n");
    550         return -1;
    551     }
    552 
    553 #if 0
    554     result = (*handle_->interface)->WritePipe(
    555             handle_->interface, handle_->bulkOut, (void *)data, len);
    556 #else
    557     /* Attempt to work around crashes in the USB driver that may be caused
    558      * by trying to write too much data at once.  The kernel IOCopyMapper
    559      * panics if a single iovmAlloc needs more than half of its mapper pages.
    560      */
    561     const int maxLenToSend = 1048576; // 1 MiB
    562     int lenRemaining = len;
    563     result = 0;
    564     while (lenRemaining > 0) {
    565         int lenToSend = lenRemaining > maxLenToSend
    566             ? maxLenToSend : lenRemaining;
    567 
    568         result = (*handle_->interface)->WritePipe(
    569                 handle_->interface, handle_->bulkOut, (void *)data, lenToSend);
    570         if (result != 0) break;
    571 
    572         lenRemaining -= lenToSend;
    573         data = (const char*)data + lenToSend;
    574     }
    575 #endif
    576 
    577     #if 0
    578     if ((result == 0) && (handle_->zero_mask)) {
    579         /* we need 0-markers and our transfer */
    580         if(!(len & handle_->zero_mask)) {
    581             result = (*handle_->interface)->WritePipe(
    582                     handle_->interface, handle_->bulkOut, (void *)data, 0);
    583         }
    584     }
    585     #endif
    586 
    587     if (result != 0) {
    588         ERR("usb_write failed with status %x\n", result);
    589         return -1;
    590     }
    591 
    592     return len;
    593 }
    594