aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Pospesel <pospeselr@gmail.com>2016-03-14 12:41:16 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2016-03-17 20:04:54 -0400
commit2d5f5611dd0de52e9a52b56391a7049a52184e72 (patch)
treeb36b2d238a2b9865a5c9297789c0288348fd341b
parenta0ad220c96692eda76b2e3fd7279f3dcd1d8a8ff (diff)
Input: byd - enable absolute mode
The Windows driver's settings dialog contains a visualization of the regions for the hardware edge scrolling capability, which uses a temporarily-enabled limited-resolution absolute mode. This patch enables this during normal operation, and combines the absolute packets with the existing relative packets to provide accurate absolute position and touch reporting. It also adds documentation for all known gesture packets and initialization commands. Reviewed-by: Chris Diamand <chris@diamand.org> Signed-off-by: Richard Pospesel <pospeselr@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/mouse/byd.c565
-rw-r--r--drivers/input/mouse/psmouse-base.c2
2 files changed, 369 insertions, 198 deletions
diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c
index 9425e0f6c5ce..fdc243ca93ed 100644
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -12,10 +12,12 @@
12#include <linux/input.h> 12#include <linux/input.h>
13#include <linux/libps2.h> 13#include <linux/libps2.h>
14#include <linux/serio.h> 14#include <linux/serio.h>
15#include <linux/slab.h>
15 16
16#include "psmouse.h" 17#include "psmouse.h"
17#include "byd.h" 18#include "byd.h"
18 19
20/* PS2 Bits */
19#define PS2_Y_OVERFLOW BIT_MASK(7) 21#define PS2_Y_OVERFLOW BIT_MASK(7)
20#define PS2_X_OVERFLOW BIT_MASK(6) 22#define PS2_X_OVERFLOW BIT_MASK(6)
21#define PS2_Y_SIGN BIT_MASK(5) 23#define PS2_Y_SIGN BIT_MASK(5)
@@ -26,69 +28,249 @@
26#define PS2_LEFT BIT_MASK(0) 28#define PS2_LEFT BIT_MASK(0)
27 29
28/* 30/*
29 * The touchpad reports gestures in the last byte of each packet. It can take 31 * BYD pad constants
30 * any of the following values:
31 */ 32 */
32 33
33/* One-finger scrolling in one of the edge scroll zones. */ 34/*
34#define BYD_SCROLLUP 0xCA 35 * True device resolution is unknown, however experiments show the
35#define BYD_SCROLLDOWN 0x36 36 * resolution is about 111 units/mm.
36#define BYD_SCROLLLEFT 0xCB 37 * Absolute coordinate packets are in the range 0-255 for both X and Y
37#define BYD_SCROLLRIGHT 0x35 38 * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in
38/* Two-finger scrolling. */ 39 * the right ballpark given the touchpad's physical dimensions and estimate
39#define BYD_2DOWN 0x2B 40 * resolution per spec sheet, device active area dimensions are
40#define BYD_2UP 0xD5 41 * 101.6 x 60.1 mm.
41#define BYD_2LEFT 0xD6 42 */
42#define BYD_2RIGHT 0x2A 43#define BYD_PAD_WIDTH 11264
43/* Pinching in or out. */ 44#define BYD_PAD_HEIGHT 6656
44#define BYD_ZOOMOUT 0xD8 45#define BYD_PAD_RESOLUTION 111
45#define BYD_ZOOMIN 0x28
46/* Three-finger swipe. */
47#define BYD_3UP 0xD3
48#define BYD_3DOWN 0x2D
49#define BYD_3LEFT 0xD4
50#define BYD_3RIGHT 0x2C
51/* Four-finger swipe. */
52#define BYD_4UP 0xCD
53#define BYD_4DOWN 0x33
54 46
55int byd_detect(struct psmouse *psmouse, bool set_properties) 47/*
48 * Given the above dimensions, relative packets velocity is in multiples of
49 * 1 unit / 11 milliseconds. We use this dt to estimate distance traveled
50 */
51#define BYD_DT 11
52/* Time in jiffies used to timeout various touch events (64 ms) */
53#define BYD_TOUCH_TIMEOUT msecs_to_jiffies(64)
54
55/* BYD commands reverse engineered from windows driver */
56
57/*
58 * Swipe gesture from off-pad to on-pad
59 * 0 : disable
60 * 1 : enable
61 */
62#define BYD_CMD_SET_OFFSCREEN_SWIPE 0x10cc
63/*
64 * Tap and drag delay time
65 * 0 : disable
66 * 1 - 8 : least to most delay
67 */
68#define BYD_CMD_SET_TAP_DRAG_DELAY_TIME 0x10cf
69/*
70 * Physical buttons function mapping
71 * 0 : enable
72 * 4 : normal
73 * 5 : left button custom command
74 * 6 : right button custom command
75 * 8 : disable
76 */
77#define BYD_CMD_SET_PHYSICAL_BUTTONS 0x10d0
78/*
79 * Absolute mode (1 byte X/Y resolution)
80 * 0 : disable
81 * 2 : enable
82 */
83#define BYD_CMD_SET_ABSOLUTE_MODE 0x10d1
84/*
85 * Two finger scrolling
86 * 1 : vertical
87 * 2 : horizontal
88 * 3 : vertical + horizontal
89 * 4 : disable
90 */
91#define BYD_CMD_SET_TWO_FINGER_SCROLL 0x10d2
92/*
93 * Handedness
94 * 1 : right handed
95 * 2 : left handed
96 */
97#define BYD_CMD_SET_HANDEDNESS 0x10d3
98/*
99 * Tap to click
100 * 1 : enable
101 * 2 : disable
102 */
103#define BYD_CMD_SET_TAP 0x10d4
104/*
105 * Tap and drag
106 * 1 : tap and hold to drag
107 * 2 : tap and hold to drag + lock
108 * 3 : disable
109 */
110#define BYD_CMD_SET_TAP_DRAG 0x10d5
111/*
112 * Touch sensitivity
113 * 1 - 7 : least to most sensitive
114 */
115#define BYD_CMD_SET_TOUCH_SENSITIVITY 0x10d6
116/*
117 * One finger scrolling
118 * 1 : vertical
119 * 2 : horizontal
120 * 3 : vertical + horizontal
121 * 4 : disable
122 */
123#define BYD_CMD_SET_ONE_FINGER_SCROLL 0x10d7
124/*
125 * One finger scrolling function
126 * 1 : free scrolling
127 * 2 : edge motion
128 * 3 : free scrolling + edge motion
129 * 4 : disable
130 */
131#define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC 0x10d8
132/*
133 * Sliding speed
134 * 1 - 5 : slowest to fastest
135 */
136#define BYD_CMD_SET_SLIDING_SPEED 0x10da
137/*
138 * Edge motion
139 * 1 : disable
140 * 2 : enable when dragging
141 * 3 : enable when dragging and pointing
142 */
143#define BYD_CMD_SET_EDGE_MOTION 0x10db
144/*
145 * Left edge region size
146 * 0 - 7 : smallest to largest width
147 */
148#define BYD_CMD_SET_LEFT_EDGE_REGION 0x10dc
149/*
150 * Top edge region size
151 * 0 - 9 : smallest to largest height
152 */
153#define BYD_CMD_SET_TOP_EDGE_REGION 0x10dd
154/*
155 * Disregard palm press as clicks
156 * 1 - 6 : smallest to largest
157 */
158#define BYD_CMD_SET_PALM_CHECK 0x10de
159/*
160 * Right edge region size
161 * 0 - 7 : smallest to largest width
162 */
163#define BYD_CMD_SET_RIGHT_EDGE_REGION 0x10df
164/*
165 * Bottom edge region size
166 * 0 - 9 : smallest to largest height
167 */
168#define BYD_CMD_SET_BOTTOM_EDGE_REGION 0x10e1
169/*
170 * Multitouch gestures
171 * 1 : enable
172 * 2 : disable
173 */
174#define BYD_CMD_SET_MULTITOUCH 0x10e3
175/*
176 * Edge motion speed
177 * 0 : control with finger pressure
178 * 1 - 9 : slowest to fastest
179 */
180#define BYD_CMD_SET_EDGE_MOTION_SPEED 0x10e4
181/*
182 * Two finger scolling function
183 * 0 : free scrolling
184 * 1 : free scrolling (with momentum)
185 * 2 : edge motion
186 * 3 : free scrolling (with momentum) + edge motion
187 * 4 : disable
188 */
189#define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC 0x10e5
190
191/*
192 * The touchpad generates a mixture of absolute and relative packets, indicated
193 * by the the last byte of each packet being set to one of the following:
194 */
195#define BYD_PACKET_ABSOLUTE 0xf8
196#define BYD_PACKET_RELATIVE 0x00
197/* Multitouch gesture packets */
198#define BYD_PACKET_PINCH_IN 0xd8
199#define BYD_PACKET_PINCH_OUT 0x28
200#define BYD_PACKET_ROTATE_CLOCKWISE 0x29
201#define BYD_PACKET_ROTATE_ANTICLOCKWISE 0xd7
202#define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT 0x2a
203#define BYD_PACKET_TWO_FINGER_SCROLL_DOWN 0x2b
204#define BYD_PACKET_TWO_FINGER_SCROLL_UP 0xd5
205#define BYD_PACKET_TWO_FINGER_SCROLL_LEFT 0xd6
206#define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT 0x2c
207#define BYD_PACKET_THREE_FINGER_SWIPE_DOWN 0x2d
208#define BYD_PACKET_THREE_FINGER_SWIPE_UP 0xd3
209#define BYD_PACKET_THREE_FINGER_SWIPE_LEFT 0xd4
210#define BYD_PACKET_FOUR_FINGER_DOWN 0x33
211#define BYD_PACKET_FOUR_FINGER_UP 0xcd
212#define BYD_PACKET_REGION_SCROLL_RIGHT 0x35
213#define BYD_PACKET_REGION_SCROLL_DOWN 0x36
214#define BYD_PACKET_REGION_SCROLL_UP 0xca
215#define BYD_PACKET_REGION_SCROLL_LEFT 0xcb
216#define BYD_PACKET_RIGHT_CORNER_CLICK 0xd2
217#define BYD_PACKET_LEFT_CORNER_CLICK 0x2e
218#define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f
219#define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT 0x37
220#define BYD_PACKET_ONTO_PAD_SWIPE_DOWN 0x30
221#define BYD_PACKET_ONTO_PAD_SWIPE_UP 0xd0
222#define BYD_PACKET_ONTO_PAD_SWIPE_LEFT 0xc9
223
224struct byd_data {
225 struct timer_list timer;
226 s32 abs_x;
227 s32 abs_y;
228 typeof(jiffies) last_touch_time;
229 bool btn_left;
230 bool btn_right;
231 bool touch;
232};
233
234static void byd_report_input(struct psmouse *psmouse)
56{ 235{
57 struct ps2dev *ps2dev = &psmouse->ps2dev; 236 struct byd_data *priv = psmouse->private;
58 unsigned char param[4]; 237 struct input_dev *dev = psmouse->dev;
59 238
60 param[0] = 0x03; 239 input_report_key(dev, BTN_TOUCH, priv->touch);
61 param[1] = 0x00; 240 input_report_key(dev, BTN_TOOL_FINGER, priv->touch);
62 param[2] = 0x00;
63 param[3] = 0x00;
64 241
65 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 242 input_report_abs(dev, ABS_X, priv->abs_x);
66 return -1; 243 input_report_abs(dev, ABS_Y, priv->abs_y);
67 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 244 input_report_key(dev, BTN_LEFT, priv->btn_left);
68 return -1; 245 input_report_key(dev, BTN_RIGHT, priv->btn_right);
69 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
70 return -1;
71 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
72 return -1;
73 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
74 return -1;
75 246
76 if (param[1] != 0x03 || param[2] != 0x64) 247 input_sync(dev);
77 return -ENODEV; 248}
78 249
79 psmouse_dbg(psmouse, "BYD touchpad detected\n"); 250static void byd_clear_touch(unsigned long data)
251{
252 struct psmouse *psmouse = (struct psmouse *)data;
253 struct byd_data *priv = psmouse->private;
80 254
81 if (set_properties) { 255 serio_pause_rx(psmouse->ps2dev.serio);
82 psmouse->vendor = "BYD"; 256 priv->touch = false;
83 psmouse->name = "TouchPad";
84 }
85 257
86 return 0; 258 byd_report_input(psmouse);
259
260 serio_continue_rx(psmouse->ps2dev.serio);
261
262 /*
263 * Move cursor back to center of pad when we lose touch - this
264 * specifically improves user experience when moving cursor with one
265 * finger, and pressing a button with another.
266 */
267 priv->abs_x = BYD_PAD_WIDTH / 2;
268 priv->abs_y = BYD_PAD_HEIGHT / 2;
87} 269}
88 270
89static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) 271static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
90{ 272{
91 struct input_dev *dev = psmouse->dev; 273 struct byd_data *priv = psmouse->private;
92 u8 *pkt = psmouse->packet; 274 u8 *pkt = psmouse->packet;
93 275
94 if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) { 276 if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) {
@@ -102,53 +284,34 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
102 284
103 /* Otherwise, a full packet has been received */ 285 /* Otherwise, a full packet has been received */
104 switch (pkt[3]) { 286 switch (pkt[3]) {
105 case 0: { 287 case BYD_PACKET_ABSOLUTE:
288 /* Only use absolute packets for the start of movement. */
289 if (!priv->touch) {
290 /* needed to detect tap */
291 typeof(jiffies) tap_time =
292 priv->last_touch_time + BYD_TOUCH_TIMEOUT;
293 priv->touch = time_after(jiffies, tap_time);
294
295 /* init abs position */
296 priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256);
297 priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256);
298 }
299 break;
300 case BYD_PACKET_RELATIVE: {
106 /* Standard packet */ 301 /* Standard packet */
107 /* Sign-extend if a sign bit is set. */ 302 /* Sign-extend if a sign bit is set. */
108 unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; 303 u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
109 unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; 304 u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
110 int dx = signx | (int) pkt[1]; 305 s32 dx = signx | (int) pkt[1];
111 int dy = signy | (int) pkt[2]; 306 s32 dy = signy | (int) pkt[2];
112 307
113 input_report_rel(psmouse->dev, REL_X, dx); 308 /* Update position based on velocity */
114 input_report_rel(psmouse->dev, REL_Y, -dy); 309 priv->abs_x += dx * BYD_DT;
310 priv->abs_y -= dy * BYD_DT;
115 311
116 input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & PS2_LEFT); 312 priv->touch = true;
117 input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & PS2_RIGHT);
118 input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & PS2_MIDDLE);
119 break; 313 break;
120 } 314 }
121
122 case BYD_SCROLLDOWN:
123 case BYD_2DOWN:
124 input_report_rel(dev, REL_WHEEL, -1);
125 break;
126
127 case BYD_SCROLLUP:
128 case BYD_2UP:
129 input_report_rel(dev, REL_WHEEL, 1);
130 break;
131
132 case BYD_SCROLLLEFT:
133 case BYD_2LEFT:
134 input_report_rel(dev, REL_HWHEEL, -1);
135 break;
136
137 case BYD_SCROLLRIGHT:
138 case BYD_2RIGHT:
139 input_report_rel(dev, REL_HWHEEL, 1);
140 break;
141
142 case BYD_ZOOMOUT:
143 case BYD_ZOOMIN:
144 case BYD_3UP:
145 case BYD_3DOWN:
146 case BYD_3LEFT:
147 case BYD_3RIGHT:
148 case BYD_4UP:
149 case BYD_4DOWN:
150 break;
151
152 default: 315 default:
153 psmouse_warn(psmouse, 316 psmouse_warn(psmouse,
154 "Unrecognized Z: pkt = %02x %02x %02x %02x\n", 317 "Unrecognized Z: pkt = %02x %02x %02x %02x\n",
@@ -157,134 +320,76 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
157 return PSMOUSE_BAD_DATA; 320 return PSMOUSE_BAD_DATA;
158 } 321 }
159 322
160 input_sync(dev); 323 priv->btn_left = pkt[0] & PS2_LEFT;
324 priv->btn_right = pkt[0] & PS2_RIGHT;
161 325
162 return PSMOUSE_FULL_PACKET; 326 byd_report_input(psmouse);
163}
164 327
165/* Send a sequence of bytes, where each is ACKed before the next is sent. */ 328 /* Reset time since last touch. */
166static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, size_t len) 329 if (priv->touch) {
167{ 330 priv->last_touch_time = jiffies;
168 unsigned int i; 331 mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT);
169
170 for (i = 0; i < len; ++i) {
171 if (ps2_command(&psmouse->ps2dev, NULL, seq[i]))
172 return -1;
173 } 332 }
174 return 0;
175}
176
177/* Keep scrolling after fingers are removed. */
178#define SCROLL_INERTIAL 0x01
179#define SCROLL_NO_INERTIAL 0x02
180
181/* Clicking can be done by tapping or pressing. */
182#define CLICK_BOTH 0x01
183/* Clicking can only be done by pressing. */
184#define CLICK_PRESS_ONLY 0x02
185 333
186static int byd_enable(struct psmouse *psmouse) 334 return PSMOUSE_FULL_PACKET;
187{
188 const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 };
189 const u8 seq2[] = {
190 0xD3, 0x01,
191 0xD0, 0x00,
192 0xD0, 0x04,
193 /* Whether clicking is done by tapping or pressing. */
194 0xD4, CLICK_PRESS_ONLY,
195 0xD5, 0x01,
196 0xD7, 0x03,
197 /* Vertical and horizontal one-finger scroll zone inertia. */
198 0xD8, SCROLL_INERTIAL,
199 0xDA, 0x05,
200 0xDB, 0x02,
201 0xE4, 0x05,
202 0xD6, 0x01,
203 0xDE, 0x04,
204 0xE3, 0x01,
205 0xCF, 0x00,
206 0xD2, 0x03,
207 /* Vertical and horizontal two-finger scrolling inertia. */
208 0xE5, SCROLL_INERTIAL,
209 0xD9, 0x02,
210 0xD9, 0x07,
211 0xDC, 0x03,
212 0xDD, 0x03,
213 0xDF, 0x03,
214 0xE1, 0x03,
215 0xD1, 0x00,
216 0xCE, 0x00,
217 0xCC, 0x00,
218 0xE0, 0x00,
219 0xE2, 0x01
220 };
221 u8 param[4];
222
223 if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1)))
224 return -1;
225
226 /* Send a 0x01 command, which should return 4 bytes. */
227 if (ps2_command(&psmouse->ps2dev, param, 0x0401))
228 return -1;
229
230 if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2)))
231 return -1;
232
233 return 0;
234} 335}
235 336
236/* 337static int byd_reset_touchpad(struct psmouse *psmouse)
237 * Send the set of PS/2 commands required to make it identify as an
238 * intellimouse with 4-byte instead of 3-byte packets.
239 */
240static int byd_send_intellimouse_sequence(struct psmouse *psmouse)
241{ 338{
242 struct ps2dev *ps2dev = &psmouse->ps2dev; 339 struct ps2dev *ps2dev = &psmouse->ps2dev;
243 u8 param[4]; 340 u8 param[4];
244 int i; 341 size_t i;
342
245 const struct { 343 const struct {
246 u16 command; 344 u16 command;
247 u8 arg; 345 u8 arg;
248 } seq[] = { 346 } seq[] = {
249 { PSMOUSE_CMD_RESET_BAT, 0 }, 347 /*
250 { PSMOUSE_CMD_RESET_BAT, 0 }, 348 * Intellimouse initialization sequence, to get 4-byte instead
251 { PSMOUSE_CMD_GETID, 0 }, 349 * of 3-byte packets.
252 { PSMOUSE_CMD_SETSCALE11, 0 }, 350 */
253 { PSMOUSE_CMD_SETSCALE11, 0 },
254 { PSMOUSE_CMD_SETSCALE11, 0 },
255 { PSMOUSE_CMD_GETINFO, 0 },
256 { PSMOUSE_CMD_SETRES, 0x03 },
257 { PSMOUSE_CMD_SETRATE, 0xC8 }, 351 { PSMOUSE_CMD_SETRATE, 0xC8 },
258 { PSMOUSE_CMD_SETRATE, 0x64 }, 352 { PSMOUSE_CMD_SETRATE, 0x64 },
259 { PSMOUSE_CMD_SETRATE, 0x50 }, 353 { PSMOUSE_CMD_SETRATE, 0x50 },
260 { PSMOUSE_CMD_GETID, 0 }, 354 { PSMOUSE_CMD_GETID, 0 },
261 { PSMOUSE_CMD_SETRATE, 0xC8 }, 355 { PSMOUSE_CMD_ENABLE, 0 },
262 { PSMOUSE_CMD_SETRATE, 0xC8 }, 356 /*
263 { PSMOUSE_CMD_SETRATE, 0x50 }, 357 * BYD-specific initialization, which enables absolute mode and
264 { PSMOUSE_CMD_GETID, 0 }, 358 * (if desired), the touchpad's built-in gesture detection.
265 { PSMOUSE_CMD_SETRATE, 0x64 }, 359 */
266 { PSMOUSE_CMD_SETRES, 0x03 }, 360 { 0x10E2, 0x00 },
267 { PSMOUSE_CMD_ENABLE, 0 } 361 { 0x10E0, 0x02 },
362 /* The touchpad should reply with 4 seemingly-random bytes */
363 { 0x14E0, 0x01 },
364 /* Pairs of parameters and values. */
365 { BYD_CMD_SET_HANDEDNESS, 0x01 },
366 { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 },
367 { BYD_CMD_SET_TAP, 0x02 },
368 { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 },
369 { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 },
370 { BYD_CMD_SET_EDGE_MOTION, 0x01 },
371 { BYD_CMD_SET_PALM_CHECK, 0x00 },
372 { BYD_CMD_SET_MULTITOUCH, 0x02 },
373 { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 },
374 { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 },
375 { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 },
376 { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 },
377 { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 },
378 { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 },
379 { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 },
380 /* Finalize initialization. */
381 { 0x10E0, 0x00 },
382 { 0x10E2, 0x01 },
268 }; 383 };
269 384
270 memset(param, 0, sizeof(param));
271 for (i = 0; i < ARRAY_SIZE(seq); ++i) { 385 for (i = 0; i < ARRAY_SIZE(seq); ++i) {
386 memset(param, 0, sizeof(param));
272 param[0] = seq[i].arg; 387 param[0] = seq[i].arg;
273 if (ps2_command(ps2dev, param, seq[i].command)) 388 if (ps2_command(ps2dev, param, seq[i].command))
274 return -1; 389 return -EIO;
275 } 390 }
276 391
277 return 0; 392 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
278}
279
280static int byd_reset_touchpad(struct psmouse *psmouse)
281{
282 if (byd_send_intellimouse_sequence(psmouse))
283 return -EIO;
284
285 if (byd_enable(psmouse))
286 return -EIO;
287
288 return 0; 393 return 0;
289} 394}
290 395
@@ -314,9 +419,50 @@ static int byd_reconnect(struct psmouse *psmouse)
314 return 0; 419 return 0;
315} 420}
316 421
422static void byd_disconnect(struct psmouse *psmouse)
423{
424 struct byd_data *priv = psmouse->private;
425
426 if (priv) {
427 del_timer(&priv->timer);
428 kfree(psmouse->private);
429 psmouse->private = NULL;
430 }
431}
432
433int byd_detect(struct psmouse *psmouse, bool set_properties)
434{
435 struct ps2dev *ps2dev = &psmouse->ps2dev;
436 u8 param[4] = {0x03, 0x00, 0x00, 0x00};
437
438 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
439 return -1;
440 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
441 return -1;
442 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
443 return -1;
444 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
445 return -1;
446 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
447 return -1;
448
449 if (param[1] != 0x03 || param[2] != 0x64)
450 return -ENODEV;
451
452 psmouse_dbg(psmouse, "BYD touchpad detected\n");
453
454 if (set_properties) {
455 psmouse->vendor = "BYD";
456 psmouse->name = "TouchPad";
457 }
458
459 return 0;
460}
461
317int byd_init(struct psmouse *psmouse) 462int byd_init(struct psmouse *psmouse)
318{ 463{
319 struct input_dev *dev = psmouse->dev; 464 struct input_dev *dev = psmouse->dev;
465 struct byd_data *priv;
320 466
321 if (psmouse_reset(psmouse)) 467 if (psmouse_reset(psmouse))
322 return -EIO; 468 return -EIO;
@@ -324,14 +470,39 @@ int byd_init(struct psmouse *psmouse)
324 if (byd_reset_touchpad(psmouse)) 470 if (byd_reset_touchpad(psmouse))
325 return -EIO; 471 return -EIO;
326 472
473 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
474 if (!priv)
475 return -ENOMEM;
476
477 memset(priv, 0, sizeof(*priv));
478 setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse);
479
480 psmouse->private = priv;
481 psmouse->disconnect = byd_disconnect;
327 psmouse->reconnect = byd_reconnect; 482 psmouse->reconnect = byd_reconnect;
328 psmouse->protocol_handler = byd_process_byte; 483 psmouse->protocol_handler = byd_process_byte;
329 psmouse->pktsize = 4; 484 psmouse->pktsize = 4;
330 psmouse->resync_time = 0; 485 psmouse->resync_time = 0;
331 486
332 __set_bit(BTN_MIDDLE, dev->keybit); 487 __set_bit(INPUT_PROP_POINTER, dev->propbit);
333 __set_bit(REL_WHEEL, dev->relbit); 488 /* Touchpad */
334 __set_bit(REL_HWHEEL, dev->relbit); 489 __set_bit(BTN_TOUCH, dev->keybit);
490 __set_bit(BTN_TOOL_FINGER, dev->keybit);
491 /* Buttons */
492 __set_bit(BTN_LEFT, dev->keybit);
493 __set_bit(BTN_RIGHT, dev->keybit);
494 __clear_bit(BTN_MIDDLE, dev->keybit);
495
496 /* Absolute position */
497 __set_bit(EV_ABS, dev->evbit);
498 input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0);
499 input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0);
500 input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION);
501 input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION);
502 /* No relative support */
503 __clear_bit(EV_REL, dev->evbit);
504 __clear_bit(REL_X, dev->relbit);
505 __clear_bit(REL_Y, dev->relbit);
335 506
336 return 0; 507 return 0;
337} 508}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 39d1becd35c9..5784e20542a4 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -846,7 +846,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
846#ifdef CONFIG_MOUSE_PS2_BYD 846#ifdef CONFIG_MOUSE_PS2_BYD
847 { 847 {
848 .type = PSMOUSE_BYD, 848 .type = PSMOUSE_BYD,
849 .name = "BydPS/2", 849 .name = "BYDPS/2",
850 .alias = "byd", 850 .alias = "byd",
851 .detect = byd_detect, 851 .detect = byd_detect,
852 .init = byd_init, 852 .init = byd_init,