14ddfe028SBastien Nocera /* 24ddfe028SBastien Nocera * ION iCade input driver 34ddfe028SBastien Nocera * 44ddfe028SBastien Nocera * Copyright (c) 2012 Bastien Nocera <hadess@hadess.net> 54ddfe028SBastien Nocera * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> 64ddfe028SBastien Nocera */ 74ddfe028SBastien Nocera 84ddfe028SBastien Nocera /* 94ddfe028SBastien Nocera * This program is free software; you can redistribute it and/or modify it 104ddfe028SBastien Nocera * under the terms of the GNU General Public License as published by the Free 114ddfe028SBastien Nocera * Software Foundation; either version 2 of the License, or (at your option) 124ddfe028SBastien Nocera * any later version. 134ddfe028SBastien Nocera */ 144ddfe028SBastien Nocera 154ddfe028SBastien Nocera #include <linux/device.h> 164ddfe028SBastien Nocera #include <linux/hid.h> 174ddfe028SBastien Nocera #include <linux/module.h> 184ddfe028SBastien Nocera 194ddfe028SBastien Nocera #include "hid-ids.h" 204ddfe028SBastien Nocera 214ddfe028SBastien Nocera /* 224ddfe028SBastien Nocera * ↑ A C Y L 234ddfe028SBastien Nocera * ← → 244ddfe028SBastien Nocera * ↓ B X Z R 254ddfe028SBastien Nocera * 264ddfe028SBastien Nocera * 274ddfe028SBastien Nocera * UP ON,OFF = w,e 284ddfe028SBastien Nocera * RT ON,OFF = d,c 294ddfe028SBastien Nocera * DN ON,OFF = x,z 304ddfe028SBastien Nocera * LT ON,OFF = a,q 314ddfe028SBastien Nocera * A ON,OFF = y,t 324ddfe028SBastien Nocera * B ON,OFF = h,r 334ddfe028SBastien Nocera * C ON,OFF = u,f 344ddfe028SBastien Nocera * X ON,OFF = j,n 354ddfe028SBastien Nocera * Y ON,OFF = i,m 364ddfe028SBastien Nocera * Z ON,OFF = k,p 374ddfe028SBastien Nocera * L ON,OFF = o,g 384ddfe028SBastien Nocera * R ON,OFF = l,v 394ddfe028SBastien Nocera */ 404ddfe028SBastien Nocera 414ddfe028SBastien Nocera /* The translation code uses HID usage instead of input layer 424ddfe028SBastien Nocera * keys. This code generates a lookup table that makes 434ddfe028SBastien Nocera * translation quick. 444ddfe028SBastien Nocera * 454ddfe028SBastien Nocera * #include <linux/input.h> 464ddfe028SBastien Nocera * #include <stdio.h> 474ddfe028SBastien Nocera * #include <assert.h> 484ddfe028SBastien Nocera * 494ddfe028SBastien Nocera * #define unk KEY_UNKNOWN 504ddfe028SBastien Nocera * 514ddfe028SBastien Nocera * < copy of hid_keyboard[] from hid-input.c > 524ddfe028SBastien Nocera * 534ddfe028SBastien Nocera * struct icade_key_translation { 544ddfe028SBastien Nocera * int from; 554ddfe028SBastien Nocera * const char *to; 564ddfe028SBastien Nocera * int press; 574ddfe028SBastien Nocera * }; 584ddfe028SBastien Nocera * 594ddfe028SBastien Nocera * static const struct icade_key_translation icade_keys[] = { 604ddfe028SBastien Nocera * { KEY_W, "KEY_UP", 1 }, 614ddfe028SBastien Nocera * { KEY_E, "KEY_UP", 0 }, 624ddfe028SBastien Nocera * { KEY_D, "KEY_RIGHT", 1 }, 634ddfe028SBastien Nocera * { KEY_C, "KEY_RIGHT", 0 }, 644ddfe028SBastien Nocera * { KEY_X, "KEY_DOWN", 1 }, 654ddfe028SBastien Nocera * { KEY_Z, "KEY_DOWN", 0 }, 664ddfe028SBastien Nocera * { KEY_A, "KEY_LEFT", 1 }, 674ddfe028SBastien Nocera * { KEY_Q, "KEY_LEFT", 0 }, 684ddfe028SBastien Nocera * { KEY_Y, "BTN_A", 1 }, 694ddfe028SBastien Nocera * { KEY_T, "BTN_A", 0 }, 704ddfe028SBastien Nocera * { KEY_H, "BTN_B", 1 }, 714ddfe028SBastien Nocera * { KEY_R, "BTN_B", 0 }, 724ddfe028SBastien Nocera * { KEY_U, "BTN_C", 1 }, 734ddfe028SBastien Nocera * { KEY_F, "BTN_C", 0 }, 744ddfe028SBastien Nocera * { KEY_J, "BTN_X", 1 }, 754ddfe028SBastien Nocera * { KEY_N, "BTN_X", 0 }, 764ddfe028SBastien Nocera * { KEY_I, "BTN_Y", 1 }, 774ddfe028SBastien Nocera * { KEY_M, "BTN_Y", 0 }, 784ddfe028SBastien Nocera * { KEY_K, "BTN_Z", 1 }, 794ddfe028SBastien Nocera * { KEY_P, "BTN_Z", 0 }, 804ddfe028SBastien Nocera * { KEY_O, "BTN_THUMBL", 1 }, 814ddfe028SBastien Nocera * { KEY_G, "BTN_THUMBL", 0 }, 824ddfe028SBastien Nocera * { KEY_L, "BTN_THUMBR", 1 }, 834ddfe028SBastien Nocera * { KEY_V, "BTN_THUMBR", 0 }, 844ddfe028SBastien Nocera * 854ddfe028SBastien Nocera * { } 864ddfe028SBastien Nocera * }; 874ddfe028SBastien Nocera * 884ddfe028SBastien Nocera * static int 894ddfe028SBastien Nocera * usage_for_key (int key) 904ddfe028SBastien Nocera * { 914ddfe028SBastien Nocera * int i; 924ddfe028SBastien Nocera * for (i = 0; i < 256; i++) { 934ddfe028SBastien Nocera * if (hid_keyboard[i] == key) 944ddfe028SBastien Nocera * return i; 954ddfe028SBastien Nocera * } 964ddfe028SBastien Nocera * assert(0); 974ddfe028SBastien Nocera * } 984ddfe028SBastien Nocera * 994ddfe028SBastien Nocera * int main (int argc, char **argv) 1004ddfe028SBastien Nocera * { 1014ddfe028SBastien Nocera * const struct icade_key_translation *trans; 1024ddfe028SBastien Nocera * int max_usage = 0; 1034ddfe028SBastien Nocera * 1044ddfe028SBastien Nocera * for (trans = icade_keys; trans->from; trans++) { 1054ddfe028SBastien Nocera * int usage = usage_for_key (trans->from); 1064ddfe028SBastien Nocera * max_usage = usage > max_usage ? usage : max_usage; 1074ddfe028SBastien Nocera * } 1084ddfe028SBastien Nocera * 1094ddfe028SBastien Nocera * printf ("#define ICADE_MAX_USAGE %d\n\n", max_usage); 1104ddfe028SBastien Nocera * printf ("struct icade_key {\n"); 1114ddfe028SBastien Nocera * printf ("\tu16 to;\n"); 1124ddfe028SBastien Nocera * printf ("\tu8 press:1;\n"); 1134ddfe028SBastien Nocera * printf ("};\n\n"); 1144ddfe028SBastien Nocera * printf ("static const struct icade_key " 1154ddfe028SBastien Nocera * "icade_usage_table[%d] = {\n", max_usage + 1); 1164ddfe028SBastien Nocera * for (trans = icade_keys; trans->from; trans++) { 1174ddfe028SBastien Nocera * printf ("\t[%d] = { %s, %d },\n", 1184ddfe028SBastien Nocera * usage_for_key (trans->from), trans->to, trans->press); 1194ddfe028SBastien Nocera * } 1204ddfe028SBastien Nocera * printf ("};\n"); 1214ddfe028SBastien Nocera * 1224ddfe028SBastien Nocera * return 0; 1234ddfe028SBastien Nocera * } 1244ddfe028SBastien Nocera */ 1254ddfe028SBastien Nocera 1264ddfe028SBastien Nocera #define ICADE_MAX_USAGE 29 1274ddfe028SBastien Nocera 1284ddfe028SBastien Nocera struct icade_key { 1294ddfe028SBastien Nocera u16 to; 1304ddfe028SBastien Nocera u8 press:1; 1314ddfe028SBastien Nocera }; 1324ddfe028SBastien Nocera 1334ddfe028SBastien Nocera static const struct icade_key icade_usage_table[30] = { 1344ddfe028SBastien Nocera [26] = { KEY_UP, 1 }, 1354ddfe028SBastien Nocera [8] = { KEY_UP, 0 }, 1364ddfe028SBastien Nocera [7] = { KEY_RIGHT, 1 }, 1374ddfe028SBastien Nocera [6] = { KEY_RIGHT, 0 }, 1384ddfe028SBastien Nocera [27] = { KEY_DOWN, 1 }, 1394ddfe028SBastien Nocera [29] = { KEY_DOWN, 0 }, 1404ddfe028SBastien Nocera [4] = { KEY_LEFT, 1 }, 1414ddfe028SBastien Nocera [20] = { KEY_LEFT, 0 }, 1424ddfe028SBastien Nocera [28] = { BTN_A, 1 }, 1434ddfe028SBastien Nocera [23] = { BTN_A, 0 }, 1444ddfe028SBastien Nocera [11] = { BTN_B, 1 }, 1454ddfe028SBastien Nocera [21] = { BTN_B, 0 }, 1464ddfe028SBastien Nocera [24] = { BTN_C, 1 }, 1474ddfe028SBastien Nocera [9] = { BTN_C, 0 }, 1484ddfe028SBastien Nocera [13] = { BTN_X, 1 }, 1494ddfe028SBastien Nocera [17] = { BTN_X, 0 }, 1504ddfe028SBastien Nocera [12] = { BTN_Y, 1 }, 1514ddfe028SBastien Nocera [16] = { BTN_Y, 0 }, 1524ddfe028SBastien Nocera [14] = { BTN_Z, 1 }, 1534ddfe028SBastien Nocera [19] = { BTN_Z, 0 }, 1544ddfe028SBastien Nocera [18] = { BTN_THUMBL, 1 }, 1554ddfe028SBastien Nocera [10] = { BTN_THUMBL, 0 }, 1564ddfe028SBastien Nocera [15] = { BTN_THUMBR, 1 }, 1574ddfe028SBastien Nocera [25] = { BTN_THUMBR, 0 }, 1584ddfe028SBastien Nocera }; 1594ddfe028SBastien Nocera 1604ddfe028SBastien Nocera static const struct icade_key *icade_find_translation(u16 from) 1614ddfe028SBastien Nocera { 162*d8565014SChen Gang if (from > ICADE_MAX_USAGE) 1634ddfe028SBastien Nocera return NULL; 1644ddfe028SBastien Nocera return &icade_usage_table[from]; 1654ddfe028SBastien Nocera } 1664ddfe028SBastien Nocera 1674ddfe028SBastien Nocera static int icade_event(struct hid_device *hdev, struct hid_field *field, 1684ddfe028SBastien Nocera struct hid_usage *usage, __s32 value) 1694ddfe028SBastien Nocera { 1704ddfe028SBastien Nocera const struct icade_key *trans; 1714ddfe028SBastien Nocera 1724ddfe028SBastien Nocera if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 1734ddfe028SBastien Nocera !usage->type) 1744ddfe028SBastien Nocera return 0; 1754ddfe028SBastien Nocera 1764ddfe028SBastien Nocera /* We ignore the fake key up, and act only on key down */ 1774ddfe028SBastien Nocera if (!value) 1784ddfe028SBastien Nocera return 1; 1794ddfe028SBastien Nocera 1804ddfe028SBastien Nocera trans = icade_find_translation(usage->hid & HID_USAGE); 1814ddfe028SBastien Nocera 1824ddfe028SBastien Nocera if (!trans) 1834ddfe028SBastien Nocera return 1; 1844ddfe028SBastien Nocera 1854ddfe028SBastien Nocera input_event(field->hidinput->input, usage->type, 1864ddfe028SBastien Nocera trans->to, trans->press); 1874ddfe028SBastien Nocera 1884ddfe028SBastien Nocera return 1; 1894ddfe028SBastien Nocera } 1904ddfe028SBastien Nocera 1914ddfe028SBastien Nocera static int icade_input_mapping(struct hid_device *hdev, struct hid_input *hi, 1924ddfe028SBastien Nocera struct hid_field *field, struct hid_usage *usage, 1934ddfe028SBastien Nocera unsigned long **bit, int *max) 1944ddfe028SBastien Nocera { 1954ddfe028SBastien Nocera const struct icade_key *trans; 1964ddfe028SBastien Nocera 1974ddfe028SBastien Nocera if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) { 1984ddfe028SBastien Nocera trans = icade_find_translation(usage->hid & HID_USAGE); 1994ddfe028SBastien Nocera 2004ddfe028SBastien Nocera if (!trans) 2014ddfe028SBastien Nocera return -1; 2024ddfe028SBastien Nocera 2034ddfe028SBastien Nocera hid_map_usage(hi, usage, bit, max, EV_KEY, trans->to); 2044ddfe028SBastien Nocera set_bit(trans->to, hi->input->keybit); 2054ddfe028SBastien Nocera 2064ddfe028SBastien Nocera return 1; 2074ddfe028SBastien Nocera } 2084ddfe028SBastien Nocera 2094ddfe028SBastien Nocera /* ignore others */ 2104ddfe028SBastien Nocera return -1; 2114ddfe028SBastien Nocera 2124ddfe028SBastien Nocera } 2134ddfe028SBastien Nocera 2144ddfe028SBastien Nocera static int icade_input_mapped(struct hid_device *hdev, struct hid_input *hi, 2154ddfe028SBastien Nocera struct hid_field *field, struct hid_usage *usage, 2164ddfe028SBastien Nocera unsigned long **bit, int *max) 2174ddfe028SBastien Nocera { 2184ddfe028SBastien Nocera if (usage->type == EV_KEY) 2194ddfe028SBastien Nocera set_bit(usage->type, hi->input->evbit); 2204ddfe028SBastien Nocera 2214ddfe028SBastien Nocera return -1; 2224ddfe028SBastien Nocera } 2234ddfe028SBastien Nocera 2244ddfe028SBastien Nocera static const struct hid_device_id icade_devices[] = { 2254ddfe028SBastien Nocera { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, 2264ddfe028SBastien Nocera 2274ddfe028SBastien Nocera { } 2284ddfe028SBastien Nocera }; 2294ddfe028SBastien Nocera MODULE_DEVICE_TABLE(hid, icade_devices); 2304ddfe028SBastien Nocera 2314ddfe028SBastien Nocera static struct hid_driver icade_driver = { 2324ddfe028SBastien Nocera .name = "icade", 2334ddfe028SBastien Nocera .id_table = icade_devices, 2344ddfe028SBastien Nocera .event = icade_event, 2354ddfe028SBastien Nocera .input_mapped = icade_input_mapped, 2364ddfe028SBastien Nocera .input_mapping = icade_input_mapping, 2374ddfe028SBastien Nocera }; 238f425458eSH Hartley Sweeten module_hid_driver(icade_driver); 2394ddfe028SBastien Nocera 2404ddfe028SBastien Nocera MODULE_LICENSE("GPL"); 2414ddfe028SBastien Nocera MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); 2424ddfe028SBastien Nocera MODULE_DESCRIPTION("ION iCade input driver"); 243