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