From patchwork Tue May 8 17:51:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukas Rusak X-Patchwork-Id: 10386791 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9856560236 for ; Tue, 8 May 2018 17:51:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8C0BA290B6 for ; Tue, 8 May 2018 17:51:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7F378290BA; Tue, 8 May 2018 17:51:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C73A1290B6 for ; Tue, 8 May 2018 17:51:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754866AbeEHRvO (ORCPT ); Tue, 8 May 2018 13:51:14 -0400 Received: from mail-pl0-f65.google.com ([209.85.160.65]:44095 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751806AbeEHRvN (ORCPT ); Tue, 8 May 2018 13:51:13 -0400 Received: by mail-pl0-f65.google.com with SMTP id e6-v6so2661972plt.11 for ; Tue, 08 May 2018 10:51:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=AouaTS+wVMPXQ+z0XzkG1kAU95quVnU8jErh9FzurLQ=; b=jmqOtQI0ekVyf8UqxNlZGm1Wn8U13gNFPfckrl+FW5RuJVzYnz48Wvh8bFd3hfw9yV zLSG3m4O9NLm1xnIVuYDy9YFZazxzx/34nZmMhRWY5QHYdNrm6L0YASl2/fgR1AWA2QQ ML8DxbAYArb14jJP0y77SHyVHJuZvqE/RFlSL+Zu1EBLPeL2T2qpiYNCM5mBC9bjrzkb TvEUymccINHrrdXZSs8OALiBn0tl4LtETBWlJiipI7eI02H8UTYGX6mpjVLzsnme2wBy BjgjNVzSt2Q/QHOy6PjPMWlP8fs6HGXiG0oQf6h0OsT8yR0pnPjv+D5ra1vl0F0a2+Rx m2PQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=AouaTS+wVMPXQ+z0XzkG1kAU95quVnU8jErh9FzurLQ=; b=c4TT5DhWK3JrlZLPp4IgaDkJo+5Hi+CbfSur39/siuBavifsdirESguuB7PPvwU/l5 86a4eM2Rn0tfGHZKGAixDhJwI7X6D/5GGKCQ1VMVLIMHW0HEzwF1gWEh+2T8bwy/sxt3 eBRBPXUHgRZ9xBYCV0bXrBBCuOPxgJrR9rNOJ44b1ABSATunLZHtapS73Rkxe6PWvyJr W/dycBJ8pDcDwthM8ALZCnt6dO28VXjYnaKMzRxynwtEN1a3RTSa/71N8O1L4dyilAlP 2lT05ameC2y08mD2ixLJlewC8cNveFSVNhEXBjf0IsfqR/tSZXGzxm1RdUWi2dtxjIwF WmuA== X-Gm-Message-State: ALQs6tCiTe03mhbkcOUFUFgsrXjfsZuITT2qKfDXmEXF6C3AYMdKuviE 52Yonu9wF3k3PHlluqikiJIAWW9y X-Google-Smtp-Source: AB8JxZpgUo+kj4Rja8yTR45nCrPs3nZaXGDrZM/QqXYM6sKXs56KZ0CTNl050+INBZQIOp0QuzegQA== X-Received: by 2002:a17:902:7883:: with SMTP id q3-v6mr7567344pll.71.1525801871890; Tue, 08 May 2018 10:51:11 -0700 (PDT) Received: from localhost.localdomain (d154-20-200-72.bchsia.telus.net. [154.20.200.72]) by smtp.gmail.com with ESMTPSA id d19sm62528036pfk.59.2018.05.08.10.51.10 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 08 May 2018 10:51:10 -0700 (PDT) From: Lukas Rusak To: linux-input@vger.kernel.org Subject: [PATCH] drivers/hid: add ouya HID driver Date: Tue, 8 May 2018 10:51:09 -0700 Message-Id: <20180508175109.5524-1-lorusak@gmail.com> X-Mailer: git-send-email 2.17.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This driver is a simple implementation to get the controller working and mapped properly. This driver does not include functionality for the touchpad (yet). The original driver was taken from from the ouya linux tree and has been simplified. It seems there may have been other versions of the controller present that had a broken report descriptor. I have removed that for now. I have permission from the original author to send this patch upstream. --- drivers/hid/Kconfig | 6 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-ouya.c | 131 +++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-quirks.c | 3 + 5 files changed, 144 insertions(+) create mode 100644 drivers/hid/hid-ouya.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 60252fd796f6..6be2c454e72e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -659,6 +659,12 @@ config HID_ORTEK - Ortek WKB-2000 - Skycable wireless presenter +config HID_OUYA + tristate "OUYA Game Controller" + depends on USB_HID + ---help--- + Support for OUYA Game Controller. + config HID_PANTHERLORD tristate "Pantherlord/GreenAsia game controller" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 17a8bd97da9d..4425890934e4 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_NTI) += hid-nti.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o +obj-$(CONFIG_HID_OUYA) += hid-ouya.o obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 0b5cc910f62e..0528efb825fa 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -859,6 +859,9 @@ #define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 #define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003 +#define USB_VENDOR_ID_OUYA 0x2836 +#define USB_DEVICE_ID_OUYA_CONTROLLER 0x0001 + #define USB_VENDOR_ID_PLANTRONICS 0x047f #define USB_VENDOR_ID_PANASONIC 0x04da diff --git a/drivers/hid/hid-ouya.c b/drivers/hid/hid-ouya.c new file mode 100644 index 000000000000..16ff142fe49c --- /dev/null +++ b/drivers/hid/hid-ouya.c @@ -0,0 +1,131 @@ +/* + * HID driver for OUYA Game Controller(s) + * + * Copyright (c) 2013 OUYA + * Copyright (c) 2013 Gregorios Leach + * Copyright (c) 2018 Lukas Rusak + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +static const unsigned int ouya_absmap[] = { + [0x30] = ABS_X, /* left stick X */ + [0x31] = ABS_Y, /* left stick Y */ + [0x32] = ABS_Z, /* L2 */ + [0x33] = ABS_RX, /* right stick X */ + [0x34] = ABS_RY, /* right stick Y */ + [0x35] = ABS_RZ, /* R2 */ +}; + +static const unsigned int ouya_keymap[] = { + [0x1] = BTN_SOUTH, /* O */ + [0x2] = BTN_WEST, /* U */ + [0x3] = BTN_NORTH, /* Y */ + [0x4] = BTN_EAST, /* A */ + [0x5] = BTN_TL, /* L1 */ + [0x6] = BTN_TR, /* R1 */ + [0x7] = BTN_THUMBL, /* L3 */ + [0x8] = BTN_THUMBR, /* R3 */ + [0x9] = BTN_DPAD_UP, /* Up */ + [0xa] = BTN_DPAD_DOWN, /* Down */ + [0xb] = BTN_DPAD_LEFT, /* Left */ + [0xc] = BTN_DPAD_RIGHT, /* Right */ + [0xd] = BTN_TL2, /* L2 */ + [0xe] = BTN_TR2, /* R2 */ + [0xf] = BTN_MODE, /* Power */ +}; + +static int ouya_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { + unsigned int key = usage->hid & HID_USAGE; + + if (key >= ARRAY_SIZE(ouya_keymap)) + return -1; + + key = ouya_keymap[key]; + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); + + return 1; + + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { + unsigned int abs = usage->hid & HID_USAGE; + + if (abs >= ARRAY_SIZE(ouya_absmap)) + return -1; + + abs = ouya_absmap[abs]; + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); + + return 1; + } + + return 0; +} + +static int ouya_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err_free; + } + + return 0; + +err_free: + return ret; +} + +static void ouya_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); +} + +static const struct hid_device_id ouya_devices[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_OUYA, USB_DEVICE_ID_OUYA_CONTROLLER) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ouya_devices); + +static struct hid_driver ouya_driver = { + .name = "ouya", + .id_table = ouya_devices, + .input_mapping = ouya_input_mapping, + .probe = ouya_probe, + .remove = ouya_remove, +}; + +static int __init ouya_init(void) +{ + return hid_register_driver(&ouya_driver); +} + +static void __exit ouya_exit(void) +{ + hid_unregister_driver(&ouya_driver); +} + +module_init(ouya_init); +module_exit(ouya_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lukas Rusak "); +MODULE_AUTHOR("Gregorios Leach "); +MODULE_DESCRIPTION("Ouya Controller Driver"); diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 587e2681a53f..b5adc13e0df1 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -538,6 +538,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S) }, { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, #endif +#if IS_ENABLED(CONFIG_HID_OUYA) + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_OUYA, USB_DEVICE_ID_OUYA_CONTROLLER) }, +#endif #if IS_ENABLED(CONFIG_HID_PANTHERLORD) { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },