Lines 81-86
__FBSDID("$FreeBSD$");
Link Here
|
81 |
#include <sys/sysctl.h> |
81 |
#include <sys/sysctl.h> |
82 |
#include <sys/time.h> |
82 |
#include <sys/time.h> |
83 |
#include <sys/uio.h> |
83 |
#include <sys/uio.h> |
|
|
84 |
#include <sys/libkern.h> |
84 |
|
85 |
|
85 |
#include <sys/limits.h> |
86 |
#include <sys/limits.h> |
86 |
#include <sys/mouse.h> |
87 |
#include <sys/mouse.h> |
Lines 161-200
typedef struct packetbuf {
Link Here
|
161 |
#define PSM_PACKETQUEUE 128 |
162 |
#define PSM_PACKETQUEUE 128 |
162 |
#endif |
163 |
#endif |
163 |
|
164 |
|
164 |
enum { |
|
|
165 |
SYNAPTICS_SYSCTL_MIN_PRESSURE, |
166 |
SYNAPTICS_SYSCTL_MAX_PRESSURE, |
167 |
SYNAPTICS_SYSCTL_MAX_WIDTH, |
168 |
SYNAPTICS_SYSCTL_MARGIN_TOP, |
169 |
SYNAPTICS_SYSCTL_MARGIN_RIGHT, |
170 |
SYNAPTICS_SYSCTL_MARGIN_BOTTOM, |
171 |
SYNAPTICS_SYSCTL_MARGIN_LEFT, |
172 |
SYNAPTICS_SYSCTL_NA_TOP, |
173 |
SYNAPTICS_SYSCTL_NA_RIGHT, |
174 |
SYNAPTICS_SYSCTL_NA_BOTTOM, |
175 |
SYNAPTICS_SYSCTL_NA_LEFT, |
176 |
SYNAPTICS_SYSCTL_WINDOW_MIN, |
177 |
SYNAPTICS_SYSCTL_WINDOW_MAX, |
178 |
SYNAPTICS_SYSCTL_MULTIPLICATOR, |
179 |
SYNAPTICS_SYSCTL_WEIGHT_CURRENT, |
180 |
SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, |
181 |
SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, |
182 |
SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, |
183 |
SYNAPTICS_SYSCTL_DIV_MIN, |
184 |
SYNAPTICS_SYSCTL_DIV_MAX, |
185 |
SYNAPTICS_SYSCTL_DIV_MAX_NA, |
186 |
SYNAPTICS_SYSCTL_DIV_LEN, |
187 |
SYNAPTICS_SYSCTL_TAP_MAX_DELTA, |
188 |
SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, |
189 |
SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, |
190 |
SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, |
191 |
SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, |
192 |
SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, |
193 |
SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, |
194 |
SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, |
195 |
SYNAPTICS_SYSCTL_TOUCHPAD_OFF |
196 |
}; |
197 |
|
198 |
typedef struct synapticsinfo { |
165 |
typedef struct synapticsinfo { |
199 |
struct sysctl_ctx_list sysctl_ctx; |
166 |
struct sysctl_ctx_list sysctl_ctx; |
200 |
struct sysctl_oid *sysctl_tree; |
167 |
struct sysctl_oid *sysctl_tree; |
Lines 231-236
typedef struct synapticsinfo {
Link Here
|
231 |
int vscroll_div_min; |
198 |
int vscroll_div_min; |
232 |
int vscroll_div_max; |
199 |
int vscroll_div_max; |
233 |
int touchpad_off; |
200 |
int touchpad_off; |
|
|
201 |
int softbuttons_y; |
202 |
int softbutton2_x; |
203 |
int softbutton3_x; |
204 |
int max_x; |
205 |
int max_y; |
234 |
} synapticsinfo_t; |
206 |
} synapticsinfo_t; |
235 |
|
207 |
|
236 |
typedef struct synapticspacket { |
208 |
typedef struct synapticspacket { |
Lines 246-267
typedef struct synapticspacket {
Link Here
|
246 |
((synhw).infoMajor > (major) || \ |
218 |
((synhw).infoMajor > (major) || \ |
247 |
((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor))) |
219 |
((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor))) |
248 |
|
220 |
|
249 |
typedef struct synapticsaction { |
221 |
typedef struct smoother { |
250 |
synapticspacket_t queue[SYNAPTICS_PACKETQUEUE]; |
222 |
synapticspacket_t queue[SYNAPTICS_PACKETQUEUE]; |
251 |
int queue_len; |
223 |
int queue_len; |
252 |
int queue_cursor; |
224 |
int queue_cursor; |
253 |
int window_min; |
|
|
254 |
int start_x; |
225 |
int start_x; |
255 |
int start_y; |
226 |
int start_y; |
256 |
int avg_dx; |
227 |
int avg_dx; |
257 |
int avg_dy; |
228 |
int avg_dy; |
258 |
int squelch_x; |
229 |
int squelch_x; |
259 |
int squelch_y; |
230 |
int squelch_y; |
|
|
231 |
int is_fuzzy; |
232 |
int active; |
233 |
} smoother_t; |
234 |
|
235 |
typedef struct gesture { |
236 |
int window_min; |
260 |
int fingers_nb; |
237 |
int fingers_nb; |
261 |
int tap_button; |
238 |
int tap_button; |
262 |
int in_taphold; |
239 |
int in_taphold; |
263 |
int in_vscroll; |
240 |
int in_vscroll; |
264 |
} synapticsaction_t; |
241 |
int zmax; /* maximum pressure value */ |
|
|
242 |
struct timeval taptimeout; /* tap timeout for touchpads */ |
243 |
} gesture_t; |
265 |
|
244 |
|
266 |
enum { |
245 |
enum { |
267 |
TRACKPOINT_SYSCTL_SENSITIVITY, |
246 |
TRACKPOINT_SYSCTL_SENSITIVITY, |
Lines 295-300
typedef struct trackpointinfo {
Link Here
|
295 |
int skipback; |
274 |
int skipback; |
296 |
} trackpointinfo_t; |
275 |
} trackpointinfo_t; |
297 |
|
276 |
|
|
|
277 |
typedef struct finger { |
278 |
int x; |
279 |
int y; |
280 |
int p; |
281 |
int w; |
282 |
int flags; |
283 |
} finger_t; |
284 |
#define PSM_FINGERS 2 /* # of processed fingers */ |
285 |
#define PSM_FINGER_IS_PEN (1<<0) |
286 |
#define PSM_FINGER_FUZZY (1<<1) |
287 |
#define PSM_FINGER_DEFAULT_P tap_threshold |
288 |
#define PSM_FINGER_DEFAULT_W 1 |
289 |
#define PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0) |
290 |
#define PSM_FINGER_RESET(f) do \ |
291 |
(f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \ |
292 |
while (0) |
293 |
|
294 |
typedef struct elantechhw { |
295 |
int hwversion; |
296 |
int fwversion; |
297 |
int sizex; |
298 |
int sizey; |
299 |
int dpmmx; |
300 |
int dpmmy; |
301 |
int ntracesx; |
302 |
int ntracesy; |
303 |
int issemimt; |
304 |
int isclickpad; |
305 |
int hascrc; |
306 |
int hastrackpad; |
307 |
int haspressure; |
308 |
} elantechhw_t; |
309 |
|
310 |
/* minimum versions supported by this driver */ |
311 |
#define ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600) |
312 |
|
313 |
#define ELANTECH_MAGIC(magic) \ |
314 |
((magic)[0] == 0x3c && (magic)[1] == 0x03 && \ |
315 |
((magic)[2] == 0xc8 || (magic)[2] == 0x00)) |
316 |
|
317 |
#define ELANTECH_FW_ID 0x00 |
318 |
#define ELANTECH_FW_VERSION 0x01 |
319 |
#define ELANTECH_CAPABILITIES 0x02 |
320 |
#define ELANTECH_SAMPLE 0x03 |
321 |
#define ELANTECH_RESOLUTION 0x04 |
322 |
#define ELANTECH_REG_READ 0x10 |
323 |
#define ELANTECH_REG_WRITE 0x11 |
324 |
#define ELANTECH_REG_RDWR 0x00 |
325 |
#define ELANTECH_CUSTOM_CMD 0xf8 |
326 |
|
327 |
#define ELANTECH_MAX_FINGERS PSM_FINGERS |
328 |
|
329 |
#define ELANTECH_FINGER_SET_XYP(pb) (finger_t) { \ |
330 |
.x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2], \ |
331 |
.y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5], \ |
332 |
.p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f), \ |
333 |
.w = PSM_FINGER_DEFAULT_W, \ |
334 |
.flags = 0 \ |
335 |
} |
336 |
|
337 |
enum { |
338 |
ELANTECH_PKT_NOP, |
339 |
ELANTECH_PKT_TRACKPOINT, |
340 |
ELANTECH_PKT_V2_COMMON, |
341 |
ELANTECH_PKT_V2_2FINGER, |
342 |
ELANTECH_PKT_V3, |
343 |
ELANTECH_PKT_V4_STATUS, |
344 |
ELANTECH_PKT_V4_HEAD, |
345 |
ELANTECH_PKT_V4_MOTION |
346 |
}; |
347 |
|
348 |
#define ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06) |
349 |
#define ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 : \ |
350 |
(pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) && \ |
351 |
(pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff && \ |
352 |
(pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff && \ |
353 |
(pb)->ipacket[5] == 0xff) |
354 |
#define ELANTECH_PKT_IS_V2(pb) \ |
355 |
(((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02) |
356 |
#define ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ? \ |
357 |
((pb)->ipacket[3] & 0x09) == 0x08 : \ |
358 |
((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02) |
359 |
#define ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ? \ |
360 |
((pb)->ipacket[3] & 0x09) == 0x09 : \ |
361 |
((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c) |
362 |
#define ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ? \ |
363 |
((pb)->ipacket[3] & 0x08) == 0x00 : \ |
364 |
((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10) |
365 |
|
366 |
typedef struct elantechaction { |
367 |
finger_t fingers[ELANTECH_MAX_FINGERS]; |
368 |
int mask; |
369 |
} elantechaction_t; |
370 |
|
298 |
/* driver control block */ |
371 |
/* driver control block */ |
299 |
struct psm_softc { /* Driver status information */ |
372 |
struct psm_softc { /* Driver status information */ |
300 |
int unit; |
373 |
int unit; |
Lines 308-314
struct psm_softc { /* Driver status information */
Link Here
|
308 |
mousehw_t hw; /* hardware information */ |
381 |
mousehw_t hw; /* hardware information */ |
309 |
synapticshw_t synhw; /* Synaptics hardware information */ |
382 |
synapticshw_t synhw; /* Synaptics hardware information */ |
310 |
synapticsinfo_t syninfo; /* Synaptics configuration */ |
383 |
synapticsinfo_t syninfo; /* Synaptics configuration */ |
311 |
synapticsaction_t synaction; /* Synaptics action context */ |
384 |
smoother_t smoother[PSM_FINGERS]; /* Motion smoothing */ |
|
|
385 |
gesture_t gesture; /* Gesture context */ |
386 |
elantechhw_t elanhw; /* Elantech hardware information */ |
387 |
elantechaction_t elanaction; /* Elantech action context */ |
312 |
int tphw; /* TrackPoint hardware information */ |
388 |
int tphw; /* TrackPoint hardware information */ |
313 |
trackpointinfo_t tpinfo; /* TrackPoint configuration */ |
389 |
trackpointinfo_t tpinfo; /* TrackPoint configuration */ |
314 |
mousemode_t mode; /* operation mode */ |
390 |
mousemode_t mode; /* operation mode */ |
Lines 324-336
struct psm_softc { /* Driver status information */
Link Here
|
324 |
int xaverage; /* average X position */ |
400 |
int xaverage; /* average X position */ |
325 |
int yaverage; /* average Y position */ |
401 |
int yaverage; /* average Y position */ |
326 |
int squelch; /* level to filter movement at low speed */ |
402 |
int squelch; /* level to filter movement at low speed */ |
327 |
int zmax; /* maximum pressure value for touchpads */ |
|
|
328 |
int syncerrors; /* # of bytes discarded to synchronize */ |
403 |
int syncerrors; /* # of bytes discarded to synchronize */ |
329 |
int pkterrors; /* # of packets failed during quaranteen. */ |
404 |
int pkterrors; /* # of packets failed during quaranteen. */ |
330 |
struct timeval inputtimeout; |
405 |
struct timeval inputtimeout; |
331 |
struct timeval lastsoftintr; /* time of last soft interrupt */ |
406 |
struct timeval lastsoftintr; /* time of last soft interrupt */ |
332 |
struct timeval lastinputerr; /* time last sync error happened */ |
407 |
struct timeval lastinputerr; /* time last sync error happened */ |
333 |
struct timeval taptimeout; /* tap timeout for touchpads */ |
408 |
struct timeval idletimeout; |
|
|
409 |
packetbuf_t idlepacket; /* packet to send after idle timeout */ |
334 |
int watchdog; /* watchdog timer flag */ |
410 |
int watchdog; /* watchdog timer flag */ |
335 |
struct callout callout; /* watchdog timer call out */ |
411 |
struct callout callout; /* watchdog timer call out */ |
336 |
struct callout softcallout; /* buffer timer call out */ |
412 |
struct callout softcallout; /* buffer timer call out */ |
Lines 389-394
TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
Link Here
|
389 |
static int trackpoint_support = 0; |
465 |
static int trackpoint_support = 0; |
390 |
TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support); |
466 |
TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support); |
391 |
|
467 |
|
|
|
468 |
static int elantech_support = 0; |
469 |
TUNABLE_INT("hw.psm.elantech_support", &elantech_support); |
470 |
|
392 |
static int verbose = PSM_DEBUG; |
471 |
static int verbose = PSM_DEBUG; |
393 |
TUNABLE_INT("debug.psm.loglevel", &verbose); |
472 |
TUNABLE_INT("debug.psm.loglevel", &verbose); |
394 |
|
473 |
|
Lines 411-416
typedef struct old_mousemode {
Link Here
|
411 |
int accelfactor; |
490 |
int accelfactor; |
412 |
} old_mousemode_t; |
491 |
} old_mousemode_t; |
413 |
|
492 |
|
|
|
493 |
#define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field) |
494 |
enum { |
495 |
SYNAPTICS_SYSCTL_MIN_PRESSURE = SYN_OFFSET(min_pressure), |
496 |
SYNAPTICS_SYSCTL_MAX_PRESSURE = SYN_OFFSET(max_pressure), |
497 |
SYNAPTICS_SYSCTL_MAX_WIDTH = SYN_OFFSET(max_width), |
498 |
SYNAPTICS_SYSCTL_MARGIN_TOP = SYN_OFFSET(margin_top), |
499 |
SYNAPTICS_SYSCTL_MARGIN_RIGHT = SYN_OFFSET(margin_right), |
500 |
SYNAPTICS_SYSCTL_MARGIN_BOTTOM = SYN_OFFSET(margin_bottom), |
501 |
SYNAPTICS_SYSCTL_MARGIN_LEFT = SYN_OFFSET(margin_left), |
502 |
SYNAPTICS_SYSCTL_NA_TOP = SYN_OFFSET(na_top), |
503 |
SYNAPTICS_SYSCTL_NA_RIGHT = SYN_OFFSET(na_right), |
504 |
SYNAPTICS_SYSCTL_NA_BOTTOM = SYN_OFFSET(na_bottom), |
505 |
SYNAPTICS_SYSCTL_NA_LEFT = SYN_OFFSET(na_left), |
506 |
SYNAPTICS_SYSCTL_WINDOW_MIN = SYN_OFFSET(window_min), |
507 |
SYNAPTICS_SYSCTL_WINDOW_MAX = SYN_OFFSET(window_max), |
508 |
SYNAPTICS_SYSCTL_MULTIPLICATOR = SYN_OFFSET(multiplicator), |
509 |
SYNAPTICS_SYSCTL_WEIGHT_CURRENT = SYN_OFFSET(weight_current), |
510 |
SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS = SYN_OFFSET(weight_previous), |
511 |
SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA = SYN_OFFSET(weight_previous_na), |
512 |
SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED = SYN_OFFSET(weight_len_squared), |
513 |
SYNAPTICS_SYSCTL_DIV_MIN = SYN_OFFSET(div_min), |
514 |
SYNAPTICS_SYSCTL_DIV_MAX = SYN_OFFSET(div_max), |
515 |
SYNAPTICS_SYSCTL_DIV_MAX_NA = SYN_OFFSET(div_max_na), |
516 |
SYNAPTICS_SYSCTL_DIV_LEN = SYN_OFFSET(div_len), |
517 |
SYNAPTICS_SYSCTL_TAP_MAX_DELTA = SYN_OFFSET(tap_max_delta), |
518 |
SYNAPTICS_SYSCTL_TAP_MIN_QUEUE = SYN_OFFSET(tap_min_queue), |
519 |
SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT = SYN_OFFSET(taphold_timeout), |
520 |
SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA = SYN_OFFSET(vscroll_hor_area), |
521 |
SYNAPTICS_SYSCTL_VSCROLL_VER_AREA = SYN_OFFSET(vscroll_ver_area), |
522 |
SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA = SYN_OFFSET(vscroll_min_delta), |
523 |
SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN = SYN_OFFSET(vscroll_div_min), |
524 |
SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX = SYN_OFFSET(vscroll_div_max), |
525 |
SYNAPTICS_SYSCTL_TOUCHPAD_OFF = SYN_OFFSET(touchpad_off), |
526 |
SYNAPTICS_SYSCTL_SOFTBUTTONS_Y = SYN_OFFSET(softbuttons_y), |
527 |
SYNAPTICS_SYSCTL_SOFTBUTTON2_X = SYN_OFFSET(softbutton2_x), |
528 |
SYNAPTICS_SYSCTL_SOFTBUTTON3_X = SYN_OFFSET(softbutton3_x), |
529 |
}; |
530 |
|
414 |
/* packet formatting function */ |
531 |
/* packet formatting function */ |
415 |
typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int, |
532 |
typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int, |
416 |
mousestatus_t *); |
533 |
mousestatus_t *); |
Lines 446-451
static int doopen(struct psm_softc *, int);
Link Here
|
446 |
static int reinitialize(struct psm_softc *, int); |
563 |
static int reinitialize(struct psm_softc *, int); |
447 |
static char *model_name(int); |
564 |
static char *model_name(int); |
448 |
static void psmsoftintr(void *); |
565 |
static void psmsoftintr(void *); |
|
|
566 |
static void psmsoftintridle(void *); |
449 |
static void psmintr(void *); |
567 |
static void psmintr(void *); |
450 |
static void psmtimeout(void *); |
568 |
static void psmtimeout(void *); |
451 |
static int timeelapsed(const struct timeval *, int, int, |
569 |
static int timeelapsed(const struct timeval *, int, int, |
Lines 458-463
static int proc_synaptics(struct psm_softc *, packetbuf_t *,
Link Here
|
458 |
mousestatus_t *, int *, int *, int *); |
576 |
mousestatus_t *, int *, int *, int *); |
459 |
static void proc_versapad(struct psm_softc *, packetbuf_t *, |
577 |
static void proc_versapad(struct psm_softc *, packetbuf_t *, |
460 |
mousestatus_t *, int *, int *, int *); |
578 |
mousestatus_t *, int *, int *, int *); |
|
|
579 |
static int proc_elantech(struct psm_softc *, packetbuf_t *, |
580 |
mousestatus_t *, int *, int *, int *); |
581 |
static int psmpalmdetect(struct psm_softc *, finger_t *, int); |
582 |
static void psmgestures(struct psm_softc *, finger_t *, int, |
583 |
mousestatus_t *); |
584 |
static void psmsmoother(struct psm_softc *, finger_t *, int, |
585 |
mousestatus_t *, int *, int *); |
461 |
static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *, |
586 |
static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *, |
462 |
u_char *); |
587 |
u_char *); |
463 |
|
588 |
|
Lines 480-485
static probefunc_t enable_mmanplus;
Link Here
|
480 |
static probefunc_t enable_synaptics; |
605 |
static probefunc_t enable_synaptics; |
481 |
static probefunc_t enable_trackpoint; |
606 |
static probefunc_t enable_trackpoint; |
482 |
static probefunc_t enable_versapad; |
607 |
static probefunc_t enable_versapad; |
|
|
608 |
static probefunc_t enable_elantech; |
483 |
|
609 |
|
484 |
static void set_trackpoint_parameters(struct psm_softc *sc); |
610 |
static void set_trackpoint_parameters(struct psm_softc *sc); |
485 |
static void synaptics_passthrough_on(struct psm_softc *sc); |
611 |
static void synaptics_passthrough_on(struct psm_softc *sc); |
Lines 511-516
static struct {
Link Here
|
511 |
0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus }, |
637 |
0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus }, |
512 |
{ MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */ |
638 |
{ MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */ |
513 |
0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics }, |
639 |
0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics }, |
|
|
640 |
{ MOUSE_MODEL_ELANTECH, /* Elantech Touchpad */ |
641 |
0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech }, |
514 |
{ MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */ |
642 |
{ MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */ |
515 |
0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli }, |
643 |
0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli }, |
516 |
{ MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */ |
644 |
{ MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */ |
Lines 762-767
model_name(int model)
Link Here
|
762 |
{ MOUSE_MODEL_4DPLUS, "4D+ Mouse" }, |
890 |
{ MOUSE_MODEL_4DPLUS, "4D+ Mouse" }, |
763 |
{ MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" }, |
891 |
{ MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" }, |
764 |
{ MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" }, |
892 |
{ MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" }, |
|
|
893 |
{ MOUSE_MODEL_ELANTECH, "Elantech Touchpad" }, |
765 |
{ MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" }, |
894 |
{ MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" }, |
766 |
{ MOUSE_MODEL_UNKNOWN, "Unknown" }, |
895 |
{ MOUSE_MODEL_UNKNOWN, "Unknown" }, |
767 |
}; |
896 |
}; |
Lines 1504-1509
psmattach(device_t dev)
Link Here
|
1504 |
case MOUSE_MODEL_SYNAPTICS: |
1633 |
case MOUSE_MODEL_SYNAPTICS: |
1505 |
case MOUSE_MODEL_GLIDEPOINT: |
1634 |
case MOUSE_MODEL_GLIDEPOINT: |
1506 |
case MOUSE_MODEL_VERSAPAD: |
1635 |
case MOUSE_MODEL_VERSAPAD: |
|
|
1636 |
case MOUSE_MODEL_ELANTECH: |
1507 |
sc->config |= PSM_CONFIG_INITAFTERSUSPEND; |
1637 |
sc->config |= PSM_CONFIG_INITAFTERSUSPEND; |
1508 |
break; |
1638 |
break; |
1509 |
default: |
1639 |
default: |
Lines 1512-1517
psmattach(device_t dev)
Link Here
|
1512 |
break; |
1642 |
break; |
1513 |
} |
1643 |
} |
1514 |
|
1644 |
|
|
|
1645 |
/* Elantech trackpad`s sync bit differs from touchpad`s one */ |
1646 |
if (sc->hw.model == MOUSE_MODEL_ELANTECH && |
1647 |
(sc->elanhw.hascrc || sc->elanhw.hastrackpad)) |
1648 |
sc->config |= PSM_CONFIG_NOCHECKSYNC; |
1649 |
|
1515 |
if (!verbose) |
1650 |
if (!verbose) |
1516 |
printf("psm%d: model %s, device ID %d\n", |
1651 |
printf("psm%d: model %s, device ID %d\n", |
1517 |
unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff); |
1652 |
unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff); |
Lines 2165-2184
psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
Link Here
|
2165 |
(*(int *)addr > PSM_LEVEL_MAX)) |
2300 |
(*(int *)addr > PSM_LEVEL_MAX)) |
2166 |
return (EINVAL); |
2301 |
return (EINVAL); |
2167 |
sc->mode.level = *(int *)addr; |
2302 |
sc->mode.level = *(int *)addr; |
2168 |
|
|
|
2169 |
if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) { |
2170 |
/* |
2171 |
* If we are entering PSM_LEVEL_NATIVE, we want to |
2172 |
* enable sending of "extended W mode" packets to |
2173 |
* userland. Reset the mode of the touchpad so that the |
2174 |
* change in the level is picked up. |
2175 |
*/ |
2176 |
error = block_mouse_data(sc, &command_byte); |
2177 |
if (error) |
2178 |
return (error); |
2179 |
synaptics_set_mode(sc, synaptics_preferred_mode(sc)); |
2180 |
unblock_mouse_data(sc, command_byte); |
2181 |
} |
2182 |
break; |
2303 |
break; |
2183 |
|
2304 |
|
2184 |
case MOUSE_GETSTATUS: |
2305 |
case MOUSE_GETSTATUS: |
Lines 2627-2633
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2627 |
{ |
2748 |
{ |
2628 |
static int touchpad_buttons; |
2749 |
static int touchpad_buttons; |
2629 |
static int guest_buttons; |
2750 |
static int guest_buttons; |
2630 |
int w, x0, y0; |
2751 |
static finger_t f[PSM_FINGERS]; |
|
|
2752 |
int w, id, nfingers, ewcode; |
2631 |
|
2753 |
|
2632 |
/* TouchPad PS/2 absolute mode message format with capFourButtons: |
2754 |
/* TouchPad PS/2 absolute mode message format with capFourButtons: |
2633 |
* |
2755 |
* |
Lines 2683-2688
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2683 |
return (-1); |
2805 |
return (-1); |
2684 |
|
2806 |
|
2685 |
*x = *y = 0; |
2807 |
*x = *y = 0; |
|
|
2808 |
ms->button = ms->obutton; |
2686 |
|
2809 |
|
2687 |
/* |
2810 |
/* |
2688 |
* Pressure value. |
2811 |
* Pressure value. |
Lines 2718-2751
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2718 |
w = 4; |
2841 |
w = 4; |
2719 |
} |
2842 |
} |
2720 |
|
2843 |
|
2721 |
/* |
2844 |
switch (w) { |
2722 |
* Handle packets from the guest device. See: |
2845 |
case 3: |
2723 |
* Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1 |
2846 |
/* |
2724 |
*/ |
2847 |
* Handle packets from the guest device. See: |
2725 |
if (w == 3 && sc->synhw.capPassthrough) { |
2848 |
* Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1 |
2726 |
*x = ((pb->ipacket[1] & 0x10) ? |
2849 |
*/ |
2727 |
pb->ipacket[4] - 256 : pb->ipacket[4]); |
2850 |
if (sc->synhw.capPassthrough) { |
2728 |
*y = ((pb->ipacket[1] & 0x20) ? |
2851 |
*x = ((pb->ipacket[1] & 0x10) ? |
2729 |
pb->ipacket[5] - 256 : pb->ipacket[5]); |
2852 |
pb->ipacket[4] - 256 : pb->ipacket[4]); |
2730 |
*z = 0; |
2853 |
*y = ((pb->ipacket[1] & 0x20) ? |
2731 |
|
2854 |
pb->ipacket[5] - 256 : pb->ipacket[5]); |
2732 |
guest_buttons = 0; |
2855 |
*z = 0; |
2733 |
if (pb->ipacket[1] & 0x01) |
2856 |
|
2734 |
guest_buttons |= MOUSE_BUTTON1DOWN; |
2857 |
guest_buttons = 0; |
2735 |
if (pb->ipacket[1] & 0x04) |
2858 |
if (pb->ipacket[1] & 0x01) |
2736 |
guest_buttons |= MOUSE_BUTTON2DOWN; |
2859 |
guest_buttons |= MOUSE_BUTTON1DOWN; |
2737 |
if (pb->ipacket[1] & 0x02) |
2860 |
if (pb->ipacket[1] & 0x04) |
2738 |
guest_buttons |= MOUSE_BUTTON3DOWN; |
2861 |
guest_buttons |= MOUSE_BUTTON2DOWN; |
|
|
2862 |
if (pb->ipacket[1] & 0x02) |
2863 |
guest_buttons |= MOUSE_BUTTON3DOWN; |
2864 |
|
2865 |
ms->button = touchpad_buttons | guest_buttons; |
2866 |
} |
2867 |
goto SYNAPTICS_END; |
2739 |
|
2868 |
|
2740 |
ms->button = touchpad_buttons | guest_buttons; |
2869 |
case 2: |
|
|
2870 |
/* Handle Extended W mode packets */ |
2871 |
ewcode = (pb->ipacket[5] & 0xf0) >> 4; |
2872 |
#if PSM_FINGERS > 1 |
2873 |
switch (ewcode) { |
2874 |
case 1: |
2875 |
/* Secondary finger */ |
2876 |
if (sc->synhw.capAdvancedGestures) |
2877 |
f[1] = (finger_t) { |
2878 |
.x = (((pb->ipacket[4] & 0x0f) << 8) | |
2879 |
pb->ipacket[1]) << 1, |
2880 |
.y = (((pb->ipacket[4] & 0xf0) << 4) | |
2881 |
pb->ipacket[2]) << 1, |
2882 |
.p = ((pb->ipacket[3] & 0x30) | |
2883 |
(pb->ipacket[5] & 0x0f)) << 1, |
2884 |
.w = PSM_FINGER_DEFAULT_W, |
2885 |
.flags = PSM_FINGER_FUZZY, |
2886 |
}; |
2887 |
else if (sc->synhw.capReportsV) |
2888 |
f[1] = (finger_t) { |
2889 |
.x = (((pb->ipacket[4] & 0x0f) << 8) | |
2890 |
(pb->ipacket[1] & 0xfe)) << 1, |
2891 |
.y = (((pb->ipacket[4] & 0xf0) << 4) | |
2892 |
(pb->ipacket[2] & 0xfe)) << 1, |
2893 |
.p = ((pb->ipacket[3] & 0x30) | |
2894 |
(pb->ipacket[5] & 0x0e)) << 1, |
2895 |
.w = (((pb->ipacket[5] & 0x01) << 2) | |
2896 |
((pb->ipacket[2] & 0x01) << 1) | |
2897 |
(pb->ipacket[1] & 0x01)) + 8, |
2898 |
.flags = PSM_FINGER_FUZZY, |
2899 |
}; |
2900 |
default: |
2901 |
break; |
2902 |
} |
2903 |
#endif |
2741 |
goto SYNAPTICS_END; |
2904 |
goto SYNAPTICS_END; |
|
|
2905 |
|
2906 |
case 1: |
2907 |
case 0: |
2908 |
nfingers = w + 2; |
2909 |
break; |
2910 |
|
2911 |
default: |
2912 |
nfingers = 1; |
2742 |
} |
2913 |
} |
2743 |
|
2914 |
|
2744 |
if (sc->syninfo.touchpad_off) { |
2915 |
if (sc->syninfo.touchpad_off) |
2745 |
*x = *y = *z = 0; |
|
|
2746 |
ms->button = ms->obutton; |
2747 |
goto SYNAPTICS_END; |
2916 |
goto SYNAPTICS_END; |
2748 |
} |
|
|
2749 |
|
2917 |
|
2750 |
/* Button presses */ |
2918 |
/* Button presses */ |
2751 |
touchpad_buttons = 0; |
2919 |
touchpad_buttons = 0; |
Lines 2764-2769
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2764 |
/* Middle Button */ |
2932 |
/* Middle Button */ |
2765 |
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01) |
2933 |
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01) |
2766 |
touchpad_buttons |= MOUSE_BUTTON2DOWN; |
2934 |
touchpad_buttons |= MOUSE_BUTTON2DOWN; |
|
|
2935 |
} else if (sc->synhw.capExtended && sc->synhw.capClickPad) { |
2936 |
/* ClickPad Button */ |
2937 |
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01) |
2938 |
touchpad_buttons = MOUSE_BUTTON1DOWN; |
2767 |
} else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) { |
2939 |
} else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) { |
2768 |
/* Extended Buttons */ |
2940 |
/* Extended Buttons */ |
2769 |
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) { |
2941 |
if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) { |
Lines 2806-2812
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2806 |
pb->ipacket[4] &= ~(mask); |
2978 |
pb->ipacket[4] &= ~(mask); |
2807 |
pb->ipacket[5] &= ~(mask); |
2979 |
pb->ipacket[5] &= ~(mask); |
2808 |
} else if (!sc->syninfo.directional_scrolls && |
2980 |
} else if (!sc->syninfo.directional_scrolls && |
2809 |
!sc->synaction.in_vscroll) { |
2981 |
!sc->gesture.in_vscroll) { |
2810 |
/* |
2982 |
/* |
2811 |
* Keep reporting MOUSE DOWN until we get a new packet |
2983 |
* Keep reporting MOUSE DOWN until we get a new packet |
2812 |
* indicating otherwise. |
2984 |
* indicating otherwise. |
Lines 2814-2906
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2814 |
touchpad_buttons |= sc->extended_buttons; |
2986 |
touchpad_buttons |= sc->extended_buttons; |
2815 |
} |
2987 |
} |
2816 |
} |
2988 |
} |
2817 |
/* Handle ClickPad. */ |
2989 |
|
2818 |
if (sc->synhw.capClickPad && |
2990 |
if (sc->synhw.capReportsV && nfingers > 1) |
2819 |
((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)) |
2991 |
f[0] = (finger_t) { |
2820 |
touchpad_buttons |= MOUSE_BUTTON1DOWN; |
2992 |
.x = ((pb->ipacket[3] & 0x10) << 8) | |
|
|
2993 |
((pb->ipacket[1] & 0x0f) << 8) | |
2994 |
(pb->ipacket[4] & 0xfd), |
2995 |
.y = ((pb->ipacket[3] & 0x20) << 7) | |
2996 |
((pb->ipacket[1] & 0xf0) << 4) | |
2997 |
(pb->ipacket[5] & 0xfd), |
2998 |
.p = *z & 0xfe, |
2999 |
.w = (((pb->ipacket[2] & 0x01) << 2) | |
3000 |
(pb->ipacket[5] & 0x02) | |
3001 |
((pb->ipacket[4] & 0x02) >> 1)) + 8, |
3002 |
.flags = PSM_FINGER_FUZZY, |
3003 |
}; |
3004 |
else |
3005 |
f[0] = (finger_t) { |
3006 |
.x = ((pb->ipacket[3] & 0x10) << 8) | |
3007 |
((pb->ipacket[1] & 0x0f) << 8) | |
3008 |
pb->ipacket[4], |
3009 |
.y = ((pb->ipacket[3] & 0x20) << 7) | |
3010 |
((pb->ipacket[1] & 0xf0) << 4) | |
3011 |
pb->ipacket[5], |
3012 |
.p = *z, |
3013 |
.w = w, |
3014 |
.flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0, |
3015 |
}; |
3016 |
|
3017 |
/* Ignore hovering and unmeasurable touches */ |
3018 |
if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2) |
3019 |
nfingers = 0; |
3020 |
|
3021 |
for (id = 0; id < PSM_FINGERS; id++) |
3022 |
if (id >= nfingers) |
3023 |
PSM_FINGER_RESET(f[id]); |
2821 |
|
3024 |
|
2822 |
ms->button = touchpad_buttons | guest_buttons; |
3025 |
ms->button = touchpad_buttons | guest_buttons; |
2823 |
|
3026 |
|
|
|
3027 |
/* Palm detection doesn't terminate the current action. */ |
3028 |
if (!psmpalmdetect(sc, &f[0], nfingers)) { |
3029 |
psmgestures(sc, &f[0], nfingers, ms); |
3030 |
for (id = 0; id < PSM_FINGERS; id++) |
3031 |
psmsmoother(sc, &f[id], id, ms, x, y); |
3032 |
} else { |
3033 |
VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", f[0].w)); |
3034 |
} |
3035 |
|
3036 |
SYNAPTICS_END: |
3037 |
/* |
3038 |
* Use the extra buttons as a scrollwheel |
3039 |
* |
3040 |
* XXX X.Org uses the Z axis for vertical wheel only, |
3041 |
* whereas moused(8) understands special values to differ |
3042 |
* vertical and horizontal wheels. |
3043 |
* |
3044 |
* xf86-input-mouse needs therefore a small patch to |
3045 |
* understand these special values. Without it, the |
3046 |
* horizontal wheel acts as a vertical wheel in X.Org. |
3047 |
* |
3048 |
* That's why the horizontal wheel is disabled by |
3049 |
* default for now. |
3050 |
*/ |
3051 |
if (ms->button & MOUSE_BUTTON4DOWN) |
3052 |
*z = -1; |
3053 |
else if (ms->button & MOUSE_BUTTON5DOWN) |
3054 |
*z = 1; |
3055 |
else if (ms->button & MOUSE_BUTTON6DOWN) |
3056 |
*z = -2; |
3057 |
else if (ms->button & MOUSE_BUTTON7DOWN) |
3058 |
*z = 2; |
3059 |
else |
3060 |
*z = 0; |
3061 |
ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN | |
3062 |
MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN); |
3063 |
|
3064 |
return (0); |
3065 |
} |
3066 |
|
3067 |
static int |
3068 |
psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers) |
3069 |
{ |
3070 |
if (!( |
3071 |
((sc->synhw.capMultiFinger || |
3072 |
sc->synhw.capAdvancedGestures) && nfingers > 1) || |
3073 |
(sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) || |
3074 |
(!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) || |
3075 |
(sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) { |
3076 |
/* |
3077 |
* We consider the packet irrelevant for the current |
3078 |
* action when: |
3079 |
* - the width isn't comprised in: |
3080 |
* [1; max_width] |
3081 |
* - the pressure isn't comprised in: |
3082 |
* [min_pressure; max_pressure] |
3083 |
* - pen aren't supported but PSM_FINGER_IS_PEN is set |
3084 |
*/ |
3085 |
return (1); |
3086 |
} |
3087 |
return (0); |
3088 |
} |
3089 |
|
3090 |
static void |
3091 |
psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers, |
3092 |
mousestatus_t *ms) |
3093 |
{ |
3094 |
smoother_t *smoother; |
3095 |
gesture_t *gest; |
3096 |
finger_t *f; |
3097 |
int y_ok, center_button, center_x, right_button, right_x, i; |
3098 |
|
3099 |
f = &fingers[0]; |
3100 |
smoother = &sc->smoother[0]; |
3101 |
gest = &sc->gesture; |
3102 |
|
3103 |
/* Find first active finger. */ |
3104 |
if (nfingers > 0) { |
3105 |
for (i = 0; i < PSM_FINGERS; i++) { |
3106 |
if (PSM_FINGER_IS_SET(fingers[i])) { |
3107 |
f = &fingers[i]; |
3108 |
smoother = &sc->smoother[i]; |
3109 |
break; |
3110 |
} |
3111 |
} |
3112 |
} |
3113 |
|
2824 |
/* |
3114 |
/* |
2825 |
* Check pressure to detect a real wanted action on the |
3115 |
* Check pressure to detect a real wanted action on the |
2826 |
* touchpad. |
3116 |
* touchpad. |
2827 |
*/ |
3117 |
*/ |
2828 |
if (*z >= sc->syninfo.min_pressure) { |
3118 |
if (f->p >= sc->syninfo.min_pressure) { |
2829 |
synapticsaction_t *synaction; |
3119 |
int x0, y0; |
2830 |
int cursor, peer, window; |
3120 |
int dxp, dyp; |
2831 |
int dx, dy, dxp, dyp; |
|
|
2832 |
int max_width, max_pressure; |
2833 |
int margin_top, margin_right, margin_bottom, margin_left; |
3121 |
int margin_top, margin_right, margin_bottom, margin_left; |
2834 |
int na_top, na_right, na_bottom, na_left; |
|
|
2835 |
int window_min, window_max; |
3122 |
int window_min, window_max; |
2836 |
int multiplicator; |
|
|
2837 |
int weight_current, weight_previous, weight_len_squared; |
2838 |
int div_min, div_max, div_len; |
2839 |
int vscroll_hor_area, vscroll_ver_area; |
3123 |
int vscroll_hor_area, vscroll_ver_area; |
2840 |
int two_finger_scroll; |
3124 |
int two_finger_scroll; |
2841 |
int len, weight_prev_x, weight_prev_y; |
3125 |
int max_x, max_y; |
2842 |
int div_max_x, div_max_y, div_x, div_y; |
|
|
2843 |
int exiting_scroll; |
2844 |
|
3126 |
|
2845 |
/* Read sysctl. */ |
3127 |
/* Read sysctl. */ |
2846 |
/* XXX Verify values? */ |
3128 |
/* XXX Verify values? */ |
2847 |
max_width = sc->syninfo.max_width; |
|
|
2848 |
max_pressure = sc->syninfo.max_pressure; |
2849 |
margin_top = sc->syninfo.margin_top; |
3129 |
margin_top = sc->syninfo.margin_top; |
2850 |
margin_right = sc->syninfo.margin_right; |
3130 |
margin_right = sc->syninfo.margin_right; |
2851 |
margin_bottom = sc->syninfo.margin_bottom; |
3131 |
margin_bottom = sc->syninfo.margin_bottom; |
2852 |
margin_left = sc->syninfo.margin_left; |
3132 |
margin_left = sc->syninfo.margin_left; |
2853 |
na_top = sc->syninfo.na_top; |
|
|
2854 |
na_right = sc->syninfo.na_right; |
2855 |
na_bottom = sc->syninfo.na_bottom; |
2856 |
na_left = sc->syninfo.na_left; |
2857 |
window_min = sc->syninfo.window_min; |
3133 |
window_min = sc->syninfo.window_min; |
2858 |
window_max = sc->syninfo.window_max; |
3134 |
window_max = sc->syninfo.window_max; |
2859 |
multiplicator = sc->syninfo.multiplicator; |
|
|
2860 |
weight_current = sc->syninfo.weight_current; |
2861 |
weight_previous = sc->syninfo.weight_previous; |
2862 |
weight_len_squared = sc->syninfo.weight_len_squared; |
2863 |
div_min = sc->syninfo.div_min; |
2864 |
div_max = sc->syninfo.div_max; |
2865 |
div_len = sc->syninfo.div_len; |
2866 |
vscroll_hor_area = sc->syninfo.vscroll_hor_area; |
3135 |
vscroll_hor_area = sc->syninfo.vscroll_hor_area; |
2867 |
vscroll_ver_area = sc->syninfo.vscroll_ver_area; |
3136 |
vscroll_ver_area = sc->syninfo.vscroll_ver_area; |
2868 |
two_finger_scroll = sc->syninfo.two_finger_scroll; |
3137 |
two_finger_scroll = sc->syninfo.two_finger_scroll; |
2869 |
|
3138 |
max_x = sc->syninfo.max_x; |
2870 |
exiting_scroll = 0; |
3139 |
max_y = sc->syninfo.max_y; |
2871 |
|
|
|
2872 |
/* Palm detection. */ |
2873 |
if (!( |
2874 |
((sc->synhw.capMultiFinger || |
2875 |
sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) || |
2876 |
(sc->synhw.capPalmDetect && w >= 4 && w <= max_width) || |
2877 |
(!sc->synhw.capPalmDetect && *z <= max_pressure) || |
2878 |
(sc->synhw.capPen && w == 2))) { |
2879 |
/* |
2880 |
* We consider the packet irrelevant for the current |
2881 |
* action when: |
2882 |
* - the width isn't comprised in: |
2883 |
* [4; max_width] |
2884 |
* - the pressure isn't comprised in: |
2885 |
* [min_pressure; max_pressure] |
2886 |
* - pen aren't supported but w is 2 |
2887 |
* |
2888 |
* Note that this doesn't terminate the current action. |
2889 |
*/ |
2890 |
VLOG(2, (LOG_DEBUG, |
2891 |
"synaptics: palm detected! (%d)\n", w)); |
2892 |
goto SYNAPTICS_END; |
2893 |
} |
2894 |
|
3140 |
|
2895 |
/* Read current absolute position. */ |
3141 |
/* Read current absolute position. */ |
2896 |
x0 = ((pb->ipacket[3] & 0x10) << 8) | |
3142 |
x0 = f->x; |
2897 |
((pb->ipacket[1] & 0x0f) << 8) | |
3143 |
y0 = f->y; |
2898 |
pb->ipacket[4]; |
3144 |
|
2899 |
y0 = ((pb->ipacket[3] & 0x20) << 7) | |
3145 |
/* |
2900 |
((pb->ipacket[1] & 0xf0) << 4) | |
3146 |
* Limit the coordinates to the specified margins because |
2901 |
pb->ipacket[5]; |
3147 |
* this area isn't very reliable. |
|
|
3148 |
*/ |
3149 |
if (x0 <= margin_left) |
3150 |
x0 = margin_left; |
3151 |
else if (x0 >= max_x - margin_right) |
3152 |
x0 = max_x - margin_right; |
3153 |
if (y0 <= margin_bottom) |
3154 |
y0 = margin_bottom; |
3155 |
else if (y0 >= max_y - margin_top) |
3156 |
y0 = max_y - margin_top; |
2902 |
|
3157 |
|
2903 |
synaction = &(sc->synaction); |
3158 |
VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n", |
|
|
3159 |
x0, y0, f->p, f->w)); |
2904 |
|
3160 |
|
2905 |
/* |
3161 |
/* |
2906 |
* If the action is just beginning, init the structure and |
3162 |
* If the action is just beginning, init the structure and |
Lines 2909-3015
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
2909 |
if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { |
3165 |
if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { |
2910 |
VLOG(3, (LOG_DEBUG, "synaptics: ----\n")); |
3166 |
VLOG(3, (LOG_DEBUG, "synaptics: ----\n")); |
2911 |
|
3167 |
|
2912 |
/* Store the first point of this action. */ |
|
|
2913 |
synaction->start_x = x0; |
2914 |
synaction->start_y = y0; |
2915 |
dx = dy = 0; |
2916 |
|
2917 |
/* Initialize queue. */ |
3168 |
/* Initialize queue. */ |
2918 |
synaction->queue_cursor = SYNAPTICS_PACKETQUEUE; |
3169 |
gest->window_min = window_min; |
2919 |
synaction->queue_len = 0; |
|
|
2920 |
synaction->window_min = window_min; |
2921 |
|
2922 |
/* Reset average. */ |
2923 |
synaction->avg_dx = 0; |
2924 |
synaction->avg_dy = 0; |
2925 |
|
2926 |
/* Reset squelch. */ |
2927 |
synaction->squelch_x = 0; |
2928 |
synaction->squelch_y = 0; |
2929 |
|
3170 |
|
2930 |
/* Reset pressure peak. */ |
3171 |
/* Reset pressure peak. */ |
2931 |
sc->zmax = 0; |
3172 |
gest->zmax = 0; |
2932 |
|
3173 |
|
2933 |
/* Reset fingers count. */ |
3174 |
/* Reset fingers count. */ |
2934 |
synaction->fingers_nb = 0; |
3175 |
gest->fingers_nb = 0; |
2935 |
|
3176 |
|
2936 |
/* Reset virtual scrolling state. */ |
3177 |
/* Reset virtual scrolling state. */ |
2937 |
synaction->in_vscroll = 0; |
3178 |
gest->in_vscroll = 0; |
2938 |
|
3179 |
|
2939 |
/* Compute tap timeout. */ |
3180 |
/* Compute tap timeout. */ |
2940 |
sc->taptimeout.tv_sec = tap_timeout / 1000000; |
3181 |
gest->taptimeout.tv_sec = tap_timeout / 1000000; |
2941 |
sc->taptimeout.tv_usec = tap_timeout % 1000000; |
3182 |
gest->taptimeout.tv_usec = tap_timeout % 1000000; |
2942 |
timevaladd(&sc->taptimeout, &sc->lastsoftintr); |
3183 |
timevaladd(&gest->taptimeout, &sc->lastsoftintr); |
2943 |
|
3184 |
|
2944 |
sc->flags |= PSM_FLAGS_FINGERDOWN; |
3185 |
sc->flags |= PSM_FLAGS_FINGERDOWN; |
2945 |
} else { |
|
|
2946 |
/* Calculate the current delta. */ |
2947 |
cursor = synaction->queue_cursor; |
2948 |
dx = x0 - synaction->queue[cursor].x; |
2949 |
dy = y0 - synaction->queue[cursor].y; |
2950 |
} |
3186 |
} |
2951 |
|
3187 |
|
2952 |
/* If in tap-hold, add the recorded button. */ |
|
|
2953 |
if (synaction->in_taphold) |
2954 |
ms->button |= synaction->tap_button; |
2955 |
|
3188 |
|
2956 |
/* |
3189 |
/* Process ClickPad softbuttons */ |
2957 |
* From now on, we can use the SYNAPTICS_END label to skip |
3190 |
if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) { |
2958 |
* the current packet. |
3191 |
y_ok = sc->syninfo.softbuttons_y >= 0 ? |
2959 |
*/ |
3192 |
f->y < sc->syninfo.softbuttons_y : |
|
|
3193 |
f->y > max_y - sc->syninfo.softbuttons_y; |
2960 |
|
3194 |
|
2961 |
/* |
3195 |
center_button = MOUSE_BUTTON2DOWN; |
2962 |
* Limit the coordinates to the specified margins because |
3196 |
center_x = sc->syninfo.softbutton2_x; |
2963 |
* this area isn't very reliable. |
3197 |
right_button = MOUSE_BUTTON3DOWN; |
2964 |
*/ |
3198 |
right_x = sc->syninfo.softbutton3_x; |
2965 |
if (x0 <= margin_left) |
|
|
2966 |
x0 = margin_left; |
2967 |
else if (x0 >= 6143 - margin_right) |
2968 |
x0 = 6143 - margin_right; |
2969 |
if (y0 <= margin_bottom) |
2970 |
y0 = margin_bottom; |
2971 |
else if (y0 >= 6143 - margin_top) |
2972 |
y0 = 6143 - margin_top; |
2973 |
|
3199 |
|
2974 |
VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n", |
3200 |
if (center_x > 0 && right_x > 0 && center_x > right_x) { |
2975 |
x0, y0, *z, w)); |
3201 |
center_button = MOUSE_BUTTON3DOWN; |
|
|
3202 |
center_x = sc->syninfo.softbutton3_x; |
3203 |
right_button = MOUSE_BUTTON2DOWN; |
3204 |
right_x = sc->syninfo.softbutton2_x; |
3205 |
} |
2976 |
|
3206 |
|
2977 |
/* Queue this new packet. */ |
3207 |
if (right_x > 0 && smoother->start_x > right_x && y_ok) |
2978 |
cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1); |
3208 |
ms->button = (ms->button & |
2979 |
synaction->queue[cursor].x = x0; |
3209 |
~MOUSE_BUTTON1DOWN) | right_button; |
2980 |
synaction->queue[cursor].y = y0; |
3210 |
else if (center_x > 0 && |
2981 |
synaction->queue_cursor = cursor; |
3211 |
smoother->start_x > center_x && y_ok) |
2982 |
if (synaction->queue_len < SYNAPTICS_PACKETQUEUE) |
3212 |
ms->button = (ms->button & |
2983 |
synaction->queue_len++; |
3213 |
~MOUSE_BUTTON1DOWN) | center_button; |
2984 |
VLOG(5, (LOG_DEBUG, |
3214 |
} |
2985 |
"synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n", |
3215 |
|
2986 |
cursor, x0, y0, dx, dy)); |
3216 |
/* If in tap-hold, add the recorded button. */ |
|
|
3217 |
if (gest->in_taphold) |
3218 |
ms->button |= gest->tap_button; |
2987 |
|
3219 |
|
2988 |
/* |
3220 |
/* |
2989 |
* For tap, we keep the maximum number of fingers and the |
3221 |
* For tap, we keep the maximum number of fingers and the |
2990 |
* pressure peak. Also with multiple fingers, we increase |
3222 |
* pressure peak. Also with multiple fingers, we increase |
2991 |
* the minimum window. |
3223 |
* the minimum window. |
2992 |
*/ |
3224 |
*/ |
2993 |
switch (w) { |
3225 |
if (nfingers > 1) |
2994 |
case 1: /* Three or more fingers. */ |
3226 |
gest->window_min = window_max; |
2995 |
synaction->fingers_nb = imax(3, synaction->fingers_nb); |
3227 |
gest->fingers_nb = imax(nfingers, gest->fingers_nb); |
2996 |
synaction->window_min = window_max; |
3228 |
gest->zmax = imax(f->p, gest->zmax); |
2997 |
break; |
|
|
2998 |
case 0: /* Two fingers. */ |
2999 |
synaction->fingers_nb = imax(2, synaction->fingers_nb); |
3000 |
synaction->window_min = window_max; |
3001 |
break; |
3002 |
default: /* One finger or undetectable. */ |
3003 |
synaction->fingers_nb = imax(1, synaction->fingers_nb); |
3004 |
} |
3005 |
sc->zmax = imax(*z, sc->zmax); |
3006 |
|
3229 |
|
3007 |
/* Do we have enough packets to consider this a movement? */ |
3230 |
/* Do we have enough packets to consider this a gesture? */ |
3008 |
if (synaction->queue_len < synaction->window_min) |
3231 |
if (smoother->queue_len + 1 < gest->window_min) |
3009 |
goto SYNAPTICS_END; |
3232 |
return; |
3010 |
|
3233 |
|
3011 |
/* Is a scrolling action occurring? */ |
3234 |
/* Is a scrolling action occurring? */ |
3012 |
if (!synaction->in_taphold && !synaction->in_vscroll) { |
3235 |
if (!gest->in_taphold && !ms->button && |
|
|
3236 |
(!gest->in_vscroll || two_finger_scroll)) { |
3013 |
/* |
3237 |
/* |
3014 |
* A scrolling action must not conflict with a tap |
3238 |
* A scrolling action must not conflict with a tap |
3015 |
* action. Here are the conditions to consider a |
3239 |
* action. Here are the conditions to consider a |
Lines 3020-3031
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
3020 |
* first should be above a configurable minimum |
3244 |
* first should be above a configurable minimum |
3021 |
* . tap timed out |
3245 |
* . tap timed out |
3022 |
*/ |
3246 |
*/ |
3023 |
dxp = abs(synaction->queue[synaction->queue_cursor].x - |
3247 |
dxp = abs(x0 - smoother->start_x); |
3024 |
synaction->start_x); |
3248 |
dyp = abs(y0 - smoother->start_y); |
3025 |
dyp = abs(synaction->queue[synaction->queue_cursor].y - |
|
|
3026 |
synaction->start_y); |
3027 |
|
3249 |
|
3028 |
if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) || |
3250 |
if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) || |
3029 |
dxp >= sc->syninfo.vscroll_min_delta || |
3251 |
dxp >= sc->syninfo.vscroll_min_delta || |
3030 |
dyp >= sc->syninfo.vscroll_min_delta) { |
3252 |
dyp >= sc->syninfo.vscroll_min_delta) { |
3031 |
/* |
3253 |
/* |
Lines 3034-3209
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
3034 |
* as that keeps the maximum number of fingers. |
3256 |
* as that keeps the maximum number of fingers. |
3035 |
*/ |
3257 |
*/ |
3036 |
if (two_finger_scroll) { |
3258 |
if (two_finger_scroll) { |
3037 |
if (w == 0) { |
3259 |
if (nfingers == 2) { |
3038 |
synaction->in_vscroll += |
3260 |
gest->in_vscroll += |
3039 |
dyp ? 2 : 0; |
3261 |
dyp ? 2 : 0; |
3040 |
synaction->in_vscroll += |
3262 |
gest->in_vscroll += |
3041 |
dxp ? 1 : 0; |
3263 |
dxp ? 1 : 0; |
3042 |
} |
3264 |
} |
3043 |
} else { |
3265 |
} else { |
3044 |
/* Check for horizontal scrolling. */ |
3266 |
/* Check for horizontal scrolling. */ |
3045 |
if ((vscroll_hor_area > 0 && |
3267 |
if ((vscroll_hor_area > 0 && |
3046 |
synaction->start_y <= |
3268 |
smoother->start_y <= |
3047 |
vscroll_hor_area) || |
3269 |
vscroll_hor_area) || |
3048 |
(vscroll_hor_area < 0 && |
3270 |
(vscroll_hor_area < 0 && |
3049 |
synaction->start_y >= |
3271 |
smoother->start_y >= |
3050 |
6143 + vscroll_hor_area)) |
3272 |
max_y + vscroll_hor_area)) |
3051 |
synaction->in_vscroll += 2; |
3273 |
gest->in_vscroll += 2; |
3052 |
|
3274 |
|
3053 |
/* Check for vertical scrolling. */ |
3275 |
/* Check for vertical scrolling. */ |
3054 |
if ((vscroll_ver_area > 0 && |
3276 |
if ((vscroll_ver_area > 0 && |
3055 |
synaction->start_x <= |
3277 |
smoother->start_x <= |
3056 |
vscroll_ver_area) || |
3278 |
vscroll_ver_area) || |
3057 |
(vscroll_ver_area < 0 && |
3279 |
(vscroll_ver_area < 0 && |
3058 |
synaction->start_x >= |
3280 |
smoother->start_x >= |
3059 |
6143 + vscroll_ver_area)) |
3281 |
max_x + vscroll_ver_area)) |
3060 |
synaction->in_vscroll += 1; |
3282 |
gest->in_vscroll += 1; |
3061 |
} |
3283 |
} |
3062 |
|
3284 |
|
3063 |
/* Avoid conflicts if area overlaps. */ |
3285 |
/* Avoid conflicts if area overlaps. */ |
3064 |
if (synaction->in_vscroll >= 3) |
3286 |
if (gest->in_vscroll >= 3) |
3065 |
synaction->in_vscroll = |
3287 |
gest->in_vscroll = |
3066 |
(dxp > dyp) ? 2 : 1; |
3288 |
(dxp > dyp) ? 2 : 1; |
3067 |
} |
3289 |
} |
3068 |
} |
3290 |
} |
3069 |
/* |
3291 |
/* |
3070 |
* Reset two finger scrolling when the number of fingers |
3292 |
* Reset two finger scrolling when the number of fingers |
3071 |
* is different from two. |
3293 |
* is different from two or any button is pressed. |
3072 |
*/ |
3294 |
*/ |
3073 |
if (two_finger_scroll && w != 0 && synaction->in_vscroll != 0) { |
3295 |
if (two_finger_scroll && gest->in_vscroll != 0 && |
3074 |
synaction->in_vscroll = 0; |
3296 |
(nfingers != 2 || ms->button)) |
3075 |
exiting_scroll = 1; |
3297 |
gest->in_vscroll = 0; |
3076 |
} |
|
|
3077 |
|
3298 |
|
3078 |
VLOG(5, (LOG_DEBUG, |
3299 |
VLOG(5, (LOG_DEBUG, |
3079 |
"synaptics: virtual scrolling: %s " |
3300 |
"synaptics: virtual scrolling: %s " |
3080 |
"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n", |
3301 |
"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n", |
3081 |
synaction->in_vscroll ? "YES" : "NO", |
3302 |
gest->in_vscroll ? "YES" : "NO", |
3082 |
synaction->in_vscroll, dxp, dyp, |
3303 |
gest->in_vscroll, dxp, dyp, |
3083 |
synaction->fingers_nb)); |
3304 |
gest->fingers_nb)); |
3084 |
|
|
|
3085 |
weight_prev_x = weight_prev_y = weight_previous; |
3086 |
div_max_x = div_max_y = div_max; |
3087 |
|
3088 |
if (synaction->in_vscroll) { |
3089 |
/* Dividers are different with virtual scrolling. */ |
3090 |
div_min = sc->syninfo.vscroll_div_min; |
3091 |
div_max_x = div_max_y = sc->syninfo.vscroll_div_max; |
3092 |
} else { |
3093 |
/* |
3094 |
* There's a lot of noise in coordinates when |
3095 |
* the finger is on the touchpad's borders. When |
3096 |
* using this area, we apply a special weight and |
3097 |
* div. |
3098 |
*/ |
3099 |
if (x0 <= na_left || x0 >= 6143 - na_right) { |
3100 |
weight_prev_x = sc->syninfo.weight_previous_na; |
3101 |
div_max_x = sc->syninfo.div_max_na; |
3102 |
} |
3103 |
|
3104 |
if (y0 <= na_bottom || y0 >= 6143 - na_top) { |
3105 |
weight_prev_y = sc->syninfo.weight_previous_na; |
3106 |
div_max_y = sc->syninfo.div_max_na; |
3107 |
} |
3108 |
} |
3109 |
|
3110 |
/* |
3111 |
* Calculate weights for the average operands and |
3112 |
* the divisor. Both depend on the distance between |
3113 |
* the current packet and a previous one (based on the |
3114 |
* window width). |
3115 |
*/ |
3116 |
window = imin(synaction->queue_len, window_max); |
3117 |
peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1); |
3118 |
dxp = abs(x0 - synaction->queue[peer].x) + 1; |
3119 |
dyp = abs(y0 - synaction->queue[peer].y) + 1; |
3120 |
len = (dxp * dxp) + (dyp * dyp); |
3121 |
weight_prev_x = imin(weight_prev_x, |
3122 |
weight_len_squared * weight_prev_x / len); |
3123 |
weight_prev_y = imin(weight_prev_y, |
3124 |
weight_len_squared * weight_prev_y / len); |
3125 |
|
3126 |
len = (dxp + dyp) / 2; |
3127 |
div_x = div_len * div_max_x / len; |
3128 |
div_x = imin(div_max_x, div_x); |
3129 |
div_x = imax(div_min, div_x); |
3130 |
div_y = div_len * div_max_y / len; |
3131 |
div_y = imin(div_max_y, div_y); |
3132 |
div_y = imax(div_min, div_y); |
3133 |
|
3134 |
VLOG(3, (LOG_DEBUG, |
3135 |
"synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n", |
3136 |
peer, len, weight_prev_x, weight_prev_y, div_x, div_y)); |
3137 |
|
3138 |
/* Compute averages. */ |
3139 |
synaction->avg_dx = |
3140 |
(weight_current * dx * multiplicator + |
3141 |
weight_prev_x * synaction->avg_dx) / |
3142 |
(weight_current + weight_prev_x); |
3143 |
|
3144 |
synaction->avg_dy = |
3145 |
(weight_current * dy * multiplicator + |
3146 |
weight_prev_y * synaction->avg_dy) / |
3147 |
(weight_current + weight_prev_y); |
3148 |
|
3149 |
VLOG(5, (LOG_DEBUG, |
3150 |
"synaptics: avg_dx~=%d, avg_dy~=%d\n", |
3151 |
synaction->avg_dx / multiplicator, |
3152 |
synaction->avg_dy / multiplicator)); |
3153 |
|
3154 |
/* Use these averages to calculate x & y. */ |
3155 |
synaction->squelch_x += synaction->avg_dx; |
3156 |
*x = synaction->squelch_x / (div_x * multiplicator); |
3157 |
synaction->squelch_x = synaction->squelch_x % |
3158 |
(div_x * multiplicator); |
3159 |
|
3160 |
synaction->squelch_y += synaction->avg_dy; |
3161 |
*y = synaction->squelch_y / (div_y * multiplicator); |
3162 |
synaction->squelch_y = synaction->squelch_y % |
3163 |
(div_y * multiplicator); |
3164 |
|
3305 |
|
3165 |
if (synaction->in_vscroll) { |
|
|
3166 |
switch(synaction->in_vscroll) { |
3167 |
case 1: /* Vertical scrolling. */ |
3168 |
if (*y != 0) |
3169 |
ms->button |= (*y > 0) ? |
3170 |
MOUSE_BUTTON4DOWN : |
3171 |
MOUSE_BUTTON5DOWN; |
3172 |
break; |
3173 |
case 2: /* Horizontal scrolling. */ |
3174 |
if (*x != 0) |
3175 |
ms->button |= (*x > 0) ? |
3176 |
MOUSE_BUTTON7DOWN : |
3177 |
MOUSE_BUTTON6DOWN; |
3178 |
break; |
3179 |
} |
3180 |
|
3181 |
/* The pointer is not moved. */ |
3182 |
*x = *y = 0; |
3183 |
} else { |
3184 |
/* On exit the x/y pos may jump, ignore this */ |
3185 |
if (exiting_scroll) |
3186 |
*x = *y = 0; |
3187 |
|
3188 |
VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n", |
3189 |
dx, dy, *x, *y)); |
3190 |
} |
3191 |
} else if (sc->flags & PSM_FLAGS_FINGERDOWN) { |
3306 |
} else if (sc->flags & PSM_FLAGS_FINGERDOWN) { |
3192 |
/* |
3307 |
/* |
3193 |
* An action is currently taking place but the pressure |
3308 |
* An action is currently taking place but the pressure |
3194 |
* dropped under the minimum, putting an end to it. |
3309 |
* dropped under the minimum, putting an end to it. |
3195 |
*/ |
3310 |
*/ |
3196 |
synapticsaction_t *synaction; |
|
|
3197 |
int taphold_timeout, dx, dy, tap_max_delta; |
3311 |
int taphold_timeout, dx, dy, tap_max_delta; |
3198 |
|
3312 |
|
3199 |
synaction = &(sc->synaction); |
3313 |
dx = abs(smoother->queue[smoother->queue_cursor].x - |
3200 |
dx = abs(synaction->queue[synaction->queue_cursor].x - |
3314 |
smoother->start_x); |
3201 |
synaction->start_x); |
3315 |
dy = abs(smoother->queue[smoother->queue_cursor].y - |
3202 |
dy = abs(synaction->queue[synaction->queue_cursor].y - |
3316 |
smoother->start_y); |
3203 |
synaction->start_y); |
|
|
3204 |
|
3317 |
|
3205 |
/* Max delta is disabled for multi-fingers tap. */ |
3318 |
/* Max delta is disabled for multi-fingers tap. */ |
3206 |
if (synaction->fingers_nb > 1) |
3319 |
if (gest->fingers_nb > 1) |
3207 |
tap_max_delta = imax(dx, dy); |
3320 |
tap_max_delta = imax(dx, dy); |
3208 |
else |
3321 |
else |
3209 |
tap_max_delta = sc->syninfo.tap_max_delta; |
3322 |
tap_max_delta = sc->syninfo.tap_max_delta; |
Lines 3214-3225
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
3214 |
VLOG(3, (LOG_DEBUG, |
3327 |
VLOG(3, (LOG_DEBUG, |
3215 |
"synaptics: zmax=%d, dx=%d, dy=%d, " |
3328 |
"synaptics: zmax=%d, dx=%d, dy=%d, " |
3216 |
"delta=%d, fingers=%d, queue=%d\n", |
3329 |
"delta=%d, fingers=%d, queue=%d\n", |
3217 |
sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb, |
3330 |
gest->zmax, dx, dy, tap_max_delta, gest->fingers_nb, |
3218 |
synaction->queue_len)); |
3331 |
smoother->queue_len)); |
3219 |
if (!synaction->in_vscroll && sc->zmax >= tap_threshold && |
3332 |
if (!gest->in_vscroll && gest->zmax >= tap_threshold && |
3220 |
timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) && |
3333 |
timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=) && |
3221 |
dx <= tap_max_delta && dy <= tap_max_delta && |
3334 |
dx <= tap_max_delta && dy <= tap_max_delta && |
3222 |
synaction->queue_len >= sc->syninfo.tap_min_queue) { |
3335 |
smoother->queue_len >= sc->syninfo.tap_min_queue) { |
3223 |
/* |
3336 |
/* |
3224 |
* We have a tap if: |
3337 |
* We have a tap if: |
3225 |
* - the maximum pressure went over tap_threshold |
3338 |
* - the maximum pressure went over tap_threshold |
Lines 3228-3239
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
3228 |
* To handle tap-hold, we must delay any button push to |
3341 |
* To handle tap-hold, we must delay any button push to |
3229 |
* the next action. |
3342 |
* the next action. |
3230 |
*/ |
3343 |
*/ |
3231 |
if (synaction->in_taphold) { |
3344 |
if (gest->in_taphold) { |
3232 |
/* |
3345 |
/* |
3233 |
* This is the second and last tap of a |
3346 |
* This is the second and last tap of a |
3234 |
* double tap action, not a tap-hold. |
3347 |
* double tap action, not a tap-hold. |
3235 |
*/ |
3348 |
*/ |
3236 |
synaction->in_taphold = 0; |
3349 |
gest->in_taphold = 0; |
3237 |
|
3350 |
|
3238 |
/* |
3351 |
/* |
3239 |
* For double-tap to work: |
3352 |
* For double-tap to work: |
Lines 3245-3346
proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
3245 |
*/ |
3358 |
*/ |
3246 |
VLOG(2, (LOG_DEBUG, |
3359 |
VLOG(2, (LOG_DEBUG, |
3247 |
"synaptics: button RELEASE: %d\n", |
3360 |
"synaptics: button RELEASE: %d\n", |
3248 |
synaction->tap_button)); |
3361 |
gest->tap_button)); |
3249 |
sc->flags |= PSM_FLAGS_FINGERDOWN; |
3362 |
sc->flags |= PSM_FLAGS_FINGERDOWN; |
|
|
3363 |
|
3364 |
/* Schedule button press on next interrupt */ |
3365 |
sc->idletimeout.tv_sec = psmhz > 1 ? |
3366 |
0 : 1; |
3367 |
sc->idletimeout.tv_usec = psmhz > 1 ? |
3368 |
1000000 / psmhz : 0; |
3250 |
} else { |
3369 |
} else { |
3251 |
/* |
3370 |
/* |
3252 |
* This is the first tap: we set the |
3371 |
* This is the first tap: we set the |
3253 |
* tap-hold state and notify the button |
3372 |
* tap-hold state and notify the button |
3254 |
* down event. |
3373 |
* down event. |
3255 |
*/ |
3374 |
*/ |
3256 |
synaction->in_taphold = 1; |
3375 |
gest->in_taphold = 1; |
3257 |
taphold_timeout = sc->syninfo.taphold_timeout; |
3376 |
taphold_timeout = sc->syninfo.taphold_timeout; |
3258 |
sc->taptimeout.tv_sec = taphold_timeout / |
3377 |
gest->taptimeout.tv_sec = taphold_timeout / |
3259 |
1000000; |
3378 |
1000000; |
3260 |
sc->taptimeout.tv_usec = taphold_timeout % |
3379 |
gest->taptimeout.tv_usec = taphold_timeout % |
3261 |
1000000; |
3380 |
1000000; |
3262 |
timevaladd(&sc->taptimeout, &sc->lastsoftintr); |
3381 |
sc->idletimeout = gest->taptimeout; |
|
|
3382 |
timevaladd(&gest->taptimeout, |
3383 |
&sc->lastsoftintr); |
3263 |
|
3384 |
|
3264 |
switch (synaction->fingers_nb) { |
3385 |
switch (gest->fingers_nb) { |
3265 |
case 3: |
3386 |
case 3: |
3266 |
synaction->tap_button = |
3387 |
gest->tap_button = |
3267 |
MOUSE_BUTTON2DOWN; |
3388 |
MOUSE_BUTTON2DOWN; |
3268 |
break; |
3389 |
break; |
3269 |
case 2: |
3390 |
case 2: |
3270 |
synaction->tap_button = |
3391 |
gest->tap_button = |
3271 |
MOUSE_BUTTON3DOWN; |
3392 |
MOUSE_BUTTON3DOWN; |
3272 |
break; |
3393 |
break; |
3273 |
default: |
3394 |
default: |
3274 |
synaction->tap_button = |
3395 |
gest->tap_button = |
3275 |
MOUSE_BUTTON1DOWN; |
3396 |
MOUSE_BUTTON1DOWN; |
3276 |
} |
3397 |
} |
3277 |
VLOG(2, (LOG_DEBUG, |
3398 |
VLOG(2, (LOG_DEBUG, |
3278 |
"synaptics: button PRESS: %d\n", |
3399 |
"synaptics: button PRESS: %d\n", |
3279 |
synaction->tap_button)); |
3400 |
gest->tap_button)); |
3280 |
ms->button |= synaction->tap_button; |
3401 |
ms->button |= gest->tap_button; |
3281 |
} |
3402 |
} |
3282 |
} else { |
3403 |
} else { |
3283 |
/* |
3404 |
/* |
3284 |
* Not enough pressure or timeout: reset |
3405 |
* Not enough pressure or timeout: reset |
3285 |
* tap-hold state. |
3406 |
* tap-hold state. |
3286 |
*/ |
3407 |
*/ |
3287 |
if (synaction->in_taphold) { |
3408 |
if (gest->in_taphold) { |
3288 |
VLOG(2, (LOG_DEBUG, |
3409 |
VLOG(2, (LOG_DEBUG, |
3289 |
"synaptics: button RELEASE: %d\n", |
3410 |
"synaptics: button RELEASE: %d\n", |
3290 |
synaction->tap_button)); |
3411 |
gest->tap_button)); |
3291 |
synaction->in_taphold = 0; |
3412 |
gest->in_taphold = 0; |
3292 |
} else { |
3413 |
} else { |
3293 |
VLOG(2, (LOG_DEBUG, |
3414 |
VLOG(2, (LOG_DEBUG, |
3294 |
"synaptics: not a tap-hold\n")); |
3415 |
"synaptics: not a tap-hold\n")); |
3295 |
} |
3416 |
} |
3296 |
} |
3417 |
} |
3297 |
} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && |
3418 |
} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && gest->in_taphold) { |
3298 |
sc->synaction.in_taphold) { |
|
|
3299 |
/* |
3419 |
/* |
3300 |
* For a tap-hold to work, the button must remain down at |
3420 |
* For a tap-hold to work, the button must remain down at |
3301 |
* least until timeout (where the in_taphold flags will be |
3421 |
* least until timeout (where the in_taphold flags will be |
3302 |
* cleared) or during the next action. |
3422 |
* cleared) or during the next action. |
3303 |
*/ |
3423 |
*/ |
3304 |
if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) { |
3424 |
if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=)) { |
3305 |
ms->button |= sc->synaction.tap_button; |
3425 |
ms->button |= gest->tap_button; |
3306 |
} else { |
3426 |
} else { |
3307 |
VLOG(2, (LOG_DEBUG, |
3427 |
VLOG(2, (LOG_DEBUG, "synaptics: button RELEASE: %d\n", |
3308 |
"synaptics: button RELEASE: %d\n", |
3428 |
gest->tap_button)); |
3309 |
sc->synaction.tap_button)); |
3429 |
gest->in_taphold = 0; |
3310 |
sc->synaction.in_taphold = 0; |
|
|
3311 |
} |
3430 |
} |
3312 |
} |
3431 |
} |
3313 |
|
3432 |
|
3314 |
SYNAPTICS_END: |
3433 |
return; |
|
|
3434 |
} |
3435 |
|
3436 |
static void |
3437 |
psmsmoother(struct psm_softc *sc, finger_t *f, int smoother_id, |
3438 |
mousestatus_t *ms, int *x, int *y) |
3439 |
{ |
3440 |
smoother_t *smoother = &sc->smoother[smoother_id]; |
3441 |
gesture_t *gest = &(sc->gesture); |
3442 |
|
3315 |
/* |
3443 |
/* |
3316 |
* Use the extra buttons as a scrollwheel |
3444 |
* Check pressure to detect a real wanted action on the |
3317 |
* |
3445 |
* touchpad. |
3318 |
* XXX X.Org uses the Z axis for vertical wheel only, |
|
|
3319 |
* whereas moused(8) understands special values to differ |
3320 |
* vertical and horizontal wheels. |
3321 |
* |
3322 |
* xf86-input-mouse needs therefore a small patch to |
3323 |
* understand these special values. Without it, the |
3324 |
* horizontal wheel acts as a vertical wheel in X.Org. |
3325 |
* |
3326 |
* That's why the horizontal wheel is disabled by |
3327 |
* default for now. |
3328 |
*/ |
3446 |
*/ |
3329 |
|
3447 |
if (f->p >= sc->syninfo.min_pressure) { |
3330 |
if (ms->button & MOUSE_BUTTON4DOWN) { |
3448 |
int x0, y0; |
3331 |
*z = -1; |
3449 |
int cursor, peer, window; |
3332 |
ms->button &= ~MOUSE_BUTTON4DOWN; |
3450 |
int dx, dy, dxp, dyp; |
3333 |
} else if (ms->button & MOUSE_BUTTON5DOWN) { |
3451 |
int max_width, max_pressure; |
|
|
3452 |
int margin_top, margin_right, margin_bottom, margin_left; |
3453 |
int na_top, na_right, na_bottom, na_left; |
3454 |
int window_min, window_max; |
3455 |
int multiplicator; |
3456 |
int weight_current, weight_previous, weight_len_squared; |
3457 |
int div_min, div_max, div_len; |
3458 |
int vscroll_hor_area, vscroll_ver_area; |
3459 |
int two_finger_scroll; |
3460 |
int max_x, max_y; |
3461 |
int len, weight_prev_x, weight_prev_y; |
3462 |
int div_max_x, div_max_y, div_x, div_y; |
3463 |
int is_fuzzy; |
3464 |
|
3465 |
/* Read sysctl. */ |
3466 |
/* XXX Verify values? */ |
3467 |
max_width = sc->syninfo.max_width; |
3468 |
max_pressure = sc->syninfo.max_pressure; |
3469 |
margin_top = sc->syninfo.margin_top; |
3470 |
margin_right = sc->syninfo.margin_right; |
3471 |
margin_bottom = sc->syninfo.margin_bottom; |
3472 |
margin_left = sc->syninfo.margin_left; |
3473 |
na_top = sc->syninfo.na_top; |
3474 |
na_right = sc->syninfo.na_right; |
3475 |
na_bottom = sc->syninfo.na_bottom; |
3476 |
na_left = sc->syninfo.na_left; |
3477 |
window_min = sc->syninfo.window_min; |
3478 |
window_max = sc->syninfo.window_max; |
3479 |
multiplicator = sc->syninfo.multiplicator; |
3480 |
weight_current = sc->syninfo.weight_current; |
3481 |
weight_previous = sc->syninfo.weight_previous; |
3482 |
weight_len_squared = sc->syninfo.weight_len_squared; |
3483 |
div_min = sc->syninfo.div_min; |
3484 |
div_max = sc->syninfo.div_max; |
3485 |
div_len = sc->syninfo.div_len; |
3486 |
vscroll_hor_area = sc->syninfo.vscroll_hor_area; |
3487 |
vscroll_ver_area = sc->syninfo.vscroll_ver_area; |
3488 |
two_finger_scroll = sc->syninfo.two_finger_scroll; |
3489 |
max_x = sc->syninfo.max_x; |
3490 |
max_y = sc->syninfo.max_y; |
3491 |
|
3492 |
is_fuzzy = (f->flags & PSM_FINGER_FUZZY) != 0; |
3493 |
|
3494 |
/* Read current absolute position. */ |
3495 |
x0 = f->x; |
3496 |
y0 = f->y; |
3497 |
|
3498 |
/* |
3499 |
* Limit the coordinates to the specified margins because |
3500 |
* this area isn't very reliable. |
3501 |
*/ |
3502 |
if (x0 <= margin_left) |
3503 |
x0 = margin_left; |
3504 |
else if (x0 >= max_x - margin_right) |
3505 |
x0 = max_x - margin_right; |
3506 |
if (y0 <= margin_bottom) |
3507 |
y0 = margin_bottom; |
3508 |
else if (y0 >= max_y - margin_top) |
3509 |
y0 = max_y - margin_top; |
3510 |
|
3511 |
/* If the action is just beginning, init the structure. */ |
3512 |
if (smoother->active == 0) { |
3513 |
VLOG(3, (LOG_DEBUG, "smoother%d: ---\n", smoother_id)); |
3514 |
|
3515 |
/* Store the first point of this action. */ |
3516 |
smoother->start_x = x0; |
3517 |
smoother->start_y = y0; |
3518 |
dx = dy = 0; |
3519 |
|
3520 |
/* Initialize queue. */ |
3521 |
smoother->queue_cursor = SYNAPTICS_PACKETQUEUE; |
3522 |
smoother->queue_len = 0; |
3523 |
|
3524 |
/* Reset average. */ |
3525 |
smoother->avg_dx = 0; |
3526 |
smoother->avg_dy = 0; |
3527 |
|
3528 |
/* Reset squelch. */ |
3529 |
smoother->squelch_x = 0; |
3530 |
smoother->squelch_y = 0; |
3531 |
|
3532 |
/* Activate queue */ |
3533 |
smoother->active = 1; |
3534 |
} else { |
3535 |
/* Calculate the current delta. */ |
3536 |
cursor = smoother->queue_cursor; |
3537 |
dx = x0 - smoother->queue[cursor].x; |
3538 |
dy = y0 - smoother->queue[cursor].y; |
3539 |
} |
3540 |
|
3541 |
VLOG(3, (LOG_DEBUG, "smoother%d: ipacket: [%d, %d], %d, %d\n", |
3542 |
smoother_id, x0, y0, f->p, f->w)); |
3543 |
|
3544 |
/* Queue this new packet. */ |
3545 |
cursor = SYNAPTICS_QUEUE_CURSOR(smoother->queue_cursor - 1); |
3546 |
smoother->queue[cursor].x = x0; |
3547 |
smoother->queue[cursor].y = y0; |
3548 |
smoother->queue_cursor = cursor; |
3549 |
if (smoother->queue_len < SYNAPTICS_PACKETQUEUE) |
3550 |
smoother->queue_len++; |
3551 |
VLOG(5, (LOG_DEBUG, |
3552 |
"smoother%d: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n", |
3553 |
smoother_id, cursor, x0, y0, dx, dy)); |
3554 |
|
3555 |
/* Do we have enough packets to consider this a movement? */ |
3556 |
if (smoother->queue_len < gest->window_min) |
3557 |
return; |
3558 |
|
3559 |
weight_prev_x = weight_prev_y = weight_previous; |
3560 |
div_max_x = div_max_y = div_max; |
3561 |
|
3562 |
if (gest->in_vscroll) { |
3563 |
/* Dividers are different with virtual scrolling. */ |
3564 |
div_min = sc->syninfo.vscroll_div_min; |
3565 |
div_max_x = div_max_y = sc->syninfo.vscroll_div_max; |
3566 |
} else { |
3567 |
/* |
3568 |
* There's a lot of noise in coordinates when |
3569 |
* the finger is on the touchpad's borders. When |
3570 |
* using this area, we apply a special weight and |
3571 |
* div. |
3572 |
*/ |
3573 |
if (x0 <= na_left || x0 >= max_x - na_right) { |
3574 |
weight_prev_x = sc->syninfo.weight_previous_na; |
3575 |
div_max_x = sc->syninfo.div_max_na; |
3576 |
} |
3577 |
|
3578 |
if (y0 <= na_bottom || y0 >= max_y - na_top) { |
3579 |
weight_prev_y = sc->syninfo.weight_previous_na; |
3580 |
div_max_y = sc->syninfo.div_max_na; |
3581 |
} |
3582 |
} |
3583 |
|
3584 |
/* |
3585 |
* Calculate weights for the average operands and |
3586 |
* the divisor. Both depend on the distance between |
3587 |
* the current packet and a previous one (based on the |
3588 |
* window width). |
3589 |
*/ |
3590 |
window = imin(smoother->queue_len, window_max); |
3591 |
peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1); |
3592 |
dxp = abs(x0 - smoother->queue[peer].x) + 1; |
3593 |
dyp = abs(y0 - smoother->queue[peer].y) + 1; |
3594 |
len = (dxp * dxp) + (dyp * dyp); |
3595 |
weight_prev_x = imin(weight_prev_x, |
3596 |
weight_len_squared * weight_prev_x / len); |
3597 |
weight_prev_y = imin(weight_prev_y, |
3598 |
weight_len_squared * weight_prev_y / len); |
3599 |
|
3600 |
len = (dxp + dyp) / 2; |
3601 |
div_x = div_len * div_max_x / len; |
3602 |
div_x = imin(div_max_x, div_x); |
3603 |
div_x = imax(div_min, div_x); |
3604 |
div_y = div_len * div_max_y / len; |
3605 |
div_y = imin(div_max_y, div_y); |
3606 |
div_y = imax(div_min, div_y); |
3607 |
|
3608 |
VLOG(3, (LOG_DEBUG, |
3609 |
"smoother%d: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n", |
3610 |
smoother_id, peer, len, weight_prev_x, weight_prev_y, |
3611 |
div_x, div_y)); |
3612 |
|
3613 |
/* Compute averages. */ |
3614 |
smoother->avg_dx = |
3615 |
(weight_current * dx * multiplicator + |
3616 |
weight_prev_x * smoother->avg_dx) / |
3617 |
(weight_current + weight_prev_x); |
3618 |
|
3619 |
smoother->avg_dy = |
3620 |
(weight_current * dy * multiplicator + |
3621 |
weight_prev_y * smoother->avg_dy) / |
3622 |
(weight_current + weight_prev_y); |
3623 |
|
3624 |
VLOG(5, (LOG_DEBUG, |
3625 |
"smoother%d: avg_dx~=%d, avg_dy~=%d\n", smoother_id, |
3626 |
smoother->avg_dx / multiplicator, |
3627 |
smoother->avg_dy / multiplicator)); |
3628 |
|
3629 |
/* Use these averages to calculate x & y. */ |
3630 |
smoother->squelch_x += smoother->avg_dx; |
3631 |
dxp = smoother->squelch_x / (div_x * multiplicator); |
3632 |
smoother->squelch_x = smoother->squelch_x % |
3633 |
(div_x * multiplicator); |
3634 |
|
3635 |
smoother->squelch_y += smoother->avg_dy; |
3636 |
dyp = smoother->squelch_y / (div_y * multiplicator); |
3637 |
smoother->squelch_y = smoother->squelch_y % |
3638 |
(div_y * multiplicator); |
3639 |
|
3640 |
switch(gest->in_vscroll) { |
3641 |
case 0: /* Pointer movement. */ |
3642 |
/* On real<->fuzzy finger switch the x/y pos jumps */ |
3643 |
if (is_fuzzy == smoother->is_fuzzy) { |
3644 |
*x += dxp; |
3645 |
*y += dyp; |
3646 |
} |
3647 |
|
3648 |
VLOG(3, (LOG_DEBUG, "smoother%d: [%d, %d] -> [%d, %d]\n", |
3649 |
smoother_id, dx, dy, dxp, dyp)); |
3650 |
break; |
3651 |
case 1: /* Vertical scrolling. */ |
3652 |
if (dyp != 0) |
3653 |
ms->button |= (dyp > 0) ? |
3654 |
MOUSE_BUTTON4DOWN : MOUSE_BUTTON5DOWN; |
3655 |
break; |
3656 |
case 2: /* Horizontal scrolling. */ |
3657 |
if (dxp != 0) |
3658 |
ms->button |= (dxp > 0) ? |
3659 |
MOUSE_BUTTON7DOWN : MOUSE_BUTTON6DOWN; |
3660 |
break; |
3661 |
} |
3662 |
|
3663 |
smoother->is_fuzzy = is_fuzzy; |
3664 |
|
3665 |
} else { |
3666 |
/* |
3667 |
* Deactivate queue. Note: We can not just reset queue here |
3668 |
* as these values are still used by gesture processor. |
3669 |
* So postpone reset till next touch. |
3670 |
*/ |
3671 |
smoother->active = 0; |
3672 |
} |
3673 |
} |
3674 |
|
3675 |
static int |
3676 |
proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, |
3677 |
int *x, int *y, int *z) |
3678 |
{ |
3679 |
static int touchpad_button, trackpoint_button; |
3680 |
finger_t fn, f[ELANTECH_MAX_FINGERS]; |
3681 |
int pkt, id, scale, i, nfingers, mask; |
3682 |
|
3683 |
if (!elantech_support) |
3684 |
return (0); |
3685 |
|
3686 |
/* Determine packet format and do a sanity check for out of sync packets. */ |
3687 |
if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion)) |
3688 |
pkt = ELANTECH_PKT_NOP; |
3689 |
else if (ELANTECH_PKT_IS_TRACKPOINT(pb)) |
3690 |
pkt = ELANTECH_PKT_TRACKPOINT; |
3691 |
else |
3692 |
switch (sc->elanhw.hwversion) { |
3693 |
case 2: |
3694 |
if (!ELANTECH_PKT_IS_V2(pb)) |
3695 |
return (-1); |
3696 |
|
3697 |
pkt = (pb->ipacket[0] & 0xc0) == 0x80 ? |
3698 |
ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON; |
3699 |
break; |
3700 |
case 3: |
3701 |
if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) && |
3702 |
!ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc)) |
3703 |
return (-1); |
3704 |
|
3705 |
pkt = ELANTECH_PKT_V3; |
3706 |
break; |
3707 |
case 4: |
3708 |
if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc)) |
3709 |
return (-1); |
3710 |
|
3711 |
switch (pb->ipacket[3] & 0x03) { |
3712 |
case 0x00: |
3713 |
pkt = ELANTECH_PKT_V4_STATUS; |
3714 |
break; |
3715 |
case 0x01: |
3716 |
pkt = ELANTECH_PKT_V4_HEAD; |
3717 |
break; |
3718 |
case 0x02: |
3719 |
pkt = ELANTECH_PKT_V4_MOTION; |
3720 |
break; |
3721 |
default: |
3722 |
return (-1); |
3723 |
} |
3724 |
break; |
3725 |
default: |
3726 |
return (-1); |
3727 |
} |
3728 |
|
3729 |
VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt)); |
3730 |
|
3731 |
for (id = 0; id < ELANTECH_MAX_FINGERS; id++) |
3732 |
PSM_FINGER_RESET(f[id]); |
3733 |
|
3734 |
*x = *y = *z = 0; |
3735 |
ms->button = ms->obutton; |
3736 |
|
3737 |
if (sc->syninfo.touchpad_off) |
3738 |
return (0); |
3739 |
|
3740 |
/* Common legend |
3741 |
* L: Left mouse button pressed |
3742 |
* R: Right mouse button pressed |
3743 |
* N: number of fingers on touchpad |
3744 |
* X: absolute x value (horizontal) |
3745 |
* Y: absolute y value (vertical) |
3746 |
* W; width of the finger touch |
3747 |
* P: pressure |
3748 |
*/ |
3749 |
switch (pkt) { |
3750 |
case ELANTECH_PKT_V2_COMMON: /* HW V2. One/Three finger touch */ |
3751 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3752 |
* ------------------------------------------- |
3753 |
* ipacket[0]: N1 N0 W3 W2 . . R L |
3754 |
* ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 |
3755 |
* ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 |
3756 |
* ipacket[3]: N4 VF W1 W0 . . . B2 |
3757 |
* ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 |
3758 |
* ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 |
3759 |
* ------------------------------------------- |
3760 |
* N4: set if more than 3 fingers (only in 3 fingers mode) |
3761 |
* VF: a kind of flag? (only on EF123, 0 when finger |
3762 |
* is over one of the buttons, 1 otherwise) |
3763 |
* B2: (on EF113 only, 0 otherwise), one button pressed |
3764 |
* P & W is not reported on EF113 touchpads |
3765 |
*/ |
3766 |
nfingers = (pb->ipacket[0] & 0xc0) >> 6; |
3767 |
if (nfingers == 3 && (pb->ipacket[3] & 0x80)) |
3768 |
nfingers = 4; |
3769 |
mask = (1 << nfingers) - 1; |
3770 |
|
3771 |
fn = ELANTECH_FINGER_SET_XYP(pb); |
3772 |
if (sc->elanhw.haspressure) { |
3773 |
fn.w = ((pb->ipacket[0] & 0x30) >> 2) | |
3774 |
((pb->ipacket[3] & 0x30) >> 4); |
3775 |
} else { |
3776 |
fn.p = PSM_FINGER_DEFAULT_P; |
3777 |
fn.w = PSM_FINGER_DEFAULT_W; |
3778 |
} |
3779 |
|
3780 |
/* |
3781 |
* HW v2 dont report exact finger positions when 3 or more |
3782 |
* fingers are on touchpad. Use reported value as fingers |
3783 |
* position as it is required for tap detection |
3784 |
*/ |
3785 |
if (nfingers > 2) |
3786 |
fn.flags = PSM_FINGER_FUZZY; |
3787 |
|
3788 |
for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++) |
3789 |
f[id] = fn; |
3790 |
break; |
3791 |
|
3792 |
case ELANTECH_PKT_V2_2FINGER: /*HW V2. Two finger touch */ |
3793 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3794 |
* ------------------------------------------- |
3795 |
* ipacket[0]: N1 N0 AY8 AX8 . . R L |
3796 |
* ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0 |
3797 |
* ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0 |
3798 |
* ipacket[3]: . . BY8 BX8 . . . . |
3799 |
* ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0 |
3800 |
* ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0 |
3801 |
* ------------------------------------------- |
3802 |
* AX: lower-left finger absolute x value |
3803 |
* AY: lower-left finger absolute y value |
3804 |
* BX: upper-right finger absolute x value |
3805 |
* BY: upper-right finger absolute y value |
3806 |
*/ |
3807 |
nfingers = 2; |
3808 |
mask = (1 << nfingers) - 1; |
3809 |
|
3810 |
for (id = 0; id < imin(2, ELANTECH_MAX_FINGERS); id ++) |
3811 |
f[id] = (finger_t) { |
3812 |
.x = (((pb->ipacket[id * 3] & 0x10) << 4) | |
3813 |
pb->ipacket[id * 3 + 1]) << 2, |
3814 |
.y = (((pb->ipacket[id * 3] & 0x20) << 3) | |
3815 |
pb->ipacket[id * 3 + 2]) << 2, |
3816 |
.p = PSM_FINGER_DEFAULT_P, |
3817 |
.w = PSM_FINGER_DEFAULT_W, |
3818 |
/* HW ver.2 sends bounding box */ |
3819 |
.flags = PSM_FINGER_FUZZY |
3820 |
}; |
3821 |
break; |
3822 |
|
3823 |
case ELANTECH_PKT_V3: /* HW Version 3 */ |
3824 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3825 |
* ------------------------------------------- |
3826 |
* ipacket[0]: N1 N0 W3 W2 0 1 R L |
3827 |
* ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 |
3828 |
* ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 |
3829 |
* ipacket[3]: 0 0 W1 W0 0 0 1 0 |
3830 |
* ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 |
3831 |
* ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 |
3832 |
* ------------------------------------------- |
3833 |
*/ |
3834 |
nfingers = (pb->ipacket[0] & 0xc0) >> 6; |
3835 |
mask = (1 << nfingers) - 1; |
3836 |
id = nfingers - 1; |
3837 |
|
3838 |
fn = ELANTECH_FINGER_SET_XYP(pb); |
3839 |
fn.w = ((pb->ipacket[0] & 0x30) >> 2) | |
3840 |
((pb->ipacket[3] & 0x30) >> 4); |
3841 |
|
3842 |
/* |
3843 |
* HW v3 dont report exact finger positions when 3 or more |
3844 |
* fingers are on touchpad. Use reported value as fingers |
3845 |
* position as it is required for tap detection |
3846 |
*/ |
3847 |
if (nfingers > 1) |
3848 |
fn.flags = PSM_FINGER_FUZZY; |
3849 |
|
3850 |
for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++) |
3851 |
f[id] = fn; |
3852 |
|
3853 |
if (nfingers == 2) { |
3854 |
if (ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc)) { |
3855 |
sc->elanaction.fingers[0] = fn; |
3856 |
return (0); |
3857 |
} else |
3858 |
f[0] = sc->elanaction.fingers[0]; |
3859 |
} |
3860 |
break; |
3861 |
|
3862 |
case ELANTECH_PKT_V4_STATUS: /* HW Version 4. Status packet */ |
3863 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3864 |
* ------------------------------------------- |
3865 |
* ipacket[0]: . . . . 0 1 R L |
3866 |
* ipacket[1]: . . . F4 F3 F2 F1 F0 |
3867 |
* ipacket[2]: . . . . . . . . |
3868 |
* ipacket[3]: . . . 1 0 0 0 0 |
3869 |
* ipacket[4]: PL . . . . . . . |
3870 |
* ipacket[5]: . . . . . . . . |
3871 |
* ------------------------------------------- |
3872 |
* Fn: finger n is on touchpad |
3873 |
* PL: palm |
3874 |
* HV ver4 sends a status packet to indicate that the numbers |
3875 |
* or identities of the fingers has been changed |
3876 |
*/ |
3877 |
|
3878 |
mask = pb->ipacket[1] & 0x1f; |
3879 |
nfingers = bitcount(mask); |
3880 |
|
3881 |
/* Skip "new finger is on touchpad" packets */ |
3882 |
if ((sc->elanaction.mask & mask) == sc->elanaction.mask && |
3883 |
(mask & ~sc->elanaction.mask)) { |
3884 |
sc->elanaction.mask = mask; |
3885 |
return (0); |
3886 |
} |
3887 |
|
3888 |
break; |
3889 |
|
3890 |
case ELANTECH_PKT_V4_HEAD: /* HW Version 4. Head packet */ |
3891 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3892 |
* ------------------------------------------- |
3893 |
* ipacket[0]: W3 W2 W1 W0 0 1 R L |
3894 |
* ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 |
3895 |
* ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 |
3896 |
* ipacket[3]: ID2 ID1 ID0 1 0 0 0 1 |
3897 |
* ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 |
3898 |
* ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 |
3899 |
* ------------------------------------------- |
3900 |
* ID: finger id |
3901 |
* HW ver 4 sends head packets in two cases: |
3902 |
* 1. One finger touch and movement. |
3903 |
* 2. Next after status packet to tell new finger positions. |
3904 |
*/ |
3905 |
mask = sc->elanaction.mask; |
3906 |
nfingers = bitcount(mask); |
3907 |
id = ((pb->ipacket[3] & 0xe0) >> 5) - 1; |
3908 |
|
3909 |
if (id >= 0 && id < ELANTECH_MAX_FINGERS) { |
3910 |
f[id] = ELANTECH_FINGER_SET_XYP(pb); |
3911 |
f[id].w = (pb->ipacket[0] & 0xf0) >> 4; |
3912 |
} |
3913 |
break; |
3914 |
|
3915 |
case ELANTECH_PKT_V4_MOTION: /* HW Version 4. Motion packet */ |
3916 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3917 |
* ------------------------------------------- |
3918 |
* ipacket[0]: ID2 ID1 ID0 OF 0 1 R L |
3919 |
* ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 |
3920 |
* ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 |
3921 |
* ipacket[3]: ID2 ID1 ID0 1 0 0 1 0 |
3922 |
* ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 |
3923 |
* ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 |
3924 |
* ------------------------------------------- |
3925 |
* OF: delta overflows (> 127 or < -128), in this case |
3926 |
* firmware sends us (delta x / 5) and (delta y / 5) |
3927 |
* ID: finger id |
3928 |
* DX: delta x (two's complement) |
3929 |
* XY: delta y (two's complement) |
3930 |
* byte 0 ~ 2 for one finger |
3931 |
* byte 3 ~ 5 for another finger |
3932 |
*/ |
3933 |
mask = sc->elanaction.mask; |
3934 |
nfingers = bitcount(mask); |
3935 |
|
3936 |
scale = (pb->ipacket[0] & 0x10) ? 5 : 1; |
3937 |
for (i = 0; i <= 3; i += 3) { |
3938 |
id = ((pb->ipacket[i] & 0xe0) >> 5) - 1; |
3939 |
if (id < 0 || id >= ELANTECH_MAX_FINGERS) |
3940 |
continue; |
3941 |
|
3942 |
if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) { |
3943 |
f[id] = sc->elanaction.fingers[id]; |
3944 |
f[id].x += imax(-f[id].x, |
3945 |
(signed char)pb->ipacket[i+1] * scale); |
3946 |
f[id].y += imax(-f[id].y, |
3947 |
(signed char)pb->ipacket[i+2] * scale); |
3948 |
} else { |
3949 |
VLOG(3, (LOG_DEBUG, "elantech: " |
3950 |
"HW v4 motion packet skipped\n")); |
3951 |
} |
3952 |
} |
3953 |
|
3954 |
break; |
3955 |
|
3956 |
case ELANTECH_PKT_TRACKPOINT: |
3957 |
/* 7 6 5 4 3 2 1 0 (LSB) |
3958 |
* ------------------------------------------- |
3959 |
* ipacket[0]: 0 0 SX SY 0 M R L |
3960 |
* ipacket[1]: ~SX 0 0 0 0 0 0 0 |
3961 |
* ipacket[2]: ~SY 0 0 0 0 0 0 0 |
3962 |
* ipacket[3]: 0 0 ~SY ~SX 0 1 1 0 |
3963 |
* ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0 |
3964 |
* ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 |
3965 |
* ------------------------------------------- |
3966 |
* X and Y are written in two's complement spread |
3967 |
* over 9 bits with SX/SY the relative top bit and |
3968 |
* X7..X0 and Y7..Y0 the lower bits. |
3969 |
*/ |
3970 |
*x = (pb->ipacket[0] & 0x20) ? |
3971 |
pb->ipacket[4] - 256 : pb->ipacket[4]; |
3972 |
*y = (pb->ipacket[0] & 0x10) ? |
3973 |
pb->ipacket[5] - 256 : pb->ipacket[5]; |
3974 |
|
3975 |
trackpoint_button = |
3976 |
((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) | |
3977 |
((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) | |
3978 |
((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0); |
3979 |
|
3980 |
ms->button = touchpad_button | trackpoint_button; |
3981 |
return (0); |
3982 |
|
3983 |
case ELANTECH_PKT_NOP: |
3984 |
return (0); |
3985 |
|
3986 |
default: |
3987 |
return (-1); |
3988 |
} |
3989 |
|
3990 |
for (id = 0; id < ELANTECH_MAX_FINGERS; id++) |
3991 |
if (PSM_FINGER_IS_SET(f[id])) |
3992 |
VLOG(2, (LOG_DEBUG, "elantech: " |
3993 |
"finger %d: down [%d, %d], %d, %d, %d\n", id + 1, |
3994 |
f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags)); |
3995 |
|
3996 |
/* Touchpad button presses */ |
3997 |
if (sc->elanhw.isclickpad) { |
3998 |
touchpad_button = |
3999 |
((pb->ipacket[0] & 0x03) ? MOUSE_BUTTON1DOWN : 0); |
4000 |
} else { |
4001 |
touchpad_button = |
4002 |
((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) | |
4003 |
((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0); |
4004 |
} |
4005 |
|
4006 |
ms->button = touchpad_button | trackpoint_button; |
4007 |
|
4008 |
/* Palm detection doesn't terminate the current action. */ |
4009 |
if (!psmpalmdetect(sc, &f[0], nfingers)) { |
4010 |
/* Send finger 1 position to gesture processor */ |
4011 |
if (PSM_FINGER_IS_SET(f[0]) || PSM_FINGER_IS_SET(f[1]) || |
4012 |
nfingers == 0) |
4013 |
psmgestures(sc, &f[0], imin(nfingers, 3), ms); |
4014 |
/* Send fingers positions to movement smoothers */ |
4015 |
for (id = 0; id < PSM_FINGERS; id++) |
4016 |
if (PSM_FINGER_IS_SET(f[id]) || !(mask & (1 << id))) |
4017 |
psmsmoother(sc, &f[id], id, ms, x, y); |
4018 |
} else { |
4019 |
VLOG(2, (LOG_DEBUG, "elantech: palm detected! (%d)\n", |
4020 |
f[0].w)); |
4021 |
} |
4022 |
|
4023 |
/* Store current finger positions in action context */ |
4024 |
for (id = 0; id < ELANTECH_MAX_FINGERS; id++) { |
4025 |
if (PSM_FINGER_IS_SET(f[id])) |
4026 |
sc->elanaction.fingers[id] = f[id]; |
4027 |
if ((sc->elanaction.mask & (1 << id)) && !(mask & (1 << id))) |
4028 |
PSM_FINGER_RESET(sc->elanaction.fingers[id]); |
4029 |
} |
4030 |
sc->elanaction.mask = mask; |
4031 |
|
4032 |
/* Use the extra buttons as a scrollwheel */ |
4033 |
if (ms->button & MOUSE_BUTTON4DOWN) |
4034 |
*z = -1; |
4035 |
else if (ms->button & MOUSE_BUTTON5DOWN) |
3334 |
*z = 1; |
4036 |
*z = 1; |
3335 |
ms->button &= ~MOUSE_BUTTON5DOWN; |
4037 |
else if (ms->button & MOUSE_BUTTON6DOWN) |
3336 |
} else if (ms->button & MOUSE_BUTTON6DOWN) { |
|
|
3337 |
*z = -2; |
4038 |
*z = -2; |
3338 |
ms->button &= ~MOUSE_BUTTON6DOWN; |
4039 |
else if (ms->button & MOUSE_BUTTON7DOWN) |
3339 |
} else if (ms->button & MOUSE_BUTTON7DOWN) { |
|
|
3340 |
*z = 2; |
4040 |
*z = 2; |
3341 |
ms->button &= ~MOUSE_BUTTON7DOWN; |
4041 |
else |
3342 |
} else |
|
|
3343 |
*z = 0; |
4042 |
*z = 0; |
|
|
4043 |
ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN | |
4044 |
MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN); |
3344 |
|
4045 |
|
3345 |
return (0); |
4046 |
return (0); |
3346 |
} |
4047 |
} |
Lines 3413-3418
proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
Link Here
|
3413 |
} |
4114 |
} |
3414 |
|
4115 |
|
3415 |
static void |
4116 |
static void |
|
|
4117 |
psmsoftintridle(void *arg) |
4118 |
{ |
4119 |
struct psm_softc *sc = arg; |
4120 |
packetbuf_t *pb; |
4121 |
|
4122 |
/* Invoke soft handler only when pqueue is empty. Otherwise it will be |
4123 |
* invoked from psmintr soon with pqueue filled with real data */ |
4124 |
if (sc->pqueue_start == sc->pqueue_end && |
4125 |
sc->idlepacket.inputbytes > 0) { |
4126 |
/* Grow circular queue backwards to avoid race with psmintr */ |
4127 |
if (--sc->pqueue_start < 0) |
4128 |
sc->pqueue_start = PSM_PACKETQUEUE - 1; |
4129 |
|
4130 |
pb = &sc->pqueue[sc->pqueue_start]; |
4131 |
memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t)); |
4132 |
VLOG(4, (LOG_DEBUG, |
4133 |
"psmsoftintridle: %02x %02x %02x %02x %02x %02x\n", |
4134 |
pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], |
4135 |
pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); |
4136 |
|
4137 |
psmsoftintr(arg); |
4138 |
} |
4139 |
} |
4140 |
|
4141 |
static void |
3416 |
psmsoftintr(void *arg) |
4142 |
psmsoftintr(void *arg) |
3417 |
{ |
4143 |
{ |
3418 |
/* |
4144 |
/* |
Lines 3465-3470
psmsoftintr(void *arg)
Link Here
|
3465 |
if (sc->config & PSM_CONFIG_FORCETAP) |
4191 |
if (sc->config & PSM_CONFIG_FORCETAP) |
3466 |
ms.button |= ((c & MOUSE_PS2_TAP)) ? |
4192 |
ms.button |= ((c & MOUSE_PS2_TAP)) ? |
3467 |
0 : MOUSE_BUTTON4DOWN; |
4193 |
0 : MOUSE_BUTTON4DOWN; |
|
|
4194 |
timevalclear(&sc->idletimeout); |
4195 |
sc->idlepacket.inputbytes = 0; |
3468 |
|
4196 |
|
3469 |
switch (sc->hw.model) { |
4197 |
switch (sc->hw.model) { |
3470 |
|
4198 |
|
Lines 3603-3608
psmsoftintr(void *arg)
Link Here
|
3603 |
goto next; |
4331 |
goto next; |
3604 |
break; |
4332 |
break; |
3605 |
|
4333 |
|
|
|
4334 |
case MOUSE_MODEL_ELANTECH: |
4335 |
if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0) |
4336 |
goto next; |
4337 |
break; |
4338 |
|
3606 |
case MOUSE_MODEL_TRACKPOINT: |
4339 |
case MOUSE_MODEL_TRACKPOINT: |
3607 |
case MOUSE_MODEL_GENERIC: |
4340 |
case MOUSE_MODEL_GENERIC: |
3608 |
default: |
4341 |
default: |
Lines 3627-3632
psmsoftintr(void *arg)
Link Here
|
3627 |
} |
4360 |
} |
3628 |
} |
4361 |
} |
3629 |
|
4362 |
|
|
|
4363 |
/* Store last packet for reinjection if it has not been set already */ |
4364 |
if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0) |
4365 |
sc->idlepacket = *pb; |
4366 |
|
3630 |
ms.dx = x; |
4367 |
ms.dx = x; |
3631 |
ms.dy = y; |
4368 |
ms.dy = y; |
3632 |
ms.dz = z; |
4369 |
ms.dz = z; |
Lines 3673-3678
next:
Link Here
|
3673 |
pgsigio(&sc->async, SIGIO, 0); |
4410 |
pgsigio(&sc->async, SIGIO, 0); |
3674 |
} |
4411 |
} |
3675 |
sc->state &= ~PSM_SOFTARMED; |
4412 |
sc->state &= ~PSM_SOFTARMED; |
|
|
4413 |
|
4414 |
/* schedule injection of predefined packet after idletimeout |
4415 |
* if no data packets have been received from psmintr */ |
4416 |
if (timevalisset(&sc->idletimeout)) { |
4417 |
sc->state |= PSM_SOFTARMED; |
4418 |
callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout), |
4419 |
psmsoftintridle, sc); |
4420 |
VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n", |
4421 |
tvtohz(&sc->idletimeout))); |
4422 |
} |
3676 |
splx(s); |
4423 |
splx(s); |
3677 |
} |
4424 |
} |
3678 |
|
4425 |
|
Lines 4106-4115
enable_4dplus(struct psm_softc *sc, enum probearg arg)
Link Here
|
4106 |
static int |
4853 |
static int |
4107 |
synaptics_sysctl(SYSCTL_HANDLER_ARGS) |
4854 |
synaptics_sysctl(SYSCTL_HANDLER_ARGS) |
4108 |
{ |
4855 |
{ |
|
|
4856 |
struct psm_softc *sc; |
4109 |
int error, arg; |
4857 |
int error, arg; |
4110 |
|
4858 |
|
|
|
4859 |
if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 || |
4860 |
oidp->oid_arg2 > SYNAPTICS_SYSCTL_SOFTBUTTON3_X) |
4861 |
return (EINVAL); |
4862 |
|
4863 |
sc = oidp->oid_arg1; |
4864 |
|
4111 |
/* Read the current value. */ |
4865 |
/* Read the current value. */ |
4112 |
arg = *(int *)oidp->oid_arg1; |
4866 |
arg = *(int *)((char *)sc + oidp->oid_arg2); |
4113 |
error = sysctl_handle_int(oidp, &arg, 0, req); |
4867 |
error = sysctl_handle_int(oidp, &arg, 0, req); |
4114 |
|
4868 |
|
4115 |
/* Sanity check. */ |
4869 |
/* Sanity check. */ |
Lines 4131-4144
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
Link Here
|
4131 |
return (EINVAL); |
4885 |
return (EINVAL); |
4132 |
break; |
4886 |
break; |
4133 |
case SYNAPTICS_SYSCTL_MARGIN_TOP: |
4887 |
case SYNAPTICS_SYSCTL_MARGIN_TOP: |
4134 |
case SYNAPTICS_SYSCTL_MARGIN_RIGHT: |
|
|
4135 |
case SYNAPTICS_SYSCTL_MARGIN_BOTTOM: |
4888 |
case SYNAPTICS_SYSCTL_MARGIN_BOTTOM: |
4136 |
case SYNAPTICS_SYSCTL_MARGIN_LEFT: |
|
|
4137 |
case SYNAPTICS_SYSCTL_NA_TOP: |
4889 |
case SYNAPTICS_SYSCTL_NA_TOP: |
4138 |
case SYNAPTICS_SYSCTL_NA_RIGHT: |
|
|
4139 |
case SYNAPTICS_SYSCTL_NA_BOTTOM: |
4890 |
case SYNAPTICS_SYSCTL_NA_BOTTOM: |
|
|
4891 |
if (arg < 0 || arg > sc->synhw.maximumYCoord) |
4892 |
return (EINVAL); |
4893 |
break; |
4894 |
case SYNAPTICS_SYSCTL_SOFTBUTTON2_X: |
4895 |
case SYNAPTICS_SYSCTL_SOFTBUTTON3_X: |
4896 |
/* Softbuttons is clickpad only feature */ |
4897 |
if (!sc->synhw.capClickPad && arg != 0) |
4898 |
return (EINVAL); |
4899 |
/* FALLTHROUGH */ |
4900 |
case SYNAPTICS_SYSCTL_MARGIN_RIGHT: |
4901 |
case SYNAPTICS_SYSCTL_MARGIN_LEFT: |
4902 |
case SYNAPTICS_SYSCTL_NA_RIGHT: |
4140 |
case SYNAPTICS_SYSCTL_NA_LEFT: |
4903 |
case SYNAPTICS_SYSCTL_NA_LEFT: |
4141 |
if (arg < 0 || arg > 6143) |
4904 |
if (arg < 0 || arg > sc->synhw.maximumXCoord) |
4142 |
return (EINVAL); |
4905 |
return (EINVAL); |
4143 |
break; |
4906 |
break; |
4144 |
case SYNAPTICS_SYSCTL_WINDOW_MIN: |
4907 |
case SYNAPTICS_SYSCTL_WINDOW_MIN: |
Lines 4168-4175
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
Link Here
|
4168 |
return (EINVAL); |
4931 |
return (EINVAL); |
4169 |
break; |
4932 |
break; |
4170 |
case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA: |
4933 |
case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA: |
|
|
4934 |
if (arg < -sc->synhw.maximumXCoord || |
4935 |
arg > sc->synhw.maximumXCoord) |
4936 |
return (EINVAL); |
4937 |
break; |
4938 |
case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y: |
4939 |
/* Softbuttons is clickpad only feature */ |
4940 |
if (!sc->synhw.capClickPad && arg != 0) |
4941 |
return (EINVAL); |
4942 |
/* FALLTHROUGH */ |
4171 |
case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA: |
4943 |
case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA: |
4172 |
if (arg < -6143 || arg > 6143) |
4944 |
if (arg < -sc->synhw.maximumYCoord || |
|
|
4945 |
arg > sc->synhw.maximumYCoord) |
4173 |
return (EINVAL); |
4946 |
return (EINVAL); |
4174 |
break; |
4947 |
break; |
4175 |
case SYNAPTICS_SYSCTL_TOUCHPAD_OFF: |
4948 |
case SYNAPTICS_SYSCTL_TOUCHPAD_OFF: |
Lines 4181-4193
synaptics_sysctl(SYSCTL_HANDLER_ARGS)
Link Here
|
4181 |
} |
4954 |
} |
4182 |
|
4955 |
|
4183 |
/* Update. */ |
4956 |
/* Update. */ |
4184 |
*(int *)oidp->oid_arg1 = arg; |
4957 |
*(int *)((char *)sc + oidp->oid_arg2) = arg; |
4185 |
|
4958 |
|
4186 |
return (error); |
4959 |
return (error); |
4187 |
} |
4960 |
} |
4188 |
|
4961 |
|
4189 |
static void |
4962 |
static void |
4190 |
synaptics_sysctl_create_tree(struct psm_softc *sc) |
4963 |
synaptics_sysctl_create_softbuttons_tree(struct psm_softc *sc) |
|
|
4964 |
{ |
4965 |
/* |
4966 |
* Set predefined sizes for softbuttons. |
4967 |
* Values are taken to match HP Pavilion dv6 clickpad drawings |
4968 |
* with thin middle softbutton placed on separator |
4969 |
*/ |
4970 |
|
4971 |
/* hw.psm.synaptics.softbuttons_y */ |
4972 |
sc->syninfo.softbuttons_y = 1700; |
4973 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4974 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4975 |
"softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4976 |
sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y, |
4977 |
synaptics_sysctl, "I", |
4978 |
"Vertical size of softbuttons area"); |
4979 |
|
4980 |
/* hw.psm.synaptics.softbutton2_x */ |
4981 |
sc->syninfo.softbutton2_x = 3100; |
4982 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4983 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4984 |
"softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4985 |
sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X, |
4986 |
synaptics_sysctl, "I", |
4987 |
"Horisontal position of 2-nd softbutton left edge (0-disable)"); |
4988 |
|
4989 |
/* hw.psm.synaptics.softbutton3_x */ |
4990 |
sc->syninfo.softbutton3_x = 3900; |
4991 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4992 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4993 |
"softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4994 |
sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X, |
4995 |
synaptics_sysctl, "I", |
4996 |
"Horisontal position of 3-rd softbutton left edge (0-disable)"); |
4997 |
} |
4998 |
|
4999 |
static void |
5000 |
synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name, |
5001 |
const char *descr) |
4191 |
{ |
5002 |
{ |
4192 |
|
5003 |
|
4193 |
if (sc->syninfo.sysctl_tree != NULL) |
5004 |
if (sc->syninfo.sysctl_tree != NULL) |
Lines 4196-4203
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4196 |
/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ |
5007 |
/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ |
4197 |
sysctl_ctx_init(&sc->syninfo.sysctl_ctx); |
5008 |
sysctl_ctx_init(&sc->syninfo.sysctl_ctx); |
4198 |
sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, |
5009 |
sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, |
4199 |
SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD, |
5010 |
SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD, |
4200 |
0, "Synaptics TouchPad"); |
5011 |
0, descr); |
4201 |
|
5012 |
|
4202 |
/* hw.psm.synaptics.directional_scrolls. */ |
5013 |
/* hw.psm.synaptics.directional_scrolls. */ |
4203 |
sc->syninfo.directional_scrolls = 0; |
5014 |
sc->syninfo.directional_scrolls = 0; |
Lines 4208-4213
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4208 |
"Enable hardware scrolling pad (if non-zero) or register it as " |
5019 |
"Enable hardware scrolling pad (if non-zero) or register it as " |
4209 |
"extended buttons (if 0)"); |
5020 |
"extended buttons (if 0)"); |
4210 |
|
5021 |
|
|
|
5022 |
/* hw.psm.synaptics.max_x. */ |
5023 |
sc->syninfo.max_x = 6143; |
5024 |
SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, |
5025 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5026 |
"max_x", CTLFLAG_RD|CTLFLAG_ANYBODY, |
5027 |
&sc->syninfo.max_x, 0, |
5028 |
"Horizontal reporting range"); |
5029 |
|
5030 |
/* hw.psm.synaptics.max_y. */ |
5031 |
sc->syninfo.max_y = 6143; |
5032 |
SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, |
5033 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5034 |
"max_y", CTLFLAG_RD|CTLFLAG_ANYBODY, |
5035 |
&sc->syninfo.max_y, 0, |
5036 |
"Vertical reporting range"); |
5037 |
|
4211 |
/* |
5038 |
/* |
4212 |
* Turn off two finger scroll if we have a |
5039 |
* Turn off two finger scroll if we have a |
4213 |
* physical area reserved for scrolling or when |
5040 |
* physical area reserved for scrolling or when |
Lines 4230-4236
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4230 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5057 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4231 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5058 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4232 |
"min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5059 |
"min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4233 |
&sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE, |
5060 |
sc, SYNAPTICS_SYSCTL_MIN_PRESSURE, |
4234 |
synaptics_sysctl, "I", |
5061 |
synaptics_sysctl, "I", |
4235 |
"Minimum pressure required to start an action"); |
5062 |
"Minimum pressure required to start an action"); |
4236 |
|
5063 |
|
Lines 4239-4245
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4239 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5066 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4240 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5067 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4241 |
"max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5068 |
"max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4242 |
&sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE, |
5069 |
sc, SYNAPTICS_SYSCTL_MAX_PRESSURE, |
4243 |
synaptics_sysctl, "I", |
5070 |
synaptics_sysctl, "I", |
4244 |
"Maximum pressure to detect palm"); |
5071 |
"Maximum pressure to detect palm"); |
4245 |
|
5072 |
|
Lines 4248-4254
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4248 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5075 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4249 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5076 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4250 |
"max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5077 |
"max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4251 |
&sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH, |
5078 |
sc, SYNAPTICS_SYSCTL_MAX_WIDTH, |
4252 |
synaptics_sysctl, "I", |
5079 |
synaptics_sysctl, "I", |
4253 |
"Maximum finger width to detect palm"); |
5080 |
"Maximum finger width to detect palm"); |
4254 |
|
5081 |
|
Lines 4257-4263
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4257 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5084 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4258 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5085 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4259 |
"margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5086 |
"margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4260 |
&sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP, |
5087 |
sc, SYNAPTICS_SYSCTL_MARGIN_TOP, |
4261 |
synaptics_sysctl, "I", |
5088 |
synaptics_sysctl, "I", |
4262 |
"Top margin"); |
5089 |
"Top margin"); |
4263 |
|
5090 |
|
Lines 4266-4272
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4266 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5093 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4267 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5094 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4268 |
"margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5095 |
"margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4269 |
&sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT, |
5096 |
sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT, |
4270 |
synaptics_sysctl, "I", |
5097 |
synaptics_sysctl, "I", |
4271 |
"Right margin"); |
5098 |
"Right margin"); |
4272 |
|
5099 |
|
Lines 4275-4281
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4275 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5102 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4276 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5103 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4277 |
"margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5104 |
"margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4278 |
&sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM, |
5105 |
sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM, |
4279 |
synaptics_sysctl, "I", |
5106 |
synaptics_sysctl, "I", |
4280 |
"Bottom margin"); |
5107 |
"Bottom margin"); |
4281 |
|
5108 |
|
Lines 4284-4290
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4284 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5111 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4285 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5112 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4286 |
"margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5113 |
"margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4287 |
&sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT, |
5114 |
sc, SYNAPTICS_SYSCTL_MARGIN_LEFT, |
4288 |
synaptics_sysctl, "I", |
5115 |
synaptics_sysctl, "I", |
4289 |
"Left margin"); |
5116 |
"Left margin"); |
4290 |
|
5117 |
|
Lines 4293-4299
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4293 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5120 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4294 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5121 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4295 |
"na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5122 |
"na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4296 |
&sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP, |
5123 |
sc, SYNAPTICS_SYSCTL_NA_TOP, |
4297 |
synaptics_sysctl, "I", |
5124 |
synaptics_sysctl, "I", |
4298 |
"Top noisy area, where weight_previous_na is used instead " |
5125 |
"Top noisy area, where weight_previous_na is used instead " |
4299 |
"of weight_previous"); |
5126 |
"of weight_previous"); |
Lines 4303-4309
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4303 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5130 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4304 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5131 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4305 |
"na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5132 |
"na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4306 |
&sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT, |
5133 |
sc, SYNAPTICS_SYSCTL_NA_RIGHT, |
4307 |
synaptics_sysctl, "I", |
5134 |
synaptics_sysctl, "I", |
4308 |
"Right noisy area, where weight_previous_na is used instead " |
5135 |
"Right noisy area, where weight_previous_na is used instead " |
4309 |
"of weight_previous"); |
5136 |
"of weight_previous"); |
Lines 4313-4319
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4313 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5140 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4314 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5141 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4315 |
"na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5142 |
"na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4316 |
&sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM, |
5143 |
sc, SYNAPTICS_SYSCTL_NA_BOTTOM, |
4317 |
synaptics_sysctl, "I", |
5144 |
synaptics_sysctl, "I", |
4318 |
"Bottom noisy area, where weight_previous_na is used instead " |
5145 |
"Bottom noisy area, where weight_previous_na is used instead " |
4319 |
"of weight_previous"); |
5146 |
"of weight_previous"); |
Lines 4323-4329
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4323 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5150 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4324 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5151 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4325 |
"na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5152 |
"na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4326 |
&sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT, |
5153 |
sc, SYNAPTICS_SYSCTL_NA_LEFT, |
4327 |
synaptics_sysctl, "I", |
5154 |
synaptics_sysctl, "I", |
4328 |
"Left noisy area, where weight_previous_na is used instead " |
5155 |
"Left noisy area, where weight_previous_na is used instead " |
4329 |
"of weight_previous"); |
5156 |
"of weight_previous"); |
Lines 4333-4339
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4333 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5160 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4334 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5161 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4335 |
"window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5162 |
"window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4336 |
&sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN, |
5163 |
sc, SYNAPTICS_SYSCTL_WINDOW_MIN, |
4337 |
synaptics_sysctl, "I", |
5164 |
synaptics_sysctl, "I", |
4338 |
"Minimum window size to start an action"); |
5165 |
"Minimum window size to start an action"); |
4339 |
|
5166 |
|
Lines 4342-4348
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4342 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5169 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4343 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5170 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4344 |
"window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5171 |
"window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4345 |
&sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX, |
5172 |
sc, SYNAPTICS_SYSCTL_WINDOW_MAX, |
4346 |
synaptics_sysctl, "I", |
5173 |
synaptics_sysctl, "I", |
4347 |
"Maximum window size"); |
5174 |
"Maximum window size"); |
4348 |
|
5175 |
|
Lines 4351-4357
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4351 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5178 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4352 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5179 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4353 |
"multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5180 |
"multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4354 |
&sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR, |
5181 |
sc, SYNAPTICS_SYSCTL_MULTIPLICATOR, |
4355 |
synaptics_sysctl, "I", |
5182 |
synaptics_sysctl, "I", |
4356 |
"Multiplicator to increase precision in averages and divisions"); |
5183 |
"Multiplicator to increase precision in averages and divisions"); |
4357 |
|
5184 |
|
Lines 4360-4366
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4360 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5187 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4361 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5188 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4362 |
"weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5189 |
"weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4363 |
&sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT, |
5190 |
sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT, |
4364 |
synaptics_sysctl, "I", |
5191 |
synaptics_sysctl, "I", |
4365 |
"Weight of the current movement in the new average"); |
5192 |
"Weight of the current movement in the new average"); |
4366 |
|
5193 |
|
Lines 4369-4375
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4369 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5196 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4370 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5197 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4371 |
"weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5198 |
"weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4372 |
&sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, |
5199 |
sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, |
4373 |
synaptics_sysctl, "I", |
5200 |
synaptics_sysctl, "I", |
4374 |
"Weight of the previous average"); |
5201 |
"Weight of the previous average"); |
4375 |
|
5202 |
|
Lines 4378-4385
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4378 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5205 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4379 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5206 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4380 |
"weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5207 |
"weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4381 |
&sc->syninfo.weight_previous_na, |
5208 |
sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, |
4382 |
SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, |
|
|
4383 |
synaptics_sysctl, "I", |
5209 |
synaptics_sysctl, "I", |
4384 |
"Weight of the previous average (inside the noisy area)"); |
5210 |
"Weight of the previous average (inside the noisy area)"); |
4385 |
|
5211 |
|
Lines 4388-4395
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4388 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5214 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4389 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5215 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4390 |
"weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5216 |
"weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4391 |
&sc->syninfo.weight_len_squared, |
5217 |
sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, |
4392 |
SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, |
|
|
4393 |
synaptics_sysctl, "I", |
5218 |
synaptics_sysctl, "I", |
4394 |
"Length (squared) of segments where weight_previous " |
5219 |
"Length (squared) of segments where weight_previous " |
4395 |
"starts to decrease"); |
5220 |
"starts to decrease"); |
Lines 4399-4405
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4399 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5224 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4400 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5225 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4401 |
"div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5226 |
"div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4402 |
&sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN, |
5227 |
sc, SYNAPTICS_SYSCTL_DIV_MIN, |
4403 |
synaptics_sysctl, "I", |
5228 |
synaptics_sysctl, "I", |
4404 |
"Divisor for fast movements"); |
5229 |
"Divisor for fast movements"); |
4405 |
|
5230 |
|
Lines 4408-4414
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4408 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5233 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4409 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5234 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4410 |
"div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5235 |
"div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4411 |
&sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX, |
5236 |
sc, SYNAPTICS_SYSCTL_DIV_MAX, |
4412 |
synaptics_sysctl, "I", |
5237 |
synaptics_sysctl, "I", |
4413 |
"Divisor for slow movements"); |
5238 |
"Divisor for slow movements"); |
4414 |
|
5239 |
|
Lines 4417-4423
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4417 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5242 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4418 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5243 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4419 |
"div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5244 |
"div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4420 |
&sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA, |
5245 |
sc, SYNAPTICS_SYSCTL_DIV_MAX_NA, |
4421 |
synaptics_sysctl, "I", |
5246 |
synaptics_sysctl, "I", |
4422 |
"Divisor with slow movements (inside the noisy area)"); |
5247 |
"Divisor with slow movements (inside the noisy area)"); |
4423 |
|
5248 |
|
Lines 4426-4432
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4426 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5251 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4427 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5252 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4428 |
"div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5253 |
"div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4429 |
&sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN, |
5254 |
sc, SYNAPTICS_SYSCTL_DIV_LEN, |
4430 |
synaptics_sysctl, "I", |
5255 |
synaptics_sysctl, "I", |
4431 |
"Length of segments where div_max starts to decrease"); |
5256 |
"Length of segments where div_max starts to decrease"); |
4432 |
|
5257 |
|
Lines 4435-4441
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4435 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5260 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4436 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5261 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4437 |
"tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5262 |
"tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4438 |
&sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA, |
5263 |
sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA, |
4439 |
synaptics_sysctl, "I", |
5264 |
synaptics_sysctl, "I", |
4440 |
"Length of segments above which a tap is ignored"); |
5265 |
"Length of segments above which a tap is ignored"); |
4441 |
|
5266 |
|
Lines 4444-4460
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4444 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5269 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4445 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5270 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4446 |
"tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5271 |
"tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4447 |
&sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, |
5272 |
sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, |
4448 |
synaptics_sysctl, "I", |
5273 |
synaptics_sysctl, "I", |
4449 |
"Number of packets required to consider a tap"); |
5274 |
"Number of packets required to consider a tap"); |
4450 |
|
5275 |
|
4451 |
/* hw.psm.synaptics.taphold_timeout. */ |
5276 |
/* hw.psm.synaptics.taphold_timeout. */ |
4452 |
sc->synaction.in_taphold = 0; |
5277 |
sc->gesture.in_taphold = 0; |
4453 |
sc->syninfo.taphold_timeout = tap_timeout; |
5278 |
sc->syninfo.taphold_timeout = tap_timeout; |
4454 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5279 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4455 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5280 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4456 |
"taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5281 |
"taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4457 |
&sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, |
5282 |
sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, |
4458 |
synaptics_sysctl, "I", |
5283 |
synaptics_sysctl, "I", |
4459 |
"Maximum elapsed time between two taps to consider a tap-hold " |
5284 |
"Maximum elapsed time between two taps to consider a tap-hold " |
4460 |
"action"); |
5285 |
"action"); |
Lines 4464-4479
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4464 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5289 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4465 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5290 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4466 |
"vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5291 |
"vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4467 |
&sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, |
5292 |
sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, |
4468 |
synaptics_sysctl, "I", |
5293 |
synaptics_sysctl, "I", |
4469 |
"Area reserved for horizontal virtual scrolling"); |
5294 |
"Area reserved for horizontal virtual scrolling"); |
4470 |
|
5295 |
|
4471 |
/* hw.psm.synaptics.vscroll_ver_area. */ |
5296 |
/* hw.psm.synaptics.vscroll_ver_area. */ |
4472 |
sc->syninfo.vscroll_ver_area = -600; |
5297 |
sc->syninfo.vscroll_ver_area = -400 - sc->syninfo.margin_right; |
4473 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5298 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4474 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5299 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4475 |
"vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5300 |
"vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4476 |
&sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, |
5301 |
sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, |
4477 |
synaptics_sysctl, "I", |
5302 |
synaptics_sysctl, "I", |
4478 |
"Area reserved for vertical virtual scrolling"); |
5303 |
"Area reserved for vertical virtual scrolling"); |
4479 |
|
5304 |
|
Lines 4482-4489
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4482 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5307 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4483 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5308 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4484 |
"vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5309 |
"vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4485 |
&sc->syninfo.vscroll_min_delta, |
5310 |
sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, |
4486 |
SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, |
|
|
4487 |
synaptics_sysctl, "I", |
5311 |
synaptics_sysctl, "I", |
4488 |
"Minimum movement to consider virtual scrolling"); |
5312 |
"Minimum movement to consider virtual scrolling"); |
4489 |
|
5313 |
|
Lines 4492-4498
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4492 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5316 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4493 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5317 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4494 |
"vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5318 |
"vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4495 |
&sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, |
5319 |
sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, |
4496 |
synaptics_sysctl, "I", |
5320 |
synaptics_sysctl, "I", |
4497 |
"Divisor for fast scrolling"); |
5321 |
"Divisor for fast scrolling"); |
4498 |
|
5322 |
|
Lines 4501-4507
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4501 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5325 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4502 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5326 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4503 |
"vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5327 |
"vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4504 |
&sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, |
5328 |
sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, |
4505 |
synaptics_sysctl, "I", |
5329 |
synaptics_sysctl, "I", |
4506 |
"Divisor for slow scrolling"); |
5330 |
"Divisor for slow scrolling"); |
4507 |
|
5331 |
|
Lines 4510-4537
synaptics_sysctl_create_tree(struct psm_softc *sc)
Link Here
|
4510 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
5334 |
SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, |
4511 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
5335 |
SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, |
4512 |
"touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
5336 |
"touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, |
4513 |
&sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF, |
5337 |
sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF, |
4514 |
synaptics_sysctl, "I", |
5338 |
synaptics_sysctl, "I", |
4515 |
"Turn off touchpad"); |
5339 |
"Turn off touchpad"); |
|
|
5340 |
|
5341 |
sc->syninfo.softbuttons_y = 0; |
5342 |
sc->syninfo.softbutton2_x = 0; |
5343 |
sc->syninfo.softbutton3_x = 0; |
5344 |
|
5345 |
/* skip softbuttons sysctl on not clickpads */ |
5346 |
if (sc->synhw.capClickPad) |
5347 |
synaptics_sysctl_create_softbuttons_tree(sc); |
4516 |
} |
5348 |
} |
4517 |
|
5349 |
|
4518 |
static int |
5350 |
static int |
4519 |
synaptics_preferred_mode(struct psm_softc *sc) { |
5351 |
synaptics_preferred_mode(struct psm_softc *sc) { |
4520 |
int mode_byte; |
5352 |
int mode_byte; |
4521 |
|
5353 |
|
4522 |
mode_byte = 0xc0; |
5354 |
mode_byte = 0xc4; |
4523 |
|
5355 |
|
4524 |
/* request wmode where available */ |
5356 |
/* request wmode where available */ |
4525 |
if (sc->synhw.capExtended) |
5357 |
if (sc->synhw.capExtended) |
4526 |
mode_byte |= 1; |
5358 |
mode_byte |= 1; |
4527 |
|
5359 |
|
4528 |
/* |
|
|
4529 |
* Disable gesture processing when native packets are requested. This |
4530 |
* enables sending of encapsulated "extended W mode" packets. |
4531 |
*/ |
4532 |
if (sc->mode.level == PSM_LEVEL_NATIVE) |
4533 |
mode_byte |= (1 << 2); |
4534 |
|
4535 |
return mode_byte; |
5360 |
return mode_byte; |
4536 |
} |
5361 |
} |
4537 |
|
5362 |
|
Lines 4546-4552
synaptics_set_mode(struct psm_softc *sc, int mode_byte) {
Link Here
|
4546 |
* Enable advanced gestures mode if supported and we are not entering |
5371 |
* Enable advanced gestures mode if supported and we are not entering |
4547 |
* passthrough mode. |
5372 |
* passthrough mode. |
4548 |
*/ |
5373 |
*/ |
4549 |
if (sc->synhw.capAdvancedGestures && !(mode_byte & (1 << 5))) { |
5374 |
if ((sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) && |
|
|
5375 |
!(mode_byte & (1 << 5))) { |
4550 |
mouse_ext_command(sc->kbdc, 3); |
5376 |
mouse_ext_command(sc->kbdc, 3); |
4551 |
set_mouse_sampling_rate(sc->kbdc, 0xc8); |
5377 |
set_mouse_sampling_rate(sc->kbdc, 0xc8); |
4552 |
} |
5378 |
} |
Lines 4754-4760
enable_synaptics(struct psm_softc *sc, enum probearg arg)
Link Here
|
4754 |
((status[1] & 0x0f) << 1); |
5580 |
((status[1] & 0x0f) << 1); |
4755 |
synhw.maximumYCoord = (status[2] << 5) | |
5581 |
synhw.maximumYCoord = (status[2] << 5) | |
4756 |
((status[1] & 0xf0) >> 3); |
5582 |
((status[1] & 0xf0) >> 3); |
|
|
5583 |
} else { |
5584 |
/* |
5585 |
* Typical bezel limits. Taken from 'Synaptics |
5586 |
* PS/2 * TouchPad Interfacing Guide' p.3.2.3. |
5587 |
*/ |
5588 |
synhw.maximumXCoord = 5472; |
5589 |
synhw.maximumYCoord = 4448; |
4757 |
} |
5590 |
} |
|
|
5591 |
|
4758 |
if (synhw.capReportsMin) { |
5592 |
if (synhw.capReportsMin) { |
4759 |
if (!set_mouse_scaling(kbdc, 1)) |
5593 |
if (!set_mouse_scaling(kbdc, 1)) |
4760 |
return (FALSE); |
5594 |
return (FALSE); |
Lines 4767-4772
enable_synaptics(struct psm_softc *sc, enum probearg arg)
Link Here
|
4767 |
((status[1] & 0x0f) << 1); |
5601 |
((status[1] & 0x0f) << 1); |
4768 |
synhw.minimumYCoord = (status[2] << 5) | |
5602 |
synhw.minimumYCoord = (status[2] << 5) | |
4769 |
((status[1] & 0xf0) >> 3); |
5603 |
((status[1] & 0xf0) >> 3); |
|
|
5604 |
} else { |
5605 |
/* |
5606 |
* Typical bezel limits. Taken from 'Synaptics |
5607 |
* PS/2 * TouchPad Interfacing Guide' p.3.2.3. |
5608 |
*/ |
5609 |
synhw.minimumXCoord = 1472; |
5610 |
synhw.minimumYCoord = 1408; |
4770 |
} |
5611 |
} |
4771 |
|
5612 |
|
4772 |
if (verbose >= 2) { |
5613 |
if (verbose >= 2) { |
Lines 4854-4860
enable_synaptics(struct psm_softc *sc, enum probearg arg)
Link Here
|
4854 |
|
5695 |
|
4855 |
if (arg == PROBE) { |
5696 |
if (arg == PROBE) { |
4856 |
/* Create sysctl tree. */ |
5697 |
/* Create sysctl tree. */ |
4857 |
synaptics_sysctl_create_tree(sc); |
5698 |
synaptics_sysctl_create_tree(sc, "synaptics", |
|
|
5699 |
"Synaptics TouchPad"); |
4858 |
sc->hw.buttons = buttons; |
5700 |
sc->hw.buttons = buttons; |
4859 |
} |
5701 |
} |
4860 |
|
5702 |
|
Lines 5171-5176
enable_versapad(struct psm_softc *sc, enum probearg arg)
Link Here
|
5171 |
return (TRUE); /* PS/2 absolute mode */ |
6013 |
return (TRUE); /* PS/2 absolute mode */ |
5172 |
} |
6014 |
} |
5173 |
|
6015 |
|
|
|
6016 |
/* Elantech Touchpad */ |
6017 |
static int |
6018 |
elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val) |
6019 |
{ |
6020 |
int res, readcmd, retidx; |
6021 |
int resp[3]; |
6022 |
|
6023 |
readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR; |
6024 |
retidx = hwversion == 4 ? 1 : 0; |
6025 |
|
6026 |
res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6027 |
res |= send_aux_command(kbdc, readcmd) != PSM_ACK; |
6028 |
res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6029 |
res |= send_aux_command(kbdc, reg) != PSM_ACK; |
6030 |
res |= get_mouse_status(kbdc, resp, 0, 3) != 3; |
6031 |
|
6032 |
if (res == 0) |
6033 |
*val = resp[retidx]; |
6034 |
|
6035 |
return (res); |
6036 |
} |
6037 |
|
6038 |
static int |
6039 |
elantech_write_1(KBDC kbdc, int hwversion, int reg, int val) |
6040 |
{ |
6041 |
int res, writecmd; |
6042 |
|
6043 |
writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR; |
6044 |
|
6045 |
res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6046 |
res |= send_aux_command(kbdc, writecmd) != PSM_ACK; |
6047 |
res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6048 |
res |= send_aux_command(kbdc, reg) != PSM_ACK; |
6049 |
if (hwversion == 4) { |
6050 |
res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6051 |
res |= send_aux_command(kbdc, writecmd) != PSM_ACK; |
6052 |
} |
6053 |
res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6054 |
res |= send_aux_command(kbdc, val) != PSM_ACK; |
6055 |
res |= set_mouse_scaling(kbdc, 1) == 0; |
6056 |
|
6057 |
return (res); |
6058 |
} |
6059 |
|
6060 |
static int |
6061 |
elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp) |
6062 |
{ |
6063 |
int res; |
6064 |
|
6065 |
if (hwversion == 2) { |
6066 |
res = set_mouse_scaling(kbdc, 1) == 0; |
6067 |
res |= mouse_ext_command(kbdc, cmd) == 0; |
6068 |
} else { |
6069 |
res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; |
6070 |
res |= send_aux_command(kbdc, cmd) != PSM_ACK; |
6071 |
} |
6072 |
res |= get_mouse_status(kbdc, resp, 0, 3) != 3; |
6073 |
|
6074 |
return (res); |
6075 |
} |
6076 |
|
6077 |
static int |
6078 |
elantech_init(KBDC kbdc, elantechhw_t *elanhw) |
6079 |
{ |
6080 |
int i, val, res, hwversion, reg10; |
6081 |
|
6082 |
/* set absolute mode */ |
6083 |
hwversion = elanhw->hwversion; |
6084 |
reg10 = -1; |
6085 |
switch (hwversion) { |
6086 |
case 2: |
6087 |
reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4; |
6088 |
res = elantech_write_1(kbdc, hwversion, 0x10, reg10); |
6089 |
if (res) |
6090 |
break; |
6091 |
res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A); |
6092 |
break; |
6093 |
case 3: |
6094 |
reg10 = 0x0b; |
6095 |
res = elantech_write_1(kbdc, hwversion, 0x10, reg10); |
6096 |
break; |
6097 |
case 4: |
6098 |
res = elantech_write_1(kbdc, hwversion, 0x07, 0x01); |
6099 |
break; |
6100 |
default: |
6101 |
res = 1; |
6102 |
} |
6103 |
|
6104 |
/* Read back reg 0x10 to ensure hardware is ready. */ |
6105 |
if (res == 0 && reg10 >= 0) { |
6106 |
for (i = 0; i < 5; i++) { |
6107 |
if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0) |
6108 |
break; |
6109 |
DELAY(2000); |
6110 |
} |
6111 |
if (i == 5) |
6112 |
res = 1; |
6113 |
} |
6114 |
|
6115 |
if (res) |
6116 |
printf("couldn't set absolute mode\n"); |
6117 |
|
6118 |
return (res); |
6119 |
} |
6120 |
|
6121 |
static void |
6122 |
elantech_init_synaptics(struct psm_softc *sc) |
6123 |
{ |
6124 |
|
6125 |
/* Set capabilites required by movement smother */ |
6126 |
sc->synhw.infoMajor = sc->elanhw.hwversion; |
6127 |
sc->synhw.infoMinor = sc->elanhw.fwversion; |
6128 |
sc->synhw.infoXupmm = sc->elanhw.dpmmx; |
6129 |
sc->synhw.infoYupmm = sc->elanhw.dpmmy; |
6130 |
sc->synhw.verticalScroll = 0; |
6131 |
sc->synhw.nExtendedQueries = 4; |
6132 |
sc->synhw.capExtended = 1; |
6133 |
sc->synhw.capPassthrough = sc->elanhw.hastrackpad; |
6134 |
sc->synhw.capClickPad = sc->elanhw.isclickpad; |
6135 |
sc->synhw.capMultiFinger = 1; |
6136 |
sc->synhw.capAdvancedGestures = 1; |
6137 |
sc->synhw.capPalmDetect = 1; |
6138 |
sc->synhw.capPen = 0; |
6139 |
sc->synhw.capReportsMax = 1; |
6140 |
sc->synhw.maximumXCoord = sc->elanhw.sizex; |
6141 |
sc->synhw.maximumYCoord = sc->elanhw.sizey; |
6142 |
sc->synhw.capReportsMin = 1; |
6143 |
sc->synhw.minimumXCoord = 0; |
6144 |
sc->synhw.minimumYCoord = 0; |
6145 |
|
6146 |
if (sc->syninfo.sysctl_tree == NULL) { |
6147 |
synaptics_sysctl_create_tree(sc, "elantech", |
6148 |
"Elantech Touchpad"); |
6149 |
|
6150 |
/* |
6151 |
* Adjust synaptic smoother tunables |
6152 |
* 1. Disable finger detection pressure threshold. Unlike |
6153 |
* synaptics we assume the finger is acting when packet with |
6154 |
* its X&Y arrives not when pressure exceedes some threshold |
6155 |
* 2. Disable unrelated features like margins and noisy areas |
6156 |
* 3. Disable virtual scroll areas as 2nd finger is preferable |
6157 |
* 4. For clickpads set bottom quarter as 42% - 16% - 42% sized |
6158 |
* softbuttons |
6159 |
* 5. Scale down divisors and movement lengths by a factor of 3 |
6160 |
* where 3 is Synaptics to Elantech (~2200/800) dpi ratio |
6161 |
*/ |
6162 |
|
6163 |
/* Set reporting range to be equal touchpad size */ |
6164 |
sc->syninfo.max_x = sc->elanhw.sizex; |
6165 |
sc->syninfo.max_y = sc->elanhw.sizey; |
6166 |
|
6167 |
/* Disable finger detection pressure threshold */ |
6168 |
sc->syninfo.min_pressure = 1; |
6169 |
|
6170 |
/* Use full area of touchpad */ |
6171 |
sc->syninfo.margin_top = 0; |
6172 |
sc->syninfo.margin_right = 0; |
6173 |
sc->syninfo.margin_bottom = 0; |
6174 |
sc->syninfo.margin_left = 0; |
6175 |
|
6176 |
/* Disable noisy area */ |
6177 |
sc->syninfo.na_top = 0; |
6178 |
sc->syninfo.na_right = 0; |
6179 |
sc->syninfo.na_bottom = 0; |
6180 |
sc->syninfo.na_left = 0; |
6181 |
|
6182 |
/* Tune divisors and movement lengths */ |
6183 |
sc->syninfo.weight_len_squared = 200; |
6184 |
sc->syninfo.div_min = 3; |
6185 |
sc->syninfo.div_max = 6; |
6186 |
sc->syninfo.div_max_na = 10; |
6187 |
sc->syninfo.div_len = 30; |
6188 |
sc->syninfo.tap_max_delta = 25; |
6189 |
|
6190 |
/* Disable virtual scrolling areas and tune its divisors */ |
6191 |
sc->syninfo.vscroll_hor_area = 0; |
6192 |
sc->syninfo.vscroll_ver_area = 0; |
6193 |
sc->syninfo.vscroll_min_delta = 15; |
6194 |
sc->syninfo.vscroll_div_min = 30; |
6195 |
sc->syninfo.vscroll_div_max = 50; |
6196 |
|
6197 |
/* Set bottom quarter as 42% - 16% - 42% sized softbuttons */ |
6198 |
if (sc->elanhw.isclickpad) { |
6199 |
sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4; |
6200 |
sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25; |
6201 |
sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25; |
6202 |
} |
6203 |
} |
6204 |
|
6205 |
return; |
6206 |
} |
6207 |
|
6208 |
static int |
6209 |
enable_elantech(struct psm_softc *sc, enum probearg arg) |
6210 |
{ |
6211 |
static const int ic2hw[] = |
6212 |
/*IC: 0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
6213 |
{ 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0 }; |
6214 |
elantechhw_t elanhw; |
6215 |
int icversion, hwversion, dptracex, dptracey, id, resp[3], dpix, dpiy; |
6216 |
KBDC kbdc = sc->kbdc; |
6217 |
|
6218 |
VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n")); |
6219 |
|
6220 |
set_mouse_scaling(kbdc, 1); |
6221 |
set_mouse_scaling(kbdc, 1); |
6222 |
set_mouse_scaling(kbdc, 1); |
6223 |
if (get_mouse_status(kbdc, resp, 0, 3) != 3) |
6224 |
return (FALSE); |
6225 |
|
6226 |
if (!ELANTECH_MAGIC(resp)) |
6227 |
return (FALSE); |
6228 |
|
6229 |
/* Identify the Touchpad version. */ |
6230 |
if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp)) |
6231 |
return (FALSE); |
6232 |
|
6233 |
bzero(&elanhw, sizeof(elanhw)); |
6234 |
|
6235 |
elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2]; |
6236 |
icversion = resp[0] & 0x0f; |
6237 |
hwversion = ic2hw[icversion]; |
6238 |
|
6239 |
if (verbose >= 2) |
6240 |
printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n", |
6241 |
hwversion, elanhw.fwversion); |
6242 |
|
6243 |
if (ELANTECH_HW_IS_V1(elanhw.fwversion)) { |
6244 |
printf (" Unsupported touchpad hardware (v1)\n"); |
6245 |
return (FALSE); |
6246 |
} |
6247 |
if (hwversion == 0) { |
6248 |
printf (" Unknown touchpad hardware (firmware v.0x%06x)\n", |
6249 |
elanhw.fwversion); |
6250 |
return (FALSE); |
6251 |
} |
6252 |
|
6253 |
/* Get the Touchpad model information. */ |
6254 |
elanhw.hwversion = hwversion; |
6255 |
elanhw.issemimt = hwversion == 2; |
6256 |
elanhw.isclickpad = (resp[1] & 0x10) != 0; |
6257 |
elanhw.hascrc = (resp[1] & 0x40) != 0; |
6258 |
elanhw.haspressure = elanhw.fwversion >= 0x020800; |
6259 |
|
6260 |
/* Read the capability bits. */ |
6261 |
if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) { |
6262 |
printf(" Failed to read capability bits\n"); |
6263 |
return (FALSE); |
6264 |
} |
6265 |
|
6266 |
elanhw.ntracesx = resp[1] - 1; |
6267 |
elanhw.ntracesy = resp[2] - 1; |
6268 |
elanhw.hastrackpad = (resp[0] & 0x80) != 0; |
6269 |
|
6270 |
/* Get the touchpad resolution */ |
6271 |
switch (hwversion) { |
6272 |
case 4: |
6273 |
if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp) |
6274 |
== 0) { |
6275 |
dpix = (resp[1] & 0x0f) * 10 + 790; |
6276 |
dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790; |
6277 |
elanhw.dpmmx = (dpix * 10 + 5) / 254; |
6278 |
elanhw.dpmmy = (dpiy * 10 + 5) / 254; |
6279 |
break; |
6280 |
} |
6281 |
/* FALLTHROUGH */ |
6282 |
case 2: |
6283 |
case 3: |
6284 |
elanhw.dpmmx = elanhw.dpmmy = 32; /* 800 dpi */ |
6285 |
break; |
6286 |
} |
6287 |
|
6288 |
if (!elantech_support) |
6289 |
return (FALSE); |
6290 |
|
6291 |
if (elantech_init(kbdc, &elanhw)) { |
6292 |
printf("couldn't initialize elantech touchpad\n"); |
6293 |
return (FALSE); |
6294 |
} |
6295 |
|
6296 |
/* |
6297 |
* Get the touchpad reporting range. |
6298 |
* On HW v.3 touchpads it should be done after switching hardware |
6299 |
* to real resolution mode (by setting bit 3 of reg10) |
6300 |
*/ |
6301 |
if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) { |
6302 |
printf(" Failed to read touchpad size\n"); |
6303 |
elanhw.sizex = 10000; /* Arbitrary high values to */ |
6304 |
elanhw.sizey = 10000; /* prevent clipping in smoother */ |
6305 |
} else if (hwversion == 2) { |
6306 |
dptracex = dptracey = 64; |
6307 |
if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) && |
6308 |
!elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) { |
6309 |
dptracex = resp[1] / 2; |
6310 |
dptracey = resp[2] / 2; |
6311 |
} |
6312 |
elanhw.sizex = (elanhw.ntracesx - 1) * dptracex; |
6313 |
elanhw.sizey = (elanhw.ntracesy - 1) * dptracey; |
6314 |
} else { |
6315 |
elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1]; |
6316 |
elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2]; |
6317 |
} |
6318 |
|
6319 |
if (verbose >= 2) { |
6320 |
printf(" Model information:\n"); |
6321 |
printf(" MaxX: %d\n", elanhw.sizex); |
6322 |
printf(" MaxY: %d\n", elanhw.sizey); |
6323 |
printf(" DpmmX: %d\n", elanhw.dpmmx); |
6324 |
printf(" DpmmY: %d\n", elanhw.dpmmy); |
6325 |
printf(" TracesX: %d\n", elanhw.ntracesx); |
6326 |
printf(" TracesY: %d\n", elanhw.ntracesy); |
6327 |
printf(" SemiMT: %d\n", elanhw.issemimt); |
6328 |
printf(" Clickpad: %d\n", elanhw.isclickpad); |
6329 |
printf(" Trackpad: %d\n", elanhw.hastrackpad); |
6330 |
printf(" CRC: %d\n", elanhw.hascrc); |
6331 |
printf(" Pressure: %d\n", elanhw.haspressure); |
6332 |
} |
6333 |
|
6334 |
VLOG(3, (LOG_DEBUG, "elantech: END init\n")); |
6335 |
|
6336 |
if (arg == PROBE) { |
6337 |
sc->elanhw = elanhw; |
6338 |
sc->hw.buttons = 3; |
6339 |
|
6340 |
/* Initialize synaptics movement smoother */ |
6341 |
elantech_init_synaptics(sc); |
6342 |
|
6343 |
for (id = 0; id < ELANTECH_MAX_FINGERS; id++) |
6344 |
PSM_FINGER_RESET(sc->elanaction.fingers[id]); |
6345 |
} |
6346 |
|
6347 |
return (TRUE); |
6348 |
} |
6349 |
|
5174 |
/* |
6350 |
/* |
5175 |
* Return true if 'now' is earlier than (start + (secs.usecs)). |
6351 |
* Return true if 'now' is earlier than (start + (secs.usecs)). |
5176 |
* Now may be NULL and the function will fetch the current time from |
6352 |
* Now may be NULL and the function will fetch the current time from |