Received: by 2002:a05:6a10:a852:0:0:0:0 with SMTP id d18csp2250616pxy; Sun, 2 May 2021 16:32:29 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzd2gW9E+7g8yADKzkVL5Ft2oVkqikebD4lrf6gRhq6nRouilvxPn9I7EzzXNNZDYMbUmQw X-Received: by 2002:a17:906:5855:: with SMTP id h21mr14297927ejs.522.1619998349769; Sun, 02 May 2021 16:32:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1619998349; cv=none; d=google.com; s=arc-20160816; b=jX3PCxj3e3x703VhWzObLEPn72q+Ds7JZlbNu05Z+9Yi3VpUTgVLVh81MeFFoAZWeP U2eYSrvUQD8S+/lDvzCiTyD92/8wlMM/ziJaiHVDWJOf1RVqaf+OJXTw4iWwxtki7eRG 41cxDFZASX8ZP30emalK1ujoGvh5e4PdZwtgcF+Dbrb3UNW3d8G82uFHCwtiqHe6zbY5 I4JTn3XjARsn6Uhw62m38VIBz/y4tGhpoTTD5oj8n+lA0nZa2GtFiP4XB5c2BOZpW8yx VJPQeyNxGvd9tb7A4XJ8qEEVV1NIB6Wmd1PWOswGX7zNImye0uBe50W8khaHDNfWubzq M9Aw== 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=ekL6ikZjCFfSsiwMEjFLWuUH0ACdCCeoRfTgwMA0bFM=; b=ezr0T6rfrJP5NBEJhuqKt6ejlmYRVyTY4ssv+zxGE9eed9zXxc5qCaDK8AGpcXpFtz 3xtOWslp4dvqO0twuASOBzDCCIzD57CVQHQ5cOxUvCfUJ9ZU2eqYmJPNUcqw71B6Sheu SBlFxAVKqvuM4qdMIEFTA5h2c0U15vWpHco5OyTKNphpnKaaoXm9+p2U/fsWxsh+EftO 045nygC5YvTIqeBAQ8ai595iTZS/uA6IJUB5RlvXF/t3kzSslIiteiVR196vS8xPeWCz e6Ni2Cqwph/OJAydljD3vwLO7ZF7ExqvJaOFEhUGW1UslT0k7xvt3iNVgl7sd71QLi5J /soA== 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 i11si9358369ejv.738.2021.05.02.16.32.06; Sun, 02 May 2021 16:32:29 -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 S232584AbhEBXaI (ORCPT + 99 others); Sun, 2 May 2021 19:30:08 -0400 Received: from 82-65-109-163.subs.proxad.net ([82.65.109.163]:54992 "EHLO luna.linkmauve.fr" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232459AbhEBX3z (ORCPT ); Sun, 2 May 2021 19:29:55 -0400 Received: by luna.linkmauve.fr (Postfix, from userid 1000) id 4505CF405D9; Mon, 3 May 2021 01:29:00 +0200 (CEST) From: Emmanuel Gil Peyrot To: linux-input@vger.kernel.org Cc: Emmanuel Gil Peyrot , Ash Logan , =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= , Jiri Kosina , Benjamin Tissoires , linux-kernel@vger.kernel.org Subject: [PATCH 3/4] HID: wiiu-drc: Add accelerometer, gyroscope and magnetometer readings Date: Mon, 3 May 2021 01:28:34 +0200 Message-Id: <20210502232836.26134-4-linkmauve@linkmauve.fr> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210502232836.26134-1-linkmauve@linkmauve.fr> References: <20210502232836.26134-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 seems to give at least 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 over time. Another solution might be to go for the iio subsystem instead, but 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-wiiu-drc.c | 78 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-wiiu-drc.c b/drivers/hid/hid-wiiu-drc.c index 77e70827c37d..80faaaad2bb5 100644 --- a/drivers/hid/hid-wiiu-drc.c +++ b/drivers/hid/hid-wiiu-drc.c @@ -61,15 +61,25 @@ #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 ACCEL_MIN +#define MAGNET_MAX ACCEL_MAX + /* * 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 { struct input_dev *joy_input_dev; struct input_dev *touch_input_dev; + struct input_dev *accel_input_dev; struct hid_device *hdev; }; @@ -77,7 +87,7 @@ static int drc_raw_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) @@ -171,6 +181,31 @@ static int drc_raw_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; } @@ -239,6 +274,41 @@ 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"); + if (!input_dev) + return false; + + input_dev->evbit[0] = BIT(EV_ABS); + + /* 1G accel is reported as about -7600 */ + 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); + + set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); + + drc->accel_input_dev = input_dev; + + return true; +} + static bool drc_setup_joypad(struct drc *drc, struct hid_device *hdev) { @@ -303,13 +373,15 @@ static int drc_probe(struct hid_device *hdev, const struct hid_device_id *id) } 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; } 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.31.1