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:
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  enum LEDPattern {
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_OFF = 0,
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // 2 quick flashes, then a series of slow flashes (about 1 per second).
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH = 1,
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Flash three times then hold the LED on. This is the standard way to tell
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the player which player number they are.
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_TOP_LEFT = 2,
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_TOP_RIGHT = 3,
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_BOTTOM_LEFT = 4,
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_BOTTOM_RIGHT = 5,
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Simply turn on the specified LED and turn all other LEDs off.
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_TOP_LEFT = 6,
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_TOP_RIGHT = 7,
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_BOTTOM_LEFT = 8,
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_HOLD_BOTTOM_RIGHT = 9,
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_ROTATE = 10,
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_FAST = 11,
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_SLOW = 12,  // Flash about once per 3 seconds
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Flash alternating LEDs for a few seconds, then flash all LEDs about once
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // per second
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_ALTERNATE_PATTERN = 13,
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // 14 is just another boring flashing speed.
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Flash all LEDs once then go black.
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_FLASH_ONCE = 15,
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LED_NUM_PATTERNS
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  struct Data {
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool buttons[15];
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float triggers[2];
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    float axes[4];
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  class Delegate {
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   public:
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxControllerGotData(XboxController* controller,
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                       const Data& data) = 0;
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxControllerError(XboxController* controller) = 0;
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit XboxController(Delegate* delegate_);
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~XboxController();
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool OpenDevice(io_service_t service);
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void SetLEDPattern(LEDPattern pattern);
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UInt32 location_id() { return location_id_; }
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int GetVendorId() const;
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int GetProductId() const;
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void WriteComplete(void* context, IOReturn result, void* arg0);
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void GotData(void* context, IOReturn result, void* arg0);
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void ProcessPacket(size_t length);
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void QueueRead();
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void IOError();
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Handle for the USB device. IOUSBDeviceStruct320 is the latest version of
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the device API that is supported on Mac OS 10.6.
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedIOPluginInterface<struct IOUSBDeviceStruct320> device_;
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Handle for the interface on the device which sends button and analog data.
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The other interfaces (for the ChatPad and headset) are ignored.
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedIOPluginInterface<struct IOUSBInterfaceStruct300> interface_;
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool device_is_open_;
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool interface_is_open_;
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ScopedCFTypeRef<CFRunLoopSourceRef> source_;
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // This will be set to the max packet size reported by the interface, which
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // is 32 bytes. I would have expected USB to do message framing itself, but
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // somehow we still sometimes (rarely!) get packets off the interface which
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // aren't correctly framed. The 360 controller frames its packets with a 2
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // byte header (type, total length) so we can reframe the packet data
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // ourselves.
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  uint16 read_buffer_size_;
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<uint8[]> read_buffer_;
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The pattern that the LEDs on the device are currently displaying, or
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // LED_NUM_PATTERNS if unknown.
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LEDPattern led_pattern_;
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UInt32 location_id_;
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Delegate* delegate_;
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XboxController);
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class XboxDataFetcher : public XboxController::Delegate {
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  class Delegate {
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   public:
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxDeviceAdd(XboxController* device) = 0;
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxDeviceRemove(XboxController* device) = 0;
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    virtual void XboxValueChanged(XboxController* device,
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const XboxController::Data& data) = 0;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit XboxDataFetcher(Delegate* delegate);
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~XboxDataFetcher();
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool RegisterForNotifications();
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void UnregisterFromNotifications();
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  XboxController* ControllerForLocation(UInt32 location_id);
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void DeviceAdded(void* context, io_iterator_t iterator);
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static void DeviceRemoved(void* context, io_iterator_t iterator);
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void AddController(XboxController* controller);
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void RemoveController(XboxController* controller);
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void RemoveControllerByLocationID(uint32 id);
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void XboxControllerGotData(XboxController* controller,
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     const XboxController::Data& data) OVERRIDE;
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void XboxControllerError(XboxController* controller) OVERRIDE;
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Delegate* delegate_;
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::set<XboxController*> controllers_;
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool listening_;
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // port_ owns source_, so this doesn't need to be a ScopedCFTypeRef, but we
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // do need to maintain a reference to it so we can invalidate it.
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CFRunLoopSourceRef source_;
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  IONotificationPortRef port_;
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedIOObject<io_iterator_t> device_added_iter_;
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::mac::ScopedIOObject<io_iterator_t> device_removed_iter_;
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(XboxDataFetcher);
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif  // CONTENT_BROWSER_GAMEPAD_XBOX_DATA_FETCHER_MAC_H_
168