linux/drivers/hid/hid-ps3remote.c
<<
>>
Prefs
   1/*
   2 * HID driver for Sony PS3 BD Remote Control
   3 *
   4 * Copyright (c) 2012 David Dillow <dave@thedillows.org>
   5 * Based on a blend of the bluez fakehid user-space code by Marcel Holtmann
   6 * and other kernel HID drivers.
   7 */
   8
   9/*
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the Free
  12 * Software Foundation; either version 2 of the License, or (at your option)
  13 * any later version.
  14 */
  15
  16/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
  17 * a Bluetooth host, the key combination Start+Enter has to be kept pressed
  18 * for about 7 seconds with the Bluetooth Host Controller in discovering mode.
  19 *
  20 * There will be no PIN request from the device.
  21 */
  22
  23#include <linux/device.h>
  24#include <linux/hid.h>
  25#include <linux/module.h>
  26
  27#include "hid-ids.h"
  28
  29static __u8 ps3remote_rdesc[] = {
  30        0x05, 0x01,          /* GUsagePage Generic Desktop */
  31        0x09, 0x05,          /* LUsage 0x05 [Game Pad] */
  32        0xA1, 0x01,          /* MCollection Application (mouse, keyboard) */
  33
  34         /* Use collection 1 for joypad buttons */
  35         0xA1, 0x02,         /* MCollection Logical (interrelated data) */
  36
  37          /* Ignore the 1st byte, maybe it is used for a controller
  38           * number but it's not needed for correct operation */
  39          0x75, 0x08,        /* GReportSize 0x08 [8] */
  40          0x95, 0x01,        /* GReportCount 0x01 [1] */
  41          0x81, 0x01,        /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
  42
  43          /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these
  44           * buttons multiple keypresses are allowed */
  45          0x05, 0x09,        /* GUsagePage Button */
  46          0x19, 0x01,        /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */
  47          0x29, 0x18,        /* LUsageMaximum 0x18 [Button 24] */
  48          0x14,              /* GLogicalMinimum [0] */
  49          0x25, 0x01,        /* GLogicalMaximum 0x01 [1] */
  50          0x75, 0x01,        /* GReportSize 0x01 [1] */
  51          0x95, 0x18,        /* GReportCount 0x18 [24] */
  52          0x81, 0x02,        /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
  53
  54          0xC0,              /* MEndCollection */
  55
  56         /* Use collection 2 for remote control buttons */
  57         0xA1, 0x02,         /* MCollection Logical (interrelated data) */
  58
  59          /* 5th byte is used for remote control buttons */
  60          0x05, 0x09,        /* GUsagePage Button */
  61          0x18,              /* LUsageMinimum [No button pressed] */
  62          0x29, 0xFE,        /* LUsageMaximum 0xFE [Button 254] */
  63          0x14,              /* GLogicalMinimum [0] */
  64          0x26, 0xFE, 0x00,  /* GLogicalMaximum 0x00FE [254] */
  65          0x75, 0x08,        /* GReportSize 0x08 [8] */
  66          0x95, 0x01,        /* GReportCount 0x01 [1] */
  67          0x80,              /* MInput  */
  68
  69          /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at
  70           * 0xff and 11th is for press indication */
  71          0x75, 0x08,        /* GReportSize 0x08 [8] */
  72          0x95, 0x06,        /* GReportCount 0x06 [6] */
  73          0x81, 0x01,        /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
  74
  75          /* 12th byte is for battery strength */
  76          0x05, 0x06,        /* GUsagePage Generic Device Controls */
  77          0x09, 0x20,        /* LUsage 0x20 [Battery Strength] */
  78          0x14,              /* GLogicalMinimum [0] */
  79          0x25, 0x05,        /* GLogicalMaximum 0x05 [5] */
  80          0x75, 0x08,        /* GReportSize 0x08 [8] */
  81          0x95, 0x01,        /* GReportCount 0x01 [1] */
  82          0x81, 0x02,        /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
  83
  84          0xC0,              /* MEndCollection */
  85
  86         0xC0                /* MEndCollection [Game Pad] */
  87};
  88
  89static const unsigned int ps3remote_keymap_joypad_buttons[] = {
  90        [0x01] = KEY_SELECT,
  91        [0x02] = BTN_THUMBL,            /* L3 */
  92        [0x03] = BTN_THUMBR,            /* R3 */
  93        [0x04] = BTN_START,
  94        [0x05] = KEY_UP,
  95        [0x06] = KEY_RIGHT,
  96        [0x07] = KEY_DOWN,
  97        [0x08] = KEY_LEFT,
  98        [0x09] = BTN_TL2,               /* L2 */
  99        [0x0a] = BTN_TR2,               /* R2 */
 100        [0x0b] = BTN_TL,                /* L1 */
 101        [0x0c] = BTN_TR,                /* R1 */
 102        [0x0d] = KEY_OPTION,            /* options/triangle */
 103        [0x0e] = KEY_BACK,              /* back/circle */
 104        [0x0f] = BTN_0,                 /* cross */
 105        [0x10] = KEY_SCREEN,            /* view/square */
 106        [0x11] = KEY_HOMEPAGE,          /* PS button */
 107        [0x14] = KEY_ENTER,
 108};
 109static const unsigned int ps3remote_keymap_remote_buttons[] = {
 110        [0x00] = KEY_1,
 111        [0x01] = KEY_2,
 112        [0x02] = KEY_3,
 113        [0x03] = KEY_4,
 114        [0x04] = KEY_5,
 115        [0x05] = KEY_6,
 116        [0x06] = KEY_7,
 117        [0x07] = KEY_8,
 118        [0x08] = KEY_9,
 119        [0x09] = KEY_0,
 120        [0x0e] = KEY_ESC,               /* return */
 121        [0x0f] = KEY_CLEAR,
 122        [0x16] = KEY_EJECTCD,
 123        [0x1a] = KEY_MENU,              /* top menu */
 124        [0x28] = KEY_TIME,
 125        [0x30] = KEY_PREVIOUS,
 126        [0x31] = KEY_NEXT,
 127        [0x32] = KEY_PLAY,
 128        [0x33] = KEY_REWIND,            /* scan back */
 129        [0x34] = KEY_FORWARD,           /* scan forward */
 130        [0x38] = KEY_STOP,
 131        [0x39] = KEY_PAUSE,
 132        [0x40] = KEY_CONTEXT_MENU,      /* pop up/menu */
 133        [0x60] = KEY_FRAMEBACK,         /* slow/step back */
 134        [0x61] = KEY_FRAMEFORWARD,      /* slow/step forward */
 135        [0x63] = KEY_SUBTITLE,
 136        [0x64] = KEY_AUDIO,
 137        [0x65] = KEY_ANGLE,
 138        [0x70] = KEY_INFO,              /* display */
 139        [0x80] = KEY_BLUE,
 140        [0x81] = KEY_RED,
 141        [0x82] = KEY_GREEN,
 142        [0x83] = KEY_YELLOW,
 143};
 144
 145static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
 146                             unsigned int *rsize)
 147{
 148        *rsize = sizeof(ps3remote_rdesc);
 149        return ps3remote_rdesc;
 150}
 151
 152static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
 153                             struct hid_field *field, struct hid_usage *usage,
 154                             unsigned long **bit, int *max)
 155{
 156        unsigned int key = usage->hid & HID_USAGE;
 157
 158        if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
 159                return -1;
 160
 161        switch (usage->collection_index) {
 162        case 1:
 163                if (key >= ARRAY_SIZE(ps3remote_keymap_joypad_buttons))
 164                        return -1;
 165
 166                key = ps3remote_keymap_joypad_buttons[key];
 167                if (!key)
 168                        return -1;
 169                break;
 170        case 2:
 171                if (key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
 172                        return -1;
 173
 174                key = ps3remote_keymap_remote_buttons[key];
 175                if (!key)
 176                        return -1;
 177                break;
 178        default:
 179                return -1;
 180        }
 181
 182        hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
 183        return 1;
 184}
 185
 186static const struct hid_device_id ps3remote_devices[] = {
 187        /* PS3 BD Remote Control */
 188        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
 189        /* Logitech Harmony Adapter for PS3 */
 190        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
 191        { }
 192};
 193MODULE_DEVICE_TABLE(hid, ps3remote_devices);
 194
 195static struct hid_driver ps3remote_driver = {
 196        .name          = "ps3_remote",
 197        .id_table      = ps3remote_devices,
 198        .report_fixup  = ps3remote_fixup,
 199        .input_mapping = ps3remote_mapping,
 200};
 201module_hid_driver(ps3remote_driver);
 202
 203MODULE_LICENSE("GPL");
 204MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
 205