Deleted Added
full compact
psm.c (281127) psm.c (281440)
1/*-
2 * Copyright (c) 1992, 1993 Erik Forsberg.
3 * Copyright (c) 1996, 1997 Kazutaka YOKOTA.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
15 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23/*
24 * Ported to 386bsd Oct 17, 1992
25 * Sandi Donno, Computer Science, University of Cape Town, South Africa
26 * Please send bug reports to sandi@cs.uct.ac.za
27 *
28 * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
29 * although I was only partially successful in getting the alpha release
30 * of his "driver for the Logitech and ATI Inport Bus mice for use with
31 * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
32 * found his code to be an invaluable reference when porting this driver
33 * to 386bsd.
34 *
35 * Further modifications for latest 386BSD+patchkit and port to NetBSD,
36 * Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
37 *
38 * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
39 * Andrew Herbert - 12 June 1993
40 *
41 * Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
42 * - 13 June 1993
43 *
44 * Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
45 * - 24 October 1993
46 *
47 * Hardware access routines and probe logic rewritten by
48 * Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
49 * - 3, 14, 22 October 1996.
50 * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
51 * - 14, 30 November 1996. Uses `kbdio.c'.
52 * - 13 December 1996. Uses queuing version of `kbdio.c'.
53 * - January/February 1997. Tweaked probe logic for
54 * HiNote UltraII/Latitude/Armada laptops.
55 * - 30 July 1997. Added APM support.
56 * - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
57 * Improved sync check logic.
58 * Vendor specific support routines.
59 */
60
61#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1992, 1993 Erik Forsberg.
3 * Copyright (c) 1996, 1997 Kazutaka YOKOTA.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
15 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23/*
24 * Ported to 386bsd Oct 17, 1992
25 * Sandi Donno, Computer Science, University of Cape Town, South Africa
26 * Please send bug reports to sandi@cs.uct.ac.za
27 *
28 * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
29 * although I was only partially successful in getting the alpha release
30 * of his "driver for the Logitech and ATI Inport Bus mice for use with
31 * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
32 * found his code to be an invaluable reference when porting this driver
33 * to 386bsd.
34 *
35 * Further modifications for latest 386BSD+patchkit and port to NetBSD,
36 * Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
37 *
38 * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
39 * Andrew Herbert - 12 June 1993
40 *
41 * Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
42 * - 13 June 1993
43 *
44 * Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
45 * - 24 October 1993
46 *
47 * Hardware access routines and probe logic rewritten by
48 * Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
49 * - 3, 14, 22 October 1996.
50 * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
51 * - 14, 30 November 1996. Uses `kbdio.c'.
52 * - 13 December 1996. Uses queuing version of `kbdio.c'.
53 * - January/February 1997. Tweaked probe logic for
54 * HiNote UltraII/Latitude/Armada laptops.
55 * - 30 July 1997. Added APM support.
56 * - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
57 * Improved sync check logic.
58 * Vendor specific support routines.
59 */
60
61#include <sys/cdefs.h>
62__FBSDID("$FreeBSD: head/sys/dev/atkbdc/psm.c 281127 2015-04-06 01:04:08Z rpaulo $");
62__FBSDID("$FreeBSD: head/sys/dev/atkbdc/psm.c 281440 2015-04-11 18:44:07Z rpaulo $");
63
64#include "opt_isa.h"
65#include "opt_psm.h"
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/kernel.h>
70#include <sys/module.h>
71#include <sys/bus.h>
72#include <sys/conf.h>
73#include <sys/filio.h>
74#include <sys/poll.h>
75#include <sys/sigio.h>
76#include <sys/signalvar.h>
77#include <sys/syslog.h>
78#include <machine/bus.h>
79#include <sys/rman.h>
80#include <sys/selinfo.h>
81#include <sys/sysctl.h>
82#include <sys/time.h>
83#include <sys/uio.h>
84
85#include <sys/limits.h>
86#include <sys/mouse.h>
87#include <machine/resource.h>
88
89#ifdef DEV_ISA
90#include <isa/isavar.h>
91#endif
92
93#include <dev/atkbdc/atkbdcreg.h>
94#include <dev/atkbdc/psm.h>
95
96/*
97 * Driver specific options: the following options may be set by
98 * `options' statements in the kernel configuration file.
99 */
100
101/* debugging */
102#ifndef PSM_DEBUG
103#define PSM_DEBUG 0 /*
104 * logging: 0: none, 1: brief, 2: verbose
105 * 3: sync errors, 4: all packets
106 */
107#endif
108#define VLOG(level, args) do { \
109 if (verbose >= level) \
110 log args; \
111} while (0)
112
113#ifndef PSM_INPUT_TIMEOUT
114#define PSM_INPUT_TIMEOUT 2000000 /* 2 sec */
115#endif
116
117#ifndef PSM_TAP_TIMEOUT
118#define PSM_TAP_TIMEOUT 125000
119#endif
120
121#ifndef PSM_TAP_THRESHOLD
122#define PSM_TAP_THRESHOLD 25
123#endif
124
125/* end of driver specific options */
126
127#define PSMCPNP_DRIVER_NAME "psmcpnp"
128
129/* input queue */
130#define PSM_BUFSIZE 960
131#define PSM_SMALLBUFSIZE 240
132
133/* operation levels */
134#define PSM_LEVEL_BASE 0
135#define PSM_LEVEL_STANDARD 1
136#define PSM_LEVEL_NATIVE 2
137#define PSM_LEVEL_MIN PSM_LEVEL_BASE
138#define PSM_LEVEL_MAX PSM_LEVEL_NATIVE
139
140/* Logitech PS2++ protocol */
141#define MOUSE_PS2PLUS_CHECKBITS(b) \
142 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
143#define MOUSE_PS2PLUS_PACKET_TYPE(b) \
144 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
145
146/* ring buffer */
147typedef struct ringbuf {
148 int count; /* # of valid elements in the buffer */
149 int head; /* head pointer */
150 int tail; /* tail poiner */
151 u_char buf[PSM_BUFSIZE];
152} ringbuf_t;
153
154/* data buffer */
155typedef struct packetbuf {
156 u_char ipacket[16]; /* interim input buffer */
157 int inputbytes; /* # of bytes in the input buffer */
158} packetbuf_t;
159
160#ifndef PSM_PACKETQUEUE
161#define PSM_PACKETQUEUE 128
162#endif
163
164enum {
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};
196
197typedef struct synapticsinfo {
198 struct sysctl_ctx_list sysctl_ctx;
199 struct sysctl_oid *sysctl_tree;
200 int directional_scrolls;
63
64#include "opt_isa.h"
65#include "opt_psm.h"
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/kernel.h>
70#include <sys/module.h>
71#include <sys/bus.h>
72#include <sys/conf.h>
73#include <sys/filio.h>
74#include <sys/poll.h>
75#include <sys/sigio.h>
76#include <sys/signalvar.h>
77#include <sys/syslog.h>
78#include <machine/bus.h>
79#include <sys/rman.h>
80#include <sys/selinfo.h>
81#include <sys/sysctl.h>
82#include <sys/time.h>
83#include <sys/uio.h>
84
85#include <sys/limits.h>
86#include <sys/mouse.h>
87#include <machine/resource.h>
88
89#ifdef DEV_ISA
90#include <isa/isavar.h>
91#endif
92
93#include <dev/atkbdc/atkbdcreg.h>
94#include <dev/atkbdc/psm.h>
95
96/*
97 * Driver specific options: the following options may be set by
98 * `options' statements in the kernel configuration file.
99 */
100
101/* debugging */
102#ifndef PSM_DEBUG
103#define PSM_DEBUG 0 /*
104 * logging: 0: none, 1: brief, 2: verbose
105 * 3: sync errors, 4: all packets
106 */
107#endif
108#define VLOG(level, args) do { \
109 if (verbose >= level) \
110 log args; \
111} while (0)
112
113#ifndef PSM_INPUT_TIMEOUT
114#define PSM_INPUT_TIMEOUT 2000000 /* 2 sec */
115#endif
116
117#ifndef PSM_TAP_TIMEOUT
118#define PSM_TAP_TIMEOUT 125000
119#endif
120
121#ifndef PSM_TAP_THRESHOLD
122#define PSM_TAP_THRESHOLD 25
123#endif
124
125/* end of driver specific options */
126
127#define PSMCPNP_DRIVER_NAME "psmcpnp"
128
129/* input queue */
130#define PSM_BUFSIZE 960
131#define PSM_SMALLBUFSIZE 240
132
133/* operation levels */
134#define PSM_LEVEL_BASE 0
135#define PSM_LEVEL_STANDARD 1
136#define PSM_LEVEL_NATIVE 2
137#define PSM_LEVEL_MIN PSM_LEVEL_BASE
138#define PSM_LEVEL_MAX PSM_LEVEL_NATIVE
139
140/* Logitech PS2++ protocol */
141#define MOUSE_PS2PLUS_CHECKBITS(b) \
142 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
143#define MOUSE_PS2PLUS_PACKET_TYPE(b) \
144 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
145
146/* ring buffer */
147typedef struct ringbuf {
148 int count; /* # of valid elements in the buffer */
149 int head; /* head pointer */
150 int tail; /* tail poiner */
151 u_char buf[PSM_BUFSIZE];
152} ringbuf_t;
153
154/* data buffer */
155typedef struct packetbuf {
156 u_char ipacket[16]; /* interim input buffer */
157 int inputbytes; /* # of bytes in the input buffer */
158} packetbuf_t;
159
160#ifndef PSM_PACKETQUEUE
161#define PSM_PACKETQUEUE 128
162#endif
163
164enum {
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};
196
197typedef struct synapticsinfo {
198 struct sysctl_ctx_list sysctl_ctx;
199 struct sysctl_oid *sysctl_tree;
200 int directional_scrolls;
201 int two_finger_scroll;
201 int min_pressure;
202 int max_pressure;
203 int max_width;
204 int margin_top;
205 int margin_right;
206 int margin_bottom;
207 int margin_left;
208 int na_top;
209 int na_right;
210 int na_bottom;
211 int na_left;
212 int window_min;
213 int window_max;
214 int multiplicator;
215 int weight_current;
216 int weight_previous;
217 int weight_previous_na;
218 int weight_len_squared;
219 int div_min;
220 int div_max;
221 int div_max_na;
222 int div_len;
223 int tap_max_delta;
224 int tap_min_queue;
225 int taphold_timeout;
226 int vscroll_ver_area;
227 int vscroll_hor_area;
228 int vscroll_min_delta;
229 int vscroll_div_min;
230 int vscroll_div_max;
231} synapticsinfo_t;
232
233typedef struct synapticspacket {
234 int x;
235 int y;
236} synapticspacket_t;
237
238#define SYNAPTICS_PACKETQUEUE 10
239#define SYNAPTICS_QUEUE_CURSOR(x) \
240 (x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE
241
242#define SYNAPTICS_VERSION_GE(synhw, major, minor) \
243 ((synhw).infoMajor > (major) || \
244 ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
245
246typedef struct synapticsaction {
247 synapticspacket_t queue[SYNAPTICS_PACKETQUEUE];
248 int queue_len;
249 int queue_cursor;
250 int window_min;
251 int start_x;
252 int start_y;
253 int avg_dx;
254 int avg_dy;
255 int squelch_x;
256 int squelch_y;
257 int fingers_nb;
258 int tap_button;
259 int in_taphold;
260 int in_vscroll;
261} synapticsaction_t;
262
263enum {
264 TRACKPOINT_SYSCTL_SENSITIVITY,
265 TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
266 TRACKPOINT_SYSCTL_UPPER_PLATEAU,
267 TRACKPOINT_SYSCTL_BACKUP_RANGE,
268 TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
269 TRACKPOINT_SYSCTL_MINIMUM_DRAG,
270 TRACKPOINT_SYSCTL_UP_THRESHOLD,
271 TRACKPOINT_SYSCTL_THRESHOLD,
272 TRACKPOINT_SYSCTL_JENKS_CURVATURE,
273 TRACKPOINT_SYSCTL_Z_TIME,
274 TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
275 TRACKPOINT_SYSCTL_SKIP_BACKUPS
276};
277
278typedef struct trackpointinfo {
279 struct sysctl_ctx_list sysctl_ctx;
280 struct sysctl_oid *sysctl_tree;
281 int sensitivity;
282 int inertia;
283 int uplateau;
284 int reach;
285 int draghys;
286 int mindrag;
287 int upthresh;
288 int threshold;
289 int jenks;
290 int ztime;
291 int pts;
292 int skipback;
293} trackpointinfo_t;
294
295/* driver control block */
296struct psm_softc { /* Driver status information */
297 int unit;
298 struct selinfo rsel; /* Process selecting for Input */
299 u_char state; /* Mouse driver state */
300 int config; /* driver configuration flags */
301 int flags; /* other flags */
302 KBDC kbdc; /* handle to access kbd controller */
303 struct resource *intr; /* IRQ resource */
304 void *ih; /* interrupt handle */
305 mousehw_t hw; /* hardware information */
306 synapticshw_t synhw; /* Synaptics hardware information */
307 synapticsinfo_t syninfo; /* Synaptics configuration */
308 synapticsaction_t synaction; /* Synaptics action context */
309 int tphw; /* TrackPoint hardware information */
310 trackpointinfo_t tpinfo; /* TrackPoint configuration */
311 mousemode_t mode; /* operation mode */
312 mousemode_t dflt_mode; /* default operation mode */
313 mousestatus_t status; /* accumulated mouse movement */
314 ringbuf_t queue; /* mouse status queue */
315 packetbuf_t pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
316 int pqueue_start; /* start of data in queue */
317 int pqueue_end; /* end of data in queue */
318 int button; /* the latest button state */
319 int xold; /* previous absolute X position */
320 int yold; /* previous absolute Y position */
321 int xaverage; /* average X position */
322 int yaverage; /* average Y position */
323 int squelch; /* level to filter movement at low speed */
324 int zmax; /* maximum pressure value for touchpads */
325 int syncerrors; /* # of bytes discarded to synchronize */
326 int pkterrors; /* # of packets failed during quaranteen. */
327 struct timeval inputtimeout;
328 struct timeval lastsoftintr; /* time of last soft interrupt */
329 struct timeval lastinputerr; /* time last sync error happened */
330 struct timeval taptimeout; /* tap timeout for touchpads */
331 int watchdog; /* watchdog timer flag */
332 struct callout callout; /* watchdog timer call out */
333 struct callout softcallout; /* buffer timer call out */
334 struct cdev *dev;
335 struct cdev *bdev;
336 int lasterr;
337 int cmdcount;
338 struct sigio *async; /* Processes waiting for SIGIO */
202 int min_pressure;
203 int max_pressure;
204 int max_width;
205 int margin_top;
206 int margin_right;
207 int margin_bottom;
208 int margin_left;
209 int na_top;
210 int na_right;
211 int na_bottom;
212 int na_left;
213 int window_min;
214 int window_max;
215 int multiplicator;
216 int weight_current;
217 int weight_previous;
218 int weight_previous_na;
219 int weight_len_squared;
220 int div_min;
221 int div_max;
222 int div_max_na;
223 int div_len;
224 int tap_max_delta;
225 int tap_min_queue;
226 int taphold_timeout;
227 int vscroll_ver_area;
228 int vscroll_hor_area;
229 int vscroll_min_delta;
230 int vscroll_div_min;
231 int vscroll_div_max;
232} synapticsinfo_t;
233
234typedef struct synapticspacket {
235 int x;
236 int y;
237} synapticspacket_t;
238
239#define SYNAPTICS_PACKETQUEUE 10
240#define SYNAPTICS_QUEUE_CURSOR(x) \
241 (x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE
242
243#define SYNAPTICS_VERSION_GE(synhw, major, minor) \
244 ((synhw).infoMajor > (major) || \
245 ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
246
247typedef struct synapticsaction {
248 synapticspacket_t queue[SYNAPTICS_PACKETQUEUE];
249 int queue_len;
250 int queue_cursor;
251 int window_min;
252 int start_x;
253 int start_y;
254 int avg_dx;
255 int avg_dy;
256 int squelch_x;
257 int squelch_y;
258 int fingers_nb;
259 int tap_button;
260 int in_taphold;
261 int in_vscroll;
262} synapticsaction_t;
263
264enum {
265 TRACKPOINT_SYSCTL_SENSITIVITY,
266 TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
267 TRACKPOINT_SYSCTL_UPPER_PLATEAU,
268 TRACKPOINT_SYSCTL_BACKUP_RANGE,
269 TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
270 TRACKPOINT_SYSCTL_MINIMUM_DRAG,
271 TRACKPOINT_SYSCTL_UP_THRESHOLD,
272 TRACKPOINT_SYSCTL_THRESHOLD,
273 TRACKPOINT_SYSCTL_JENKS_CURVATURE,
274 TRACKPOINT_SYSCTL_Z_TIME,
275 TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
276 TRACKPOINT_SYSCTL_SKIP_BACKUPS
277};
278
279typedef struct trackpointinfo {
280 struct sysctl_ctx_list sysctl_ctx;
281 struct sysctl_oid *sysctl_tree;
282 int sensitivity;
283 int inertia;
284 int uplateau;
285 int reach;
286 int draghys;
287 int mindrag;
288 int upthresh;
289 int threshold;
290 int jenks;
291 int ztime;
292 int pts;
293 int skipback;
294} trackpointinfo_t;
295
296/* driver control block */
297struct psm_softc { /* Driver status information */
298 int unit;
299 struct selinfo rsel; /* Process selecting for Input */
300 u_char state; /* Mouse driver state */
301 int config; /* driver configuration flags */
302 int flags; /* other flags */
303 KBDC kbdc; /* handle to access kbd controller */
304 struct resource *intr; /* IRQ resource */
305 void *ih; /* interrupt handle */
306 mousehw_t hw; /* hardware information */
307 synapticshw_t synhw; /* Synaptics hardware information */
308 synapticsinfo_t syninfo; /* Synaptics configuration */
309 synapticsaction_t synaction; /* Synaptics action context */
310 int tphw; /* TrackPoint hardware information */
311 trackpointinfo_t tpinfo; /* TrackPoint configuration */
312 mousemode_t mode; /* operation mode */
313 mousemode_t dflt_mode; /* default operation mode */
314 mousestatus_t status; /* accumulated mouse movement */
315 ringbuf_t queue; /* mouse status queue */
316 packetbuf_t pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
317 int pqueue_start; /* start of data in queue */
318 int pqueue_end; /* end of data in queue */
319 int button; /* the latest button state */
320 int xold; /* previous absolute X position */
321 int yold; /* previous absolute Y position */
322 int xaverage; /* average X position */
323 int yaverage; /* average Y position */
324 int squelch; /* level to filter movement at low speed */
325 int zmax; /* maximum pressure value for touchpads */
326 int syncerrors; /* # of bytes discarded to synchronize */
327 int pkterrors; /* # of packets failed during quaranteen. */
328 struct timeval inputtimeout;
329 struct timeval lastsoftintr; /* time of last soft interrupt */
330 struct timeval lastinputerr; /* time last sync error happened */
331 struct timeval taptimeout; /* tap timeout for touchpads */
332 int watchdog; /* watchdog timer flag */
333 struct callout callout; /* watchdog timer call out */
334 struct callout softcallout; /* buffer timer call out */
335 struct cdev *dev;
336 struct cdev *bdev;
337 int lasterr;
338 int cmdcount;
339 struct sigio *async; /* Processes waiting for SIGIO */
340 int extended_buttons;
339};
340static devclass_t psm_devclass;
341
342/* driver state flags (state) */
343#define PSM_VALID 0x80
344#define PSM_OPEN 1 /* Device is open */
345#define PSM_ASLP 2 /* Waiting for mouse data */
346#define PSM_SOFTARMED 4 /* Software interrupt armed */
347#define PSM_NEED_SYNCBITS 8 /* Set syncbits using next data pkt */
348
349/* driver configuration flags (config) */
350#define PSM_CONFIG_RESOLUTION 0x000f /* resolution */
351#define PSM_CONFIG_ACCEL 0x00f0 /* acceleration factor */
352#define PSM_CONFIG_NOCHECKSYNC 0x0100 /* disable sync. test */
353#define PSM_CONFIG_NOIDPROBE 0x0200 /* disable mouse model probe */
354#define PSM_CONFIG_NORESET 0x0400 /* don't reset the mouse */
355#define PSM_CONFIG_FORCETAP 0x0800 /* assume `tap' action exists */
356#define PSM_CONFIG_IGNPORTERROR 0x1000 /* ignore error in aux port test */
357#define PSM_CONFIG_HOOKRESUME 0x2000 /* hook the system resume event */
358#define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
359
360#define PSM_CONFIG_FLAGS \
361 (PSM_CONFIG_RESOLUTION | \
362 PSM_CONFIG_ACCEL | \
363 PSM_CONFIG_NOCHECKSYNC | \
364 PSM_CONFIG_NOIDPROBE | \
365 PSM_CONFIG_NORESET | \
366 PSM_CONFIG_FORCETAP | \
367 PSM_CONFIG_IGNPORTERROR | \
368 PSM_CONFIG_HOOKRESUME | \
369 PSM_CONFIG_INITAFTERSUSPEND)
370
371/* other flags (flags) */
372#define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */
373
374#define kbdcp(p) ((atkbdc_softc_t *)(p))
375#define ALWAYS_RESTORE_CONTROLLER(kbdc) !(kbdcp(kbdc)->quirks \
376 & KBDC_QUIRK_KEEP_ACTIVATED)
377
378/* Tunables */
379static int tap_enabled = -1;
380TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
381
382static int synaptics_support = 0;
383TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
384
385static int trackpoint_support = 0;
386TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
387
388static int verbose = PSM_DEBUG;
389TUNABLE_INT("debug.psm.loglevel", &verbose);
390
391/* for backward compatibility */
392#define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t)
393#define OLD_MOUSE_GETMODE _IOR('M', 2, old_mousemode_t)
394#define OLD_MOUSE_SETMODE _IOW('M', 3, old_mousemode_t)
395
396typedef struct old_mousehw {
397 int buttons;
398 int iftype;
399 int type;
400 int hwid;
401} old_mousehw_t;
402
403typedef struct old_mousemode {
404 int protocol;
405 int rate;
406 int resolution;
407 int accelfactor;
408} old_mousemode_t;
409
410/* packet formatting function */
411typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int,
412 mousestatus_t *);
413
414/* function prototypes */
415static void psmidentify(driver_t *, device_t);
416static int psmprobe(device_t);
417static int psmattach(device_t);
418static int psmdetach(device_t);
419static int psmresume(device_t);
420
421static d_open_t psmopen;
422static d_close_t psmclose;
423static d_read_t psmread;
424static d_write_t psmwrite;
425static d_ioctl_t psmioctl;
426static d_poll_t psmpoll;
427
428static int enable_aux_dev(KBDC);
429static int disable_aux_dev(KBDC);
430static int get_mouse_status(KBDC, int *, int, int);
431static int get_aux_id(KBDC);
432static int set_mouse_sampling_rate(KBDC, int);
433static int set_mouse_scaling(KBDC, int);
434static int set_mouse_resolution(KBDC, int);
435static int set_mouse_mode(KBDC);
436static int get_mouse_buttons(KBDC);
437static int is_a_mouse(int);
438static void recover_from_error(KBDC);
439static int restore_controller(KBDC, int);
440static int doinitialize(struct psm_softc *, mousemode_t *);
441static int doopen(struct psm_softc *, int);
442static int reinitialize(struct psm_softc *, int);
443static char *model_name(int);
444static void psmsoftintr(void *);
445static void psmintr(void *);
446static void psmtimeout(void *);
447static int timeelapsed(const struct timeval *, int, int,
448 const struct timeval *);
449static void dropqueue(struct psm_softc *);
450static void flushpackets(struct psm_softc *);
451static void proc_mmanplus(struct psm_softc *, packetbuf_t *,
452 mousestatus_t *, int *, int *, int *);
453static int proc_synaptics(struct psm_softc *, packetbuf_t *,
454 mousestatus_t *, int *, int *, int *);
455static void proc_versapad(struct psm_softc *, packetbuf_t *,
456 mousestatus_t *, int *, int *, int *);
457static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
458 u_char *);
459
460/* vendor specific features */
461typedef int probefunc_t(KBDC, struct psm_softc *);
462
463static int mouse_id_proc1(KBDC, int, int, int *);
464static int mouse_ext_command(KBDC, int);
465
466static probefunc_t enable_groller;
467static probefunc_t enable_gmouse;
468static probefunc_t enable_aglide;
469static probefunc_t enable_kmouse;
470static probefunc_t enable_msexplorer;
471static probefunc_t enable_msintelli;
472static probefunc_t enable_4dmouse;
473static probefunc_t enable_4dplus;
474static probefunc_t enable_mmanplus;
475static probefunc_t enable_synaptics;
476static probefunc_t enable_trackpoint;
477static probefunc_t enable_versapad;
478
479static struct {
480 int model;
481 u_char syncmask;
482 int packetsize;
483 probefunc_t *probefunc;
484} vendortype[] = {
485 /*
486 * WARNING: the order of probe is very important. Don't mess it
487 * unless you know what you are doing.
488 */
489 { MOUSE_MODEL_NET, /* Genius NetMouse */
490 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
491 { MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */
492 0xc8, 6, enable_groller },
493 { MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */
494 0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
495 { MOUSE_MODEL_EXPLORER, /* Microsoft IntelliMouse Explorer */
496 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
497 { MOUSE_MODEL_4D, /* A4 Tech 4D Mouse */
498 0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
499 { MOUSE_MODEL_4DPLUS, /* A4 Tech 4D+ Mouse */
500 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
501 { MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */
502 0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
503 { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
504 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
505 { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
506 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
507 { MOUSE_MODEL_THINK, /* Kensington ThinkingMouse */
508 0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
509 { MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */
510 0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
511 { MOUSE_MODEL_TRACKPOINT, /* IBM/Lenovo TrackPoint */
512 0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint },
513 { MOUSE_MODEL_GENERIC,
514 0xc0, MOUSE_PS2_PACKETSIZE, NULL },
515};
516#define GENERIC_MOUSE_ENTRY \
517 ((sizeof(vendortype) / sizeof(*vendortype)) - 1)
518
519/* device driver declarateion */
520static device_method_t psm_methods[] = {
521 /* Device interface */
522 DEVMETHOD(device_identify, psmidentify),
523 DEVMETHOD(device_probe, psmprobe),
524 DEVMETHOD(device_attach, psmattach),
525 DEVMETHOD(device_detach, psmdetach),
526 DEVMETHOD(device_resume, psmresume),
527
528 { 0, 0 }
529};
530
531static driver_t psm_driver = {
532 PSM_DRIVER_NAME,
533 psm_methods,
534 sizeof(struct psm_softc),
535};
536
537static struct cdevsw psm_cdevsw = {
538 .d_version = D_VERSION,
539 .d_flags = D_NEEDGIANT,
540 .d_open = psmopen,
541 .d_close = psmclose,
542 .d_read = psmread,
543 .d_write = psmwrite,
544 .d_ioctl = psmioctl,
545 .d_poll = psmpoll,
546 .d_name = PSM_DRIVER_NAME,
547};
548
549/* device I/O routines */
550static int
551enable_aux_dev(KBDC kbdc)
552{
553 int res;
554
555 res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
556 VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
557
558 return (res == PSM_ACK);
559}
560
561static int
562disable_aux_dev(KBDC kbdc)
563{
564 int res;
565
566 res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
567 VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
568
569 return (res == PSM_ACK);
570}
571
572static int
573get_mouse_status(KBDC kbdc, int *status, int flag, int len)
574{
575 int cmd;
576 int res;
577 int i;
578
579 switch (flag) {
580 case 0:
581 default:
582 cmd = PSMC_SEND_DEV_STATUS;
583 break;
584 case 1:
585 cmd = PSMC_SEND_DEV_DATA;
586 break;
587 }
588 empty_aux_buffer(kbdc, 5);
589 res = send_aux_command(kbdc, cmd);
590 VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
591 (flag == 1) ? "DATA" : "STATUS", res));
592 if (res != PSM_ACK)
593 return (0);
594
595 for (i = 0; i < len; ++i) {
596 status[i] = read_aux_data(kbdc);
597 if (status[i] < 0)
598 break;
599 }
600
601 VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
602 (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
603
604 return (i);
605}
606
607static int
608get_aux_id(KBDC kbdc)
609{
610 int res;
611 int id;
612
613 empty_aux_buffer(kbdc, 5);
614 res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
615 VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
616 if (res != PSM_ACK)
617 return (-1);
618
619 /* 10ms delay */
620 DELAY(10000);
621
622 id = read_aux_data(kbdc);
623 VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
624
625 return (id);
626}
627
628static int
629set_mouse_sampling_rate(KBDC kbdc, int rate)
630{
631 int res;
632
633 res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
634 VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
635
636 return ((res == PSM_ACK) ? rate : -1);
637}
638
639static int
640set_mouse_scaling(KBDC kbdc, int scale)
641{
642 int res;
643
644 switch (scale) {
645 case 1:
646 default:
647 scale = PSMC_SET_SCALING11;
648 break;
649 case 2:
650 scale = PSMC_SET_SCALING21;
651 break;
652 }
653 res = send_aux_command(kbdc, scale);
654 VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
655 (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
656
657 return (res == PSM_ACK);
658}
659
660/* `val' must be 0 through PSMD_MAX_RESOLUTION */
661static int
662set_mouse_resolution(KBDC kbdc, int val)
663{
664 int res;
665
666 res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
667 VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
668
669 return ((res == PSM_ACK) ? val : -1);
670}
671
672/*
673 * NOTE: once `set_mouse_mode()' is called, the mouse device must be
674 * re-enabled by calling `enable_aux_dev()'
675 */
676static int
677set_mouse_mode(KBDC kbdc)
678{
679 int res;
680
681 res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
682 VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
683
684 return (res == PSM_ACK);
685}
686
687static int
688get_mouse_buttons(KBDC kbdc)
689{
690 int c = 2; /* assume two buttons by default */
691 int status[3];
692
693 /*
694 * NOTE: a special sequence to obtain Logitech Mouse specific
695 * information: set resolution to 25 ppi, set scaling to 1:1, set
696 * scaling to 1:1, set scaling to 1:1. Then the second byte of the
697 * mouse status bytes is the number of available buttons.
698 * Some manufactures also support this sequence.
699 */
700 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
701 return (c);
702 if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
703 set_mouse_scaling(kbdc, 1) &&
704 get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
705 return (status[1]);
706 return (c);
707}
708
709/* misc subroutines */
710/*
711 * Someday, I will get the complete list of valid pointing devices and
712 * their IDs... XXX
713 */
714static int
715is_a_mouse(int id)
716{
717#if 0
718 static int valid_ids[] = {
719 PSM_MOUSE_ID, /* mouse */
720 PSM_BALLPOINT_ID, /* ballpoint device */
721 PSM_INTELLI_ID, /* Intellimouse */
722 PSM_EXPLORER_ID, /* Intellimouse Explorer */
723 -1 /* end of table */
724 };
725 int i;
726
727 for (i = 0; valid_ids[i] >= 0; ++i)
728 if (valid_ids[i] == id)
729 return (TRUE);
730 return (FALSE);
731#else
732 return (TRUE);
733#endif
734}
735
736static char *
737model_name(int model)
738{
739 static struct {
740 int model_code;
741 char *model_name;
742 } models[] = {
743 { MOUSE_MODEL_NETSCROLL, "NetScroll" },
744 { MOUSE_MODEL_NET, "NetMouse/NetScroll Optical" },
745 { MOUSE_MODEL_GLIDEPOINT, "GlidePoint" },
746 { MOUSE_MODEL_THINK, "ThinkingMouse" },
747 { MOUSE_MODEL_INTELLI, "IntelliMouse" },
748 { MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" },
749 { MOUSE_MODEL_VERSAPAD, "VersaPad" },
750 { MOUSE_MODEL_EXPLORER, "IntelliMouse Explorer" },
751 { MOUSE_MODEL_4D, "4D Mouse" },
752 { MOUSE_MODEL_4DPLUS, "4D+ Mouse" },
753 { MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" },
754 { MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" },
755 { MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" },
756 { MOUSE_MODEL_UNKNOWN, "Unknown" },
757 };
758 int i;
759
760 for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
761 if (models[i].model_code == model)
762 break;
763 return (models[i].model_name);
764}
765
766static void
767recover_from_error(KBDC kbdc)
768{
769 /* discard anything left in the output buffer */
770 empty_both_buffers(kbdc, 10);
771
772#if 0
773 /*
774 * NOTE: KBDC_RESET_KBD may not restore the communication between the
775 * keyboard and the controller.
776 */
777 reset_kbd(kbdc);
778#else
779 /*
780 * NOTE: somehow diagnostic and keyboard port test commands bring the
781 * keyboard back.
782 */
783 if (!test_controller(kbdc))
784 log(LOG_ERR, "psm: keyboard controller failed.\n");
785 /* if there isn't a keyboard in the system, the following error is OK */
786 if (test_kbd_port(kbdc) != 0)
787 VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
788#endif
789}
790
791static int
792restore_controller(KBDC kbdc, int command_byte)
793{
794 empty_both_buffers(kbdc, 10);
795
796 if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
797 log(LOG_ERR, "psm: failed to restore the keyboard controller "
798 "command byte.\n");
799 empty_both_buffers(kbdc, 10);
800 return (FALSE);
801 } else {
802 empty_both_buffers(kbdc, 10);
803 return (TRUE);
804 }
805}
806
807/*
808 * Re-initialize the aux port and device. The aux port must be enabled
809 * and its interrupt must be disabled before calling this routine.
810 * The aux device will be disabled before returning.
811 * The keyboard controller must be locked via `kbdc_lock()' before
812 * calling this routine.
813 */
814static int
815doinitialize(struct psm_softc *sc, mousemode_t *mode)
816{
817 KBDC kbdc = sc->kbdc;
818 int stat[3];
819 int i;
820
821 switch((i = test_aux_port(kbdc))) {
822 case 1: /* ignore these errors */
823 case 2:
824 case 3:
825 case PSM_ACK:
826 if (verbose)
827 log(LOG_DEBUG,
828 "psm%d: strange result for test aux port (%d).\n",
829 sc->unit, i);
830 /* FALLTHROUGH */
831 case 0: /* no error */
832 break;
833 case -1: /* time out */
834 default: /* error */
835 recover_from_error(kbdc);
836 if (sc->config & PSM_CONFIG_IGNPORTERROR)
837 break;
838 log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
839 sc->unit, i);
840 return (FALSE);
841 }
842
843 if (sc->config & PSM_CONFIG_NORESET) {
844 /*
845 * Don't try to reset the pointing device. It may possibly
846 * be left in the unknown state, though...
847 */
848 } else {
849 /*
850 * NOTE: some controllers appears to hang the `keyboard' when
851 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
852 */
853 if (!reset_aux_dev(kbdc)) {
854 recover_from_error(kbdc);
855 log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
856 sc->unit);
857 return (FALSE);
858 }
859 }
860
861 /*
862 * both the aux port and the aux device is functioning, see
863 * if the device can be enabled.
864 */
865 if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
866 log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
867 sc->unit);
868 return (FALSE);
869 }
870 empty_both_buffers(kbdc, 10); /* remove stray data if any */
871
872 /* Re-enable the mouse. */
873 for (i = 0; vendortype[i].probefunc != NULL; ++i)
874 if (vendortype[i].model == sc->hw.model)
875 (*vendortype[i].probefunc)(sc->kbdc, NULL);
876
877 /* set mouse parameters */
878 if (mode != (mousemode_t *)NULL) {
879 if (mode->rate > 0)
880 mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
881 if (mode->resolution >= 0)
882 mode->resolution =
883 set_mouse_resolution(kbdc, mode->resolution);
884 set_mouse_scaling(kbdc, 1);
885 set_mouse_mode(kbdc);
886 }
887
888 /* Record sync on the next data packet we see. */
889 sc->flags |= PSM_NEED_SYNCBITS;
890
891 /* just check the status of the mouse */
892 if (get_mouse_status(kbdc, stat, 0, 3) < 3)
893 log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
894 sc->unit);
895
896 return (TRUE);
897}
898
899static int
900doopen(struct psm_softc *sc, int command_byte)
901{
902 int stat[3];
903
904 /*
905 * FIXME: Synaptics TouchPad seems to go back to Relative Mode with
906 * no obvious reason. Thus we check the current mode and restore the
907 * Absolute Mode if it was cleared.
908 *
909 * The previous hack at the end of psmprobe() wasn't efficient when
910 * moused(8) was restarted.
911 *
912 * A Reset (FF) or Set Defaults (F6) command would clear the
913 * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5
914 * doesn't show any evidence of such a command.
915 */
916 if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
917 mouse_ext_command(sc->kbdc, 1);
918 get_mouse_status(sc->kbdc, stat, 0, 3);
919 if ((SYNAPTICS_VERSION_GE(sc->synhw, 7, 5) ||
920 stat[1] == 0x47) &&
921 stat[2] == 0x40) {
922 /* Set the mode byte -- request wmode where
923 * available */
924 if (sc->synhw.capExtended)
925 mouse_ext_command(sc->kbdc, 0xc1);
926 else
927 mouse_ext_command(sc->kbdc, 0xc0);
928 set_mouse_sampling_rate(sc->kbdc, 20);
929 VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode "
930 "hopefully restored\n",
931 sc->unit));
932 }
933 }
934
935 /*
936 * A user may want to disable tap and drag gestures on a Synaptics
937 * TouchPad when it operates in Relative Mode.
938 */
939 if (sc->hw.model == MOUSE_MODEL_GENERIC) {
940 if (tap_enabled > 0) {
941 /*
942 * Enable tap & drag gestures. We use a Mode Byte
943 * and clear the DisGest bit (see ��2.5 of Synaptics
944 * TouchPad Interfacing Guide).
945 */
946 VLOG(2, (LOG_DEBUG,
947 "psm%d: enable tap and drag gestures\n",
948 sc->unit));
949 mouse_ext_command(sc->kbdc, 0x00);
950 set_mouse_sampling_rate(sc->kbdc, 20);
951 } else if (tap_enabled == 0) {
952 /*
953 * Disable tap & drag gestures. We use a Mode Byte
954 * and set the DisGest bit (see ��2.5 of Synaptics
955 * TouchPad Interfacing Guide).
956 */
957 VLOG(2, (LOG_DEBUG,
958 "psm%d: disable tap and drag gestures\n",
959 sc->unit));
960 mouse_ext_command(sc->kbdc, 0x04);
961 set_mouse_sampling_rate(sc->kbdc, 20);
962 }
963 }
964
965 /* enable the mouse device */
966 if (!enable_aux_dev(sc->kbdc)) {
967 /* MOUSE ERROR: failed to enable the mouse because:
968 * 1) the mouse is faulty,
969 * 2) the mouse has been removed(!?)
970 * In the latter case, the keyboard may have hung, and need
971 * recovery procedure...
972 */
973 recover_from_error(sc->kbdc);
974#if 0
975 /* FIXME: we could reset the mouse here and try to enable
976 * it again. But it will take long time and it's not a good
977 * idea to disable the keyboard that long...
978 */
979 if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
980 recover_from_error(sc->kbdc);
981#else
982 {
983#endif
984 restore_controller(sc->kbdc, command_byte);
985 /* mark this device is no longer available */
986 sc->state &= ~PSM_VALID;
987 log(LOG_ERR,
988 "psm%d: failed to enable the device (doopen).\n",
989 sc->unit);
990 return (EIO);
991 }
992 }
993
994 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
995 log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
996 sc->unit);
997
998 /* enable the aux port and interrupt */
999 if (!set_controller_command_byte(sc->kbdc,
1000 kbdc_get_device_mask(sc->kbdc),
1001 (command_byte & KBD_KBD_CONTROL_BITS) |
1002 KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
1003 /* CONTROLLER ERROR */
1004 disable_aux_dev(sc->kbdc);
1005 restore_controller(sc->kbdc, command_byte);
1006 log(LOG_ERR,
1007 "psm%d: failed to enable the aux interrupt (doopen).\n",
1008 sc->unit);
1009 return (EIO);
1010 }
1011
1012 /* start the watchdog timer */
1013 sc->watchdog = FALSE;
1014 callout_reset(&sc->callout, hz * 2, psmtimeout, sc);
1015
1016 return (0);
1017}
1018
1019static int
1020reinitialize(struct psm_softc *sc, int doinit)
1021{
1022 int err;
1023 int c;
1024 int s;
1025
1026 /* don't let anybody mess with the aux device */
1027 if (!kbdc_lock(sc->kbdc, TRUE))
1028 return (EIO);
1029 s = spltty();
1030
1031 /* block our watchdog timer */
1032 sc->watchdog = FALSE;
1033 callout_stop(&sc->callout);
1034
1035 /* save the current controller command byte */
1036 empty_both_buffers(sc->kbdc, 10);
1037 c = get_controller_command_byte(sc->kbdc);
1038 VLOG(2, (LOG_DEBUG,
1039 "psm%d: current command byte: %04x (reinitialize).\n",
1040 sc->unit, c));
1041
1042 /* enable the aux port but disable the aux interrupt and the keyboard */
1043 if ((c == -1) || !set_controller_command_byte(sc->kbdc,
1044 kbdc_get_device_mask(sc->kbdc),
1045 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1046 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1047 /* CONTROLLER ERROR */
1048 splx(s);
1049 kbdc_lock(sc->kbdc, FALSE);
1050 log(LOG_ERR,
1051 "psm%d: unable to set the command byte (reinitialize).\n",
1052 sc->unit);
1053 return (EIO);
1054 }
1055
1056 /* flush any data */
1057 if (sc->state & PSM_VALID) {
1058 /* this may fail; but never mind... */
1059 disable_aux_dev(sc->kbdc);
1060 empty_aux_buffer(sc->kbdc, 10);
1061 }
1062 flushpackets(sc);
1063 sc->syncerrors = 0;
1064 sc->pkterrors = 0;
1065 memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
1066
1067 /* try to detect the aux device; are you still there? */
1068 err = 0;
1069 if (doinit) {
1070 if (doinitialize(sc, &sc->mode)) {
1071 /* yes */
1072 sc->state |= PSM_VALID;
1073 } else {
1074 /* the device has gone! */
1075 restore_controller(sc->kbdc, c);
1076 sc->state &= ~PSM_VALID;
1077 log(LOG_ERR,
1078 "psm%d: the aux device has gone! (reinitialize).\n",
1079 sc->unit);
1080 err = ENXIO;
1081 }
1082 }
1083 splx(s);
1084
1085 /* restore the driver state */
1086 if ((sc->state & PSM_OPEN) && (err == 0)) {
1087 /* enable the aux device and the port again */
1088 err = doopen(sc, c);
1089 if (err != 0)
1090 log(LOG_ERR, "psm%d: failed to enable the device "
1091 "(reinitialize).\n", sc->unit);
1092 } else {
1093 /* restore the keyboard port and disable the aux port */
1094 if (!set_controller_command_byte(sc->kbdc,
1095 kbdc_get_device_mask(sc->kbdc),
1096 (c & KBD_KBD_CONTROL_BITS) |
1097 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1098 /* CONTROLLER ERROR */
1099 log(LOG_ERR, "psm%d: failed to disable the aux port "
1100 "(reinitialize).\n", sc->unit);
1101 err = EIO;
1102 }
1103 }
1104
1105 kbdc_lock(sc->kbdc, FALSE);
1106 return (err);
1107}
1108
1109/* psm driver entry points */
1110
1111static void
1112psmidentify(driver_t *driver, device_t parent)
1113{
1114 device_t psmc;
1115 device_t psm;
1116 u_long irq;
1117 int unit;
1118
1119 unit = device_get_unit(parent);
1120
1121 /* always add at least one child */
1122 psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit);
1123 if (psm == NULL)
1124 return;
1125
1126 irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
1127 if (irq > 0)
1128 return;
1129
1130 /*
1131 * If the PS/2 mouse device has already been reported by ACPI or
1132 * PnP BIOS, obtain the IRQ resource from it.
1133 * (See psmcpnp_attach() below.)
1134 */
1135 psmc = device_find_child(device_get_parent(parent),
1136 PSMCPNP_DRIVER_NAME, unit);
1137 if (psmc == NULL)
1138 return;
1139 irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
1140 if (irq <= 0)
1141 return;
1142 bus_delete_resource(psmc, SYS_RES_IRQ, 0);
1143 bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
1144}
1145
1146#define endprobe(v) do { \
1147 if (bootverbose) \
1148 --verbose; \
1149 kbdc_set_device_mask(sc->kbdc, mask); \
1150 kbdc_lock(sc->kbdc, FALSE); \
1151 return (v); \
1152} while (0)
1153
1154static int
1155psmprobe(device_t dev)
1156{
1157 int unit = device_get_unit(dev);
1158 struct psm_softc *sc = device_get_softc(dev);
1159 int stat[3];
1160 int command_byte;
1161 int mask;
1162 int rid;
1163 int i;
1164
1165#if 0
1166 kbdc_debug(TRUE);
1167#endif
1168
1169 /* see if IRQ is available */
1170 rid = KBDC_RID_AUX;
1171 sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1172 if (sc->intr == NULL) {
1173 if (bootverbose)
1174 device_printf(dev, "unable to allocate IRQ\n");
1175 return (ENXIO);
1176 }
1177 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1178
1179 sc->unit = unit;
1180 sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
1181 sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS;
1182 /* XXX: for backward compatibility */
1183#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
1184 sc->config |=
1185#ifdef PSM_RESETAFTERSUSPEND
1186 PSM_CONFIG_INITAFTERSUSPEND;
1187#else
1188 PSM_CONFIG_HOOKRESUME;
1189#endif
1190#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
1191 sc->flags = 0;
1192 if (bootverbose)
1193 ++verbose;
1194
1195 device_set_desc(dev, "PS/2 Mouse");
1196
1197 if (!kbdc_lock(sc->kbdc, TRUE)) {
1198 printf("psm%d: unable to lock the controller.\n", unit);
1199 if (bootverbose)
1200 --verbose;
1201 return (ENXIO);
1202 }
1203
1204 /*
1205 * NOTE: two bits in the command byte controls the operation of the
1206 * aux port (mouse port): the aux port disable bit (bit 5) and the aux
1207 * port interrupt (IRQ 12) enable bit (bit 2).
1208 */
1209
1210 /* discard anything left after the keyboard initialization */
1211 empty_both_buffers(sc->kbdc, 10);
1212
1213 /* save the current command byte; it will be used later */
1214 mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
1215 command_byte = get_controller_command_byte(sc->kbdc);
1216 if (verbose)
1217 printf("psm%d: current command byte:%04x\n", unit,
1218 command_byte);
1219 if (command_byte == -1) {
1220 /* CONTROLLER ERROR */
1221 printf("psm%d: unable to get the current command byte value.\n",
1222 unit);
1223 endprobe(ENXIO);
1224 }
1225
1226 /*
1227 * disable the keyboard port while probing the aux port, which must be
1228 * enabled during this routine
1229 */
1230 if (!set_controller_command_byte(sc->kbdc,
1231 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1232 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1233 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1234 /*
1235 * this is CONTROLLER ERROR; I don't know how to recover
1236 * from this error...
1237 */
1238 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1239 restore_controller(sc->kbdc, command_byte);
1240 printf("psm%d: unable to set the command byte.\n", unit);
1241 endprobe(ENXIO);
1242 }
1243 write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
1244
1245 /*
1246 * NOTE: `test_aux_port()' is designed to return with zero if the aux
1247 * port exists and is functioning. However, some controllers appears
1248 * to respond with zero even when the aux port doesn't exist. (It may
1249 * be that this is only the case when the controller DOES have the aux
1250 * port but the port is not wired on the motherboard.) The keyboard
1251 * controllers without the port, such as the original AT, are
1252 * supposed to return with an error code or simply time out. In any
1253 * case, we have to continue probing the port even when the controller
1254 * passes this test.
1255 *
1256 * XXX: some controllers erroneously return the error code 1, 2 or 3
1257 * when it has a perfectly functional aux port. We have to ignore
1258 * this error code. Even if the controller HAS error with the aux
1259 * port, it will be detected later...
1260 * XXX: another incompatible controller returns PSM_ACK (0xfa)...
1261 */
1262 switch ((i = test_aux_port(sc->kbdc))) {
1263 case 1: /* ignore these errors */
1264 case 2:
1265 case 3:
1266 case PSM_ACK:
1267 if (verbose)
1268 printf("psm%d: strange result for test aux port "
1269 "(%d).\n", unit, i);
1270 /* FALLTHROUGH */
1271 case 0: /* no error */
1272 break;
1273 case -1: /* time out */
1274 default: /* error */
1275 recover_from_error(sc->kbdc);
1276 if (sc->config & PSM_CONFIG_IGNPORTERROR)
1277 break;
1278 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1279 restore_controller(sc->kbdc, command_byte);
1280 if (verbose)
1281 printf("psm%d: the aux port is not functioning (%d).\n",
1282 unit, i);
1283 endprobe(ENXIO);
1284 }
1285
1286 if (sc->config & PSM_CONFIG_NORESET) {
1287 /*
1288 * Don't try to reset the pointing device. It may possibly be
1289 * left in an unknown state, though...
1290 */
1291 } else {
1292 /*
1293 * NOTE: some controllers appears to hang the `keyboard' when
1294 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
1295 *
1296 * Attempt to reset the controller twice -- this helps
1297 * pierce through some KVM switches. The second reset
1298 * is non-fatal.
1299 */
1300 if (!reset_aux_dev(sc->kbdc)) {
1301 recover_from_error(sc->kbdc);
1302 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1303 restore_controller(sc->kbdc, command_byte);
1304 if (verbose)
1305 printf("psm%d: failed to reset the aux "
1306 "device.\n", unit);
1307 endprobe(ENXIO);
1308 } else if (!reset_aux_dev(sc->kbdc)) {
1309 recover_from_error(sc->kbdc);
1310 if (verbose >= 2)
1311 printf("psm%d: failed to reset the aux device "
1312 "(2).\n", unit);
1313 }
1314 }
1315
1316 /*
1317 * both the aux port and the aux device are functioning, see if the
1318 * device can be enabled. NOTE: when enabled, the device will start
1319 * sending data; we shall immediately disable the device once we know
1320 * the device can be enabled.
1321 */
1322 if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
1323 /* MOUSE ERROR */
1324 recover_from_error(sc->kbdc);
1325 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1326 restore_controller(sc->kbdc, command_byte);
1327 if (verbose)
1328 printf("psm%d: failed to enable the aux device.\n",
1329 unit);
1330 endprobe(ENXIO);
1331 }
1332
1333 /* save the default values after reset */
1334 if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
1335 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1336 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1337 } else {
1338 sc->dflt_mode.rate = sc->mode.rate = -1;
1339 sc->dflt_mode.resolution = sc->mode.resolution = -1;
1340 }
1341
1342 /* hardware information */
1343 sc->hw.iftype = MOUSE_IF_PS2;
1344
1345 /* verify the device is a mouse */
1346 sc->hw.hwid = get_aux_id(sc->kbdc);
1347 if (!is_a_mouse(sc->hw.hwid)) {
1348 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1349 restore_controller(sc->kbdc, command_byte);
1350 if (verbose)
1351 printf("psm%d: unknown device type (%d).\n", unit,
1352 sc->hw.hwid);
1353 endprobe(ENXIO);
1354 }
1355 switch (sc->hw.hwid) {
1356 case PSM_BALLPOINT_ID:
1357 sc->hw.type = MOUSE_TRACKBALL;
1358 break;
1359 case PSM_MOUSE_ID:
1360 case PSM_INTELLI_ID:
1361 case PSM_EXPLORER_ID:
1362 case PSM_4DMOUSE_ID:
1363 case PSM_4DPLUS_ID:
1364 sc->hw.type = MOUSE_MOUSE;
1365 break;
1366 default:
1367 sc->hw.type = MOUSE_UNKNOWN;
1368 break;
1369 }
1370
1371 if (sc->config & PSM_CONFIG_NOIDPROBE) {
1372 sc->hw.buttons = 2;
1373 i = GENERIC_MOUSE_ENTRY;
1374 } else {
1375 /* # of buttons */
1376 sc->hw.buttons = get_mouse_buttons(sc->kbdc);
1377
1378 /* other parameters */
1379 for (i = 0; vendortype[i].probefunc != NULL; ++i)
1380 if ((*vendortype[i].probefunc)(sc->kbdc, sc)) {
1381 if (verbose >= 2)
1382 printf("psm%d: found %s\n", unit,
1383 model_name(vendortype[i].model));
1384 break;
1385 }
1386 }
1387
1388 sc->hw.model = vendortype[i].model;
1389
1390 sc->dflt_mode.level = PSM_LEVEL_BASE;
1391 sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
1392 sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
1393 if (sc->config & PSM_CONFIG_NOCHECKSYNC)
1394 sc->dflt_mode.syncmask[0] = 0;
1395 else
1396 sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
1397 if (sc->config & PSM_CONFIG_FORCETAP)
1398 sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
1399 sc->dflt_mode.syncmask[1] = 0; /* syncbits */
1400 sc->mode = sc->dflt_mode;
1401 sc->mode.packetsize = vendortype[i].packetsize;
1402
1403 /* set mouse parameters */
1404#if 0
1405 /*
1406 * A version of Logitech FirstMouse+ won't report wheel movement,
1407 * if SET_DEFAULTS is sent... Don't use this command.
1408 * This fix was found by Takashi Nishida.
1409 */
1410 i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
1411 if (verbose >= 2)
1412 printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
1413#endif
1414 if (sc->config & PSM_CONFIG_RESOLUTION)
1415 sc->mode.resolution =
1416 set_mouse_resolution(sc->kbdc,
1417 (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1418 else if (sc->mode.resolution >= 0)
1419 sc->mode.resolution =
1420 set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1421 if (sc->mode.rate > 0)
1422 sc->mode.rate =
1423 set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1424 set_mouse_scaling(sc->kbdc, 1);
1425
1426 /* Record sync on the next data packet we see. */
1427 sc->flags |= PSM_NEED_SYNCBITS;
1428
1429 /* just check the status of the mouse */
1430 /*
1431 * NOTE: XXX there are some arcane controller/mouse combinations out
1432 * there, which hung the controller unless there is data transmission
1433 * after ACK from the mouse.
1434 */
1435 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1436 printf("psm%d: failed to get status.\n", unit);
1437 else {
1438 /*
1439 * When in its native mode, some mice operate with different
1440 * default parameters than in the PS/2 compatible mode.
1441 */
1442 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1443 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1444 }
1445
1446 /* disable the aux port for now... */
1447 if (!set_controller_command_byte(sc->kbdc,
1448 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1449 (command_byte & KBD_KBD_CONTROL_BITS) |
1450 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1451 /*
1452 * this is CONTROLLER ERROR; I don't know the proper way to
1453 * recover from this error...
1454 */
1455 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1456 restore_controller(sc->kbdc, command_byte);
1457 printf("psm%d: unable to set the command byte.\n", unit);
1458 endprobe(ENXIO);
1459 }
1460
1461 /* done */
1462 kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1463 kbdc_lock(sc->kbdc, FALSE);
1464 return (0);
1465}
1466
1467static int
1468psmattach(device_t dev)
1469{
1470 int unit = device_get_unit(dev);
1471 struct psm_softc *sc = device_get_softc(dev);
1472 int error;
1473 int rid;
1474
1475 /* Setup initial state */
1476 sc->state = PSM_VALID;
1477 callout_init(&sc->callout, 0);
1478 callout_init(&sc->softcallout, 0);
1479
1480 /* Setup our interrupt handler */
1481 rid = KBDC_RID_AUX;
1482 sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1483 if (sc->intr == NULL)
1484 return (ENXIO);
1485 error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc,
1486 &sc->ih);
1487 if (error) {
1488 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1489 return (error);
1490 }
1491
1492 /* Done */
1493 sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit);
1494 sc->dev->si_drv1 = sc;
1495 sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit);
1496 sc->bdev->si_drv1 = sc;
1497
1498 /* Some touchpad devices need full reinitialization after suspend. */
1499 switch (sc->hw.model) {
1500 case MOUSE_MODEL_SYNAPTICS:
1501 case MOUSE_MODEL_GLIDEPOINT:
1502 case MOUSE_MODEL_VERSAPAD:
1503 sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1504 break;
1505 default:
1506 if (sc->synhw.infoMajor >= 4 || sc->tphw > 0)
1507 sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1508 break;
1509 }
1510
1511 if (!verbose)
1512 printf("psm%d: model %s, device ID %d\n",
1513 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1514 else {
1515 printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1516 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
1517 sc->hw.hwid >> 8, sc->hw.buttons);
1518 printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1519 unit, sc->config, sc->flags, sc->mode.packetsize);
1520 printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1521 unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1522 }
1523
1524 if (bootverbose)
1525 --verbose;
1526
1527 return (0);
1528}
1529
1530static int
1531psmdetach(device_t dev)
1532{
1533 struct psm_softc *sc;
1534 int rid;
1535
1536 sc = device_get_softc(dev);
1537 if (sc->state & PSM_OPEN)
1538 return (EBUSY);
1539
1540 rid = KBDC_RID_AUX;
1541 bus_teardown_intr(dev, sc->intr, sc->ih);
1542 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1543
1544 destroy_dev(sc->dev);
1545 destroy_dev(sc->bdev);
1546
1547 callout_drain(&sc->callout);
1548 callout_drain(&sc->softcallout);
1549
1550 return (0);
1551}
1552
1553static int
1554psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
1555{
1556 struct psm_softc *sc;
1557 int command_byte;
1558 int err;
1559 int s;
1560
1561 /* Get device data */
1562 sc = dev->si_drv1;
1563 if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
1564 /* the device is no longer valid/functioning */
1565 return (ENXIO);
1566 }
1567
1568 /* Disallow multiple opens */
1569 if (sc->state & PSM_OPEN)
1570 return (EBUSY);
1571
1572 device_busy(devclass_get_device(psm_devclass, sc->unit));
1573
1574 /* Initialize state */
1575 sc->mode.level = sc->dflt_mode.level;
1576 sc->mode.protocol = sc->dflt_mode.protocol;
1577 sc->watchdog = FALSE;
1578 sc->async = NULL;
1579
1580 /* flush the event queue */
1581 sc->queue.count = 0;
1582 sc->queue.head = 0;
1583 sc->queue.tail = 0;
1584 sc->status.flags = 0;
1585 sc->status.button = 0;
1586 sc->status.obutton = 0;
1587 sc->status.dx = 0;
1588 sc->status.dy = 0;
1589 sc->status.dz = 0;
1590 sc->button = 0;
1591 sc->pqueue_start = 0;
1592 sc->pqueue_end = 0;
1593
1594 /* empty input buffer */
1595 flushpackets(sc);
1596 sc->syncerrors = 0;
1597 sc->pkterrors = 0;
1598
1599 /* don't let timeout routines in the keyboard driver to poll the kbdc */
1600 if (!kbdc_lock(sc->kbdc, TRUE))
1601 return (EIO);
1602
1603 /* save the current controller command byte */
1604 s = spltty();
1605 command_byte = get_controller_command_byte(sc->kbdc);
1606
1607 /* enable the aux port and temporalily disable the keyboard */
1608 if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
1609 kbdc_get_device_mask(sc->kbdc),
1610 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1611 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1612 /* CONTROLLER ERROR; do you know how to get out of this? */
1613 kbdc_lock(sc->kbdc, FALSE);
1614 splx(s);
1615 log(LOG_ERR,
1616 "psm%d: unable to set the command byte (psmopen).\n",
1617 sc->unit);
1618 return (EIO);
1619 }
1620 /*
1621 * Now that the keyboard controller is told not to generate
1622 * the keyboard and mouse interrupts, call `splx()' to allow
1623 * the other tty interrupts. The clock interrupt may also occur,
1624 * but timeout routines will be blocked by the poll flag set
1625 * via `kbdc_lock()'
1626 */
1627 splx(s);
1628
1629 /* enable the mouse device */
1630 err = doopen(sc, command_byte);
1631
1632 /* done */
1633 if (err == 0)
1634 sc->state |= PSM_OPEN;
1635 kbdc_lock(sc->kbdc, FALSE);
1636 return (err);
1637}
1638
1639static int
1640psmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
1641{
1642 struct psm_softc *sc = dev->si_drv1;
1643 int stat[3];
1644 int command_byte;
1645 int s;
1646
1647 /* don't let timeout routines in the keyboard driver to poll the kbdc */
1648 if (!kbdc_lock(sc->kbdc, TRUE))
1649 return (EIO);
1650
1651 /* save the current controller command byte */
1652 s = spltty();
1653 command_byte = get_controller_command_byte(sc->kbdc);
1654 if (command_byte == -1) {
1655 kbdc_lock(sc->kbdc, FALSE);
1656 splx(s);
1657 return (EIO);
1658 }
1659
1660 /* disable the aux interrupt and temporalily disable the keyboard */
1661 if (!set_controller_command_byte(sc->kbdc,
1662 kbdc_get_device_mask(sc->kbdc),
1663 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1664 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1665 log(LOG_ERR,
1666 "psm%d: failed to disable the aux int (psmclose).\n",
1667 sc->unit);
1668 /* CONTROLLER ERROR;
1669 * NOTE: we shall force our way through. Because the only
1670 * ill effect we shall see is that we may not be able
1671 * to read ACK from the mouse, and it doesn't matter much
1672 * so long as the mouse will accept the DISABLE command.
1673 */
1674 }
1675 splx(s);
1676
1677 /* stop the watchdog timer */
1678 callout_stop(&sc->callout);
1679
1680 /* remove anything left in the output buffer */
1681 empty_aux_buffer(sc->kbdc, 10);
1682
1683 /* disable the aux device, port and interrupt */
1684 if (sc->state & PSM_VALID) {
1685 if (!disable_aux_dev(sc->kbdc)) {
1686 /* MOUSE ERROR;
1687 * NOTE: we don't return (error) and continue,
1688 * pretending we have successfully disabled the device.
1689 * It's OK because the interrupt routine will discard
1690 * any data from the mouse hereafter.
1691 */
1692 log(LOG_ERR,
1693 "psm%d: failed to disable the device (psmclose).\n",
1694 sc->unit);
1695 }
1696
1697 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1698 log(LOG_DEBUG,
1699 "psm%d: failed to get status (psmclose).\n",
1700 sc->unit);
1701 }
1702
1703 if (!set_controller_command_byte(sc->kbdc,
1704 kbdc_get_device_mask(sc->kbdc),
1705 (command_byte & KBD_KBD_CONTROL_BITS) |
1706 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1707 /*
1708 * CONTROLLER ERROR;
1709 * we shall ignore this error; see the above comment.
1710 */
1711 log(LOG_ERR,
1712 "psm%d: failed to disable the aux port (psmclose).\n",
1713 sc->unit);
1714 }
1715
1716 /* remove anything left in the output buffer */
1717 empty_aux_buffer(sc->kbdc, 10);
1718
1719 /* clean up and sigio requests */
1720 if (sc->async != NULL) {
1721 funsetown(&sc->async);
1722 sc->async = NULL;
1723 }
1724
1725 /* close is almost always successful */
1726 sc->state &= ~PSM_OPEN;
1727 kbdc_lock(sc->kbdc, FALSE);
1728 device_unbusy(devclass_get_device(psm_devclass, sc->unit));
1729 return (0);
1730}
1731
1732static int
1733tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
1734 u_char *buf)
1735{
1736 static u_char butmapps2[8] = {
1737 0,
1738 MOUSE_PS2_BUTTON1DOWN,
1739 MOUSE_PS2_BUTTON2DOWN,
1740 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1741 MOUSE_PS2_BUTTON3DOWN,
1742 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1743 MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1744 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
1745 MOUSE_PS2_BUTTON3DOWN,
1746 };
1747 static u_char butmapmsc[8] = {
1748 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
1749 MOUSE_MSC_BUTTON3UP,
1750 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1751 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1752 MOUSE_MSC_BUTTON3UP,
1753 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1754 MOUSE_MSC_BUTTON2UP,
1755 MOUSE_MSC_BUTTON1UP,
1756 0,
1757 };
1758 int mapped;
1759 int i;
1760
1761 if (sc->mode.level == PSM_LEVEL_BASE) {
1762 mapped = status->button & ~MOUSE_BUTTON4DOWN;
1763 if (status->button & MOUSE_BUTTON4DOWN)
1764 mapped |= MOUSE_BUTTON1DOWN;
1765 status->button = mapped;
1766 buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1767 i = imax(imin(status->dx, 255), -256);
1768 if (i < 0)
1769 buf[0] |= MOUSE_PS2_XNEG;
1770 buf[1] = i;
1771 i = imax(imin(status->dy, 255), -256);
1772 if (i < 0)
1773 buf[0] |= MOUSE_PS2_YNEG;
1774 buf[2] = i;
1775 return (MOUSE_PS2_PACKETSIZE);
1776 } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1777 buf[0] = MOUSE_MSC_SYNC |
1778 butmapmsc[status->button & MOUSE_STDBUTTONS];
1779 i = imax(imin(status->dx, 255), -256);
1780 buf[1] = i >> 1;
1781 buf[3] = i - buf[1];
1782 i = imax(imin(status->dy, 255), -256);
1783 buf[2] = i >> 1;
1784 buf[4] = i - buf[2];
1785 i = imax(imin(status->dz, 127), -128);
1786 buf[5] = (i >> 1) & 0x7f;
1787 buf[6] = (i - (i >> 1)) & 0x7f;
1788 buf[7] = (~status->button >> 3) & 0x7f;
1789 return (MOUSE_SYS_PACKETSIZE);
1790 }
1791 return (pb->inputbytes);
1792}
1793
1794static int
1795psmread(struct cdev *dev, struct uio *uio, int flag)
1796{
1797 struct psm_softc *sc = dev->si_drv1;
1798 u_char buf[PSM_SMALLBUFSIZE];
1799 int error = 0;
1800 int s;
1801 int l;
1802
1803 if ((sc->state & PSM_VALID) == 0)
1804 return (EIO);
1805
1806 /* block until mouse activity occured */
1807 s = spltty();
1808 while (sc->queue.count <= 0) {
1809 if (dev != sc->bdev) {
1810 splx(s);
1811 return (EWOULDBLOCK);
1812 }
1813 sc->state |= PSM_ASLP;
1814 error = tsleep(sc, PZERO | PCATCH, "psmrea", 0);
1815 sc->state &= ~PSM_ASLP;
1816 if (error) {
1817 splx(s);
1818 return (error);
1819 } else if ((sc->state & PSM_VALID) == 0) {
1820 /* the device disappeared! */
1821 splx(s);
1822 return (EIO);
1823 }
1824 }
1825 splx(s);
1826
1827 /* copy data to the user land */
1828 while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1829 s = spltty();
1830 l = imin(sc->queue.count, uio->uio_resid);
1831 if (l > sizeof(buf))
1832 l = sizeof(buf);
1833 if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1834 bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1835 sizeof(sc->queue.buf) - sc->queue.head);
1836 bcopy(&sc->queue.buf[0],
1837 &buf[sizeof(sc->queue.buf) - sc->queue.head],
1838 l - (sizeof(sc->queue.buf) - sc->queue.head));
1839 } else
1840 bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1841 sc->queue.count -= l;
1842 sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1843 splx(s);
1844 error = uiomove(buf, l, uio);
1845 if (error)
1846 break;
1847 }
1848
1849 return (error);
1850}
1851
1852static int
1853block_mouse_data(struct psm_softc *sc, int *c)
1854{
1855 int s;
1856
1857 if (!kbdc_lock(sc->kbdc, TRUE))
1858 return (EIO);
1859
1860 s = spltty();
1861 *c = get_controller_command_byte(sc->kbdc);
1862 if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
1863 kbdc_get_device_mask(sc->kbdc),
1864 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1865 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1866 /* this is CONTROLLER ERROR */
1867 splx(s);
1868 kbdc_lock(sc->kbdc, FALSE);
1869 return (EIO);
1870 }
1871
1872 /*
1873 * The device may be in the middle of status data transmission.
1874 * The transmission will be interrupted, thus, incomplete status
1875 * data must be discarded. Although the aux interrupt is disabled
1876 * at the keyboard controller level, at most one aux interrupt
1877 * may have already been pending and a data byte is in the
1878 * output buffer; throw it away. Note that the second argument
1879 * to `empty_aux_buffer()' is zero, so that the call will just
1880 * flush the internal queue.
1881 * `psmintr()' will be invoked after `splx()' if an interrupt is
1882 * pending; it will see no data and returns immediately.
1883 */
1884 empty_aux_buffer(sc->kbdc, 0); /* flush the queue */
1885 read_aux_data_no_wait(sc->kbdc); /* throw away data if any */
1886 flushpackets(sc);
1887 splx(s);
1888
1889 return (0);
1890}
1891
1892static void
1893dropqueue(struct psm_softc *sc)
1894{
1895
1896 sc->queue.count = 0;
1897 sc->queue.head = 0;
1898 sc->queue.tail = 0;
1899 if ((sc->state & PSM_SOFTARMED) != 0) {
1900 sc->state &= ~PSM_SOFTARMED;
1901 callout_stop(&sc->softcallout);
1902 }
1903 sc->pqueue_start = sc->pqueue_end;
1904}
1905
1906static void
1907flushpackets(struct psm_softc *sc)
1908{
1909
1910 dropqueue(sc);
1911 bzero(&sc->pqueue, sizeof(sc->pqueue));
1912}
1913
1914static int
1915unblock_mouse_data(struct psm_softc *sc, int c)
1916{
1917 int error = 0;
1918
1919 /*
1920 * We may have seen a part of status data during `set_mouse_XXX()'.
1921 * they have been queued; flush it.
1922 */
1923 empty_aux_buffer(sc->kbdc, 0);
1924
1925 /* restore ports and interrupt */
1926 if (!set_controller_command_byte(sc->kbdc,
1927 kbdc_get_device_mask(sc->kbdc),
1928 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1929 /*
1930 * CONTROLLER ERROR; this is serious, we may have
1931 * been left with the inaccessible keyboard and
1932 * the disabled mouse interrupt.
1933 */
1934 error = EIO;
1935 }
1936
1937 kbdc_lock(sc->kbdc, FALSE);
1938 return (error);
1939}
1940
1941static int
1942psmwrite(struct cdev *dev, struct uio *uio, int flag)
1943{
1944 struct psm_softc *sc = dev->si_drv1;
1945 u_char buf[PSM_SMALLBUFSIZE];
1946 int error = 0, i, l;
1947
1948 if ((sc->state & PSM_VALID) == 0)
1949 return (EIO);
1950
1951 if (sc->mode.level < PSM_LEVEL_NATIVE)
1952 return (ENODEV);
1953
1954 /* copy data from the user land */
1955 while (uio->uio_resid > 0) {
1956 l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
1957 error = uiomove(buf, l, uio);
1958 if (error)
1959 break;
1960 for (i = 0; i < l; i++) {
1961 VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
1962 if (!write_aux_command(sc->kbdc, buf[i])) {
1963 VLOG(2, (LOG_DEBUG,
1964 "psm: cmd 0x%x failed.\n", buf[i]));
1965 return (reinitialize(sc, FALSE));
1966 }
1967 }
1968 }
1969
1970 return (error);
1971}
1972
1973static int
1974psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
1975 struct thread *td)
1976{
1977 struct psm_softc *sc = dev->si_drv1;
1978 mousemode_t mode;
1979 mousestatus_t status;
1980#if (defined(MOUSE_GETVARS))
1981 mousevar_t *var;
1982#endif
1983 mousedata_t *data;
1984 int stat[3];
1985 int command_byte;
1986 int error = 0;
1987 int s;
1988
1989 /* Perform IOCTL command */
1990 switch (cmd) {
1991
1992 case OLD_MOUSE_GETHWINFO:
1993 s = spltty();
1994 ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
1995 ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
1996 ((old_mousehw_t *)addr)->type = sc->hw.type;
1997 ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
1998 splx(s);
1999 break;
2000
2001 case MOUSE_GETHWINFO:
2002 s = spltty();
2003 *(mousehw_t *)addr = sc->hw;
2004 if (sc->mode.level == PSM_LEVEL_BASE)
2005 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
2006 splx(s);
2007 break;
2008
2009 case MOUSE_SYN_GETHWINFO:
2010 s = spltty();
2011 if (sc->synhw.infoMajor >= 4)
2012 *(synapticshw_t *)addr = sc->synhw;
2013 else
2014 error = EINVAL;
2015 splx(s);
2016 break;
2017
2018 case OLD_MOUSE_GETMODE:
2019 s = spltty();
2020 switch (sc->mode.level) {
2021 case PSM_LEVEL_BASE:
2022 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2023 break;
2024 case PSM_LEVEL_STANDARD:
2025 ((old_mousemode_t *)addr)->protocol =
2026 MOUSE_PROTO_SYSMOUSE;
2027 break;
2028 case PSM_LEVEL_NATIVE:
2029 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2030 break;
2031 }
2032 ((old_mousemode_t *)addr)->rate = sc->mode.rate;
2033 ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
2034 ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
2035 splx(s);
2036 break;
2037
2038 case MOUSE_GETMODE:
2039 s = spltty();
2040 *(mousemode_t *)addr = sc->mode;
2041 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2042 ((mousemode_t *)addr)->syncmask[0] = 0;
2043 ((mousemode_t *)addr)->syncmask[1] = 0;
2044 }
2045 ((mousemode_t *)addr)->resolution =
2046 MOUSE_RES_LOW - sc->mode.resolution;
2047 switch (sc->mode.level) {
2048 case PSM_LEVEL_BASE:
2049 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2050 ((mousemode_t *)addr)->packetsize =
2051 MOUSE_PS2_PACKETSIZE;
2052 break;
2053 case PSM_LEVEL_STANDARD:
2054 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
2055 ((mousemode_t *)addr)->packetsize =
2056 MOUSE_SYS_PACKETSIZE;
2057 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
2058 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
2059 break;
2060 case PSM_LEVEL_NATIVE:
2061 /* FIXME: this isn't quite correct... XXX */
2062 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2063 break;
2064 }
2065 splx(s);
2066 break;
2067
2068 case OLD_MOUSE_SETMODE:
2069 case MOUSE_SETMODE:
2070 if (cmd == OLD_MOUSE_SETMODE) {
2071 mode.rate = ((old_mousemode_t *)addr)->rate;
2072 /*
2073 * resolution old I/F new I/F
2074 * default 0 0
2075 * low 1 -2
2076 * medium low 2 -3
2077 * medium high 3 -4
2078 * high 4 -5
2079 */
2080 if (((old_mousemode_t *)addr)->resolution > 0)
2081 mode.resolution =
2082 -((old_mousemode_t *)addr)->resolution - 1;
2083 else
2084 mode.resolution = 0;
2085 mode.accelfactor =
2086 ((old_mousemode_t *)addr)->accelfactor;
2087 mode.level = -1;
2088 } else
2089 mode = *(mousemode_t *)addr;
2090
2091 /* adjust and validate parameters. */
2092 if (mode.rate > UCHAR_MAX)
2093 return (EINVAL);
2094 if (mode.rate == 0)
2095 mode.rate = sc->dflt_mode.rate;
2096 else if (mode.rate == -1)
2097 /* don't change the current setting */
2098 ;
2099 else if (mode.rate < 0)
2100 return (EINVAL);
2101 if (mode.resolution >= UCHAR_MAX)
2102 return (EINVAL);
2103 if (mode.resolution >= 200)
2104 mode.resolution = MOUSE_RES_HIGH;
2105 else if (mode.resolution >= 100)
2106 mode.resolution = MOUSE_RES_MEDIUMHIGH;
2107 else if (mode.resolution >= 50)
2108 mode.resolution = MOUSE_RES_MEDIUMLOW;
2109 else if (mode.resolution > 0)
2110 mode.resolution = MOUSE_RES_LOW;
2111 if (mode.resolution == MOUSE_RES_DEFAULT)
2112 mode.resolution = sc->dflt_mode.resolution;
2113 else if (mode.resolution == -1)
2114 /* don't change the current setting */
2115 ;
2116 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2117 mode.resolution = MOUSE_RES_LOW - mode.resolution;
2118 if (mode.level == -1)
2119 /* don't change the current setting */
2120 mode.level = sc->mode.level;
2121 else if ((mode.level < PSM_LEVEL_MIN) ||
2122 (mode.level > PSM_LEVEL_MAX))
2123 return (EINVAL);
2124 if (mode.accelfactor == -1)
2125 /* don't change the current setting */
2126 mode.accelfactor = sc->mode.accelfactor;
2127 else if (mode.accelfactor < 0)
2128 return (EINVAL);
2129
2130 /* don't allow anybody to poll the keyboard controller */
2131 error = block_mouse_data(sc, &command_byte);
2132 if (error)
2133 return (error);
2134
2135 /* set mouse parameters */
2136 if (mode.rate > 0)
2137 mode.rate = set_mouse_sampling_rate(sc->kbdc,
2138 mode.rate);
2139 if (mode.resolution >= 0)
2140 mode.resolution =
2141 set_mouse_resolution(sc->kbdc, mode.resolution);
2142 set_mouse_scaling(sc->kbdc, 1);
2143 get_mouse_status(sc->kbdc, stat, 0, 3);
2144
2145 s = spltty();
2146 sc->mode.rate = mode.rate;
2147 sc->mode.resolution = mode.resolution;
2148 sc->mode.accelfactor = mode.accelfactor;
2149 sc->mode.level = mode.level;
2150 splx(s);
2151
2152 unblock_mouse_data(sc, command_byte);
2153 break;
2154
2155 case MOUSE_GETLEVEL:
2156 *(int *)addr = sc->mode.level;
2157 break;
2158
2159 case MOUSE_SETLEVEL:
2160 if ((*(int *)addr < PSM_LEVEL_MIN) ||
2161 (*(int *)addr > PSM_LEVEL_MAX))
2162 return (EINVAL);
2163 sc->mode.level = *(int *)addr;
2164 break;
2165
2166 case MOUSE_GETSTATUS:
2167 s = spltty();
2168 status = sc->status;
2169 sc->status.flags = 0;
2170 sc->status.obutton = sc->status.button;
2171 sc->status.button = 0;
2172 sc->status.dx = 0;
2173 sc->status.dy = 0;
2174 sc->status.dz = 0;
2175 splx(s);
2176 *(mousestatus_t *)addr = status;
2177 break;
2178
2179#if (defined(MOUSE_GETVARS))
2180 case MOUSE_GETVARS:
2181 var = (mousevar_t *)addr;
2182 bzero(var, sizeof(*var));
2183 s = spltty();
2184 var->var[0] = MOUSE_VARS_PS2_SIG;
2185 var->var[1] = sc->config;
2186 var->var[2] = sc->flags;
2187 splx(s);
2188 break;
2189
2190 case MOUSE_SETVARS:
2191 return (ENODEV);
2192#endif /* MOUSE_GETVARS */
2193
2194 case MOUSE_READSTATE:
2195 case MOUSE_READDATA:
2196 data = (mousedata_t *)addr;
2197 if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
2198 return (EINVAL);
2199
2200 error = block_mouse_data(sc, &command_byte);
2201 if (error)
2202 return (error);
2203 if ((data->len = get_mouse_status(sc->kbdc, data->buf,
2204 (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
2205 error = EIO;
2206 unblock_mouse_data(sc, command_byte);
2207 break;
2208
2209#if (defined(MOUSE_SETRESOLUTION))
2210 case MOUSE_SETRESOLUTION:
2211 mode.resolution = *(int *)addr;
2212 if (mode.resolution >= UCHAR_MAX)
2213 return (EINVAL);
2214 else if (mode.resolution >= 200)
2215 mode.resolution = MOUSE_RES_HIGH;
2216 else if (mode.resolution >= 100)
2217 mode.resolution = MOUSE_RES_MEDIUMHIGH;
2218 else if (mode.resolution >= 50)
2219 mode.resolution = MOUSE_RES_MEDIUMLOW;
2220 else if (mode.resolution > 0)
2221 mode.resolution = MOUSE_RES_LOW;
2222 if (mode.resolution == MOUSE_RES_DEFAULT)
2223 mode.resolution = sc->dflt_mode.resolution;
2224 else if (mode.resolution == -1)
2225 mode.resolution = sc->mode.resolution;
2226 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2227 mode.resolution = MOUSE_RES_LOW - mode.resolution;
2228
2229 error = block_mouse_data(sc, &command_byte);
2230 if (error)
2231 return (error);
2232 sc->mode.resolution =
2233 set_mouse_resolution(sc->kbdc, mode.resolution);
2234 if (sc->mode.resolution != mode.resolution)
2235 error = EIO;
2236 unblock_mouse_data(sc, command_byte);
2237 break;
2238#endif /* MOUSE_SETRESOLUTION */
2239
2240#if (defined(MOUSE_SETRATE))
2241 case MOUSE_SETRATE:
2242 mode.rate = *(int *)addr;
2243 if (mode.rate > UCHAR_MAX)
2244 return (EINVAL);
2245 if (mode.rate == 0)
2246 mode.rate = sc->dflt_mode.rate;
2247 else if (mode.rate < 0)
2248 mode.rate = sc->mode.rate;
2249
2250 error = block_mouse_data(sc, &command_byte);
2251 if (error)
2252 return (error);
2253 sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
2254 if (sc->mode.rate != mode.rate)
2255 error = EIO;
2256 unblock_mouse_data(sc, command_byte);
2257 break;
2258#endif /* MOUSE_SETRATE */
2259
2260#if (defined(MOUSE_SETSCALING))
2261 case MOUSE_SETSCALING:
2262 if ((*(int *)addr <= 0) || (*(int *)addr > 2))
2263 return (EINVAL);
2264
2265 error = block_mouse_data(sc, &command_byte);
2266 if (error)
2267 return (error);
2268 if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
2269 error = EIO;
2270 unblock_mouse_data(sc, command_byte);
2271 break;
2272#endif /* MOUSE_SETSCALING */
2273
2274#if (defined(MOUSE_GETHWID))
2275 case MOUSE_GETHWID:
2276 error = block_mouse_data(sc, &command_byte);
2277 if (error)
2278 return (error);
2279 sc->hw.hwid &= ~0x00ff;
2280 sc->hw.hwid |= get_aux_id(sc->kbdc);
2281 *(int *)addr = sc->hw.hwid & 0x00ff;
2282 unblock_mouse_data(sc, command_byte);
2283 break;
2284#endif /* MOUSE_GETHWID */
2285
2286 case FIONBIO:
2287 case FIOASYNC:
2288 break;
2289 case FIOSETOWN:
2290 error = fsetown(*(int *)addr, &sc->async);
2291 break;
2292 case FIOGETOWN:
2293 *(int *) addr = fgetown(&sc->async);
2294 break;
2295 default:
2296 return (ENOTTY);
2297 }
2298
2299 return (error);
2300}
2301
2302static void
2303psmtimeout(void *arg)
2304{
2305 struct psm_softc *sc;
2306 int s;
2307
2308 sc = (struct psm_softc *)arg;
2309 s = spltty();
2310 if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
2311 VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
2312 psmintr(sc);
2313 kbdc_lock(sc->kbdc, FALSE);
2314 }
2315 sc->watchdog = TRUE;
2316 splx(s);
2317 callout_reset(&sc->callout, hz, psmtimeout, sc);
2318}
2319
2320/* Add all sysctls under the debug.psm and hw.psm nodes */
2321static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2322static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2323
2324SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
2325 "Verbosity level");
2326
2327static int psmhz = 20;
2328SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0,
2329 "Frequency of the softcallout (in hz)");
2330static int psmerrsecs = 2;
2331SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0,
2332 "Number of seconds during which packets will dropped after a sync error");
2333static int psmerrusecs = 0;
2334SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0,
2335 "Microseconds to add to psmerrsecs");
2336static int psmsecs = 0;
2337SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0,
2338 "Max number of seconds between soft interrupts");
2339static int psmusecs = 500000;
2340SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0,
2341 "Microseconds to add to psmsecs");
2342static int pkterrthresh = 2;
2343SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
2344 "Number of error packets allowed before reinitializing the mouse");
2345
2346SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
2347 "Enable tap and drag gestures");
2348static int tap_threshold = PSM_TAP_THRESHOLD;
2349SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
2350 "Button tap threshold");
2351static int tap_timeout = PSM_TAP_TIMEOUT;
2352SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
2353 "Tap timeout for touchpads");
2354
2355static void
2356psmintr(void *arg)
2357{
2358 struct psm_softc *sc = arg;
2359 struct timeval now;
2360 int c;
2361 packetbuf_t *pb;
2362
2363
2364 /* read until there is nothing to read */
2365 while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
2366 pb = &sc->pqueue[sc->pqueue_end];
2367
2368 /* discard the byte if the device is not open */
2369 if ((sc->state & PSM_OPEN) == 0)
2370 continue;
2371
2372 getmicrouptime(&now);
2373 if ((pb->inputbytes > 0) &&
2374 timevalcmp(&now, &sc->inputtimeout, >)) {
2375 VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
2376 "resetting byte count\n"));
2377 pb->inputbytes = 0;
2378 sc->syncerrors = 0;
2379 sc->pkterrors = 0;
2380 }
2381 sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
2382 sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
2383 timevaladd(&sc->inputtimeout, &now);
2384
2385 pb->ipacket[pb->inputbytes++] = c;
2386
2387 if (sc->mode.level == PSM_LEVEL_NATIVE) {
2388 VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
2389 sc->syncerrors = 0;
2390 sc->pkterrors = 0;
2391 goto next;
2392 } else {
2393 if (pb->inputbytes < sc->mode.packetsize)
2394 continue;
2395
2396 VLOG(4, (LOG_DEBUG,
2397 "psmintr: %02x %02x %02x %02x %02x %02x\n",
2398 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
2399 pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
2400 }
2401
2402 c = pb->ipacket[0];
2403
2404 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2405 sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
2406 sc->flags &= ~PSM_NEED_SYNCBITS;
2407 VLOG(2, (LOG_DEBUG,
2408 "psmintr: Sync bytes now %04x,%04x\n",
2409 sc->mode.syncmask[0], sc->mode.syncmask[0]));
2410 } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
2411 VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
2412 "(%04x != %04x) %d cmds since last error.\n",
2413 c & sc->mode.syncmask[0], sc->mode.syncmask[1],
2414 sc->cmdcount - sc->lasterr));
2415 sc->lasterr = sc->cmdcount;
2416 /*
2417 * The sync byte test is a weak measure of packet
2418 * validity. Conservatively discard any input yet
2419 * to be seen by userland when we detect a sync
2420 * error since there is a good chance some of
2421 * the queued packets have undetected errors.
2422 */
2423 dropqueue(sc);
2424 if (sc->syncerrors == 0)
2425 sc->pkterrors++;
2426 ++sc->syncerrors;
2427 sc->lastinputerr = now;
2428 if (sc->syncerrors >= sc->mode.packetsize * 2 ||
2429 sc->pkterrors >= pkterrthresh) {
2430 /*
2431 * If we've failed to find a single sync byte
2432 * in 2 packets worth of data, or we've seen
2433 * persistent packet errors during the
2434 * validation period, reinitialize the mouse
2435 * in hopes of returning it to the expected
2436 * mode.
2437 */
2438 VLOG(3, (LOG_DEBUG,
2439 "psmintr: reset the mouse.\n"));
2440 reinitialize(sc, TRUE);
2441 } else if (sc->syncerrors == sc->mode.packetsize) {
2442 /*
2443 * Try a soft reset after searching for a sync
2444 * byte through a packet length of bytes.
2445 */
2446 VLOG(3, (LOG_DEBUG,
2447 "psmintr: re-enable the mouse.\n"));
2448 pb->inputbytes = 0;
2449 disable_aux_dev(sc->kbdc);
2450 enable_aux_dev(sc->kbdc);
2451 } else {
2452 VLOG(3, (LOG_DEBUG,
2453 "psmintr: discard a byte (%d)\n",
2454 sc->syncerrors));
2455 pb->inputbytes--;
2456 bcopy(&pb->ipacket[1], &pb->ipacket[0],
2457 pb->inputbytes);
2458 }
2459 continue;
2460 }
2461
2462 /*
2463 * We have what appears to be a valid packet.
2464 * Reset the error counters.
2465 */
2466 sc->syncerrors = 0;
2467
2468 /*
2469 * Drop even good packets if they occur within a timeout
2470 * period of a sync error. This allows the detection of
2471 * a change in the mouse's packet mode without exposing
2472 * erratic mouse behavior to the user. Some KVMs forget
2473 * enhanced mouse modes during switch events.
2474 */
2475 if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
2476 &now)) {
2477 pb->inputbytes = 0;
2478 continue;
2479 }
2480
2481 /*
2482 * Now that we're out of the validation period, reset
2483 * the packet error count.
2484 */
2485 sc->pkterrors = 0;
2486
2487 sc->cmdcount++;
2488next:
2489 if (++sc->pqueue_end >= PSM_PACKETQUEUE)
2490 sc->pqueue_end = 0;
2491 /*
2492 * If we've filled the queue then call the softintr ourselves,
2493 * otherwise schedule the interrupt for later.
2494 */
2495 if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
2496 (sc->pqueue_end == sc->pqueue_start)) {
2497 if ((sc->state & PSM_SOFTARMED) != 0) {
2498 sc->state &= ~PSM_SOFTARMED;
2499 callout_stop(&sc->softcallout);
2500 }
2501 psmsoftintr(arg);
2502 } else if ((sc->state & PSM_SOFTARMED) == 0) {
2503 sc->state |= PSM_SOFTARMED;
2504 callout_reset(&sc->softcallout,
2505 psmhz < 1 ? 1 : (hz/psmhz), psmsoftintr, arg);
2506 }
2507 }
2508}
2509
2510static void
2511proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2512 int *x, int *y, int *z)
2513{
2514
2515 /*
2516 * PS2++ protocol packet
2517 *
2518 * b7 b6 b5 b4 b3 b2 b1 b0
2519 * byte 1: * 1 p3 p2 1 * * *
2520 * byte 2: c1 c2 p1 p0 d1 d0 1 0
2521 *
2522 * p3-p0: packet type
2523 * c1, c2: c1 & c2 == 1, if p2 == 0
2524 * c1 & c2 == 0, if p2 == 1
2525 *
2526 * packet type: 0 (device type)
2527 * See comments in enable_mmanplus() below.
2528 *
2529 * packet type: 1 (wheel data)
2530 *
2531 * b7 b6 b5 b4 b3 b2 b1 b0
2532 * byte 3: h * B5 B4 s d2 d1 d0
2533 *
2534 * h: 1, if horizontal roller data
2535 * 0, if vertical roller data
2536 * B4, B5: button 4 and 5
2537 * s: sign bit
2538 * d2-d0: roller data
2539 *
2540 * packet type: 2 (reserved)
2541 */
2542 if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
2543 (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
2544 /*
2545 * the extended data packet encodes button
2546 * and wheel events
2547 */
2548 switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
2549 case 1:
2550 /* wheel data packet */
2551 *x = *y = 0;
2552 if (pb->ipacket[2] & 0x80) {
2553 /* XXX horizontal roller count - ignore it */
2554 ;
2555 } else {
2556 /* vertical roller count */
2557 *z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
2558 (pb->ipacket[2] & 0x0f) - 16 :
2559 (pb->ipacket[2] & 0x0f);
2560 }
2561 ms->button |= (pb->ipacket[2] &
2562 MOUSE_PS2PLUS_BUTTON4DOWN) ?
2563 MOUSE_BUTTON4DOWN : 0;
2564 ms->button |= (pb->ipacket[2] &
2565 MOUSE_PS2PLUS_BUTTON5DOWN) ?
2566 MOUSE_BUTTON5DOWN : 0;
2567 break;
2568 case 2:
2569 /*
2570 * this packet type is reserved by
2571 * Logitech...
2572 */
2573 /*
2574 * IBM ScrollPoint Mouse uses this
2575 * packet type to encode both vertical
2576 * and horizontal scroll movement.
2577 */
2578 *x = *y = 0;
2579 /* horizontal count */
2580 if (pb->ipacket[2] & 0x0f)
2581 *z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
2582 -2 : 2;
2583 /* vertical count */
2584 if (pb->ipacket[2] & 0xf0)
2585 *z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
2586 -1 : 1;
2587 break;
2588 case 0:
2589 /* device type packet - shouldn't happen */
2590 /* FALLTHROUGH */
2591 default:
2592 *x = *y = 0;
2593 ms->button = ms->obutton;
2594 VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
2595 "type %d: 0x%02x 0x%02x 0x%02x\n",
2596 MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
2597 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
2598 break;
2599 }
2600 } else {
2601 /* preserve button states */
2602 ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
2603 }
2604}
2605
2606static int
2607proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2608 int *x, int *y, int *z)
2609{
2610 static int touchpad_buttons;
2611 static int guest_buttons;
2612 int w, x0, y0;
2613
2614 /* TouchPad PS/2 absolute mode message format with capFourButtons:
2615 *
2616 * Bits: 7 6 5 4 3 2 1 0 (LSB)
2617 * ------------------------------------------------
2618 * ipacket[0]: 1 0 W3 W2 0 W1 R L
2619 * ipacket[1]: Yb Ya Y9 Y8 Xb Xa X9 X8
2620 * ipacket[2]: Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
2621 * ipacket[3]: 1 1 Yc Xc 0 W0 D^R U^L
2622 * ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0
2623 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
2624 *
2625 * Legend:
2626 * L: left physical mouse button
2627 * R: right physical mouse button
2628 * D: down button
2629 * U: up button
2630 * W: "wrist" value
2631 * X: x position
2632 * Y: y position
2633 * Z: pressure
2634 *
2635 * Without capFourButtons but with nExtendeButtons and/or capMiddle
2636 *
2637 * Bits: 7 6 5 4 3 2 1 0 (LSB)
2638 * ------------------------------------------------------
2639 * ipacket[3]: 1 1 Yc Xc 0 W0 E^R M^L
2640 * ipacket[4]: X7 X6 X5 X4 X3|b7 X2|b5 X1|b3 X0|b1
2641 * ipacket[5]: Y7 Y6 Y5 Y4 Y3|b8 Y2|b6 Y1|b4 Y0|b2
2642 *
2643 * Legend:
2644 * M: Middle physical mouse button
2645 * E: Extended mouse buttons reported instead of low bits of X and Y
2646 * b1-b8: Extended mouse buttons
2647 * Only ((nExtendedButtons + 1) >> 1) bits are used in packet
2648 * 4 and 5, for reading X and Y value they should be zeroed.
2649 *
2650 * Absolute reportable limits: 0 - 6143.
2651 * Typical bezel limits: 1472 - 5472.
2652 * Typical edge marings: 1632 - 5312.
2653 *
2654 * w = 3 Passthrough Packet
2655 *
2656 * Byte 2,5,6 == Byte 1,2,3 of "Guest"
2657 */
2658
2659 if (!synaptics_support)
2660 return (0);
2661
2662 /* Sanity check for out of sync packets. */
2663 if ((pb->ipacket[0] & 0xc8) != 0x80 ||
2664 (pb->ipacket[3] & 0xc8) != 0xc0)
2665 return (-1);
2666
2667 *x = *y = 0;
2668
2669 /*
2670 * Pressure value.
2671 * Interpretation:
2672 * z = 0 No finger contact
2673 * z = 10 Finger hovering near the pad
2674 * z = 30 Very light finger contact
2675 * z = 80 Normal finger contact
2676 * z = 110 Very heavy finger contact
2677 * z = 200 Finger lying flat on pad surface
2678 * z = 255 Maximum reportable Z
2679 */
2680 *z = pb->ipacket[2];
2681
2682 /*
2683 * Finger width value
2684 * Interpretation:
2685 * w = 0 Two finger on the pad (capMultiFinger needed)
2686 * w = 1 Three or more fingers (capMultiFinger needed)
2687 * w = 2 Pen (instead of finger) (capPen needed)
2688 * w = 3 Reserved (passthrough?)
2689 * w = 4-7 Finger of normal width (capPalmDetect needed)
2690 * w = 8-14 Very wide finger or palm (capPalmDetect needed)
2691 * w = 15 Maximum reportable width (capPalmDetect needed)
2692 */
2693 /* XXX Is checking capExtended enough? */
2694 if (sc->synhw.capExtended)
2695 w = ((pb->ipacket[0] & 0x30) >> 2) |
2696 ((pb->ipacket[0] & 0x04) >> 1) |
2697 ((pb->ipacket[3] & 0x04) >> 2);
2698 else {
2699 /* Assume a finger of regular width. */
2700 w = 4;
2701 }
2702
2703 /*
2704 * Handle packets from the guest device. See:
2705 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
2706 */
2707 if (w == 3 && sc->synhw.capPassthrough) {
2708 *x = ((pb->ipacket[1] & 0x10) ?
2709 pb->ipacket[4] - 256 : pb->ipacket[4]);
2710 *y = ((pb->ipacket[1] & 0x20) ?
2711 pb->ipacket[5] - 256 : pb->ipacket[5]);
2712 *z = 0;
2713
2714 guest_buttons = 0;
2715 if (pb->ipacket[1] & 0x01)
2716 guest_buttons |= MOUSE_BUTTON1DOWN;
2717 if (pb->ipacket[1] & 0x04)
2718 guest_buttons |= MOUSE_BUTTON2DOWN;
2719 if (pb->ipacket[1] & 0x02)
2720 guest_buttons |= MOUSE_BUTTON3DOWN;
2721
2722 ms->button = touchpad_buttons | guest_buttons;
2723 goto SYNAPTICS_END;
2724 }
2725
2726 /* Button presses */
2727 touchpad_buttons = 0;
2728 if (pb->ipacket[0] & 0x01)
2729 touchpad_buttons |= MOUSE_BUTTON1DOWN;
2730 if (pb->ipacket[0] & 0x02)
2731 touchpad_buttons |= MOUSE_BUTTON3DOWN;
2732
2733 if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
2734 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01)
2735 touchpad_buttons |= MOUSE_BUTTON4DOWN;
2736 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
2737 touchpad_buttons |= MOUSE_BUTTON5DOWN;
2738 } else if (sc->synhw.capExtended && sc->synhw.capMiddle) {
2739 /* Middle Button */
2740 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2741 touchpad_buttons |= MOUSE_BUTTON2DOWN;
2742 } else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
2743 /* Extended Buttons */
2744 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
2745 if (sc->syninfo.directional_scrolls) {
2746 if (pb->ipacket[4] & 0x01)
2747 touchpad_buttons |= MOUSE_BUTTON4DOWN;
2748 if (pb->ipacket[5] & 0x01)
2749 touchpad_buttons |= MOUSE_BUTTON5DOWN;
2750 if (pb->ipacket[4] & 0x02)
2751 touchpad_buttons |= MOUSE_BUTTON6DOWN;
2752 if (pb->ipacket[5] & 0x02)
2753 touchpad_buttons |= MOUSE_BUTTON7DOWN;
2754 } else {
341};
342static devclass_t psm_devclass;
343
344/* driver state flags (state) */
345#define PSM_VALID 0x80
346#define PSM_OPEN 1 /* Device is open */
347#define PSM_ASLP 2 /* Waiting for mouse data */
348#define PSM_SOFTARMED 4 /* Software interrupt armed */
349#define PSM_NEED_SYNCBITS 8 /* Set syncbits using next data pkt */
350
351/* driver configuration flags (config) */
352#define PSM_CONFIG_RESOLUTION 0x000f /* resolution */
353#define PSM_CONFIG_ACCEL 0x00f0 /* acceleration factor */
354#define PSM_CONFIG_NOCHECKSYNC 0x0100 /* disable sync. test */
355#define PSM_CONFIG_NOIDPROBE 0x0200 /* disable mouse model probe */
356#define PSM_CONFIG_NORESET 0x0400 /* don't reset the mouse */
357#define PSM_CONFIG_FORCETAP 0x0800 /* assume `tap' action exists */
358#define PSM_CONFIG_IGNPORTERROR 0x1000 /* ignore error in aux port test */
359#define PSM_CONFIG_HOOKRESUME 0x2000 /* hook the system resume event */
360#define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
361
362#define PSM_CONFIG_FLAGS \
363 (PSM_CONFIG_RESOLUTION | \
364 PSM_CONFIG_ACCEL | \
365 PSM_CONFIG_NOCHECKSYNC | \
366 PSM_CONFIG_NOIDPROBE | \
367 PSM_CONFIG_NORESET | \
368 PSM_CONFIG_FORCETAP | \
369 PSM_CONFIG_IGNPORTERROR | \
370 PSM_CONFIG_HOOKRESUME | \
371 PSM_CONFIG_INITAFTERSUSPEND)
372
373/* other flags (flags) */
374#define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */
375
376#define kbdcp(p) ((atkbdc_softc_t *)(p))
377#define ALWAYS_RESTORE_CONTROLLER(kbdc) !(kbdcp(kbdc)->quirks \
378 & KBDC_QUIRK_KEEP_ACTIVATED)
379
380/* Tunables */
381static int tap_enabled = -1;
382TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
383
384static int synaptics_support = 0;
385TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
386
387static int trackpoint_support = 0;
388TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
389
390static int verbose = PSM_DEBUG;
391TUNABLE_INT("debug.psm.loglevel", &verbose);
392
393/* for backward compatibility */
394#define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t)
395#define OLD_MOUSE_GETMODE _IOR('M', 2, old_mousemode_t)
396#define OLD_MOUSE_SETMODE _IOW('M', 3, old_mousemode_t)
397
398typedef struct old_mousehw {
399 int buttons;
400 int iftype;
401 int type;
402 int hwid;
403} old_mousehw_t;
404
405typedef struct old_mousemode {
406 int protocol;
407 int rate;
408 int resolution;
409 int accelfactor;
410} old_mousemode_t;
411
412/* packet formatting function */
413typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int,
414 mousestatus_t *);
415
416/* function prototypes */
417static void psmidentify(driver_t *, device_t);
418static int psmprobe(device_t);
419static int psmattach(device_t);
420static int psmdetach(device_t);
421static int psmresume(device_t);
422
423static d_open_t psmopen;
424static d_close_t psmclose;
425static d_read_t psmread;
426static d_write_t psmwrite;
427static d_ioctl_t psmioctl;
428static d_poll_t psmpoll;
429
430static int enable_aux_dev(KBDC);
431static int disable_aux_dev(KBDC);
432static int get_mouse_status(KBDC, int *, int, int);
433static int get_aux_id(KBDC);
434static int set_mouse_sampling_rate(KBDC, int);
435static int set_mouse_scaling(KBDC, int);
436static int set_mouse_resolution(KBDC, int);
437static int set_mouse_mode(KBDC);
438static int get_mouse_buttons(KBDC);
439static int is_a_mouse(int);
440static void recover_from_error(KBDC);
441static int restore_controller(KBDC, int);
442static int doinitialize(struct psm_softc *, mousemode_t *);
443static int doopen(struct psm_softc *, int);
444static int reinitialize(struct psm_softc *, int);
445static char *model_name(int);
446static void psmsoftintr(void *);
447static void psmintr(void *);
448static void psmtimeout(void *);
449static int timeelapsed(const struct timeval *, int, int,
450 const struct timeval *);
451static void dropqueue(struct psm_softc *);
452static void flushpackets(struct psm_softc *);
453static void proc_mmanplus(struct psm_softc *, packetbuf_t *,
454 mousestatus_t *, int *, int *, int *);
455static int proc_synaptics(struct psm_softc *, packetbuf_t *,
456 mousestatus_t *, int *, int *, int *);
457static void proc_versapad(struct psm_softc *, packetbuf_t *,
458 mousestatus_t *, int *, int *, int *);
459static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
460 u_char *);
461
462/* vendor specific features */
463typedef int probefunc_t(KBDC, struct psm_softc *);
464
465static int mouse_id_proc1(KBDC, int, int, int *);
466static int mouse_ext_command(KBDC, int);
467
468static probefunc_t enable_groller;
469static probefunc_t enable_gmouse;
470static probefunc_t enable_aglide;
471static probefunc_t enable_kmouse;
472static probefunc_t enable_msexplorer;
473static probefunc_t enable_msintelli;
474static probefunc_t enable_4dmouse;
475static probefunc_t enable_4dplus;
476static probefunc_t enable_mmanplus;
477static probefunc_t enable_synaptics;
478static probefunc_t enable_trackpoint;
479static probefunc_t enable_versapad;
480
481static struct {
482 int model;
483 u_char syncmask;
484 int packetsize;
485 probefunc_t *probefunc;
486} vendortype[] = {
487 /*
488 * WARNING: the order of probe is very important. Don't mess it
489 * unless you know what you are doing.
490 */
491 { MOUSE_MODEL_NET, /* Genius NetMouse */
492 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
493 { MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */
494 0xc8, 6, enable_groller },
495 { MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */
496 0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
497 { MOUSE_MODEL_EXPLORER, /* Microsoft IntelliMouse Explorer */
498 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
499 { MOUSE_MODEL_4D, /* A4 Tech 4D Mouse */
500 0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
501 { MOUSE_MODEL_4DPLUS, /* A4 Tech 4D+ Mouse */
502 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
503 { MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */
504 0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
505 { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
506 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
507 { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
508 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
509 { MOUSE_MODEL_THINK, /* Kensington ThinkingMouse */
510 0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
511 { MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */
512 0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
513 { MOUSE_MODEL_TRACKPOINT, /* IBM/Lenovo TrackPoint */
514 0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint },
515 { MOUSE_MODEL_GENERIC,
516 0xc0, MOUSE_PS2_PACKETSIZE, NULL },
517};
518#define GENERIC_MOUSE_ENTRY \
519 ((sizeof(vendortype) / sizeof(*vendortype)) - 1)
520
521/* device driver declarateion */
522static device_method_t psm_methods[] = {
523 /* Device interface */
524 DEVMETHOD(device_identify, psmidentify),
525 DEVMETHOD(device_probe, psmprobe),
526 DEVMETHOD(device_attach, psmattach),
527 DEVMETHOD(device_detach, psmdetach),
528 DEVMETHOD(device_resume, psmresume),
529
530 { 0, 0 }
531};
532
533static driver_t psm_driver = {
534 PSM_DRIVER_NAME,
535 psm_methods,
536 sizeof(struct psm_softc),
537};
538
539static struct cdevsw psm_cdevsw = {
540 .d_version = D_VERSION,
541 .d_flags = D_NEEDGIANT,
542 .d_open = psmopen,
543 .d_close = psmclose,
544 .d_read = psmread,
545 .d_write = psmwrite,
546 .d_ioctl = psmioctl,
547 .d_poll = psmpoll,
548 .d_name = PSM_DRIVER_NAME,
549};
550
551/* device I/O routines */
552static int
553enable_aux_dev(KBDC kbdc)
554{
555 int res;
556
557 res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
558 VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
559
560 return (res == PSM_ACK);
561}
562
563static int
564disable_aux_dev(KBDC kbdc)
565{
566 int res;
567
568 res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
569 VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
570
571 return (res == PSM_ACK);
572}
573
574static int
575get_mouse_status(KBDC kbdc, int *status, int flag, int len)
576{
577 int cmd;
578 int res;
579 int i;
580
581 switch (flag) {
582 case 0:
583 default:
584 cmd = PSMC_SEND_DEV_STATUS;
585 break;
586 case 1:
587 cmd = PSMC_SEND_DEV_DATA;
588 break;
589 }
590 empty_aux_buffer(kbdc, 5);
591 res = send_aux_command(kbdc, cmd);
592 VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
593 (flag == 1) ? "DATA" : "STATUS", res));
594 if (res != PSM_ACK)
595 return (0);
596
597 for (i = 0; i < len; ++i) {
598 status[i] = read_aux_data(kbdc);
599 if (status[i] < 0)
600 break;
601 }
602
603 VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
604 (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
605
606 return (i);
607}
608
609static int
610get_aux_id(KBDC kbdc)
611{
612 int res;
613 int id;
614
615 empty_aux_buffer(kbdc, 5);
616 res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
617 VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
618 if (res != PSM_ACK)
619 return (-1);
620
621 /* 10ms delay */
622 DELAY(10000);
623
624 id = read_aux_data(kbdc);
625 VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
626
627 return (id);
628}
629
630static int
631set_mouse_sampling_rate(KBDC kbdc, int rate)
632{
633 int res;
634
635 res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
636 VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
637
638 return ((res == PSM_ACK) ? rate : -1);
639}
640
641static int
642set_mouse_scaling(KBDC kbdc, int scale)
643{
644 int res;
645
646 switch (scale) {
647 case 1:
648 default:
649 scale = PSMC_SET_SCALING11;
650 break;
651 case 2:
652 scale = PSMC_SET_SCALING21;
653 break;
654 }
655 res = send_aux_command(kbdc, scale);
656 VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
657 (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
658
659 return (res == PSM_ACK);
660}
661
662/* `val' must be 0 through PSMD_MAX_RESOLUTION */
663static int
664set_mouse_resolution(KBDC kbdc, int val)
665{
666 int res;
667
668 res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
669 VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
670
671 return ((res == PSM_ACK) ? val : -1);
672}
673
674/*
675 * NOTE: once `set_mouse_mode()' is called, the mouse device must be
676 * re-enabled by calling `enable_aux_dev()'
677 */
678static int
679set_mouse_mode(KBDC kbdc)
680{
681 int res;
682
683 res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
684 VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
685
686 return (res == PSM_ACK);
687}
688
689static int
690get_mouse_buttons(KBDC kbdc)
691{
692 int c = 2; /* assume two buttons by default */
693 int status[3];
694
695 /*
696 * NOTE: a special sequence to obtain Logitech Mouse specific
697 * information: set resolution to 25 ppi, set scaling to 1:1, set
698 * scaling to 1:1, set scaling to 1:1. Then the second byte of the
699 * mouse status bytes is the number of available buttons.
700 * Some manufactures also support this sequence.
701 */
702 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
703 return (c);
704 if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
705 set_mouse_scaling(kbdc, 1) &&
706 get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
707 return (status[1]);
708 return (c);
709}
710
711/* misc subroutines */
712/*
713 * Someday, I will get the complete list of valid pointing devices and
714 * their IDs... XXX
715 */
716static int
717is_a_mouse(int id)
718{
719#if 0
720 static int valid_ids[] = {
721 PSM_MOUSE_ID, /* mouse */
722 PSM_BALLPOINT_ID, /* ballpoint device */
723 PSM_INTELLI_ID, /* Intellimouse */
724 PSM_EXPLORER_ID, /* Intellimouse Explorer */
725 -1 /* end of table */
726 };
727 int i;
728
729 for (i = 0; valid_ids[i] >= 0; ++i)
730 if (valid_ids[i] == id)
731 return (TRUE);
732 return (FALSE);
733#else
734 return (TRUE);
735#endif
736}
737
738static char *
739model_name(int model)
740{
741 static struct {
742 int model_code;
743 char *model_name;
744 } models[] = {
745 { MOUSE_MODEL_NETSCROLL, "NetScroll" },
746 { MOUSE_MODEL_NET, "NetMouse/NetScroll Optical" },
747 { MOUSE_MODEL_GLIDEPOINT, "GlidePoint" },
748 { MOUSE_MODEL_THINK, "ThinkingMouse" },
749 { MOUSE_MODEL_INTELLI, "IntelliMouse" },
750 { MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" },
751 { MOUSE_MODEL_VERSAPAD, "VersaPad" },
752 { MOUSE_MODEL_EXPLORER, "IntelliMouse Explorer" },
753 { MOUSE_MODEL_4D, "4D Mouse" },
754 { MOUSE_MODEL_4DPLUS, "4D+ Mouse" },
755 { MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" },
756 { MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" },
757 { MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" },
758 { MOUSE_MODEL_UNKNOWN, "Unknown" },
759 };
760 int i;
761
762 for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
763 if (models[i].model_code == model)
764 break;
765 return (models[i].model_name);
766}
767
768static void
769recover_from_error(KBDC kbdc)
770{
771 /* discard anything left in the output buffer */
772 empty_both_buffers(kbdc, 10);
773
774#if 0
775 /*
776 * NOTE: KBDC_RESET_KBD may not restore the communication between the
777 * keyboard and the controller.
778 */
779 reset_kbd(kbdc);
780#else
781 /*
782 * NOTE: somehow diagnostic and keyboard port test commands bring the
783 * keyboard back.
784 */
785 if (!test_controller(kbdc))
786 log(LOG_ERR, "psm: keyboard controller failed.\n");
787 /* if there isn't a keyboard in the system, the following error is OK */
788 if (test_kbd_port(kbdc) != 0)
789 VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
790#endif
791}
792
793static int
794restore_controller(KBDC kbdc, int command_byte)
795{
796 empty_both_buffers(kbdc, 10);
797
798 if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
799 log(LOG_ERR, "psm: failed to restore the keyboard controller "
800 "command byte.\n");
801 empty_both_buffers(kbdc, 10);
802 return (FALSE);
803 } else {
804 empty_both_buffers(kbdc, 10);
805 return (TRUE);
806 }
807}
808
809/*
810 * Re-initialize the aux port and device. The aux port must be enabled
811 * and its interrupt must be disabled before calling this routine.
812 * The aux device will be disabled before returning.
813 * The keyboard controller must be locked via `kbdc_lock()' before
814 * calling this routine.
815 */
816static int
817doinitialize(struct psm_softc *sc, mousemode_t *mode)
818{
819 KBDC kbdc = sc->kbdc;
820 int stat[3];
821 int i;
822
823 switch((i = test_aux_port(kbdc))) {
824 case 1: /* ignore these errors */
825 case 2:
826 case 3:
827 case PSM_ACK:
828 if (verbose)
829 log(LOG_DEBUG,
830 "psm%d: strange result for test aux port (%d).\n",
831 sc->unit, i);
832 /* FALLTHROUGH */
833 case 0: /* no error */
834 break;
835 case -1: /* time out */
836 default: /* error */
837 recover_from_error(kbdc);
838 if (sc->config & PSM_CONFIG_IGNPORTERROR)
839 break;
840 log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
841 sc->unit, i);
842 return (FALSE);
843 }
844
845 if (sc->config & PSM_CONFIG_NORESET) {
846 /*
847 * Don't try to reset the pointing device. It may possibly
848 * be left in the unknown state, though...
849 */
850 } else {
851 /*
852 * NOTE: some controllers appears to hang the `keyboard' when
853 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
854 */
855 if (!reset_aux_dev(kbdc)) {
856 recover_from_error(kbdc);
857 log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
858 sc->unit);
859 return (FALSE);
860 }
861 }
862
863 /*
864 * both the aux port and the aux device is functioning, see
865 * if the device can be enabled.
866 */
867 if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
868 log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
869 sc->unit);
870 return (FALSE);
871 }
872 empty_both_buffers(kbdc, 10); /* remove stray data if any */
873
874 /* Re-enable the mouse. */
875 for (i = 0; vendortype[i].probefunc != NULL; ++i)
876 if (vendortype[i].model == sc->hw.model)
877 (*vendortype[i].probefunc)(sc->kbdc, NULL);
878
879 /* set mouse parameters */
880 if (mode != (mousemode_t *)NULL) {
881 if (mode->rate > 0)
882 mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
883 if (mode->resolution >= 0)
884 mode->resolution =
885 set_mouse_resolution(kbdc, mode->resolution);
886 set_mouse_scaling(kbdc, 1);
887 set_mouse_mode(kbdc);
888 }
889
890 /* Record sync on the next data packet we see. */
891 sc->flags |= PSM_NEED_SYNCBITS;
892
893 /* just check the status of the mouse */
894 if (get_mouse_status(kbdc, stat, 0, 3) < 3)
895 log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
896 sc->unit);
897
898 return (TRUE);
899}
900
901static int
902doopen(struct psm_softc *sc, int command_byte)
903{
904 int stat[3];
905
906 /*
907 * FIXME: Synaptics TouchPad seems to go back to Relative Mode with
908 * no obvious reason. Thus we check the current mode and restore the
909 * Absolute Mode if it was cleared.
910 *
911 * The previous hack at the end of psmprobe() wasn't efficient when
912 * moused(8) was restarted.
913 *
914 * A Reset (FF) or Set Defaults (F6) command would clear the
915 * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5
916 * doesn't show any evidence of such a command.
917 */
918 if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
919 mouse_ext_command(sc->kbdc, 1);
920 get_mouse_status(sc->kbdc, stat, 0, 3);
921 if ((SYNAPTICS_VERSION_GE(sc->synhw, 7, 5) ||
922 stat[1] == 0x47) &&
923 stat[2] == 0x40) {
924 /* Set the mode byte -- request wmode where
925 * available */
926 if (sc->synhw.capExtended)
927 mouse_ext_command(sc->kbdc, 0xc1);
928 else
929 mouse_ext_command(sc->kbdc, 0xc0);
930 set_mouse_sampling_rate(sc->kbdc, 20);
931 VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode "
932 "hopefully restored\n",
933 sc->unit));
934 }
935 }
936
937 /*
938 * A user may want to disable tap and drag gestures on a Synaptics
939 * TouchPad when it operates in Relative Mode.
940 */
941 if (sc->hw.model == MOUSE_MODEL_GENERIC) {
942 if (tap_enabled > 0) {
943 /*
944 * Enable tap & drag gestures. We use a Mode Byte
945 * and clear the DisGest bit (see ��2.5 of Synaptics
946 * TouchPad Interfacing Guide).
947 */
948 VLOG(2, (LOG_DEBUG,
949 "psm%d: enable tap and drag gestures\n",
950 sc->unit));
951 mouse_ext_command(sc->kbdc, 0x00);
952 set_mouse_sampling_rate(sc->kbdc, 20);
953 } else if (tap_enabled == 0) {
954 /*
955 * Disable tap & drag gestures. We use a Mode Byte
956 * and set the DisGest bit (see ��2.5 of Synaptics
957 * TouchPad Interfacing Guide).
958 */
959 VLOG(2, (LOG_DEBUG,
960 "psm%d: disable tap and drag gestures\n",
961 sc->unit));
962 mouse_ext_command(sc->kbdc, 0x04);
963 set_mouse_sampling_rate(sc->kbdc, 20);
964 }
965 }
966
967 /* enable the mouse device */
968 if (!enable_aux_dev(sc->kbdc)) {
969 /* MOUSE ERROR: failed to enable the mouse because:
970 * 1) the mouse is faulty,
971 * 2) the mouse has been removed(!?)
972 * In the latter case, the keyboard may have hung, and need
973 * recovery procedure...
974 */
975 recover_from_error(sc->kbdc);
976#if 0
977 /* FIXME: we could reset the mouse here and try to enable
978 * it again. But it will take long time and it's not a good
979 * idea to disable the keyboard that long...
980 */
981 if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
982 recover_from_error(sc->kbdc);
983#else
984 {
985#endif
986 restore_controller(sc->kbdc, command_byte);
987 /* mark this device is no longer available */
988 sc->state &= ~PSM_VALID;
989 log(LOG_ERR,
990 "psm%d: failed to enable the device (doopen).\n",
991 sc->unit);
992 return (EIO);
993 }
994 }
995
996 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
997 log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
998 sc->unit);
999
1000 /* enable the aux port and interrupt */
1001 if (!set_controller_command_byte(sc->kbdc,
1002 kbdc_get_device_mask(sc->kbdc),
1003 (command_byte & KBD_KBD_CONTROL_BITS) |
1004 KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
1005 /* CONTROLLER ERROR */
1006 disable_aux_dev(sc->kbdc);
1007 restore_controller(sc->kbdc, command_byte);
1008 log(LOG_ERR,
1009 "psm%d: failed to enable the aux interrupt (doopen).\n",
1010 sc->unit);
1011 return (EIO);
1012 }
1013
1014 /* start the watchdog timer */
1015 sc->watchdog = FALSE;
1016 callout_reset(&sc->callout, hz * 2, psmtimeout, sc);
1017
1018 return (0);
1019}
1020
1021static int
1022reinitialize(struct psm_softc *sc, int doinit)
1023{
1024 int err;
1025 int c;
1026 int s;
1027
1028 /* don't let anybody mess with the aux device */
1029 if (!kbdc_lock(sc->kbdc, TRUE))
1030 return (EIO);
1031 s = spltty();
1032
1033 /* block our watchdog timer */
1034 sc->watchdog = FALSE;
1035 callout_stop(&sc->callout);
1036
1037 /* save the current controller command byte */
1038 empty_both_buffers(sc->kbdc, 10);
1039 c = get_controller_command_byte(sc->kbdc);
1040 VLOG(2, (LOG_DEBUG,
1041 "psm%d: current command byte: %04x (reinitialize).\n",
1042 sc->unit, c));
1043
1044 /* enable the aux port but disable the aux interrupt and the keyboard */
1045 if ((c == -1) || !set_controller_command_byte(sc->kbdc,
1046 kbdc_get_device_mask(sc->kbdc),
1047 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1048 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1049 /* CONTROLLER ERROR */
1050 splx(s);
1051 kbdc_lock(sc->kbdc, FALSE);
1052 log(LOG_ERR,
1053 "psm%d: unable to set the command byte (reinitialize).\n",
1054 sc->unit);
1055 return (EIO);
1056 }
1057
1058 /* flush any data */
1059 if (sc->state & PSM_VALID) {
1060 /* this may fail; but never mind... */
1061 disable_aux_dev(sc->kbdc);
1062 empty_aux_buffer(sc->kbdc, 10);
1063 }
1064 flushpackets(sc);
1065 sc->syncerrors = 0;
1066 sc->pkterrors = 0;
1067 memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
1068
1069 /* try to detect the aux device; are you still there? */
1070 err = 0;
1071 if (doinit) {
1072 if (doinitialize(sc, &sc->mode)) {
1073 /* yes */
1074 sc->state |= PSM_VALID;
1075 } else {
1076 /* the device has gone! */
1077 restore_controller(sc->kbdc, c);
1078 sc->state &= ~PSM_VALID;
1079 log(LOG_ERR,
1080 "psm%d: the aux device has gone! (reinitialize).\n",
1081 sc->unit);
1082 err = ENXIO;
1083 }
1084 }
1085 splx(s);
1086
1087 /* restore the driver state */
1088 if ((sc->state & PSM_OPEN) && (err == 0)) {
1089 /* enable the aux device and the port again */
1090 err = doopen(sc, c);
1091 if (err != 0)
1092 log(LOG_ERR, "psm%d: failed to enable the device "
1093 "(reinitialize).\n", sc->unit);
1094 } else {
1095 /* restore the keyboard port and disable the aux port */
1096 if (!set_controller_command_byte(sc->kbdc,
1097 kbdc_get_device_mask(sc->kbdc),
1098 (c & KBD_KBD_CONTROL_BITS) |
1099 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1100 /* CONTROLLER ERROR */
1101 log(LOG_ERR, "psm%d: failed to disable the aux port "
1102 "(reinitialize).\n", sc->unit);
1103 err = EIO;
1104 }
1105 }
1106
1107 kbdc_lock(sc->kbdc, FALSE);
1108 return (err);
1109}
1110
1111/* psm driver entry points */
1112
1113static void
1114psmidentify(driver_t *driver, device_t parent)
1115{
1116 device_t psmc;
1117 device_t psm;
1118 u_long irq;
1119 int unit;
1120
1121 unit = device_get_unit(parent);
1122
1123 /* always add at least one child */
1124 psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit);
1125 if (psm == NULL)
1126 return;
1127
1128 irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
1129 if (irq > 0)
1130 return;
1131
1132 /*
1133 * If the PS/2 mouse device has already been reported by ACPI or
1134 * PnP BIOS, obtain the IRQ resource from it.
1135 * (See psmcpnp_attach() below.)
1136 */
1137 psmc = device_find_child(device_get_parent(parent),
1138 PSMCPNP_DRIVER_NAME, unit);
1139 if (psmc == NULL)
1140 return;
1141 irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
1142 if (irq <= 0)
1143 return;
1144 bus_delete_resource(psmc, SYS_RES_IRQ, 0);
1145 bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
1146}
1147
1148#define endprobe(v) do { \
1149 if (bootverbose) \
1150 --verbose; \
1151 kbdc_set_device_mask(sc->kbdc, mask); \
1152 kbdc_lock(sc->kbdc, FALSE); \
1153 return (v); \
1154} while (0)
1155
1156static int
1157psmprobe(device_t dev)
1158{
1159 int unit = device_get_unit(dev);
1160 struct psm_softc *sc = device_get_softc(dev);
1161 int stat[3];
1162 int command_byte;
1163 int mask;
1164 int rid;
1165 int i;
1166
1167#if 0
1168 kbdc_debug(TRUE);
1169#endif
1170
1171 /* see if IRQ is available */
1172 rid = KBDC_RID_AUX;
1173 sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1174 if (sc->intr == NULL) {
1175 if (bootverbose)
1176 device_printf(dev, "unable to allocate IRQ\n");
1177 return (ENXIO);
1178 }
1179 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1180
1181 sc->unit = unit;
1182 sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
1183 sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS;
1184 /* XXX: for backward compatibility */
1185#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
1186 sc->config |=
1187#ifdef PSM_RESETAFTERSUSPEND
1188 PSM_CONFIG_INITAFTERSUSPEND;
1189#else
1190 PSM_CONFIG_HOOKRESUME;
1191#endif
1192#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
1193 sc->flags = 0;
1194 if (bootverbose)
1195 ++verbose;
1196
1197 device_set_desc(dev, "PS/2 Mouse");
1198
1199 if (!kbdc_lock(sc->kbdc, TRUE)) {
1200 printf("psm%d: unable to lock the controller.\n", unit);
1201 if (bootverbose)
1202 --verbose;
1203 return (ENXIO);
1204 }
1205
1206 /*
1207 * NOTE: two bits in the command byte controls the operation of the
1208 * aux port (mouse port): the aux port disable bit (bit 5) and the aux
1209 * port interrupt (IRQ 12) enable bit (bit 2).
1210 */
1211
1212 /* discard anything left after the keyboard initialization */
1213 empty_both_buffers(sc->kbdc, 10);
1214
1215 /* save the current command byte; it will be used later */
1216 mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
1217 command_byte = get_controller_command_byte(sc->kbdc);
1218 if (verbose)
1219 printf("psm%d: current command byte:%04x\n", unit,
1220 command_byte);
1221 if (command_byte == -1) {
1222 /* CONTROLLER ERROR */
1223 printf("psm%d: unable to get the current command byte value.\n",
1224 unit);
1225 endprobe(ENXIO);
1226 }
1227
1228 /*
1229 * disable the keyboard port while probing the aux port, which must be
1230 * enabled during this routine
1231 */
1232 if (!set_controller_command_byte(sc->kbdc,
1233 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1234 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1235 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1236 /*
1237 * this is CONTROLLER ERROR; I don't know how to recover
1238 * from this error...
1239 */
1240 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1241 restore_controller(sc->kbdc, command_byte);
1242 printf("psm%d: unable to set the command byte.\n", unit);
1243 endprobe(ENXIO);
1244 }
1245 write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
1246
1247 /*
1248 * NOTE: `test_aux_port()' is designed to return with zero if the aux
1249 * port exists and is functioning. However, some controllers appears
1250 * to respond with zero even when the aux port doesn't exist. (It may
1251 * be that this is only the case when the controller DOES have the aux
1252 * port but the port is not wired on the motherboard.) The keyboard
1253 * controllers without the port, such as the original AT, are
1254 * supposed to return with an error code or simply time out. In any
1255 * case, we have to continue probing the port even when the controller
1256 * passes this test.
1257 *
1258 * XXX: some controllers erroneously return the error code 1, 2 or 3
1259 * when it has a perfectly functional aux port. We have to ignore
1260 * this error code. Even if the controller HAS error with the aux
1261 * port, it will be detected later...
1262 * XXX: another incompatible controller returns PSM_ACK (0xfa)...
1263 */
1264 switch ((i = test_aux_port(sc->kbdc))) {
1265 case 1: /* ignore these errors */
1266 case 2:
1267 case 3:
1268 case PSM_ACK:
1269 if (verbose)
1270 printf("psm%d: strange result for test aux port "
1271 "(%d).\n", unit, i);
1272 /* FALLTHROUGH */
1273 case 0: /* no error */
1274 break;
1275 case -1: /* time out */
1276 default: /* error */
1277 recover_from_error(sc->kbdc);
1278 if (sc->config & PSM_CONFIG_IGNPORTERROR)
1279 break;
1280 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1281 restore_controller(sc->kbdc, command_byte);
1282 if (verbose)
1283 printf("psm%d: the aux port is not functioning (%d).\n",
1284 unit, i);
1285 endprobe(ENXIO);
1286 }
1287
1288 if (sc->config & PSM_CONFIG_NORESET) {
1289 /*
1290 * Don't try to reset the pointing device. It may possibly be
1291 * left in an unknown state, though...
1292 */
1293 } else {
1294 /*
1295 * NOTE: some controllers appears to hang the `keyboard' when
1296 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
1297 *
1298 * Attempt to reset the controller twice -- this helps
1299 * pierce through some KVM switches. The second reset
1300 * is non-fatal.
1301 */
1302 if (!reset_aux_dev(sc->kbdc)) {
1303 recover_from_error(sc->kbdc);
1304 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1305 restore_controller(sc->kbdc, command_byte);
1306 if (verbose)
1307 printf("psm%d: failed to reset the aux "
1308 "device.\n", unit);
1309 endprobe(ENXIO);
1310 } else if (!reset_aux_dev(sc->kbdc)) {
1311 recover_from_error(sc->kbdc);
1312 if (verbose >= 2)
1313 printf("psm%d: failed to reset the aux device "
1314 "(2).\n", unit);
1315 }
1316 }
1317
1318 /*
1319 * both the aux port and the aux device are functioning, see if the
1320 * device can be enabled. NOTE: when enabled, the device will start
1321 * sending data; we shall immediately disable the device once we know
1322 * the device can be enabled.
1323 */
1324 if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
1325 /* MOUSE ERROR */
1326 recover_from_error(sc->kbdc);
1327 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1328 restore_controller(sc->kbdc, command_byte);
1329 if (verbose)
1330 printf("psm%d: failed to enable the aux device.\n",
1331 unit);
1332 endprobe(ENXIO);
1333 }
1334
1335 /* save the default values after reset */
1336 if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
1337 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1338 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1339 } else {
1340 sc->dflt_mode.rate = sc->mode.rate = -1;
1341 sc->dflt_mode.resolution = sc->mode.resolution = -1;
1342 }
1343
1344 /* hardware information */
1345 sc->hw.iftype = MOUSE_IF_PS2;
1346
1347 /* verify the device is a mouse */
1348 sc->hw.hwid = get_aux_id(sc->kbdc);
1349 if (!is_a_mouse(sc->hw.hwid)) {
1350 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1351 restore_controller(sc->kbdc, command_byte);
1352 if (verbose)
1353 printf("psm%d: unknown device type (%d).\n", unit,
1354 sc->hw.hwid);
1355 endprobe(ENXIO);
1356 }
1357 switch (sc->hw.hwid) {
1358 case PSM_BALLPOINT_ID:
1359 sc->hw.type = MOUSE_TRACKBALL;
1360 break;
1361 case PSM_MOUSE_ID:
1362 case PSM_INTELLI_ID:
1363 case PSM_EXPLORER_ID:
1364 case PSM_4DMOUSE_ID:
1365 case PSM_4DPLUS_ID:
1366 sc->hw.type = MOUSE_MOUSE;
1367 break;
1368 default:
1369 sc->hw.type = MOUSE_UNKNOWN;
1370 break;
1371 }
1372
1373 if (sc->config & PSM_CONFIG_NOIDPROBE) {
1374 sc->hw.buttons = 2;
1375 i = GENERIC_MOUSE_ENTRY;
1376 } else {
1377 /* # of buttons */
1378 sc->hw.buttons = get_mouse_buttons(sc->kbdc);
1379
1380 /* other parameters */
1381 for (i = 0; vendortype[i].probefunc != NULL; ++i)
1382 if ((*vendortype[i].probefunc)(sc->kbdc, sc)) {
1383 if (verbose >= 2)
1384 printf("psm%d: found %s\n", unit,
1385 model_name(vendortype[i].model));
1386 break;
1387 }
1388 }
1389
1390 sc->hw.model = vendortype[i].model;
1391
1392 sc->dflt_mode.level = PSM_LEVEL_BASE;
1393 sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
1394 sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
1395 if (sc->config & PSM_CONFIG_NOCHECKSYNC)
1396 sc->dflt_mode.syncmask[0] = 0;
1397 else
1398 sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
1399 if (sc->config & PSM_CONFIG_FORCETAP)
1400 sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
1401 sc->dflt_mode.syncmask[1] = 0; /* syncbits */
1402 sc->mode = sc->dflt_mode;
1403 sc->mode.packetsize = vendortype[i].packetsize;
1404
1405 /* set mouse parameters */
1406#if 0
1407 /*
1408 * A version of Logitech FirstMouse+ won't report wheel movement,
1409 * if SET_DEFAULTS is sent... Don't use this command.
1410 * This fix was found by Takashi Nishida.
1411 */
1412 i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
1413 if (verbose >= 2)
1414 printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
1415#endif
1416 if (sc->config & PSM_CONFIG_RESOLUTION)
1417 sc->mode.resolution =
1418 set_mouse_resolution(sc->kbdc,
1419 (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1420 else if (sc->mode.resolution >= 0)
1421 sc->mode.resolution =
1422 set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1423 if (sc->mode.rate > 0)
1424 sc->mode.rate =
1425 set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1426 set_mouse_scaling(sc->kbdc, 1);
1427
1428 /* Record sync on the next data packet we see. */
1429 sc->flags |= PSM_NEED_SYNCBITS;
1430
1431 /* just check the status of the mouse */
1432 /*
1433 * NOTE: XXX there are some arcane controller/mouse combinations out
1434 * there, which hung the controller unless there is data transmission
1435 * after ACK from the mouse.
1436 */
1437 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1438 printf("psm%d: failed to get status.\n", unit);
1439 else {
1440 /*
1441 * When in its native mode, some mice operate with different
1442 * default parameters than in the PS/2 compatible mode.
1443 */
1444 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1445 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1446 }
1447
1448 /* disable the aux port for now... */
1449 if (!set_controller_command_byte(sc->kbdc,
1450 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1451 (command_byte & KBD_KBD_CONTROL_BITS) |
1452 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1453 /*
1454 * this is CONTROLLER ERROR; I don't know the proper way to
1455 * recover from this error...
1456 */
1457 if (ALWAYS_RESTORE_CONTROLLER(sc->kbdc))
1458 restore_controller(sc->kbdc, command_byte);
1459 printf("psm%d: unable to set the command byte.\n", unit);
1460 endprobe(ENXIO);
1461 }
1462
1463 /* done */
1464 kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1465 kbdc_lock(sc->kbdc, FALSE);
1466 return (0);
1467}
1468
1469static int
1470psmattach(device_t dev)
1471{
1472 int unit = device_get_unit(dev);
1473 struct psm_softc *sc = device_get_softc(dev);
1474 int error;
1475 int rid;
1476
1477 /* Setup initial state */
1478 sc->state = PSM_VALID;
1479 callout_init(&sc->callout, 0);
1480 callout_init(&sc->softcallout, 0);
1481
1482 /* Setup our interrupt handler */
1483 rid = KBDC_RID_AUX;
1484 sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1485 if (sc->intr == NULL)
1486 return (ENXIO);
1487 error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc,
1488 &sc->ih);
1489 if (error) {
1490 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1491 return (error);
1492 }
1493
1494 /* Done */
1495 sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit);
1496 sc->dev->si_drv1 = sc;
1497 sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit);
1498 sc->bdev->si_drv1 = sc;
1499
1500 /* Some touchpad devices need full reinitialization after suspend. */
1501 switch (sc->hw.model) {
1502 case MOUSE_MODEL_SYNAPTICS:
1503 case MOUSE_MODEL_GLIDEPOINT:
1504 case MOUSE_MODEL_VERSAPAD:
1505 sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1506 break;
1507 default:
1508 if (sc->synhw.infoMajor >= 4 || sc->tphw > 0)
1509 sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1510 break;
1511 }
1512
1513 if (!verbose)
1514 printf("psm%d: model %s, device ID %d\n",
1515 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1516 else {
1517 printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1518 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
1519 sc->hw.hwid >> 8, sc->hw.buttons);
1520 printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1521 unit, sc->config, sc->flags, sc->mode.packetsize);
1522 printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1523 unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1524 }
1525
1526 if (bootverbose)
1527 --verbose;
1528
1529 return (0);
1530}
1531
1532static int
1533psmdetach(device_t dev)
1534{
1535 struct psm_softc *sc;
1536 int rid;
1537
1538 sc = device_get_softc(dev);
1539 if (sc->state & PSM_OPEN)
1540 return (EBUSY);
1541
1542 rid = KBDC_RID_AUX;
1543 bus_teardown_intr(dev, sc->intr, sc->ih);
1544 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1545
1546 destroy_dev(sc->dev);
1547 destroy_dev(sc->bdev);
1548
1549 callout_drain(&sc->callout);
1550 callout_drain(&sc->softcallout);
1551
1552 return (0);
1553}
1554
1555static int
1556psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
1557{
1558 struct psm_softc *sc;
1559 int command_byte;
1560 int err;
1561 int s;
1562
1563 /* Get device data */
1564 sc = dev->si_drv1;
1565 if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
1566 /* the device is no longer valid/functioning */
1567 return (ENXIO);
1568 }
1569
1570 /* Disallow multiple opens */
1571 if (sc->state & PSM_OPEN)
1572 return (EBUSY);
1573
1574 device_busy(devclass_get_device(psm_devclass, sc->unit));
1575
1576 /* Initialize state */
1577 sc->mode.level = sc->dflt_mode.level;
1578 sc->mode.protocol = sc->dflt_mode.protocol;
1579 sc->watchdog = FALSE;
1580 sc->async = NULL;
1581
1582 /* flush the event queue */
1583 sc->queue.count = 0;
1584 sc->queue.head = 0;
1585 sc->queue.tail = 0;
1586 sc->status.flags = 0;
1587 sc->status.button = 0;
1588 sc->status.obutton = 0;
1589 sc->status.dx = 0;
1590 sc->status.dy = 0;
1591 sc->status.dz = 0;
1592 sc->button = 0;
1593 sc->pqueue_start = 0;
1594 sc->pqueue_end = 0;
1595
1596 /* empty input buffer */
1597 flushpackets(sc);
1598 sc->syncerrors = 0;
1599 sc->pkterrors = 0;
1600
1601 /* don't let timeout routines in the keyboard driver to poll the kbdc */
1602 if (!kbdc_lock(sc->kbdc, TRUE))
1603 return (EIO);
1604
1605 /* save the current controller command byte */
1606 s = spltty();
1607 command_byte = get_controller_command_byte(sc->kbdc);
1608
1609 /* enable the aux port and temporalily disable the keyboard */
1610 if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
1611 kbdc_get_device_mask(sc->kbdc),
1612 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1613 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1614 /* CONTROLLER ERROR; do you know how to get out of this? */
1615 kbdc_lock(sc->kbdc, FALSE);
1616 splx(s);
1617 log(LOG_ERR,
1618 "psm%d: unable to set the command byte (psmopen).\n",
1619 sc->unit);
1620 return (EIO);
1621 }
1622 /*
1623 * Now that the keyboard controller is told not to generate
1624 * the keyboard and mouse interrupts, call `splx()' to allow
1625 * the other tty interrupts. The clock interrupt may also occur,
1626 * but timeout routines will be blocked by the poll flag set
1627 * via `kbdc_lock()'
1628 */
1629 splx(s);
1630
1631 /* enable the mouse device */
1632 err = doopen(sc, command_byte);
1633
1634 /* done */
1635 if (err == 0)
1636 sc->state |= PSM_OPEN;
1637 kbdc_lock(sc->kbdc, FALSE);
1638 return (err);
1639}
1640
1641static int
1642psmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
1643{
1644 struct psm_softc *sc = dev->si_drv1;
1645 int stat[3];
1646 int command_byte;
1647 int s;
1648
1649 /* don't let timeout routines in the keyboard driver to poll the kbdc */
1650 if (!kbdc_lock(sc->kbdc, TRUE))
1651 return (EIO);
1652
1653 /* save the current controller command byte */
1654 s = spltty();
1655 command_byte = get_controller_command_byte(sc->kbdc);
1656 if (command_byte == -1) {
1657 kbdc_lock(sc->kbdc, FALSE);
1658 splx(s);
1659 return (EIO);
1660 }
1661
1662 /* disable the aux interrupt and temporalily disable the keyboard */
1663 if (!set_controller_command_byte(sc->kbdc,
1664 kbdc_get_device_mask(sc->kbdc),
1665 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1666 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1667 log(LOG_ERR,
1668 "psm%d: failed to disable the aux int (psmclose).\n",
1669 sc->unit);
1670 /* CONTROLLER ERROR;
1671 * NOTE: we shall force our way through. Because the only
1672 * ill effect we shall see is that we may not be able
1673 * to read ACK from the mouse, and it doesn't matter much
1674 * so long as the mouse will accept the DISABLE command.
1675 */
1676 }
1677 splx(s);
1678
1679 /* stop the watchdog timer */
1680 callout_stop(&sc->callout);
1681
1682 /* remove anything left in the output buffer */
1683 empty_aux_buffer(sc->kbdc, 10);
1684
1685 /* disable the aux device, port and interrupt */
1686 if (sc->state & PSM_VALID) {
1687 if (!disable_aux_dev(sc->kbdc)) {
1688 /* MOUSE ERROR;
1689 * NOTE: we don't return (error) and continue,
1690 * pretending we have successfully disabled the device.
1691 * It's OK because the interrupt routine will discard
1692 * any data from the mouse hereafter.
1693 */
1694 log(LOG_ERR,
1695 "psm%d: failed to disable the device (psmclose).\n",
1696 sc->unit);
1697 }
1698
1699 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1700 log(LOG_DEBUG,
1701 "psm%d: failed to get status (psmclose).\n",
1702 sc->unit);
1703 }
1704
1705 if (!set_controller_command_byte(sc->kbdc,
1706 kbdc_get_device_mask(sc->kbdc),
1707 (command_byte & KBD_KBD_CONTROL_BITS) |
1708 KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1709 /*
1710 * CONTROLLER ERROR;
1711 * we shall ignore this error; see the above comment.
1712 */
1713 log(LOG_ERR,
1714 "psm%d: failed to disable the aux port (psmclose).\n",
1715 sc->unit);
1716 }
1717
1718 /* remove anything left in the output buffer */
1719 empty_aux_buffer(sc->kbdc, 10);
1720
1721 /* clean up and sigio requests */
1722 if (sc->async != NULL) {
1723 funsetown(&sc->async);
1724 sc->async = NULL;
1725 }
1726
1727 /* close is almost always successful */
1728 sc->state &= ~PSM_OPEN;
1729 kbdc_lock(sc->kbdc, FALSE);
1730 device_unbusy(devclass_get_device(psm_devclass, sc->unit));
1731 return (0);
1732}
1733
1734static int
1735tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
1736 u_char *buf)
1737{
1738 static u_char butmapps2[8] = {
1739 0,
1740 MOUSE_PS2_BUTTON1DOWN,
1741 MOUSE_PS2_BUTTON2DOWN,
1742 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1743 MOUSE_PS2_BUTTON3DOWN,
1744 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1745 MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1746 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
1747 MOUSE_PS2_BUTTON3DOWN,
1748 };
1749 static u_char butmapmsc[8] = {
1750 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
1751 MOUSE_MSC_BUTTON3UP,
1752 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1753 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1754 MOUSE_MSC_BUTTON3UP,
1755 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1756 MOUSE_MSC_BUTTON2UP,
1757 MOUSE_MSC_BUTTON1UP,
1758 0,
1759 };
1760 int mapped;
1761 int i;
1762
1763 if (sc->mode.level == PSM_LEVEL_BASE) {
1764 mapped = status->button & ~MOUSE_BUTTON4DOWN;
1765 if (status->button & MOUSE_BUTTON4DOWN)
1766 mapped |= MOUSE_BUTTON1DOWN;
1767 status->button = mapped;
1768 buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1769 i = imax(imin(status->dx, 255), -256);
1770 if (i < 0)
1771 buf[0] |= MOUSE_PS2_XNEG;
1772 buf[1] = i;
1773 i = imax(imin(status->dy, 255), -256);
1774 if (i < 0)
1775 buf[0] |= MOUSE_PS2_YNEG;
1776 buf[2] = i;
1777 return (MOUSE_PS2_PACKETSIZE);
1778 } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1779 buf[0] = MOUSE_MSC_SYNC |
1780 butmapmsc[status->button & MOUSE_STDBUTTONS];
1781 i = imax(imin(status->dx, 255), -256);
1782 buf[1] = i >> 1;
1783 buf[3] = i - buf[1];
1784 i = imax(imin(status->dy, 255), -256);
1785 buf[2] = i >> 1;
1786 buf[4] = i - buf[2];
1787 i = imax(imin(status->dz, 127), -128);
1788 buf[5] = (i >> 1) & 0x7f;
1789 buf[6] = (i - (i >> 1)) & 0x7f;
1790 buf[7] = (~status->button >> 3) & 0x7f;
1791 return (MOUSE_SYS_PACKETSIZE);
1792 }
1793 return (pb->inputbytes);
1794}
1795
1796static int
1797psmread(struct cdev *dev, struct uio *uio, int flag)
1798{
1799 struct psm_softc *sc = dev->si_drv1;
1800 u_char buf[PSM_SMALLBUFSIZE];
1801 int error = 0;
1802 int s;
1803 int l;
1804
1805 if ((sc->state & PSM_VALID) == 0)
1806 return (EIO);
1807
1808 /* block until mouse activity occured */
1809 s = spltty();
1810 while (sc->queue.count <= 0) {
1811 if (dev != sc->bdev) {
1812 splx(s);
1813 return (EWOULDBLOCK);
1814 }
1815 sc->state |= PSM_ASLP;
1816 error = tsleep(sc, PZERO | PCATCH, "psmrea", 0);
1817 sc->state &= ~PSM_ASLP;
1818 if (error) {
1819 splx(s);
1820 return (error);
1821 } else if ((sc->state & PSM_VALID) == 0) {
1822 /* the device disappeared! */
1823 splx(s);
1824 return (EIO);
1825 }
1826 }
1827 splx(s);
1828
1829 /* copy data to the user land */
1830 while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1831 s = spltty();
1832 l = imin(sc->queue.count, uio->uio_resid);
1833 if (l > sizeof(buf))
1834 l = sizeof(buf);
1835 if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1836 bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1837 sizeof(sc->queue.buf) - sc->queue.head);
1838 bcopy(&sc->queue.buf[0],
1839 &buf[sizeof(sc->queue.buf) - sc->queue.head],
1840 l - (sizeof(sc->queue.buf) - sc->queue.head));
1841 } else
1842 bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1843 sc->queue.count -= l;
1844 sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1845 splx(s);
1846 error = uiomove(buf, l, uio);
1847 if (error)
1848 break;
1849 }
1850
1851 return (error);
1852}
1853
1854static int
1855block_mouse_data(struct psm_softc *sc, int *c)
1856{
1857 int s;
1858
1859 if (!kbdc_lock(sc->kbdc, TRUE))
1860 return (EIO);
1861
1862 s = spltty();
1863 *c = get_controller_command_byte(sc->kbdc);
1864 if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
1865 kbdc_get_device_mask(sc->kbdc),
1866 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1867 KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1868 /* this is CONTROLLER ERROR */
1869 splx(s);
1870 kbdc_lock(sc->kbdc, FALSE);
1871 return (EIO);
1872 }
1873
1874 /*
1875 * The device may be in the middle of status data transmission.
1876 * The transmission will be interrupted, thus, incomplete status
1877 * data must be discarded. Although the aux interrupt is disabled
1878 * at the keyboard controller level, at most one aux interrupt
1879 * may have already been pending and a data byte is in the
1880 * output buffer; throw it away. Note that the second argument
1881 * to `empty_aux_buffer()' is zero, so that the call will just
1882 * flush the internal queue.
1883 * `psmintr()' will be invoked after `splx()' if an interrupt is
1884 * pending; it will see no data and returns immediately.
1885 */
1886 empty_aux_buffer(sc->kbdc, 0); /* flush the queue */
1887 read_aux_data_no_wait(sc->kbdc); /* throw away data if any */
1888 flushpackets(sc);
1889 splx(s);
1890
1891 return (0);
1892}
1893
1894static void
1895dropqueue(struct psm_softc *sc)
1896{
1897
1898 sc->queue.count = 0;
1899 sc->queue.head = 0;
1900 sc->queue.tail = 0;
1901 if ((sc->state & PSM_SOFTARMED) != 0) {
1902 sc->state &= ~PSM_SOFTARMED;
1903 callout_stop(&sc->softcallout);
1904 }
1905 sc->pqueue_start = sc->pqueue_end;
1906}
1907
1908static void
1909flushpackets(struct psm_softc *sc)
1910{
1911
1912 dropqueue(sc);
1913 bzero(&sc->pqueue, sizeof(sc->pqueue));
1914}
1915
1916static int
1917unblock_mouse_data(struct psm_softc *sc, int c)
1918{
1919 int error = 0;
1920
1921 /*
1922 * We may have seen a part of status data during `set_mouse_XXX()'.
1923 * they have been queued; flush it.
1924 */
1925 empty_aux_buffer(sc->kbdc, 0);
1926
1927 /* restore ports and interrupt */
1928 if (!set_controller_command_byte(sc->kbdc,
1929 kbdc_get_device_mask(sc->kbdc),
1930 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1931 /*
1932 * CONTROLLER ERROR; this is serious, we may have
1933 * been left with the inaccessible keyboard and
1934 * the disabled mouse interrupt.
1935 */
1936 error = EIO;
1937 }
1938
1939 kbdc_lock(sc->kbdc, FALSE);
1940 return (error);
1941}
1942
1943static int
1944psmwrite(struct cdev *dev, struct uio *uio, int flag)
1945{
1946 struct psm_softc *sc = dev->si_drv1;
1947 u_char buf[PSM_SMALLBUFSIZE];
1948 int error = 0, i, l;
1949
1950 if ((sc->state & PSM_VALID) == 0)
1951 return (EIO);
1952
1953 if (sc->mode.level < PSM_LEVEL_NATIVE)
1954 return (ENODEV);
1955
1956 /* copy data from the user land */
1957 while (uio->uio_resid > 0) {
1958 l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
1959 error = uiomove(buf, l, uio);
1960 if (error)
1961 break;
1962 for (i = 0; i < l; i++) {
1963 VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
1964 if (!write_aux_command(sc->kbdc, buf[i])) {
1965 VLOG(2, (LOG_DEBUG,
1966 "psm: cmd 0x%x failed.\n", buf[i]));
1967 return (reinitialize(sc, FALSE));
1968 }
1969 }
1970 }
1971
1972 return (error);
1973}
1974
1975static int
1976psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
1977 struct thread *td)
1978{
1979 struct psm_softc *sc = dev->si_drv1;
1980 mousemode_t mode;
1981 mousestatus_t status;
1982#if (defined(MOUSE_GETVARS))
1983 mousevar_t *var;
1984#endif
1985 mousedata_t *data;
1986 int stat[3];
1987 int command_byte;
1988 int error = 0;
1989 int s;
1990
1991 /* Perform IOCTL command */
1992 switch (cmd) {
1993
1994 case OLD_MOUSE_GETHWINFO:
1995 s = spltty();
1996 ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
1997 ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
1998 ((old_mousehw_t *)addr)->type = sc->hw.type;
1999 ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
2000 splx(s);
2001 break;
2002
2003 case MOUSE_GETHWINFO:
2004 s = spltty();
2005 *(mousehw_t *)addr = sc->hw;
2006 if (sc->mode.level == PSM_LEVEL_BASE)
2007 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
2008 splx(s);
2009 break;
2010
2011 case MOUSE_SYN_GETHWINFO:
2012 s = spltty();
2013 if (sc->synhw.infoMajor >= 4)
2014 *(synapticshw_t *)addr = sc->synhw;
2015 else
2016 error = EINVAL;
2017 splx(s);
2018 break;
2019
2020 case OLD_MOUSE_GETMODE:
2021 s = spltty();
2022 switch (sc->mode.level) {
2023 case PSM_LEVEL_BASE:
2024 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2025 break;
2026 case PSM_LEVEL_STANDARD:
2027 ((old_mousemode_t *)addr)->protocol =
2028 MOUSE_PROTO_SYSMOUSE;
2029 break;
2030 case PSM_LEVEL_NATIVE:
2031 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2032 break;
2033 }
2034 ((old_mousemode_t *)addr)->rate = sc->mode.rate;
2035 ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
2036 ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
2037 splx(s);
2038 break;
2039
2040 case MOUSE_GETMODE:
2041 s = spltty();
2042 *(mousemode_t *)addr = sc->mode;
2043 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2044 ((mousemode_t *)addr)->syncmask[0] = 0;
2045 ((mousemode_t *)addr)->syncmask[1] = 0;
2046 }
2047 ((mousemode_t *)addr)->resolution =
2048 MOUSE_RES_LOW - sc->mode.resolution;
2049 switch (sc->mode.level) {
2050 case PSM_LEVEL_BASE:
2051 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2052 ((mousemode_t *)addr)->packetsize =
2053 MOUSE_PS2_PACKETSIZE;
2054 break;
2055 case PSM_LEVEL_STANDARD:
2056 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
2057 ((mousemode_t *)addr)->packetsize =
2058 MOUSE_SYS_PACKETSIZE;
2059 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
2060 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
2061 break;
2062 case PSM_LEVEL_NATIVE:
2063 /* FIXME: this isn't quite correct... XXX */
2064 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2065 break;
2066 }
2067 splx(s);
2068 break;
2069
2070 case OLD_MOUSE_SETMODE:
2071 case MOUSE_SETMODE:
2072 if (cmd == OLD_MOUSE_SETMODE) {
2073 mode.rate = ((old_mousemode_t *)addr)->rate;
2074 /*
2075 * resolution old I/F new I/F
2076 * default 0 0
2077 * low 1 -2
2078 * medium low 2 -3
2079 * medium high 3 -4
2080 * high 4 -5
2081 */
2082 if (((old_mousemode_t *)addr)->resolution > 0)
2083 mode.resolution =
2084 -((old_mousemode_t *)addr)->resolution - 1;
2085 else
2086 mode.resolution = 0;
2087 mode.accelfactor =
2088 ((old_mousemode_t *)addr)->accelfactor;
2089 mode.level = -1;
2090 } else
2091 mode = *(mousemode_t *)addr;
2092
2093 /* adjust and validate parameters. */
2094 if (mode.rate > UCHAR_MAX)
2095 return (EINVAL);
2096 if (mode.rate == 0)
2097 mode.rate = sc->dflt_mode.rate;
2098 else if (mode.rate == -1)
2099 /* don't change the current setting */
2100 ;
2101 else if (mode.rate < 0)
2102 return (EINVAL);
2103 if (mode.resolution >= UCHAR_MAX)
2104 return (EINVAL);
2105 if (mode.resolution >= 200)
2106 mode.resolution = MOUSE_RES_HIGH;
2107 else if (mode.resolution >= 100)
2108 mode.resolution = MOUSE_RES_MEDIUMHIGH;
2109 else if (mode.resolution >= 50)
2110 mode.resolution = MOUSE_RES_MEDIUMLOW;
2111 else if (mode.resolution > 0)
2112 mode.resolution = MOUSE_RES_LOW;
2113 if (mode.resolution == MOUSE_RES_DEFAULT)
2114 mode.resolution = sc->dflt_mode.resolution;
2115 else if (mode.resolution == -1)
2116 /* don't change the current setting */
2117 ;
2118 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2119 mode.resolution = MOUSE_RES_LOW - mode.resolution;
2120 if (mode.level == -1)
2121 /* don't change the current setting */
2122 mode.level = sc->mode.level;
2123 else if ((mode.level < PSM_LEVEL_MIN) ||
2124 (mode.level > PSM_LEVEL_MAX))
2125 return (EINVAL);
2126 if (mode.accelfactor == -1)
2127 /* don't change the current setting */
2128 mode.accelfactor = sc->mode.accelfactor;
2129 else if (mode.accelfactor < 0)
2130 return (EINVAL);
2131
2132 /* don't allow anybody to poll the keyboard controller */
2133 error = block_mouse_data(sc, &command_byte);
2134 if (error)
2135 return (error);
2136
2137 /* set mouse parameters */
2138 if (mode.rate > 0)
2139 mode.rate = set_mouse_sampling_rate(sc->kbdc,
2140 mode.rate);
2141 if (mode.resolution >= 0)
2142 mode.resolution =
2143 set_mouse_resolution(sc->kbdc, mode.resolution);
2144 set_mouse_scaling(sc->kbdc, 1);
2145 get_mouse_status(sc->kbdc, stat, 0, 3);
2146
2147 s = spltty();
2148 sc->mode.rate = mode.rate;
2149 sc->mode.resolution = mode.resolution;
2150 sc->mode.accelfactor = mode.accelfactor;
2151 sc->mode.level = mode.level;
2152 splx(s);
2153
2154 unblock_mouse_data(sc, command_byte);
2155 break;
2156
2157 case MOUSE_GETLEVEL:
2158 *(int *)addr = sc->mode.level;
2159 break;
2160
2161 case MOUSE_SETLEVEL:
2162 if ((*(int *)addr < PSM_LEVEL_MIN) ||
2163 (*(int *)addr > PSM_LEVEL_MAX))
2164 return (EINVAL);
2165 sc->mode.level = *(int *)addr;
2166 break;
2167
2168 case MOUSE_GETSTATUS:
2169 s = spltty();
2170 status = sc->status;
2171 sc->status.flags = 0;
2172 sc->status.obutton = sc->status.button;
2173 sc->status.button = 0;
2174 sc->status.dx = 0;
2175 sc->status.dy = 0;
2176 sc->status.dz = 0;
2177 splx(s);
2178 *(mousestatus_t *)addr = status;
2179 break;
2180
2181#if (defined(MOUSE_GETVARS))
2182 case MOUSE_GETVARS:
2183 var = (mousevar_t *)addr;
2184 bzero(var, sizeof(*var));
2185 s = spltty();
2186 var->var[0] = MOUSE_VARS_PS2_SIG;
2187 var->var[1] = sc->config;
2188 var->var[2] = sc->flags;
2189 splx(s);
2190 break;
2191
2192 case MOUSE_SETVARS:
2193 return (ENODEV);
2194#endif /* MOUSE_GETVARS */
2195
2196 case MOUSE_READSTATE:
2197 case MOUSE_READDATA:
2198 data = (mousedata_t *)addr;
2199 if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
2200 return (EINVAL);
2201
2202 error = block_mouse_data(sc, &command_byte);
2203 if (error)
2204 return (error);
2205 if ((data->len = get_mouse_status(sc->kbdc, data->buf,
2206 (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
2207 error = EIO;
2208 unblock_mouse_data(sc, command_byte);
2209 break;
2210
2211#if (defined(MOUSE_SETRESOLUTION))
2212 case MOUSE_SETRESOLUTION:
2213 mode.resolution = *(int *)addr;
2214 if (mode.resolution >= UCHAR_MAX)
2215 return (EINVAL);
2216 else if (mode.resolution >= 200)
2217 mode.resolution = MOUSE_RES_HIGH;
2218 else if (mode.resolution >= 100)
2219 mode.resolution = MOUSE_RES_MEDIUMHIGH;
2220 else if (mode.resolution >= 50)
2221 mode.resolution = MOUSE_RES_MEDIUMLOW;
2222 else if (mode.resolution > 0)
2223 mode.resolution = MOUSE_RES_LOW;
2224 if (mode.resolution == MOUSE_RES_DEFAULT)
2225 mode.resolution = sc->dflt_mode.resolution;
2226 else if (mode.resolution == -1)
2227 mode.resolution = sc->mode.resolution;
2228 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2229 mode.resolution = MOUSE_RES_LOW - mode.resolution;
2230
2231 error = block_mouse_data(sc, &command_byte);
2232 if (error)
2233 return (error);
2234 sc->mode.resolution =
2235 set_mouse_resolution(sc->kbdc, mode.resolution);
2236 if (sc->mode.resolution != mode.resolution)
2237 error = EIO;
2238 unblock_mouse_data(sc, command_byte);
2239 break;
2240#endif /* MOUSE_SETRESOLUTION */
2241
2242#if (defined(MOUSE_SETRATE))
2243 case MOUSE_SETRATE:
2244 mode.rate = *(int *)addr;
2245 if (mode.rate > UCHAR_MAX)
2246 return (EINVAL);
2247 if (mode.rate == 0)
2248 mode.rate = sc->dflt_mode.rate;
2249 else if (mode.rate < 0)
2250 mode.rate = sc->mode.rate;
2251
2252 error = block_mouse_data(sc, &command_byte);
2253 if (error)
2254 return (error);
2255 sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
2256 if (sc->mode.rate != mode.rate)
2257 error = EIO;
2258 unblock_mouse_data(sc, command_byte);
2259 break;
2260#endif /* MOUSE_SETRATE */
2261
2262#if (defined(MOUSE_SETSCALING))
2263 case MOUSE_SETSCALING:
2264 if ((*(int *)addr <= 0) || (*(int *)addr > 2))
2265 return (EINVAL);
2266
2267 error = block_mouse_data(sc, &command_byte);
2268 if (error)
2269 return (error);
2270 if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
2271 error = EIO;
2272 unblock_mouse_data(sc, command_byte);
2273 break;
2274#endif /* MOUSE_SETSCALING */
2275
2276#if (defined(MOUSE_GETHWID))
2277 case MOUSE_GETHWID:
2278 error = block_mouse_data(sc, &command_byte);
2279 if (error)
2280 return (error);
2281 sc->hw.hwid &= ~0x00ff;
2282 sc->hw.hwid |= get_aux_id(sc->kbdc);
2283 *(int *)addr = sc->hw.hwid & 0x00ff;
2284 unblock_mouse_data(sc, command_byte);
2285 break;
2286#endif /* MOUSE_GETHWID */
2287
2288 case FIONBIO:
2289 case FIOASYNC:
2290 break;
2291 case FIOSETOWN:
2292 error = fsetown(*(int *)addr, &sc->async);
2293 break;
2294 case FIOGETOWN:
2295 *(int *) addr = fgetown(&sc->async);
2296 break;
2297 default:
2298 return (ENOTTY);
2299 }
2300
2301 return (error);
2302}
2303
2304static void
2305psmtimeout(void *arg)
2306{
2307 struct psm_softc *sc;
2308 int s;
2309
2310 sc = (struct psm_softc *)arg;
2311 s = spltty();
2312 if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
2313 VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
2314 psmintr(sc);
2315 kbdc_lock(sc->kbdc, FALSE);
2316 }
2317 sc->watchdog = TRUE;
2318 splx(s);
2319 callout_reset(&sc->callout, hz, psmtimeout, sc);
2320}
2321
2322/* Add all sysctls under the debug.psm and hw.psm nodes */
2323static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2324static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2325
2326SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
2327 "Verbosity level");
2328
2329static int psmhz = 20;
2330SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0,
2331 "Frequency of the softcallout (in hz)");
2332static int psmerrsecs = 2;
2333SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0,
2334 "Number of seconds during which packets will dropped after a sync error");
2335static int psmerrusecs = 0;
2336SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0,
2337 "Microseconds to add to psmerrsecs");
2338static int psmsecs = 0;
2339SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0,
2340 "Max number of seconds between soft interrupts");
2341static int psmusecs = 500000;
2342SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0,
2343 "Microseconds to add to psmsecs");
2344static int pkterrthresh = 2;
2345SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
2346 "Number of error packets allowed before reinitializing the mouse");
2347
2348SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
2349 "Enable tap and drag gestures");
2350static int tap_threshold = PSM_TAP_THRESHOLD;
2351SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
2352 "Button tap threshold");
2353static int tap_timeout = PSM_TAP_TIMEOUT;
2354SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
2355 "Tap timeout for touchpads");
2356
2357static void
2358psmintr(void *arg)
2359{
2360 struct psm_softc *sc = arg;
2361 struct timeval now;
2362 int c;
2363 packetbuf_t *pb;
2364
2365
2366 /* read until there is nothing to read */
2367 while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
2368 pb = &sc->pqueue[sc->pqueue_end];
2369
2370 /* discard the byte if the device is not open */
2371 if ((sc->state & PSM_OPEN) == 0)
2372 continue;
2373
2374 getmicrouptime(&now);
2375 if ((pb->inputbytes > 0) &&
2376 timevalcmp(&now, &sc->inputtimeout, >)) {
2377 VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
2378 "resetting byte count\n"));
2379 pb->inputbytes = 0;
2380 sc->syncerrors = 0;
2381 sc->pkterrors = 0;
2382 }
2383 sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
2384 sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
2385 timevaladd(&sc->inputtimeout, &now);
2386
2387 pb->ipacket[pb->inputbytes++] = c;
2388
2389 if (sc->mode.level == PSM_LEVEL_NATIVE) {
2390 VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
2391 sc->syncerrors = 0;
2392 sc->pkterrors = 0;
2393 goto next;
2394 } else {
2395 if (pb->inputbytes < sc->mode.packetsize)
2396 continue;
2397
2398 VLOG(4, (LOG_DEBUG,
2399 "psmintr: %02x %02x %02x %02x %02x %02x\n",
2400 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
2401 pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
2402 }
2403
2404 c = pb->ipacket[0];
2405
2406 if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2407 sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
2408 sc->flags &= ~PSM_NEED_SYNCBITS;
2409 VLOG(2, (LOG_DEBUG,
2410 "psmintr: Sync bytes now %04x,%04x\n",
2411 sc->mode.syncmask[0], sc->mode.syncmask[0]));
2412 } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
2413 VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
2414 "(%04x != %04x) %d cmds since last error.\n",
2415 c & sc->mode.syncmask[0], sc->mode.syncmask[1],
2416 sc->cmdcount - sc->lasterr));
2417 sc->lasterr = sc->cmdcount;
2418 /*
2419 * The sync byte test is a weak measure of packet
2420 * validity. Conservatively discard any input yet
2421 * to be seen by userland when we detect a sync
2422 * error since there is a good chance some of
2423 * the queued packets have undetected errors.
2424 */
2425 dropqueue(sc);
2426 if (sc->syncerrors == 0)
2427 sc->pkterrors++;
2428 ++sc->syncerrors;
2429 sc->lastinputerr = now;
2430 if (sc->syncerrors >= sc->mode.packetsize * 2 ||
2431 sc->pkterrors >= pkterrthresh) {
2432 /*
2433 * If we've failed to find a single sync byte
2434 * in 2 packets worth of data, or we've seen
2435 * persistent packet errors during the
2436 * validation period, reinitialize the mouse
2437 * in hopes of returning it to the expected
2438 * mode.
2439 */
2440 VLOG(3, (LOG_DEBUG,
2441 "psmintr: reset the mouse.\n"));
2442 reinitialize(sc, TRUE);
2443 } else if (sc->syncerrors == sc->mode.packetsize) {
2444 /*
2445 * Try a soft reset after searching for a sync
2446 * byte through a packet length of bytes.
2447 */
2448 VLOG(3, (LOG_DEBUG,
2449 "psmintr: re-enable the mouse.\n"));
2450 pb->inputbytes = 0;
2451 disable_aux_dev(sc->kbdc);
2452 enable_aux_dev(sc->kbdc);
2453 } else {
2454 VLOG(3, (LOG_DEBUG,
2455 "psmintr: discard a byte (%d)\n",
2456 sc->syncerrors));
2457 pb->inputbytes--;
2458 bcopy(&pb->ipacket[1], &pb->ipacket[0],
2459 pb->inputbytes);
2460 }
2461 continue;
2462 }
2463
2464 /*
2465 * We have what appears to be a valid packet.
2466 * Reset the error counters.
2467 */
2468 sc->syncerrors = 0;
2469
2470 /*
2471 * Drop even good packets if they occur within a timeout
2472 * period of a sync error. This allows the detection of
2473 * a change in the mouse's packet mode without exposing
2474 * erratic mouse behavior to the user. Some KVMs forget
2475 * enhanced mouse modes during switch events.
2476 */
2477 if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
2478 &now)) {
2479 pb->inputbytes = 0;
2480 continue;
2481 }
2482
2483 /*
2484 * Now that we're out of the validation period, reset
2485 * the packet error count.
2486 */
2487 sc->pkterrors = 0;
2488
2489 sc->cmdcount++;
2490next:
2491 if (++sc->pqueue_end >= PSM_PACKETQUEUE)
2492 sc->pqueue_end = 0;
2493 /*
2494 * If we've filled the queue then call the softintr ourselves,
2495 * otherwise schedule the interrupt for later.
2496 */
2497 if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
2498 (sc->pqueue_end == sc->pqueue_start)) {
2499 if ((sc->state & PSM_SOFTARMED) != 0) {
2500 sc->state &= ~PSM_SOFTARMED;
2501 callout_stop(&sc->softcallout);
2502 }
2503 psmsoftintr(arg);
2504 } else if ((sc->state & PSM_SOFTARMED) == 0) {
2505 sc->state |= PSM_SOFTARMED;
2506 callout_reset(&sc->softcallout,
2507 psmhz < 1 ? 1 : (hz/psmhz), psmsoftintr, arg);
2508 }
2509 }
2510}
2511
2512static void
2513proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2514 int *x, int *y, int *z)
2515{
2516
2517 /*
2518 * PS2++ protocol packet
2519 *
2520 * b7 b6 b5 b4 b3 b2 b1 b0
2521 * byte 1: * 1 p3 p2 1 * * *
2522 * byte 2: c1 c2 p1 p0 d1 d0 1 0
2523 *
2524 * p3-p0: packet type
2525 * c1, c2: c1 & c2 == 1, if p2 == 0
2526 * c1 & c2 == 0, if p2 == 1
2527 *
2528 * packet type: 0 (device type)
2529 * See comments in enable_mmanplus() below.
2530 *
2531 * packet type: 1 (wheel data)
2532 *
2533 * b7 b6 b5 b4 b3 b2 b1 b0
2534 * byte 3: h * B5 B4 s d2 d1 d0
2535 *
2536 * h: 1, if horizontal roller data
2537 * 0, if vertical roller data
2538 * B4, B5: button 4 and 5
2539 * s: sign bit
2540 * d2-d0: roller data
2541 *
2542 * packet type: 2 (reserved)
2543 */
2544 if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
2545 (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
2546 /*
2547 * the extended data packet encodes button
2548 * and wheel events
2549 */
2550 switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
2551 case 1:
2552 /* wheel data packet */
2553 *x = *y = 0;
2554 if (pb->ipacket[2] & 0x80) {
2555 /* XXX horizontal roller count - ignore it */
2556 ;
2557 } else {
2558 /* vertical roller count */
2559 *z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
2560 (pb->ipacket[2] & 0x0f) - 16 :
2561 (pb->ipacket[2] & 0x0f);
2562 }
2563 ms->button |= (pb->ipacket[2] &
2564 MOUSE_PS2PLUS_BUTTON4DOWN) ?
2565 MOUSE_BUTTON4DOWN : 0;
2566 ms->button |= (pb->ipacket[2] &
2567 MOUSE_PS2PLUS_BUTTON5DOWN) ?
2568 MOUSE_BUTTON5DOWN : 0;
2569 break;
2570 case 2:
2571 /*
2572 * this packet type is reserved by
2573 * Logitech...
2574 */
2575 /*
2576 * IBM ScrollPoint Mouse uses this
2577 * packet type to encode both vertical
2578 * and horizontal scroll movement.
2579 */
2580 *x = *y = 0;
2581 /* horizontal count */
2582 if (pb->ipacket[2] & 0x0f)
2583 *z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
2584 -2 : 2;
2585 /* vertical count */
2586 if (pb->ipacket[2] & 0xf0)
2587 *z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
2588 -1 : 1;
2589 break;
2590 case 0:
2591 /* device type packet - shouldn't happen */
2592 /* FALLTHROUGH */
2593 default:
2594 *x = *y = 0;
2595 ms->button = ms->obutton;
2596 VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
2597 "type %d: 0x%02x 0x%02x 0x%02x\n",
2598 MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
2599 pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
2600 break;
2601 }
2602 } else {
2603 /* preserve button states */
2604 ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
2605 }
2606}
2607
2608static int
2609proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2610 int *x, int *y, int *z)
2611{
2612 static int touchpad_buttons;
2613 static int guest_buttons;
2614 int w, x0, y0;
2615
2616 /* TouchPad PS/2 absolute mode message format with capFourButtons:
2617 *
2618 * Bits: 7 6 5 4 3 2 1 0 (LSB)
2619 * ------------------------------------------------
2620 * ipacket[0]: 1 0 W3 W2 0 W1 R L
2621 * ipacket[1]: Yb Ya Y9 Y8 Xb Xa X9 X8
2622 * ipacket[2]: Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
2623 * ipacket[3]: 1 1 Yc Xc 0 W0 D^R U^L
2624 * ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0
2625 * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
2626 *
2627 * Legend:
2628 * L: left physical mouse button
2629 * R: right physical mouse button
2630 * D: down button
2631 * U: up button
2632 * W: "wrist" value
2633 * X: x position
2634 * Y: y position
2635 * Z: pressure
2636 *
2637 * Without capFourButtons but with nExtendeButtons and/or capMiddle
2638 *
2639 * Bits: 7 6 5 4 3 2 1 0 (LSB)
2640 * ------------------------------------------------------
2641 * ipacket[3]: 1 1 Yc Xc 0 W0 E^R M^L
2642 * ipacket[4]: X7 X6 X5 X4 X3|b7 X2|b5 X1|b3 X0|b1
2643 * ipacket[5]: Y7 Y6 Y5 Y4 Y3|b8 Y2|b6 Y1|b4 Y0|b2
2644 *
2645 * Legend:
2646 * M: Middle physical mouse button
2647 * E: Extended mouse buttons reported instead of low bits of X and Y
2648 * b1-b8: Extended mouse buttons
2649 * Only ((nExtendedButtons + 1) >> 1) bits are used in packet
2650 * 4 and 5, for reading X and Y value they should be zeroed.
2651 *
2652 * Absolute reportable limits: 0 - 6143.
2653 * Typical bezel limits: 1472 - 5472.
2654 * Typical edge marings: 1632 - 5312.
2655 *
2656 * w = 3 Passthrough Packet
2657 *
2658 * Byte 2,5,6 == Byte 1,2,3 of "Guest"
2659 */
2660
2661 if (!synaptics_support)
2662 return (0);
2663
2664 /* Sanity check for out of sync packets. */
2665 if ((pb->ipacket[0] & 0xc8) != 0x80 ||
2666 (pb->ipacket[3] & 0xc8) != 0xc0)
2667 return (-1);
2668
2669 *x = *y = 0;
2670
2671 /*
2672 * Pressure value.
2673 * Interpretation:
2674 * z = 0 No finger contact
2675 * z = 10 Finger hovering near the pad
2676 * z = 30 Very light finger contact
2677 * z = 80 Normal finger contact
2678 * z = 110 Very heavy finger contact
2679 * z = 200 Finger lying flat on pad surface
2680 * z = 255 Maximum reportable Z
2681 */
2682 *z = pb->ipacket[2];
2683
2684 /*
2685 * Finger width value
2686 * Interpretation:
2687 * w = 0 Two finger on the pad (capMultiFinger needed)
2688 * w = 1 Three or more fingers (capMultiFinger needed)
2689 * w = 2 Pen (instead of finger) (capPen needed)
2690 * w = 3 Reserved (passthrough?)
2691 * w = 4-7 Finger of normal width (capPalmDetect needed)
2692 * w = 8-14 Very wide finger or palm (capPalmDetect needed)
2693 * w = 15 Maximum reportable width (capPalmDetect needed)
2694 */
2695 /* XXX Is checking capExtended enough? */
2696 if (sc->synhw.capExtended)
2697 w = ((pb->ipacket[0] & 0x30) >> 2) |
2698 ((pb->ipacket[0] & 0x04) >> 1) |
2699 ((pb->ipacket[3] & 0x04) >> 2);
2700 else {
2701 /* Assume a finger of regular width. */
2702 w = 4;
2703 }
2704
2705 /*
2706 * Handle packets from the guest device. See:
2707 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
2708 */
2709 if (w == 3 && sc->synhw.capPassthrough) {
2710 *x = ((pb->ipacket[1] & 0x10) ?
2711 pb->ipacket[4] - 256 : pb->ipacket[4]);
2712 *y = ((pb->ipacket[1] & 0x20) ?
2713 pb->ipacket[5] - 256 : pb->ipacket[5]);
2714 *z = 0;
2715
2716 guest_buttons = 0;
2717 if (pb->ipacket[1] & 0x01)
2718 guest_buttons |= MOUSE_BUTTON1DOWN;
2719 if (pb->ipacket[1] & 0x04)
2720 guest_buttons |= MOUSE_BUTTON2DOWN;
2721 if (pb->ipacket[1] & 0x02)
2722 guest_buttons |= MOUSE_BUTTON3DOWN;
2723
2724 ms->button = touchpad_buttons | guest_buttons;
2725 goto SYNAPTICS_END;
2726 }
2727
2728 /* Button presses */
2729 touchpad_buttons = 0;
2730 if (pb->ipacket[0] & 0x01)
2731 touchpad_buttons |= MOUSE_BUTTON1DOWN;
2732 if (pb->ipacket[0] & 0x02)
2733 touchpad_buttons |= MOUSE_BUTTON3DOWN;
2734
2735 if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
2736 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01)
2737 touchpad_buttons |= MOUSE_BUTTON4DOWN;
2738 if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
2739 touchpad_buttons |= MOUSE_BUTTON5DOWN;
2740 } else if (sc->synhw.capExtended && sc->synhw.capMiddle) {
2741 /* Middle Button */
2742 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2743 touchpad_buttons |= MOUSE_BUTTON2DOWN;
2744 } else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
2745 /* Extended Buttons */
2746 if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
2747 if (sc->syninfo.directional_scrolls) {
2748 if (pb->ipacket[4] & 0x01)
2749 touchpad_buttons |= MOUSE_BUTTON4DOWN;
2750 if (pb->ipacket[5] & 0x01)
2751 touchpad_buttons |= MOUSE_BUTTON5DOWN;
2752 if (pb->ipacket[4] & 0x02)
2753 touchpad_buttons |= MOUSE_BUTTON6DOWN;
2754 if (pb->ipacket[5] & 0x02)
2755 touchpad_buttons |= MOUSE_BUTTON7DOWN;
2756 } else {
2755 touchpad_buttons |= MOUSE_BUTTON2DOWN;
2757 if (pb->ipacket[4] & 0x01)
2758 touchpad_buttons |= MOUSE_BUTTON1DOWN;
2759 if (pb->ipacket[5] & 0x01)
2760 touchpad_buttons |= MOUSE_BUTTON3DOWN;
2761 if (pb->ipacket[4] & 0x02)
2762 touchpad_buttons |= MOUSE_BUTTON2DOWN;
2763 sc->extended_buttons = touchpad_buttons;
2756 }
2757
2758 /*
2759 * Zero out bits used by extended buttons to avoid
2760 * misinterpretation of the data absolute position.
2761 *
2762 * The bits represented by
2763 *
2764 * (nExtendedButtons + 1) >> 1
2765 *
2766 * will be masked out in both bytes.
2767 * The mask for n bits is computed with the formula
2768 *
2769 * (1 << n) - 1
2770 */
2771 int maskedbits = 0;
2772 int mask = 0;
2773 maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
2774 mask = (1 << maskedbits) - 1;
2775 pb->ipacket[4] &= ~(mask);
2776 pb->ipacket[5] &= ~(mask);
2764 }
2765
2766 /*
2767 * Zero out bits used by extended buttons to avoid
2768 * misinterpretation of the data absolute position.
2769 *
2770 * The bits represented by
2771 *
2772 * (nExtendedButtons + 1) >> 1
2773 *
2774 * will be masked out in both bytes.
2775 * The mask for n bits is computed with the formula
2776 *
2777 * (1 << n) - 1
2778 */
2779 int maskedbits = 0;
2780 int mask = 0;
2781 maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
2782 mask = (1 << maskedbits) - 1;
2783 pb->ipacket[4] &= ~(mask);
2784 pb->ipacket[5] &= ~(mask);
2785 } else if (!sc->syninfo.directional_scrolls &&
2786 !sc->synaction.in_vscroll) {
2787 /*
2788 * Keep reporting MOUSE DOWN until we get a new packet
2789 * indicating otherwise.
2790 */
2791 touchpad_buttons |= sc->extended_buttons;
2777 }
2778 }
2792 }
2793 }
2794 /* Handle ClickPad. */
2795 if (sc->synhw.capClickPad &&
2796 ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
2797 touchpad_buttons |= MOUSE_BUTTON1DOWN;
2779
2780 ms->button = touchpad_buttons | guest_buttons;
2781
2798
2799 ms->button = touchpad_buttons | guest_buttons;
2800
2782 /* Check pressure to detect a real wanted action on the
2783 * touchpad. */
2801 /*
2802 * Check pressure to detect a real wanted action on the
2803 * touchpad.
2804 */
2784 if (*z >= sc->syninfo.min_pressure) {
2785 synapticsaction_t *synaction;
2786 int cursor, peer, window;
2787 int dx, dy, dxp, dyp;
2788 int max_width, max_pressure;
2789 int margin_top, margin_right, margin_bottom, margin_left;
2790 int na_top, na_right, na_bottom, na_left;
2791 int window_min, window_max;
2792 int multiplicator;
2793 int weight_current, weight_previous, weight_len_squared;
2794 int div_min, div_max, div_len;
2795 int vscroll_hor_area, vscroll_ver_area;
2805 if (*z >= sc->syninfo.min_pressure) {
2806 synapticsaction_t *synaction;
2807 int cursor, peer, window;
2808 int dx, dy, dxp, dyp;
2809 int max_width, max_pressure;
2810 int margin_top, margin_right, margin_bottom, margin_left;
2811 int na_top, na_right, na_bottom, na_left;
2812 int window_min, window_max;
2813 int multiplicator;
2814 int weight_current, weight_previous, weight_len_squared;
2815 int div_min, div_max, div_len;
2816 int vscroll_hor_area, vscroll_ver_area;
2796
2817 int two_finger_scroll;
2797 int len, weight_prev_x, weight_prev_y;
2798 int div_max_x, div_max_y, div_x, div_y;
2799
2800 /* Read sysctl. */
2801 /* XXX Verify values? */
2802 max_width = sc->syninfo.max_width;
2803 max_pressure = sc->syninfo.max_pressure;
2804 margin_top = sc->syninfo.margin_top;
2805 margin_right = sc->syninfo.margin_right;
2806 margin_bottom = sc->syninfo.margin_bottom;
2807 margin_left = sc->syninfo.margin_left;
2808 na_top = sc->syninfo.na_top;
2809 na_right = sc->syninfo.na_right;
2810 na_bottom = sc->syninfo.na_bottom;
2811 na_left = sc->syninfo.na_left;
2812 window_min = sc->syninfo.window_min;
2813 window_max = sc->syninfo.window_max;
2814 multiplicator = sc->syninfo.multiplicator;
2815 weight_current = sc->syninfo.weight_current;
2816 weight_previous = sc->syninfo.weight_previous;
2817 weight_len_squared = sc->syninfo.weight_len_squared;
2818 div_min = sc->syninfo.div_min;
2819 div_max = sc->syninfo.div_max;
2820 div_len = sc->syninfo.div_len;
2821 vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2822 vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2818 int len, weight_prev_x, weight_prev_y;
2819 int div_max_x, div_max_y, div_x, div_y;
2820
2821 /* Read sysctl. */
2822 /* XXX Verify values? */
2823 max_width = sc->syninfo.max_width;
2824 max_pressure = sc->syninfo.max_pressure;
2825 margin_top = sc->syninfo.margin_top;
2826 margin_right = sc->syninfo.margin_right;
2827 margin_bottom = sc->syninfo.margin_bottom;
2828 margin_left = sc->syninfo.margin_left;
2829 na_top = sc->syninfo.na_top;
2830 na_right = sc->syninfo.na_right;
2831 na_bottom = sc->syninfo.na_bottom;
2832 na_left = sc->syninfo.na_left;
2833 window_min = sc->syninfo.window_min;
2834 window_max = sc->syninfo.window_max;
2835 multiplicator = sc->syninfo.multiplicator;
2836 weight_current = sc->syninfo.weight_current;
2837 weight_previous = sc->syninfo.weight_previous;
2838 weight_len_squared = sc->syninfo.weight_len_squared;
2839 div_min = sc->syninfo.div_min;
2840 div_max = sc->syninfo.div_max;
2841 div_len = sc->syninfo.div_len;
2842 vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2843 vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2844 two_finger_scroll = sc->syninfo.two_finger_scroll;
2823
2824 /* Palm detection. */
2825 if (!(
2826 (sc->synhw.capMultiFinger && (w == 0 || w == 1)) ||
2827 (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
2828 (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
2829 (sc->synhw.capPen && w == 2))) {
2830 /*
2831 * We consider the packet irrelevant for the current
2832 * action when:
2833 * - the width isn't comprised in:
2834 * [4; max_width]
2835 * - the pressure isn't comprised in:
2836 * [min_pressure; max_pressure]
2837 * - pen aren't supported but w is 2
2838 *
2839 * Note that this doesn't terminate the current action.
2840 */
2841 VLOG(2, (LOG_DEBUG,
2842 "synaptics: palm detected! (%d)\n", w));
2843 goto SYNAPTICS_END;
2844 }
2845
2846 /* Read current absolute position. */
2847 x0 = ((pb->ipacket[3] & 0x10) << 8) |
2848 ((pb->ipacket[1] & 0x0f) << 8) |
2849 pb->ipacket[4];
2850 y0 = ((pb->ipacket[3] & 0x20) << 7) |
2851 ((pb->ipacket[1] & 0xf0) << 4) |
2852 pb->ipacket[5];
2853
2854 synaction = &(sc->synaction);
2855
2856 /*
2857 * If the action is just beginning, init the structure and
2858 * compute tap timeout.
2859 */
2860 if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
2861 VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
2862
2863 /* Store the first point of this action. */
2864 synaction->start_x = x0;
2865 synaction->start_y = y0;
2866 dx = dy = 0;
2867
2868 /* Initialize queue. */
2869 synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
2870 synaction->queue_len = 0;
2871 synaction->window_min = window_min;
2872
2873 /* Reset average. */
2874 synaction->avg_dx = 0;
2875 synaction->avg_dy = 0;
2876
2877 /* Reset squelch. */
2878 synaction->squelch_x = 0;
2879 synaction->squelch_y = 0;
2880
2881 /* Reset pressure peak. */
2882 sc->zmax = 0;
2883
2884 /* Reset fingers count. */
2885 synaction->fingers_nb = 0;
2886
2887 /* Reset virtual scrolling state. */
2888 synaction->in_vscroll = 0;
2889
2890 /* Compute tap timeout. */
2891 sc->taptimeout.tv_sec = tap_timeout / 1000000;
2892 sc->taptimeout.tv_usec = tap_timeout % 1000000;
2893 timevaladd(&sc->taptimeout, &sc->lastsoftintr);
2894
2895 sc->flags |= PSM_FLAGS_FINGERDOWN;
2896 } else {
2897 /* Calculate the current delta. */
2898 cursor = synaction->queue_cursor;
2899 dx = x0 - synaction->queue[cursor].x;
2900 dy = y0 - synaction->queue[cursor].y;
2901 }
2902
2903 /* If in tap-hold, add the recorded button. */
2904 if (synaction->in_taphold)
2905 ms->button |= synaction->tap_button;
2906
2907 /*
2908 * From now on, we can use the SYNAPTICS_END label to skip
2909 * the current packet.
2910 */
2911
2912 /*
2913 * Limit the coordinates to the specified margins because
2914 * this area isn't very reliable.
2915 */
2916 if (x0 <= margin_left)
2917 x0 = margin_left;
2918 else if (x0 >= 6143 - margin_right)
2919 x0 = 6143 - margin_right;
2920 if (y0 <= margin_bottom)
2921 y0 = margin_bottom;
2922 else if (y0 >= 6143 - margin_top)
2923 y0 = 6143 - margin_top;
2924
2925 VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
2926 x0, y0, *z, w));
2927
2928 /* Queue this new packet. */
2929 cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
2930 synaction->queue[cursor].x = x0;
2931 synaction->queue[cursor].y = y0;
2932 synaction->queue_cursor = cursor;
2933 if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
2934 synaction->queue_len++;
2935 VLOG(5, (LOG_DEBUG,
2936 "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
2937 cursor, x0, y0, dx, dy));
2938
2939 /*
2940 * For tap, we keep the maximum number of fingers and the
2941 * pressure peak. Also with multiple fingers, we increase
2942 * the minimum window.
2943 */
2944 switch (w) {
2945 case 1: /* Three or more fingers. */
2946 synaction->fingers_nb = imax(3, synaction->fingers_nb);
2947 synaction->window_min = window_max;
2948 break;
2949 case 0: /* Two fingers. */
2950 synaction->fingers_nb = imax(2, synaction->fingers_nb);
2951 synaction->window_min = window_max;
2952 break;
2953 default: /* One finger or undetectable. */
2954 synaction->fingers_nb = imax(1, synaction->fingers_nb);
2955 }
2956 sc->zmax = imax(*z, sc->zmax);
2957
2958 /* Do we have enough packets to consider this a movement? */
2959 if (synaction->queue_len < synaction->window_min)
2960 goto SYNAPTICS_END;
2961
2962 /* Is a scrolling action occuring? */
2963 if (!synaction->in_taphold && !synaction->in_vscroll) {
2964 /*
2965 * A scrolling action must not conflict with a tap
2966 * action. Here are the conditions to consider a
2967 * scrolling action:
2968 * - the action in a configurable area
2969 * - one of the following:
2970 * . the distance between the last packet and the
2971 * first should be above a configurable minimum
2972 * . tap timed out
2973 */
2974 dxp = abs(synaction->queue[synaction->queue_cursor].x -
2975 synaction->start_x);
2976 dyp = abs(synaction->queue[synaction->queue_cursor].y -
2977 synaction->start_y);
2978
2979 if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
2980 dxp >= sc->syninfo.vscroll_min_delta ||
2981 dyp >= sc->syninfo.vscroll_min_delta) {
2845
2846 /* Palm detection. */
2847 if (!(
2848 (sc->synhw.capMultiFinger && (w == 0 || w == 1)) ||
2849 (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
2850 (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
2851 (sc->synhw.capPen && w == 2))) {
2852 /*
2853 * We consider the packet irrelevant for the current
2854 * action when:
2855 * - the width isn't comprised in:
2856 * [4; max_width]
2857 * - the pressure isn't comprised in:
2858 * [min_pressure; max_pressure]
2859 * - pen aren't supported but w is 2
2860 *
2861 * Note that this doesn't terminate the current action.
2862 */
2863 VLOG(2, (LOG_DEBUG,
2864 "synaptics: palm detected! (%d)\n", w));
2865 goto SYNAPTICS_END;
2866 }
2867
2868 /* Read current absolute position. */
2869 x0 = ((pb->ipacket[3] & 0x10) << 8) |
2870 ((pb->ipacket[1] & 0x0f) << 8) |
2871 pb->ipacket[4];
2872 y0 = ((pb->ipacket[3] & 0x20) << 7) |
2873 ((pb->ipacket[1] & 0xf0) << 4) |
2874 pb->ipacket[5];
2875
2876 synaction = &(sc->synaction);
2877
2878 /*
2879 * If the action is just beginning, init the structure and
2880 * compute tap timeout.
2881 */
2882 if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
2883 VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
2884
2885 /* Store the first point of this action. */
2886 synaction->start_x = x0;
2887 synaction->start_y = y0;
2888 dx = dy = 0;
2889
2890 /* Initialize queue. */
2891 synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
2892 synaction->queue_len = 0;
2893 synaction->window_min = window_min;
2894
2895 /* Reset average. */
2896 synaction->avg_dx = 0;
2897 synaction->avg_dy = 0;
2898
2899 /* Reset squelch. */
2900 synaction->squelch_x = 0;
2901 synaction->squelch_y = 0;
2902
2903 /* Reset pressure peak. */
2904 sc->zmax = 0;
2905
2906 /* Reset fingers count. */
2907 synaction->fingers_nb = 0;
2908
2909 /* Reset virtual scrolling state. */
2910 synaction->in_vscroll = 0;
2911
2912 /* Compute tap timeout. */
2913 sc->taptimeout.tv_sec = tap_timeout / 1000000;
2914 sc->taptimeout.tv_usec = tap_timeout % 1000000;
2915 timevaladd(&sc->taptimeout, &sc->lastsoftintr);
2916
2917 sc->flags |= PSM_FLAGS_FINGERDOWN;
2918 } else {
2919 /* Calculate the current delta. */
2920 cursor = synaction->queue_cursor;
2921 dx = x0 - synaction->queue[cursor].x;
2922 dy = y0 - synaction->queue[cursor].y;
2923 }
2924
2925 /* If in tap-hold, add the recorded button. */
2926 if (synaction->in_taphold)
2927 ms->button |= synaction->tap_button;
2928
2929 /*
2930 * From now on, we can use the SYNAPTICS_END label to skip
2931 * the current packet.
2932 */
2933
2934 /*
2935 * Limit the coordinates to the specified margins because
2936 * this area isn't very reliable.
2937 */
2938 if (x0 <= margin_left)
2939 x0 = margin_left;
2940 else if (x0 >= 6143 - margin_right)
2941 x0 = 6143 - margin_right;
2942 if (y0 <= margin_bottom)
2943 y0 = margin_bottom;
2944 else if (y0 >= 6143 - margin_top)
2945 y0 = 6143 - margin_top;
2946
2947 VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
2948 x0, y0, *z, w));
2949
2950 /* Queue this new packet. */
2951 cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
2952 synaction->queue[cursor].x = x0;
2953 synaction->queue[cursor].y = y0;
2954 synaction->queue_cursor = cursor;
2955 if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
2956 synaction->queue_len++;
2957 VLOG(5, (LOG_DEBUG,
2958 "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
2959 cursor, x0, y0, dx, dy));
2960
2961 /*
2962 * For tap, we keep the maximum number of fingers and the
2963 * pressure peak. Also with multiple fingers, we increase
2964 * the minimum window.
2965 */
2966 switch (w) {
2967 case 1: /* Three or more fingers. */
2968 synaction->fingers_nb = imax(3, synaction->fingers_nb);
2969 synaction->window_min = window_max;
2970 break;
2971 case 0: /* Two fingers. */
2972 synaction->fingers_nb = imax(2, synaction->fingers_nb);
2973 synaction->window_min = window_max;
2974 break;
2975 default: /* One finger or undetectable. */
2976 synaction->fingers_nb = imax(1, synaction->fingers_nb);
2977 }
2978 sc->zmax = imax(*z, sc->zmax);
2979
2980 /* Do we have enough packets to consider this a movement? */
2981 if (synaction->queue_len < synaction->window_min)
2982 goto SYNAPTICS_END;
2983
2984 /* Is a scrolling action occuring? */
2985 if (!synaction->in_taphold && !synaction->in_vscroll) {
2986 /*
2987 * A scrolling action must not conflict with a tap
2988 * action. Here are the conditions to consider a
2989 * scrolling action:
2990 * - the action in a configurable area
2991 * - one of the following:
2992 * . the distance between the last packet and the
2993 * first should be above a configurable minimum
2994 * . tap timed out
2995 */
2996 dxp = abs(synaction->queue[synaction->queue_cursor].x -
2997 synaction->start_x);
2998 dyp = abs(synaction->queue[synaction->queue_cursor].y -
2999 synaction->start_y);
3000
3001 if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
3002 dxp >= sc->syninfo.vscroll_min_delta ||
3003 dyp >= sc->syninfo.vscroll_min_delta) {
2982 /* Check for horizontal scrolling. */
2983 if ((vscroll_hor_area > 0 &&
2984 synaction->start_y <= vscroll_hor_area) ||
2985 (vscroll_hor_area < 0 &&
2986 synaction->start_y >=
2987 6143 + vscroll_hor_area))
2988 synaction->in_vscroll += 2;
3004 /*
3005 * Handle two finger scrolling.
3006 * Note that we don't rely on fingers_nb
3007 * as that keeps the maximum number of fingers.
3008 */
3009 if (two_finger_scroll) {
3010 if (w == 0) {
3011 synaction->in_vscroll +=
3012 dyp ? 2 : 0;
3013 synaction->in_vscroll +=
3014 dxp ? 1 : 0;
3015 }
3016 } else {
3017 /* Check for horizontal scrolling. */
3018 if ((vscroll_hor_area > 0 &&
3019 synaction->start_y <=
3020 vscroll_hor_area) ||
3021 (vscroll_hor_area < 0 &&
3022 synaction->start_y >=
3023 6143 + vscroll_hor_area))
3024 synaction->in_vscroll += 2;
2989
3025
2990 /* Check for vertical scrolling. */
2991 if ((vscroll_ver_area > 0 &&
2992 synaction->start_x <= vscroll_ver_area) ||
2993 (vscroll_ver_area < 0 &&
2994 synaction->start_x >=
2995 6143 + vscroll_ver_area))
2996 synaction->in_vscroll += 1;
3026 /* Check for vertical scrolling. */
3027 if ((vscroll_ver_area > 0 &&
3028 synaction->start_x <=
3029 vscroll_ver_area) ||
3030 (vscroll_ver_area < 0 &&
3031 synaction->start_x >=
3032 6143 + vscroll_ver_area))
3033 synaction->in_vscroll += 1;
3034 }
2997
2998 /* Avoid conflicts if area overlaps. */
3035
3036 /* Avoid conflicts if area overlaps. */
2999 if (synaction->in_vscroll == 3)
3037 if (synaction->in_vscroll >= 3)
3000 synaction->in_vscroll =
3001 (dxp > dyp) ? 2 : 1;
3002 }
3038 synaction->in_vscroll =
3039 (dxp > dyp) ? 2 : 1;
3040 }
3003 VLOG(5, (LOG_DEBUG,
3004 "synaptics: virtual scrolling: %s "
3005 "(direction=%d, dxp=%d, dyp=%d)\n",
3006 synaction->in_vscroll ? "YES" : "NO",
3007 synaction->in_vscroll, dxp, dyp));
3008 }
3041 }
3042 /*
3043 * Reset two finger scrolling when the number of fingers
3044 * is different from two.
3045 */
3046 if (two_finger_scroll && w != 0)
3047 synaction->in_vscroll = 0;
3009
3048
3049 VLOG(5, (LOG_DEBUG,
3050 "synaptics: virtual scrolling: %s "
3051 "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3052 synaction->in_vscroll ? "YES" : "NO",
3053 synaction->in_vscroll, dxp, dyp,
3054 synaction->fingers_nb));
3055
3010 weight_prev_x = weight_prev_y = weight_previous;
3011 div_max_x = div_max_y = div_max;
3012
3013 if (synaction->in_vscroll) {
3014 /* Dividers are different with virtual scrolling. */
3015 div_min = sc->syninfo.vscroll_div_min;
3016 div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3017 } else {
3018 /*
3019 * There's a lot of noise in coordinates when
3020 * the finger is on the touchpad's borders. When
3021 * using this area, we apply a special weight and
3022 * div.
3023 */
3024 if (x0 <= na_left || x0 >= 6143 - na_right) {
3025 weight_prev_x = sc->syninfo.weight_previous_na;
3026 div_max_x = sc->syninfo.div_max_na;
3027 }
3028
3029 if (y0 <= na_bottom || y0 >= 6143 - na_top) {
3030 weight_prev_y = sc->syninfo.weight_previous_na;
3031 div_max_y = sc->syninfo.div_max_na;
3032 }
3033 }
3034
3035 /*
3036 * Calculate weights for the average operands and
3037 * the divisor. Both depend on the distance between
3038 * the current packet and a previous one (based on the
3039 * window width).
3040 */
3041 window = imin(synaction->queue_len, window_max);
3042 peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3043 dxp = abs(x0 - synaction->queue[peer].x) + 1;
3044 dyp = abs(y0 - synaction->queue[peer].y) + 1;
3045 len = (dxp * dxp) + (dyp * dyp);
3046 weight_prev_x = imin(weight_prev_x,
3047 weight_len_squared * weight_prev_x / len);
3048 weight_prev_y = imin(weight_prev_y,
3049 weight_len_squared * weight_prev_y / len);
3050
3051 len = (dxp + dyp) / 2;
3052 div_x = div_len * div_max_x / len;
3053 div_x = imin(div_max_x, div_x);
3054 div_x = imax(div_min, div_x);
3055 div_y = div_len * div_max_y / len;
3056 div_y = imin(div_max_y, div_y);
3057 div_y = imax(div_min, div_y);
3058
3059 VLOG(3, (LOG_DEBUG,
3060 "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3061 peer, len, weight_prev_x, weight_prev_y, div_x, div_y));
3062
3063 /* Compute averages. */
3064 synaction->avg_dx =
3065 (weight_current * dx * multiplicator +
3066 weight_prev_x * synaction->avg_dx) /
3067 (weight_current + weight_prev_x);
3068
3069 synaction->avg_dy =
3070 (weight_current * dy * multiplicator +
3071 weight_prev_y * synaction->avg_dy) /
3072 (weight_current + weight_prev_y);
3073
3074 VLOG(5, (LOG_DEBUG,
3075 "synaptics: avg_dx~=%d, avg_dy~=%d\n",
3076 synaction->avg_dx / multiplicator,
3077 synaction->avg_dy / multiplicator));
3078
3079 /* Use these averages to calculate x & y. */
3080 synaction->squelch_x += synaction->avg_dx;
3081 *x = synaction->squelch_x / (div_x * multiplicator);
3082 synaction->squelch_x = synaction->squelch_x %
3083 (div_x * multiplicator);
3084
3085 synaction->squelch_y += synaction->avg_dy;
3086 *y = synaction->squelch_y / (div_y * multiplicator);
3087 synaction->squelch_y = synaction->squelch_y %
3088 (div_y * multiplicator);
3089
3090 if (synaction->in_vscroll) {
3091 switch(synaction->in_vscroll) {
3092 case 1: /* Vertical scrolling. */
3093 if (*y != 0)
3094 ms->button |= (*y > 0) ?
3095 MOUSE_BUTTON4DOWN :
3096 MOUSE_BUTTON5DOWN;
3097 break;
3098 case 2: /* Horizontal scrolling. */
3099 if (*x != 0)
3100 ms->button |= (*x > 0) ?
3101 MOUSE_BUTTON7DOWN :
3102 MOUSE_BUTTON6DOWN;
3103 break;
3104 }
3105
3106 /* The pointer is not moved. */
3107 *x = *y = 0;
3108 } else {
3109 VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n",
3110 dx, dy, *x, *y));
3111 }
3112 } else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3113 /*
3114 * An action is currently taking place but the pressure
3115 * dropped under the minimum, putting an end to it.
3116 */
3117 synapticsaction_t *synaction;
3118 int taphold_timeout, dx, dy, tap_max_delta;
3119
3120 synaction = &(sc->synaction);
3121 dx = abs(synaction->queue[synaction->queue_cursor].x -
3122 synaction->start_x);
3123 dy = abs(synaction->queue[synaction->queue_cursor].y -
3124 synaction->start_y);
3125
3126 /* Max delta is disabled for multi-fingers tap. */
3127 if (synaction->fingers_nb > 1)
3128 tap_max_delta = imax(dx, dy);
3129 else
3130 tap_max_delta = sc->syninfo.tap_max_delta;
3131
3132 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3133
3134 /* Check for tap. */
3135 VLOG(3, (LOG_DEBUG,
3136 "synaptics: zmax=%d, dx=%d, dy=%d, "
3137 "delta=%d, fingers=%d, queue=%d\n",
3138 sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
3139 synaction->queue_len));
3140 if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
3141 timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
3142 dx <= tap_max_delta && dy <= tap_max_delta &&
3143 synaction->queue_len >= sc->syninfo.tap_min_queue) {
3144 /*
3145 * We have a tap if:
3146 * - the maximum pressure went over tap_threshold
3147 * - the action ended before tap_timeout
3148 *
3149 * To handle tap-hold, we must delay any button push to
3150 * the next action.
3151 */
3152 if (synaction->in_taphold) {
3153 /*
3154 * This is the second and last tap of a
3155 * double tap action, not a tap-hold.
3156 */
3157 synaction->in_taphold = 0;
3158
3159 /*
3160 * For double-tap to work:
3161 * - no button press is emitted (to
3162 * simulate a button release)
3163 * - PSM_FLAGS_FINGERDOWN is set to
3164 * force the next packet to emit a
3165 * button press)
3166 */
3167 VLOG(2, (LOG_DEBUG,
3168 "synaptics: button RELEASE: %d\n",
3169 synaction->tap_button));
3170 sc->flags |= PSM_FLAGS_FINGERDOWN;
3171 } else {
3172 /*
3173 * This is the first tap: we set the
3174 * tap-hold state and notify the button
3175 * down event.
3176 */
3177 synaction->in_taphold = 1;
3178 taphold_timeout = sc->syninfo.taphold_timeout;
3179 sc->taptimeout.tv_sec = taphold_timeout /
3180 1000000;
3181 sc->taptimeout.tv_usec = taphold_timeout %
3182 1000000;
3183 timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3184
3185 switch (synaction->fingers_nb) {
3186 case 3:
3187 synaction->tap_button =
3188 MOUSE_BUTTON2DOWN;
3189 break;
3190 case 2:
3191 synaction->tap_button =
3192 MOUSE_BUTTON3DOWN;
3193 break;
3194 default:
3195 synaction->tap_button =
3196 MOUSE_BUTTON1DOWN;
3197 }
3198 VLOG(2, (LOG_DEBUG,
3199 "synaptics: button PRESS: %d\n",
3200 synaction->tap_button));
3201 ms->button |= synaction->tap_button;
3202 }
3203 } else {
3204 /*
3205 * Not enough pressure or timeout: reset
3206 * tap-hold state.
3207 */
3208 if (synaction->in_taphold) {
3209 VLOG(2, (LOG_DEBUG,
3210 "synaptics: button RELEASE: %d\n",
3211 synaction->tap_button));
3212 synaction->in_taphold = 0;
3213 } else {
3214 VLOG(2, (LOG_DEBUG,
3215 "synaptics: not a tap-hold\n"));
3216 }
3217 }
3218 } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3219 sc->synaction.in_taphold) {
3220 /*
3221 * For a tap-hold to work, the button must remain down at
3222 * least until timeout (where the in_taphold flags will be
3223 * cleared) or during the next action.
3224 */
3225 if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3226 ms->button |= sc->synaction.tap_button;
3227 } else {
3228 VLOG(2, (LOG_DEBUG,
3229 "synaptics: button RELEASE: %d\n",
3230 sc->synaction.tap_button));
3231 sc->synaction.in_taphold = 0;
3232 }
3233 }
3234
3235SYNAPTICS_END:
3236 /*
3237 * Use the extra buttons as a scrollwheel
3238 *
3239 * XXX X.Org uses the Z axis for vertical wheel only,
3240 * whereas moused(8) understands special values to differ
3241 * vertical and horizontal wheels.
3242 *
3243 * xf86-input-mouse needs therefore a small patch to
3244 * understand these special values. Without it, the
3245 * horizontal wheel acts as a vertical wheel in X.Org.
3246 *
3247 * That's why the horizontal wheel is disabled by
3248 * default for now.
3249 */
3056 weight_prev_x = weight_prev_y = weight_previous;
3057 div_max_x = div_max_y = div_max;
3058
3059 if (synaction->in_vscroll) {
3060 /* Dividers are different with virtual scrolling. */
3061 div_min = sc->syninfo.vscroll_div_min;
3062 div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3063 } else {
3064 /*
3065 * There's a lot of noise in coordinates when
3066 * the finger is on the touchpad's borders. When
3067 * using this area, we apply a special weight and
3068 * div.
3069 */
3070 if (x0 <= na_left || x0 >= 6143 - na_right) {
3071 weight_prev_x = sc->syninfo.weight_previous_na;
3072 div_max_x = sc->syninfo.div_max_na;
3073 }
3074
3075 if (y0 <= na_bottom || y0 >= 6143 - na_top) {
3076 weight_prev_y = sc->syninfo.weight_previous_na;
3077 div_max_y = sc->syninfo.div_max_na;
3078 }
3079 }
3080
3081 /*
3082 * Calculate weights for the average operands and
3083 * the divisor. Both depend on the distance between
3084 * the current packet and a previous one (based on the
3085 * window width).
3086 */
3087 window = imin(synaction->queue_len, window_max);
3088 peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3089 dxp = abs(x0 - synaction->queue[peer].x) + 1;
3090 dyp = abs(y0 - synaction->queue[peer].y) + 1;
3091 len = (dxp * dxp) + (dyp * dyp);
3092 weight_prev_x = imin(weight_prev_x,
3093 weight_len_squared * weight_prev_x / len);
3094 weight_prev_y = imin(weight_prev_y,
3095 weight_len_squared * weight_prev_y / len);
3096
3097 len = (dxp + dyp) / 2;
3098 div_x = div_len * div_max_x / len;
3099 div_x = imin(div_max_x, div_x);
3100 div_x = imax(div_min, div_x);
3101 div_y = div_len * div_max_y / len;
3102 div_y = imin(div_max_y, div_y);
3103 div_y = imax(div_min, div_y);
3104
3105 VLOG(3, (LOG_DEBUG,
3106 "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3107 peer, len, weight_prev_x, weight_prev_y, div_x, div_y));
3108
3109 /* Compute averages. */
3110 synaction->avg_dx =
3111 (weight_current * dx * multiplicator +
3112 weight_prev_x * synaction->avg_dx) /
3113 (weight_current + weight_prev_x);
3114
3115 synaction->avg_dy =
3116 (weight_current * dy * multiplicator +
3117 weight_prev_y * synaction->avg_dy) /
3118 (weight_current + weight_prev_y);
3119
3120 VLOG(5, (LOG_DEBUG,
3121 "synaptics: avg_dx~=%d, avg_dy~=%d\n",
3122 synaction->avg_dx / multiplicator,
3123 synaction->avg_dy / multiplicator));
3124
3125 /* Use these averages to calculate x & y. */
3126 synaction->squelch_x += synaction->avg_dx;
3127 *x = synaction->squelch_x / (div_x * multiplicator);
3128 synaction->squelch_x = synaction->squelch_x %
3129 (div_x * multiplicator);
3130
3131 synaction->squelch_y += synaction->avg_dy;
3132 *y = synaction->squelch_y / (div_y * multiplicator);
3133 synaction->squelch_y = synaction->squelch_y %
3134 (div_y * multiplicator);
3135
3136 if (synaction->in_vscroll) {
3137 switch(synaction->in_vscroll) {
3138 case 1: /* Vertical scrolling. */
3139 if (*y != 0)
3140 ms->button |= (*y > 0) ?
3141 MOUSE_BUTTON4DOWN :
3142 MOUSE_BUTTON5DOWN;
3143 break;
3144 case 2: /* Horizontal scrolling. */
3145 if (*x != 0)
3146 ms->button |= (*x > 0) ?
3147 MOUSE_BUTTON7DOWN :
3148 MOUSE_BUTTON6DOWN;
3149 break;
3150 }
3151
3152 /* The pointer is not moved. */
3153 *x = *y = 0;
3154 } else {
3155 VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n",
3156 dx, dy, *x, *y));
3157 }
3158 } else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3159 /*
3160 * An action is currently taking place but the pressure
3161 * dropped under the minimum, putting an end to it.
3162 */
3163 synapticsaction_t *synaction;
3164 int taphold_timeout, dx, dy, tap_max_delta;
3165
3166 synaction = &(sc->synaction);
3167 dx = abs(synaction->queue[synaction->queue_cursor].x -
3168 synaction->start_x);
3169 dy = abs(synaction->queue[synaction->queue_cursor].y -
3170 synaction->start_y);
3171
3172 /* Max delta is disabled for multi-fingers tap. */
3173 if (synaction->fingers_nb > 1)
3174 tap_max_delta = imax(dx, dy);
3175 else
3176 tap_max_delta = sc->syninfo.tap_max_delta;
3177
3178 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3179
3180 /* Check for tap. */
3181 VLOG(3, (LOG_DEBUG,
3182 "synaptics: zmax=%d, dx=%d, dy=%d, "
3183 "delta=%d, fingers=%d, queue=%d\n",
3184 sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
3185 synaction->queue_len));
3186 if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
3187 timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
3188 dx <= tap_max_delta && dy <= tap_max_delta &&
3189 synaction->queue_len >= sc->syninfo.tap_min_queue) {
3190 /*
3191 * We have a tap if:
3192 * - the maximum pressure went over tap_threshold
3193 * - the action ended before tap_timeout
3194 *
3195 * To handle tap-hold, we must delay any button push to
3196 * the next action.
3197 */
3198 if (synaction->in_taphold) {
3199 /*
3200 * This is the second and last tap of a
3201 * double tap action, not a tap-hold.
3202 */
3203 synaction->in_taphold = 0;
3204
3205 /*
3206 * For double-tap to work:
3207 * - no button press is emitted (to
3208 * simulate a button release)
3209 * - PSM_FLAGS_FINGERDOWN is set to
3210 * force the next packet to emit a
3211 * button press)
3212 */
3213 VLOG(2, (LOG_DEBUG,
3214 "synaptics: button RELEASE: %d\n",
3215 synaction->tap_button));
3216 sc->flags |= PSM_FLAGS_FINGERDOWN;
3217 } else {
3218 /*
3219 * This is the first tap: we set the
3220 * tap-hold state and notify the button
3221 * down event.
3222 */
3223 synaction->in_taphold = 1;
3224 taphold_timeout = sc->syninfo.taphold_timeout;
3225 sc->taptimeout.tv_sec = taphold_timeout /
3226 1000000;
3227 sc->taptimeout.tv_usec = taphold_timeout %
3228 1000000;
3229 timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3230
3231 switch (synaction->fingers_nb) {
3232 case 3:
3233 synaction->tap_button =
3234 MOUSE_BUTTON2DOWN;
3235 break;
3236 case 2:
3237 synaction->tap_button =
3238 MOUSE_BUTTON3DOWN;
3239 break;
3240 default:
3241 synaction->tap_button =
3242 MOUSE_BUTTON1DOWN;
3243 }
3244 VLOG(2, (LOG_DEBUG,
3245 "synaptics: button PRESS: %d\n",
3246 synaction->tap_button));
3247 ms->button |= synaction->tap_button;
3248 }
3249 } else {
3250 /*
3251 * Not enough pressure or timeout: reset
3252 * tap-hold state.
3253 */
3254 if (synaction->in_taphold) {
3255 VLOG(2, (LOG_DEBUG,
3256 "synaptics: button RELEASE: %d\n",
3257 synaction->tap_button));
3258 synaction->in_taphold = 0;
3259 } else {
3260 VLOG(2, (LOG_DEBUG,
3261 "synaptics: not a tap-hold\n"));
3262 }
3263 }
3264 } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3265 sc->synaction.in_taphold) {
3266 /*
3267 * For a tap-hold to work, the button must remain down at
3268 * least until timeout (where the in_taphold flags will be
3269 * cleared) or during the next action.
3270 */
3271 if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3272 ms->button |= sc->synaction.tap_button;
3273 } else {
3274 VLOG(2, (LOG_DEBUG,
3275 "synaptics: button RELEASE: %d\n",
3276 sc->synaction.tap_button));
3277 sc->synaction.in_taphold = 0;
3278 }
3279 }
3280
3281SYNAPTICS_END:
3282 /*
3283 * Use the extra buttons as a scrollwheel
3284 *
3285 * XXX X.Org uses the Z axis for vertical wheel only,
3286 * whereas moused(8) understands special values to differ
3287 * vertical and horizontal wheels.
3288 *
3289 * xf86-input-mouse needs therefore a small patch to
3290 * understand these special values. Without it, the
3291 * horizontal wheel acts as a vertical wheel in X.Org.
3292 *
3293 * That's why the horizontal wheel is disabled by
3294 * default for now.
3295 */
3296
3250 if (ms->button & MOUSE_BUTTON4DOWN) {
3251 *z = -1;
3252 ms->button &= ~MOUSE_BUTTON4DOWN;
3253 } else if (ms->button & MOUSE_BUTTON5DOWN) {
3254 *z = 1;
3255 ms->button &= ~MOUSE_BUTTON5DOWN;
3256 } else if (ms->button & MOUSE_BUTTON6DOWN) {
3257 *z = -2;
3258 ms->button &= ~MOUSE_BUTTON6DOWN;
3259 } else if (ms->button & MOUSE_BUTTON7DOWN) {
3260 *z = 2;
3261 ms->button &= ~MOUSE_BUTTON7DOWN;
3262 } else
3263 *z = 0;
3264
3265 return (0);
3266}
3267
3268static void
3269proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3270 int *x, int *y, int *z)
3271{
3272 static int butmap_versapad[8] = {
3273 0,
3274 MOUSE_BUTTON3DOWN,
3275 0,
3276 MOUSE_BUTTON3DOWN,
3277 MOUSE_BUTTON1DOWN,
3278 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3279 MOUSE_BUTTON1DOWN,
3280 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
3281 };
3282 int c, x0, y0;
3283
3284 /* VersaPad PS/2 absolute mode message format
3285 *
3286 * [packet1] 7 6 5 4 3 2 1 0(LSB)
3287 * ipacket[0]: 1 1 0 A 1 L T R
3288 * ipacket[1]: H7 H6 H5 H4 H3 H2 H1 H0
3289 * ipacket[2]: V7 V6 V5 V4 V3 V2 V1 V0
3290 * ipacket[3]: 1 1 1 A 1 L T R
3291 * ipacket[4]:V11 V10 V9 V8 H11 H10 H9 H8
3292 * ipacket[5]: 0 P6 P5 P4 P3 P2 P1 P0
3293 *
3294 * [note]
3295 * R: right physical mouse button (1=on)
3296 * T: touch pad virtual button (1=tapping)
3297 * L: left physical mouse button (1=on)
3298 * A: position data is valid (1=valid)
3299 * H: horizontal data (12bit signed integer. H11 is sign bit.)
3300 * V: vertical data (12bit signed integer. V11 is sign bit.)
3301 * P: pressure data
3302 *
3303 * Tapping is mapped to MOUSE_BUTTON4.
3304 */
3305 c = pb->ipacket[0];
3306 *x = *y = 0;
3307 ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
3308 ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
3309 if (c & MOUSE_PS2VERSA_IN_USE) {
3310 x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
3311 y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
3312 if (x0 & 0x800)
3313 x0 -= 0x1000;
3314 if (y0 & 0x800)
3315 y0 -= 0x1000;
3316 if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3317 *x = sc->xold - x0;
3318 *y = y0 - sc->yold;
3319 if (*x < 0) /* XXX */
3320 ++*x;
3321 else if (*x)
3322 --*x;
3323 if (*y < 0)
3324 ++*y;
3325 else if (*y)
3326 --*y;
3327 } else
3328 sc->flags |= PSM_FLAGS_FINGERDOWN;
3329 sc->xold = x0;
3330 sc->yold = y0;
3331 } else
3332 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3333}
3334
3335static void
3336psmsoftintr(void *arg)
3337{
3338 /*
3339 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
3340 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
3341 */
3342 static int butmap[8] = {
3343 0,
3344 MOUSE_BUTTON1DOWN,
3345 MOUSE_BUTTON3DOWN,
3346 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3347 MOUSE_BUTTON2DOWN,
3348 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
3349 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
3350 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
3351 };
3352 struct psm_softc *sc = arg;
3353 mousestatus_t ms;
3354 packetbuf_t *pb;
3355 int x, y, z, c, l, s;
3356
3357 getmicrouptime(&sc->lastsoftintr);
3358
3359 s = spltty();
3360
3361 do {
3362 pb = &sc->pqueue[sc->pqueue_start];
3363
3364 if (sc->mode.level == PSM_LEVEL_NATIVE)
3365 goto next_native;
3366
3367 c = pb->ipacket[0];
3368 /*
3369 * A kludge for Kensington device!
3370 * The MSB of the horizontal count appears to be stored in
3371 * a strange place.
3372 */
3373 if (sc->hw.model == MOUSE_MODEL_THINK)
3374 pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
3375
3376 /* ignore the overflow bits... */
3377 x = (c & MOUSE_PS2_XNEG) ?
3378 pb->ipacket[1] - 256 : pb->ipacket[1];
3379 y = (c & MOUSE_PS2_YNEG) ?
3380 pb->ipacket[2] - 256 : pb->ipacket[2];
3381 z = 0;
3382 ms.obutton = sc->button; /* previous button state */
3383 ms.button = butmap[c & MOUSE_PS2_BUTTONS];
3384 /* `tapping' action */
3385 if (sc->config & PSM_CONFIG_FORCETAP)
3386 ms.button |= ((c & MOUSE_PS2_TAP)) ?
3387 0 : MOUSE_BUTTON4DOWN;
3388
3389 switch (sc->hw.model) {
3390
3391 case MOUSE_MODEL_EXPLORER:
3392 /*
3393 * b7 b6 b5 b4 b3 b2 b1 b0
3394 * byte 1: oy ox sy sx 1 M R L
3395 * byte 2: x x x x x x x x
3396 * byte 3: y y y y y y y y
3397 * byte 4: * * S2 S1 s d2 d1 d0
3398 *
3399 * L, M, R, S1, S2: left, middle, right and side buttons
3400 * s: wheel data sign bit
3401 * d2-d0: wheel data
3402 */
3403 z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
3404 (pb->ipacket[3] & 0x0f) - 16 :
3405 (pb->ipacket[3] & 0x0f);
3406 ms.button |=
3407 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
3408 MOUSE_BUTTON4DOWN : 0;
3409 ms.button |=
3410 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
3411 MOUSE_BUTTON5DOWN : 0;
3412 break;
3413
3414 case MOUSE_MODEL_INTELLI:
3415 case MOUSE_MODEL_NET:
3416 /* wheel data is in the fourth byte */
3417 z = (char)pb->ipacket[3];
3418 /*
3419 * XXX some mice may send 7 when there is no Z movement? */
3420 if ((z >= 7) || (z <= -7))
3421 z = 0;
3422 /* some compatible mice have additional buttons */
3423 ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
3424 MOUSE_BUTTON4DOWN : 0;
3425 ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
3426 MOUSE_BUTTON5DOWN : 0;
3427 break;
3428
3429 case MOUSE_MODEL_MOUSEMANPLUS:
3430 proc_mmanplus(sc, pb, &ms, &x, &y, &z);
3431 break;
3432
3433 case MOUSE_MODEL_GLIDEPOINT:
3434 /* `tapping' action */
3435 ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
3436 MOUSE_BUTTON4DOWN;
3437 break;
3438
3439 case MOUSE_MODEL_NETSCROLL:
3440 /*
3441 * three addtional bytes encode buttons and
3442 * wheel events
3443 */
3444 ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
3445 MOUSE_BUTTON4DOWN : 0;
3446 ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
3447 MOUSE_BUTTON5DOWN : 0;
3448 z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
3449 pb->ipacket[4] - 256 : pb->ipacket[4];
3450 break;
3451
3452 case MOUSE_MODEL_THINK:
3453 /* the fourth button state in the first byte */
3454 ms.button |= (c & MOUSE_PS2_TAP) ?
3455 MOUSE_BUTTON4DOWN : 0;
3456 break;
3457
3458 case MOUSE_MODEL_VERSAPAD:
3459 proc_versapad(sc, pb, &ms, &x, &y, &z);
3460 c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
3461 ((y < 0) ? MOUSE_PS2_YNEG : 0);
3462 break;
3297 if (ms->button & MOUSE_BUTTON4DOWN) {
3298 *z = -1;
3299 ms->button &= ~MOUSE_BUTTON4DOWN;
3300 } else if (ms->button & MOUSE_BUTTON5DOWN) {
3301 *z = 1;
3302 ms->button &= ~MOUSE_BUTTON5DOWN;
3303 } else if (ms->button & MOUSE_BUTTON6DOWN) {
3304 *z = -2;
3305 ms->button &= ~MOUSE_BUTTON6DOWN;
3306 } else if (ms->button & MOUSE_BUTTON7DOWN) {
3307 *z = 2;
3308 ms->button &= ~MOUSE_BUTTON7DOWN;
3309 } else
3310 *z = 0;
3311
3312 return (0);
3313}
3314
3315static void
3316proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3317 int *x, int *y, int *z)
3318{
3319 static int butmap_versapad[8] = {
3320 0,
3321 MOUSE_BUTTON3DOWN,
3322 0,
3323 MOUSE_BUTTON3DOWN,
3324 MOUSE_BUTTON1DOWN,
3325 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3326 MOUSE_BUTTON1DOWN,
3327 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
3328 };
3329 int c, x0, y0;
3330
3331 /* VersaPad PS/2 absolute mode message format
3332 *
3333 * [packet1] 7 6 5 4 3 2 1 0(LSB)
3334 * ipacket[0]: 1 1 0 A 1 L T R
3335 * ipacket[1]: H7 H6 H5 H4 H3 H2 H1 H0
3336 * ipacket[2]: V7 V6 V5 V4 V3 V2 V1 V0
3337 * ipacket[3]: 1 1 1 A 1 L T R
3338 * ipacket[4]:V11 V10 V9 V8 H11 H10 H9 H8
3339 * ipacket[5]: 0 P6 P5 P4 P3 P2 P1 P0
3340 *
3341 * [note]
3342 * R: right physical mouse button (1=on)
3343 * T: touch pad virtual button (1=tapping)
3344 * L: left physical mouse button (1=on)
3345 * A: position data is valid (1=valid)
3346 * H: horizontal data (12bit signed integer. H11 is sign bit.)
3347 * V: vertical data (12bit signed integer. V11 is sign bit.)
3348 * P: pressure data
3349 *
3350 * Tapping is mapped to MOUSE_BUTTON4.
3351 */
3352 c = pb->ipacket[0];
3353 *x = *y = 0;
3354 ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
3355 ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
3356 if (c & MOUSE_PS2VERSA_IN_USE) {
3357 x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
3358 y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
3359 if (x0 & 0x800)
3360 x0 -= 0x1000;
3361 if (y0 & 0x800)
3362 y0 -= 0x1000;
3363 if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3364 *x = sc->xold - x0;
3365 *y = y0 - sc->yold;
3366 if (*x < 0) /* XXX */
3367 ++*x;
3368 else if (*x)
3369 --*x;
3370 if (*y < 0)
3371 ++*y;
3372 else if (*y)
3373 --*y;
3374 } else
3375 sc->flags |= PSM_FLAGS_FINGERDOWN;
3376 sc->xold = x0;
3377 sc->yold = y0;
3378 } else
3379 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3380}
3381
3382static void
3383psmsoftintr(void *arg)
3384{
3385 /*
3386 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
3387 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
3388 */
3389 static int butmap[8] = {
3390 0,
3391 MOUSE_BUTTON1DOWN,
3392 MOUSE_BUTTON3DOWN,
3393 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3394 MOUSE_BUTTON2DOWN,
3395 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
3396 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
3397 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
3398 };
3399 struct psm_softc *sc = arg;
3400 mousestatus_t ms;
3401 packetbuf_t *pb;
3402 int x, y, z, c, l, s;
3403
3404 getmicrouptime(&sc->lastsoftintr);
3405
3406 s = spltty();
3407
3408 do {
3409 pb = &sc->pqueue[sc->pqueue_start];
3410
3411 if (sc->mode.level == PSM_LEVEL_NATIVE)
3412 goto next_native;
3413
3414 c = pb->ipacket[0];
3415 /*
3416 * A kludge for Kensington device!
3417 * The MSB of the horizontal count appears to be stored in
3418 * a strange place.
3419 */
3420 if (sc->hw.model == MOUSE_MODEL_THINK)
3421 pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
3422
3423 /* ignore the overflow bits... */
3424 x = (c & MOUSE_PS2_XNEG) ?
3425 pb->ipacket[1] - 256 : pb->ipacket[1];
3426 y = (c & MOUSE_PS2_YNEG) ?
3427 pb->ipacket[2] - 256 : pb->ipacket[2];
3428 z = 0;
3429 ms.obutton = sc->button; /* previous button state */
3430 ms.button = butmap[c & MOUSE_PS2_BUTTONS];
3431 /* `tapping' action */
3432 if (sc->config & PSM_CONFIG_FORCETAP)
3433 ms.button |= ((c & MOUSE_PS2_TAP)) ?
3434 0 : MOUSE_BUTTON4DOWN;
3435
3436 switch (sc->hw.model) {
3437
3438 case MOUSE_MODEL_EXPLORER:
3439 /*
3440 * b7 b6 b5 b4 b3 b2 b1 b0
3441 * byte 1: oy ox sy sx 1 M R L
3442 * byte 2: x x x x x x x x
3443 * byte 3: y y y y y y y y
3444 * byte 4: * * S2 S1 s d2 d1 d0
3445 *
3446 * L, M, R, S1, S2: left, middle, right and side buttons
3447 * s: wheel data sign bit
3448 * d2-d0: wheel data
3449 */
3450 z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
3451 (pb->ipacket[3] & 0x0f) - 16 :
3452 (pb->ipacket[3] & 0x0f);
3453 ms.button |=
3454 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
3455 MOUSE_BUTTON4DOWN : 0;
3456 ms.button |=
3457 (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
3458 MOUSE_BUTTON5DOWN : 0;
3459 break;
3460
3461 case MOUSE_MODEL_INTELLI:
3462 case MOUSE_MODEL_NET:
3463 /* wheel data is in the fourth byte */
3464 z = (char)pb->ipacket[3];
3465 /*
3466 * XXX some mice may send 7 when there is no Z movement? */
3467 if ((z >= 7) || (z <= -7))
3468 z = 0;
3469 /* some compatible mice have additional buttons */
3470 ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
3471 MOUSE_BUTTON4DOWN : 0;
3472 ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
3473 MOUSE_BUTTON5DOWN : 0;
3474 break;
3475
3476 case MOUSE_MODEL_MOUSEMANPLUS:
3477 proc_mmanplus(sc, pb, &ms, &x, &y, &z);
3478 break;
3479
3480 case MOUSE_MODEL_GLIDEPOINT:
3481 /* `tapping' action */
3482 ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
3483 MOUSE_BUTTON4DOWN;
3484 break;
3485
3486 case MOUSE_MODEL_NETSCROLL:
3487 /*
3488 * three addtional bytes encode buttons and
3489 * wheel events
3490 */
3491 ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
3492 MOUSE_BUTTON4DOWN : 0;
3493 ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
3494 MOUSE_BUTTON5DOWN : 0;
3495 z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
3496 pb->ipacket[4] - 256 : pb->ipacket[4];
3497 break;
3498
3499 case MOUSE_MODEL_THINK:
3500 /* the fourth button state in the first byte */
3501 ms.button |= (c & MOUSE_PS2_TAP) ?
3502 MOUSE_BUTTON4DOWN : 0;
3503 break;
3504
3505 case MOUSE_MODEL_VERSAPAD:
3506 proc_versapad(sc, pb, &ms, &x, &y, &z);
3507 c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
3508 ((y < 0) ? MOUSE_PS2_YNEG : 0);
3509 break;
3463
3510
3464 case MOUSE_MODEL_4D:
3465 /*
3466 * b7 b6 b5 b4 b3 b2 b1 b0
3467 * byte 1: s2 d2 s1 d1 1 M R L
3468 * byte 2: sx x x x x x x x
3469 * byte 3: sy y y y y y y y
3470 *
3471 * s1: wheel 1 direction
3472 * d1: wheel 1 data
3473 * s2: wheel 2 direction
3474 * d2: wheel 2 data
3475 */
3476 x = (pb->ipacket[1] & 0x80) ?
3477 pb->ipacket[1] - 256 : pb->ipacket[1];
3478 y = (pb->ipacket[2] & 0x80) ?
3479 pb->ipacket[2] - 256 : pb->ipacket[2];
3480 switch (c & MOUSE_4D_WHEELBITS) {
3481 case 0x10:
3482 z = 1;
3483 break;
3484 case 0x30:
3485 z = -1;
3486 break;
3487 case 0x40: /* XXX 2nd wheel turning right */
3488 z = 2;
3489 break;
3490 case 0xc0: /* XXX 2nd wheel turning left */
3491 z = -2;
3492 break;
3493 }
3494 break;
3495
3496 case MOUSE_MODEL_4DPLUS:
3497 if ((x < 16 - 256) && (y < 16 - 256)) {
3498 /*
3499 * b7 b6 b5 b4 b3 b2 b1 b0
3500 * byte 1: 0 0 1 1 1 M R L
3501 * byte 2: 0 0 0 0 1 0 0 0
3502 * byte 3: 0 0 0 0 S s d1 d0
3503 *
3504 * L, M, R, S: left, middle, right,
3505 * and side buttons
3506 * s: wheel data sign bit
3507 * d1-d0: wheel data
3508 */
3509 x = y = 0;
3510 if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
3511 ms.button |= MOUSE_BUTTON4DOWN;
3512 z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
3513 ((pb->ipacket[2] & 0x07) - 8) :
3514 (pb->ipacket[2] & 0x07) ;
3515 } else {
3516 /* preserve previous button states */
3517 ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
3518 }
3519 break;
3520
3521 case MOUSE_MODEL_SYNAPTICS:
3522 if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0)
3523 goto next;
3524 break;
3525
3526 case MOUSE_MODEL_TRACKPOINT:
3527 case MOUSE_MODEL_GENERIC:
3528 default:
3529 break;
3530 }
3531
3532 /* scale values */
3533 if (sc->mode.accelfactor >= 1) {
3534 if (x != 0) {
3535 x = x * x / sc->mode.accelfactor;
3536 if (x == 0)
3537 x = 1;
3538 if (c & MOUSE_PS2_XNEG)
3539 x = -x;
3540 }
3541 if (y != 0) {
3542 y = y * y / sc->mode.accelfactor;
3543 if (y == 0)
3544 y = 1;
3545 if (c & MOUSE_PS2_YNEG)
3546 y = -y;
3547 }
3548 }
3549
3550 ms.dx = x;
3551 ms.dy = y;
3552 ms.dz = z;
3553 ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
3554 (ms.obutton ^ ms.button);
3555
3556 pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
3557
3558 sc->status.flags |= ms.flags;
3559 sc->status.dx += ms.dx;
3560 sc->status.dy += ms.dy;
3561 sc->status.dz += ms.dz;
3562 sc->status.button = ms.button;
3563 sc->button = ms.button;
3564
3565next_native:
3566 sc->watchdog = FALSE;
3567
3568 /* queue data */
3569 if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
3570 l = imin(pb->inputbytes,
3571 sizeof(sc->queue.buf) - sc->queue.tail);
3572 bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
3573 if (pb->inputbytes > l)
3574 bcopy(&pb->ipacket[l], &sc->queue.buf[0],
3575 pb->inputbytes - l);
3576 sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
3577 sizeof(sc->queue.buf);
3578 sc->queue.count += pb->inputbytes;
3579 }
3580 pb->inputbytes = 0;
3581
3582next:
3583 if (++sc->pqueue_start >= PSM_PACKETQUEUE)
3584 sc->pqueue_start = 0;
3585 } while (sc->pqueue_start != sc->pqueue_end);
3586
3587 if (sc->state & PSM_ASLP) {
3588 sc->state &= ~PSM_ASLP;
3589 wakeup(sc);
3590 }
3591 selwakeuppri(&sc->rsel, PZERO);
3592 if (sc->async != NULL) {
3593 pgsigio(&sc->async, SIGIO, 0);
3594 }
3595 sc->state &= ~PSM_SOFTARMED;
3596 splx(s);
3597}
3598
3599static int
3600psmpoll(struct cdev *dev, int events, struct thread *td)
3601{
3602 struct psm_softc *sc = dev->si_drv1;
3603 int s;
3604 int revents = 0;
3605
3606 /* Return true if a mouse event available */
3607 s = spltty();
3608 if (events & (POLLIN | POLLRDNORM)) {
3609 if (sc->queue.count > 0)
3610 revents |= events & (POLLIN | POLLRDNORM);
3611 else
3612 selrecord(td, &sc->rsel);
3613 }
3614 splx(s);
3615
3616 return (revents);
3617}
3618
3619/* vendor/model specific routines */
3620
3621static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
3622{
3623 if (set_mouse_resolution(kbdc, res) != res)
3624 return (FALSE);
3625 if (set_mouse_scaling(kbdc, scale) &&
3626 set_mouse_scaling(kbdc, scale) &&
3627 set_mouse_scaling(kbdc, scale) &&
3628 (get_mouse_status(kbdc, status, 0, 3) >= 3))
3629 return (TRUE);
3630 return (FALSE);
3631}
3632
3633static int
3634mouse_ext_command(KBDC kbdc, int command)
3635{
3636 int c;
3637
3638 c = (command >> 6) & 0x03;
3639 if (set_mouse_resolution(kbdc, c) != c)
3640 return (FALSE);
3641 c = (command >> 4) & 0x03;
3642 if (set_mouse_resolution(kbdc, c) != c)
3643 return (FALSE);
3644 c = (command >> 2) & 0x03;
3645 if (set_mouse_resolution(kbdc, c) != c)
3646 return (FALSE);
3647 c = (command >> 0) & 0x03;
3648 if (set_mouse_resolution(kbdc, c) != c)
3649 return (FALSE);
3650 return (TRUE);
3651}
3652
3653#ifdef notyet
3654/* Logitech MouseMan Cordless II */
3655static int
3656enable_lcordless(KDBC kbdc, struct psm_softc *sc)
3657{
3658 int status[3];
3659 int ch;
3660
3661 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 2, status))
3662 return (FALSE);
3663 if (status[1] == PSMD_RES_HIGH)
3664 return (FALSE);
3665 ch = (status[0] & 0x07) - 1; /* channel # */
3666 if ((ch <= 0) || (ch > 4))
3667 return (FALSE);
3668 /*
3669 * status[1]: always one?
3670 * status[2]: battery status? (0-100)
3671 */
3672 return (TRUE);
3673}
3674#endif /* notyet */
3675
3676/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
3677static int
3678enable_groller(KBDC kbdc, struct psm_softc *sc)
3679{
3680 int status[3];
3681
3682 /*
3683 * The special sequence to enable the fourth button and the
3684 * roller. Immediately after this sequence check status bytes.
3685 * if the mouse is NetScroll, the second and the third bytes are
3686 * '3' and 'D'.
3687 */
3688
3689 /*
3690 * If the mouse is an ordinary PS/2 mouse, the status bytes should
3691 * look like the following.
3692 *
3693 * byte 1 bit 7 always 0
3694 * bit 6 stream mode (0)
3695 * bit 5 disabled (0)
3696 * bit 4 1:1 scaling (0)
3697 * bit 3 always 0
3698 * bit 0-2 button status
3699 * byte 2 resolution (PSMD_RES_HIGH)
3700 * byte 3 report rate (?)
3701 */
3702
3703 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3704 return (FALSE);
3705 if ((status[1] != '3') || (status[2] != 'D'))
3706 return (FALSE);
3707 /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
3708 if (sc != NULL)
3709 sc->hw.buttons = 4;
3710 return (TRUE);
3711}
3712
3713/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
3714static int
3715enable_gmouse(KBDC kbdc, struct psm_softc *sc)
3716{
3717 int status[3];
3718
3719 /*
3720 * The special sequence to enable the middle, "rubber" button.
3721 * Immediately after this sequence check status bytes.
3722 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
3723 * the second and the third bytes are '3' and 'U'.
3724 * NOTE: NetMouse reports that it has three buttons although it has
3725 * two buttons and a rubber button. NetMouse Pro and MIE Mouse
3726 * say they have three buttons too and they do have a button on the
3727 * side...
3728 */
3729 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3730 return (FALSE);
3731 if ((status[1] != '3') || (status[2] != 'U'))
3732 return (FALSE);
3733 return (TRUE);
3734}
3735
3736/* ALPS GlidePoint */
3737static int
3738enable_aglide(KBDC kbdc, struct psm_softc *sc)
3739{
3740 int status[3];
3741
3742 /*
3743 * The special sequence to obtain ALPS GlidePoint specific
3744 * information. Immediately after this sequence, status bytes will
3745 * contain something interesting.
3746 * NOTE: ALPS produces several models of GlidePoint. Some of those
3747 * do not respond to this sequence, thus, cannot be detected this way.
3748 */
3749 if (set_mouse_sampling_rate(kbdc, 100) != 100)
3750 return (FALSE);
3751 if (!mouse_id_proc1(kbdc, PSMD_RES_LOW, 2, status))
3752 return (FALSE);
3753 if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
3754 return (FALSE);
3755 return (TRUE);
3756}
3757
3758/* Kensington ThinkingMouse/Trackball */
3759static int
3760enable_kmouse(KBDC kbdc, struct psm_softc *sc)
3761{
3762 static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
3763 int status[3];
3764 int id1;
3765 int id2;
3766 int i;
3767
3768 id1 = get_aux_id(kbdc);
3769 if (set_mouse_sampling_rate(kbdc, 10) != 10)
3770 return (FALSE);
3771 /*
3772 * The device is now in the native mode? It returns a different
3773 * ID value...
3774 */
3775 id2 = get_aux_id(kbdc);
3776 if ((id1 == id2) || (id2 != 2))
3777 return (FALSE);
3778
3779 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
3780 return (FALSE);
3781#if PSM_DEBUG >= 2
3782 /* at this point, resolution is LOW, sampling rate is 10/sec */
3783 if (get_mouse_status(kbdc, status, 0, 3) < 3)
3784 return (FALSE);
3785#endif
3786
3787 /*
3788 * The special sequence to enable the third and fourth buttons.
3789 * Otherwise they behave like the first and second buttons.
3790 */
3791 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3792 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3793 return (FALSE);
3794
3795 /*
3796 * At this point, the device is using default resolution and
3797 * sampling rate for the native mode.
3798 */
3799 if (get_mouse_status(kbdc, status, 0, 3) < 3)
3800 return (FALSE);
3801 if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
3802 return (FALSE);
3803
3804 /* the device appears be enabled by this sequence, diable it for now */
3805 disable_aux_dev(kbdc);
3806 empty_aux_buffer(kbdc, 5);
3807
3808 return (TRUE);
3809}
3810
3811/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
3812static int
3813enable_mmanplus(KBDC kbdc, struct psm_softc *sc)
3814{
3815 int data[3];
3816
3817 /* the special sequence to enable the fourth button and the roller. */
3818 /*
3819 * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
3820 * must be called exactly three times since the last RESET command
3821 * before this sequence. XXX
3822 */
3823 if (!set_mouse_scaling(kbdc, 1))
3824 return (FALSE);
3825 if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
3826 return (FALSE);
3827 if (get_mouse_status(kbdc, data, 1, 3) < 3)
3828 return (FALSE);
3829
3830 /*
3831 * PS2++ protocol, packet type 0
3832 *
3833 * b7 b6 b5 b4 b3 b2 b1 b0
3834 * byte 1: * 1 p3 p2 1 * * *
3835 * byte 2: 1 1 p1 p0 m1 m0 1 0
3836 * byte 3: m7 m6 m5 m4 m3 m2 m1 m0
3837 *
3838 * p3-p0: packet type: 0
3839 * m7-m0: model ID: MouseMan+:0x50,
3840 * FirstMouse+:0x51,
3841 * ScrollPoint:0x58...
3842 */
3843 /* check constant bits */
3844 if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
3845 return (FALSE);
3846 if ((data[1] & 0xc3) != 0xc2)
3847 return (FALSE);
3848 /* check d3-d0 in byte 2 */
3849 if (!MOUSE_PS2PLUS_CHECKBITS(data))
3850 return (FALSE);
3851 /* check p3-p0 */
3852 if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
3853 return (FALSE);
3854
3855 if (sc != NULL) {
3856 sc->hw.hwid &= 0x00ff;
3857 sc->hw.hwid |= data[2] << 8; /* save model ID */
3858 }
3859
3860 /*
3861 * MouseMan+ (or FirstMouse+) is now in its native mode, in which
3862 * the wheel and the fourth button events are encoded in the
3863 * special data packet. The mouse may be put in the IntelliMouse mode
3864 * if it is initialized by the IntelliMouse's method.
3865 */
3866 return (TRUE);
3867}
3868
3869/* MS IntelliMouse Explorer */
3870static int
3871enable_msexplorer(KBDC kbdc, struct psm_softc *sc)
3872{
3873 static u_char rate0[] = { 200, 100, 80, };
3874 static u_char rate1[] = { 200, 200, 80, };
3875 int id;
3876 int i;
3877
3878 /*
3879 * This is needed for at least A4Tech X-7xx mice - they do not go
3880 * straight to Explorer mode, but need to be set to Intelli mode
3881 * first.
3882 */
3883 enable_msintelli(kbdc, sc);
3884
3885 /* the special sequence to enable the extra buttons and the roller. */
3886 for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i)
3887 if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
3888 return (FALSE);
3889 /* the device will give the genuine ID only after the above sequence */
3890 id = get_aux_id(kbdc);
3891 if (id != PSM_EXPLORER_ID)
3892 return (FALSE);
3893
3894 if (sc != NULL) {
3895 sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */
3896 sc->hw.hwid = id;
3897 }
3898
3899 /*
3900 * XXX: this is a kludge to fool some KVM switch products
3901 * which think they are clever enough to know the 4-byte IntelliMouse
3902 * protocol, and assume any other protocols use 3-byte packets.
3903 * They don't convey 4-byte data packets from the IntelliMouse Explorer
3904 * correctly to the host computer because of this!
3905 * The following sequence is actually IntelliMouse's "wake up"
3906 * sequence; it will make the KVM think the mouse is IntelliMouse
3907 * when it is in fact IntelliMouse Explorer.
3908 */
3909 for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i)
3910 if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
3911 break;
3912 get_aux_id(kbdc);
3913
3914 return (TRUE);
3915}
3916
3917/* MS IntelliMouse */
3918static int
3919enable_msintelli(KBDC kbdc, struct psm_softc *sc)
3920{
3921 /*
3922 * Logitech MouseMan+ and FirstMouse+ will also respond to this
3923 * probe routine and act like IntelliMouse.
3924 */
3925
3926 static u_char rate[] = { 200, 100, 80, };
3927 int id;
3928 int i;
3929
3930 /* the special sequence to enable the third button and the roller. */
3931 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3932 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3933 return (FALSE);
3934 /* the device will give the genuine ID only after the above sequence */
3935 id = get_aux_id(kbdc);
3936 if (id != PSM_INTELLI_ID)
3937 return (FALSE);
3938
3939 if (sc != NULL) {
3940 sc->hw.buttons = 3;
3941 sc->hw.hwid = id;
3942 }
3943
3944 return (TRUE);
3945}
3946
3947/* A4 Tech 4D Mouse */
3948static int
3949enable_4dmouse(KBDC kbdc, struct psm_softc *sc)
3950{
3951 /*
3952 * Newer wheel mice from A4 Tech may use the 4D+ protocol.
3953 */
3954
3955 static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
3956 int id;
3957 int i;
3958
3959 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3960 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3961 return (FALSE);
3962 id = get_aux_id(kbdc);
3963 /*
3964 * WinEasy 4D, 4 Way Scroll 4D: 6
3965 * Cable-Free 4D: 8 (4DPLUS)
3966 * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
3967 */
3968 if (id != PSM_4DMOUSE_ID)
3969 return (FALSE);
3970
3971 if (sc != NULL) {
3972 sc->hw.buttons = 3; /* XXX some 4D mice have 4? */
3973 sc->hw.hwid = id;
3974 }
3975
3976 return (TRUE);
3977}
3978
3979/* A4 Tech 4D+ Mouse */
3980static int
3981enable_4dplus(KBDC kbdc, struct psm_softc *sc)
3982{
3983 /*
3984 * Newer wheel mice from A4 Tech seem to use this protocol.
3985 * Older models are recognized as either 4D Mouse or IntelliMouse.
3986 */
3987 int id;
3988
3989 /*
3990 * enable_4dmouse() already issued the following ID sequence...
3991 static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
3992 int i;
3993
3994 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3995 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3996 return (FALSE);
3997 */
3998
3999 id = get_aux_id(kbdc);
4000 switch (id) {
4001 case PSM_4DPLUS_ID:
4002 break;
4003 case PSM_4DPLUS_RFSW35_ID:
4004 break;
4005 default:
4006 return (FALSE);
4007 }
4008
4009 if (sc != NULL) {
4010 sc->hw.buttons = (id == PSM_4DPLUS_ID) ? 4 : 3;
4011 sc->hw.hwid = id;
4012 }
4013
4014 return (TRUE);
4015}
4016
4017/* Synaptics Touchpad */
4018static int
4019synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4020{
4021 int error, arg;
4022
4023 /* Read the current value. */
4024 arg = *(int *)oidp->oid_arg1;
4025 error = sysctl_handle_int(oidp, &arg, 0, req);
4026
4027 /* Sanity check. */
4028 if (error || !req->newptr)
4029 return (error);
4030
4031 /*
4032 * Check that the new value is in the concerned node's range
4033 * of values.
4034 */
4035 switch (oidp->oid_arg2) {
4036 case SYNAPTICS_SYSCTL_MIN_PRESSURE:
4037 case SYNAPTICS_SYSCTL_MAX_PRESSURE:
4038 if (arg < 0 || arg > 255)
4039 return (EINVAL);
4040 break;
4041 case SYNAPTICS_SYSCTL_MAX_WIDTH:
4042 if (arg < 4 || arg > 15)
4043 return (EINVAL);
4044 break;
4045 case SYNAPTICS_SYSCTL_MARGIN_TOP:
4046 case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4047 case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4048 case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4049 case SYNAPTICS_SYSCTL_NA_TOP:
4050 case SYNAPTICS_SYSCTL_NA_RIGHT:
4051 case SYNAPTICS_SYSCTL_NA_BOTTOM:
4052 case SYNAPTICS_SYSCTL_NA_LEFT:
4053 if (arg < 0 || arg > 6143)
4054 return (EINVAL);
4055 break;
4056 case SYNAPTICS_SYSCTL_WINDOW_MIN:
4057 case SYNAPTICS_SYSCTL_WINDOW_MAX:
4058 case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE:
4059 if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE)
4060 return (EINVAL);
4061 break;
4062 case SYNAPTICS_SYSCTL_MULTIPLICATOR:
4063 case SYNAPTICS_SYSCTL_WEIGHT_CURRENT:
4064 case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS:
4065 case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA:
4066 case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED:
4067 case SYNAPTICS_SYSCTL_DIV_MIN:
4068 case SYNAPTICS_SYSCTL_DIV_MAX:
4069 case SYNAPTICS_SYSCTL_DIV_MAX_NA:
4070 case SYNAPTICS_SYSCTL_DIV_LEN:
4071 case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN:
4072 case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX:
4073 if (arg < 1)
4074 return (EINVAL);
4075 break;
4076 case SYNAPTICS_SYSCTL_TAP_MAX_DELTA:
4077 case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT:
4078 case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA:
4079 if (arg < 0)
4080 return (EINVAL);
4081 break;
4082 case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4083 case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4084 if (arg < -6143 || arg > 6143)
4085 return (EINVAL);
4086 break;
4087 default:
4088 return (EINVAL);
4089 }
4090
4091 /* Update. */
4092 *(int *)oidp->oid_arg1 = arg;
4093
4094 return (error);
4095}
4096
4097static void
4098synaptics_sysctl_create_tree(struct psm_softc *sc)
4099{
4100
4101 if (sc->syninfo.sysctl_tree != NULL)
4102 return;
4103
4104 /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4105 sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4106 sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4107 SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
4108 0, "Synaptics TouchPad");
4109
4110 /* hw.psm.synaptics.directional_scrolls. */
3511 case MOUSE_MODEL_4D:
3512 /*
3513 * b7 b6 b5 b4 b3 b2 b1 b0
3514 * byte 1: s2 d2 s1 d1 1 M R L
3515 * byte 2: sx x x x x x x x
3516 * byte 3: sy y y y y y y y
3517 *
3518 * s1: wheel 1 direction
3519 * d1: wheel 1 data
3520 * s2: wheel 2 direction
3521 * d2: wheel 2 data
3522 */
3523 x = (pb->ipacket[1] & 0x80) ?
3524 pb->ipacket[1] - 256 : pb->ipacket[1];
3525 y = (pb->ipacket[2] & 0x80) ?
3526 pb->ipacket[2] - 256 : pb->ipacket[2];
3527 switch (c & MOUSE_4D_WHEELBITS) {
3528 case 0x10:
3529 z = 1;
3530 break;
3531 case 0x30:
3532 z = -1;
3533 break;
3534 case 0x40: /* XXX 2nd wheel turning right */
3535 z = 2;
3536 break;
3537 case 0xc0: /* XXX 2nd wheel turning left */
3538 z = -2;
3539 break;
3540 }
3541 break;
3542
3543 case MOUSE_MODEL_4DPLUS:
3544 if ((x < 16 - 256) && (y < 16 - 256)) {
3545 /*
3546 * b7 b6 b5 b4 b3 b2 b1 b0
3547 * byte 1: 0 0 1 1 1 M R L
3548 * byte 2: 0 0 0 0 1 0 0 0
3549 * byte 3: 0 0 0 0 S s d1 d0
3550 *
3551 * L, M, R, S: left, middle, right,
3552 * and side buttons
3553 * s: wheel data sign bit
3554 * d1-d0: wheel data
3555 */
3556 x = y = 0;
3557 if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
3558 ms.button |= MOUSE_BUTTON4DOWN;
3559 z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
3560 ((pb->ipacket[2] & 0x07) - 8) :
3561 (pb->ipacket[2] & 0x07) ;
3562 } else {
3563 /* preserve previous button states */
3564 ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
3565 }
3566 break;
3567
3568 case MOUSE_MODEL_SYNAPTICS:
3569 if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0)
3570 goto next;
3571 break;
3572
3573 case MOUSE_MODEL_TRACKPOINT:
3574 case MOUSE_MODEL_GENERIC:
3575 default:
3576 break;
3577 }
3578
3579 /* scale values */
3580 if (sc->mode.accelfactor >= 1) {
3581 if (x != 0) {
3582 x = x * x / sc->mode.accelfactor;
3583 if (x == 0)
3584 x = 1;
3585 if (c & MOUSE_PS2_XNEG)
3586 x = -x;
3587 }
3588 if (y != 0) {
3589 y = y * y / sc->mode.accelfactor;
3590 if (y == 0)
3591 y = 1;
3592 if (c & MOUSE_PS2_YNEG)
3593 y = -y;
3594 }
3595 }
3596
3597 ms.dx = x;
3598 ms.dy = y;
3599 ms.dz = z;
3600 ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
3601 (ms.obutton ^ ms.button);
3602
3603 pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
3604
3605 sc->status.flags |= ms.flags;
3606 sc->status.dx += ms.dx;
3607 sc->status.dy += ms.dy;
3608 sc->status.dz += ms.dz;
3609 sc->status.button = ms.button;
3610 sc->button = ms.button;
3611
3612next_native:
3613 sc->watchdog = FALSE;
3614
3615 /* queue data */
3616 if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
3617 l = imin(pb->inputbytes,
3618 sizeof(sc->queue.buf) - sc->queue.tail);
3619 bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
3620 if (pb->inputbytes > l)
3621 bcopy(&pb->ipacket[l], &sc->queue.buf[0],
3622 pb->inputbytes - l);
3623 sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
3624 sizeof(sc->queue.buf);
3625 sc->queue.count += pb->inputbytes;
3626 }
3627 pb->inputbytes = 0;
3628
3629next:
3630 if (++sc->pqueue_start >= PSM_PACKETQUEUE)
3631 sc->pqueue_start = 0;
3632 } while (sc->pqueue_start != sc->pqueue_end);
3633
3634 if (sc->state & PSM_ASLP) {
3635 sc->state &= ~PSM_ASLP;
3636 wakeup(sc);
3637 }
3638 selwakeuppri(&sc->rsel, PZERO);
3639 if (sc->async != NULL) {
3640 pgsigio(&sc->async, SIGIO, 0);
3641 }
3642 sc->state &= ~PSM_SOFTARMED;
3643 splx(s);
3644}
3645
3646static int
3647psmpoll(struct cdev *dev, int events, struct thread *td)
3648{
3649 struct psm_softc *sc = dev->si_drv1;
3650 int s;
3651 int revents = 0;
3652
3653 /* Return true if a mouse event available */
3654 s = spltty();
3655 if (events & (POLLIN | POLLRDNORM)) {
3656 if (sc->queue.count > 0)
3657 revents |= events & (POLLIN | POLLRDNORM);
3658 else
3659 selrecord(td, &sc->rsel);
3660 }
3661 splx(s);
3662
3663 return (revents);
3664}
3665
3666/* vendor/model specific routines */
3667
3668static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
3669{
3670 if (set_mouse_resolution(kbdc, res) != res)
3671 return (FALSE);
3672 if (set_mouse_scaling(kbdc, scale) &&
3673 set_mouse_scaling(kbdc, scale) &&
3674 set_mouse_scaling(kbdc, scale) &&
3675 (get_mouse_status(kbdc, status, 0, 3) >= 3))
3676 return (TRUE);
3677 return (FALSE);
3678}
3679
3680static int
3681mouse_ext_command(KBDC kbdc, int command)
3682{
3683 int c;
3684
3685 c = (command >> 6) & 0x03;
3686 if (set_mouse_resolution(kbdc, c) != c)
3687 return (FALSE);
3688 c = (command >> 4) & 0x03;
3689 if (set_mouse_resolution(kbdc, c) != c)
3690 return (FALSE);
3691 c = (command >> 2) & 0x03;
3692 if (set_mouse_resolution(kbdc, c) != c)
3693 return (FALSE);
3694 c = (command >> 0) & 0x03;
3695 if (set_mouse_resolution(kbdc, c) != c)
3696 return (FALSE);
3697 return (TRUE);
3698}
3699
3700#ifdef notyet
3701/* Logitech MouseMan Cordless II */
3702static int
3703enable_lcordless(KDBC kbdc, struct psm_softc *sc)
3704{
3705 int status[3];
3706 int ch;
3707
3708 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 2, status))
3709 return (FALSE);
3710 if (status[1] == PSMD_RES_HIGH)
3711 return (FALSE);
3712 ch = (status[0] & 0x07) - 1; /* channel # */
3713 if ((ch <= 0) || (ch > 4))
3714 return (FALSE);
3715 /*
3716 * status[1]: always one?
3717 * status[2]: battery status? (0-100)
3718 */
3719 return (TRUE);
3720}
3721#endif /* notyet */
3722
3723/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
3724static int
3725enable_groller(KBDC kbdc, struct psm_softc *sc)
3726{
3727 int status[3];
3728
3729 /*
3730 * The special sequence to enable the fourth button and the
3731 * roller. Immediately after this sequence check status bytes.
3732 * if the mouse is NetScroll, the second and the third bytes are
3733 * '3' and 'D'.
3734 */
3735
3736 /*
3737 * If the mouse is an ordinary PS/2 mouse, the status bytes should
3738 * look like the following.
3739 *
3740 * byte 1 bit 7 always 0
3741 * bit 6 stream mode (0)
3742 * bit 5 disabled (0)
3743 * bit 4 1:1 scaling (0)
3744 * bit 3 always 0
3745 * bit 0-2 button status
3746 * byte 2 resolution (PSMD_RES_HIGH)
3747 * byte 3 report rate (?)
3748 */
3749
3750 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3751 return (FALSE);
3752 if ((status[1] != '3') || (status[2] != 'D'))
3753 return (FALSE);
3754 /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
3755 if (sc != NULL)
3756 sc->hw.buttons = 4;
3757 return (TRUE);
3758}
3759
3760/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
3761static int
3762enable_gmouse(KBDC kbdc, struct psm_softc *sc)
3763{
3764 int status[3];
3765
3766 /*
3767 * The special sequence to enable the middle, "rubber" button.
3768 * Immediately after this sequence check status bytes.
3769 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
3770 * the second and the third bytes are '3' and 'U'.
3771 * NOTE: NetMouse reports that it has three buttons although it has
3772 * two buttons and a rubber button. NetMouse Pro and MIE Mouse
3773 * say they have three buttons too and they do have a button on the
3774 * side...
3775 */
3776 if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3777 return (FALSE);
3778 if ((status[1] != '3') || (status[2] != 'U'))
3779 return (FALSE);
3780 return (TRUE);
3781}
3782
3783/* ALPS GlidePoint */
3784static int
3785enable_aglide(KBDC kbdc, struct psm_softc *sc)
3786{
3787 int status[3];
3788
3789 /*
3790 * The special sequence to obtain ALPS GlidePoint specific
3791 * information. Immediately after this sequence, status bytes will
3792 * contain something interesting.
3793 * NOTE: ALPS produces several models of GlidePoint. Some of those
3794 * do not respond to this sequence, thus, cannot be detected this way.
3795 */
3796 if (set_mouse_sampling_rate(kbdc, 100) != 100)
3797 return (FALSE);
3798 if (!mouse_id_proc1(kbdc, PSMD_RES_LOW, 2, status))
3799 return (FALSE);
3800 if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
3801 return (FALSE);
3802 return (TRUE);
3803}
3804
3805/* Kensington ThinkingMouse/Trackball */
3806static int
3807enable_kmouse(KBDC kbdc, struct psm_softc *sc)
3808{
3809 static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
3810 int status[3];
3811 int id1;
3812 int id2;
3813 int i;
3814
3815 id1 = get_aux_id(kbdc);
3816 if (set_mouse_sampling_rate(kbdc, 10) != 10)
3817 return (FALSE);
3818 /*
3819 * The device is now in the native mode? It returns a different
3820 * ID value...
3821 */
3822 id2 = get_aux_id(kbdc);
3823 if ((id1 == id2) || (id2 != 2))
3824 return (FALSE);
3825
3826 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
3827 return (FALSE);
3828#if PSM_DEBUG >= 2
3829 /* at this point, resolution is LOW, sampling rate is 10/sec */
3830 if (get_mouse_status(kbdc, status, 0, 3) < 3)
3831 return (FALSE);
3832#endif
3833
3834 /*
3835 * The special sequence to enable the third and fourth buttons.
3836 * Otherwise they behave like the first and second buttons.
3837 */
3838 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3839 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3840 return (FALSE);
3841
3842 /*
3843 * At this point, the device is using default resolution and
3844 * sampling rate for the native mode.
3845 */
3846 if (get_mouse_status(kbdc, status, 0, 3) < 3)
3847 return (FALSE);
3848 if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
3849 return (FALSE);
3850
3851 /* the device appears be enabled by this sequence, diable it for now */
3852 disable_aux_dev(kbdc);
3853 empty_aux_buffer(kbdc, 5);
3854
3855 return (TRUE);
3856}
3857
3858/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
3859static int
3860enable_mmanplus(KBDC kbdc, struct psm_softc *sc)
3861{
3862 int data[3];
3863
3864 /* the special sequence to enable the fourth button and the roller. */
3865 /*
3866 * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
3867 * must be called exactly three times since the last RESET command
3868 * before this sequence. XXX
3869 */
3870 if (!set_mouse_scaling(kbdc, 1))
3871 return (FALSE);
3872 if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
3873 return (FALSE);
3874 if (get_mouse_status(kbdc, data, 1, 3) < 3)
3875 return (FALSE);
3876
3877 /*
3878 * PS2++ protocol, packet type 0
3879 *
3880 * b7 b6 b5 b4 b3 b2 b1 b0
3881 * byte 1: * 1 p3 p2 1 * * *
3882 * byte 2: 1 1 p1 p0 m1 m0 1 0
3883 * byte 3: m7 m6 m5 m4 m3 m2 m1 m0
3884 *
3885 * p3-p0: packet type: 0
3886 * m7-m0: model ID: MouseMan+:0x50,
3887 * FirstMouse+:0x51,
3888 * ScrollPoint:0x58...
3889 */
3890 /* check constant bits */
3891 if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
3892 return (FALSE);
3893 if ((data[1] & 0xc3) != 0xc2)
3894 return (FALSE);
3895 /* check d3-d0 in byte 2 */
3896 if (!MOUSE_PS2PLUS_CHECKBITS(data))
3897 return (FALSE);
3898 /* check p3-p0 */
3899 if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
3900 return (FALSE);
3901
3902 if (sc != NULL) {
3903 sc->hw.hwid &= 0x00ff;
3904 sc->hw.hwid |= data[2] << 8; /* save model ID */
3905 }
3906
3907 /*
3908 * MouseMan+ (or FirstMouse+) is now in its native mode, in which
3909 * the wheel and the fourth button events are encoded in the
3910 * special data packet. The mouse may be put in the IntelliMouse mode
3911 * if it is initialized by the IntelliMouse's method.
3912 */
3913 return (TRUE);
3914}
3915
3916/* MS IntelliMouse Explorer */
3917static int
3918enable_msexplorer(KBDC kbdc, struct psm_softc *sc)
3919{
3920 static u_char rate0[] = { 200, 100, 80, };
3921 static u_char rate1[] = { 200, 200, 80, };
3922 int id;
3923 int i;
3924
3925 /*
3926 * This is needed for at least A4Tech X-7xx mice - they do not go
3927 * straight to Explorer mode, but need to be set to Intelli mode
3928 * first.
3929 */
3930 enable_msintelli(kbdc, sc);
3931
3932 /* the special sequence to enable the extra buttons and the roller. */
3933 for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i)
3934 if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
3935 return (FALSE);
3936 /* the device will give the genuine ID only after the above sequence */
3937 id = get_aux_id(kbdc);
3938 if (id != PSM_EXPLORER_ID)
3939 return (FALSE);
3940
3941 if (sc != NULL) {
3942 sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */
3943 sc->hw.hwid = id;
3944 }
3945
3946 /*
3947 * XXX: this is a kludge to fool some KVM switch products
3948 * which think they are clever enough to know the 4-byte IntelliMouse
3949 * protocol, and assume any other protocols use 3-byte packets.
3950 * They don't convey 4-byte data packets from the IntelliMouse Explorer
3951 * correctly to the host computer because of this!
3952 * The following sequence is actually IntelliMouse's "wake up"
3953 * sequence; it will make the KVM think the mouse is IntelliMouse
3954 * when it is in fact IntelliMouse Explorer.
3955 */
3956 for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i)
3957 if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
3958 break;
3959 get_aux_id(kbdc);
3960
3961 return (TRUE);
3962}
3963
3964/* MS IntelliMouse */
3965static int
3966enable_msintelli(KBDC kbdc, struct psm_softc *sc)
3967{
3968 /*
3969 * Logitech MouseMan+ and FirstMouse+ will also respond to this
3970 * probe routine and act like IntelliMouse.
3971 */
3972
3973 static u_char rate[] = { 200, 100, 80, };
3974 int id;
3975 int i;
3976
3977 /* the special sequence to enable the third button and the roller. */
3978 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3979 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3980 return (FALSE);
3981 /* the device will give the genuine ID only after the above sequence */
3982 id = get_aux_id(kbdc);
3983 if (id != PSM_INTELLI_ID)
3984 return (FALSE);
3985
3986 if (sc != NULL) {
3987 sc->hw.buttons = 3;
3988 sc->hw.hwid = id;
3989 }
3990
3991 return (TRUE);
3992}
3993
3994/* A4 Tech 4D Mouse */
3995static int
3996enable_4dmouse(KBDC kbdc, struct psm_softc *sc)
3997{
3998 /*
3999 * Newer wheel mice from A4 Tech may use the 4D+ protocol.
4000 */
4001
4002 static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
4003 int id;
4004 int i;
4005
4006 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4007 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4008 return (FALSE);
4009 id = get_aux_id(kbdc);
4010 /*
4011 * WinEasy 4D, 4 Way Scroll 4D: 6
4012 * Cable-Free 4D: 8 (4DPLUS)
4013 * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
4014 */
4015 if (id != PSM_4DMOUSE_ID)
4016 return (FALSE);
4017
4018 if (sc != NULL) {
4019 sc->hw.buttons = 3; /* XXX some 4D mice have 4? */
4020 sc->hw.hwid = id;
4021 }
4022
4023 return (TRUE);
4024}
4025
4026/* A4 Tech 4D+ Mouse */
4027static int
4028enable_4dplus(KBDC kbdc, struct psm_softc *sc)
4029{
4030 /*
4031 * Newer wheel mice from A4 Tech seem to use this protocol.
4032 * Older models are recognized as either 4D Mouse or IntelliMouse.
4033 */
4034 int id;
4035
4036 /*
4037 * enable_4dmouse() already issued the following ID sequence...
4038 static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
4039 int i;
4040
4041 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4042 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4043 return (FALSE);
4044 */
4045
4046 id = get_aux_id(kbdc);
4047 switch (id) {
4048 case PSM_4DPLUS_ID:
4049 break;
4050 case PSM_4DPLUS_RFSW35_ID:
4051 break;
4052 default:
4053 return (FALSE);
4054 }
4055
4056 if (sc != NULL) {
4057 sc->hw.buttons = (id == PSM_4DPLUS_ID) ? 4 : 3;
4058 sc->hw.hwid = id;
4059 }
4060
4061 return (TRUE);
4062}
4063
4064/* Synaptics Touchpad */
4065static int
4066synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4067{
4068 int error, arg;
4069
4070 /* Read the current value. */
4071 arg = *(int *)oidp->oid_arg1;
4072 error = sysctl_handle_int(oidp, &arg, 0, req);
4073
4074 /* Sanity check. */
4075 if (error || !req->newptr)
4076 return (error);
4077
4078 /*
4079 * Check that the new value is in the concerned node's range
4080 * of values.
4081 */
4082 switch (oidp->oid_arg2) {
4083 case SYNAPTICS_SYSCTL_MIN_PRESSURE:
4084 case SYNAPTICS_SYSCTL_MAX_PRESSURE:
4085 if (arg < 0 || arg > 255)
4086 return (EINVAL);
4087 break;
4088 case SYNAPTICS_SYSCTL_MAX_WIDTH:
4089 if (arg < 4 || arg > 15)
4090 return (EINVAL);
4091 break;
4092 case SYNAPTICS_SYSCTL_MARGIN_TOP:
4093 case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4094 case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4095 case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4096 case SYNAPTICS_SYSCTL_NA_TOP:
4097 case SYNAPTICS_SYSCTL_NA_RIGHT:
4098 case SYNAPTICS_SYSCTL_NA_BOTTOM:
4099 case SYNAPTICS_SYSCTL_NA_LEFT:
4100 if (arg < 0 || arg > 6143)
4101 return (EINVAL);
4102 break;
4103 case SYNAPTICS_SYSCTL_WINDOW_MIN:
4104 case SYNAPTICS_SYSCTL_WINDOW_MAX:
4105 case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE:
4106 if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE)
4107 return (EINVAL);
4108 break;
4109 case SYNAPTICS_SYSCTL_MULTIPLICATOR:
4110 case SYNAPTICS_SYSCTL_WEIGHT_CURRENT:
4111 case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS:
4112 case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA:
4113 case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED:
4114 case SYNAPTICS_SYSCTL_DIV_MIN:
4115 case SYNAPTICS_SYSCTL_DIV_MAX:
4116 case SYNAPTICS_SYSCTL_DIV_MAX_NA:
4117 case SYNAPTICS_SYSCTL_DIV_LEN:
4118 case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN:
4119 case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX:
4120 if (arg < 1)
4121 return (EINVAL);
4122 break;
4123 case SYNAPTICS_SYSCTL_TAP_MAX_DELTA:
4124 case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT:
4125 case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA:
4126 if (arg < 0)
4127 return (EINVAL);
4128 break;
4129 case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4130 case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4131 if (arg < -6143 || arg > 6143)
4132 return (EINVAL);
4133 break;
4134 default:
4135 return (EINVAL);
4136 }
4137
4138 /* Update. */
4139 *(int *)oidp->oid_arg1 = arg;
4140
4141 return (error);
4142}
4143
4144static void
4145synaptics_sysctl_create_tree(struct psm_softc *sc)
4146{
4147
4148 if (sc->syninfo.sysctl_tree != NULL)
4149 return;
4150
4151 /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4152 sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4153 sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4154 SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
4155 0, "Synaptics TouchPad");
4156
4157 /* hw.psm.synaptics.directional_scrolls. */
4111 sc->syninfo.directional_scrolls = 1;
4158 sc->syninfo.directional_scrolls = 0;
4112 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4113 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4114 "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
4115 &sc->syninfo.directional_scrolls, 0,
4116 "Enable hardware scrolling pad (if non-zero) or register it as "
4159 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4160 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4161 "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
4162 &sc->syninfo.directional_scrolls, 0,
4163 "Enable hardware scrolling pad (if non-zero) or register it as "
4117 "a middle-click (if 0)");
4164 "extended buttons (if 0)");
4118
4165
4166 /*
4167 * Turn off two finger scroll if we have a
4168 * physical area reserved for scrolling or when
4169 * there's no multi finger support.
4170 */
4171 if (sc->synhw.verticalScroll || sc->synhw.capMultiFinger == 0)
4172 sc->syninfo.two_finger_scroll = 0;
4173 else
4174 sc->syninfo.two_finger_scroll = 1;
4175 /* hw.psm.synaptics.two_finger_scroll. */
4176 SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4177 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4178 "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY,
4179 &sc->syninfo.two_finger_scroll, 0,
4180 "Enable two finger scrolling");
4181
4119 /* hw.psm.synaptics.min_pressure. */
4120 sc->syninfo.min_pressure = 16;
4121 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4122 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4123 "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4124 &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4125 synaptics_sysctl, "I",
4126 "Minimum pressure required to start an action");
4127
4128 /* hw.psm.synaptics.max_pressure. */
4129 sc->syninfo.max_pressure = 220;
4130 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4131 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4132 "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4133 &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4134 synaptics_sysctl, "I",
4135 "Maximum pressure to detect palm");
4136
4137 /* hw.psm.synaptics.max_width. */
4138 sc->syninfo.max_width = 10;
4139 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4140 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4141 "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4142 &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
4143 synaptics_sysctl, "I",
4144 "Maximum finger width to detect palm");
4145
4146 /* hw.psm.synaptics.top_margin. */
4147 sc->syninfo.margin_top = 200;
4148 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4149 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4150 "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4151 &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
4152 synaptics_sysctl, "I",
4153 "Top margin");
4154
4155 /* hw.psm.synaptics.right_margin. */
4156 sc->syninfo.margin_right = 200;
4157 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4158 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4159 "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4160 &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4161 synaptics_sysctl, "I",
4162 "Right margin");
4163
4164 /* hw.psm.synaptics.bottom_margin. */
4165 sc->syninfo.margin_bottom = 200;
4166 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4167 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4168 "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4169 &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4170 synaptics_sysctl, "I",
4171 "Bottom margin");
4172
4173 /* hw.psm.synaptics.left_margin. */
4174 sc->syninfo.margin_left = 200;
4175 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4176 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4177 "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4178 &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4179 synaptics_sysctl, "I",
4180 "Left margin");
4181
4182 /* hw.psm.synaptics.na_top. */
4183 sc->syninfo.na_top = 1783;
4184 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4185 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4186 "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4187 &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
4188 synaptics_sysctl, "I",
4189 "Top noisy area, where weight_previous_na is used instead "
4190 "of weight_previous");
4191
4192 /* hw.psm.synaptics.na_right. */
4193 sc->syninfo.na_right = 563;
4194 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4195 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4196 "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4197 &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
4198 synaptics_sysctl, "I",
4199 "Right noisy area, where weight_previous_na is used instead "
4200 "of weight_previous");
4201
4202 /* hw.psm.synaptics.na_bottom. */
4203 sc->syninfo.na_bottom = 1408;
4204 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4205 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4206 "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4207 &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
4208 synaptics_sysctl, "I",
4209 "Bottom noisy area, where weight_previous_na is used instead "
4210 "of weight_previous");
4211
4212 /* hw.psm.synaptics.na_left. */
4213 sc->syninfo.na_left = 1600;
4214 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4215 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4216 "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4217 &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
4218 synaptics_sysctl, "I",
4219 "Left noisy area, where weight_previous_na is used instead "
4220 "of weight_previous");
4221
4222 /* hw.psm.synaptics.window_min. */
4223 sc->syninfo.window_min = 4;
4224 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4225 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4226 "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4227 &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
4228 synaptics_sysctl, "I",
4229 "Minimum window size to start an action");
4230
4231 /* hw.psm.synaptics.window_max. */
4232 sc->syninfo.window_max = 10;
4233 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4234 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4235 "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4236 &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
4237 synaptics_sysctl, "I",
4238 "Maximum window size");
4239
4240 /* hw.psm.synaptics.multiplicator. */
4241 sc->syninfo.multiplicator = 10000;
4242 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4243 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4244 "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4245 &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4246 synaptics_sysctl, "I",
4247 "Multiplicator to increase precision in averages and divisions");
4248
4249 /* hw.psm.synaptics.weight_current. */
4250 sc->syninfo.weight_current = 3;
4251 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4252 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4253 "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4254 &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4255 synaptics_sysctl, "I",
4256 "Weight of the current movement in the new average");
4257
4258 /* hw.psm.synaptics.weight_previous. */
4259 sc->syninfo.weight_previous = 6;
4260 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4261 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4262 "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4263 &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4264 synaptics_sysctl, "I",
4265 "Weight of the previous average");
4266
4267 /* hw.psm.synaptics.weight_previous_na. */
4268 sc->syninfo.weight_previous_na = 20;
4269 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4270 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4271 "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4272 &sc->syninfo.weight_previous_na,
4273 SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4274 synaptics_sysctl, "I",
4275 "Weight of the previous average (inside the noisy area)");
4276
4277 /* hw.psm.synaptics.weight_len_squared. */
4278 sc->syninfo.weight_len_squared = 2000;
4279 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4280 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4281 "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4282 &sc->syninfo.weight_len_squared,
4283 SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4284 synaptics_sysctl, "I",
4285 "Length (squared) of segments where weight_previous "
4286 "starts to decrease");
4287
4288 /* hw.psm.synaptics.div_min. */
4289 sc->syninfo.div_min = 9;
4290 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4291 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4292 "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4293 &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
4294 synaptics_sysctl, "I",
4295 "Divisor for fast movements");
4296
4297 /* hw.psm.synaptics.div_max. */
4298 sc->syninfo.div_max = 17;
4299 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4300 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4301 "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4302 &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
4303 synaptics_sysctl, "I",
4304 "Divisor for slow movements");
4305
4306 /* hw.psm.synaptics.div_max_na. */
4307 sc->syninfo.div_max_na = 30;
4308 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4309 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4310 "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4311 &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4312 synaptics_sysctl, "I",
4313 "Divisor with slow movements (inside the noisy area)");
4314
4315 /* hw.psm.synaptics.div_len. */
4316 sc->syninfo.div_len = 100;
4317 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4318 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4319 "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4320 &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
4321 synaptics_sysctl, "I",
4322 "Length of segments where div_max starts to decrease");
4323
4324 /* hw.psm.synaptics.tap_max_delta. */
4325 sc->syninfo.tap_max_delta = 80;
4326 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4327 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4328 "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4329 &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4330 synaptics_sysctl, "I",
4331 "Length of segments above which a tap is ignored");
4332
4333 /* hw.psm.synaptics.tap_min_queue. */
4334 sc->syninfo.tap_min_queue = 2;
4335 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4336 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4337 "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4338 &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4339 synaptics_sysctl, "I",
4340 "Number of packets required to consider a tap");
4341
4342 /* hw.psm.synaptics.taphold_timeout. */
4343 sc->synaction.in_taphold = 0;
4344 sc->syninfo.taphold_timeout = tap_timeout;
4345 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4346 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4347 "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4348 &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4349 synaptics_sysctl, "I",
4350 "Maximum elapsed time between two taps to consider a tap-hold "
4351 "action");
4352
4353 /* hw.psm.synaptics.vscroll_hor_area. */
4354 sc->syninfo.vscroll_hor_area = 0; /* 1300 */
4355 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4356 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4357 "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4358 &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4359 synaptics_sysctl, "I",
4360 "Area reserved for horizontal virtual scrolling");
4361
4362 /* hw.psm.synaptics.vscroll_ver_area. */
4363 sc->syninfo.vscroll_ver_area = -600;
4364 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4365 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4366 "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4367 &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4368 synaptics_sysctl, "I",
4369 "Area reserved for vertical virtual scrolling");
4370
4371 /* hw.psm.synaptics.vscroll_min_delta. */
4372 sc->syninfo.vscroll_min_delta = 50;
4373 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4374 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4375 "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4376 &sc->syninfo.vscroll_min_delta,
4377 SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4378 synaptics_sysctl, "I",
4379 "Minimum movement to consider virtual scrolling");
4380
4381 /* hw.psm.synaptics.vscroll_div_min. */
4382 sc->syninfo.vscroll_div_min = 100;
4383 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4384 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4385 "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4386 &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4387 synaptics_sysctl, "I",
4388 "Divisor for fast scrolling");
4389
4390 /* hw.psm.synaptics.vscroll_div_min. */
4391 sc->syninfo.vscroll_div_max = 150;
4392 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4393 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4394 "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4395 &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4396 synaptics_sysctl, "I",
4397 "Divisor for slow scrolling");
4398}
4399
4400static int
4401enable_synaptics(KBDC kbdc, struct psm_softc *sc)
4402{
4403 synapticshw_t synhw;
4404 int status[3];
4405 int buttons;
4406
4407 VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n"));
4408
4409 /*
4410 * Just to be on the safe side: this avoids troubles with
4411 * following mouse_ext_command() when the previous command
4412 * was PSMC_SET_RESOLUTION. Set Scaling has no effect on
4413 * Synaptics Touchpad behaviour.
4414 */
4415 set_mouse_scaling(kbdc, 1);
4416
4417 /* Identify the Touchpad version. */
4418 if (mouse_ext_command(kbdc, 0) == 0)
4419 return (FALSE);
4420 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4421 return (FALSE);
4422 if (status[1] != 0x47)
4423 return (FALSE);
4424
4425 bzero(&synhw, sizeof(synhw));
4426 synhw.infoMinor = status[0];
4427 synhw.infoMajor = status[2] & 0x0f;
4428
4429 if (verbose >= 2)
4430 printf("Synaptics Touchpad v%d.%d\n", synhw.infoMajor,
4431 synhw.infoMinor);
4432
4433 if (synhw.infoMajor < 4) {
4434 printf(" Unsupported (pre-v4) Touchpad detected\n");
4435 return (FALSE);
4436 }
4437
4438 /* Get the Touchpad model information. */
4439 if (mouse_ext_command(kbdc, 3) == 0)
4440 return (FALSE);
4441 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4442 return (FALSE);
4443 if ((status[1] & 0x01) != 0) {
4444 printf(" Failed to read model information\n");
4445 return (FALSE);
4446 }
4447
4448 synhw.infoRot180 = (status[0] & 0x80) != 0;
4449 synhw.infoPortrait = (status[0] & 0x40) != 0;
4450 synhw.infoSensor = status[0] & 0x3f;
4451 synhw.infoHardware = (status[1] & 0xfe) >> 1;
4452 synhw.infoNewAbs = (status[2] & 0x80) != 0;
4453 synhw.capPen = (status[2] & 0x40) != 0;
4454 synhw.infoSimplC = (status[2] & 0x20) != 0;
4455 synhw.infoGeometry = status[2] & 0x0f;
4456
4457 if (verbose >= 2) {
4458 printf(" Model information:\n");
4459 printf(" infoRot180: %d\n", synhw.infoRot180);
4460 printf(" infoPortrait: %d\n", synhw.infoPortrait);
4461 printf(" infoSensor: %d\n", synhw.infoSensor);
4462 printf(" infoHardware: %d\n", synhw.infoHardware);
4463 printf(" infoNewAbs: %d\n", synhw.infoNewAbs);
4464 printf(" capPen: %d\n", synhw.capPen);
4465 printf(" infoSimplC: %d\n", synhw.infoSimplC);
4466 printf(" infoGeometry: %d\n", synhw.infoGeometry);
4467 }
4468
4469 /* Read the extended capability bits. */
4470 if (mouse_ext_command(kbdc, 2) == 0)
4471 return (FALSE);
4472 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4473 return (FALSE);
4474 if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4475 printf(" Failed to read extended capability bits\n");
4476 return (FALSE);
4477 }
4478
4479 /* Set the different capabilities when they exist. */
4480 buttons = 0;
4481 synhw.capExtended = (status[0] & 0x80) != 0;
4482 if (synhw.capExtended) {
4483 synhw.nExtendedQueries = (status[0] & 0x70) != 0;
4484 synhw.capMiddle = (status[0] & 0x04) != 0;
4485 synhw.capPassthrough = (status[2] & 0x80) != 0;
4486 synhw.capLowPower = (status[2] & 0x40) != 0;
4487 synhw.capMultiFingerReport =
4488 (status[2] & 0x20) != 0;
4489 synhw.capSleep = (status[2] & 0x10) != 0;
4490 synhw.capFourButtons = (status[2] & 0x08) != 0;
4491 synhw.capBallistics = (status[2] & 0x04) != 0;
4492 synhw.capMultiFinger = (status[2] & 0x02) != 0;
4493 synhw.capPalmDetect = (status[2] & 0x01) != 0;
4494
4495 if (verbose >= 2) {
4496 printf(" Extended capabilities:\n");
4497 printf(" capExtended: %d\n", synhw.capExtended);
4498 printf(" capMiddle: %d\n", synhw.capMiddle);
4499 printf(" nExtendedQueries: %d\n",
4500 synhw.nExtendedQueries);
4501 printf(" capPassthrough: %d\n", synhw.capPassthrough);
4502 printf(" capLowPower: %d\n", synhw.capLowPower);
4503 printf(" capMultiFingerReport: %d\n",
4504 synhw.capMultiFingerReport);
4505 printf(" capSleep: %d\n", synhw.capSleep);
4506 printf(" capFourButtons: %d\n", synhw.capFourButtons);
4507 printf(" capBallistics: %d\n", synhw.capBallistics);
4508 printf(" capMultiFinger: %d\n", synhw.capMultiFinger);
4509 printf(" capPalmDetect: %d\n", synhw.capPalmDetect);
4510 }
4511
4512 /*
4513 * If nExtendedQueries is 1 or greater, then the TouchPad
4514 * supports this number of extended queries. We can load
4515 * more information about buttons using query 0x09.
4516 */
4517 if (synhw.capExtended && synhw.nExtendedQueries) {
4518 if (mouse_ext_command(kbdc, 0x09) == 0)
4519 return (FALSE);
4520 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4521 return (FALSE);
4182 /* hw.psm.synaptics.min_pressure. */
4183 sc->syninfo.min_pressure = 16;
4184 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4185 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4186 "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4187 &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4188 synaptics_sysctl, "I",
4189 "Minimum pressure required to start an action");
4190
4191 /* hw.psm.synaptics.max_pressure. */
4192 sc->syninfo.max_pressure = 220;
4193 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4194 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4195 "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4196 &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4197 synaptics_sysctl, "I",
4198 "Maximum pressure to detect palm");
4199
4200 /* hw.psm.synaptics.max_width. */
4201 sc->syninfo.max_width = 10;
4202 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4203 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4204 "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4205 &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
4206 synaptics_sysctl, "I",
4207 "Maximum finger width to detect palm");
4208
4209 /* hw.psm.synaptics.top_margin. */
4210 sc->syninfo.margin_top = 200;
4211 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4212 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4213 "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4214 &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
4215 synaptics_sysctl, "I",
4216 "Top margin");
4217
4218 /* hw.psm.synaptics.right_margin. */
4219 sc->syninfo.margin_right = 200;
4220 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4221 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4222 "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4223 &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4224 synaptics_sysctl, "I",
4225 "Right margin");
4226
4227 /* hw.psm.synaptics.bottom_margin. */
4228 sc->syninfo.margin_bottom = 200;
4229 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4230 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4231 "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4232 &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4233 synaptics_sysctl, "I",
4234 "Bottom margin");
4235
4236 /* hw.psm.synaptics.left_margin. */
4237 sc->syninfo.margin_left = 200;
4238 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4239 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4240 "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4241 &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4242 synaptics_sysctl, "I",
4243 "Left margin");
4244
4245 /* hw.psm.synaptics.na_top. */
4246 sc->syninfo.na_top = 1783;
4247 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4248 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4249 "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4250 &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
4251 synaptics_sysctl, "I",
4252 "Top noisy area, where weight_previous_na is used instead "
4253 "of weight_previous");
4254
4255 /* hw.psm.synaptics.na_right. */
4256 sc->syninfo.na_right = 563;
4257 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4258 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4259 "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4260 &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
4261 synaptics_sysctl, "I",
4262 "Right noisy area, where weight_previous_na is used instead "
4263 "of weight_previous");
4264
4265 /* hw.psm.synaptics.na_bottom. */
4266 sc->syninfo.na_bottom = 1408;
4267 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4268 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4269 "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4270 &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
4271 synaptics_sysctl, "I",
4272 "Bottom noisy area, where weight_previous_na is used instead "
4273 "of weight_previous");
4274
4275 /* hw.psm.synaptics.na_left. */
4276 sc->syninfo.na_left = 1600;
4277 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4278 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4279 "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4280 &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
4281 synaptics_sysctl, "I",
4282 "Left noisy area, where weight_previous_na is used instead "
4283 "of weight_previous");
4284
4285 /* hw.psm.synaptics.window_min. */
4286 sc->syninfo.window_min = 4;
4287 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4288 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4289 "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4290 &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
4291 synaptics_sysctl, "I",
4292 "Minimum window size to start an action");
4293
4294 /* hw.psm.synaptics.window_max. */
4295 sc->syninfo.window_max = 10;
4296 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4297 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4298 "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4299 &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
4300 synaptics_sysctl, "I",
4301 "Maximum window size");
4302
4303 /* hw.psm.synaptics.multiplicator. */
4304 sc->syninfo.multiplicator = 10000;
4305 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4306 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4307 "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4308 &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4309 synaptics_sysctl, "I",
4310 "Multiplicator to increase precision in averages and divisions");
4311
4312 /* hw.psm.synaptics.weight_current. */
4313 sc->syninfo.weight_current = 3;
4314 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4315 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4316 "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4317 &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4318 synaptics_sysctl, "I",
4319 "Weight of the current movement in the new average");
4320
4321 /* hw.psm.synaptics.weight_previous. */
4322 sc->syninfo.weight_previous = 6;
4323 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4324 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4325 "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4326 &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4327 synaptics_sysctl, "I",
4328 "Weight of the previous average");
4329
4330 /* hw.psm.synaptics.weight_previous_na. */
4331 sc->syninfo.weight_previous_na = 20;
4332 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4333 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4334 "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4335 &sc->syninfo.weight_previous_na,
4336 SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4337 synaptics_sysctl, "I",
4338 "Weight of the previous average (inside the noisy area)");
4339
4340 /* hw.psm.synaptics.weight_len_squared. */
4341 sc->syninfo.weight_len_squared = 2000;
4342 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4343 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4344 "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4345 &sc->syninfo.weight_len_squared,
4346 SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4347 synaptics_sysctl, "I",
4348 "Length (squared) of segments where weight_previous "
4349 "starts to decrease");
4350
4351 /* hw.psm.synaptics.div_min. */
4352 sc->syninfo.div_min = 9;
4353 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4354 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4355 "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4356 &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
4357 synaptics_sysctl, "I",
4358 "Divisor for fast movements");
4359
4360 /* hw.psm.synaptics.div_max. */
4361 sc->syninfo.div_max = 17;
4362 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4363 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4364 "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4365 &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
4366 synaptics_sysctl, "I",
4367 "Divisor for slow movements");
4368
4369 /* hw.psm.synaptics.div_max_na. */
4370 sc->syninfo.div_max_na = 30;
4371 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4372 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4373 "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4374 &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4375 synaptics_sysctl, "I",
4376 "Divisor with slow movements (inside the noisy area)");
4377
4378 /* hw.psm.synaptics.div_len. */
4379 sc->syninfo.div_len = 100;
4380 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4381 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4382 "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4383 &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
4384 synaptics_sysctl, "I",
4385 "Length of segments where div_max starts to decrease");
4386
4387 /* hw.psm.synaptics.tap_max_delta. */
4388 sc->syninfo.tap_max_delta = 80;
4389 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4390 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4391 "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4392 &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4393 synaptics_sysctl, "I",
4394 "Length of segments above which a tap is ignored");
4395
4396 /* hw.psm.synaptics.tap_min_queue. */
4397 sc->syninfo.tap_min_queue = 2;
4398 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4399 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4400 "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4401 &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4402 synaptics_sysctl, "I",
4403 "Number of packets required to consider a tap");
4404
4405 /* hw.psm.synaptics.taphold_timeout. */
4406 sc->synaction.in_taphold = 0;
4407 sc->syninfo.taphold_timeout = tap_timeout;
4408 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4409 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4410 "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4411 &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4412 synaptics_sysctl, "I",
4413 "Maximum elapsed time between two taps to consider a tap-hold "
4414 "action");
4415
4416 /* hw.psm.synaptics.vscroll_hor_area. */
4417 sc->syninfo.vscroll_hor_area = 0; /* 1300 */
4418 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4419 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4420 "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4421 &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4422 synaptics_sysctl, "I",
4423 "Area reserved for horizontal virtual scrolling");
4424
4425 /* hw.psm.synaptics.vscroll_ver_area. */
4426 sc->syninfo.vscroll_ver_area = -600;
4427 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4428 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4429 "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4430 &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4431 synaptics_sysctl, "I",
4432 "Area reserved for vertical virtual scrolling");
4433
4434 /* hw.psm.synaptics.vscroll_min_delta. */
4435 sc->syninfo.vscroll_min_delta = 50;
4436 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4437 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4438 "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4439 &sc->syninfo.vscroll_min_delta,
4440 SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4441 synaptics_sysctl, "I",
4442 "Minimum movement to consider virtual scrolling");
4443
4444 /* hw.psm.synaptics.vscroll_div_min. */
4445 sc->syninfo.vscroll_div_min = 100;
4446 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4447 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4448 "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4449 &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4450 synaptics_sysctl, "I",
4451 "Divisor for fast scrolling");
4452
4453 /* hw.psm.synaptics.vscroll_div_min. */
4454 sc->syninfo.vscroll_div_max = 150;
4455 SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4456 SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4457 "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4458 &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4459 synaptics_sysctl, "I",
4460 "Divisor for slow scrolling");
4461}
4462
4463static int
4464enable_synaptics(KBDC kbdc, struct psm_softc *sc)
4465{
4466 synapticshw_t synhw;
4467 int status[3];
4468 int buttons;
4469
4470 VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n"));
4471
4472 /*
4473 * Just to be on the safe side: this avoids troubles with
4474 * following mouse_ext_command() when the previous command
4475 * was PSMC_SET_RESOLUTION. Set Scaling has no effect on
4476 * Synaptics Touchpad behaviour.
4477 */
4478 set_mouse_scaling(kbdc, 1);
4479
4480 /* Identify the Touchpad version. */
4481 if (mouse_ext_command(kbdc, 0) == 0)
4482 return (FALSE);
4483 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4484 return (FALSE);
4485 if (status[1] != 0x47)
4486 return (FALSE);
4487
4488 bzero(&synhw, sizeof(synhw));
4489 synhw.infoMinor = status[0];
4490 synhw.infoMajor = status[2] & 0x0f;
4491
4492 if (verbose >= 2)
4493 printf("Synaptics Touchpad v%d.%d\n", synhw.infoMajor,
4494 synhw.infoMinor);
4495
4496 if (synhw.infoMajor < 4) {
4497 printf(" Unsupported (pre-v4) Touchpad detected\n");
4498 return (FALSE);
4499 }
4500
4501 /* Get the Touchpad model information. */
4502 if (mouse_ext_command(kbdc, 3) == 0)
4503 return (FALSE);
4504 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4505 return (FALSE);
4506 if ((status[1] & 0x01) != 0) {
4507 printf(" Failed to read model information\n");
4508 return (FALSE);
4509 }
4510
4511 synhw.infoRot180 = (status[0] & 0x80) != 0;
4512 synhw.infoPortrait = (status[0] & 0x40) != 0;
4513 synhw.infoSensor = status[0] & 0x3f;
4514 synhw.infoHardware = (status[1] & 0xfe) >> 1;
4515 synhw.infoNewAbs = (status[2] & 0x80) != 0;
4516 synhw.capPen = (status[2] & 0x40) != 0;
4517 synhw.infoSimplC = (status[2] & 0x20) != 0;
4518 synhw.infoGeometry = status[2] & 0x0f;
4519
4520 if (verbose >= 2) {
4521 printf(" Model information:\n");
4522 printf(" infoRot180: %d\n", synhw.infoRot180);
4523 printf(" infoPortrait: %d\n", synhw.infoPortrait);
4524 printf(" infoSensor: %d\n", synhw.infoSensor);
4525 printf(" infoHardware: %d\n", synhw.infoHardware);
4526 printf(" infoNewAbs: %d\n", synhw.infoNewAbs);
4527 printf(" capPen: %d\n", synhw.capPen);
4528 printf(" infoSimplC: %d\n", synhw.infoSimplC);
4529 printf(" infoGeometry: %d\n", synhw.infoGeometry);
4530 }
4531
4532 /* Read the extended capability bits. */
4533 if (mouse_ext_command(kbdc, 2) == 0)
4534 return (FALSE);
4535 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4536 return (FALSE);
4537 if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4538 printf(" Failed to read extended capability bits\n");
4539 return (FALSE);
4540 }
4541
4542 /* Set the different capabilities when they exist. */
4543 buttons = 0;
4544 synhw.capExtended = (status[0] & 0x80) != 0;
4545 if (synhw.capExtended) {
4546 synhw.nExtendedQueries = (status[0] & 0x70) != 0;
4547 synhw.capMiddle = (status[0] & 0x04) != 0;
4548 synhw.capPassthrough = (status[2] & 0x80) != 0;
4549 synhw.capLowPower = (status[2] & 0x40) != 0;
4550 synhw.capMultiFingerReport =
4551 (status[2] & 0x20) != 0;
4552 synhw.capSleep = (status[2] & 0x10) != 0;
4553 synhw.capFourButtons = (status[2] & 0x08) != 0;
4554 synhw.capBallistics = (status[2] & 0x04) != 0;
4555 synhw.capMultiFinger = (status[2] & 0x02) != 0;
4556 synhw.capPalmDetect = (status[2] & 0x01) != 0;
4557
4558 if (verbose >= 2) {
4559 printf(" Extended capabilities:\n");
4560 printf(" capExtended: %d\n", synhw.capExtended);
4561 printf(" capMiddle: %d\n", synhw.capMiddle);
4562 printf(" nExtendedQueries: %d\n",
4563 synhw.nExtendedQueries);
4564 printf(" capPassthrough: %d\n", synhw.capPassthrough);
4565 printf(" capLowPower: %d\n", synhw.capLowPower);
4566 printf(" capMultiFingerReport: %d\n",
4567 synhw.capMultiFingerReport);
4568 printf(" capSleep: %d\n", synhw.capSleep);
4569 printf(" capFourButtons: %d\n", synhw.capFourButtons);
4570 printf(" capBallistics: %d\n", synhw.capBallistics);
4571 printf(" capMultiFinger: %d\n", synhw.capMultiFinger);
4572 printf(" capPalmDetect: %d\n", synhw.capPalmDetect);
4573 }
4574
4575 /*
4576 * If nExtendedQueries is 1 or greater, then the TouchPad
4577 * supports this number of extended queries. We can load
4578 * more information about buttons using query 0x09.
4579 */
4580 if (synhw.capExtended && synhw.nExtendedQueries) {
4581 if (mouse_ext_command(kbdc, 0x09) == 0)
4582 return (FALSE);
4583 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4584 return (FALSE);
4585 synhw.verticalScroll = (status[0] & 0x01) != 0;
4586 synhw.horizontalScroll = (status[0] & 0x02) != 0;
4587 synhw.verticalWheel = (status[0] & 0x08) != 0;
4522 synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
4588 synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
4589 if (verbose >= 2) {
4590 printf(" Extended model ID:\n");
4591 printf(" verticalScroll: %d\n",
4592 synhw.verticalScroll);
4593 printf(" horizontalScroll: %d\n",
4594 synhw.horizontalScroll);
4595 printf(" verticalWheel: %d\n",
4596 synhw.verticalWheel);
4597 printf(" nExtendedButtons: %d\n",
4598 synhw.nExtendedButtons);
4599 }
4523 /*
4524 * Add the number of extended buttons to the total
4525 * button support count, including the middle button
4526 * if capMiddle support bit is set.
4527 */
4528 buttons = synhw.nExtendedButtons + synhw.capMiddle;
4529 } else
4530 /*
4531 * If the capFourButtons support bit is set,
4532 * add a fourth button to the total button count.
4533 */
4534 buttons = synhw.capFourButtons ? 1 : 0;
4535 }
4536 if (verbose >= 2) {
4537 if (synhw.capExtended)
4538 printf(" Additional Buttons: %d\n", buttons);
4539 else
4540 printf(" No extended capabilities\n");
4541 }
4542
4600 /*
4601 * Add the number of extended buttons to the total
4602 * button support count, including the middle button
4603 * if capMiddle support bit is set.
4604 */
4605 buttons = synhw.nExtendedButtons + synhw.capMiddle;
4606 } else
4607 /*
4608 * If the capFourButtons support bit is set,
4609 * add a fourth button to the total button count.
4610 */
4611 buttons = synhw.capFourButtons ? 1 : 0;
4612 }
4613 if (verbose >= 2) {
4614 if (synhw.capExtended)
4615 printf(" Additional Buttons: %d\n", buttons);
4616 else
4617 printf(" No extended capabilities\n");
4618 }
4619
4620 /* Read the continued capabilities bits. */
4621 if (mouse_ext_command(kbdc, 0xc) != 0 &&
4622 get_mouse_status(kbdc, status, 0, 3) == 3) {
4623 synhw.capClickPad = (status[1] & 0x01) << 1;
4624 synhw.capClickPad |= (status[0] & 0x10) != 0;
4625 synhw.capDeluxeLEDs = (status[1] & 0x02) != 0;
4626 synhw.noAbsoluteFilter = (status[1] & 0x04) != 0;
4627 synhw.capReportsV = (status[1] & 0x08) != 0;
4628 synhw.capUniformClickPad = (status[1] & 0x10) != 0;
4629 synhw.capReportsMin = (status[1] & 0x20) != 0;
4630 synhw.capInterTouch = (status[1] & 0x40) != 0;
4631 synhw.capReportsMax = (status[2] & 0x02) != 0;
4632 synhw.capClearPad = (status[2] & 0x04) != 0;
4633 synhw.capAdvancedGestures = (status[2] & 0x08) != 0;
4634 synhw.capCoveredPad = (status[2] & 0x80) != 0;
4635
4636 if (verbose >= 2) {
4637 printf(" Continued capabilities:\n");
4638 printf(" capClickPad: %d\n", synhw.capClickPad);
4639 printf(" capDeluxeLEDs: %d\n", synhw.capDeluxeLEDs);
4640 printf(" noAbsoluteFilter: %d\n",
4641 synhw.noAbsoluteFilter);
4642 printf(" capReportsV: %d\n", synhw.capReportsV);
4643 printf(" capUniformClickPad: %d\n",
4644 synhw.capUniformClickPad);
4645 printf(" capReportsMin: %d\n", synhw.capReportsMin);
4646 printf(" capInterTouch: %d\n", synhw.capInterTouch);
4647 printf(" capReportsMax: %d\n", synhw.capReportsMax);
4648 printf(" capClearPad: %d\n", synhw.capClearPad);
4649 printf(" capAdvancedGestures: %d\n",
4650 synhw.capAdvancedGestures);
4651 printf(" capCoveredPad: %d\n", synhw.capCoveredPad);
4652 }
4653 buttons += synhw.capClickPad;
4654 }
4655
4543 /*
4544 * Add the default number of 3 buttons to the total
4545 * count of supported buttons reported above.
4546 */
4547 buttons += 3;
4548
4549 /*
4550 * Read the mode byte.
4551 *
4552 * XXX: Note the Synaptics documentation also defines the first
4553 * byte of the response to this query to be a constant 0x3b, this
4554 * does not appear to be true for Touchpads with guest devices.
4555 */
4556 if (mouse_ext_command(kbdc, 1) == 0)
4557 return (FALSE);
4558 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4559 return (FALSE);
4560 if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4561 printf(" Failed to read mode byte\n");
4562 return (FALSE);
4563 }
4564
4565 if (sc != NULL)
4566 sc->synhw = synhw;
4567 if (!synaptics_support)
4568 return (FALSE);
4569
4570 /* Set the mode byte; request wmode where available. */
4571 mouse_ext_command(kbdc, synhw.capExtended ? 0xc1 : 0xc0);
4572
4573 /* "Commit" the Set Mode Byte command sent above. */
4574 set_mouse_sampling_rate(kbdc, 20);
4575
4576 VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
4577
4578 if (sc != NULL) {
4579 /* Create sysctl tree. */
4580 synaptics_sysctl_create_tree(sc);
4581
4582 sc->hw.buttons = buttons;
4583 }
4584
4585 return (TRUE);
4586}
4587
4588/* IBM/Lenovo TrackPoint */
4589static int
4590trackpoint_command(KBDC kbdc, int cmd, int loc, int val)
4591{
4592 const int seq[] = { 0xe2, cmd, loc, val };
4593 int i;
4594
4595 for (i = 0; i < nitems(seq); i++)
4596 if (send_aux_command(kbdc, seq[i]) != PSM_ACK)
4597 return (EIO);
4598 return (0);
4599}
4600
4601#define PSM_TPINFO(x) offsetof(struct psm_softc, tpinfo.x)
4602#define TPMASK 0
4603#define TPLOC 1
4604#define TPINFO 2
4605
4606static int
4607trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
4608{
4609 static const int data[][3] = {
4610 { 0x00, 0x4a, PSM_TPINFO(sensitivity) },
4611 { 0x00, 0x4d, PSM_TPINFO(inertia) },
4612 { 0x00, 0x60, PSM_TPINFO(uplateau) },
4613 { 0x00, 0x57, PSM_TPINFO(reach) },
4614 { 0x00, 0x58, PSM_TPINFO(draghys) },
4615 { 0x00, 0x59, PSM_TPINFO(mindrag) },
4616 { 0x00, 0x5a, PSM_TPINFO(upthresh) },
4617 { 0x00, 0x5c, PSM_TPINFO(threshold) },
4618 { 0x00, 0x5d, PSM_TPINFO(jenks) },
4619 { 0x00, 0x5e, PSM_TPINFO(ztime) },
4620 { 0x01, 0x2c, PSM_TPINFO(pts) },
4621 { 0x08, 0x2d, PSM_TPINFO(skipback) }
4622 };
4623 struct psm_softc *sc;
4624 int error, newval, *oldvalp;
4625 const int *tp;
4626
4627 if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data))
4628 return (EINVAL);
4629 sc = arg1;
4630 tp = data[arg2];
4631 oldvalp = (int *)((intptr_t)sc + tp[TPINFO]);
4632 newval = *oldvalp;
4633 error = sysctl_handle_int(oidp, &newval, 0, req);
4634 if (error != 0)
4635 return (error);
4636 if (newval == *oldvalp)
4637 return (0);
4638 if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
4639 return (EINVAL);
4640 error = trackpoint_command(sc->kbdc, tp[TPMASK] == 0 ? 0x81 : 0x47,
4641 tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
4642 if (error != 0)
4643 return (error);
4644 *oldvalp = newval;
4645
4646 return (0);
4647}
4648
4649static void
4650trackpoint_sysctl_create_tree(struct psm_softc *sc)
4651{
4652
4653 if (sc->tpinfo.sysctl_tree != NULL)
4654 return;
4655
4656 /* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
4657 sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
4658 sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
4659 SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
4660 0, "IBM/Lenovo TrackPoint");
4661
4662 /* hw.psm.trackpoint.sensitivity */
4663 sc->tpinfo.sensitivity = 0x64;
4664 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4665 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4666 "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4667 sc, TRACKPOINT_SYSCTL_SENSITIVITY,
4668 trackpoint_sysctl, "I",
4669 "Sensitivity");
4670
4671 /* hw.psm.trackpoint.negative_inertia */
4672 sc->tpinfo.inertia = 0x06;
4673 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4674 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4675 "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4676 sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
4677 trackpoint_sysctl, "I",
4678 "Negative inertia factor");
4679
4680 /* hw.psm.trackpoint.upper_plateau */
4681 sc->tpinfo.uplateau = 0x61;
4682 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4683 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4684 "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4685 sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
4686 trackpoint_sysctl, "I",
4687 "Transfer function upper plateau speed");
4688
4689 /* hw.psm.trackpoint.backup_range */
4690 sc->tpinfo.reach = 0x0a;
4691 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4692 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4693 "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4694 sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
4695 trackpoint_sysctl, "I",
4696 "Backup range");
4697
4698 /* hw.psm.trackpoint.drag_hysteresis */
4699 sc->tpinfo.draghys = 0xff;
4700 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4701 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4702 "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4703 sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
4704 trackpoint_sysctl, "I",
4705 "Drag hysteresis");
4706
4707 /* hw.psm.trackpoint.minimum_drag */
4708 sc->tpinfo.mindrag = 0x14;
4709 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4710 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4711 "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4712 sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
4713 trackpoint_sysctl, "I",
4714 "Minimum drag");
4715
4716 /* hw.psm.trackpoint.up_threshold */
4717 sc->tpinfo.upthresh = 0xff;
4718 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4719 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4720 "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4721 sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
4722 trackpoint_sysctl, "I",
4723 "Up threshold for release");
4724
4725 /* hw.psm.trackpoint.threshold */
4726 sc->tpinfo.threshold = 0x08;
4727 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4728 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4729 "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4730 sc, TRACKPOINT_SYSCTL_THRESHOLD,
4731 trackpoint_sysctl, "I",
4732 "Threshold");
4733
4734 /* hw.psm.trackpoint.jenks_curvature */
4735 sc->tpinfo.jenks = 0x87;
4736 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4737 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4738 "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4739 sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
4740 trackpoint_sysctl, "I",
4741 "Jenks curvature");
4742
4743 /* hw.psm.trackpoint.z_time */
4744 sc->tpinfo.ztime = 0x26;
4745 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4746 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4747 "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4748 sc, TRACKPOINT_SYSCTL_Z_TIME,
4749 trackpoint_sysctl, "I",
4750 "Z time constant");
4751
4752 /* hw.psm.trackpoint.press_to_select */
4753 sc->tpinfo.pts = 0x00;
4754 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4755 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4756 "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4757 sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
4758 trackpoint_sysctl, "I",
4759 "Press to Select");
4760
4761 /* hw.psm.trackpoint.skip_backups */
4762 sc->tpinfo.skipback = 0x00;
4763 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4764 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4765 "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4766 sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
4767 trackpoint_sysctl, "I",
4768 "Skip backups from drags");
4769}
4770
4771static int
4772enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
4773{
4774 int id;
4775
4776 if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
4777 read_aux_data(kbdc) != 0x01)
4778 return (FALSE);
4779 id = read_aux_data(kbdc);
4780 if (id < 0x01)
4781 return (FALSE);
4782 if (sc != NULL)
4783 sc->tphw = id;
4784 if (!trackpoint_support)
4785 return (FALSE);
4786
4787 if (sc != NULL) {
4788 /* Create sysctl tree. */
4789 trackpoint_sysctl_create_tree(sc);
4790
4791 trackpoint_command(kbdc, 0x81, 0x4a, sc->tpinfo.sensitivity);
4792 trackpoint_command(kbdc, 0x81, 0x4d, sc->tpinfo.inertia);
4793 trackpoint_command(kbdc, 0x81, 0x60, sc->tpinfo.uplateau);
4794 trackpoint_command(kbdc, 0x81, 0x57, sc->tpinfo.reach);
4795 trackpoint_command(kbdc, 0x81, 0x58, sc->tpinfo.draghys);
4796 trackpoint_command(kbdc, 0x81, 0x59, sc->tpinfo.mindrag);
4797 trackpoint_command(kbdc, 0x81, 0x5a, sc->tpinfo.upthresh);
4798 trackpoint_command(kbdc, 0x81, 0x5c, sc->tpinfo.threshold);
4799 trackpoint_command(kbdc, 0x81, 0x5d, sc->tpinfo.jenks);
4800 trackpoint_command(kbdc, 0x81, 0x5e, sc->tpinfo.ztime);
4801 if (sc->tpinfo.pts == 0x01)
4802 trackpoint_command(kbdc, 0x47, 0x2c, 0x01);
4803 if (sc->tpinfo.skipback == 0x01)
4804 trackpoint_command(kbdc, 0x47, 0x2d, 0x08);
4805
4806 sc->hw.hwid = id;
4807 sc->hw.buttons = 3;
4808 }
4809
4810 return (TRUE);
4811}
4812
4813/* Interlink electronics VersaPad */
4814static int
4815enable_versapad(KBDC kbdc, struct psm_softc *sc)
4816{
4817 int data[3];
4818
4819 set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
4820 set_mouse_sampling_rate(kbdc, 100); /* set rate 100 */
4821 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4822 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4823 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4824 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4825 if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */
4826 return (FALSE);
4827 if (data[2] != 0xa || data[1] != 0 ) /* rate == 0xa && res. == 0 */
4828 return (FALSE);
4829 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4830
4831 return (TRUE); /* PS/2 absolute mode */
4832}
4833
4834/*
4835 * Return true if 'now' is earlier than (start + (secs.usecs)).
4836 * Now may be NULL and the function will fetch the current time from
4837 * getmicrouptime(), or a cached 'now' can be passed in.
4838 * All values should be numbers derived from getmicrouptime().
4839 */
4840static int
4841timeelapsed(start, secs, usecs, now)
4842 const struct timeval *start, *now;
4843 int secs, usecs;
4844{
4845 struct timeval snow, tv;
4846
4847 /* if there is no 'now' passed in, the get it as a convience. */
4848 if (now == NULL) {
4849 getmicrouptime(&snow);
4850 now = &snow;
4851 }
4852
4853 tv.tv_sec = secs;
4854 tv.tv_usec = usecs;
4855 timevaladd(&tv, start);
4856 return (timevalcmp(&tv, now, <));
4857}
4858
4859static int
4860psmresume(device_t dev)
4861{
4862 struct psm_softc *sc = device_get_softc(dev);
4863 int unit = device_get_unit(dev);
4864 int err;
4865
4866 VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
4867
4868 if ((sc->config &
4869 (PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND)) == 0)
4870 return (0);
4871
4872 err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
4873
4874 if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
4875 /*
4876 * Release the blocked process; it must be notified that
4877 * the device cannot be accessed anymore.
4878 */
4879 sc->state &= ~PSM_ASLP;
4880 wakeup(sc);
4881 }
4882
4883 VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
4884
4885 return (err);
4886}
4887
4888DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
4889
4890#ifdef DEV_ISA
4891
4892/*
4893 * This sucks up assignments from PNPBIOS and ACPI.
4894 */
4895
4896/*
4897 * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
4898 * appear BEFORE the AT keyboard controller. As the PS/2 mouse device
4899 * can be probed and attached only after the AT keyboard controller is
4900 * attached, we shall quietly reserve the IRQ resource for later use.
4901 * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
4902 * copy the IRQ resource to the PS/2 mouse device instance hanging
4903 * under the keyboard controller, then probe and attach it.
4904 */
4905
4906static devclass_t psmcpnp_devclass;
4907
4908static device_probe_t psmcpnp_probe;
4909static device_attach_t psmcpnp_attach;
4910
4911static device_method_t psmcpnp_methods[] = {
4912 DEVMETHOD(device_probe, psmcpnp_probe),
4913 DEVMETHOD(device_attach, psmcpnp_attach),
4914
4915 { 0, 0 }
4916};
4917
4918static driver_t psmcpnp_driver = {
4919 PSMCPNP_DRIVER_NAME,
4920 psmcpnp_methods,
4921 1, /* no softc */
4922};
4923
4924static struct isa_pnp_id psmcpnp_ids[] = {
4925 { 0x030fd041, "PS/2 mouse port" }, /* PNP0F03 */
4926 { 0x0e0fd041, "PS/2 mouse port" }, /* PNP0F0E */
4927 { 0x120fd041, "PS/2 mouse port" }, /* PNP0F12 */
4928 { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */
4929 { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */
4930 { 0x02002e4f, "Dell PS/2 mouse port" }, /* Lat. X200, Dell */
4931 { 0x0002a906, "ALPS Glide Point" }, /* ALPS Glide Point */
4932 { 0x80374d24, "IBM PS/2 mouse port" }, /* IBM3780, ThinkPad */
4933 { 0x81374d24, "IBM PS/2 mouse port" }, /* IBM3781, ThinkPad */
4934 { 0x0190d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9001, Vaio */
4935 { 0x0290d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9002, Vaio */
4936 { 0x0390d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9003, Vaio */
4937 { 0x0490d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9004, Vaio */
4938 { 0 }
4939};
4940
4941static int
4942create_a_copy(device_t atkbdc, device_t me)
4943{
4944 device_t psm;
4945 u_long irq;
4946
4947 /* find the PS/2 mouse device instance under the keyboard controller */
4948 psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
4949 device_get_unit(atkbdc));
4950 if (psm == NULL)
4951 return (ENXIO);
4952 if (device_get_state(psm) != DS_NOTPRESENT)
4953 return (0);
4954
4955 /* move our resource to the found device */
4956 irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
4957 bus_delete_resource(me, SYS_RES_IRQ, 0);
4958 bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
4959
4960 /* ...then probe and attach it */
4961 return (device_probe_and_attach(psm));
4962}
4963
4964static int
4965psmcpnp_probe(device_t dev)
4966{
4967 struct resource *res;
4968 u_long irq;
4969 int rid;
4970
4971 if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
4972 return (ENXIO);
4973
4974 /*
4975 * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
4976 * to the PS/2 mouse device node. But, some buggy PnP BIOS
4977 * declares the PS/2 mouse device node without an IRQ resource!
4978 * If this happens, we shall refer to device hints.
4979 * If we still don't find it there, use a hardcoded value... XXX
4980 */
4981 rid = 0;
4982 irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
4983 if (irq <= 0) {
4984 if (resource_long_value(PSM_DRIVER_NAME,
4985 device_get_unit(dev),"irq", &irq) != 0)
4986 irq = 12; /* XXX */
4987 device_printf(dev, "irq resource info is missing; "
4988 "assuming irq %ld\n", irq);
4989 bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
4990 }
4991 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
4992 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
4993
4994 /* keep quiet */
4995 if (!bootverbose)
4996 device_quiet(dev);
4997
4998 return ((res == NULL) ? ENXIO : 0);
4999}
5000
5001static int
5002psmcpnp_attach(device_t dev)
5003{
5004 device_t atkbdc;
5005
5006 /* find the keyboard controller, which may be on acpi* or isa* bus */
5007 atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
5008 device_get_unit(dev));
5009 if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
5010 create_a_copy(atkbdc, dev);
5011
5012 return (0);
5013}
5014
5015DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5016DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5017
5018#endif /* DEV_ISA */
4656 /*
4657 * Add the default number of 3 buttons to the total
4658 * count of supported buttons reported above.
4659 */
4660 buttons += 3;
4661
4662 /*
4663 * Read the mode byte.
4664 *
4665 * XXX: Note the Synaptics documentation also defines the first
4666 * byte of the response to this query to be a constant 0x3b, this
4667 * does not appear to be true for Touchpads with guest devices.
4668 */
4669 if (mouse_ext_command(kbdc, 1) == 0)
4670 return (FALSE);
4671 if (get_mouse_status(kbdc, status, 0, 3) != 3)
4672 return (FALSE);
4673 if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4674 printf(" Failed to read mode byte\n");
4675 return (FALSE);
4676 }
4677
4678 if (sc != NULL)
4679 sc->synhw = synhw;
4680 if (!synaptics_support)
4681 return (FALSE);
4682
4683 /* Set the mode byte; request wmode where available. */
4684 mouse_ext_command(kbdc, synhw.capExtended ? 0xc1 : 0xc0);
4685
4686 /* "Commit" the Set Mode Byte command sent above. */
4687 set_mouse_sampling_rate(kbdc, 20);
4688
4689 VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
4690
4691 if (sc != NULL) {
4692 /* Create sysctl tree. */
4693 synaptics_sysctl_create_tree(sc);
4694
4695 sc->hw.buttons = buttons;
4696 }
4697
4698 return (TRUE);
4699}
4700
4701/* IBM/Lenovo TrackPoint */
4702static int
4703trackpoint_command(KBDC kbdc, int cmd, int loc, int val)
4704{
4705 const int seq[] = { 0xe2, cmd, loc, val };
4706 int i;
4707
4708 for (i = 0; i < nitems(seq); i++)
4709 if (send_aux_command(kbdc, seq[i]) != PSM_ACK)
4710 return (EIO);
4711 return (0);
4712}
4713
4714#define PSM_TPINFO(x) offsetof(struct psm_softc, tpinfo.x)
4715#define TPMASK 0
4716#define TPLOC 1
4717#define TPINFO 2
4718
4719static int
4720trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
4721{
4722 static const int data[][3] = {
4723 { 0x00, 0x4a, PSM_TPINFO(sensitivity) },
4724 { 0x00, 0x4d, PSM_TPINFO(inertia) },
4725 { 0x00, 0x60, PSM_TPINFO(uplateau) },
4726 { 0x00, 0x57, PSM_TPINFO(reach) },
4727 { 0x00, 0x58, PSM_TPINFO(draghys) },
4728 { 0x00, 0x59, PSM_TPINFO(mindrag) },
4729 { 0x00, 0x5a, PSM_TPINFO(upthresh) },
4730 { 0x00, 0x5c, PSM_TPINFO(threshold) },
4731 { 0x00, 0x5d, PSM_TPINFO(jenks) },
4732 { 0x00, 0x5e, PSM_TPINFO(ztime) },
4733 { 0x01, 0x2c, PSM_TPINFO(pts) },
4734 { 0x08, 0x2d, PSM_TPINFO(skipback) }
4735 };
4736 struct psm_softc *sc;
4737 int error, newval, *oldvalp;
4738 const int *tp;
4739
4740 if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data))
4741 return (EINVAL);
4742 sc = arg1;
4743 tp = data[arg2];
4744 oldvalp = (int *)((intptr_t)sc + tp[TPINFO]);
4745 newval = *oldvalp;
4746 error = sysctl_handle_int(oidp, &newval, 0, req);
4747 if (error != 0)
4748 return (error);
4749 if (newval == *oldvalp)
4750 return (0);
4751 if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
4752 return (EINVAL);
4753 error = trackpoint_command(sc->kbdc, tp[TPMASK] == 0 ? 0x81 : 0x47,
4754 tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
4755 if (error != 0)
4756 return (error);
4757 *oldvalp = newval;
4758
4759 return (0);
4760}
4761
4762static void
4763trackpoint_sysctl_create_tree(struct psm_softc *sc)
4764{
4765
4766 if (sc->tpinfo.sysctl_tree != NULL)
4767 return;
4768
4769 /* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
4770 sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
4771 sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
4772 SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
4773 0, "IBM/Lenovo TrackPoint");
4774
4775 /* hw.psm.trackpoint.sensitivity */
4776 sc->tpinfo.sensitivity = 0x64;
4777 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4778 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4779 "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4780 sc, TRACKPOINT_SYSCTL_SENSITIVITY,
4781 trackpoint_sysctl, "I",
4782 "Sensitivity");
4783
4784 /* hw.psm.trackpoint.negative_inertia */
4785 sc->tpinfo.inertia = 0x06;
4786 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4787 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4788 "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4789 sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
4790 trackpoint_sysctl, "I",
4791 "Negative inertia factor");
4792
4793 /* hw.psm.trackpoint.upper_plateau */
4794 sc->tpinfo.uplateau = 0x61;
4795 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4796 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4797 "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4798 sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
4799 trackpoint_sysctl, "I",
4800 "Transfer function upper plateau speed");
4801
4802 /* hw.psm.trackpoint.backup_range */
4803 sc->tpinfo.reach = 0x0a;
4804 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4805 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4806 "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4807 sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
4808 trackpoint_sysctl, "I",
4809 "Backup range");
4810
4811 /* hw.psm.trackpoint.drag_hysteresis */
4812 sc->tpinfo.draghys = 0xff;
4813 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4814 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4815 "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4816 sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
4817 trackpoint_sysctl, "I",
4818 "Drag hysteresis");
4819
4820 /* hw.psm.trackpoint.minimum_drag */
4821 sc->tpinfo.mindrag = 0x14;
4822 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4823 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4824 "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4825 sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
4826 trackpoint_sysctl, "I",
4827 "Minimum drag");
4828
4829 /* hw.psm.trackpoint.up_threshold */
4830 sc->tpinfo.upthresh = 0xff;
4831 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4832 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4833 "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4834 sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
4835 trackpoint_sysctl, "I",
4836 "Up threshold for release");
4837
4838 /* hw.psm.trackpoint.threshold */
4839 sc->tpinfo.threshold = 0x08;
4840 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4841 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4842 "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4843 sc, TRACKPOINT_SYSCTL_THRESHOLD,
4844 trackpoint_sysctl, "I",
4845 "Threshold");
4846
4847 /* hw.psm.trackpoint.jenks_curvature */
4848 sc->tpinfo.jenks = 0x87;
4849 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4850 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4851 "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4852 sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
4853 trackpoint_sysctl, "I",
4854 "Jenks curvature");
4855
4856 /* hw.psm.trackpoint.z_time */
4857 sc->tpinfo.ztime = 0x26;
4858 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4859 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4860 "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4861 sc, TRACKPOINT_SYSCTL_Z_TIME,
4862 trackpoint_sysctl, "I",
4863 "Z time constant");
4864
4865 /* hw.psm.trackpoint.press_to_select */
4866 sc->tpinfo.pts = 0x00;
4867 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4868 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4869 "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4870 sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
4871 trackpoint_sysctl, "I",
4872 "Press to Select");
4873
4874 /* hw.psm.trackpoint.skip_backups */
4875 sc->tpinfo.skipback = 0x00;
4876 SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4877 SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4878 "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4879 sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
4880 trackpoint_sysctl, "I",
4881 "Skip backups from drags");
4882}
4883
4884static int
4885enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
4886{
4887 int id;
4888
4889 if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
4890 read_aux_data(kbdc) != 0x01)
4891 return (FALSE);
4892 id = read_aux_data(kbdc);
4893 if (id < 0x01)
4894 return (FALSE);
4895 if (sc != NULL)
4896 sc->tphw = id;
4897 if (!trackpoint_support)
4898 return (FALSE);
4899
4900 if (sc != NULL) {
4901 /* Create sysctl tree. */
4902 trackpoint_sysctl_create_tree(sc);
4903
4904 trackpoint_command(kbdc, 0x81, 0x4a, sc->tpinfo.sensitivity);
4905 trackpoint_command(kbdc, 0x81, 0x4d, sc->tpinfo.inertia);
4906 trackpoint_command(kbdc, 0x81, 0x60, sc->tpinfo.uplateau);
4907 trackpoint_command(kbdc, 0x81, 0x57, sc->tpinfo.reach);
4908 trackpoint_command(kbdc, 0x81, 0x58, sc->tpinfo.draghys);
4909 trackpoint_command(kbdc, 0x81, 0x59, sc->tpinfo.mindrag);
4910 trackpoint_command(kbdc, 0x81, 0x5a, sc->tpinfo.upthresh);
4911 trackpoint_command(kbdc, 0x81, 0x5c, sc->tpinfo.threshold);
4912 trackpoint_command(kbdc, 0x81, 0x5d, sc->tpinfo.jenks);
4913 trackpoint_command(kbdc, 0x81, 0x5e, sc->tpinfo.ztime);
4914 if (sc->tpinfo.pts == 0x01)
4915 trackpoint_command(kbdc, 0x47, 0x2c, 0x01);
4916 if (sc->tpinfo.skipback == 0x01)
4917 trackpoint_command(kbdc, 0x47, 0x2d, 0x08);
4918
4919 sc->hw.hwid = id;
4920 sc->hw.buttons = 3;
4921 }
4922
4923 return (TRUE);
4924}
4925
4926/* Interlink electronics VersaPad */
4927static int
4928enable_versapad(KBDC kbdc, struct psm_softc *sc)
4929{
4930 int data[3];
4931
4932 set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
4933 set_mouse_sampling_rate(kbdc, 100); /* set rate 100 */
4934 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4935 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4936 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4937 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4938 if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */
4939 return (FALSE);
4940 if (data[2] != 0xa || data[1] != 0 ) /* rate == 0xa && res. == 0 */
4941 return (FALSE);
4942 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
4943
4944 return (TRUE); /* PS/2 absolute mode */
4945}
4946
4947/*
4948 * Return true if 'now' is earlier than (start + (secs.usecs)).
4949 * Now may be NULL and the function will fetch the current time from
4950 * getmicrouptime(), or a cached 'now' can be passed in.
4951 * All values should be numbers derived from getmicrouptime().
4952 */
4953static int
4954timeelapsed(start, secs, usecs, now)
4955 const struct timeval *start, *now;
4956 int secs, usecs;
4957{
4958 struct timeval snow, tv;
4959
4960 /* if there is no 'now' passed in, the get it as a convience. */
4961 if (now == NULL) {
4962 getmicrouptime(&snow);
4963 now = &snow;
4964 }
4965
4966 tv.tv_sec = secs;
4967 tv.tv_usec = usecs;
4968 timevaladd(&tv, start);
4969 return (timevalcmp(&tv, now, <));
4970}
4971
4972static int
4973psmresume(device_t dev)
4974{
4975 struct psm_softc *sc = device_get_softc(dev);
4976 int unit = device_get_unit(dev);
4977 int err;
4978
4979 VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
4980
4981 if ((sc->config &
4982 (PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND)) == 0)
4983 return (0);
4984
4985 err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
4986
4987 if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
4988 /*
4989 * Release the blocked process; it must be notified that
4990 * the device cannot be accessed anymore.
4991 */
4992 sc->state &= ~PSM_ASLP;
4993 wakeup(sc);
4994 }
4995
4996 VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
4997
4998 return (err);
4999}
5000
5001DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
5002
5003#ifdef DEV_ISA
5004
5005/*
5006 * This sucks up assignments from PNPBIOS and ACPI.
5007 */
5008
5009/*
5010 * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
5011 * appear BEFORE the AT keyboard controller. As the PS/2 mouse device
5012 * can be probed and attached only after the AT keyboard controller is
5013 * attached, we shall quietly reserve the IRQ resource for later use.
5014 * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
5015 * copy the IRQ resource to the PS/2 mouse device instance hanging
5016 * under the keyboard controller, then probe and attach it.
5017 */
5018
5019static devclass_t psmcpnp_devclass;
5020
5021static device_probe_t psmcpnp_probe;
5022static device_attach_t psmcpnp_attach;
5023
5024static device_method_t psmcpnp_methods[] = {
5025 DEVMETHOD(device_probe, psmcpnp_probe),
5026 DEVMETHOD(device_attach, psmcpnp_attach),
5027
5028 { 0, 0 }
5029};
5030
5031static driver_t psmcpnp_driver = {
5032 PSMCPNP_DRIVER_NAME,
5033 psmcpnp_methods,
5034 1, /* no softc */
5035};
5036
5037static struct isa_pnp_id psmcpnp_ids[] = {
5038 { 0x030fd041, "PS/2 mouse port" }, /* PNP0F03 */
5039 { 0x0e0fd041, "PS/2 mouse port" }, /* PNP0F0E */
5040 { 0x120fd041, "PS/2 mouse port" }, /* PNP0F12 */
5041 { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */
5042 { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */
5043 { 0x02002e4f, "Dell PS/2 mouse port" }, /* Lat. X200, Dell */
5044 { 0x0002a906, "ALPS Glide Point" }, /* ALPS Glide Point */
5045 { 0x80374d24, "IBM PS/2 mouse port" }, /* IBM3780, ThinkPad */
5046 { 0x81374d24, "IBM PS/2 mouse port" }, /* IBM3781, ThinkPad */
5047 { 0x0190d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9001, Vaio */
5048 { 0x0290d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9002, Vaio */
5049 { 0x0390d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9003, Vaio */
5050 { 0x0490d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9004, Vaio */
5051 { 0 }
5052};
5053
5054static int
5055create_a_copy(device_t atkbdc, device_t me)
5056{
5057 device_t psm;
5058 u_long irq;
5059
5060 /* find the PS/2 mouse device instance under the keyboard controller */
5061 psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
5062 device_get_unit(atkbdc));
5063 if (psm == NULL)
5064 return (ENXIO);
5065 if (device_get_state(psm) != DS_NOTPRESENT)
5066 return (0);
5067
5068 /* move our resource to the found device */
5069 irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
5070 bus_delete_resource(me, SYS_RES_IRQ, 0);
5071 bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
5072
5073 /* ...then probe and attach it */
5074 return (device_probe_and_attach(psm));
5075}
5076
5077static int
5078psmcpnp_probe(device_t dev)
5079{
5080 struct resource *res;
5081 u_long irq;
5082 int rid;
5083
5084 if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
5085 return (ENXIO);
5086
5087 /*
5088 * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
5089 * to the PS/2 mouse device node. But, some buggy PnP BIOS
5090 * declares the PS/2 mouse device node without an IRQ resource!
5091 * If this happens, we shall refer to device hints.
5092 * If we still don't find it there, use a hardcoded value... XXX
5093 */
5094 rid = 0;
5095 irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
5096 if (irq <= 0) {
5097 if (resource_long_value(PSM_DRIVER_NAME,
5098 device_get_unit(dev),"irq", &irq) != 0)
5099 irq = 12; /* XXX */
5100 device_printf(dev, "irq resource info is missing; "
5101 "assuming irq %ld\n", irq);
5102 bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
5103 }
5104 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
5105 bus_release_resource(dev, SYS_RES_IRQ, rid, res);
5106
5107 /* keep quiet */
5108 if (!bootverbose)
5109 device_quiet(dev);
5110
5111 return ((res == NULL) ? ENXIO : 0);
5112}
5113
5114static int
5115psmcpnp_attach(device_t dev)
5116{
5117 device_t atkbdc;
5118
5119 /* find the keyboard controller, which may be on acpi* or isa* bus */
5120 atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
5121 device_get_unit(dev));
5122 if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
5123 create_a_copy(atkbdc, dev);
5124
5125 return (0);
5126}
5127
5128DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5129DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5130
5131#endif /* DEV_ISA */