summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>1996-12-01 19:05:50 +0000
committersos <sos@FreeBSD.org>1996-12-01 19:05:50 +0000
commit0a8ebf33fc34909b6f0e7ecd100e7c353b856355 (patch)
tree54352ee80d9cef4ec7de46e9031694a7e6a7126f /sys/i386/isa
parentfacb673a9aff2058f0ae04c490c808063761bc84 (diff)
downloadFreeBSD-src-0a8ebf33fc34909b6f0e7ecd100e7c353b856355.zip
FreeBSD-src-0a8ebf33fc34909b6f0e7ecd100e7c353b856355.tar.gz
Alot of fixes from kazu:
1. All the suggestions earlier made by Bruce: renaming some symbols, stricter error checking, removing redundant code, etc. 2. The `psm' driver preserves the default counter resolution and report rate, whatever they are after reset. (Based on reports and suggestion from Nate and Rob Bolin). 3. The `psm' driver now does not check the so-called sync. bit in the first byte of the data packet by default, so that the tapping feature of ALPUS GlidePoint works (based on reports from Louis Mamakos). I tested the code with ALPUS Desktop GlidePoint (M/N GP101) and found no problem; tapping worked. It appears ALPUS produces several models of GlidePoint. I hope the other models are OK too. The check code can still be activated by defining the PSM_CHECKSYNC option in the config file. (The bit checking slightly reduces, if not completely eliminates, weird mouse behavior cased by unsynchronized mouse data packets. It also helps us to detect if the mouse interrupt can ever be lost. But, well, if there are devices which cannot be supported this way...) 4. The `psm' driver does not include the protocol emulation code by default. The code can still be compiled in if the PSM_EMULATION option is specified in the config file. Louis Mamakos suggests the emulation code is putting too much in the kernel, and `moused' works well. I will think about this later and decide if the entire emulation code should be removed. 5. And, of course, the fix in `scprobe()' from Bruce to cure the UserConfig problem. My code in `kbdio.c' is slightly different from his patch, but has the same effect. There still is a possibility that `scprobe()' gets confused, if, for whatever reasons, the user holds down a key for very long time during the boot process. But we cannot cope with everything, can we? Submitted by: Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
Diffstat (limited to 'sys/i386/isa')
-rw-r--r--sys/i386/isa/kbdio.c255
-rw-r--r--sys/i386/isa/kbdio.h24
-rw-r--r--sys/i386/isa/psm.c640
-rw-r--r--sys/i386/isa/syscons.c71
4 files changed, 682 insertions, 308 deletions
diff --git a/sys/i386/isa/kbdio.c b/sys/i386/isa/kbdio.c
index f326295..797dcff 100644
--- a/sys/i386/isa/kbdio.c
+++ b/sys/i386/isa/kbdio.c
@@ -26,16 +26,23 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: kbdio.c,v 1.1 1996/11/14 22:19:06 sos Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/syslog.h>
#include <machine/clock.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/kbdio.h>
+#ifndef KBDIO_DEBUG
+#define KBDIO_DEBUG 0
+#endif
+
+static int verbose = KBDIO_DEBUG;
+
/*
* device I/O routines
*/
@@ -45,22 +52,7 @@ wait_while_controller_busy(int port)
/* CPU will stay inside the loop for 100msec at most */
int retry = 5000;
- while (inb(port + KBD_STATUS_PORT) & KBDS_CONTROLLER_BUSY) {
- DELAY(20);
- if (--retry < 0)
- return FALSE;
- }
- return TRUE;
-}
-
-int
-wait_until_controller_is_really_idle(int port)
-{
- /* CPU will stay inside the loop for 100msec at most */
- int retry = 5000;
-
- while (inb(port + KBD_STATUS_PORT)
- & (KBDS_CONTROLLER_BUSY | KBDS_ANY_BUFFER_FULL)) {
+ while (inb(port + KBD_STATUS_PORT) & KBDS_INPUT_BUFFER_FULL) {
DELAY(20);
if (--retry < 0)
return FALSE;
@@ -83,6 +75,7 @@ wait_for_data(int port)
if (--retry < 0)
return FALSE;
}
+ DELAY(7);
return TRUE;
}
@@ -99,6 +92,7 @@ wait_for_kbd_data(int port)
if (--retry < 0)
return FALSE;
}
+ DELAY(7);
return TRUE;
}
@@ -115,46 +109,54 @@ wait_for_aux_data(int port)
if (--retry < 0)
return FALSE;
}
+ DELAY(7);
return TRUE;
}
-void
+int
write_controller_command(int port, int c)
{
- wait_until_controller_is_really_idle(port);
+ if (!wait_while_controller_busy(port))
+ return FALSE;
outb(port + KBD_COMMAND_PORT, c);
+ return TRUE;
}
-void
+int
write_controller_data(int port, int c)
{
- wait_until_controller_is_really_idle(port);
+ if (!wait_while_controller_busy(port))
+ return FALSE;
outb(port + KBD_DATA_PORT, c);
+ return TRUE;
}
-void
+int
write_kbd_command(int port, int c)
{
- wait_until_controller_is_really_idle(port);
+ if (!wait_while_controller_busy(port))
+ return FALSE;
outb(port + KBD_DATA_PORT, c);
+ return TRUE;
}
-void
+int
write_aux_command(int port, int c)
{
- write_controller_command(port,KBDC_WRITE_TO_AUX);
- write_controller_data(port, c);
+ if (!write_controller_command(port,KBDC_WRITE_TO_AUX))
+ return FALSE;
+ return write_controller_data(port, c);
}
int
send_kbd_command(int port, int c)
{
int retry = KBD_MAXRETRY;
- int res;
+ int res = -1;
while (retry-- > 0) {
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_DATA_PORT, c);
+ if (!write_kbd_command(port, c))
+ continue;
res = read_controller_data(port);
if (res == KBD_ACK)
break;
@@ -166,13 +168,11 @@ int
send_aux_command(int port, int c)
{
int retry = KBD_MAXRETRY;
- int res;
+ int res = -1;
while (retry-- > 0) {
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_COMMAND_PORT, KBDC_WRITE_TO_AUX);
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_DATA_PORT, c);
+ if (!write_aux_command(port, c))
+ continue;
res = read_aux_data(port);
if (res == PSM_ACK)
break;
@@ -184,19 +184,23 @@ int
send_kbd_command_and_data(int port, int c, int d)
{
int retry;
- int res;
+ int res = -1;
for (retry = KBD_MAXRETRY; retry > 0; --retry) {
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_DATA_PORT, c);
+ if (!write_kbd_command(port, c))
+ continue;
res = read_controller_data(port);
if (res == KBD_ACK)
break;
+ else if (res != PSM_RESEND)
+ return res;
}
+ if (retry <= 0)
+ return res;
- for (retry = KBD_MAXRETRY; retry > 0; --retry) {
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_DATA_PORT, d);
+ for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
+ if (!write_kbd_command(port, d))
+ continue;
res = read_controller_data(port);
if (res != KBD_RESEND)
break;
@@ -208,25 +212,23 @@ int
send_aux_command_and_data(int port, int c, int d)
{
int retry;
- int res;
+ int res = -1;
for (retry = KBD_MAXRETRY; retry > 0; --retry) {
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_COMMAND_PORT, KBDC_WRITE_TO_AUX);
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_DATA_PORT, c);
+ if (!write_aux_command(port, c))
+ continue;
res = read_aux_data(port);
if (res == PSM_ACK)
break;
else if (res != PSM_RESEND)
return res;
}
+ if (retry <= 0)
+ return res;
- for (retry = KBD_MAXRETRY; retry > 0; --retry) {
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_COMMAND_PORT, KBDC_WRITE_TO_AUX);
- wait_until_controller_is_really_idle(port);
- outb(port + KBD_DATA_PORT, d);
+ for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
+ if (!write_aux_command(port, d))
+ continue;
res = read_aux_data(port);
if (res != PSM_RESEND)
break;
@@ -241,7 +243,6 @@ send_aux_command_and_data(int port, int c, int d)
int
read_controller_data(int port)
{
- wait_while_controller_busy(port);
if (!wait_for_data(port))
return -1; /* timeout */
return inb(port + KBD_DATA_PORT);
@@ -251,7 +252,6 @@ read_controller_data(int port)
int
read_kbd_data(int port)
{
- wait_while_controller_busy(port);
if (!wait_for_kbd_data(port))
return -1; /* timeout */
return inb(port + KBD_DATA_PORT);
@@ -263,10 +263,10 @@ read_kbd_data(int port)
int
read_kbd_data_no_wait(int port)
{
- wait_while_controller_busy(port);
if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
!= KBDS_KBD_BUFFER_FULL)
return -1; /* no data */
+ DELAY(7);
return inb(port + KBD_DATA_PORT);
}
@@ -274,7 +274,6 @@ read_kbd_data_no_wait(int port)
int
read_aux_data(int port)
{
- wait_while_controller_busy(port);
if (!wait_for_aux_data(port))
return -1; /* timeout */
return inb(port + KBD_DATA_PORT);
@@ -282,55 +281,64 @@ read_aux_data(int port)
/* discard data from the keyboard */
void
-empty_kbd_buffer(int port)
+empty_kbd_buffer(int port, int t)
{
int b;
int c = 0;
+ int delta = 2;
- while ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
+ for (; t > 0; t -= delta) {
+ if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
== KBDS_KBD_BUFFER_FULL) {
+ DELAY(7);
b = inb(port + KBD_DATA_PORT);
++c;
- DELAY(20);
}
-#ifdef KBDIO_DEBUG
+ DELAY(delta*1000);
+ }
+ if ((verbose >= 2) && (c > 0))
log(LOG_DEBUG,"kbdio: %d char read (empty_kbd_buffer)\n",c);
-#endif
}
/* discard data from the aux device */
void
-empty_aux_buffer(int port)
+empty_aux_buffer(int port, int t)
{
int b;
int c = 0;
+ int delta = 2;
- while ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
+ for (; t > 0; t -= delta) {
+ if ((inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
== KBDS_AUX_BUFFER_FULL) {
+ DELAY(7);
b = inb(port + KBD_DATA_PORT);
++c;
- DELAY(20);
}
-#ifdef KBDIO_DEBUG
+ DELAY(delta*1000);
+ }
+ if ((verbose >= 2) && (c > 0))
log(LOG_DEBUG,"kbdio: %d char read (empty_aux_buffer)\n",c);
-#endif
}
/* discard any data from the keyboard or the aux device */
void
-empty_both_buffers(int port)
+empty_both_buffers(int port, int t)
{
int b;
int c = 0;
+ int delta = 2;
- while (inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
+ for (; t > 0; t -= delta) {
+ if (inb(port + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
+ DELAY(7);
b = inb(port + KBD_DATA_PORT);
++c;
- DELAY(20);
}
-#ifdef KBDIO_DEBUG
+ DELAY(delta*1000);
+ }
+ if ((verbose >= 2) && (c > 0))
log(LOG_DEBUG,"kbdio: %d char read (empty_both_buffers)\n",c);
-#endif
}
/* keyboard and mouse device control */
@@ -343,15 +351,15 @@ reset_kbd(int port)
{
int retry = KBD_MAXRETRY;
int again = KBD_MAXWAIT;
- int c;
+ int c = KBD_RESEND; /* keep the compiler happy */
while (retry-- > 0) {
- empty_both_buffers(port);
- write_kbd_command(port, KBDC_RESET_KBD);
+ empty_both_buffers(port, 10);
+ if (!write_kbd_command(port, KBDC_RESET_KBD))
+ continue;
c = read_controller_data(port);
-#ifdef KBDIO_DEBUG
+ if (verbose)
log(LOG_DEBUG,"kbdio: RESET_KBD return code:%04x\n",c);
-#endif
if (c == KBD_ACK) /* keyboard has agreed to reset itself... */
break;
}
@@ -365,9 +373,8 @@ reset_kbd(int port)
if (c != -1) /* wait again if the controller is not ready */
break;
}
-#ifdef KBDIO_DEBUG
+ if (verbose)
log(LOG_DEBUG,"kbdio: RESET_KBD status:%04x\n",c);
-#endif
if (c != KBD_RESET_DONE)
return FALSE;
return TRUE;
@@ -381,15 +388,15 @@ reset_aux_dev(int port)
{
int retry = KBD_MAXRETRY;
int again = KBD_MAXWAIT;
- int c;
+ int c = PSM_RESEND; /* keep the compiler happy */
while (retry-- > 0) {
- empty_both_buffers(port);
- write_aux_command(port, PSMC_RESET_DEV);
- c = read_controller_data(port); /* read_aux_data()? */
-#ifdef KBDIO_DEBUG
+ empty_both_buffers(port, 10);
+ if (!write_aux_command(port, PSMC_RESET_DEV))
+ continue;
+ c = read_controller_data(port);
+ if (verbose)
log(LOG_DEBUG,"kbdio: RESET_AUX return code:%04x\n",c);
-#endif
if (c == PSM_ACK) /* aux dev is about to reset... */
break;
}
@@ -403,16 +410,14 @@ reset_aux_dev(int port)
if (c != -1) /* wait again if the controller is not ready */
break;
}
-#ifdef KBDIO_DEBUG
+ if (verbose)
log(LOG_DEBUG,"kbdio: RESET_AUX status:%04x\n",c);
-#endif
if (c != PSM_RESET_DONE) /* reset status */
return FALSE;
c = read_aux_data(port); /* device ID */
-#ifdef KBDIO_DEBUG
+ if (verbose)
log(LOG_DEBUG,"kbdio: RESET_AUX ID:%04x\n",c);
-#endif
/* NOTE: we could check the device ID now, but leave it later... */
return TRUE;
}
@@ -422,49 +427,91 @@ reset_aux_dev(int port)
int
test_controller(int port)
{
- int c;
+ int retry = KBD_MAXRETRY;
+ int again = KBD_MAXWAIT;
+ int c = KBD_DIAG_FAIL;
+
+ while (retry-- > 0) {
+ empty_both_buffers(port, 10);
+ if (write_controller_command(port, KBDC_DIAGNOSE))
+ break;
+ }
+ if (retry < 0)
+ return FALSE;
- empty_both_buffers(port);
- write_controller_command(port, KBDC_DIAGNOSE);
+ while (again-- > 0) {
+ /* wait awhile */
+ DELAY(KBD_RESETDELAY*1000);
c = read_controller_data(port); /* DIAG_DONE/DIAG_FAIL */
-#ifdef KBDIO_DEBUG
+ if (c != -1) /* wait again if the controller is not ready */
+ break;
+ }
+ if (verbose)
log(LOG_DEBUG,"kbdio: DIAGNOSE status:%04x\n",c);
-#endif
return (c == KBD_DIAG_DONE);
}
int
test_kbd_port(int port)
{
- int c;
+ int retry = KBD_MAXRETRY;
+ int again = KBD_MAXWAIT;
+ int c = -1;
- empty_both_buffers(port);
- write_controller_command(port, KBDC_TEST_KBD_PORT);
+ while (retry-- > 0) {
+ empty_both_buffers(port, 10);
+ if (write_controller_command(port, KBDC_TEST_KBD_PORT))
+ break;
+ }
+ if (retry < 0)
+ return FALSE;
+
+ while (again-- > 0) {
c = read_controller_data(port);
-#ifdef KBDIO_DEBUG
+ if (c != -1) /* try again if the controller is not ready */
+ break;
+ }
+ if (verbose)
log(LOG_DEBUG,"kbdio: TEST_KBD_PORT status:%04x\n",c);
-#endif
return c;
}
int
test_aux_port(int port)
{
- int c;
+ int retry = KBD_MAXRETRY;
+ int again = KBD_MAXWAIT;
+ int c = -1;
- empty_both_buffers(port);
- write_controller_command(port, KBDC_TEST_AUX_PORT);
+ while (retry-- > 0) {
+ empty_both_buffers(port, 10);
+ if (write_controller_command(port, KBDC_TEST_AUX_PORT))
+ break;
+ }
+ if (retry < 0)
+ return FALSE;
+
+ while (again-- > 0) {
c = read_controller_data(port);
-#ifdef KBDIO_DEBUG
+ if (c != -1) /* try again if the controller is not ready */
+ break;
+ }
+ if (verbose)
log(LOG_DEBUG,"kbdio: TEST_AUX_PORT status:%04x\n",c);
-#endif
return c;
}
-void
+int
set_controller_command_byte(int port, int command, int flag)
{
- write_controller_command(port, KBDC_SET_COMMAND_BYTE);
- write_controller_data(port, command | flag);
+ if ((command | flag) & KBD_DISABLE_KBD_PORT) {
+ if (!write_controller_command(port, KBDC_DISABLE_KBD_PORT))
+ return FALSE;
+ }
+ if (!write_controller_command(port, KBDC_SET_COMMAND_BYTE))
+ return FALSE;
+ if (!write_controller_data(port, command | flag))
+ return FALSE;
wait_while_controller_busy(port);
+ return TRUE;
}
diff --git a/sys/i386/isa/kbdio.h b/sys/i386/isa/kbdio.h
index c547780..5833b86 100644
--- a/sys/i386/isa/kbdio.h
+++ b/sys/i386/isa/kbdio.h
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: kbdio.h,v 1.1 1996/11/14 22:19:09 sos Exp $
*/
#ifndef _I386_ISA_KBDIO_H_
@@ -58,6 +58,7 @@
/* controller command byte (set by KBDC_SET_COMMAND_BYTE) */
#define KBD_TRANSLATION 0x0040
#define KBD_RESERVED_BITS 0x0004
+#define KBD_OVERRIDE_KBD_LOCK 0x0008
#define KBD_ENABLE_KBD_PORT 0x0000
#define KBD_DISABLE_KBD_PORT 0x0010
#define KBD_ENABLE_AUX_PORT 0x0000
@@ -86,10 +87,12 @@
#define PSMC_DISABLE_DEV 0x00f5
#define PSMC_SEND_DEV_ID 0x00f2
#define PSMC_SEND_DEV_STATUS 0x00e9
+#define PSMC_SEND_DEV_DATA 0x00eb
#define PSMC_SET_SCALING11 0x00e6
#define PSMC_SET_SCALING21 0x00e7
#define PSMC_SET_RESOLUTION 0x00e8
#define PSMC_SET_STREAM_MODE 0x00ea
+#define PSMC_SET_REMOTE_MODE 0x00f0
#define PSMC_SET_SAMPLING_RATE 0x00f3
/* PSMC_SET_RESOLUTION argument */
@@ -111,7 +114,7 @@
#define KBDS_ANY_BUFFER_FULL 0x0001
#define KBDS_KBD_BUFFER_FULL 0x0001
#define KBDS_AUX_BUFFER_FULL 0x0021
-#define KBDS_CONTROLLER_BUSY 0x0002
+#define KBDS_INPUT_BUFFER_FULL 0x0002
/* return code */
#define KBD_ACK 0x00fa
@@ -165,17 +168,16 @@
/* function prototypes */
int wait_while_controller_busy __P((int port));
-int wait_until_controller_is_really_idle __P((int port));
int wait_for_data __P((int port));
int wait_for_kbd_data __P((int port));
int wait_for_aux_data __P((int port));
-void write_controller_command __P((int port,int c));
-void write_controller_data __P((int port,int c));
+int write_controller_command __P((int port,int c));
+int write_controller_data __P((int port,int c));
-void write_kbd_command __P((int port,int c));
-void write_aux_command __P((int port,int c));
+int write_kbd_command __P((int port,int c));
+int write_aux_command __P((int port,int c));
int send_kbd_command __P((int port,int c));
int send_aux_command __P((int port,int c));
int send_kbd_command_and_data __P((int port,int c,int d));
@@ -186,9 +188,9 @@ int read_kbd_data __P((int port));
int read_kbd_data_no_wait __P((int port));
int read_aux_data __P((int port));
-void empty_kbd_buffer __P((int port));
-void empty_aux_buffer __P((int port));
-void empty_both_buffers __P((int port));
+void empty_kbd_buffer __P((int port, int t));
+void empty_aux_buffer __P((int port, int t));
+void empty_both_buffers __P((int port, int t));
int reset_kbd __P((int port));
int reset_aux_dev __P((int port));
@@ -197,7 +199,7 @@ int test_controller __P((int port));
int test_kbd_port __P((int port));
int test_aux_port __P((int port));
-void set_controller_command_byte __P((int port,int command,int flag));
+int set_controller_command_byte __P((int port,int command,int flag));
#endif /* KERNEL */
diff --git a/sys/i386/isa/psm.c b/sys/i386/isa/psm.c
index 2e11729..2709038 100644
--- a/sys/i386/isa/psm.c
+++ b/sys/i386/isa/psm.c
@@ -19,7 +19,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: psm.c,v 1.30 1996/11/27 22:52:25 phk Exp $
+ * $Id: psm.c,v 1.31 1996/11/28 17:18:56 phk Exp $
*/
/*
@@ -51,9 +51,9 @@
* - 3 October 1996.
* - 14 October 1996.
* - 22 October 1996.
- * - 28 October 1996. Start adding IOCTLs.
* - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
* - 14 November 1996. Uses `kbdio.c'.
+ * - 30 November 1996. More fixes.
*/
#include "psm.h"
@@ -90,20 +90,20 @@
#define PSM_DEBUG 0 /* logging: 0: none, 1: brief, 2: verbose */
#endif
-/* features */
-/* #define PSM_NOCHECKSYNC if defined, don't check the header data byte */
+/* #define PSM_CHECKSYNC if defined, check the header data byte */
+/* features */
#ifndef PSM_ACCEL
#define PSM_ACCEL 0 /* must be one or greater; acceleration will be
* disabled if zero */
#endif
-/* #define PSM_NOEMULATION disables protocol emulation */
+/* #define PSM_EMULATION enables protocol emulation */
/* end of driver specific options */
/* default values */
-#define PSMD_DEFAULT_RESOLUTION 800 /* resolution: 800 ppi */
+#define PSMD_DEFAULT_RESOLUTION 200 /* resolution: 200 ppi */
#define PSMD_DEFAULT_RATE 100 /* report rate: 100 Hz */
/* some macros */
@@ -118,14 +118,6 @@
#define min(x,y) ((x) < (y) ? (x) : (y))
#endif
-/* mouse status block */
-typedef struct mousestatus {
- int button; /* button status */
- int obutton; /* previous button status */
- int dx; /* x movement */
- int dy; /* y movement */
-} mousestatus_t;
-
/* ring buffer */
#define PSM_BUFSIZE 256
@@ -169,7 +161,9 @@ static struct psm_softc { /* Driver status information */
static int psmprobe __P((struct isa_device *));
static int psmattach __P((struct isa_device *));
static int mkms __P((unsigned char *, int *, int, mousestatus_t *));
+static int mkman __P((unsigned char *, int *, int, mousestatus_t *));
static int mkmsc __P((unsigned char *, int *, int, mousestatus_t *));
+static int mkmm __P((unsigned char *, int *, int, mousestatus_t *));
static int mkps2 __P((unsigned char *, int *, int, mousestatus_t *));
static d_open_t psmopen;
@@ -221,7 +215,7 @@ get_mouse_status(int port, int *status)
{
int res;
- empty_both_buffers(port);
+ empty_both_buffers(port, 2);
res = send_aux_command(port, PSMC_SEND_DEV_STATUS);
if (verbose >= 2)
log(LOG_DEBUG, "psm: SEND_AUX_STATUS return code:%04x\n", res);
@@ -238,23 +232,18 @@ get_mouse_status(int port, int *status)
static int
get_aux_id(int port)
{
- int retry;
+ int res;
int id;
- int c;
- for (retry = KBD_MAXRETRY; retry > 0; --retry) {
- empty_both_buffers(port);
- write_aux_command(port, PSMC_SEND_DEV_ID);
+ empty_both_buffers(port, 2);
+ res = send_aux_command(port, PSMC_SEND_DEV_ID);
+ if (verbose >= 2)
+ log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res);
+ if (res != PSM_ACK)
+ return (-1);
+
/* 10ms delay */
DELAY(10000);
- c = read_controller_data(port);
- if (verbose >= 2)
- log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", c);
- if (c == PSM_ACK)
- break;
- }
- if (retry <= 0)
- return -1;
id = read_aux_data(port);
if (verbose >= 2)
@@ -287,13 +276,10 @@ set_mouse_scaling(int port)
return (res == PSM_ACK);
}
-static int
-set_mouse_resolution(int port, int res)
-{
- static struct {
+static struct {
int resolution;
int code;
- } rescode[] = {
+} rescode[] = {
{ 25, PSMD_RESOLUTION_25 },
{ 50, PSMD_RESOLUTION_50 },
{ 100, PSMD_RESOLUTION_100 },
@@ -301,12 +287,17 @@ set_mouse_resolution(int port, int res)
{ 400, PSMD_RESOLUTION_400 }, /* ?? */
{ 800, PSMD_RESOLUTION_800 }, /* ?? */
{ INT_MAX, PSMD_MAX_RESOLUTION },
- };
+ { -1 },
+};
+
+static int
+set_mouse_resolution(int port, int res)
+{
int ret;
int i;
if (res <= 0)
- return FALSE;
+ return (-1);
for (i = 0; rescode[i].resolution > 0; ++i)
if (rescode[i].resolution >= res)
break;
@@ -344,6 +335,7 @@ static int
get_mouse_buttons(int port)
{
int c = 2; /* assume two buttons by default */
+ int res;
int status[3];
/*
@@ -352,7 +344,7 @@ get_mouse_buttons(int port)
* scaling to 1:1, set scaling to 1:1. Then the second byte of the
* mouse status bytes is the number of available buttons.
*/
- if (!set_mouse_resolution(port, 25))
+ if (set_mouse_resolution(port, 25) != 25)
return c;
if (set_mouse_scaling(port) && set_mouse_scaling(port)
&& set_mouse_scaling(port) && get_mouse_status(port, status)) {
@@ -386,15 +378,16 @@ is_a_mouse(int id)
if (valid_ids[i] == id)
return TRUE;
return FALSE;
-#endif
+#else
return TRUE;
+#endif
}
static void
recover_from_error(int port)
{
/* discard anything left in the output buffer */
- empty_both_buffers(port);
+ empty_both_buffers(port, 10);
#if 0
/*
@@ -407,19 +400,100 @@ recover_from_error(int port)
* NOTE: somehow diagnostic and keyboard port test commands bring the
* keyboard back.
*/
- test_controller(port);
- test_kbd_port(port);
+ if (!test_controller(port))
+ log(LOG_ERR, "psm: keyboard controller failed.\n");
+ /* if there isn't a keyboard in the system, the following error is OK */
+ if (test_kbd_port(port) != 0) {
+ if (verbose)
+ log(LOG_ERR, "psm: keyboard port failed.\n");
+ }
#endif
}
-static void
+static int
restore_controller(int port, int command_byte)
{
- set_controller_command_byte(port, command_byte, 0);
+ if (!set_controller_command_byte(port, command_byte, 0)) {
+ log(LOG_ERR, "psm: failed to restore the keyboard controller "
+ "command byte.\n");
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/*
+ * Re-initialize the aux port and device. The aux port must be enabled
+ * and its interrupt must be disabled before calling this routine.
+ * The aux device will be disabled before returning.
+ */
+static int
+reinitialize(dev_t dev, mousemode_t *mode)
+{
+ int port = psm_softc[PSM_UNIT(dev)]->addr;
+ int stat[3];
+ int i;
+
+ switch((i = test_aux_port(port))) {
+ case 0: /* no error */
+ break;
+ case -1: /* time out */
+ default: /* error */
+ recover_from_error(port);
+ log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
+ PSM_UNIT(dev),i);
+ return FALSE;
+ }
+
+ /*
+ * NOTE: some controllers appears to hang the `keyboard' when
+ * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
+ */
+ if (!reset_aux_dev(port)) {
+ recover_from_error(port);
+ log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
+ PSM_UNIT(dev));
+ return FALSE;
+ }
+
+ /*
+ * both the aux port and the aux device is functioning, see
+ * if the device can be enabled.
+ */
+ if (!enable_aux_dev(port) || !disable_aux_dev(port)) {
+ log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
+ PSM_UNIT(dev));
+ return FALSE;
+ }
+ empty_both_buffers(port, 10);
+
+ /* set mouse parameters */
+ if (mode != (mousemode_t *)NULL) {
+ if (mode->rate > 0)
+ mode->rate = set_mouse_sampling_rate(port, mode->rate);
+ if (mode->resolution > 0)
+ mode->resolution = set_mouse_resolution(port, mode->resolution);
+ set_mouse_scaling(port);
+ set_mouse_mode(port);
+ }
+
+ /* just check the status of the mouse */
+ if (verbose) {
+ get_mouse_status(port, stat);
+ log(LOG_DEBUG, "psm%d: status %02x %02x %02x (reinitialized)\n",
+ PSM_UNIT(dev), stat[0], stat[1], stat[2]);
+ }
+
+ return TRUE;
}
/* psm driver entry points */
+#define endprobe(v) { if (bootverbose) \
+ --verbose; \
+ return (v); \
+ }
+
static int
psmprobe(struct isa_device *dvp)
{
@@ -427,6 +501,7 @@ psmprobe(struct isa_device *dvp)
int ioport = dvp->id_iobase;
struct psm_softc *sc;
int stat[3];
+ int setparams;
int i;
/* validate unit number */
@@ -481,29 +556,43 @@ psmprobe(struct isa_device *dvp)
*/
/* save the current command byte; it will be used later */
- write_controller_command(ioport, KBDC_GET_COMMAND_BYTE);
+ if (!write_controller_command(ioport,KBDC_GET_COMMAND_BYTE)) {
+ /* CONTROLLER ERROR */
+ printf("psm%d: failed to get the current command byte value.\n",
+ unit);
+ free(sc, M_DEVBUF);
+ endprobe(0);
+ }
sc->command_byte = read_controller_data(ioport);
if (verbose) {
printf("psm%d: current command byte:%04x\n",
unit, sc->command_byte);
}
if (sc->command_byte == -1) {
+ /* CONTROLLER ERROR */
printf("psm%d: unable to get the current command byte value.\n",
unit);
free(sc, M_DEVBUF);
- return (0);
+ endprobe(0);
}
/*
* disable the keyboard port while probing the aux port, which must be
* enabled during this routine
*/
- write_controller_command(ioport, KBDC_DISABLE_KBD_PORT);
- set_controller_command_byte(ioport,
- sc->command_byte
- & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS),
+ if (!set_controller_command_byte(ioport,
+ sc->command_byte & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS),
KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
- | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ /*
+ * this is CONTROLLER ERROR; I don't know how to recover
+ * from this error...
+ */
+ restore_controller(ioport, sc->command_byte);
+ printf("psm%d: unable to set the command byte.\n", unit);
+ free(sc, M_DEVBUF);
+ endprobe(0);
+ }
/*
* NOTE: `test_aux_port()' is designed to return with zero if the aux
@@ -526,10 +615,8 @@ psmprobe(struct isa_device *dvp)
if (verbose)
printf("psm%d: the aux port is not functioning (%d).\n",
unit, i);
- if (bootverbose)
- --verbose;
free(sc, M_DEVBUF);
- return (0);
+ endprobe(0);
}
/*
@@ -542,7 +629,7 @@ psmprobe(struct isa_device *dvp)
if (verbose)
printf("psm%d: failed to reset the aux device.\n", unit);
free(sc, M_DEVBUF);
- return (0);
+ endprobe(0);
}
/*
* both the aux port and the aux device is functioning, see if the
@@ -551,15 +638,31 @@ psmprobe(struct isa_device *dvp)
* the device can be enabled.
*/
if (!enable_aux_dev(ioport) || !disable_aux_dev(ioport)) {
+ /* MOUSE ERROR */
restore_controller(ioport, sc->command_byte);
if (verbose)
printf("psm%d: failed to enable the aux device.\n", unit);
- if (bootverbose)
- --verbose;
free(sc, M_DEVBUF);
- return (0);
+ endprobe(0);
+ }
+ empty_both_buffers(ioport, 10); /* remove stray data if any */
+
+ /* save the default values after reset */
+ if (get_mouse_status(ioport, stat)) {
+ if (verbose)
+ printf("psm%d: status after reset %02x %02x %02x\n",
+ unit, stat[0], stat[1], stat[2]);
+ sc->mode.rate = stat[2];
+ sc->mode.resolution = PSMD_DEFAULT_RESOLUTION;
+ for (i = 0; rescode[i].resolution > 0; ++i)
+ if (rescode[i].code == stat[1])
+ sc->mode.resolution = rescode[i].resolution;
+ setparams = TRUE;
+ } else {
+ sc->mode.rate = -1;
+ sc->mode.resolution = -1;
+ setparams = FALSE;
}
- empty_both_buffers(ioport); /* remove stray data if any */
/* hardware information */
sc->hw.iftype = MOUSE_IF_PS2;
@@ -570,10 +673,8 @@ psmprobe(struct isa_device *dvp)
restore_controller(ioport, sc->command_byte);
if (verbose)
printf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid);
- if (bootverbose)
- --verbose;
free(sc, M_DEVBUF);
- return (0);
+ endprobe(0);
}
switch (sc->hw.hwid) {
case PSM_BALLPOINT_ID:
@@ -588,15 +689,18 @@ psmprobe(struct isa_device *dvp)
}
/* # of buttons */
- sc->hw.buttons = get_mouse_buttons(ioport);
+ sc->hw.buttons = (setparams) ? get_mouse_buttons(ioport) : 2;
/* set mouse parameters */
-
- /* FIXME:XXX I don't know if these parameters are reasonable */
/* FIXME:XXX should we set them in `psmattach()' rather than here? */
- sc->mode.rate = set_mouse_sampling_rate(ioport, PSMD_DEFAULT_RATE);
+ if (setparams) {
+ if (sc->mode.rate > 0)
+ sc->mode.rate = set_mouse_sampling_rate(ioport, sc->mode.rate);
+ if (sc->mode.resolution > 0)
sc->mode.resolution =
- set_mouse_resolution(ioport, PSMD_DEFAULT_RESOLUTION);
+ set_mouse_resolution(ioport, sc->mode.resolution);
+ }
+ /* FIXME:XXX I don't know if these parameters are reasonable */
set_mouse_scaling(ioport); /* 1:1 scaling */
set_mouse_mode(ioport); /* stream mode */
@@ -616,9 +720,19 @@ psmprobe(struct isa_device *dvp)
* the course of its operation (this is the case with `syscons'). If
* not,...
*/
+ if (!set_controller_command_byte(ioport,
+ sc->command_byte & ~KBD_AUX_CONTROL_BITS,
+ KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ /*
+ * this is CONTROLLER ERROR; I don't know the proper way to
+ * recover from this error...
+ */
+ restore_controller(ioport, sc->command_byte);
+ printf("psm%d: unable to set the command byte.\n", unit);
+ free(sc, M_DEVBUF);
+ endprobe(0);
+ }
sc->command_byte &= ~KBD_AUX_CONTROL_BITS;
- set_controller_command_byte(ioport, sc->command_byte,
- KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
/* done */
psm_softc[unit] = sc;
@@ -673,6 +787,7 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
/* Get device data */
sc = psm_softc[unit];
if ((sc->state & PSM_VALID) == 0)
+ /* the device is no longer valid/functioning */
return (ENXIO);
ioport = sc->addr;
@@ -681,7 +796,6 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
return (EBUSY);
/* Initialize state */
- sc->state |= PSM_OPEN;
sc->rsel.si_flags = 0;
sc->rsel.si_pid = 0;
@@ -697,29 +811,64 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
sc->outputhead = 0;
/* enable the aux port and temporalily disable the keyboard */
- write_controller_command(ioport, KBDC_DISABLE_KBD_PORT);
- set_controller_command_byte(ioport,
+ if (!set_controller_command_byte(ioport,
sc->command_byte & ~KBD_KBD_CONTROL_BITS,
KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
- | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ /* CONTROLLER ERROR; do you know how to get out of this? */
+ set_controller_command_byte(ioport,
+ sc->command_byte, KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n",
+ unit);
+ return (EIO);
+ }
/* enable the mouse device */
if (!enable_aux_dev(ioport)) {
- set_controller_command_byte(ioport, sc->command_byte,
- KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
- log(LOG_ERR, "psm%d: unable to enable the pointing device.\n", unit);
+ /* MOUSE ERROR: failed to enable the mouse because:
+ * 1) the mouse is faulty,
+ * 2) the mouse has been removed(!?)
+ * In the latter case, the keyboard may have hung, and need
+ * recovery procedure...
+ */
+ recover_from_error(ioport);
+#if 0
+ /* FIXME: we could reset the mouse here and try to enable
+ * it again. But it will take long time and it's not a good
+ * idea to disable the keyboard that long...
+ */
+ if (!reinitialize(dev, &sc->mode) || !enable_aux_dev(ioport))
+ recover_from_error(ioport);
+#endif
+ set_controller_command_byte(ioport,
+ sc->command_byte, KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ /* mark this device is no longer available */
+ sc->state &= ~PSM_VALID;
+ log(LOG_ERR, "psm%d: failed to enable the device (psmopen).\n",
+ unit);
return (EIO);
}
+
if (verbose >= 2) {
get_mouse_status(ioport, stat);
log(LOG_DEBUG, "psm%d: status %02x %02x %02x\n",
unit, stat[0], stat[1], stat[2]);
}
+
/* enable the aux port and interrupt */
+ if (!set_controller_command_byte(ioport, sc->command_byte,
+ KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
+ /* CONTROLLER ERROR */
+ disable_aux_dev(ioport);
set_controller_command_byte(ioport, sc->command_byte,
- KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT);
+ KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ log(LOG_ERR, "psm%d: failed to enable the aux interrupt (psmopen).\n",
+ unit);
+ return (EIO);
+ }
/* done */
+ sc->state |= PSM_OPEN;
return (0);
}
@@ -730,46 +879,65 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
int ioport = sc->addr;
/* disable the aux interrupt */
- set_controller_command_byte(ioport, sc->command_byte,
- KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ if (!set_controller_command_byte(ioport, sc->command_byte,
+ KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n",
+ PSM_UNIT(dev));
+ /* CONTROLLER ERROR;
+ * NOTE: we shall force our way through. Because the only
+ * ill effect we shall see is that we may not be able
+ * to read ACK from the mouse, and it doesn't matter much
+ * so long as the mouse will accept the DISABLE command.
+ */
+ }
/* remove anything left in the output buffer */
- empty_aux_buffer(ioport);
+ empty_aux_buffer(ioport, 20);
/* disable the aux device, port and interrupt */
- disable_aux_dev(ioport);
- set_controller_command_byte(ioport, sc->command_byte,
- KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ if (!disable_aux_dev(ioport)) {
+ /* MOUSE ERROR;
+ * NOTE: we don't return error and continue, pretending
+ * we have successfully disabled the device. It's OK because
+ * the interrupt routine will discard any data from the mouse
+ * hereafter.
+ */
+ log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
+ PSM_UNIT(dev));
+ }
+ if (!set_controller_command_byte(ioport, sc->command_byte,
+ KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ /* CONTROLLER ERROR;
+ * we shall ignore this error; see the above comment.
+ */
+ log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
+ PSM_UNIT(dev));
+ }
/* remove anything left in the output buffer */
- empty_aux_buffer(ioport);
-
- /* Complete the close */
- sc->state &= ~PSM_OPEN;
+ empty_aux_buffer(ioport, 10);
/* close is almost always successful */
+ sc->state &= ~PSM_OPEN;
return (0);
}
+#ifdef PSM_EMULATION
static int
mkms(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
{
static int butmap[] = {
- 0,
- MOUSE_MSS_BUTTON3DOWN, MOUSE_MSS_BUTTON2DOWN,
- MOUSE_MSS_BUTTON3DOWN | MOUSE_MSS_BUTTON2DOWN,
- MOUSE_MSS_BUTTON1DOWN,
- MOUSE_MSS_BUTTON3DOWN | MOUSE_MSS_BUTTON1DOWN,
- MOUSE_MSS_BUTTON2DOWN | MOUSE_MSS_BUTTON1DOWN,
- MOUSE_MSS_BUTTON3DOWN | MOUSE_MSS_BUTTON2DOWN | MOUSE_MSS_BUTTON1DOWN,
+ 0, MOUSE_MSS_BUTTON1DOWN,
+ 0, MOUSE_MSS_BUTTON1DOWN ,
+ MOUSE_MSS_BUTTON3DOWN, MOUSE_MSS_BUTTON1DOWN | MOUSE_MSS_BUTTON3DOWN,
+ MOUSE_MSS_BUTTON3DOWN, MOUSE_MSS_BUTTON1DOWN | MOUSE_MSS_BUTTON3DOWN,
};
unsigned char delta;
if (maxlen - *len < MOUSE_MSS_PACKETSIZE)
return FALSE;
- buf[0] = MOUSE_MSS_SYNC;
- buf[0] |= butmap[status->button & BUTSTATMASK];
+ buf[0] = MOUSE_MSS_SYNC | butmap[status->button & MOUSE_STDBUTTONS];
if (status->dx < -128)
delta = 0x80; /* -128 */
@@ -797,24 +965,23 @@ mkms(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
}
static int
-mkmsc(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
+mkman(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
{
static int butmap[] = {
- 0,
- MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON2UP,
- MOUSE_MSC_BUTTON3UP | MOUSE_MSC_BUTTON2UP,
- MOUSE_MSC_BUTTON1UP,
- MOUSE_MSC_BUTTON3UP | MOUSE_MSC_BUTTON1UP,
- MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON1UP,
- MOUSE_MSC_BUTTON3UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON1UP,
+ 0, MOUSE_MSS_BUTTON1DOWN,
+ 0, MOUSE_MSS_BUTTON1DOWN,
+ MOUSE_MSS_BUTTON3DOWN, MOUSE_MSS_BUTTON1DOWN | MOUSE_MSS_BUTTON3DOWN,
+ MOUSE_MSS_BUTTON3DOWN, MOUSE_MSS_BUTTON1DOWN | MOUSE_MSS_BUTTON3DOWN,
};
unsigned char delta;
+ int l;
- if (maxlen - *len < MOUSE_PS2_PACKETSIZE)
+ l = ((status->button ^ status->obutton) & MOUSE_BUTTON2DOWN) ?
+ MOUSE_MSS_PACKETSIZE + 1: MOUSE_MSS_PACKETSIZE;
+ if (maxlen - *len < l)
return FALSE;
- buf[0] = MOUSE_MSC_SYNC;
- buf[0] |= ~butmap[status->button & BUTSTATMASK] & MOUSE_MSC_BUTTONS;
+ buf[0] = MOUSE_MSS_SYNC | butmap[status->button & MOUSE_STDBUTTONS];
if (status->dx < -128)
delta = 0x80; /* -128 */
@@ -823,8 +990,8 @@ mkmsc(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
delta = 0x7f; /* 127 */
else
delta = (unsigned char) status->dx;
- buf[1] = delta >> 2;
- buf[3] = delta - buf[1];
+ buf[0] |= (delta & 0xc0) >> 6; /* bit 6-7 */
+ buf[1] = delta & 0x3f; /* bit 0-5 */
if (status->dy < -128)
delta = 0x80; /* -128 */
@@ -833,7 +1000,59 @@ mkmsc(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
delta = 0x7f; /* 127 */
else
delta = (unsigned char) status->dy;
- buf[2] = delta >> 2;
+ buf[0] |= (delta & 0xc0) >> 4; /* bit 6-7 */
+ buf[2] = delta & 0x3f; /* bit 0-5 */
+
+ if (l > MOUSE_MSS_PACKETSIZE)
+ buf[3] = (status->button & MOUSE_BUTTON2DOWN)
+ ? MOUSE_LMAN_BUTTON2DOWN : 0;
+
+ *len += l;
+
+ return TRUE;
+}
+
+static int
+mkmsc(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
+{
+ static int butmap[] = {
+ 0,
+ MOUSE_MSC_BUTTON1UP, MOUSE_MSC_BUTTON2UP,
+ MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
+ MOUSE_MSC_BUTTON3UP,
+ MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
+ MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
+ MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
+ };
+ register int delta;
+
+ if (maxlen - *len < MOUSE_MSC_PACKETSIZE)
+ return FALSE;
+
+ buf[0] = MOUSE_MSC_SYNC
+ | (~butmap[status->button & MOUSE_STDBUTTONS] & MOUSE_MSC_BUTTONS);
+
+ /* data bytes cannot be between 80h (-128) and 87h (-120).
+ * values we can return is 255 (0ffh) through -251 (10fh = 87h*2 + 1).
+ */
+ if (status->dx < -251)
+ delta = -251;
+ else
+ if (status->dx > 255)
+ delta = 255;
+ else
+ delta = status->dx;
+ buf[1] = delta/2;
+ buf[3] = delta - buf[1];
+
+ if (status->dy < -251)
+ delta = -251;
+ else
+ if (status->dy > 255)
+ delta = 255;
+ else
+ delta = status->dy;
+ buf[2] = delta/2;
buf[4] = delta - buf[2];
*len += MOUSE_MSC_PACKETSIZE;
@@ -842,24 +1061,59 @@ mkmsc(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
}
static int
+mkmm(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
+{
+ static int butmap[] = {
+ 0,
+ MOUSE_MM_BUTTON1DOWN, MOUSE_MM_BUTTON2DOWN,
+ MOUSE_MM_BUTTON1DOWN | MOUSE_MM_BUTTON2DOWN,
+ MOUSE_MM_BUTTON3DOWN,
+ MOUSE_MM_BUTTON1DOWN | MOUSE_MM_BUTTON3DOWN,
+ MOUSE_MM_BUTTON2DOWN | MOUSE_MM_BUTTON3DOWN,
+ MOUSE_MM_BUTTON1DOWN | MOUSE_MM_BUTTON2DOWN | MOUSE_MM_BUTTON3DOWN,
+ };
+ int delta;
+
+ if (maxlen - *len < MOUSE_MM_PACKETSIZE)
+ return FALSE;
+
+ buf[0] = MOUSE_MM_SYNC
+ | butmap[status->button & MOUSE_STDBUTTONS]
+ | ((status->dx > 0) ? MOUSE_MM_XPOSITIVE : 0)
+ | ((status->dy > 0) ? MOUSE_MM_YPOSITIVE : 0);
+
+ delta = (status->dx < 0) ? -status->dx : status->dx;
+ buf[1] = min(delta, 127);
+ delta = (status->dy < 0) ? -status->dy : status->dy;
+ buf[2] = min(delta, 127);
+
+ *len += MOUSE_MM_PACKETSIZE;
+
+ return TRUE;
+}
+#endif /* PSM_EMULATION */
+
+static int
mkps2(unsigned char *buf, int *len, int maxlen, register mousestatus_t *status)
{
static int butmap[] = {
0,
- MOUSE_PS2_BUTTON3DOWN, MOUSE_PS2_BUTTON2DOWN,
- MOUSE_PS2_BUTTON3DOWN | MOUSE_PS2_BUTTON2DOWN,
- MOUSE_PS2_BUTTON1DOWN,
- MOUSE_PS2_BUTTON3DOWN | MOUSE_PS2_BUTTON1DOWN,
- MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON1DOWN,
- MOUSE_PS2_BUTTON3DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON1DOWN,
+ MOUSE_PS2_BUTTON1DOWN, MOUSE_PS2_BUTTON2DOWN,
+ MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
+ MOUSE_PS2_BUTTON3DOWN,
+ MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
+ MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
+ MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
};
register int delta;
if (maxlen - *len < MOUSE_PS2_PACKETSIZE)
return FALSE;
- buf[0] = MOUSE_PS2_SYNC;
- buf[0] |= butmap[status->button & BUTSTATMASK];
+ buf[0] = ((status->button & MOUSE_BUTTON4DOWN) ? 0 : MOUSE_PS2_BUTTON4UP)
+ | butmap[status->button & MOUSE_STDBUTTONS];
+ if ((verbose >= 2) && ((buf[0] & MOUSE_PS2_BUTTON4UP) == 0))
+ log(LOG_DEBUG, "psm: button 4 down (%04x) (mkps2)\n", buf[0]);
if (status->dx < -128)
delta = -128;
@@ -906,14 +1160,14 @@ psmread(dev_t dev, struct uio *uio, int flag)
return (EWOULDBLOCK);
}
sc->state |= PSM_ASLP;
- error = tsleep((caddr_t) sc, PZERO | PCATCH,
- "psmread", 0);
+ error = tsleep((caddr_t) sc, PZERO | PCATCH, "psmread", 0);
if (error) {
splx(s);
return (error);
}
}
}
+
if (sc->outputbytes >= uio->uio_resid) {
/* nothing to be done */
} else {
@@ -949,8 +1203,8 @@ static int
psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
struct psm_softc *sc = psm_softc[PSM_UNIT(dev)];
- mouseinfo_t info;
- mousestatus_t *ms;
+ mousemode_t mode;
+ mousestatus_t status;
packetfunc_t func;
int error = 0;
int s;
@@ -967,22 +1221,35 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
break;
case MOUSE_SETMODE:
- if (((mousemode_t *) addr)->rate < 0) {
- error = EINVAL;
- break;
+ mode = *(mousemode_t *) addr;
+ if (mode.rate == 0) {
+ mode.rate = PSMD_DEFAULT_RATE;
+ } else if (mode.rate > 0) {
+ mode.rate = min(mode.rate, PSMD_MAX_RATE);
+ } else { /* mode.rate < 0 */
+ mode.rate = sc->mode.rate;
+ }
+ if (mode.resolution == 0) {
+ mode.resolution = PSMD_DEFAULT_RESOLUTION;
+ } else if (mode.resolution > 0) {
+ mode.resolution = mode.resolution;
+ } else { /* mode.resolution < 0 */
+ mode.resolution = sc->mode.resolution;
}
- if (((mousemode_t *) addr)->resolution < 0) {
- error = EINVAL;
- break;
- }
-#ifndef PSM_NOEMULATION
- switch (((mousemode_t *) addr)->protocol) {
+#ifdef PSM_EMULATION
+ switch (mode.protocol) {
case MOUSE_PROTO_MS:
func = mkms;
break;
+ case MOUSE_PROTO_LOGIMOUSEMAN:
+ func = mkman;
+ break;
case MOUSE_PROTO_MSC:
func = mkmsc;
break;
+ case MOUSE_PROTO_MM:
+ func = mkmm;
+ break;
case MOUSE_PROTO_PS2:
func = mkps2;
break;
@@ -993,42 +1260,59 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
}
if (error)
break;
-#endif /* PSM_NOEMULATION */
- if (((mousemode_t *) addr)->accelfactor < 0) {
+#else
+ mode.protocol = sc->mode.protocol;
+#endif /* PSM_EMULATION */
+ if (mode.accelfactor < 0) {
error = EINVAL;
break;
}
+
s = spltty(); /* disable interrupt while updating */
- sc->mode.rate = (((mousemode_t *) addr)->rate == 0) ?
- PSMD_DEFAULT_RATE :
- min(((mousemode_t *) addr)->rate, PSMD_MAX_RATE);
- sc->mode.resolution = (((mousemode_t *) addr)->resolution == 0) ?
- PSMD_DEFAULT_RESOLUTION :
- ((mousemode_t *) addr)->resolution;
/* temporalily disable the keyboard */
- write_controller_command(sc->addr, KBDC_DISABLE_KBD_PORT);
- set_controller_command_byte(sc->addr,
+ if (!set_controller_command_byte(sc->addr,
sc->command_byte & ~KBD_KBD_CONTROL_BITS,
KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
- | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+ | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ /* this is CONTROLLER ERROR; I don't know how to recover
+ * from this error. The least we can do is to send
+ * ENABLE_KBD_PORT...
+ */
+ write_controller_command(sc->addr, KBDC_ENABLE_KBD_PORT);
+ splx(s);
+ log(LOG_ERR, "psm%d: failed to set the command byte (psmioctl).\n",
+ PSM_UNIT(dev));
+ error = EIO;
+ break;
+ }
/* program the mouse */
- sc->mode.rate = set_mouse_sampling_rate(sc->addr, sc->mode.rate);
- sc->mode.resolution =
- set_mouse_resolution(sc->addr, sc->mode.resolution);
+ if (mode.rate > 0)
+ mode.rate = set_mouse_sampling_rate(sc->addr, mode.rate);
+ if (mode.resolution > 0)
+ mode.resolution = set_mouse_resolution(sc->addr, mode.resolution);
/* enable the aux port and interrupt */
- set_controller_command_byte(sc->addr, sc->command_byte,
- KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT);
-
-#ifndef PSM_NOEMULATION
- sc->mode.protocol = ((mousemode_t *) addr)->protocol;
+ if (!set_controller_command_byte(sc->addr, sc->command_byte,
+ KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
+ /* CONTROLLER ERROR; this is serious, we may have
+ * been left with the unaccessible keyboard and
+ * the disabled mouse interrupt.
+ */
+ splx(s);
+ log(LOG_ERR, "psm%d: failed to re-enable the aux port and int (psmioctl).\n",
+ PSM_UNIT(dev));
+ error = EIO;
+ break;
+ }
+
+ sc->mode = mode;
+#ifdef PSM_EMULATION
sc->mkpacket = func;
sc->outputbytes = 0;
sc->outputhead = 0;
-#endif /* PSM_NOEMULATION */
- sc->mode.accelfactor = ((mousemode_t *) addr)->accelfactor;
+#endif /* PSM_EMULATION */
splx(s);
break;
@@ -1038,30 +1322,18 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
break;
case MOUSE_GETSTATE:
- info.status = 0;
- info.xmotion = 0;
- info.ymotion = 0;
-
s = spltty();
if (sc->queue.count > 0) {
- ms = &sc->queue.buf[sc->queue.head];
-
- /* button status */
- info.status = ms->button; /* BUT?STAT bits */
- info.status |= /* BUT?CHNG bits */
- ((ms->button ^ ms->obutton) << 3);
- /* mouse motion */
- info.xmotion = ms->dx;
- info.ymotion = ms->dy;
- if ((info.xmotion != 0) || (info.ymotion != 0))
- info.status |= MOVEMENT;
-
+ status = sc->queue.buf[sc->queue.head];
sc->queue.head = (sc->queue.head + 1) % PSM_BUFSIZE;
--sc->queue.count;
+ } else {
+ status.button = status.obutton = sc->button;
+ status.dx = status.dy = 0;
}
splx(s);
- *(mouseinfo_t *) addr = info;
+ *(mousestatus_t *) addr = status;
break;
default:
@@ -1078,12 +1350,16 @@ psmintr(int unit)
{
/*
* the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
- * into `mouseinfo' button bits (BUT?STAT).
+ * into `mousestatus' button bits (BUTTON?DOWN).
*/
static butmap[8] = {
- 0, BUT1STAT, BUT3STAT, BUT1STAT | BUT3STAT,
- BUT2STAT, BUT1STAT | BUT2STAT, BUT2STAT | BUT3STAT,
- BUT1STAT | BUT2STAT | BUT3STAT
+ 0,
+ MOUSE_BUTTON1DOWN, MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
};
register struct psm_softc *sc = psm_softc[unit];
int ioport = sc->addr;
@@ -1095,6 +1371,7 @@ psmintr(int unit)
if ((inb(ioport + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
!= KBDS_AUX_BUFFER_FULL)
return;
+ DELAY(7);
/* read a byte */
c = inb(ioport + KBD_DATA_PORT);
@@ -1103,8 +1380,9 @@ psmintr(int unit)
if ((sc->state & PSM_OPEN) == 0)
return;
+ /* interpret data bytes */
/*
- * interpret data bytes FIXME: there seems no way to reliably
+ * FIXME: there seems no way to reliably
* re-synchronize with the PS/2 mouse once we are out of sync. Sure,
* there is sync bits in the first data byte, but the second and the
* third bytes may have these bits on (they are not functioning as
@@ -1113,10 +1391,14 @@ psmintr(int unit)
* without moving the mouse?)
*/
if (sc->inputbytes == 0) {
-#ifndef PSM_NOCHECKSYNC
+#ifdef PSM_CHECKSYNC
if ((c & MOUSE_PS2_SYNCMASK) == MOUSE_PS2_SYNC)
-#endif /* PSM_NOCHECKSYNC */
sc->ipacket[sc->inputbytes++] = c;
+ else
+ log(LOG_DEBUG, "psmintr: sync. bit is off.\n");
+#else
+ sc->ipacket[sc->inputbytes++] = c;
+#endif /* PSM_CHECKSYNC */
} else {
sc->ipacket[sc->inputbytes++] = c;
if (sc->inputbytes >= MOUSE_PS2_PACKETSIZE) {
@@ -1163,7 +1445,15 @@ psmintr(int unit)
ms->dy = y;
ms->obutton = sc->button; /* previous button state */
sc->button = ms->button = /* latest button state */
- butmap[sc->ipacket[0] & MOUSE_PS2_BUTTONS];
+ butmap[sc->ipacket[0] & MOUSE_PS2_BUTTONS]
+ | ((sc->ipacket[0] & MOUSE_PS2_BUTTON4UP)
+ ? 0 : MOUSE_BUTTON4DOWN);
+#if 0
+ if ((verbose >= 2)
+ && ((sc->ipacket[0] & MOUSE_PS2_BUTTON4UP) == 0))
+ log(LOG_DEBUG, "psm%d: button 4 down (%04x) (psmintr)\n",
+ unit, sc->ipacket[0]);
+#endif
sc->queue.tail =
(sc->queue.tail + 1) % PSM_BUFSIZE;
++sc->queue.count;
diff --git a/sys/i386/isa/syscons.c b/sys/i386/isa/syscons.c
index 8b9fff1..691460a 100644
--- a/sys/i386/isa/syscons.c
+++ b/sys/i386/isa/syscons.c
@@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: syscons.c,v 1.188 1996/11/15 08:45:24 sos Exp $
+ * $Id: syscons.c,v 1.189 1996/11/19 17:08:10 nate Exp $
*/
#include "sc.h"
@@ -298,31 +298,47 @@ scprobe(struct isa_device *dev)
sc_port = dev->id_iobase;
+ /* discard anything left after UserConfig */
+ empty_both_buffers(sc_port, 10);
+
/* save the current keyboard controller command byte */
- write_controller_command(sc_port, KBDC_GET_COMMAND_BYTE);
+ c = -1;
+ if (!write_controller_command(sc_port, KBDC_GET_COMMAND_BYTE)) {
+ /* CONTROLLER ERROR */
+ printf("sc%d: unable to get the current command byte value.\n",
+ dev->id_unit);
+ goto fail;
+ }
c = read_controller_data(sc_port);
if (c == -1) {
+ /* CONTROLLER ERROR */
printf("sc%d: unable to get the current command byte value.\n",
dev->id_unit);
goto fail;
}
+#if 0
+ /* override the keyboard lock switch */
+ c |= KBD_OVERRIDE_KBD_LOCK;
+#endif
/*
* enable the keyboard port, but disable the keyboard intr.
* the aux port (mouse port) is disabled too.
*/
- write_controller_command(sc_port, KBDC_DISABLE_KBD_PORT);
- set_controller_command_byte(sc_port,
- c&~(KBD_KBD_CONTROL_BITS|KBD_AUX_CONTROL_BITS),
- KBD_ENABLE_KBD_PORT|KBD_DISABLE_KBD_INT
- |KBD_DISABLE_AUX_PORT|KBD_DISABLE_AUX_INT);
-
- /* flush any noise in the buffer */
- empty_both_buffers(sc_port);
+ if (!set_controller_command_byte(sc_port,
+ c & ~(KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS),
+ KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT
+ | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+ /* CONTROLLER ERROR
+ * there is very little we can do...
+ */
+ printf("sc%d: unable to set the command byte.\n", dev->id_unit);
+ goto fail;
+ }
/* reset keyboard hardware */
if (!reset_kbd(sc_port)) {
- /*
+ /* KEYBOARD ERROR
* Keyboard reset may fail either because the keyboard doen't exist,
* or because the keyboard doesn't pass the self-test, or the keyboard
* controller on the motherboard and the keyboard somehow fail to
@@ -331,15 +347,17 @@ scprobe(struct isa_device *dev)
* test_controller() and test_kbd_port() appear to bring the keyboard
* controller back (I don't know why and how, though.)
*/
+ empty_both_buffers(sc_port, 10);
test_controller(sc_port);
test_kbd_port(sc_port);
/* We could disable the keyboard port and interrupt... but,
- * the keyboard may still exist (see above). Just leave the command
- * byte as before.
+ * the keyboard may still exist (see above).
*/
- set_controller_command_byte(sc_port, c, 0);
+ if (bootverbose)
+ printf("sc%d: failed to reset the keyboard.\n", dev->id_unit);
goto fail;
}
+
/*
* Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
* such as those on the IBM ThinkPad laptop computers can be used
@@ -347,19 +365,36 @@ scprobe(struct isa_device *dev)
*/
if (dev->id_flags & XT_KEYBD) {
if (send_kbd_command_and_data(
- sc_port, KBDC_SET_SCAN_CODESET, 1) == KBD_ACK)
+ sc_port, KBDC_SET_SCAN_CODESET, 1) == KBD_ACK) {
/* XT kbd doesn't need scan code translation */
c &= ~KBD_TRANSLATION;
- wait_while_controller_busy(sc_port);
+ } else {
+ /* KEYBOARD ERROR
+ * The XT kbd isn't usable unless the proper scan code set
+ * is selected.
+ */
+ printf("sc%d: unable to set the XT keyboard mode.\n", dev->id_unit);
+ goto fail;
+ }
}
/* enable the keyboard port and intr. */
- set_controller_command_byte(sc_port, c & ~KBD_KBD_CONTROL_BITS,
- KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT);
+ if (!set_controller_command_byte(sc_port, c & ~KBD_KBD_CONTROL_BITS,
+ KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
+ /* CONTROLLER ERROR
+ * This is serious; we are left with the disabled keyboard intr.
+ */
+ printf("sc%d: unable to enable the keyboard port and intr.\n",
+ dev->id_unit);
+ goto fail;
+ }
succeed:
return (IO_KBDSIZE);
fail:
+ if (c != -1)
+ /* try to restore the command byte as before, if possible */
+ set_controller_command_byte(sc_port, c, 0);
return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
}
OpenPOWER on IntegriCloud