/* * Copyright (c) 1999 Greg Haerr * 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 #include #include /* strcmp */ #include #include #include #include #include #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 ); }