mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
Merge branch 'for-5.17/magicmouse' into for-linus
- proper batter reporting for hid-magicmouse USB-connected devices (José Expósito)
This commit is contained in:
commit
f771656344
@ -59,6 +59,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,
|
||||
@ -142,6 +144,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)
|
||||
@ -752,6 +755,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)
|
||||
{
|
||||
@ -759,11 +800,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");
|
||||
@ -789,6 +825,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;
|
||||
@ -841,6 +887,7 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
|
||||
return 0;
|
||||
err_stop_hw:
|
||||
del_timer_sync(&msc->battery_timer);
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
}
|
||||
@ -849,17 +896,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,
|
||||
@ -875,6 +957,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,
|
||||
|
Loading…
Reference in New Issue
Block a user