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