usb_osx.c revision a481d096feba7cf6e61d54e416a68e2d46498df1
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <CoreFoundation/CoreFoundation.h> 18 19#include <IOKit/IOKitLib.h> 20#include <IOKit/IOCFPlugIn.h> 21#include <IOKit/usb/IOUSBLib.h> 22#include <IOKit/IOMessage.h> 23#include <mach/mach_port.h> 24 25#include "sysdeps.h" 26 27#include <stdio.h> 28 29#define TRACE_TAG TRACE_USB 30#include "adb.h" 31#include "usb_vendors.h" 32 33#define DBG D 34 35static IONotificationPortRef notificationPort = 0; 36static io_iterator_t* notificationIterators; 37 38struct usb_handle 39{ 40 UInt8 bulkIn; 41 UInt8 bulkOut; 42 IOUSBInterfaceInterface **interface; 43 io_object_t usbNotification; 44 unsigned int zero_mask; 45}; 46 47static CFRunLoopRef currentRunLoop = 0; 48static pthread_mutex_t start_lock; 49static pthread_cond_t start_cond; 50 51 52static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator); 53static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator, 54 natural_t messageType, 55 void *messageArgument); 56static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface, 57 UInt16 vendor, UInt16 product); 58 59static int 60InitUSB() 61{ 62 CFMutableDictionaryRef matchingDict; 63 CFRunLoopSourceRef runLoopSource; 64 SInt32 vendor, if_subclass, if_protocol; 65 unsigned i; 66 67 //* To set up asynchronous notifications, create a notification port and 68 //* add its run loop event source to the program's run loop 69 notificationPort = IONotificationPortCreate(kIOMasterPortDefault); 70 runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); 71 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); 72 73 memset(notificationIterators, 0, sizeof(notificationIterators)); 74 75 //* loop through all supported vendors 76 for (i = 0; i < vendorIdCount; i++) { 77 //* Create our matching dictionary to find the Android device's 78 //* adb interface 79 //* IOServiceAddMatchingNotification consumes the reference, so we do 80 //* not need to release this 81 matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); 82 83 if (!matchingDict) { 84 DBG("ERR: Couldn't create USB matching dictionary.\n"); 85 return -1; 86 } 87 88 //* Match based on vendor id, interface subclass and protocol 89 vendor = vendorIds[i]; 90 if_subclass = ADB_SUBCLASS; 91 if_protocol = ADB_PROTOCOL; 92 CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), 93 CFNumberCreate(kCFAllocatorDefault, 94 kCFNumberSInt32Type, &vendor)); 95 CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), 96 CFNumberCreate(kCFAllocatorDefault, 97 kCFNumberSInt32Type, &if_subclass)); 98 CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), 99 CFNumberCreate(kCFAllocatorDefault, 100 kCFNumberSInt32Type, &if_protocol)); 101 IOServiceAddMatchingNotification( 102 notificationPort, 103 kIOFirstMatchNotification, 104 matchingDict, 105 AndroidInterfaceAdded, 106 NULL, 107 ¬ificationIterators[i]); 108 109 //* Iterate over set of matching interfaces to access already-present 110 //* devices and to arm the notification 111 AndroidInterfaceAdded(NULL, notificationIterators[i]); 112 } 113 114 return 0; 115} 116 117static void 118AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) 119{ 120 kern_return_t kr; 121 io_service_t usbDevice; 122 io_service_t usbInterface; 123 IOCFPlugInInterface **plugInInterface = NULL; 124 IOUSBInterfaceInterface220 **iface = NULL; 125 IOUSBDeviceInterface197 **dev = NULL; 126 HRESULT result; 127 SInt32 score; 128 UInt16 vendor; 129 UInt16 product; 130 UInt8 serialIndex; 131 char serial[256]; 132 133 while ((usbInterface = IOIteratorNext(iterator))) { 134 //* Create an intermediate interface plugin 135 kr = IOCreatePlugInInterfaceForService(usbInterface, 136 kIOUSBInterfaceUserClientTypeID, 137 kIOCFPlugInInterfaceID, 138 &plugInInterface, &score); 139 IOObjectRelease(usbInterface); 140 if ((kIOReturnSuccess != kr) || (!plugInInterface)) { 141 DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr); 142 continue; 143 } 144 145 //* This gets us the interface object 146 result = (*plugInInterface)->QueryInterface(plugInInterface, 147 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) 148 &iface); 149 //* We only needed the plugin to get the interface, so discard it 150 (*plugInInterface)->Release(plugInInterface); 151 if (result || !iface) { 152 DBG("ERR: Couldn't query the interface (%08x)\n", (int) result); 153 continue; 154 } 155 156 //* this gets us an ioservice, with which we will find the actual 157 //* device; after getting a plugin, and querying the interface, of 158 //* course. 159 //* Gotta love OS X 160 kr = (*iface)->GetDevice(iface, &usbDevice); 161 if (kIOReturnSuccess != kr || !usbDevice) { 162 DBG("ERR: Couldn't grab device from interface (%08x)\n", kr); 163 continue; 164 } 165 166 plugInInterface = NULL; 167 score = 0; 168 //* create an intermediate device plugin 169 kr = IOCreatePlugInInterfaceForService(usbDevice, 170 kIOUSBDeviceUserClientTypeID, 171 kIOCFPlugInInterfaceID, 172 &plugInInterface, &score); 173 //* only needed this to find the plugin 174 (void)IOObjectRelease(usbDevice); 175 if ((kIOReturnSuccess != kr) || (!plugInInterface)) { 176 DBG("ERR: Unable to create a device plug-in (%08x)\n", kr); 177 continue; 178 } 179 180 result = (*plugInInterface)->QueryInterface(plugInInterface, 181 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); 182 //* only needed this to query the plugin 183 (*plugInInterface)->Release(plugInInterface); 184 if (result || !dev) { 185 DBG("ERR: Couldn't create a device interface (%08x)\n", 186 (int) result); 187 continue; 188 } 189 190 //* Now after all that, we actually have a ref to the device and 191 //* the interface that matched our criteria 192 193 kr = (*dev)->GetDeviceVendor(dev, &vendor); 194 kr = (*dev)->GetDeviceProduct(dev, &product); 195 kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex); 196 197 if (serialIndex > 0) { 198 IOUSBDevRequest req; 199 UInt16 buffer[256]; 200 201 req.bmRequestType = 202 USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); 203 req.bRequest = kUSBRqGetDescriptor; 204 req.wValue = (kUSBStringDesc << 8) | serialIndex; 205 req.wIndex = 0; 206 req.pData = buffer; 207 req.wLength = sizeof(buffer); 208 kr = (*dev)->DeviceRequest(dev, &req); 209 210 if (kr == kIOReturnSuccess && req.wLenDone > 0) { 211 int i, count; 212 213 // skip first word, and copy the rest to the serial string, 214 // changing shorts to bytes. 215 count = (req.wLenDone - 1) / 2; 216 for (i = 0; i < count; i++) 217 serial[i] = buffer[i + 1]; 218 serial[i] = 0; 219 } 220 } 221 (*dev)->Release(dev); 222 223 DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product, 224 serial); 225 226 usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface, 227 vendor, product); 228 if (handle == NULL) { 229 DBG("ERR: Could not find device interface: %08x\n", kr); 230 (*iface)->Release(iface); 231 continue; 232 } 233 234 DBG("AndroidDeviceAdded calling register_usb_transport\n"); 235 register_usb_transport(handle, (serial[0] ? serial : NULL)); 236 237 // Register for an interest notification of this device being removed. 238 // Pass the reference to our private data as the refCon for the 239 // notification. 240 kr = IOServiceAddInterestNotification(notificationPort, 241 usbInterface, 242 kIOGeneralInterest, 243 AndroidInterfaceNotify, 244 handle, 245 &handle->usbNotification); 246 247 if (kIOReturnSuccess != kr) { 248 DBG("ERR: Unable to create interest notification (%08x)\n", kr); 249 } 250 } 251} 252 253static void 254AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) 255{ 256 usb_handle *handle = (usb_handle *)refCon; 257 258 if (messageType == kIOMessageServiceIsTerminated) { 259 if (!handle) { 260 DBG("ERR: NULL handle\n"); 261 return; 262 } 263 DBG("AndroidInterfaceNotify\n"); 264 IOObjectRelease(handle->usbNotification); 265 usb_kick(handle); 266 } 267} 268 269//* TODO: simplify this further since we only register to get ADB interface 270//* subclass+protocol events 271static usb_handle* 272CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product) 273{ 274 usb_handle* handle = NULL; 275 IOReturn kr; 276 UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol; 277 UInt8 endpoint; 278 279 280 //* Now open the interface. This will cause the pipes associated with 281 //* the endpoints in the interface descriptor to be instantiated 282 kr = (*interface)->USBInterfaceOpen(interface); 283 if (kr != kIOReturnSuccess) { 284 DBG("ERR: Could not open interface: (%08x)\n", kr); 285 return NULL; 286 } 287 288 //* Get the number of endpoints associated with this interface 289 kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints); 290 if (kr != kIOReturnSuccess) { 291 DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr); 292 goto err_get_num_ep; 293 } 294 295 //* Get interface class, subclass and protocol 296 if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess || 297 (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess || 298 (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) { 299 DBG("ERR: Unable to get interface class, subclass and protocol\n"); 300 goto err_get_interface_class; 301 } 302 303 //* check to make sure interface class, subclass and protocol match ADB 304 //* avoid opening mass storage endpoints 305 if (!is_adb_interface(vendor, product, interfaceClass, 306 interfaceSubClass, interfaceProtocol)) 307 goto err_bad_adb_interface; 308 309 handle = calloc(1, sizeof(usb_handle)); 310 311 //* Iterate over the endpoints for this interface and find the first 312 //* bulk in/out pipes available. These will be our read/write pipes. 313 for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { 314 UInt8 transferType; 315 UInt16 maxPacketSize; 316 UInt8 interval; 317 UInt8 number; 318 UInt8 direction; 319 320 kr = (*interface)->GetPipeProperties(interface, endpoint, &direction, 321 &number, &transferType, &maxPacketSize, &interval); 322 323 if (kIOReturnSuccess == kr) { 324 if (kUSBBulk != transferType) 325 continue; 326 327 if (kUSBIn == direction) 328 handle->bulkIn = endpoint; 329 330 if (kUSBOut == direction) 331 handle->bulkOut = endpoint; 332 333 handle->zero_mask = maxPacketSize - 1; 334 } else { 335 DBG("ERR: FindDeviceInterface - could not get pipe properties\n"); 336 goto err_get_pipe_props; 337 } 338 } 339 340 handle->interface = interface; 341 return handle; 342 343err_get_pipe_props: 344 free(handle); 345err_bad_adb_interface: 346err_get_interface_class: 347err_get_num_ep: 348 (*interface)->USBInterfaceClose(interface); 349 return NULL; 350} 351 352 353void* RunLoopThread(void* unused) 354{ 355 unsigned i; 356 357 InitUSB(); 358 359 currentRunLoop = CFRunLoopGetCurrent(); 360 361 // Signal the parent that we are running 362 adb_mutex_lock(&start_lock); 363 adb_cond_signal(&start_cond); 364 adb_mutex_unlock(&start_lock); 365 366 CFRunLoopRun(); 367 currentRunLoop = 0; 368 369 for (i = 0; i < vendorIdCount; i++) { 370 IOObjectRelease(notificationIterators[i]); 371 } 372 IONotificationPortDestroy(notificationPort); 373 374 DBG("RunLoopThread done\n"); 375 return NULL; 376} 377 378 379static int initialized = 0; 380void usb_init() 381{ 382 if (!initialized) 383 { 384 adb_thread_t tid; 385 386 notificationIterators = (io_iterator_t*)malloc( 387 vendorIdCount * sizeof(io_iterator_t)); 388 389 adb_mutex_init(&start_lock, NULL); 390 adb_cond_init(&start_cond, NULL); 391 392 if(adb_thread_create(&tid, RunLoopThread, NULL)) 393 fatal_errno("cannot create input thread"); 394 395 // Wait for initialization to finish 396 adb_mutex_lock(&start_lock); 397 adb_cond_wait(&start_cond, &start_lock); 398 adb_mutex_unlock(&start_lock); 399 400 adb_mutex_destroy(&start_lock); 401 adb_cond_destroy(&start_cond); 402 403 initialized = 1; 404 } 405} 406 407void usb_cleanup() 408{ 409 DBG("usb_cleanup\n"); 410 close_usb_devices(); 411 if (currentRunLoop) 412 CFRunLoopStop(currentRunLoop); 413 414 if (notificationIterators != NULL) { 415 free(notificationIterators); 416 notificationIterators = NULL; 417 } 418} 419 420int usb_write(usb_handle *handle, const void *buf, int len) 421{ 422 IOReturn result; 423 424 if (!len) 425 return 0; 426 427 if (!handle) 428 return -1; 429 430 if (NULL == handle->interface) { 431 DBG("ERR: usb_write interface was null\n"); 432 return -1; 433 } 434 435 if (0 == handle->bulkOut) { 436 DBG("ERR: bulkOut endpoint not assigned\n"); 437 return -1; 438 } 439 440 result = 441 (*handle->interface)->WritePipe( 442 handle->interface, handle->bulkOut, (void *)buf, len); 443 444 if ((result == 0) && (handle->zero_mask)) { 445 /* we need 0-markers and our transfer */ 446 if(!(len & handle->zero_mask)) { 447 result = 448 (*handle->interface)->WritePipe( 449 handle->interface, handle->bulkOut, (void *)buf, 0); 450 } 451 } 452 453 if (0 == result) 454 return 0; 455 456 DBG("ERR: usb_write failed with status %d\n", result); 457 return -1; 458} 459 460int usb_read(usb_handle *handle, void *buf, int len) 461{ 462 IOReturn result; 463 UInt32 numBytes = len; 464 465 if (!len) { 466 return 0; 467 } 468 469 if (!handle) { 470 return -1; 471 } 472 473 if (NULL == handle->interface) { 474 DBG("ERR: usb_read interface was null\n"); 475 return -1; 476 } 477 478 if (0 == handle->bulkIn) { 479 DBG("ERR: bulkIn endpoint not assigned\n"); 480 return -1; 481 } 482 483 result = 484 (*handle->interface)->ReadPipe(handle->interface, 485 handle->bulkIn, buf, &numBytes); 486 487 if (0 == result) 488 return 0; 489 else { 490 DBG("ERR: usb_read failed with status %d\n", result); 491 } 492 493 return -1; 494} 495 496int usb_close(usb_handle *handle) 497{ 498 return 0; 499} 500 501void usb_kick(usb_handle *handle) 502{ 503 /* release the interface */ 504 if (!handle) 505 return; 506 507 if (handle->interface) 508 { 509 (*handle->interface)->USBInterfaceClose(handle->interface); 510 (*handle->interface)->Release(handle->interface); 511 handle->interface = 0; 512 } 513} 514