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