From patchwork Thu Nov 3 18:47:42 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcel Hasler X-Patchwork-Id: 9411349 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 B169960573 for ; Thu, 3 Nov 2016 18:47:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AD2492AED7 for ; Thu, 3 Nov 2016 18:47:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A22A72AEDA; Thu, 3 Nov 2016 18:47:50 +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=-6.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, 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 0BAC52AED7 for ; Thu, 3 Nov 2016 18:47:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757710AbcKCSrt (ORCPT ); Thu, 3 Nov 2016 14:47:49 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:34370 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756911AbcKCSrs (ORCPT ); Thu, 3 Nov 2016 14:47:48 -0400 Received: by mail-wm0-f65.google.com with SMTP id p190so378995wmp.1 for ; Thu, 03 Nov 2016 11:47:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=PIv6TJPHroTqFsMD/pKMsR7IuYNZE95hGNcJt1y9lis=; b=0w70BqMhy1/+6d7abWcIurqaj4nIVcYc00owIN2rluFMWFQ0LYbstne+NVMFMSiU9u +RuhKBBgbEPT+7qW1+9z2fxDR91MK4bscRbapF/OysN7hN455rSGWjyhKOCLvUJYqt7H G7XS+z/8SI4G21qvIg+zv26jyUGcwloIFDbpfftsX7u9wZIRj/7Xo4cnqiJ7HzLJGhsx KCvFyuxsl9IhWJA0VQlP7H0cw2seuGZPOkR2mkLMQ86G/IrhtLwpmimpatVBdlscSi7j Jaf4DobJJplOXgepXnMw59yg7iaGjcU8sEKJq2XfM/HHPWH+xyP2hEU091cSOeB7D1fu 1pRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=PIv6TJPHroTqFsMD/pKMsR7IuYNZE95hGNcJt1y9lis=; b=C2GNTFDRthUj0iLoE3fHb2DVQE4DMqzB0nB2Lrm4CrnwEPoMfV1mUGaqZKCgKCmVWT 2DEevnRZbtaPZw0Xu2CxCz0AcTQyS5haL8KYVRwij/mIS66wFzuPS0KITqD4jN0T1WLI oPaXNFUSHXnYmbhhlUOVk3uCPdBbVO2VNCmq4mw6uazegTLIY6i/n6mED1Nda8IWjzQG EoTFJMJZjYjsAa8nI3mH2n3ue/gQph0VjwoQclcsm8a+eC4FIyTzDIol0cV8Q2r6Cvjl mvQvc3haQsrhH0P0tSPcqIC6bv61DOUJQymMnx9r/aSnX852MZPVdGrvRtjzOEOmVPB0 xeeg== X-Gm-Message-State: ABUngvem7QXDbo/6aiEfJ0EP/mAW+ra+dczhy/E390tykN0LR2MfhAuLP2LLxHSb5kVUoQ== X-Received: by 10.194.161.68 with SMTP id xq4mr8521355wjb.205.1478198867198; Thu, 03 Nov 2016 11:47:47 -0700 (PDT) Received: from arch-desktop ([2a02:908:672:a420:922b:34ff:fe11:2b9f]) by smtp.gmail.com with ESMTPSA id n72sm409801wmd.11.2016.11.03.11.47.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Nov 2016 11:47:46 -0700 (PDT) Date: Thu, 3 Nov 2016 19:47:42 +0100 From: Marcel Hasler To: Jiri Kosina , Benjamin Tissoires Cc: linux-input@vger.kernel.org Subject: [PATCH v3 2/2] Add new force feedback driver for Mayflash game controller adapters. Message-ID: <20161103184742.GA21349@arch-desktop> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.7.1 (2016-10-04) 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 Add a new module named hid-mf that implements force feedback for game controller adapters manufactured by Mayflash. Currently only the PS3 adapter is supported, other adapters still need to be tested. Signed-off-by: Marcel Hasler --- drivers/hid/Kconfig | 8 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 3 + drivers/hid/hid-mf.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 drivers/hid/hid-mf.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cd4599c..1530d28 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -512,6 +512,14 @@ config HID_MAGICMOUSE Say Y here if you want support for the multi-touch features of the Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. +config HID_MAYFLASH + tristate "Mayflash game controller adapter force feedback" + depends on HID + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you have HJZ Mayflash PS3 game controller adapters + and want to enable force feedback support. + config HID_MICROSOFT tristate "Microsoft non-fully HID-compliant devices" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 86b2b57..c0453f1 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o +obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2b89c70..39694a5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1883,6 +1883,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, +#if IS_ENABLED(CONFIG_HID_MAYFLASH) + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3) }, +#endif { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, diff --git a/drivers/hid/hid-mf.c b/drivers/hid/hid-mf.c new file mode 100644 index 0000000..d909076 --- /dev/null +++ b/drivers/hid/hid-mf.c @@ -0,0 +1,166 @@ +/* + * Force feedback support for Mayflash game controller adapters. + * + * These devices are manufactured by Mayflash but identify themselves + * using the vendor ID of DragonRise Inc. + * + * Tested with: + * 0079:1801 "DragonRise Inc. Mayflash PS3 Game Controller Adapter" + * + * The following adapters probably work too, but need to be tested: + * 0079:1800 "DragonRise Inc. Mayflash WIIU Game Controller Adapter" + * 0079:1843 "DragonRise Inc. Mayflash GameCube Game Controller Adapter" + * + * Copyright (c) 2016 Marcel Hasler + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +struct mf_device { + struct hid_report *report; +}; + +static int mf_play(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct mf_device *mf = data; + int strong, weak; + + strong = effect->u.rumble.strong_magnitude; + weak = effect->u.rumble.weak_magnitude; + + dbg_hid("Called with 0x%04x 0x%04x.\n", strong, weak); + + strong = strong * 0xff / 0xffff; + weak = weak * 0xff / 0xffff; + + dbg_hid("Running with 0x%02x 0x%02x.\n", strong, weak); + + mf->report->field[0]->value[0] = weak; + mf->report->field[0]->value[1] = strong; + hid_hw_request(hid, mf->report, HID_REQ_SET_REPORT); + + return 0; +} + +static int mf_init(struct hid_device *hid) +{ + struct mf_device *mf; + + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + + struct list_head *report_ptr; + struct hid_report *report; + + struct list_head *input_ptr = &hid->inputs; + struct hid_input *input; + + struct input_dev *dev; + + int error; + + /* Setup each of the four inputs */ + list_for_each(report_ptr, report_list) { + report = list_entry(report_ptr, struct hid_report, list); + + if (report->maxfield < 1 || report->field[0]->report_count < 2) { + hid_err(hid, "Invalid report, this should never happen!\n"); + return -ENODEV; + } + + if (list_is_last(input_ptr, &hid->inputs)) { + hid_err(hid, "Missing input, this should never happen!\n"); + return -ENODEV; + } + + input_ptr = input_ptr->next; + input = list_entry(input_ptr, struct hid_input, list); + + mf = kzalloc(sizeof(struct mf_device), GFP_KERNEL); + if (!mf) + return -ENOMEM; + + dev = input->input; + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, mf, mf_play); + if (error) { + kfree(mf); + return error; + } + + mf->report = report; + mf->report->field[0]->value[0] = 0x00; + mf->report->field[0]->value[1] = 0x00; + hid_hw_request(hid, mf->report, HID_REQ_SET_REPORT); + } + + hid_info(hid, "Force feedback for HJZ Mayflash game controller " + "adapters by Marcel Hasler \n"); + + return 0; +} + +static int mf_probe(struct hid_device *hid, const struct hid_device_id *id) +{ + int error; + + dev_dbg(&hid->dev, "Mayflash HID hardware probe...\n"); + + /* Split device into four inputs */ + hid->quirks |= HID_QUIRK_MULTI_INPUT; + + error = hid_parse(hid); + if (error) { + hid_err(hid, "HID parse failed.\n"); + return error; + } + + error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (error) { + hid_err(hid, "HID hw start failed\n"); + return error; + } + + error = mf_init(hid); + if (error) { + hid_err(hid, "Force feedback init failed.\n"); + hid_hw_stop(hid); + return error; + } + + return 0; +} + +static const struct hid_device_id mf_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), }, + { } +}; +MODULE_DEVICE_TABLE(hid, mf_devices); + +static struct hid_driver mf_driver = { + .name = "hid_mf", + .id_table = mf_devices, + .probe = mf_probe, +}; +module_hid_driver(mf_driver); + +MODULE_LICENSE("GPL");