Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp3384591pxb; Mon, 17 Jan 2022 19:14:31 -0800 (PST) X-Google-Smtp-Source: ABdhPJzhutfza6A9bQDS3hAPd8wUhHEqJiaJpRmxxPyznaxp6++s6wwOTFsAzdj5BHJPFROQSici X-Received: by 2002:a17:902:e845:b0:14a:4ef1:dd0b with SMTP id t5-20020a170902e84500b0014a4ef1dd0bmr25476597plg.21.1642475671361; Mon, 17 Jan 2022 19:14:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1642475671; cv=none; d=google.com; s=arc-20160816; b=ZCJXRIggNqBhmJ80T3MyqDwX6tT/QMh928O1EWhF06tOmz6NuOE/bXbAzZFJFH2MKb 5iNbbD5S8Q8ebNOzd0L3fD4yXyXgho5j7AJYZhwDef8PQyTMIdcSxRmxPXS/htimqVM7 QlA/0rto+LwG694IT/hbBZIWdbXZpTd4VH9+TW6BqmJJaFs9+RKY9xUDGxpTOO4qs2sw S8i3ydfi5/s5ZIjGUx28yjkBMLMy10jmdTRCl2zfZIgDiybabmPS5BdCUOPgr3+ky39Z UegkaaXSCcBakxTheZolLOcI6HGrF2KOhpAcCs80lHv4ndhOicpmkXWj979WX5GZ/xcV XYqQ== 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 :dkim-signature; bh=fLUwRNvhsmab9d+k/tjwh2hB7Z+HNljgLsA4CTouxKU=; b=Xa29+cVBA6ABti8MoDuv5DZhHtC7eGpIxn5zT6pcsKLztbFG5Bb4eXwwzhtIbp5NrZ yLF6AOJCkEqMF4jDKxKVBwThvw7B2uF8JzSYB23A51JzPvUTmdBuyd/oGN2iOFE3DnUx eWNYbqjCmUmZKyq9s7fKhZq8he3qqYzabxdBAxQgvfUm3NdMg90ItMqMoWSLPGsOpjAs dOsQMzQ2Bcd1BGoeyTIEe65bpMeOGNQ3zQfCME2pOFc05KjALs/zAEATn4qJhOx+aUiG q8tzgK6zua9oR6n6Y17ebHAbkarr4zLhPfWiEwNL0YKG9/BWpB8Ji0TKrUspxgtH/FjI 4hRA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=hNkTQqXu; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id pj13si1404611pjb.133.2022.01.17.19.14.09; Mon, 17 Jan 2022 19:14:31 -0800 (PST) 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; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=hNkTQqXu; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245217AbiARCXT (ORCPT + 99 others); Mon, 17 Jan 2022 21:23:19 -0500 Received: from dfw.source.kernel.org ([139.178.84.217]:39016 "EHLO dfw.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244864AbiARCW2 (ORCPT ); Mon, 17 Jan 2022 21:22:28 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 5839B60A6B; Tue, 18 Jan 2022 02:22:28 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DD179C36AEF; Tue, 18 Jan 2022 02:22:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1642472547; bh=1EyoLpH3u/C9VtsMId1mXlNNHGrLClCkoMSf0/DC940=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hNkTQqXuYgVeFdMG8aVRz/PbIoxCFufQJAN/cZrncaETkooaUxzVbaUcMYKildpcP pxeryes58xIx+WecBMZtpP2wFqmBBkUPSn4Ag6tetUbyxn8NP7clXyYPkDA7dZc36F b9HDwlULvspeZrU6g/AvDisppJYacWYjkDfRWpn3zcOmXil8Rekdo5qD5SYSm6e1sY sajZqVfOQrBXV0zBRh8jMkCxRqQHMmTylhC5XKIi32Y98JAOqaENBc9//aI9uJpmSn iQQ9GCTZ2U2kn4wOWjTjMwacAwmwANZfErR/A4WSPCS/zXFwNsrpFwlRhJqnpgLRkw NGm7SG/C4nsGg== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= , Jiri Kosina , Sasha Levin , jikos@kernel.org, benjamin.tissoires@redhat.com, linux-input@vger.kernel.org Subject: [PATCH AUTOSEL 5.16 048/217] HID: magicmouse: Report battery level over USB Date: Mon, 17 Jan 2022 21:16:51 -0500 Message-Id: <20220118021940.1942199-48-sashal@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220118021940.1942199-1-sashal@kernel.org> References: <20220118021940.1942199-1-sashal@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: José Expósito [ Upstream commit 0b91b4e4dae63cd43871fc2012370b86ee588f91 ] When connected over USB, the Apple Magic Mouse 2 and the Apple Magic Trackpad 2 register multiple interfaces, one of them is used to report the battery level. However, unlike when connected over Bluetooth, the battery level is not reported automatically and it is required to fetch it manually. Fix the battery report descriptor and add a timer to fetch the battery level. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- drivers/hid/hid-magicmouse.c | 94 +++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index d7687ce706144..eba1e8087bfd1 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -57,6 +57,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define MOUSE_REPORT_ID 0x29 #define MOUSE2_REPORT_ID 0x12 #define DOUBLE_REPORT_ID 0xf7 +#define USB_BATTERY_TIMEOUT_MS 60000 + /* These definitions are not precise, but they're close enough. (Bits * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem * to be some kind of bit mask -- 0x20 may be a near-field reading, @@ -140,6 +142,7 @@ struct magicmouse_sc { struct hid_device *hdev; struct delayed_work work; + struct timer_list battery_timer; }; static int magicmouse_firm_touch(struct magicmouse_sc *msc) @@ -738,6 +741,44 @@ static void magicmouse_enable_mt_work(struct work_struct *work) hid_err(msc->hdev, "unable to request touch data (%d)\n", ret); } +static int magicmouse_fetch_battery(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_BATTERY_STRENGTH + struct hid_report_enum *report_enum; + struct hid_report *report; + + if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE || + (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 && + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) + return -1; + + report_enum = &hdev->report_enum[hdev->battery_report_type]; + report = report_enum->report_id_hash[hdev->battery_report_id]; + + if (!report || report->maxfield < 1) + return -1; + + if (hdev->battery_capacity == hdev->battery_max) + return -1; + + hid_hw_request(hdev, report, HID_REQ_GET_REPORT); + return 0; +#else + return -1; +#endif +} + +static void magicmouse_battery_timer_tick(struct timer_list *t) +{ + struct magicmouse_sc *msc = from_timer(msc, t, battery_timer); + struct hid_device *hdev = msc->hdev; + + if (magicmouse_fetch_battery(hdev) == 0) { + mod_timer(&msc->battery_timer, + jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS)); + } +} + static int magicmouse_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -745,11 +786,6 @@ static int magicmouse_probe(struct hid_device *hdev, struct hid_report *report; int ret; - if (id->vendor == USB_VENDOR_ID_APPLE && - id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && - hdev->type != HID_TYPE_USBMOUSE) - return -ENODEV; - msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); if (msc == NULL) { hid_err(hdev, "can't alloc magicmouse descriptor\n"); @@ -775,6 +811,16 @@ static int magicmouse_probe(struct hid_device *hdev, return ret; } + timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0); + mod_timer(&msc->battery_timer, + jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS)); + magicmouse_fetch_battery(hdev); + + if (id->vendor == USB_VENDOR_ID_APPLE && + (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE))) + return 0; + if (!msc->input) { hid_err(hdev, "magicmouse input not registered\n"); ret = -ENOMEM; @@ -835,17 +881,52 @@ static void magicmouse_remove(struct hid_device *hdev) { struct magicmouse_sc *msc = hid_get_drvdata(hdev); - if (msc) + if (msc) { cancel_delayed_work_sync(&msc->work); + del_timer_sync(&msc->battery_timer); + } hid_hw_stop(hdev); } +static __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + /* + * Change the usage from: + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 + * 0x09, 0x0b, // Usage (Vendor Usage 0x0b) 3 + * To: + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x02, // Usage (Mouse) 2 + */ + if (hdev->vendor == USB_VENDOR_ID_APPLE && + (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && + *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) { + hid_info(hdev, + "fixing up magicmouse battery report descriptor\n"); + *rsize = *rsize - 1; + rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL); + if (!rdesc) + return NULL; + + rdesc[0] = 0x05; + rdesc[1] = 0x01; + rdesc[2] = 0x09; + rdesc[3] = 0x02; + } + + return rdesc; +} + static const struct hid_device_id magic_mice[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, @@ -861,6 +942,7 @@ static struct hid_driver magicmouse_driver = { .id_table = magic_mice, .probe = magicmouse_probe, .remove = magicmouse_remove, + .report_fixup = magicmouse_report_fixup, .raw_event = magicmouse_raw_event, .event = magicmouse_event, .input_mapping = magicmouse_input_mapping, -- 2.34.1