FreeBSD/Linux Kernel Cross Reference
sys/isa/psm.c
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 * $FreeBSD$
24 */
25
26 /*
27 * Ported to 386bsd Oct 17, 1992
28 * Sandi Donno, Computer Science, University of Cape Town, South Africa
29 * Please send bug reports to sandi@cs.uct.ac.za
30 *
31 * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
32 * although I was only partially successful in getting the alpha release
33 * of his "driver for the Logitech and ATI Inport Bus mice for use with
34 * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
35 * found his code to be an invaluable reference when porting this driver
36 * to 386bsd.
37 *
38 * Further modifications for latest 386BSD+patchkit and port to NetBSD,
39 * Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
40 *
41 * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
42 * Andrew Herbert - 12 June 1993
43 *
44 * Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
45 * - 13 June 1993
46 *
47 * Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
48 * - 24 October 1993
49 *
50 * Hardware access routines and probe logic rewritten by
51 * Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
52 * - 3, 14, 22 October 1996.
53 * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
54 * - 14, 30 November 1996. Uses `kbdio.c'.
55 * - 13 December 1996. Uses queuing version of `kbdio.c'.
56 * - January/February 1997. Tweaked probe logic for
57 * HiNote UltraII/Latitude/Armada laptops.
58 * - 30 July 1997. Added APM support.
59 * - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
60 * Improved sync check logic.
61 * Vendor specific support routines.
62 */
63
64 #include "psm.h"
65 /* #include "apm.h" */
66 #include "opt_devfs.h"
67 #include "opt_psm.h"
68
69 #if NPSM > 0
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/module.h>
75 #include <sys/bus.h>
76 #include <sys/conf.h>
77 #include <sys/poll.h>
78 #include <sys/syslog.h>
79 #include <sys/malloc.h>
80 #include <sys/rman.h>
81 #ifdef DEVFS
82 #include <sys/devfsext.h>
83 #endif
84 #include <sys/select.h>
85 #include <sys/uio.h>
86
87 #include <machine/clock.h>
88 #include <machine/limits.h>
89 #include <machine/mouse.h>
90 #include <machine/resource.h>
91
92 #include <isa/isareg.h>
93 #include <isa/isavar.h>
94 #include <dev/kbd/atkbdcreg.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 /* logging: 0: none, 1: brief, 2: verbose */
104 #endif
105
106 /* features */
107
108 /* #define PSM_HOOKAPM hook the APM resume event */
109 /* #define PSM_RESETAFTERSUSPEND reset the device at the resume event */
110
111 #if NAPM <= 0
112 #undef PSM_HOOKAPM
113 #endif /* NAPM */
114
115 #ifndef PSM_HOOKAPM
116 #undef PSM_RESETAFTERSUSPEND
117 #endif /* PSM_HOOKAPM */
118
119 /* end of driver specific options */
120
121 /* input queue */
122 #define PSM_BUFSIZE 960
123 #define PSM_SMALLBUFSIZE 240
124
125 /* operation levels */
126 #define PSM_LEVEL_BASE 0
127 #define PSM_LEVEL_STANDARD 1
128 #define PSM_LEVEL_NATIVE 2
129 #define PSM_LEVEL_MIN PSM_LEVEL_BASE
130 #define PSM_LEVEL_MAX PSM_LEVEL_NATIVE
131
132 /* Logitech PS2++ protocol */
133 #define MOUSE_PS2PLUS_CHECKBITS(b) \
134 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
135 #define MOUSE_PS2PLUS_PACKET_TYPE(b) \
136 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
137
138 /* some macros */
139 #define PSM_UNIT(dev) (minor(dev) >> 1)
140 #define PSM_NBLOCKIO(dev) (minor(dev) & 1)
141 #define PSM_MKMINOR(unit,block) (((unit) << 1) | ((block) ? 0:1))
142
143 #ifndef max
144 #define max(x,y) ((x) > (y) ? (x) : (y))
145 #endif
146 #ifndef min
147 #define min(x,y) ((x) < (y) ? (x) : (y))
148 #endif
149
150 #define abs(x) (((x) < 0) ? -(x) : (x))
151
152 /* ring buffer */
153 typedef struct ringbuf {
154 int count; /* # of valid elements in the buffer */
155 int head; /* head pointer */
156 int tail; /* tail poiner */
157 unsigned char buf[PSM_BUFSIZE];
158 } ringbuf_t;
159
160 /* driver control block */
161 struct psm_softc { /* Driver status information */
162 struct selinfo rsel; /* Process selecting for Input */
163 unsigned char state; /* Mouse driver state */
164 int config; /* driver configuration flags */
165 int flags; /* other flags */
166 KBDC kbdc; /* handle to access the keyboard controller */
167 int addr; /* I/O port address */
168 mousehw_t hw; /* hardware information */
169 mousemode_t mode; /* operation mode */
170 mousemode_t dflt_mode; /* default operation mode */
171 mousestatus_t status; /* accumulated mouse movement */
172 ringbuf_t queue; /* mouse status queue */
173 unsigned char ipacket[16]; /* interim input buffer */
174 int inputbytes; /* # of bytes in the input buffer */
175 int button; /* the latest button state */
176 int xold; /* previous absolute X position */
177 int yold; /* previous absolute Y position */
178 #ifdef DEVFS
179 void *devfs_token;
180 void *b_devfs_token;
181 #endif
182 #ifdef PSM_HOOKAPM
183 struct apmhook resumehook;
184 #endif
185 };
186 devclass_t psm_devclass;
187 #define PSM_SOFTC(unit) ((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
188
189 /* driver state flags (state) */
190 #define PSM_VALID 0x80
191 #define PSM_OPEN 1 /* Device is open */
192 #define PSM_ASLP 2 /* Waiting for mouse data */
193
194 /* driver configuration flags (config) */
195 #define PSM_CONFIG_RESOLUTION 0x000f /* resolution */
196 #define PSM_CONFIG_ACCEL 0x00f0 /* acceleration factor */
197 #define PSM_CONFIG_NOCHECKSYNC 0x0100 /* disable sync. test */
198 #define PSM_CONFIG_NOIDPROBE 0x0200 /* disable mouse model probe */
199 #define PSM_CONFIG_NORESET 0x0400 /* don't reset the mouse */
200 #define PSM_CONFIG_FORCETAP 0x0800 /* assume `tap' action exists */
201 #define PSM_CONFIG_IGNPORTERROR 0x1000 /* ignore error in aux port test */
202
203 #define PSM_CONFIG_FLAGS (PSM_CONFIG_RESOLUTION \
204 | PSM_CONFIG_ACCEL \
205 | PSM_CONFIG_NOCHECKSYNC \
206 | PSM_CONFIG_NOIDPROBE \
207 | PSM_CONFIG_NORESET \
208 | PSM_CONFIG_FORCETAP \
209 | PSM_CONFIG_IGNPORTERROR)
210
211 /* other flags (flags) */
212 #define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */
213
214 /* for backward compatibility */
215 #define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t)
216 #define OLD_MOUSE_GETMODE _IOR('M', 2, old_mousemode_t)
217 #define OLD_MOUSE_SETMODE _IOW('M', 3, old_mousemode_t)
218
219 typedef struct old_mousehw {
220 int buttons;
221 int iftype;
222 int type;
223 int hwid;
224 } old_mousehw_t;
225
226 typedef struct old_mousemode {
227 int protocol;
228 int rate;
229 int resolution;
230 int accelfactor;
231 } old_mousemode_t;
232
233 /* packet formatting function */
234 typedef int packetfunc_t __P((struct psm_softc *, unsigned char *,
235 int *, int, mousestatus_t *));
236
237 /* function prototypes */
238 static int psmprobe __P((device_t));
239 static int psmattach __P((device_t));
240 #ifdef PSM_HOOKAPM
241 static int psmresume __P((void *));
242 #endif
243
244 static d_open_t psmopen;
245 static d_close_t psmclose;
246 static d_read_t psmread;
247 static d_ioctl_t psmioctl;
248 static d_poll_t psmpoll;
249
250 static int enable_aux_dev __P((KBDC));
251 static int disable_aux_dev __P((KBDC));
252 static int get_mouse_status __P((KBDC, int *, int, int));
253 static int get_aux_id __P((KBDC));
254 static int set_mouse_sampling_rate __P((KBDC, int));
255 static int set_mouse_scaling __P((KBDC, int));
256 static int set_mouse_resolution __P((KBDC, int));
257 #ifdef PSM_RESETAFTERSUSPEND
258 static int set_mouse_mode __P((KBDC));
259 #endif /* PSM_RESETAFTERSUSPEND */
260 static int get_mouse_buttons __P((KBDC));
261 static int is_a_mouse __P((int));
262 static void recover_from_error __P((KBDC));
263 static int restore_controller __P((KBDC, int));
264 #ifdef PSM_RESETAFTERSUSPEND
265 static int reinitialize __P((int, mousemode_t *));
266 #endif
267 static int doopen __P((int, int));
268 static char *model_name(int);
269 static void psmintr(void*);
270
271 /* vendor specific features */
272 typedef int probefunc_t __P((struct psm_softc *));
273
274 static int mouse_id_proc1 __P((KBDC, int, int, int *));
275 static probefunc_t enable_groller;
276 static probefunc_t enable_gmouse;
277 static probefunc_t enable_aglide;
278 static probefunc_t enable_kmouse;
279 static probefunc_t enable_msintelli;
280 static probefunc_t enable_mmanplus;
281 static probefunc_t enable_versapad;
282 static int tame_mouse __P((struct psm_softc *, mousestatus_t *, unsigned char *));
283
284 static struct {
285 int model;
286 unsigned char syncmask;
287 int packetsize;
288 probefunc_t *probefunc;
289 } vendortype[] = {
290 { MOUSE_MODEL_NET, /* Genius NetMouse */
291 0xc8, MOUSE_INTELLI_PACKETSIZE, enable_gmouse, },
292 { MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */
293 0xc8, 6, enable_groller, },
294 { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
295 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
296 { MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */
297 0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, },
298 { MOUSE_MODEL_THINK, /* Kensignton ThinkingMouse */
299 0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
300 { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
301 0xc8, MOUSE_INTELLI_PACKETSIZE, enable_msintelli, },
302 { MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */
303 0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
304 { MOUSE_MODEL_GENERIC,
305 0xc0, MOUSE_PS2_PACKETSIZE, NULL, },
306 };
307 #define GENERIC_MOUSE_ENTRY 7
308
309 /* device driver declarateion */
310 static device_method_t psm_methods[] = {
311 /* Device interface */
312 DEVMETHOD(device_probe, psmprobe),
313 DEVMETHOD(device_attach, psmattach),
314
315 { 0, 0 }
316 };
317
318 static driver_t psm_driver = {
319 "psm",
320 psm_methods,
321 DRIVER_TYPE_TTY,
322 sizeof(struct psm_softc),
323 };
324
325 #define CDEV_MAJOR 21
326
327 static struct cdevsw psm_cdevsw = {
328 psmopen, psmclose, psmread, nowrite, /* 21 */
329 psmioctl, nostop, nullreset, nodevtotty,
330 psmpoll, nommap, NULL, "psm", NULL, -1
331 };
332
333 /* debug message level */
334 static int verbose = PSM_DEBUG;
335
336 /* device I/O routines */
337 static int
338 enable_aux_dev(KBDC kbdc)
339 {
340 int res;
341
342 res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
343 if (verbose >= 2)
344 log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res);
345
346 return (res == PSM_ACK);
347 }
348
349 static int
350 disable_aux_dev(KBDC kbdc)
351 {
352 int res;
353
354 res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
355 if (verbose >= 2)
356 log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res);
357
358 return (res == PSM_ACK);
359 }
360
361 static int
362 get_mouse_status(KBDC kbdc, int *status, int flag, int len)
363 {
364 int cmd;
365 int res;
366 int i;
367
368 switch (flag) {
369 case 0:
370 default:
371 cmd = PSMC_SEND_DEV_STATUS;
372 break;
373 case 1:
374 cmd = PSMC_SEND_DEV_DATA;
375 break;
376 }
377 empty_aux_buffer(kbdc, 5);
378 res = send_aux_command(kbdc, cmd);
379 if (verbose >= 2)
380 log(LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
381 (flag == 1) ? "DATA" : "STATUS", res);
382 if (res != PSM_ACK)
383 return 0;
384
385 for (i = 0; i < len; ++i) {
386 status[i] = read_aux_data(kbdc);
387 if (status[i] < 0)
388 break;
389 }
390
391 if (verbose) {
392 log(LOG_DEBUG, "psm: %s %02x %02x %02x\n",
393 (flag == 1) ? "data" : "status", status[0], status[1], status[2]);
394 }
395
396 return i;
397 }
398
399 static int
400 get_aux_id(KBDC kbdc)
401 {
402 int res;
403 int id;
404
405 empty_aux_buffer(kbdc, 5);
406 res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
407 if (verbose >= 2)
408 log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res);
409 if (res != PSM_ACK)
410 return (-1);
411
412 /* 10ms delay */
413 DELAY(10000);
414
415 id = read_aux_data(kbdc);
416 if (verbose >= 2)
417 log(LOG_DEBUG, "psm: device ID: %04x\n", id);
418
419 return id;
420 }
421
422 static int
423 set_mouse_sampling_rate(KBDC kbdc, int rate)
424 {
425 int res;
426
427 res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
428 if (verbose >= 2)
429 log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res);
430
431 return ((res == PSM_ACK) ? rate : -1);
432 }
433
434 static int
435 set_mouse_scaling(KBDC kbdc, int scale)
436 {
437 int res;
438
439 switch (scale) {
440 case 1:
441 default:
442 scale = PSMC_SET_SCALING11;
443 break;
444 case 2:
445 scale = PSMC_SET_SCALING21;
446 break;
447 }
448 res = send_aux_command(kbdc, scale);
449 if (verbose >= 2)
450 log(LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
451 (scale == PSMC_SET_SCALING21) ? "21" : "11", res);
452
453 return (res == PSM_ACK);
454 }
455
456 /* `val' must be 0 through PSMD_MAX_RESOLUTION */
457 static int
458 set_mouse_resolution(KBDC kbdc, int val)
459 {
460 int res;
461
462 res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
463 if (verbose >= 2)
464 log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res);
465
466 return ((res == PSM_ACK) ? val : -1);
467 }
468
469 #ifdef PSM_RESETAFTERSUSPEND
470 /*
471 * NOTE: once `set_mouse_mode()' is called, the mouse device must be
472 * re-enabled by calling `enable_aux_dev()'
473 */
474 static int
475 set_mouse_mode(KBDC kbdc)
476 {
477 int res;
478
479 res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
480 if (verbose >= 2)
481 log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res);
482
483 return (res == PSM_ACK);
484 }
485 #endif /* PSM_RESETAFTERSUSPEND */
486
487
488 static int
489 get_mouse_buttons(KBDC kbdc)
490 {
491 int c = 2; /* assume two buttons by default */
492 int status[3];
493
494 /*
495 * NOTE: a special sequence to obtain Logitech Mouse specific
496 * information: set resolution to 25 ppi, set scaling to 1:1, set
497 * scaling to 1:1, set scaling to 1:1. Then the second byte of the
498 * mouse status bytes is the number of available buttons.
499 * Some manufactures also support this sequence.
500 */
501 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
502 return c;
503 if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1)
504 && set_mouse_scaling(kbdc, 1)
505 && (get_mouse_status(kbdc, status, 0, 3) >= 3)) {
506 if (status[1] != 0)
507 return status[1];
508 }
509 return c;
510 }
511
512 /* misc subroutines */
513 /*
514 * Someday, I will get the complete list of valid pointing devices and
515 * their IDs... XXX
516 */
517 static int
518 is_a_mouse(int id)
519 {
520 #if 0
521 static int valid_ids[] = {
522 PSM_MOUSE_ID, /* mouse */
523 PSM_BALLPOINT_ID, /* ballpoint device */
524 PSM_INTELLI_ID, /* Intellimouse */
525 -1 /* end of table */
526 };
527 int i;
528
529 for (i = 0; valid_ids[i] >= 0; ++i)
530 if (valid_ids[i] == id)
531 return TRUE;
532 return FALSE;
533 #else
534 return TRUE;
535 #endif
536 }
537
538 static char *
539 model_name(int model)
540 {
541 static struct {
542 int model_code;
543 char *model_name;
544 } models[] = {
545 { MOUSE_MODEL_NETSCROLL, "NetScroll Mouse" },
546 { MOUSE_MODEL_NET, "NetMouse" },
547 { MOUSE_MODEL_GLIDEPOINT, "GlidePoint" },
548 { MOUSE_MODEL_THINK, "ThinkingMouse" },
549 { MOUSE_MODEL_INTELLI, "IntelliMouse" },
550 { MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" },
551 { MOUSE_MODEL_VERSAPAD, "VersaPad" },
552 { MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" },
553 { MOUSE_MODEL_UNKNOWN, NULL },
554 };
555 int i;
556
557 for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i) {
558 if (models[i].model_code == model)
559 return models[i].model_name;
560 }
561 return "Unknown";
562 }
563
564 static void
565 recover_from_error(KBDC kbdc)
566 {
567 /* discard anything left in the output buffer */
568 empty_both_buffers(kbdc, 10);
569
570 #if 0
571 /*
572 * NOTE: KBDC_RESET_KBD may not restore the communication between the
573 * keyboard and the controller.
574 */
575 reset_kbd(kbdc);
576 #else
577 /*
578 * NOTE: somehow diagnostic and keyboard port test commands bring the
579 * keyboard back.
580 */
581 if (!test_controller(kbdc))
582 log(LOG_ERR, "psm: keyboard controller failed.\n");
583 /* if there isn't a keyboard in the system, the following error is OK */
584 if (test_kbd_port(kbdc) != 0) {
585 if (verbose)
586 log(LOG_ERR, "psm: keyboard port failed.\n");
587 }
588 #endif
589 }
590
591 static int
592 restore_controller(KBDC kbdc, int command_byte)
593 {
594 empty_both_buffers(kbdc, 10);
595
596 if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
597 log(LOG_ERR, "psm: failed to restore the keyboard controller "
598 "command byte.\n");
599 return FALSE;
600 } else {
601 return TRUE;
602 }
603 }
604
605 #ifdef PSM_RESETAFTERSUSPEND
606 /*
607 * Re-initialize the aux port and device. The aux port must be enabled
608 * and its interrupt must be disabled before calling this routine.
609 * The aux device will be disabled before returning.
610 * The keyboard controller must be locked via `kbdc_lock()' before
611 * calling this routine.
612 */
613 static int
614 reinitialize(int unit, mousemode_t *mode)
615 {
616 struct psm_softc *sc = PSM_SOFTC(unit);
617 KBDC kbdc = sc->kbdc;
618 int stat[3];
619 int i;
620
621 switch((i = test_aux_port(kbdc))) {
622 case 1: /* ignore this error */
623 case PSM_ACK:
624 if (verbose)
625 log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n",
626 unit, i);
627 /* fall though */
628 case 0: /* no error */
629 break;
630 case -1: /* time out */
631 default: /* error */
632 recover_from_error(kbdc);
633 if (sc->config & PSM_CONFIG_IGNPORTERROR)
634 break;
635 log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
636 unit, i);
637 return FALSE;
638 }
639
640 if (sc->config & PSM_CONFIG_NORESET) {
641 /*
642 * Don't try to reset the pointing device. It may possibly be
643 * left in the unknown state, though...
644 */
645 } else {
646 /*
647 * NOTE: some controllers appears to hang the `keyboard' when
648 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
649 */
650 if (!reset_aux_dev(kbdc)) {
651 recover_from_error(kbdc);
652 log(LOG_ERR, "psm%d: failed to reset the aux device.\n", unit);
653 return FALSE;
654 }
655 }
656
657 /*
658 * both the aux port and the aux device is functioning, see
659 * if the device can be enabled.
660 */
661 if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
662 log(LOG_ERR, "psm%d: failed to enable the aux device.\n", unit);
663 return FALSE;
664 }
665 empty_both_buffers(kbdc, 10); /* remove stray data if any */
666
667 if (sc->config & PSM_CONFIG_NOIDPROBE) {
668 i = GENERIC_MOUSE_ENTRY;
669 } else {
670 /* FIXME: hardware ID, mouse buttons? */
671
672 /* other parameters */
673 for (i = 0; vendortype[i].probefunc != NULL; ++i) {
674 if ((*vendortype[i].probefunc)(sc)) {
675 if (verbose >= 2)
676 log(LOG_ERR, "psm%d: found %s\n",
677 unit, model_name(vendortype[i].model));
678 break;
679 }
680 }
681 }
682
683 sc->hw.model = vendortype[i].model;
684 sc->mode.packetsize = vendortype[i].packetsize;
685
686 /* set mouse parameters */
687 if (mode != (mousemode_t *)NULL) {
688 if (mode->rate > 0)
689 mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
690 if (mode->resolution >= 0)
691 mode->resolution = set_mouse_resolution(kbdc, mode->resolution);
692 set_mouse_scaling(kbdc, 1);
693 set_mouse_mode(kbdc);
694 }
695
696 /* request a data packet and extract sync. bits */
697 if (get_mouse_status(kbdc, stat, 1, 3) < 3) {
698 log(LOG_DEBUG, "psm%d: failed to get data (reinitialize).\n", unit);
699 sc->mode.syncmask[0] = 0;
700 } else {
701 sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0]; /* syncbits */
702 /* the NetScroll Mouse will send three more bytes... Ignore them */
703 empty_aux_buffer(kbdc, 5);
704 }
705
706 /* just check the status of the mouse */
707 if (get_mouse_status(kbdc, stat, 0, 3) < 3)
708 log(LOG_DEBUG, "psm%d: failed to get status (reinitialize).\n", unit);
709
710 return TRUE;
711 }
712 #endif /* PSM_RESETAFTERSUSPEND */
713
714 static int
715 doopen(int unit, int command_byte)
716 {
717 struct psm_softc *sc = PSM_SOFTC(unit);
718 int stat[3];
719
720 /* enable the mouse device */
721 if (!enable_aux_dev(sc->kbdc)) {
722 /* MOUSE ERROR: failed to enable the mouse because:
723 * 1) the mouse is faulty,
724 * 2) the mouse has been removed(!?)
725 * In the latter case, the keyboard may have hung, and need
726 * recovery procedure...
727 */
728 recover_from_error(sc->kbdc);
729 #if 0
730 /* FIXME: we could reset the mouse here and try to enable
731 * it again. But it will take long time and it's not a good
732 * idea to disable the keyboard that long...
733 */
734 if (!reinitialize(unit, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
735 recover_from_error(sc->kbdc);
736 #else
737 {
738 #endif
739 restore_controller(sc->kbdc, command_byte);
740 /* mark this device is no longer available */
741 sc->state &= ~PSM_VALID;
742 log(LOG_ERR, "psm%d: failed to enable the device (doopen).\n",
743 unit);
744 return (EIO);
745 }
746 }
747
748 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
749 log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", unit);
750
751 /* enable the aux port and interrupt */
752 if (!set_controller_command_byte(sc->kbdc,
753 kbdc_get_device_mask(sc->kbdc),
754 (command_byte & KBD_KBD_CONTROL_BITS)
755 | KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
756 /* CONTROLLER ERROR */
757 disable_aux_dev(sc->kbdc);
758 restore_controller(sc->kbdc, command_byte);
759 log(LOG_ERR, "psm%d: failed to enable the aux interrupt (doopen).\n",
760 unit);
761 return (EIO);
762 }
763
764 return (0);
765 }
766
767 /* psm driver entry points */
768
769 #define endprobe(v) { if (bootverbose) \
770 --verbose; \
771 kbdc_set_device_mask(sc->kbdc, mask); \
772 kbdc_lock(sc->kbdc, FALSE); \
773 free(sc, M_DEVBUF); \
774 return (v); \
775 }
776
777 static int
778 psmprobe(device_t dev)
779 {
780 int unit = device_get_unit(dev);
781 struct psm_softc *sc = device_get_softc(dev);
782 u_long port;
783 u_long flags;
784 int stat[3];
785 int command_byte;
786 int mask;
787 int i;
788
789 #if 0
790 kbdc_debug(TRUE);
791 #endif
792 BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
793 BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
794
795 sc->addr = port;
796 sc->kbdc = kbdc_open(sc->addr);
797 sc->config = flags & PSM_CONFIG_FLAGS;
798 sc->flags = 0;
799 if (bootverbose)
800 ++verbose;
801
802 device_set_desc(dev, "PS/2 Mouse");
803
804 if (!kbdc_lock(sc->kbdc, TRUE)) {
805 printf("psm%d: unable to lock the controller.\n", unit);
806 if (bootverbose)
807 --verbose;
808 return (ENXIO);
809 }
810
811 /*
812 * NOTE: two bits in the command byte controls the operation of the
813 * aux port (mouse port): the aux port disable bit (bit 5) and the aux
814 * port interrupt (IRQ 12) enable bit (bit 2).
815 */
816
817 /* discard anything left after the keyboard initialization */
818 empty_both_buffers(sc->kbdc, 10);
819
820 /* save the current command byte; it will be used later */
821 mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
822 command_byte = get_controller_command_byte(sc->kbdc);
823 if (verbose)
824 printf("psm%d: current command byte:%04x\n", unit, command_byte);
825 if (command_byte == -1) {
826 /* CONTROLLER ERROR */
827 printf("psm%d: unable to get the current command byte value.\n",
828 unit);
829 endprobe(ENXIO);
830 }
831
832 /*
833 * disable the keyboard port while probing the aux port, which must be
834 * enabled during this routine
835 */
836 if (!set_controller_command_byte(sc->kbdc,
837 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
838 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
839 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
840 /*
841 * this is CONTROLLER ERROR; I don't know how to recover
842 * from this error...
843 */
844 restore_controller(sc->kbdc, command_byte);
845 printf("psm%d: unable to set the command byte.\n", unit);
846 endprobe(ENXIO);
847 }
848 write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
849
850 /*
851 * NOTE: `test_aux_port()' is designed to return with zero if the aux
852 * port exists and is functioning. However, some controllers appears
853 * to respond with zero even when the aux port doesn't exist. (It may
854 * be that this is only the case when the controller DOES have the aux
855 * port but the port is not wired on the motherboard.) The keyboard
856 * controllers without the port, such as the original AT, are
857 * supporsed to return with an error code or simply time out. In any
858 * case, we have to continue probing the port even when the controller
859 * passes this test.
860 *
861 * XXX: some controllers erroneously return the error code 1 when
862 * it has the perfectly functional aux port. We have to ignore this
863 * error code. Even if the controller HAS error with the aux port,
864 * it will be detected later...
865 * XXX: another incompatible controller returns PSM_ACK (0xfa)...
866 */
867 switch ((i = test_aux_port(sc->kbdc))) {
868 case 1: /* ignore this error */
869 case PSM_ACK:
870 if (verbose)
871 printf("psm%d: strange result for test aux port (%d).\n",
872 unit, i);
873 /* fall though */
874 case 0: /* no error */
875 break;
876 case -1: /* time out */
877 default: /* error */
878 recover_from_error(sc->kbdc);
879 if (sc->config & PSM_CONFIG_IGNPORTERROR)
880 break;
881 restore_controller(sc->kbdc, command_byte);
882 if (verbose)
883 printf("psm%d: the aux port is not functioning (%d).\n",
884 unit, i);
885 endprobe(ENXIO);
886 }
887
888 if (sc->config & PSM_CONFIG_NORESET) {
889 /*
890 * Don't try to reset the pointing device. It may possibly be
891 * left in the unknown state, though...
892 */
893 } else {
894 /*
895 * NOTE: some controllers appears to hang the `keyboard' when the aux
896 * port doesn't exist and `PSMC_RESET_DEV' is issued.
897 */
898 if (!reset_aux_dev(sc->kbdc)) {
899 recover_from_error(sc->kbdc);
900 restore_controller(sc->kbdc, command_byte);
901 if (verbose)
902 printf("psm%d: failed to reset the aux device.\n", unit);
903 endprobe(ENXIO);
904 }
905 }
906
907 /*
908 * both the aux port and the aux device is functioning, see if the
909 * device can be enabled. NOTE: when enabled, the device will start
910 * sending data; we shall immediately disable the device once we know
911 * the device can be enabled.
912 */
913 if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
914 /* MOUSE ERROR */
915 recover_from_error(sc->kbdc);
916 restore_controller(sc->kbdc, command_byte);
917 if (verbose)
918 printf("psm%d: failed to enable the aux device.\n", unit);
919 endprobe(ENXIO);
920 }
921
922 /* save the default values after reset */
923 if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
924 sc->dflt_mode.rate = sc->mode.rate = stat[2];
925 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
926 } else {
927 sc->dflt_mode.rate = sc->mode.rate = -1;
928 sc->dflt_mode.resolution = sc->mode.resolution = -1;
929 }
930
931 /* hardware information */
932 sc->hw.iftype = MOUSE_IF_PS2;
933
934 /* verify the device is a mouse */
935 sc->hw.hwid = get_aux_id(sc->kbdc);
936 if (!is_a_mouse(sc->hw.hwid)) {
937 restore_controller(sc->kbdc, command_byte);
938 if (verbose)
939 printf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid);
940 endprobe(ENXIO);
941 }
942 switch (sc->hw.hwid) {
943 case PSM_BALLPOINT_ID:
944 sc->hw.type = MOUSE_TRACKBALL;
945 break;
946 case PSM_MOUSE_ID:
947 case PSM_INTELLI_ID:
948 sc->hw.type = MOUSE_MOUSE;
949 break;
950 default:
951 sc->hw.type = MOUSE_UNKNOWN;
952 break;
953 }
954
955 if (sc->config & PSM_CONFIG_NOIDPROBE) {
956 sc->hw.buttons = 2;
957 i = GENERIC_MOUSE_ENTRY;
958 } else {
959 /* # of buttons */
960 sc->hw.buttons = get_mouse_buttons(sc->kbdc);
961
962 /* other parameters */
963 for (i = 0; vendortype[i].probefunc != NULL; ++i) {
964 if ((*vendortype[i].probefunc)(sc)) {
965 if (verbose >= 2)
966 printf("psm%d: found %s\n",
967 unit, model_name(vendortype[i].model));
968 break;
969 }
970 }
971 }
972
973 sc->hw.model = vendortype[i].model;
974
975 sc->dflt_mode.level = PSM_LEVEL_BASE;
976 sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
977 sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
978 if (sc->config & PSM_CONFIG_NOCHECKSYNC)
979 sc->dflt_mode.syncmask[0] = 0;
980 else
981 sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
982 if (sc->config & PSM_CONFIG_FORCETAP)
983 sc->mode.syncmask[0] &= ~MOUSE_PS2_TAP;
984 sc->dflt_mode.syncmask[1] = 0; /* syncbits */
985 sc->mode = sc->dflt_mode;
986 sc->mode.packetsize = vendortype[i].packetsize;
987
988 /* set mouse parameters */
989 #if 0
990 /*
991 * A version of Logitech FirstMouse+ won't report wheel movement,
992 * if SET_DEFAULTS is sent... Don't use this command.
993 * This fix was found by Takashi Nishida.
994 */
995 i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
996 if (verbose >= 2)
997 printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
998 #endif
999 if (sc->config & PSM_CONFIG_RESOLUTION) {
1000 sc->mode.resolution
1001 = set_mouse_resolution(sc->kbdc,
1002 (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1003 } else if (sc->mode.resolution >= 0) {
1004 sc->mode.resolution
1005 = set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1006 }
1007 if (sc->mode.rate > 0) {
1008 sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1009 }
1010 set_mouse_scaling(sc->kbdc, 1);
1011
1012 /* request a data packet and extract sync. bits */
1013 if (get_mouse_status(sc->kbdc, stat, 1, 3) < 3) {
1014 printf("psm%d: failed to get data.\n", unit);
1015 sc->mode.syncmask[0] = 0;
1016 } else {
1017 sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0]; /* syncbits */
1018 /* the NetScroll Mouse will send three more bytes... Ignore them */
1019 empty_aux_buffer(sc->kbdc, 5);
1020 }
1021
1022 /* just check the status of the mouse */
1023 /*
1024 * NOTE: XXX there are some arcane controller/mouse combinations out
1025 * there, which hung the controller unless there is data transmission
1026 * after ACK from the mouse.
1027 */
1028 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) {
1029 printf("psm%d: failed to get status.\n", unit);
1030 } else {
1031 /*
1032 * When in its native mode, some mice operate with different
1033 * default parameters than in the PS/2 compatible mode.
1034 */
1035 sc->dflt_mode.rate = sc->mode.rate = stat[2];
1036 sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1037 }
1038
1039 /* disable the aux port for now... */
1040 if (!set_controller_command_byte(sc->kbdc,
1041 KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1042 (command_byte & KBD_KBD_CONTROL_BITS)
1043 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1044 /*
1045 * this is CONTROLLER ERROR; I don't know the proper way to
1046 * recover from this error...
1047 */
1048 restore_controller(sc->kbdc, command_byte);
1049 printf("psm%d: unable to set the command byte.\n", unit);
1050 endprobe(ENXIO);
1051 }
1052
1053 /* done */
1054 kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1055 kbdc_lock(sc->kbdc, FALSE);
1056 return (0);
1057 }
1058
1059 static int
1060 psmattach(device_t dev)
1061 {
1062 int unit = device_get_unit(dev);
1063 struct psm_softc *sc = device_get_softc(dev);
1064 void *ih;
1065 struct resource *res;
1066 u_long irq;
1067 int zero = 0;
1068
1069 if (sc == NULL) /* shouldn't happen */
1070 return (ENXIO);
1071
1072 /* Setup initial state */
1073 sc->state = PSM_VALID;
1074
1075 /* Done */
1076 #ifdef DEVFS
1077 sc->devfs_token =
1078 devfs_add_devswf(&psm_cdevsw, PSM_MKMINOR(unit, FALSE),
1079 DV_CHR, 0, 0, 0666, "psm%d", unit);
1080 sc->b_devfs_token =
1081 devfs_add_devswf(&psm_cdevsw, PSM_MKMINOR(unit, TRUE),
1082 DV_CHR, 0, 0, 0666, "bpsm%d", unit);
1083 #endif /* DEVFS */
1084
1085 #ifdef PSM_HOOKAPM
1086 sc->resumehook.ah_name = "PS/2 mouse";
1087 sc->resumehook.ah_fun = psmresume;
1088 sc->resumehook.ah_arg = (void *)unit;
1089 sc->resumehook.ah_order = APM_MID_ORDER;
1090 apm_hook_establish(APM_HOOK_RESUME , &sc->resumehook);
1091 if (verbose)
1092 printf("psm%d: APM hooks installed.\n", unit);
1093 #endif /* PSM_HOOKAPM */
1094
1095 if (!verbose) {
1096 printf("psm%d: model %s, device ID %d\n",
1097 unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1098 } else {
1099 printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1100 unit, model_name(sc->hw.model),
1101 sc->hw.hwid & 0x00ff, sc->hw.hwid >> 8, sc->hw.buttons);
1102 printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1103 unit, sc->config, sc->flags, sc->mode.packetsize);
1104 printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1105 unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1106 }
1107
1108 if (bootverbose)
1109 --verbose;
1110
1111 BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
1112 res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
1113 RF_SHAREABLE | RF_ACTIVE);
1114 BUS_SETUP_INTR(device_get_parent(dev), dev, res, psmintr, sc,
1115 &ih);
1116
1117 return (0);
1118 }
1119
1120 static int
1121 psmopen(dev_t dev, int flag, int fmt, struct proc *p)
1122 {
1123 int unit = PSM_UNIT(dev);
1124 struct psm_softc *sc;
1125 int command_byte;
1126 int err;
1127 int s;
1128
1129 /* Validate unit number */
1130 if (unit >= NPSM)
1131 return (ENXIO);
1132
1133 /* Get device data */
1134 sc = PSM_SOFTC(unit);
1135 if ((sc == NULL) || (sc->state & PSM_VALID) == 0)
1136 /* the device is no longer valid/functioning */
1137 return (ENXIO);
1138
1139 /* Disallow multiple opens */
1140 if (sc->state & PSM_OPEN)
1141 return (EBUSY);
1142
1143 device_busy(devclass_get_device(psm_devclass, unit));
1144
1145 /* Initialize state */
1146 sc->rsel.si_flags = 0;
1147 sc->rsel.si_pid = 0;
1148 sc->mode.level = sc->dflt_mode.level;
1149 sc->mode.protocol = sc->dflt_mode.protocol;
1150
1151 /* flush the event queue */
1152 sc->queue.count = 0;
1153 sc->queue.head = 0;
1154 sc->queue.tail = 0;
1155 sc->status.flags = 0;
1156 sc->status.button = 0;
1157 sc->status.obutton = 0;
1158 sc->status.dx = 0;
1159 sc->status.dy = 0;
1160 sc->status.dz = 0;
1161 sc->button = 0;
1162
1163 /* empty input buffer */
1164 bzero(sc->ipacket, sizeof(sc->ipacket));
1165 sc->inputbytes = 0;
1166
1167 /* don't let timeout routines in the keyboard driver to poll the kbdc */
1168 if (!kbdc_lock(sc->kbdc, TRUE))
1169 return (EIO);
1170
1171 /* save the current controller command byte */
1172 s = spltty();
1173 command_byte = get_controller_command_byte(sc->kbdc);
1174
1175 /* enable the aux port and temporalily disable the keyboard */
1176 if ((command_byte == -1)
1177 || !set_controller_command_byte(sc->kbdc,
1178 kbdc_get_device_mask(sc->kbdc),
1179 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1180 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1181 /* CONTROLLER ERROR; do you know how to get out of this? */
1182 kbdc_lock(sc->kbdc, FALSE);
1183 splx(s);
1184 log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n",
1185 unit);
1186 return (EIO);
1187 }
1188 /*
1189 * Now that the keyboard controller is told not to generate
1190 * the keyboard and mouse interrupts, call `splx()' to allow
1191 * the other tty interrupts. The clock interrupt may also occur,
1192 * but timeout routines will be blocked by the poll flag set
1193 * via `kbdc_lock()'
1194 */
1195 splx(s);
1196
1197 /* enable the mouse device */
1198 err = doopen(unit, command_byte);
1199
1200 /* done */
1201 if (err == 0)
1202 sc->state |= PSM_OPEN;
1203 kbdc_lock(sc->kbdc, FALSE);
1204 return (err);
1205 }
1206
1207 static int
1208 psmclose(dev_t dev, int flag, int fmt, struct proc *p)
1209 {
1210 int unit = PSM_UNIT(dev);
1211 struct psm_softc *sc = PSM_SOFTC(unit);
1212 int stat[3];
1213 int command_byte;
1214 int s;
1215
1216 /* don't let timeout routines in the keyboard driver to poll the kbdc */
1217 if (!kbdc_lock(sc->kbdc, TRUE))
1218 return (EIO);
1219
1220 /* save the current controller command byte */
1221 s = spltty();
1222 command_byte = get_controller_command_byte(sc->kbdc);
1223 if (command_byte == -1) {
1224 kbdc_lock(sc->kbdc, FALSE);
1225 splx(s);
1226 return (EIO);
1227 }
1228
1229 /* disable the aux interrupt and temporalily disable the keyboard */
1230 if (!set_controller_command_byte(sc->kbdc,
1231 kbdc_get_device_mask(sc->kbdc),
1232 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1233 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1234 log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n",
1235 PSM_UNIT(dev));
1236 /* CONTROLLER ERROR;
1237 * NOTE: we shall force our way through. Because the only
1238 * ill effect we shall see is that we may not be able
1239 * to read ACK from the mouse, and it doesn't matter much
1240 * so long as the mouse will accept the DISABLE command.
1241 */
1242 }
1243 splx(s);
1244
1245 /* remove anything left in the output buffer */
1246 empty_aux_buffer(sc->kbdc, 10);
1247
1248 /* disable the aux device, port and interrupt */
1249 if (sc->state & PSM_VALID) {
1250 if (!disable_aux_dev(sc->kbdc)) {
1251 /* MOUSE ERROR;
1252 * NOTE: we don't return error and continue, pretending
1253 * we have successfully disabled the device. It's OK because
1254 * the interrupt routine will discard any data from the mouse
1255 * hereafter.
1256 */
1257 log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
1258 PSM_UNIT(dev));
1259 }
1260
1261 if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1262 log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n",
1263 PSM_UNIT(dev));
1264 }
1265
1266 if (!set_controller_command_byte(sc->kbdc,
1267 kbdc_get_device_mask(sc->kbdc),
1268 (command_byte & KBD_KBD_CONTROL_BITS)
1269 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1270 /* CONTROLLER ERROR;
1271 * we shall ignore this error; see the above comment.
1272 */
1273 log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
1274 PSM_UNIT(dev));
1275 }
1276
1277 /* remove anything left in the output buffer */
1278 empty_aux_buffer(sc->kbdc, 10);
1279
1280 /* close is almost always successful */
1281 sc->state &= ~PSM_OPEN;
1282 kbdc_lock(sc->kbdc, FALSE);
1283 device_unbusy(devclass_get_device(psm_devclass, unit));
1284 return (0);
1285 }
1286
1287 static int
1288 tame_mouse(struct psm_softc *sc, mousestatus_t *status, unsigned char *buf)
1289 {
1290 static unsigned char butmapps2[8] = {
1291 0,
1292 MOUSE_PS2_BUTTON1DOWN,
1293 MOUSE_PS2_BUTTON2DOWN,
1294 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1295 MOUSE_PS2_BUTTON3DOWN,
1296 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1297 MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1298 MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1299 };
1300 static unsigned char butmapmsc[8] = {
1301 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1302 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1303 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1304 MOUSE_MSC_BUTTON3UP,
1305 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1306 MOUSE_MSC_BUTTON2UP,
1307 MOUSE_MSC_BUTTON1UP,
1308 0,
1309 };
1310 int mapped;
1311 int i;
1312
1313 if (sc->mode.level == PSM_LEVEL_BASE) {
1314 mapped = status->button & ~MOUSE_BUTTON4DOWN;
1315 if (status->button & MOUSE_BUTTON4DOWN)
1316 mapped |= MOUSE_BUTTON1DOWN;
1317 status->button = mapped;
1318 buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1319 i = max(min(status->dx, 255), -256);
1320 if (i < 0)
1321 buf[0] |= MOUSE_PS2_XNEG;
1322 buf[1] = i;
1323 i = max(min(status->dy, 255), -256);
1324 if (i < 0)
1325 buf[0] |= MOUSE_PS2_YNEG;
1326 buf[2] = i;
1327 return MOUSE_PS2_PACKETSIZE;
1328 } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1329 buf[0] = MOUSE_MSC_SYNC | butmapmsc[status->button & MOUSE_STDBUTTONS];
1330 i = max(min(status->dx, 255), -256);
1331 buf[1] = i >> 1;
1332 buf[3] = i - buf[1];
1333 i = max(min(status->dy, 255), -256);
1334 buf[2] = i >> 1;
1335 buf[4] = i - buf[2];
1336 i = max(min(status->dz, 127), -128);
1337 buf[5] = (i >> 1) & 0x7f;
1338 buf[6] = (i - (i >> 1)) & 0x7f;
1339 buf[7] = (~status->button >> 3) & 0x7f;
1340 return MOUSE_SYS_PACKETSIZE;
1341 }
1342 return sc->inputbytes;;
1343 }
1344
1345 static int
1346 psmread(dev_t dev, struct uio *uio, int flag)
1347 {
1348 register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1349 unsigned char buf[PSM_SMALLBUFSIZE];
1350 int error = 0;
1351 int s;
1352 int l;
1353
1354 if ((sc->state & PSM_VALID) == 0)
1355 return EIO;
1356
1357 /* block until mouse activity occured */
1358 s = spltty();
1359 while (sc->queue.count <= 0) {
1360 if (PSM_NBLOCKIO(dev)) {
1361 splx(s);
1362 return EWOULDBLOCK;
1363 }
1364 sc->state |= PSM_ASLP;
1365 error = tsleep((caddr_t) sc, PZERO | PCATCH, "psmrea", 0);
1366 sc->state &= ~PSM_ASLP;
1367 if (error) {
1368 splx(s);
1369 return error;
1370 } else if ((sc->state & PSM_VALID) == 0) {
1371 /* the device disappeared! */
1372 splx(s);
1373 return EIO;
1374 }
1375 }
1376 splx(s);
1377
1378 /* copy data to the user land */
1379 while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1380 s = spltty();
1381 l = min(sc->queue.count, uio->uio_resid);
1382 if (l > sizeof(buf))
1383 l = sizeof(buf);
1384 if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1385 bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1386 sizeof(sc->queue.buf) - sc->queue.head);
1387 bcopy(&sc->queue.buf[0],
1388 &buf[sizeof(sc->queue.buf) - sc->queue.head],
1389 l - (sizeof(sc->queue.buf) - sc->queue.head));
1390 } else {
1391 bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1392 }
1393 sc->queue.count -= l;
1394 sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1395 splx(s);
1396 error = uiomove(buf, l, uio);
1397 if (error)
1398 break;
1399 }
1400
1401 return error;
1402 }
1403
1404 static int
1405 block_mouse_data(struct psm_softc *sc, int *c)
1406 {
1407 int s;
1408
1409 if (!kbdc_lock(sc->kbdc, TRUE))
1410 return EIO;
1411
1412 s = spltty();
1413 *c = get_controller_command_byte(sc->kbdc);
1414 if ((*c == -1)
1415 || !set_controller_command_byte(sc->kbdc,
1416 kbdc_get_device_mask(sc->kbdc),
1417 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1418 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1419 /* this is CONTROLLER ERROR */
1420 splx(s);
1421 kbdc_lock(sc->kbdc, FALSE);
1422 return EIO;
1423 }
1424
1425 /*
1426 * The device may be in the middle of status data transmission.
1427 * The transmission will be interrupted, thus, incomplete status
1428 * data must be discarded. Although the aux interrupt is disabled
1429 * at the keyboard controller level, at most one aux interrupt
1430 * may have already been pending and a data byte is in the
1431 * output buffer; throw it away. Note that the second argument
1432 * to `empty_aux_buffer()' is zero, so that the call will just
1433 * flush the internal queue.
1434 * `psmintr()' will be invoked after `splx()' if an interrupt is
1435 * pending; it will see no data and returns immediately.
1436 */
1437 empty_aux_buffer(sc->kbdc, 0); /* flush the queue */
1438 read_aux_data_no_wait(sc->kbdc); /* throw away data if any */
1439 sc->inputbytes = 0;
1440 splx(s);
1441
1442 return 0;
1443 }
1444
1445 static int
1446 unblock_mouse_data(struct psm_softc *sc, int c)
1447 {
1448 int error = 0;
1449
1450 /*
1451 * We may have seen a part of status data during `set_mouse_XXX()'.
1452 * they have been queued; flush it.
1453 */
1454 empty_aux_buffer(sc->kbdc, 0);
1455
1456 /* restore ports and interrupt */
1457 if (!set_controller_command_byte(sc->kbdc,
1458 kbdc_get_device_mask(sc->kbdc),
1459 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1460 /* CONTROLLER ERROR; this is serious, we may have
1461 * been left with the inaccessible keyboard and
1462 * the disabled mouse interrupt.
1463 */
1464 error = EIO;
1465 }
1466
1467 kbdc_lock(sc->kbdc, FALSE);
1468 return error;
1469 }
1470
1471 static int
1472 psmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1473 {
1474 struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1475 mousemode_t mode;
1476 mousestatus_t status;
1477 #if (defined(MOUSE_GETVARS))
1478 mousevar_t *var;
1479 #endif
1480 mousedata_t *data;
1481 int stat[3];
1482 int command_byte;
1483 int error = 0;
1484 int s;
1485
1486 /* Perform IOCTL command */
1487 switch (cmd) {
1488
1489 case OLD_MOUSE_GETHWINFO:
1490 s = spltty();
1491 ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
1492 ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
1493 ((old_mousehw_t *)addr)->type = sc->hw.type;
1494 ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
1495 splx(s);
1496 break;
1497
1498 case MOUSE_GETHWINFO:
1499 s = spltty();
1500 *(mousehw_t *)addr = sc->hw;
1501 if (sc->mode.level == PSM_LEVEL_BASE)
1502 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
1503 splx(s);
1504 break;
1505
1506 case OLD_MOUSE_GETMODE:
1507 s = spltty();
1508 switch (sc->mode.level) {
1509 case PSM_LEVEL_BASE:
1510 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1511 break;
1512 case PSM_LEVEL_STANDARD:
1513 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
1514 break;
1515 case PSM_LEVEL_NATIVE:
1516 ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1517 break;
1518 }
1519 ((old_mousemode_t *)addr)->rate = sc->mode.rate;
1520 ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
1521 ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
1522 splx(s);
1523 break;
1524
1525 case MOUSE_GETMODE:
1526 s = spltty();
1527 *(mousemode_t *)addr = sc->mode;
1528 ((mousemode_t *)addr)->resolution =
1529 MOUSE_RES_LOW - sc->mode.resolution;
1530 switch (sc->mode.level) {
1531 case PSM_LEVEL_BASE:
1532 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1533 ((mousemode_t *)addr)->packetsize = MOUSE_PS2_PACKETSIZE;
1534 break;
1535 case PSM_LEVEL_STANDARD:
1536 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
1537 ((mousemode_t *)addr)->packetsize = MOUSE_SYS_PACKETSIZE;
1538 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
1539 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
1540 break;
1541 case PSM_LEVEL_NATIVE:
1542 /* FIXME: this isn't quite correct... XXX */
1543 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1544 break;
1545 }
1546 splx(s);
1547 break;
1548
1549 case OLD_MOUSE_SETMODE:
1550 case MOUSE_SETMODE:
1551 if (cmd == OLD_MOUSE_SETMODE) {
1552 mode.rate = ((old_mousemode_t *)addr)->rate;
1553 /*
1554 * resolution old I/F new I/F
1555 * default 0 0
1556 * low 1 -2
1557 * medium low 2 -3
1558 * medium high 3 -4
1559 * high 4 -5
1560 */
1561 if (((old_mousemode_t *)addr)->resolution > 0)
1562 mode.resolution = -((old_mousemode_t *)addr)->resolution - 1;
1563 mode.accelfactor = ((old_mousemode_t *)addr)->accelfactor;
1564 mode.level = -1;
1565 } else {
1566 mode = *(mousemode_t *)addr;
1567 }
1568
1569 /* adjust and validate parameters. */
1570 if (mode.rate > UCHAR_MAX)
1571 return EINVAL;
1572 if (mode.rate == 0)
1573 mode.rate = sc->dflt_mode.rate;
1574 else if (mode.rate == -1)
1575 /* don't change the current setting */
1576 ;
1577 else if (mode.rate < 0)
1578 return EINVAL;
1579 if (mode.resolution >= UCHAR_MAX)
1580 return EINVAL;
1581 if (mode.resolution >= 200)
1582 mode.resolution = MOUSE_RES_HIGH;
1583 else if (mode.resolution >= 100)
1584 mode.resolution = MOUSE_RES_MEDIUMHIGH;
1585 else if (mode.resolution >= 50)
1586 mode.resolution = MOUSE_RES_MEDIUMLOW;
1587 else if (mode.resolution > 0)
1588 mode.resolution = MOUSE_RES_LOW;
1589 if (mode.resolution == MOUSE_RES_DEFAULT)
1590 mode.resolution = sc->dflt_mode.resolution;
1591 else if (mode.resolution == -1)
1592 /* don't change the current setting */
1593 ;
1594 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
1595 mode.resolution = MOUSE_RES_LOW - mode.resolution;
1596 if (mode.level == -1)
1597 /* don't change the current setting */
1598 mode.level = sc->mode.level;
1599 else if ((mode.level < PSM_LEVEL_MIN) || (mode.level > PSM_LEVEL_MAX))
1600 return EINVAL;
1601 if (mode.accelfactor == -1)
1602 /* don't change the current setting */
1603 mode.accelfactor = sc->mode.accelfactor;
1604 else if (mode.accelfactor < 0)
1605 return EINVAL;
1606
1607 /* don't allow anybody to poll the keyboard controller */
1608 error = block_mouse_data(sc, &command_byte);
1609 if (error)
1610 return error;
1611
1612 /* set mouse parameters */
1613 if (mode.rate > 0)
1614 mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
1615 if (mode.resolution >= 0)
1616 mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
1617 set_mouse_scaling(sc->kbdc, 1);
1618 get_mouse_status(sc->kbdc, stat, 0, 3);
1619
1620 s = spltty();
1621 sc->mode.rate = mode.rate;
1622 sc->mode.resolution = mode.resolution;
1623 sc->mode.accelfactor = mode.accelfactor;
1624 sc->mode.level = mode.level;
1625 splx(s);
1626
1627 unblock_mouse_data(sc, command_byte);
1628 break;
1629
1630 case MOUSE_GETLEVEL:
1631 *(int *)addr = sc->mode.level;
1632 break;
1633
1634 case MOUSE_SETLEVEL:
1635 if ((*(int *)addr < PSM_LEVEL_MIN) || (*(int *)addr > PSM_LEVEL_MAX))
1636 return EINVAL;
1637 sc->mode.level = *(int *)addr;
1638 break;
1639
1640 case MOUSE_GETSTATUS:
1641 s = spltty();
1642 status = sc->status;
1643 sc->status.flags = 0;
1644 sc->status.obutton = sc->status.button;
1645 sc->status.button = 0;
1646 sc->status.dx = 0;
1647 sc->status.dy = 0;
1648 sc->status.dz = 0;
1649 splx(s);
1650 *(mousestatus_t *)addr = status;
1651 break;
1652
1653 #if (defined(MOUSE_GETVARS))
1654 case MOUSE_GETVARS:
1655 var = (mousevar_t *)addr;
1656 bzero(var, sizeof(*var));
1657 s = spltty();
1658 var->var[0] = MOUSE_VARS_PS2_SIG;
1659 var->var[1] = sc->config;
1660 var->var[2] = sc->flags;
1661 splx(s);
1662 break;
1663
1664 case MOUSE_SETVARS:
1665 return ENODEV;
1666 #endif /* MOUSE_GETVARS */
1667
1668 case MOUSE_READSTATE:
1669 case MOUSE_READDATA:
1670 data = (mousedata_t *)addr;
1671 if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
1672 return EINVAL;
1673
1674 error = block_mouse_data(sc, &command_byte);
1675 if (error)
1676 return error;
1677 if ((data->len = get_mouse_status(sc->kbdc, data->buf,
1678 (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
1679 error = EIO;
1680 unblock_mouse_data(sc, command_byte);
1681 break;
1682
1683 #if (defined(MOUSE_SETRESOLUTION))
1684 case MOUSE_SETRESOLUTION:
1685 mode.resolution = *(int *)addr;
1686 if (mode.resolution >= UCHAR_MAX)
1687 return EINVAL;
1688 else if (mode.resolution >= 200)
1689 mode.resolution = MOUSE_RES_HIGH;
1690 else if (mode.resolution >= 100)
1691 mode.resolution = MOUSE_RES_MEDIUMHIGH;
1692 else if (mode.resolution >= 50)
1693 mode.resolution = MOUSE_RES_MEDIUMLOW;
1694 else if (mode.resolution > 0)
1695 mode.resolution = MOUSE_RES_LOW;
1696 if (mode.resolution == MOUSE_RES_DEFAULT)
1697 mode.resolution = sc->dflt_mode.resolution;
1698 else if (mode.resolution == -1)
1699 mode.resolution = sc->mode.resolution;
1700 else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
1701 mode.resolution = MOUSE_RES_LOW - mode.resolution;
1702
1703 error = block_mouse_data(sc, &command_byte);
1704 if (error)
1705 return error;
1706 sc->mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
1707 if (sc->mode.resolution != mode.resolution)
1708 error = EIO;
1709 unblock_mouse_data(sc, command_byte);
1710 break;
1711 #endif /* MOUSE_SETRESOLUTION */
1712
1713 #if (defined(MOUSE_SETRATE))
1714 case MOUSE_SETRATE:
1715 mode.rate = *(int *)addr;
1716 if (mode.rate > UCHAR_MAX)
1717 return EINVAL;
1718 if (mode.rate == 0)
1719 mode.rate = sc->dflt_mode.rate;
1720 else if (mode.rate < 0)
1721 mode.rate = sc->mode.rate;
1722
1723 error = block_mouse_data(sc, &command_byte);
1724 if (error)
1725 return error;
1726 sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
1727 if (sc->mode.rate != mode.rate)
1728 error = EIO;
1729 unblock_mouse_data(sc, command_byte);
1730 break;
1731 #endif /* MOUSE_SETRATE */
1732
1733 #if (defined(MOUSE_SETSCALING))
1734 case MOUSE_SETSCALING:
1735 if ((*(int *)addr <= 0) || (*(int *)addr > 2))
1736 return EINVAL;
1737
1738 error = block_mouse_data(sc, &command_byte);
1739 if (error)
1740 return error;
1741 if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
1742 error = EIO;
1743 unblock_mouse_data(sc, command_byte);
1744 break;
1745 #endif /* MOUSE_SETSCALING */
1746
1747 #if (defined(MOUSE_GETHWID))
1748 case MOUSE_GETHWID:
1749 error = block_mouse_data(sc, &command_byte);
1750 if (error)
1751 return error;
1752 sc->hw.hwid &= ~0x00ff;
1753 sc->hw.hwid |= get_aux_id(sc->kbdc);
1754 *(int *)addr = sc->hw.hwid & 0x00ff;
1755 unblock_mouse_data(sc, command_byte);
1756 break;
1757 #endif /* MOUSE_GETHWID */
1758
1759 default:
1760 return ENOTTY;
1761 }
1762
1763 return error;
1764 }
1765
1766 static void
1767 psmintr(void *arg)
1768 {
1769 /*
1770 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
1771 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
1772 */
1773 static int butmap[8] = {
1774 0,
1775 MOUSE_BUTTON1DOWN,
1776 MOUSE_BUTTON3DOWN,
1777 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1778 MOUSE_BUTTON2DOWN,
1779 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
1780 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1781 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
1782 };
1783 static int butmap_versapad[8] = {
1784 0,
1785 MOUSE_BUTTON3DOWN,
1786 0,
1787 MOUSE_BUTTON3DOWN,
1788 MOUSE_BUTTON1DOWN,
1789 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1790 MOUSE_BUTTON1DOWN,
1791 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
1792 };
1793 register struct psm_softc *sc = arg;
1794 mousestatus_t ms;
1795 int x, y, z;
1796 int c;
1797 int l;
1798 int x0, y0;
1799
1800 /* read until there is nothing to read */
1801 while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
1802
1803 /* discard the byte if the device is not open */
1804 if ((sc->state & PSM_OPEN) == 0)
1805 continue;
1806
1807 /*
1808 * Check sync bits. We check for overflow bits and the bit 3
1809 * for most mice. True, the code doesn't work if overflow
1810 * condition occurs. But we expect it rarely happens...
1811 */
1812 if ((sc->inputbytes == 0)
1813 && ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1])) {
1814 log(LOG_DEBUG, "psmintr: out of sync (%04x != %04x).\n",
1815 c & sc->mode.syncmask[0], sc->mode.syncmask[1]);
1816 continue;
1817 }
1818
1819 sc->ipacket[sc->inputbytes++] = c;
1820 if (sc->inputbytes < sc->mode.packetsize)
1821 continue;
1822
1823 #if 0
1824 log(LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n",
1825 sc->ipacket[0], sc->ipacket[1], sc->ipacket[2],
1826 sc->ipacket[3], sc->ipacket[4], sc->ipacket[5]);
1827 #endif
1828
1829 c = sc->ipacket[0];
1830
1831 /*
1832 * A kludge for Kensington device!
1833 * The MSB of the horizontal count appears to be stored in
1834 * a strange place. This kludge doesn't affect other mice
1835 * because the bit is the overflow bit which is, in most cases,
1836 * expected to be zero when we reach here. XXX
1837 */
1838 if (sc->hw.model != MOUSE_MODEL_VERSAPAD)
1839 sc->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
1840
1841 /* ignore the overflow bits... */
1842 x = (c & MOUSE_PS2_XNEG) ? sc->ipacket[1] - 256 : sc->ipacket[1];
1843 y = (c & MOUSE_PS2_YNEG) ? sc->ipacket[2] - 256 : sc->ipacket[2];
1844 z = 0;
1845 ms.obutton = sc->button; /* previous button state */
1846 ms.button = butmap[c & MOUSE_PS2_BUTTONS];
1847 /* `tapping' action */
1848 if (sc->config & PSM_CONFIG_FORCETAP)
1849 ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
1850
1851 switch (sc->hw.model) {
1852
1853 case MOUSE_MODEL_INTELLI:
1854 case MOUSE_MODEL_NET:
1855 /* wheel data is in the fourth byte */
1856 z = (char)sc->ipacket[3];
1857 break;
1858
1859 case MOUSE_MODEL_MOUSEMANPLUS:
1860 /*
1861 * PS2++ protocl packet
1862 *
1863 * b7 b6 b5 b4 b3 b2 b1 b0
1864 * byte 1: * 1 p3 p2 1 * * *
1865 * byte 2: c1 c2 p1 p0 d1 d0 1 0
1866 *
1867 * p3-p0: packet type
1868 * c1, c2: c1 & c2 == 1, if p2 == 0
1869 * c1 & c2 == 0, if p2 == 1
1870 *
1871 * packet type: 0 (device type)
1872 * See comments in enable_mmanplus() below.
1873 *
1874 * packet type: 1 (wheel data)
1875 *
1876 * b7 b6 b5 b4 b3 b2 b1 b0
1877 * byte 3: h * B5 B4 s d2 d1 d0
1878 *
1879 * h: 1, if horizontal roller data
1880 * 0, if vertical roller data
1881 * B4, B5: button 4 and 5
1882 * s: sign bit
1883 * d2-d0: roller data
1884 *
1885 * packet type: 2 (reserved)
1886 */
1887 if (((c & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
1888 && (abs(x) > 191)
1889 && MOUSE_PS2PLUS_CHECKBITS(sc->ipacket)) {
1890 /* the extended data packet encodes button and wheel events */
1891 switch (MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket)) {
1892 case 1:
1893 /* wheel data packet */
1894 x = y = 0;
1895 if (sc->ipacket[2] & 0x80) {
1896 /* horizontal roller count - ignore it XXX*/
1897 } else {
1898 /* vertical roller count */
1899 z = (sc->ipacket[2] & MOUSE_PS2PLUS_ZNEG)
1900 ? (sc->ipacket[2] & 0x0f) - 16
1901 : (sc->ipacket[2] & 0x0f);
1902 }
1903 ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
1904 ? MOUSE_BUTTON4DOWN : 0;
1905 ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
1906 ? MOUSE_BUTTON5DOWN : 0;
1907 break;
1908 case 2:
1909 /* this packet type is reserved, and currently ignored */
1910 /* FALL THROUGH */
1911 case 0:
1912 /* device type packet - shouldn't happen */
1913 /* FALL THROUGH */
1914 default:
1915 x = y = 0;
1916 ms.button = ms.obutton;
1917 log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
1918 "0x%02x 0x%02x 0x%02x\n",
1919 MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
1920 sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
1921 break;
1922 }
1923 } else {
1924 /* preserve button states */
1925 ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
1926 }
1927 break;
1928
1929 case MOUSE_MODEL_GLIDEPOINT:
1930 /* `tapping' action */
1931 ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
1932 break;
1933
1934 case MOUSE_MODEL_NETSCROLL:
1935 /* three addtional bytes encode button and wheel events */
1936 ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
1937 ? MOUSE_BUTTON4DOWN : 0;
1938 z = (sc->ipacket[3] & MOUSE_PS2_XNEG)
1939 ? sc->ipacket[4] - 256 : sc->ipacket[4];
1940 break;
1941
1942 case MOUSE_MODEL_THINK:
1943 /* the fourth button state in the first byte */
1944 ms.button |= (c & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
1945 break;
1946
1947 case MOUSE_MODEL_VERSAPAD:
1948 /* VersaPad PS/2 absolute mode message format
1949 *
1950 * [packet1] 7 6 5 4 3 2 1 0(LSB)
1951 * ipacket[0]: 1 1 0 A 1 L T R
1952 * ipacket[1]: H7 H6 H5 H4 H3 H2 H1 H0
1953 * ipacket[2]: V7 V6 V5 V4 V3 V2 V1 V0
1954 * ipacket[3]: 1 1 1 A 1 L T R
1955 * ipacket[4]:V11 V10 V9 V8 H11 H10 H9 H8
1956 * ipacket[5]: 0 P6 P5 P4 P3 P2 P1 P0
1957 *
1958 * [note]
1959 * R: right physical mouse button (1=on)
1960 * T: touch pad virtual button (1=tapping)
1961 * L: left physical mouse button (1=on)
1962 * A: position data is valid (1=valid)
1963 * H: horizontal data (12bit signed integer. H11 is sign bit.)
1964 * V: vertical data (12bit signed integer. V11 is sign bit.)
1965 * P: pressure data
1966 *
1967 * Tapping is mapped to MOUSE_BUTTON4.
1968 */
1969 ms.button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
1970 ms.button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
1971 x = y = 0;
1972 if (c & MOUSE_PS2VERSA_IN_USE) {
1973 x0 = sc->ipacket[1] | (((sc->ipacket[4]) & 0x0f) << 8);
1974 y0 = sc->ipacket[2] | (((sc->ipacket[4]) & 0xf0) << 4);
1975 if (x0 & 0x800)
1976 x0 -= 0x1000;
1977 if (y0 & 0x800)
1978 y0 -= 0x1000;
1979 if (sc->flags & PSM_FLAGS_FINGERDOWN) {
1980 x = sc->xold - x0;
1981 y = y0 - sc->yold;
1982 if (x < 0) /* XXX */
1983 x++;
1984 else if (x)
1985 x--;
1986 if (y < 0)
1987 y++;
1988 else if (y)
1989 y--;
1990 } else {
1991 sc->flags |= PSM_FLAGS_FINGERDOWN;
1992 }
1993 sc->xold = x0;
1994 sc->yold = y0;
1995 } else {
1996 sc->flags &= ~PSM_FLAGS_FINGERDOWN;
1997 }
1998 c = ((x < 0) ? MOUSE_PS2_XNEG : 0)
1999 | ((y < 0) ? MOUSE_PS2_YNEG : 0);
2000 break;
2001
2002 case MOUSE_MODEL_GENERIC:
2003 default:
2004 break;
2005 }
2006
2007 /* scale values */
2008 if (sc->mode.accelfactor >= 1) {
2009 if (x != 0) {
2010 x = x * x / sc->mode.accelfactor;
2011 if (x == 0)
2012 x = 1;
2013 if (c & MOUSE_PS2_XNEG)
2014 x = -x;
2015 }
2016 if (y != 0) {
2017 y = y * y / sc->mode.accelfactor;
2018 if (y == 0)
2019 y = 1;
2020 if (c & MOUSE_PS2_YNEG)
2021 y = -y;
2022 }
2023 }
2024
2025 ms.dx = x;
2026 ms.dy = y;
2027 ms.dz = z;
2028 ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0)
2029 | (ms.obutton ^ ms.button);
2030
2031 if (sc->mode.level < PSM_LEVEL_NATIVE)
2032 sc->inputbytes = tame_mouse(sc, &ms, sc->ipacket);
2033
2034 sc->status.flags |= ms.flags;
2035 sc->status.dx += ms.dx;
2036 sc->status.dy += ms.dy;
2037 sc->status.dz += ms.dz;
2038 sc->status.button = ms.button;
2039 sc->button = ms.button;
2040
2041 /* queue data */
2042 if (sc->queue.count + sc->inputbytes < sizeof(sc->queue.buf)) {
2043 l = min(sc->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail);
2044 bcopy(&sc->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
2045 if (sc->inputbytes > l)
2046 bcopy(&sc->ipacket[l], &sc->queue.buf[0], sc->inputbytes - l);
2047 sc->queue.tail =
2048 (sc->queue.tail + sc->inputbytes) % sizeof(sc->queue.buf);
2049 sc->queue.count += sc->inputbytes;
2050 }
2051 sc->inputbytes = 0;
2052
2053 if (sc->state & PSM_ASLP) {
2054 sc->state &= ~PSM_ASLP;
2055 wakeup((caddr_t) sc);
2056 }
2057 selwakeup(&sc->rsel);
2058 }
2059 }
2060
2061 static int
2062 psmpoll(dev_t dev, int events, struct proc *p)
2063 {
2064 struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
2065 int s;
2066 int revents = 0;
2067
2068 /* Return true if a mouse event available */
2069 s = spltty();
2070 if (events & (POLLIN | POLLRDNORM)) {
2071 if (sc->queue.count > 0)
2072 revents |= events & (POLLIN | POLLRDNORM);
2073 else
2074 selrecord(p, &sc->rsel);
2075 }
2076 splx(s);
2077
2078 return (revents);
2079 }
2080
2081 /* vendor/model specific routines */
2082
2083 static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
2084 {
2085 if (set_mouse_resolution(kbdc, res) != res)
2086 return FALSE;
2087 if (set_mouse_scaling(kbdc, scale)
2088 && set_mouse_scaling(kbdc, scale)
2089 && set_mouse_scaling(kbdc, scale)
2090 && (get_mouse_status(kbdc, status, 0, 3) >= 3))
2091 return TRUE;
2092 return FALSE;
2093 }
2094
2095 #if notyet
2096 /* Logitech MouseMan Cordless II */
2097 static int
2098 enable_lcordless(struct psm_softc *sc)
2099 {
2100 int status[3];
2101 int ch;
2102
2103 if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status))
2104 return FALSE;
2105 if (status[1] == PSMD_RES_HIGH)
2106 return FALSE;
2107 ch = (status[0] & 0x07) - 1; /* channel # */
2108 if ((ch <= 0) || (ch > 4))
2109 return FALSE;
2110 /*
2111 * status[1]: always one?
2112 * status[2]: battery status? (0-100)
2113 */
2114 return TRUE;
2115 }
2116 #endif /* notyet */
2117
2118 /* Genius NetScroll Mouse */
2119 static int
2120 enable_groller(struct psm_softc *sc)
2121 {
2122 int status[3];
2123
2124 /*
2125 * The special sequence to enable the fourth button and the
2126 * roller. Immediately after this sequence check status bytes.
2127 * if the mouse is NetScroll, the second and the third bytes are
2128 * '3' and 'D'.
2129 */
2130
2131 /*
2132 * If the mouse is an ordinary PS/2 mouse, the status bytes should
2133 * look like the following.
2134 *
2135 * byte 1 bit 7 always 0
2136 * bit 6 stream mode (0)
2137 * bit 5 disabled (0)
2138 * bit 4 1:1 scaling (0)
2139 * bit 3 always 0
2140 * bit 0-2 button status
2141 * byte 2 resolution (PSMD_RES_HIGH)
2142 * byte 3 report rate (?)
2143 */
2144
2145 if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
2146 return FALSE;
2147 if ((status[1] != '3') || (status[2] != 'D'))
2148 return FALSE;
2149 /* FIXME!! */
2150 sc->hw.buttons = get_mouse_buttons(sc->kbdc);
2151 sc->hw.buttons = 4;
2152 return TRUE;
2153 }
2154
2155 /* Genius NetMouse/NetMouse Pro */
2156 static int
2157 enable_gmouse(struct psm_softc *sc)
2158 {
2159 int status[3];
2160
2161 /*
2162 * The special sequence to enable the middle, "rubber" button.
2163 * Immediately after this sequence check status bytes.
2164 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
2165 * the second and the third bytes are '3' and 'U'.
2166 * NOTE: NetMouse reports that it has three buttons although it has
2167 * two buttons and a rubber button. NetMouse Pro and MIE Mouse
2168 * say they have three buttons too and they do have a button on the
2169 * side...
2170 */
2171 if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
2172 return FALSE;
2173 if ((status[1] != '3') || (status[2] != 'U'))
2174 return FALSE;
2175 return TRUE;
2176 }
2177
2178 /* ALPS GlidePoint */
2179 static int
2180 enable_aglide(struct psm_softc *sc)
2181 {
2182 int status[3];
2183
2184 /*
2185 * The special sequence to obtain ALPS GlidePoint specific
2186 * information. Immediately after this sequence, status bytes will
2187 * contain something interesting.
2188 * NOTE: ALPS produces several models of GlidePoint. Some of those
2189 * do not respond to this sequence, thus, cannot be detected this way.
2190 */
2191 if (set_mouse_sampling_rate(sc->kbdc, 100) != 100)
2192 return FALSE;
2193 if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status))
2194 return FALSE;
2195 if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
2196 return FALSE;
2197 return TRUE;
2198 }
2199
2200 /* Kensington ThinkingMouse/Trackball */
2201 static int
2202 enable_kmouse(struct psm_softc *sc)
2203 {
2204 static unsigned char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
2205 KBDC kbdc = sc->kbdc;
2206 int status[3];
2207 int id1;
2208 int id2;
2209 int i;
2210
2211 id1 = get_aux_id(kbdc);
2212 if (set_mouse_sampling_rate(kbdc, 10) != 10)
2213 return FALSE;
2214 /*
2215 * The device is now in the native mode? It returns a different
2216 * ID value...
2217 */
2218 id2 = get_aux_id(kbdc);
2219 if ((id1 == id2) || (id2 != 2))
2220 return FALSE;
2221
2222 if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
2223 return FALSE;
2224 #if PSM_DEBUG >= 2
2225 /* at this point, resolution is LOW, sampling rate is 10/sec */
2226 if (get_mouse_status(kbdc, status, 0, 3) < 3)
2227 return FALSE;
2228 #endif
2229
2230 /*
2231 * The special sequence to enable the third and fourth buttons.
2232 * Otherwise they behave like the first and second buttons.
2233 */
2234 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
2235 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
2236 return FALSE;
2237 }
2238
2239 /*
2240 * At this point, the device is using default resolution and
2241 * sampling rate for the native mode.
2242 */
2243 if (get_mouse_status(kbdc, status, 0, 3) < 3)
2244 return FALSE;
2245 if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
2246 return FALSE;
2247
2248 /* the device appears be enabled by this sequence, diable it for now */
2249 disable_aux_dev(kbdc);
2250 empty_aux_buffer(kbdc, 5);
2251
2252 return TRUE;
2253 }
2254
2255 /* Logitech MouseMan+/FirstMouse+ */
2256 static int
2257 enable_mmanplus(struct psm_softc *sc)
2258 {
2259 static char res[] = {
2260 -1, PSMD_RES_LOW, PSMD_RES_HIGH, PSMD_RES_MEDIUM_HIGH,
2261 PSMD_RES_MEDIUM_LOW, -1, PSMD_RES_HIGH, PSMD_RES_MEDIUM_LOW,
2262 PSMD_RES_MEDIUM_HIGH, PSMD_RES_HIGH,
2263 };
2264 KBDC kbdc = sc->kbdc;
2265 int data[3];
2266 int i;
2267
2268 /* the special sequence to enable the fourth button and the roller. */
2269 for (i = 0; i < sizeof(res)/sizeof(res[0]); ++i) {
2270 if (res[i] < 0) {
2271 if (!set_mouse_scaling(kbdc, 1))
2272 return FALSE;
2273 } else {
2274 if (set_mouse_resolution(kbdc, res[i]) != res[i])
2275 return FALSE;
2276 }
2277 }
2278
2279 if (get_mouse_status(kbdc, data, 1, 3) < 3)
2280 return FALSE;
2281
2282 /*
2283 * PS2++ protocl, packet type 0
2284 *
2285 * b7 b6 b5 b4 b3 b2 b1 b0
2286 * byte 1: * 1 p3 p2 1 * * *
2287 * byte 2: 1 1 p1 p0 m1 m0 1 0
2288 * byte 3: m7 m6 m5 m4 m3 m2 m1 m0
2289 *
2290 * p3-p0: packet type: 0
2291 * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51,...
2292 */
2293 /* check constant bits */
2294 if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
2295 return FALSE;
2296 if ((data[1] & 0xc3) != 0xc2)
2297 return FALSE;
2298 /* check d3-d0 in byte 2 */
2299 if (!MOUSE_PS2PLUS_CHECKBITS(data))
2300 return FALSE;
2301 /* check p3-p0 */
2302 if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
2303 return FALSE;
2304
2305 sc->hw.hwid &= 0x00ff;
2306 sc->hw.hwid |= data[2] << 8; /* save model ID */
2307
2308 /*
2309 * MouseMan+ (or FirstMouse+) is now in its native mode, in which
2310 * the wheel and the fourth button events are encoded in the
2311 * special data packet. The mouse may be put in the IntelliMouse mode
2312 * if it is initialized by the IntelliMouse's method.
2313 */
2314 return TRUE;
2315 }
2316
2317 /* MS IntelliMouse */
2318 static int
2319 enable_msintelli(struct psm_softc *sc)
2320 {
2321 /*
2322 * Logitech MouseMan+ and FirstMouse+ will also respond to this
2323 * probe routine and act like IntelliMouse.
2324 */
2325
2326 static unsigned char rate[] = { 200, 100, 80, };
2327 KBDC kbdc = sc->kbdc;
2328 int id;
2329 int i;
2330
2331 /* the special sequence to enable the third button and the roller. */
2332 for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
2333 if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
2334 return FALSE;
2335 }
2336 /* the device will give the genuine ID only after the above sequence */
2337 id = get_aux_id(kbdc);
2338 if (id != PSM_INTELLI_ID)
2339 return FALSE;
2340
2341 sc->hw.hwid = id;
2342 sc->hw.buttons = 3;
2343
2344 return TRUE;
2345 }
2346
2347 /* Interlink electronics VersaPad */
2348 static int
2349 enable_versapad(struct psm_softc *sc)
2350 {
2351 KBDC kbdc = sc->kbdc;
2352 int data[3];
2353
2354 set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
2355 set_mouse_sampling_rate(kbdc, 100); /* set rate 100 */
2356 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
2357 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
2358 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
2359 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
2360 if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */
2361 return FALSE;
2362 if (data[2] != 0xa || data[1] != 0 ) /* rate == 0xa && res. == 0 */
2363 return FALSE;
2364 set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
2365
2366 return TRUE; /* PS/2 absolute mode */
2367 }
2368
2369 #ifdef PSM_HOOKAPM
2370 static int
2371 psmresume(void *dummy)
2372 {
2373 struct psm_softc *sc = psm_softc[(int)dummy];
2374 int unit = (int)dummy;
2375 int err = 0;
2376 int s;
2377 int c;
2378
2379 if (verbose >= 2)
2380 log(LOG_NOTICE, "psm%d: APM resume hook called.\n", unit);
2381
2382 /* don't let anybody mess with the aux device */
2383 if (!kbdc_lock(sc->kbdc, TRUE))
2384 return (EIO);
2385 s = spltty();
2386
2387 /* save the current controller command byte */
2388 empty_both_buffers(sc->kbdc, 10);
2389 c = get_controller_command_byte(sc->kbdc);
2390 if (verbose >= 2)
2391 log(LOG_DEBUG, "psm%d: current command byte: %04x (psmresume).\n",
2392 unit, c);
2393
2394 /* enable the aux port but disable the aux interrupt and the keyboard */
2395 if ((c == -1) || !set_controller_command_byte(sc->kbdc,
2396 kbdc_get_device_mask(sc->kbdc),
2397 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
2398 | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
2399 /* CONTROLLER ERROR */
2400 splx(s);
2401 kbdc_lock(sc->kbdc, FALSE);
2402 log(LOG_ERR, "psm%d: unable to set the command byte (psmresume).\n",
2403 unit);
2404 return (EIO);
2405 }
2406
2407 /* flush any data */
2408 if (sc->state & PSM_VALID) {
2409 disable_aux_dev(sc->kbdc); /* this may fail; but never mind... */
2410 empty_aux_buffer(sc->kbdc, 10);
2411 }
2412 sc->inputbytes = 0;
2413
2414 #ifdef PSM_RESETAFTERSUSPEND
2415 /* try to detect the aux device; are you still there? */
2416 if (reinitialize(unit, &sc->mode)) {
2417 /* yes */
2418 sc->state |= PSM_VALID;
2419 } else {
2420 /* the device has gone! */
2421 restore_controller(sc->kbdc, c);
2422 sc->state &= ~PSM_VALID;
2423 log(LOG_ERR, "psm%d: the aux device has gone! (psmresume).\n",
2424 unit);
2425 err = ENXIO;
2426 }
2427 #endif /* PSM_RESETAFTERSUSPEND */
2428 splx(s);
2429
2430 /* restore the driver state */
2431 if ((sc->state & PSM_OPEN) && (err == 0)) {
2432 /* enable the aux device and the port again */
2433 err = doopen(unit, c);
2434 if (err != 0)
2435 log(LOG_ERR, "psm%d: failed to enable the device (psmresume).\n",
2436 unit);
2437 } else {
2438 /* restore the keyboard port and disable the aux port */
2439 if (!set_controller_command_byte(sc->kbdc,
2440 kbdc_get_device_mask(sc->kbdc),
2441 (c & KBD_KBD_CONTROL_BITS)
2442 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
2443 /* CONTROLLER ERROR */
2444 log(LOG_ERR, "psm%d: failed to disable the aux port (psmresume).\n",
2445 unit);
2446 err = EIO;
2447 }
2448 }
2449
2450 /* done */
2451 kbdc_lock(sc->kbdc, FALSE);
2452 if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
2453 /*
2454 * Release the blocked process; it must be notified that the device
2455 * cannot be accessed anymore.
2456 */
2457 sc->state &= ~PSM_ASLP;
2458 wakeup((caddr_t)sc);
2459 }
2460
2461 if (verbose >= 2)
2462 log(LOG_DEBUG, "psm%d: APM resume hook exiting.\n", unit);
2463
2464 return (err);
2465 }
2466 #endif /* PSM_HOOKAPM */
2467
2468 CDEV_DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass,
2469 CDEV_MAJOR, psm_cdevsw, 0, 0);
2470
2471 #endif /* NPSM > 0 */
Cache object: 23bc87e73f8a8eed9f5fc72a04d6d471
|