summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386/pc386/console/mouse_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/i386/pc386/console/mouse_parser.c')
-rw-r--r--c/src/lib/libbsp/i386/pc386/console/mouse_parser.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/console/mouse_parser.c b/c/src/lib/libbsp/i386/pc386/console/mouse_parser.c
new file mode 100644
index 0000000000..ca068df87d
--- /dev/null
+++ b/c/src/lib/libbsp/i386/pc386/console/mouse_parser.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 1999 Greg Haerr <greg@censoft.com>
+ * Portions Copyright (c) 1991 David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * UNIX Serial Port Mouse Driver
+ *
+ * This driver opens a serial port directly, and interprets serial data.
+ * Microsoft, PC, Logitech and PS/2 mice are supported.
+ * The PS/2 mouse is only supported if the OS runs the mouse
+ * byte codes through the serial port.
+ *
+ * The following environment variables control the mouse type expected
+ * and the serial port to open.
+ *
+ * Environment Var Default Allowed
+ * MOUSE_TYPE pc ms, pc, logi, ps2
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <bsp.h>
+#include "keyboard.h"
+#include "mouse_parser.h"
+#include "serial_mouse.h"
+
+
+/* NOTE NOTE NOTE NOTE:
+ Select here the mouse type !!!!!
+*/
+#ifndef MOUSE_TYPE
+#define MOUSE_TYPE "ms" /* default mouse type "ms","pc","ps2" */
+#endif
+
+/* states for the mouse*/
+#define IDLE 0 /* start of byte sequence */
+#define XSET 1 /* setting x delta */
+#define YSET 2 /* setting y delta */
+#define XADD 3 /* adjusting x delta */
+#define YADD 4 /* adjusting y delta */
+
+/* values in the bytes returned by the mouse for the buttons*/
+#define PC_LEFT_BUTTON 4
+#define PC_MIDDLE_BUTTON 2
+#define PC_RIGHT_BUTTON 1
+
+#define MS_LEFT_BUTTON 2
+#define MS_RIGHT_BUTTON 1
+
+#define PS2_CTRL_BYTE 0x08
+#define PS2_LEFT_BUTTON 1
+#define PS2_RIGHT_BUTTON 2
+
+/* Bit fields in the bytes sent by the mouse.*/
+#define TOP_FIVE_BITS 0xf8
+#define BOTTOM_THREE_BITS 0x07
+#define TOP_BIT 0x80
+#define SIXTH_BIT 0x40
+#define BOTTOM_TWO_BITS 0x03
+#define THIRD_FOURTH_BITS 0x0c
+#define BOTTOM_SIX_BITS 0x3f
+
+/* local data*/
+static int state; /* IDLE, XSET, ... */
+static BUTTON buttons; /* current mouse buttons pressed*/
+static BUTTON availbuttons; /* which buttons are available */
+static COORD xd; /* change in x */
+static COORD yd; /* change in y */
+
+static int left; /* because the button values change */
+static int middle; /* between mice, the buttons are */
+static int right; /* redefined */
+
+static int (*parse)( int ); /* parse routine */
+
+/* local routines*/
+static int ParsePC(int); /* routine to interpret PC mouse */
+static int ParseMS(int); /* routine to interpret MS mouse */
+static int ParsePS2(int); /* routine to interpret PS/2 mouse */
+
+extern void uart_set_driver_handler( int port, void ( *handler )( void *, char *, int ) );
+extern void kbd_set_driver_handler( void ( *handler )( void *, unsigned short, unsigned long ) );
+extern void ps2_set_driver_handler( int port, void ( *handler )( void *, char *, int ) );
+
+/*
+ * Open up the mouse device.
+ * Returns the fd if successful, or negative if unsuccessful.
+ */
+int MOU_Init()
+{
+ char *type;
+
+ /* get mouse type and port*/
+ type = MOUSE_TYPE;
+
+ /* set button bits and parse procedure*/
+ if(!strcmp(type, "pc") || !strcmp(type, "logi")) {
+ /* pc or logitech mouse*/
+ left = PC_LEFT_BUTTON;
+ middle = PC_MIDDLE_BUTTON;
+ right = PC_RIGHT_BUTTON;
+ parse = ParsePC;
+ } else if (strcmp(type, "ms") == 0) {
+ /* microsoft mouse*/
+ left = MS_LEFT_BUTTON;
+ right = MS_RIGHT_BUTTON;
+ middle = 0;
+ parse = ParseMS;
+ } else if (strcmp(type, "ps2") == 0) {
+ /* PS/2 mouse*/
+ left = PS2_LEFT_BUTTON;
+ right = PS2_RIGHT_BUTTON;
+ middle = 0;
+ parse = ParsePS2;
+ } else
+ return -1;
+
+ printk("Device: /dev/mouse -- mouse type is: %s\n", MOUSE_TYPE );
+
+ /* initialize data*/
+ availbuttons = left | middle | right;
+ state = IDLE;
+ buttons = 0;
+ xd = 0;
+ yd = 0;
+ return 0;
+}
+
+/*
+ * Attempt to read bytes from the mouse and interpret them.
+ * Returns -1 on error, 0 if either no bytes were read or not enough
+ * was read for a complete state, or 1 if the new state was read.
+ * When a new state is read, the current buttons and x and y deltas
+ * are returned. This routine does not block.
+ */
+int MOU_Data( int ch, COORD *dx, COORD *dy, COORD *dz, BUTTON *bptr)
+{
+ int b;
+
+ /*
+ * Loop over all the bytes read in the buffer, parsing them.
+ * When a complete state has been read, return the results,
+ * leaving further bytes in the buffer for later calls.
+ */
+ if( (*parse)( ch ) )
+ {
+ *dx = xd;
+ *dy = yd;
+ *dz = 0;
+ b = 0;
+ if(buttons & left)
+ b |= LBUTTON;
+ if(buttons & right)
+ b |= RBUTTON;
+ if(buttons & middle)
+ b |= MBUTTON;
+ *bptr = b;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Input routine for PC mouse.
+ * Returns nonzero when a new mouse state has been completed.
+ */
+static int ParsePC(int byte)
+{
+ int sign; /* sign of movement */
+
+ switch (state) {
+ case IDLE:
+ if ((byte & TOP_FIVE_BITS) == TOP_BIT) {
+ buttons = ~byte & BOTTOM_THREE_BITS;
+ state = XSET;
+ }
+ break;
+
+ case XSET:
+ sign = 1;
+ if (byte > 127) {
+ byte = 256 - byte;
+ sign = -1;
+ }
+ xd = byte * sign;
+ state = YSET;
+ break;
+
+ case YSET:
+ sign = 1;
+ if (byte > 127) {
+ byte = 256 - byte;
+ sign = -1;
+ }
+ yd = -byte * sign;
+ state = XADD;
+ break;
+
+ case XADD:
+ sign = 1;
+ if (byte > 127) {
+ byte = 256 - byte;
+ sign = -1;
+ }
+ xd += byte * sign;
+ state = YADD;
+ break;
+
+ case YADD:
+ sign = 1;
+ if (byte > 127) {
+ byte = 256 - byte;
+ sign = -1;
+ }
+ yd -= byte * sign;
+ state = IDLE;
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Input routine for Microsoft mouse.
+ * Returns nonzero when a new mouse state has been completed.
+ */
+static int ParseMS(int byte)
+{
+ switch (state) {
+ case IDLE:
+ if (byte & SIXTH_BIT) {
+ buttons = (byte >> 4) & BOTTOM_TWO_BITS;
+ yd = ((byte & THIRD_FOURTH_BITS) << 4);
+ xd = ((byte & BOTTOM_TWO_BITS) << 6);
+ state = XADD;
+ }
+ break;
+
+ case XADD:
+ xd |= (byte & BOTTOM_SIX_BITS);
+ state = YADD;
+ break;
+
+ case YADD:
+ yd |= (byte & BOTTOM_SIX_BITS);
+ state = IDLE;
+ if (xd > 127)
+ xd -= 256;
+ if (yd > 127)
+ yd -= 256;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Input routine for PS/2 mouse.
+ * Returns nonzero when a new mouse state has been completed.
+ */
+static int ParsePS2(int byte)
+{
+ switch (state) {
+ case IDLE:
+ if (byte & PS2_CTRL_BYTE) {
+ buttons = byte &
+ (PS2_LEFT_BUTTON|PS2_RIGHT_BUTTON);
+ state = XSET;
+ }
+ break;
+
+ case XSET:
+ if(byte > 127)
+ byte -= 256;
+ xd = byte;
+ state = YSET;
+ break;
+
+ case YSET:
+ if(byte > 127)
+ byte -= 256;
+ yd = -byte;
+ state = IDLE;
+ return 1;
+ }
+ return 0;
+}
+
+static rtems_id queue_id = 0;
+
+/* generic keyboard parser */
+static void mouse_parser( void *ptr, char *buffer, int size )
+{
+ COORD dx;
+ COORD dy;
+ COORD dz;
+ BUTTON bptr;
+ while( size-- )
+ {
+ if( MOU_Data( *buffer++, &dx, &dy, &dz, &bptr ) )
+ {
+ struct MW_UID_MESSAGE m;
+ m.type = MV_UID_REL_POS;
+ /* buttons definitons have been selected to match */
+ m.m.pos.btns = bptr;
+ m.m.pos.x = dx;
+ m.m.pos.y = dy;
+ m.m.pos.z = dz;
+/* printk( "Mouse: msg: dx=%d, dy=%d, btn=%X\n", dx, dy, bptr ); */
+ rtems_message_queue_send( queue_id, ( void * )&m, sizeof( struct MW_UID_MESSAGE ) );
+ }
+ }
+}
+
+/* enable the mouse to add messages to the queue */
+void register_mou_msg_queue( char * q_name, int port )
+{
+ rtems_name queue_name;
+ rtems_status_code status;
+ queue_name = rtems_build_name( q_name[0],
+ q_name[1],
+ q_name[2],
+ q_name[3] );
+ status = rtems_message_queue_ident( queue_name, RTEMS_LOCAL, &queue_id );
+ if( status != RTEMS_SUCCESSFUL )
+ {
+ printk( "UID_Queue: error open queue: %d\n", status );
+ return;
+ }
+ MOU_Init();
+ if( port == -1 )
+ {
+ /* we know the mouse type in this case, let's initialize everything */
+ left = PS2_LEFT_BUTTON;
+ right = PS2_RIGHT_BUTTON;
+ middle = 0;
+ parse = ParsePS2;
+ ps2_set_driver_handler( port, mouse_parser );
+ }
+ else
+ {
+ uart_set_driver_handler( port, mouse_parser );
+ }
+}
+
+/* stop the mouse from adding messages to the queue */
+void unregister_mou_msg_queue( int port )
+{
+ if( port == -1 )
+ {
+ ps2_set_driver_handler( port, NULL );
+ }
+ else
+ {
+ uart_set_driver_handler( port, NULL );
+ }
+}
+
+/* adds a kbd message to the queue */
+static void kbd_parser( void *ptr, unsigned short keycode, unsigned long mods )
+{
+ struct MW_UID_MESSAGE m;
+ struct kbd_struct * kbd = ( struct kbd_struct *)ptr;
+
+ m.type = MV_UID_KBD;
+ m.m.kbd.code = keycode;
+ m.m.kbd.modifiers = kbd->ledflagstate;
+ m.m.kbd.mode = kbd->kbdmode;
+ /* printk( "kbd: msg: keycode=%X, mod=%X\n", keycode, mods ); */
+ rtems_message_queue_send( queue_id, ( void * )&m,
+ sizeof( struct MW_UID_MESSAGE ) );
+}
+
+void register_kbd_msg_queue( char *q_name, int port )
+{
+ rtems_name queue_name;
+ rtems_status_code status;
+
+ queue_name = rtems_build_name( q_name[0],
+ q_name[1],
+ q_name[2],
+ q_name[3] );
+ status = rtems_message_queue_ident( queue_name, RTEMS_LOCAL, &queue_id );
+ if( status != RTEMS_SUCCESSFUL )
+ {
+ printk( "UID_Queue: error open queue: %d\n", status );
+ return;
+ }
+ kbd_set_driver_handler( kbd_parser );
+}
+
+
+void unregister_kbd_msg_queue( int port )
+{
+ kbd_set_driver_handler( NULL );
+}