1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/gamepad/xbox_data_fetcher_mac.h" 6 7 #include <algorithm> 8 #include <cmath> 9 #include <limits> 10 11 #include <CoreFoundation/CoreFoundation.h> 12 #include <IOKit/IOCFPlugIn.h> 13 #include <IOKit/IOKitLib.h> 14 #include <IOKit/usb/IOUSBLib.h> 15 #include <IOKit/usb/USB.h> 16 17 #include "base/logging.h" 18 #include "base/mac/foundation_util.h" 19 20 namespace { 21 const int kVendorMicrosoft = 0x045e; 22 const int kProductXbox360Controller = 0x028e; 23 const int kProductXboxOneController = 0x02d1; 24 25 const int kXbox360ReadEndpoint = 1; 26 const int kXbox360ControlEndpoint = 2; 27 28 const int kXboxOneReadEndpoint = 2; 29 const int kXboxOneControlEndpoint = 1; 30 31 enum { 32 STATUS_MESSAGE_BUTTONS = 0, 33 STATUS_MESSAGE_LED = 1, 34 35 // Apparently this message tells you if the rumble pack is disabled in the 36 // controller. If the rumble pack is disabled, vibration control messages 37 // have no effect. 38 STATUS_MESSAGE_RUMBLE = 3, 39 }; 40 41 enum { 42 XBOX_ONE_STATUS_MESSAGE_BUTTONS = 0x20, 43 }; 44 45 enum { 46 CONTROL_MESSAGE_SET_RUMBLE = 0, 47 CONTROL_MESSAGE_SET_LED = 1, 48 }; 49 50 #pragma pack(push, 1) 51 struct Xbox360ButtonData { 52 bool dpad_up : 1; 53 bool dpad_down : 1; 54 bool dpad_left : 1; 55 bool dpad_right : 1; 56 57 bool start : 1; 58 bool back : 1; 59 bool stick_left_click : 1; 60 bool stick_right_click : 1; 61 62 bool bumper_left : 1; 63 bool bumper_right : 1; 64 bool guide : 1; 65 bool dummy1 : 1; // Always 0. 66 67 bool a : 1; 68 bool b : 1; 69 bool x : 1; 70 bool y : 1; 71 72 uint8 trigger_left; 73 uint8 trigger_right; 74 75 int16 stick_left_x; 76 int16 stick_left_y; 77 int16 stick_right_x; 78 int16 stick_right_y; 79 80 // Always 0. 81 uint32 dummy2; 82 uint16 dummy3; 83 }; 84 85 struct XboxOneButtonData { 86 bool sync : 1; 87 bool dummy1 : 1; // Always 0. 88 bool start : 1; 89 bool back : 1; 90 91 bool a : 1; 92 bool b : 1; 93 bool x : 1; 94 bool y : 1; 95 96 bool dpad_up : 1; 97 bool dpad_down : 1; 98 bool dpad_left : 1; 99 bool dpad_right : 1; 100 101 bool bumper_left : 1; 102 bool bumper_right : 1; 103 bool stick_left_click : 1; 104 bool stick_right_click : 1; 105 106 uint16 trigger_left; 107 uint16 trigger_right; 108 109 int16 stick_left_x; 110 int16 stick_left_y; 111 int16 stick_right_x; 112 int16 stick_right_y; 113 }; 114 #pragma pack(pop) 115 116 COMPILE_ASSERT(sizeof(Xbox360ButtonData) == 18, xbox_button_data_wrong_size); 117 COMPILE_ASSERT(sizeof(XboxOneButtonData) == 14, xbox_button_data_wrong_size); 118 119 // From MSDN: 120 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee417001(v=vs.85).aspx#dead_zone 121 const int16 kLeftThumbDeadzone = 7849; 122 const int16 kRightThumbDeadzone = 8689; 123 const uint8 kXbox360TriggerDeadzone = 30; 124 const uint16 kXboxOneTriggerMax = 1023; 125 const uint16 kXboxOneTriggerDeadzone = 120; 126 127 void NormalizeAxis(int16 x, 128 int16 y, 129 int16 deadzone, 130 float* x_out, 131 float* y_out) { 132 float x_val = x; 133 float y_val = y; 134 135 // Determine how far the stick is pushed. 136 float real_magnitude = std::sqrt(x_val * x_val + y_val * y_val); 137 138 // Check if the controller is outside a circular dead zone. 139 if (real_magnitude > deadzone) { 140 // Clip the magnitude at its expected maximum value. 141 float magnitude = std::min(32767.0f, real_magnitude); 142 143 // Adjust magnitude relative to the end of the dead zone. 144 magnitude -= deadzone; 145 146 // Normalize the magnitude with respect to its expected range giving a 147 // magnitude value of 0.0 to 1.0 148 float ratio = (magnitude / (32767 - deadzone)) / real_magnitude; 149 150 // Y is negated because xbox controllers have an opposite sign from 151 // the 'standard controller' recommendations. 152 *x_out = x_val * ratio; 153 *y_out = -y_val * ratio; 154 } else { 155 // If the controller is in the deadzone zero out the magnitude. 156 *x_out = *y_out = 0.0f; 157 } 158 } 159 160 float NormalizeTrigger(uint8 value) { 161 return value < kXbox360TriggerDeadzone ? 0 : 162 static_cast<float>(value - kXbox360TriggerDeadzone) / 163 (std::numeric_limits<uint8>::max() - kXbox360TriggerDeadzone); 164 } 165 166 float NormalizeXboxOneTrigger(uint16 value) { 167 return value < kXboxOneTriggerDeadzone ? 0 : 168 static_cast<float>(value - kXboxOneTriggerDeadzone) / 169 (kXboxOneTriggerMax - kXboxOneTriggerDeadzone); 170 } 171 172 void NormalizeXbox360ButtonData(const Xbox360ButtonData& data, 173 XboxController::Data* normalized_data) { 174 normalized_data->buttons[0] = data.a; 175 normalized_data->buttons[1] = data.b; 176 normalized_data->buttons[2] = data.x; 177 normalized_data->buttons[3] = data.y; 178 normalized_data->buttons[4] = data.bumper_left; 179 normalized_data->buttons[5] = data.bumper_right; 180 normalized_data->buttons[6] = data.back; 181 normalized_data->buttons[7] = data.start; 182 normalized_data->buttons[8] = data.stick_left_click; 183 normalized_data->buttons[9] = data.stick_right_click; 184 normalized_data->buttons[10] = data.dpad_up; 185 normalized_data->buttons[11] = data.dpad_down; 186 normalized_data->buttons[12] = data.dpad_left; 187 normalized_data->buttons[13] = data.dpad_right; 188 normalized_data->buttons[14] = data.guide; 189 normalized_data->triggers[0] = NormalizeTrigger(data.trigger_left); 190 normalized_data->triggers[1] = NormalizeTrigger(data.trigger_right); 191 NormalizeAxis(data.stick_left_x, 192 data.stick_left_y, 193 kLeftThumbDeadzone, 194 &normalized_data->axes[0], 195 &normalized_data->axes[1]); 196 NormalizeAxis(data.stick_right_x, 197 data.stick_right_y, 198 kRightThumbDeadzone, 199 &normalized_data->axes[2], 200 &normalized_data->axes[3]); 201 } 202 203 void NormalizeXboxOneButtonData(const XboxOneButtonData& data, 204 XboxController::Data* normalized_data) { 205 normalized_data->buttons[0] = data.a; 206 normalized_data->buttons[1] = data.b; 207 normalized_data->buttons[2] = data.x; 208 normalized_data->buttons[3] = data.y; 209 normalized_data->buttons[4] = data.bumper_left; 210 normalized_data->buttons[5] = data.bumper_right; 211 normalized_data->buttons[6] = data.back; 212 normalized_data->buttons[7] = data.start; 213 normalized_data->buttons[8] = data.stick_left_click; 214 normalized_data->buttons[9] = data.stick_right_click; 215 normalized_data->buttons[10] = data.dpad_up; 216 normalized_data->buttons[11] = data.dpad_down; 217 normalized_data->buttons[12] = data.dpad_left; 218 normalized_data->buttons[13] = data.dpad_right; 219 normalized_data->buttons[14] = data.sync; 220 normalized_data->triggers[0] = NormalizeXboxOneTrigger(data.trigger_left); 221 normalized_data->triggers[1] = NormalizeXboxOneTrigger(data.trigger_right); 222 NormalizeAxis(data.stick_left_x, 223 data.stick_left_y, 224 kLeftThumbDeadzone, 225 &normalized_data->axes[0], 226 &normalized_data->axes[1]); 227 NormalizeAxis(data.stick_right_x, 228 data.stick_right_y, 229 kRightThumbDeadzone, 230 &normalized_data->axes[2], 231 &normalized_data->axes[3]); 232 } 233 234 } // namespace 235 236 XboxController::XboxController(Delegate* delegate) 237 : device_(NULL), 238 interface_(NULL), 239 device_is_open_(false), 240 interface_is_open_(false), 241 read_buffer_size_(0), 242 led_pattern_(LED_NUM_PATTERNS), 243 location_id_(0), 244 delegate_(delegate), 245 controller_type_(UNKNOWN_CONTROLLER), 246 read_endpoint_(0), 247 control_endpoint_(0) { 248 } 249 250 XboxController::~XboxController() { 251 if (source_) 252 CFRunLoopSourceInvalidate(source_); 253 if (interface_ && interface_is_open_) 254 (*interface_)->USBInterfaceClose(interface_); 255 if (device_ && device_is_open_) 256 (*device_)->USBDeviceClose(device_); 257 } 258 259 bool XboxController::OpenDevice(io_service_t service) { 260 IOCFPlugInInterface **plugin; 261 SInt32 score; // Unused, but required for IOCreatePlugInInterfaceForService. 262 kern_return_t kr = 263 IOCreatePlugInInterfaceForService(service, 264 kIOUSBDeviceUserClientTypeID, 265 kIOCFPlugInInterfaceID, 266 &plugin, 267 &score); 268 if (kr != KERN_SUCCESS) 269 return false; 270 base::mac::ScopedIOPluginInterface<IOCFPlugInInterface> plugin_ref(plugin); 271 272 HRESULT res = 273 (*plugin)->QueryInterface(plugin, 274 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID320), 275 (LPVOID *)&device_); 276 if (!SUCCEEDED(res) || !device_) 277 return false; 278 279 UInt16 vendor_id; 280 kr = (*device_)->GetDeviceVendor(device_, &vendor_id); 281 if (kr != KERN_SUCCESS || vendor_id != kVendorMicrosoft) 282 return false; 283 284 UInt16 product_id; 285 kr = (*device_)->GetDeviceProduct(device_, &product_id); 286 if (kr != KERN_SUCCESS) 287 return false; 288 289 IOUSBFindInterfaceRequest request; 290 switch (product_id) { 291 case kProductXbox360Controller: 292 controller_type_ = XBOX_360_CONTROLLER; 293 read_endpoint_ = kXbox360ReadEndpoint; 294 control_endpoint_ = kXbox360ControlEndpoint; 295 request.bInterfaceClass = 255; 296 request.bInterfaceSubClass = 93; 297 request.bInterfaceProtocol = 1; 298 request.bAlternateSetting = kIOUSBFindInterfaceDontCare; 299 break; 300 case kProductXboxOneController: 301 controller_type_ = XBOX_ONE_CONTROLLER; 302 read_endpoint_ = kXboxOneReadEndpoint; 303 control_endpoint_ = kXboxOneControlEndpoint; 304 request.bInterfaceClass = 255; 305 request.bInterfaceSubClass = 71; 306 request.bInterfaceProtocol = 208; 307 request.bAlternateSetting = kIOUSBFindInterfaceDontCare; 308 break; 309 default: 310 return false; 311 } 312 313 // Open the device and configure it. 314 kr = (*device_)->USBDeviceOpen(device_); 315 if (kr != KERN_SUCCESS) 316 return false; 317 device_is_open_ = true; 318 319 // Xbox controllers have one configuration option which has configuration 320 // value 1. Try to set it and fail if it couldn't be configured. 321 IOUSBConfigurationDescriptorPtr config_desc; 322 kr = (*device_)->GetConfigurationDescriptorPtr(device_, 0, &config_desc); 323 if (kr != KERN_SUCCESS) 324 return false; 325 kr = (*device_)->SetConfiguration(device_, config_desc->bConfigurationValue); 326 if (kr != KERN_SUCCESS) 327 return false; 328 329 // The device has 4 interfaces. They are as follows: 330 // Protocol 1: 331 // - Endpoint 1 (in) : Controller events, including button presses. 332 // - Endpoint 2 (out): Rumble pack and LED control 333 // Protocol 2 has a single endpoint to read from a connected ChatPad device. 334 // Protocol 3 is used by a connected headset device. 335 // The device also has an interface on subclass 253, protocol 10 with no 336 // endpoints. It is unused. 337 // 338 // We don't currently support the ChatPad or headset, so protocol 1 is the 339 // only protocol we care about. 340 // 341 // For more detail, see 342 // https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL 343 io_iterator_t iter; 344 kr = (*device_)->CreateInterfaceIterator(device_, &request, &iter); 345 if (kr != KERN_SUCCESS) 346 return false; 347 base::mac::ScopedIOObject<io_iterator_t> iter_ref(iter); 348 349 // There should be exactly one USB interface which matches the requested 350 // settings. 351 io_service_t usb_interface = IOIteratorNext(iter); 352 if (!usb_interface) 353 return false; 354 355 // We need to make an InterfaceInterface to communicate with the device 356 // endpoint. This is the same process as earlier: first make a 357 // PluginInterface from the io_service then make the InterfaceInterface from 358 // that. 359 IOCFPlugInInterface **plugin_interface; 360 kr = IOCreatePlugInInterfaceForService(usb_interface, 361 kIOUSBInterfaceUserClientTypeID, 362 kIOCFPlugInInterfaceID, 363 &plugin_interface, 364 &score); 365 if (kr != KERN_SUCCESS || !plugin_interface) 366 return false; 367 base::mac::ScopedIOPluginInterface<IOCFPlugInInterface> interface_ref( 368 plugin_interface); 369 370 // Release the USB interface, and any subsequent interfaces returned by the 371 // iterator. (There shouldn't be any, but in case a future device does 372 // contain more interfaces, this will serve to avoid memory leaks.) 373 do { 374 IOObjectRelease(usb_interface); 375 } while ((usb_interface = IOIteratorNext(iter))); 376 377 // Actually create the interface. 378 res = (*plugin_interface)->QueryInterface( 379 plugin_interface, 380 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID300), 381 (LPVOID *)&interface_); 382 383 if (!SUCCEEDED(res) || !interface_) 384 return false; 385 386 // Actually open the interface. 387 kr = (*interface_)->USBInterfaceOpen(interface_); 388 if (kr != KERN_SUCCESS) 389 return false; 390 interface_is_open_ = true; 391 392 CFRunLoopSourceRef source_ref; 393 kr = (*interface_)->CreateInterfaceAsyncEventSource(interface_, &source_ref); 394 if (kr != KERN_SUCCESS || !source_ref) 395 return false; 396 source_.reset(source_ref); 397 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode); 398 399 // The interface should have two pipes. Pipe 1 with direction kUSBIn and pipe 400 // 2 with direction kUSBOut. Both pipes should have type kUSBInterrupt. 401 uint8 num_endpoints; 402 kr = (*interface_)->GetNumEndpoints(interface_, &num_endpoints); 403 if (kr != KERN_SUCCESS || num_endpoints < 2) 404 return false; 405 406 for (int i = 1; i <= 2; i++) { 407 uint8 direction; 408 uint8 number; 409 uint8 transfer_type; 410 uint16 max_packet_size; 411 uint8 interval; 412 413 kr = (*interface_)->GetPipeProperties(interface_, 414 i, 415 &direction, 416 &number, 417 &transfer_type, 418 &max_packet_size, 419 &interval); 420 if (kr != KERN_SUCCESS || transfer_type != kUSBInterrupt) { 421 return false; 422 } 423 if (i == read_endpoint_) { 424 if (direction != kUSBIn) 425 return false; 426 read_buffer_.reset(new uint8[max_packet_size]); 427 read_buffer_size_ = max_packet_size; 428 QueueRead(); 429 } else if (i == control_endpoint_) { 430 if (direction != kUSBOut) 431 return false; 432 if (controller_type_ == XBOX_ONE_CONTROLLER) 433 WriteXboxOneInit(); 434 } 435 } 436 437 // The location ID is unique per controller, and can be used to track 438 // controllers through reconnections (though if a controller is detached from 439 // one USB hub and attached to another, the location ID will change). 440 kr = (*device_)->GetLocationID(device_, &location_id_); 441 if (kr != KERN_SUCCESS) 442 return false; 443 444 return true; 445 } 446 447 void XboxController::SetLEDPattern(LEDPattern pattern) { 448 led_pattern_ = pattern; 449 const UInt8 length = 3; 450 451 // This buffer will be released in WriteComplete when WritePipeAsync 452 // finishes. 453 UInt8* buffer = new UInt8[length]; 454 buffer[0] = static_cast<UInt8>(CONTROL_MESSAGE_SET_LED); 455 buffer[1] = length; 456 buffer[2] = static_cast<UInt8>(pattern); 457 kern_return_t kr = (*interface_)->WritePipeAsync(interface_, 458 control_endpoint_, 459 buffer, 460 (UInt32)length, 461 WriteComplete, 462 buffer); 463 if (kr != KERN_SUCCESS) { 464 delete[] buffer; 465 IOError(); 466 return; 467 } 468 } 469 470 int XboxController::GetVendorId() const { 471 return kVendorMicrosoft; 472 } 473 474 int XboxController::GetProductId() const { 475 if (controller_type_ == XBOX_360_CONTROLLER) 476 return kProductXbox360Controller; 477 else 478 return kProductXboxOneController; 479 } 480 481 XboxController::ControllerType XboxController::GetControllerType() const { 482 return controller_type_; 483 } 484 485 void XboxController::WriteComplete(void* context, IOReturn result, void* arg0) { 486 UInt8* buffer = static_cast<UInt8*>(context); 487 delete[] buffer; 488 489 // Ignoring any errors sending data, because they will usually only occur 490 // when the device is disconnected, in which case it really doesn't matter if 491 // the data got to the controller or not. 492 if (result != kIOReturnSuccess) 493 return; 494 } 495 496 void XboxController::GotData(void* context, IOReturn result, void* arg0) { 497 size_t bytes_read = reinterpret_cast<size_t>(arg0); 498 XboxController* controller = static_cast<XboxController*>(context); 499 500 if (result != kIOReturnSuccess) { 501 // This will happen if the device was disconnected. The gamepad has 502 // probably been destroyed by a meteorite. 503 controller->IOError(); 504 return; 505 } 506 507 if (controller->GetControllerType() == XBOX_360_CONTROLLER) 508 controller->ProcessXbox360Packet(bytes_read); 509 else 510 controller->ProcessXboxOnePacket(bytes_read); 511 512 // Queue up another read. 513 controller->QueueRead(); 514 } 515 516 void XboxController::ProcessXbox360Packet(size_t length) { 517 if (length < 2) 518 return; 519 DCHECK(length <= read_buffer_size_); 520 if (length > read_buffer_size_) { 521 IOError(); 522 return; 523 } 524 uint8* buffer = read_buffer_.get(); 525 526 if (buffer[1] != length) 527 // Length in packet doesn't match length reported by USB. 528 return; 529 530 uint8 type = buffer[0]; 531 buffer += 2; 532 length -= 2; 533 switch (type) { 534 case STATUS_MESSAGE_BUTTONS: { 535 if (length != sizeof(Xbox360ButtonData)) 536 return; 537 Xbox360ButtonData* data = reinterpret_cast<Xbox360ButtonData*>(buffer); 538 Data normalized_data; 539 NormalizeXbox360ButtonData(*data, &normalized_data); 540 delegate_->XboxControllerGotData(this, normalized_data); 541 break; 542 } 543 case STATUS_MESSAGE_LED: 544 if (length != 3) 545 return; 546 // The controller sends one of these messages every time the LED pattern 547 // is set, as well as once when it is plugged in. 548 if (led_pattern_ == LED_NUM_PATTERNS && buffer[0] < LED_NUM_PATTERNS) 549 led_pattern_ = static_cast<LEDPattern>(buffer[0]); 550 break; 551 default: 552 // Unknown packet: ignore! 553 break; 554 } 555 } 556 557 void XboxController::ProcessXboxOnePacket(size_t length) { 558 if (length < 2) 559 return; 560 DCHECK(length <= read_buffer_size_); 561 if (length > read_buffer_size_) { 562 IOError(); 563 return; 564 } 565 uint8* buffer = read_buffer_.get(); 566 567 uint8 type = buffer[0]; 568 buffer += 4; 569 length -= 4; 570 switch (type) { 571 case XBOX_ONE_STATUS_MESSAGE_BUTTONS: { 572 if (length != sizeof(XboxOneButtonData)) 573 return; 574 XboxOneButtonData* data = reinterpret_cast<XboxOneButtonData*>(buffer); 575 Data normalized_data; 576 NormalizeXboxOneButtonData(*data, &normalized_data); 577 delegate_->XboxControllerGotData(this, normalized_data); 578 break; 579 } 580 default: 581 // Unknown packet: ignore! 582 break; 583 } 584 } 585 586 void XboxController::QueueRead() { 587 kern_return_t kr = (*interface_)->ReadPipeAsync(interface_, 588 read_endpoint_, 589 read_buffer_.get(), 590 read_buffer_size_, 591 GotData, 592 this); 593 if (kr != KERN_SUCCESS) 594 IOError(); 595 } 596 597 void XboxController::IOError() { 598 delegate_->XboxControllerError(this); 599 } 600 601 void XboxController::WriteXboxOneInit() { 602 const UInt8 length = 2; 603 604 // This buffer will be released in WriteComplete when WritePipeAsync 605 // finishes. 606 UInt8* buffer = new UInt8[length]; 607 buffer[0] = 0x05; 608 buffer[1] = 0x20; 609 kern_return_t kr = (*interface_)->WritePipeAsync(interface_, 610 control_endpoint_, 611 buffer, 612 (UInt32)length, 613 WriteComplete, 614 buffer); 615 if (kr != KERN_SUCCESS) { 616 delete[] buffer; 617 IOError(); 618 return; 619 } 620 } 621 622 //----------------------------------------------------------------------------- 623 624 XboxDataFetcher::XboxDataFetcher(Delegate* delegate) 625 : delegate_(delegate), 626 listening_(false), 627 source_(NULL), 628 port_(NULL) { 629 } 630 631 XboxDataFetcher::~XboxDataFetcher() { 632 while (!controllers_.empty()) { 633 RemoveController(*controllers_.begin()); 634 } 635 UnregisterFromNotifications(); 636 } 637 638 void XboxDataFetcher::DeviceAdded(void* context, io_iterator_t iterator) { 639 DCHECK(context); 640 XboxDataFetcher* fetcher = static_cast<XboxDataFetcher*>(context); 641 io_service_t ref; 642 while ((ref = IOIteratorNext(iterator))) { 643 base::mac::ScopedIOObject<io_service_t> scoped_ref(ref); 644 XboxController* controller = new XboxController(fetcher); 645 if (controller->OpenDevice(ref)) { 646 fetcher->AddController(controller); 647 } else { 648 delete controller; 649 } 650 } 651 } 652 653 void XboxDataFetcher::DeviceRemoved(void* context, io_iterator_t iterator) { 654 DCHECK(context); 655 XboxDataFetcher* fetcher = static_cast<XboxDataFetcher*>(context); 656 io_service_t ref; 657 while ((ref = IOIteratorNext(iterator))) { 658 base::mac::ScopedIOObject<io_service_t> scoped_ref(ref); 659 base::ScopedCFTypeRef<CFNumberRef> number( 660 base::mac::CFCastStrict<CFNumberRef>( 661 IORegistryEntryCreateCFProperty(ref, 662 CFSTR(kUSBDevicePropertyLocationID), 663 kCFAllocatorDefault, 664 kNilOptions))); 665 UInt32 location_id = 0; 666 CFNumberGetValue(number, kCFNumberSInt32Type, &location_id); 667 fetcher->RemoveControllerByLocationID(location_id); 668 } 669 } 670 671 bool XboxDataFetcher::RegisterForNotifications() { 672 if (listening_) 673 return true; 674 port_ = IONotificationPortCreate(kIOMasterPortDefault); 675 if (!port_) 676 return false; 677 source_ = IONotificationPortGetRunLoopSource(port_); 678 if (!source_) 679 return false; 680 CFRunLoopAddSource(CFRunLoopGetCurrent(), source_, kCFRunLoopDefaultMode); 681 682 listening_ = true; 683 684 if (!RegisterForDeviceNotifications( 685 kVendorMicrosoft, kProductXboxOneController, 686 &xbox_one_device_added_iter_, 687 &xbox_one_device_removed_iter_)) 688 return false; 689 690 if (!RegisterForDeviceNotifications( 691 kVendorMicrosoft, kProductXbox360Controller, 692 &xbox_360_device_added_iter_, 693 &xbox_360_device_removed_iter_)) 694 return false; 695 696 return true; 697 } 698 699 bool XboxDataFetcher::RegisterForDeviceNotifications( 700 int vendor_id, 701 int product_id, 702 base::mac::ScopedIOObject<io_iterator_t>* added_iter, 703 base::mac::ScopedIOObject<io_iterator_t>* removed_iter) { 704 base::ScopedCFTypeRef<CFNumberRef> vendor_cf(CFNumberCreate( 705 kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id)); 706 base::ScopedCFTypeRef<CFNumberRef> product_cf(CFNumberCreate( 707 kCFAllocatorDefault, kCFNumberSInt32Type, &product_id)); 708 base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( 709 IOServiceMatching(kIOUSBDeviceClassName)); 710 if (!matching_dict) 711 return false; 712 CFDictionarySetValue(matching_dict, CFSTR(kUSBVendorID), vendor_cf); 713 CFDictionarySetValue(matching_dict, CFSTR(kUSBProductID), product_cf); 714 715 // IOServiceAddMatchingNotification() releases the dictionary when it's done. 716 // Retain it before each call to IOServiceAddMatchingNotification to keep 717 // things balanced. 718 CFRetain(matching_dict); 719 io_iterator_t device_added_iter; 720 IOReturn ret; 721 ret = IOServiceAddMatchingNotification(port_, 722 kIOFirstMatchNotification, 723 matching_dict, 724 DeviceAdded, 725 this, 726 &device_added_iter); 727 added_iter->reset(device_added_iter); 728 if (ret != kIOReturnSuccess) { 729 LOG(ERROR) << "Error listening for Xbox controller add events: " << ret; 730 return false; 731 } 732 DeviceAdded(this, added_iter->get()); 733 734 CFRetain(matching_dict); 735 io_iterator_t device_removed_iter; 736 ret = IOServiceAddMatchingNotification(port_, 737 kIOTerminatedNotification, 738 matching_dict, 739 DeviceRemoved, 740 this, 741 &device_removed_iter); 742 removed_iter->reset(device_removed_iter); 743 if (ret != kIOReturnSuccess) { 744 LOG(ERROR) << "Error listening for Xbox controller remove events: " << ret; 745 return false; 746 } 747 DeviceRemoved(this, removed_iter->get()); 748 return true; 749 } 750 751 void XboxDataFetcher::UnregisterFromNotifications() { 752 if (!listening_) 753 return; 754 listening_ = false; 755 if (source_) 756 CFRunLoopSourceInvalidate(source_); 757 if (port_) 758 IONotificationPortDestroy(port_); 759 port_ = NULL; 760 } 761 762 XboxController* XboxDataFetcher::ControllerForLocation(UInt32 location_id) { 763 for (std::set<XboxController*>::iterator i = controllers_.begin(); 764 i != controllers_.end(); 765 ++i) { 766 if ((*i)->location_id() == location_id) 767 return *i; 768 } 769 return NULL; 770 } 771 772 void XboxDataFetcher::AddController(XboxController* controller) { 773 DCHECK(!ControllerForLocation(controller->location_id())) 774 << "Controller with location ID " << controller->location_id() 775 << " already exists in the set of controllers."; 776 controllers_.insert(controller); 777 delegate_->XboxDeviceAdd(controller); 778 } 779 780 void XboxDataFetcher::RemoveController(XboxController* controller) { 781 delegate_->XboxDeviceRemove(controller); 782 controllers_.erase(controller); 783 delete controller; 784 } 785 786 void XboxDataFetcher::RemoveControllerByLocationID(uint32 location_id) { 787 XboxController* controller = NULL; 788 for (std::set<XboxController*>::iterator i = controllers_.begin(); 789 i != controllers_.end(); 790 ++i) { 791 if ((*i)->location_id() == location_id) { 792 controller = *i; 793 break; 794 } 795 } 796 if (controller) 797 RemoveController(controller); 798 } 799 800 void XboxDataFetcher::XboxControllerGotData(XboxController* controller, 801 const XboxController::Data& data) { 802 delegate_->XboxValueChanged(controller, data); 803 } 804 805 void XboxDataFetcher::XboxControllerError(XboxController* controller) { 806 RemoveController(controller); 807 } 808