linux/drivers/hid/hid-icade.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  ION iCade input driver
   4 *
   5 *  Copyright (c) 2012 Bastien Nocera <hadess@hadess.net>
   6 *  Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
   7 */
   8
   9/*
  10 */
  11
  12#include <linux/device.h>
  13#include <linux/hid.h>
  14#include <linux/module.h>
  15
  16#include "hid-ids.h"
  17
  18/*
  19 *   ↑      A C Y L
  20 *  ← →
  21 *   ↓      B X Z R
  22 *
  23 *
  24 *  UP ON,OFF  = w,e
  25 *  RT ON,OFF  = d,c
  26 *  DN ON,OFF  = x,z
  27 *  LT ON,OFF  = a,q
  28 *  A  ON,OFF  = y,t
  29 *  B  ON,OFF  = h,r
  30 *  C  ON,OFF  = u,f
  31 *  X  ON,OFF  = j,n
  32 *  Y  ON,OFF  = i,m
  33 *  Z  ON,OFF  = k,p
  34 *  L  ON,OFF  = o,g
  35 *  R  ON,OFF  = l,v
  36 */
  37
  38/* The translation code uses HID usage instead of input layer
  39 * keys. This code generates a lookup table that makes
  40 * translation quick.
  41 *
  42 * #include <linux/input.h>
  43 * #include <stdio.h>
  44 * #include <assert.h>
  45 *
  46 * #define unk     KEY_UNKNOWN
  47 *
  48 * < copy of hid_keyboard[] from hid-input.c >
  49 *
  50 * struct icade_key_translation {
  51 *     int         from;
  52 *     const char *to;
  53 *     int         press;
  54 * };
  55 *
  56 * static const struct icade_key_translation icade_keys[] = {
  57 *    { KEY_W,        "KEY_UP",         1 },
  58 *    { KEY_E,        "KEY_UP",         0 },
  59 *    { KEY_D,        "KEY_RIGHT",      1 },
  60 *    { KEY_C,        "KEY_RIGHT",      0 },
  61 *    { KEY_X,        "KEY_DOWN",       1 },
  62 *    { KEY_Z,        "KEY_DOWN",       0 },
  63 *    { KEY_A,        "KEY_LEFT",       1 },
  64 *    { KEY_Q,        "KEY_LEFT",       0 },
  65 *    { KEY_Y,        "BTN_A",          1 },
  66 *    { KEY_T,        "BTN_A",          0 },
  67 *    { KEY_H,        "BTN_B",          1 },
  68 *    { KEY_R,        "BTN_B",          0 },
  69 *    { KEY_U,        "BTN_C",          1 },
  70 *    { KEY_F,        "BTN_C",          0 },
  71 *    { KEY_J,        "BTN_X",          1 },
  72 *    { KEY_N,        "BTN_X",          0 },
  73 *    { KEY_I,        "BTN_Y",          1 },
  74 *    { KEY_M,        "BTN_Y",          0 },
  75 *    { KEY_K,        "BTN_Z",          1 },
  76 *    { KEY_P,        "BTN_Z",          0 },
  77 *    { KEY_O,        "BTN_THUMBL",     1 },
  78 *    { KEY_G,        "BTN_THUMBL",     0 },
  79 *    { KEY_L,        "BTN_THUMBR",     1 },
  80 *    { KEY_V,        "BTN_THUMBR",     0 },
  81 *
  82 *    { }
  83 * };
  84 *
  85 * static int
  86 * usage_for_key (int key)
  87 * {
  88 *     int i;
  89 *     for (i = 0; i < 256; i++) {
  90 *     if (hid_keyboard[i] == key)
  91 *         return i;
  92 *     }
  93 *     assert(0);
  94 * }
  95 *
  96 * int main (int argc, char **argv)
  97 * {
  98 *     const struct icade_key_translation *trans;
  99 *     int max_usage = 0;
 100 *
 101 *     for (trans = icade_keys; trans->from; trans++) {
 102 *         int usage = usage_for_key (trans->from);
 103 *         max_usage = usage > max_usage ? usage : max_usage;
 104 *     }
 105 *
 106 *     printf ("#define ICADE_MAX_USAGE %d\n\n", max_usage);
 107 *     printf ("struct icade_key {\n");
 108 *     printf ("\tu16 to;\n");
 109 *     printf ("\tu8 press:1;\n");
 110 *     printf ("};\n\n");
 111 *     printf ("static const struct icade_key "
 112 *             "icade_usage_table[%d] = {\n", max_usage + 1);
 113 *     for (trans = icade_keys; trans->from; trans++) {
 114 *         printf ("\t[%d] = { %s, %d },\n",
 115 *                 usage_for_key (trans->from), trans->to, trans->press);
 116 *     }
 117 *     printf ("};\n");
 118 *
 119 *     return 0;
 120 * }
 121 */
 122
 123#define ICADE_MAX_USAGE 29
 124
 125struct icade_key {
 126        u16 to;
 127        u8 press:1;
 128};
 129
 130static const struct icade_key icade_usage_table[30] = {
 131        [26] = { KEY_UP, 1 },
 132        [8] = { KEY_UP, 0 },
 133        [7] = { KEY_RIGHT, 1 },
 134        [6] = { KEY_RIGHT, 0 },
 135        [27] = { KEY_DOWN, 1 },
 136        [29] = { KEY_DOWN, 0 },
 137        [4] = { KEY_LEFT, 1 },
 138        [20] = { KEY_LEFT, 0 },
 139        [28] = { BTN_A, 1 },
 140        [23] = { BTN_A, 0 },
 141        [11] = { BTN_B, 1 },
 142        [21] = { BTN_B, 0 },
 143        [24] = { BTN_C, 1 },
 144        [9] = { BTN_C, 0 },
 145        [13] = { BTN_X, 1 },
 146        [17] = { BTN_X, 0 },
 147        [12] = { BTN_Y, 1 },
 148        [16] = { BTN_Y, 0 },
 149        [14] = { BTN_Z, 1 },
 150        [19] = { BTN_Z, 0 },
 151        [18] = { BTN_THUMBL, 1 },
 152        [10] = { BTN_THUMBL, 0 },
 153        [15] = { BTN_THUMBR, 1 },
 154        [25] = { BTN_THUMBR, 0 },
 155};
 156
 157static const struct icade_key *icade_find_translation(u16 from)
 158{
 159        if (from > ICADE_MAX_USAGE)
 160                return NULL;
 161        return &icade_usage_table[from];
 162}
 163
 164static int icade_event(struct hid_device *hdev, struct hid_field *field,
 165                struct hid_usage *usage, __s32 value)
 166{
 167        const struct icade_key *trans;
 168
 169        if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
 170                        !usage->type)
 171                return 0;
 172
 173        /* We ignore the fake key up, and act only on key down */
 174        if (!value)
 175                return 1;
 176
 177        trans = icade_find_translation(usage->hid & HID_USAGE);
 178
 179        if (!trans)
 180                return 1;
 181
 182        input_event(field->hidinput->input, usage->type,
 183                        trans->to, trans->press);
 184
 185        return 1;
 186}
 187
 188static int icade_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 189                struct hid_field *field, struct hid_usage *usage,
 190                unsigned long **bit, int *max)
 191{
 192        const struct icade_key *trans;
 193
 194        if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) {
 195                trans = icade_find_translation(usage->hid & HID_USAGE);
 196
 197                if (!trans)
 198                        return -1;
 199
 200                hid_map_usage(hi, usage, bit, max, EV_KEY, trans->to);
 201                set_bit(trans->to, hi->input->keybit);
 202
 203                return 1;
 204        }
 205
 206        /* ignore others */
 207        return -1;
 208
 209}
 210
 211static int icade_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 212                struct hid_field *field, struct hid_usage *usage,
 213                unsigned long **bit, int *max)
 214{
 215        if (usage->type == EV_KEY)
 216                set_bit(usage->type, hi->input->evbit);
 217
 218        return -1;
 219}
 220
 221static const struct hid_device_id icade_devices[] = {
 222        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
 223
 224        { }
 225};
 226MODULE_DEVICE_TABLE(hid, icade_devices);
 227
 228static struct hid_driver icade_driver = {
 229        .name = "icade",
 230        .id_table = icade_devices,
 231        .event = icade_event,
 232        .input_mapped = icade_input_mapped,
 233        .input_mapping = icade_input_mapping,
 234};
 235module_hid_driver(icade_driver);
 236
 237MODULE_LICENSE("GPL");
 238MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
 239MODULE_DESCRIPTION("ION iCade input driver");
 240