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
bbd128b5
Commit
bbd128b5
authored
Oct 23, 2010
by
Jiri Kosina
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches '3m', 'egalax', 'logitech', 'magicmouse', 'ntrig' and 'roccat' into for-linus
parents
c3d9d743
48216fbd
f5166110
2c6118e4
921990b7
0277873c
d2b570a5
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1928 additions
and
213 deletions
+1928
-213
Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
+98
-0
Documentation/input/ntrig.txt
Documentation/input/ntrig.txt
+126
-0
drivers/hid/Kconfig
drivers/hid/Kconfig
+17
-2
drivers/hid/Makefile
drivers/hid/Makefile
+4
-0
drivers/hid/hid-3m-pct.c
drivers/hid/hid-3m-pct.c
+72
-55
drivers/hid/hid-core.c
drivers/hid/hid-core.c
+4
-0
drivers/hid/hid-egalax.c
drivers/hid/hid-egalax.c
+11
-5
drivers/hid/hid-ids.h
drivers/hid/hid-ids.h
+5
-0
drivers/hid/hid-input.c
drivers/hid/hid-input.c
+3
-0
drivers/hid/hid-lg.c
drivers/hid/hid-lg.c
+41
-0
drivers/hid/hid-lg.h
drivers/hid/hid-lg.h
+6
-0
drivers/hid/hid-lg2ff.c
drivers/hid/hid-lg2ff.c
+2
-2
drivers/hid/hid-lg4ff.c
drivers/hid/hid-lg4ff.c
+136
-0
drivers/hid/hid-magicmouse.c
drivers/hid/hid-magicmouse.c
+187
-138
drivers/hid/hid-ntrig.c
drivers/hid/hid-ntrig.c
+60
-9
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-roccat-pyra.c
+968
-0
drivers/hid/hid-roccat-pyra.h
drivers/hid/hid-roccat-pyra.h
+186
-0
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-core.c
+1
-1
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hid-quirks.c
+0
-1
include/linux/hid.h
include/linux/hid.h
+1
-0
No files found.
Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
0 → 100644
View file @
bbd128b5
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_cpi
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: It is possible to switch the cpi setting of the mouse with the
press of a button.
When read, this file returns the raw number of the actual cpi
setting reported by the mouse. This number has to be further
processed to receive the real dpi value.
VALUE DPI
1 400
2 800
4 1600
This file is readonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in
range 0-4.
This file is readonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the raw integer version number of the
firmware reported by the mouse. Using the integer value eases
further usage in other programs. To receive the real version
number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 138 means 1.38
This file is readonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_settings
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds informations like resolution, sensitivity
and light effects.
When written, this file lets one write the respective profile
settings back to the mouse. The data has to be 13 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
This file is writeonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_settings
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds informations like resolution, sensitivity
and light effects.
When read, these files return the respective profile settings.
The returned data is 13 bytes in size.
This file is readonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_buttons
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds informations about button layout.
When written, this file lets one write the respective profile
buttons back to the mouse. The data has to be 19 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
This file is writeonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_buttons
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds informations about button layout.
When read, these files return the respective profile buttons.
The returned data is 19 bytes in size.
This file is readonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the profile
that's active when the mouse is powered on.
This file is readonly.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the settings stored in the mouse.
The size of the data is 3 bytes and holds information on the
startup_profile.
When written, this file lets write settings back to the mouse.
The data has to be 3 bytes long. The mouse will reject invalid
data.
Documentation/input/ntrig.txt
0 → 100644
View file @
bbd128b5
N-Trig touchscreen Driver
-------------------------
Copyright (c) 2008-2010 Rafi Rubin <rafi@seas.upenn.edu>
Copyright (c) 2009-2010 Stephane Chatty
This driver provides support for N-Trig pen and multi-touch sensors. Single
and multi-touch events are translated to the appropriate protocols for
the hid and input systems. Pen events are sufficiently hid compliant and
are left to the hid core. The driver also provides additional filtering
and utility functions accessible with sysfs and module parameters.
This driver has been reported to work properly with multiple N-Trig devices
attached.
Parameters
----------
Note: values set at load time are global and will apply to all applicable
devices. Adjusting parameters with sysfs will override the load time values,
but only for that one device.
The following parameters are used to configure filters to reduce noise:
activate_slack number of fingers to ignore before processing events
activation_height size threshold to activate immediately
activation_width
min_height size threshold bellow which fingers are ignored
min_width both to decide activation and during activity
deactivate_slack the number of "no contact" frames to ignore before
propagating the end of activity events
When the last finger is removed from the device, it sends a number of empty
frames. By holding off on deactivation for a few frames we can tolerate false
erroneous disconnects, where the sensor may mistakenly not detect a finger that
is still present. Thus deactivate_slack addresses problems where a users might
see breaks in lines during drawing, or drop an object during a long drag.
Additional sysfs items
----------------------
These nodes just provide easy access to the ranges reported by the device.
sensor_logical_height the range for positions reported during activity
sensor_logical_width
sensor_physical_height internal ranges not used for normal events but
sensor_physical_width useful for tuning
All N-Trig devices with product id of 1 report events in the ranges of
X: 0-9600
Y: 0-7200
However not all of these devices have the same physical dimensions. Most
seem to be 12" sensors (Dell Latitude XT and XT2 and the HP TX2), and
at least one model (Dell Studio 17) has a 17" sensor. The ratio of physical
to logical sizes is used to adjust the size based filter parameters.
Filtering
---------
With the release of the early multi-touch firmwares it became increasingly
obvious that these sensors were prone to erroneous events. Users reported
seeing both inappropriately dropped contact and ghosts, contacts reported
where no finger was actually touching the screen.
Deactivation slack helps prevent dropped contact for single touch use, but does
not address the problem of dropping one of more contacts while other contacts
are still active. Drops in the multi-touch context require additional
processing and should be handled in tandem with tacking.
As observed ghost contacts are similar to actual use of the sensor, but they
seem to have different profiles. Ghost activity typically shows up as small
short lived touches. As such, I assume that the longer the continuous stream
of events the more likely those events are from a real contact, and that the
larger the size of each contact the more likely it is real. Balancing the
goals of preventing ghosts and accepting real events quickly (to minimize
user observable latency), the filter accumulates confidence for incoming
events until it hits thresholds and begins propagating. In the interest in
minimizing stored state as well as the cost of operations to make a decision,
I've kept that decision simple.
Time is measured in terms of the number of fingers reported, not frames since
the probability of multiple simultaneous ghosts is expected to drop off
dramatically with increasing numbers. Rather than accumulate weight as a
function of size, I just use it as a binary threshold. A sufficiently large
contact immediately overrides the waiting period and leads to activation.
Setting the activation size thresholds to large values will result in deciding
primarily on activation slack. If you see longer lived ghosts, turning up the
activation slack while reducing the size thresholds may suffice to eliminate
the ghosts while keeping the screen quite responsive to firm taps.
Contacts continue to be filtered with min_height and min_width even after
the initial activation filter is satisfied. The intent is to provide
a mechanism for filtering out ghosts in the form of an extra finger while
you actually are using the screen. In practice this sort of ghost has
been far less problematic or relatively rare and I've left the defaults
set to 0 for both parameters, effectively turning off that filter.
I don't know what the optimal values are for these filters. If the defaults
don't work for you, please play with the parameters. If you do find other
values more comfortable, I would appreciate feedback.
The calibration of these devices does drift over time. If ghosts or contact
dropping worsen and interfere with the normal usage of your device, try
recalibrating it.
Calibration
-----------
The N-Trig windows tools provide calibration and testing routines. Also an
unofficial unsupported set of user space tools including a calibrator is
available at:
http://code.launchpad.net/~rafi-seas/+junk/ntrig_calib
Tracking
--------
As of yet, all tested N-Trig firmwares do not track fingers. When multiple
contacts are active they seem to be sorted primarily by Y position.
drivers/hid/Kconfig
View file @
bbd128b5
...
...
@@ -220,12 +220,12 @@ config LOGITECH_FF
force feedback.
config LOGIRUMBLEPAD2_FF
bool "Logitech Rumblepad 2 force feedback support"
bool "Logitech Rumble
Pad/Rumble
pad 2 force feedback support"
depends on HID_LOGITECH
select INPUT_FF_MEMLESS
help
Say Y here if you want to enable force feedback support for Logitech
Rumblepad 2 devices.
Rumble
Pad and Rumble
pad 2 devices.
config LOGIG940_FF
bool "Logitech Flight System G940 force feedback support"
...
...
@@ -235,6 +235,14 @@ config LOGIG940_FF
Say Y here if you want to enable force feedback support for Logitech
Flight System G940 devices.
config LOGIWII_FF
bool "Logitech Speed Force Wireless force feedback support"
depends on HID_LOGITECH
select INPUT_FF_MEMLESS
help
Say Y here if you want to enable force feedback support for Logitech
Speed Force Wireless (Wii) devices.
config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support"
depends on BT_HIDP
...
...
@@ -376,6 +384,13 @@ config HID_ROCCAT_KONE
---help---
Support for Roccat Kone mouse.
config HID_ROCCAT_PYRA
tristate "Roccat Pyra mouse support"
depends on USB_HID
select HID_ROCCAT
---help---
Support for Roccat Pyra mouse.
config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards"
depends on USB_HID
...
...
drivers/hid/Makefile
View file @
bbd128b5
...
...
@@ -21,6 +21,9 @@ endif
ifdef
CONFIG_LOGIG940_FF
hid-logitech-objs
+=
hid-lg3ff.o
endif
ifdef
CONFIG_LOGIWII_FF
hid-logitech-objs
+=
hid-lg4ff.o
endif
obj-$(CONFIG_HID_3M_PCT)
+=
hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH)
+=
hid-a4tech.o
...
...
@@ -52,6 +55,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD)
+=
hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT)
+=
hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_KONE)
+=
hid-roccat-kone.o
obj-$(CONFIG_HID_ROCCAT_PYRA)
+=
hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG)
+=
hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS)
+=
hid-sjoy.o
obj-$(CONFIG_HID_SONY)
+=
hid-sony.o
...
...
drivers/hid/hid-3m-pct.c
View file @
bbd128b5
...
...
@@ -2,6 +2,8 @@
* HID driver for 3M PCT multitouch panels
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
*/
...
...
@@ -24,15 +26,26 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
#define MAX_TRKID USHRT_MAX
#define MAX_EVENTS 360
/* estimated signal-to-noise ratios */
#define SN_MOVE 2048
#define SN_WIDTH 128
struct
mmm_finger
{
__s32
x
,
y
,
w
,
h
;
__u8
rank
;
__u16
id
;
bool
prev_touch
;
bool
touch
,
valid
;
};
struct
mmm_data
{
struct
mmm_finger
f
[
10
];
__u8
curid
,
num
;
struct
mmm_finger
f
[
MAX_SLOTS
];
__u16
id
;
__u8
curid
;
__u8
nexp
,
nreal
;
bool
touch
,
valid
;
};
...
...
@@ -40,6 +53,10 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
int
f1
=
field
->
logical_minimum
;
int
f2
=
field
->
logical_maximum
;
int
df
=
f2
-
f1
;
switch
(
usage
->
hid
&
HID_USAGE_PAGE
)
{
case
HID_UP_BUTTON
:
...
...
@@ -50,18 +67,20 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case
HID_GD_X
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_POSITION_X
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_POSITION_X
,
f1
,
f2
,
df
/
SN_MOVE
,
0
);
/* touchscreen emulation */
input_set_abs_params
(
hi
->
input
,
ABS_X
,
field
->
logical_minimum
,
field
->
logical_maximum
,
0
,
0
);
f1
,
f2
,
df
/
SN_MOVE
,
0
);
return
1
;
case
HID_GD_Y
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_POSITION_Y
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_POSITION_Y
,
f1
,
f2
,
df
/
SN_MOVE
,
0
);
/* touchscreen emulation */
input_set_abs_params
(
hi
->
input
,
ABS_Y
,
field
->
logical_minimum
,
field
->
logical_maximum
,
0
,
0
);
f1
,
f2
,
df
/
SN_MOVE
,
0
);
return
1
;
}
return
0
;
...
...
@@ -81,21 +100,31 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case
HID_DG_TIPSWITCH
:
/* touchscreen emulation */
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
BTN_TOUCH
);
input_set_capability
(
hi
->
input
,
EV_KEY
,
BTN_TOUCH
);
return
1
;
case
HID_DG_WIDTH
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_TOUCH_MAJOR
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_TOUCH_MAJOR
,
f1
,
f2
,
df
/
SN_WIDTH
,
0
);
return
1
;
case
HID_DG_HEIGHT
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_TOUCH_MINOR
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_TOUCH_MINOR
,
f1
,
f2
,
df
/
SN_WIDTH
,
0
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_ORIENTATION
,
1
,
1
,
0
,
0
);
0
,
1
,
0
,
0
);
return
1
;
case
HID_DG_CONTACTID
:
field
->
logical_maximum
=
59
;
field
->
logical_maximum
=
MAX_TRKID
;
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_TRACKING_ID
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_TRACKING_ID
,
0
,
MAX_TRKID
,
0
,
0
);
if
(
!
hi
->
input
->
mt
)
input_mt_create_slots
(
hi
->
input
,
MAX_SLOTS
);
input_set_events_per_packet
(
hi
->
input
,
MAX_EVENTS
);
return
1
;
}
/* let hid-input decide for the others */
...
...
@@ -113,10 +142,10 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
/* tell hid-input to skip setup of these event types */
if
(
usage
->
type
==
EV_KEY
||
usage
->
type
==
EV_ABS
)
clear_bit
(
usage
->
code
,
*
bit
);
return
0
;
set_bit
(
usage
->
type
,
hi
->
input
->
evbit
);
return
-
1
;
}
/*
...
...
@@ -126,70 +155,49 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static
void
mmm_filter_event
(
struct
mmm_data
*
md
,
struct
input_dev
*
input
)
{
struct
mmm_finger
*
oldest
=
0
;
bool
pressed
=
false
,
released
=
false
;
int
i
;
/*
* we need to iterate on all fingers to decide if we have a press
* or a release event in our touchscreen emulation.
*/
for
(
i
=
0
;
i
<
10
;
++
i
)
{
for
(
i
=
0
;
i
<
MAX_SLOTS
;
++
i
)
{
struct
mmm_finger
*
f
=
&
md
->
f
[
i
];
if
(
!
f
->
valid
)
{
/* this finger is just placeholder data, ignore */
}
else
if
(
f
->
touch
)
{
continue
;
}
input_mt_slot
(
input
,
i
);
if
(
f
->
touch
)
{
/* this finger is on the screen */
int
wide
=
(
f
->
w
>
f
->
h
);
input_event
(
input
,
EV_ABS
,
ABS_MT_TRACKING_ID
,
i
);
/* divided by two to match visual scale of touch */
int
major
=
max
(
f
->
w
,
f
->
h
)
>>
1
;
int
minor
=
min
(
f
->
w
,
f
->
h
)
>>
1
;
if
(
!
f
->
prev_touch
)
f
->
id
=
md
->
id
++
;
input_event
(
input
,
EV_ABS
,
ABS_MT_TRACKING_ID
,
f
->
id
);
input_event
(
input
,
EV_ABS
,
ABS_MT_POSITION_X
,
f
->
x
);
input_event
(
input
,
EV_ABS
,
ABS_MT_POSITION_Y
,
f
->
y
);
input_event
(
input
,
EV_ABS
,
ABS_MT_ORIENTATION
,
wide
);
input_event
(
input
,
EV_ABS
,
ABS_MT_TOUCH_MAJOR
,
wide
?
f
->
w
:
f
->
h
);
input_event
(
input
,
EV_ABS
,
ABS_MT_TOUCH_MINOR
,
wide
?
f
->
h
:
f
->
w
);
input_mt_sync
(
input
);
/*
* touchscreen emulation: maintain the age rank
* of this finger, decide if we have a press
*/
if
(
f
->
rank
==
0
)
{
f
->
rank
=
++
(
md
->
num
);
if
(
f
->
rank
==
1
)
pressed
=
true
;
}
if
(
f
->
rank
==
1
)
input_event
(
input
,
EV_ABS
,
ABS_MT_TOUCH_MAJOR
,
major
);
input_event
(
input
,
EV_ABS
,
ABS_MT_TOUCH_MINOR
,
minor
);
/* touchscreen emulation: pick the oldest contact */
if
(
!
oldest
||
((
f
->
id
-
oldest
->
id
)
&
(
SHRT_MAX
+
1
)))
oldest
=
f
;
}
else
{
/* this finger took off the screen */
/* touchscreen emulation: maintain age rank of others */
int
j
;
for
(
j
=
0
;
j
<
10
;
++
j
)
{
struct
mmm_finger
*
g
=
&
md
->
f
[
j
];
if
(
g
->
rank
>
f
->
rank
)
{
g
->
rank
--
;
if
(
g
->
rank
==
1
)
oldest
=
g
;
}
}
f
->
rank
=
0
;
--
(
md
->
num
);
if
(
md
->
num
==
0
)
released
=
true
;
input_event
(
input
,
EV_ABS
,
ABS_MT_TRACKING_ID
,
-
1
);
}
f
->
prev_touch
=
f
->
touch
;
f
->
valid
=
0
;
}
/* touchscreen emulation */
if
(
oldest
)
{
if
(
pressed
)
input_event
(
input
,
EV_KEY
,
BTN_TOUCH
,
1
);
input_event
(
input
,
EV_KEY
,
BTN_TOUCH
,
1
);
input_event
(
input
,
EV_ABS
,
ABS_X
,
oldest
->
x
);
input_event
(
input
,
EV_ABS
,
ABS_Y
,
oldest
->
y
);
}
else
if
(
released
)
{
}
else
{
input_event
(
input
,
EV_KEY
,
BTN_TOUCH
,
0
);
}
input_sync
(
input
);
}
/*
...
...
@@ -223,10 +231,12 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
md
->
f
[
md
->
curid
].
h
=
value
;
break
;
case
HID_DG_CONTACTID
:
value
=
clamp_val
(
value
,
0
,
MAX_SLOTS
-
1
);
if
(
md
->
valid
)
{
md
->
curid
=
value
;
md
->
f
[
value
].
touch
=
md
->
touch
;
md
->
f
[
value
].
valid
=
1
;
md
->
nreal
++
;
}
break
;
case
HID_GD_X
:
...
...
@@ -238,7 +248,12 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
md
->
f
[
md
->
curid
].
y
=
value
;
break
;
case
HID_DG_CONTACTCOUNT
:
mmm_filter_event
(
md
,
input
);
if
(
value
)
md
->
nexp
=
value
;
if
(
md
->
nreal
>=
md
->
nexp
)
{
mmm_filter_event
(
md
,
input
);
md
->
nreal
=
0
;
}
break
;
}
}
...
...
@@ -255,6 +270,8 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
int
ret
;
struct
mmm_data
*
md
;
hdev
->
quirks
|=
HID_QUIRK_NO_INPUT_SYNC
;
md
=
kzalloc
(
sizeof
(
struct
mmm_data
),
GFP_KERNEL
);
if
(
!
md
)
{
dev_err
(
&
hdev
->
dev
,
"cannot allocate 3M data
\n
"
);
...
...
drivers/hid/hid-core.c
View file @
bbd128b5
...
...
@@ -1249,6 +1249,7 @@ static const struct hid_device_id hid_blacklist[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_IRCONTROL4
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_MIGHTYMOUSE
)
},
{
HID_BLUETOOTH_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
},
{
HID_BLUETOOTH_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_MAGICTRACKPAD
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_FOUNTAIN_ISO
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_GEYSER_ANSI
)
},
...
...
@@ -1328,6 +1329,7 @@ static const struct hid_device_id hid_blacklist[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_EXTREME_3D
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_WHEEL
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_WINGMAN_F3D
)
},
...
...
@@ -1337,6 +1339,7 @@ static const struct hid_device_id hid_blacklist[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_MOMO_WHEEL
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_G25_WHEEL
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_WII_WHEEL
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD2
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_SPACETRAVELLER
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_SPACENAVIGATOR
)
},
...
...
@@ -1372,6 +1375,7 @@ static const struct hid_device_id hid_blacklist[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_QUANTA
,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_QUANTA
,
USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_ROCCAT
,
USB_DEVICE_ID_ROCCAT_KONE
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_ROCCAT
,
USB_DEVICE_ID_ROCCAT_PYRA_WIRED
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SAMSUNG
,
USB_DEVICE_ID_SAMSUNG_IR_REMOTE
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SAMSUNG
,
USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_PS3_CONTROLLER
)
},
...
...
drivers/hid/hid-egalax.c
View file @
bbd128b5
...
...
@@ -31,7 +31,7 @@ struct egalax_data {
bool
first
;
/* is this the first finger in the frame? */
bool
valid
;
/* valid finger data, or just placeholder? */
bool
activity
;
/* at least one active finger previously? */
__u16
lastx
,
lasty
;
/* latest valid (x, y
) in the frame */
__u16
lastx
,
lasty
,
lastz
;
/* latest valid (x, y, z
) in the frame */
};
static
int
egalax_input_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
...
...
@@ -79,6 +79,10 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case
HID_DG_TIPPRESSURE
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_PRESSURE
);
/* touchscreen emulation */
input_set_abs_params
(
hi
->
input
,
ABS_PRESSURE
,
field
->
logical_minimum
,
field
->
logical_maximum
,
0
,
0
);
return
1
;
}
return
0
;
...
...
@@ -109,8 +113,8 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
if
(
td
->
valid
)
{
/* emit multitouch events */
input_event
(
input
,
EV_ABS
,
ABS_MT_TRACKING_ID
,
td
->
id
);
input_event
(
input
,
EV_ABS
,
ABS_MT_POSITION_X
,
td
->
x
);
input_event
(
input
,
EV_ABS
,
ABS_MT_POSITION_Y
,
td
->
y
);
input_event
(
input
,
EV_ABS
,
ABS_MT_POSITION_X
,
td
->
x
>>
3
);
input_event
(
input
,
EV_ABS
,
ABS_MT_POSITION_Y
,
td
->
y
>>
3
);
input_event
(
input
,
EV_ABS
,
ABS_MT_PRESSURE
,
td
->
z
);
input_mt_sync
(
input
);
...
...
@@ -121,6 +125,7 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
*/
td
->
lastx
=
td
->
x
;
td
->
lasty
=
td
->
y
;
td
->
lastz
=
td
->
z
;
}
/*
...
...
@@ -129,8 +134,9 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
* the oldest on the panel, the one we want for single touch
*/
if
(
!
td
->
first
&&
td
->
activity
)
{
input_event
(
input
,
EV_ABS
,
ABS_X
,
td
->
lastx
);
input_event
(
input
,
EV_ABS
,
ABS_Y
,
td
->
lasty
);
input_event
(
input
,
EV_ABS
,
ABS_X
,
td
->
lastx
>>
3
);
input_event
(
input
,
EV_ABS
,
ABS_Y
,
td
->
lasty
>>
3
);
input_event
(
input
,
EV_ABS
,
ABS_PRESSURE
,
td
->
lastz
);
}
if
(
!
td
->
valid
)
{
...
...
drivers/hid/hid-ids.h
View file @
bbd128b5
...
...
@@ -64,6 +64,7 @@
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
...
...
@@ -345,6 +346,7 @@
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
...
...
@@ -356,6 +358,7 @@
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
...
...
@@ -468,6 +471,8 @@
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
...
...
drivers/hid/hid-input.c
View file @
bbd128b5
...
...
@@ -739,6 +739,9 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
{
struct
hid_input
*
hidinput
;
if
(
hid
->
quirks
&
HID_QUIRK_NO_INPUT_SYNC
)
return
;
list_for_each_entry
(
hidinput
,
&
hid
->
inputs
,
list
)
input_sync
(
hidinput
->
input
);
}
...
...
drivers/hid/hid-lg.c
View file @
bbd128b5
...
...
@@ -7,6 +7,7 @@
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2007 Paul Walmsley
* Copyright (c) 2008 Jiri Slaby
* Copyright (c) 2010 Hendrik Iben
*/
/*
...
...
@@ -19,6 +20,9 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include "hid-ids.h"
#include "hid-lg.h"
...
...
@@ -35,6 +39,7 @@
#define LG_FF2 0x400
#define LG_RDESC_REL_ABS 0x800
#define LG_FF3 0x1000
#define LG_FF4 0x2000
/*
* Certain Logitech keyboards send in report #3 keys which are far
...
...
@@ -60,6 +65,17 @@ static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
"report descriptor
\n
"
);
rdesc
[
33
]
=
rdesc
[
50
]
=
0x02
;
}
if
((
quirks
&
LG_FF4
)
&&
rsize
>=
101
&&
rdesc
[
41
]
==
0x95
&&
rdesc
[
42
]
==
0x0B
&&
rdesc
[
47
]
==
0x05
&&
rdesc
[
48
]
==
0x09
)
{
dev_info
(
&
hdev
->
dev
,
"fixing up Logitech Speed Force Wireless "
"button descriptor
\n
"
);
rdesc
[
41
]
=
0x05
;
rdesc
[
42
]
=
0x09
;
rdesc
[
47
]
=
0x95
;
rdesc
[
48
]
=
0x0B
;
}
}
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
...
...
@@ -285,12 +301,33 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto
err_free
;
}
if
(
quirks
&
LG_FF4
)
{
unsigned
char
buf
[]
=
{
0x00
,
0xAF
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
ret
=
hdev
->
hid_output_raw_report
(
hdev
,
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
);
if
(
ret
>=
0
)
{
/* insert a little delay of 10 jiffies ~ 40ms */
wait_queue_head_t
wait
;
init_waitqueue_head
(
&
wait
);
wait_event_interruptible_timeout
(
wait
,
0
,
10
);
/* Select random Address */
buf
[
1
]
=
0xB2
;
get_random_bytes
(
&
buf
[
2
],
2
);
ret
=
hdev
->
hid_output_raw_report
(
hdev
,
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
);
}
}
if
(
quirks
&
LG_FF
)
lgff_init
(
hdev
);
if
(
quirks
&
LG_FF2
)
lg2ff_init
(
hdev
);
if
(
quirks
&
LG_FF3
)
lg3ff_init
(
hdev
);
if
(
quirks
&
LG_FF4
)
lg4ff_init
(
hdev
);
return
0
;
err_free:
...
...
@@ -325,6 +362,8 @@ static const struct hid_device_id lg_devices[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_WHEEL
),
.
driver_data
=
LG_NOGET
|
LG_FF
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD
),
.
driver_data
=
LG_FF2
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD
),
.
driver_data
=
LG_FF
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2
),
...
...
@@ -339,6 +378,8 @@ static const struct hid_device_id lg_devices[] = {
.
driver_data
=
LG_FF
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_G25_WHEEL
),
.
driver_data
=
LG_FF
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_WII_WHEEL
),
.
driver_data
=
LG_FF4
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_WINGMAN_FFG
),
.
driver_data
=
LG_FF
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_LOGITECH
,
USB_DEVICE_ID_LOGITECH_RUMBLEPAD2
),
...
...
drivers/hid/hid-lg.h
View file @
bbd128b5
...
...
@@ -19,4 +19,10 @@ int lg3ff_init(struct hid_device *hdev);
static
inline
int
lg3ff_init
(
struct
hid_device
*
hdev
)
{
return
-
1
;
}
#endif
#ifdef CONFIG_LOGIWII_FF
int
lg4ff_init
(
struct
hid_device
*
hdev
);
#else
static
inline
int
lg4ff_init
(
struct
hid_device
*
hdev
)
{
return
-
1
;
}
#endif
#endif
drivers/hid/hid-lg2ff.c
View file @
bbd128b5
/*
* Force feedback support for Logitech Rumblepad 2
* Force feedback support for Logitech Rumble
Pad and Rumble
pad 2
*
* Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
*/
...
...
@@ -110,7 +110,7 @@ int lg2ff_init(struct hid_device *hid)
usbhid_submit_report
(
hid
,
report
,
USB_DIR_OUT
);
dev_info
(
&
hid
->
dev
,
"Force feedback for Logitech Rumblepad 2 by "
dev_info
(
&
hid
->
dev
,
"Force feedback for Logitech Rumble
Pad/Rumble
pad 2 by "
"Anssi Hannula <anssi.hannula@gmail.com>
\n
"
);
return
0
;
...
...
drivers/hid/hid-lg4ff.c
0 → 100644
View file @
bbd128b5
/*
* Force feedback support for Logitech Speed Force Wireless
*
* http://wiibrew.org/wiki/Logitech_USB_steering_wheel
*
* Copyright (c) 2010 Simon Wood <simon@mungewell.org>
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h"
struct
lg4ff_device
{
struct
hid_report
*
report
;
};
static
const
signed
short
ff4_wheel_ac
[]
=
{
FF_CONSTANT
,
FF_AUTOCENTER
,
-
1
};
static
int
hid_lg4ff_play
(
struct
input_dev
*
dev
,
void
*
data
,
struct
ff_effect
*
effect
)
{
struct
hid_device
*
hid
=
input_get_drvdata
(
dev
);
struct
list_head
*
report_list
=
&
hid
->
report_enum
[
HID_OUTPUT_REPORT
].
report_list
;
struct
hid_report
*
report
=
list_entry
(
report_list
->
next
,
struct
hid_report
,
list
);
int
x
;
#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
switch
(
effect
->
type
)
{
case
FF_CONSTANT
:
x
=
effect
->
u
.
ramp
.
start_level
+
0x80
;
/* 0x80 is no force */
CLAMP
(
x
);
report
->
field
[
0
]
->
value
[
0
]
=
0x11
;
/* Slot 1 */
report
->
field
[
0
]
->
value
[
1
]
=
0x10
;
report
->
field
[
0
]
->
value
[
2
]
=
x
;
report
->
field
[
0
]
->
value
[
3
]
=
0x00
;
report
->
field
[
0
]
->
value
[
4
]
=
0x00
;
report
->
field
[
0
]
->
value
[
5
]
=
0x08
;
report
->
field
[
0
]
->
value
[
6
]
=
0x00
;
dbg_hid
(
"Autocenter, x=0x%02X
\n
"
,
x
);
usbhid_submit_report
(
hid
,
report
,
USB_DIR_OUT
);
break
;
}
return
0
;
}
static
void
hid_lg4ff_set_autocenter
(
struct
input_dev
*
dev
,
u16
magnitude
)
{
struct
hid_device
*
hid
=
input_get_drvdata
(
dev
);
struct
list_head
*
report_list
=
&
hid
->
report_enum
[
HID_OUTPUT_REPORT
].
report_list
;
struct
hid_report
*
report
=
list_entry
(
report_list
->
next
,
struct
hid_report
,
list
);
__s32
*
value
=
report
->
field
[
0
]
->
value
;
*
value
++
=
0xfe
;
*
value
++
=
0x0d
;
*
value
++
=
0x07
;
*
value
++
=
0x07
;
*
value
++
=
(
magnitude
>>
8
)
&
0xff
;
*
value
++
=
0x00
;
*
value
=
0x00
;
usbhid_submit_report
(
hid
,
report
,
USB_DIR_OUT
);
}
int
lg4ff_init
(
struct
hid_device
*
hid
)
{
struct
hid_input
*
hidinput
=
list_entry
(
hid
->
inputs
.
next
,
struct
hid_input
,
list
);
struct
list_head
*
report_list
=
&
hid
->
report_enum
[
HID_OUTPUT_REPORT
].
report_list
;
struct
input_dev
*
dev
=
hidinput
->
input
;
struct
hid_report
*
report
;
struct
hid_field
*
field
;
const
signed
short
*
ff_bits
=
ff4_wheel_ac
;
int
error
;
int
i
;
/* Find the report to use */
if
(
list_empty
(
report_list
))
{
err_hid
(
"No output report found"
);
return
-
1
;
}
/* Check that the report looks ok */
report
=
list_entry
(
report_list
->
next
,
struct
hid_report
,
list
);
if
(
!
report
)
{
err_hid
(
"NULL output report"
);
return
-
1
;
}
field
=
report
->
field
[
0
];
if
(
!
field
)
{
err_hid
(
"NULL field"
);
return
-
1
;
}
for
(
i
=
0
;
ff_bits
[
i
]
>=
0
;
i
++
)
set_bit
(
ff_bits
[
i
],
dev
->
ffbit
);
error
=
input_ff_create_memless
(
dev
,
NULL
,
hid_lg4ff_play
);
if
(
error
)
return
error
;
if
(
test_bit
(
FF_AUTOCENTER
,
dev
->
ffbit
))
dev
->
ff
->
set_autocenter
=
hid_lg4ff_set_autocenter
;
dev_info
(
&
hid
->
dev
,
"Force feedback for Logitech Speed Force Wireless by "
"Simon Wood <simon@mungewell.org>
\n
"
);
return
0
;
}
drivers/hid/hid-magicmouse.c
View file @
bbd128b5
...
...
@@ -2,6 +2,7 @@
* Apple "Magic" Wireless Mouse driver
*
* Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
* Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
*/
/*
...
...
@@ -53,7 +54,9 @@ static bool report_undeciphered;
module_param
(
report_undeciphered
,
bool
,
0644
);
MODULE_PARM_DESC
(
report_undeciphered
,
"Report undeciphered multi-touch state field using a MSC_RAW event"
);
#define TOUCH_REPORT_ID 0x29
#define TRACKPAD_REPORT_ID 0x28
#define MOUSE_REPORT_ID 0x29
#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
* to be some kind of bit mask -- 0x20 may be a near-field reading,
...
...
@@ -67,15 +70,19 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define SCROLL_ACCEL_DEFAULT 7
/* Single touch emulation should only begin when no touches are currently down.
* This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches
* are down and the touch providing for single touch emulation is lifted,
* single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is
* occuring, single_touch_id corresponds with the tracking id of the touch used.
*/
#define NO_TOUCHES -1
#define SINGLE_TOUCH_UP -2
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
* @quirks: Currently unused.
* @last_timestamp: Timestamp from most recent (18-bit) touch report
* (units of milliseconds over short windows, but seems to
* increase faster when there are no touches).
* @delta_time: 18-bit difference between the two most recent touch
* reports from the mouse.
* @ntouches: Number of touches in most recent touch report.
* @scroll_accel: Number of consecutive scroll motions.
* @scroll_jiffies: Time of last scroll motion.
...
...
@@ -86,8 +93,6 @@ struct magicmouse_sc {
struct
input_dev
*
input
;
unsigned
long
quirks
;
int
last_timestamp
;
int
delta_time
;
int
ntouches
;
int
scroll_accel
;
unsigned
long
scroll_jiffies
;
...
...
@@ -98,9 +103,9 @@ struct magicmouse_sc {
short
scroll_x
;
short
scroll_y
;
u8
size
;
u8
down
;
}
touches
[
16
];
int
tracking_ids
[
16
];
int
single_touch_id
;
};
static
int
magicmouse_firm_touch
(
struct
magicmouse_sc
*
msc
)
...
...
@@ -166,18 +171,35 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
static
void
magicmouse_emit_touch
(
struct
magicmouse_sc
*
msc
,
int
raw_id
,
u8
*
tdata
)
{
struct
input_dev
*
input
=
msc
->
input
;
__s32
x_y
=
tdata
[
0
]
<<
8
|
tdata
[
1
]
<<
16
|
tdata
[
2
]
<<
24
;
int
misc
=
tdata
[
5
]
|
tdata
[
6
]
<<
8
;
int
id
=
(
misc
>>
6
)
&
15
;
int
x
=
x_y
<<
12
>>
20
;
int
y
=
-
(
x_y
>>
20
);
int
down
=
(
tdata
[
7
]
&
TOUCH_STATE_MASK
)
!=
TOUCH_STATE_NONE
;
int
id
,
x
,
y
,
size
,
orientation
,
touch_major
,
touch_minor
,
state
,
down
;
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
id
=
(
tdata
[
6
]
<<
2
|
tdata
[
5
]
>>
6
)
&
0xf
;
x
=
(
tdata
[
1
]
<<
28
|
tdata
[
0
]
<<
20
)
>>
20
;
y
=
-
((
tdata
[
2
]
<<
24
|
tdata
[
1
]
<<
16
)
>>
20
);
size
=
tdata
[
5
]
&
0x3f
;
orientation
=
(
tdata
[
6
]
>>
2
)
-
32
;
touch_major
=
tdata
[
3
];
touch_minor
=
tdata
[
4
];
state
=
tdata
[
7
]
&
TOUCH_STATE_MASK
;
down
=
state
!=
TOUCH_STATE_NONE
;
}
else
{
/* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
id
=
(
tdata
[
7
]
<<
2
|
tdata
[
6
]
>>
6
)
&
0xf
;
x
=
(
tdata
[
1
]
<<
27
|
tdata
[
0
]
<<
19
)
>>
19
;
y
=
-
((
tdata
[
3
]
<<
30
|
tdata
[
2
]
<<
22
|
tdata
[
1
]
<<
14
)
>>
19
);
size
=
tdata
[
6
]
&
0x3f
;
orientation
=
(
tdata
[
7
]
>>
2
)
-
32
;
touch_major
=
tdata
[
4
];
touch_minor
=
tdata
[
5
];
state
=
tdata
[
8
]
&
TOUCH_STATE_MASK
;
down
=
state
!=
TOUCH_STATE_NONE
;
}
/* Store tracking ID and other fields. */
msc
->
tracking_ids
[
raw_id
]
=
id
;
msc
->
touches
[
id
].
x
=
x
;
msc
->
touches
[
id
].
y
=
y
;
msc
->
touches
[
id
].
size
=
misc
&
63
;
msc
->
touches
[
id
].
size
=
size
;
/* If requested, emulate a scroll wheel by detecting small
* vertical touch motions.
...
...
@@ -188,7 +210,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
int
step_y
=
msc
->
touches
[
id
].
scroll_y
-
y
;
/* Calculate and apply the scroll motion. */
switch
(
tdata
[
7
]
&
TOUCH_STATE_MASK
)
{
switch
(
state
)
{
case
TOUCH_STATE_START
:
msc
->
touches
[
id
].
scroll_x
=
x
;
msc
->
touches
[
id
].
scroll_y
=
y
;
...
...
@@ -222,21 +244,28 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
}
}
if
(
down
)
{
msc
->
ntouches
++
;
if
(
msc
->
single_touch_id
==
NO_TOUCHES
)
msc
->
single_touch_id
=
id
;
}
else
if
(
msc
->
single_touch_id
==
id
)
msc
->
single_touch_id
=
SINGLE_TOUCH_UP
;
/* Generate the input events for this touch. */
if
(
report_touches
&&
down
)
{
int
orientation
=
(
misc
>>
10
)
-
32
;
msc
->
touches
[
id
].
down
=
1
;
input_report_abs
(
input
,
ABS_MT_TRACKING_ID
,
id
);
input_report_abs
(
input
,
ABS_MT_TOUCH_MAJOR
,
t
data
[
3
]
);
input_report_abs
(
input
,
ABS_MT_TOUCH_MINOR
,
t
data
[
4
]
);
input_report_abs
(
input
,
ABS_MT_TOUCH_MAJOR
,
t
ouch_major
<<
2
);
input_report_abs
(
input
,
ABS_MT_TOUCH_MINOR
,
t
ouch_minor
<<
2
);
input_report_abs
(
input
,
ABS_MT_ORIENTATION
,
orientation
);
input_report_abs
(
input
,
ABS_MT_POSITION_X
,
x
);
input_report_abs
(
input
,
ABS_MT_POSITION_Y
,
y
);
if
(
report_undeciphered
)
input_event
(
input
,
EV_MSC
,
MSC_RAW
,
tdata
[
7
]);
if
(
report_undeciphered
)
{
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
input_event
(
input
,
EV_MSC
,
MSC_RAW
,
tdata
[
7
]);
else
/* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
input_event
(
input
,
EV_MSC
,
MSC_RAW
,
tdata
[
8
]);
}
input_mt_sync
(
input
);
}
...
...
@@ -247,39 +276,43 @@ static int magicmouse_raw_event(struct hid_device *hdev,
{
struct
magicmouse_sc
*
msc
=
hid_get_drvdata
(
hdev
);
struct
input_dev
*
input
=
msc
->
input
;
int
x
,
y
,
ts
,
ii
,
clicks
,
last_up
;
int
x
=
0
,
y
=
0
,
ii
,
clicks
=
0
,
npoints
;
switch
(
data
[
0
])
{
case
0x10
:
if
(
size
!=
6
)
case
TRACKPAD_REPORT_ID
:
/* Expect four bytes of prefix, and N*9 bytes of touch data. */
if
(
size
<
4
||
((
size
-
4
)
%
9
)
!=
0
)
return
0
;
x
=
(
__s16
)(
data
[
2
]
|
data
[
3
]
<<
8
);
y
=
(
__s16
)(
data
[
4
]
|
data
[
5
]
<<
8
);
npoints
=
(
size
-
4
)
/
9
;
msc
->
ntouches
=
0
;
for
(
ii
=
0
;
ii
<
npoints
;
ii
++
)
magicmouse_emit_touch
(
msc
,
ii
,
data
+
ii
*
9
+
4
);
/* We don't need an MT sync here because trackpad emits a
* BTN_TOUCH event in a new frame when all touches are released.
*/
if
(
msc
->
ntouches
==
0
)
msc
->
single_touch_id
=
NO_TOUCHES
;
clicks
=
data
[
1
];
/* The following bits provide a device specific timestamp. They
* are unused here.
*
* ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
*/
break
;
case
TOUCH
_REPORT_ID
:
case
MOUSE
_REPORT_ID
:
/* Expect six bytes of prefix, and N*8 bytes of touch data. */
if
(
size
<
6
||
((
size
-
6
)
%
8
)
!=
0
)
return
0
;
ts
=
data
[
3
]
>>
6
|
data
[
4
]
<<
2
|
data
[
5
]
<<
10
;
msc
->
delta_time
=
(
ts
-
msc
->
last_timestamp
)
&
0x3ffff
;
msc
->
last_timestamp
=
ts
;
msc
->
ntouches
=
(
size
-
6
)
/
8
;
for
(
ii
=
0
;
ii
<
msc
->
ntouches
;
ii
++
)
npoints
=
(
size
-
6
)
/
8
;
msc
->
ntouches
=
0
;
for
(
ii
=
0
;
ii
<
npoints
;
ii
++
)
magicmouse_emit_touch
(
msc
,
ii
,
data
+
ii
*
8
+
6
);
if
(
report_touches
)
{
last_up
=
1
;
for
(
ii
=
0
;
ii
<
ARRAY_SIZE
(
msc
->
touches
);
ii
++
)
{
if
(
msc
->
touches
[
ii
].
down
)
{
last_up
=
0
;
msc
->
touches
[
ii
].
down
=
0
;
}
}
if
(
last_up
)
{
input_mt_sync
(
input
);
}
}
if
(
report_touches
&&
msc
->
ntouches
==
0
)
input_mt_sync
(
input
);
/* When emulating three-button mode, it is important
* to have the current touch information before
...
...
@@ -288,68 +321,72 @@ static int magicmouse_raw_event(struct hid_device *hdev,
x
=
(
int
)(((
data
[
3
]
&
0x0c
)
<<
28
)
|
(
data
[
1
]
<<
22
))
>>
22
;
y
=
(
int
)(((
data
[
3
]
&
0x30
)
<<
26
)
|
(
data
[
2
]
<<
22
))
>>
22
;
clicks
=
data
[
3
];
/* The following bits provide a device specific timestamp. They
* are unused here.
*
* ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
*/
break
;
case
DOUBLE_REPORT_ID
:
/* Sometimes the trackpad sends two touch reports in one
* packet.
*/
magicmouse_raw_event
(
hdev
,
report
,
data
+
2
,
data
[
1
]);
magicmouse_raw_event
(
hdev
,
report
,
data
+
2
+
data
[
1
],
size
-
2
-
data
[
1
]);
break
;
case
0x20
:
/* Theoretically battery status (0-100), but I have
* never seen it -- maybe it is only upon request.
*/
case
0x60
:
/* Unknown, maybe laser on/off. */
case
0x61
:
/* Laser reflection status change.
* data[1]: 0 = spotted, 1 = lost
*/
default:
return
0
;
}
magicmouse_emit_buttons
(
msc
,
clicks
&
3
);
input_report_rel
(
input
,
REL_X
,
x
);
input_report_rel
(
input
,
REL_Y
,
y
);
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
magicmouse_emit_buttons
(
msc
,
clicks
&
3
);
input_report_rel
(
input
,
REL_X
,
x
);
input_report_rel
(
input
,
REL_Y
,
y
);
}
else
{
/* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
input_report_key
(
input
,
BTN_MOUSE
,
clicks
&
1
);
input_report_key
(
input
,
BTN_TOUCH
,
msc
->
ntouches
>
0
);
input_report_key
(
input
,
BTN_TOOL_FINGER
,
msc
->
ntouches
==
1
);
input_report_key
(
input
,
BTN_TOOL_DOUBLETAP
,
msc
->
ntouches
==
2
);
input_report_key
(
input
,
BTN_TOOL_TRIPLETAP
,
msc
->
ntouches
==
3
);
input_report_key
(
input
,
BTN_TOOL_QUADTAP
,
msc
->
ntouches
==
4
);
if
(
msc
->
single_touch_id
>=
0
)
{
input_report_abs
(
input
,
ABS_X
,
msc
->
touches
[
msc
->
single_touch_id
].
x
);
input_report_abs
(
input
,
ABS_Y
,
msc
->
touches
[
msc
->
single_touch_id
].
y
);
}
}
input_sync
(
input
);
return
1
;
}
static
int
magicmouse_input_open
(
struct
input_dev
*
dev
)
{
struct
hid_device
*
hid
=
input_get_drvdata
(
dev
);
return
hid
->
ll_driver
->
open
(
hid
);
}
static
void
magicmouse_input_close
(
struct
input_dev
*
dev
)
{
struct
hid_device
*
hid
=
input_get_drvdata
(
dev
);
hid
->
ll_driver
->
close
(
hid
);
}
static
void
magicmouse_setup_input
(
struct
input_dev
*
input
,
struct
hid_device
*
hdev
)
{
input_set_drvdata
(
input
,
hdev
);
input
->
event
=
hdev
->
ll_driver
->
hidinput_input_event
;
input
->
open
=
magicmouse_input_open
;
input
->
close
=
magicmouse_input_close
;
input
->
name
=
hdev
->
name
;
input
->
phys
=
hdev
->
phys
;
input
->
uniq
=
hdev
->
uniq
;
input
->
id
.
bustype
=
hdev
->
bus
;
input
->
id
.
vendor
=
hdev
->
vendor
;
input
->
id
.
product
=
hdev
->
product
;
input
->
id
.
version
=
hdev
->
version
;
input
->
dev
.
parent
=
hdev
->
dev
.
parent
;
__set_bit
(
EV_KEY
,
input
->
evbit
);
__set_bit
(
BTN_LEFT
,
input
->
keybit
);
__set_bit
(
BTN_RIGHT
,
input
->
keybit
);
if
(
emulate_3button
)
__set_bit
(
BTN_MIDDLE
,
input
->
keybit
);
__set_bit
(
BTN_TOOL_FINGER
,
input
->
keybit
);
__set_bit
(
EV_REL
,
input
->
evbit
);
__set_bit
(
REL_X
,
input
->
relbit
);
__set_bit
(
REL_Y
,
input
->
relbit
);
if
(
emulate_scroll_wheel
)
{
__set_bit
(
REL_WHEEL
,
input
->
relbit
);
__set_bit
(
REL_HWHEEL
,
input
->
relbit
);
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
__set_bit
(
BTN_LEFT
,
input
->
keybit
);
__set_bit
(
BTN_RIGHT
,
input
->
keybit
);
if
(
emulate_3button
)
__set_bit
(
BTN_MIDDLE
,
input
->
keybit
);
__set_bit
(
EV_REL
,
input
->
evbit
);
__set_bit
(
REL_X
,
input
->
relbit
);
__set_bit
(
REL_Y
,
input
->
relbit
);
if
(
emulate_scroll_wheel
)
{
__set_bit
(
REL_WHEEL
,
input
->
relbit
);
__set_bit
(
REL_HWHEEL
,
input
->
relbit
);
}
}
else
{
/* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
__set_bit
(
BTN_MOUSE
,
input
->
keybit
);
__set_bit
(
BTN_TOOL_FINGER
,
input
->
keybit
);
__set_bit
(
BTN_TOOL_DOUBLETAP
,
input
->
keybit
);
__set_bit
(
BTN_TOOL_TRIPLETAP
,
input
->
keybit
);
__set_bit
(
BTN_TOOL_QUADTAP
,
input
->
keybit
);
__set_bit
(
BTN_TOUCH
,
input
->
keybit
);
}
if
(
report_touches
)
{
...
...
@@ -359,16 +396,26 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
input_set_abs_params
(
input
,
ABS_MT_TOUCH_MAJOR
,
0
,
255
,
4
,
0
);
input_set_abs_params
(
input
,
ABS_MT_TOUCH_MINOR
,
0
,
255
,
4
,
0
);
input_set_abs_params
(
input
,
ABS_MT_ORIENTATION
,
-
32
,
31
,
1
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
-
1100
,
1358
,
4
,
0
);
/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
* HID recommends the coordinates work). This driver keeps
* the origin at the same position, and just uses the additive
* inverse of the reported Y.
*/
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
-
1589
,
2047
,
4
,
0
);
if
(
input
->
id
.
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
{
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
-
1100
,
1358
,
4
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
-
1589
,
2047
,
4
,
0
);
}
else
{
/* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
input_set_abs_params
(
input
,
ABS_X
,
-
2909
,
3167
,
4
,
0
);
input_set_abs_params
(
input
,
ABS_Y
,
-
2456
,
2565
,
4
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_X
,
-
2909
,
3167
,
4
,
0
);
input_set_abs_params
(
input
,
ABS_MT_POSITION_Y
,
-
2456
,
2565
,
4
,
0
);
}
}
if
(
report_undeciphered
)
{
...
...
@@ -377,12 +424,22 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
}
}
static
int
magicmouse_input_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
struct
magicmouse_sc
*
msc
=
hid_get_drvdata
(
hdev
);
if
(
!
msc
->
input
)
msc
->
input
=
hi
->
input
;
return
0
;
}
static
int
magicmouse_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
__u8
feature_1
[]
=
{
0xd7
,
0x01
};
__u8
feature_2
[]
=
{
0xf8
,
0x01
,
0x32
};
struct
input_dev
*
input
;
__u8
feature
[]
=
{
0xd7
,
0x01
};
struct
magicmouse_sc
*
msc
;
struct
hid_report
*
report
;
int
ret
;
...
...
@@ -398,6 +455,8 @@ static int magicmouse_probe(struct hid_device *hdev,
msc
->
quirks
=
id
->
driver_data
;
hid_set_drvdata
(
hdev
,
msc
);
msc
->
single_touch_id
=
NO_TOUCHES
;
ret
=
hid_parse
(
hdev
);
if
(
ret
)
{
dev_err
(
&
hdev
->
dev
,
"magicmouse hid parse failed
\n
"
);
...
...
@@ -410,10 +469,22 @@ static int magicmouse_probe(struct hid_device *hdev,
goto
err_free
;
}
/* we are handling the input ourselves */
hidinput_disconnect
(
hdev
);
/* We do this after hid-input is done parsing reports so that
* hid-input uses the most natural button and axis IDs.
*/
if
(
msc
->
input
)
magicmouse_setup_input
(
msc
->
input
,
hdev
);
if
(
id
->
product
==
USB_DEVICE_ID_APPLE_MAGICMOUSE
)
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
MOUSE_REPORT_ID
);
else
{
/* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
TRACKPAD_REPORT_ID
);
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
DOUBLE_REPORT_ID
);
}
report
=
hid_register_report
(
hdev
,
HID_INPUT_REPORT
,
TOUCH_REPORT_ID
);
if
(
!
report
)
{
dev_err
(
&
hdev
->
dev
,
"unable to register touch report
\n
"
);
ret
=
-
ENOMEM
;
...
...
@@ -421,39 +492,15 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report
->
size
=
6
;
ret
=
hdev
->
hid_output_raw_report
(
hdev
,
feature
_1
,
sizeof
(
feature_1
),
ret
=
hdev
->
hid_output_raw_report
(
hdev
,
feature
,
sizeof
(
feature
),
HID_FEATURE_REPORT
);
if
(
ret
!=
sizeof
(
feature_1
))
{
dev_err
(
&
hdev
->
dev
,
"unable to request touch data (1:%d)
\n
"
,
ret
);
goto
err_stop_hw
;
}
ret
=
hdev
->
hid_output_raw_report
(
hdev
,
feature_2
,
sizeof
(
feature_2
),
HID_FEATURE_REPORT
);
if
(
ret
!=
sizeof
(
feature_2
))
{
dev_err
(
&
hdev
->
dev
,
"unable to request touch data (2:%d)
\n
"
,
if
(
ret
!=
sizeof
(
feature
))
{
dev_err
(
&
hdev
->
dev
,
"unable to request touch data (%d)
\n
"
,
ret
);
goto
err_stop_hw
;
}
input
=
input_allocate_device
();
if
(
!
input
)
{
dev_err
(
&
hdev
->
dev
,
"can't alloc input device
\n
"
);
ret
=
-
ENOMEM
;
goto
err_stop_hw
;
}
magicmouse_setup_input
(
input
,
hdev
);
ret
=
input_register_device
(
input
);
if
(
ret
)
{
dev_err
(
&
hdev
->
dev
,
"input device registration failed
\n
"
);
goto
err_input
;
}
msc
->
input
=
input
;
return
0
;
err_input:
input_free_device
(
input
);
err_stop_hw:
hid_hw_stop
(
hdev
);
err_free:
...
...
@@ -466,13 +513,14 @@ static void magicmouse_remove(struct hid_device *hdev)
struct
magicmouse_sc
*
msc
=
hid_get_drvdata
(
hdev
);
hid_hw_stop
(
hdev
);
input_unregister_device
(
msc
->
input
);
kfree
(
msc
);
}
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
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_MAGICMOUSE
),
.
driver_data
=
0
},
{
HID_BLUETOOTH_DEVICE
(
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_MAGICTRACKPAD
),
.
driver_data
=
0
},
{
}
};
MODULE_DEVICE_TABLE
(
hid
,
magic_mice
);
...
...
@@ -483,6 +531,7 @@ static struct hid_driver magicmouse_driver = {
.
probe
=
magicmouse_probe
,
.
remove
=
magicmouse_remove
,
.
raw_event
=
magicmouse_raw_event
,
.
input_mapping
=
magicmouse_input_mapping
,
};
static
int
__init
magicmouse_init
(
void
)
...
...
drivers/hid/hid-ntrig.c
View file @
bbd128b5
...
...
@@ -90,6 +90,55 @@ struct ntrig_data {
};
/*
* This function converts the 4 byte raw firmware code into
* a string containing 5 comma separated numbers.
*/
static
int
ntrig_version_string
(
unsigned
char
*
raw
,
char
*
buf
)
{
__u8
a
=
(
raw
[
1
]
&
0x0e
)
>>
1
;
__u8
b
=
(
raw
[
0
]
&
0x3c
)
>>
2
;
__u8
c
=
((
raw
[
0
]
&
0x03
)
<<
3
)
|
((
raw
[
3
]
&
0xe0
)
>>
5
);
__u8
d
=
((
raw
[
3
]
&
0x07
)
<<
3
)
|
((
raw
[
2
]
&
0xe0
)
>>
5
);
__u8
e
=
raw
[
2
]
&
0x07
;
/*
* As yet unmapped bits:
* 0b11000000 0b11110001 0b00011000 0b00011000
*/
return
sprintf
(
buf
,
"%u.%u.%u.%u.%u"
,
a
,
b
,
c
,
d
,
e
);
}
static
void
ntrig_report_version
(
struct
hid_device
*
hdev
)
{
int
ret
;
char
buf
[
20
];
struct
usb_device
*
usb_dev
=
hid_to_usb_dev
(
hdev
);
unsigned
char
*
data
=
kmalloc
(
8
,
GFP_KERNEL
);
if
(
!
data
)
goto
err_free
;
ret
=
usb_control_msg
(
usb_dev
,
usb_rcvctrlpipe
(
usb_dev
,
0
),
USB_REQ_CLEAR_FEATURE
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_IN
,
0x30c
,
1
,
data
,
8
,
USB_CTRL_SET_TIMEOUT
);
if
(
ret
==
8
)
{
ret
=
ntrig_version_string
(
&
data
[
2
],
buf
);
dev_info
(
&
hdev
->
dev
,
"Firmware version: %s (%02x%02x %02x%02x)
\n
"
,
buf
,
data
[
2
],
data
[
3
],
data
[
4
],
data
[
5
]);
}
err_free:
kfree
(
data
);
}
static
ssize_t
show_phys_width
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
...
...
@@ -377,8 +426,8 @@ static struct attribute_group ntrig_attribute_group = {
*/
static
int
ntrig_input_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
struct
ntrig_data
*
nd
=
hid_get_drvdata
(
hdev
);
...
...
@@ -448,13 +497,13 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* width/height mapped on TouchMajor/TouchMinor/Orientation */
case
HID_DG_WIDTH
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_TOUCH_MAJOR
);
EV_ABS
,
ABS_MT_TOUCH_MAJOR
);
return
1
;
case
HID_DG_HEIGHT
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
ABS_MT_TOUCH_MINOR
);
EV_ABS
,
ABS_MT_TOUCH_MINOR
);
input_set_abs_params
(
hi
->
input
,
ABS_MT_ORIENTATION
,
0
,
1
,
0
,
0
);
0
,
1
,
0
,
0
);
return
1
;
}
return
0
;
...
...
@@ -468,8 +517,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
static
int
ntrig_input_mapped
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
/* No special mappings needed for the pen and single touch */
if
(
field
->
physical
)
...
...
@@ -489,7 +538,7 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
* and call input_mt_sync after each point if necessary
*/
static
int
ntrig_event
(
struct
hid_device
*
hid
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
__s32
value
)
struct
hid_usage
*
usage
,
__s32
value
)
{
struct
input_dev
*
input
=
field
->
hidinput
->
input
;
struct
ntrig_data
*
nd
=
hid_get_drvdata
(
hid
);
...
...
@@ -848,6 +897,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
if
(
report
)
usbhid_submit_report
(
hdev
,
report
,
USB_DIR_OUT
);
ntrig_report_version
(
hdev
);
ret
=
sysfs_create_group
(
&
hdev
->
dev
.
kobj
,
&
ntrig_attribute_group
);
...
...
@@ -860,7 +911,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
static
void
ntrig_remove
(
struct
hid_device
*
hdev
)
{
sysfs_remove_group
(
&
hdev
->
dev
.
kobj
,
&
ntrig_attribute_group
);
&
ntrig_attribute_group
);
hid_hw_stop
(
hdev
);
kfree
(
hid_get_drvdata
(
hdev
));
}
...
...
drivers/hid/hid-roccat-pyra.c
0 → 100644
View file @
bbd128b5
/*
* Roccat Pyra driver for Linux
*
* Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
/*
* Roccat Pyra is a mobile gamer mouse which comes in wired and wireless
* variant. Wireless variant is not tested.
* Userland tools can be found at http://sourceforge.net/projects/roccat
*/
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "hid-ids.h"
#include "hid-roccat.h"
#include "hid-roccat-pyra.h"
static
void
profile_activated
(
struct
pyra_device
*
pyra
,
unsigned
int
new_profile
)
{
pyra
->
actual_profile
=
new_profile
;
pyra
->
actual_cpi
=
pyra
->
profile_settings
[
pyra
->
actual_profile
].
y_cpi
;
}
static
int
pyra_send_control
(
struct
usb_device
*
usb_dev
,
int
value
,
enum
pyra_control_requests
request
)
{
int
len
;
struct
pyra_control
control
;
if
((
request
==
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS
||
request
==
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS
)
&&
(
value
<
0
||
value
>
4
))
return
-
EINVAL
;
control
.
command
=
PYRA_COMMAND_CONTROL
;
control
.
value
=
value
;
control
.
request
=
request
;
len
=
usb_control_msg
(
usb_dev
,
usb_sndctrlpipe
(
usb_dev
,
0
),
USB_REQ_SET_CONFIGURATION
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_OUT
,
PYRA_USB_COMMAND_CONTROL
,
0
,
(
char
*
)
&
control
,
sizeof
(
struct
pyra_control
),
USB_CTRL_SET_TIMEOUT
);
if
(
len
!=
sizeof
(
struct
pyra_control
))
return
len
;
return
0
;
}
static
int
pyra_receive_control_status
(
struct
usb_device
*
usb_dev
)
{
int
len
;
struct
pyra_control
control
;
do
{
msleep
(
10
);
len
=
usb_control_msg
(
usb_dev
,
usb_rcvctrlpipe
(
usb_dev
,
0
),
USB_REQ_CLEAR_FEATURE
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_IN
,
PYRA_USB_COMMAND_CONTROL
,
0
,
(
char
*
)
&
control
,
sizeof
(
struct
pyra_control
),
USB_CTRL_SET_TIMEOUT
);
/* requested too early, try again */
}
while
(
len
==
-
EPROTO
);
if
(
len
==
sizeof
(
struct
pyra_control
)
&&
control
.
command
==
PYRA_COMMAND_CONTROL
&&
control
.
request
==
PYRA_CONTROL_REQUEST_STATUS
&&
control
.
value
==
1
)
return
0
;
else
{
dev_err
(
&
usb_dev
->
dev
,
"receive control status: "
"unknown response 0x%x 0x%x
\n
"
,
control
.
request
,
control
.
value
);
return
-
EINVAL
;
}
}
static
int
pyra_get_profile_settings
(
struct
usb_device
*
usb_dev
,
struct
pyra_profile_settings
*
buf
,
int
number
)
{
int
retval
;
retval
=
pyra_send_control
(
usb_dev
,
number
,
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS
);
if
(
retval
)
return
retval
;
retval
=
usb_control_msg
(
usb_dev
,
usb_rcvctrlpipe
(
usb_dev
,
0
),
USB_REQ_CLEAR_FEATURE
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_IN
,
PYRA_USB_COMMAND_PROFILE_SETTINGS
,
0
,
(
char
*
)
buf
,
sizeof
(
struct
pyra_profile_settings
),
USB_CTRL_SET_TIMEOUT
);
if
(
retval
!=
sizeof
(
struct
pyra_profile_settings
))
return
retval
;
return
0
;
}
static
int
pyra_get_profile_buttons
(
struct
usb_device
*
usb_dev
,
struct
pyra_profile_buttons
*
buf
,
int
number
)
{
int
retval
;
retval
=
pyra_send_control
(
usb_dev
,
number
,
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS
);
if
(
retval
)
return
retval
;
retval
=
usb_control_msg
(
usb_dev
,
usb_rcvctrlpipe
(
usb_dev
,
0
),
USB_REQ_CLEAR_FEATURE
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_IN
,
PYRA_USB_COMMAND_PROFILE_BUTTONS
,
0
,
(
char
*
)
buf
,
sizeof
(
struct
pyra_profile_buttons
),
USB_CTRL_SET_TIMEOUT
);
if
(
retval
!=
sizeof
(
struct
pyra_profile_buttons
))
return
retval
;
return
0
;
}
static
int
pyra_get_settings
(
struct
usb_device
*
usb_dev
,
struct
pyra_settings
*
buf
)
{
int
len
;
len
=
usb_control_msg
(
usb_dev
,
usb_rcvctrlpipe
(
usb_dev
,
0
),
USB_REQ_CLEAR_FEATURE
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_IN
,
PYRA_USB_COMMAND_SETTINGS
,
0
,
buf
,
sizeof
(
struct
pyra_settings
),
USB_CTRL_SET_TIMEOUT
);
if
(
len
!=
sizeof
(
struct
pyra_settings
))
return
-
EIO
;
return
0
;
}
static
int
pyra_get_info
(
struct
usb_device
*
usb_dev
,
struct
pyra_info
*
buf
)
{
int
len
;
len
=
usb_control_msg
(
usb_dev
,
usb_rcvctrlpipe
(
usb_dev
,
0
),
USB_REQ_CLEAR_FEATURE
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_IN
,
PYRA_USB_COMMAND_INFO
,
0
,
buf
,
sizeof
(
struct
pyra_info
),
USB_CTRL_SET_TIMEOUT
);
if
(
len
!=
sizeof
(
struct
pyra_info
))
return
-
EIO
;
return
0
;
}
static
int
pyra_set_profile_settings
(
struct
usb_device
*
usb_dev
,
struct
pyra_profile_settings
const
*
settings
)
{
int
len
;
len
=
usb_control_msg
(
usb_dev
,
usb_sndctrlpipe
(
usb_dev
,
0
),
USB_REQ_SET_CONFIGURATION
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_OUT
,
PYRA_USB_COMMAND_PROFILE_SETTINGS
,
0
,
(
char
*
)
settings
,
sizeof
(
struct
pyra_profile_settings
),
USB_CTRL_SET_TIMEOUT
);
if
(
len
!=
sizeof
(
struct
pyra_profile_settings
))
return
-
EIO
;
if
(
pyra_receive_control_status
(
usb_dev
))
return
-
EIO
;
return
0
;
}
static
int
pyra_set_profile_buttons
(
struct
usb_device
*
usb_dev
,
struct
pyra_profile_buttons
const
*
buttons
)
{
int
len
;
len
=
usb_control_msg
(
usb_dev
,
usb_sndctrlpipe
(
usb_dev
,
0
),
USB_REQ_SET_CONFIGURATION
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_OUT
,
PYRA_USB_COMMAND_PROFILE_BUTTONS
,
0
,
(
char
*
)
buttons
,
sizeof
(
struct
pyra_profile_buttons
),
USB_CTRL_SET_TIMEOUT
);
if
(
len
!=
sizeof
(
struct
pyra_profile_buttons
))
return
-
EIO
;
if
(
pyra_receive_control_status
(
usb_dev
))
return
-
EIO
;
return
0
;
}
static
int
pyra_set_settings
(
struct
usb_device
*
usb_dev
,
struct
pyra_settings
const
*
settings
)
{
int
len
;
len
=
usb_control_msg
(
usb_dev
,
usb_sndctrlpipe
(
usb_dev
,
0
),
USB_REQ_SET_CONFIGURATION
,
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
|
USB_DIR_OUT
,
PYRA_USB_COMMAND_SETTINGS
,
0
,
(
char
*
)
settings
,
sizeof
(
struct
pyra_settings
),
USB_CTRL_SET_TIMEOUT
);
if
(
len
!=
sizeof
(
struct
pyra_settings
))
return
-
EIO
;
if
(
pyra_receive_control_status
(
usb_dev
))
return
-
EIO
;
return
0
;
}
static
ssize_t
pyra_sysfs_read_profilex_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
,
int
number
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
if
(
off
>=
sizeof
(
struct
pyra_profile_settings
))
return
0
;
if
(
off
+
count
>
sizeof
(
struct
pyra_profile_settings
))
count
=
sizeof
(
struct
pyra_profile_settings
)
-
off
;
mutex_lock
(
&
pyra
->
pyra_lock
);
memcpy
(
buf
,
((
char
const
*
)
&
pyra
->
profile_settings
[
number
])
+
off
,
count
);
mutex_unlock
(
&
pyra
->
pyra_lock
);
return
count
;
}
static
ssize_t
pyra_sysfs_read_profile1_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_settings
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
0
);
}
static
ssize_t
pyra_sysfs_read_profile2_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_settings
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
1
);
}
static
ssize_t
pyra_sysfs_read_profile3_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_settings
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
2
);
}
static
ssize_t
pyra_sysfs_read_profile4_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_settings
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
3
);
}
static
ssize_t
pyra_sysfs_read_profile5_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_settings
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
4
);
}
static
ssize_t
pyra_sysfs_read_profilex_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
,
int
number
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
if
(
off
>=
sizeof
(
struct
pyra_profile_buttons
))
return
0
;
if
(
off
+
count
>
sizeof
(
struct
pyra_profile_buttons
))
count
=
sizeof
(
struct
pyra_profile_buttons
)
-
off
;
mutex_lock
(
&
pyra
->
pyra_lock
);
memcpy
(
buf
,
((
char
const
*
)
&
pyra
->
profile_buttons
[
number
])
+
off
,
count
);
mutex_unlock
(
&
pyra
->
pyra_lock
);
return
count
;
}
static
ssize_t
pyra_sysfs_read_profile1_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_buttons
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
0
);
}
static
ssize_t
pyra_sysfs_read_profile2_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_buttons
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
1
);
}
static
ssize_t
pyra_sysfs_read_profile3_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_buttons
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
2
);
}
static
ssize_t
pyra_sysfs_read_profile4_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_buttons
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
3
);
}
static
ssize_t
pyra_sysfs_read_profile5_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
return
pyra_sysfs_read_profilex_buttons
(
fp
,
kobj
,
attr
,
buf
,
off
,
count
,
4
);
}
static
ssize_t
pyra_sysfs_write_profile_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
struct
usb_device
*
usb_dev
=
interface_to_usbdev
(
to_usb_interface
(
dev
));
int
retval
=
0
;
int
difference
;
int
profile_number
;
struct
pyra_profile_settings
*
profile_settings
;
if
(
off
!=
0
||
count
!=
sizeof
(
struct
pyra_profile_settings
))
return
-
EINVAL
;
profile_number
=
((
struct
pyra_profile_settings
const
*
)
buf
)
->
number
;
profile_settings
=
&
pyra
->
profile_settings
[
profile_number
];
mutex_lock
(
&
pyra
->
pyra_lock
);
difference
=
memcmp
(
buf
,
profile_settings
,
sizeof
(
struct
pyra_profile_settings
));
if
(
difference
)
{
retval
=
pyra_set_profile_settings
(
usb_dev
,
(
struct
pyra_profile_settings
const
*
)
buf
);
if
(
!
retval
)
memcpy
(
profile_settings
,
buf
,
sizeof
(
struct
pyra_profile_settings
));
}
mutex_unlock
(
&
pyra
->
pyra_lock
);
if
(
retval
)
return
retval
;
return
sizeof
(
struct
pyra_profile_settings
);
}
static
ssize_t
pyra_sysfs_write_profile_buttons
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
struct
usb_device
*
usb_dev
=
interface_to_usbdev
(
to_usb_interface
(
dev
));
int
retval
=
0
;
int
difference
;
int
profile_number
;
struct
pyra_profile_buttons
*
profile_buttons
;
if
(
off
!=
0
||
count
!=
sizeof
(
struct
pyra_profile_buttons
))
return
-
EINVAL
;
profile_number
=
((
struct
pyra_profile_buttons
const
*
)
buf
)
->
number
;
profile_buttons
=
&
pyra
->
profile_buttons
[
profile_number
];
mutex_lock
(
&
pyra
->
pyra_lock
);
difference
=
memcmp
(
buf
,
profile_buttons
,
sizeof
(
struct
pyra_profile_buttons
));
if
(
difference
)
{
retval
=
pyra_set_profile_buttons
(
usb_dev
,
(
struct
pyra_profile_buttons
const
*
)
buf
);
if
(
!
retval
)
memcpy
(
profile_buttons
,
buf
,
sizeof
(
struct
pyra_profile_buttons
));
}
mutex_unlock
(
&
pyra
->
pyra_lock
);
if
(
retval
)
return
retval
;
return
sizeof
(
struct
pyra_profile_buttons
);
}
static
ssize_t
pyra_sysfs_read_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
if
(
off
>=
sizeof
(
struct
pyra_settings
))
return
0
;
if
(
off
+
count
>
sizeof
(
struct
pyra_settings
))
count
=
sizeof
(
struct
pyra_settings
)
-
off
;
mutex_lock
(
&
pyra
->
pyra_lock
);
memcpy
(
buf
,
((
char
const
*
)
&
pyra
->
settings
)
+
off
,
count
);
mutex_unlock
(
&
pyra
->
pyra_lock
);
return
count
;
}
static
ssize_t
pyra_sysfs_write_settings
(
struct
file
*
fp
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
struct
usb_device
*
usb_dev
=
interface_to_usbdev
(
to_usb_interface
(
dev
));
int
retval
=
0
;
int
difference
;
if
(
off
!=
0
||
count
!=
sizeof
(
struct
pyra_settings
))
return
-
EINVAL
;
mutex_lock
(
&
pyra
->
pyra_lock
);
difference
=
memcmp
(
buf
,
&
pyra
->
settings
,
sizeof
(
struct
pyra_settings
));
if
(
difference
)
{
retval
=
pyra_set_settings
(
usb_dev
,
(
struct
pyra_settings
const
*
)
buf
);
if
(
!
retval
)
memcpy
(
&
pyra
->
settings
,
buf
,
sizeof
(
struct
pyra_settings
));
}
mutex_unlock
(
&
pyra
->
pyra_lock
);
if
(
retval
)
return
retval
;
profile_activated
(
pyra
,
pyra
->
settings
.
startup_profile
);
return
sizeof
(
struct
pyra_settings
);
}
static
ssize_t
pyra_sysfs_show_actual_cpi
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
return
snprintf
(
buf
,
PAGE_SIZE
,
"%d
\n
"
,
pyra
->
actual_cpi
);
}
static
ssize_t
pyra_sysfs_show_actual_profile
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
return
snprintf
(
buf
,
PAGE_SIZE
,
"%d
\n
"
,
pyra
->
actual_profile
);
}
static
ssize_t
pyra_sysfs_show_firmware_version
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
return
snprintf
(
buf
,
PAGE_SIZE
,
"%d
\n
"
,
pyra
->
firmware_version
);
}
static
ssize_t
pyra_sysfs_show_startup_profile
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
dev_get_drvdata
(
dev
));
return
snprintf
(
buf
,
PAGE_SIZE
,
"%d
\n
"
,
pyra
->
settings
.
startup_profile
);
}
static
DEVICE_ATTR
(
actual_cpi
,
0440
,
pyra_sysfs_show_actual_cpi
,
NULL
);
static
DEVICE_ATTR
(
actual_profile
,
0440
,
pyra_sysfs_show_actual_profile
,
NULL
);
static
DEVICE_ATTR
(
firmware_version
,
0440
,
pyra_sysfs_show_firmware_version
,
NULL
);
static
DEVICE_ATTR
(
startup_profile
,
0440
,
pyra_sysfs_show_startup_profile
,
NULL
);
static
struct
attribute
*
pyra_attributes
[]
=
{
&
dev_attr_actual_cpi
.
attr
,
&
dev_attr_actual_profile
.
attr
,
&
dev_attr_firmware_version
.
attr
,
&
dev_attr_startup_profile
.
attr
,
NULL
};
static
struct
attribute_group
pyra_attribute_group
=
{
.
attrs
=
pyra_attributes
};
static
struct
bin_attribute
pyra_profile_settings_attr
=
{
.
attr
=
{
.
name
=
"profile_settings"
,
.
mode
=
0220
},
.
size
=
sizeof
(
struct
pyra_profile_settings
),
.
write
=
pyra_sysfs_write_profile_settings
};
static
struct
bin_attribute
pyra_profile1_settings_attr
=
{
.
attr
=
{
.
name
=
"profile1_settings"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_settings
),
.
read
=
pyra_sysfs_read_profile1_settings
};
static
struct
bin_attribute
pyra_profile2_settings_attr
=
{
.
attr
=
{
.
name
=
"profile2_settings"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_settings
),
.
read
=
pyra_sysfs_read_profile2_settings
};
static
struct
bin_attribute
pyra_profile3_settings_attr
=
{
.
attr
=
{
.
name
=
"profile3_settings"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_settings
),
.
read
=
pyra_sysfs_read_profile3_settings
};
static
struct
bin_attribute
pyra_profile4_settings_attr
=
{
.
attr
=
{
.
name
=
"profile4_settings"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_settings
),
.
read
=
pyra_sysfs_read_profile4_settings
};
static
struct
bin_attribute
pyra_profile5_settings_attr
=
{
.
attr
=
{
.
name
=
"profile5_settings"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_settings
),
.
read
=
pyra_sysfs_read_profile5_settings
};
static
struct
bin_attribute
pyra_profile_buttons_attr
=
{
.
attr
=
{
.
name
=
"profile_buttons"
,
.
mode
=
0220
},
.
size
=
sizeof
(
struct
pyra_profile_buttons
),
.
write
=
pyra_sysfs_write_profile_buttons
};
static
struct
bin_attribute
pyra_profile1_buttons_attr
=
{
.
attr
=
{
.
name
=
"profile1_buttons"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_buttons
),
.
read
=
pyra_sysfs_read_profile1_buttons
};
static
struct
bin_attribute
pyra_profile2_buttons_attr
=
{
.
attr
=
{
.
name
=
"profile2_buttons"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_buttons
),
.
read
=
pyra_sysfs_read_profile2_buttons
};
static
struct
bin_attribute
pyra_profile3_buttons_attr
=
{
.
attr
=
{
.
name
=
"profile3_buttons"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_buttons
),
.
read
=
pyra_sysfs_read_profile3_buttons
};
static
struct
bin_attribute
pyra_profile4_buttons_attr
=
{
.
attr
=
{
.
name
=
"profile4_buttons"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_buttons
),
.
read
=
pyra_sysfs_read_profile4_buttons
};
static
struct
bin_attribute
pyra_profile5_buttons_attr
=
{
.
attr
=
{
.
name
=
"profile5_buttons"
,
.
mode
=
0440
},
.
size
=
sizeof
(
struct
pyra_profile_buttons
),
.
read
=
pyra_sysfs_read_profile5_buttons
};
static
struct
bin_attribute
pyra_settings_attr
=
{
.
attr
=
{
.
name
=
"settings"
,
.
mode
=
0660
},
.
size
=
sizeof
(
struct
pyra_settings
),
.
read
=
pyra_sysfs_read_settings
,
.
write
=
pyra_sysfs_write_settings
};
static
int
pyra_create_sysfs_attributes
(
struct
usb_interface
*
intf
)
{
int
retval
;
retval
=
sysfs_create_group
(
&
intf
->
dev
.
kobj
,
&
pyra_attribute_group
);
if
(
retval
)
goto
exit_1
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile_settings_attr
);
if
(
retval
)
goto
exit_2
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile1_settings_attr
);
if
(
retval
)
goto
exit_3
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile2_settings_attr
);
if
(
retval
)
goto
exit_4
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile3_settings_attr
);
if
(
retval
)
goto
exit_5
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile4_settings_attr
);
if
(
retval
)
goto
exit_6
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile5_settings_attr
);
if
(
retval
)
goto
exit_7
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile_buttons_attr
);
if
(
retval
)
goto
exit_8
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile1_buttons_attr
);
if
(
retval
)
goto
exit_9
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile2_buttons_attr
);
if
(
retval
)
goto
exit_10
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile3_buttons_attr
);
if
(
retval
)
goto
exit_11
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile4_buttons_attr
);
if
(
retval
)
goto
exit_12
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile5_buttons_attr
);
if
(
retval
)
goto
exit_13
;
retval
=
sysfs_create_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_settings_attr
);
if
(
retval
)
goto
exit_14
;
return
0
;
exit_14:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile5_buttons_attr
);
exit_13:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile4_buttons_attr
);
exit_12:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile3_buttons_attr
);
exit_11:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile2_buttons_attr
);
exit_10:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile1_buttons_attr
);
exit_9:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile_buttons_attr
);
exit_8:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile5_settings_attr
);
exit_7:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile4_settings_attr
);
exit_6:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile3_settings_attr
);
exit_5:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile2_settings_attr
);
exit_4:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile1_settings_attr
);
exit_3:
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile_settings_attr
);
exit_2:
sysfs_remove_group
(
&
intf
->
dev
.
kobj
,
&
pyra_attribute_group
);
exit_1:
return
retval
;
}
static
void
pyra_remove_sysfs_attributes
(
struct
usb_interface
*
intf
)
{
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_settings_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile5_buttons_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile4_buttons_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile3_buttons_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile2_buttons_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile1_buttons_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile_buttons_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile5_settings_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile4_settings_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile3_settings_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile2_settings_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile1_settings_attr
);
sysfs_remove_bin_file
(
&
intf
->
dev
.
kobj
,
&
pyra_profile_settings_attr
);
sysfs_remove_group
(
&
intf
->
dev
.
kobj
,
&
pyra_attribute_group
);
}
static
int
pyra_init_pyra_device_struct
(
struct
usb_device
*
usb_dev
,
struct
pyra_device
*
pyra
)
{
struct
pyra_info
*
info
;
int
retval
,
i
;
mutex_init
(
&
pyra
->
pyra_lock
);
info
=
kmalloc
(
sizeof
(
struct
pyra_info
),
GFP_KERNEL
);
if
(
!
info
)
return
-
ENOMEM
;
retval
=
pyra_get_info
(
usb_dev
,
info
);
if
(
retval
)
{
kfree
(
info
);
return
retval
;
}
pyra
->
firmware_version
=
info
->
firmware_version
;
kfree
(
info
);
retval
=
pyra_get_settings
(
usb_dev
,
&
pyra
->
settings
);
if
(
retval
)
return
retval
;
for
(
i
=
0
;
i
<
5
;
++
i
)
{
retval
=
pyra_get_profile_settings
(
usb_dev
,
&
pyra
->
profile_settings
[
i
],
i
);
if
(
retval
)
return
retval
;
retval
=
pyra_get_profile_buttons
(
usb_dev
,
&
pyra
->
profile_buttons
[
i
],
i
);
if
(
retval
)
return
retval
;
}
profile_activated
(
pyra
,
pyra
->
settings
.
startup_profile
);
return
0
;
}
static
int
pyra_init_specials
(
struct
hid_device
*
hdev
)
{
struct
usb_interface
*
intf
=
to_usb_interface
(
hdev
->
dev
.
parent
);
struct
usb_device
*
usb_dev
=
interface_to_usbdev
(
intf
);
struct
pyra_device
*
pyra
;
int
retval
;
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceProtocol
==
USB_INTERFACE_PROTOCOL_MOUSE
)
{
pyra
=
kzalloc
(
sizeof
(
*
pyra
),
GFP_KERNEL
);
if
(
!
pyra
)
{
dev_err
(
&
hdev
->
dev
,
"can't alloc device descriptor
\n
"
);
return
-
ENOMEM
;
}
hid_set_drvdata
(
hdev
,
pyra
);
retval
=
pyra_init_pyra_device_struct
(
usb_dev
,
pyra
);
if
(
retval
)
{
dev_err
(
&
hdev
->
dev
,
"couldn't init struct pyra_device
\n
"
);
goto
exit_free
;
}
retval
=
roccat_connect
(
hdev
);
if
(
retval
<
0
)
{
dev_err
(
&
hdev
->
dev
,
"couldn't init char dev
\n
"
);
}
else
{
pyra
->
chrdev_minor
=
retval
;
pyra
->
roccat_claimed
=
1
;
}
retval
=
pyra_create_sysfs_attributes
(
intf
);
if
(
retval
)
{
dev_err
(
&
hdev
->
dev
,
"cannot create sysfs files
\n
"
);
goto
exit_free
;
}
}
else
{
hid_set_drvdata
(
hdev
,
NULL
);
}
return
0
;
exit_free:
kfree
(
pyra
);
return
retval
;
}
static
void
pyra_remove_specials
(
struct
hid_device
*
hdev
)
{
struct
usb_interface
*
intf
=
to_usb_interface
(
hdev
->
dev
.
parent
);
struct
pyra_device
*
pyra
;
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceProtocol
==
USB_INTERFACE_PROTOCOL_MOUSE
)
{
pyra_remove_sysfs_attributes
(
intf
);
pyra
=
hid_get_drvdata
(
hdev
);
if
(
pyra
->
roccat_claimed
)
roccat_disconnect
(
pyra
->
chrdev_minor
);
kfree
(
hid_get_drvdata
(
hdev
));
}
}
static
int
pyra_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
int
retval
;
retval
=
hid_parse
(
hdev
);
if
(
retval
)
{
dev_err
(
&
hdev
->
dev
,
"parse failed
\n
"
);
goto
exit
;
}
retval
=
hid_hw_start
(
hdev
,
HID_CONNECT_DEFAULT
);
if
(
retval
)
{
dev_err
(
&
hdev
->
dev
,
"hw start failed
\n
"
);
goto
exit
;
}
retval
=
pyra_init_specials
(
hdev
);
if
(
retval
)
{
dev_err
(
&
hdev
->
dev
,
"couldn't install mouse
\n
"
);
goto
exit_stop
;
}
return
0
;
exit_stop:
hid_hw_stop
(
hdev
);
exit:
return
retval
;
}
static
void
pyra_remove
(
struct
hid_device
*
hdev
)
{
pyra_remove_specials
(
hdev
);
hid_hw_stop
(
hdev
);
}
static
void
pyra_keep_values_up_to_date
(
struct
pyra_device
*
pyra
,
u8
const
*
data
)
{
struct
pyra_mouse_event_button
const
*
button_event
;
switch
(
data
[
0
])
{
case
PYRA_MOUSE_REPORT_NUMBER_BUTTON
:
button_event
=
(
struct
pyra_mouse_event_button
const
*
)
data
;
switch
(
button_event
->
type
)
{
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2
:
profile_activated
(
pyra
,
button_event
->
data1
-
1
);
break
;
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI
:
pyra
->
actual_cpi
=
button_event
->
data1
;
break
;
}
break
;
}
}
static
void
pyra_report_to_chrdev
(
struct
pyra_device
const
*
pyra
,
u8
const
*
data
)
{
struct
pyra_roccat_report
roccat_report
;
struct
pyra_mouse_event_button
const
*
button_event
;
if
(
data
[
0
]
!=
PYRA_MOUSE_REPORT_NUMBER_BUTTON
)
return
;
button_event
=
(
struct
pyra_mouse_event_button
const
*
)
data
;
switch
(
button_event
->
type
)
{
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2
:
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI
:
roccat_report
.
type
=
button_event
->
type
;
roccat_report
.
value
=
button_event
->
data1
;
roccat_report
.
key
=
0
;
roccat_report_event
(
pyra
->
chrdev_minor
,
(
uint8_t
const
*
)
&
roccat_report
,
sizeof
(
struct
pyra_roccat_report
));
break
;
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO
:
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT
:
case
PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH
:
if
(
button_event
->
data2
==
PYRA_MOUSE_EVENT_BUTTON_PRESS
)
{
roccat_report
.
type
=
button_event
->
type
;
roccat_report
.
key
=
button_event
->
data1
;
/*
* pyra reports profile numbers with range 1-5.
* Keeping this behaviour.
*/
roccat_report
.
value
=
pyra
->
actual_profile
+
1
;
roccat_report_event
(
pyra
->
chrdev_minor
,
(
uint8_t
const
*
)
&
roccat_report
,
sizeof
(
struct
pyra_roccat_report
));
}
break
;
}
}
static
int
pyra_raw_event
(
struct
hid_device
*
hdev
,
struct
hid_report
*
report
,
u8
*
data
,
int
size
)
{
struct
usb_interface
*
intf
=
to_usb_interface
(
hdev
->
dev
.
parent
);
struct
pyra_device
*
pyra
=
hid_get_drvdata
(
hdev
);
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceProtocol
!=
USB_INTERFACE_PROTOCOL_MOUSE
)
return
0
;
pyra_keep_values_up_to_date
(
pyra
,
data
);
if
(
pyra
->
roccat_claimed
)
pyra_report_to_chrdev
(
pyra
,
data
);
return
0
;
}
static
const
struct
hid_device_id
pyra_devices
[]
=
{
{
HID_USB_DEVICE
(
USB_VENDOR_ID_ROCCAT
,
USB_DEVICE_ID_ROCCAT_PYRA_WIRED
)
},
/* TODO add USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS after testing */
{
}
};
MODULE_DEVICE_TABLE
(
hid
,
pyra_devices
);
static
struct
hid_driver
pyra_driver
=
{
.
name
=
"pyra"
,
.
id_table
=
pyra_devices
,
.
probe
=
pyra_probe
,
.
remove
=
pyra_remove
,
.
raw_event
=
pyra_raw_event
};
static
int
__init
pyra_init
(
void
)
{
return
hid_register_driver
(
&
pyra_driver
);
}
static
void
__exit
pyra_exit
(
void
)
{
hid_unregister_driver
(
&
pyra_driver
);
}
module_init
(
pyra_init
);
module_exit
(
pyra_exit
);
MODULE_AUTHOR
(
"Stefan Achatz"
);
MODULE_DESCRIPTION
(
"USB Roccat Pyra driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/hid/hid-roccat-pyra.h
0 → 100644
View file @
bbd128b5
#ifndef __HID_ROCCAT_PYRA_H
#define __HID_ROCCAT_PYRA_H
/*
* Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/types.h>
#pragma pack(push)
#pragma pack(1)
struct
pyra_b
{
uint8_t
command
;
/* PYRA_COMMAND_B */
uint8_t
size
;
/* always 3 */
uint8_t
unknown
;
/* 1 */
};
struct
pyra_control
{
uint8_t
command
;
/* PYRA_COMMAND_CONTROL */
/*
* value is profile number for request_settings and request_buttons
* 1 if status ok for request_status
*/
uint8_t
value
;
/* Range 0-4 */
uint8_t
request
;
};
enum
pyra_control_requests
{
PYRA_CONTROL_REQUEST_STATUS
=
0x00
,
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS
=
0x10
,
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS
=
0x20
};
struct
pyra_settings
{
uint8_t
command
;
/* PYRA_COMMAND_SETTINGS */
uint8_t
size
;
/* always 3 */
uint8_t
startup_profile
;
/* Range 0-4! */
};
struct
pyra_profile_settings
{
uint8_t
command
;
/* PYRA_COMMAND_PROFILE_SETTINGS */
uint8_t
size
;
/* always 0xd */
uint8_t
number
;
/* Range 0-4 */
uint8_t
xysync
;
uint8_t
x_sensitivity
;
/* 0x1-0xa */
uint8_t
y_sensitivity
;
uint8_t
x_cpi
;
/* unused */
uint8_t
y_cpi
;
/* this value is for x and y */
uint8_t
lightswitch
;
/* 0 = off, 1 = on */
uint8_t
light_effect
;
uint8_t
handedness
;
uint16_t
checksum
;
/* byte sum */
};
struct
pyra_profile_buttons
{
uint8_t
command
;
/* PYRA_COMMAND_PROFILE_BUTTONS */
uint8_t
size
;
/* always 0x13 */
uint8_t
number
;
/* Range 0-4 */
uint8_t
buttons
[
14
];
uint16_t
checksum
;
/* byte sum */
};
struct
pyra_info
{
uint8_t
command
;
/* PYRA_COMMAND_INFO */
uint8_t
size
;
/* always 6 */
uint8_t
firmware_version
;
uint8_t
unknown1
;
/* always 0 */
uint8_t
unknown2
;
/* always 1 */
uint8_t
unknown3
;
/* always 0 */
};
enum
pyra_commands
{
PYRA_COMMAND_CONTROL
=
0x4
,
PYRA_COMMAND_SETTINGS
=
0x5
,
PYRA_COMMAND_PROFILE_SETTINGS
=
0x6
,
PYRA_COMMAND_PROFILE_BUTTONS
=
0x7
,
PYRA_COMMAND_INFO
=
0x9
,
PYRA_COMMAND_B
=
0xb
};
enum
pyra_usb_commands
{
PYRA_USB_COMMAND_CONTROL
=
0x304
,
PYRA_USB_COMMAND_SETTINGS
=
0x305
,
PYRA_USB_COMMAND_PROFILE_SETTINGS
=
0x306
,
PYRA_USB_COMMAND_PROFILE_BUTTONS
=
0x307
,
PYRA_USB_COMMAND_INFO
=
0x309
,
PYRA_USB_COMMAND_B
=
0x30b
/* writes 3 bytes */
};
enum
pyra_mouse_report_numbers
{
PYRA_MOUSE_REPORT_NUMBER_HID
=
1
,
PYRA_MOUSE_REPORT_NUMBER_AUDIO
=
2
,
PYRA_MOUSE_REPORT_NUMBER_BUTTON
=
3
,
};
struct
pyra_mouse_event_button
{
uint8_t
report_number
;
/* always 3 */
uint8_t
unknown
;
/* always 0 */
uint8_t
type
;
uint8_t
data1
;
uint8_t
data2
;
};
struct
pyra_mouse_event_audio
{
uint8_t
report_number
;
/* always 2 */
uint8_t
type
;
uint8_t
unused
;
/* always 0 */
};
/* hid audio controls */
enum
pyra_mouse_event_audio_types
{
PYRA_MOUSE_EVENT_AUDIO_TYPE_MUTE
=
0xe2
,
PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_UP
=
0xe9
,
PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_DOWN
=
0xea
,
};
enum
pyra_mouse_event_button_types
{
/*
* Mouse sends tilt events on report_number 1 and 3
* Tilt events are sent repeatedly with 0.94s between first and second
* event and 0.22s on subsequent
*/
PYRA_MOUSE_EVENT_BUTTON_TYPE_TILT
=
0x10
,
/*
* These are sent sequentially
* data1 contains new profile number in range 1-5
*/
PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_1
=
0x20
,
PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2
=
0x30
,
/*
* data1 = button_number (rmp index)
* data2 = pressed/released
*/
PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO
=
0x40
,
PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT
=
0x50
,
/*
* data1 = button_number (rmp index)
*/
PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH
=
0x60
,
/* data1 = new cpi */
PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI
=
0xb0
,
/* data1 and data2 = new sensitivity */
PYRA_MOUSE_EVENT_BUTTON_TYPE_SENSITIVITY
=
0xc0
,
PYRA_MOUSE_EVENT_BUTTON_TYPE_MULTIMEDIA
=
0xf0
,
};
enum
{
PYRA_MOUSE_EVENT_BUTTON_PRESS
=
0
,
PYRA_MOUSE_EVENT_BUTTON_RELEASE
=
1
,
};
struct
pyra_roccat_report
{
uint8_t
type
;
uint8_t
value
;
uint8_t
key
;
};
#pragma pack(pop)
struct
pyra_device
{
int
actual_profile
;
int
actual_cpi
;
int
firmware_version
;
int
roccat_claimed
;
int
chrdev_minor
;
struct
mutex
pyra_lock
;
struct
pyra_settings
settings
;
struct
pyra_profile_settings
profile_settings
[
5
];
struct
pyra_profile_buttons
profile_buttons
[
5
];
};
#endif
drivers/hid/usbhid/hid-core.c
View file @
bbd128b5
...
...
@@ -807,7 +807,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
struct
usb_host_interface
*
interface
=
intf
->
cur_altsetting
;
int
ret
;
if
(
usbhid
->
urbout
)
{
if
(
usbhid
->
urbout
&&
report_type
!=
HID_FEATURE_REPORT
)
{
int
actual_length
;
int
skipped_report_id
=
0
;
...
...
drivers/hid/usbhid/hid-quirks.c
View file @
bbd128b5
...
...
@@ -34,7 +34,6 @@ static const struct hid_blacklist {
{
USB_VENDOR_ID_ALPS
,
USB_DEVICE_ID_IBM_GAMEPAD
,
HID_QUIRK_BADPAD
},
{
USB_VENDOR_ID_CHIC
,
USB_DEVICE_ID_CHIC_GAMEPAD
,
HID_QUIRK_BADPAD
},
{
USB_VENDOR_ID_DWAV
,
USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER
,
HID_QUIRK_MULTI_INPUT
|
HID_QUIRK_NOGET
},
{
USB_VENDOR_ID_DWAV
,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH
,
HID_QUIRK_MULTI_INPUT
},
{
USB_VENDOR_ID_MOJO
,
USB_DEVICE_ID_RETRO_ADAPTER
,
HID_QUIRK_MULTI_INPUT
},
{
USB_VENDOR_ID_TURBOX
,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART
,
HID_QUIRK_MULTI_INPUT
},
{
USB_VENDOR_ID_HAPP
,
USB_DEVICE_ID_UGCI_DRIVING
,
HID_QUIRK_BADPAD
|
HID_QUIRK_MULTI_INPUT
},
...
...
include/linux/hid.h
View file @
bbd128b5
...
...
@@ -316,6 +316,7 @@ struct hid_item {
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
#define HID_QUIRK_NO_IGNORE 0x40000000
#define HID_QUIRK_NO_INPUT_SYNC 0x80000000
/*
* This is the global environment of the parser. This information is
...
...
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