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
ba521f1b
Commit
ba521f1b
authored
Mar 17, 2018
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'psmouse' into next
Merge various PS/2 handling improvements.
parents
83fc580d
3aceaa34
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
521 additions
and
396 deletions
+521
-396
drivers/input/mouse/alps.c
drivers/input/mouse/alps.c
+7
-23
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.c
+16
-24
drivers/input/mouse/lifebook.c
drivers/input/mouse/lifebook.c
+33
-29
drivers/input/mouse/logips2pp.c
drivers/input/mouse/logips2pp.c
+87
-65
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse-base.c
+103
-86
drivers/input/mouse/psmouse.h
drivers/input/mouse/psmouse.h
+4
-1
drivers/input/mouse/sentelic.c
drivers/input/mouse/sentelic.c
+1
-10
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.c
+4
-4
drivers/input/mouse/trackpoint.c
drivers/input/mouse/trackpoint.c
+24
-36
drivers/input/serio/libps2.c
drivers/input/serio/libps2.c
+219
-103
include/linux/libps2.h
include/linux/libps2.h
+23
-15
No files found.
drivers/input/mouse/alps.c
View file @
ba521f1b
...
...
@@ -827,7 +827,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
unsigned
char
*
packet
=
psmouse
->
packet
;
struct
input_dev
*
dev
=
psmouse
->
dev
;
struct
input_dev
*
dev2
=
priv
->
dev2
;
int
x
,
y
,
z
,
left
,
right
,
middle
;
int
x
,
y
,
z
;
/*
* We can use Byte5 to distinguish if the packet is from Touchpad
...
...
@@ -847,9 +847,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
x
=
packet
[
1
]
|
((
packet
[
3
]
&
0x20
)
<<
2
);
y
=
packet
[
2
]
|
((
packet
[
3
]
&
0x40
)
<<
1
);
z
=
packet
[
4
];
left
=
packet
[
3
]
&
0x01
;
right
=
packet
[
3
]
&
0x02
;
middle
=
packet
[
3
]
&
0x04
;
/* To prevent the cursor jump when finger lifted */
if
(
x
==
0x7F
&&
y
==
0x7F
&&
z
==
0x7F
)
...
...
@@ -859,9 +856,7 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
input_report_rel
(
dev2
,
REL_X
,
(
char
)
x
/
4
);
input_report_rel
(
dev2
,
REL_Y
,
-
((
char
)
y
/
4
));
input_report_key
(
dev2
,
BTN_LEFT
,
left
);
input_report_key
(
dev2
,
BTN_RIGHT
,
right
);
input_report_key
(
dev2
,
BTN_MIDDLE
,
middle
);
psmouse_report_standard_buttons
(
dev2
,
packet
[
3
]);
input_sync
(
dev2
);
return
;
...
...
@@ -871,8 +866,6 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
x
=
packet
[
1
]
|
((
packet
[
3
]
&
0x78
)
<<
4
);
y
=
packet
[
2
]
|
((
packet
[
4
]
&
0x78
)
<<
4
);
z
=
packet
[
5
];
left
=
packet
[
3
]
&
0x01
;
right
=
packet
[
3
]
&
0x02
;
if
(
z
>
30
)
input_report_key
(
dev
,
BTN_TOUCH
,
1
);
...
...
@@ -888,8 +881,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
input_report_key
(
dev
,
BTN_TOOL_FINGER
,
z
>
0
);
/* v6 touchpad does not have middle button */
input_report_key
(
dev
,
BTN_LEFT
,
left
);
input_report_key
(
dev
,
BTN_RIGHT
,
right
);
packet
[
3
]
&=
~
BIT
(
2
);
psmouse_report_standard_buttons
(
dev2
,
packet
[
3
]
);
input_sync
(
dev
);
}
...
...
@@ -1098,7 +1091,7 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
struct
alps_data
*
priv
=
psmouse
->
private
;
unsigned
char
*
packet
=
psmouse
->
packet
;
struct
input_dev
*
dev2
=
priv
->
dev2
;
int
x
,
y
,
z
,
left
,
right
,
middle
;
int
x
,
y
,
z
;
/* It should be a DualPoint when received trackstick packet */
if
(
!
(
priv
->
flags
&
ALPS_DUALPOINT
))
{
...
...
@@ -1112,16 +1105,10 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
((
packet
[
3
]
&
0x20
)
<<
1
);
z
=
(
packet
[
5
]
&
0x3f
)
|
((
packet
[
3
]
&
0x80
)
>>
1
);
left
=
(
packet
[
1
]
&
0x01
);
right
=
(
packet
[
1
]
&
0x02
)
>>
1
;
middle
=
(
packet
[
1
]
&
0x04
)
>>
2
;
input_report_rel
(
dev2
,
REL_X
,
(
char
)
x
);
input_report_rel
(
dev2
,
REL_Y
,
-
((
char
)
y
));
input_report_key
(
dev2
,
BTN_LEFT
,
left
);
input_report_key
(
dev2
,
BTN_RIGHT
,
right
);
input_report_key
(
dev2
,
BTN_MIDDLE
,
middle
);
psmouse_report_standard_buttons
(
dev2
,
packet
[
1
]);
input_sync
(
dev2
);
}
...
...
@@ -1503,10 +1490,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
alps_report_buttons
(
dev
,
dev2
,
packet
[
0
]
&
1
,
packet
[
0
]
&
2
,
packet
[
0
]
&
4
);
input_report_rel
(
dev
,
REL_X
,
packet
[
1
]
?
packet
[
1
]
-
((
packet
[
0
]
<<
4
)
&
0x100
)
:
0
);
input_report_rel
(
dev
,
REL_Y
,
packet
[
2
]
?
((
packet
[
0
]
<<
3
)
&
0x100
)
-
packet
[
2
]
:
0
);
psmouse_report_standard_motion
(
dev
,
packet
);
input_sync
(
dev
);
}
...
...
drivers/input/mouse/elantech.c
View file @
ba521f1b
...
...
@@ -35,7 +35,7 @@
static
int
synaptics_send_cmd
(
struct
psmouse
*
psmouse
,
unsigned
char
c
,
unsigned
char
*
param
)
{
if
(
ps
mouse_sliced_command
(
psmouse
,
c
)
||
if
(
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
c
)
||
ps2_command
(
&
psmouse
->
ps2dev
,
param
,
PSMOUSE_CMD_GETINFO
))
{
psmouse_err
(
psmouse
,
"%s query 0x%02x failed.
\n
"
,
__func__
,
c
);
return
-
1
;
...
...
@@ -107,8 +107,8 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
switch
(
etd
->
hw_version
)
{
case
1
:
if
(
ps
mouse_sliced_command
(
psmouse
,
ETP_REGISTER_READ
)
||
ps
mouse_sliced_command
(
psmouse
,
reg
)
||
if
(
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
ETP_REGISTER_READ
)
||
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
reg
)
||
ps2_command
(
&
psmouse
->
ps2dev
,
param
,
PSMOUSE_CMD_GETINFO
))
{
rc
=
-
1
;
}
...
...
@@ -162,9 +162,9 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
switch
(
etd
->
hw_version
)
{
case
1
:
if
(
ps
mouse_sliced_command
(
psmouse
,
ETP_REGISTER_WRITE
)
||
ps
mouse_sliced_command
(
psmouse
,
reg
)
||
ps
mouse_sliced_command
(
psmouse
,
val
)
||
if
(
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
ETP_REGISTER_WRITE
)
||
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
reg
)
||
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
val
)
||
ps2_command
(
&
psmouse
->
ps2dev
,
NULL
,
PSMOUSE_CMD_SETSCALE11
))
{
rc
=
-
1
;
}
...
...
@@ -279,8 +279,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
input_report_key
(
dev
,
BTN_TOOL_FINGER
,
fingers
==
1
);
input_report_key
(
dev
,
BTN_TOOL_DOUBLETAP
,
fingers
==
2
);
input_report_key
(
dev
,
BTN_TOOL_TRIPLETAP
,
fingers
==
3
);
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
0x01
);
input_report_key
(
dev
,
BTN_RIGHT
,
packet
[
0
]
&
0x02
);
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]
);
if
(
etd
->
fw_version
<
0x020000
&&
(
etd
->
capabilities
[
0
]
&
ETP_CAP_HAS_ROCKER
))
{
...
...
@@ -390,8 +390,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
input_report_key
(
dev
,
BTN_TOOL_DOUBLETAP
,
fingers
==
2
);
input_report_key
(
dev
,
BTN_TOOL_TRIPLETAP
,
fingers
==
3
);
input_report_key
(
dev
,
BTN_TOOL_QUADTAP
,
fingers
==
4
);
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
0x01
);
input_report_key
(
dev
,
BTN_RIGHT
,
packet
[
0
]
&
0x02
);
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]);
if
(
etd
->
reports_pressure
)
{
input_report_abs
(
dev
,
ABS_PRESSURE
,
pres
);
input_report_abs
(
dev
,
ABS_TOOL_WIDTH
,
width
);
...
...
@@ -434,9 +433,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
x
=
packet
[
4
]
-
(
int
)((
packet
[
1
]
^
0x80
)
<<
1
);
y
=
(
int
)((
packet
[
2
]
^
0x80
)
<<
1
)
-
packet
[
5
];
input_report_key
(
tp_dev
,
BTN_LEFT
,
packet
[
0
]
&
0x01
);
input_report_key
(
tp_dev
,
BTN_RIGHT
,
packet
[
0
]
&
0x02
);
input_report_key
(
tp_dev
,
BTN_MIDDLE
,
packet
[
0
]
&
0x04
);
psmouse_report_standard_buttons
(
tp_dev
,
packet
[
0
]);
input_report_rel
(
tp_dev
,
REL_X
,
x
);
input_report_rel
(
tp_dev
,
REL_Y
,
y
);
...
...
@@ -526,12 +523,10 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
input_report_key
(
dev
,
BTN_TOOL_TRIPLETAP
,
fingers
==
3
);
/* For clickpads map both buttons to BTN_LEFT */
if
(
etd
->
fw_version
&
0x001000
)
{
if
(
etd
->
fw_version
&
0x001000
)
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
0x03
);
}
else
{
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
0x01
);
input_report_key
(
dev
,
BTN_RIGHT
,
packet
[
0
]
&
0x02
);
}
else
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]);
input_report_abs
(
dev
,
ABS_PRESSURE
,
pres
);
input_report_abs
(
dev
,
ABS_TOOL_WIDTH
,
width
);
...
...
@@ -546,13 +541,10 @@ static void elantech_input_sync_v4(struct psmouse *psmouse)
unsigned
char
*
packet
=
psmouse
->
packet
;
/* For clickpads map both buttons to BTN_LEFT */
if
(
etd
->
fw_version
&
0x001000
)
{
if
(
etd
->
fw_version
&
0x001000
)
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
0x03
);
}
else
{
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
0x01
);
input_report_key
(
dev
,
BTN_RIGHT
,
packet
[
0
]
&
0x02
);
input_report_key
(
dev
,
BTN_MIDDLE
,
packet
[
0
]
&
0x04
);
}
else
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]);
input_mt_report_pointer_emulation
(
dev
,
true
);
input_sync
(
dev
);
...
...
drivers/input/mouse/lifebook.c
View file @
ba521f1b
...
...
@@ -17,6 +17,7 @@
#include <linux/libps2.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "psmouse.h"
#include "lifebook.h"
...
...
@@ -136,7 +137,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
struct
lifebook_data
*
priv
=
psmouse
->
private
;
struct
input_dev
*
dev1
=
psmouse
->
dev
;
struct
input_dev
*
dev2
=
priv
?
priv
->
dev2
:
NULL
;
u
nsigned
char
*
packet
=
psmouse
->
packet
;
u
8
*
packet
=
psmouse
->
packet
;
bool
relative_packet
=
packet
[
0
]
&
0x08
;
if
(
relative_packet
||
!
lifebook_use_6byte_proto
)
{
...
...
@@ -188,14 +189,10 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
}
if
(
dev2
)
{
if
(
relative_packet
)
{
input_report_rel
(
dev2
,
REL_X
,
((
packet
[
0
]
&
0x10
)
?
packet
[
1
]
-
256
:
packet
[
1
]));
input_report_rel
(
dev2
,
REL_Y
,
-
(
int
)((
packet
[
0
]
&
0x20
)
?
packet
[
2
]
-
256
:
packet
[
2
]));
}
input_report_key
(
dev2
,
BTN_LEFT
,
packet
[
0
]
&
0x01
);
input_report_key
(
dev2
,
BTN_RIGHT
,
packet
[
0
]
&
0x02
);
if
(
relative_packet
)
psmouse_report_standard_motion
(
dev2
,
packet
);
psmouse_report_standard_buttons
(
dev2
,
packet
[
0
]);
input_sync
(
dev2
);
}
...
...
@@ -205,10 +202,12 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
static
int
lifebook_absolute_mode
(
struct
psmouse
*
psmouse
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
unsigned
char
param
;
u8
param
;
int
error
;
if
(
psmouse_reset
(
psmouse
))
return
-
1
;
error
=
psmouse_reset
(
psmouse
);
if
(
error
)
return
error
;
/*
* Enable absolute output -- ps2_command fails always but if
...
...
@@ -224,15 +223,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
static
void
lifebook_relative_mode
(
struct
psmouse
*
psmouse
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
=
0x06
;
u
8
param
=
0x06
;
ps2_command
(
ps2dev
,
&
param
,
PSMOUSE_CMD_SETRES
);
}
static
void
lifebook_set_resolution
(
struct
psmouse
*
psmouse
,
unsigned
int
resolution
)
{
static
const
u
nsigned
char
params
[]
=
{
0
,
1
,
2
,
2
,
3
};
u
nsigned
char
p
;
static
const
u
8
params
[]
=
{
0
,
1
,
2
,
2
,
3
};
u
8
p
;
if
(
resolution
==
0
||
resolution
>
400
)
resolution
=
400
;
...
...
@@ -257,11 +256,11 @@ static void lifebook_disconnect(struct psmouse *psmouse)
int
lifebook_detect
(
struct
psmouse
*
psmouse
,
bool
set_properties
)
{
if
(
!
lifebook_present
)
return
-
1
;
return
-
ENXIO
;
if
(
desired_serio_phys
&&
strcmp
(
psmouse
->
ps2dev
.
serio
->
phys
,
desired_serio_phys
))
return
-
1
;
return
-
ENXIO
;
if
(
set_properties
)
{
psmouse
->
vendor
=
"Fujitsu"
;
...
...
@@ -294,10 +293,10 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
dev2
->
id
.
version
=
0x0000
;
dev2
->
dev
.
parent
=
&
psmouse
->
ps2dev
.
serio
->
dev
;
dev2
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_REL
);
dev2
->
relbit
[
BIT_WORD
(
REL_X
)]
=
BIT_MASK
(
REL_X
)
|
BIT_MASK
(
REL_Y
);
dev2
->
keybit
[
BIT_WORD
(
BTN_LEFT
)]
=
BIT_MASK
(
BTN_LEFT
)
|
BIT_MASK
(
BTN_RIGHT
);
input_set_capability
(
dev2
,
EV_REL
,
REL_X
);
input_set_capability
(
dev2
,
EV_REL
,
REL_Y
);
input_set_capability
(
dev2
,
EV_KEY
,
BTN_LEFT
);
input_set_capability
(
dev2
,
EV_KEY
,
BTN_RIGHT
);
error
=
input_register_device
(
priv
->
dev2
);
if
(
error
)
...
...
@@ -316,21 +315,26 @@ int lifebook_init(struct psmouse *psmouse)
{
struct
input_dev
*
dev1
=
psmouse
->
dev
;
int
max_coord
=
lifebook_use_6byte_proto
?
4096
:
1024
;
int
error
;
error
=
lifebook_absolute_mode
(
psmouse
);
if
(
error
)
return
error
;
if
(
lifebook_absolute_mode
(
psmouse
))
return
-
1
;
/* Clear default capabilities */
bitmap_zero
(
dev1
->
evbit
,
EV_CNT
);
bitmap_zero
(
dev1
->
relbit
,
REL_CNT
);
bitmap_zero
(
dev1
->
keybit
,
KEY_CNT
);
dev1
->
evbit
[
0
]
=
BIT_MASK
(
EV_ABS
)
|
BIT_MASK
(
EV_KEY
);
dev1
->
relbit
[
0
]
=
0
;
dev1
->
keybit
[
BIT_WORD
(
BTN_MOUSE
)]
=
0
;
dev1
->
keybit
[
BIT_WORD
(
BTN_TOUCH
)]
=
BIT_MASK
(
BTN_TOUCH
);
input_set_capability
(
dev1
,
EV_KEY
,
BTN_TOUCH
);
input_set_abs_params
(
dev1
,
ABS_X
,
0
,
max_coord
,
0
,
0
);
input_set_abs_params
(
dev1
,
ABS_Y
,
0
,
max_coord
,
0
,
0
);
if
(
!
desired_serio_phys
)
{
if
(
lifebook_create_relative_device
(
psmouse
))
{
error
=
lifebook_create_relative_device
(
psmouse
);
if
(
error
)
{
lifebook_relative_mode
(
psmouse
);
return
-
1
;
return
error
;
}
}
...
...
drivers/input/mouse/logips2pp.c
View file @
ba521f1b
...
...
@@ -9,9 +9,11 @@
* the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include <linux/types.h>
#include "psmouse.h"
#include "logips2pp.h"
...
...
@@ -22,12 +24,12 @@
#define PS2PP_KIND_TRACKMAN 4
/* Logitech mouse features */
#define PS2PP_WHEEL
0x01
#define PS2PP_HWHEEL
0x02
#define PS2PP_SIDE_BTN
0x04
#define PS2PP_EXTRA_BTN
0x08
#define PS2PP_TASK_BTN
0x10
#define PS2PP_NAV_BTN
0x20
#define PS2PP_WHEEL
BIT(0)
#define PS2PP_HWHEEL
BIT(1)
#define PS2PP_SIDE_BTN
BIT(2)
#define PS2PP_EXTRA_BTN
BIT(3)
#define PS2PP_TASK_BTN
BIT(4)
#define PS2PP_NAV_BTN
BIT(5)
struct
ps2pp_info
{
u8
model
;
...
...
@@ -42,7 +44,7 @@ struct ps2pp_info {
static
psmouse_ret_t
ps2pp_process_byte
(
struct
psmouse
*
psmouse
)
{
struct
input_dev
*
dev
=
psmouse
->
dev
;
u
nsigned
char
*
packet
=
psmouse
->
packet
;
u
8
*
packet
=
psmouse
->
packet
;
if
(
psmouse
->
pktcnt
<
3
)
return
PSMOUSE_GOOD_DATA
;
...
...
@@ -58,28 +60,30 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
case
0x0d
:
/* Mouse extra info */
input_report_rel
(
dev
,
packet
[
2
]
&
0x80
?
REL_HWHEEL
:
REL_WHEEL
,
(
int
)
(
packet
[
2
]
&
8
)
-
(
int
)
(
packet
[
2
]
&
7
));
input_report_key
(
dev
,
BTN_SIDE
,
(
packet
[
2
]
>>
4
)
&
1
);
input_report_key
(
dev
,
BTN_EXTRA
,
(
packet
[
2
]
>>
5
)
&
1
);
input_report_rel
(
dev
,
packet
[
2
]
&
0x80
?
REL_HWHEEL
:
REL_WHEEL
,
-
sign_extend32
(
packet
[
2
],
3
));
input_report_key
(
dev
,
BTN_SIDE
,
packet
[
2
]
&
BIT
(
4
));
input_report_key
(
dev
,
BTN_EXTRA
,
packet
[
2
]
&
BIT
(
5
));
break
;
case
0x0e
:
/* buttons 4, 5, 6, 7, 8, 9, 10 info */
input_report_key
(
dev
,
BTN_SIDE
,
(
packet
[
2
])
&
1
);
input_report_key
(
dev
,
BTN_EXTRA
,
(
packet
[
2
]
>>
1
)
&
1
);
input_report_key
(
dev
,
BTN_
BACK
,
(
packet
[
2
]
>>
3
)
&
1
);
input_report_key
(
dev
,
BTN_
FORWARD
,
(
packet
[
2
]
>>
4
)
&
1
);
input_report_key
(
dev
,
BTN_
TASK
,
(
packet
[
2
]
>>
2
)
&
1
);
input_report_key
(
dev
,
BTN_SIDE
,
packet
[
2
]
&
BIT
(
0
)
);
input_report_key
(
dev
,
BTN_EXTRA
,
packet
[
2
]
&
BIT
(
1
)
);
input_report_key
(
dev
,
BTN_
TASK
,
packet
[
2
]
&
BIT
(
2
)
);
input_report_key
(
dev
,
BTN_
BACK
,
packet
[
2
]
&
BIT
(
3
)
);
input_report_key
(
dev
,
BTN_
FORWARD
,
packet
[
2
]
&
BIT
(
4
)
);
break
;
case
0x0f
:
/* TouchPad extra info */
input_report_rel
(
dev
,
packet
[
2
]
&
0x08
?
REL_HWHEEL
:
REL_WHEEL
,
(
int
)
((
packet
[
2
]
>>
4
)
&
8
)
-
(
int
)
((
packet
[
2
]
>>
4
)
&
7
));
packet
[
0
]
=
packet
[
2
]
|
0x08
;
input_report_rel
(
dev
,
packet
[
2
]
&
0x08
?
REL_HWHEEL
:
REL_WHEEL
,
-
sign_extend32
(
packet
[
2
]
>>
4
,
3
));
packet
[
0
]
=
packet
[
2
]
|
BIT
(
3
);
break
;
default:
...
...
@@ -88,16 +92,14 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
(
packet
[
1
]
>>
4
)
|
(
packet
[
0
]
&
0x30
));
break
;
}
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]);
}
else
{
/* Standard PS/2 motion data */
input_report_rel
(
dev
,
REL_X
,
packet
[
1
]
?
(
int
)
packet
[
1
]
-
(
int
)
((
packet
[
0
]
<<
4
)
&
0x100
)
:
0
);
input_report_rel
(
dev
,
REL_Y
,
packet
[
2
]
?
(
int
)
((
packet
[
0
]
<<
3
)
&
0x100
)
-
(
int
)
packet
[
2
]
:
0
);
psmouse_report_standard_packet
(
dev
,
packet
);
}
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
1
);
input_report_key
(
dev
,
BTN_MIDDLE
,
(
packet
[
0
]
>>
2
)
&
1
);
input_report_key
(
dev
,
BTN_RIGHT
,
(
packet
[
0
]
>>
1
)
&
1
);
input_sync
(
dev
);
return
PSMOUSE_FULL_PACKET
;
...
...
@@ -111,13 +113,17 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
* Ugly.
*/
static
int
ps2pp_cmd
(
struct
psmouse
*
psmouse
,
u
nsigned
char
*
param
,
unsigned
char
command
)
static
int
ps2pp_cmd
(
struct
psmouse
*
psmouse
,
u
8
*
param
,
u8
command
)
{
if
(
psmouse_sliced_command
(
psmouse
,
command
))
return
-
1
;
int
error
;
if
(
ps2_command
(
&
psmouse
->
ps2dev
,
param
,
PSMOUSE_CMD_POLL
|
0x0300
))
return
-
1
;
error
=
ps2_sliced_command
(
&
psmouse
->
ps2dev
,
command
);
if
(
error
)
return
error
;
error
=
ps2_command
(
&
psmouse
->
ps2dev
,
param
,
PSMOUSE_CMD_POLL
|
0x0300
);
if
(
error
)
return
error
;
return
0
;
}
...
...
@@ -133,7 +139,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
static
void
ps2pp_set_smartscroll
(
struct
psmouse
*
psmouse
,
bool
smartscroll
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
[
4
];
u
8
param
[
4
];
ps2pp_cmd
(
psmouse
,
param
,
0x32
);
...
...
@@ -171,7 +177,7 @@ static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
}
PSMOUSE_DEFINE_ATTR
(
smartscroll
,
S_IWUSR
|
S_IRUGO
,
NULL
,
ps2pp_attr_show_smartscroll
,
ps2pp_attr_set_smartscroll
);
ps2pp_attr_show_smartscroll
,
ps2pp_attr_set_smartscroll
);
/*
* Support 800 dpi resolution _only_ if the user wants it (there are good
...
...
@@ -179,11 +185,12 @@ PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
* also good reasons to use it, let the user decide).
*/
static
void
ps2pp_set_resolution
(
struct
psmouse
*
psmouse
,
unsigned
int
resolution
)
static
void
ps2pp_set_resolution
(
struct
psmouse
*
psmouse
,
unsigned
int
resolution
)
{
if
(
resolution
>
400
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
=
3
;
u
8
param
=
3
;
ps2_command
(
ps2dev
,
NULL
,
PSMOUSE_CMD_SETSCALE11
);
ps2_command
(
ps2dev
,
NULL
,
PSMOUSE_CMD_SETSCALE11
);
...
...
@@ -196,7 +203,8 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio
static
void
ps2pp_disconnect
(
struct
psmouse
*
psmouse
)
{
device_remove_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
.
dattr
);
device_remove_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
.
dattr
);
}
static
const
struct
ps2pp_info
*
get_model_info
(
unsigned
char
model
)
...
...
@@ -269,24 +277,24 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
struct
input_dev
*
input_dev
=
psmouse
->
dev
;
if
(
model_info
->
features
&
PS2PP_SIDE_BTN
)
__set_bit
(
BTN_SIDE
,
input_dev
->
keybit
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_SIDE
);
if
(
model_info
->
features
&
PS2PP_EXTRA_BTN
)
__set_bit
(
BTN_EXTRA
,
input_dev
->
keybit
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_EXTRA
);
if
(
model_info
->
features
&
PS2PP_TASK_BTN
)
__set_bit
(
BTN_TASK
,
input_dev
->
keybit
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_TASK
);
if
(
model_info
->
features
&
PS2PP_NAV_BTN
)
{
__set_bit
(
BTN_FORWARD
,
input_dev
->
keybit
);
__set_bit
(
BTN_BACK
,
input_dev
->
keybit
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_FORWARD
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_BACK
);
}
if
(
model_info
->
features
&
PS2PP_WHEEL
)
__set_bit
(
REL_WHEEL
,
input_dev
->
relbit
);
input_set_capability
(
input_dev
,
EV_REL
,
REL_WHEEL
);
if
(
model_info
->
features
&
PS2PP_HWHEEL
)
__set_bit
(
REL_HWHEEL
,
input_dev
->
relbit
);
input_set_capability
(
input_dev
,
EV_REL
,
REL_HWHEEL
);
switch
(
model_info
->
kind
)
{
...
...
@@ -318,6 +326,30 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
}
}
static
int
ps2pp_setup_protocol
(
struct
psmouse
*
psmouse
,
const
struct
ps2pp_info
*
model_info
)
{
int
error
;
psmouse
->
protocol_handler
=
ps2pp_process_byte
;
psmouse
->
pktsize
=
3
;
if
(
model_info
->
kind
!=
PS2PP_KIND_TP3
)
{
psmouse
->
set_resolution
=
ps2pp_set_resolution
;
psmouse
->
disconnect
=
ps2pp_disconnect
;
error
=
device_create_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
.
dattr
);
if
(
error
)
{
psmouse_err
(
psmouse
,
"failed to create smartscroll sysfs attribute, error: %d
\n
"
,
error
);
return
error
;
}
}
return
0
;
}
/*
* Logitech magic init. Detect whether the mouse is a Logitech one
...
...
@@ -328,9 +360,9 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
int
ps2pp_detect
(
struct
psmouse
*
psmouse
,
bool
set_properties
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
unsigned
char
param
[
4
];
unsigned
char
model
,
buttons
;
const
struct
ps2pp_info
*
model_info
;
u8
param
[
4
];
u8
model
,
buttons
;
bool
use_ps2pp
=
false
;
int
error
;
...
...
@@ -346,7 +378,7 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
buttons
=
param
[
1
];
if
(
!
model
||
!
buttons
)
return
-
1
;
return
-
ENXIO
;
model_info
=
get_model_info
(
model
);
if
(
model_info
)
{
...
...
@@ -368,7 +400,8 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
param
[
0
]
=
0
;
if
(
!
ps2_command
(
ps2dev
,
param
,
0x13d1
)
&&
param
[
0
]
==
0x06
&&
param
[
1
]
==
0x00
&&
param
[
2
]
==
0x14
)
{
param
[
0
]
==
0x06
&&
param
[
1
]
==
0x00
&&
param
[
2
]
==
0x14
)
{
use_ps2pp
=
true
;
}
...
...
@@ -387,7 +420,9 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
}
}
else
{
psmouse_warn
(
psmouse
,
"Detected unknown Logitech mouse model %d
\n
"
,
model
);
psmouse_warn
(
psmouse
,
"Detected unknown Logitech mouse model %d
\n
"
,
model
);
}
if
(
set_properties
)
{
...
...
@@ -395,31 +430,18 @@ int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
psmouse
->
model
=
model
;
if
(
use_ps2pp
)
{
psmouse
->
protocol_handler
=
ps2pp_process_byte
;
psmouse
->
pktsize
=
3
;
if
(
model_info
->
kind
!=
PS2PP_KIND_TP3
)
{
psmouse
->
set_resolution
=
ps2pp_set_resolution
;
psmouse
->
disconnect
=
ps2pp_disconnect
;
error
=
device_create_file
(
&
ps2dev
->
serio
->
dev
,
&
psmouse_attr_smartscroll
.
dattr
);
if
(
error
)
{
psmouse_err
(
psmouse
,
"failed to create smartscroll sysfs attribute, error: %d
\n
"
,
error
);
return
-
1
;
}
}
error
=
ps2pp_setup_protocol
(
psmouse
,
model_info
);
if
(
error
)
return
error
;
}
if
(
buttons
>=
3
)
__set_bit
(
BTN_MIDDLE
,
psmouse
->
dev
->
keybit
);
input_set_capability
(
psmouse
->
dev
,
EV_KEY
,
BTN_MIDDLE
);
if
(
model_info
)
ps2pp_set_model_properties
(
psmouse
,
model_info
,
use_ps2pp
);
}
return
use_ps2pp
?
0
:
-
1
;
return
use_ps2pp
?
0
:
-
ENXIO
;
}
drivers/input/mouse/psmouse-base.c
View file @
ba521f1b
...
...
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define psmouse_fmt(fmt) fmt
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
...
...
@@ -23,6 +24,7 @@
#include <linux/init.h>
#include <linux/libps2.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include "psmouse.h"
#include "synaptics.h"
...
...
@@ -68,6 +70,10 @@ static bool psmouse_smartscroll = true;
module_param_named
(
smartscroll
,
psmouse_smartscroll
,
bool
,
0644
);
MODULE_PARM_DESC
(
smartscroll
,
"Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."
);
static
bool
psmouse_a4tech_2wheels
;
module_param_named
(
a4tech_workaround
,
psmouse_a4tech_2wheels
,
bool
,
0644
);
MODULE_PARM_DESC
(
a4tech_workaround
,
"A4Tech second scroll wheel workaround, 1 = enabled, 0 = disabled (default)."
);
static
unsigned
int
psmouse_resetafter
=
5
;
module_param_named
(
resetafter
,
psmouse_resetafter
,
uint
,
0644
);
MODULE_PARM_DESC
(
resetafter
,
"Reset device after so many bad packets (0 = never)."
);
...
...
@@ -116,13 +122,30 @@ static DEFINE_MUTEX(psmouse_mutex);
static
struct
workqueue_struct
*
kpsmoused_wq
;
static
void
psmouse_report_standard_buttons
(
struct
input_dev
*
dev
,
u8
buttons
)
void
psmouse_report_standard_buttons
(
struct
input_dev
*
dev
,
u8
buttons
)
{
input_report_key
(
dev
,
BTN_LEFT
,
buttons
&
BIT
(
0
));
input_report_key
(
dev
,
BTN_MIDDLE
,
buttons
&
BIT
(
2
));
input_report_key
(
dev
,
BTN_RIGHT
,
buttons
&
BIT
(
1
));
}
void
psmouse_report_standard_motion
(
struct
input_dev
*
dev
,
u8
*
packet
)
{
int
x
,
y
;
x
=
packet
[
1
]
?
packet
[
1
]
-
((
packet
[
0
]
<<
4
)
&
0x100
)
:
0
;
y
=
packet
[
2
]
?
packet
[
2
]
-
((
packet
[
0
]
<<
3
)
&
0x100
)
:
0
;
input_report_rel
(
dev
,
REL_X
,
x
);
input_report_rel
(
dev
,
REL_Y
,
-
y
);
}
void
psmouse_report_standard_packet
(
struct
input_dev
*
dev
,
u8
*
packet
)
{
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]);
psmouse_report_standard_motion
(
dev
,
packet
);
}
/*
* psmouse_process_byte() analyzes the PS/2 data stream and reports
* relevant events to the input module once full packet has arrived.
...
...
@@ -130,7 +153,8 @@ static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
psmouse_ret_t
psmouse_process_byte
(
struct
psmouse
*
psmouse
)
{
struct
input_dev
*
dev
=
psmouse
->
dev
;
unsigned
char
*
packet
=
psmouse
->
packet
;
u8
*
packet
=
psmouse
->
packet
;
int
wheel
;
if
(
psmouse
->
pktcnt
<
psmouse
->
pktsize
)
return
PSMOUSE_GOOD_DATA
;
...
...
@@ -140,39 +164,52 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
switch
(
psmouse
->
protocol
->
type
)
{
case
PSMOUSE_IMPS
:
/* IntelliMouse has scroll wheel */
input_report_rel
(
dev
,
REL_WHEEL
,
-
(
s
igned
char
)
packet
[
3
]);
input_report_rel
(
dev
,
REL_WHEEL
,
-
(
s
8
)
packet
[
3
]);
break
;
case
PSMOUSE_IMEX
:
/* Scroll wheel and buttons on IntelliMouse Explorer */
switch
(
packet
[
3
]
&
0xC0
)
{
case
0x80
:
/* vertical scroll on IntelliMouse Explorer 4.0 */
input_report_rel
(
dev
,
REL_WHEEL
,
(
int
)
(
packet
[
3
]
&
32
)
-
(
int
)
(
packet
[
3
]
&
31
));
input_report_rel
(
dev
,
REL_WHEEL
,
-
sign_extend32
(
packet
[
3
],
5
));
break
;
case
0x40
:
/* horizontal scroll on IntelliMouse Explorer 4.0 */
input_report_rel
(
dev
,
REL_HWHEEL
,
(
int
)
(
packet
[
3
]
&
32
)
-
(
int
)
(
packet
[
3
]
&
31
));
input_report_rel
(
dev
,
REL_HWHEEL
,
-
sign_extend32
(
packet
[
3
],
5
));
break
;
case
0x00
:
case
0xC0
:
input_report_rel
(
dev
,
REL_WHEEL
,
(
int
)
(
packet
[
3
]
&
8
)
-
(
int
)
(
packet
[
3
]
&
7
));
input_report_key
(
dev
,
BTN_SIDE
,
(
packet
[
3
]
>>
4
)
&
1
);
input_report_key
(
dev
,
BTN_EXTRA
,
(
packet
[
3
]
>>
5
)
&
1
);
wheel
=
sign_extend32
(
packet
[
3
],
3
);
/*
* Some A4Tech mice have two scroll wheels, with first
* one reporting +/-1 in the lower nibble, and second
* one reporting +/-2.
*/
if
(
psmouse_a4tech_2wheels
&&
abs
(
wheel
)
>
1
)
input_report_rel
(
dev
,
REL_HWHEEL
,
wheel
/
2
);
else
input_report_rel
(
dev
,
REL_WHEEL
,
-
wheel
);
input_report_key
(
dev
,
BTN_SIDE
,
BIT
(
4
));
input_report_key
(
dev
,
BTN_EXTRA
,
BIT
(
5
));
break
;
}
break
;
case
PSMOUSE_GENPS
:
/* Report scroll buttons on NetMice */
input_report_rel
(
dev
,
REL_WHEEL
,
-
(
s
igned
char
)
packet
[
3
]);
input_report_rel
(
dev
,
REL_WHEEL
,
-
(
s
8
)
packet
[
3
]);
/* Extra buttons on Genius NewNet 3D */
input_report_key
(
dev
,
BTN_SIDE
,
(
packet
[
0
]
>>
6
)
&
1
);
input_report_key
(
dev
,
BTN_EXTRA
,
(
packet
[
0
]
>>
7
)
&
1
);
input_report_key
(
dev
,
BTN_SIDE
,
BIT
(
6
)
);
input_report_key
(
dev
,
BTN_EXTRA
,
BIT
(
7
)
);
break
;
case
PSMOUSE_THINKPS
:
/* Extra button on ThinkingMouse */
input_report_key
(
dev
,
BTN_EXTRA
,
(
packet
[
0
]
>>
3
)
&
1
);
input_report_key
(
dev
,
BTN_EXTRA
,
BIT
(
3
)
);
/*
* Without this bit of weirdness moving up gives wildly
...
...
@@ -186,8 +223,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
* Cortron PS2 Trackball reports SIDE button in the
* 4th bit of the first byte.
*/
input_report_key
(
dev
,
BTN_SIDE
,
(
packet
[
0
]
>>
3
)
&
1
);
packet
[
0
]
|=
0x08
;
input_report_key
(
dev
,
BTN_SIDE
,
BIT
(
3
)
);
packet
[
0
]
|=
BIT
(
3
)
;
break
;
default:
...
...
@@ -195,11 +232,8 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
}
/* Generic PS/2 Mouse */
psmouse_report_standard_buttons
(
dev
,
packet
[
0
]
|
psmouse
->
extra_buttons
);
input_report_rel
(
dev
,
REL_X
,
packet
[
1
]
?
(
int
)
packet
[
1
]
-
(
int
)
((
packet
[
0
]
<<
4
)
&
0x100
)
:
0
);
input_report_rel
(
dev
,
REL_Y
,
packet
[
2
]
?
(
int
)
((
packet
[
0
]
<<
3
)
&
0x100
)
-
(
int
)
packet
[
2
]
:
0
);
packet
[
0
]
|=
psmouse
->
extra_buttons
;
psmouse_report_standard_packet
(
dev
,
packet
);
input_sync
(
dev
);
...
...
@@ -255,7 +289,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
psmouse_notice
(
psmouse
,
"issuing reconnect request
\n
"
);
serio_reconnect
(
psmouse
->
ps2dev
.
serio
);
return
-
1
;
return
-
EIO
;
}
}
psmouse
->
pktcnt
=
0
;
...
...
@@ -306,7 +340,7 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
* for normal processing or gathering them as command response.
*/
static
irqreturn_t
psmouse_interrupt
(
struct
serio
*
serio
,
unsigned
char
data
,
unsigned
int
flags
)
u8
data
,
unsigned
int
flags
)
{
struct
psmouse
*
psmouse
=
serio_get_drvdata
(
serio
);
...
...
@@ -397,41 +431,20 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
return
IRQ_HANDLED
;
}
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech
* or Synaptics touchpads. The command is encoded as:
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command.
*/
int
psmouse_sliced_command
(
struct
psmouse
*
psmouse
,
unsigned
char
command
)
{
int
i
;
if
(
ps2_command
(
&
psmouse
->
ps2dev
,
NULL
,
PSMOUSE_CMD_SETSCALE11
))
return
-
1
;
for
(
i
=
6
;
i
>=
0
;
i
-=
2
)
{
unsigned
char
d
=
(
command
>>
i
)
&
3
;
if
(
ps2_command
(
&
psmouse
->
ps2dev
,
&
d
,
PSMOUSE_CMD_SETRES
))
return
-
1
;
}
return
0
;
}
/*
* psmouse_reset() resets the mouse into power-on state.
*/
int
psmouse_reset
(
struct
psmouse
*
psmouse
)
{
unsigned
char
param
[
2
];
u8
param
[
2
];
int
error
;
if
(
ps2_command
(
&
psmouse
->
ps2dev
,
param
,
PSMOUSE_CMD_RESET_BAT
))
return
-
1
;
error
=
ps2_command
(
&
psmouse
->
ps2dev
,
param
,
PSMOUSE_CMD_RESET_BAT
);
if
(
error
)
return
error
;
if
(
param
[
0
]
!=
PSMOUSE_RET_BAT
&&
param
[
1
]
!=
PSMOUSE_RET_ID
)
return
-
1
;
return
-
EIO
;
return
0
;
}
...
...
@@ -441,8 +454,8 @@ int psmouse_reset(struct psmouse *psmouse)
*/
void
psmouse_set_resolution
(
struct
psmouse
*
psmouse
,
unsigned
int
resolution
)
{
static
const
u
nsigned
char
params
[]
=
{
0
,
1
,
2
,
2
,
3
};
u
nsigned
char
p
;
static
const
u
8
params
[]
=
{
0
,
1
,
2
,
2
,
3
};
u
8
p
;
if
(
resolution
==
0
||
resolution
>
200
)
resolution
=
200
;
...
...
@@ -457,11 +470,12 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
*/
static
void
psmouse_set_rate
(
struct
psmouse
*
psmouse
,
unsigned
int
rate
)
{
static
const
u
nsigned
char
rates
[]
=
{
200
,
100
,
80
,
60
,
40
,
20
,
10
,
0
};
u
nsigned
char
r
;
static
const
u
8
rates
[]
=
{
200
,
100
,
80
,
60
,
40
,
20
,
10
,
0
};
u
8
r
;
int
i
=
0
;
while
(
rates
[
i
]
>
rate
)
i
++
;
while
(
rates
[
i
]
>
rate
)
i
++
;
r
=
rates
[
i
];
ps2_command
(
&
psmouse
->
ps2dev
,
&
r
,
PSMOUSE_CMD_SETRATE
);
psmouse
->
rate
=
r
;
...
...
@@ -533,7 +547,7 @@ bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
static
int
genius_detect
(
struct
psmouse
*
psmouse
,
bool
set_properties
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
[
4
];
u
8
param
[
4
];
param
[
0
]
=
3
;
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_SETRES
);
...
...
@@ -543,7 +557,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_GETINFO
);
if
(
param
[
0
]
!=
0x00
||
param
[
1
]
!=
0x33
||
param
[
2
]
!=
0x55
)
return
-
1
;
return
-
ENODEV
;
if
(
set_properties
)
{
__set_bit
(
BTN_MIDDLE
,
psmouse
->
dev
->
keybit
);
...
...
@@ -565,7 +579,7 @@ static int genius_detect(struct psmouse *psmouse, bool set_properties)
static
int
intellimouse_detect
(
struct
psmouse
*
psmouse
,
bool
set_properties
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
[
2
];
u
8
param
[
2
];
param
[
0
]
=
200
;
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_SETRATE
);
...
...
@@ -576,7 +590,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_GETID
);
if
(
param
[
0
]
!=
3
)
return
-
1
;
return
-
ENODEV
;
if
(
set_properties
)
{
__set_bit
(
BTN_MIDDLE
,
psmouse
->
dev
->
keybit
);
...
...
@@ -598,7 +612,7 @@ static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
static
int
im_explorer_detect
(
struct
psmouse
*
psmouse
,
bool
set_properties
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
[
2
];
u
8
param
[
2
];
intellimouse_detect
(
psmouse
,
0
);
...
...
@@ -611,7 +625,7 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_GETID
);
if
(
param
[
0
]
!=
4
)
return
-
1
;
return
-
ENODEV
;
/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
param
[
0
]
=
200
;
...
...
@@ -644,8 +658,8 @@ static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
static
int
thinking_detect
(
struct
psmouse
*
psmouse
,
bool
set_properties
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
u
nsigned
char
param
[
2
];
static
const
u
nsigned
char
seq
[]
=
{
20
,
60
,
40
,
20
,
20
,
60
,
40
,
20
,
20
};
u
8
param
[
2
];
static
const
u
8
seq
[]
=
{
20
,
60
,
40
,
20
,
20
,
60
,
40
,
20
,
20
};
int
i
;
param
[
0
]
=
10
;
...
...
@@ -659,7 +673,7 @@ static int thinking_detect(struct psmouse *psmouse, bool set_properties)
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_GETID
);
if
(
param
[
0
]
!=
2
)
return
-
1
;
return
-
ENODEV
;
if
(
set_properties
)
{
__set_bit
(
BTN_MIDDLE
,
psmouse
->
dev
->
keybit
);
...
...
@@ -687,7 +701,7 @@ static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
* We have no way of figuring true number of buttons so let's
* assume that the device has 3.
*/
__set_bit
(
BTN_MIDDLE
,
psmouse
->
dev
->
keybit
);
input_set_capability
(
psmouse
->
dev
,
EV_KEY
,
BTN_MIDDLE
);
}
return
0
;
...
...
@@ -942,20 +956,17 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
{
struct
input_dev
*
input_dev
=
psmouse
->
dev
;
memset
(
input_dev
->
evbit
,
0
,
sizeof
(
input_dev
->
evbit
));
memset
(
input_dev
->
keybit
,
0
,
sizeof
(
input_dev
->
keybit
));
memset
(
input_dev
->
relbit
,
0
,
sizeof
(
input_dev
->
relbit
));
memset
(
input_dev
->
absbit
,
0
,
sizeof
(
input_dev
->
absbit
));
memset
(
input_dev
->
mscbit
,
0
,
sizeof
(
input_dev
->
mscbit
));
__set_bit
(
EV_KEY
,
input_dev
->
evbit
);
__set_bit
(
EV_REL
,
input_dev
->
evbit
);
bitmap_zero
(
input_dev
->
evbit
,
EV_CNT
);
bitmap_zero
(
input_dev
->
keybit
,
KEY_CNT
);
bitmap_zero
(
input_dev
->
relbit
,
REL_CNT
);
bitmap_zero
(
input_dev
->
absbit
,
ABS_CNT
);
bitmap_zero
(
input_dev
->
mscbit
,
MSC_CNT
);
__set_bit
(
BTN_LEFT
,
input_dev
->
keybit
);
__set_bit
(
BTN_RIGHT
,
input_dev
->
keybit
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_LEFT
);
input_set_capability
(
input_dev
,
EV_KEY
,
BTN_RIGHT
);
__set_bit
(
REL_X
,
input_dev
->
relbit
);
__set_bit
(
REL_Y
,
input_dev
->
relbit
);
input_set_capability
(
input_dev
,
EV_REL
,
REL_X
);
input_set_capability
(
input_dev
,
EV_REL
,
REL_Y
);
__set_bit
(
INPUT_PROP_POINTER
,
input_dev
->
propbit
);
...
...
@@ -1225,7 +1236,8 @@ static int psmouse_extensions(struct psmouse *psmouse,
static
int
psmouse_probe
(
struct
psmouse
*
psmouse
)
{
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
unsigned
char
param
[
2
];
u8
param
[
2
];
int
error
;
/*
* First, we check if it's a mouse. It should send 0x00 or 0x03 in
...
...
@@ -1234,20 +1246,22 @@ static int psmouse_probe(struct psmouse *psmouse)
* subsequent ID queries, probably due to a firmware bug.
*/
param
[
0
]
=
0xa5
;
if
(
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_GETID
))
return
-
1
;
error
=
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_GETID
);
if
(
error
)
return
error
;
if
(
param
[
0
]
!=
0x00
&&
param
[
0
]
!=
0x03
&&
param
[
0
]
!=
0x04
&&
param
[
0
]
!=
0xff
)
return
-
1
;
return
-
ENODEV
;
/*
* Then we reset and disable the mouse so that it doesn't generate
* events.
*/
if
(
ps2_command
(
ps2dev
,
NULL
,
PSMOUSE_CMD_RESET_DIS
))
psmouse_warn
(
psmouse
,
"Failed to reset mouse on %s
\n
"
,
ps2dev
->
serio
->
phys
);
error
=
ps2_command
(
ps2dev
,
NULL
,
PSMOUSE_CMD_RESET_DIS
);
if
(
error
)
psmouse_warn
(
psmouse
,
"Failed to reset mouse on %s: %d
\n
"
,
ps2dev
->
serio
->
phys
,
error
);
return
0
;
}
...
...
@@ -1288,10 +1302,13 @@ int psmouse_activate(struct psmouse *psmouse)
*/
int
psmouse_deactivate
(
struct
psmouse
*
psmouse
)
{
if
(
ps2_command
(
&
psmouse
->
ps2dev
,
NULL
,
PSMOUSE_CMD_DISABLE
))
{
psmouse_warn
(
psmouse
,
"Failed to deactivate mouse on %s
\n
"
,
psmouse
->
ps2dev
.
serio
->
phys
);
return
-
1
;
int
error
;
error
=
ps2_command
(
&
psmouse
->
ps2dev
,
NULL
,
PSMOUSE_CMD_DISABLE
);
if
(
error
)
{
psmouse_warn
(
psmouse
,
"Failed to deactivate mouse on %s: %d
\n
"
,
psmouse
->
ps2dev
.
serio
->
phys
,
error
);
return
error
;
}
psmouse_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
...
...
drivers/input/mouse/psmouse.h
View file @
ba521f1b
...
...
@@ -131,7 +131,6 @@ struct psmouse {
void
psmouse_queue_work
(
struct
psmouse
*
psmouse
,
struct
delayed_work
*
work
,
unsigned
long
delay
);
int
psmouse_sliced_command
(
struct
psmouse
*
psmouse
,
unsigned
char
command
);
int
psmouse_reset
(
struct
psmouse
*
psmouse
);
void
psmouse_set_state
(
struct
psmouse
*
psmouse
,
enum
psmouse_state
new_state
);
void
psmouse_set_resolution
(
struct
psmouse
*
psmouse
,
unsigned
int
resolution
);
...
...
@@ -140,6 +139,10 @@ int psmouse_activate(struct psmouse *psmouse);
int
psmouse_deactivate
(
struct
psmouse
*
psmouse
);
bool
psmouse_matches_pnp_id
(
struct
psmouse
*
psmouse
,
const
char
*
const
ids
[]);
void
psmouse_report_standard_buttons
(
struct
input_dev
*
,
u8
buttons
);
void
psmouse_report_standard_motion
(
struct
input_dev
*
,
u8
*
packet
);
void
psmouse_report_standard_packet
(
struct
input_dev
*
,
u8
*
packet
);
struct
psmouse_attribute
{
struct
device_attribute
dattr
;
void
*
data
;
...
...
drivers/input/mouse/sentelic.c
View file @
ba521f1b
...
...
@@ -710,7 +710,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
unsigned
char
*
packet
=
psmouse
->
packet
;
unsigned
char
button_status
=
0
,
lscroll
=
0
,
rscroll
=
0
;
unsigned
short
abs_x
,
abs_y
,
fgrs
=
0
;
int
rel_x
,
rel_y
;
if
(
psmouse
->
pktcnt
<
4
)
return
PSMOUSE_GOOD_DATA
;
...
...
@@ -840,15 +839,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
/*
* Standard PS/2 Mouse
*/
input_report_key
(
dev
,
BTN_LEFT
,
packet
[
0
]
&
1
);
input_report_key
(
dev
,
BTN_MIDDLE
,
(
packet
[
0
]
>>
2
)
&
1
);
input_report_key
(
dev
,
BTN_RIGHT
,
(
packet
[
0
]
>>
1
)
&
1
);
rel_x
=
packet
[
1
]
?
(
int
)
packet
[
1
]
-
(
int
)((
packet
[
0
]
<<
4
)
&
0x100
)
:
0
;
rel_y
=
packet
[
2
]
?
(
int
)((
packet
[
0
]
<<
3
)
&
0x100
)
-
(
int
)
packet
[
2
]
:
0
;
input_report_rel
(
dev
,
REL_X
,
rel_x
);
input_report_rel
(
dev
,
REL_Y
,
rel_y
);
psmouse_report_standard_packet
(
dev
,
packet
);
break
;
}
...
...
drivers/input/mouse/synaptics.c
View file @
ba521f1b
...
...
@@ -84,7 +84,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
u8
param
[
1
];
int
error
;
error
=
ps
mouse_sliced_command
(
psmouse
,
mode
);
error
=
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
mode
);
if
(
error
)
return
error
;
...
...
@@ -190,7 +190,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
{
int
error
;
error
=
ps
mouse_sliced_command
(
psmouse
,
cmd
);
error
=
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
cmd
);
if
(
error
)
return
error
;
...
...
@@ -547,7 +547,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
static
u8
param
=
0xc8
;
int
error
;
error
=
ps
mouse_sliced_command
(
psmouse
,
SYN_QUE_MODEL
);
error
=
ps
2_sliced_command
(
&
psmouse
->
ps2dev
,
SYN_QUE_MODEL
);
if
(
error
)
return
error
;
...
...
@@ -614,7 +614,7 @@ static int synaptics_pt_write(struct serio *serio, u8 c)
u8
rate_param
=
SYN_PS_CLIENT_CMD
;
/* indicates that we want pass-through port */
int
error
;
error
=
ps
mouse_sliced_command
(
parent
,
c
);
error
=
ps
2_sliced_command
(
&
parent
->
ps2dev
,
c
);
if
(
error
)
return
error
;
...
...
drivers/input/mouse/trackpoint.c
View file @
ba521f1b
...
...
@@ -33,18 +33,15 @@ static const char * const trackpoint_variants[] = {
*/
static
int
trackpoint_power_on_reset
(
struct
ps2dev
*
ps2dev
)
{
u8
results
[
2
]
;
int
tries
=
0
;
u8
param
[
2
]
=
{
TP_POR
}
;
int
err
;
/* Issue POR command, and repeat up to once if 0xFC00 received */
do
{
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
results
,
MAKE_PS2_CMD
(
0
,
2
,
TP_POR
)))
return
-
1
;
}
while
(
results
[
0
]
==
0xFC
&&
results
[
1
]
==
0x00
&&
++
tries
<
2
);
err
=
ps2_command
(
ps2dev
,
param
,
MAKE_PS2_CMD
(
1
,
2
,
TP_COMMAND
));
if
(
err
)
return
err
;
/* Check for success response -- 0xAA00 */
if
(
results
[
0
]
!=
0xAA
||
results
[
1
]
!=
0x00
)
if
(
param
[
0
]
!=
0xAA
||
param
[
1
]
!=
0x00
)
return
-
ENODEV
;
return
0
;
...
...
@@ -55,49 +52,39 @@ static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
*/
static
int
trackpoint_read
(
struct
ps2dev
*
ps2dev
,
u8
loc
,
u8
*
results
)
{
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
results
,
MAKE_PS2_CMD
(
0
,
1
,
loc
)))
{
return
-
1
;
}
results
[
0
]
=
loc
;
return
0
;
return
ps2_command
(
ps2dev
,
results
,
MAKE_PS2_CMD
(
1
,
1
,
TP_COMMAND
))
;
}
static
int
trackpoint_write
(
struct
ps2dev
*
ps2dev
,
u8
loc
,
u8
val
)
{
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_WRITE_MEM
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
loc
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
val
)))
{
return
-
1
;
}
u8
param
[
3
]
=
{
TP_WRITE_MEM
,
loc
,
val
};
return
0
;
return
ps2_command
(
ps2dev
,
param
,
MAKE_PS2_CMD
(
3
,
0
,
TP_COMMAND
))
;
}
static
int
trackpoint_toggle_bit
(
struct
ps2dev
*
ps2dev
,
u8
loc
,
u8
mask
)
{
u8
param
[
3
]
=
{
TP_TOGGLE
,
loc
,
mask
};
/* Bad things will happen if the loc param isn't in this range */
if
(
loc
<
0x20
||
loc
>=
0x2F
)
return
-
1
;
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_TOGGLE
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
loc
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
mask
)))
{
return
-
1
;
}
return
-
EINVAL
;
return
0
;
return
ps2_command
(
ps2dev
,
param
,
MAKE_PS2_CMD
(
3
,
0
,
TP_COMMAND
))
;
}
static
int
trackpoint_update_bit
(
struct
ps2dev
*
ps2dev
,
u8
loc
,
u8
mask
,
u8
value
)
{
int
retval
=
0
;
int
retval
;
u8
data
;
trackpoint_read
(
ps2dev
,
loc
,
&
data
);
retval
=
trackpoint_read
(
ps2dev
,
loc
,
&
data
);
if
(
retval
)
return
retval
;
if
(((
data
&
mask
)
==
mask
)
!=
!!
value
)
retval
=
trackpoint_toggle_bit
(
ps2dev
,
loc
,
mask
);
...
...
@@ -142,9 +129,9 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
return
err
;
*
field
=
value
;
trackpoint_write
(
&
psmouse
->
ps2dev
,
attr
->
command
,
value
);
err
=
trackpoint_write
(
&
psmouse
->
ps2dev
,
attr
->
command
,
value
);
return
count
;
return
err
?:
count
;
}
#define TRACKPOINT_INT_ATTR(_name, _command, _default) \
...
...
@@ -175,10 +162,11 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
if
(
*
field
!=
value
)
{
*
field
=
value
;
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
attr
->
command
,
attr
->
mask
);
err
=
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
attr
->
command
,
attr
->
mask
);
}
return
count
;
return
err
?:
count
;
}
...
...
drivers/input/serio/libps2.c
View file @
ba521f1b
...
...
@@ -26,31 +26,79 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION
(
"PS/2 driver library"
);
MODULE_LICENSE
(
"GPL"
);
static
int
ps2_do_sendbyte
(
struct
ps2dev
*
ps2dev
,
u8
byte
,
unsigned
int
timeout
,
unsigned
int
max_attempts
)
__releases
(
&
ps2dev
->
serio
->
lock
)
__acquires
(
&
ps2dev
->
serio
->
lock
)
{
int
attempt
=
0
;
int
error
;
lockdep_assert_held
(
&
ps2dev
->
serio
->
lock
);
do
{
ps2dev
->
nak
=
1
;
ps2dev
->
flags
|=
PS2_FLAG_ACK
;
serio_continue_rx
(
ps2dev
->
serio
);
error
=
serio_write
(
ps2dev
->
serio
,
byte
);
if
(
error
)
dev_dbg
(
&
ps2dev
->
serio
->
dev
,
"failed to write %#02x: %d
\n
"
,
byte
,
error
);
else
wait_event_timeout
(
ps2dev
->
wait
,
!
(
ps2dev
->
flags
&
PS2_FLAG_ACK
),
msecs_to_jiffies
(
timeout
));
serio_pause_rx
(
ps2dev
->
serio
);
}
while
(
ps2dev
->
nak
==
PS2_RET_NAK
&&
++
attempt
<
max_attempts
);
ps2dev
->
flags
&=
~
PS2_FLAG_ACK
;
if
(
!
error
)
{
switch
(
ps2dev
->
nak
)
{
case
0
:
break
;
case
PS2_RET_NAK
:
error
=
-
EAGAIN
;
break
;
case
PS2_RET_ERR
:
error
=
-
EPROTO
;
break
;
default:
error
=
-
EIO
;
break
;
}
}
if
(
error
||
attempt
>
1
)
dev_dbg
(
&
ps2dev
->
serio
->
dev
,
"%02x - %d (%x), attempt %d
\n
"
,
byte
,
error
,
ps2dev
->
nak
,
attempt
);
return
error
;
}
/*
* ps2_sendbyte() sends a byte to the device and waits for acknowledge.
* It doesn't handle retransmission, th
ough it could - because if ther
e
* i
s a need for retransmissions device has to be replaced anyway
.
* It doesn't handle retransmission, th
e caller is expected to handl
e
* i
t when needed
.
*
* ps2_sendbyte() can only be called from a process context.
*/
int
ps2_sendbyte
(
struct
ps2dev
*
ps2dev
,
u
nsigned
char
byte
,
int
timeout
)
int
ps2_sendbyte
(
struct
ps2dev
*
ps2dev
,
u
8
byte
,
unsigned
int
timeout
)
{
int
retval
;
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
nak
=
1
;
ps2dev
->
flags
|=
PS2_FLAG_ACK
;
serio_continue_rx
(
ps2dev
->
serio
);
if
(
serio_write
(
ps2dev
->
serio
,
byte
)
==
0
)
wait_event_timeout
(
ps2dev
->
wait
,
!
(
ps2dev
->
flags
&
PS2_FLAG_ACK
),
msecs_to_jiffies
(
timeout
));
retval
=
ps2_do_sendbyte
(
ps2dev
,
byte
,
timeout
,
1
);
dev_dbg
(
&
ps2dev
->
serio
->
dev
,
"%02x - %x
\n
"
,
byte
,
ps2dev
->
nak
);
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
flags
&=
~
PS2_FLAG_ACK
;
serio_continue_rx
(
ps2dev
->
serio
);
return
-
ps2dev
->
nak
;
return
retval
;
}
EXPORT_SYMBOL
(
ps2_sendbyte
);
...
...
@@ -75,7 +123,7 @@ EXPORT_SYMBOL(ps2_end_command);
* and discards them.
*/
void
ps2_drain
(
struct
ps2dev
*
ps2dev
,
int
maxbytes
,
int
timeout
)
void
ps2_drain
(
struct
ps2dev
*
ps2dev
,
size_t
maxbytes
,
unsigned
int
timeout
)
{
if
(
maxbytes
>
sizeof
(
ps2dev
->
cmdbuf
))
{
WARN_ON
(
1
);
...
...
@@ -102,9 +150,9 @@ EXPORT_SYMBOL(ps2_drain);
* known keyboard IDs.
*/
int
ps2_is_keyboard_id
(
char
id_byte
)
bool
ps2_is_keyboard_id
(
u8
id_byte
)
{
static
const
char
keyboard_ids
[]
=
{
static
const
u8
keyboard_ids
[]
=
{
0xab
,
/* Regular keyboards */
0xac
,
/* NCD Sun keyboard */
0x2b
,
/* Trust keyboard, translated */
...
...
@@ -123,49 +171,50 @@ EXPORT_SYMBOL(ps2_is_keyboard_id);
* completion.
*/
static
int
ps2_adjust_timeout
(
struct
ps2dev
*
ps2dev
,
int
command
,
int
timeout
)
static
int
ps2_adjust_timeout
(
struct
ps2dev
*
ps2dev
,
unsigned
int
command
,
unsigned
int
timeout
)
{
switch
(
command
)
{
case
PS2_CMD_RESET_BAT
:
/*
* Device has sent the first response byte after
* reset command, reset is thus done, so we can
* shorten the timeout.
* The next byte will come soon (keyboard) or not
* at all (mouse).
*/
if
(
timeout
>
msecs_to_jiffies
(
100
))
timeout
=
msecs_to_jiffies
(
100
);
break
;
case
PS2_CMD_RESET_BAT
:
/*
* Device has sent the first response byte after
* reset command, reset is thus done, so we can
* shorten the timeout.
* The next byte will come soon (keyboard) or not
* at all (mouse).
*/
if
(
timeout
>
msecs_to_jiffies
(
100
))
timeout
=
msecs_to_jiffies
(
100
);
break
;
case
PS2_CMD_GETID
:
/*
* Microsoft Natural Elite keyboard responds to
* the GET ID command as it were a mouse, with
* a single byte. Fail the command so atkbd will
* use alternative probe to detect it.
*/
if
(
ps2dev
->
cmdbuf
[
1
]
==
0xaa
)
{
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
flags
=
0
;
serio_continue_rx
(
ps2dev
->
serio
);
timeout
=
0
;
}
/*
* If device behind the port is not a keyboard there
* won't be 2nd byte of ID response.
*/
if
(
!
ps2_is_keyboard_id
(
ps2dev
->
cmdbuf
[
1
]))
{
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
flags
=
ps2dev
->
cmdcnt
=
0
;
serio_continue_rx
(
ps2dev
->
serio
);
timeout
=
0
;
}
break
;
case
PS2_CMD_GETID
:
/*
* Microsoft Natural Elite keyboard responds to
* the GET ID command as it were a mouse, with
* a single byte. Fail the command so atkbd will
* use alternative probe to detect it.
*/
if
(
ps2dev
->
cmdbuf
[
1
]
==
0xaa
)
{
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
flags
=
0
;
serio_continue_rx
(
ps2dev
->
serio
);
timeout
=
0
;
}
default:
break
;
/*
* If device behind the port is not a keyboard there
* won't be 2nd byte of ID response.
*/
if
(
!
ps2_is_keyboard_id
(
ps2dev
->
cmdbuf
[
1
]))
{
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
flags
=
ps2dev
->
cmdcnt
=
0
;
serio_continue_rx
(
ps2dev
->
serio
);
timeout
=
0
;
}
break
;
default:
break
;
}
return
timeout
;
...
...
@@ -178,50 +227,60 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
* ps2_command() can only be called from a process context
*/
int
__ps2_command
(
struct
ps2dev
*
ps2dev
,
u
nsigned
char
*
param
,
int
command
)
int
__ps2_command
(
struct
ps2dev
*
ps2dev
,
u
8
*
param
,
unsigned
int
command
)
{
int
timeout
;
int
send
=
(
command
>>
12
)
&
0xf
;
int
receive
=
(
command
>>
8
)
&
0xf
;
int
rc
=
-
1
;
unsigned
int
timeout
;
unsigned
int
send
=
(
command
>>
12
)
&
0xf
;
unsigned
int
receive
=
(
command
>>
8
)
&
0xf
;
int
rc
;
int
i
;
u8
send_param
[
16
];
if
(
receive
>
sizeof
(
ps2dev
->
cmdbuf
))
{
WARN_ON
(
1
);
return
-
1
;
return
-
EINVAL
;
}
if
(
send
&&
!
param
)
{
WARN_ON
(
1
);
return
-
1
;
return
-
EINVAL
;
}
memcpy
(
send_param
,
param
,
send
);
serio_pause_rx
(
ps2dev
->
serio
);
ps2dev
->
flags
=
command
==
PS2_CMD_GETID
?
PS2_FLAG_WAITID
:
0
;
ps2dev
->
cmdcnt
=
receive
;
if
(
receive
&&
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
ps2dev
->
cmdbuf
[(
receive
-
1
)
-
i
]
=
param
[
i
];
serio_continue_rx
(
ps2dev
->
serio
);
/* Signal that we are sending the command byte */
ps2dev
->
flags
|=
PS2_FLAG_ACK_CMD
;
/*
* Some devices (Synaptics) peform the reset before
* ACKing the reset command, and so it can take a long
* time before the ACK arrives.
*/
if
(
ps2_sendbyte
(
ps2dev
,
command
&
0xff
,
command
==
PS2_CMD_RESET_BAT
?
1000
:
200
))
{
serio_pause_rx
(
ps2dev
->
serio
);
timeout
=
command
==
PS2_CMD_RESET_BAT
?
1000
:
200
;
rc
=
ps2_do_sendbyte
(
ps2dev
,
command
&
0xff
,
timeout
,
2
);
if
(
rc
)
goto
out_reset_flags
;
}
/* Now we are sending command parameters, if any */
ps2dev
->
flags
&=
~
PS2_FLAG_ACK_CMD
;
for
(
i
=
0
;
i
<
send
;
i
++
)
{
if
(
ps2_sendbyte
(
ps2dev
,
param
[
i
],
200
))
{
serio_pause_rx
(
ps2dev
->
serio
);
rc
=
ps2_do_sendbyte
(
ps2dev
,
param
[
i
],
200
,
2
);
if
(
rc
)
goto
out_reset_flags
;
}
}
serio_continue_rx
(
ps2dev
->
serio
);
/*
* The reset command takes a long time to execute.
*/
...
...
@@ -243,8 +302,11 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
for
(
i
=
0
;
i
<
receive
;
i
++
)
param
[
i
]
=
ps2dev
->
cmdbuf
[(
receive
-
1
)
-
i
];
if
(
ps2dev
->
cmdcnt
&&
(
command
!=
PS2_CMD_RESET_BAT
||
ps2dev
->
cmdcnt
!=
1
))
if
(
ps2dev
->
cmdcnt
&&
(
command
!=
PS2_CMD_RESET_BAT
||
ps2dev
->
cmdcnt
!=
1
))
{
rc
=
-
EPROTO
;
goto
out_reset_flags
;
}
rc
=
0
;
...
...
@@ -252,11 +314,21 @@ int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
ps2dev
->
flags
=
0
;
serio_continue_rx
(
ps2dev
->
serio
);
return
rc
;
dev_dbg
(
&
ps2dev
->
serio
->
dev
,
"%02x [%*ph] - %x/%08lx [%*ph]
\n
"
,
command
&
0xff
,
send
,
send_param
,
ps2dev
->
nak
,
ps2dev
->
flags
,
receive
,
param
?:
send_param
);
/*
* ps_command() handles resends itself, so do not leak -EAGAIN
* to the callers.
*/
return
rc
!=
-
EAGAIN
?
rc
:
-
EPROTO
;
}
EXPORT_SYMBOL
(
__ps2_command
);
int
ps2_command
(
struct
ps2dev
*
ps2dev
,
u
nsigned
char
*
param
,
int
command
)
int
ps2_command
(
struct
ps2dev
*
ps2dev
,
u
8
*
param
,
unsigned
int
command
)
{
int
rc
;
...
...
@@ -268,6 +340,39 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
}
EXPORT_SYMBOL
(
ps2_command
);
/*
* ps2_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech
* or Synaptics touchpads. The command is encoded as:
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command.
*/
int
ps2_sliced_command
(
struct
ps2dev
*
ps2dev
,
u8
command
)
{
int
i
;
int
retval
;
ps2_begin_command
(
ps2dev
);
retval
=
__ps2_command
(
ps2dev
,
NULL
,
PS2_CMD_SETSCALE11
);
if
(
retval
)
goto
out
;
for
(
i
=
6
;
i
>=
0
;
i
-=
2
)
{
u8
d
=
(
command
>>
i
)
&
3
;
retval
=
__ps2_command
(
ps2dev
,
&
d
,
PS2_CMD_SETRES
);
if
(
retval
)
break
;
}
out:
dev_dbg
(
&
ps2dev
->
serio
->
dev
,
"%02x - %d
\n
"
,
command
,
retval
);
ps2_end_command
(
ps2dev
);
return
retval
;
}
EXPORT_SYMBOL
(
ps2_sliced_command
);
/*
* ps2_init() initializes ps2dev structure
*/
...
...
@@ -286,42 +391,53 @@ EXPORT_SYMBOL(ps2_init);
* to properly process ACK/NAK of a command from a PS/2 device.
*/
int
ps2_handle_ack
(
struct
ps2dev
*
ps2dev
,
unsigned
char
data
)
bool
ps2_handle_ack
(
struct
ps2dev
*
ps2dev
,
u8
data
)
{
switch
(
data
)
{
case
PS2_RET_ACK
:
ps2dev
->
nak
=
0
;
case
PS2_RET_ACK
:
ps2dev
->
nak
=
0
;
break
;
case
PS2_RET_NAK
:
ps2dev
->
flags
|=
PS2_FLAG_NAK
;
ps2dev
->
nak
=
PS2_RET_NAK
;
break
;
case
PS2_RET_ERR
:
if
(
ps2dev
->
flags
&
PS2_FLAG_NAK
)
{
ps2dev
->
flags
&=
~
PS2_FLAG_NAK
;
ps2dev
->
nak
=
PS2_RET_ERR
;
break
;
}
case
PS2_RET_NAK
:
ps2dev
->
flags
|=
PS2_FLAG_NAK
;
ps2dev
->
nak
=
PS2_RET_NAK
;
/*
* Workaround for mice which don't ACK the Get ID command.
* These are valid mouse IDs that we recognize.
*/
case
0x00
:
case
0x03
:
case
0x04
:
if
(
ps2dev
->
flags
&
PS2_FLAG_WAITID
)
{
ps2dev
->
nak
=
0
;
break
;
case
PS2_RET_ERR
:
if
(
ps2dev
->
flags
&
PS2_FLAG_NAK
)
{
ps2dev
->
flags
&=
~
PS2_FLAG_NAK
;
ps2dev
->
nak
=
PS2_RET_ERR
;
break
;
}
}
/* Fall through */
default:
/*
* Workaround for mice which don't ACK the Get ID command.
* These are valid mouse IDs that we recognize.
* Do not signal errors if we get unexpected reply while
* waiting for an ACK to the initial (first) command byte:
* the device might not be quiesced yet and continue
* delivering data.
* Note that we reset PS2_FLAG_WAITID flag, so the workaround
* for mice not acknowledging the Get ID command only triggers
* on the 1st byte; if device spews data we really want to see
* a real ACK from it.
*/
case
0x00
:
case
0x03
:
case
0x04
:
if
(
ps2dev
->
flags
&
PS2_FLAG_WAITID
)
{
ps2dev
->
nak
=
0
;
break
;
}
/* Fall through */
default:
return
0
;
dev_dbg
(
&
ps2dev
->
serio
->
dev
,
"unexpected %#02x
\n
"
,
data
);
ps2dev
->
flags
&=
~
PS2_FLAG_WAITID
;
return
ps2dev
->
flags
&
PS2_FLAG_ACK_CMD
;
}
if
(
!
ps2dev
->
nak
)
{
ps2dev
->
flags
&=
~
PS2_FLAG_NAK
;
if
(
ps2dev
->
cmdcnt
)
...
...
@@ -334,7 +450,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
if
(
data
!=
PS2_RET_ACK
)
ps2_handle_response
(
ps2dev
,
data
);
return
1
;
return
true
;
}
EXPORT_SYMBOL
(
ps2_handle_ack
);
...
...
@@ -344,7 +460,7 @@ EXPORT_SYMBOL(ps2_handle_ack);
* waiting for completion of the command.
*/
int
ps2_handle_response
(
struct
ps2dev
*
ps2dev
,
unsigned
char
data
)
bool
ps2_handle_response
(
struct
ps2dev
*
ps2dev
,
u8
data
)
{
if
(
ps2dev
->
cmdcnt
)
ps2dev
->
cmdbuf
[
--
ps2dev
->
cmdcnt
]
=
data
;
...
...
@@ -360,7 +476,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
wake_up
(
&
ps2dev
->
wait
);
}
return
1
;
return
true
;
}
EXPORT_SYMBOL
(
ps2_handle_response
);
...
...
include/linux/libps2.h
View file @
ba521f1b
...
...
@@ -10,7 +10,13 @@
* the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/wait.h>
#define PS2_CMD_SETSCALE11 0x00e6
#define PS2_CMD_SETRES 0x10e8
#define PS2_CMD_GETID 0x02f2
#define PS2_CMD_RESET_BAT 0x02ff
...
...
@@ -20,11 +26,12 @@
#define PS2_RET_NAK 0xfe
#define PS2_RET_ERR 0xfc
#define PS2_FLAG_ACK 1
/* Waiting for ACK/NAK */
#define PS2_FLAG_CMD 2
/* Waiting for command to finish */
#define PS2_FLAG_CMD1 4
/* Waiting for the first byte of command response */
#define PS2_FLAG_WAITID 8
/* Command execiting is GET ID */
#define PS2_FLAG_NAK 16
/* Last transmission was NAKed */
#define PS2_FLAG_ACK BIT(0)
/* Waiting for ACK/NAK */
#define PS2_FLAG_CMD BIT(1)
/* Waiting for a command to finish */
#define PS2_FLAG_CMD1 BIT(2)
/* Waiting for the first byte of command response */
#define PS2_FLAG_WAITID BIT(3)
/* Command executing is GET ID */
#define PS2_FLAG_NAK BIT(4)
/* Last transmission was NAKed */
#define PS2_FLAG_ACK_CMD BIT(5)
/* Waiting to ACK the command (first) byte */
struct
ps2dev
{
struct
serio
*
serio
;
...
...
@@ -36,21 +43,22 @@ struct ps2dev {
wait_queue_head_t
wait
;
unsigned
long
flags
;
u
nsigned
char
cmdbuf
[
8
];
u
nsigned
char
cmdcnt
;
u
nsigned
char
nak
;
u
8
cmdbuf
[
8
];
u
8
cmdcnt
;
u
8
nak
;
};
void
ps2_init
(
struct
ps2dev
*
ps2dev
,
struct
serio
*
serio
);
int
ps2_sendbyte
(
struct
ps2dev
*
ps2dev
,
u
nsigned
char
byte
,
int
timeout
);
void
ps2_drain
(
struct
ps2dev
*
ps2dev
,
int
maxbytes
,
int
timeout
);
int
ps2_sendbyte
(
struct
ps2dev
*
ps2dev
,
u
8
byte
,
unsigned
int
timeout
);
void
ps2_drain
(
struct
ps2dev
*
ps2dev
,
size_t
maxbytes
,
unsigned
int
timeout
);
void
ps2_begin_command
(
struct
ps2dev
*
ps2dev
);
void
ps2_end_command
(
struct
ps2dev
*
ps2dev
);
int
__ps2_command
(
struct
ps2dev
*
ps2dev
,
unsigned
char
*
param
,
int
command
);
int
ps2_command
(
struct
ps2dev
*
ps2dev
,
unsigned
char
*
param
,
int
command
);
int
ps2_handle_ack
(
struct
ps2dev
*
ps2dev
,
unsigned
char
data
);
int
ps2_handle_response
(
struct
ps2dev
*
ps2dev
,
unsigned
char
data
);
int
__ps2_command
(
struct
ps2dev
*
ps2dev
,
u8
*
param
,
unsigned
int
command
);
int
ps2_command
(
struct
ps2dev
*
ps2dev
,
u8
*
param
,
unsigned
int
command
);
int
ps2_sliced_command
(
struct
ps2dev
*
ps2dev
,
u8
command
);
bool
ps2_handle_ack
(
struct
ps2dev
*
ps2dev
,
u8
data
);
bool
ps2_handle_response
(
struct
ps2dev
*
ps2dev
,
u8
data
);
void
ps2_cmd_aborted
(
struct
ps2dev
*
ps2dev
);
int
ps2_is_keyboard_id
(
char
id
);
bool
ps2_is_keyboard_id
(
u8
id
);
#endif
/* _LIBPS2_H */
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