Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp881333pxb; Wed, 27 Oct 2021 14:23:03 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxOzyPM48tmVA3SH3Bujceb8OqdSRW4VRtotrGVIKOdBR/4/6mWvkuXK4MjfFZ3VvrVMyDw X-Received: by 2002:a17:907:6da3:: with SMTP id sb35mr51053ejc.41.1635369783437; Wed, 27 Oct 2021 14:23:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1635369783; cv=none; d=google.com; s=arc-20160816; b=Rd3NnLCua1U3eoKvBR9OFq2GTx0s/tmaqxIp/8MBeRX++AsUOjW9GKXgjueCYo4dT3 KFkr5QhFnv059XkZaW53YlIubIO5jz4+J9bTLxCakJSayh9+Ol9TyCxYQrRNULMxYiNL 5Zu8yKYdNVXufX4vbJcQzeyK8fVRe6TGglkEeDJppBh3ESFcjza4yFIr4YVWYlTZaW5E bj73nMy4f+L7ZeRxMrM8Naj5Ueq2DXzDZeT6+RMiaqXgKBjSxuOOdXH9hWFfnNsc2u8p yOUqEPadArzQ0JR60QiXvqUD/Z3Zu9iG5YbwzyJTwCAGdoMbyjH7ucAgcIv3RSWGtEf7 5QVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=5YgMXw0H/D0QxaxkBbVh0mwnE8PB4mcdLRGnu85ohsY=; b=x00QGAbgR/+0ADMDbiCbk/qefygxYMNiPLdHX6DnrfBsrkmDxLZqCYpAEUOL7iTJH7 ap+j4wKZThOYtAAYP7N9FDkH7dbipr8TqXv+1fXhMFRYvAqkxfeJof/+rJM4TtNaHBaS zpuZaJT90RwVP7IZAzb0b3UPXh2sHaqJgj9nSjyvRfUNN3/INR+T4Z3GfDd4mOR1NJmw IlZgqRkWjc/f+NHEefRIeDUisD/OZpBDXPTQxqH5AOnXLsL+4cw6sK/eIZUprcyObV97 HUQIdKWI4ANuTHsbLtDRLCO0dfcMRXhJAmdvxL9vr2Pd8XdxlWnGDekYI+esGctc+vUf Ax7A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z42si1122829ede.468.2021.10.27.14.22.40; Wed, 27 Oct 2021 14:23:03 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241387AbhJ0KNf (ORCPT + 97 others); Wed, 27 Oct 2021 06:13:35 -0400 Received: from 82-65-109-163.subs.proxad.net ([82.65.109.163]:50214 "EHLO luna.linkmauve.fr" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241322AbhJ0KNR (ORCPT ); Wed, 27 Oct 2021 06:13:17 -0400 Received: by luna.linkmauve.fr (Postfix, from userid 1000) id A87EDF40CA5; Wed, 27 Oct 2021 12:10:48 +0200 (CEST) From: Emmanuel Gil Peyrot To: Jiri Kosina Cc: Emmanuel Gil Peyrot , linux-input@vger.kernel.org, Ash Logan , =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= , =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= , Benjamin Tissoires , linux-kernel@vger.kernel.org, "Daniel J . Ogorchock" Subject: [PATCH v5 4/5] HID: nintendo: drc: add accelerometer, gyroscope and magnetometer readings Date: Wed, 27 Oct 2021 12:10:42 +0200 Message-Id: <20211027101043.31609-5-linkmauve@linkmauve.fr> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211027101043.31609-1-linkmauve@linkmauve.fr> References: <20211019110418.26874-1-linkmauve@linkmauve.fr> <20211027101043.31609-1-linkmauve@linkmauve.fr> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org These are mostly untested so far, because I have no idea which userland to test against, but evtest at least seems to give sensible values. The magnetometer doesn’t have dedicated INPUT_PROP_ACCELEROMETER buttons, so I used three clearly invalid absolute values, in the hope that someone will fix that eventually. Another solution might be to go for the iio subsystem instead, but then it wouldn’t be tied to the HID any longer and I would feel uneasy about that. Especially because multiple such gamepads could be connected to a single computer. Signed-off-by: Ash Logan Signed-off-by: Emmanuel Gil Peyrot --- drivers/hid/hid-nintendo-wiiu.c | 77 +++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-nintendo-wiiu.c b/drivers/hid/hid-nintendo-wiiu.c index 144316d324cb..813abb104275 100644 --- a/drivers/hid/hid-nintendo-wiiu.c +++ b/drivers/hid/hid-nintendo-wiiu.c @@ -64,10 +64,19 @@ #define TOUCH_BORDER_X 100 #define TOUCH_BORDER_Y 200 +/* Accelerometer, gyroscope and magnetometer constants */ +#define ACCEL_MIN -(1 << 15) +#define ACCEL_MAX ((1 << 15) - 1) +#define GYRO_MIN -(1 << 23) +#define GYRO_MAX ((1 << 23) - 1) +#define MAGNET_MIN -(1 << 15) +#define MAGNET_MAX ((1 << 15) - 1) + /* * The device is setup with multiple input devices: * - A joypad with the buttons and sticks. * - The touch area which works as a touchscreen. + * - An accelerometer + gyroscope + magnetometer device. */ struct drc { @@ -75,6 +84,7 @@ struct drc { struct hid_device *hdev; struct input_dev *joy_input_dev; struct input_dev *touch_input_dev; + struct input_dev *accel_input_dev; }; /* @@ -89,7 +99,7 @@ int wiiu_hid_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int len) { struct drc *drc = hid_get_drvdata(hdev); - int i, x, y, pressure, base; + int i, x, y, z, pressure, base; u32 buttons; if (len != 128) @@ -184,6 +194,31 @@ int wiiu_hid_event(struct hid_device *hdev, struct hid_report *report, } input_sync(drc->touch_input_dev); + /* accelerometer */ + x = (data[16] << 8) | data[15]; + y = (data[18] << 8) | data[17]; + z = (data[20] << 8) | data[19]; + input_report_abs(drc->accel_input_dev, ABS_X, (int16_t)x); + input_report_abs(drc->accel_input_dev, ABS_Y, (int16_t)y); + input_report_abs(drc->accel_input_dev, ABS_Z, (int16_t)z); + + /* gyroscope */ + x = (data[23] << 24) | (data[22] << 16) | (data[21] << 8); + y = (data[26] << 24) | (data[25] << 16) | (data[24] << 8); + z = (data[29] << 24) | (data[28] << 16) | (data[27] << 8); + input_report_abs(drc->accel_input_dev, ABS_RX, x >> 8); + input_report_abs(drc->accel_input_dev, ABS_RY, y >> 8); + input_report_abs(drc->accel_input_dev, ABS_RZ, z >> 8); + + /* magnetometer */ + x = (data[31] << 8) | data[30]; + y = (data[33] << 8) | data[32]; + z = (data[35] << 8) | data[34]; + input_report_abs(drc->accel_input_dev, ABS_THROTTLE, (int16_t)x); + input_report_abs(drc->accel_input_dev, ABS_RUDDER, (int16_t)y); + input_report_abs(drc->accel_input_dev, ABS_WHEEL, (int16_t)z); + input_sync(drc->accel_input_dev); + /* let hidraw and hiddev handle the report */ return 0; } @@ -299,6 +334,40 @@ static bool drc_setup_touch(struct drc *drc, return true; } +static bool drc_setup_accel(struct drc *drc, + struct hid_device *hdev) +{ + struct input_dev *input_dev; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME " accelerometer, gyroscope and magnetometer"); + if (!input_dev) + return false; + + drc->accel_input_dev = input_dev; + + set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); + + /* 1G accel is reported as about -7900 */ + input_set_abs_params(input_dev, ABS_X, ACCEL_MIN, ACCEL_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_Y, ACCEL_MIN, ACCEL_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_Z, ACCEL_MIN, ACCEL_MAX, 0, 0); + + /* gyroscope */ + input_set_abs_params(input_dev, ABS_RX, GYRO_MIN, GYRO_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_RY, GYRO_MIN, GYRO_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_RZ, GYRO_MIN, GYRO_MAX, 0, 0); + + /* magnetometer */ + /* TODO: Figure out which ABS_* would make more sense to expose, or + * maybe go for the iio subsystem? + */ + input_set_abs_params(input_dev, ABS_THROTTLE, MAGNET_MIN, MAGNET_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_RUDDER, MAGNET_MIN, MAGNET_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_WHEEL, MAGNET_MIN, MAGNET_MAX, 0, 0); + + return true; +} + int wiiu_hid_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -321,7 +390,8 @@ int wiiu_hid_probe(struct hid_device *hdev, } if (!drc_setup_joypad(drc, hdev) || - !drc_setup_touch(drc, hdev)) { + !drc_setup_touch(drc, hdev) || + !drc_setup_accel(drc, hdev)) { hid_err(hdev, "could not allocate interfaces\n"); return -ENOMEM; } @@ -333,7 +403,8 @@ int wiiu_hid_probe(struct hid_device *hdev, } ret = input_register_device(drc->joy_input_dev) || - input_register_device(drc->touch_input_dev); + input_register_device(drc->touch_input_dev) || + input_register_device(drc->accel_input_dev); if (ret) { hid_err(hdev, "failed to register interfaces\n"); return ret; -- 2.33.1