Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
275ac61b
Commit
275ac61b
authored
Apr 29, 2021
by
Jiri Kosina
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-5.13/magicmouse' into for-linus
- Apple Magic Mouse 2 support from John Chen
parents
686e161e
9de07a4e
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
147 additions
and
38 deletions
+147
-38
drivers/hid/hid-debug.c
drivers/hid/hid-debug.c
+1
-0
drivers/hid/hid-ids.h
drivers/hid/hid-ids.h
+1
-0
drivers/hid/hid-input.c
drivers/hid/hid-input.c
+16
-6
drivers/hid/hid-magicmouse.c
drivers/hid/hid-magicmouse.c
+126
-32
include/linux/hid.h
include/linux/hid.h
+3
-0
No files found.
drivers/hid/hid-debug.c
View file @
275ac61b
...
...
@@ -417,6 +417,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{
0x85
,
0x44
,
"Charging"
},
{
0x85
,
0x45
,
"Discharging"
},
{
0x85
,
0x4b
,
"NeedReplacement"
},
{
0x85
,
0x65
,
"AbsoluteStateOfCharge"
},
{
0x85
,
0x66
,
"RemainingCapacity"
},
{
0x85
,
0x68
,
"RunTimeToEmpty"
},
{
0x85
,
0x6a
,
"AverageTimeToFull"
},
...
...
drivers/hid/hid-ids.h
View file @
275ac61b
...
...
@@ -93,6 +93,7 @@
#define BT_VENDOR_ID_APPLE 0x004c
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
#define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
...
...
drivers/hid/hid-input.c
View file @
275ac61b
...
...
@@ -435,7 +435,8 @@ static int hidinput_get_battery_property(struct power_supply *psy,
return
ret
;
}
static
int
hidinput_setup_battery
(
struct
hid_device
*
dev
,
unsigned
report_type
,
struct
hid_field
*
field
)
static
int
hidinput_setup_battery
(
struct
hid_device
*
dev
,
unsigned
report_type
,
struct
hid_field
*
field
,
bool
is_percentage
)
{
struct
power_supply_desc
*
psy_desc
;
struct
power_supply_config
psy_cfg
=
{
.
drv_data
=
dev
,
};
...
...
@@ -475,7 +476,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
min
=
field
->
logical_minimum
;
max
=
field
->
logical_maximum
;
if
(
quirks
&
HID_BATTERY_QUIRK_PERCENT
)
{
if
(
is_percentage
||
(
quirks
&
HID_BATTERY_QUIRK_PERCENT
)
)
{
min
=
0
;
max
=
100
;
}
...
...
@@ -552,7 +553,7 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
}
#else
/* !CONFIG_HID_BATTERY_STRENGTH */
static
int
hidinput_setup_battery
(
struct
hid_device
*
dev
,
unsigned
report_type
,
struct
hid_field
*
field
)
struct
hid_field
*
field
,
bool
is_percentage
)
{
return
0
;
}
...
...
@@ -806,7 +807,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break
;
case
0x3b
:
/* Battery Strength */
hidinput_setup_battery
(
device
,
HID_INPUT_REPORT
,
field
);
hidinput_setup_battery
(
device
,
HID_INPUT_REPORT
,
field
,
false
);
usage
->
type
=
EV_PWR
;
return
;
...
...
@@ -1068,7 +1069,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case
HID_UP_GENDEVCTRLS
:
switch
(
usage
->
hid
)
{
case
HID_DC_BATTERYSTRENGTH
:
hidinput_setup_battery
(
device
,
HID_INPUT_REPORT
,
field
);
hidinput_setup_battery
(
device
,
HID_INPUT_REPORT
,
field
,
false
);
usage
->
type
=
EV_PWR
;
return
;
}
goto
unknown
;
case
HID_UP_BATTERY
:
switch
(
usage
->
hid
)
{
case
HID_BAT_ABSOLUTESTATEOFCHARGE
:
hidinput_setup_battery
(
device
,
HID_INPUT_REPORT
,
field
,
true
);
usage
->
type
=
EV_PWR
;
return
;
}
...
...
@@ -1672,7 +1682,7 @@ static void report_features(struct hid_device *hid)
/* Verify if Battery Strength feature is available */
if
(
usage
->
hid
==
HID_DC_BATTERYSTRENGTH
)
hidinput_setup_battery
(
hid
,
HID_FEATURE_REPORT
,
rep
->
field
[
i
]);
rep
->
field
[
i
]
,
false
);
if
(
drv
->
feature_mapping
)
drv
->
feature_mapping
(
hid
,
rep
->
field
[
i
],
usage
);
...
...
drivers/hid/hid-magicmouse.c
View file @
275ac61b
...
...
@@ -16,6 +16,7 @@
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include "hid-ids.h"
...
...
@@ -54,6 +55,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define TRACKPAD2_USB_REPORT_ID 0x02
#define TRACKPAD2_BT_REPORT_ID 0x31
#define MOUSE_REPORT_ID 0x29
#define MOUSE2_REPORT_ID 0x12
#define DOUBLE_REPORT_ID 0xf7
/* These definitions are not precise, but they're close enough. (Bits
* 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
...
...
@@ -127,6 +129,9 @@ struct magicmouse_sc {
u8
size
;
}
touches
[
16
];
int
tracking_ids
[
16
];
struct
hid_device
*
hdev
;
struct
delayed_work
work
;
};
static
int
magicmouse_firm_touch
(
struct
magicmouse_sc
*
msc
)
...
...
@@ -195,7 +200,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
int
id
,
x
,
y
,
size
,
orientation
,
touch_major
,
touch_minor
,
state
,
down
;
int
pressure
=
0
;
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
||
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
{
id
=
(
tdata
[
6
]
<<
2
|
tdata
[
5
]
>>
6
)
&
0xf
;
x
=
(
tdata
[
1
]
<<
28
|
tdata
[
0
]
<<
20
)
>>
20
;
y
=
-
((
tdata
[
2
]
<<
24
|
tdata
[
1
]
<<
16
)
>>
20
);
...
...
@@ -296,7 +302,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
input_report_abs
(
input
,
ABS_MT_PRESSURE
,
pressure
);
if
(
report_undeciphered
)
{
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
||
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
input_event
(
input
,
EV_MSC
,
MSC_RAW
,
tdata
[
7
]);
else
if
(
input
->
id
.
product
!=
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2
)
...
...
@@ -380,6 +387,34 @@ static int magicmouse_raw_event(struct hid_device *hdev,
* ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
*/
break
;
case
MOUSE2_REPORT_ID
:
/* Size is either 8 or (14 + 8 * N) */
if
(
size
!=
8
&&
(
size
<
14
||
(
size
-
14
)
%
8
!=
0
))
return
0
;
npoints
=
(
size
-
14
)
/
8
;
if
(
npoints
>
15
)
{
hid_warn
(
hdev
,
"invalid size value (%d) for MOUSE2_REPORT_ID
\n
"
,
size
);
return
0
;
}
msc
->
ntouches
=
0
;
for
(
ii
=
0
;
ii
<
npoints
;
ii
++
)
magicmouse_emit_touch
(
msc
,
ii
,
data
+
ii
*
8
+
14
);
/* When emulating three-button mode, it is important
* to have the current touch information before
* generating a click event.
*/
x
=
(
int
)((
data
[
3
]
<<
24
)
|
(
data
[
2
]
<<
16
))
>>
16
;
y
=
(
int
)((
data
[
5
]
<<
24
)
|
(
data
[
4
]
<<
16
))
>>
16
;
clicks
=
data
[
1
];
/* The following bits provide a device specific timestamp. They
* are unused here.
*
* ts = data[11] >> 6 | data[12] << 2 | data[13] << 10;
*/
break
;
case
DOUBLE_REPORT_ID
:
/* Sometimes the trackpad sends two touch reports in one
* packet.
...
...
@@ -392,7 +427,8 @@ static int magicmouse_raw_event(struct hid_device *hdev,
return
0
;
}
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
||
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
{
magicmouse_emit_buttons
(
msc
,
clicks
&
3
);
input_report_rel
(
input
,
REL_X
,
x
);
input_report_rel
(
input
,
REL_Y
,
y
);
...
...
@@ -408,6 +444,23 @@ static int magicmouse_raw_event(struct hid_device *hdev,
return
1
;
}
static
int
magicmouse_event
(
struct
hid_device
*
hdev
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
__s32
value
)
{
struct
magicmouse_sc
*
msc
=
hid_get_drvdata
(
hdev
);
if
(
msc
->
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
&&
field
->
report
->
id
==
MOUSE2_REPORT_ID
)
{
/*
* magic_mouse_raw_event has done all the work. Skip hidinput.
*
* Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT,
* breaking emulate_3button.
*/
return
1
;
}
return
0
;
}
static
int
magicmouse_setup_input
(
struct
input_dev
*
input
,
struct
hid_device
*
hdev
)
{
int
error
;
...
...
@@ -415,7 +468,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
__set_bit
(
EV_KEY
,
input
->
evbit
);
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
||
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
{
__set_bit
(
BTN_LEFT
,
input
->
keybit
);
__set_bit
(
BTN_RIGHT
,
input
->
keybit
);
if
(
emulate_3button
)
...
...
@@ -480,7 +534,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
* the origin at the same position, and just uses the additive
* inverse of the reported Y.
*/
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
||
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
{
input_set_abs_params
(
input
,
ABS_MT_ORIENTATION
,
-
31
,
32
,
1
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
MOUSE_MIN_X
,
MOUSE_MAX_X
,
4
,
0
);
...
...
@@ -580,19 +635,60 @@ static int magicmouse_input_configured(struct hid_device *hdev,
return
0
;
}
static
int
magicmouse_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
static
int
magicmouse_enable_multitouch
(
struct
hid_device
*
hdev
)
{
const
u8
*
feature
;
const
u8
feature_mt
[]
=
{
0xD7
,
0x01
};
const
u8
feature_mt_mouse2
[]
=
{
0xF1
,
0x02
,
0x01
};
const
u8
feature_mt_trackpad2_usb
[]
=
{
0x02
,
0x01
};
const
u8
feature_mt_trackpad2_bt
[]
=
{
0xF1
,
0x02
,
0x01
};
u8
*
buf
;
int
ret
;
int
feature_size
;
if
(
hdev
->
product
==
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2
)
{
if
(
hdev
->
vendor
==
BT_VENDOR_ID_APPLE
)
{
feature_size
=
sizeof
(
feature_mt_trackpad2_bt
);
feature
=
feature_mt_trackpad2_bt
;
}
else
{
/* USB_VENDOR_ID_APPLE */
feature_size
=
sizeof
(
feature_mt_trackpad2_usb
);
feature
=
feature_mt_trackpad2_usb
;
}
}
else
if
(
hdev
->
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
{
feature_size
=
sizeof
(
feature_mt_mouse2
);
feature
=
feature_mt_mouse2
;
}
else
{
feature_size
=
sizeof
(
feature_mt
);
feature
=
feature_mt
;
}
buf
=
kmemdup
(
feature
,
feature_size
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
ret
=
hid_hw_raw_request
(
hdev
,
buf
[
0
],
buf
,
feature_size
,
HID_FEATURE_REPORT
,
HID_REQ_SET_REPORT
);
kfree
(
buf
);
return
ret
;
}
static
void
magicmouse_enable_mt_work
(
struct
work_struct
*
work
)
{
struct
magicmouse_sc
*
msc
=
container_of
(
work
,
struct
magicmouse_sc
,
work
.
work
);
int
ret
;
ret
=
magicmouse_enable_multitouch
(
msc
->
hdev
);
if
(
ret
<
0
)
hid_err
(
msc
->
hdev
,
"unable to request touch data (%d)
\n
"
,
ret
);
}
static
int
magicmouse_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
struct
magicmouse_sc
*
msc
;
struct
hid_report
*
report
;
int
ret
;
int
feature_size
;
if
(
id
->
vendor
==
USB_VENDOR_ID_APPLE
&&
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2
&&
...
...
@@ -606,6 +702,8 @@ static int magicmouse_probe(struct hid_device *hdev,
}
msc
->
scroll_accel
=
SCROLL_ACCEL_DEFAULT
;
msc
->
hdev
=
hdev
;
INIT_DEFERRABLE_WORK
(
&
msc
->
work
,
magicmouse_enable_mt_work
);
msc
->
quirks
=
id
->
driver_data
;
hid_set_drvdata
(
hdev
,
msc
);
...
...
@@ -631,6 +729,9 @@ static int magicmouse_probe(struct hid_device *hdev,
if
(
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
MOUSE_REPORT_ID
,
0
);
else
if
(
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
MOUSE2_REPORT_ID
,
0
);
else
if
(
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2
)
{
if
(
id
->
vendor
==
BT_VENDOR_ID_APPLE
)
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
...
...
@@ -652,25 +753,6 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report
->
size
=
6
;
if
(
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2
)
{
if
(
id
->
vendor
==
BT_VENDOR_ID_APPLE
)
{
feature_size
=
sizeof
(
feature_mt_trackpad2_bt
);
feature
=
feature_mt_trackpad2_bt
;
}
else
{
/* USB_VENDOR_ID_APPLE */
feature_size
=
sizeof
(
feature_mt_trackpad2_usb
);
feature
=
feature_mt_trackpad2_usb
;
}
}
else
{
feature_size
=
sizeof
(
feature_mt
);
feature
=
feature_mt
;
}
buf
=
kmemdup
(
feature
,
feature_size
,
GFP_KERNEL
);
if
(
!
buf
)
{
ret
=
-
ENOMEM
;
goto
err_stop_hw
;
}
/*
* Some devices repond with 'invalid report id' when feature
* report switching it into multitouch mode is sent to it.
...
...
@@ -679,13 +761,14 @@ static int magicmouse_probe(struct hid_device *hdev,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
ret
=
hid_hw_raw_request
(
hdev
,
buf
[
0
],
buf
,
feature_size
,
HID_FEATURE_REPORT
,
HID_REQ_SET_REPORT
);
kfree
(
buf
);
if
(
ret
!=
-
EIO
&&
ret
!=
feature_size
)
{
ret
=
magicmouse_enable_multitouch
(
hdev
);
if
(
ret
!=
-
EIO
&&
ret
<
0
)
{
hid_err
(
hdev
,
"unable to request touch data (%d)
\n
"
,
ret
);
goto
err_stop_hw
;
}
if
(
ret
==
-
EIO
&&
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE2
)
{
schedule_delayed_work
(
&
msc
->
work
,
msecs_to_jiffies
(
500
));
}
return
0
;
err_stop_hw:
...
...
@@ -693,9 +776,18 @@ static int magicmouse_probe(struct hid_device *hdev,
return
ret
;
}
static
void
magicmouse_remove
(
struct
hid_device
*
hdev
)
{
struct
magicmouse_sc
*
msc
=
hid_get_drvdata
(
hdev
);
cancel_delayed_work_sync
(
&
msc
->
work
);
hid_hw_stop
(
hdev
);
}
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_BLUETOOTH_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_MAGICTRACKPAD
),
.
driver_data
=
0
},
{
HID_BLUETOOTH_DEVICE
(
BT_VENDOR_ID_APPLE
,
...
...
@@ -710,7 +802,9 @@ static struct hid_driver magicmouse_driver = {
.
name
=
"magicmouse"
,
.
id_table
=
magic_mice
,
.
probe
=
magicmouse_probe
,
.
remove
=
magicmouse_remove
,
.
raw_event
=
magicmouse_raw_event
,
.
event
=
magicmouse_event
,
.
input_mapping
=
magicmouse_input_mapping
,
.
input_configured
=
magicmouse_input_configured
,
};
...
...
include/linux/hid.h
View file @
275ac61b
...
...
@@ -153,6 +153,7 @@ struct hid_item {
#define HID_UP_CONSUMER 0x000c0000
#define HID_UP_DIGITIZER 0x000d0000
#define HID_UP_PID 0x000f0000
#define HID_UP_BATTERY 0x00850000
#define HID_UP_HPVENDOR 0xff7f0000
#define HID_UP_HPVENDOR2 0xff010000
#define HID_UP_MSVENDOR 0xff000000
...
...
@@ -297,6 +298,8 @@ struct hid_item {
#define HID_DG_TOOLSERIALNUMBER 0x000d005b
#define HID_DG_LATENCYMODE 0x000d0060
#define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065
#define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076
/*
* HID report types --- Ouch! HID spec says 1 2 3!
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment