diff options
Diffstat (limited to 'drivers/input/serio/libps2.c')
-rw-r--r-- | drivers/input/serio/libps2.c | 136 |
1 files changed, 100 insertions, 36 deletions
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index c978657068c5..d4c990f7c85e 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c | |||
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL"); | |||
29 | 29 | ||
30 | EXPORT_SYMBOL(ps2_init); | 30 | EXPORT_SYMBOL(ps2_init); |
31 | EXPORT_SYMBOL(ps2_sendbyte); | 31 | EXPORT_SYMBOL(ps2_sendbyte); |
32 | EXPORT_SYMBOL(ps2_drain); | ||
32 | EXPORT_SYMBOL(ps2_command); | 33 | EXPORT_SYMBOL(ps2_command); |
33 | EXPORT_SYMBOL(ps2_schedule_command); | 34 | EXPORT_SYMBOL(ps2_schedule_command); |
34 | EXPORT_SYMBOL(ps2_handle_ack); | 35 | EXPORT_SYMBOL(ps2_handle_ack); |
@@ -45,11 +46,11 @@ struct ps2work { | |||
45 | 46 | ||
46 | 47 | ||
47 | /* | 48 | /* |
48 | * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge. | 49 | * ps2_sendbyte() sends a byte to the device and waits for acknowledge. |
49 | * It doesn't handle retransmission, though it could - because when there would | 50 | * It doesn't handle retransmission, though it could - because if there |
50 | * be need for retransmissions, the mouse has to be replaced anyway. | 51 | * is a need for retransmissions device has to be replaced anyway. |
51 | * | 52 | * |
52 | * ps2_sendbyte() can only be called from a process context | 53 | * ps2_sendbyte() can only be called from a process context. |
53 | */ | 54 | */ |
54 | 55 | ||
55 | int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) | 56 | int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) |
@@ -72,6 +73,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) | |||
72 | } | 73 | } |
73 | 74 | ||
74 | /* | 75 | /* |
76 | * ps2_drain() waits for device to transmit requested number of bytes | ||
77 | * and discards them. | ||
78 | */ | ||
79 | |||
80 | void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) | ||
81 | { | ||
82 | if (maxbytes > sizeof(ps2dev->cmdbuf)) { | ||
83 | WARN_ON(1); | ||
84 | maxbytes = sizeof(ps2dev->cmdbuf); | ||
85 | } | ||
86 | |||
87 | down(&ps2dev->cmd_sem); | ||
88 | |||
89 | serio_pause_rx(ps2dev->serio); | ||
90 | ps2dev->flags = PS2_FLAG_CMD; | ||
91 | ps2dev->cmdcnt = maxbytes; | ||
92 | serio_continue_rx(ps2dev->serio); | ||
93 | |||
94 | wait_event_timeout(ps2dev->wait, | ||
95 | !(ps2dev->flags & PS2_FLAG_CMD), | ||
96 | msecs_to_jiffies(timeout)); | ||
97 | up(&ps2dev->cmd_sem); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * ps2_is_keyboard_id() checks received ID byte against the list of | ||
102 | * known keyboard IDs. | ||
103 | */ | ||
104 | |||
105 | static inline int ps2_is_keyboard_id(char id_byte) | ||
106 | { | ||
107 | static char keyboard_ids[] = { | ||
108 | 0xab, /* Regular keyboards */ | ||
109 | 0xac, /* NCD Sun keyboard */ | ||
110 | 0x2b, /* Trust keyboard, translated */ | ||
111 | 0x5d, /* Trust keyboard */ | ||
112 | 0x60, /* NMB SGI keyboard, translated */ | ||
113 | 0x47, /* NMB SGI keyboard */ | ||
114 | }; | ||
115 | |||
116 | return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * ps2_adjust_timeout() is called after receiving 1st byte of command | ||
121 | * response and tries to reduce remaining timeout to speed up command | ||
122 | * completion. | ||
123 | */ | ||
124 | |||
125 | static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) | ||
126 | { | ||
127 | switch (command) { | ||
128 | case PS2_CMD_RESET_BAT: | ||
129 | /* | ||
130 | * Device has sent the first response byte after | ||
131 | * reset command, reset is thus done, so we can | ||
132 | * shorten the timeout. | ||
133 | * The next byte will come soon (keyboard) or not | ||
134 | * at all (mouse). | ||
135 | */ | ||
136 | if (timeout > msecs_to_jiffies(100)) | ||
137 | timeout = msecs_to_jiffies(100); | ||
138 | break; | ||
139 | |||
140 | case PS2_CMD_GETID: | ||
141 | /* | ||
142 | * If device behind the port is not a keyboard there | ||
143 | * won't be 2nd byte of ID response. | ||
144 | */ | ||
145 | if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) { | ||
146 | serio_pause_rx(ps2dev->serio); | ||
147 | ps2dev->flags = ps2dev->cmdcnt = 0; | ||
148 | serio_continue_rx(ps2dev->serio); | ||
149 | timeout = 0; | ||
150 | } | ||
151 | break; | ||
152 | |||
153 | default: | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | return timeout; | ||
158 | } | ||
159 | |||
160 | /* | ||
75 | * ps2_command() sends a command and its parameters to the mouse, | 161 | * ps2_command() sends a command and its parameters to the mouse, |
76 | * then waits for the response and puts it in the param array. | 162 | * then waits for the response and puts it in the param array. |
77 | * | 163 | * |
@@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |||
86 | int rc = -1; | 172 | int rc = -1; |
87 | int i; | 173 | int i; |
88 | 174 | ||
175 | if (receive > sizeof(ps2dev->cmdbuf)) { | ||
176 | WARN_ON(1); | ||
177 | return -1; | ||
178 | } | ||
179 | |||
89 | down(&ps2dev->cmd_sem); | 180 | down(&ps2dev->cmd_sem); |
90 | 181 | ||
91 | serio_pause_rx(ps2dev->serio); | 182 | serio_pause_rx(ps2dev->serio); |
@@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |||
101 | * ACKing the reset command, and so it can take a long | 192 | * ACKing the reset command, and so it can take a long |
102 | * time before the ACK arrrives. | 193 | * time before the ACK arrrives. |
103 | */ | 194 | */ |
104 | if (command & 0xff) | 195 | if (ps2_sendbyte(ps2dev, command & 0xff, |
105 | if (ps2_sendbyte(ps2dev, command & 0xff, | 196 | command == PS2_CMD_RESET_BAT ? 1000 : 200)) |
106 | command == PS2_CMD_RESET_BAT ? 1000 : 200)) | 197 | goto out; |
107 | goto out; | ||
108 | 198 | ||
109 | for (i = 0; i < send; i++) | 199 | for (i = 0; i < send; i++) |
110 | if (ps2_sendbyte(ps2dev, param[i], 200)) | 200 | if (ps2_sendbyte(ps2dev, param[i], 200)) |
@@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |||
120 | 210 | ||
121 | if (ps2dev->cmdcnt && timeout > 0) { | 211 | if (ps2dev->cmdcnt && timeout > 0) { |
122 | 212 | ||
123 | if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) { | 213 | timeout = ps2_adjust_timeout(ps2dev, command, timeout); |
124 | /* | ||
125 | * Device has sent the first response byte | ||
126 | * after a reset command, reset is thus done, | ||
127 | * shorten the timeout. The next byte will come | ||
128 | * soon (keyboard) or not at all (mouse). | ||
129 | */ | ||
130 | timeout = msecs_to_jiffies(100); | ||
131 | } | ||
132 | |||
133 | if (command == PS2_CMD_GETID && | ||
134 | ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */ | ||
135 | ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */ | ||
136 | ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */ | ||
137 | ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */ | ||
138 | ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */ | ||
139 | ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */ | ||
140 | /* | ||
141 | * Device behind the port is not a keyboard | ||
142 | * so we don't need to wait for the 2nd byte | ||
143 | * of ID response. | ||
144 | */ | ||
145 | serio_pause_rx(ps2dev->serio); | ||
146 | ps2dev->flags = ps2dev->cmdcnt = 0; | ||
147 | serio_continue_rx(ps2dev->serio); | ||
148 | } | ||
149 | |||
150 | wait_event_timeout(ps2dev->wait, | 214 | wait_event_timeout(ps2dev->wait, |
151 | !(ps2dev->flags & PS2_FLAG_CMD), timeout); | 215 | !(ps2dev->flags & PS2_FLAG_CMD), timeout); |
152 | } | 216 | } |
@@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |||
160 | 224 | ||
161 | rc = 0; | 225 | rc = 0; |
162 | 226 | ||
163 | out: | 227 | out: |
164 | serio_pause_rx(ps2dev->serio); | 228 | serio_pause_rx(ps2dev->serio); |
165 | ps2dev->flags = 0; | 229 | ps2dev->flags = 0; |
166 | serio_continue_rx(ps2dev->serio); | 230 | serio_continue_rx(ps2dev->serio); |