190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#ifndef CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#define CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <CoreFoundation/CoreFoundation.h>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <IOKit/IOKitLib.h>
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <set>
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/basictypes.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/mac/scoped_cftyperef.h"
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/mac/scoped_ioobject.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/mac/scoped_ioplugininterface.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class XboxController {
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  enum ControllerType {
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    UNKNOWN_CONTROLLER,
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    XBOX_360_CONTROLLER,
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    XBOX_ONE_CONTROLLER
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  enum LEDPattern {
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_OFF = 0,
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // 2 quick flashes, then a series of slow flashes (about 1 per second).
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH = 1,
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Flash three times then hold the LED on. This is the standard way to tell
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the player which player number they are.
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_TOP_LEFT = 2,
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_TOP_RIGHT = 3,
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_BOTTOM_LEFT = 4,
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_BOTTOM_RIGHT = 5,
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Simply turn on the specified LED and turn all other LEDs off.
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_TOP_LEFT = 6,
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_TOP_RIGHT = 7,
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_BOTTOM_LEFT = 8,
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_BOTTOM_RIGHT = 9,
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_ROTATE = 10,
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_FAST = 11,
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_SLOW = 12,  // Flash about once per 3 seconds
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Flash alternating LEDs for a few seconds, then flash all LEDs about once
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // per second
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_ALTERNATE_PATTERN = 13,
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // 14 is just another boring flashing speed.
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Flash all LEDs once then go black.
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_ONCE = 15,
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_NUM_PATTERNS
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  struct Data {
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool buttons[15];
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float triggers[2];
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float axes[4];
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  class Delegate {
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   public:
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxControllerGotData(XboxController* controller,
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                       const Data& data) = 0;
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxControllerError(XboxController* controller) = 0;
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit XboxController(Delegate* delegate_);
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~XboxController();
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool OpenDevice(io_service_t service);
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void SetLEDPattern(LEDPattern pattern);
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UInt32 location_id() { return location_id_; }
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int GetVendorId() const;
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int GetProductId() const;
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ControllerType GetControllerType() const;
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void WriteComplete(void* context, IOReturn result, void* arg0);
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void GotData(void* context, IOReturn result, void* arg0);
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void ProcessXbox360Packet(size_t length);
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void ProcessXboxOnePacket(size_t length);
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void QueueRead();
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void IOError();
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void WriteXboxOneInit();
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Handle for the USB device. IOUSBDeviceStruct320 is the latest version of
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the device API that is supported on Mac OS 10.6.
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedIOPluginInterface<struct IOUSBDeviceStruct320> device_;
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Handle for the interface on the device which sends button and analog data.
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The other interfaces (for the ChatPad and headset) are ignored.
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedIOPluginInterface<struct IOUSBInterfaceStruct300> interface_;
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool device_is_open_;
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool interface_is_open_;
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ScopedCFTypeRef<CFRunLoopSourceRef> source_;
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This will be set to the max packet size reported by the interface, which
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // is 32 bytes. I would have expected USB to do message framing itself, but
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // somehow we still sometimes (rarely!) get packets off the interface which
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // aren't correctly framed. The 360 controller frames its packets with a 2
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // byte header (type, total length) so we can reframe the packet data
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // ourselves.
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  uint16 read_buffer_size_;
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<uint8[]> read_buffer_;
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The pattern that the LEDs on the device are currently displaying, or
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // LED_NUM_PATTERNS if unknown.
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LEDPattern led_pattern_;
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UInt32 location_id_;
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Delegate* delegate_;
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ControllerType controller_type_;
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int read_endpoint_;
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int control_endpoint_;
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XboxController);
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class XboxDataFetcher : public XboxController::Delegate {
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  class Delegate {
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   public:
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxDeviceAdd(XboxController* device) = 0;
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxDeviceRemove(XboxController* device) = 0;
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxValueChanged(XboxController* device,
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const XboxController::Data& data) = 0;
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit XboxDataFetcher(Delegate* delegate);
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~XboxDataFetcher();
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool RegisterForNotifications();
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool RegisterForDeviceNotifications(
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int vendor_id,
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int product_id,
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::mac::ScopedIOObject<io_iterator_t>* added_iter,
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::mac::ScopedIOObject<io_iterator_t>* removed_iter);
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void UnregisterFromNotifications();
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  XboxController* ControllerForLocation(UInt32 location_id);
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void DeviceAdded(void* context, io_iterator_t iterator);
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void DeviceRemoved(void* context, io_iterator_t iterator);
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void AddController(XboxController* controller);
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void RemoveController(XboxController* controller);
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void RemoveControllerByLocationID(uint32 id);
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void XboxControllerGotData(XboxController* controller,
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     const XboxController::Data& data) OVERRIDE;
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void XboxControllerError(XboxController* controller) OVERRIDE;
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Delegate* delegate_;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::set<XboxController*> controllers_;
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool listening_;
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // port_ owns source_, so this doesn't need to be a ScopedCFTypeRef, but we
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // do need to maintain a reference to it so we can invalidate it.
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CFRunLoopSourceRef source_;
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  IONotificationPortRef port_;
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::mac::ScopedIOObject<io_iterator_t> xbox_360_device_added_iter_;
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::mac::ScopedIOObject<io_iterator_t> xbox_360_device_removed_iter_;
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::mac::ScopedIOObject<io_iterator_t> xbox_one_device_added_iter_;
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::mac::ScopedIOObject<io_iterator_t> xbox_one_device_removed_iter_;
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XboxDataFetcher);
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif  // CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_
189