summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/psm.c
diff options
context:
space:
mode:
authornate <nate@FreeBSD.org>1996-11-15 05:30:52 +0000
committernate <nate@FreeBSD.org>1996-11-15 05:30:52 +0000
commita3d6bdf148f40fda392336a636828cebc02a2b41 (patch)
treef103fb2236ddb84b75db895ccd8beb12fa6c4f15 /sys/i386/isa/psm.c
parent99126ea5a0d2856a36ea492de2c9aafed82d7d40 (diff)
downloadFreeBSD-src-a3d6bdf148f40fda392336a636828cebc02a2b41.zip
FreeBSD-src-a3d6bdf148f40fda392336a636828cebc02a2b41.tar.gz
New PS/2 mouse drive which uses the new 'shared' keyboard/psm read
routines. An older version of this was tested successfully on all of my systems with PS/2 mice. This was brought in without testing because it is necessary due to the previously committed syscons changes. Submitted by: Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
Diffstat (limited to 'sys/i386/isa/psm.c')
-rw-r--r--sys/i386/isa/psm.c1252
1 files changed, 998 insertions, 254 deletions
diff --git a/sys/i386/isa/psm.c b/sys/i386/isa/psm.c
index 536046f..30b301d 100644
--- a/sys/i386/isa/psm.c
+++ b/sys/i386/isa/psm.c
@@ -18,6 +18,8 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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$
*/
/*
@@ -43,189 +45,629 @@
*
* Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
* - 24 October 1993
+ *
+ * Hardware access routines and probe logic rewritten by
+ * Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
+ * - 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'.
*/
#include "psm.h"
#if NPSM > 0
+#include <limits.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/conf.h>
+#include <sys/syslog.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /*DEVFS*/
+/*
#include <machine/mouse.h>
#include <machine/clock.h>
+*/
+#include <i386/include/mouse.h>
+#include <i386/include/clock.h>
+#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
+#include <i386/isa/kbdio.h>
+
+/* driver specific options: the following options may be set by
+ `options' statements in the kernel configuration file. */
+
+/* debugging */
+#ifndef PSM_DEBUG
+#define PSM_DEBUG 2 /* controls debug logging:
+ 0: no logging, 1: brief, 2: verbose */
+#endif
+
+/* version dependency */
+#define PSM_CURRENT /* compiles for FreeBSD-current, if defined.
+ otherwise, compiles for FreeBSD 2.1.x. */
+
+/* features */
+/* #define PSM_NOCHECKSYNC the driver does not check the header data
+ byte, if defined */
+
+#ifndef PSM_ACCEL
+#define PSM_ACCEL 2 /* the default acceleration factor, must
+ be one or greater; acceleration will be
+ disabled if zero */
+#endif
+
+/* #define PSM_NOEMULATION disables protocol emulation */
+
+/* end of driver specific options */
+
+/* default values */
+#define PSMD_DEFAULT_RESOLUTION 800 /* resolution: 800 ppi */
+#define PSMD_DEFAULT_RATE 100 /* report rate: 100 Hz */
+
+/* misc */
+#define TRUE (-1)
+#define FALSE 0
-#define PSM_DATA 0x00 /* Offset for data port, read-write */
-#define PSM_CNTRL 0x04 /* Offset for control port, write-only */
-#define PSM_STATUS 0x04 /* Offset for status port, read-only */
-
-/* status bits */
-#define PSM_OUTPUT_ACK 0x02 /* output acknowledge */
-
-/* controller commands */
-#define PSM_INT_ENABLE 0x47 /* enable controller interrupts */
-#define PSM_INT_DISABLE 0x65 /* disable controller interrupts */
-#define PSM_DISABLE 0xa7 /* disable auxiliary port */
-#define PSM_ENABLE 0xa8 /* enable auxiliary port */
-#define PSM_AUX_TEST 0xa9 /* test auxiliary port */
-
-/* mouse commands */
-#define PSM_SET_SCALE11 0xe6 /* set 1:1 scaling */
-#define PSM_SET_SCALE21 0xe7 /* set 2:1 scaling */
-#define PSM_SET_RES 0xe8 /* set resolution */
-#define PSM_GET_SCALE 0xe9 /* set scaling factor */
-#define PSM_SET_STREAM 0xea /* set streaming mode */
-#define PSM_SET_SAMPLE 0xf3 /* set sampling rate */
-#define PSM_DEV_ENABLE 0xf4 /* mouse on */
-#define PSM_DEV_DISABLE 0xf5 /* mouse off */
-#define PSM_RESET 0xff /* reset */
-
-#define PSMUNIT(dev) (minor(dev) >> 1)
+/* some macros */
+#define PSM_UNIT(dev) (minor(dev) >> 1)
+#define PSM_NBLOCKIO(dev) (minor(dev) & 1)
+#define PSM_MKMINOR(unit,block) (((unit) << 1) | ((block) ? 0:1))
+
+#ifndef max
+#define max(x,y) ((x) > (y) ? (x) : (y))
+#endif
#ifndef min
-#define min(x,y) (x < y ? x : y)
-#endif min
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#endif
-static int psmprobe(struct isa_device *);
-static int psmattach(struct isa_device *);
-static void psm_poll_status(int);
+/* mouse status block */
-static int psmaddr[NPSM]; /* Base I/O port addresses per unit */
+typedef struct mousestatus {
+ int button; /* button status */
+ int obutton; /* previous button status */
+ int dx; /* x movement */
+ int dy; /* y movement */
+} mousestatus_t;
-#define PSM_CHUNK 128 /* chunk size for read */
-#define PSM_BSIZE 1024 /* buffer size */
+/* ring buffer */
-struct ringbuf {
- int count, first, last;
- char queue[PSM_BSIZE];
-};
+#define PSM_BUFSIZE 256
+
+typedef struct ringbuf {
+ int count;
+ int head;
+ int tail;
+ mousestatus_t buf[PSM_BUFSIZE];
+} ringbuf_t;
+
+/* driver control block */
+
+typedef int (*packetfunc_t) __P((unsigned char *,int *,int,mousestatus_t *));
static struct psm_softc { /* Driver status information */
- struct ringbuf inq; /* Input queue */
- struct selinfo rsel; /* Process selecting for Input */
+ struct selinfo rsel; /* Process selecting for Input */
unsigned char state; /* Mouse driver state */
- unsigned char status; /* Mouse button status */
- unsigned char button; /* Previous mouse button status bits */
- int x, y; /* accumulated motion in the X,Y axis */
+ int addr; /* I/O port address */
+ int command_byte; /* controller command byte */
+ mousehw_t hw; /* hardware information */
+ mousemode_t mode; /* operation mode */
+ ringbuf_t queue; /* mouse status queue */
+ packetfunc_t mkpacket; /* func. to turn queued data
+ into output format */
+ char ipacket[MOUSE_PS2_PACKETSIZE]; /* interim input buffer */
+ unsigned char opacket[PSM_BUFSIZE]; /* output buffer */
+ int inputbytes; /* # of bytes in the input buffer */
+ int outputbytes; /* # of bytes in the output buffer */
+ int outputhead; /* points the head of the output buffer */
+ int button; /* the latest button state */
#ifdef DEVFS
void *devfs_token;
void *n_devfs_token;
#endif
} psm_softc[NPSM];
-#define PSM_OPEN 1 /* Device is open */
-#define PSM_ASLP 2 /* Waiting for mouse data */
+/* driver state flags (state) */
+#define PSM_VALID 0x80
+#define PSM_OPEN 1 /* Device is open */
+#define PSM_ASLP 2 /* Waiting for mouse data */
+
+/* function prototypes */
+
+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 mkmsc __P((unsigned char *,int *,int,mousestatus_t *));
+static int mkps2 __P((unsigned char *,int *,int,mousestatus_t *));
+
+#ifdef PSM_CURRENT
+static d_open_t psmopen;
+static d_close_t psmclose;
+static d_read_t psmread;
+static d_ioctl_t psmioctl;
+static d_select_t psmselect;
+#endif /* PSM_CURRENT */
+
+/* device driver declarateion */
+
+struct isa_driver psmdriver = { psmprobe, psmattach, "psm", FALSE };
+
+#ifdef PSM_CURRENT
+#define CDEV_MAJOR 21
+
+static struct cdevsw psm_cdevsw = {
+ psmopen, psmclose, psmread, nowrite, /* 21 */
+ psmioctl, nostop, nullreset, nodevtotty,
+ psmselect, nommap, NULL, "psm", NULL, -1
+};
+#endif /* PSM_CURRENT */
+
+/* debug message level */
+
+extern int bootverbose; /* `-v' option at `boot:' prompt */
+static int verbose = PSM_DEBUG;
+
+/* device I/O routines */
+
+static int
+enable_aux_dev(int port)
+{
+ int res;
+
+ res = send_aux_command(port,PSMC_ENABLE_DEV);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: ENABLE_DEV return code:%04x\n",res);
+
+ return (res == PSM_ACK);
+}
+
+static int
+disable_aux_dev(int port)
+{
+ int res;
+
+ res = send_aux_command(port,PSMC_DISABLE_DEV);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: DISABLE_DEV return code:%04x\n",res);
+
+ return (res == PSM_ACK);
+}
+
+static int
+get_mouse_status(int port,int *status)
+{
+ int res;
+
+ empty_both_buffers(port);
+ res = send_aux_command(port,PSMC_SEND_DEV_STATUS);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: SEND_AUX_STATUS return code:%04x\n",res);
+ if (res != PSM_ACK)
+ return FALSE;
+
+ status[0] = read_aux_data(port);
+ status[1] = read_aux_data(port);
+ status[2] = read_aux_data(port);
+
+ return TRUE;
+}
+
+static int
+get_aux_id(int port)
+{
+ int retry;
+ int id;
+ int c;
+
+ for(retry = KBD_MAXRETRY; retry > 0; --retry) {
+ empty_both_buffers(port);
+ write_aux_command(port,PSMC_SEND_DEV_ID);
+ /* 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)
+ log(LOG_DEBUG,"psm: device ID: %04x\n",id);
+
+ return id;
+}
+
+static int
+set_mouse_sampling_rate(int port,int rate)
+{
+ int res;
-struct isa_driver psmdriver = { psmprobe, psmattach, "psm" };
+ res = send_aux_command_and_data(port,PSMC_SET_SAMPLING_RATE,rate);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: SET_SAMPLING_RATE (%d) %04x\n",rate,res);
+
+ return ((res == PSM_ACK) ? rate : -1);
+}
+
+static int
+set_mouse_scaling(int port)
+{
+ int res;
-static d_open_t psmopen;
-static d_close_t psmclose;
-static d_read_t psmread;
-static d_ioctl_t psmioctl;
-static d_select_t psmselect;
+ res = send_aux_command(port,PSMC_SET_SCALING11);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: SET_SCALING11 return code:%04x\n",res);
-#define CDEV_MAJOR 21
-static struct cdevsw psm_cdevsw =
- { psmopen, psmclose, psmread, nowrite, /*21*/
- psmioctl, nostop, nullreset, nodevtotty,
- psmselect, nommap, NULL, "psm", NULL, -1 };
+ return (res == PSM_ACK);
+}
+
+static int
+set_mouse_resolution(int port,int res)
+{
+ static struct {
+ int resolution;
+ int code;
+ } rescode[] = {
+ { 25, PSMD_RESOLUTION_25 },
+ { 50, PSMD_RESOLUTION_50 },
+ { 100, PSMD_RESOLUTION_100 },
+ { 200, PSMD_RESOLUTION_200 },
+ { 400, PSMD_RESOLUTION_400 }, /* ?? */
+ { 800, PSMD_RESOLUTION_800 }, /* ?? */
+ { INT_MAX, PSMD_MAX_RESOLUTION },
+ };
+ int ret;
+ int i;
+
+ if (res <= 0)
+ return FALSE;
+ for(i = 0; rescode[i].resolution > 0; ++i) {
+ if (rescode[i].resolution >= res)
+ break;
+ }
+
+ for(; i >= 0; --i) {
+ ret = send_aux_command_and_data(port,
+ PSMC_SET_RESOLUTION,rescode[i].code);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: SET_RESOLUTION (%d) %04x\n",
+ rescode[i].code,ret);
+ if (ret == PSM_ACK)
+ return rescode[i].resolution;
+ }
+
+ return (-1);
+}
+
+/* NOTE: once `set_mouse_mode()' is called, the mouse device must be
+ re-enabled by calling `enable_aux_dev()' */
+static int
+set_mouse_mode(int port)
+{
+ int res;
+
+ res = send_aux_command(port,PSMC_SET_STREAM_MODE);
+ if (verbose >= 2)
+ log(LOG_DEBUG,"psm: SET_STREAM_MODE return code:%04x\n",res);
+
+ return (res == PSM_ACK);
+}
+
+static int
+get_mouse_buttons(int port)
+{
+ int c = 2; /* assume two buttons by default */
+ int status[3];
+
+ /* NOTE: a special sequence to obtain Logitech-Mouse-specific
+ information: set resolution to 25 ppi, set scaling to 1:1,
+ set 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))
+ return c;
+ if (set_mouse_scaling(port) && set_mouse_scaling(port)
+ && set_mouse_scaling(port) && get_mouse_status(port,status)) {
+ if (verbose) {
+ log(LOG_DEBUG,"psm: status %02x %02x %02x (get_mouse_buttons)\n",
+ status[0],status[1],status[2]);
+ }
+ if (status[1] == 3)
+ return 3;
+ }
+ return c;
+}
+
+/* FIXME: someday, I will get the list of valid pointing devices and
+ their IDs... */
+static int
+is_a_mouse(int id)
+{
+ static int valid_ids[] = {
+ PSM_MOUSE_ID, /* mouse */
+ PSM_BALLPOINT_ID, /* ballpoint device */
+ -1 /* end of table */
+ };
+ /*
+ int i;
+
+ for(i = 0; valid_ids[i] >= 0; ++i) {
+ if (valid_ids[i] == id)
+ return TRUE;
+ }
+ return FALSE;
+ */
+ return TRUE;
+}
static void
-psm_write_dev(int ioport, u_char value)
+recover_from_error(int port)
{
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, 0xd4);
- psm_poll_status(ioport);
- outb(ioport+PSM_DATA, value);
+ /* discard anything left in the output buffer */
+ empty_both_buffers(port);
+
+ /* NOTE: KBDC_RESET_KBD may not restore the communication between
+ the keyboard and the controller. */
+ /* reset_kbd(port); */
+ /* NOTE: somehow diagnostic and keyboard port test commands bring
+ the keyboard back. */
+ test_controller(port);
+ test_kbd_port(port);
}
-static inline void
-psm_command(int ioport, u_char value)
+static void
+restore_controller(int port,int command_byte)
{
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, 0x60);
- psm_poll_status(ioport);
- outb(ioport+PSM_DATA, value);
+ set_controller_command_byte(port,command_byte,0);
}
-static int
+/* psm driver entry points */
+
+static int
psmprobe(struct isa_device *dvp)
{
- /* XXX: Needs a real probe routine. */
- int ioport, c, unit;
+ int unit = dvp->id_unit;
+ int ioport = dvp->id_iobase;
+ struct psm_softc *sc;
+ int stat[3];
+ int i;
- ioport=dvp->id_iobase;
- unit=dvp->id_unit;
+ /* validate unit number */
+ if (unit >= NPSM)
+ return (0);
-#ifndef PSM_NO_RESET
- psm_write_dev(ioport, PSM_RESET); /* Reset aux device */
-#endif
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, PSM_AUX_TEST);
- psm_poll_status(ioport);
-#if 0
- outb(ioport+PSM_CNTRL, 0xaa);
-#endif
- c = inb(ioport+PSM_DATA);
- if(c & 0x04) {
-/* printf("PS/2 AUX mouse is not found\n");*/
- psm_command(ioport, PSM_INT_DISABLE);
- psmaddr[unit] = 0; /* Device not found */
+ sc = &psm_softc[unit];
+ sc->addr = ioport;
+ if (bootverbose)
+ ++verbose;
+
+ /* FIXME: the keyboard interrupt should be disabled while
+ probing a mouse? */
+
+ /* NOTE: two bits in the command byte controls the operation of
+ the aux port (mouse port): the aux port disable bit (bit 5) and
+ the aux port interrupt (IRQ 12) enable bit (bit 2).
+ When this probe routine is called, there are following possibilities
+ about the presence of the aux port and the PS/2 mouse.
+
+ Case 1: aux port disabled (bit 5:1), aux int. disabled (bit 2:0)
+ The aux port most certainly exists. A device may or may not be
+ connected to the port. No driver is probably installed yet.
+
+ Case 2: aux port enabled (bit 5:0), aux int. disabled (bit 2:0)
+ Three possibile situations here:
+
+ Case 2a:
+ The aux port does not exist, therefore, is not explicitly disabled.
+ Case 2b:
+ The aux port exists. A device and a driver may exist,
+ using the device in the polling(remote) mode.
+ Case 2c:
+ The aux port exists. A device may exist, but someone who knows
+ nothing about the aux port has set the command byte this way
+ (this is the case with `syscons').
+
+ Case 3: aux port disabled (bit 5:1), aux int. enabled (bit 2:1)
+ The aux port exists, but someone is controlloing the device and
+ temporalily disabled the port.
+
+ Case 4: aux port enabled (bit 5:0), aux int. enabled (bit 2:1)
+ The aux port exists, a device is attached to the port, and
+ someone is controlling the device. Some BIOS set the bits this
+ way after boot.
+
+ All in all, it is no use examing the bits for detecting
+ the presence of the port and the mouse device.
+ */
+
+ /* save the current command byte; it will be used later */
+ write_controller_command(ioport,KBDC_GET_COMMAND_BYTE);
+ 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) {
+ printf("psm%d: unable to get the current command byte value.\n",
+ unit);
+ return (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),
+ KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
+ | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+
+ /* NOTE: `test_aux_port()' is designed to return with zero
+ if the aux port exists and is functioning. However, some
+ controllers appears to respond with zero even when the aux port
+ doesn't exist. (It may be that this is only the case when the
+ controller DOES have the aux port but the port is not wired
+ on the motherboard.) The keyboard controllers without the port,
+ such as the original AT, are supporsed to return with
+ an error code or simply time out. In any case, we have to
+ continue probing the port even when the controller passes
+ this test.
+ */
+ switch((i = test_aux_port(ioport))) {
+ case 0: /* no error */
+ break;
+ case -1: /* time out */
+ default: /* error */
+ recover_from_error(ioport);
+ restore_controller(ioport,sc->command_byte);
+ if (verbose)
+ printf("psm%d: the aux port is not functioning (%d).\n",
+ unit,i);
+ if (bootverbose)
+ --verbose;
return (0);
}
-/* printf("PS/2 AUX mouse found. Installing driver\n");*/
- return (4);
+
+ /* 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(ioport)) {
+ recover_from_error(ioport);
+ restore_controller(ioport,sc->command_byte);
+ if (verbose)
+ printf("psm%d: failed to reset the aux device.\n",unit);
+ return (0);
+ }
+
+ /* both the aux port and the aux device is functioning, see
+ if the device can be enabled.
+ NOTE: when enabled, the device will start sending data;
+ we shall immediately disable the device once we know
+ the device can be enabled. */
+ if (!enable_aux_dev(ioport) || !disable_aux_dev(ioport)) {
+ restore_controller(ioport,sc->command_byte);
+ if (verbose)
+ printf("psm%d: failed to enable the aux device.\n",unit);
+ if (bootverbose)
+ --verbose;
+ return (0);
+ }
+ empty_both_buffers(ioport); /* remove stray data if any */
+
+ /* hardware information */
+ sc->hw.iftype = MOUSE_IF_PS2;
+
+ /* verify the device is a mouse */
+ sc->hw.hwid = get_aux_id(ioport);
+ if (!is_a_mouse(sc->hw.hwid)) {
+ restore_controller(ioport,sc->command_byte);
+ if (verbose)
+ printf("psm%d: unknown device type (%d).\n",unit,sc->hw.hwid);
+ if (bootverbose)
+ --verbose;
+ return (0);
+ }
+ switch (sc->hw.hwid) {
+ case PSM_BALLPOINT_ID:
+ sc->hw.type = MOUSE_TRACKBALL;
+ break;
+ case PSM_MOUSE_ID:
+ sc->hw.type = MOUSE_MOUSE;
+ break;
+ default:
+ sc->hw.type = MOUSE_UNKNOWN;
+ break;
+ }
+
+ /* # of buttons */
+ sc->hw.buttons = get_mouse_buttons(ioport);
+
+ /* set mouse parameters */
+ /* FIXME: I don't know if these parameters are reasonable */
+ /* FIXME: should we set them in `psmattach()' rather than here? */
+ sc->mode.rate = set_mouse_sampling_rate(ioport,PSMD_DEFAULT_RATE);
+ sc->mode.resolution =
+ set_mouse_resolution(ioport,PSMD_DEFAULT_RESOLUTION);
+ set_mouse_scaling(ioport); /* 1:1 scaling */
+ set_mouse_mode(ioport); /* stream mode */
+
+ /* just check the status of the mouse */
+ if (verbose) {
+ get_mouse_status(ioport,stat);
+ log(LOG_DEBUG,"psm%d: status %02x %02x %02x\n",
+ unit,stat[0],stat[1],stat[2]);
+ }
+
+ /* disable the aux port for now... */
+ /* WARNING: we save the controller command byte and use it later
+ during `psmopen()' and `psmclose()'. This will be OK, so long
+ as the keyboard/console device driver won't change the command
+ byte in the course of its operation (this is the case with
+ `syscons'). If not,... */
+ sc->command_byte &= ~KBD_AUX_CONTROL_BITS;
+ set_controller_command_byte(ioport,sc->command_byte,
+ KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+
+ /* done */
+ return (IO_PSMSIZE);
}
static int
psmattach(struct isa_device *dvp)
{
int unit = dvp->id_unit;
- int ioport = dvp->id_iobase;
struct psm_softc *sc = &psm_softc[unit];
- /* Save I/O base address */
- psmaddr[unit] = ioport;
-
- /* Disable mouse interrupts */
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, PSM_ENABLE);
-#ifdef 0
- psm_write(ioport, PSM_SET_RES);
- psm_write(ioport, 0x03); /* 8 counts/mm */
- psm_write(ioport, PSM_SET_SCALE);
- psm_write(ioport, 0x02); /* 2:1 */
- psm_write(ioport, PSM_SET_SCALE21);
- psm_write(ioport, PSM_SET_SAMPLE);
- psm_write(ioport, 0x64); /* 100 samples/sec */
- psm_write(ioport, PSM_SET_STREAM);
-#endif
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, PSM_DISABLE);
- psm_command(ioport, PSM_INT_DISABLE);
+ /* initial operation mode */
+ sc->mode.accelfactor = PSM_ACCEL;
+ sc->mode.protocol = MOUSE_PROTO_PS2;
+ sc->mkpacket = mkps2;
/* Setup initial state */
- sc->state = 0;
+ sc->state = PSM_VALID;
/* Done */
- return (0); /* XXX eh? usually 1 indicates success */
+#ifdef DEVFS
+ sc->devfs_token =
+ devfs_add_devswf(&psm_cdevsw, PSM_MKMINOR(unit,TRUE),
+ DV_CHR, 0, 0, 0666, "psm%d", unit);
+ sc->n_devfs_token =
+ devfs_add_devswf(&psm_cdevsw, PSM_MKMINOR(unit,FALSE),
+ DV_CHR,0, 0, 0666, "npsm%d", unit);
+#endif
+
+ printf("psm%d: device ID %d, %d buttons?\n",
+ unit,sc->hw.hwid,sc->hw.buttons);
+
+ if (bootverbose)
+ --verbose;
+
+ return (1);
+ /* return (0); XXX eh? usually 1 indicates success */
}
-static int
+#ifdef PSM_CURRENT
+static
+#endif
+int
psmopen(dev_t dev, int flag, int fmt, struct proc *p)
{
- struct psm_softc *sc;
+ int unit = PSM_UNIT(dev);
int ioport;
- int unit = PSMUNIT(dev);
+ struct psm_softc *sc;
+ int stat[3];
/* Validate unit number */
if (unit >= NPSM)
@@ -233,11 +675,9 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
/* Get device data */
sc = &psm_softc[unit];
- ioport = psmaddr[unit];
-
- /* If device does not exist */
- if (ioport == 0)
+ if ((sc->state & PSM_VALID) == 0)
return (ENXIO);
+ ioport = sc->addr;
/* Disallow multiple opens */
if (sc->state & PSM_OPEN)
@@ -247,63 +687,70 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
sc->state |= PSM_OPEN;
sc->rsel.si_flags = 0;
sc->rsel.si_pid = 0;
- sc->status = 0;
+
+ /* flush the event queue */
+ sc->queue.count = 0;
+ sc->queue.head = 0;
+ sc->queue.tail = 0;
sc->button = 0;
- sc->x = 0;
- sc->y = 0;
- /* Allocate and initialize a ring buffer */
- sc->inq.count = sc->inq.first = sc->inq.last = 0;
+ /* empty input/output buffers */
+ sc->inputbytes = 0;
+ sc->outputbytes = 0;
+ 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,
+ sc->command_byte & ~KBD_KBD_CONTROL_BITS,
+ KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
+ | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+
+ /* 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);
+ return (EIO);
+ }
- /* Enable Bus Mouse interrupts */
- psm_write_dev(ioport, PSM_DEV_ENABLE);
-
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, PSM_ENABLE);
- psm_command(ioport, PSM_INT_ENABLE);
+ 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]);
+ }
- /* Successful open */
-#ifdef DEVFS
- sc->devfs_token =
- devfs_add_devswf(&psm_cdevsw, unit << 1, DV_CHR, 0, 0, 0666,
- "psm%d", unit);
- sc->n_devfs_token =
- devfs_add_devswf(&psm_cdevsw, (unit<<1)+1, DV_CHR,0, 0, 0666,
- "npsm%d", unit);
-#endif
+ /* enable the aux port and interrupt */
+ set_controller_command_byte(ioport,sc->command_byte,
+ KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT);
+ /* done */
return (0);
}
-static void
-psm_poll_status(int ioport)
+#ifdef PSM_CURRENT
+static
+#endif
+int
+psmclose(dev_t dev, int flag, int fmt, struct proc *p)
{
- u_char c;
+ struct psm_softc *sc = &psm_softc[PSM_UNIT(dev)];
+ int ioport = sc->addr;
- while(c = inb(ioport+PSM_STATUS) & 0x03)
- if(c & PSM_OUTPUT_ACK == PSM_OUTPUT_ACK) {
- /* XXX - Avoids some keyboard hangs during probe */
- DELAY(6);
- inb(ioport+PSM_DATA);
- }
- return;
-}
+ /* disable the aux interrupt */
+ set_controller_command_byte(ioport,sc->command_byte,
+ KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
-static int
-psmclose(dev_t dev, int flag, int fmt, struct proc *p)
-{
- int unit, ioport;
- struct psm_softc *sc;
+ /* remove anything left in the output buffer */
+ empty_aux_buffer(ioport);
- /* Get unit and associated info */
- unit = PSMUNIT(dev);
- sc = &psm_softc[unit];
- ioport = psmaddr[unit];
+ /* 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);
- /* Disable further mouse interrupts */
- psm_command(ioport, PSM_INT_DISABLE);
- psm_poll_status(ioport);
- outb(ioport+PSM_CNTRL, PSM_DISABLE);
+ /* remove anything left in the output buffer */
+ empty_aux_buffer(ioport);
/* Complete the close */
sc->state &= ~PSM_OPEN;
@@ -313,109 +760,315 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
}
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,
+ };
+ unsigned char delta;
+
+ if (maxlen - *len < MOUSE_MSS_PACKETSIZE)
+ return FALSE;
+
+ buf[0] = MOUSE_MSS_SYNC;
+ buf[0] |= butmap[status->button & BUTSTATMASK];
+
+ if (status->dx < -128)
+ delta = 0x80; /* -128 */
+ else if (status->dx > 127)
+ delta = 0x7f; /* 127 */
+ else
+ delta = (unsigned char)status->dx;
+ buf[0] |= (delta & 0xc0) >> 6; /* bit 6-7 */
+ buf[1] = delta & 0x3f; /* bit 0-5 */
+
+ if (status->dy < -128)
+ delta = 0x80; /* -128 */
+ else if (status->dy > 127)
+ delta = 0x7f; /* 127 */
+ else
+ delta = (unsigned char)status->dy;
+ buf[0] |= (delta & 0xc0) >> 4; /* bit 6-7 */
+ buf[2] = delta & 0x3f; /* bit 0-5 */
+
+ *len += MOUSE_MSS_PACKETSIZE;
+
+ return TRUE;
+}
+
+static int
+mkmsc(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,
+ };
+ unsigned char delta;
+
+ if (maxlen - *len < MOUSE_PS2_PACKETSIZE)
+ return FALSE;
+
+ buf[0] = MOUSE_MSC_SYNC;
+ buf[0] |= ~butmap[status->button & BUTSTATMASK] & MOUSE_MSC_BUTTONS;
+
+ if (status->dx < -128)
+ delta = 0x80; /* -128 */
+ else if (status->dx > 127)
+ delta = 0x7f; /* 127 */
+ else
+ delta = (unsigned char)status->dx;
+ buf[1] = delta >> 2;
+ buf[3] = delta - buf[1];
+
+ if (status->dy < -128)
+ delta = 0x80; /* -128 */
+ else if (status->dy > 127)
+ delta = 0x7f; /* 127 */
+ else
+ delta = (unsigned char)status->dy;
+ buf[2] = delta >> 2;
+ buf[4] = delta - buf[2];
+
+ *len += MOUSE_MSC_PACKETSIZE;
+
+ return TRUE;
+}
+
+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,
+ };
+ register int delta;
+
+ if (maxlen - *len < MOUSE_PS2_PACKETSIZE)
+ return FALSE;
+
+ buf[0] = MOUSE_PS2_SYNC;
+ buf[0] |= butmap[status->button & BUTSTATMASK];
+
+ if (status->dx < -128)
+ delta = -128;
+ else if (status->dx > 127)
+ delta = 127;
+ else
+ delta = status->dx;
+ if (delta < 0)
+ buf[0] |= MOUSE_PS2_XNEG;
+ buf[1] = delta;
+
+ if (status->dy < -128)
+ delta = -128;
+ else if (status->dy > 127)
+ delta = 127;
+ else
+ delta = status->dy;
+ if (delta < 0)
+ buf[0] |= MOUSE_PS2_YNEG;
+ buf[2] = delta;
+
+ *len += MOUSE_PS2_PACKETSIZE;
+
+ return TRUE;
+}
+
+#ifdef PSM_CURRENT
+static
+#endif
+int
psmread(dev_t dev, struct uio *uio, int flag)
{
+ register struct psm_softc *sc = &psm_softc[PSM_UNIT(dev)];
+ unsigned int length;
+ int error;
int s;
- int error = 0; /* keep compiler quiet, even though initialisation
- is unnecessary */
- unsigned length;
- struct psm_softc *sc;
- unsigned char buffer[PSM_CHUNK];
+ int i;
- /* Get device information */
- sc = &psm_softc[PSMUNIT(dev)];
-
- /* Block until mouse activity occured */
+ /* block until mouse activity occured */
s = spltty();
- while (sc->inq.count == 0) {
- if (minor(dev) & 0x1) {
- splx(s);
- return (EWOULDBLOCK);
- }
- sc->state |= PSM_ASLP;
- error = tsleep((caddr_t)sc, PZERO | PCATCH, "psmrea", 0);
- if (error != 0) {
- splx(s);
- return (error);
+ if ((sc->outputbytes <= 0) && (sc->queue.count <= 0)) {
+ while (sc->queue.count <= 0) {
+ if (PSM_NBLOCKIO(dev)) {
+ splx(s);
+ return (EWOULDBLOCK);
+ }
+ sc->state |= PSM_ASLP;
+ error = tsleep((caddr_t)sc, PZERO | PCATCH,
+ "psmread", 0);
+ if (error) {
+ splx(s);
+ return (error);
+ }
}
}
- /* Transfer as many chunks as possible */
- while (sc->inq.count > 0 && uio->uio_resid > 0) {
- length = min(sc->inq.count, uio->uio_resid);
- if (length > sizeof(buffer))
- length = sizeof(buffer);
-
- /* Remove a small chunk from input queue */
- if (sc->inq.first + length >= PSM_BSIZE) {
- bcopy(&sc->inq.queue[sc->inq.first],
- buffer, PSM_BSIZE - sc->inq.first);
- bcopy(sc->inq.queue, &buffer[PSM_BSIZE - sc->inq.first],
- length - (PSM_BSIZE - sc->inq.first));
+ if (sc->outputbytes >= uio->uio_resid) {
+ /* nothing to be done */
+ } else {
+ if (sc->outputbytes > 0) {
+ bcopy(&sc->opacket[sc->outputhead],sc->opacket,
+ sc->outputbytes);
}
- else
- bcopy(&sc->inq.queue[sc->inq.first], buffer, length);
-
- sc->inq.first = (sc->inq.first + length) % PSM_BSIZE;
- sc->inq.count -= length;
-
- /* Copy data to user process */
- error = uiomove(buffer, length, uio);
- if (error)
- break;
+ sc->outputhead = 0;
+ for(i = sc->queue.head; sc->queue.count > 0;
+ i = (i + 1) % PSM_BUFSIZE, --sc->queue.count) {
+ if (!(*sc->mkpacket)(&sc->opacket[sc->outputbytes],
+ &sc->outputbytes,PSM_BUFSIZE,&sc->queue.buf[i]))
+ break;
+ }
+ sc->queue.head = i;
}
- sc->x = sc->y = 0;
- /* Allow interrupts again */
+ /* allow interrupts again */
splx(s);
+
+ /* copy data to user process */
+ length = min(sc->outputbytes,uio->uio_resid);
+ error = uiomove(&sc->opacket[sc->outputhead], length, uio);
+ if (error)
+ return (error);
+ sc->outputhead += length;
+ sc->outputbytes -= length;
+
return (error);
}
-static int
+#ifdef PSM_CURRENT
+static
+#endif
+int
psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
- struct psm_softc *sc;
- struct mouseinfo info;
- int s, error;
-
- /* Get device information */
- sc = &psm_softc[PSMUNIT(dev)];
+ struct psm_softc *sc = &psm_softc[PSM_UNIT(dev)];
+ mouseinfo_t info;
+ mousestatus_t *ms;
+ packetfunc_t func;
+ int error = 0;
+ int s;
/* Perform IOCTL command */
switch (cmd) {
- case MOUSEIOCREAD:
- /* Don't modify info while calculating */
- s = spltty();
+ case MOUSE_GETINFO:
+ *(mousehw_t *)addr = sc->hw;
+ break;
- /* Build mouse status octet */
- info.status = sc->status;
- if (sc->x || sc->y)
- info.status |= MOVEMENT;
-
- /* Encode X and Y motion as good as we can */
- if (sc->x > 127)
- info.xmotion = 127;
- else if (sc->x < -128)
- info.xmotion = -128;
- else
- info.xmotion = sc->x;
-
- if (sc->y > 127)
- info.ymotion = 127;
- else if (sc->y < -128)
- info.ymotion = -128;
- else
- info.ymotion = sc->y;
-
- /* Reset historical information */
- sc->x = 0;
- sc->y = 0;
- sc->status &= ~BUTCHNGMASK;
-
- /* Allow interrupts and copy result buffer */
+ case MOUSE_GETMODE:
+ *(mousemode_t *)addr = sc->mode;
+ break;
+
+ case MOUSE_SETMODE:
+ if (((mousemode_t *)addr)->rate < 0) {
+ error = EINVAL;
+ break;
+ }
+ if (((mousemode_t *)addr)->resolution < 0) {
+ error = EINVAL;
+ break;
+ }
+#ifndef PSM_NOEMULATION
+ switch (((mousemode_t *)addr)->protocol) {
+ case MOUSE_PROTO_MS:
+ func = mkms;
+ break;
+ case MOUSE_PROTO_MSC:
+ func = mkmsc;
+ break;
+ case MOUSE_PROTO_PS2:
+ func = mkps2;
+ break;
+ default:
+ error = EINVAL;
+ func = (packetfunc_t)NULL;
+ break;
+ }
+ if (error)
+ break;
+#endif /* PSM_NOEMULATION */
+ if (((mousemode_t *)addr)->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,
+ sc->command_byte & ~KBD_KBD_CONTROL_BITS,
+ KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
+ | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT);
+
+ /* 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);
+
+ /* 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;
+ sc->mkpacket = func;
+ sc->outputbytes = 0;
+ sc->outputhead = 0;
+#endif /* PSM_NOEMULATION */
+ sc->mode.accelfactor = ((mousemode_t *)addr)->accelfactor;
+
+ splx(s);
+ break;
+
+ case MOUSEIOCREAD: /* FIXME: this should go... */
+ error = EINVAL;
+ 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;
+
+ sc->queue.head = (sc->queue.head + 1) % PSM_BUFSIZE;
+ --sc->queue.count;
+ }
splx(s);
- error = copyout(&info, addr, sizeof(struct mouseinfo));
+
+ *(mouseinfo_t *)addr = info;
break;
default:
@@ -430,23 +1083,111 @@ psmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
void
psmintr(int unit)
{
- struct psm_softc *sc = &psm_softc[unit];
- int ioport = psmaddr[unit];
+ /* the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
+ into `mouseinfo' button bits (BUT?STAT). */
+ static butmap[8] = {
+ 0, BUT1STAT, BUT3STAT, BUT1STAT | BUT3STAT,
+ BUT2STAT, BUT1STAT | BUT2STAT, BUT2STAT | BUT3STAT,
+ BUT1STAT | BUT2STAT | BUT3STAT
+ };
+ register struct psm_softc *sc = &psm_softc[unit];
+ int ioport = sc->addr;
+ mousestatus_t *ms;
+ unsigned char c;
+ int x, y;
+
+ /* is this really for us? */
+ if ((inb(ioport + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)
+ != KBDS_AUX_BUFFER_FULL)
+ return;
+
+ /* read a byte */
+ c = inb(ioport + KBD_DATA_PORT);
+
+ /* discard the byte if the device is not open */
+ if ((sc->state & PSM_OPEN) == 0)
+ return;
+
+ /* interpret data bytes
+ 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 sync bits then!). There need to be two consequtive
+ bytes with these bits off to re-sync. (This can be done
+ if the user clicks buttons without moving the mouse?)
+ */
+ if (sc->inputbytes == 0) {
+#ifndef PSM_NOCHECKSYNC
+ if ((c & MOUSE_PS2_SYNCMASK) == MOUSE_PS2_SYNC)
+#endif /* PSM_NOCHECKSYNC */
+ sc->ipacket[sc->inputbytes++] = c;
+ } else {
+ sc->ipacket[sc->inputbytes++] = c;
+ if (sc->inputbytes >= MOUSE_PS2_PACKETSIZE) {
+ if (sc->queue.count >= PSM_BUFSIZE) {
+ /* no room in the queue */
+ sc->inputbytes = 0;
+ return;
+ }
+ if (sc->mode.accelfactor >= 1) {
+ x = (sc->ipacket[0] & MOUSE_PS2_XOVERFLOW) ?
+ 128 : sc->ipacket[1];
+ if (x != 0) {
+ x = x*x/sc->mode.accelfactor;
+ if (x == 0)
+ x = 1;
+ if (sc->ipacket[0] & MOUSE_PS2_XNEG)
+ x = -x;
+ }
+ y = (sc->ipacket[0] & MOUSE_PS2_YOVERFLOW) ?
+ 128 : sc->ipacket[2];
+ if (y != 0) {
+ y = y*y/sc->mode.accelfactor;
+ if (y == 0)
+ y = 1;
+ if (sc->ipacket[0] & MOUSE_PS2_YNEG)
+ y = -y;
+ }
+ } else { /* sc->mode.accelfactor <= 0 */
+ x = (sc->ipacket[0] & MOUSE_PS2_XOVERFLOW) ?
+ ((sc->ipacket[0] & MOUSE_PS2_XNEG) ?
+ -128 : 127) : sc->ipacket[1];
+ y = (sc->ipacket[0] & MOUSE_PS2_YOVERFLOW) ?
+ ((sc->ipacket[0] & MOUSE_PS2_YNEG) ?
+ -128 : 127) : sc->ipacket[2];
+ }
+
+ /* FIXME: we shouldn't store data if no movement
+ and no button status change is detected? */
+ ms = &sc->queue.buf[sc->queue.tail];
+ ms->dx = x;
+ ms->dy = y;
+ ms->obutton = sc->button; /* previous button state */
+ sc->button = ms->button = /* latest button state */
+ butmap[sc->ipacket[0] & MOUSE_PS2_BUTTONS];
+ sc->queue.tail =
+ (sc->queue.tail + 1) % PSM_BUFSIZE;
+ ++sc->queue.count;
+ sc->inputbytes = 0;
+ }
+ }
- sc->inq.queue[sc->inq.last++ % PSM_BSIZE] = inb(ioport+PSM_DATA);
- sc->inq.count++;
- if (sc -> state & PSM_ASLP) {
+ if (sc->state & PSM_ASLP) {
sc->state &= ~PSM_ASLP;
wakeup((caddr_t)sc);
}
selwakeup(&sc->rsel);
}
-static int
+#ifdef PSM_CURRENT
+static
+#endif
+int
psmselect(dev_t dev, int rw, struct proc *p)
{
+ struct psm_softc *sc = &psm_softc[PSM_UNIT(dev)];
int s, ret;
- struct psm_softc *sc = &psm_softc[PSMUNIT(dev)];
/* Silly to select for output */
if (rw == FWRITE)
@@ -454,9 +1195,9 @@ psmselect(dev_t dev, int rw, struct proc *p)
/* Return true if a mouse event available */
s = spltty();
- if (sc->inq.count)
+ if ((sc->outputbytes > 0) || (sc->queue.count > 0)) {
ret = 1;
- else {
+ } else {
selrecord(p, &sc->rsel);
ret = 0;
}
@@ -465,21 +1206,24 @@ psmselect(dev_t dev, int rw, struct proc *p)
return (ret);
}
+#ifdef PSM_CURRENT
-static psm_devsw_installed = 0;
+static int psm_devsw_installed = FALSE;
static void
psm_drvinit(void *unused)
{
dev_t dev;
- if( ! psm_devsw_installed ) {
+ if (!psm_devsw_installed) {
dev = makedev(CDEV_MAJOR, 0);
cdevsw_add(&dev,&psm_cdevsw, NULL);
- psm_devsw_installed = 1;
+ psm_devsw_installed = TRUE;
}
}
-SYSINIT(psmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,psm_drvinit,NULL)
+SYSINIT(psmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE + CDEV_MAJOR,psm_drvinit,NULL)
+
+#endif /* PSM_CURRENT */
#endif /* NPSM > 0 */
OpenPOWER on IntegriCloud