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
nexedi
linux
Commits
b3d07e03
Commit
b3d07e03
authored
May 22, 2012
by
Jiri Kosina
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'device-groups', 'logitech' and 'multitouch' into for-linus
parents
b565a390
c6e6dc87
3ac36d15
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
287 additions
and
89 deletions
+287
-89
drivers/hid/hid-lg.c
drivers/hid/hid-lg.c
+32
-23
drivers/hid/hid-lg.h
drivers/hid/hid-lg.h
+5
-0
drivers/hid/hid-lg4ff.c
drivers/hid/hid-lg4ff.c
+204
-54
drivers/hid/hid-multitouch.c
drivers/hid/hid-multitouch.c
+46
-12
No files found.
drivers/hid/hid-lg.c
View file @
b3d07e03
...
@@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = {
...
@@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = {
static
__u8
*
lg_report_fixup
(
struct
hid_device
*
hdev
,
__u8
*
rdesc
,
static
__u8
*
lg_report_fixup
(
struct
hid_device
*
hdev
,
__u8
*
rdesc
,
unsigned
int
*
rsize
)
unsigned
int
*
rsize
)
{
{
unsigned
long
quirks
=
(
unsigned
long
)
hid_get_drvdata
(
hdev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hdev
);
if
((
quirks
&
LG_RDESC
)
&&
*
rsize
>=
90
&&
rdesc
[
83
]
==
0x26
&&
if
((
drv_data
->
quirks
&
LG_RDESC
)
&&
*
rsize
>=
90
&&
rdesc
[
83
]
==
0x26
&&
rdesc
[
84
]
==
0x8c
&&
rdesc
[
85
]
==
0x02
)
{
rdesc
[
84
]
==
0x8c
&&
rdesc
[
85
]
==
0x02
)
{
hid_info
(
hdev
,
hid_info
(
hdev
,
"fixing up Logitech keyboard report descriptor
\n
"
);
"fixing up Logitech keyboard report descriptor
\n
"
);
rdesc
[
84
]
=
rdesc
[
89
]
=
0x4d
;
rdesc
[
84
]
=
rdesc
[
89
]
=
0x4d
;
rdesc
[
85
]
=
rdesc
[
90
]
=
0x10
;
rdesc
[
85
]
=
rdesc
[
90
]
=
0x10
;
}
}
if
((
quirks
&
LG_RDESC_REL_ABS
)
&&
*
rsize
>=
50
&&
if
((
drv_data
->
quirks
&
LG_RDESC_REL_ABS
)
&&
*
rsize
>=
50
&&
rdesc
[
32
]
==
0x81
&&
rdesc
[
33
]
==
0x06
&&
rdesc
[
32
]
==
0x81
&&
rdesc
[
33
]
==
0x06
&&
rdesc
[
49
]
==
0x81
&&
rdesc
[
50
]
==
0x06
)
{
rdesc
[
49
]
==
0x81
&&
rdesc
[
50
]
==
0x06
)
{
hid_info
(
hdev
,
hid_info
(
hdev
,
"fixing up rel/abs in Logitech report descriptor
\n
"
);
"fixing up rel/abs in Logitech report descriptor
\n
"
);
rdesc
[
33
]
=
rdesc
[
50
]
=
0x02
;
rdesc
[
33
]
=
rdesc
[
50
]
=
0x02
;
}
}
if
((
quirks
&
LG_FF4
)
&&
*
rsize
>=
101
&&
if
((
drv_data
->
quirks
&
LG_FF4
)
&&
*
rsize
>=
101
&&
rdesc
[
41
]
==
0x95
&&
rdesc
[
42
]
==
0x0B
&&
rdesc
[
41
]
==
0x95
&&
rdesc
[
42
]
==
0x0B
&&
rdesc
[
47
]
==
0x05
&&
rdesc
[
48
]
==
0x09
)
{
rdesc
[
47
]
==
0x05
&&
rdesc
[
48
]
==
0x09
)
{
hid_info
(
hdev
,
"fixing up Logitech Speed Force Wireless button descriptor
\n
"
);
hid_info
(
hdev
,
"fixing up Logitech Speed Force Wireless button descriptor
\n
"
);
...
@@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0
,
0
,
0
,
0
,
0
,
183
,
184
,
185
,
186
,
187
,
0
,
0
,
0
,
0
,
0
,
183
,
184
,
185
,
186
,
187
,
188
,
189
,
190
,
191
,
192
,
193
,
194
,
0
,
0
,
0
188
,
189
,
190
,
191
,
192
,
193
,
194
,
0
,
0
,
0
};
};
unsigned
long
quirks
=
(
unsigned
long
)
hid_get_drvdata
(
hdev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hdev
);
unsigned
int
hid
=
usage
->
hid
;
unsigned
int
hid
=
usage
->
hid
;
if
(
hdev
->
product
==
USB_DEVICE_ID_LOGITECH_RECEIVER
&&
if
(
hdev
->
product
==
USB_DEVICE_ID_LOGITECH_RECEIVER
&&
...
@@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
lg_dinovo_mapping
(
hi
,
usage
,
bit
,
max
))
lg_dinovo_mapping
(
hi
,
usage
,
bit
,
max
))
return
1
;
return
1
;
if
((
quirks
&
LG_WIRELESS
)
&&
lg_wireless_mapping
(
hi
,
usage
,
bit
,
max
))
if
((
drv_data
->
quirks
&
LG_WIRELESS
)
&&
lg_wireless_mapping
(
hi
,
usage
,
bit
,
max
))
return
1
;
return
1
;
if
((
hid
&
HID_USAGE_PAGE
)
!=
HID_UP_BUTTON
)
if
((
hid
&
HID_USAGE_PAGE
)
!=
HID_UP_BUTTON
)
...
@@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* Special handling for Logitech Cordless Desktop */
/* Special handling for Logitech Cordless Desktop */
if
(
field
->
application
==
HID_GD_MOUSE
)
{
if
(
field
->
application
==
HID_GD_MOUSE
)
{
if
((
quirks
&
LG_IGNORE_DOUBLED_WHEEL
)
&&
if
((
drv_data
->
quirks
&
LG_IGNORE_DOUBLED_WHEEL
)
&&
(
hid
==
7
||
hid
==
8
))
(
hid
==
7
||
hid
==
8
))
return
-
1
;
return
-
1
;
}
else
{
}
else
{
if
((
quirks
&
LG_EXPANDED_KEYMAP
)
&&
if
((
drv_data
->
quirks
&
LG_EXPANDED_KEYMAP
)
&&
hid
<
ARRAY_SIZE
(
e_keymap
)
&&
hid
<
ARRAY_SIZE
(
e_keymap
)
&&
e_keymap
[
hid
]
!=
0
)
{
e_keymap
[
hid
]
!=
0
)
{
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
...
@@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
...
@@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
unsigned
long
**
bit
,
int
*
max
)
{
{
unsigned
long
quirks
=
(
unsigned
long
)
hid_get_drvdata
(
hdev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hdev
);
if
((
quirks
&
LG_BAD_RELATIVE_KEYS
)
&&
usage
->
type
==
EV_KEY
&&
if
((
drv_data
->
quirks
&
LG_BAD_RELATIVE_KEYS
)
&&
usage
->
type
==
EV_KEY
&&
(
field
->
flags
&
HID_MAIN_ITEM_RELATIVE
))
(
field
->
flags
&
HID_MAIN_ITEM_RELATIVE
))
field
->
flags
&=
~
HID_MAIN_ITEM_RELATIVE
;
field
->
flags
&=
~
HID_MAIN_ITEM_RELATIVE
;
if
((
quirks
&
LG_DUPLICATE_USAGES
)
&&
(
usage
->
type
==
EV_KEY
||
if
((
drv_data
->
quirks
&
LG_DUPLICATE_USAGES
)
&&
(
usage
->
type
==
EV_KEY
||
usage
->
type
==
EV_REL
||
usage
->
type
==
EV_ABS
))
usage
->
type
==
EV_REL
||
usage
->
type
==
EV_ABS
))
clear_bit
(
usage
->
code
,
*
bit
);
clear_bit
(
usage
->
code
,
*
bit
);
...
@@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
...
@@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static
int
lg_event
(
struct
hid_device
*
hdev
,
struct
hid_field
*
field
,
static
int
lg_event
(
struct
hid_device
*
hdev
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
__s32
value
)
struct
hid_usage
*
usage
,
__s32
value
)
{
{
unsigned
long
quirks
=
(
unsigned
long
)
hid_get_drvdata
(
hdev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hdev
);
if
((
quirks
&
LG_INVERT_HWHEEL
)
&&
usage
->
code
==
REL_HWHEEL
)
{
if
((
drv_data
->
quirks
&
LG_INVERT_HWHEEL
)
&&
usage
->
code
==
REL_HWHEEL
)
{
input_event
(
field
->
hidinput
->
input
,
usage
->
type
,
usage
->
code
,
input_event
(
field
->
hidinput
->
input
,
usage
->
type
,
usage
->
code
,
-
value
);
-
value
);
return
1
;
return
1
;
...
@@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
...
@@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
static
int
lg_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
static
int
lg_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
{
unsigned
long
quirks
=
id
->
driver_data
;
unsigned
int
connect_mask
=
HID_CONNECT_DEFAULT
;
unsigned
int
connect_mask
=
HID_CONNECT_DEFAULT
;
struct
lg_drv_data
*
drv_data
;
int
ret
;
int
ret
;
hid_set_drvdata
(
hdev
,
(
void
*
)
quirks
);
drv_data
=
kzalloc
(
sizeof
(
struct
lg_drv_data
),
GFP_KERNEL
);
if
(
!
drv_data
)
{
hid_err
(
hdev
,
"Insufficient memory, cannot allocate driver data
\n
"
);
return
-
ENOMEM
;
}
drv_data
->
quirks
=
id
->
driver_data
;
hid_set_drvdata
(
hdev
,
(
void
*
)
drv_data
);
if
(
quirks
&
LG_NOGET
)
if
(
drv_data
->
quirks
&
LG_NOGET
)
hdev
->
quirks
|=
HID_QUIRK_NOGET
;
hdev
->
quirks
|=
HID_QUIRK_NOGET
;
ret
=
hid_parse
(
hdev
);
ret
=
hid_parse
(
hdev
);
...
@@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto
err_free
;
goto
err_free
;
}
}
if
(
quirks
&
(
LG_FF
|
LG_FF2
|
LG_FF3
|
LG_FF4
))
if
(
drv_data
->
quirks
&
(
LG_FF
|
LG_FF2
|
LG_FF3
|
LG_FF4
))
connect_mask
&=
~
HID_CONNECT_FF
;
connect_mask
&=
~
HID_CONNECT_FF
;
ret
=
hid_hw_start
(
hdev
,
connect_mask
);
ret
=
hid_hw_start
(
hdev
,
connect_mask
);
...
@@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
}
}
if
(
quirks
&
LG_FF
)
if
(
drv_data
->
quirks
&
LG_FF
)
lgff_init
(
hdev
);
lgff_init
(
hdev
);
if
(
quirks
&
LG_FF2
)
if
(
drv_data
->
quirks
&
LG_FF2
)
lg2ff_init
(
hdev
);
lg2ff_init
(
hdev
);
if
(
quirks
&
LG_FF3
)
if
(
drv_data
->
quirks
&
LG_FF3
)
lg3ff_init
(
hdev
);
lg3ff_init
(
hdev
);
if
(
quirks
&
LG_FF4
)
if
(
drv_data
->
quirks
&
LG_FF4
)
lg4ff_init
(
hdev
);
lg4ff_init
(
hdev
);
return
0
;
return
0
;
err_free:
err_free:
kfree
(
drv_data
);
return
ret
;
return
ret
;
}
}
static
void
lg_remove
(
struct
hid_device
*
hdev
)
static
void
lg_remove
(
struct
hid_device
*
hdev
)
{
{
unsigned
long
quirks
=
(
unsigned
long
)
hid_get_drvdata
(
hdev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hdev
);
if
(
quirks
&
LG_FF4
)
if
(
drv_data
->
quirks
&
LG_FF4
)
lg4ff_deinit
(
hdev
);
lg4ff_deinit
(
hdev
);
hid_hw_stop
(
hdev
);
hid_hw_stop
(
hdev
);
kfree
(
drv_data
);
}
}
static
const
struct
hid_device_id
lg_devices
[]
=
{
static
const
struct
hid_device_id
lg_devices
[]
=
{
...
...
drivers/hid/hid-lg.h
View file @
b3d07e03
#ifndef __HID_LG_H
#ifndef __HID_LG_H
#define __HID_LG_H
#define __HID_LG_H
struct
lg_drv_data
{
unsigned
long
quirks
;
void
*
device_props
;
/* Device specific properties */
};
#ifdef CONFIG_LOGITECH_FF
#ifdef CONFIG_LOGITECH_FF
int
lgff_init
(
struct
hid_device
*
hdev
);
int
lgff_init
(
struct
hid_device
*
hdev
);
#else
#else
...
...
drivers/hid/hid-lg4ff.c
View file @
b3d07e03
/*
/*
* Force feedback support for Logitech
Speed Force Wireles
s
* Force feedback support for Logitech
Gaming Wheel
s
*
*
* http://wiibrew.org/wiki/Logitech_USB_steering_wheel
* Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
* Speed Force Wireless (WiiWheel)
*
*
* Copyright (c) 2010 Simon Wood <simon@mungewell.org>
* Copyright (c) 2010 Simon Wood <simon@mungewell.org>
*/
*/
...
@@ -51,20 +52,18 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
...
@@ -51,20 +52,18 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
static
DEVICE_ATTR
(
range
,
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
lg4ff_range_show
,
lg4ff_range_store
);
static
DEVICE_ATTR
(
range
,
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
lg4ff_range_show
,
lg4ff_range_store
);
static
bool
list_inited
;
struct
lg4ff_device_entry
{
struct
lg4ff_device_entry
{
char
*
device_id
;
/* Use name in respective kobject structure's address as the ID */
__u16
range
;
__u16
range
;
__u16
min_range
;
__u16
min_range
;
__u16
max_range
;
__u16
max_range
;
__u8
leds
;
#ifdef CONFIG_LEDS_CLASS
__u8
led_state
;
struct
led_classdev
*
led
[
5
];
#endif
struct
list_head
list
;
struct
list_head
list
;
void
(
*
set_range
)(
struct
hid_device
*
hid
,
u16
range
);
void
(
*
set_range
)(
struct
hid_device
*
hid
,
u16
range
);
};
};
static
struct
lg4ff_device_entry
device_list
;
static
const
signed
short
lg4ff_wheel_effects
[]
=
{
static
const
signed
short
lg4ff_wheel_effects
[]
=
{
FF_CONSTANT
,
FF_CONSTANT
,
FF_AUTOCENTER
,
FF_AUTOCENTER
,
...
@@ -285,18 +284,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
...
@@ -285,18 +284,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
/* Read current range and display it in terminal */
/* Read current range and display it in terminal */
static
ssize_t
lg4ff_range_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
static
ssize_t
lg4ff_range_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
struct
lg4ff_device_entry
*
uninitialized_var
(
entry
);
struct
list_head
*
h
;
struct
hid_device
*
hid
=
to_hid_device
(
dev
);
struct
hid_device
*
hid
=
to_hid_device
(
dev
);
struct
lg4ff_device_entry
*
entry
;
struct
lg_drv_data
*
drv_data
;
size_t
count
;
size_t
count
;
list_for_each
(
h
,
&
device_list
.
list
)
{
drv_data
=
hid_get_drvdata
(
hid
);
entry
=
list_entry
(
h
,
struct
lg4ff_device_entry
,
list
);
if
(
!
drv_data
)
{
if
(
strcmp
(
entry
->
device_id
,
(
&
hid
->
dev
)
->
kobj
.
name
)
==
0
)
hid_err
(
hid
,
"Private driver data not found!
\n
"
);
break
;
return
0
;
}
}
if
(
h
==
&
device_list
.
list
)
{
dbg_hid
(
"Device not found!"
);
entry
=
drv_data
->
device_props
;
if
(
!
entry
)
{
hid_err
(
hid
,
"Device properties not found!
\n
"
);
return
0
;
return
0
;
}
}
...
@@ -308,19 +309,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
...
@@ -308,19 +309,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
* according to the type of the wheel */
* according to the type of the wheel */
static
ssize_t
lg4ff_range_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
static
ssize_t
lg4ff_range_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
{
struct
lg4ff_device_entry
*
uninitialized_var
(
entry
);
struct
list_head
*
h
;
struct
hid_device
*
hid
=
to_hid_device
(
dev
);
struct
hid_device
*
hid
=
to_hid_device
(
dev
);
struct
lg4ff_device_entry
*
entry
;
struct
lg_drv_data
*
drv_data
;
__u16
range
=
simple_strtoul
(
buf
,
NULL
,
10
);
__u16
range
=
simple_strtoul
(
buf
,
NULL
,
10
);
list_for_each
(
h
,
&
device_list
.
list
)
{
drv_data
=
hid_get_drvdata
(
hid
);
entry
=
list_entry
(
h
,
struct
lg4ff_device_entry
,
list
);
if
(
!
drv_data
)
{
if
(
strcmp
(
entry
->
device_id
,
(
&
hid
->
dev
)
->
kobj
.
name
)
==
0
)
hid_err
(
hid
,
"Private driver data not found!
\n
"
);
break
;
return
0
;
}
}
if
(
h
==
&
device_list
.
list
)
{
dbg_hid
(
"Device not found!"
);
entry
=
drv_data
->
device_props
;
return
count
;
if
(
!
entry
)
{
hid_err
(
hid
,
"Device properties not found!
\n
"
);
return
0
;
}
}
if
(
range
==
0
)
if
(
range
==
0
)
...
@@ -336,6 +339,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
...
@@ -336,6 +339,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
return
count
;
return
count
;
}
}
#ifdef CONFIG_LEDS_CLASS
static
void
lg4ff_set_leds
(
struct
hid_device
*
hid
,
__u8
leds
)
{
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
);
report
->
field
[
0
]
->
value
[
0
]
=
0xf8
;
report
->
field
[
0
]
->
value
[
1
]
=
0x12
;
report
->
field
[
0
]
->
value
[
2
]
=
leds
;
report
->
field
[
0
]
->
value
[
3
]
=
0x00
;
report
->
field
[
0
]
->
value
[
4
]
=
0x00
;
report
->
field
[
0
]
->
value
[
5
]
=
0x00
;
report
->
field
[
0
]
->
value
[
6
]
=
0x00
;
usbhid_submit_report
(
hid
,
report
,
USB_DIR_OUT
);
}
static
void
lg4ff_led_set_brightness
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
{
struct
device
*
dev
=
led_cdev
->
dev
->
parent
;
struct
hid_device
*
hid
=
container_of
(
dev
,
struct
hid_device
,
dev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hid
);
struct
lg4ff_device_entry
*
entry
;
int
i
,
state
=
0
;
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Device data not found."
);
return
;
}
entry
=
(
struct
lg4ff_device_entry
*
)
drv_data
->
device_props
;
if
(
!
entry
)
{
hid_err
(
hid
,
"Device properties not found."
);
return
;
}
for
(
i
=
0
;
i
<
5
;
i
++
)
{
if
(
led_cdev
!=
entry
->
led
[
i
])
continue
;
state
=
(
entry
->
led_state
>>
i
)
&
1
;
if
(
value
==
LED_OFF
&&
state
)
{
entry
->
led_state
&=
~
(
1
<<
i
);
lg4ff_set_leds
(
hid
,
entry
->
led_state
);
}
else
if
(
value
!=
LED_OFF
&&
!
state
)
{
entry
->
led_state
|=
1
<<
i
;
lg4ff_set_leds
(
hid
,
entry
->
led_state
);
}
break
;
}
}
static
enum
led_brightness
lg4ff_led_get_brightness
(
struct
led_classdev
*
led_cdev
)
{
struct
device
*
dev
=
led_cdev
->
dev
->
parent
;
struct
hid_device
*
hid
=
container_of
(
dev
,
struct
hid_device
,
dev
);
struct
lg_drv_data
*
drv_data
=
(
struct
lg_drv_data
*
)
hid_get_drvdata
(
hid
);
struct
lg4ff_device_entry
*
entry
;
int
i
,
value
=
0
;
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Device data not found."
);
return
LED_OFF
;
}
entry
=
(
struct
lg4ff_device_entry
*
)
drv_data
->
device_props
;
if
(
!
entry
)
{
hid_err
(
hid
,
"Device properties not found."
);
return
LED_OFF
;
}
for
(
i
=
0
;
i
<
5
;
i
++
)
if
(
led_cdev
==
entry
->
led
[
i
])
{
value
=
(
entry
->
led_state
>>
i
)
&
1
;
break
;
}
return
value
?
LED_FULL
:
LED_OFF
;
}
#endif
int
lg4ff_init
(
struct
hid_device
*
hid
)
int
lg4ff_init
(
struct
hid_device
*
hid
)
{
{
struct
hid_input
*
hidinput
=
list_entry
(
hid
->
inputs
.
next
,
struct
hid_input
,
list
);
struct
hid_input
*
hidinput
=
list_entry
(
hid
->
inputs
.
next
,
struct
hid_input
,
list
);
...
@@ -344,6 +429,7 @@ int lg4ff_init(struct hid_device *hid)
...
@@ -344,6 +429,7 @@ int lg4ff_init(struct hid_device *hid)
struct
hid_report
*
report
;
struct
hid_report
*
report
;
struct
hid_field
*
field
;
struct
hid_field
*
field
;
struct
lg4ff_device_entry
*
entry
;
struct
lg4ff_device_entry
*
entry
;
struct
lg_drv_data
*
drv_data
;
struct
usb_device_descriptor
*
udesc
;
struct
usb_device_descriptor
*
udesc
;
int
error
,
i
,
j
;
int
error
,
i
,
j
;
__u16
bcdDevice
,
rev_maj
,
rev_min
;
__u16
bcdDevice
,
rev_maj
,
rev_min
;
...
@@ -423,28 +509,24 @@ int lg4ff_init(struct hid_device *hid)
...
@@ -423,28 +509,24 @@ int lg4ff_init(struct hid_device *hid)
dev
->
ff
->
set_autocenter
(
dev
,
0
);
dev
->
ff
->
set_autocenter
(
dev
,
0
);
}
}
/* Initialize device_list if this is the first device to handle by lg4ff */
/* Get private driver data */
if
(
!
list_inited
)
{
drv_data
=
hid_get_drvdata
(
hid
);
INIT_LIST_HEAD
(
&
device_list
.
list
);
if
(
!
drv_data
)
{
list_inited
=
1
;
hid_err
(
hid
,
"Cannot add device, private driver data not allocated
\n
"
);
return
-
1
;
}
}
/*
Add the device to device_list
*/
/*
Initialize device properties
*/
entry
=
kzalloc
(
sizeof
(
struct
lg4ff_device_entry
),
GFP_KERNEL
);
entry
=
kzalloc
(
sizeof
(
struct
lg4ff_device_entry
),
GFP_KERNEL
);
if
(
!
entry
)
{
if
(
!
entry
)
{
hid_err
(
hid
,
"Cannot add device, insufficient memory.
\n
"
);
hid_err
(
hid
,
"Cannot add device, insufficient memory to allocate device properties.
\n
"
);
return
-
ENOMEM
;
}
entry
->
device_id
=
kstrdup
((
&
hid
->
dev
)
->
kobj
.
name
,
GFP_KERNEL
);
if
(
!
entry
->
device_id
)
{
hid_err
(
hid
,
"Cannot set device_id, insufficient memory.
\n
"
);
kfree
(
entry
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
drv_data
->
device_props
=
entry
;
entry
->
min_range
=
lg4ff_devices
[
i
].
min_range
;
entry
->
min_range
=
lg4ff_devices
[
i
].
min_range
;
entry
->
max_range
=
lg4ff_devices
[
i
].
max_range
;
entry
->
max_range
=
lg4ff_devices
[
i
].
max_range
;
entry
->
set_range
=
lg4ff_devices
[
i
].
set_range
;
entry
->
set_range
=
lg4ff_devices
[
i
].
set_range
;
list_add
(
&
entry
->
list
,
&
device_list
.
list
);
/* Create sysfs interface */
/* Create sysfs interface */
error
=
device_create_file
(
&
hid
->
dev
,
&
dev_attr_range
);
error
=
device_create_file
(
&
hid
->
dev
,
&
dev_attr_range
);
...
@@ -457,32 +539,100 @@ int lg4ff_init(struct hid_device *hid)
...
@@ -457,32 +539,100 @@ int lg4ff_init(struct hid_device *hid)
if
(
entry
->
set_range
!=
NULL
)
if
(
entry
->
set_range
!=
NULL
)
entry
->
set_range
(
hid
,
entry
->
range
);
entry
->
set_range
(
hid
,
entry
->
range
);
hid_info
(
hid
,
"Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>
\n
"
);
#ifdef CONFIG_LEDS_CLASS
/* register led subsystem - G27 only */
entry
->
led_state
=
0
;
for
(
j
=
0
;
j
<
5
;
j
++
)
entry
->
led
[
j
]
=
NULL
;
if
(
lg4ff_devices
[
i
].
product_id
==
USB_DEVICE_ID_LOGITECH_G27_WHEEL
)
{
struct
led_classdev
*
led
;
size_t
name_sz
;
char
*
name
;
lg4ff_set_leds
(
hid
,
0
);
name_sz
=
strlen
(
dev_name
(
&
hid
->
dev
))
+
8
;
for
(
j
=
0
;
j
<
5
;
j
++
)
{
led
=
kzalloc
(
sizeof
(
struct
led_classdev
)
+
name_sz
,
GFP_KERNEL
);
if
(
!
led
)
{
hid_err
(
hid
,
"can't allocate memory for LED %d
\n
"
,
j
);
goto
err
;
}
name
=
(
void
*
)(
&
led
[
1
]);
snprintf
(
name
,
name_sz
,
"%s::RPM%d"
,
dev_name
(
&
hid
->
dev
),
j
+
1
);
led
->
name
=
name
;
led
->
brightness
=
0
;
led
->
max_brightness
=
1
;
led
->
brightness_get
=
lg4ff_led_get_brightness
;
led
->
brightness_set
=
lg4ff_led_set_brightness
;
entry
->
led
[
j
]
=
led
;
error
=
led_classdev_register
(
&
hid
->
dev
,
led
);
if
(
error
)
{
hid_err
(
hid
,
"failed to register LED %d. Aborting.
\n
"
,
j
);
err:
/* Deregister LEDs (if any) */
for
(
j
=
0
;
j
<
5
;
j
++
)
{
led
=
entry
->
led
[
j
];
entry
->
led
[
j
]
=
NULL
;
if
(
!
led
)
continue
;
led_classdev_unregister
(
led
);
kfree
(
led
);
}
goto
out
;
/* Let the driver continue without LEDs */
}
}
}
out:
#endif
hid_info
(
hid
,
"Force feedback support for Logitech Gaming Wheels
\n
"
);
return
0
;
return
0
;
}
}
int
lg4ff_deinit
(
struct
hid_device
*
hid
)
int
lg4ff_deinit
(
struct
hid_device
*
hid
)
{
{
bool
found
=
0
;
struct
lg4ff_device_entry
*
entry
;
struct
lg4ff_device_entry
*
entry
;
struct
list_head
*
h
,
*
g
;
struct
lg_drv_data
*
drv_data
;
list_for_each_safe
(
h
,
g
,
&
device_list
.
list
)
{
entry
=
list_entry
(
h
,
struct
lg4ff_device_entry
,
list
);
device_remove_file
(
&
hid
->
dev
,
&
dev_attr_range
);
if
(
strcmp
(
entry
->
device_id
,
(
&
hid
->
dev
)
->
kobj
.
name
)
==
0
)
{
list_del
(
h
);
kfree
(
entry
->
device_id
);
kfree
(
entry
);
found
=
1
;
break
;
}
}
if
(
!
found
)
{
drv_data
=
hid_get_drvdata
(
hid
);
dbg_hid
(
"Device entry not found!
\n
"
);
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Error while deinitializing device, no private driver data.
\n
"
);
return
-
1
;
}
entry
=
drv_data
->
device_props
;
if
(
!
entry
)
{
hid_err
(
hid
,
"Error while deinitializing device, no device properties data.
\n
"
);
return
-
1
;
return
-
1
;
}
}
device_remove_file
(
&
hid
->
dev
,
&
dev_attr_range
);
#ifdef CONFIG_LEDS_CLASS
{
int
j
;
struct
led_classdev
*
led
;
/* Deregister LEDs (if any) */
for
(
j
=
0
;
j
<
5
;
j
++
)
{
led
=
entry
->
led
[
j
];
entry
->
led
[
j
]
=
NULL
;
if
(
!
led
)
continue
;
led_classdev_unregister
(
led
);
kfree
(
led
);
}
}
#endif
/* Deallocate memory */
kfree
(
entry
);
dbg_hid
(
"Device successfully unregistered
\n
"
);
dbg_hid
(
"Device successfully unregistered
\n
"
);
return
0
;
return
0
;
}
}
drivers/hid/hid-multitouch.c
View file @
b3d07e03
...
@@ -70,9 +70,16 @@ struct mt_class {
...
@@ -70,9 +70,16 @@ struct mt_class {
bool
is_indirect
;
/* true for touchpads */
bool
is_indirect
;
/* true for touchpads */
};
};
struct
mt_fields
{
unsigned
usages
[
HID_MAX_FIELDS
];
unsigned
int
length
;
};
struct
mt_device
{
struct
mt_device
{
struct
mt_slot
curdata
;
/* placeholder of incoming data */
struct
mt_slot
curdata
;
/* placeholder of incoming data */
struct
mt_class
mtclass
;
/* our mt device class */
struct
mt_class
mtclass
;
/* our mt device class */
struct
mt_fields
*
fields
;
/* temporary placeholder for storing the
multitouch fields */
unsigned
last_field_index
;
/* last field index of the report */
unsigned
last_field_index
;
/* last field index of the report */
unsigned
last_slot_field
;
/* the last field of a slot */
unsigned
last_slot_field
;
/* the last field of a slot */
__s8
inputmode
;
/* InputMode HID feature, -1 if non-existent */
__s8
inputmode
;
/* InputMode HID feature, -1 if non-existent */
...
@@ -278,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,
...
@@ -278,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_set_abs_params
(
input
,
code
,
fmin
,
fmax
,
fuzz
,
0
);
input_set_abs_params
(
input
,
code
,
fmin
,
fmax
,
fuzz
,
0
);
}
}
static
void
set_last_slot
_field
(
struct
hid_usage
*
usage
,
struct
mt_device
*
td
,
static
void
mt_store
_field
(
struct
hid_usage
*
usage
,
struct
mt_device
*
td
,
struct
hid_input
*
hi
)
struct
hid_input
*
hi
)
{
{
if
(
!
test_bit
(
usage
->
hid
,
hi
->
input
->
absbit
))
struct
mt_fields
*
f
=
td
->
fields
;
td
->
last_slot_field
=
usage
->
hid
;
if
(
f
->
length
>=
HID_MAX_FIELDS
)
return
;
f
->
usages
[
f
->
length
++
]
=
usage
->
hid
;
}
}
static
int
mt_input_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
static
int
mt_input_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
...
@@ -333,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -333,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls
->
sn_move
);
cls
->
sn_move
);
/* touchscreen emulation */
/* touchscreen emulation */
set_abs
(
hi
->
input
,
ABS_X
,
field
,
cls
->
sn_move
);
set_abs
(
hi
->
input
,
ABS_X
,
field
,
cls
->
sn_move
);
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_GD_Y
:
case
HID_GD_Y
:
...
@@ -343,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -343,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls
->
sn_move
);
cls
->
sn_move
);
/* touchscreen emulation */
/* touchscreen emulation */
set_abs
(
hi
->
input
,
ABS_Y
,
field
,
cls
->
sn_move
);
set_abs
(
hi
->
input
,
ABS_Y
,
field
,
cls
->
sn_move
);
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
}
}
...
@@ -352,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -352,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case
HID_UP_DIGITIZER
:
case
HID_UP_DIGITIZER
:
switch
(
usage
->
hid
)
{
switch
(
usage
->
hid
)
{
case
HID_DG_INRANGE
:
case
HID_DG_INRANGE
:
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_DG_CONFIDENCE
:
case
HID_DG_CONFIDENCE
:
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_DG_TIPSWITCH
:
case
HID_DG_TIPSWITCH
:
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
BTN_TOUCH
);
hid_map_usage
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
BTN_TOUCH
);
input_set_capability
(
hi
->
input
,
EV_KEY
,
BTN_TOUCH
);
input_set_capability
(
hi
->
input
,
EV_KEY
,
BTN_TOUCH
);
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_DG_CONTACTID
:
case
HID_DG_CONTACTID
:
if
(
!
td
->
maxcontacts
)
if
(
!
td
->
maxcontacts
)
td
->
maxcontacts
=
MT_DEFAULT_MAXCONTACT
;
td
->
maxcontacts
=
MT_DEFAULT_MAXCONTACT
;
input_mt_init_slots
(
hi
->
input
,
td
->
maxcontacts
);
input_mt_init_slots
(
hi
->
input
,
td
->
maxcontacts
);
td
->
last_slot_field
=
usage
->
hid
;
mt_store_field
(
usage
,
td
,
hi
)
;
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
td
->
touches_by_report
++
;
td
->
touches_by_report
++
;
return
1
;
return
1
;
...
@@ -378,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -378,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS
,
ABS_MT_TOUCH_MAJOR
);
EV_ABS
,
ABS_MT_TOUCH_MAJOR
);
set_abs
(
hi
->
input
,
ABS_MT_TOUCH_MAJOR
,
field
,
set_abs
(
hi
->
input
,
ABS_MT_TOUCH_MAJOR
,
field
,
cls
->
sn_width
);
cls
->
sn_width
);
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_DG_HEIGHT
:
case
HID_DG_HEIGHT
:
...
@@ -388,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -388,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls
->
sn_height
);
cls
->
sn_height
);
input_set_abs_params
(
hi
->
input
,
input_set_abs_params
(
hi
->
input
,
ABS_MT_ORIENTATION
,
0
,
1
,
0
,
0
);
ABS_MT_ORIENTATION
,
0
,
1
,
0
,
0
);
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_DG_TIPPRESSURE
:
case
HID_DG_TIPPRESSURE
:
...
@@ -399,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...
@@ -399,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */
/* touchscreen emulation */
set_abs
(
hi
->
input
,
ABS_PRESSURE
,
field
,
set_abs
(
hi
->
input
,
ABS_PRESSURE
,
field
,
cls
->
sn_pressure
);
cls
->
sn_pressure
);
set_last_slot
_field
(
usage
,
td
,
hi
);
mt_store
_field
(
usage
,
td
,
hi
);
td
->
last_field_index
=
field
->
index
;
td
->
last_field_index
=
field
->
index
;
return
1
;
return
1
;
case
HID_DG_CONTACTCOUNT
:
case
HID_DG_CONTACTCOUNT
:
...
@@ -653,6 +664,16 @@ static void mt_post_parse_default_settings(struct mt_device *td)
...
@@ -653,6 +664,16 @@ static void mt_post_parse_default_settings(struct mt_device *td)
td
->
mtclass
.
quirks
=
quirks
;
td
->
mtclass
.
quirks
=
quirks
;
}
}
static
void
mt_post_parse
(
struct
mt_device
*
td
)
{
struct
mt_fields
*
f
=
td
->
fields
;
if
(
td
->
touches_by_report
>
0
)
{
int
field_count_per_touch
=
f
->
length
/
td
->
touches_by_report
;
td
->
last_slot_field
=
f
->
usages
[
field_count_per_touch
-
1
];
}
}
static
int
mt_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
static
int
mt_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
{
int
ret
,
i
;
int
ret
,
i
;
...
@@ -683,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -683,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td
->
maxcontact_report_id
=
-
1
;
td
->
maxcontact_report_id
=
-
1
;
hid_set_drvdata
(
hdev
,
td
);
hid_set_drvdata
(
hdev
,
td
);
td
->
fields
=
kzalloc
(
sizeof
(
struct
mt_fields
),
GFP_KERNEL
);
if
(
!
td
->
fields
)
{
dev_err
(
&
hdev
->
dev
,
"cannot allocate multitouch fields data
\n
"
);
ret
=
-
ENOMEM
;
goto
fail
;
}
ret
=
hid_parse
(
hdev
);
ret
=
hid_parse
(
hdev
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
goto
fail
;
goto
fail
;
...
@@ -691,6 +719,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -691,6 +719,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if
(
ret
)
if
(
ret
)
goto
fail
;
goto
fail
;
mt_post_parse
(
td
);
if
(
id
->
vendor
==
HID_ANY_ID
&&
id
->
product
==
HID_ANY_ID
)
if
(
id
->
vendor
==
HID_ANY_ID
&&
id
->
product
==
HID_ANY_ID
)
mt_post_parse_default_settings
(
td
);
mt_post_parse_default_settings
(
td
);
...
@@ -708,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -708,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
mt_set_maxcontacts
(
hdev
);
mt_set_maxcontacts
(
hdev
);
mt_set_input_mode
(
hdev
);
mt_set_input_mode
(
hdev
);
kfree
(
td
->
fields
);
td
->
fields
=
NULL
;
return
0
;
return
0
;
fail:
fail:
kfree
(
td
->
fields
);
kfree
(
td
);
kfree
(
td
);
return
ret
;
return
ret
;
}
}
...
...
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