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 125 struct icade_key { 126 u16 to; 127 u8 press:1; 128 }; 129 130 static 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 157 static 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 164 static 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 188 static 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 211 static 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 221 static const struct hid_device_id icade_devices[] = { 222 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, 223 224 { } 225 }; 226 MODULE_DEVICE_TABLE(hid, icade_devices); 227 228 static 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 }; 235 module_hid_driver(icade_driver); 236 237 MODULE_LICENSE("GPL"); 238 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); 239 MODULE_DESCRIPTION("ION iCade input driver"); 240